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