1 /* $KAME: getaddrinfo.c,v 1.14 2001/01/06 09:41:15 jinmei Exp $ */
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the project nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
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 * - IPv4 classful (shortened) form. RFC2553 is silent about it. XNET 5.2
39 * says to use inet_aton() to convert IPv4 numeric to binary (allows
40 * classful form as a result).
41 * current code - disallow classful form for IPv4 (due to use of inet_pton).
42 * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
44 * current code - SEGV on freeaddrinfo(NULL)
46 * - We use getipnodebyname() just for thread-safeness. There's no intent
47 * to let it do PF_UNSPEC (actually we never pass PF_UNSPEC to
49 * - The code filters out AFs that are not supported by the kernel,
50 * when globbing NULL hostname (to loopback, or wildcard). Is it the right
51 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
53 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
54 * (1) what should we do against numeric hostname (2) what should we do
55 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready?
56 * non-loopback address configured? global address configured?
57 * - To avoid search order issue, we have a big amount of code duplicate
58 * from gethnamaddr.c and some other places. The issues that there's no
59 * lower layer function to lookup "IPv4 or IPv6" record. Calling
60 * gethostbyname2 from getaddrinfo will end up in wrong search order, as
62 * - The code makes use of following calls when asked to resolver with
63 * ai_family = PF_UNSPEC:
64 * getipnodebyname(host, AF_INET6);
65 * getipnodebyname(host, AF_INET);
66 * This will result in the following queries if the node is configure to
67 * prefer /etc/hosts than DNS:
68 * lookup /etc/hosts for IPv6 address
69 * lookup DNS for IPv6 address
70 * lookup /etc/hosts for IPv4 address
71 * lookup DNS for IPv4 address
72 * which may not meet people's requirement.
73 * The right thing to happen is to have underlying layer which does
74 * PF_UNSPEC lookup (lookup both) and return chain of addrinfos.
75 * This would result in a bit of code duplicate with _dns_ghbyname() and
79 #include "port_before.h"
81 #include <sys/types.h>
82 #include <sys/param.h>
83 #include <sys/socket.h>
86 #include <netinet/in.h>
88 #include <arpa/inet.h>
89 #include <arpa/nameser.h>
104 #include <isc/assertions.h>
106 #include "port_after.h"
108 #include "irs_data.h"
115 static const char in_addrany
[] = { 0, 0, 0, 0 };
116 static const char in6_addrany
[] = {
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
119 static const char in_loopback
[] = { 127, 0, 0, 1 };
120 static const char in6_loopback
[] = {
121 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
124 static const struct afd
{
129 const char *a_addrany
;
130 const char *a_loopback
;
133 {PF_INET6
, sizeof(struct in6_addr
),
134 sizeof(struct sockaddr_in6
),
135 offsetof(struct sockaddr_in6
, sin6_addr
),
136 in6_addrany
, in6_loopback
, 1},
137 {PF_INET
, sizeof(struct in_addr
),
138 sizeof(struct sockaddr_in
),
139 offsetof(struct sockaddr_in
, sin_addr
),
140 in_addrany
, in_loopback
, 0},
141 {0, 0, 0, 0, NULL
, NULL
, 0},
148 const char *e_protostr
;
150 #define WILD_AF(ex) ((ex)->e_wild & 0x01)
151 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
152 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
155 static const struct explore explore
[] = {
157 { PF_LOCAL
, 0, ANY
, ANY
, NULL
, 0x01 },
159 { PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
, "udp", 0x07 },
160 { PF_INET6
, SOCK_STREAM
, IPPROTO_TCP
, "tcp", 0x07 },
161 { PF_INET6
, SOCK_RAW
, ANY
, NULL
, 0x05 },
162 { PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
, "udp", 0x07 },
163 { PF_INET
, SOCK_STREAM
, IPPROTO_TCP
, "tcp", 0x07 },
164 { PF_INET
, SOCK_RAW
, ANY
, NULL
, 0x05 },
165 { -1, 0, 0, NULL
, 0 },
170 static int str_isnumber
__P((const char *));
171 static int explore_fqdn
__P((const struct addrinfo
*, const char *,
172 const char *, struct addrinfo
**));
173 static int explore_copy
__P((const struct addrinfo
*, const struct addrinfo
*,
174 struct addrinfo
**));
175 static int explore_null
__P((const struct addrinfo
*,
176 const char *, struct addrinfo
**));
177 static int explore_numeric
__P((const struct addrinfo
*, const char *,
178 const char *, struct addrinfo
**));
179 static int explore_numeric_scope
__P((const struct addrinfo
*, const char *,
180 const char *, struct addrinfo
**));
181 static int get_canonname
__P((const struct addrinfo
*,
182 struct addrinfo
*, const char *));
183 static struct addrinfo
*get_ai
__P((const struct addrinfo
*,
184 const struct afd
*, const char *));
185 static struct addrinfo
*copy_ai
__P((const struct addrinfo
*));
186 static int get_portmatch
__P((const struct addrinfo
*, const char *));
187 static int get_port
__P((const struct addrinfo
*, const char *, int));
188 static const struct afd
*find_afd
__P((int));
189 static int addrconfig
__P((int));
190 static int ip6_str2scopeid
__P((char *, struct sockaddr_in6
*,
191 u_int32_t
*scopeidp
));
192 static struct net_data
*init
__P((void));
194 struct addrinfo
*hostent2addrinfo
__P((struct hostent
*,
195 const struct addrinfo
*));
196 struct addrinfo
*addr2addrinfo
__P((const struct addrinfo
*,
200 static const char *ai_errlist
[] = {
202 "Address family for hostname not supported", /* EAI_ADDRFAMILY */
203 "Temporary failure in name resolution", /* EAI_AGAIN */
204 "Invalid value for ai_flags", /* EAI_BADFLAGS */
205 "Non-recoverable failure in name resolution", /* EAI_FAIL */
206 "ai_family not supported", /* EAI_FAMILY */
207 "Memory allocation failure", /* EAI_MEMORY */
208 "No address associated with hostname", /* EAI_NODATA */
209 "hostname nor servname provided, or not known", /* EAI_NONAME */
210 "servname not supported for ai_socktype", /* EAI_SERVICE */
211 "ai_socktype not supported", /* EAI_SOCKTYPE */
212 "System error returned in errno", /* EAI_SYSTEM */
213 "Invalid value for hints", /* EAI_BADHINTS */
214 "Resolved protocol is unknown", /* EAI_PROTOCOL */
215 "Unknown error", /* EAI_MAX */
219 /* XXX macros that make external reference is BAD. */
221 #define GET_AI(ai, afd, addr) \
223 /* external reference: pai, error, and label free */ \
224 (ai) = get_ai(pai, (afd), (addr)); \
225 if ((ai) == NULL) { \
226 error = EAI_MEMORY; \
229 } while (/*CONSTCOND*/0)
231 #define GET_PORT(ai, serv) \
233 /* external reference: error and label free */ \
234 error = get_port((ai), (serv), 0); \
237 } while (/*CONSTCOND*/0)
239 #define GET_CANONNAME(ai, str) \
241 /* external reference: pai, error and label free */ \
242 error = get_canonname(pai, (ai), (str)); \
245 } while (/*CONSTCOND*/0)
249 /* external reference: error, and label bad */ \
253 } while (/*CONSTCOND*/0)
255 #define MATCH_FAMILY(x, y, w) \
256 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
257 #define MATCH(x, y, w) \
258 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
260 #if 0 /* bind8 has its own version */
265 if (ecode
< 0 || ecode
> EAI_MAX
)
267 return ai_errlist
[ecode
];
275 struct addrinfo
*next
;
279 if (ai
->ai_canonname
)
280 free(ai
->ai_canonname
);
281 /* no need to free(ai->ai_addr) */
297 (void)strtoul(p
, &ep
, 10);
298 if (errno
== 0 && ep
&& *ep
== '\0')
305 getaddrinfo(hostname
, servname
, hints
, res
)
306 const char *hostname
, *servname
;
307 const struct addrinfo
*hints
;
308 struct addrinfo
**res
;
310 struct addrinfo sentinel
;
311 struct addrinfo
*cur
;
313 struct addrinfo ai
, ai0
, *afai
= NULL
;
314 struct addrinfo
*pai
;
315 const struct explore
*ex
;
317 memset(&sentinel
, 0, sizeof(sentinel
));
321 pai
->ai_family
= PF_UNSPEC
;
322 pai
->ai_socktype
= ANY
;
323 pai
->ai_protocol
= ANY
;
325 pai
->ai_canonname
= NULL
;
329 if (hostname
== NULL
&& servname
== NULL
)
332 /* error check for hints */
333 if (hints
->ai_addrlen
|| hints
->ai_canonname
||
334 hints
->ai_addr
|| hints
->ai_next
)
335 ERR(EAI_BADHINTS
); /* xxx */
336 if (hints
->ai_flags
& ~AI_MASK
)
338 switch (hints
->ai_family
) {
346 memcpy(pai
, hints
, sizeof(*pai
));
349 * if both socktype/protocol are specified, check if they
350 * are meaningful combination.
352 if (pai
->ai_socktype
!= ANY
&& pai
->ai_protocol
!= ANY
) {
353 for (ex
= explore
; ex
->e_af
>= 0; ex
++) {
354 if (pai
->ai_family
!= ex
->e_af
)
356 if (ex
->e_socktype
== ANY
)
358 if (ex
->e_protocol
== ANY
)
360 if (pai
->ai_socktype
== ex
->e_socktype
&&
361 pai
->ai_protocol
!= ex
->e_protocol
) {
369 * post-2553: AI_ALL and AI_V4MAPPED are effective only against
370 * AF_INET6 query. They needs to be ignored if specified in other
373 switch (pai
->ai_flags
& (AI_ALL
| AI_V4MAPPED
)) {
375 case AI_ALL
| AI_V4MAPPED
:
376 if (pai
->ai_family
!= AF_INET6
)
377 pai
->ai_flags
&= ~(AI_ALL
| AI_V4MAPPED
);
384 pai
->ai_flags
&= ~(AI_ALL
| AI_V4MAPPED
);
390 * check for special cases. (1) numeric servname is disallowed if
391 * socktype/protocol are left unspecified. (2) servname is disallowed
392 * for raw and other inet{,6} sockets.
394 if (MATCH_FAMILY(pai
->ai_family
, PF_INET
, 1)
396 || MATCH_FAMILY(pai
->ai_family
, PF_INET6
, 1)
399 ai0
= *pai
; /* backup *pai */
401 if (pai
->ai_family
== PF_UNSPEC
) {
403 pai
->ai_family
= PF_INET6
;
405 pai
->ai_family
= PF_INET
;
408 error
= get_portmatch(pai
, servname
);
417 /* NULL hostname, or numeric hostname */
418 for (ex
= explore
; ex
->e_af
>= 0; ex
++) {
421 if (!MATCH_FAMILY(pai
->ai_family
, ex
->e_af
, WILD_AF(ex
)))
423 if (!MATCH(pai
->ai_socktype
, ex
->e_socktype
, WILD_SOCKTYPE(ex
)))
425 if (!MATCH(pai
->ai_protocol
, ex
->e_protocol
, WILD_PROTOCOL(ex
)))
428 if (pai
->ai_family
== PF_UNSPEC
)
429 pai
->ai_family
= ex
->e_af
;
430 if (pai
->ai_socktype
== ANY
&& ex
->e_socktype
!= ANY
)
431 pai
->ai_socktype
= ex
->e_socktype
;
432 if (pai
->ai_protocol
== ANY
&& ex
->e_protocol
!= ANY
)
433 pai
->ai_protocol
= ex
->e_protocol
;
436 * if the servname does not match socktype/protocol, ignore it.
438 if (get_portmatch(pai
, servname
) != 0)
441 if (hostname
== NULL
) {
443 * filter out AFs that are not supported by the kernel
446 if (!addrconfig(pai
->ai_family
))
448 error
= explore_null(pai
, servname
, &cur
->ai_next
);
450 error
= explore_numeric_scope(pai
, hostname
, servname
,
456 while (cur
&& cur
->ai_next
)
462 * If numreic representation of AF1 can be interpreted as FQDN
463 * representation of AF2, we need to think again about the code below.
465 if (sentinel
.ai_next
)
468 if (pai
->ai_flags
& AI_NUMERICHOST
)
470 if (hostname
== NULL
)
474 * hostname as alphabetical name.
475 * We'll make sure that
476 * - if returning addrinfo list is empty, return non-zero error
477 * value (already known one or EAI_NONAME).
479 * + if we haven't had any errors, return 0 (i.e. success).
480 * + if we've had an error, free the list and return the error.
481 * without any assumption on the behavior of explore_fqdn().
484 /* first, try to query DNS for all possible address families. */
486 error
= explore_fqdn(pai
, hostname
, servname
, &afai
);
493 error
= EAI_NONAME
; /* we've had no errors. */
498 * we would like to prefer AF_INET6 than AF_INET, so we'll make an
501 for (ex
= explore
; ex
->e_af
>= 0; ex
++) {
504 if (pai
->ai_family
== PF_UNSPEC
)
505 pai
->ai_family
= ex
->e_af
;
507 if (!MATCH_FAMILY(pai
->ai_family
, ex
->e_af
, WILD_AF(ex
)))
509 if (!MATCH(pai
->ai_socktype
, ex
->e_socktype
,
510 WILD_SOCKTYPE(ex
))) {
513 if (!MATCH(pai
->ai_protocol
, ex
->e_protocol
,
514 WILD_PROTOCOL(ex
))) {
520 * If AI_ADDRCONFIG is specified, check if we are
521 * expected to return the address family or not.
523 if ((pai
->ai_flags
& AI_ADDRCONFIG
) != 0 &&
524 !addrconfig(pai
->ai_family
))
528 if (pai
->ai_family
== PF_UNSPEC
)
529 pai
->ai_family
= ex
->e_af
;
530 if (pai
->ai_socktype
== ANY
&& ex
->e_socktype
!= ANY
)
531 pai
->ai_socktype
= ex
->e_socktype
;
532 if (pai
->ai_protocol
== ANY
&& ex
->e_protocol
!= ANY
)
533 pai
->ai_protocol
= ex
->e_protocol
;
536 * if the servname does not match socktype/protocol, ignore it.
538 if (get_portmatch(pai
, servname
) != 0)
541 if ((error
= explore_copy(pai
, afai
, &cur
->ai_next
)) != 0) {
546 while (cur
&& cur
->ai_next
)
550 freeaddrinfo(afai
); /* afai must not be NULL at this point. */
552 /* we must not have got any errors. */
553 if (error
!= 0) /* just for diagnosis */
556 if (sentinel
.ai_next
) {
558 *res
= sentinel
.ai_next
;
562 * All the process succeeded, but we've had an empty list.
563 * This can happen if the given hints do not match our
571 if (sentinel
.ai_next
)
572 freeaddrinfo(sentinel
.ai_next
);
578 * FQDN hostname, DNS lookup
581 explore_fqdn(pai
, hostname
, servname
, res
)
582 const struct addrinfo
*pai
;
583 const char *hostname
;
584 const char *servname
;
585 struct addrinfo
**res
;
587 struct addrinfo
*result
;
588 struct addrinfo
*cur
;
589 struct net_data
*net_data
= init();
592 char tmp
[NS_MAXDNAME
];
595 INSIST(res
!= NULL
&& *res
== NULL
);
598 * if the servname does not match socktype/protocol, ignore it.
600 if (get_portmatch(pai
, servname
) != 0)
603 if (!net_data
|| !(ho
= net_data
->ho
))
605 #if 0 /* XXX (notyet) */
606 if (net_data
->ho_stayopen
&& net_data
->ho_last
&&
607 net_data
->ho_last
->h_addrtype
== af
) {
608 if (ns_samename(name
, net_data
->ho_last
->h_name
) == 1)
609 return (net_data
->ho_last
);
610 for (hap
= net_data
->ho_last
->h_aliases
; hap
&& *hap
; hap
++)
611 if (ns_samename(name
, *hap
) == 1)
612 return (net_data
->ho_last
);
615 if (!strchr(hostname
, '.') &&
616 (cp
= res_hostalias(net_data
->res
, hostname
,
619 result
= (*ho
->addrinfo
)(ho
, hostname
, pai
);
620 if (!net_data
->ho_stayopen
) {
623 if (result
== NULL
) {
641 case NETDB_SUCCESS
: /* should be impossible... */
648 for (cur
= result
; cur
; cur
= cur
->ai_next
) {
649 GET_PORT(cur
, servname
); /* XXX: redundant lookups... */
650 /* canonname should already be filled. */
659 freeaddrinfo(result
);
664 explore_copy(pai
, src0
, res
)
665 const struct addrinfo
*pai
; /* seed */
666 const struct addrinfo
*src0
; /* source */
667 struct addrinfo
**res
;
670 struct addrinfo sentinel
, *cur
;
671 const struct addrinfo
*src
;
674 sentinel
.ai_next
= NULL
;
677 for (src
= src0
; src
!= NULL
; src
= src
->ai_next
) {
678 if (src
->ai_family
!= pai
->ai_family
)
681 cur
->ai_next
= copy_ai(src
);
687 cur
->ai_next
->ai_socktype
= pai
->ai_socktype
;
688 cur
->ai_next
->ai_protocol
= pai
->ai_protocol
;
692 *res
= sentinel
.ai_next
;
696 freeaddrinfo(sentinel
.ai_next
);
702 * passive socket -> anyaddr (0.0.0.0 or ::)
703 * non-passive socket -> localhost (127.0.0.1 or ::1)
706 explore_null(pai
, servname
, res
)
707 const struct addrinfo
*pai
;
708 const char *servname
;
709 struct addrinfo
**res
;
711 const struct afd
*afd
;
712 struct addrinfo
*cur
;
713 struct addrinfo sentinel
;
717 sentinel
.ai_next
= NULL
;
720 afd
= find_afd(pai
->ai_family
);
724 if (pai
->ai_flags
& AI_PASSIVE
) {
725 GET_AI(cur
->ai_next
, afd
, afd
->a_addrany
);
727 * GET_CANONNAME(cur->ai_next, "anyaddr");
729 GET_PORT(cur
->ai_next
, servname
);
731 GET_AI(cur
->ai_next
, afd
, afd
->a_loopback
);
733 * GET_CANONNAME(cur->ai_next, "localhost");
735 GET_PORT(cur
->ai_next
, servname
);
739 *res
= sentinel
.ai_next
;
743 if (sentinel
.ai_next
)
744 freeaddrinfo(sentinel
.ai_next
);
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
;
765 sentinel
.ai_next
= NULL
;
768 afd
= find_afd(pai
->ai_family
);
773 #if 0 /*X/Open spec*/
775 if (inet_aton(hostname
, (struct in_addr
*)pton
) == 1) {
776 if (pai
->ai_family
== afd
->a_af
||
777 pai
->ai_family
== PF_UNSPEC
/*?*/) {
778 GET_AI(cur
->ai_next
, afd
, pton
);
779 GET_PORT(cur
->ai_next
, servname
);
780 while (cur
&& cur
->ai_next
)
783 ERR(EAI_FAMILY
); /*xxx*/
788 if (inet_pton(afd
->a_af
, hostname
, pton
) == 1) {
789 if (pai
->ai_family
== afd
->a_af
||
790 pai
->ai_family
== PF_UNSPEC
/*?*/) {
791 GET_AI(cur
->ai_next
, afd
, pton
);
792 GET_PORT(cur
->ai_next
, servname
);
793 while (cur
&& cur
->ai_next
)
796 ERR(EAI_FAMILY
); /*xxx*/
801 *res
= sentinel
.ai_next
;
806 if (sentinel
.ai_next
)
807 freeaddrinfo(sentinel
.ai_next
);
812 * numeric hostname with scope
815 explore_numeric_scope(pai
, hostname
, servname
, res
)
816 const struct addrinfo
*pai
;
817 const char *hostname
;
818 const char *servname
;
819 struct addrinfo
**res
;
821 #ifndef SCOPE_DELIMITER
822 return explore_numeric(pai
, hostname
, servname
, res
);
824 const struct afd
*afd
;
825 struct addrinfo
*cur
;
827 char *cp
, *hostname2
= NULL
, *scope
, *addr
;
828 struct sockaddr_in6
*sin6
;
830 afd
= find_afd(pai
->ai_family
);
835 return explore_numeric(pai
, hostname
, servname
, res
);
837 cp
= strchr(hostname
, SCOPE_DELIMITER
);
839 return explore_numeric(pai
, hostname
, servname
, res
);
842 * Handle special case of <scoped_address><delimiter><scope id>
844 hostname2
= strdup(hostname
);
845 if (hostname2
== NULL
)
847 /* terminate at the delimiter */
848 hostname2
[cp
- hostname
] = '\0';
852 error
= explore_numeric(pai
, addr
, servname
, res
);
854 u_int32_t scopeid
= 0;
856 for (cur
= *res
; cur
; cur
= cur
->ai_next
) {
857 if (cur
->ai_family
!= AF_INET6
)
859 sin6
= (struct sockaddr_in6
*)(void *)cur
->ai_addr
;
860 if (!ip6_str2scopeid(scope
, sin6
, &scopeid
)) {
862 return(EAI_NONAME
); /* XXX: is return OK? */
864 #ifdef HAVE_SIN6_SCOPE_ID
865 sin6
->sin6_scope_id
= scopeid
;
877 get_canonname(pai
, ai
, str
)
878 const struct addrinfo
*pai
;
882 if ((pai
->ai_flags
& AI_CANONNAME
) != 0) {
883 ai
->ai_canonname
= (char *)malloc(strlen(str
) + 1);
884 if (ai
->ai_canonname
== NULL
)
886 strcpy(ai
->ai_canonname
, str
);
891 static struct addrinfo
*
892 get_ai(pai
, afd
, addr
)
893 const struct addrinfo
*pai
;
894 const struct afd
*afd
;
900 ai
= (struct addrinfo
*)malloc(sizeof(struct addrinfo
)
905 memcpy(ai
, pai
, sizeof(struct addrinfo
));
906 ai
->ai_addr
= (struct sockaddr
*)(void *)(ai
+ 1);
907 memset(ai
->ai_addr
, 0, (size_t)afd
->a_socklen
);
909 ai
->ai_addr
->sa_len
= afd
->a_socklen
;
911 ai
->ai_addrlen
= afd
->a_socklen
;
912 ai
->ai_addr
->sa_family
= ai
->ai_family
= afd
->a_af
;
913 p
= (char *)(void *)(ai
->ai_addr
);
914 memcpy(p
+ afd
->a_off
, addr
, (size_t)afd
->a_addrlen
);
918 /* XXX need to malloc() the same way we do from other functions! */
919 static struct addrinfo
*
921 const struct addrinfo
*pai
;
926 l
= sizeof(*ai
) + pai
->ai_addrlen
;
927 if ((ai
= (struct addrinfo
*)malloc(l
)) == NULL
)
930 memcpy(ai
, pai
, sizeof(*ai
));
931 ai
->ai_addr
= (struct sockaddr
*)(void *)(ai
+ 1);
932 memcpy(ai
->ai_addr
, pai
->ai_addr
, pai
->ai_addrlen
);
934 if (pai
->ai_canonname
) {
935 l
= strlen(pai
->ai_canonname
) + 1;
936 if ((ai
->ai_canonname
= malloc(l
)) == NULL
) {
940 strcpy(ai
->ai_canonname
, pai
->ai_canonname
); /* (checked) */
942 /* just to make sure */
943 ai
->ai_canonname
= NULL
;
952 get_portmatch(const struct addrinfo
*ai
, const char *servname
) {
954 /* get_port does not touch first argument. when matchonly == 1. */
955 /* LINTED const cast */
956 return get_port((const struct addrinfo
*)ai
, servname
, 1);
960 get_port(const struct addrinfo
*ai
, const char *servname
, int matchonly
) {
966 if (servname
== NULL
)
968 switch (ai
->ai_family
) {
978 switch (ai
->ai_socktype
) {
986 switch (ai
->ai_family
) {
1002 if (str_isnumber(servname
)) {
1005 port
= atoi(servname
);
1006 if (port
< 0 || port
> 65535)
1010 switch (ai
->ai_socktype
) {
1022 if ((sp
= getservbyname(servname
, proto
)) == NULL
)
1028 switch (ai
->ai_family
) {
1030 ((struct sockaddr_in
*)(void *)
1031 ai
->ai_addr
)->sin_port
= port
;
1034 ((struct sockaddr_in6
*)(void *)
1035 ai
->ai_addr
)->sin6_port
= port
;
1043 static const struct afd
*
1047 const struct afd
*afd
;
1049 if (af
== PF_UNSPEC
)
1051 for (afd
= afdl
; afd
->a_af
; afd
++) {
1052 if (afd
->a_af
== af
)
1059 * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend
1060 * will take care of it.
1061 * the semantics of AI_ADDRCONFIG is not defined well. we are not sure
1062 * if the code is right or not.
1071 s
= socket(af
, SOCK_DGRAM
, 0);
1073 if (errno
!= EMFILE
)
1080 /* convert a string to a scope identifier. XXX: IPv6 specific */
1082 ip6_str2scopeid(char *scope
, struct sockaddr_in6
*sin6
,
1083 u_int32_t
*scopeidp
)
1087 struct in6_addr
*a6
= &sin6
->sin6_addr
;
1090 /* empty scopeid portion is invalid */
1094 #ifdef USE_IFNAMELINKID
1095 if (IN6_IS_ADDR_LINKLOCAL(a6
) || IN6_IS_ADDR_MC_LINKLOCAL(a6
)) {
1097 * Using interface names as link indices can be allowed
1098 * only when we can assume a one-to-one mappings between
1099 * links and interfaces. See comments in getnameinfo.c.
1101 scopeid
= if_nametoindex(scope
);
1104 *scopeidp
= scopeid
;
1109 /* still unclear about literal, allow numeric only - placeholder */
1110 if (IN6_IS_ADDR_SITELOCAL(a6
) || IN6_IS_ADDR_MC_SITELOCAL(a6
))
1112 if (IN6_IS_ADDR_MC_ORGLOCAL(a6
))
1115 goto trynumeric
; /* global */
1117 /* try to convert to a numeric id as a last resort */
1120 lscopeid
= strtoul(scope
, &ep
, 10);
1121 scopeid
= lscopeid
& 0xffffffff;
1122 if (errno
== 0 && ep
&& *ep
== '\0' && scopeid
== lscopeid
) {
1123 *scopeidp
= scopeid
;
1130 hostent2addrinfo(hp
, pai
)
1132 const struct addrinfo
*pai
;
1134 int i
, af
, error
= 0;
1135 char **aplist
= NULL
, *ap
;
1136 struct addrinfo sentinel
, *cur
;
1137 const struct afd
*afd
;
1139 af
= hp
->h_addrtype
;
1140 if (pai
->ai_family
!= AF_UNSPEC
&& af
!= pai
->ai_family
)
1147 aplist
= hp
->h_addr_list
;
1149 memset(&sentinel
, 0, sizeof(sentinel
));
1152 for (i
= 0; (ap
= aplist
[i
]) != NULL
; i
++) {
1153 #if 0 /* the trick seems too much */
1154 af
= hp
->h_addr_list
;
1155 if (af
== AF_INET6
&&
1156 IN6_IS_ADDR_V4MAPPED((struct in6_addr
*)ap
)) {
1158 ap
= ap
+ sizeof(struct in6_addr
)
1159 - sizeof(struct in_addr
);
1166 GET_AI(cur
->ai_next
, afd
, ap
);
1168 /* GET_PORT(cur->ai_next, servname); */
1169 if ((pai
->ai_flags
& AI_CANONNAME
) != 0) {
1171 * RFC2553 says that ai_canonname will be set only for
1172 * the first element. we do it for all the elements,
1173 * just for convenience.
1175 GET_CANONNAME(cur
->ai_next
, hp
->h_name
);
1177 while (cur
&& cur
->ai_next
) /* no need to loop, actually. */
1183 freeaddrinfo(cur
->ai_next
);
1184 cur
->ai_next
= NULL
;
1185 /* continue, without tht pointer CUR advanced. */
1188 return(sentinel
.ai_next
);
1192 addr2addrinfo(pai
, cp
)
1193 const struct addrinfo
*pai
;
1196 const struct afd
*afd
;
1198 afd
= find_afd(pai
->ai_family
);
1202 return(get_ai(pai
, afd
, cp
));
1205 static struct net_data
*
1208 struct net_data
*net_data
;
1210 if (!(net_data
= net_data_init(NULL
)))
1212 if (!net_data
->ho
) {
1213 net_data
->ho
= (*net_data
->irs
->ho_map
)(net_data
->irs
);
1214 if (!net_data
->ho
|| !net_data
->res
) {
1217 if (net_data
&& net_data
->res
)
1218 RES_SET_H_ERRNO(net_data
->res
, NETDB_INTERNAL
);
1222 (*net_data
->ho
->res_set
)(net_data
->ho
, net_data
->res
, NULL
);