summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoritojun <>1999-12-30 08:54:20 +0000
committeritojun <>1999-12-30 08:54:20 +0000
commitd9056b0e3240e176c6cfdfc13ac1cf384b0a04fd (patch)
tree356686aebb42f6ae34e6f80d29a8d44b44ff2879
parentc90229eaa6df37dd29c45c1aa632cb37ca8cfa06 (diff)
downloadopenbsd-d9056b0e3240e176c6cfdfc13ac1cf384b0a04fd.tar.gz
openbsd-d9056b0e3240e176c6cfdfc13ac1cf384b0a04fd.tar.bz2
openbsd-d9056b0e3240e176c6cfdfc13ac1cf384b0a04fd.zip
replace NRL get{addr,name}info with KAME get{addr,name}info.
removed functionality: new code will not return AF_LOCAL addrinfo struct. added funtionality: SOCK_RAW is permitted as ai_socktype (no servname allowed). draft-ietf-ipngwg-scopedaddr-format-00.txt
-rw-r--r--src/lib/libc/net/gai_strerror.c6
-rw-r--r--src/lib/libc/net/getaddrinfo.c1434
-rw-r--r--src/lib/libc/net/getnameinfo.c446
3 files changed, 1214 insertions, 672 deletions
diff --git a/src/lib/libc/net/gai_strerror.c b/src/lib/libc/net/gai_strerror.c
index c701c8f422..708fb23d18 100644
--- a/src/lib/libc/net/gai_strerror.c
+++ b/src/lib/libc/net/gai_strerror.c
@@ -1,3 +1,5 @@
1/* $OpenBSD: gai_strerror.c,v 1.4 1999/12/30 08:54:20 itojun Exp $ */
2
1/* 3/*
2 * %%% copyright-cmetz-97-bsd 4 * %%% copyright-cmetz-97-bsd
3 * Copyright (c) 1997-1999, Craig Metz, All rights reserved. 5 * Copyright (c) 1997-1999, Craig Metz, All rights reserved.
@@ -65,6 +67,10 @@ gai_strerror(int errnum)
65 return "memory allocation failure"; 67 return "memory allocation failure";
66 case EAI_SYSTEM: 68 case EAI_SYSTEM:
67 return "system error"; 69 return "system error";
70 case EAI_BADHINTS:
71 return "invalid value for hints";
72 case EAI_PROTOCOL:
73 return "resolved protocol is unknown";
68 default: 74 default:
69 return "unknown/invalid error"; 75 return "unknown/invalid error";
70 } 76 }
diff --git a/src/lib/libc/net/getaddrinfo.c b/src/lib/libc/net/getaddrinfo.c
index 5f3fa20c3a..9c89de2863 100644
--- a/src/lib/libc/net/getaddrinfo.c
+++ b/src/lib/libc/net/getaddrinfo.c
@@ -1,7 +1,9 @@
1/* $OpenBSD: getaddrinfo.c,v 1.5 1999/12/30 08:54:20 itojun Exp $ */
2
1/* 3/*
2 * %%% copyright-cmetz-96-bsd 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * Copyright (c) 1996-1999, Craig Metz, All rights reserved. 5 * All rights reserved.
4 * 6 *
5 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
7 * are met: 9 * are met:
@@ -10,18 +12,14 @@
10 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software 15 * 3. Neither the name of the project nor the names of its contributors
14 * must display the following acknowledgement:
15 * This product includes software developed by Craig Metz and
16 * by other 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 16 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission. 17 * without specific prior written permission.
20 * 18 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -31,537 +29,1055 @@
31 * SUCH DAMAGE. 29 * SUCH DAMAGE.
32 */ 30 */
33 31
34/* getaddrinfo() v1.38 */
35
36/* 32/*
37 I'd like to thank Matti Aarnio for finding some bugs in this code and 33 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
38 sending me patches, as well as everyone else who has contributed to this 34 *
39 code (by reporting bugs, suggesting improvements, and commented on its 35 * Issues to be discussed:
40 behavior and proposed changes). 36 * - Thread safe-ness must be checked.
41*/ 37 * - Return values. There are nonstandard return values defined and used
38 * in the source code. This is because RFC2553 is silent about which error
39 * code must be returned for which situation.
40 * Note:
41 * - We use getipnodebyname() just for thread-safeness. There's no intent
42 * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
43 * getipnodebyname().
44 * - The code filters out AFs that are not supported by the kernel,
45 * when resolving FQDNs and globbing NULL hostname. Is it the right
46 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
47 * in ai_flags?
48 */
49
50#if 0
51#ifdef HAVE_CONFIG_H
52#include "config.h"
53#endif
54#else
55#define HAVE_SOCKADDR_SA_LEN
56#define INET6
57#endif
42 58
43#include <sys/types.h> 59#include <sys/types.h>
44#include <stdlib.h> 60#include <sys/param.h>
45#include <unistd.h> 61#if 0
62#include <sys/sysctl.h>
63#endif
46#include <sys/socket.h> 64#include <sys/socket.h>
47#include <string.h> 65#include <net/if.h>
48#include <stdio.h>
49#include <sys/utsname.h>
50#include <sys/un.h>
51#include <netinet/in.h> 66#include <netinet/in.h>
52#include <arpa/inet.h> 67#include <arpa/inet.h>
68#include <arpa/nameser.h>
53#include <netdb.h> 69#include <netdb.h>
70#include <resolv.h>
71#include <string.h>
72#include <stdlib.h>
73#include <stddef.h>
74#include <ctype.h>
75#include <unistd.h>
76#include <stdio.h>
54#include <errno.h> 77#include <errno.h>
55 78
56#define GAIH_OKIFUNSPEC 0x0100 79#if 0
57#define GAIH_EAI ~(GAIH_OKIFUNSPEC) 80#ifndef HAVE_PORTABLE_PROTOTYPE
58 81#include "cdecl_ext.h"
59static struct addrinfo nullreq = { 82#endif
60 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL 83
84#ifndef HAVE_U_INT32_T
85#include "bittypes.h"
86#endif
87
88#ifndef HAVE_SOCKADDR_STORAGE
89#include "sockstorage.h"
90#endif
91
92#ifndef HAVE_ADDRINFO
93#include "addrinfo.h"
94#endif
95
96#if defined(__KAME__) && defined(INET6)
97# define FAITH
98#endif
99#endif
100
101#define SUCCESS 0
102#define ANY 0
103#define YES 1
104#define NO 0
105
106#ifdef FAITH
107static int translate = NO;
108static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
109#endif
110
111static const char in_addrany[] = { 0, 0, 0, 0 };
112static const char in6_addrany[] = {
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
61}; 114};
62 115static const char in_loopback[] = { 127, 0, 0, 1 };
63struct gaih_service { 116static const char in6_loopback[] = {
64 char *name; 117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
65 int num;
66}; 118};
67 119
68struct gaih_servtuple { 120struct sockinet {
69 struct gaih_servtuple *next; 121 u_char si_len;
70 int socktype; 122 u_char si_family;
71 int protocol; 123 u_short si_port;
72 int port; 124 u_int32_t si_scope_id;
73}; 125};
74 126
75static struct gaih_servtuple nullserv = { 127static const struct afd {
76 NULL, 0, 0, 0 128 int a_af;
129 int a_addrlen;
130 int a_socklen;
131 int a_off;
132 const char *a_addrany;
133 const char *a_loopback;
134 int a_scoped;
135} afdl [] = {
136#ifdef INET6
137 {PF_INET6, sizeof(struct in6_addr),
138 sizeof(struct sockaddr_in6),
139 offsetof(struct sockaddr_in6, sin6_addr),
140 in6_addrany, in6_loopback, 1},
141#endif
142 {PF_INET, sizeof(struct in_addr),
143 sizeof(struct sockaddr_in),
144 offsetof(struct sockaddr_in, sin_addr),
145 in_addrany, in_loopback, 0},
146 {0, 0, 0, 0, NULL, NULL, 0},
77}; 147};
78 148
79struct gaih_addrtuple { 149struct explore {
80 struct gaih_addrtuple *next; 150 int e_af;
81 int family; 151 int e_socktype;
82 char addr[16]; 152 int e_protocol;
83 char *cname; 153 const char *e_protostr;
154 int e_wild;
155#define WILD_AF(ex) ((ex)->e_wild & 0x01)
156#define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
157#define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
84}; 158};
85 159
86static struct gaih_typeproto { 160static const struct explore explore[] = {
87 int socktype; 161#if 0
88 int protocol; 162 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
89 char *name; 163#endif
90} gaih_inet_typeproto[] = { 164#ifdef INET6
91 { 0, 0, NULL }, 165 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
92 { SOCK_STREAM, IPPROTO_TCP, "tcp" }, 166 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
93 { SOCK_DGRAM, IPPROTO_UDP, "udp" }, 167 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
94 { 0, 0, NULL } 168#endif
169 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
170 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
171 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
172 { -1, 0, 0, NULL, 0 },
95}; 173};
96 174
97static int 175#ifdef INET6
98netdb_lookup_addr(const char *name, int af, 176#define PTON_MAX 16
99 const struct addrinfo *req, struct gaih_addrtuple **pat) 177#else
178#define PTON_MAX 4
179#endif
180
181
182static int str_isnumber __P((const char *));
183static int explore_fqdn __P((const struct addrinfo *, const char *,
184 const char *, struct addrinfo **));
185static int explore_null __P((const struct addrinfo *, const char *,
186 const char *, struct addrinfo **));
187static int explore_numeric __P((const struct addrinfo *, const char *,
188 const char *, struct addrinfo **));
189static int explore_numeric_scope __P((const struct addrinfo *, const char *,
190 const char *, struct addrinfo **));
191static int get_name __P((const char *, const struct afd *, struct addrinfo **,
192 char *, const struct addrinfo *, const char *));
193static int get_canonname __P((const struct addrinfo *,
194 struct addrinfo *, const char *));
195static struct addrinfo *get_ai __P((const struct addrinfo *,
196 const struct afd *, const char *));
197static int get_portmatch __P((const struct addrinfo *, const char *));
198static int get_port __P((struct addrinfo *, const char *, int));
199static const struct afd *find_afd __P((int));
200
201#if 0
202static char *ai_errlist[] = {
203 "Success",
204 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
205 "Temporary failure in name resolution", /* EAI_AGAIN */
206 "Invalid value for ai_flags", /* EAI_BADFLAGS */
207 "Non-recoverable failure in name resolution", /* EAI_FAIL */
208 "ai_family not supported", /* EAI_FAMILY */
209 "Memory allocation failure", /* EAI_MEMORY */
210 "No address associated with hostname", /* EAI_NODATA */
211 "hostname nor servname provided, or not known", /* EAI_NONAME */
212 "servname not supported for ai_socktype", /* EAI_SERVICE */
213 "ai_socktype not supported", /* EAI_SOCKTYPE */
214 "System error returned in errno", /* EAI_SYSTEM */
215 "Invalid value for hints", /* EAI_BADHINTS */
216 "Resolved protocol is unknown", /* EAI_PROTOCOL */
217 "Unknown error", /* EAI_MAX */
218};
219#endif
220
221/* XXX macros that make external reference is BAD. */
222
223#define GET_AI(ai, afd, addr) \
224do { \
225 /* external reference: pai, error, and label free */ \
226 (ai) = get_ai(pai, (afd), (addr)); \
227 if ((ai) == NULL) { \
228 error = EAI_MEMORY; \
229 goto free; \
230 } \
231} while (0)
232
233#define GET_PORT(ai, serv) \
234do { \
235 /* external reference: error and label free */ \
236 error = get_port((ai), (serv), 0); \
237 if (error != 0) \
238 goto free; \
239} while (0)
240
241#define GET_CANONNAME(ai, str) \
242do { \
243 /* external reference: pai, error and label free */ \
244 error = get_canonname(pai, (ai), (str)); \
245 if (error != 0) \
246 goto free; \
247} while (0)
248
249#define ERR(err) \
250do { \
251 /* external reference: error, and label bad */ \
252 error = (err); \
253 goto bad; \
254} while (0)
255
256#define MATCH_FAMILY(x, y, w) \
257 ((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
258#define MATCH(x, y, w) \
259 ((x) == (y) || ((w) && ((x) == ANY || (y) == ANY)))
260
261static int
262str_isnumber(p)
263 const char *p;
100{ 264{
101 int rval = 0, herrno, i; 265 char *q = (char *)p;
102 char *prevcname = NULL; 266 while (*q) {
103 struct hostent *h; 267 if (! isdigit(*q))
104 268 return NO;
105 h = gethostbyname2(name, af); 269 q++;
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 } 270 }
271 return YES;
272}
124 273
125 for (i = 0; h->h_addr_list[i]; i++) { 274int
126 while (*pat) 275getaddrinfo(hostname, servname, hints, res)
127 pat = &((*pat)->next); 276 const char *hostname, *servname;
128 277 const struct addrinfo *hints;
129 if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) 278 struct addrinfo **res;
130 return -EAI_MEMORY; 279{
131 memset(*pat, 0, sizeof(struct gaih_addrtuple)); 280 struct addrinfo sentinel;
132 281 struct addrinfo *cur;
133 switch ((*pat)->family = af) { 282 int error = 0;
134 case AF_INET: 283 struct addrinfo ai;
135 memcpy((*pat)->addr, h->h_addr_list[i], 284 struct addrinfo ai0;
136 sizeof(struct in_addr)); 285 struct addrinfo *pai;
137 break; 286 const struct afd *afd;
138 case AF_INET6: 287 const struct explore *ex;
139 memcpy((*pat)->addr, h->h_addr_list[i], 288#ifndef AI_MASK
140 sizeof(struct in6_addr)); 289#define AI_MASK (AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST)
290#endif
291
292#ifdef FAITH
293 static int firsttime = 1;
294
295 if (firsttime) {
296 /* translator hack */
297 char *q = getenv("GAI");
298 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
299 translate = YES;
300 firsttime = 0;
301 }
302#endif
303
304 sentinel.ai_next = NULL;
305 cur = &sentinel;
306 pai = &ai;
307 pai->ai_flags = 0;
308 pai->ai_family = PF_UNSPEC;
309 pai->ai_socktype = ANY;
310 pai->ai_protocol = ANY;
311 pai->ai_addrlen = 0;
312 pai->ai_canonname = NULL;
313 pai->ai_addr = NULL;
314 pai->ai_next = NULL;
315
316 if (hostname == NULL && servname == NULL)
317 return EAI_NONAME;
318 if (hints) {
319 /* error check for hints */
320 if (hints->ai_addrlen || hints->ai_canonname ||
321 hints->ai_addr || hints->ai_next)
322 ERR(EAI_BADHINTS); /* xxx */
323 if (hints->ai_flags & ~AI_MASK)
324 ERR(EAI_BADFLAGS);
325 switch (hints->ai_family) {
326 case PF_UNSPEC:
327 case PF_INET:
328#ifdef INET6
329 case PF_INET6:
330#endif
141 break; 331 break;
142 default: 332 default:
143 return -EAI_FAIL; 333 ERR(EAI_FAMILY);
144 } 334 }
145 335 memcpy(pai, hints, sizeof(*pai));
146 if (req->ai_flags & AI_CANONNAME) { 336
147 if (prevcname && !strcmp(prevcname, h->h_name)) 337 /*
148 (*pat)->cname = prevcname; 338 * if both socktype/protocol are specified, check if they
149 else 339 * are meaningful combination.
150 prevcname = (*pat)->cname = strdup(h->h_name); 340 */
341 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
342 for (ex = explore; ex->e_af >= 0; ex++) {
343 if (pai->ai_family != ex->e_af)
344 continue;
345 if (ex->e_socktype == ANY)
346 continue;
347 if (ex->e_protocol == ANY)
348 continue;
349 if (pai->ai_socktype == ex->e_socktype
350 && pai->ai_protocol != ex->e_protocol) {
351 ERR(EAI_BADHINTS);
352 }
353 }
151 } 354 }
152 pat = &((*pat)->next);
153 } 355 }
154 return rval;
155}
156 356
157static int 357 /*
158gaih_local(const char *name, const struct gaih_service *service, 358 * check for special cases. (1) numeric servname is disallowed if
159 const struct addrinfo *req, struct addrinfo **pai) 359 * socktype/protocol are left unspecified. (2) servname is disallowed
160{ 360 * for raw and other inet{,6} sockets.
161 struct utsname utsname; 361 */
162 struct addrinfo *ai; 362 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
163 struct sockaddr_un *sun; 363 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)) {
164 int siz; 364 ai0 = *pai;
165 365
166 if (name || (req->ai_flags & AI_CANONNAME)) 366 if (pai->ai_family == PF_UNSPEC)
167 if (uname(&utsname) < 0) 367 pai->ai_family = PF_INET6;
168 return (-EAI_SYSTEM); 368 error = get_portmatch(pai, servname);
169 369 if (error)
170 if (name && strcmp(name, "localhost") && strcmp(name, "local") && 370 ERR(error);
171 strcmp(name, "unix") && strcmp(name, utsname.nodename)) 371
172 return (GAIH_OKIFUNSPEC | -EAI_NONAME); 372 *pai = ai0;
173
174 siz = sizeof(struct addrinfo) + sizeof(struct sockaddr_un);
175 if (req->ai_flags & AI_CANONNAME)
176 siz += strlen(utsname.nodename) + 1;
177
178 if (!(ai = malloc(siz)))
179 return -EAI_MEMORY;
180
181 *pai = ai;
182 ai->ai_next = NULL;
183 ai->ai_flags = req->ai_flags;
184 ai->ai_family = AF_LOCAL;
185 ai->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
186 ai->ai_protocol = req->ai_protocol;
187 ai->ai_addrlen = sizeof(struct sockaddr_un);
188 ai->ai_addr = (void *)ai + sizeof(struct addrinfo);
189
190 sun = (struct sockaddr_un *)ai->ai_addr;
191 sun->sun_len = sizeof(struct sockaddr_un);
192 sun->sun_family = AF_LOCAL;
193 memset(&sun->sun_path, 0, sizeof sun->sun_path);
194
195 if (service) {
196 char *c;
197
198 c = strchr(service->name, '/');
199 if (c) {
200 if (strlen(service->name) >= sizeof(sun->sun_path))
201 return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
202 strlcpy(sun->sun_path, service->name, sizeof (sun->sun_path));
203 } else {
204 if (strlen(P_tmpdir "/") + strlen(service->name) + 1 >=
205 sizeof(sun->sun_path))
206 return(GAIH_OKIFUNSPEC | -EAI_SERVICE);
207 snprintf(sun->sun_path, sizeof(sun->sun_path), "%s/%s",
208 P_tmpdir, service->name);
209 }
210 } else {
211 extern char *_mktemp __P((char *));
212 char tmpn[MAXPATHLEN], *c;
213
214 snprintf(tmpn, sizeof tmpn, "%stmp.XXXXXXXXXXXXX", P_tmpdir);
215 if (!(c = _mktemp(tmpn)))
216 return (GAIH_OKIFUNSPEC | -EAI_SYSTEM);
217 strlcpy(sun->sun_path, c, sizeof(sun->sun_path));
218 } 373 }
219 374
220 ai->ai_canonname = NULL; 375 ai0 = *pai;
221 if (req->ai_flags & AI_CANONNAME) {
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}
228 376
229static int 377 /* NULL hostname, or numeric hostname */
230gaih_inet_serv(char *servicename, struct gaih_typeproto *tp, 378 for (ex = explore; ex->e_af >= 0; ex++) {
231 struct gaih_servtuple **st) 379 *pai = ai0;
232{
233 struct servent *s;
234 380
235 s = getservbyname(servicename, tp->name); 381 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
236 if (!s) 382 continue;
237 return (GAIH_OKIFUNSPEC | -EAI_SERVICE); 383 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
384 continue;
385 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
386 continue;
238 387
239 if (!(*st = malloc(sizeof(struct gaih_servtuple)))) 388 if (pai->ai_family == PF_UNSPEC)
240 return (-EAI_MEMORY); 389 pai->ai_family = ex->e_af;
390 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
391 pai->ai_socktype = ex->e_socktype;
392 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
393 pai->ai_protocol = ex->e_protocol;
241 394
242 (*st)->next = NULL; 395 if (hostname == NULL)
243 (*st)->socktype = tp->socktype; 396 error = explore_null(pai, hostname, servname, &cur->ai_next);
244 (*st)->protocol = tp->protocol; 397 else
245 (*st)->port = s->s_port; 398 error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
246 return (0);
247}
248 399
249static int 400 if (error)
250gaih_inet(const char *name, const struct gaih_service *service, 401 goto free;
251 const struct addrinfo*req, struct addrinfo **pai) 402
252{ 403 while (cur && cur->ai_next)
253 struct gaih_typeproto *tp = gaih_inet_typeproto; 404 cur = cur->ai_next;
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 } 405 }
273 if (service && (service->num < 0)) { 406
274 if (tp->name) { 407 /*
275 rval = gaih_inet_serv(service->name, tp, &st); 408 * XXX
276 if (rval) 409 * If numreic representation of AF1 can be interpreted as FQDN
277 goto ret; 410 * representation of AF2, we need to think again about the code below.
278 } else { 411 */
279 struct gaih_servtuple **pst = &st; 412 if (sentinel.ai_next)
280 for (tp++; tp->name; tp++) { 413 goto good;
281 rval = gaih_inet_serv(service->name, tp, pst); 414
282 if (rval) { 415 if (pai->ai_flags & AI_NUMERICHOST)
283 if (rval & GAIH_OKIFUNSPEC) 416 ERR(EAI_NONAME);
284 continue; 417 if (hostname == NULL)
285 goto ret; 418 ERR(EAI_NONAME);
286 } 419
287 pst = &((*pst)->next); 420 /*
421 * hostname as alphabetical name.
422 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
423 * outer loop by AFs.
424 */
425 for (afd = afdl; afd->a_af; afd++) {
426 *pai = ai0;
427
428 if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
429 continue;
430
431 for (ex = explore; ex->e_af >= 0; ex++) {
432 *pai = ai0;
433
434 if (pai->ai_family == PF_UNSPEC)
435 pai->ai_family = afd->a_af;
436
437 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
438 continue;
439 if (!MATCH(pai->ai_socktype, ex->e_socktype,
440 WILD_SOCKTYPE(ex))) {
441 continue;
288 } 442 }
289 if (st == &nullserv) { 443 if (!MATCH(pai->ai_protocol, ex->e_protocol,
290 rval = GAIH_OKIFUNSPEC | -EAI_SERVICE; 444 WILD_PROTOCOL(ex))) {
291 goto ret; 445 continue;
292 } 446 }
447
448 if (pai->ai_family == PF_UNSPEC)
449 pai->ai_family = ex->e_af;
450 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
451 pai->ai_socktype = ex->e_socktype;
452 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
453 pai->ai_protocol = ex->e_protocol;
454
455 error = explore_fqdn(pai, hostname, servname,
456 &cur->ai_next);
457
458 while (cur && cur->ai_next)
459 cur = cur->ai_next;
293 } 460 }
294 } else { 461 }
295 if (!(st = malloc(sizeof(struct gaih_servtuple)))) {
296 rval = -EAI_MEMORY;
297 goto ret;
298 }
299 462
300 st->next = NULL; 463 /* XXX */
301 st->socktype = tp->socktype; 464 if (sentinel.ai_next)
302 st->protocol = tp->protocol; 465 error = 0;
303 if (service) 466
304 st->port = htons(service->num); 467 if (error)
305 else 468 goto free;
306 st->port = 0; 469 if (error == 0) {
470 if (sentinel.ai_next) {
471 good:
472 *res = sentinel.ai_next;
473 return SUCCESS;
474 } else
475 error = EAI_FAIL;
307 } 476 }
477 free:
478 bad:
479 if (sentinel.ai_next)
480 freeaddrinfo(sentinel.ai_next);
481 *res = NULL;
482 return error;
483}
308 484
309 if (!name) { 485/*
310 if (!(at = malloc(sizeof(struct gaih_addrtuple)))) { 486 * FQDN hostname, DNS lookup
311 rval = -EAI_MEMORY; 487 */
312 goto ret; 488static int
489explore_fqdn(pai, hostname, servname, res)
490 const struct addrinfo *pai;
491 const char *hostname;
492 const char *servname;
493 struct addrinfo **res;
494{
495 int s;
496 struct hostent *hp;
497 int h_error;
498 int af;
499 char **aplist = NULL, *apbuf = NULL;
500 char *ap;
501 struct addrinfo sentinel, *cur;
502 int i;
503#ifndef USE_GETIPNODEBY
504 int naddrs;
505#endif
506 const struct afd *afd;
507 int error;
508
509 *res = NULL;
510 sentinel.ai_next = NULL;
511 cur = &sentinel;
512
513 /*
514 * filter out AFs that are not supported by the kernel
515 * XXX errno?
516 */
517 s = socket(pai->ai_family, SOCK_DGRAM, 0);
518 if (s < 0) {
519 if (errno != EMFILE)
520 return 0;
521 } else
522 close(s);
523
524 /*
525 * if the servname does not match socktype/protocol, ignore it.
526 */
527 if (get_portmatch(pai, servname) != 0)
528 return 0;
529
530 afd = find_afd(pai->ai_family);
531
532 /*
533 * post-RFC2553: should look at (pai->ai_flags & AI_ADDRCONFIG)
534 * rather than hardcoding it. we may need to add AI_ADDRCONFIG
535 * handling code by ourselves in case we don't have getipnodebyname().
536 */
537#ifdef USE_GETIPNODEBY
538 hp = getipnodebyname(hostname, pai->ai_family, AI_ADDRCONFIG, &h_error);
539#else
540 hp = gethostbyname2(hostname, pai->ai_family);
541 h_error = h_errno;
542#endif
543
544 if (hp == NULL) {
545 switch (h_error) {
546 case HOST_NOT_FOUND:
547 case NO_DATA:
548 error = EAI_NODATA;
549 break;
550 case TRY_AGAIN:
551 error = EAI_AGAIN;
552 break;
553 case NO_RECOVERY:
554 case NETDB_INTERNAL:
555 default:
556 error = EAI_FAIL;
557 break;
313 } 558 }
559 } else if ((hp->h_name == NULL) || (hp->h_name[0] == 0)
560 || (hp->h_addr_list[0] == NULL)) {
561#ifdef USE_GETIPNODEBY
562 freehostent(hp);
563#endif
564 hp = NULL;
565 error = EAI_FAIL;
566 }
314 567
315 memset(at, 0, sizeof(struct gaih_addrtuple)); 568 if (hp == NULL)
316 569 goto free;
317 if (req->ai_family) 570
318 at->family = req->ai_family; 571#ifdef USE_GETIPNODEBY
319 else { 572 aplist = hp->h_addr_list;
320 if (!(at->next = malloc(sizeof(struct gaih_addrtuple)))) { 573#else
321 rval = -EAI_MEMORY; 574 /*
322 goto ret; 575 * hp will be overwritten if we use gethostbyname2().
323 } 576 * always deep copy for simplification.
577 */
578 for (naddrs = 0; hp->h_addr_list[naddrs] != NULL; naddrs++)
579 ;
580 naddrs++;
581 aplist = (char **)malloc(sizeof(aplist[0]) * naddrs);
582 apbuf = (char *)malloc(hp->h_length * naddrs);
583 if (aplist == NULL || apbuf == NULL) {
584 error = EAI_MEMORY;
585 goto free;
586 }
587 memset(aplist, 0, sizeof(aplist[0]) * naddrs);
588 for (i = 0; i < naddrs; i++) {
589 if (hp->h_addr_list[i] == NULL) {
590 aplist[i] = NULL;
591 continue;
592 }
593 memcpy(&apbuf[i * hp->h_length], hp->h_addr_list[i],
594 hp->h_length);
595 aplist[i] = &apbuf[i * hp->h_length];
596 }
597#endif
598
599 for (i = 0; aplist[i] != NULL; i++) {
600 af = hp->h_addrtype;
601 ap = aplist[i];
602 if (af == AF_INET6
603 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
604 af = AF_INET;
605 ap = ap + sizeof(struct in6_addr)
606 - sizeof(struct in_addr);
607 }
324 608
325 at->family = AF_INET6; 609 if (af != pai->ai_family)
610 continue;
326 611
327 memset(at->next, 0, sizeof(struct gaih_addrtuple)); 612 if ((pai->ai_flags & AI_CANONNAME) == 0) {
328 at->next->family = AF_INET; 613 GET_AI(cur->ai_next, afd, ap);
614 GET_PORT(cur->ai_next, servname);
615 } else {
616 /*
617 * if AI_CANONNAME and if reverse lookup
618 * fail, return ai anyway to pacify
619 * calling application.
620 *
621 * XXX getaddrinfo() is a name->address
622 * translation function, and it looks
623 * strange that we do addr->name
624 * translation here.
625 */
626 get_name(ap, afd, &cur->ai_next,
627 ap, pai, servname);
329 } 628 }
330 629
331 goto build; 630 while (cur && cur->ai_next)
631 cur = cur->ai_next;
332 } 632 }
333 633
334 if (!req->ai_family || (req->ai_family == AF_INET)) { 634 *res = sentinel.ai_next;
335 struct in_addr in_addr; 635 return 0;
336 if (inet_pton(AF_INET, name, &in_addr) > 0) {
337 if (!(at = malloc(sizeof(struct gaih_addrtuple)))) {
338 rval = -EAI_MEMORY;
339 goto ret;
340 }
341 636
342 memset(at, 0, sizeof(struct gaih_addrtuple)); 637free:
638#ifdef USE_GETIPNODEBY
639 if (hp)
640 freehostent(hp);
641#endif
642 if (aplist)
643 free(aplist);
644 if (apbuf)
645 free(apbuf);
646 if (sentinel.ai_next)
647 freeaddrinfo(sentinel.ai_next);
648 return error;
649}
343 650
344 at->family = AF_INET; 651/*
345 memcpy(at->addr, &in_addr, sizeof(struct in_addr)); 652 * hostname == NULL.
346 goto build; 653 * passive socket -> anyaddr (0.0.0.0 or ::)
347 } 654 * non-passive socket -> localhost (127.0.0.1 or ::1)
655 */
656static int
657explore_null(pai, hostname, servname, res)
658 const struct addrinfo *pai;
659 const char *hostname;
660 const char *servname;
661 struct addrinfo **res;
662{
663 int s;
664 const struct afd *afd;
665 struct addrinfo *cur;
666 struct addrinfo sentinel;
667 int error;
668
669 *res = NULL;
670 sentinel.ai_next = NULL;
671 cur = &sentinel;
672
673 /*
674 * filter out AFs that are not supported by the kernel
675 * XXX errno?
676 */
677 s = socket(pai->ai_family, SOCK_DGRAM, 0);
678 if (s < 0) {
679 if (errno != EMFILE)
680 return 0;
681 } else
682 close(s);
683
684 /*
685 * if the servname does not match socktype/protocol, ignore it.
686 */
687 if (get_portmatch(pai, servname) != 0)
688 return 0;
689
690 afd = find_afd(pai->ai_family);
691
692 if (pai->ai_flags & AI_PASSIVE) {
693 GET_AI(cur->ai_next, afd, afd->a_addrany);
694 /* xxx meaningless?
695 * GET_CANONNAME(cur->ai_next, "anyaddr");
696 */
697 GET_PORT(cur->ai_next, servname);
698 } else {
699 GET_AI(cur->ai_next, afd, afd->a_loopback);
700 /* xxx meaningless?
701 * GET_CANONNAME(cur->ai_next, "localhost");
702 */
703 GET_PORT(cur->ai_next, servname);
348 } 704 }
705 cur = cur->ai_next;
349 706
350 if (!req->ai_family || (req->ai_family == AF_INET6)) { 707 *res = sentinel.ai_next;
351 struct in6_addr in6_addr; 708 return 0;
352 if (inet_pton(AF_INET6, name, &in6_addr) > 0) {
353 if (!(at = malloc(sizeof(struct gaih_addrtuple)))) {
354 rval = -EAI_MEMORY;
355 goto ret;
356 }
357 709
358 memset(at, 0, sizeof(struct gaih_addrtuple)); 710free:
711 if (sentinel.ai_next)
712 freeaddrinfo(sentinel.ai_next);
713 return error;
714}
359 715
360 at->family = AF_INET6; 716/*
361 memcpy(at->addr, &in6_addr, sizeof(struct in6_addr)); 717 * numeric hostname
362 goto build; 718 */
719static int
720explore_numeric(pai, hostname, servname, res)
721 const struct addrinfo *pai;
722 const char *hostname;
723 const char *servname;
724 struct addrinfo **res;
725{
726 const struct afd *afd;
727 struct addrinfo *cur;
728 struct addrinfo sentinel;
729 int error;
730 char pton[PTON_MAX];
731 int flags;
732
733 *res = NULL;
734 sentinel.ai_next = NULL;
735 cur = &sentinel;
736
737 /*
738 * if the servname does not match socktype/protocol, ignore it.
739 */
740 if (get_portmatch(pai, servname) != 0)
741 return 0;
742
743 afd = find_afd(pai->ai_family);
744 flags = pai->ai_flags;
745
746 if (inet_pton(afd->a_af, hostname, pton) == 1) {
747 u_int32_t v4a;
748#ifdef INET6
749 u_char pfx;
750#endif
751
752 switch (afd->a_af) {
753 case AF_INET:
754 v4a = (u_int32_t)ntohl(((struct in_addr *)pton)->s_addr);
755 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
756 flags &= ~AI_CANONNAME;
757 v4a >>= IN_CLASSA_NSHIFT;
758 if (v4a == 0 || v4a == IN_LOOPBACKNET)
759 flags &= ~AI_CANONNAME;
760 break;
761#ifdef INET6
762 case AF_INET6:
763 pfx = ((struct in6_addr *)pton)->s6_addr[0];
764 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
765 flags &= ~AI_CANONNAME;
766 break;
767#endif
363 } 768 }
769
770 if (pai->ai_family == afd->a_af ||
771 pai->ai_family == PF_UNSPEC /*?*/) {
772 if ((flags & AI_CANONNAME) == 0) {
773 GET_AI(cur->ai_next, afd, pton);
774 GET_PORT(cur->ai_next, servname);
775 } else {
776 /*
777 * if AI_CANONNAME and if reverse lookup
778 * fail, return ai anyway to pacify
779 * calling application.
780 *
781 * XXX getaddrinfo() is a name->address
782 * translation function, and it looks
783 * strange that we do addr->name
784 * translation here.
785 */
786 get_name(pton, afd, &cur->ai_next,
787 pton, pai, servname);
788 }
789 while (cur && cur->ai_next)
790 cur = cur->ai_next;
791 } else
792 ERR(EAI_FAMILY); /*xxx*/
364 } 793 }
365 794
366 if (!(req->ai_flags & AI_NUMERICHOST)) { 795 *res = sentinel.ai_next;
367 if (!req->ai_family || (req->ai_family == AF_INET6)) 796 return 0;
368 if ((rval = netdb_lookup_addr(name, AF_INET6, req, &at)) < 0)
369 goto ret;
370 if (!req->ai_family || (req->ai_family == AF_INET))
371 if ((rval = netdb_lookup_addr(name, AF_INET, req, &at)) < 0)
372 goto ret;
373 797
374 if (!rval) 798free:
375 goto build; 799bad:
376 } 800 if (sentinel.ai_next)
801 freeaddrinfo(sentinel.ai_next);
802 return error;
803}
377 804
378 if (!at) { 805/*
379 rval = GAIH_OKIFUNSPEC | -EAI_NONAME; 806 * numeric hostname with scope
380 goto ret; 807 */
808static int
809explore_numeric_scope(pai, hostname, servname, res)
810 const struct addrinfo *pai;
811 const char *hostname;
812 const char *servname;
813 struct addrinfo **res;
814{
815#ifndef SCOPE_DELIMITER
816 return explore_numeric(pai, hostname, servname, res);
817#else
818 const struct afd *afd;
819 struct addrinfo *cur;
820 int error;
821 char *cp, *hostname2 = NULL;
822 int scope;
823 struct sockaddr_in6 *sin6;
824
825 /*
826 * if the servname does not match socktype/protocol, ignore it.
827 */
828 if (get_portmatch(pai, servname) != 0)
829 return 0;
830
831 afd = find_afd(pai->ai_family);
832 if (!afd->a_scoped)
833 return explore_numeric(pai, hostname, servname, res);
834
835 cp = strchr(hostname, SCOPE_DELIMITER);
836 if (cp == NULL)
837 return explore_numeric(pai, hostname, servname, res);
838
839 /*
840 * Handle special case of <scoped_address><delimiter><scope id>
841 */
842 hostname2 = strdup(hostname);
843 if (hostname2 == NULL)
844 return EAI_MEMORY;
845 /* terminate at the delimiter */
846 hostname2[cp - hostname] = '\0';
847
848 cp++;
849 switch (pai->ai_family) {
850#ifdef INET6
851 case AF_INET6:
852 scope = if_nametoindex(cp);
853 if (scope == 0) {
854 free(hostname2);
855 return (EAI_NONAME);
856 }
857 break;
858#endif
381 } 859 }
382 860
383build: 861 error = explore_numeric(pai, hostname2, servname, res);
384 at2 = at; 862 if (error == 0) {
385 while (at2) { 863 for (cur = *res; cur; cur = cur->ai_next) {
386 if (req->ai_flags & AI_CANONNAME) { 864 if (cur->ai_family != AF_INET6)
387 if (at2->cname) 865 continue;
388 canonlen = strlen(at2->cname) + 1; 866 sin6 = (struct sockaddr_in6 *)cur->ai_addr;
389 else 867 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
390 if (name) 868 IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr))
391 canonlen = strlen(name) + 1; 869 sin6->sin6_scope_id = scope;
392 else 870 }
393 canonlen = 2; 871 }
394 } else
395 canonlen = 0;
396 872
397 if (at2->family == AF_INET6) 873 free(hostname2);
398 addrlen = sizeof(struct sockaddr_in6);
399 else
400 addrlen = sizeof(struct sockaddr_in);
401
402 st2 = st;
403 while (st2) {
404 if (!(ai = malloc(sizeof(struct addrinfo) +
405 addrlen + canonlen))) {
406 rval = -EAI_MEMORY;
407 goto ret;
408 }
409 874
410 *pai = ai; 875 return error;
411 memset(ai, 0, sizeof(struct addrinfo) + addrlen + canonlen); 876#endif
412 877}
413 ai->ai_flags = req->ai_flags;
414 ai->ai_family = at2->family;
415 ai->ai_socktype = st2->socktype;
416 ai->ai_protocol = st2->protocol;
417 ai->ai_addrlen = addrlen;
418 ai->ai_addr = (void *)ai + sizeof(struct addrinfo);
419 ai->ai_addr->sa_len = addrlen;
420 ai->ai_addr->sa_family = at2->family;
421
422 switch (at2->family) {
423 case AF_INET6:
424 {
425 struct sockaddr_in6 *sin6 = (void *)ai->ai_addr;
426
427 memcpy(&sin6->sin6_addr, at2->addr,
428 sizeof(sin6->sin6_addr));
429 sin6->sin6_port = st2->port;
430 break;
431 }
432 default:
433 {
434 struct sockaddr_in *sin = (void *)ai->ai_addr;
435
436 memcpy(&sin->sin_addr, at2->addr,
437 sizeof(sin->sin_addr));
438 sin->sin_port = st2->port;
439 break;
440 }
441 }
442 878
443 if (canonlen) { 879static int
444 ai->ai_canonname = (void *) ai->ai_addr + addrlen; 880get_name(addr, afd, res, numaddr, pai, servname)
445 881 const char *addr;
446 if (at2->cname) { 882 const struct afd *afd;
447 strcpy(ai->ai_canonname, at2->cname); 883 struct addrinfo **res;
448 if (prevcname != at2->cname) { 884 char *numaddr;
449 if (prevcname) 885 const struct addrinfo *pai;
450 free(prevcname); 886 const char *servname;
451 prevcname = at2->cname; 887{
452 } 888 struct hostent *hp = NULL;
453 } else 889 struct addrinfo *cur = NULL;
454 strcpy(ai->ai_canonname, name ? name : "*"); 890 int error = 0;
455 } 891 char *ap = NULL, *cn = NULL;
456 pai = &(ai->ai_next); 892#ifdef USE_GETIPNODEBY
457 st2 = st2->next; 893 int h_error;
458 } 894
459 at2 = at2->next; 895 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
460 } 896#else
461 rval = 0; 897 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
462 898#endif
463ret: 899 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
464 if (st != &nullserv) { 900#ifdef USE_GETIPNODEBY
465 struct gaih_servtuple *st2 = st; 901 GET_AI(cur, afd, hp->h_addr_list[0]);
466 while (st) { 902 GET_PORT(cur, servname);
467 st2 = st->next; 903 GET_CANONNAME(cur, hp->h_name);
468 free(st); 904#else
469 st = st2; 905 /* hp will be damaged if we use gethostbyaddr() */
906 if ((ap = (char *)malloc(hp->h_length)) == NULL) {
907 error = EAI_MEMORY;
908 goto free;
470 } 909 }
471 } 910 memcpy(ap, hp->h_addr_list[0], hp->h_length);
472 if (at) { 911 if ((cn = strdup(hp->h_name)) == NULL) {
473 struct gaih_addrtuple *at2 = at; 912 error = EAI_MEMORY;
474 while (at) { 913 goto free;
475 at2 = at->next;
476 free(at);
477 at = at2;
478 } 914 }
915
916 GET_AI(cur, afd, ap);
917 GET_PORT(cur, servname);
918 GET_CANONNAME(cur, cn);
919 free(ap); ap = NULL;
920 free(cn); cn = NULL;
921#endif
922 } else {
923 GET_AI(cur, afd, numaddr);
924 GET_PORT(cur, servname);
479 } 925 }
480 return rval; 926
927#ifdef USE_GETIPNODEBY
928 if (hp)
929 freehostent(hp);
930#endif
931 *res = cur;
932 return SUCCESS;
933 free:
934 if (cur)
935 freeaddrinfo(cur);
936 if (ap)
937 free(ap);
938 if (cn)
939 free(cn);
940#ifdef USE_GETIPNODEBY
941 if (hp)
942 freehostent(hp);
943#endif
944 *res = NULL;
945 return error;
481} 946}
482 947
483static struct gaih { 948static int
484 int family; 949get_canonname(pai, ai, str)
485 char *name; 950 const struct addrinfo *pai;
486 int (*gaih) __P((const char *name, 951 struct addrinfo *ai;
487 const struct gaih_service *service, 952 const char *str;
488 const struct addrinfo *req, struct addrinfo **pai)); 953{
489} gaih[] = { 954 if ((pai->ai_flags & AI_CANONNAME) != 0) {
490 { PF_INET6, "inet6", gaih_inet }, 955 ai->ai_canonname = (char *)malloc(strlen(str) + 1);
491 { PF_INET, "inet", gaih_inet }, 956 if (ai->ai_canonname == NULL)
492 { PF_LOCAL, "local", gaih_local }, 957 return EAI_MEMORY;
493 { -1, NULL, NULL} 958 strcpy(ai->ai_canonname, str);
494}; 959 }
960 return 0;
961}
495 962
496int 963static struct addrinfo *
497getaddrinfo(const char *name, const char *service, 964get_ai(pai, afd, addr)
498 const struct addrinfo *req, struct addrinfo **pai) 965 const struct addrinfo *pai;
966 const struct afd *afd;
967 const char *addr;
499{ 968{
500 int rval = EAI_SYSTEM; /* XXX */ 969 char *p;
501 int j = 0; 970 struct addrinfo *ai;
502 struct addrinfo *p = NULL, **end;
503 struct gaih *g = gaih, *pg = NULL;
504 struct gaih_service gaih_service, *pservice;
505 971
506 if (name && (name[0] == '*') && !name[1]) 972 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
507 name = NULL; 973 + (afd->a_socklen));
974 if (ai == NULL)
975 return NULL;
976
977 memcpy(ai, pai, sizeof(struct addrinfo));
978 ai->ai_addr = (struct sockaddr *)(ai + 1);
979 memset(ai->ai_addr, 0, afd->a_socklen);
980#ifdef HAVE_SOCKADDR_SA_LEN
981 ai->ai_addr->sa_len = afd->a_socklen;
982#endif
983 ai->ai_addrlen = afd->a_socklen;
984 ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
985 p = (char *)(ai->ai_addr);
986 memcpy(p + afd->a_off, addr, afd->a_addrlen);
987 return ai;
988}
508 989
509 if (service && service[0] == '*' && service[1] == '\0') 990static int
510 service = NULL; 991get_portmatch(ai, servname)
992 const struct addrinfo *ai;
993 const char *servname;
994{
511 995
512 if (!req) 996 /* get_port does not touch first argument. when matchonly == 1. */
513 req = &nullreq; 997 return get_port((struct addrinfo *)ai, servname, 1);
998}
999
1000static int
1001get_port(ai, servname, matchonly)
1002 struct addrinfo *ai;
1003 const char *servname;
1004 int matchonly;
1005{
1006 const char *proto;
1007 struct servent *sp;
1008 int port;
1009 int allownumeric;
1010
1011 if (servname == NULL)
1012 return 0;
1013 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
1014 return 0;
1015
1016 switch (ai->ai_socktype) {
1017 case SOCK_RAW:
1018 return EAI_SERVICE;
1019 case SOCK_DGRAM:
1020 case SOCK_STREAM:
1021 allownumeric = 1;
1022 break;
1023 case ANY:
1024 allownumeric = 0;
1025 break;
1026 default:
1027 return EAI_SOCKTYPE;
1028 }
514 1029
515 if (req->ai_flags & ~(AI_CANONNAME | AI_PASSIVE | AI_NUMERICHOST | AI_EXT)) 1030 if (str_isnumber(servname)) {
516 return (EAI_BADFLAGS); 1031 if (!allownumeric)
1032 return EAI_SERVICE;
1033 port = htons(atoi(servname));
1034 if (port < 0 || port > 65535)
1035 return EAI_SERVICE;
1036 } else {
1037 switch (ai->ai_socktype) {
1038 case SOCK_DGRAM:
1039 proto = "udp";
1040 break;
1041 case SOCK_STREAM:
1042 proto = "tcp";
1043 break;
1044 default:
1045 proto = NULL;
1046 break;
1047 }
517 1048
518 if (service && *service) { 1049 if ((sp = getservbyname(servname, proto)) == NULL)
519 char *c; 1050 return EAI_SERVICE;
1051 port = sp->s_port;
1052 }
520 1053
521 gaih_service.num = strtoul(service, &c, 10); 1054 if (!matchonly) {
522 if (*c) 1055 switch (ai->ai_family) {
523 gaih_service.num = -1; 1056 case AF_INET:
524 gaih_service.name = (void *)service; 1057 ((struct sockaddr_in *)ai->ai_addr)->sin_port = port;
525 pservice = &gaih_service; 1058 break;
526 } else 1059#ifdef INET6
527 pservice = NULL; 1060 case AF_INET6:
528 1061 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port;
529 if (pai) 1062 break;
530 end = &p; 1063#endif
531 else
532 end = NULL;
533
534 while (g->gaih) {
535 if ((req->ai_family == g->family) || !req->ai_family) {
536 j++;
537 if (!((pg && (pg->gaih == g->gaih)))) {
538 pg = g;
539 rval = g->gaih(name, pservice, req, end);
540 if (rval) {
541 if (!req->ai_family && (rval & GAIH_OKIFUNSPEC))
542 continue;
543
544 if (p)
545 freeaddrinfo(p);
546
547 return -(rval & GAIH_EAI);
548 }
549 if (end)
550 while (*end)
551 end = &((*end)->ai_next);
552 }
553 } 1064 }
554 g++;
555 } 1065 }
556 1066
557 if (!j) 1067 return 0;
558 return (EAI_FAMILY); 1068}
1069
1070static const struct afd *
1071find_afd(af)
1072 int af;
1073{
1074 const struct afd *afd;
559 1075
560 if (p) { 1076 if (af == PF_UNSPEC)
561 *pai = p; 1077 return NULL;
562 return (0); 1078 for (afd = afdl; afd->a_af; afd++) {
1079 if (afd->a_af == af)
1080 return afd;
563 } 1081 }
564 if (!pai && !rval) 1082 return NULL;
565 return (0);
566 return EAI_NONAME;
567} 1083}
diff --git a/src/lib/libc/net/getnameinfo.c b/src/lib/libc/net/getnameinfo.c
index 62c4b9d928..787beec9c6 100644
--- a/src/lib/libc/net/getnameinfo.c
+++ b/src/lib/libc/net/getnameinfo.c
@@ -1,7 +1,9 @@
1/* $OpenBSD: getnameinfo.c,v 1.5 1999/12/30 08:54:20 itojun Exp $ */
2
1/* 3/*
2 * %%% copyright-cmetz-96-bsd 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * Copyright (c) 1996-1999, Craig Metz, All rights reserved. 5 * All rights reserved.
4 * 6 *
5 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
7 * are met: 9 * are met:
@@ -10,18 +12,14 @@
10 * 2. Redistributions in binary form must reproduce the above copyright 12 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the 13 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software 15 * 3. Neither the name of the project nor the names of its contributors
14 * must display the following acknowledgement:
15 * This product includes software developed by Craig Metz and
16 * by other 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 16 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission. 17 * without specific prior written permission.
20 * 18 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
@@ -29,236 +27,258 @@
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * 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 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE. 29 * SUCH DAMAGE.
32 *
33 */ 30 */
34 31
35/* getnameinfo() v1.38 */ 32/*
33 * Issues to be discussed:
34 * - Thread safe-ness must be checked
35 * - Return values. There seems to be no standard for return value (RFC2553)
36 * but INRIA implementation returns EAI_xxx defined for getaddrinfo().
37 * - RFC2553 says that we should raise error on short buffer. X/Open says
38 * we need to truncate the result. We obey RFC2553 (and X/Open should be
39 * modified).
40 */
41
42#if 0
43#ifdef HAVE_CONFIG_H
44#include "config.h"
45#endif
46#else
47#define HAVE_SA_LEN
48#define INET6
49#endif
36 50
37#include <sys/types.h> 51#include <sys/types.h>
38#include <sys/socket.h> 52#include <sys/socket.h>
53#include <net/if.h>
39#include <netinet/in.h> 54#include <netinet/in.h>
40#include <sys/un.h>
41#include <sys/utsname.h>
42#include <netdb.h>
43#include <arpa/inet.h> 55#include <arpa/inet.h>
44#include <errno.h> 56#include <arpa/nameser.h>
45#include <string.h> 57#include <netdb.h>
46#include <resolv.h> 58#include <resolv.h>
59#include <string.h>
60#include <stddef.h>
47 61
48#ifndef min 62#if 0
49#define min(x,y) (((x) > (y)) ? (y) : (x)) 63#ifndef HAVE_PORTABLE_PROTOTYPE
50#endif /* min */ 64#include "cdecl_ext.h"
51 65#endif
52static int
53netdb_lookup_name(int family, void *addr, int addrlen, char *name,
54 int namelen, int flags)
55{
56 struct hostent *hostent;
57 char *c, *c2;
58 int i;
59
60 if (!(hostent = gethostbyaddr(addr, addrlen, family))) {
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;
88}
89
90int
91getnameinfo(const struct sockaddr *sa, size_t addrlen, char *host,
92 size_t hostlen, char *serv, size_t servlen, int flags)
93{
94 int rval;
95 int saved_errno;
96
97 if (sa == NULL || addrlen != sa->sa_len)
98 return EAI_FAIL;
99 saved_errno = errno;
100 66
101 if (host && hostlen > 0) { 67#ifndef HAVE_ADDRINFO
102 switch (sa->sa_family) { 68#include "addrinfo.h"
103 case AF_INET6: 69#endif
104 { 70#endif
105 struct sockaddr_in6 *sin6 = (void *)sa;
106 71
107 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 72#define SUCCESS 0
108 if (flags & NI_NUMERICHOST) 73#define ANY 0
109 goto inet6_noname; 74#define YES 1
110 strlcpy(host, "*", hostlen); 75#define NO 0
111 break;
112 }
113 76
114 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { 77static struct afd {
115 struct sockaddr_in sin; 78 int a_af;
79 int a_addrlen;
80 int a_socklen;
81 int a_off;
82} afdl [] = {
83#ifdef INET6
84 {PF_INET6, sizeof(struct in6_addr), sizeof(struct sockaddr_in6),
85 offsetof(struct sockaddr_in6, sin6_addr)},
86#endif
87 {PF_INET, sizeof(struct in_addr), sizeof(struct sockaddr_in),
88 offsetof(struct sockaddr_in, sin_addr)},
89 {0, 0, 0},
90};
116 91
117 memset(&sin, 0, sizeof(struct sockaddr_in)); 92struct sockinet {
118 sin.sin_len = sizeof(struct sockaddr_in); 93 u_char si_len;
119 sin.sin_family = AF_INET; 94 u_char si_family;
120 sin.sin_port = sin6->sin6_port; 95 u_short si_port;
121 sin.sin_addr.s_addr = 96};
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 97
132 if (flags & NI_NUMERICHOST) 98#define ENI_NOSOCKET 0
133 goto inet6_noname; 99#define ENI_NOSERVNAME 1
134 if ((rval = netdb_lookup_name(AF_INET6, 100#define ENI_NOHOSTNAME 2
135 &sin6->sin6_addr, sizeof(struct in6_addr), 101#define ENI_MEMORY 3
136 host, hostlen, flags)) < 0) 102#define ENI_SYSTEM 4
137 goto ret; 103#define ENI_FAMILY 5
104#define ENI_SALEN 6
138 105
139 if (!rval) 106int
140 break; 107getnameinfo(sa, salen, host, hostlen, serv, servlen, flags)
141 inet6_noname: 108 const struct sockaddr *sa;
142 if (flags & NI_NAMEREQD) { 109 size_t salen;
143 rval = EAI_NONAME; 110 char *host;
144 goto ret; 111 size_t hostlen;
145 } 112 char *serv;
146 if (!inet_ntop(AF_INET6, &sin6->sin6_addr, host, hostlen)) { 113 size_t servlen;
147 rval = EAI_NONAME; 114 int flags;
148 goto ret; 115{
149 } 116 struct afd *afd;
150 break; 117 struct servent *sp;
151 } 118 struct hostent *hp;
152 case AF_INET: 119 u_short port;
153 { 120 int family, i;
154 struct sockaddr_in *sin = (void *)sa; 121 char *addr, *p;
122 u_int32_t v4a;
123 int h_error;
124 char numserv[512];
125 char numaddr[512];
155 126
156 if (flags & NI_NUMERICHOST) 127 if (sa == NULL)
157 goto inet_noname; 128 return ENI_NOSOCKET;
158 129
159 if (sin->sin_addr.s_addr == 0) { 130#ifdef HAVE_SA_LEN /*XXX*/
160 strlcpy(host, "*", hostlen); 131 if (sa->sa_len != salen)
161 break; 132 return ENI_SALEN;
162 } 133#endif
134
135 family = sa->sa_family;
136 for (i = 0; afdl[i].a_af; i++)
137 if (afdl[i].a_af == family) {
138 afd = &afdl[i];
139 goto found;
140 }
141 return ENI_FAMILY;
142
143 found:
144 if (salen != afd->a_socklen)
145 return ENI_SALEN;
146
147 port = ((struct sockinet *)sa)->si_port; /* network byte order */
148 addr = (char *)sa + afd->a_off;
163 149
164 if ((rval = netdb_lookup_name(AF_INET, 150 if (serv == NULL || servlen == 0) {
165 &sin->sin_addr, sizeof(struct in_addr), 151 /*
166 host, hostlen, flags)) < 0) 152 * do nothing in this case.
167 goto ret; 153 * in case you are wondering if "&&" is more correct than
154 * "||" here: RFC2553 says that serv == NULL OR servlen == 0
155 * means that the caller does not want the result.
156 */
157 } else {
158 if (flags & NI_NUMERICSERV)
159 sp = NULL;
160 else {
161 sp = getservbyport(port,
162 (flags & NI_DGRAM) ? "udp" : "tcp");
163 }
164 if (sp) {
165 if (strlen(sp->s_name) > servlen)
166 return ENI_MEMORY;
167 strcpy(serv, sp->s_name);
168 } else {
169 snprintf(numserv, sizeof(numserv), "%d", ntohs(port));
170 if (strlen(numserv) > servlen)
171 return ENI_MEMORY;
172 strcpy(serv, numserv);
173 }
174 }
168 175
169 if (!rval) 176 switch (sa->sa_family) {
170 break; 177 case AF_INET:
171 inet_noname: 178 v4a = (u_int32_t)
172 if (flags & NI_NAMEREQD) { 179 ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
173 rval = EAI_NONAME; 180 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
174 goto ret; 181 flags |= NI_NUMERICHOST;
175 } 182 v4a >>= IN_CLASSA_NSHIFT;
176 if (!inet_ntop(AF_INET, &sin->sin_addr, host, hostlen)) { 183 if (v4a == 0 || v4a == IN_LOOPBACKNET)
177 rval = EAI_NONAME; 184 flags |= NI_NUMERICHOST;
178 goto ret; 185 break;
179 } 186#ifdef INET6
187 case AF_INET6:
188 {
189 struct sockaddr_in6 *sin6;
190 sin6 = (struct sockaddr_in6 *)sa;
191 switch (sin6->sin6_addr.s6_addr[0]) {
192 case 0x00:
193 if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
194 ;
195 else if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
196 ;
197 else
198 flags |= NI_NUMERICHOST;
180 break; 199 break;
181 } 200 default:
182 case AF_LOCAL: 201 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
183 if (!(flags & NI_NUMERICHOST)) { 202 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 } 203 }
196 204 else if (IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
197 strlcpy(host, "localhost", hostlen); 205 flags |= NI_NUMERICHOST;
198 break; 206 break;
199 default:
200 rval = EAI_FAMILY;
201 goto ret;
202 } 207 }
208 }
209 break;
210#endif
203 } 211 }
212 if (host == NULL || hostlen == 0) {
213 /*
214 * do nothing in this case.
215 * in case you are wondering if "&&" is more correct than
216 * "||" here: RFC2553 says that host == NULL OR hostlen == 0
217 * means that the caller does not want the result.
218 */
219 } else if (flags & NI_NUMERICHOST) {
220 /* NUMERICHOST and NAMEREQD conflicts with each other */
221 if (flags & NI_NAMEREQD)
222 return ENI_NOHOSTNAME;
223 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
224 == NULL)
225 return ENI_SYSTEM;
226 if (strlen(numaddr) > hostlen)
227 return ENI_MEMORY;
228 strcpy(host, numaddr);
229#if defined(INET6) && defined(NI_WITHSCOPEID)
230 if (afd->a_af == AF_INET6 &&
231 (IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)addr) ||
232 IN6_IS_ADDR_MULTICAST((struct in6_addr *)addr)) &&
233 ((struct sockaddr_in6 *)sa)->sin6_scope_id) {
234#ifndef ALWAYS_WITHSCOPE
235 if (flags & NI_WITHSCOPEID)
236#endif /* !ALWAYS_WITHSCOPE */
237 {
238 char *ep = strchr(host, '\0');
239 unsigned int ifindex =
240 ((struct sockaddr_in6 *)sa)->sin6_scope_id;
204 241
205 if (serv && servlen > 0) { 242 *ep = SCOPE_DELIMITER;
206 switch (sa->sa_family) { 243 if ((if_indextoname(ifindex, ep + 1)) == NULL)
207 case AF_INET: 244 /* XXX what should we do? */
208 { 245 strncpy(ep + 1, "???", 3);
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 } 246 }
224 snprintf(serv, servlen, "%d", ntohs(sin->sin_port)); 247 }
225 break; 248#endif /* INET6 */
226 } 249 } else {
227 case AF_INET6: 250#ifdef USE_GETIPNODEBY
228 { 251 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
229 struct sockaddr_in6 *sin6 = (void *)sa; 252#else
230 struct servent *s; 253 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
231 254 h_error = h_errno;
232 if ((flags & NI_NUMERICSERV) == 0) { 255#endif
233 256
234 s = getservbyport(sin6->sin6_port, 257 if (hp) {
235 (flags & NI_DGRAM) ? "udp" : "tcp"); 258 if (flags & NI_NOFQDN) {
236 if (s) { 259 p = strchr(hp->h_name, '.');
237 strlcpy(serv, s->s_name, servlen); 260 if (p) *p = '\0';
238 break;
239 }
240 if (sin6->sin6_port == 0) {
241 strlcpy(serv, "*", servlen);
242 break;
243 }
244 } 261 }
245 snprintf(serv, servlen, "%d", ntohs(sin6->sin6_port)); 262 if (strlen(hp->h_name) > hostlen) {
246 break; 263#ifdef USE_GETIPNODEBY
247 } 264 freehostent(hp);
248 case AF_LOCAL: 265#endif
249 { 266 return ENI_MEMORY;
250 struct sockaddr_un *sun = (void *)sa; 267 }
251 268 strcpy(host, hp->h_name);
252 strlcpy(serv, sun->sun_path, servlen); 269#ifdef USE_GETIPNODEBY
253 break; 270 freehostent(hp);
254 } 271#endif
272 } else {
273 if (flags & NI_NAMEREQD)
274 return ENI_NOHOSTNAME;
275 if (inet_ntop(afd->a_af, addr, numaddr, sizeof(numaddr))
276 == NULL)
277 return ENI_NOHOSTNAME;
278 if (strlen(numaddr) > hostlen)
279 return ENI_MEMORY;
280 strcpy(host, numaddr);
255 } 281 }
256 } 282 }
257 rval = 0; 283 return SUCCESS;
258
259ret:
260 if (rval == 1)
261 rval = EAI_FAIL;
262 errno = saved_errno;
263 return (rval);
264} 284}