getaddrinfo.c revision 1.1 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 * 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 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 ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 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 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/sysctl.h>
44 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
47 #include <arpa/nameser.h>
48 #include <netdb.h>
49 #include <resolv.h>
50 #include <string.h>
51 #include <stdlib.h>
52 #include <stddef.h>
53 #include <ctype.h>
54 #include <unistd.h>
55
56 #if 0 /*quickhack*/
57 #if defined(__KAME__) && defined(INET6)
58 # define FAITH
59 #endif
60 #endif
61
62 #define SUCCESS 0
63 #define ANY 0
64 #define YES 1
65 #define NO 0
66
67 #ifdef FAITH
68 static int translate = NO;
69 static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
70 #endif
71
72 static const char in_addrany[] = { 0, 0, 0, 0 };
73 static const char in6_addrany[] = {
74 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
75 };
76 static const char in_loopback[] = { 127, 0, 0, 1 };
77 static const char in6_loopback[] = {
78 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
79 };
80
81 struct sockinet {
82 u_char si_len;
83 u_char si_family;
84 u_short si_port;
85 };
86
87 static struct afd {
88 int a_af;
89 int a_addrlen;
90 int a_socklen;
91 int a_off;
92 const char *a_addrany;
93 const char *a_loopback;
94 } afdl [] = {
95 #ifdef INET6
96 #define N_INET6 0
97 {PF_INET6, sizeof(struct in6_addr),
98 sizeof(struct sockaddr_in6),
99 offsetof(struct sockaddr_in6, sin6_addr),
100 in6_addrany, in6_loopback},
101 #define N_INET 1
102 #else
103 #define N_INET 0
104 #endif
105 {PF_INET, sizeof(struct in_addr),
106 sizeof(struct sockaddr_in),
107 offsetof(struct sockaddr_in, sin_addr),
108 in_addrany, in_loopback},
109 {0, 0, 0, 0, NULL, NULL},
110 };
111
112 #ifdef INET6
113 #define PTON_MAX 16
114 #else
115 #define PTON_MAX 4
116 #endif
117
118
119 static int get_name __P((const char *, struct afd *,
120 struct addrinfo **, char *, struct addrinfo *,
121 int));
122 static int get_addr __P((const char *, int, struct addrinfo **,
123 struct addrinfo *, int));
124 static int get_addr0 __P((const char *, int, struct addrinfo **,
125 struct addrinfo *, int));
126 static int str_isnumber __P((const char *));
127
128 static char *ai_errlist[] = {
129 "success.",
130 "address family for hostname not supported.", /* EAI_ADDRFAMILY */
131 "temporary failure in name resolution.", /* EAI_AGAIN */
132 "invalid value for ai_flags.", /* EAI_BADFLAGS */
133 "non-recoverable failure in name resolution.", /* EAI_FAIL */
134 "ai_family not supported.", /* EAI_FAMILY */
135 "memory allocation failure.", /* EAI_MEMORY */
136 "no address associated with hostname.", /* EAI_NODATA */
137 "hostname nor servname provided, or not known.",/* EAI_NONAME */
138 "servname not supported for ai_socktype.", /* EAI_SERVICE */
139 "ai_socktype not supported.", /* EAI_SOCKTYPE */
140 "system error returned in errno.", /* EAI_SYSTEM */
141 "invalid value for hints.", /* EAI_BADHINTS */
142 "resolved protocol is unknown.", /* EAI_PROTOCOL */
143 "unknown error.", /* EAI_MAX */
144 };
145
146 #define GET_CANONNAME(ai, str) \
147 if (pai->ai_flags & AI_CANONNAME) {\
148 if (((ai)->ai_canonname = (char *)malloc(strlen(str) + 1)) != NULL) {\
149 strcpy((ai)->ai_canonname, (str));\
150 } else {\
151 error = EAI_MEMORY;\
152 goto free;\
153 }\
154 }
155
156 #define GET_AI(ai, afd, addr, port) {\
157 char *p;\
158 if (((ai) = (struct addrinfo *)malloc(sizeof(struct addrinfo) +\
159 ((afd)->a_socklen)))\
160 == NULL) {\
161 error = EAI_MEMORY;\
162 goto free;\
163 }\
164 memcpy(ai, pai, sizeof(struct addrinfo));\
165 (ai)->ai_addr = (struct sockaddr *)((ai) + 1);\
166 memset((ai)->ai_addr, 0, (afd)->a_socklen);\
167 (ai)->ai_addr->sa_len = (ai)->ai_addrlen = (afd)->a_socklen;\
168 (ai)->ai_addr->sa_family = (ai)->ai_family = (afd)->a_af;\
169 ((struct sockinet *)(ai)->ai_addr)->si_port = port;\
170 p = (char *)((ai)->ai_addr);\
171 memcpy(p + (afd)->a_off, (addr), (afd)->a_addrlen);\
172 }
173
174 #define ERR(err) { error = (err); goto bad; }
175
176 char *
177 gai_strerror(ecode)
178 int ecode;
179 {
180 if (ecode < 0 || ecode > EAI_MAX)
181 ecode = EAI_MAX;
182 return ai_errlist[ecode];
183 }
184
185 void
186 freeaddrinfo(ai)
187 struct addrinfo *ai;
188 {
189 struct addrinfo *next;
190
191 do {
192 next = ai->ai_next;
193 if (ai->ai_canonname)
194 free(ai->ai_canonname);
195 /* no need to free(ai->ai_addr) */
196 free(ai);
197 } while ((ai = next) != NULL);
198 }
199
200 static int
201 str_isnumber(p)
202 const char *p;
203 {
204 char *q = (char *)p;
205 while (*q) {
206 if (! isdigit(*q))
207 return NO;
208 q++;
209 }
210 return YES;
211 }
212
213 int
214 getaddrinfo(hostname, servname, hints, res)
215 const char *hostname, *servname;
216 const struct addrinfo *hints;
217 struct addrinfo **res;
218 {
219 struct addrinfo sentinel;
220 struct addrinfo *top = NULL;
221 struct addrinfo *cur;
222 int i, error = 0;
223 char pton[PTON_MAX];
224 struct addrinfo ai;
225 struct addrinfo *pai;
226 u_short port;
227
228 #ifdef FAITH
229 static int firsttime = 1;
230
231 if (firsttime) {
232 /* translator hack */
233 {
234 char *q = getenv("GAI");
235 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
236 translate = YES;
237 }
238 firsttime = 0;
239 }
240 #endif
241
242 /* initialize file static vars */
243 sentinel.ai_next = NULL;
244 cur = &sentinel;
245 pai = &ai;
246 pai->ai_flags = 0;
247 pai->ai_family = PF_UNSPEC;
248 pai->ai_socktype = ANY;
249 pai->ai_protocol = ANY;
250 pai->ai_addrlen = 0;
251 pai->ai_canonname = NULL;
252 pai->ai_addr = NULL;
253 pai->ai_next = NULL;
254 port = ANY;
255
256 if (hostname == NULL && servname == NULL)
257 return EAI_NONAME;
258 if (hints) {
259 /* error check for hints */
260 if (hints->ai_addrlen || hints->ai_canonname ||
261 hints->ai_addr || hints->ai_next)
262 ERR(EAI_BADHINTS); /* xxx */
263 if (hints->ai_flags & ~AI_MASK)
264 ERR(EAI_BADFLAGS);
265 switch (hints->ai_family) {
266 case PF_UNSPEC:
267 case PF_INET:
268 #ifdef INET6
269 case PF_INET6:
270 #endif
271 break;
272 default:
273 ERR(EAI_FAMILY);
274 }
275 memcpy(pai, hints, sizeof(*pai));
276 switch (pai->ai_socktype) {
277 case ANY:
278 switch (pai->ai_protocol) {
279 case ANY:
280 break;
281 case IPPROTO_UDP:
282 pai->ai_socktype = SOCK_DGRAM;
283 break;
284 case IPPROTO_TCP:
285 pai->ai_socktype = SOCK_STREAM;
286 break;
287 default:
288 pai->ai_socktype = SOCK_RAW;
289 break;
290 }
291 break;
292 case SOCK_RAW:
293 break;
294 case SOCK_DGRAM:
295 if (pai->ai_protocol != IPPROTO_UDP &&
296 pai->ai_protocol != ANY)
297 ERR(EAI_BADHINTS); /*xxx*/
298 pai->ai_protocol = IPPROTO_UDP;
299 break;
300 case SOCK_STREAM:
301 if (pai->ai_protocol != IPPROTO_TCP &&
302 pai->ai_protocol != ANY)
303 ERR(EAI_BADHINTS); /*xxx*/
304 pai->ai_protocol = IPPROTO_TCP;
305 break;
306 default:
307 ERR(EAI_SOCKTYPE);
308 break;
309 }
310 }
311
312 /*
313 * service port
314 */
315 if (servname) {
316 if (str_isnumber(servname)) {
317 if (pai->ai_socktype == ANY) {
318 /* caller accept *ANY* socktype */
319 pai->ai_socktype = SOCK_DGRAM;
320 pai->ai_protocol = IPPROTO_UDP;
321 }
322 port = htons(atoi(servname));
323 } else {
324 struct servent *sp;
325 char *proto;
326
327 proto = NULL;
328 switch (pai->ai_socktype) {
329 case ANY:
330 proto = NULL;
331 break;
332 case SOCK_DGRAM:
333 proto = "udp";
334 break;
335 case SOCK_STREAM:
336 proto = "tcp";
337 break;
338 default:
339 fprintf(stderr, "panic!\n");
340 break;
341 }
342 if ((sp = getservbyname(servname, proto)) == NULL)
343 ERR(EAI_SERVICE);
344 port = sp->s_port;
345 if (pai->ai_socktype == ANY) {
346 if (strcmp(sp->s_proto, "udp") == 0) {
347 pai->ai_socktype = SOCK_DGRAM;
348 pai->ai_protocol = IPPROTO_UDP;
349 } else if (strcmp(sp->s_proto, "tcp") == 0) {
350 pai->ai_socktype = SOCK_STREAM;
351 pai->ai_protocol = IPPROTO_TCP;
352 } else
353 ERR(EAI_PROTOCOL); /*xxx*/
354 }
355 }
356 }
357
358 /*
359 * hostname == NULL.
360 * passive socket -> anyaddr (0.0.0.0 or ::)
361 * non-passive socket -> localhost (127.0.0.1 or ::1)
362 */
363 if (hostname == NULL) {
364 struct afd *afd;
365 int s;
366
367 for (afd = &afdl[0]; afd->a_af; afd++) {
368 if (!(pai->ai_family == PF_UNSPEC
369 || pai->ai_family == afd->a_af)) {
370 continue;
371 }
372
373 /*
374 * filter out AFs that are not supported by the kernel
375 * XXX errno?
376 */
377 s = socket(afd->a_af, SOCK_DGRAM, 0);
378 if (s < 0)
379 continue;
380 close(s);
381
382 if (pai->ai_flags & AI_PASSIVE) {
383 GET_AI(cur->ai_next, afd, afd->a_addrany, port);
384 /* xxx meaningless?
385 * GET_CANONNAME(cur->ai_next, "anyaddr");
386 */
387 } else {
388 GET_AI(cur->ai_next, afd, afd->a_loopback,
389 port);
390 /* xxx meaningless?
391 * GET_CANONNAME(cur->ai_next, "localhost");
392 */
393 }
394 cur = cur->ai_next;
395 }
396 top = sentinel.ai_next;
397 if (top)
398 goto good;
399 else
400 ERR(EAI_FAMILY);
401 }
402
403 /* hostname as numeric name */
404 for (i = 0; afdl[i].a_af; i++) {
405 if (inet_pton(afdl[i].a_af, hostname, pton)) {
406 u_long v4a;
407 u_char pfx;
408
409 switch (afdl[i].a_af) {
410 case AF_INET:
411 v4a = ntohl(((struct in_addr *)pton)->s_addr);
412 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
413 pai->ai_flags &= ~AI_CANONNAME;
414 v4a >>= IN_CLASSA_NSHIFT;
415 if (v4a == 0 || v4a == IN_LOOPBACKNET)
416 pai->ai_flags &= ~AI_CANONNAME;
417 break;
418 #ifdef INET6
419 case AF_INET6:
420 pfx = ((struct in6_addr *)pton)->s6_addr8[0];
421 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
422 pai->ai_flags &= ~AI_CANONNAME;
423 break;
424 #endif
425 }
426
427 if (pai->ai_family == afdl[i].a_af ||
428 pai->ai_family == PF_UNSPEC) {
429 if (! (pai->ai_flags & AI_CANONNAME)) {
430 GET_AI(top, &afdl[i], pton, port);
431 goto good;
432 }
433 /*
434 * if AI_CANONNAME and if reverse lookup
435 * fail, return ai anyway to pacify
436 * calling application.
437 *
438 * XXX getaddrinfo() is a name->address
439 * translation function, and it looks strange
440 * that we do addr->name translation here.
441 */
442 get_name(pton, &afdl[i], &top, pton, pai, port);
443 goto good;
444 } else
445 ERR(EAI_FAMILY); /*xxx*/
446 }
447 }
448
449 if (pai->ai_flags & AI_NUMERICHOST)
450 ERR(EAI_NONAME);
451
452 /* hostname as alphabetical name */
453 error = get_addr(hostname, pai->ai_family, &top, pai, port);
454 if (error == 0) {
455 if (top) {
456 good:
457 *res = top;
458 return SUCCESS;
459 } else
460 error = EAI_FAIL;
461 }
462 free:
463 if (top)
464 freeaddrinfo(top);
465 bad:
466 *res = NULL;
467 return error;
468 }
469
470 static int
471 get_name(addr, afd, res, numaddr, pai, port0)
472 const char *addr;
473 struct afd *afd;
474 struct addrinfo **res;
475 char *numaddr;
476 struct addrinfo *pai;
477 int port0;
478 {
479 u_short port = port0 & 0xffff;
480 struct hostent *hp;
481 struct addrinfo *cur;
482 int error = 0;
483 #ifdef USE_GETIPNODEBY
484 int h_error;
485
486 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
487 #else
488 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
489 #endif
490 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
491 GET_AI(cur, afd, hp->h_addr_list[0], port);
492 GET_CANONNAME(cur, hp->h_name);
493 } else
494 GET_AI(cur, afd, numaddr, port);
495
496 #ifdef USE_GETIPNODEBY
497 if (hp)
498 freehostent(hp);
499 #endif
500 *res = cur;
501 return SUCCESS;
502 free:
503 if (cur)
504 freeaddrinfo(cur);
505 #ifdef USE_GETIPNODEBY
506 if (hp)
507 freehostent(hp);
508 #endif
509 /* bad: */
510 *res = NULL;
511 return error;
512 }
513
514 static int
515 get_addr(hostname, af, res, pai, port0)
516 const char *hostname;
517 int af;
518 struct addrinfo **res;
519 struct addrinfo *pai;
520 int port0;
521 {
522 int i, error;
523 struct addrinfo *cur;
524
525 #ifdef USE_GETIPNODEBY
526 return get_addr0(hostname, af, res, pai, port0);
527 #else
528 for (i = 0; afdl[i].a_af; i++) {
529 if (af == AF_UNSPEC || af == afdl[i].a_af)
530 ;
531 else
532 continue;
533 error = get_addr0(hostname, afdl[i].a_af, res, pai, port0);
534 if (error == EAI_FAIL)
535 return error;
536 else
537 error = 0;
538 if (*res) {
539 /* make chain of addrs */
540 for (cur = *res;
541 cur && cur->ai_next;
542 cur = cur->ai_next)
543 ;
544 if (!cur)
545 return EAI_FAIL;
546 res = &cur->ai_next;
547 }
548 }
549
550 return error;
551 #endif
552 }
553
554 static int
555 get_addr0(hostname, af, res, pai, port0)
556 const char *hostname;
557 int af;
558 struct addrinfo **res;
559 struct addrinfo *pai;
560 int port0;
561 {
562 u_short port = port0 & 0xffff;
563 struct addrinfo sentinel;
564 struct hostent *hp;
565 struct addrinfo *top, *cur;
566 struct afd *afd;
567 int i, error = 0, h_error;
568 char *ap;
569 #ifndef USE_GETIPNODEBY
570 extern int h_errno;
571 #endif
572
573 top = NULL;
574 sentinel.ai_next = NULL;
575 cur = &sentinel;
576 #ifdef USE_GETIPNODEBY
577 if (af == AF_UNSPEC) {
578 hp = getipnodebyname(hostname, AF_INET6,
579 AI_ADDRCONFIG|AI_ALL|AI_V4MAPPED, &h_error);
580 } else
581 hp = getipnodebyname(hostname, af, AI_ADDRCONFIG, &h_error);
582 #else
583 if (af == AF_UNSPEC) {
584 error = EAI_FAIL;
585 goto bad;
586 }
587 hp = gethostbyname2(hostname, af);
588 h_error = h_errno;
589 #endif
590 if (hp == NULL) {
591 switch (h_error) {
592 case HOST_NOT_FOUND:
593 case NO_DATA:
594 error = EAI_NODATA;
595 break;
596 case TRY_AGAIN:
597 error = EAI_AGAIN;
598 break;
599 case NO_RECOVERY:
600 default:
601 error = EAI_FAIL;
602 break;
603 }
604 goto bad;
605 }
606
607 if ((hp->h_name == NULL) || (hp->h_name[0] == 0) ||
608 (hp->h_addr_list[0] == NULL))
609 ERR(EAI_FAIL);
610
611 for (i = 0; (ap = hp->h_addr_list[i]) != NULL; i++) {
612 switch (af) {
613 #ifdef INET6
614 case AF_INET6:
615 afd = &afdl[N_INET6];
616 break;
617 #endif
618 #ifndef INET6
619 default: /* AF_UNSPEC */
620 #endif
621 case AF_INET:
622 afd = &afdl[N_INET];
623 break;
624 #ifdef INET6
625 default: /* AF_UNSPEC */
626 if (IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
627 ap += sizeof(struct in6_addr) -
628 sizeof(struct in_addr);
629 afd = &afdl[N_INET];
630 } else
631 afd = &afdl[N_INET6];
632 break;
633 #endif
634 }
635 #ifdef FAITH
636 if (translate && afd->a_af == AF_INET) {
637 struct in6_addr *in6;
638
639 GET_AI(cur->ai_next, &afdl[N_INET6], ap, port);
640 in6 = &((struct sockaddr_in6 *)cur->ai_next->ai_addr)->sin6_addr;
641 memcpy(&in6->s6_addr32[0], &faith_prefix,
642 sizeof(struct in6_addr) - sizeof(struct in_addr));
643 memcpy(&in6->s6_addr32[3], ap, sizeof(struct in_addr));
644 } else
645 #endif /* FAITH */
646 GET_AI(cur->ai_next, afd, ap, port);
647 if (cur == &sentinel) {
648 top = cur->ai_next;
649 GET_CANONNAME(top, hp->h_name);
650 }
651 cur = cur->ai_next;
652 }
653 #ifdef USE_GETIPNODEBY
654 freehostent(hp);
655 #endif
656 *res = top;
657 return SUCCESS;
658 free:
659 if (top)
660 freeaddrinfo(top);
661 #ifdef USE_GETIPNODEBY
662 if (hp)
663 freehostent(hp);
664 #endif
665 bad:
666 *res = NULL;
667 return error;
668 }
669