]> The Tcpdump Group git mirrors - tcpdump/blob - missing/getaddrinfo.c
778d8bf166c123b3309f9e618a4b1de5da2b3dd8
[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 #ifdef HAVE_H_ERRNO
543 h_error = h_errno;
544 #else
545 h_error = EINVAL;
546 #endif
547 #else
548 if (pai->ai_family != AF_INET)
549 return 0;
550 hp = gethostbyname(hostname);
551 #ifdef HAVE_H_ERRNO
552 h_error = h_errno;
553 #else
554 h_error = EINVAL;
555 #endif
556 #endif
557
558 if (hp == NULL) {
559 switch (h_error) {
560 case HOST_NOT_FOUND:
561 case NO_DATA:
562 error = EAI_NODATA;
563 break;
564 case TRY_AGAIN:
565 error = EAI_AGAIN;
566 break;
567 case NO_RECOVERY:
568 case NETDB_INTERNAL:
569 default:
570 error = EAI_FAIL;
571 break;
572 }
573 } else if ((hp->h_name == NULL) || (hp->h_name[0] == 0)
574 || (hp->h_addr_list[0] == NULL)) {
575 #ifdef USE_GETIPNODEBY
576 freehostent(hp);
577 #endif
578 hp = NULL;
579 error = EAI_FAIL;
580 }
581
582 if (hp == NULL)
583 goto free;
584
585 for (i = 0; hp->h_addr_list[i] != NULL; i++) {
586 af = hp->h_addrtype;
587 ap = hp->h_addr_list[i];
588 #ifdef INET6
589 if (af == AF_INET6
590 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
591 af = AF_INET;
592 ap = ap + sizeof(struct in6_addr)
593 - sizeof(struct in_addr);
594 }
595 #endif
596
597 if (af != pai->ai_family)
598 continue;
599
600 if ((pai->ai_flags & AI_CANONNAME) == 0) {
601 GET_AI(cur->ai_next, afd, ap);
602 GET_PORT(cur->ai_next, servname);
603 } else {
604 /*
605 * if AI_CANONNAME and if reverse lookup
606 * fail, return ai anyway to pacify
607 * calling application.
608 *
609 * XXX getaddrinfo() is a name->address
610 * translation function, and it looks
611 * strange that we do addr->name
612 * translation here.
613 */
614 get_name(ap, afd, &cur->ai_next,
615 ap, pai, servname);
616 }
617
618 while (cur && cur->ai_next)
619 cur = cur->ai_next;
620 }
621
622 *res = sentinel.ai_next;
623 return 0;
624
625 free:
626 #ifdef USE_GETIPNODEBY
627 if (hp)
628 freehostent(hp);
629 #endif
630 if (sentinel.ai_next)
631 freeaddrinfo(sentinel.ai_next);
632 return error;
633 }
634
635 /*
636 * hostname == NULL.
637 * passive socket -> anyaddr (0.0.0.0 or ::)
638 * non-passive socket -> localhost (127.0.0.1 or ::1)
639 */
640 static int
641 explore_null(pai, hostname, servname, res)
642 const struct addrinfo *pai;
643 const char *hostname;
644 const char *servname;
645 struct addrinfo **res;
646 {
647 int s;
648 const struct afd *afd;
649 struct addrinfo *cur;
650 struct addrinfo sentinel;
651 int error;
652
653 *res = NULL;
654 sentinel.ai_next = NULL;
655 cur = &sentinel;
656
657 /*
658 * filter out AFs that are not supported by the kernel
659 * XXX errno?
660 */
661 s = socket(pai->ai_family, SOCK_DGRAM, 0);
662 if (s < 0)
663 return 0;
664 close(s);
665
666 /*
667 * if the servname does not match socktype/protocol, ignore it.
668 */
669 if (get_portmatch(pai, servname) != 0)
670 return 0;
671
672 afd = find_afd(pai->ai_family);
673
674 if (pai->ai_flags & AI_PASSIVE) {
675 GET_AI(cur->ai_next, afd, afd->a_addrany);
676 /* xxx meaningless?
677 * GET_CANONNAME(cur->ai_next, "anyaddr");
678 */
679 GET_PORT(cur->ai_next, servname);
680 } else {
681 GET_AI(cur->ai_next, afd, afd->a_loopback);
682 /* xxx meaningless?
683 * GET_CANONNAME(cur->ai_next, "localhost");
684 */
685 GET_PORT(cur->ai_next, servname);
686 }
687 cur = cur->ai_next;
688
689 *res = sentinel.ai_next;
690 return 0;
691
692 free:
693 if (sentinel.ai_next)
694 freeaddrinfo(sentinel.ai_next);
695 return error;
696 }
697
698 /*
699 * numeric hostname
700 */
701 static int
702 explore_numeric(pai, hostname, servname, res)
703 const struct addrinfo *pai;
704 const char *hostname;
705 const char *servname;
706 struct addrinfo **res;
707 {
708 const struct afd *afd;
709 struct addrinfo *cur;
710 struct addrinfo sentinel;
711 int error;
712 char pton[PTON_MAX];
713 int flags;
714
715 *res = NULL;
716 sentinel.ai_next = NULL;
717 cur = &sentinel;
718
719 /*
720 * if the servname does not match socktype/protocol, ignore it.
721 */
722 if (get_portmatch(pai, servname) != 0)
723 return 0;
724
725 afd = find_afd(pai->ai_family);
726 flags = pai->ai_flags;
727
728 if (inet_pton(afd->a_af, hostname, pton) == 1) {
729 u_int32_t v4a;
730 #ifdef INET6
731 u_char pfx;
732 #endif
733
734 switch (afd->a_af) {
735 case AF_INET:
736 v4a = (u_int32_t)ntohl(((struct in_addr *)pton)->s_addr);
737 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
738 flags &= ~AI_CANONNAME;
739 v4a >>= IN_CLASSA_NSHIFT;
740 if (v4a == 0 || v4a == IN_LOOPBACKNET)
741 flags &= ~AI_CANONNAME;
742 break;
743 #ifdef INET6
744 case AF_INET6:
745 pfx = ((struct in6_addr *)pton)->s6_addr[0];
746 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
747 flags &= ~AI_CANONNAME;
748 break;
749 #endif
750 }
751
752 if (pai->ai_family == afd->a_af ||
753 pai->ai_family == PF_UNSPEC /*?*/) {
754 if ((flags & AI_CANONNAME) == 0) {
755 GET_AI(cur->ai_next, afd, pton);
756 GET_PORT(cur->ai_next, servname);
757 } else {
758 /*
759 * if AI_CANONNAME and if reverse lookup
760 * fail, return ai anyway to pacify
761 * calling application.
762 *
763 * XXX getaddrinfo() is a name->address
764 * translation function, and it looks
765 * strange that we do addr->name
766 * translation here.
767 */
768 get_name(pton, afd, &cur->ai_next,
769 pton, pai, servname);
770 }
771 while (cur && cur->ai_next)
772 cur = cur->ai_next;
773 } else
774 ERR(EAI_FAMILY); /*xxx*/
775 }
776
777 *res = sentinel.ai_next;
778 return 0;
779
780 free:
781 bad:
782 if (sentinel.ai_next)
783 freeaddrinfo(sentinel.ai_next);
784 return error;
785 }
786
787 /*
788 * numeric hostname with scope
789 */
790 static int
791 explore_numeric_scope(pai, hostname, servname, res)
792 const struct addrinfo *pai;
793 const char *hostname;
794 const char *servname;
795 struct addrinfo **res;
796 {
797 #ifndef SCOPE_DELIMITER
798 return explore_numeric(pai, hostname, servname, res);
799 #else
800 const struct afd *afd;
801 struct addrinfo *cur;
802 int error;
803 char *cp, *hostname2 = NULL;
804 int scope;
805 struct sockaddr_in6 *sin6;
806
807 /*
808 * if the servname does not match socktype/protocol, ignore it.
809 */
810 if (get_portmatch(pai, servname) != 0)
811 return 0;
812
813 afd = find_afd(pai->ai_family);
814 if (!afd->a_scoped)
815 return explore_numeric(pai, hostname, servname, res);
816
817 cp = strchr(hostname, SCOPE_DELIMITER);
818 if (cp == NULL)
819 return explore_numeric(pai, hostname, servname, res);
820
821 /*
822 * Handle special case of <scoped_address><delimiter><scope id>
823 */
824 hostname2 = strdup(hostname);
825 if (hostname2 == NULL)
826 return EAI_MEMORY;
827 /* terminate at the delimiter */
828 hostname2[cp - hostname] = '\0';
829
830 cp++;
831 switch (pai->ai_family) {
832 #ifdef INET6
833 case AF_INET6:
834 scope = if_nametoindex(cp);
835 break;
836 #endif
837 }
838
839 error = explore_numeric(pai, hostname2, servname, res);
840 if (error == 0) {
841 for (cur = *res; cur; cur = cur->ai_next) {
842 if (cur->ai_family != AF_INET6)
843 continue;
844 sin6 = (struct sockaddr_in6 *)cur->ai_addr;
845 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
846 IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr))
847 sin6->sin6_scope_id = scope;
848 }
849 }
850
851 free(hostname2);
852
853 return error;
854 #endif
855 }
856
857 static int
858 get_name(addr, afd, res, numaddr, pai, servname)
859 const char *addr;
860 const struct afd *afd;
861 struct addrinfo **res;
862 char *numaddr;
863 const struct addrinfo *pai;
864 const char *servname;
865 {
866 struct hostent *hp;
867 struct addrinfo *cur;
868 int error = 0;
869 #ifdef USE_GETIPNODEBY
870 int h_error;
871
872 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
873 #else
874 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
875 #endif
876 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
877 GET_AI(cur, afd, hp->h_addr_list[0]);
878 GET_PORT(cur, servname);
879 GET_CANONNAME(cur, hp->h_name);
880 } else {
881 GET_AI(cur, afd, numaddr);
882 GET_PORT(cur, servname);
883 }
884
885 #ifdef USE_GETIPNODEBY
886 if (hp)
887 freehostent(hp);
888 #endif
889 *res = cur;
890 return SUCCESS;
891 free:
892 if (cur)
893 freeaddrinfo(cur);
894 #ifdef USE_GETIPNODEBY
895 if (hp)
896 freehostent(hp);
897 #endif
898 /* bad: */
899 *res = NULL;
900 return error;
901 }
902
903 static int
904 get_canonname(pai, ai, str)
905 const struct addrinfo *pai;
906 struct addrinfo *ai;
907 const char *str;
908 {
909 if ((pai->ai_flags & AI_CANONNAME) != 0) {
910 ai->ai_canonname = (char *)malloc(strlen(str) + 1);
911 if (ai->ai_canonname == NULL)
912 return EAI_MEMORY;
913 strcpy(ai->ai_canonname, str);
914 }
915 return 0;
916 }
917
918 static struct addrinfo *
919 get_ai(pai, afd, addr)
920 const struct addrinfo *pai;
921 const struct afd *afd;
922 const char *addr;
923 {
924 char *p;
925 struct addrinfo *ai;
926
927 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
928 + (afd->a_socklen));
929 if (ai == NULL)
930 return NULL;
931
932 memcpy(ai, pai, sizeof(struct addrinfo));
933 ai->ai_addr = (struct sockaddr *)(ai + 1);
934 memset(ai->ai_addr, 0, afd->a_socklen);
935 #ifdef HAVE_SOCKADDR_SA_LEN
936 ai->ai_addr->sa_len = afd->a_socklen;
937 #endif
938 ai->ai_addrlen = afd->a_socklen;
939 ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
940 p = (char *)(ai->ai_addr);
941 memcpy(p + afd->a_off, addr, afd->a_addrlen);
942 return ai;
943 }
944
945 static int
946 get_portmatch(ai, servname)
947 const struct addrinfo *ai;
948 const char *servname;
949 {
950 /* get_port does not touch first argument. when matchonly == 1. */
951 return get_port((struct addrinfo *)ai, servname, 1);
952 }
953
954 static int
955 get_port(ai, servname, matchonly)
956 struct addrinfo *ai;
957 const char *servname;
958 int matchonly;
959 {
960 const char *proto;
961 struct servent *sp;
962 int port;
963 int allownumeric;
964
965 if (servname == NULL)
966 return 0;
967 if (ai->ai_family != AF_INET
968 #ifdef AF_INET6
969 && ai->ai_family != AF_INET6
970 #endif
971 )
972 return 0;
973
974 switch (ai->ai_socktype) {
975 case SOCK_RAW:
976 return EAI_SERVICE;
977 case SOCK_DGRAM:
978 case SOCK_STREAM:
979 allownumeric = 1;
980 break;
981 case ANY:
982 allownumeric = 0;
983 break;
984 default:
985 return EAI_SOCKTYPE;
986 }
987
988 if (str_isnumber(servname)) {
989 if (!allownumeric)
990 return EAI_SERVICE;
991 port = htons(atoi(servname));
992 if (port < 0 || port > 65535)
993 return EAI_SERVICE;
994 } else {
995 switch (ai->ai_socktype) {
996 case SOCK_DGRAM:
997 proto = "udp";
998 break;
999 case SOCK_STREAM:
1000 proto = "tcp";
1001 break;
1002 default:
1003 proto = NULL;
1004 break;
1005 }
1006
1007 if ((sp = getservbyname(servname, proto)) == NULL)
1008 return EAI_SERVICE;
1009 port = sp->s_port;
1010 }
1011
1012 if (!matchonly) {
1013 switch (ai->ai_family) {
1014 case AF_INET:
1015 ((struct sockaddr_in *)ai->ai_addr)->sin_port = port;
1016 break;
1017 #ifdef INET6
1018 case AF_INET6:
1019 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port;
1020 break;
1021 #endif
1022 }
1023 }
1024
1025 return 0;
1026 }
1027
1028 static const struct afd *
1029 find_afd(af)
1030 int af;
1031 {
1032 const struct afd *afd;
1033
1034 if (af == PF_UNSPEC)
1035 return NULL;
1036 for (afd = afdl; afd->a_af; afd++) {
1037 if (afd->a_af == af)
1038 return afd;
1039 }
1040 return NULL;
1041 }