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