summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorderaadt <>1999-07-03 21:45:44 +0000
committerderaadt <>1999-07-03 21:45:44 +0000
commit0395bc5800143dafc68a0782a5243348d093419e (patch)
treea228bf063fbcb765aec27af54950c8defa19f79f /src/lib
parent11b6f12bb197a5b34ad2a1da38937da31e9410ac (diff)
downloadopenbsd-0395bc5800143dafc68a0782a5243348d093419e.tar.gz
openbsd-0395bc5800143dafc68a0782a5243348d093419e.tar.bz2
openbsd-0395bc5800143dafc68a0782a5243348d093419e.zip
cleaned up
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/libc/net/getaddrinfo.c923
-rw-r--r--src/lib/libc/net/getnameinfo.c388
2 files changed, 678 insertions, 633 deletions
diff --git a/src/lib/libc/net/getaddrinfo.c b/src/lib/libc/net/getaddrinfo.c
index 0e33aa1368..2094692339 100644
--- a/src/lib/libc/net/getaddrinfo.c
+++ b/src/lib/libc/net/getaddrinfo.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * %%% copyright-cmetz-96-bsd 2 * %%% copyright-cmetz-96-bsd
3 * Copyright (c) 1996-1999, Craig Metz, All rights reserved. 3 * Copyright (c) 1996-1999, Craig Metz, All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
@@ -17,7 +17,7 @@
17 * 4. Neither the name of the author nor the names of contributors 17 * 4. Neither the name of the author nor the names of contributors
18 * may be used to endorse or promote products derived from this software 18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission. 19 * without specific prior written permission.
20 * 20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -29,7 +29,6 @@
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE. 31 * SUCH DAMAGE.
32 *
33 */ 32 */
34 33
35/* getaddrinfo() v1.38 */ 34/* getaddrinfo() v1.38 */
@@ -50,504 +49,518 @@
50#include <sys/utsname.h> 49#include <sys/utsname.h>
51#include <sys/un.h> 50#include <sys/un.h>
52#include <netinet/in.h> 51#include <netinet/in.h>
52#include <arpa/inet.h>
53#include <netdb.h> 53#include <netdb.h>
54#include <errno.h> 54#include <errno.h>
55 55
56#ifndef AF_LOCAL 56#define GAIH_OKIFUNSPEC 0x0100
57#define AF_LOCAL AF_UNIX 57#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
58#endif /* AF_LOCAL */
59#ifndef PF_LOCAL
60#define PF_LOCAL PF_UNIX
61#endif /* PF_LOCAL */
62#ifndef UNIX_PATH_MAX
63#define UNIX_PATH_MAX 108
64#endif /* UNIX_PATH_MAX */
65
66#define GAIH_OKIFUNSPEC 0x0100
67#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
68 58
69static struct addrinfo nullreq = 59static struct addrinfo nullreq = {
70{ 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL }; 60 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL
61};
71 62
72struct gaih_service { 63struct gaih_service {
73 char *name; 64 char *name;
74 int num; 65 int num;
75}; 66};
76 67
77struct gaih_servtuple { 68struct gaih_servtuple {
78 struct gaih_servtuple *next; 69 struct gaih_servtuple *next;
79 int socktype; 70 int socktype;
80 int protocol; 71 int protocol;
81 int port; 72 int port;
82}; 73};
83 74
84static struct gaih_servtuple nullserv = { 75static struct gaih_servtuple nullserv = {
85 NULL, 0, 0, 0 76 NULL, 0, 0, 0
86}; 77};
87 78
88struct gaih_addrtuple { 79struct gaih_addrtuple {
89 struct gaih_addrtuple *next; 80 struct gaih_addrtuple *next;
90 int family; 81 int family;
91 char addr[16]; 82 char addr[16];
92 char *cname; 83 char *cname;
93}; 84};
94 85
95struct gaih_typeproto { 86static struct gaih_typeproto {
96 int socktype; 87 int socktype;
97 int protocol; 88 int protocol;
98 char *name; 89 char *name;
90} gaih_inet_typeproto[] = {
91 { 0, 0, NULL },
92 { SOCK_STREAM, IPPROTO_TCP, "tcp" },
93 { SOCK_DGRAM, IPPROTO_UDP, "udp" },
94 { 0, 0, NULL }
99}; 95};
100 96
101#define RETURN_ERROR(x) do { \ 97static int
102 rval = (x); \ 98netdb_lookup_addr(const char *name, int af,
103 goto ret; \ 99 const struct addrinfo *req, struct gaih_addrtuple **pat)
104 } while(0) 100{
101 int rval = 0, herrno, i;
102 char *prevcname = NULL;
103 struct hostent *h;
104
105 h = gethostbyname2(name, af);
106 herrno = h_errno;
107
108 if (!h) {
109 switch (herrno) {
110 case NETDB_INTERNAL:
111 return -EAI_SYSTEM;
112 case HOST_NOT_FOUND:
113 return 1;
114 case TRY_AGAIN:
115 return -EAI_AGAIN;
116 case NO_RECOVERY:
117 return -EAI_FAIL;
118 case NO_DATA:
119 return 1;
120 default:
121 return -EAI_FAIL;
122 }
123 }
124
125 for (i = 0; h->h_addr_list[i]; i++) {
126 while (*pat)
127 pat = &((*pat)->next);
128
129 if (!(*pat = malloc(sizeof(struct gaih_addrtuple))))
130 return -EAI_MEMORY;
131 memset(*pat, 0, sizeof(struct gaih_addrtuple));
132
133 switch ((*pat)->family = af) {
134 case AF_INET:
135 memcpy((*pat)->addr, h->h_addr_list[i],
136 sizeof(struct in_addr));
137 break;
138 case AF_INET6:
139 memcpy((*pat)->addr, h->h_addr_list[i],
140 sizeof(struct in6_addr));
141 break;
142 default:
143 return -EAI_FAIL;
144 }
145
146 if (req->ai_flags & AI_CANONNAME) {
147 if (prevcname && !strcmp(prevcname, h->h_name))
148 (*pat)->cname = prevcname;
149 else
150 prevcname = (*pat)->cname = strdup(h->h_name);
151 }
152 pat = &((*pat)->next);
153 }
154 return rval;
155}
105 156
106static int netdb_lookup_addr(const char *name, int af, const struct addrinfo *req, struct gaih_addrtuple **pat) 157static int
158gaih_local(const char *name, const struct gaih_service *service,
159 const struct addrinfo *req, struct addrinfo **pai)
107{ 160{
108 int rval, herrno, i; 161 struct utsname utsname;
109 char *prevcname = NULL; 162 struct addrinfo *ai;
110 struct hostent *h; 163 struct sockaddr_un *sun;
111 164 int siz;
112 h = gethostbyname2(name, af); 165
113 herrno = h_errno; 166 if (name || (req->ai_flags & AI_CANONNAME))
114 167 if (uname(&utsname) < 0)
115 if (!h) { 168 return (-EAI_SYSTEM);
116 switch(herrno) { 169
117 case NETDB_INTERNAL: 170 if (name && strcmp(name, "localhost") && strcmp(name, "local") &&
118 RETURN_ERROR(-EAI_SYSTEM); 171 strcmp(name, "unix") && strcmp(name, utsname.nodename))
119 case HOST_NOT_FOUND: 172 return (GAIH_OKIFUNSPEC | -EAI_NONAME);
120 RETURN_ERROR(1); 173
121 case TRY_AGAIN: 174 siz = sizeof(struct addrinfo) + sizeof(struct sockaddr_un);
122 RETURN_ERROR(-EAI_AGAIN); 175 if (req->ai_flags & AI_CANONNAME)
123 case NO_RECOVERY: 176 siz += strlen(utsname.nodename) + 1;
124 RETURN_ERROR(-EAI_FAIL); 177
125 case NO_DATA: 178 if (!(ai = malloc(siz)))
126 RETURN_ERROR(1); 179 return -EAI_MEMORY;
127 default: 180
128 RETURN_ERROR(-EAI_FAIL); 181 *pai = ai;
129 }; 182 ai->ai_next = NULL;
130 }; 183 ai->ai_flags = req->ai_flags;
131 184 ai->ai_family = AF_LOCAL;
132 for (i = 0; h->h_addr_list[i]; i++) { 185 ai->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
133 while(*pat) 186 ai->ai_protocol = req->ai_protocol;
134 pat = &((*pat)->next); 187 ai->ai_addrlen = sizeof(struct sockaddr_un);
135 188 ai->ai_addr = (void *)ai + sizeof(struct addrinfo);
136 if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) 189
137 RETURN_ERROR(-EAI_MEMORY); 190 sun = (struct sockaddr_un *)ai->ai_addr;
138 191 sun->sun_len = sizeof(struct sockaddr_un);
139 memset(*pat, 0, sizeof(struct gaih_addrtuple)); 192 sun->sun_family = AF_LOCAL;
140 193 memset(&sun->sun_path, 0, sizeof sun->sun_path);
141 switch((*pat)->family = af) { 194
142 case AF_INET: 195 if (service) {
143 memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in_addr)); 196 char *c;
144 break; 197
145 case AF_INET6: 198 c = strchr(service->name, '/');
146 memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in6_addr)); 199 if (c) {
147 break; 200 if (strlen(service->name) >= sizeof(sun->sun_path))
148 default: 201 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
149 RETURN_ERROR(-EAI_FAIL); 202 strlcpy(sun->sun_path, service->name, sizeof (sun->sun_path));
150 }; 203 } else {
151 204 if (strlen(P_tmpdir "/") + strlen(service->name) + 1 >=
152 if (req->ai_flags & AI_CANONNAME) { 205 sizeof(sun->sun_path))
153 if (prevcname && !strcmp(prevcname, h->h_name)) 206 return(GAIH_OKIFUNSPEC | -EAI_SERVICE);
154 (*pat)->cname = prevcname; 207 snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s",
155 else 208 P_tmpdir, service->name);
156 prevcname = (*pat)->cname = strdup(h->h_name); 209 }
157 }; 210 } else {
158 211 extern char *_mktemp __P((char *));
159 pat = &((*pat)->next); 212 char tmpn[MAXPATHLEN], *c;
160 } 213
161 214 snprintf(tmpn, sizeof tmpn, "%stmp.XXXXXXXXXXXXX", P_tmpdir);
162 rval = 0; 215 if (!(c = _mktemp(tmpn)))
216 return (GAIH_OKIFUNSPEC | -EAI_SYSTEM);
217 strlcpy(sun->sun_path, c, sizeof(sun->sun_path));
218 }
163 219
164ret: 220 ai->ai_canonname = NULL;
165 return rval; 221 if (req->ai_flags & AI_CANONNAME) {
166}; 222 ai->ai_canonname = (void *)sun + sizeof(struct sockaddr_un);
223 strlcpy(ai->ai_canonname, utsname.nodename,
224 strlen(utsname.nodename)+1);
225 }
226 return 0;
227}
167 228
168static int gaih_local(const char *name, const struct gaih_service *service, 229static int
169 const struct addrinfo *req, struct addrinfo **pai) 230gaih_inet_serv(char *servicename, struct gaih_typeproto *tp,
231 struct gaih_servtuple **st)
170{ 232{
171 int rval; 233 struct servent *s;
172 struct utsname utsname;
173
174 if (name || (req->ai_flags & AI_CANONNAME))
175 if (uname(&utsname) < 0)
176 RETURN_ERROR(-EAI_SYSTEM);
177 if (name) {
178 if (strcmp(name, "localhost") && strcmp(name, "local") && strcmp(name, "unix") && strcmp(name, utsname.nodename))
179 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_NONAME);
180 };
181
182 if (!(*pai = malloc(sizeof(struct addrinfo) + sizeof(struct sockaddr_un) + ((req->ai_flags & AI_CANONNAME) ? (strlen(utsname.nodename) + 1): 0))))
183 RETURN_ERROR(-EAI_MEMORY);
184
185 (*pai)->ai_next = NULL;
186 (*pai)->ai_flags = req->ai_flags;
187 (*pai)->ai_family = AF_LOCAL;
188 (*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
189 (*pai)->ai_protocol = req->ai_protocol;
190 (*pai)->ai_addrlen = sizeof(struct sockaddr_un);
191 (*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo);
192 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_len = sizeof(struct sockaddr_un);
193 ((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
194 memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
195 if (service) {
196 char *c;
197 if (c = strchr(service->name, '/')) {
198 if (strlen(service->name) >= sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path))
199 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE);
200 strcpy(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, service->name);
201 } else {
202 if (strlen(P_tmpdir "/") + 1 + strlen(service->name) >= sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path))
203 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE);
204 strcpy(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, P_tmpdir "/");
205 strcat(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, service->name);
206 };
207 } else {
208 char *c;
209 if (!(c = tmpnam(NULL)))
210 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SYSTEM);
211
212 strncpy((((struct sockaddr_un *)(*pai)->ai_addr)->sun_path), c, sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path) - 1);
213 c[sizeof(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path) - 1] = 0;
214 };
215 if (req->ai_flags & AI_CANONNAME) {
216 strncpy((*pai)->ai_canonname = (char *)(*pai) + sizeof(struct addrinfo) + sizeof(struct sockaddr_un), utsname.nodename, sizeof(utsname.nodename) - 1);
217 (*pai)->ai_canonname[sizeof(utsname.nodename) - 1] = 0;
218 } else
219 (*pai)->ai_canonname = NULL;
220
221 rval = 0;
222 234
223ret: 235 s = getservbyname(servicename, tp->name);
224 return rval; 236 if (!s)
225}; 237 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
226 238
227static struct gaih_typeproto gaih_inet_typeproto[] = { 239 if (!(*st = malloc(sizeof(struct gaih_servtuple))))
228 { 0, 0, NULL }, 240 return (-EAI_MEMORY);
229 { SOCK_STREAM, IPPROTO_TCP, "tcp" },
230 { SOCK_DGRAM, IPPROTO_UDP, "udp" },
231 { 0, 0, NULL }
232};
233 241
234static int gaih_inet_serv(char *servicename, struct gaih_typeproto *tp, struct gaih_servtuple **st) 242 (*st)->next = NULL;
243 (*st)->socktype = tp->socktype;
244 (*st)->protocol = tp->protocol;
245 (*st)->port = s->s_port;
246 return (0);
247}
248
249static int
250gaih_inet(const char *name, const struct gaih_service *service,
251 const struct addrinfo*req, struct addrinfo **pai)
235{ 252{
236 int rval; 253 struct gaih_typeproto *tp = gaih_inet_typeproto;
237 struct servent *s; 254 struct gaih_servtuple *st = &nullserv;
255 struct gaih_addrtuple *at = NULL;
256 char *prevcname = NULL;
257 struct gaih_servtuple *st2;
258 struct gaih_addrtuple *at2 = at;
259 struct addrinfo *ai = NULL;
260 int canonlen, addrlen, rval = 0;
261
262 if (req->ai_protocol || req->ai_socktype) {
263 for (tp++; tp->name &&
264 ((req->ai_socktype != tp->socktype) || !req->ai_socktype) &&
265 ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++);
266 if (!tp->name) {
267 rval = GAIH_OKIFUNSPEC | -EAI_SERVICE;
268 if (req->ai_socktype)
269 rval = GAIH_OKIFUNSPEC | -EAI_SOCKTYPE;
270 goto ret;
271 }
272 }
273 if (service && (service->num < 0)) {
274 if (tp->name) {
275 rval = gaih_inet_serv(service->name, tp, &st);
276 if (rval)
277 goto ret;
278 } else {
279 struct gaih_servtuple **pst = &st;
280 for (tp++; tp->name; tp++) {
281 rval = gaih_inet_serv(service->name, tp, pst);
282 if (rval) {
283 if (rval & GAIH_OKIFUNSPEC)
284 continue;
285 goto ret;
286 }
287 pst = &((*pst)->next);
288 }
289 if (st == &nullserv) {
290 rval = GAIH_OKIFUNSPEC | -EAI_SERVICE;
291 goto ret;
292 }
293 }
294 } else {
295 if (!(st = malloc(sizeof(struct gaih_servtuple)))) {
296 rval = -EAI_MEMORY;
297 goto ret;
298 }
299
300 st->next = NULL;
301 st->socktype = tp->socktype;
302 st->protocol = tp->protocol;
303 if (service)
304 st->port = htons(service->num);
305 else
306 st->port = 0;
307 }
238 308
239 if (!(s = getservbyname(servicename, tp->name))) 309 if (!name) {
240 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); 310 if (!(at = malloc(sizeof(struct gaih_addrtuple)))) {
311 rval = -EAI_MEMORY;
312 goto ret;
313 }
241 314
242 if (!(*st = malloc(sizeof(struct gaih_servtuple)))) 315 memset(at, 0, sizeof(struct gaih_addrtuple));
243 RETURN_ERROR(-EAI_MEMORY);
244 316
245 (*st)->next = NULL; 317 if (req->ai_family)
246 (*st)->socktype = tp->socktype; 318 at->family = req->ai_family;
247 (*st)->protocol = tp->protocol; 319 else {
248 (*st)->port = s->s_port; 320 if (!(at->next = malloc(sizeof(struct gaih_addrtuple)))) {
321 rval = -EAI_MEMORY;
322 goto ret;
323 }
249 324
250 rval = 0; 325 at->family = AF_INET6;
251 326
252ret: 327 memset(at->next, 0, sizeof(struct gaih_addrtuple));
253 return rval; 328 at->next->family = AF_INET;
254} 329 }
255 330
256static int gaih_inet(const char *name, const struct gaih_service *service, 331 goto build;
257 const struct addrinfo *req, struct addrinfo **pai) 332 }
258{ 333
259 int rval; 334 if (!req->ai_family || (req->ai_family == AF_INET)) {
260 struct hostent *h = NULL; 335 struct in_addr in_addr;
261 struct gaih_typeproto *tp = gaih_inet_typeproto; 336 if (inet_pton(AF_INET, name, &in_addr) > 0) {
262 struct gaih_servtuple *st = &nullserv; 337 if (!(at = malloc(sizeof(struct gaih_addrtuple)))) {
263 struct gaih_addrtuple *at = NULL; 338 rval = -EAI_MEMORY;
264 int i; 339 goto ret;
265 340 }
266 if (req->ai_protocol || req->ai_socktype) { 341
267 for (tp++; tp->name && 342 memset(at, 0, sizeof(struct gaih_addrtuple));
268 ((req->ai_socktype != tp->socktype) || !req->ai_socktype) && 343
269 ((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++); 344 at->family = AF_INET;
270 if (!tp->name) 345 memcpy(at->addr, &in_addr, sizeof(struct in_addr));
271 if (req->ai_socktype) 346 goto build;
272 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SOCKTYPE); 347 }
273 else 348 }
274 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); 349
275 } 350 if (!req->ai_family || (req->ai_family == AF_INET6)) {
276 351 struct in6_addr in6_addr;
277 if (service && (service->num < 0)) { 352 if (inet_pton(AF_INET6, name, &in6_addr) > 0) {
278 if (tp->name) { 353 if (!(at = malloc(sizeof(struct gaih_addrtuple)))) {
279 if (rval = gaih_inet_serv(service->name, tp, &st)) 354 rval = -EAI_MEMORY;
280 goto ret; 355 goto ret;
281 } else { 356 }
282 struct gaih_servtuple **pst = &st; 357
283 for (tp++; tp->name; tp++) { 358 memset(at, 0, sizeof(struct gaih_addrtuple));
284 if (rval = gaih_inet_serv(service->name, tp, pst)) { 359
285 if (rval & GAIH_OKIFUNSPEC) 360 at->family = AF_INET6;
286 continue; 361 memcpy(at->addr, &in6_addr, sizeof(struct in6_addr));
287 goto ret; 362 goto build;
288 }; 363 }
289 pst = &((*pst)->next); 364 }
290 }; 365
291 if (st == &nullserv) 366 if (!(req->ai_flags & AI_NUMERICHOST)) {
292 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_SERVICE); 367 if (!req->ai_family || (req->ai_family == AF_INET6))
293 }; 368 if ((rval = netdb_lookup_addr(name, AF_INET6, req, &at)) < 0)
294 } else { 369 goto ret;
295 if (!(st = malloc(sizeof(struct gaih_servtuple)))) 370 if (!req->ai_family || (req->ai_family == AF_INET))
296 RETURN_ERROR(-EAI_MEMORY); 371 if ((rval = netdb_lookup_addr(name, AF_INET, req, &at)) < 0)
297 372 goto ret;
298 st->next = NULL; 373
299 st->socktype = tp->socktype; 374 if (!rval)
300 st->protocol = tp->protocol; 375 goto build;
301 if (service) 376 }
302 st->port = htons(service->num); 377
303 else 378 if (!at) {
304 st->port = 0; 379 rval = GAIH_OKIFUNSPEC | -EAI_NONAME;
305 }; 380 goto ret;
306 381 }
307 if (!name) {
308 if (!(at = malloc(sizeof(struct gaih_addrtuple))))
309 RETURN_ERROR(-EAI_MEMORY);
310
311 memset(at, 0, sizeof(struct gaih_addrtuple));
312
313 if (req->ai_family)
314 at->family = req->ai_family;
315 else {
316 if (!(at->next = malloc(sizeof(struct gaih_addrtuple))))
317 RETURN_ERROR(-EAI_MEMORY);
318
319 at->family = AF_INET6;
320
321 memset(at->next, 0, sizeof(struct gaih_addrtuple));
322 at->next->family = AF_INET;
323 };
324
325 goto build;
326 };
327
328 if (!req->ai_family || (req->ai_family == AF_INET)) {
329 struct in_addr in_addr;
330 if (inet_pton(AF_INET, name, &in_addr) > 0) {
331 if (!(at = malloc(sizeof(struct gaih_addrtuple))))
332 RETURN_ERROR(-EAI_MEMORY);
333
334 memset(at, 0, sizeof(struct gaih_addrtuple));
335
336 at->family = AF_INET;
337 memcpy(at->addr, &in_addr, sizeof(struct in_addr));
338 goto build;
339 };
340 };
341
342 if (!req->ai_family || (req->ai_family == AF_INET6)) {
343 struct in6_addr in6_addr;
344 if (inet_pton(AF_INET6, name, &in6_addr) > 0) {
345 if (!(at = malloc(sizeof(struct gaih_addrtuple))))
346 RETURN_ERROR(-EAI_MEMORY);
347
348 memset(at, 0, sizeof(struct gaih_addrtuple));
349
350 at->family = AF_INET6;
351 memcpy(at->addr, &in6_addr, sizeof(struct in6_addr));
352 goto build;
353 };
354 };
355
356 if (!(req->ai_flags & AI_NUMERICHOST)) {
357 if (!req->ai_family || (req->ai_family == AF_INET6))
358 if ((rval = netdb_lookup_addr(name, AF_INET6, req, &at)) < 0)
359 goto ret;
360 if (!req->ai_family || (req->ai_family == AF_INET))
361 if ((rval = netdb_lookup_addr(name, AF_INET, req, &at)) < 0)
362 goto ret;
363
364 if (!rval)
365 goto build;
366 };
367
368 if (!at)
369 RETURN_ERROR(GAIH_OKIFUNSPEC | -EAI_NONAME);
370 382
371build: 383build:
372 { 384 while (at2) {
373 char *prevcname = NULL; 385 if (req->ai_flags & AI_CANONNAME) {
374 struct gaih_servtuple *st2; 386 if (at2->cname)
375 struct gaih_addrtuple *at2 = at; 387 canonlen = strlen(at2->cname) + 1;
376 int j; 388 else
377 389 if (name)
378 while(at2) { 390 canonlen = strlen(name) + 1;
379 if (req->ai_flags & AI_CANONNAME) { 391 else
380 if (at2->cname) 392 canonlen = 2;
381 j = strlen(at2->cname) + 1; 393 } else
382 else 394 canonlen = 0;
383 if (name) 395
384 j = strlen(name) + 1; 396 if (at2->family == AF_INET6)
385 else 397 addrlen = sizeof(struct sockaddr_in6);
386 j = 2; 398 else
387 } else 399 addrlen = sizeof(struct sockaddr_in);
388 j = 0; 400
389 401 st2 = st;
390 if (at2->family == AF_INET6) 402 while (st2) {
391 i = sizeof(struct sockaddr_in6); 403 if (!(ai = malloc(sizeof(struct addrinfo) +
392 else 404 addrlen + canonlen))) {
393 i = sizeof(struct sockaddr_in); 405 rval = -EAI_MEMORY;
394 406 goto ret;
395 st2 = st; 407 }
396 while(st2) { 408
397 if (!(*pai = malloc(sizeof(struct addrinfo) + i + j))) 409 *pai = ai;
398 RETURN_ERROR(-EAI_MEMORY); 410 memset(ai, 0, sizeof(struct addrinfo) + addrlen + canonlen);
399 411
400 memset(*pai, 0, sizeof(struct addrinfo) + i + j); 412 ai->ai_flags = req->ai_flags;
401 413 ai->ai_family = at2->family;
402 (*pai)->ai_flags = req->ai_flags; 414 ai->ai_socktype = st2->socktype;
403 (*pai)->ai_family = at2->family; 415 ai->ai_protocol = st2->protocol;
404 (*pai)->ai_socktype = st2->socktype; 416 ai->ai_addrlen = addrlen;
405 (*pai)->ai_protocol = st2->protocol; 417 ai->ai_addr = (void *)ai + sizeof(struct addrinfo);
406 (*pai)->ai_addrlen = i; 418 ai->ai_addr->sa_len = addrlen;
407 (*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo); 419 ai->ai_addr->sa_family = at2->family;
408 ((struct sockaddr_in *)(*pai)->ai_addr)->sin_len = i; 420
409 ((struct sockaddr_in *)(*pai)->ai_addr)->sin_family = at2->family; 421 switch (at2->family) {
410 ((struct sockaddr_in *)(*pai)->ai_addr)->sin_port = st2->port; 422 case AF_INET6:
411 423 {
412 if (at2->family == AF_INET6) 424 struct sockaddr_in6 *sin6 = (void *)ai->ai_addr;
413 memcpy(&((struct sockaddr_in6 *)(*pai)->ai_addr)->sin6_addr, at2->addr, sizeof(struct in6_addr)); 425
414 else 426 memcpy(&sin6->sin6_addr, at2->addr,
415 memcpy(&((struct sockaddr_in *)(*pai)->ai_addr)->sin_addr, at2->addr, sizeof(struct in_addr)); 427 sizeof(sin6->sin6_addr));
416 428 sin6->sin6_port = st2->port;
417 if (j) { 429 break;
418 (*pai)->ai_canonname = (void *)(*pai) + sizeof(struct addrinfo) + i; 430 }
419 if (at2->cname) { 431 default:
420 strcpy((*pai)->ai_canonname, at2->cname); 432 {
421 if (prevcname != at2->cname) { 433 struct sockaddr_in *sin = (void *)ai->ai_addr;
422 if (prevcname) 434
423 free(prevcname); 435 memcpy(&sin->sin_addr, at2->addr,
424 prevcname = at2->cname; 436 sizeof(sin->sin_addr));
425 }; 437 sin->sin_port = st2->port;
426 } else 438 break;
427 strcpy((*pai)->ai_canonname, name ? name : "*"); 439 }
428 }; 440 }
429 441
430 pai = &((*pai)->ai_next); 442 if (canonlen) {
431 443 ai->ai_canonname = (void *) ai->ai_addr + addrlen;
432 st2 = st2->next; 444
433 }; 445 if (at2->cname) {
434 at2 = at2->next; 446 strcpy(ai->ai_canonname, at2->cname);
435 }; 447 if (prevcname != at2->cname) {
436 }; 448 if (prevcname)
437 449 free(prevcname);
438 rval = 0; 450 prevcname = at2->cname;
451 }
452 } else
453 strcpy(ai->ai_canonname, name ? name : "*");
454 }
455 pai = &(ai->ai_next);
456 st2 = st2->next;
457 }
458 at2 = at2->next;
459 }
460 rval = 0;
439 461
440ret: 462ret:
441 if (st != &nullserv) { 463 if (st != &nullserv) {
442 struct gaih_servtuple *st2 = st; 464 struct gaih_servtuple *st2 = st;
443 while(st) { 465 while (st) {
444 st2 = st->next; 466 st2 = st->next;
445 free(st); 467 free(st);
446 st = st2; 468 st = st2;
447 } 469 }
448 } 470 }
449 if (at) { 471 if (at) {
450 struct gaih_addrtuple *at2 = at; 472 struct gaih_addrtuple *at2 = at;
451 while(at) { 473 while (at) {
452 at2 = at->next; 474 at2 = at->next;
453 free(at); 475 free(at);
454 at = at2; 476 at = at2;
455 } 477 }
456 } 478 }
457 479 return rval;
458 return rval;
459} 480}
460 481
461struct gaih { 482static struct gaih {
462 int family; 483 int family;
463 char *name; 484 char *name;
464 int (*gaih)(const char *name, const struct gaih_service *service, 485 int (*gaih) __P((const char *name,
465 const struct addrinfo *req, struct addrinfo **pai); 486 const struct gaih_service *service,
466}; 487 const struct addrinfo *req, struct addrinfo **pai));
467 488} gaih[] = {
468static struct gaih gaih[] = { 489 { PF_INET6, "inet6", gaih_inet },
469 { PF_INET6, "inet6", gaih_inet }, 490 { PF_INET, "inet", gaih_inet },
470 { PF_INET, "inet", gaih_inet }, 491 { PF_LOCAL, "local", gaih_local },
471 { PF_LOCAL, "local", gaih_local }, 492 { -1, NULL, NULL}
472 { -1, NULL, NULL }
473}; 493};
474 494
475int getaddrinfo(const char *name, const char *service, 495int
476 const struct addrinfo *req, struct addrinfo **pai) 496getaddrinfo(const char *name, const char *service,
497 const struct addrinfo *req, struct addrinfo **pai)
477{ 498{
478 int rval = EAI_SYSTEM; /* XXX */ 499 int rval = EAI_SYSTEM; /* XXX */
479 int i, j = 0; 500 int j = 0;
480 struct addrinfo *p = NULL, **end; 501 struct addrinfo *p = NULL, **end;
481 struct gaih *g = gaih, *pg = NULL; 502 struct gaih *g = gaih, *pg = NULL;
482 struct gaih_service gaih_service, *pservice; 503 struct gaih_service gaih_service, *pservice;
483
484 if (name && (name[0] == '*') && !name[1])
485 name = NULL;
486
487 if (service && (service[0] == '*') && !service[1])
488 service = NULL;
489
490 if (!req)
491 req = &nullreq;
492
493 if (req->ai_flags & ~(AI_CANONNAME | AI_PASSIVE | AI_NUMERICHOST | AI_EXT))
494 RETURN_ERROR(EAI_BADFLAGS);
495
496 if (service && *service) {
497 char *c;
498 gaih_service.num = strtoul(gaih_service.name = (void *)service, &c, 10);
499 if (*c) {
500 gaih_service.num = -1;
501 }
502
503 pservice = &gaih_service;
504 } else
505 pservice = NULL;
506
507 if (pai)
508 end = &p;
509 else
510 end = NULL;
511
512 while(g->gaih) {
513 if ((req->ai_family == g->family) || !req->ai_family) {
514 j++;
515 if (!((pg && (pg->gaih == g->gaih)))) {
516 pg = g;
517 if (rval = g->gaih(name, pservice, req, end)) {
518 if (!req->ai_family && (rval & GAIH_OKIFUNSPEC))
519 continue;
520
521 if (p)
522 freeaddrinfo(p);
523
524 rval = -(rval & GAIH_EAI);
525 goto ret;
526 }
527 if (end)
528 while(*end) end = &((*end)->ai_next);
529 }
530 }
531 g++;
532 }
533 504
534 if (!j) 505 if (name && (name[0] == '*') && !name[1])
535 RETURN_ERROR(EAI_FAMILY); 506 name = NULL;
536 507
537 if (p) { 508 if (service && service[0] == '*' && service[1] == '\0')
538 *pai = p; 509 service = NULL;
539 rval = 0;
540 goto ret;
541 }
542 510
543 if (!pai && !rval) { 511 if (!req)
544 rval = 0; 512 req = &nullreq;
545 goto ret;
546 };
547 513
548 RETURN_ERROR(EAI_NONAME); 514 if (req->ai_flags & ~(AI_CANONNAME | AI_PASSIVE | AI_NUMERICHOST | AI_EXT))
515 return (EAI_BADFLAGS);
549 516
550ret: 517 if (service && *service) {
551 return rval; 518 char *c;
552}
553 519
520 gaih_service.num = strtoul(service, &c, 10);
521 if (*c)
522 gaih_service.num = -1;
523 gaih_service.name = (void *)service;
524 pservice = &gaih_service;
525 } else
526 pservice = NULL;
527
528 if (pai)
529 end = &p;
530 else
531 end = NULL;
532
533 while (g->gaih) {
534 if ((req->ai_family == g->family) || !req->ai_family) {
535 j++;
536 if (!((pg && (pg->gaih == g->gaih)))) {
537 pg = g;
538 rval = g->gaih(name, pservice, req, end);
539 if (rval) {
540 if (!req->ai_family && (rval & GAIH_OKIFUNSPEC))
541 continue;
542
543 if (p)
544 freeaddrinfo(p);
545
546 return -(rval & GAIH_EAI);
547 }
548 if (end)
549 while (*end)
550 end = &((*end)->ai_next);
551 }
552 }
553 g++;
554 }
555
556 if (!j)
557 return (EAI_FAMILY);
558
559 if (p) {
560 *pai = p;
561 return (0);
562 }
563 if (!pai && !rval)
564 return (0);
565 return EAI_NONAME;
566}
diff --git a/src/lib/libc/net/getnameinfo.c b/src/lib/libc/net/getnameinfo.c
index 1ae197c15a..62c4b9d928 100644
--- a/src/lib/libc/net/getnameinfo.c
+++ b/src/lib/libc/net/getnameinfo.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * %%% copyright-cmetz-96-bsd 2 * %%% copyright-cmetz-96-bsd
3 * Copyright (c) 1996-1999, Craig Metz, All rights reserved. 3 * Copyright (c) 1996-1999, Craig Metz, All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
@@ -17,7 +17,7 @@
17 * 4. Neither the name of the author nor the names of contributors 17 * 4. Neither the name of the author nor the names of contributors
18 * may be used to endorse or promote products derived from this software 18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission. 19 * without specific prior written permission.
20 * 20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -36,197 +36,229 @@
36 36
37#include <sys/types.h> 37#include <sys/types.h>
38#include <sys/socket.h> 38#include <sys/socket.h>
39
40#include <netinet/in.h> 39#include <netinet/in.h>
41#include <sys/un.h> 40#include <sys/un.h>
42#include <sys/utsname.h> 41#include <sys/utsname.h>
43#include <netdb.h> 42#include <netdb.h>
43#include <arpa/inet.h>
44#include <errno.h> 44#include <errno.h>
45#include <string.h> 45#include <string.h>
46#include <resolv.h> 46#include <resolv.h>
47 47
48#ifndef AF_LOCAL 48#ifndef min
49#define AF_LOCAL AF_UNIX
50#endif /* AF_LOCAL */
51
52#ifndef min
53#define min(x,y) (((x) > (y)) ? (y) : (x)) 49#define min(x,y) (((x) > (y)) ? (y) : (x))
54#endif /* min */ 50#endif /* min */
55 51
56#define RETURN_ERROR(x) do { \ 52static int
57 rval = (x); \ 53netdb_lookup_name(int family, void *addr, int addrlen, char *name,
58 goto ret; \ 54 int namelen, int flags)
59 } while(0)
60
61static int netdb_lookup_name(int family, void *addr, int addrlen, char *name,
62 int namelen, int flags)
63{ 55{
64 struct hostent *hostent; 56 struct hostent *hostent;
65 char *c, *c2; 57 char *c, *c2;
66 int rval, i; 58 int i;
67
68 if (!(hostent = gethostbyaddr(addr, addrlen, family))) {
69 switch(h_errno) {
70 case NETDB_INTERNAL:
71 RETURN_ERROR(EAI_SYSTEM);
72 case HOST_NOT_FOUND:
73 RETURN_ERROR(1);
74 case TRY_AGAIN:
75 RETURN_ERROR(EAI_AGAIN);
76 case NO_RECOVERY:
77 RETURN_ERROR(EAI_FAIL);
78 case NO_DATA:
79 RETURN_ERROR(1);
80 default:
81 RETURN_ERROR(EAI_FAIL);
82 };
83 };
84
85 endhostent();
86
87 c = hostent->h_name;
88 if ((flags & NI_NOFQDN) && (_res.options & RES_INIT) && _res.defdname[0] &&
89 (c2 = strstr(c + 1, _res.defdname)) && (*(--c2) == '.')) {
90 *c2 = 0;
91 i = min(c2 - c, namelen) - 1;
92 strncpy(name, c, i);
93 } else
94 strncpy(name, c, namelen - 1);
95
96 rval = 0;
97 59
98ret: 60 if (!(hostent = gethostbyaddr(addr, addrlen, family))) {
99 return rval; 61 switch (h_errno) {
62 case NETDB_INTERNAL:
63 return(EAI_SYSTEM);
64 case HOST_NOT_FOUND:
65 return(1);
66 case TRY_AGAIN:
67 return(EAI_AGAIN);
68 case NO_RECOVERY:
69 return(EAI_FAIL);
70 case NO_DATA:
71 return(1);
72 default:
73 return(EAI_FAIL);
74 }
75 }
76
77 endhostent();
78
79 c = hostent->h_name;
80 if ((flags & NI_NOFQDN) && (_res.options & RES_INIT) && _res.defdname[0] &&
81 (c2 = strstr(c + 1, _res.defdname)) && (*(--c2) == '.')) {
82 *c2 = 0;
83 i = min(c2 - c, namelen);
84 strlcpy(name, c, i);
85 } else
86 strlcpy(name, c, namelen);
87 return 0;
100} 88}
101 89
102int getnameinfo(const struct sockaddr *sa, size_t addrlen, char *host, size_t hostlen, char *serv, size_t servlen, int flags) 90int
91getnameinfo(const struct sockaddr *sa, size_t addrlen, char *host,
92 size_t hostlen, char *serv, size_t servlen, int flags)
103{ 93{
104 int rval; 94 int rval;
105 int serrno = errno; 95 int saved_errno;
106
107 if (!sa || (addrlen != SA_LEN(sa)))
108 RETURN_ERROR(EAI_FAIL);
109
110 if (host && (hostlen > 0))
111 switch(sa->sa_family) {
112 case AF_INET6:
113 if (IN6_IS_ADDR_UNSPECIFIED(&((struct sockaddr_in6 *)sa)->sin6_addr)) {
114 if (flags & NI_NUMERICHOST)
115 goto inet6_noname;
116 else
117 strncpy(host, "*", hostlen - 1);
118 break;
119 };
120
121 if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)sa)->sin6_addr)) {
122 struct sockaddr_in sin;
123 memset(&sin, 0, sizeof(struct sockaddr_in));
124 sin.sin_len = sizeof(struct sockaddr_in);
125 sin.sin_family = AF_INET;
126 sin.sin_port = ((struct sockaddr_in6 *)sa)->sin6_port;
127 sin.sin_addr.s_addr = ((u_int32_t *)&((struct sockaddr_in6 *)sa)->sin6_addr)[3];
128 if (!(rval = getnameinfo((struct sockaddr *)&sin, sizeof(struct sockaddr_in), host, hostlen, serv, servlen, flags | NI_NAMEREQD)))
129 goto ret;
130 if (rval != EAI_NONAME)
131 goto ret;
132 goto inet6_noname;
133 };
134
135 if (flags & NI_NUMERICHOST)
136 goto inet6_noname;
137
138 if ((rval = netdb_lookup_name(AF_INET6,
139 &((struct sockaddr_in6 *)sa)->sin6_addr, sizeof(struct in6_addr),
140 host, hostlen, flags)) < 0)
141 goto ret;
142
143 if (!rval)
144 break;
145
146inet6_noname:
147 if (flags & NI_NAMEREQD)
148 RETURN_ERROR(EAI_NONAME);
149
150 if (!inet_ntop(AF_INET6, &((struct sockaddr_in6 *)sa)->sin6_addr, host, hostlen))
151 RETURN_ERROR(EAI_NONAME);
152
153 break;
154 case AF_INET:
155 if (flags & NI_NUMERICHOST)
156 goto inet_noname;
157
158 if (!((struct sockaddr_in *)sa)->sin_addr.s_addr) {
159 strncpy(host, "*", hostlen - 1);
160 break;
161 };
162
163 if ((rval = netdb_lookup_name(AF_INET,
164 &((struct sockaddr_in *)sa)->sin_addr, sizeof(struct in_addr),
165 host, hostlen, flags)) < 0)
166 goto ret;
167
168 if (!rval)
169 break;
170inet_noname:
171 if (flags & NI_NAMEREQD)
172 RETURN_ERROR(EAI_NONAME);
173
174 if (!inet_ntop(AF_INET, &((struct sockaddr_in *)sa)->sin_addr, host, hostlen))
175 RETURN_ERROR(EAI_NONAME);
176
177 break;
178 case AF_LOCAL:
179 if (!(flags & NI_NUMERICHOST)) {
180 struct utsname utsname;
181
182 if (!uname(&utsname)) {
183 strncpy(host, utsname.nodename, hostlen - 1);
184 break;
185 };
186 };
187
188 if (flags & NI_NAMEREQD)
189 RETURN_ERROR(EAI_NONAME);
190
191 strncpy(host, "localhost", hostlen - 1);
192 break;
193 default:
194 RETURN_ERROR(EAI_FAMILY);
195 };
196
197 if (serv && (servlen > 0))
198 switch(sa->sa_family) {
199 case AF_INET:
200 case AF_INET6:
201 if (!(flags & NI_NUMERICSERV)) {
202 struct servent *s;
203 if (s = getservbyport(((struct sockaddr_in *)sa)->sin_port, (flags & NI_DGRAM) ? "udp" : "tcp")) {
204 strncpy(serv, s->s_name, servlen - 1);
205 break;
206 };
207 if (!((struct sockaddr_in *)sa)->sin_port) {
208 strncpy(serv, "*", servlen - 1);
209 break;
210 };
211 };
212 snprintf(serv, servlen - 1, "%d", ntohs(((struct sockaddr_in *)sa)->sin_port));
213 break;
214 case AF_LOCAL:
215 strncpy(serv, ((struct sockaddr_un *)sa)->sun_path, servlen - 1);
216 break;
217 };
218
219 if (host && (hostlen > 0))
220 host[hostlen-1] = 0;
221 if (serv && (servlen > 0))
222 serv[servlen-1] = 0;
223 rval = 0;
224 96
225ret: 97 if (sa == NULL || addrlen != sa->sa_len)
226 if (rval == 1) 98 return EAI_FAIL;
227 rval = EAI_FAIL; 99 saved_errno = errno;
100
101 if (host && hostlen > 0) {
102 switch (sa->sa_family) {
103 case AF_INET6:
104 {
105 struct sockaddr_in6 *sin6 = (void *)sa;
106
107 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
108 if (flags & NI_NUMERICHOST)
109 goto inet6_noname;
110 strlcpy(host, "*", hostlen);
111 break;
112 }
113
114 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
115 struct sockaddr_in sin;
116
117 memset(&sin, 0, sizeof(struct sockaddr_in));
118 sin.sin_len = sizeof(struct sockaddr_in);
119 sin.sin_family = AF_INET;
120 sin.sin_port = sin6->sin6_port;
121 sin.sin_addr.s_addr =
122 ((u_int32_t *)&sin6->sin6_addr)[3];
123 if (!(rval = getnameinfo((struct sockaddr *)&sin,
124 sizeof(struct sockaddr_in), host, hostlen,
125 serv, servlen, flags | NI_NAMEREQD)))
126 goto ret;
127 if (rval != EAI_NONAME)
128 goto ret;
129 goto inet6_noname;
130 }
131
132 if (flags & NI_NUMERICHOST)
133 goto inet6_noname;
134 if ((rval = netdb_lookup_name(AF_INET6,
135 &sin6->sin6_addr, sizeof(struct in6_addr),
136 host, hostlen, flags)) < 0)
137 goto ret;
228 138
229 errno = serrno; 139 if (!rval)
140 break;
141 inet6_noname:
142 if (flags & NI_NAMEREQD) {
143 rval = EAI_NONAME;
144 goto ret;
145 }
146 if (!inet_ntop(AF_INET6, &sin6->sin6_addr, host, hostlen)) {
147 rval = EAI_NONAME;
148 goto ret;
149 }
150 break;
151 }
152 case AF_INET:
153 {
154 struct sockaddr_in *sin = (void *)sa;
230 155
231 return rval; 156 if (flags & NI_NUMERICHOST)
232}; 157 goto inet_noname;
158
159 if (sin->sin_addr.s_addr == 0) {
160 strlcpy(host, "*", hostlen);
161 break;
162 }
163
164 if ((rval = netdb_lookup_name(AF_INET,
165 &sin->sin_addr, sizeof(struct in_addr),
166 host, hostlen, flags)) < 0)
167 goto ret;
168
169 if (!rval)
170 break;
171 inet_noname:
172 if (flags & NI_NAMEREQD) {
173 rval = EAI_NONAME;
174 goto ret;
175 }
176 if (!inet_ntop(AF_INET, &sin->sin_addr, host, hostlen)) {
177 rval = EAI_NONAME;
178 goto ret;
179 }
180 break;
181 }
182 case AF_LOCAL:
183 if (!(flags & NI_NUMERICHOST)) {
184 struct utsname utsname;
185
186 if (!uname(&utsname)) {
187 strlcpy(host, utsname.nodename, hostlen);
188 break;
189 }
190 }
191
192 if (flags & NI_NAMEREQD) {
193 rval = EAI_NONAME;
194 goto ret;
195 }
196
197 strlcpy(host, "localhost", hostlen);
198 break;
199 default:
200 rval = EAI_FAMILY;
201 goto ret;
202 }
203 }
204
205 if (serv && servlen > 0) {
206 switch (sa->sa_family) {
207 case AF_INET:
208 {
209 struct sockaddr_in *sin = (void *)sa;
210 struct servent *s;
211
212 if ((flags & NI_NUMERICSERV) == 0) {
213 s = getservbyport(sin->sin_port,
214 (flags & NI_DGRAM) ? "udp" : "tcp");
215 if (s) {
216 strlcpy(serv, s->s_name, servlen);
217 break;
218 }
219 if (sin->sin_port == 0) {
220 strlcpy(serv, "*", servlen);
221 break;
222 }
223 }
224 snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
225 break;
226 }
227 case AF_INET6:
228 {
229 struct sockaddr_in6 *sin6 = (void *)sa;
230 struct servent *s;
231
232 if ((flags & NI_NUMERICSERV) == 0) {
233
234 s = getservbyport(sin6->sin6_port,
235 (flags & NI_DGRAM) ? "udp" : "tcp");
236 if (s) {
237 strlcpy(serv, s->s_name, servlen);
238 break;
239 }
240 if (sin6->sin6_port == 0) {
241 strlcpy(serv, "*", servlen);
242 break;
243 }
244 }
245 snprintf(serv, servlen, "%d", ntohs(sin6->sin6_port));
246 break;
247 }
248 case AF_LOCAL:
249 {
250 struct sockaddr_un *sun = (void *)sa;
251
252 strlcpy(serv, sun->sun_path, servlen);
253 break;
254 }
255 }
256 }
257 rval = 0;
258
259ret:
260 if (rval == 1)
261 rval = EAI_FAIL;
262 errno = saved_errno;
263 return (rval);
264}