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