|
1 /* |
|
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
|
3 * All rights reserved. |
|
4 * |
|
5 * Redistribution and use in source and binary forms, with or without |
|
6 * modification, are permitted provided that the following conditions |
|
7 * are met: |
|
8 * 1. Redistributions of source code must retain the above copyright |
|
9 * notice, this list of conditions and the following disclaimer. |
|
10 * 2. Redistributions in binary form must reproduce the above copyright |
|
11 * notice, this list of conditions and the following disclaimer in the |
|
12 * documentation and/or other materials provided with the distribution. |
|
13 * 3. Neither the name of the project nor the names of its contributors |
|
14 * may be used to endorse or promote products derived from this software |
|
15 * without specific prior written permission. |
|
16 * |
|
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
|
18 * GAI_ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
|
21 * FOR GAI_ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
24 * HOWEVER CAUSED AND ON GAI_ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN GAI_ANY WAY |
|
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
27 * SUCH DAMAGE. |
|
28 */ |
|
29 |
|
30 /* |
|
31 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator. |
|
32 * |
|
33 * Issues to be discussed: |
|
34 * - Thread safe-ness must be checked. |
|
35 * - Return values. There are nonstandard return values defined and used |
|
36 * in the source code. This is because RFC2133 is silent about which error |
|
37 * code must be returned for which situation. |
|
38 * - PF_UNSPEC case would be handled in getipnodebyname() with the AI_ALL flag. |
|
39 */ |
|
40 |
|
41 #if 0 |
|
42 #include <sys/types.h> |
|
43 #include <sys/param.h> |
|
44 #include <sys/sysctl.h> |
|
45 #include <sys/socket.h> |
|
46 #include <netinet/in.h> |
|
47 #include <arpa/inet.h> |
|
48 #include <arpa/nameser.h> |
|
49 #include <netdb.h> |
|
50 #include <resolv.h> |
|
51 #include <string.h> |
|
52 #include <stdlib.h> |
|
53 #include <stddef.h> |
|
54 #include <ctype.h> |
|
55 #include <unistd.h> |
|
56 |
|
57 #include "addrinfo.h" |
|
58 #endif |
|
59 |
|
60 #if defined(__KAME__) && defined(ENABLE_IPV6) |
|
61 # define FAITH |
|
62 #endif |
|
63 |
|
64 #define SUCCESS 0 |
|
65 #define GAI_ANY 0 |
|
66 #define YES 1 |
|
67 #define NO 0 |
|
68 |
|
69 #ifdef FAITH |
|
70 static int translate = NO; |
|
71 static struct in6_addr faith_prefix = IN6ADDR_GAI_ANY_INIT; |
|
72 #endif |
|
73 |
|
74 static const char in_addrany[] = { 0, 0, 0, 0 }; |
|
75 static const char in6_addrany[] = { |
|
76 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 |
|
77 }; |
|
78 static const char in_loopback[] = { 127, 0, 0, 1 }; |
|
79 static const char in6_loopback[] = { |
|
80 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 |
|
81 }; |
|
82 |
|
83 struct sockinet { |
|
84 u_char si_len; |
|
85 u_char si_family; |
|
86 u_short si_port; |
|
87 }; |
|
88 |
|
89 static struct gai_afd { |
|
90 int a_af; |
|
91 int a_addrlen; |
|
92 int a_socklen; |
|
93 int a_off; |
|
94 const char *a_addrany; |
|
95 const char *a_loopback; |
|
96 } gai_afdl [] = { |
|
97 #ifdef ENABLE_IPV6 |
|
98 #define N_INET6 0 |
|
99 {PF_INET6, sizeof(struct in6_addr), |
|
100 sizeof(struct sockaddr_in6), |
|
101 offsetof(struct sockaddr_in6, sin6_addr), |
|
102 in6_addrany, in6_loopback}, |
|
103 #define N_INET 1 |
|
104 #else |
|
105 #define N_INET 0 |
|
106 #endif |
|
107 {PF_INET, sizeof(struct in_addr), |
|
108 sizeof(struct sockaddr_in), |
|
109 offsetof(struct sockaddr_in, sin_addr), |
|
110 in_addrany, in_loopback}, |
|
111 {0, 0, 0, 0, NULL, NULL}, |
|
112 }; |
|
113 |
|
114 #ifdef ENABLE_IPV6 |
|
115 #define PTON_MAX 16 |
|
116 #else |
|
117 #define PTON_MAX 4 |
|
118 #endif |
|
119 |
|
120 #ifndef IN_MULTICAST |
|
121 #define IN_MULTICAST(i) (((i) & 0xf0000000U) == 0xe0000000U) |
|
122 #endif |
|
123 |
|
124 #ifndef IN_EXPERIMENTAL |
|
125 #define IN_EXPERIMENTAL(i) (((i) & 0xe0000000U) == 0xe0000000U) |
|
126 #endif |
|
127 |
|
128 #ifndef IN_LOOPBACKNET |
|
129 #define IN_LOOPBACKNET 127 |
|
130 #endif |
|
131 |
|
132 static int get_name Py_PROTO((const char *, struct gai_afd *, |
|
133 struct addrinfo **, char *, struct addrinfo *, |
|
134 int)); |
|
135 static int get_addr Py_PROTO((const char *, int, struct addrinfo **, |
|
136 struct addrinfo *, int)); |
|
137 static int str_isnumber Py_PROTO((const char *)); |
|
138 |
|
139 static char *ai_errlist[] = { |
|
140 "success.", |
|
141 "address family for hostname not supported.", /* EAI_ADDRFAMILY */ |
|
142 "temporary failure in name resolution.", /* EAI_AGAIN */ |
|
143 "invalid value for ai_flags.", /* EAI_BADFLAGS */ |
|
144 "non-recoverable failure in name resolution.", /* EAI_FAIL */ |
|
145 "ai_family not supported.", /* EAI_FAMILY */ |
|
146 "memory allocation failure.", /* EAI_MEMORY */ |
|
147 "no address associated with hostname.", /* EAI_NODATA */ |
|
148 "hostname nor servname provided, or not known.",/* EAI_NONAME */ |
|
149 "servname not supported for ai_socktype.", /* EAI_SERVICE */ |
|
150 "ai_socktype not supported.", /* EAI_SOCKTYPE */ |
|
151 "system error returned in errno.", /* EAI_SYSTEM */ |
|
152 "invalid value for hints.", /* EAI_BADHINTS */ |
|
153 "resolved protocol is unknown.", /* EAI_PROTOCOL */ |
|
154 "unknown error.", /* EAI_MAX */ |
|
155 }; |
|
156 |
|
157 #define GET_CANONNAME(ai, str) \ |
|
158 if (pai->ai_flags & AI_CANONNAME) {\ |
|
159 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\ |
|
160 strcpy((ai)->ai_canonname, (str));\ |
|
161 } else {\ |
|
162 error = EAI_MEMORY;\ |
|
163 goto free;\ |
|
164 }\ |
|
165 } |
|
166 |
|
167 #ifdef HAVE_SOCKADDR_SA_LEN |
|
168 #define GET_AI(ai, gai_afd, addr, port) {\ |
|
169 char *p;\ |
|
170 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ |
|
171 ((gai_afd)->a_socklen)))\ |
|
172 == NULL) goto free;\ |
|
173 memcpy(ai, pai, sizeof(struct addrinfo));\ |
|
174 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ |
|
175 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\ |
|
176 (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (gai_afd)->a_socklen;\ |
|
177 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\ |
|
178 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ |
|
179 p = (char *)((ai)->ai_addr);\ |
|
180 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\ |
|
181 } |
|
182 #else |
|
183 #define GET_AI(ai, gai_afd, addr, port) {\ |
|
184 char *p;\ |
|
185 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\ |
|
186 ((gai_afd)->a_socklen)))\ |
|
187 == NULL) goto free;\ |
|
188 memcpy(ai, pai, sizeof(struct addrinfo));\ |
|
189 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\ |
|
190 memset((ai)->ai_addr, 0, (gai_afd)->a_socklen);\ |
|
191 (ai)->ai_addrlen = (gai_afd)->a_socklen;\ |
|
192 (ai)->ai_addr->sa_family = (ai)->ai_family = (gai_afd)->a_af;\ |
|
193 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\ |
|
194 p = (char *)((ai)->ai_addr);\ |
|
195 memcpy(p + (gai_afd)->a_off, (addr), (gai_afd)->a_addrlen);\ |
|
196 } |
|
197 #endif |
|
198 |
|
199 #define ERR(err) { error = (err); goto bad; } |
|
200 |
|
201 char * |
|
202 gai_strerror(int ecode) |
|
203 { |
|
204 if (ecode < 0 || ecode > EAI_MAX) |
|
205 ecode = EAI_MAX; |
|
206 return ai_errlist[ecode]; |
|
207 } |
|
208 |
|
209 void |
|
210 freeaddrinfo(struct addrinfo *ai) |
|
211 { |
|
212 struct addrinfo *next; |
|
213 |
|
214 do { |
|
215 next = ai->ai_next; |
|
216 if (ai->ai_canonname) |
|
217 free(ai->ai_canonname); |
|
218 /* no need to free(ai->ai_addr) */ |
|
219 free(ai); |
|
220 } while ((ai = next) != NULL); |
|
221 } |
|
222 |
|
223 static int |
|
224 str_isnumber(const char *p) |
|
225 { |
|
226 unsigned char *q = (unsigned char *)p; |
|
227 while (*q) { |
|
228 if (! isdigit(*q)) |
|
229 return NO; |
|
230 q++; |
|
231 } |
|
232 return YES; |
|
233 } |
|
234 |
|
235 int |
|
236 getaddrinfo(const char*hostname, const char*servname, |
|
237 const struct addrinfo *hints, struct addrinfo **res) |
|
238 { |
|
239 struct addrinfo sentinel; |
|
240 struct addrinfo *top = NULL; |
|
241 struct addrinfo *cur; |
|
242 int i, error = 0; |
|
243 char pton[PTON_MAX]; |
|
244 struct addrinfo ai; |
|
245 struct addrinfo *pai; |
|
246 u_short port; |
|
247 |
|
248 #ifdef FAITH |
|
249 static int firsttime = 1; |
|
250 |
|
251 if (firsttime) { |
|
252 /* translator hack */ |
|
253 { |
|
254 char *q = getenv("GAI"); |
|
255 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1) |
|
256 translate = YES; |
|
257 } |
|
258 firsttime = 0; |
|
259 } |
|
260 #endif |
|
261 |
|
262 /* initialize file static vars */ |
|
263 sentinel.ai_next = NULL; |
|
264 cur = &sentinel; |
|
265 pai = &ai; |
|
266 pai->ai_flags = 0; |
|
267 pai->ai_family = PF_UNSPEC; |
|
268 pai->ai_socktype = GAI_ANY; |
|
269 pai->ai_protocol = GAI_ANY; |
|
270 pai->ai_addrlen = 0; |
|
271 pai->ai_canonname = NULL; |
|
272 pai->ai_addr = NULL; |
|
273 pai->ai_next = NULL; |
|
274 port = GAI_ANY; |
|
275 |
|
276 if (hostname == NULL && servname == NULL) |
|
277 return EAI_NONAME; |
|
278 if (hints) { |
|
279 /* error check for hints */ |
|
280 if (hints->ai_addrlen || hints->ai_canonname || |
|
281 hints->ai_addr || hints->ai_next) |
|
282 ERR(EAI_BADHINTS); /* xxx */ |
|
283 if (hints->ai_flags & ~AI_MASK) |
|
284 ERR(EAI_BADFLAGS); |
|
285 switch (hints->ai_family) { |
|
286 case PF_UNSPEC: |
|
287 case PF_INET: |
|
288 #ifdef ENABLE_IPV6 |
|
289 case PF_INET6: |
|
290 #endif |
|
291 break; |
|
292 default: |
|
293 ERR(EAI_FAMILY); |
|
294 } |
|
295 memcpy(pai, hints, sizeof(*pai)); |
|
296 switch (pai->ai_socktype) { |
|
297 case GAI_ANY: |
|
298 switch (pai->ai_protocol) { |
|
299 case GAI_ANY: |
|
300 break; |
|
301 case IPPROTO_UDP: |
|
302 pai->ai_socktype = SOCK_DGRAM; |
|
303 break; |
|
304 case IPPROTO_TCP: |
|
305 pai->ai_socktype = SOCK_STREAM; |
|
306 break; |
|
307 default: |
|
308 pai->ai_socktype = SOCK_RAW; |
|
309 break; |
|
310 } |
|
311 break; |
|
312 case SOCK_RAW: |
|
313 break; |
|
314 case SOCK_DGRAM: |
|
315 if (pai->ai_protocol != IPPROTO_UDP && |
|
316 pai->ai_protocol != GAI_ANY) |
|
317 ERR(EAI_BADHINTS); /*xxx*/ |
|
318 pai->ai_protocol = IPPROTO_UDP; |
|
319 break; |
|
320 case SOCK_STREAM: |
|
321 if (pai->ai_protocol != IPPROTO_TCP && |
|
322 pai->ai_protocol != GAI_ANY) |
|
323 ERR(EAI_BADHINTS); /*xxx*/ |
|
324 pai->ai_protocol = IPPROTO_TCP; |
|
325 break; |
|
326 default: |
|
327 ERR(EAI_SOCKTYPE); |
|
328 /* unreachable */ |
|
329 } |
|
330 } |
|
331 |
|
332 /* |
|
333 * service port |
|
334 */ |
|
335 if (servname) { |
|
336 if (str_isnumber(servname)) { |
|
337 if (pai->ai_socktype == GAI_ANY) { |
|
338 /* caller accept *GAI_ANY* socktype */ |
|
339 pai->ai_socktype = SOCK_DGRAM; |
|
340 pai->ai_protocol = IPPROTO_UDP; |
|
341 } |
|
342 port = htons((u_short)atoi(servname)); |
|
343 } else { |
|
344 struct servent *sp; |
|
345 char *proto; |
|
346 |
|
347 proto = NULL; |
|
348 switch (pai->ai_socktype) { |
|
349 case GAI_ANY: |
|
350 proto = NULL; |
|
351 break; |
|
352 case SOCK_DGRAM: |
|
353 proto = "udp"; |
|
354 break; |
|
355 case SOCK_STREAM: |
|
356 proto = "tcp"; |
|
357 break; |
|
358 default: |
|
359 fprintf(stderr, "panic!\n"); |
|
360 break; |
|
361 } |
|
362 if ((sp = getservbyname(servname, proto)) == NULL) |
|
363 ERR(EAI_SERVICE); |
|
364 port = sp->s_port; |
|
365 if (pai->ai_socktype == GAI_ANY) { |
|
366 if (strcmp(sp->s_proto, "udp") == 0) { |
|
367 pai->ai_socktype = SOCK_DGRAM; |
|
368 pai->ai_protocol = IPPROTO_UDP; |
|
369 } else if (strcmp(sp->s_proto, "tcp") == 0) { |
|
370 pai->ai_socktype = SOCK_STREAM; |
|
371 pai->ai_protocol = IPPROTO_TCP; |
|
372 } else |
|
373 ERR(EAI_PROTOCOL); /*xxx*/ |
|
374 } |
|
375 } |
|
376 } |
|
377 |
|
378 /* |
|
379 * hostname == NULL. |
|
380 * passive socket -> anyaddr (0.0.0.0 or ::) |
|
381 * non-passive socket -> localhost (127.0.0.1 or ::1) |
|
382 */ |
|
383 if (hostname == NULL) { |
|
384 struct gai_afd *gai_afd; |
|
385 |
|
386 for (gai_afd = &gai_afdl[0]; gai_afd->a_af; gai_afd++) { |
|
387 if (!(pai->ai_family == PF_UNSPEC |
|
388 || pai->ai_family == gai_afd->a_af)) { |
|
389 continue; |
|
390 } |
|
391 |
|
392 if (pai->ai_flags & AI_PASSIVE) { |
|
393 GET_AI(cur->ai_next, gai_afd, gai_afd->a_addrany, port); |
|
394 /* xxx meaningless? |
|
395 * GET_CANONNAME(cur->ai_next, "anyaddr"); |
|
396 */ |
|
397 } else { |
|
398 GET_AI(cur->ai_next, gai_afd, gai_afd->a_loopback, |
|
399 port); |
|
400 /* xxx meaningless? |
|
401 * GET_CANONNAME(cur->ai_next, "localhost"); |
|
402 */ |
|
403 } |
|
404 cur = cur->ai_next; |
|
405 } |
|
406 top = sentinel.ai_next; |
|
407 if (top) |
|
408 goto good; |
|
409 else |
|
410 ERR(EAI_FAMILY); |
|
411 } |
|
412 |
|
413 /* hostname as numeric name */ |
|
414 for (i = 0; gai_afdl[i].a_af; i++) { |
|
415 if (inet_pton(gai_afdl[i].a_af, hostname, pton)) { |
|
416 u_long v4a; |
|
417 #ifdef ENABLE_IPV6 |
|
418 u_char pfx; |
|
419 #endif |
|
420 |
|
421 switch (gai_afdl[i].a_af) { |
|
422 case AF_INET: |
|
423 v4a = ((struct in_addr *)pton)->s_addr; |
|
424 v4a = ntohl(v4a); |
|
425 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a)) |
|
426 pai->ai_flags &= ~AI_CANONNAME; |
|
427 v4a >>= IN_CLASSA_NSHIFT; |
|
428 if (v4a == 0 || v4a == IN_LOOPBACKNET) |
|
429 pai->ai_flags &= ~AI_CANONNAME; |
|
430 break; |
|
431 #ifdef ENABLE_IPV6 |
|
432 case AF_INET6: |
|
433 pfx = ((struct in6_addr *)pton)->s6_addr8[0]; |
|
434 if (pfx == 0 || pfx == 0xfe || pfx == 0xff) |
|
435 pai->ai_flags &= ~AI_CANONNAME; |
|
436 break; |
|
437 #endif |
|
438 } |
|
439 |
|
440 if (pai->ai_family == gai_afdl[i].a_af || |
|
441 pai->ai_family == PF_UNSPEC) { |
|
442 if (! (pai->ai_flags & AI_CANONNAME)) { |
|
443 GET_AI(top, &gai_afdl[i], pton, port); |
|
444 goto good; |
|
445 } |
|
446 /* |
|
447 * if AI_CANONNAME and if reverse lookup |
|
448 * fail, return ai anyway to pacify |
|
449 * calling application. |
|
450 * |
|
451 * XXX getaddrinfo() is a name->address |
|
452 * translation function, and it looks strange |
|
453 * that we do addr->name translation here. |
|
454 */ |
|
455 get_name(pton, &gai_afdl[i], &top, pton, pai, port); |
|
456 goto good; |
|
457 } else |
|
458 ERR(EAI_FAMILY); /*xxx*/ |
|
459 } |
|
460 } |
|
461 |
|
462 if (pai->ai_flags & AI_NUMERICHOST) |
|
463 ERR(EAI_NONAME); |
|
464 |
|
465 /* hostname as alphabetical name */ |
|
466 error = get_addr(hostname, pai->ai_family, &top, pai, port); |
|
467 if (error == 0) { |
|
468 if (top) { |
|
469 good: |
|
470 *res = top; |
|
471 return SUCCESS; |
|
472 } else |
|
473 error = EAI_FAIL; |
|
474 } |
|
475 free: |
|
476 if (top) |
|
477 freeaddrinfo(top); |
|
478 bad: |
|
479 *res = NULL; |
|
480 return error; |
|
481 } |
|
482 |
|
483 static int |
|
484 get_name(addr, gai_afd, res, numaddr, pai, port0) |
|
485 const char *addr; |
|
486 struct gai_afd *gai_afd; |
|
487 struct addrinfo **res; |
|
488 char *numaddr; |
|
489 struct addrinfo *pai; |
|
490 int port0; |
|
491 { |
|
492 u_short port = port0 & 0xffff; |
|
493 struct hostent *hp; |
|
494 struct addrinfo *cur; |
|
495 int error = 0; |
|
496 #ifdef ENABLE_IPV6 |
|
497 int h_error; |
|
498 #endif |
|
499 |
|
500 #ifdef ENABLE_IPV6 |
|
501 hp = getipnodebyaddr(addr, gai_afd->a_addrlen, gai_afd->a_af, &h_error); |
|
502 #else |
|
503 hp = gethostbyaddr(addr, gai_afd->a_addrlen, AF_INET); |
|
504 #endif |
|
505 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) { |
|
506 GET_AI(cur, gai_afd, hp->h_addr_list[0], port); |
|
507 GET_CANONNAME(cur, hp->h_name); |
|
508 } else |
|
509 GET_AI(cur, gai_afd, numaddr, port); |
|
510 |
|
511 #ifdef ENABLE_IPV6 |
|
512 if (hp) |
|
513 freehostent(hp); |
|
514 #endif |
|
515 *res = cur; |
|
516 return SUCCESS; |
|
517 free: |
|
518 if (cur) |
|
519 freeaddrinfo(cur); |
|
520 #ifdef ENABLE_IPV6 |
|
521 if (hp) |
|
522 freehostent(hp); |
|
523 #endif |
|
524 /* bad: */ |
|
525 *res = NULL; |
|
526 return error; |
|
527 } |
|
528 |
|
529 static int |
|
530 get_addr(hostname, af, res, pai, port0) |
|
531 const char *hostname; |
|
532 int af; |
|
533 struct addrinfo **res; |
|
534 struct addrinfo *pai; |
|
535 int port0; |
|
536 { |
|
537 u_short port = port0 & 0xffff; |
|
538 struct addrinfo sentinel; |
|
539 struct hostent *hp; |
|
540 struct addrinfo *top, *cur; |
|
541 struct gai_afd *gai_afd; |
|
542 int i, error = 0, h_error; |
|
543 char *ap; |
|
544 |
|
545 top = NULL; |
|
546 sentinel.ai_next = NULL; |
|
547 cur = &sentinel; |
|
548 #ifdef ENABLE_IPV6 |
|
549 if (af == AF_UNSPEC) { |
|
550 hp = getipnodebyname(hostname, AF_INET6, |
|
551 AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error); |
|
552 } else |
|
553 hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error); |
|
554 #else |
|
555 hp = gethostbyname(hostname); |
|
556 h_error = h_errno; |
|
557 #endif |
|
558 if (hp == NULL) { |
|
559 switch (h_error) { |
|
560 case HOST_NOT_FOUND: |
|
561 case NO_DATA: |
|
562 error = EAI_NODATA; |
|
563 break; |
|
564 case TRY_AGAIN: |
|
565 error = EAI_AGAIN; |
|
566 break; |
|
567 case NO_RECOVERY: |
|
568 default: |
|
569 error = EAI_FAIL; |
|
570 break; |
|
571 } |
|
572 goto free; |
|
573 } |
|
574 |
|
575 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) || |
|
576 (hp->h_addr_list[0] == NULL)) { |
|
577 error = EAI_FAIL; |
|
578 goto free; |
|
579 } |
|
580 |
|
581 for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) { |
|
582 switch (af) { |
|
583 #ifdef ENABLE_IPV6 |
|
584 case AF_INET6: |
|
585 gai_afd = &gai_afdl[N_INET6]; |
|
586 break; |
|
587 #endif |
|
588 #ifndef ENABLE_IPV6 |
|
589 default: /* AF_UNSPEC */ |
|
590 #endif |
|
591 case AF_INET: |
|
592 gai_afd = &gai_afdl[N_INET]; |
|
593 break; |
|
594 #ifdef ENABLE_IPV6 |
|
595 default: /* AF_UNSPEC */ |
|
596 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) { |
|
597 ap += sizeof(struct in6_addr) - |
|
598 sizeof(struct in_addr); |
|
599 gai_afd = &gai_afdl[N_INET]; |
|
600 } else |
|
601 gai_afd = &gai_afdl[N_INET6]; |
|
602 break; |
|
603 #endif |
|
604 } |
|
605 #ifdef FAITH |
|
606 if (translate && gai_afd->a_af == AF_INET) { |
|
607 struct in6_addr *in6; |
|
608 |
|
609 GET_AI(cur->ai_next, &gai_afdl[N_INET6], ap, port); |
|
610 in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr; |
|
611 memcpy(&in6->s6_addr32[0], &faith_prefix, |
|
612 sizeof(struct in6_addr) - sizeof(struct in_addr)); |
|
613 memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr)); |
|
614 } else |
|
615 #endif /* FAITH */ |
|
616 GET_AI(cur->ai_next, gai_afd, ap, port); |
|
617 if (cur == &sentinel) { |
|
618 top = cur->ai_next; |
|
619 GET_CANONNAME(top, hp->h_name); |
|
620 } |
|
621 cur = cur->ai_next; |
|
622 } |
|
623 #ifdef ENABLE_IPV6 |
|
624 freehostent(hp); |
|
625 #endif |
|
626 *res = top; |
|
627 return SUCCESS; |
|
628 free: |
|
629 if (top) |
|
630 freeaddrinfo(top); |
|
631 #ifdef ENABLE_IPV6 |
|
632 if (hp) |
|
633 freehostent(hp); |
|
634 #endif |
|
635 /* bad: */ |
|
636 *res = NULL; |
|
637 return error; |
|
638 } |