1 /* $KAME: getaddrinfo.c,v 1.0 2005/11/14 12:57:24 sonic Exp $ */
4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
6 * Copyright (C) 2005 - 2006 Pavel Fedin
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. Neither the name of the project nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * "#ifdef FAITH" part is local hack for supporting IPv4-v6 translator.
36 * Issues to be discussed:
37 * - Thread safe-ness must be checked.
38 * - Return values. There are nonstandard return values defined and used
39 * in the source code. This is because RFC2553 is silent about which error
40 * code must be returned for which situation.
41 * - freeaddrinfo(NULL). RFC2553 is silent about it. XNET 5.2 says it is
42 * invalid. current code - SEGV on freeaddrinfo(NULL)
45 * - The code filters out AFs that are not supported by the kernel,
46 * when globbing NULL hostname (to loopback, or wildcard). Is it the right
47 * thing to do? What is the relationship with post-RFC2553 AI_ADDRCONFIG
49 * - (post-2553) semantics of AI_ADDRCONFIG itself is too vague.
50 * (1) what should we do against numeric hostname (2) what should we do
51 * against NULL hostname (3) what is AI_ADDRCONFIG itself. AF not ready?
52 * non-loopback address configured? global address configured?
54 * OS specific notes for netbsd/openbsd/freebsd4/bsdi4:
55 * - To avoid search order issue, we have a big amount of code duplicate
56 * from gethnamaddr.c and some other places. The issues that there's no
57 * lower layer function to lookup "IPv4 or IPv6" record. Calling
58 * gethostbyname2 from getaddrinfo will end up in wrong search order, as
61 * OS specific notes for freebsd4:
62 * - FreeBSD supported $GAI. The code does not.
63 * - FreeBSD allowed classful IPv4 numeric (127.1), the code does not.
66 #include <amitcp/socketbasetags.h>
67 //#include <emul/emulregs.h>
68 //#include <libraries/eztcp_private.h>
69 #define SYSTEM_PRIVATE
70 #define USE_INLINE_STDARG
71 #include <proto/socket.h>
73 #include <sys/cdefs.h>
74 //#include "namespace.h"
75 #include <sys/types.h>
76 #include <sys/param.h>
77 #include <sys/socket.h>
79 #include <netinet/in.h>
80 #include <sys/queue.h>
82 #include <net/if_var.h>
83 #include <sys/sysctl.h>
84 #include <sys/ioctl.h>
85 #include <netinet6/in6_var.h> /* XXX */
87 #include <arpa/inet.h>
88 #include <arpa/nameser.h>
90 #include <rpcsvc/yp_prot.h>
91 #include <rpcsvc/ypclnt.h>
103 //#include "res_config.h"
110 #include <nsswitch.h>
111 //#include "un-namespace.h"
112 //#include "libc_private.h"
115 #if defined(__KAME__) && defined(INET6)
124 static const char in_addrany
[] = { 0, 0, 0, 0 };
125 static const char in_loopback
[] = { 127, 0, 0, 1 };
127 static const char in6_addrany
[] = {
128 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
130 static const char in6_loopback
[] = {
131 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
136 TAILQ_ENTRY(policyqueue
) pc_entry
;
138 struct in6_addrpolicy pc_policy
;
141 TAILQ_HEAD(policyhead
, policyqueue
);
143 static const struct afd
{
148 const char *a_addrany
;
149 const char *a_loopback
;
154 {PF_INET6
, sizeof(struct in6_addr
),
155 sizeof(struct sockaddr_in6
),
156 offsetof(struct sockaddr_in6
, sin6_addr
),
157 in6_addrany
, in6_loopback
, 1},
162 {PF_INET
, sizeof(struct in_addr
),
163 sizeof(struct sockaddr_in
),
164 offsetof(struct sockaddr_in
, sin_addr
),
165 in_addrany
, in_loopback
, 0},
166 {0, 0, 0, 0, NULL
, NULL
, 0},
173 const char *e_protostr
;
175 #define WILD_AF(ex) ((ex)->e_wild & 0x01)
176 #define WILD_SOCKTYPE(ex) ((ex)->e_wild & 0x02)
177 #define WILD_PROTOCOL(ex) ((ex)->e_wild & 0x04)
180 static const struct explore explore
[] = {
182 { PF_LOCAL
, 0, ANY
, ANY
, NULL
, 0x01 },
185 { PF_INET6
, SOCK_DGRAM
, IPPROTO_UDP
, "udp", 0x07 },
186 { PF_INET6
, SOCK_STREAM
, IPPROTO_TCP
, "tcp", 0x07 },
187 { PF_INET6
, SOCK_RAW
, ANY
, NULL
, 0x05 },
189 { PF_INET
, SOCK_DGRAM
, IPPROTO_UDP
, "udp", 0x07 },
190 { PF_INET
, SOCK_STREAM
, IPPROTO_TCP
, "tcp", 0x07 },
191 { PF_INET
, SOCK_RAW
, ANY
, NULL
, 0x05 },
192 { PF_UNSPEC
, SOCK_DGRAM
, IPPROTO_UDP
, "udp", 0x07 },
193 { PF_UNSPEC
, SOCK_STREAM
, IPPROTO_TCP
, "tcp", 0x07 },
194 { PF_UNSPEC
, SOCK_RAW
, ANY
, NULL
, 0x05 },
195 { -1, 0, 0, NULL
, 0 },
204 #define AIO_SRCFLAG_DEPRECATED 0x1
208 struct sockaddr_storage aiou_ss
;
209 struct sockaddr aiou_sa
;
211 #define aio_srcsa aio_src_un.aiou_sa
212 u_int32_t aio_srcflag
;
215 struct policyqueue
*aio_srcpolicy
;
216 struct policyqueue
*aio_dstpolicy
;
217 struct addrinfo
*aio_ai
;
222 struct res_target
*next
;
223 const char *name
; /* domain name */
224 int qclass
, qtype
; /* class and type of query */
225 u_char
*answer
; /* buffer to put answer */
226 int anslen
; /* size of answer buffer */
227 int n
; /* result length */
230 #define MAXPACKET (64*1024)
234 u_char buf
[MAXPACKET
];
237 static int str2number(const char *);
238 static int explore_null(const struct addrinfo
*,
239 const char *, struct addrinfo
**, struct MiamiBase
*);
240 static int explore_numeric(const struct addrinfo
*, const char *,
241 const char *, struct addrinfo
**, const char *, struct MiamiBase
*);
242 static int explore_numeric_scope(const struct addrinfo
*, const char *,
243 const char *, struct addrinfo
**, struct MiamiBase
*);
244 static int get_canonname(const struct addrinfo
*,
245 struct addrinfo
*, const char *);
246 static struct addrinfo
*get_ai(const struct addrinfo
*,
247 const struct afd
*, const char *, struct MiamiBase
*);
248 static int get_portmatch(const struct addrinfo
*, const char *, struct MiamiBase
*);
249 static int get_port(struct addrinfo
*, const char *, int, struct MiamiBase
*);
250 static const struct afd
*find_afd(int);
251 static int addrconfig(struct addrinfo
*, MiamiBase
*);
252 static void set_source(struct ai_order
*, struct policyhead
*, struct MiamiBase
*);
253 static int comp_dst(const void *, const void *);
255 static int ip6_str2scopeid(char *, struct sockaddr_in6
*, u_int32_t
*, struct MiamiBase
*);
257 static int gai_addr2scopetype(struct sockaddr
*);
259 static int explore_fqdn(const struct addrinfo
*, const char *,
260 const char *, struct addrinfo
**, struct MiamiBase
*);
262 static int reorder(struct addrinfo
*, struct MiamiBase
*);
263 static int get_addrselectpolicy(struct policyhead
*, struct MiamiBase
*);
264 static void free_addrselectpolicy(struct policyhead
*);
265 static struct policyqueue
*match_addrselectpolicy(struct sockaddr
*,
266 struct policyhead
*);
267 static int matchlen(struct sockaddr
*, struct sockaddr
*);
269 static struct addrinfo
*getanswer(const querybuf
*, int, const char *, int,
270 const struct addrinfo
*, struct MiamiBase
*);
271 #if defined(RESOLVSORT)
272 static int addr4sort(struct addrinfo
*, struct MiamiBase
*);
274 static int _dns_getaddrinfo(void *, void *, va_list, struct MiamiBase
*);
275 /*static struct addrinfo *gethtent(const char *, const struct addrinfo *);*/
276 static int _files_getaddrinfo(void *, void *, va_list, struct MiamiBase
*);
278 static struct addrinfo
*_yphostent(char *, const struct addrinfo
*, struct MiamiBase
*);
279 static int _yp_getaddrinfo(void *, void *, va_list, struct MiamiBase
*);
281 static int _nsdispatch(void *, struct MiamiBase
*, ...);
283 static int res_queryN(const char *, struct res_target
*, struct MiamiBase
*);
284 static int res_searchN(const char *, struct res_target
*, struct MiamiBase
*);
285 static int res_querydomainN(const char *, const char *,
286 struct res_target
*, struct MiamiBase
*);
288 static struct ai_errlist
{
293 { "Temporary failure in name resolution", EAI_AGAIN
, },
294 { "Invalid value for ai_flags", EAI_BADFLAGS
, },
295 { "Non-recoverable failure in name resolution", EAI_FAIL
, },
296 { "ai_family not supported", EAI_FAMILY
, },
297 { "Memory allocation failure", EAI_MEMORY
, },
298 { "hostname nor servname provided, or not known", EAI_NONAME
, },
299 { "servname not supported for ai_socktype", EAI_SERVICE
, },
300 { "ai_socktype not supported", EAI_SOCKTYPE
, },
301 { "System error returned in errno", EAI_SYSTEM
, },
302 { "Invalid value for hints", EAI_BADHINTS
, },
303 { "Resolved protocol is unknown", EAI_PROTOCOL
, },
304 /* backward compatibility with userland code prior to 2553bis-02 */
305 { "Address family for hostname not supported", 1, },
306 { "No address associated with hostname", 7, },
310 /* XXX macros that make external reference is BAD. */
312 #define GET_AI(ai, afd, addr) \
314 /* external reference: pai, error, and label free */ \
315 (ai) = get_ai(pai, (afd), (addr), MiamiBase); \
316 if ((ai) == NULL) { \
317 error = EAI_MEMORY; \
320 } while (/*CONSTCOND*/0)
322 #define GET_PORT(ai, serv) \
324 /* external reference: error and label free */ \
325 error = get_port((ai), (serv), 0, MiamiBase); \
328 } while (/*CONSTCOND*/0)
330 #define GET_CANONNAME(ai, str) \
332 /* external reference: pai, error and label free */ \
333 error = get_canonname(pai, (ai), (str)); \
336 } while (/*CONSTCOND*/0)
340 /* external reference: error, and label bad */ \
344 } while (/*CONSTCOND*/0)
346 #define MATCH_FAMILY(x, y, w) \
347 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == PF_UNSPEC || (y) == PF_UNSPEC)))
348 #define MATCH(x, y, w) \
349 ((x) == (y) || (/*CONSTCOND*/(w) && ((x) == ANY || (y) == ANY)))
351 #define SocketBase MiamiBase->SocketBase
352 #define _res (*(MiamiBase->res_state))
358 struct ai_errlist
*p
;
360 for (p
= ai_errlist
; p
->str
; p
++) {
361 if (p
->code
== ecode
)
362 return (char *)p
->str
;
364 return "Unknown error";
371 struct addrinfo
*next
;
375 if (ai
->ai_canonname
)
376 free(ai
->ai_canonname
);
377 /* no need to free(ai->ai_addr) */
383 void freeaddrinfo(void)
385 struct addrinfo
*ai
= (struct addrinfo
*)REG_A0
;
402 v
= __strtoul(p
, &ep
, 10, &errno
);
403 SocketBaseTags(SBTM_SETVAL(SBTC_ERRNO
),errno
,TAG_DONE
);
404 if (errno
== 0 && ep
&& *ep
== '\0' && v
<= UINT_MAX
)
411 __getaddrinfo(hostname
, servname
, hints
, res
, MiamiBase
)
412 const char *hostname
, *servname
;
413 const struct addrinfo
*hints
;
414 struct addrinfo
**res
;
415 struct MiamiBase
*MiamiBase
;
417 struct addrinfo sentinel
;
418 struct addrinfo
*cur
;
422 struct addrinfo
*pai
;
423 const struct explore
*ex
;
426 memset(&sentinel
, 0, sizeof(sentinel
));
430 pai
->ai_family
= PF_UNSPEC
;
431 pai
->ai_socktype
= ANY
;
432 pai
->ai_protocol
= ANY
;
434 pai
->ai_canonname
= NULL
;
438 if (hostname
== NULL
&& servname
== NULL
)
441 /* error check for hints */
442 if (hints
->ai_addrlen
|| hints
->ai_canonname
||
443 hints
->ai_addr
|| hints
->ai_next
)
444 ERR(EAI_BADHINTS
); /* xxx */
445 if (hints
->ai_flags
& ~AI_MASK
)
447 switch (hints
->ai_family
) {
457 memcpy(pai
, hints
, sizeof(*pai
));
460 * if both socktype/protocol are specified, check if they
461 * are meaningful combination.
463 if (pai
->ai_socktype
!= ANY
&& pai
->ai_protocol
!= ANY
) {
464 for (ex
= explore
; ex
->e_af
>= 0; ex
++) {
465 if (pai
->ai_family
!= ex
->e_af
)
467 if (ex
->e_socktype
== ANY
)
469 if (ex
->e_protocol
== ANY
)
471 if (pai
->ai_socktype
== ex
->e_socktype
&&
472 pai
->ai_protocol
!= ex
->e_protocol
) {
480 * post-2553: AI_ALL and AI_V4MAPPED are effective only against
481 * AF_INET6 query. They need to be ignored if specified in other
484 switch (pai
->ai_flags
& (AI_ALL
| AI_V4MAPPED
)) {
486 case AI_ALL
| AI_V4MAPPED
:
487 if (pai
->ai_family
!= AF_INET6
)
488 pai
->ai_flags
&= ~(AI_ALL
| AI_V4MAPPED
);
495 pai
->ai_flags
&= ~(AI_ALL
| AI_V4MAPPED
);
501 * check for special cases. (1) numeric servname is disallowed if
502 * socktype/protocol are left unspecified. (2) servname is disallowed
503 * for raw and other inet{,6} sockets.
505 if (MATCH_FAMILY(pai
->ai_family
, PF_INET
, 1)
507 || MATCH_FAMILY(pai
->ai_family
, PF_INET6
, 1)
510 ai0
= *pai
; /* backup *pai */
512 if (pai
->ai_family
== PF_UNSPEC
) {
514 pai
->ai_family
= PF_INET6
;
516 pai
->ai_family
= PF_INET
;
519 error
= get_portmatch(pai
, servname
, MiamiBase
);
528 /* NULL hostname, or numeric hostname */
529 for (ex
= explore
; ex
->e_af
>= 0; ex
++) {
532 /* PF_UNSPEC entries are prepared for DNS queries only */
533 if (ex
->e_af
== PF_UNSPEC
)
536 if (!MATCH_FAMILY(pai
->ai_family
, ex
->e_af
, WILD_AF(ex
)))
538 if (!MATCH(pai
->ai_socktype
, ex
->e_socktype
, WILD_SOCKTYPE(ex
)))
540 if (!MATCH(pai
->ai_protocol
, ex
->e_protocol
, WILD_PROTOCOL(ex
)))
543 if (pai
->ai_family
== PF_UNSPEC
)
544 pai
->ai_family
= ex
->e_af
;
545 if (pai
->ai_socktype
== ANY
&& ex
->e_socktype
!= ANY
)
546 pai
->ai_socktype
= ex
->e_socktype
;
547 if (pai
->ai_protocol
== ANY
&& ex
->e_protocol
!= ANY
)
548 pai
->ai_protocol
= ex
->e_protocol
;
550 if (hostname
== NULL
)
551 error
= explore_null(pai
, servname
, &cur
->ai_next
, MiamiBase
);
553 error
= explore_numeric_scope(pai
, hostname
, servname
,
554 &cur
->ai_next
, MiamiBase
);
559 while (cur
&& cur
->ai_next
)
565 * If numreic representation of AF1 can be interpreted as FQDN
566 * representation of AF2, we need to think again about the code below.
568 if (sentinel
.ai_next
) {
573 if (hostname
== NULL
)
574 ERR(EAI_NONAME
); /* used to be EAI_NODATA */
575 if (pai
->ai_flags
& AI_NUMERICHOST
)
578 if ((pai
->ai_flags
& AI_ADDRCONFIG
) != 0 && !addrconfig(&ai0
, MiamiBase
))
582 * hostname as alphabetical name.
583 * we would like to prefer AF_INET6 than AF_INET, so we'll make a
586 for (ex
= explore
; ex
->e_af
>= 0; ex
++) {
589 /* require exact match for family field */
590 if (pai
->ai_family
!= ex
->e_af
)
593 if (!MATCH(pai
->ai_socktype
, ex
->e_socktype
,
594 WILD_SOCKTYPE(ex
))) {
597 if (!MATCH(pai
->ai_protocol
, ex
->e_protocol
,
598 WILD_PROTOCOL(ex
))) {
602 if (pai
->ai_socktype
== ANY
&& ex
->e_socktype
!= ANY
)
603 pai
->ai_socktype
= ex
->e_socktype
;
604 if (pai
->ai_protocol
== ANY
&& ex
->e_protocol
!= ANY
)
605 pai
->ai_protocol
= ex
->e_protocol
;
607 error
= explore_fqdn(pai
, hostname
, servname
,
608 &cur
->ai_next
, MiamiBase
);
610 while (cur
&& cur
->ai_next
)
614 /* XXX inhibit errors if we have the result */
615 if (sentinel
.ai_next
)
620 * ensure we return either:
621 * - error == 0, non-NULL *res
622 * - error != 0, NULL *res
625 if (sentinel
.ai_next
) {
627 * If the returned entry is for an active connection,
628 * and the given name is not numeric, reorder the
629 * list, so that the application would try the list
630 * in the most efficient order.
632 if (hints
== NULL
|| !(hints
->ai_flags
& AI_PASSIVE
)) {
634 (void)reorder(&sentinel
, MiamiBase
);
636 *res
= sentinel
.ai_next
;
643 if (sentinel
.ai_next
)
644 __freeaddrinfo(sentinel
.ai_next
);
649 int getaddrinfo(void)
651 const char *hostname
= (const char *)REG_A0
;
652 const char *servname
= (const char *)REG_A1
;
653 const struct addrinfo
*hints
= (const struct addrinfo
*)REG_A2
;
654 struct addrinfo
**res
= (struct addrinfo
**)REG_A3
;
655 struct MiamiBase
*MiamiBase
= (struct MiamiBase
*)REG_A6
;
657 return __getaddrinfo(hostname
, servname
, hints
, res
, MiamiBase
);
661 reorder(sentinel
, MiamiBase
)
662 struct addrinfo
*sentinel
;
663 struct MiamiBase
*MiamiBase
;
665 struct addrinfo
*ai
, **aip
;
666 struct ai_order
*aio
;
668 struct policyhead policyhead
;
670 /* count the number of addrinfo elements for sorting. */
671 for (n
= 0, ai
= sentinel
->ai_next
; ai
!= NULL
; ai
= ai
->ai_next
, n
++)
675 * If the number is small enough, we can skip the reordering process.
680 /* allocate a temporary array for sort and initialization of it. */
681 if ((aio
= malloc(sizeof(*aio
) * n
)) == NULL
)
682 return(n
); /* give up reordering */
683 memset(aio
, 0, sizeof(*aio
) * n
);
685 /* retrieve address selection policy from the kernel */
686 TAILQ_INIT(&policyhead
);
687 if (!get_addrselectpolicy(&policyhead
, MiamiBase
)) {
688 /* no policy is installed into kernel, we don't sort. */
693 for (i
= 0, ai
= sentinel
->ai_next
; i
< n
; ai
= ai
->ai_next
, i
++) {
695 aio
[i
].aio_dstscope
= gai_addr2scopetype(ai
->ai_addr
);
696 aio
[i
].aio_dstpolicy
= match_addrselectpolicy(ai
->ai_addr
,
698 set_source(&aio
[i
], &policyhead
, MiamiBase
);
701 /* perform sorting. */
702 qsort(aio
, n
, sizeof(*aio
), comp_dst
);
704 /* reorder the addrinfo chain. */
705 for (i
= 0, aip
= &sentinel
->ai_next
; i
< n
; i
++) {
706 *aip
= aio
[i
].aio_ai
;
707 aip
= &aio
[i
].aio_ai
->ai_next
;
711 /* cleanup and return */
713 free_addrselectpolicy(&policyhead
);
718 get_addrselectpolicy(head
, MiamiBase
)
719 struct policyhead
*head
;
720 struct MiamiBase
*MiamiBase
;
723 int mib
[] = { CTL_NET
, PF_INET6
, IPPROTO_IPV6
, IPV6CTL_ADDRCTLPOLICY
};
726 struct in6_addrpolicy
*pol
, *ep
;
728 if (EZTCP_sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), NULL
, &l
, NULL
, 0) < 0)
730 if ((buf
= malloc(l
)) == NULL
)
732 if (EZTCP_sysctl(mib
, sizeof(mib
) / sizeof(mib
[0]), buf
, &l
, NULL
, 0) < 0) {
737 ep
= (struct in6_addrpolicy
*)(buf
+ l
);
738 for (pol
= (struct in6_addrpolicy
*)buf
; pol
+ 1 <= ep
; pol
++) {
739 struct policyqueue
*new;
741 if ((new = malloc(sizeof(*new))) == NULL
) {
742 free_addrselectpolicy(head
); /* make the list empty */
745 new->pc_policy
= *pol
;
746 TAILQ_INSERT_TAIL(head
, new, pc_entry
);
757 free_addrselectpolicy(head
)
758 struct policyhead
*head
;
760 struct policyqueue
*ent
, *nent
;
762 for (ent
= TAILQ_FIRST(head
); ent
; ent
= nent
) {
763 nent
= TAILQ_NEXT(ent
, pc_entry
);
764 TAILQ_REMOVE(head
, ent
, pc_entry
);
769 static struct policyqueue
*
770 match_addrselectpolicy(addr
, head
)
771 struct sockaddr
*addr
;
772 struct policyhead
*head
;
775 struct policyqueue
*ent
, *bestent
= NULL
;
776 struct in6_addrpolicy
*pol
;
777 int matchlen
, bestmatchlen
= -1;
778 u_char
*mp
, *ep
, *k
, *p
, m
;
779 struct sockaddr_in6 key
;
781 switch(addr
->sa_family
) {
783 key
= *(struct sockaddr_in6
*)addr
;
786 /* convert the address into IPv4-mapped IPv6 address. */
787 memset(&key
, 0, sizeof(key
));
788 key
.sin6_family
= AF_INET6
;
789 key
.sin6_len
= sizeof(key
);
790 key
.sin6_addr
.s6_addr
[10] = 0xff;
791 key
.sin6_addr
.s6_addr
[11] = 0xff;
792 memcpy(&key
.sin6_addr
.s6_addr
[12],
793 &((struct sockaddr_in
*)addr
)->sin_addr
, 4);
799 for (ent
= TAILQ_FIRST(head
); ent
; ent
= TAILQ_NEXT(ent
, pc_entry
)) {
800 pol
= &ent
->pc_policy
;
803 mp
= (u_char
*)&pol
->addrmask
.sin6_addr
;
804 ep
= mp
+ 16; /* XXX: scope field? */
805 k
= (u_char
*)&key
.sin6_addr
;
806 p
= (u_char
*)&pol
->addr
.sin6_addr
;
807 for (; mp
< ep
&& *mp
; mp
++, k
++, p
++) {
810 goto next
; /* not match */
811 if (m
== 0xff) /* short cut for a typical case */
821 /* matched. check if this is better than the current best. */
822 if (matchlen
> bestmatchlen
) {
824 bestmatchlen
= matchlen
;
839 set_source(aio
, ph
, MiamiBase
)
840 struct ai_order
*aio
;
841 struct policyhead
*ph
;
842 struct MiamiBase
*MiamiBase
;
844 struct addrinfo ai
= *aio
->aio_ai
;
845 struct sockaddr_storage ss
;
848 /* set unspec ("no source is available"), just in case */
849 aio
->aio_srcsa
.sa_family
= AF_UNSPEC
;
850 aio
->aio_srcscope
= -1;
852 switch(ai
.ai_family
) {
858 default: /* ignore unsupported AFs explicitly */
862 /* XXX: make a dummy addrinfo to call connect() */
863 ai
.ai_socktype
= SOCK_DGRAM
;
864 ai
.ai_protocol
= IPPROTO_UDP
; /* is UDP too specific? */
866 memset(&ss
, 0, sizeof(ss
));
867 memcpy(&ss
, ai
.ai_addr
, ai
.ai_addrlen
);
868 ai
.ai_addr
= (struct sockaddr
*)&ss
;
869 get_port(&ai
, "1", 0, MiamiBase
);
871 /* open a socket to get the source address for the given dst */
872 if ((s
= socket(ai
.ai_family
, ai
.ai_socktype
, ai
.ai_protocol
)) < 0)
873 return; /* give up */
874 if (connect(s
, ai
.ai_addr
, ai
.ai_addrlen
) < 0)
876 srclen
= ai
.ai_addrlen
;
877 if (getsockname(s
, &aio
->aio_srcsa
, &srclen
) < 0) {
878 aio
->aio_srcsa
.sa_family
= AF_UNSPEC
;
881 aio
->aio_srcscope
= gai_addr2scopetype(&aio
->aio_srcsa
);
882 aio
->aio_srcpolicy
= match_addrselectpolicy(&aio
->aio_srcsa
, ph
);
883 aio
->aio_matchlen
= matchlen(&aio
->aio_srcsa
, aio
->aio_ai
->ai_addr
);
885 if (ai
.ai_family
== AF_INET6
) {
886 struct in6_ifreq ifr6
;
889 /* XXX: interface name should not be hardcoded */
890 strncpy(ifr6
.ifr_name
, "lo0", sizeof(ifr6
.ifr_name
));
891 memset(&ifr6
, 0, sizeof(ifr6
));
892 memcpy(&ifr6
.ifr_addr
, ai
.ai_addr
, ai
.ai_addrlen
);
893 if (IoctlSocket(s
, SIOCGIFAFLAG_IN6
, &ifr6
) == 0) {
894 flags6
= ifr6
.ifr_ifru
.ifru_flags6
;
895 if ((flags6
& IN6_IFF_DEPRECATED
))
896 aio
->aio_srcflag
|= AIO_SRCFLAG_DEPRECATED
;
908 struct sockaddr
*src
, *dst
;
915 switch (src
->sa_family
) {
918 s
= (u_char
*)&((struct sockaddr_in6
*)src
)->sin6_addr
;
919 d
= (u_char
*)&((struct sockaddr_in6
*)dst
)->sin6_addr
;
920 addrlen
= sizeof(struct in6_addr
);
925 s
= (u_char
*)&((struct sockaddr_in6
*)src
)->sin6_addr
;
926 d
= (u_char
*)&((struct sockaddr_in6
*)dst
)->sin6_addr
;
927 addrlen
= sizeof(struct in_addr
);
935 if ((r
= (*d
++ ^ *s
++)) != 0) {
936 while (r
< addrlen
* 8) {
948 const void *arg1
, *arg2
;
950 const struct ai_order
*dst1
= arg1
, *dst2
= arg2
;
953 * Rule 1: Avoid unusable destinations.
954 * XXX: we currently do not consider if an appropriate route exists.
956 if (dst1
->aio_srcsa
.sa_family
!= AF_UNSPEC
&&
957 dst2
->aio_srcsa
.sa_family
== AF_UNSPEC
) {
960 if (dst1
->aio_srcsa
.sa_family
== AF_UNSPEC
&&
961 dst2
->aio_srcsa
.sa_family
!= AF_UNSPEC
) {
965 /* Rule 2: Prefer matching scope. */
966 if (dst1
->aio_dstscope
== dst1
->aio_srcscope
&&
967 dst2
->aio_dstscope
!= dst2
->aio_srcscope
) {
970 if (dst1
->aio_dstscope
!= dst1
->aio_srcscope
&&
971 dst2
->aio_dstscope
== dst2
->aio_srcscope
) {
975 /* Rule 3: Avoid deprecated addresses. */
976 if (dst1
->aio_srcsa
.sa_family
!= AF_UNSPEC
&&
977 dst2
->aio_srcsa
.sa_family
!= AF_UNSPEC
) {
978 if (!(dst1
->aio_srcflag
& AIO_SRCFLAG_DEPRECATED
) &&
979 (dst2
->aio_srcflag
& AIO_SRCFLAG_DEPRECATED
)) {
982 if ((dst1
->aio_srcflag
& AIO_SRCFLAG_DEPRECATED
) &&
983 !(dst2
->aio_srcflag
& AIO_SRCFLAG_DEPRECATED
)) {
988 /* Rule 4: Prefer home addresses. */
989 /* XXX: not implemented yet */
991 /* Rule 5: Prefer matching label. */
993 if (dst1
->aio_srcpolicy
&& dst1
->aio_dstpolicy
&&
994 dst1
->aio_srcpolicy
->pc_policy
.label
==
995 dst1
->aio_dstpolicy
->pc_policy
.label
&&
996 (dst2
->aio_srcpolicy
== NULL
|| dst2
->aio_dstpolicy
== NULL
||
997 dst2
->aio_srcpolicy
->pc_policy
.label
!=
998 dst2
->aio_dstpolicy
->pc_policy
.label
)) {
1001 if (dst2
->aio_srcpolicy
&& dst2
->aio_dstpolicy
&&
1002 dst2
->aio_srcpolicy
->pc_policy
.label
==
1003 dst2
->aio_dstpolicy
->pc_policy
.label
&&
1004 (dst1
->aio_srcpolicy
== NULL
|| dst1
->aio_dstpolicy
== NULL
||
1005 dst1
->aio_srcpolicy
->pc_policy
.label
!=
1006 dst1
->aio_dstpolicy
->pc_policy
.label
)) {
1011 /* Rule 6: Prefer higher precedence. */
1013 if (dst1
->aio_dstpolicy
&&
1014 (dst2
->aio_dstpolicy
== NULL
||
1015 dst1
->aio_dstpolicy
->pc_policy
.preced
>
1016 dst2
->aio_dstpolicy
->pc_policy
.preced
)) {
1019 if (dst2
->aio_dstpolicy
&&
1020 (dst1
->aio_dstpolicy
== NULL
||
1021 dst2
->aio_dstpolicy
->pc_policy
.preced
>
1022 dst1
->aio_dstpolicy
->pc_policy
.preced
)) {
1027 /* Rule 7: Prefer native transport. */
1028 /* XXX: not implemented yet */
1030 /* Rule 8: Prefer smaller scope. */
1031 if (dst1
->aio_dstscope
>= 0 &&
1032 dst1
->aio_dstscope
< dst2
->aio_dstscope
) {
1035 if (dst2
->aio_dstscope
>= 0 &&
1036 dst2
->aio_dstscope
< dst1
->aio_dstscope
) {
1041 * Rule 9: Use longest matching prefix.
1042 * We compare the match length in a same AF only.
1044 if (dst1
->aio_ai
->ai_addr
->sa_family
==
1045 dst2
->aio_ai
->ai_addr
->sa_family
) {
1046 if (dst1
->aio_matchlen
> dst2
->aio_matchlen
) {
1049 if (dst1
->aio_matchlen
< dst2
->aio_matchlen
) {
1054 /* Rule 10: Otherwise, leave the order unchanged. */
1059 * Copy from scope.c.
1060 * XXX: we should standardize the functions and link them as standard
1064 gai_addr2scopetype(sa
)
1065 struct sockaddr
*sa
;
1068 struct sockaddr_in6
*sa6
;
1070 struct sockaddr_in
*sa4
;
1072 switch(sa
->sa_family
) {
1075 sa6
= (struct sockaddr_in6
*)sa
;
1076 if (IN6_IS_ADDR_MULTICAST(&sa6
->sin6_addr
)) {
1077 /* just use the scope field of the multicast address */
1078 return(sa6
->sin6_addr
.s6_addr
[2] & 0x0f);
1081 * Unicast addresses: map scope type to corresponding scope
1082 * value defined for multcast addresses.
1083 * XXX: hardcoded scope type values are bad...
1085 if (IN6_IS_ADDR_LOOPBACK(&sa6
->sin6_addr
))
1086 return(1); /* node local scope */
1087 if (IN6_IS_ADDR_LINKLOCAL(&sa6
->sin6_addr
))
1088 return(2); /* link-local scope */
1089 if (IN6_IS_ADDR_SITELOCAL(&sa6
->sin6_addr
))
1090 return(5); /* site-local scope */
1091 return(14); /* global scope */
1096 * IPv4 pseudo scoping according to RFC 3484.
1098 sa4
= (struct sockaddr_in
*)sa
;
1099 /* IPv4 autoconfiguration addresses have link-local scope. */
1100 if (((u_char
*)&sa4
->sin_addr
)[0] == 169 &&
1101 ((u_char
*)&sa4
->sin_addr
)[1] == 254)
1103 /* Private addresses have site-local scope. */
1104 if (((u_char
*)&sa4
->sin_addr
)[0] == 10 ||
1105 (((u_char
*)&sa4
->sin_addr
)[0] == 172 &&
1106 (((u_char
*)&sa4
->sin_addr
)[1] & 0xf0) == 16) ||
1107 (((u_char
*)&sa4
->sin_addr
)[0] == 192 &&
1108 ((u_char
*)&sa4
->sin_addr
)[1] == 168))
1109 return(14); /* XXX: It should be 5 unless NAT */
1110 /* Loopback addresses have link-local scope. */
1111 if (((u_char
*)&sa4
->sin_addr
)[0] == 127)
1116 SocketBaseTags(SBTM_SETVAL(SBTC_ERRNO
),EAFNOSUPPORT
,TAG_DONE
); /* is this a good error? */
1123 * passive socket -> anyaddr (0.0.0.0 or ::)
1124 * non-passive socket -> localhost (127.0.0.1 or ::1)
1127 explore_null(pai
, servname
, res
, MiamiBase
)
1128 const struct addrinfo
*pai
;
1129 const char *servname
;
1130 struct addrinfo
**res
;
1131 struct MiamiBase
*MiamiBase
;
1134 const struct afd
*afd
;
1135 struct addrinfo
*cur
;
1136 struct addrinfo sentinel
;
1140 sentinel
.ai_next
= NULL
;
1144 * filter out AFs that are not supported by the kernel
1147 s
= socket(pai
->ai_family
, SOCK_DGRAM
, 0);
1149 SocketBaseTags(SBTM_GETREF(SBTC_ERRNO
),&error
,TAG_DONE
);
1150 if (error
!= EMFILE
)
1156 * if the servname does not match socktype/protocol, ignore it.
1158 if (get_portmatch(pai
, servname
, MiamiBase
) != 0)
1161 afd
= find_afd(pai
->ai_family
);
1165 if (pai
->ai_flags
& AI_PASSIVE
) {
1166 GET_AI(cur
->ai_next
, afd
, afd
->a_addrany
);
1168 * GET_CANONNAME(cur->ai_next, "anyaddr");
1170 GET_PORT(cur
->ai_next
, servname
);
1172 GET_AI(cur
->ai_next
, afd
, afd
->a_loopback
);
1174 * GET_CANONNAME(cur->ai_next, "localhost");
1176 GET_PORT(cur
->ai_next
, servname
);
1180 *res
= sentinel
.ai_next
;
1184 if (sentinel
.ai_next
)
1185 __freeaddrinfo(sentinel
.ai_next
);
1193 explore_numeric(pai
, hostname
, servname
, res
, canonname
, MiamiBase
)
1194 const struct addrinfo
*pai
;
1195 const char *hostname
;
1196 const char *servname
;
1197 struct addrinfo
**res
;
1198 const char *canonname
;
1199 struct MiamiBase
*MiamiBase
;
1201 const struct afd
*afd
;
1202 struct addrinfo
*cur
;
1203 struct addrinfo sentinel
;
1205 char pton
[PTON_MAX
];
1208 sentinel
.ai_next
= NULL
;
1212 * if the servname does not match socktype/protocol, ignore it.
1214 if (get_portmatch(pai
, servname
, MiamiBase
) != 0)
1217 afd
= find_afd(pai
->ai_family
);
1221 switch (afd
->a_af
) {
1222 #if 1 /*X/Open spec*/
1224 if (__inet_aton(hostname
, (struct in_addr
*)pton
) == 1) {
1225 if (pai
->ai_family
== afd
->a_af
||
1226 pai
->ai_family
== PF_UNSPEC
/*?*/) {
1227 GET_AI(cur
->ai_next
, afd
, pton
);
1228 GET_PORT(cur
->ai_next
, servname
);
1229 if ((pai
->ai_flags
& AI_CANONNAME
)) {
1231 * Set the numeric address itself as
1232 * the canonical name, based on a
1233 * clarification in rfc3493.
1235 GET_CANONNAME(cur
->ai_next
, canonname
);
1237 while (cur
&& cur
->ai_next
)
1240 ERR(EAI_FAMILY
); /*xxx*/
1245 if (__inet_pton(afd
->a_af
, hostname
, pton
, SocketBase
) == 1) {
1246 if (pai
->ai_family
== afd
->a_af
||
1247 pai
->ai_family
== PF_UNSPEC
/*?*/) {
1248 GET_AI(cur
->ai_next
, afd
, pton
);
1249 GET_PORT(cur
->ai_next
, servname
);
1250 if ((pai
->ai_flags
& AI_CANONNAME
)) {
1252 * Set the numeric address itself as
1253 * the canonical name, based on a
1254 * clarification in rfc3493.
1256 GET_CANONNAME(cur
->ai_next
, canonname
);
1258 while (cur
&& cur
->ai_next
)
1261 ERR(EAI_FAMILY
); /* XXX */
1266 *res
= sentinel
.ai_next
;
1271 if (sentinel
.ai_next
)
1272 __freeaddrinfo(sentinel
.ai_next
);
1277 * numeric hostname with scope
1280 explore_numeric_scope(pai
, hostname
, servname
, res
, MiamiBase
)
1281 const struct addrinfo
*pai
;
1282 const char *hostname
;
1283 const char *servname
;
1284 struct addrinfo
**res
;
1285 struct MiamiBase
*MiamiBase
;
1287 #if !defined(SCOPE_DELIMITER) || !defined(INET6)
1288 return explore_numeric(pai
, hostname
, servname
, res
, hostname
, MiamiBase
);
1290 const struct afd
*afd
;
1291 struct addrinfo
*cur
;
1293 char *cp
, *hostname2
= NULL
, *scope
, *addr
;
1294 struct sockaddr_in6
*sin6
;
1297 * if the servname does not match socktype/protocol, ignore it.
1299 if (get_portmatch(pai
, servname
, MiamiBase
) != 0)
1302 afd
= find_afd(pai
->ai_family
);
1307 return explore_numeric(pai
, hostname
, servname
, res
, hostname
, MiamiBase
);
1309 cp
= strchr(hostname
, SCOPE_DELIMITER
);
1311 return explore_numeric(pai
, hostname
, servname
, res
, hostname
, MiamiBase
);
1314 * Handle special case of <scoped_address><delimiter><scope id>
1316 hostname2
= strdup(hostname
);
1317 if (hostname2
== NULL
)
1319 /* terminate at the delimiter */
1320 hostname2
[cp
- hostname
] = '\0';
1324 error
= explore_numeric(pai
, addr
, servname
, res
, hostname
, MiamiBase
);
1328 for (cur
= *res
; cur
; cur
= cur
->ai_next
) {
1329 if (cur
->ai_family
!= AF_INET6
)
1331 sin6
= (struct sockaddr_in6
*)(void *)cur
->ai_addr
;
1332 if (ip6_str2scopeid(scope
, sin6
, &scopeid
, MiamiBase
) == -1) {
1334 return(EAI_NONAME
); /* XXX: is return OK? */
1336 sin6
->sin6_scope_id
= scopeid
;
1347 get_canonname(pai
, ai
, str
)
1348 const struct addrinfo
*pai
;
1349 struct addrinfo
*ai
;
1352 if ((pai
->ai_flags
& AI_CANONNAME
) != 0) {
1353 ai
->ai_canonname
= strdup(str
);
1354 if (ai
->ai_canonname
== NULL
)
1360 static struct addrinfo
*
1361 get_ai(pai
, afd
, addr
, MiamiBase
)
1362 const struct addrinfo
*pai
;
1363 const struct afd
*afd
;
1365 struct MiamiBase
*MiamiBase
;
1368 struct addrinfo
*ai
;
1370 struct in6_addr faith_prefix
;
1377 * Transfrom an IPv4 addr into a special IPv6 addr format for
1378 * IPv6->IPv4 translation gateway. (only TCP is supported now)
1380 * +-----------------------------------+------------+
1381 * | faith prefix part (12 bytes) | embedded |
1382 * | | IPv4 addr part (4 bytes)
1383 * +-----------------------------------+------------+
1385 * faith prefix part is specified as ascii IPv6 addr format
1386 * in environmental variable GAI.
1387 * For FAITH to work correctly, routing to faith prefix must be
1388 * setup toward a machine where a FAITH daemon operates.
1389 * Also, the machine must enable some mechanizm
1390 * (e.g. faith interface hack) to divert those packet with
1391 * faith prefixed destination addr to user-land FAITH daemon.
1393 /* TODO: replace this getenv() with something that takes the value from ezTCP configuration */
1394 fp_str
= getenv("GAI");
1395 if (fp_str
&& __inet_pton(AF_INET6
, fp_str
, &faith_prefix
) == 1 &&
1396 afd
->a_af
== AF_INET
&& pai
->ai_socktype
== SOCK_STREAM
, SocketBase
) {
1400 memcpy(&v4a
, addr
, sizeof v4a
);
1401 v4a_top
= v4a
>> IN_CLASSA_NSHIFT
;
1402 if (!IN_MULTICAST(v4a
) && !IN_EXPERIMENTAL(v4a
) &&
1403 v4a_top
!= 0 && v4a
!= IN_LOOPBACKNET
) {
1404 afd
= &afdl
[N_INET6
];
1405 memcpy(&faith_prefix
.s6_addr
[12], addr
,
1406 sizeof(struct in_addr
));
1412 ai
= (struct addrinfo
*)malloc(sizeof(struct addrinfo
)
1413 + (afd
->a_socklen
));
1417 memcpy(ai
, pai
, sizeof(struct addrinfo
));
1418 ai
->ai_addr
= (struct sockaddr
*)(void *)(ai
+ 1);
1419 memset(ai
->ai_addr
, 0, (size_t)afd
->a_socklen
);
1420 ai
->ai_addr
->sa_len
= afd
->a_socklen
;
1421 ai
->ai_addrlen
= afd
->a_socklen
;
1422 ai
->ai_addr
->sa_family
= ai
->ai_family
= afd
->a_af
;
1423 p
= (char *)(void *)(ai
->ai_addr
);
1426 memcpy(p
+ afd
->a_off
, &faith_prefix
, (size_t)afd
->a_addrlen
);
1429 memcpy(p
+ afd
->a_off
, addr
, (size_t)afd
->a_addrlen
);
1434 get_portmatch(ai
, servname
, MiamiBase
)
1435 const struct addrinfo
*ai
;
1436 const char *servname
;
1437 struct MiamiBase
*MiamiBase
;
1440 /* get_port does not touch first argument when matchonly == 1. */
1441 /* LINTED const cast */
1442 return get_port((struct addrinfo
*)ai
, servname
, 1, MiamiBase
);
1446 get_port(ai
, servname
, matchonly
, MiamiBase
)
1447 struct addrinfo
*ai
;
1448 const char *servname
;
1450 struct MiamiBase
*MiamiBase
;
1457 if (servname
== NULL
)
1459 switch (ai
->ai_family
) {
1469 switch (ai
->ai_socktype
) {
1480 return EAI_SOCKTYPE
;
1483 port
= str2number(servname
);
1487 if (port
< 0 || port
> 65535)
1491 if (ai
->ai_flags
& AI_NUMERICSERV
)
1493 switch (ai
->ai_socktype
) {
1504 if ((sp
= getservbyname(servname
, proto
)) == NULL
) {
1511 switch (ai
->ai_family
) {
1513 ((struct sockaddr_in
*)(void *)
1514 ai
->ai_addr
)->sin_port
= port
;
1518 ((struct sockaddr_in6
*)(void *)
1519 ai
->ai_addr
)->sin6_port
= port
;
1528 static const struct afd
*
1532 const struct afd
*afd
;
1534 if (af
== PF_UNSPEC
)
1536 for (afd
= afdl
; afd
->a_af
; afd
++) {
1537 if (afd
->a_af
== af
)
1544 * post-2553: AI_ADDRCONFIG check. if we use getipnodeby* as backend, backend
1545 * will take care of it.
1546 * the semantics of AI_ADDRCONFIG is not defined well. we are not sure
1547 * if the code is right or not.
1549 * XXX PF_UNSPEC -> PF_INET6 + PF_INET mapping needs to be in sync with
1553 addrconfig(pai
, MiamiBase
)
1554 struct addrinfo
*pai
;
1555 struct MiamiBase
*MiamiBase
;
1561 * Note that implementation dependent test for address
1562 * configuration should be done everytime called
1563 * (or apropriate interval),
1564 * because addresses will be dynamically assigned or deleted.
1566 af
= pai
->ai_family
;
1567 if (af
== AF_UNSPEC
) {
1568 if ((s
= socket(AF_INET6
, SOCK_DGRAM
, 0)) < 0)
1572 if ((s
= socket(AF_INET
, SOCK_DGRAM
, 0)) < 0)
1578 if (af
!= AF_UNSPEC
) {
1579 if ((s
= socket(af
, SOCK_DGRAM
, 0)) < 0)
1583 pai
->ai_family
= af
;
1588 /* convert a string to a scope identifier. XXX: IPv6 specific */
1590 ip6_str2scopeid(scope
, sin6
, scopeid
, MiamiBase
)
1592 struct sockaddr_in6
*sin6
;
1594 struct MiamiBase
*MiamiBase
;
1597 struct in6_addr
*a6
;
1601 a6
= &sin6
->sin6_addr
;
1603 /* empty scopeid portion is invalid */
1607 if (IN6_IS_ADDR_LINKLOCAL(a6
) || IN6_IS_ADDR_MC_LINKLOCAL(a6
)) {
1609 * We currently assume a one-to-one mapping between links
1610 * and interfaces, so we simply use interface indices for
1611 * like-local scopes.
1613 *scopeid
= __if_nametoindex(scope
, SocketBase
);
1619 /* still unclear about literal, allow numeric only - placeholder */
1620 if (IN6_IS_ADDR_SITELOCAL(a6
) || IN6_IS_ADDR_MC_SITELOCAL(a6
))
1622 if (IN6_IS_ADDR_MC_ORGLOCAL(a6
))
1625 goto trynumeric
; /* global */
1627 /* try to convert to a numeric id as a last resort */
1630 lscopeid
= __strtoul(scope
, &ep
, 10, &errno
);
1631 SocketBaseTags(SBTM_SETVAL(SBTC_ERRNO
),errno
,TAG_DONE
);
1632 *scopeid
= (u_int32_t
)(lscopeid
& 0xffffffffUL
);
1633 if (errno
== 0 && ep
&& *ep
== '\0' && *scopeid
== lscopeid
)
1640 int _nsdispatch(void *retval
, struct MiamiBase
*MiamiBase
, ...)
1645 va_start(ap
, MiamiBase
);
1646 if (MiamiBase
->usens
!= 1) {
1647 if (_files_getaddrinfo(retval
, NULL
, ap
, MiamiBase
) == NS_SUCCESS
) {
1652 ret
= _dns_getaddrinfo(retval
, NULL
, ap
, MiamiBase
);
1653 if ((ret
!= NS_SUCCESS
) && (MiamiBase
->usens
!= 2))
1654 ret
= _files_getaddrinfo(retval
, NULL
, ap
, MiamiBase
);
1660 * FQDN hostname, DNS lookup
1663 explore_fqdn(pai
, hostname
, servname
, res
, MiamiBase
)
1664 const struct addrinfo
*pai
;
1665 const char *hostname
;
1666 const char *servname
;
1667 struct addrinfo
**res
;
1668 struct MiamiBase
*MiamiBase
;
1670 struct addrinfo
*result
;
1671 struct addrinfo
*cur
;
1676 * if the servname does not match socktype/protocol, ignore it.
1678 if (get_portmatch(pai
, servname
, MiamiBase
) != 0)
1681 switch (_nsdispatch(&result
, MiamiBase
, hostname
, pai
)) {
1693 for (cur
= result
; cur
; cur
= cur
->ai_next
) {
1694 GET_PORT(cur
, servname
);
1695 /* canonname should be filled already */
1706 __freeaddrinfo(result
);
1711 static const char AskedForGot
[] =
1712 "gethostby*.getanswer: asked for \"%s\", got \"%s\"";
1714 static FILE *hostf
= NULL
;
1716 static struct addrinfo
*
1717 getanswer(answer
, anslen
, qname
, qtype
, pai
, MiamiBase
)
1718 const querybuf
*answer
;
1722 const struct addrinfo
*pai
;
1723 struct MiamiBase
*MiamiBase
;
1725 struct addrinfo sentinel
, *cur
;
1727 const struct afd
*afd
;
1734 int type
, class, ancount
, qdcount
;
1735 int haveanswer
, had_error
;
1736 char tbuf
[MAXDNAME
];
1737 int (*name_ok
)(const char *);
1738 char hostbuf
[8*1024];
1740 memset(&sentinel
, 0, sizeof(sentinel
));
1744 eom
= answer
->buf
+ anslen
;
1748 case T_ANY
: /*use T_ANY only for T_A/T_AAAA lookup*/
1752 return (NULL
); /* XXX should be abort(); */
1755 * find first satisfactory answer
1758 ancount
= ntohs(hp
->ancount
);
1759 qdcount
= ntohs(hp
->qdcount
);
1761 ep
= hostbuf
+ sizeof hostbuf
;
1762 cp
= answer
->buf
+ HFIXEDSZ
;
1764 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NO_DISCOVERY
,TAG_DONE
);
1767 n
= dn_expand(answer
->buf
, eom
, cp
, bp
, ep
- bp
);
1768 if ((n
< 0) || !(*name_ok
)(bp
)) {
1769 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NO_RECOVERY
,TAG_DONE
);
1773 if (qtype
== T_A
|| qtype
== T_AAAA
|| qtype
== T_ANY
) {
1774 /* res_send() has already verified that the query name is the
1775 * same as the one we sent; this just gets the expanded name
1776 * (i.e., with the succeeding search-domain tacked on).
1778 n
= strlen(bp
) + 1; /* for the \0 */
1779 if (n
>= MAXHOSTNAMELEN
) {
1780 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NO_RECOVERY
,TAG_DONE
);
1785 /* The qname can be abbreviated, but h_name is now absolute. */
1790 while (ancount
-- > 0 && cp
< eom
&& !had_error
) {
1791 n
= dn_expand(answer
->buf
, eom
, cp
, bp
, ep
- bp
);
1792 if ((n
< 0) || !(*name_ok
)(bp
)) {
1797 type
= _getshort(cp
);
1798 cp
+= INT16SZ
; /* type */
1799 class = _getshort(cp
);
1800 cp
+= INT16SZ
+ INT32SZ
; /* class, TTL */
1802 cp
+= INT16SZ
; /* len */
1803 if (class != C_IN
) {
1804 /* XXX - debug? syslog? */
1806 continue; /* XXX - had_error++ ? */
1808 if ((qtype
== T_A
|| qtype
== T_AAAA
|| qtype
== T_ANY
) &&
1810 n
= dn_expand(answer
->buf
, eom
, cp
, tbuf
, sizeof tbuf
);
1811 if ((n
< 0) || !(*name_ok
)(tbuf
)) {
1816 /* Get canonical name. */
1817 n
= strlen(tbuf
) + 1; /* for the \0 */
1818 if (n
> ep
- bp
|| n
>= MAXHOSTNAMELEN
) {
1822 strlcpy(bp
, tbuf
, ep
- bp
);
1827 if (qtype
== T_ANY
) {
1828 if (!(type
== T_A
|| type
== T_AAAA
)) {
1832 } else if (type
!= qtype
) {
1834 if (type
!= T_KEY
&& type
!= T_SIG
)
1835 syslog(LOG_NOTICE
|LOG_AUTH
,
1836 "gethostby*.getanswer: asked for \"%s %s %s\", got type \"%s\"",
1837 qname
, p_class(C_IN
), p_type(qtype
),
1841 continue; /* XXX - had_error++ ? */
1846 if (strcasecmp(canonname
, bp
) != 0) {
1848 syslog(LOG_NOTICE
|LOG_AUTH
,
1849 AskedForGot
, canonname
, bp
);
1852 continue; /* XXX - had_error++ ? */
1854 if (type
== T_A
&& n
!= INADDRSZ
) {
1858 if (type
== T_AAAA
&& n
!= IN6ADDRSZ
) {
1862 #ifdef FILTER_V4MAPPED
1863 if (type
== T_AAAA
) {
1864 struct in6_addr in6
;
1865 memcpy(&in6
, cp
, sizeof(in6
));
1866 if (IN6_IS_ADDR_V4MAPPED(&in6
)) {
1876 nn
= strlen(bp
) + 1; /* for the \0 */
1880 /* don't overwrite pai */
1882 ai
.ai_family
= (type
== T_A
) ? AF_INET
: AF_INET6
;
1883 afd
= find_afd(ai
.ai_family
);
1888 cur
->ai_next
= get_ai(&ai
, afd
, (const char *)cp
, MiamiBase
);
1889 if (cur
->ai_next
== NULL
)
1891 while (cur
&& cur
->ai_next
)
1902 #if defined(RESOLVSORT)
1904 * We support only IPv4 address for backward
1905 * compatibility against gethostbyname(3).
1907 if (_res
.nsort
&& qtype
== T_A
) {
1908 if (addr4sort(&sentinel
, MiamiBase
) < 0) {
1909 __freeaddrinfo(sentinel
.ai_next
);
1910 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NO_RECOVERY
,TAG_DONE
);
1914 #endif /*RESOLVSORT*/
1916 (void)get_canonname(pai
, sentinel
.ai_next
, qname
);
1918 (void)get_canonname(pai
, sentinel
.ai_next
, canonname
);
1919 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NETDB_SUCCESS
,TAG_DONE
);
1920 return sentinel
.ai_next
;
1922 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NO_RECOVERY
,TAG_DONE
);
1928 struct addrinfo
*ai
;
1933 addr4sort(struct addrinfo
*sentinel
, struct MiamiBase
*MiamiBase
)
1935 struct addrinfo
*ai
;
1936 struct addr_ptr
*addrs
, addr
;
1937 struct sockaddr_in
*sin
;
1944 for (ai
= sentinel
->ai_next
; ai
; ai
= ai
->ai_next
)
1947 return 0; /* We don't need sorting. */
1948 if ((addrs
= malloc(sizeof(struct addr_ptr
) * naddrs
)) == NULL
)
1951 for (ai
= sentinel
->ai_next
; ai
; ai
= ai
->ai_next
) {
1952 sin
= (struct sockaddr_in
*)ai
->ai_addr
;
1953 for (j
= 0; (unsigned)j
< _res
.nsort
; j
++) {
1954 if (_res
.sort_list
[j
].addr
.s_addr
==
1955 (sin
->sin_addr
.s_addr
& _res
.sort_list
[j
].mask
))
1960 if (needsort
== 0 && i
> 0 && j
< addrs
[i
- 1].aval
)
1969 while (needsort
< naddrs
) {
1970 for (j
= needsort
- 1; j
>= 0; j
--) {
1971 if (addrs
[j
].aval
> addrs
[j
+1].aval
) {
1973 addrs
[j
] = addrs
[j
+ 1];
1974 addrs
[j
+ 1] = addr
;
1982 for (i
= 0; i
< naddrs
; ++i
) {
1983 ai
->ai_next
= addrs
[i
].ai
;
1990 #endif /*RESOLVSORT*/
1994 _dns_getaddrinfo(rv
, cb_data
, ap
, MiamiBase
)
1998 struct MiamiBase
*MiamiBase
;
2000 struct addrinfo
*ai
;
2001 querybuf
*buf
, *buf2
;
2002 const char *hostname
;
2003 const struct addrinfo
*pai
;
2004 struct addrinfo sentinel
, *cur
;
2005 struct res_target q
, q2
;
2007 hostname
= va_arg(ap
, char *);
2008 pai
= va_arg(ap
, const struct addrinfo
*);
2010 memset(&q
, 0, sizeof(q2
));
2011 memset(&q2
, 0, sizeof(q2
));
2012 memset(&sentinel
, 0, sizeof(sentinel
));
2015 buf
= malloc(sizeof(*buf
));
2017 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NETDB_INTERNAL
,TAG_DONE
);
2020 buf2
= malloc(sizeof(*buf2
));
2023 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NETDB_INTERNAL
,TAG_DONE
);
2027 switch (pai
->ai_family
) {
2032 q
.answer
= buf
->buf
;
2033 q
.anslen
= sizeof(buf
->buf
);
2038 q2
.answer
= buf2
->buf
;
2039 q2
.anslen
= sizeof(buf2
->buf
);
2045 q
.answer
= buf
->buf
;
2046 q
.anslen
= sizeof(buf
->buf
);
2052 q
.answer
= buf
->buf
;
2053 q
.anslen
= sizeof(buf
->buf
);
2060 if (res_searchN(hostname
, &q
, MiamiBase
) < 0) {
2067 ai
= getanswer(buf2
, q2
.n
, q2
.name
, q2
.qtype
, pai
, MiamiBase
);
2070 while (cur
&& cur
->ai_next
)
2074 ai
= getanswer(buf
, q
.n
, q
.name
, q
.qtype
, pai
, MiamiBase
);
2079 if (sentinel
.ai_next
== NULL
)
2082 SocketBaseTags(SBTM_GETREF(SBTC_HERRNO
),&h_errno
,TAG_DONE
);
2084 case HOST_NOT_FOUND
:
2092 *((struct addrinfo
**)rv
) = sentinel
.ai_next
;
2095 #if 0 /* TODO: move to netdb.c */
2096 static struct addrinfo
*
2097 _gethtent(name
, pai
)
2099 const struct addrinfo
*pai
;
2102 char *cp
, *tname
, *cname
;
2103 struct addrinfo hints
, *res0
, *res
;
2106 char hostbuf
[8*1024];
2108 if (!hostf
&& !(hostf
= fopen(_PATH_HOSTS
, "r" )))
2111 if (!(p
= fgets(hostbuf
, sizeof hostbuf
, hostf
)))
2115 cp
= strpbrk(p
, "#\n");
2118 if (!(cp
= strpbrk(p
, " \t")))
2123 /* if this is not something we're looking for, skip it. */
2125 if (*cp
== ' ' || *cp
== '\t') {
2132 if ((cp
= strpbrk(cp
, " \t")) != NULL
)
2134 if (strcasecmp(name
, tname
) == 0)
2140 /* we should not glob socktype/protocol here */
2141 memset(&hints
, 0, sizeof(hints
));
2142 hints
.ai_family
= pai
->ai_family
;
2143 hints
.ai_socktype
= SOCK_DGRAM
;
2144 hints
.ai_protocol
= 0;
2145 hints
.ai_flags
= AI_NUMERICHOST
;
2146 error
= __getaddrinfo(addr
, "0", &hints
, &res0
, MiamiBase
);
2149 #ifdef FILTER_V4MAPPED
2150 /* XXX should check all items in the chain */
2151 if (res0
->ai_family
== AF_INET6
&&
2152 IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6
*)res0
->ai_addr
)->sin6_addr
)) {
2153 __freeaddrinfo(res0
);
2157 for (res
= res0
; res
; res
= res
->ai_next
) {
2159 res
->ai_flags
= pai
->ai_flags
;
2160 res
->ai_socktype
= pai
->ai_socktype
;
2161 res
->ai_protocol
= pai
->ai_protocol
;
2163 if (pai
->ai_flags
& AI_CANONNAME
) {
2164 if (get_canonname(pai
, res
, cname
) != 0) {
2165 __freeaddrinfo(res0
);
2175 _files_getaddrinfo(rv
, cb_data
, ap
, MiamiBase
)
2179 struct MiamiBase
*MiamiBase
;
2182 const struct addrinfo
*pai
;
2183 struct addrinfo sentinel
, *cur
;
2186 name
= va_arg(ap
, char *);
2187 pai
= va_arg(ap
, struct addrinfo
*);
2189 memset(&sentinel
, 0, sizeof(sentinel
));
2193 while ((p
= gethtent(name
, pai
, MiamiBase
)) != NULL
) {
2195 while (cur
&& cur
->ai_next
)
2200 *((struct addrinfo
**)rv
) = sentinel
.ai_next
;
2201 if (sentinel
.ai_next
== NULL
)
2207 static char *__ypdomain
;
2210 static struct addrinfo
*
2211 _yphostent(line
, pai
, MiamiBase
)
2213 const struct addrinfo
*pai
;
2214 struct MiamiBase
*MiamiBase
;
2216 struct addrinfo sentinel
, *cur
;
2217 struct addrinfo hints
, *res
, *res0
;
2220 const char *addr
, *canonname
;
2224 addr
= canonname
= NULL
;
2226 memset(&sentinel
, 0, sizeof(sentinel
));
2230 /* terminate line */
2231 cp
= strchr(p
, '\n');
2238 cp
= strpbrk(p
, " \t");
2240 if (canonname
== NULL
)
2250 if (*cp
== ' ' || *cp
== '\t') {
2256 if ((cp
= strpbrk(cp
, " \t")) != NULL
)
2261 hints
.ai_flags
= AI_NUMERICHOST
;
2262 error
= __getaddrinfo(addr
, NULL
, &hints
, &res0
, MiamiBase
);
2264 for (res
= res0
; res
; res
= res
->ai_next
) {
2266 res
->ai_flags
= pai
->ai_flags
;
2268 if (pai
->ai_flags
& AI_CANONNAME
)
2269 (void)get_canonname(pai
, res
, canonname
);
2274 cur
->ai_next
= res0
;
2275 while (cur
&& cur
->ai_next
)
2285 return sentinel
.ai_next
;
2290 _yp_getaddrinfo(rv
, cb_data
, ap
, MiamiBase
)
2294 struct MiamiBase
*MiamiBase
;
2296 struct addrinfo sentinel
, *cur
;
2297 struct addrinfo
*ai
= NULL
;
2298 static char *__ypcurrent
;
2299 int __ypcurrentlen
, r
;
2301 const struct addrinfo
*pai
;
2303 name
= va_arg(ap
, char *);
2304 pai
= va_arg(ap
, const struct addrinfo
*);
2306 memset(&sentinel
, 0, sizeof(sentinel
));
2311 if (_yp_check(&__ypdomain
, MiamiBase
) == 0) {
2320 /* hosts.byname is only for IPv4 (Solaris8) */
2321 if (pai
->ai_family
== PF_UNSPEC
|| pai
->ai_family
== PF_INET
) {
2322 r
= yp_match(__ypdomain
, "hosts.byname", name
,
2323 (int)strlen(name
), &__ypcurrent
, &__ypcurrentlen
, MiamiBase
);
2325 struct addrinfo ai4
;
2328 ai4
.ai_family
= AF_INET
;
2329 ai
= _yphostent(__ypcurrent
, &ai4
, MiamiBase
);
2332 while (cur
&& cur
->ai_next
)
2338 /* ipnodes.byname can hold both IPv4/v6 */
2339 r
= yp_match(__ypdomain
, "ipnodes.byname", name
,
2340 (int)strlen(name
), &__ypcurrent
, &__ypcurrentlen
, MiamiBase
);
2342 ai
= _yphostent(__ypcurrent
, pai
, MiamiBase
);
2345 while (cur
&& cur
->ai_next
)
2351 if (sentinel
.ai_next
== NULL
) {
2352 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),HOST_NOT_FOUND
,TAG_DONE
);
2355 *((struct addrinfo
**)rv
) = sentinel
.ai_next
;
2360 /* resolver logic */
2362 extern const char *__hostalias(const char *);
2365 * Formulate a normal query, send, and await answer.
2366 * Returned answer is placed in supplied buffer "answer".
2367 * Perform preliminary check of answer, returning success only
2368 * if no error is indicated and the answer count is nonzero.
2369 * Return the size of the response on success, -1 on error.
2370 * Error number is left in h_errno.
2372 * Caller must parse answer and determine whether it answers the question.
2375 res_queryN(name
, target
, MiamiBase
)
2376 const char *name
; /* domain name */
2377 struct res_target
*target
;
2378 struct MiamiBase
*MiamiBase
;
2383 struct res_target
*t
;
2390 if ((_res
.options
& RES_INIT
) == 0 && EZTCP_res_init() == -1) {
2391 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NETDB_INTERNAL
,TAG_DONE
);
2395 buf
= malloc(MAXPACKET
);
2397 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NETDB_INTERNAL
,TAG_DONE
);
2401 for (t
= target
; t
; t
= t
->next
) {
2406 hp
= (HEADER
*)(void *)t
->answer
;
2407 hp
->rcode
= NOERROR
; /* default */
2409 /* make it easier... */
2415 if (_res
.options
& RES_DEBUG
)
2416 syslog(LOG_DEBUG
, ";; res_query(%s, %d, %d)\n", name
, class, type
);
2419 n
= EZTCP_res_mkquery(QUERY
, name
, class, type
, NULL
, 0, NULL
,
2421 if (n
> 0 && (_res
.options
& RES_USE_EDNS0
) != 0)
2422 n
= res_opt(n
, buf
, MAXPACKET
, anslen
);
2425 if (_res
.options
& RES_DEBUG
)
2426 vsyslog(LOG_DEBUG
, ";; res_query: mkquery failed\n", NULL
);
2429 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NO_RECOVERY
,TAG_DONE
);
2432 n
= EZTCP_res_send(buf
, n
, answer
, anslen
);
2436 if (_res
.options
& RES_DEBUG
)
2437 vsyslog(LOG_DEBUG
, ";; res_query: send error\n", NULL
);
2440 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),TRY_AGAIN
,TAG_DONE
);
2445 if (n
< 0 || n
> anslen
)
2446 hp
->rcode
= FORMERR
; /* XXX not very informative */
2447 if (hp
->rcode
!= NOERROR
|| ntohs(hp
->ancount
) == 0) {
2448 rcode
= hp
->rcode
; /* record most recent error */
2450 if (_res
.options
& RES_DEBUG
)
2451 syslog(LOG_DEBUG
, ";; rcode = %u, ancount=%u\n", hp
->rcode
,
2452 ntohs(hp
->ancount
));
2457 ancount
+= ntohs(hp
->ancount
);
2468 h_errno
= HOST_NOT_FOUND
;
2471 h_errno
= TRY_AGAIN
;
2480 h_errno
= NO_RECOVERY
;
2483 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),h_errno
,TAG_DONE
);
2490 * Formulate a normal query, send, and retrieve answer in supplied buffer.
2491 * Return the size of the response on success, -1 on error.
2492 * If enabled, implement search rules until answer or unrecoverable failure
2493 * is detected. Error code, if any, is left in h_errno.
2496 res_searchN(name
, target
, MiamiBase
)
2497 const char *name
; /* domain name */
2498 struct res_target
*target
;
2499 struct MiamiBase
*MiamiBase
;
2501 const char *cp
, * const *domain
;
2502 HEADER
*hp
= (HEADER
*)(void *)target
->answer
; /*XXX*/
2504 int trailing_dot
, ret
, saved_herrno
;
2506 int got_nodata
= 0, got_servfail
= 0, tried_as_is
= 0;
2508 if ((_res
.options
& RES_INIT
) == 0 && EZTCP_res_init() == -1) {
2509 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NETDB_INTERNAL
,TAG_DONE
);
2512 /* default, if we never query */
2513 SocketBaseTags(SBTM_SETVAL(SBTC_ERRNO
),0,SBTM_SETVAL(SBTC_HERRNO
),HOST_NOT_FOUND
,TAG_DONE
);
2515 for (cp
= name
; *cp
; cp
++)
2516 dots
+= (*cp
== '.');
2518 if (cp
> name
&& *--cp
== '.')
2522 * if there aren't any dots, it could be a user-level alias
2524 if (!dots
&& (cp
= __hostalias(name
)) != NULL
)
2525 return (res_queryN(cp
, target
, MiamiBase
));
2528 * If there are dots in the name already, let's just give it a try
2529 * 'as is'. The threshold can be set with the "ndots" option.
2532 if (dots
>= _res
.ndots
) {
2533 ret
= res_querydomainN(name
, NULL
, target
, MiamiBase
);
2536 SocketBaseTags(SBTM_GETREF(SBTC_HERRNO
),&saved_herrno
,TAG_DONE
);
2541 * We do at least one level of search if
2542 * - there is no dot and RES_DEFNAME is set, or
2543 * - there is at least one dot, there is no trailing dot,
2544 * and RES_DNSRCH is set.
2546 if ((!dots
&& (_res
.options
& RES_DEFNAMES
)) ||
2547 (dots
&& !trailing_dot
&& (_res
.options
& RES_DNSRCH
))) {
2550 for (domain
= (const char * const *)_res
.dnsrch
;
2554 ret
= res_querydomainN(name
, *domain
, target
, MiamiBase
);
2559 * If no server present, give up.
2560 * If name isn't found in this domain,
2561 * keep trying higher domains in the search list
2562 * (if that's enabled).
2563 * On a NO_DATA error, keep trying, otherwise
2564 * a wildcard entry of another type could keep us
2565 * from finding this entry higher in the domain.
2566 * If we get some other error (negative answer or
2567 * server failure), then stop searching up,
2568 * but try the input name below in case it's
2571 SocketBaseTags(SBTM_GETREF(SBTC_ERRNO
),&errno
,TAG_DONE
);
2572 if (errno
== ECONNREFUSED
) {
2573 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),TRY_AGAIN
,TAG_DONE
);
2576 SocketBaseTags(SBTM_GETREF(SBTC_HERRNO
),&h_errno
,TAG_DONE
);
2581 case HOST_NOT_FOUND
:
2585 if (hp
->rcode
== SERVFAIL
) {
2586 /* try next search element, if any */
2592 /* anything else implies that we're done */
2596 * if we got here for some reason other than DNSRCH,
2597 * we only wanted one iteration of the loop, so stop.
2599 if (!(_res
.options
& RES_DNSRCH
))
2605 * if we have not already tried the name "as is", do that now.
2606 * note that we do this regardless of how many dots were in the
2607 * name or whether it ends with a dot.
2609 if (!tried_as_is
&& (dots
|| !(_res
.options
& RES_NOTLDQUERY
))) {
2610 ret
= res_querydomainN(name
, NULL
, target
, MiamiBase
);
2616 * if we got here, we didn't satisfy the search.
2617 * if we did an initial full query, return that query's h_errno
2618 * (note that we wouldn't be here if that query had succeeded).
2619 * else if we ever got a nodata, send that back as the reason.
2620 * else send back meaningless h_errno, that being the one from
2621 * the last DNSRCH we did.
2623 if (saved_herrno
!= -1)
2624 h_errno
= saved_herrno
;
2625 else if (got_nodata
)
2627 else if (got_servfail
)
2628 h_errno
= TRY_AGAIN
;
2629 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),h_errno
,TAG_DONE
);
2634 * Perform a call on res_query on the concatenation of name and domain,
2635 * removing a trailing dot from name if domain is NULL.
2638 res_querydomainN(name
, domain
, target
, MiamiBase
)
2639 const char *name
, *domain
;
2640 struct res_target
*target
;
2641 struct MiamiBase
*MiamiBase
;
2643 char nbuf
[MAXDNAME
];
2644 const char *longname
= nbuf
;
2647 if ((_res
.options
& RES_INIT
) == 0 && EZTCP_res_init() == -1) {
2648 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NETDB_INTERNAL
,TAG_DONE
);
2652 if (_res
.options
& RES_DEBUG
)
2653 syslog(LOG_DEBUG
, ";; res_querydomain(%s, %s)\n",
2654 name
, domain
?domain
:"<Nil>");
2656 if (domain
== NULL
) {
2658 * Check for trailing '.';
2659 * copy without '.' if present.
2662 if (n
>= MAXDNAME
) {
2663 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NO_RECOVERY
,TAG_DONE
);
2666 if (n
> 0 && name
[--n
] == '.') {
2667 strncpy(nbuf
, name
, n
);
2674 if (n
+ d
+ 1 >= MAXDNAME
) {
2675 SocketBaseTags(SBTM_SETVAL(SBTC_HERRNO
),NO_RECOVERY
,TAG_DONE
);
2678 snprintf(nbuf
, sizeof(nbuf
), "%s.%s", name
, domain
);
2680 return (res_queryN(longname
, target
, MiamiBase
));