getaddrinfo.c revision 1.14 1 /* $NetBSD: getaddrinfo.c,v 1.14 1999/12/13 14:18:32 itojun 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 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 #endif
55
56 #include <sys/types.h>
57 #include <sys/param.h>
58 #if 0
59 #include <sys/sysctl.h>
60 #endif
61 #include <sys/socket.h>
62 #include <net/if.h>
63 #include <netinet/in.h>
64 #include <arpa/inet.h>
65 #include <arpa/nameser.h>
66 #include <netdb.h>
67 #include <resolv.h>
68 #include <string.h>
69 #include <stdlib.h>
70 #include <stddef.h>
71 #include <ctype.h>
72 #include <unistd.h>
73 #include <stdio.h>
74 #include <errno.h>
75
76 #if 0
77 #ifndef HAVE_PORTABLE_PROTOTYPE
78 #include "cdecl_ext.h"
79 #endif
80
81 #ifndef HAVE_U_INT32_T
82 #include "bittypes.h"
83 #endif
84
85 #ifndef HAVE_SOCKADDR_STORAGE
86 #include "sockstorage.h"
87 #endif
88
89 #ifndef HAVE_ADDRINFO
90 #include "addrinfo.h"
91 #endif
92
93 #if defined(__KAME__) && defined(INET6)
94 # define FAITH
95 #endif
96 #endif
97
98 #define SUCCESS 0
99 #define ANY 0
100 #define YES 1
101 #define NO 0
102
103 #ifdef FAITH
104 static int translate = NO;
105 static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
106 #endif
107
108 static const char in_addrany[] = { 0, 0, 0, 0 };
109 static const char in6_addrany[] = {
110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
111 };
112 static const char in_loopback[] = { 127, 0, 0, 1 };
113 static const char in6_loopback[] = {
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
115 };
116
117 struct sockinet {
118 u_char si_len;
119 u_char si_family;
120 u_short si_port;
121 u_int32_t si_scope_id;
122 };
123
124 static const struct afd {
125 int a_af;
126 int a_addrlen;
127 int a_socklen;
128 int a_off;
129 const char *a_addrany;
130 const char *a_loopback;
131 int a_scoped;
132 } afdl [] = {
133 #ifdef INET6
134 {PF_INET6, sizeof(struct in6_addr),
135 sizeof(struct sockaddr_in6),
136 offsetof(struct sockaddr_in6, sin6_addr),
137 in6_addrany, in6_loopback, 1},
138 #endif
139 {PF_INET, sizeof(struct in_addr),
140 sizeof(struct sockaddr_in),
141 offsetof(struct sockaddr_in, sin_addr),
142 in_addrany, in_loopback, 0},
143 {0, 0, 0, 0, NULL, NULL, 0},
144 };
145
146 struct explore {
147 int e_af;
148 int e_socktype;
149 int e_protocol;
150 const char *e_protostr;
151 int e_wild;
152 #define WILD_AF(ex) ((ex)->e_wild & 0x01)
153 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
154 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
155 };
156
157 static const struct explore explore[] = {
158 #if 0
159 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
160 #endif
161 #ifdef INET6
162 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
163 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
164 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
165 #endif
166 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
167 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
168 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
169 { -1, 0, 0, NULL, 0 },
170 };
171
172 #ifdef INET6
173 #define PTON_MAX 16
174 #else
175 #define PTON_MAX 4
176 #endif
177
178
179 static int str_isnumber __P((const char *));
180 static int explore_fqdn __P((const struct addrinfo *, const char *,
181 const char *, struct addrinfo **));
182 static int explore_null __P((const struct addrinfo *, const char *,
183 const char *, struct addrinfo **));
184 static int explore_numeric __P((const struct addrinfo *, const char *,
185 const char *, struct addrinfo **));
186 static int explore_numeric_scope __P((const struct addrinfo *, const char *,
187 const char *, struct addrinfo **));
188 static int get_name __P((const char *, const struct afd *, struct addrinfo **,
189 char *, const struct addrinfo *, const char *));
190 static int get_canonname __P((const struct addrinfo *,
191 struct addrinfo *, const char *));
192 static struct addrinfo *get_ai __P((const struct addrinfo *,
193 const struct afd *, const char *));
194 static int get_portmatch __P((const struct addrinfo *, const char *));
195 static int get_port __P((struct addrinfo *, const char *, int));
196 static const struct afd *find_afd __P((int));
197
198 static char *ai_errlist[] = {
199 "Success",
200 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
201 "Temporary failure in name resolution", /* EAI_AGAIN */
202 "Invalid value for ai_flags", /* EAI_BADFLAGS */
203 "Non-recoverable failure in name resolution", /* EAI_FAIL */
204 "ai_family not supported", /* EAI_FAMILY */
205 "Memory allocation failure", /* EAI_MEMORY */
206 "No address associated with hostname", /* EAI_NODATA */
207 "hostname nor servname provided, or not known", /* EAI_NONAME */
208 "servname not supported for ai_socktype", /* EAI_SERVICE */
209 "ai_socktype not supported", /* EAI_SOCKTYPE */
210 "System error returned in errno", /* EAI_SYSTEM */
211 "Invalid value for hints", /* EAI_BADHINTS */
212 "Resolved protocol is unknown", /* EAI_PROTOCOL */
213 "Unknown error", /* EAI_MAX */
214 };
215
216 /* XXX macros that make external reference is BAD. */
217
218 #define GET_AI(ai, afd, addr) \
219 do { \
220 /* external reference: pai, error, and label free */ \
221 (ai) = get_ai(pai, (afd), (addr)); \
222 if ((ai) == NULL) { \
223 error = EAI_MEMORY; \
224 goto free; \
225 } \
226 } while (0)
227
228 #define GET_PORT(ai, serv) \
229 do { \
230 /* external reference: error and label free */ \
231 error = get_port((ai), (serv), 0); \
232 if (error != 0) \
233 goto free; \
234 } while (0)
235
236 #define GET_CANONNAME(ai, str) \
237 do { \
238 /* external reference: pai, error and label free */ \
239 error = get_canonname(pai, (ai), (str)); \
240 if (error != 0) \
241 goto free; \
242 } while (0)
243
244 #define ERR(err) \
245 do { \
246 /* external reference: error, and label bad */ \
247 error = (err); \
248 goto bad; \
249 } while (0)
250
251 #define MATCH_FAMILY(x, y, w) \
252 ((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
253 #define MATCH(x, y, w) \
254 ((x) == (y) || ((w) && ((x) == ANY || (y) == ANY)))
255
256 char *
257 gai_strerror(ecode)
258 int ecode;
259 {
260 if (ecode < 0 || ecode > EAI_MAX)
261 ecode = EAI_MAX;
262 return ai_errlist[ecode];
263 }
264
265 void
266 freeaddrinfo(ai)
267 struct addrinfo *ai;
268 {
269 struct addrinfo *next;
270
271 do {
272 next = ai->ai_next;
273 if (ai->ai_canonname)
274 free(ai->ai_canonname);
275 /* no need to free(ai->ai_addr) */
276 free(ai);
277 } while ((ai = next) != NULL);
278 }
279
280 static int
281 str_isnumber(p)
282 const char *p;
283 {
284 char *q = (char *)p;
285 while (*q) {
286 if (! isdigit(*q))
287 return NO;
288 q++;
289 }
290 return YES;
291 }
292
293 int
294 getaddrinfo(hostname, servname, hints, res)
295 const char *hostname, *servname;
296 const struct addrinfo *hints;
297 struct addrinfo **res;
298 {
299 struct addrinfo sentinel;
300 struct addrinfo *cur;
301 int error = 0;
302 struct addrinfo ai;
303 struct addrinfo ai0;
304 struct addrinfo *pai;
305 const struct afd *afd;
306 const struct explore *ex;
307
308 #ifdef FAITH
309 static int firsttime = 1;
310
311 if (firsttime) {
312 /* translator hack */
313 char *q = getenv("GAI");
314 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
315 translate = YES;
316 firsttime = 0;
317 }
318 #endif
319
320 sentinel.ai_next = NULL;
321 cur = &sentinel;
322 pai = &ai;
323 pai->ai_flags = 0;
324 pai->ai_family = PF_UNSPEC;
325 pai->ai_socktype = ANY;
326 pai->ai_protocol = ANY;
327 pai->ai_addrlen = 0;
328 pai->ai_canonname = NULL;
329 pai->ai_addr = NULL;
330 pai->ai_next = NULL;
331
332 if (hostname == NULL && servname == NULL)
333 return EAI_NONAME;
334 if (hints) {
335 /* error check for hints */
336 if (hints->ai_addrlen || hints->ai_canonname ||
337 hints->ai_addr || hints->ai_next)
338 ERR(EAI_BADHINTS); /* xxx */
339 if (hints->ai_flags & ~AI_MASK)
340 ERR(EAI_BADFLAGS);
341 switch (hints->ai_family) {
342 case PF_UNSPEC:
343 case PF_INET:
344 #ifdef INET6
345 case PF_INET6:
346 #endif
347 break;
348 default:
349 ERR(EAI_FAMILY);
350 }
351 memcpy(pai, hints, sizeof(*pai));
352
353 /*
354 * if both socktype/protocol are specified, check if they
355 * are meaningful combination.
356 */
357 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
358 for (ex = explore; ex->e_af >= 0; ex++) {
359 if (pai->ai_family != ex->e_af)
360 continue;
361 if (ex->e_socktype == ANY)
362 continue;
363 if (ex->e_protocol == ANY)
364 continue;
365 if (pai->ai_socktype == ex->e_socktype
366 && pai->ai_protocol != ex->e_protocol) {
367 ERR(EAI_BADHINTS);
368 }
369 }
370 }
371 }
372
373 /*
374 * check for special cases. (1) numeric servname is disallowed if
375 * socktype/protocol are left unspecified. (2) servname is disallowed
376 * for raw and other inet{,6} sockets.
377 */
378 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
379 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)) {
380 ai0 = *pai;
381
382 if (pai->ai_family == PF_UNSPEC)
383 pai->ai_family = PF_INET6;
384 error = get_portmatch(pai, servname);
385 if (error)
386 ERR(error);
387
388 *pai = ai0;
389 }
390
391 ai0 = *pai;
392
393 /* NULL hostname, or numeric hostname */
394 for (ex = explore; ex->e_af >= 0; ex++) {
395 *pai = ai0;
396
397 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
398 continue;
399 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
400 continue;
401 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
402 continue;
403
404 if (pai->ai_family == PF_UNSPEC)
405 pai->ai_family = ex->e_af;
406 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
407 pai->ai_socktype = ex->e_socktype;
408 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
409 pai->ai_protocol = ex->e_protocol;
410
411 if (hostname == NULL)
412 error = explore_null(pai, hostname, servname, &cur->ai_next);
413 else
414 error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
415
416 if (error)
417 goto free;
418
419 while (cur && cur->ai_next)
420 cur = cur->ai_next;
421 }
422
423 /*
424 * XXX
425 * If numreic representation of AF1 can be interpreted as FQDN
426 * representation of AF2, we need to think again about the code below.
427 */
428 if (sentinel.ai_next)
429 goto good;
430
431 if (pai->ai_flags & AI_NUMERICHOST)
432 ERR(EAI_NONAME);
433 if (hostname == NULL)
434 ERR(EAI_NONAME);
435
436 /*
437 * hostname as alphabetical name.
438 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
439 * outer loop by AFs.
440 */
441 for (afd = afdl; afd->a_af; afd++) {
442 *pai = ai0;
443
444 if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
445 continue;
446
447 for (ex = explore; ex->e_af >= 0; ex++) {
448 *pai = ai0;
449
450 if (pai->ai_family == PF_UNSPEC)
451 pai->ai_family = afd->a_af;
452
453 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
454 continue;
455 if (!MATCH(pai->ai_socktype, ex->e_socktype,
456 WILD_SOCKTYPE(ex))) {
457 continue;
458 }
459 if (!MATCH(pai->ai_protocol, ex->e_protocol,
460 WILD_PROTOCOL(ex))) {
461 continue;
462 }
463
464 if (pai->ai_family == PF_UNSPEC)
465 pai->ai_family = ex->e_af;
466 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
467 pai->ai_socktype = ex->e_socktype;
468 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
469 pai->ai_protocol = ex->e_protocol;
470
471 error = explore_fqdn(pai, hostname, servname,
472 &cur->ai_next);
473
474 while (cur && cur->ai_next)
475 cur = cur->ai_next;
476 }
477 }
478
479 /* XXX */
480 if (sentinel.ai_next)
481 error = 0;
482
483 if (error)
484 goto free;
485 if (error == 0) {
486 if (sentinel.ai_next) {
487 good:
488 *res = sentinel.ai_next;
489 return SUCCESS;
490 } else
491 error = EAI_FAIL;
492 }
493 free:
494 bad:
495 if (sentinel.ai_next)
496 freeaddrinfo(sentinel.ai_next);
497 *res = NULL;
498 return error;
499 }
500
501 /*
502 * FQDN hostname, DNS lookup
503 */
504 static int
505 explore_fqdn(pai, hostname, servname, res)
506 const struct addrinfo *pai;
507 const char *hostname;
508 const char *servname;
509 struct addrinfo **res;
510 {
511 int s;
512 struct hostent *hp;
513 int h_error;
514 int af;
515 char *ap;
516 struct addrinfo sentinel, *cur;
517 int i;
518 const struct afd *afd;
519 int error;
520
521 *res = NULL;
522 sentinel.ai_next = NULL;
523 cur = &sentinel;
524
525 /*
526 * filter out AFs that are not supported by the kernel
527 * XXX errno?
528 */
529 s = socket(pai->ai_family, SOCK_DGRAM, 0);
530 if (s < 0) {
531 if (errno != EMFILE)
532 return 0;
533 } else
534 close(s);
535
536 /*
537 * if the servname does not match socktype/protocol, ignore it.
538 */
539 if (get_portmatch(pai, servname) != 0)
540 return 0;
541
542 afd = find_afd(pai->ai_family);
543
544 /*
545 * post-RFC2553: should look at (pai->ai_flags & AI_ADDRCONFIG)
546 * rather than hardcoding it. we may need to add AI_ADDRCONFIG
547 * handling code by ourselves in case we don't have getipnodebyname().
548 */
549 #ifdef USE_GETIPNODEBY
550 hp = getipnodebyname(hostname, pai->ai_family, AI_ADDRCONFIG, &h_error);
551 #else
552 hp = gethostbyname2(hostname, pai->ai_family);
553 h_error = h_errno;
554 #endif
555
556 if (hp == NULL) {
557 switch (h_error) {
558 case HOST_NOT_FOUND:
559 case NO_DATA:
560 error = EAI_NODATA;
561 break;
562 case TRY_AGAIN:
563 error = EAI_AGAIN;
564 break;
565 case NO_RECOVERY:
566 case NETDB_INTERNAL:
567 default:
568 error = EAI_FAIL;
569 break;
570 }
571 } else if ((hp->h_name == NULL) || (hp->h_name[0] == 0)
572 || (hp->h_addr_list[0] == NULL)) {
573 #ifdef USE_GETIPNODEBY
574 freehostent(hp);
575 #endif
576 hp = NULL;
577 error = EAI_FAIL;
578 }
579
580 if (hp == NULL)
581 goto free;
582
583 for (i = 0; hp->h_addr_list[i] != NULL; i++) {
584 af = hp->h_addrtype;
585 ap = hp->h_addr_list[i];
586 if (af == AF_INET6
587 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
588 af = AF_INET;
589 ap = ap + sizeof(struct in6_addr)
590 - sizeof(struct in_addr);
591 }
592
593 if (af != pai->ai_family)
594 continue;
595
596 if ((pai->ai_flags & AI_CANONNAME) == 0) {
597 GET_AI(cur->ai_next, afd, ap);
598 GET_PORT(cur->ai_next, servname);
599 } else {
600 /*
601 * if AI_CANONNAME and if reverse lookup
602 * fail, return ai anyway to pacify
603 * calling application.
604 *
605 * XXX getaddrinfo() is a name->address
606 * translation function, and it looks
607 * strange that we do addr->name
608 * translation here.
609 */
610 get_name(ap, afd, &cur->ai_next,
611 ap, pai, servname);
612 }
613
614 while (cur && cur->ai_next)
615 cur = cur->ai_next;
616 }
617
618 *res = sentinel.ai_next;
619 return 0;
620
621 free:
622 #ifdef USE_GETIPNODEBY
623 if (hp)
624 freehostent(hp);
625 #endif
626 if (sentinel.ai_next)
627 freeaddrinfo(sentinel.ai_next);
628 return error;
629 }
630
631 /*
632 * hostname == NULL.
633 * passive socket -> anyaddr (0.0.0.0 or ::)
634 * non-passive socket -> localhost (127.0.0.1 or ::1)
635 */
636 static int
637 explore_null(pai, hostname, servname, res)
638 const struct addrinfo *pai;
639 const char *hostname;
640 const char *servname;
641 struct addrinfo **res;
642 {
643 int s;
644 const struct afd *afd;
645 struct addrinfo *cur;
646 struct addrinfo sentinel;
647 int error;
648
649 *res = NULL;
650 sentinel.ai_next = NULL;
651 cur = &sentinel;
652
653 /*
654 * filter out AFs that are not supported by the kernel
655 * XXX errno?
656 */
657 s = socket(pai->ai_family, SOCK_DGRAM, 0);
658 if (s < 0) {
659 if (errno != EMFILE)
660 return 0;
661 } else
662 close(s);
663
664 /*
665 * if the servname does not match socktype/protocol, ignore it.
666 */
667 if (get_portmatch(pai, servname) != 0)
668 return 0;
669
670 afd = find_afd(pai->ai_family);
671
672 if (pai->ai_flags & AI_PASSIVE) {
673 GET_AI(cur->ai_next, afd, afd->a_addrany);
674 /* xxx meaningless?
675 * GET_CANONNAME(cur->ai_next, "anyaddr");
676 */
677 GET_PORT(cur->ai_next, servname);
678 } else {
679 GET_AI(cur->ai_next, afd, afd->a_loopback);
680 /* xxx meaningless?
681 * GET_CANONNAME(cur->ai_next, "localhost");
682 */
683 GET_PORT(cur->ai_next, servname);
684 }
685 cur = cur->ai_next;
686
687 *res = sentinel.ai_next;
688 return 0;
689
690 free:
691 if (sentinel.ai_next)
692 freeaddrinfo(sentinel.ai_next);
693 return error;
694 }
695
696 /*
697 * numeric hostname
698 */
699 static int
700 explore_numeric(pai, hostname, servname, res)
701 const struct addrinfo *pai;
702 const char *hostname;
703 const char *servname;
704 struct addrinfo **res;
705 {
706 const struct afd *afd;
707 struct addrinfo *cur;
708 struct addrinfo sentinel;
709 int error;
710 char pton[PTON_MAX];
711 int flags;
712
713 *res = NULL;
714 sentinel.ai_next = NULL;
715 cur = &sentinel;
716
717 /*
718 * if the servname does not match socktype/protocol, ignore it.
719 */
720 if (get_portmatch(pai, servname) != 0)
721 return 0;
722
723 afd = find_afd(pai->ai_family);
724 flags = pai->ai_flags;
725
726 if (inet_pton(afd->a_af, hostname, pton) == 1) {
727 u_int32_t v4a;
728 #ifdef INET6
729 u_char pfx;
730 #endif
731
732 switch (afd->a_af) {
733 case AF_INET:
734 v4a = (u_int32_t)ntohl(((struct in_addr *)pton)->s_addr);
735 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
736 flags &= ~AI_CANONNAME;
737 v4a >>= IN_CLASSA_NSHIFT;
738 if (v4a == 0 || v4a == IN_LOOPBACKNET)
739 flags &= ~AI_CANONNAME;
740 break;
741 #ifdef INET6
742 case AF_INET6:
743 pfx = ((struct in6_addr *)pton)->s6_addr[0];
744 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
745 flags &= ~AI_CANONNAME;
746 break;
747 #endif
748 }
749
750 if (pai->ai_family == afd->a_af ||
751 pai->ai_family == PF_UNSPEC /*?*/) {
752 if ((flags & AI_CANONNAME) == 0) {
753 GET_AI(cur->ai_next, afd, pton);
754 GET_PORT(cur->ai_next, servname);
755 } else {
756 /*
757 * if AI_CANONNAME and if reverse lookup
758 * fail, return ai anyway to pacify
759 * calling application.
760 *
761 * XXX getaddrinfo() is a name->address
762 * translation function, and it looks
763 * strange that we do addr->name
764 * translation here.
765 */
766 get_name(pton, afd, &cur->ai_next,
767 pton, pai, servname);
768 }
769 while (cur && cur->ai_next)
770 cur = cur->ai_next;
771 } else
772 ERR(EAI_FAMILY); /*xxx*/
773 }
774
775 *res = sentinel.ai_next;
776 return 0;
777
778 free:
779 bad:
780 if (sentinel.ai_next)
781 freeaddrinfo(sentinel.ai_next);
782 return error;
783 }
784
785 /*
786 * numeric hostname with scope
787 */
788 static int
789 explore_numeric_scope(pai, hostname, servname, res)
790 const struct addrinfo *pai;
791 const char *hostname;
792 const char *servname;
793 struct addrinfo **res;
794 {
795 #ifndef SCOPE_DELIMITER
796 return explore_numeric(pai, hostname, servname, res);
797 #else
798 const struct afd *afd;
799 struct addrinfo *cur;
800 int error;
801 char *cp, *hostname2 = NULL;
802 int scope;
803 struct sockaddr_in6 *sin6;
804
805 /*
806 * if the servname does not match socktype/protocol, ignore it.
807 */
808 if (get_portmatch(pai, servname) != 0)
809 return 0;
810
811 afd = find_afd(pai->ai_family);
812 if (!afd->a_scoped)
813 return explore_numeric(pai, hostname, servname, res);
814
815 cp = strchr(hostname, SCOPE_DELIMITER);
816 if (cp == NULL)
817 return explore_numeric(pai, hostname, servname, res);
818
819 /*
820 * Handle special case of <scoped_address><delimiter><scope id>
821 */
822 hostname2 = strdup(hostname);
823 if (hostname2 == NULL)
824 return EAI_MEMORY;
825 /* terminate at the delimiter */
826 hostname2[cp - hostname] = '\0';
827
828 cp++;
829 switch (pai->ai_family) {
830 #ifdef INET6
831 case AF_INET6:
832 scope = if_nametoindex(cp);
833 break;
834 #endif
835 }
836
837 error = explore_numeric(pai, hostname2, servname, res);
838 if (error == 0) {
839 for (cur = *res; cur; cur = cur->ai_next) {
840 if (cur->ai_family != AF_INET6)
841 continue;
842 sin6 = (struct sockaddr_in6 *)cur->ai_addr;
843 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
844 IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr))
845 sin6->sin6_scope_id = scope;
846 }
847 }
848
849 free(hostname2);
850
851 return error;
852 #endif
853 }
854
855 static int
856 get_name(addr, afd, res, numaddr, pai, servname)
857 const char *addr;
858 const struct afd *afd;
859 struct addrinfo **res;
860 char *numaddr;
861 const struct addrinfo *pai;
862 const char *servname;
863 {
864 struct hostent *hp;
865 struct addrinfo *cur;
866 int error = 0;
867 #ifdef USE_GETIPNODEBY
868 int h_error;
869
870 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
871 #else
872 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
873 #endif
874 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
875 GET_AI(cur, afd, hp->h_addr_list[0]);
876 GET_PORT(cur, servname);
877 GET_CANONNAME(cur, hp->h_name);
878 } else {
879 GET_AI(cur, afd, numaddr);
880 GET_PORT(cur, servname);
881 }
882
883 #ifdef USE_GETIPNODEBY
884 if (hp)
885 freehostent(hp);
886 #endif
887 *res = cur;
888 return SUCCESS;
889 free:
890 if (cur)
891 freeaddrinfo(cur);
892 #ifdef USE_GETIPNODEBY
893 if (hp)
894 freehostent(hp);
895 #endif
896 /* bad: */
897 *res = NULL;
898 return error;
899 }
900
901 static int
902 get_canonname(pai, ai, str)
903 const struct addrinfo *pai;
904 struct addrinfo *ai;
905 const char *str;
906 {
907 if ((pai->ai_flags & AI_CANONNAME) != 0) {
908 ai->ai_canonname = (char *)malloc(strlen(str) + 1);
909 if (ai->ai_canonname == NULL)
910 return EAI_MEMORY;
911 strcpy(ai->ai_canonname, str);
912 }
913 return 0;
914 }
915
916 static struct addrinfo *
917 get_ai(pai, afd, addr)
918 const struct addrinfo *pai;
919 const struct afd *afd;
920 const char *addr;
921 {
922 char *p;
923 struct addrinfo *ai;
924
925 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
926 + (afd->a_socklen));
927 if (ai == NULL)
928 return NULL;
929
930 memcpy(ai, pai, sizeof(struct addrinfo));
931 ai->ai_addr = (struct sockaddr *)(ai + 1);
932 memset(ai->ai_addr, 0, afd->a_socklen);
933 #ifdef HAVE_SOCKADDR_SA_LEN
934 ai->ai_addr->sa_len = afd->a_socklen;
935 #endif
936 ai->ai_addrlen = afd->a_socklen;
937 ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
938 p = (char *)(ai->ai_addr);
939 memcpy(p + afd->a_off, addr, afd->a_addrlen);
940 return ai;
941 }
942
943 static int
944 get_portmatch(ai, servname)
945 const struct addrinfo *ai;
946 const char *servname;
947 {
948
949 /* get_port does not touch first argument. when matchonly == 1. */
950 return get_port((struct addrinfo *)ai, servname, 1);
951 }
952
953 static int
954 get_port(ai, servname, matchonly)
955 struct addrinfo *ai;
956 const char *servname;
957 int matchonly;
958 {
959 const char *proto;
960 struct servent *sp;
961 int port;
962 int allownumeric;
963
964 if (servname == NULL)
965 return 0;
966 if (ai->ai_family != AF_INET && ai->ai_family != AF_INET6)
967 return 0;
968
969 switch (ai->ai_socktype) {
970 case SOCK_RAW:
971 return EAI_SERVICE;
972 case SOCK_DGRAM:
973 case SOCK_STREAM:
974 allownumeric = 1;
975 break;
976 case ANY:
977 allownumeric = 0;
978 break;
979 default:
980 return EAI_SOCKTYPE;
981 }
982
983 if (str_isnumber(servname)) {
984 if (!allownumeric)
985 return EAI_SERVICE;
986 port = htons(atoi(servname));
987 if (port < 0 || port > 65535)
988 return EAI_SERVICE;
989 } else {
990 switch (ai->ai_socktype) {
991 case SOCK_DGRAM:
992 proto = "udp";
993 break;
994 case SOCK_STREAM:
995 proto = "tcp";
996 break;
997 default:
998 proto = NULL;
999 break;
1000 }
1001
1002 if ((sp = getservbyname(servname, proto)) == NULL)
1003 return EAI_SERVICE;
1004 port = sp->s_port;
1005 }
1006
1007 if (!matchonly) {
1008 switch (ai->ai_family) {
1009 case AF_INET:
1010 ((struct sockaddr_in *)ai->ai_addr)->sin_port = port;
1011 break;
1012 #ifdef INET6
1013 case AF_INET6:
1014 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port;
1015 break;
1016 #endif
1017 }
1018 }
1019
1020 return 0;
1021 }
1022
1023 static const struct afd *
1024 find_afd(af)
1025 int af;
1026 {
1027 const struct afd *afd;
1028
1029 if (af == PF_UNSPEC)
1030 return NULL;
1031 for (afd = afdl; afd->a_af; afd++) {
1032 if (afd->a_af == af)
1033 return afd;
1034 }
1035 return NULL;
1036 }
1037