]> The Tcpdump Group git mirrors - tcpdump/blob - missing/getaddrinfo.c
add snprintf implementation
[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 #include <sys/types.h>
46 #include <sys/param.h>
47 #if 0
48 #include <sys/sysctl.h>
49 #endif
50 #include <sys/socket.h>
51 #include <net/if.h>
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54 #include <arpa/nameser.h>
55 #include <netdb.h>
56 #include <resolv.h>
57 #include <string.h>
58 #include <stdlib.h>
59 #include <stddef.h>
60 #include <ctype.h>
61 #include <unistd.h>
62 #include <stdio.h>
63 #include <errno.h>
64
65 #ifndef HAVE_PORTABLE_PROTOTYPE
66 #include "cdecl_ext.h"
67 #endif
68
69 #if 0
70 #ifndef HAVE_U_INT32_T
71 #include "bittypes.h"
72 #endif
73 #endif
74
75 #ifndef HAVE_SOCKADDR_STORAGE
76 #include "sockstorage.h"
77 #endif
78
79 #include "addrinfo.h"
80
81 #if defined(__KAME__) && defined(INET6)
82 # define FAITH
83 #endif
84
85 #define SUCCESS 0
86 #define ANY 0
87 #define YES 1
88 #define NO 0
89
90 #ifdef FAITH
91 static int translate = NO;
92 static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
93 #endif
94
95 static const char in_addrany[] = { 0, 0, 0, 0 };
96 static const char in6_addrany[] = {
97 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
98 };
99 static const char in_loopback[] = { 127, 0, 0, 1 };
100 static const char in6_loopback[] = {
101 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
102 };
103
104 struct sockinet {
105 u_char si_len;
106 u_char si_family;
107 u_short si_port;
108 u_int32_t si_scope_id;
109 };
110
111 static const struct afd {
112 int a_af;
113 int a_addrlen;
114 int a_socklen;
115 int a_off;
116 const char *a_addrany;
117 const char *a_loopback;
118 int a_scoped;
119 } afdl [] = {
120 #ifdef INET6
121 {PF_INET6, sizeof(struct in6_addr),
122 sizeof(struct sockaddr_in6),
123 offsetof(struct sockaddr_in6, sin6_addr),
124 in6_addrany, in6_loopback, 1},
125 #endif
126 {PF_INET, sizeof(struct in_addr),
127 sizeof(struct sockaddr_in),
128 offsetof(struct sockaddr_in, sin_addr),
129 in_addrany, in_loopback, 0},
130 {0, 0, 0, 0, NULL, NULL, 0},
131 };
132
133 struct explore {
134 int e_af;
135 int e_socktype;
136 int e_protocol;
137 const char *e_protostr;
138 int e_wild;
139 #define WILD_AF(ex) ((ex)->e_wild & 0x01)
140 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
141 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
142 };
143
144 static const struct explore explore[] = {
145 #if 0
146 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
147 #endif
148 #ifdef INET6
149 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
150 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
151 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
152 #endif
153 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
154 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
155 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
156 { -1, 0, 0, NULL, 0 },
157 };
158
159 #ifdef INET6
160 #define PTON_MAX 16
161 #else
162 #define PTON_MAX 4
163 #endif
164
165
166 static int str_isnumber __P((const char *));
167 static int explore_fqdn __P((const struct addrinfo *, const char *,
168 const char *, struct addrinfo **));
169 static int explore_null __P((const struct addrinfo *, const char *,
170 const char *, struct addrinfo **));
171 static int explore_numeric __P((const struct addrinfo *, const char *,
172 const char *, struct addrinfo **));
173 static int explore_numeric_scope __P((const struct addrinfo *, const char *,
174 const char *, struct addrinfo **));
175 static int get_name __P((const char *, const struct afd *, struct addrinfo **,
176 char *, const struct addrinfo *, const char *));
177 static int get_canonname __P((const struct addrinfo *,
178 struct addrinfo *, const char *));
179 static struct addrinfo *get_ai __P((const struct addrinfo *,
180 const struct afd *, const char *));
181 static int get_portmatch __P((const struct addrinfo *, const char *));
182 static int get_port __P((struct addrinfo *, const char *, int));
183 static const struct afd *find_afd __P((int));
184
185 static char *ai_errlist[] = {
186 "Success",
187 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
188 "Temporary failure in name resolution", /* EAI_AGAIN */
189 "Invalid value for ai_flags", /* EAI_BADFLAGS */
190 "Non-recoverable failure in name resolution", /* EAI_FAIL */
191 "ai_family not supported", /* EAI_FAMILY */
192 "Memory allocation failure", /* EAI_MEMORY */
193 "No address associated with hostname", /* EAI_NODATA */
194 "hostname nor servname provided, or not known", /* EAI_NONAME */
195 "servname not supported for ai_socktype", /* EAI_SERVICE */
196 "ai_socktype not supported", /* EAI_SOCKTYPE */
197 "System error returned in errno", /* EAI_SYSTEM */
198 "Invalid value for hints", /* EAI_BADHINTS */
199 "Resolved protocol is unknown", /* EAI_PROTOCOL */
200 "Unknown error", /* EAI_MAX */
201 };
202
203 /* XXX macros that make external reference is BAD. */
204
205 #define GET_AI(ai, afd, addr) \
206 do { \
207 /* external reference: pai, error, and label free */ \
208 (ai) = get_ai(pai, (afd), (addr)); \
209 if ((ai) == NULL) { \
210 error = EAI_MEMORY; \
211 goto free; \
212 } \
213 } while (0)
214
215 #define GET_PORT(ai, serv) \
216 do { \
217 /* external reference: error and label free */ \
218 error = get_port((ai), (serv), 0); \
219 if (error != 0) \
220 goto free; \
221 } while (0)
222
223 #define GET_CANONNAME(ai, str) \
224 do { \
225 /* external reference: pai, error and label free */ \
226 error = get_canonname(pai, (ai), (str)); \
227 if (error != 0) \
228 goto free; \
229 } while (0)
230
231 #define ERR(err) \
232 do { \
233 /* external reference: error, and label bad */ \
234 error = (err); \
235 goto bad; \
236 } while (0)
237
238 #define MATCH_FAMILY(x, y, w) \
239 ((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
240 #define MATCH(x, y, w) \
241 ((x) == (y) || ((w) && ((x) == ANY || (y) == ANY)))
242
243 char *
244 gai_strerror(ecode)
245 int ecode;
246 {
247 if (ecode < 0 || ecode > EAI_MAX)
248 ecode = EAI_MAX;
249 return ai_errlist[ecode];
250 }
251
252 void
253 freeaddrinfo(ai)
254 struct addrinfo *ai;
255 {
256 struct addrinfo *next;
257
258 do {
259 next = ai->ai_next;
260 if (ai->ai_canonname)
261 free(ai->ai_canonname);
262 /* no need to free(ai->ai_addr) */
263 free(ai);
264 } while ((ai = next) != NULL);
265 }
266
267 static int
268 str_isnumber(p)
269 const char *p;
270 {
271 char *q = (char *)p;
272 while (*q) {
273 if (! isdigit(*q))
274 return NO;
275 q++;
276 }
277 return YES;
278 }
279
280 int
281 getaddrinfo(hostname, servname, hints, res)
282 const char *hostname, *servname;
283 const struct addrinfo *hints;
284 struct addrinfo **res;
285 {
286 struct addrinfo sentinel;
287 struct addrinfo *cur;
288 int error = 0;
289 struct addrinfo ai;
290 struct addrinfo ai0;
291 struct addrinfo *pai;
292 const struct afd *afd;
293 const struct explore *ex;
294
295 #ifdef FAITH
296 static int firsttime = 1;
297
298 if (firsttime) {
299 /* translator hack */
300 char *q = getenv("GAI");
301 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
302 translate = YES;
303 firsttime = 0;
304 }
305 #endif
306
307 sentinel.ai_next = NULL;
308 cur = &sentinel;
309 pai = &ai;
310 pai->ai_flags = 0;
311 pai->ai_family = PF_UNSPEC;
312 pai->ai_socktype = ANY;
313 pai->ai_protocol = ANY;
314 pai->ai_addrlen = 0;
315 pai->ai_canonname = NULL;
316 pai->ai_addr = NULL;
317 pai->ai_next = NULL;
318
319 if (hostname == NULL && servname == NULL)
320 return EAI_NONAME;
321 if (hints) {
322 /* error check for hints */
323 if (hints->ai_addrlen || hints->ai_canonname ||
324 hints->ai_addr || hints->ai_next)
325 ERR(EAI_BADHINTS); /* xxx */
326 if (hints->ai_flags & ~AI_MASK)
327 ERR(EAI_BADFLAGS);
328 switch (hints->ai_family) {
329 case PF_UNSPEC:
330 case PF_INET:
331 #ifdef INET6
332 case PF_INET6:
333 #endif
334 break;
335 default:
336 ERR(EAI_FAMILY);
337 }
338 memcpy(pai, hints, sizeof(*pai));
339
340 /*
341 * if both socktype/protocol are specified, check if they
342 * are meaningful combination.
343 */
344 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
345 for (ex = explore; ex->e_af >= 0; ex++) {
346 if (pai->ai_family != ex->e_af)
347 continue;
348 if (ex->e_socktype == ANY)
349 continue;
350 if (ex->e_protocol == ANY)
351 continue;
352 if (pai->ai_socktype == ex->e_socktype
353 && pai->ai_protocol != ex->e_protocol) {
354 ERR(EAI_BADHINTS);
355 }
356 }
357 }
358 }
359
360 /*
361 * check for special cases. (1) numeric servname is disallowed if
362 * socktype/protocol are left unspecified. (2) servname is disallowed
363 * for raw and other inet{,6} sockets.
364 */
365 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
366 #ifdef PF_INET6
367 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
368 #endif
369 ) {
370 ai0 = *pai;
371
372 if (pai->ai_family == PF_UNSPEC)
373 #ifdef PF_INET6
374 pai->ai_family = PF_INET6;
375 #else
376 pai->ai_family = PF_INET;
377 #endif
378 error = get_portmatch(pai, servname);
379 if (error)
380 ERR(error);
381
382 *pai = ai0;
383 }
384
385 ai0 = *pai;
386
387 /* NULL hostname, or numeric hostname */
388 for (ex = explore; ex->e_af >= 0; ex++) {
389 *pai = ai0;
390
391 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
392 continue;
393 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
394 continue;
395 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
396 continue;
397
398 if (pai->ai_family == PF_UNSPEC)
399 pai->ai_family = ex->e_af;
400 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
401 pai->ai_socktype = ex->e_socktype;
402 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
403 pai->ai_protocol = ex->e_protocol;
404
405 if (hostname == NULL)
406 error = explore_null(pai, hostname, servname, &cur->ai_next);
407 else
408 error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
409
410 if (error)
411 goto free;
412
413 while (cur && cur->ai_next)
414 cur = cur->ai_next;
415 }
416
417 /*
418 * XXX
419 * If numreic representation of AF1 can be interpreted as FQDN
420 * representation of AF2, we need to think again about the code below.
421 */
422 if (sentinel.ai_next)
423 goto good;
424
425 if (pai->ai_flags & AI_NUMERICHOST)
426 ERR(EAI_NONAME);
427 if (hostname == NULL)
428 ERR(EAI_NONAME);
429
430 /*
431 * hostname as alphabetical name.
432 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
433 * outer loop by AFs.
434 */
435 for (afd = afdl; afd->a_af; afd++) {
436 *pai = ai0;
437
438 if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
439 continue;
440
441 for (ex = explore; ex->e_af >= 0; ex++) {
442 *pai = ai0;
443
444 if (pai->ai_family == PF_UNSPEC)
445 pai->ai_family = afd->a_af;
446
447 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
448 continue;
449 if (!MATCH(pai->ai_socktype, ex->e_socktype,
450 WILD_SOCKTYPE(ex))) {
451 continue;
452 }
453 if (!MATCH(pai->ai_protocol, ex->e_protocol,
454 WILD_PROTOCOL(ex))) {
455 continue;
456 }
457
458 if (pai->ai_family == PF_UNSPEC)
459 pai->ai_family = ex->e_af;
460 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
461 pai->ai_socktype = ex->e_socktype;
462 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
463 pai->ai_protocol = ex->e_protocol;
464
465 error = explore_fqdn(pai, hostname, servname,
466 &cur->ai_next);
467
468 while (cur && cur->ai_next)
469 cur = cur->ai_next;
470 }
471 }
472
473 /* XXX */
474 if (sentinel.ai_next)
475 error = 0;
476
477 if (error)
478 goto free;
479 if (error == 0) {
480 if (sentinel.ai_next) {
481 good:
482 *res = sentinel.ai_next;
483 return SUCCESS;
484 } else
485 error = EAI_FAIL;
486 }
487 free:
488 bad:
489 if (sentinel.ai_next)
490 freeaddrinfo(sentinel.ai_next);
491 *res = NULL;
492 return error;
493 }
494
495 /*
496 * FQDN hostname, DNS lookup
497 */
498 static int
499 explore_fqdn(pai, hostname, servname, res)
500 const struct addrinfo *pai;
501 const char *hostname;
502 const char *servname;
503 struct addrinfo **res;
504 {
505 int s;
506 struct hostent *hp;
507 int h_error;
508 int af;
509 char *ap;
510 struct addrinfo sentinel, *cur;
511 int i;
512 const struct afd *afd;
513 int error;
514
515 *res = NULL;
516 sentinel.ai_next = NULL;
517 cur = &sentinel;
518
519 /*
520 * filter out AFs that are not supported by the kernel
521 * XXX errno?
522 */
523 s = socket(pai->ai_family, SOCK_DGRAM, 0);
524 if (s < 0)
525 return 0;
526 close(s);
527
528 /*
529 * if the servname does not match socktype/protocol, ignore it.
530 */
531 if (get_portmatch(pai, servname) != 0)
532 return 0;
533
534 afd = find_afd(pai->ai_family);
535
536 #ifdef USE_GETIPNODEBY
537 hp = getipnodebyname(hostname, pai->ai_family, AI_ADDRCONFIG, &h_error);
538 #elif defined(HAVE_GETHOSTBYNAME2)
539 hp = gethostbyname2(hostname, pai->ai_family);
540 #ifdef HAVE_H_ERRNO
541 h_error = h_errno;
542 #else
543 h_error = EINVAL;
544 #endif
545 #else
546 if (pai->ai_family != AF_INET)
547 return 0;
548 hp = gethostbyname(hostname);
549 #ifdef HAVE_H_ERRNO
550 h_error = h_errno;
551 #else
552 h_error = EINVAL;
553 #endif
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 #ifdef INET6
587 if (af == AF_INET6
588 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
589 af = AF_INET;
590 ap = ap + sizeof(struct in6_addr)
591 - sizeof(struct in_addr);
592 }
593 #endif
594
595 if (af != pai->ai_family)
596 continue;
597
598 if ((pai->ai_flags & AI_CANONNAME) == 0) {
599 GET_AI(cur->ai_next, afd, ap);
600 GET_PORT(cur->ai_next, servname);
601 } else {
602 /*
603 * if AI_CANONNAME and if reverse lookup
604 * fail, return ai anyway to pacify
605 * calling application.
606 *
607 * XXX getaddrinfo() is a name->address
608 * translation function, and it looks
609 * strange that we do addr->name
610 * translation here.
611 */
612 get_name(ap, afd, &cur->ai_next,
613 ap, pai, servname);
614 }
615
616 while (cur && cur->ai_next)
617 cur = cur->ai_next;
618 }
619
620 *res = sentinel.ai_next;
621 return 0;
622
623 free:
624 #ifdef USE_GETIPNODEBY
625 if (hp)
626 freehostent(hp);
627 #endif
628 if (sentinel.ai_next)
629 freeaddrinfo(sentinel.ai_next);
630 return error;
631 }
632
633 /*
634 * hostname == NULL.
635 * passive socket -> anyaddr (0.0.0.0 or ::)
636 * non-passive socket -> localhost (127.0.0.1 or ::1)
637 */
638 static int
639 explore_null(pai, hostname, servname, res)
640 const struct addrinfo *pai;
641 const char *hostname;
642 const char *servname;
643 struct addrinfo **res;
644 {
645 int s;
646 const struct afd *afd;
647 struct addrinfo *cur;
648 struct addrinfo sentinel;
649 int error;
650
651 *res = NULL;
652 sentinel.ai_next = NULL;
653 cur = &sentinel;
654
655 /*
656 * filter out AFs that are not supported by the kernel
657 * XXX errno?
658 */
659 s = socket(pai->ai_family, SOCK_DGRAM, 0);
660 if (s < 0)
661 return 0;
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 /* get_port does not touch first argument. when matchonly == 1. */
949 return get_port((struct addrinfo *)ai, servname, 1);
950 }
951
952 static int
953 get_port(ai, servname, matchonly)
954 struct addrinfo *ai;
955 const char *servname;
956 int matchonly;
957 {
958 const char *proto;
959 struct servent *sp;
960 int port;
961 int allownumeric;
962
963 if (servname == NULL)
964 return 0;
965 if (ai->ai_family != AF_INET
966 #ifdef AF_INET6
967 && ai->ai_family != AF_INET6
968 #endif
969 )
970 return 0;
971
972 switch (ai->ai_socktype) {
973 case SOCK_RAW:
974 return EAI_SERVICE;
975 case SOCK_DGRAM:
976 case SOCK_STREAM:
977 allownumeric = 1;
978 break;
979 case ANY:
980 allownumeric = 0;
981 break;
982 default:
983 return EAI_SOCKTYPE;
984 }
985
986 if (str_isnumber(servname)) {
987 if (!allownumeric)
988 return EAI_SERVICE;
989 port = htons(atoi(servname));
990 if (port < 0 || port > 65535)
991 return EAI_SERVICE;
992 } else {
993 switch (ai->ai_socktype) {
994 case SOCK_DGRAM:
995 proto = "udp";
996 break;
997 case SOCK_STREAM:
998 proto = "tcp";
999 break;
1000 default:
1001 proto = NULL;
1002 break;
1003 }
1004
1005 if ((sp = getservbyname(servname, proto)) == NULL)
1006 return EAI_SERVICE;
1007 port = sp->s_port;
1008 }
1009
1010 if (!matchonly) {
1011 switch (ai->ai_family) {
1012 case AF_INET:
1013 ((struct sockaddr_in *)ai->ai_addr)->sin_port = port;
1014 break;
1015 #ifdef INET6
1016 case AF_INET6:
1017 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port;
1018 break;
1019 #endif
1020 }
1021 }
1022
1023 return 0;
1024 }
1025
1026 static const struct afd *
1027 find_afd(af)
1028 int af;
1029 {
1030 const struct afd *afd;
1031
1032 if (af == PF_UNSPEC)
1033 return NULL;
1034 for (afd = afdl; afd->a_af; afd++) {
1035 if (afd->a_af == af)
1036 return afd;
1037 }
1038 return NULL;
1039 }