diff options
author | itojun <> | 1999-12-30 08:54:20 +0000 |
---|---|---|
committer | itojun <> | 1999-12-30 08:54:20 +0000 |
commit | d9056b0e3240e176c6cfdfc13ac1cf384b0a04fd (patch) | |
tree | 356686aebb42f6ae34e6f80d29a8d44b44ff2879 | |
parent | c90229eaa6df37dd29c45c1aa632cb37ca8cfa06 (diff) | |
download | openbsd-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.c | 6 | ||||
-rw-r--r-- | src/lib/libc/net/getaddrinfo.c | 1434 | ||||
-rw-r--r-- | src/lib/libc/net/getnameinfo.c | 446 |
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" | |
59 | static 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 | ||
107 | static int translate = NO; | ||
108 | static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT; | ||
109 | #endif | ||
110 | |||
111 | static const char in_addrany[] = { 0, 0, 0, 0 }; | ||
112 | static const char in6_addrany[] = { | ||
113 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 | ||
61 | }; | 114 | }; |
62 | 115 | static const char in_loopback[] = { 127, 0, 0, 1 }; | |
63 | struct gaih_service { | 116 | static 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 | ||
68 | struct gaih_servtuple { | 120 | struct 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 | ||
75 | static struct gaih_servtuple nullserv = { | 127 | static 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 | ||
79 | struct gaih_addrtuple { | 149 | struct 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 | ||
86 | static struct gaih_typeproto { | 160 | static 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 | ||
97 | static int | 175 | #ifdef INET6 |
98 | netdb_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 | |||
182 | static int str_isnumber __P((const char *)); | ||
183 | static int explore_fqdn __P((const struct addrinfo *, const char *, | ||
184 | const char *, struct addrinfo **)); | ||
185 | static int explore_null __P((const struct addrinfo *, const char *, | ||
186 | const char *, struct addrinfo **)); | ||
187 | static int explore_numeric __P((const struct addrinfo *, const char *, | ||
188 | const char *, struct addrinfo **)); | ||
189 | static int explore_numeric_scope __P((const struct addrinfo *, const char *, | ||
190 | const char *, struct addrinfo **)); | ||
191 | static int get_name __P((const char *, const struct afd *, struct addrinfo **, | ||
192 | char *, const struct addrinfo *, const char *)); | ||
193 | static int get_canonname __P((const struct addrinfo *, | ||
194 | struct addrinfo *, const char *)); | ||
195 | static struct addrinfo *get_ai __P((const struct addrinfo *, | ||
196 | const struct afd *, const char *)); | ||
197 | static int get_portmatch __P((const struct addrinfo *, const char *)); | ||
198 | static int get_port __P((struct addrinfo *, const char *, int)); | ||
199 | static const struct afd *find_afd __P((int)); | ||
200 | |||
201 | #if 0 | ||
202 | static 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) \ | ||
224 | do { \ | ||
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) \ | ||
234 | do { \ | ||
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) \ | ||
242 | do { \ | ||
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) \ | ||
250 | do { \ | ||
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 | |||
261 | static int | ||
262 | str_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++) { | 274 | int |
126 | while (*pat) | 275 | getaddrinfo(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 | ||
157 | static int | 357 | /* |
158 | gaih_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 | ||
229 | static int | 377 | /* NULL hostname, or numeric hostname */ |
230 | gaih_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 | ||
249 | static int | 400 | if (error) |
250 | gaih_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; | 488 | static int |
489 | explore_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)); | 637 | free: |
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 | */ | ||
656 | static int | ||
657 | explore_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)); | 710 | free: |
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 | */ |
719 | static int | ||
720 | explore_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) | 798 | free: |
375 | goto build; | 799 | bad: |
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 | */ |
808 | static int | ||
809 | explore_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 | ||
383 | build: | 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) { | 879 | static int |
444 | ai->ai_canonname = (void *) ai->ai_addr + addrlen; | 880 | get_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 | |
463 | ret: | 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 | ||
483 | static struct gaih { | 948 | static int |
484 | int family; | 949 | get_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 | ||
496 | int | 963 | static struct addrinfo * |
497 | getaddrinfo(const char *name, const char *service, | 964 | get_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') | 990 | static int |
510 | service = NULL; | 991 | get_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 | |||
1000 | static int | ||
1001 | get_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 | |||
1070 | static const struct afd * | ||
1071 | find_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 | |
52 | static int | ||
53 | netdb_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 | |||
90 | int | ||
91 | getnameinfo(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)) { | 77 | static 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)); | 92 | struct 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) | 106 | int |
140 | break; | 107 | getnameinfo(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 | |||
259 | ret: | ||
260 | if (rval == 1) | ||
261 | rval = EAI_FAIL; | ||
262 | errno = saved_errno; | ||
263 | return (rval); | ||
264 | } | 284 | } |