Remove building with NOCRYPTO option
[minix.git] / external / bsd / libpcap / dist / Win32 / Src / getaddrinfo.c
blobd3ebda085f632da0e3f664665b146f8d7deff65e
1 /*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
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.
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.
31 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
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 * Note:
39 * - We use getipnodebyname() just for thread-safeness. There's no intent
40 * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
41 * getipnodebyname().
42 * - The code filters out AFs that are not supported by the kernel,
43 * when globbing NULL hostname (to loopback, or wildcard). Is it the right
44 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
45 * in ai_flags?
49 * Mingw64 has its own implementation of getaddrinfo, mingw32 no
51 #ifndef __MINGW64__
54 #ifdef HAVE_CONFIG_H
55 #include <config.h>
56 #endif
58 #include <pcap-stdinc.h>
59 #if 0
60 #include <sys/sysctl.h>
61 #endif
62 #ifndef __MINGW32__
63 #include <arpa/nameser.h>
64 #endif
65 #include <string.h>
66 #include <stdlib.h>
67 #include <stddef.h>
68 #include <ctype.h>
69 #include <stdio.h>
70 #include <errno.h>
72 #ifndef HAVE_PORTABLE_PROTOTYPE
73 #include "cdecl_ext.h"
74 #endif
76 #ifndef HAVE_U_INT32_T
77 #include "bittypes.h"
78 #endif
80 #ifndef HAVE_SOCKADDR_STORAGE
81 #ifndef __MINGW32__
82 #include "sockstorage.h"
83 #endif
84 #endif
86 #ifdef NEED_ADDRINFO_H
87 #include "addrinfo.h"
88 #ifdef WIN32
89 #include "ip6_misc.h"
90 #endif
91 #endif
94 #if defined(__KAME__) && defined(INET6)
95 # define FAITH
96 #endif
98 #define SUCCESS 0
99 #define ANY 0
100 #define YES 1
101 #define NO 0
103 #ifdef FAITH
104 static int translate = NO;
105 static struct in6_addr faith_prefix = IN6ADDR_ANY_INIT;
106 #endif
108 static const char in_addrany[] = { 0, 0, 0, 0 };
109 static const char in6_addrany[] = {
110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
112 static const char in_loopback[] = { 127, 0, 0, 1 };
113 static const char in6_loopback[] = {
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
117 struct sockinet {
118 u_char si_len;
119 u_char si_family;
120 u_short si_port;
121 u_int32_t si_scope_id;
124 static const struct afd {
125 int a_af;
126 int a_addrlen;
127 int a_socklen;
128 int a_off;
129 const char *a_addrany;
130 const char *a_loopback;
131 int a_scoped;
132 } afdl [] = {
133 #ifdef INET6
134 {PF_INET6, sizeof(struct in6_addr),
135 sizeof(struct sockaddr_in6),
136 offsetof(struct sockaddr_in6, sin6_addr),
137 in6_addrany, in6_loopback, 1},
138 #endif
139 {PF_INET, sizeof(struct in_addr),
140 sizeof(struct sockaddr_in),
141 offsetof(struct sockaddr_in, sin_addr),
142 in_addrany, in_loopback, 0},
143 {0, 0, 0, 0, NULL, NULL, 0},
146 struct explore {
147 int e_af;
148 int e_socktype;
149 int e_protocol;
150 const char *e_protostr;
151 int e_wild;
152 #define WILD_AF(ex) ((ex)->e_wild & 0x01)
153 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
154 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
157 static const struct explore explore[] = {
158 #if 0
159 { PF_LOCAL, 0, ANY, ANY, NULL, 0x01 },
160 #endif
161 #ifdef INET6
162 { PF_INET6, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
163 { PF_INET6, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
164 { PF_INET6, SOCK_RAW, ANY, NULL, 0x05 },
165 #endif
166 { PF_INET, SOCK_DGRAM, IPPROTO_UDP, "udp", 0x07 },
167 { PF_INET, SOCK_STREAM, IPPROTO_TCP, "tcp", 0x07 },
168 { PF_INET, SOCK_RAW, ANY, NULL, 0x05 },
169 { -1, 0, 0, NULL, 0 },
172 #ifdef INET6
173 #define PTON_MAX 16
174 #else
175 #define PTON_MAX 4
176 #endif
179 static int str_isnumber __P((const char *));
180 static int explore_fqdn __P((const struct addrinfo *, const char *,
181 const char *, struct addrinfo **));
182 static int explore_null __P((const struct addrinfo *, const char *,
183 const char *, struct addrinfo **));
184 static int explore_numeric __P((const struct addrinfo *, const char *,
185 const char *, struct addrinfo **));
186 static int explore_numeric_scope __P((const struct addrinfo *, const char *,
187 const char *, struct addrinfo **));
188 static int get_name __P((const char *, const struct afd *, struct addrinfo **,
189 char *, const struct addrinfo *, const char *));
190 static int get_canonname __P((const struct addrinfo *,
191 struct addrinfo *, const char *));
192 static struct addrinfo *get_ai __P((const struct addrinfo *,
193 const struct afd *, const char *));
194 static int get_portmatch __P((const struct addrinfo *, const char *));
195 static int get_port __P((struct addrinfo *, const char *, int));
196 static const struct afd *find_afd __P((int));
198 static char *ai_errlist[] = {
199 "Success",
200 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
201 "Temporary failure in name resolution", /* EAI_AGAIN */
202 "Invalid value for ai_flags", /* EAI_BADFLAGS */
203 "Non-recoverable failure in name resolution", /* EAI_FAIL */
204 "ai_family not supported", /* EAI_FAMILY */
205 "Memory allocation failure", /* EAI_MEMORY */
206 "No address associated with hostname", /* EAI_NODATA */
207 "hostname nor servname provided, or not known", /* EAI_NONAME */
208 "servname not supported for ai_socktype", /* EAI_SERVICE */
209 "ai_socktype not supported", /* EAI_SOCKTYPE */
210 "System error returned in errno", /* EAI_SYSTEM */
211 "Invalid value for hints", /* EAI_BADHINTS */
212 "Resolved protocol is unknown", /* EAI_PROTOCOL */
213 "Unknown error", /* EAI_MAX */
216 /* XXX macros that make external reference is BAD. */
218 #define GET_AI(ai, afd, addr) \
219 do { \
220 /* external reference: pai, error, and label free */ \
221 (ai) = get_ai(pai, (afd), (addr)); \
222 if ((ai) == NULL) { \
223 error = EAI_MEMORY; \
224 goto free; \
226 } while (0)
228 #define GET_PORT(ai, serv) \
229 do { \
230 /* external reference: error and label free */ \
231 error = get_port((ai), (serv), 0); \
232 if (error != 0) \
233 goto free; \
234 } while (0)
236 #define GET_CANONNAME(ai, str) \
237 do { \
238 /* external reference: pai, error and label free */ \
239 error = get_canonname(pai, (ai), (str)); \
240 if (error != 0) \
241 goto free; \
242 } while (0)
244 #define ERR(err) \
245 do { \
246 /* external reference: error, and label bad */ \
247 error = (err); \
248 goto bad; \
249 } while (0)
251 #define MATCH_FAMILY(x, y, w) \
252 ((x) == (y) || ((w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
253 #define MATCH(x, y, w) \
254 ((x) == (y) || ((w) && ((x) == ANY || (y) == ANY)))
256 #if defined(DEFINE_ADDITIONAL_IPV6_STUFF)
257 char *
258 gai_strerror(ecode)
259 int ecode;
261 if (ecode < 0 || ecode > EAI_MAX)
262 ecode = EAI_MAX;
263 return ai_errlist[ecode];
265 #endif
267 void
268 freeaddrinfo(ai)
269 struct addrinfo *ai;
271 struct addrinfo *next;
273 do {
274 next = ai->ai_next;
275 if (ai->ai_canonname)
276 free(ai->ai_canonname);
277 /* no need to free(ai->ai_addr) */
278 free(ai);
279 } while ((ai = next) != NULL);
282 static int
283 str_isnumber(p)
284 const char *p;
286 char *q = (char *)p;
287 while (*q) {
288 if (! isdigit(*q))
289 return NO;
290 q++;
292 return YES;
296 getaddrinfo(hostname, servname, hints, res)
297 const char *hostname, *servname;
298 const struct addrinfo *hints;
299 struct addrinfo **res;
301 struct addrinfo sentinel;
302 struct addrinfo *cur;
303 int error = 0;
304 struct addrinfo ai;
305 struct addrinfo ai0;
306 struct addrinfo *pai;
307 const struct afd *afd;
308 const struct explore *ex;
310 #ifdef FAITH
311 static int firsttime = 1;
313 if (firsttime) {
314 /* translator hack */
315 char *q = getenv("GAI");
316 if (q && inet_pton(AF_INET6, q, &faith_prefix) == 1)
317 translate = YES;
318 firsttime = 0;
320 #endif
322 sentinel.ai_next = NULL;
323 cur = &sentinel;
324 pai = &ai;
325 pai->ai_flags = 0;
326 pai->ai_family = PF_UNSPEC;
327 pai->ai_socktype = ANY;
328 pai->ai_protocol = ANY;
329 pai->ai_addrlen = 0;
330 pai->ai_canonname = NULL;
331 pai->ai_addr = NULL;
332 pai->ai_next = NULL;
334 if (hostname == NULL && servname == NULL)
335 return EAI_NONAME;
336 if (hints) {
337 /* error check for hints */
338 if (hints->ai_addrlen || hints->ai_canonname ||
339 hints->ai_addr || hints->ai_next)
340 ERR(EAI_BADHINTS); /* xxx */
341 if (hints->ai_flags & ~AI_MASK)
342 ERR(EAI_BADFLAGS);
343 switch (hints->ai_family) {
344 case PF_UNSPEC:
345 case PF_INET:
346 #ifdef INET6
347 case PF_INET6:
348 #endif
349 break;
350 default:
351 ERR(EAI_FAMILY);
353 memcpy(pai, hints, sizeof(*pai));
356 * if both socktype/protocol are specified, check if they
357 * are meaningful combination.
359 if (pai->ai_socktype != ANY && pai->ai_protocol != ANY) {
360 for (ex = explore; ex->e_af >= 0; ex++) {
361 if (pai->ai_family != ex->e_af)
362 continue;
363 if (ex->e_socktype == ANY)
364 continue;
365 if (ex->e_protocol == ANY)
366 continue;
367 if (pai->ai_socktype == ex->e_socktype
368 && pai->ai_protocol != ex->e_protocol) {
369 ERR(EAI_BADHINTS);
376 * check for special cases. (1) numeric servname is disallowed if
377 * socktype/protocol are left unspecified. (2) servname is disallowed
378 * for raw and other inet{,6} sockets.
380 if (MATCH_FAMILY(pai->ai_family, PF_INET, 1)
381 #ifdef PF_INET6
382 || MATCH_FAMILY(pai->ai_family, PF_INET6, 1)
383 #endif
385 ai0 = *pai;
387 if (pai->ai_family == PF_UNSPEC) {
388 #ifdef PF_INET6
389 pai->ai_family = PF_INET6;
390 #else
391 pai->ai_family = PF_INET;
392 #endif
394 error = get_portmatch(pai, servname);
395 if (error)
396 ERR(error);
398 *pai = ai0;
401 ai0 = *pai;
403 /* NULL hostname, or numeric hostname */
404 for (ex = explore; ex->e_af >= 0; ex++) {
405 *pai = ai0;
407 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
408 continue;
409 if (!MATCH(pai->ai_socktype, ex->e_socktype, WILD_SOCKTYPE(ex)))
410 continue;
411 if (!MATCH(pai->ai_protocol, ex->e_protocol, WILD_PROTOCOL(ex)))
412 continue;
414 if (pai->ai_family == PF_UNSPEC)
415 pai->ai_family = ex->e_af;
416 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
417 pai->ai_socktype = ex->e_socktype;
418 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
419 pai->ai_protocol = ex->e_protocol;
421 if (hostname == NULL)
422 error = explore_null(pai, hostname, servname, &cur->ai_next);
423 else
424 error = explore_numeric_scope(pai, hostname, servname, &cur->ai_next);
426 if (error)
427 goto free;
429 while (cur && cur->ai_next)
430 cur = cur->ai_next;
434 * XXX
435 * If numreic representation of AF1 can be interpreted as FQDN
436 * representation of AF2, we need to think again about the code below.
438 if (sentinel.ai_next)
439 goto good;
441 if (pai->ai_flags & AI_NUMERICHOST)
442 ERR(EAI_NONAME);
443 if (hostname == NULL)
444 ERR(EAI_NONAME);
447 * hostname as alphabetical name.
448 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
449 * outer loop by AFs.
451 for (afd = afdl; afd->a_af; afd++) {
452 *pai = ai0;
454 if (!MATCH_FAMILY(pai->ai_family, afd->a_af, 1))
455 continue;
457 for (ex = explore; ex->e_af >= 0; ex++) {
458 *pai = ai0;
460 if (pai->ai_family == PF_UNSPEC)
461 pai->ai_family = afd->a_af;
463 if (!MATCH_FAMILY(pai->ai_family, ex->e_af, WILD_AF(ex)))
464 continue;
465 if (!MATCH(pai->ai_socktype, ex->e_socktype,
466 WILD_SOCKTYPE(ex))) {
467 continue;
469 if (!MATCH(pai->ai_protocol, ex->e_protocol,
470 WILD_PROTOCOL(ex))) {
471 continue;
474 if (pai->ai_family == PF_UNSPEC)
475 pai->ai_family = ex->e_af;
476 if (pai->ai_socktype == ANY && ex->e_socktype != ANY)
477 pai->ai_socktype = ex->e_socktype;
478 if (pai->ai_protocol == ANY && ex->e_protocol != ANY)
479 pai->ai_protocol = ex->e_protocol;
481 error = explore_fqdn(pai, hostname, servname,
482 &cur->ai_next);
484 while (cur && cur->ai_next)
485 cur = cur->ai_next;
489 /* XXX */
490 if (sentinel.ai_next)
491 error = 0;
493 if (error)
494 goto free;
495 if (error == 0) {
496 if (sentinel.ai_next) {
497 good:
498 *res = sentinel.ai_next;
499 return SUCCESS;
500 } else
501 error = EAI_FAIL;
503 free:
504 bad:
505 if (sentinel.ai_next)
506 freeaddrinfo(sentinel.ai_next);
507 *res = NULL;
508 return error;
512 * FQDN hostname, DNS lookup
514 static int
515 explore_fqdn(pai, hostname, servname, res)
516 const struct addrinfo *pai;
517 const char *hostname;
518 const char *servname;
519 struct addrinfo **res;
521 struct hostent *hp;
522 int h_error;
523 int af;
524 char **aplist = NULL, *apbuf = NULL;
525 char *ap;
526 struct addrinfo sentinel, *cur;
527 int i;
528 #ifndef USE_GETIPNODEBY
529 int naddrs;
530 #endif
531 const struct afd *afd;
532 int error;
534 *res = NULL;
535 sentinel.ai_next = NULL;
536 cur = &sentinel;
539 * Do not filter unsupported AFs here. We need to honor content of
540 * databases (/etc/hosts, DNS and others). Otherwise we cannot
541 * replace gethostbyname() by getaddrinfo().
545 * if the servname does not match socktype/protocol, ignore it.
547 if (get_portmatch(pai, servname) != 0)
548 return 0;
550 afd = find_afd(pai->ai_family);
553 * post-RFC2553: should look at (pai->ai_flags & AI_ADDRCONFIG)
554 * rather than hardcoding it. we may need to add AI_ADDRCONFIG
555 * handling code by ourselves in case we don't have getipnodebyname().
557 #ifdef USE_GETIPNODEBY
558 hp = getipnodebyname(hostname, pai->ai_family, AI_ADDRCONFIG, &h_error);
559 #else
560 #ifdef HAVE_GETHOSTBYNAME2
561 hp = gethostbyname2(hostname, pai->ai_family);
562 #else
563 if (pai->ai_family != AF_INET)
564 return 0;
565 hp = gethostbyname(hostname);
566 #ifdef HAVE_H_ERRNO
567 h_error = h_errno;
568 #else
569 h_error = EINVAL;
570 #endif
571 #endif /*HAVE_GETHOSTBYNAME2*/
572 #endif /*USE_GETIPNODEBY*/
574 if (hp == NULL) {
575 switch (h_error) {
576 case HOST_NOT_FOUND:
577 case NO_DATA:
578 error = EAI_NODATA;
579 break;
580 case TRY_AGAIN:
581 error = EAI_AGAIN;
582 break;
583 case NO_RECOVERY:
584 case NETDB_INTERNAL:
585 default:
586 error = EAI_FAIL;
587 break;
589 } else if ((hp->h_name == NULL) || (hp->h_name[0] == 0)
590 || (hp->h_addr_list[0] == NULL)) {
591 #ifdef USE_GETIPNODEBY
592 freehostent(hp);
593 #endif
594 hp = NULL;
595 error = EAI_FAIL;
598 if (hp == NULL)
599 goto free;
601 #ifdef USE_GETIPNODEBY
602 aplist = hp->h_addr_list;
603 #else
605 * hp will be overwritten if we use gethostbyname2().
606 * always deep copy for simplification.
608 for (naddrs = 0; hp->h_addr_list[naddrs] != NULL; naddrs++)
610 naddrs++;
611 aplist = (char **)malloc(sizeof(aplist[0]) * naddrs);
612 apbuf = (char *)malloc(hp->h_length * naddrs);
613 if (aplist == NULL || apbuf == NULL) {
614 error = EAI_MEMORY;
615 goto free;
617 memset(aplist, 0, sizeof(aplist[0]) * naddrs);
618 for (i = 0; i < naddrs; i++) {
619 if (hp->h_addr_list[i] == NULL) {
620 aplist[i] = NULL;
621 continue;
623 memcpy(&apbuf[i * hp->h_length], hp->h_addr_list[i],
624 hp->h_length);
625 aplist[i] = &apbuf[i * hp->h_length];
627 #endif
629 for (i = 0; aplist[i] != NULL; i++) {
630 af = hp->h_addrtype;
631 ap = aplist[i];
632 #ifdef AF_INET6
633 if (af == AF_INET6
634 && IN6_IS_ADDR_V4MAPPED((struct in6_addr *)ap)) {
635 af = AF_INET;
636 ap = ap + sizeof(struct in6_addr)
637 - sizeof(struct in_addr);
639 #endif
641 if (af != pai->ai_family)
642 continue;
644 if ((pai->ai_flags & AI_CANONNAME) == 0) {
645 GET_AI(cur->ai_next, afd, ap);
646 GET_PORT(cur->ai_next, servname);
647 } else {
649 * if AI_CANONNAME and if reverse lookup
650 * fail, return ai anyway to pacify
651 * calling application.
653 * XXX getaddrinfo() is a name->address
654 * translation function, and it looks
655 * strange that we do addr->name
656 * translation here.
658 get_name(ap, afd, &cur->ai_next,
659 ap, pai, servname);
662 while (cur && cur->ai_next)
663 cur = cur->ai_next;
666 *res = sentinel.ai_next;
667 return 0;
669 free:
670 #ifdef USE_GETIPNODEBY
671 if (hp)
672 freehostent(hp);
673 #endif
674 if (aplist)
675 free(aplist);
676 if (apbuf)
677 free(apbuf);
678 if (sentinel.ai_next)
679 freeaddrinfo(sentinel.ai_next);
680 return error;
684 * hostname == NULL.
685 * passive socket -> anyaddr (0.0.0.0 or ::)
686 * non-passive socket -> localhost (127.0.0.1 or ::1)
688 static int
689 explore_null(pai, hostname, servname, res)
690 const struct addrinfo *pai;
691 const char *hostname;
692 const char *servname;
693 struct addrinfo **res;
695 int s;
696 const struct afd *afd;
697 struct addrinfo *cur;
698 struct addrinfo sentinel;
699 int error;
701 *res = NULL;
702 sentinel.ai_next = NULL;
703 cur = &sentinel;
706 * filter out AFs that are not supported by the kernel
707 * XXX errno?
709 s = socket(pai->ai_family, SOCK_DGRAM, 0);
710 if (s < 0) {
711 if (errno != EMFILE)
712 return 0;
713 } else
714 close(s);
717 * if the servname does not match socktype/protocol, ignore it.
719 if (get_portmatch(pai, servname) != 0)
720 return 0;
722 afd = find_afd(pai->ai_family);
724 if (pai->ai_flags & AI_PASSIVE) {
725 GET_AI(cur->ai_next, afd, afd->a_addrany);
726 /* xxx meaningless?
727 * GET_CANONNAME(cur->ai_next, "anyaddr");
729 GET_PORT(cur->ai_next, servname);
730 } else {
731 GET_AI(cur->ai_next, afd, afd->a_loopback);
732 /* xxx meaningless?
733 * GET_CANONNAME(cur->ai_next, "localhost");
735 GET_PORT(cur->ai_next, servname);
737 cur = cur->ai_next;
739 *res = sentinel.ai_next;
740 return 0;
742 free:
743 if (sentinel.ai_next)
744 freeaddrinfo(sentinel.ai_next);
745 return error;
749 * numeric hostname
751 static int
752 explore_numeric(pai, hostname, servname, res)
753 const struct addrinfo *pai;
754 const char *hostname;
755 const char *servname;
756 struct addrinfo **res;
758 const struct afd *afd;
759 struct addrinfo *cur;
760 struct addrinfo sentinel;
761 int error;
762 char pton[PTON_MAX];
763 int flags;
765 *res = NULL;
766 sentinel.ai_next = NULL;
767 cur = &sentinel;
770 * if the servname does not match socktype/protocol, ignore it.
772 if (get_portmatch(pai, servname) != 0)
773 return 0;
775 afd = find_afd(pai->ai_family);
776 flags = pai->ai_flags;
778 if (inet_pton(afd->a_af, hostname, pton) == 1) {
779 u_int32_t v4a;
780 #ifdef INET6
781 u_char pfx;
782 #endif
784 switch (afd->a_af) {
785 case AF_INET:
786 v4a = (u_int32_t)ntohl(((struct in_addr *)pton)->s_addr);
787 if (IN_MULTICAST(v4a) || IN_EXPERIMENTAL(v4a))
788 flags &= ~AI_CANONNAME;
789 v4a >>= IN_CLASSA_NSHIFT;
790 if (v4a == 0 || v4a == IN_LOOPBACKNET)
791 flags &= ~AI_CANONNAME;
792 break;
793 #ifdef INET6
794 case AF_INET6:
795 pfx = ((struct in6_addr *)pton)->s6_addr[0];
796 if (pfx == 0 || pfx == 0xfe || pfx == 0xff)
797 flags &= ~AI_CANONNAME;
798 break;
799 #endif
802 if (pai->ai_family == afd->a_af ||
803 pai->ai_family == PF_UNSPEC /*?*/) {
804 if ((flags & AI_CANONNAME) == 0) {
805 GET_AI(cur->ai_next, afd, pton);
806 GET_PORT(cur->ai_next, servname);
807 } else {
809 * if AI_CANONNAME and if reverse lookup
810 * fail, return ai anyway to pacify
811 * calling application.
813 * XXX getaddrinfo() is a name->address
814 * translation function, and it looks
815 * strange that we do addr->name
816 * translation here.
818 get_name(pton, afd, &cur->ai_next,
819 pton, pai, servname);
821 while (cur && cur->ai_next)
822 cur = cur->ai_next;
823 } else
824 ERR(EAI_FAMILY); /*xxx*/
827 *res = sentinel.ai_next;
828 return 0;
830 free:
831 bad:
832 if (sentinel.ai_next)
833 freeaddrinfo(sentinel.ai_next);
834 return error;
838 * numeric hostname with scope
840 static int
841 explore_numeric_scope(pai, hostname, servname, res)
842 const struct addrinfo *pai;
843 const char *hostname;
844 const char *servname;
845 struct addrinfo **res;
847 #ifndef SCOPE_DELIMITER
848 return explore_numeric(pai, hostname, servname, res);
849 #else
850 const struct afd *afd;
851 struct addrinfo *cur;
852 int error;
853 char *cp, *hostname2 = NULL;
854 int scope;
855 struct sockaddr_in6 *sin6;
858 * if the servname does not match socktype/protocol, ignore it.
860 if (get_portmatch(pai, servname) != 0)
861 return 0;
863 afd = find_afd(pai->ai_family);
864 if (!afd->a_scoped)
865 return explore_numeric(pai, hostname, servname, res);
867 cp = strchr(hostname, SCOPE_DELIMITER);
868 if (cp == NULL)
869 return explore_numeric(pai, hostname, servname, res);
872 * Handle special case of <scoped_address><delimiter><scope id>
874 hostname2 = strdup(hostname);
875 if (hostname2 == NULL)
876 return EAI_MEMORY;
877 /* terminate at the delimiter */
878 hostname2[cp - hostname] = '\0';
880 cp++;
881 switch (pai->ai_family) {
882 #ifdef INET6
883 case AF_INET6:
884 scope = if_nametoindex(cp);
885 if (scope == 0) {
886 free(hostname2);
887 return (EAI_NONAME);
889 break;
890 #endif
893 error = explore_numeric(pai, hostname2, servname, res);
894 if (error == 0) {
895 for (cur = *res; cur; cur = cur->ai_next) {
896 if (cur->ai_family != AF_INET6)
897 continue;
898 sin6 = (struct sockaddr_in6 *)cur->ai_addr;
899 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) ||
900 IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr))
901 sin6->sin6_scope_id = scope;
905 free(hostname2);
907 return error;
908 #endif
911 static int
912 get_name(addr, afd, res, numaddr, pai, servname)
913 const char *addr;
914 const struct afd *afd;
915 struct addrinfo **res;
916 char *numaddr;
917 const struct addrinfo *pai;
918 const char *servname;
920 struct hostent *hp = NULL;
921 struct addrinfo *cur = NULL;
922 int error = 0;
923 char *ap = NULL, *cn = NULL;
924 #ifdef USE_GETIPNODEBY
925 int h_error;
927 hp = getipnodebyaddr(addr, afd->a_addrlen, afd->a_af, &h_error);
928 #else
929 hp = gethostbyaddr(addr, afd->a_addrlen, afd->a_af);
930 #endif
931 if (hp && hp->h_name && hp->h_name[0] && hp->h_addr_list[0]) {
932 #ifdef USE_GETIPNODEBY
933 GET_AI(cur, afd, hp->h_addr_list[0]);
934 GET_PORT(cur, servname);
935 GET_CANONNAME(cur, hp->h_name);
936 #else
937 /* hp will be damaged if we use gethostbyaddr() */
938 if ((ap = (char *)malloc(hp->h_length)) == NULL) {
939 error = EAI_MEMORY;
940 goto free;
942 memcpy(ap, hp->h_addr_list[0], hp->h_length);
943 if ((cn = strdup(hp->h_name)) == NULL) {
944 error = EAI_MEMORY;
945 goto free;
948 GET_AI(cur, afd, ap);
949 GET_PORT(cur, servname);
950 GET_CANONNAME(cur, cn);
951 free(ap); ap = NULL;
952 free(cn); cn = NULL;
953 #endif
954 } else {
955 GET_AI(cur, afd, numaddr);
956 GET_PORT(cur, servname);
959 #ifdef USE_GETIPNODEBY
960 if (hp)
961 freehostent(hp);
962 #endif
963 *res = cur;
964 return SUCCESS;
965 free:
966 if (cur)
967 freeaddrinfo(cur);
968 if (ap)
969 free(ap);
970 if (cn)
971 free(cn);
972 #ifdef USE_GETIPNODEBY
973 if (hp)
974 freehostent(hp);
975 #endif
976 *res = NULL;
977 return error;
980 static int
981 get_canonname(pai, ai, str)
982 const struct addrinfo *pai;
983 struct addrinfo *ai;
984 const char *str;
986 if ((pai->ai_flags & AI_CANONNAME) != 0) {
987 ai->ai_canonname = strdup(str);
988 if (ai->ai_canonname == NULL)
989 return EAI_MEMORY;
991 return 0;
994 static struct addrinfo *
995 get_ai(pai, afd, addr)
996 const struct addrinfo *pai;
997 const struct afd *afd;
998 const char *addr;
1000 char *p;
1001 struct addrinfo *ai;
1003 ai = (struct addrinfo *)malloc(sizeof(struct addrinfo)
1004 + (afd->a_socklen));
1005 if (ai == NULL)
1006 return NULL;
1008 memcpy(ai, pai, sizeof(struct addrinfo));
1009 ai->ai_addr = (struct sockaddr *)(ai + 1);
1010 memset(ai->ai_addr, 0, afd->a_socklen);
1011 #ifdef HAVE_SOCKADDR_SA_LEN
1012 ai->ai_addr->sa_len = afd->a_socklen;
1013 #endif
1014 ai->ai_addrlen = afd->a_socklen;
1015 ai->ai_addr->sa_family = ai->ai_family = afd->a_af;
1016 p = (char *)(ai->ai_addr);
1017 memcpy(p + afd->a_off, addr, afd->a_addrlen);
1018 return ai;
1021 static int
1022 get_portmatch(ai, servname)
1023 const struct addrinfo *ai;
1024 const char *servname;
1027 /* get_port does not touch first argument. when matchonly == 1. */
1028 return get_port((struct addrinfo *)ai, servname, 1);
1031 static int
1032 get_port(ai, servname, matchonly)
1033 struct addrinfo *ai;
1034 const char *servname;
1035 int matchonly;
1037 const char *proto;
1038 struct servent *sp;
1039 int port;
1040 int allownumeric;
1042 if (servname == NULL)
1043 return 0;
1044 switch (ai->ai_family) {
1045 case AF_INET:
1046 #ifdef AF_INET6
1047 case AF_INET6:
1048 #endif
1049 break;
1050 default:
1051 return 0;
1054 switch (ai->ai_socktype) {
1055 case SOCK_RAW:
1056 return EAI_SERVICE;
1057 case SOCK_DGRAM:
1058 case SOCK_STREAM:
1059 allownumeric = 1;
1060 break;
1061 case ANY:
1062 allownumeric = 0;
1063 break;
1064 default:
1065 return EAI_SOCKTYPE;
1068 if (str_isnumber(servname)) {
1069 if (!allownumeric)
1070 return EAI_SERVICE;
1071 port = htons(atoi(servname));
1072 if (port < 0 || port > 65535)
1073 return EAI_SERVICE;
1074 } else {
1075 switch (ai->ai_socktype) {
1076 case SOCK_DGRAM:
1077 proto = "udp";
1078 break;
1079 case SOCK_STREAM:
1080 proto = "tcp";
1081 break;
1082 default:
1083 proto = NULL;
1084 break;
1087 if ((sp = getservbyname(servname, proto)) == NULL)
1088 return EAI_SERVICE;
1089 port = sp->s_port;
1092 if (!matchonly) {
1093 switch (ai->ai_family) {
1094 case AF_INET:
1095 ((struct sockaddr_in *)ai->ai_addr)->sin_port = port;
1096 break;
1097 #ifdef INET6
1098 case AF_INET6:
1099 ((struct sockaddr_in6 *)ai->ai_addr)->sin6_port = port;
1100 break;
1101 #endif
1105 return 0;
1108 static const struct afd *
1109 find_afd(af)
1110 int af;
1112 const struct afd *afd;
1114 if (af == PF_UNSPEC)
1115 return NULL;
1116 for (afd = afdl; afd->a_af; afd++) {
1117 if (afd->a_af == af)
1118 return afd;
1120 return NULL;
1124 #endif /*__MING64__*/