4 * Portions Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC")
5 * Portions Copyright (C) 1996-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
21 * Copyright (c) 1985, 1988, 1993
22 * The Regents of the University of California. All rights reserved.
24 * Redistribution and use in source and binary forms, with or without
25 * modification, are permitted provided that the following conditions
27 * 1. Redistributions of source code must retain the above copyright
28 * notice, this list of conditions and the following disclaimer.
29 * 2. Redistributions in binary form must reproduce the above copyright
30 * notice, this list of conditions and the following disclaimer in the
31 * documentation and/or other materials provided with the distribution.
32 * 3. All advertising materials mentioning features or use of this software
33 * must display the following acknowledgement:
34 * This product includes software developed by the University of
35 * California, Berkeley and its contributors.
36 * 4. Neither the name of the University nor the names of its contributors
37 * may be used to endorse or promote products derived from this software
38 * without specific prior written permission.
40 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
53 /* from gethostnamadr.c 8.1 (Berkeley) 6/4/93 */
54 /* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */
56 #if defined(LIBC_SCCS) && !defined(lint)
57 static const char rcsid
[] = "Id: dns_ho.c,v 1.23 2008/11/14 02:36:51 marka Exp";
58 #endif /* LIBC_SCCS and not lint */
62 #include "port_before.h"
64 #include <sys/types.h>
65 #include <sys/param.h>
66 #include <sys/socket.h>
68 #include <netinet/in.h>
69 #include <arpa/inet.h>
70 #include <arpa/nameser.h>
81 #include <isc/memcluster.h>
84 #include "port_after.h"
90 # define SPRINTF(x) strlen(sprintf/**/x)
92 # define SPRINTF(x) sprintf x
100 #define MAXPACKET (65535) /*%< Maximum TCP message size */
101 #define BOUNDS_CHECK(ptr, count) \
102 if ((ptr) + (count) > eom) { \
109 u_char buf
[MAXPACKET
];
112 struct dns_res_target
{
113 struct dns_res_target
*next
;
114 querybuf qbuf
; /*%< query buffer */
115 u_char
*answer
; /*%< buffer to put answer */
116 int anslen
; /*%< size of answer buffer */
117 int qclass
, qtype
; /*%< class and type of query */
118 int action
; /*%< condition whether query is really issued */
119 char qname
[MAXDNAME
+1]; /*%< domain name */
121 int n
; /*%< result length */
124 enum {RESTGT_DOALWAYS
, RESTGT_AFTERFAILURE
, RESTGT_IGNORE
};
125 enum {RESQRY_SUCCESS
, RESQRY_FAIL
};
129 char * h_addr_ptrs
[MAXADDRS
+ 1];
130 char * host_aliases
[MAXALIASES
];
131 char hostbuf
[8*1024];
132 u_char host_addr
[16]; /*%< IPv4 or IPv6 */
133 struct __res_state
*res
;
134 void (*free_res
)(void *);
142 static const u_char mapped
[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
143 static const u_char tunnelled
[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
144 /* Note: the IPv6 loopback address is in the "tunnel" space */
145 static const u_char v6local
[] = { 0,0, 0,1 }; /*%< last 4 bytes of IPv6 addr */
148 static void ho_close(struct irs_ho
*this);
149 static struct hostent
* ho_byname(struct irs_ho
*this, const char *name
);
150 static struct hostent
* ho_byname2(struct irs_ho
*this, const char *name
,
152 static struct hostent
* ho_byaddr(struct irs_ho
*this, const void *addr
,
154 static struct hostent
* ho_next(struct irs_ho
*this);
155 static void ho_rewind(struct irs_ho
*this);
156 static void ho_minimize(struct irs_ho
*this);
157 static struct __res_state
* ho_res_get(struct irs_ho
*this);
158 static void ho_res_set(struct irs_ho
*this,
159 struct __res_state
*res
,
160 void (*free_res
)(void *));
161 static struct addrinfo
* ho_addrinfo(struct irs_ho
*this, const char *name
,
162 const struct addrinfo
*pai
);
164 static void map_v4v6_hostent(struct hostent
*hp
, char **bp
,
166 static void addrsort(res_state
, char **, int);
167 static struct hostent
* gethostans(struct irs_ho
*this,
168 const u_char
*ansbuf
, int anslen
,
169 const char *qname
, int qtype
,
171 struct addrinfo
**ret_aip
,
172 const struct addrinfo
*pai
);
173 static int add_hostent(struct pvt
*pvt
, char *bp
, char **hap
,
174 struct addrinfo
*ai
);
175 static int init(struct irs_ho
*this);
180 irs_dns_ho(struct irs_acc
*this) {
186 if (!(pvt
= memget(sizeof *pvt
))) {
190 memset(pvt
, 0, sizeof *pvt
);
192 if (!(ho
= memget(sizeof *ho
))) {
193 memput(pvt
, sizeof *pvt
);
197 memset(ho
, 0x5e, sizeof *ho
);
199 ho
->close
= ho_close
;
200 ho
->byname
= ho_byname
;
201 ho
->byname2
= ho_byname2
;
202 ho
->byaddr
= ho_byaddr
;
204 ho
->rewind
= ho_rewind
;
205 ho
->minimize
= ho_minimize
;
206 ho
->res_get
= ho_res_get
;
207 ho
->res_set
= ho_res_set
;
208 ho
->addrinfo
= ho_addrinfo
;
215 ho_close(struct irs_ho
*this) {
216 struct pvt
*pvt
= (struct pvt
*)this->private;
219 if (pvt
->res
&& pvt
->free_res
)
220 (*pvt
->free_res
)(pvt
->res
);
221 memput(pvt
, sizeof *pvt
);
222 memput(this, sizeof *this);
225 static struct hostent
*
226 ho_byname(struct irs_ho
*this, const char *name
) {
227 struct pvt
*pvt
= (struct pvt
*)this->private;
230 if (init(this) == -1)
233 if (pvt
->res
->options
& RES_USE_INET6
) {
234 hp
= ho_byname2(this, name
, AF_INET6
);
238 return (ho_byname2(this, name
, AF_INET
));
241 static struct hostent
*
242 ho_byname2(struct irs_ho
*this, const char *name
, int af
)
244 struct pvt
*pvt
= (struct pvt
*)this->private;
245 struct hostent
*hp
= NULL
;
247 char tmp
[NS_MAXDNAME
];
250 struct dns_res_target
*q
, *p
;
251 int querystate
= RESQRY_FAIL
;
253 if (init(this) == -1)
256 q
= memget(sizeof(*q
));
258 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
262 memset(q
, 0, sizeof(*q
));
269 q
->answer
= q
->qbuf
.buf
;
270 q
->anslen
= sizeof(q
->qbuf
);
271 q
->action
= RESTGT_DOALWAYS
;
277 q
->answer
= q
->qbuf
.buf
;
278 q
->anslen
= sizeof(q
->qbuf
);
279 q
->action
= RESTGT_DOALWAYS
;
282 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
283 errno
= EAFNOSUPPORT
;
289 * if there aren't any dots, it could be a user-level alias.
290 * this is also done in res_nquery() since we are not the only
291 * function that looks up host names.
293 if (!strchr(name
, '.') && (cp
= res_hostalias(pvt
->res
, name
,
297 for (p
= q
; p
; p
= p
->next
) {
299 case RESTGT_DOALWAYS
:
301 case RESTGT_AFTERFAILURE
:
302 if (querystate
== RESQRY_SUCCESS
)
309 if ((n
= res_nsearch(pvt
->res
, name
, p
->qclass
, p
->qtype
,
310 p
->answer
, p
->anslen
)) < 0) {
311 querystate
= RESQRY_FAIL
;
315 memset(&ai
, 0, sizeof(ai
));
317 if ((hp
= gethostans(this, p
->answer
, n
, name
, p
->qtype
,
319 (const struct addrinfo
*)&ai
)) != NULL
)
320 goto cleanup
; /*%< no more loop is necessary */
321 querystate
= RESQRY_FAIL
;
327 memput(q
, sizeof(*q
));
331 static struct hostent
*
332 ho_byaddr(struct irs_ho
*this, const void *addr
, int len
, int af
)
334 struct pvt
*pvt
= (struct pvt
*)this->private;
335 const u_char
*uaddr
= addr
;
337 struct hostent
*hp
= NULL
;
339 struct dns_res_target
*q
, *q2
, *p
;
341 int querystate
= RESQRY_FAIL
;
343 if (init(this) == -1)
346 q
= memget(sizeof(*q
));
347 q2
= memget(sizeof(*q2
));
348 if (q
== NULL
|| q2
== NULL
) {
349 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
353 memset(q
, 0, sizeof(*q
));
354 memset(q2
, 0, sizeof(*q2
));
356 if (af
== AF_INET6
&& len
== IN6ADDRSZ
&&
357 (!memcmp(uaddr
, mapped
, sizeof mapped
) ||
358 (!memcmp(uaddr
, tunnelled
, sizeof tunnelled
) &&
359 memcmp(&uaddr
[sizeof tunnelled
], v6local
, sizeof(v6local
))))) {
361 addr
= (const char *)addr
+ sizeof mapped
;
362 uaddr
+= sizeof mapped
;
371 q
->answer
= q
->qbuf
.buf
;
372 q
->anslen
= sizeof(q
->qbuf
);
373 q
->action
= RESTGT_DOALWAYS
;
379 q
->answer
= q
->qbuf
.buf
;
380 q
->anslen
= sizeof(q
->qbuf
);
382 q
->action
= RESTGT_DOALWAYS
;
385 q2
->answer
= q2
->qbuf
.buf
;
386 q2
->anslen
= sizeof(q2
->qbuf
);
387 if ((pvt
->res
->options
& RES_NO_NIBBLE2
) != 0U)
388 q2
->action
= RESTGT_IGNORE
;
390 q2
->action
= RESTGT_AFTERFAILURE
;
393 errno
= EAFNOSUPPORT
;
394 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
400 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
407 (void) sprintf(qp
, "%u.%u.%u.%u.in-addr.arpa",
414 if (q
->action
!= RESTGT_IGNORE
) {
415 const char *nibsuff
= res_get_nibblesuffix(pvt
->res
);
417 for (n
= IN6ADDRSZ
- 1; n
>= 0; n
--) {
418 i
= SPRINTF((qp
, "%x.%x.",
420 (uaddr
[n
] >> 4) & 0xf));
425 if (strlen(q
->qname
) + strlen(nibsuff
) + 1 >
427 errno
= ENAMETOOLONG
;
428 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
432 strcpy(qp
, nibsuff
); /* (checked) */
434 if (q2
->action
!= RESTGT_IGNORE
) {
435 const char *nibsuff2
= res_get_nibblesuffix2(pvt
->res
);
437 for (n
= IN6ADDRSZ
- 1; n
>= 0; n
--) {
438 i
= SPRINTF((qp
, "%x.%x.",
440 (uaddr
[n
] >> 4) & 0xf));
445 if (strlen(q2
->qname
) + strlen(nibsuff2
) + 1 >
447 errno
= ENAMETOOLONG
;
448 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
452 strcpy(qp
, nibsuff2
); /* (checked) */
459 for (p
= q
; p
; p
= p
->next
) {
461 case RESTGT_DOALWAYS
:
463 case RESTGT_AFTERFAILURE
:
464 if (querystate
== RESQRY_SUCCESS
)
471 if ((n
= res_nquery(pvt
->res
, p
->qname
, p
->qclass
, p
->qtype
,
472 p
->answer
, p
->anslen
)) < 0) {
473 querystate
= RESQRY_FAIL
;
477 memset(&ai
, 0, sizeof(ai
));
479 hp
= gethostans(this, p
->answer
, n
, p
->qname
, T_PTR
, af
, size
,
480 NULL
, (const struct addrinfo
*)&ai
);
482 querystate
= RESQRY_FAIL
;
486 memcpy(pvt
->host_addr
, addr
, len
);
487 pvt
->h_addr_ptrs
[0] = (char *)pvt
->host_addr
;
488 pvt
->h_addr_ptrs
[1] = NULL
;
489 if (af
== AF_INET
&& (pvt
->res
->options
& RES_USE_INET6
)) {
490 map_v4v6_address((char*)pvt
->host_addr
,
491 (char*)pvt
->host_addr
);
492 pvt
->host
.h_addrtype
= AF_INET6
;
493 pvt
->host
.h_length
= IN6ADDRSZ
;
496 RES_SET_H_ERRNO(pvt
->res
, NETDB_SUCCESS
);
497 goto cleanup
; /*%< no more loop is necessary. */
499 hp
= NULL
; /*%< H_ERRNO was set by subroutines */
502 memput(q
, sizeof(*q
));
504 memput(q2
, sizeof(*q2
));
508 static struct hostent
*
509 ho_next(struct irs_ho
*this) {
517 ho_rewind(struct irs_ho
*this) {
525 ho_minimize(struct irs_ho
*this) {
526 struct pvt
*pvt
= (struct pvt
*)this->private;
529 res_nclose(pvt
->res
);
532 static struct __res_state
*
533 ho_res_get(struct irs_ho
*this) {
534 struct pvt
*pvt
= (struct pvt
*)this->private;
537 struct __res_state
*res
;
538 res
= (struct __res_state
*)malloc(sizeof *res
);
543 memset(res
, 0, sizeof *res
);
544 ho_res_set(this, res
, free
);
551 extern struct addrinfo
*addr2addrinfo
__P((const struct addrinfo
*,
554 static struct addrinfo
*
555 ho_addrinfo(struct irs_ho
*this, const char *name
, const struct addrinfo
*pai
)
557 struct pvt
*pvt
= (struct pvt
*)this->private;
559 char tmp
[NS_MAXDNAME
];
561 struct dns_res_target
*q
, *q2
, *p
;
562 struct addrinfo sentinel
, *cur
;
563 int querystate
= RESQRY_FAIL
;
565 if (init(this) == -1)
568 memset(&sentinel
, 0, sizeof(sentinel
));
571 q
= memget(sizeof(*q
));
572 q2
= memget(sizeof(*q2
));
573 if (q
== NULL
|| q2
== NULL
) {
574 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
578 memset(q
, 0, sizeof(*q2
));
579 memset(q2
, 0, sizeof(*q2
));
581 switch (pai
->ai_family
) {
586 q
->answer
= q
->qbuf
.buf
;
587 q
->anslen
= sizeof(q
->qbuf
);
589 q
->action
= RESTGT_DOALWAYS
;
592 q2
->answer
= q2
->qbuf
.buf
;
593 q2
->anslen
= sizeof(q2
->qbuf
);
594 q2
->action
= RESTGT_DOALWAYS
;
599 q
->answer
= q
->qbuf
.buf
;
600 q
->anslen
= sizeof(q
->qbuf
);
601 q
->action
= RESTGT_DOALWAYS
;
606 q
->answer
= q
->qbuf
.buf
;
607 q
->anslen
= sizeof(q
->qbuf
);
608 q
->action
= RESTGT_DOALWAYS
;
611 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
); /*%< better error? */
616 * if there aren't any dots, it could be a user-level alias.
617 * this is also done in res_nquery() since we are not the only
618 * function that looks up host names.
620 if (!strchr(name
, '.') && (cp
= res_hostalias(pvt
->res
, name
,
624 for (p
= q
; p
; p
= p
->next
) {
628 case RESTGT_DOALWAYS
:
630 case RESTGT_AFTERFAILURE
:
631 if (querystate
== RESQRY_SUCCESS
)
638 if ((n
= res_nsearch(pvt
->res
, name
, p
->qclass
, p
->qtype
,
639 p
->answer
, p
->anslen
)) < 0) {
640 querystate
= RESQRY_FAIL
;
643 (void)gethostans(this, p
->answer
, n
, name
, p
->qtype
,
644 pai
->ai_family
, /*%< XXX: meaningless */
647 querystate
= RESQRY_SUCCESS
;
652 querystate
= RESQRY_FAIL
;
657 memput(q
, sizeof(*q
));
659 memput(q2
, sizeof(*q2
));
660 return(sentinel
.ai_next
);
664 ho_res_set(struct irs_ho
*this, struct __res_state
*res
,
665 void (*free_res
)(void *)) {
666 struct pvt
*pvt
= (struct pvt
*)this->private;
668 if (pvt
->res
&& pvt
->free_res
) {
669 res_nclose(pvt
->res
);
670 (*pvt
->free_res
)(pvt
->res
);
674 pvt
->free_res
= free_res
;
679 static struct hostent
*
680 gethostans(struct irs_ho
*this,
681 const u_char
*ansbuf
, int anslen
, const char *qname
, int qtype
,
682 int af
, int size
, /*!< meaningless for addrinfo cases */
683 struct addrinfo
**ret_aip
, const struct addrinfo
*pai
)
685 struct pvt
*pvt
= (struct pvt
*)this->private;
686 int type
, class, ancount
, qdcount
, n
, haveanswer
, had_error
;
687 int error
= NETDB_SUCCESS
;
688 int (*name_ok
)(const char *);
695 char *bp
, *ep
, **ap
, **hap
;
696 char tbuf
[MAXDNAME
+1];
697 struct addrinfo sentinel
, *cur
, ai
;
699 if (pai
== NULL
) abort();
702 memset(&sentinel
, 0, sizeof(sentinel
));
706 eom
= ansbuf
+ anslen
;
710 case T_ANY
: /*%< use T_ANY only for T_A/T_AAAA lookup */
720 pvt
->host
.h_addrtype
= af
;
721 pvt
->host
.h_length
= size
;
722 hname
= pvt
->host
.h_name
= NULL
;
725 * Find first satisfactory answer.
727 if (ansbuf
+ HFIXEDSZ
> eom
) {
728 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
731 hp
= (const HEADER
*)ansbuf
;
732 ancount
= ntohs(hp
->ancount
);
733 qdcount
= ntohs(hp
->qdcount
);
735 ep
= pvt
->hostbuf
+ sizeof(pvt
->hostbuf
);
736 cp
= ansbuf
+ HFIXEDSZ
;
738 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
741 n
= dn_expand(ansbuf
, eom
, cp
, bp
, ep
- bp
);
742 if (n
< 0 || !maybe_ok(pvt
->res
, bp
, name_ok
)) {
743 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
748 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
751 if (qtype
== T_A
|| qtype
== T_AAAA
|| qtype
== T_ANY
) {
752 /* res_nsend() has already verified that the query name is the
753 * same as the one we sent; this just gets the expanded name
754 * (i.e., with the succeeding search-domain tacked on).
756 n
= strlen(bp
) + 1; /*%< for the \\0 */
757 if (n
> MAXHOSTNAMELEN
) {
758 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
761 pvt
->host
.h_name
= bp
;
764 /* The qname can be abbreviated, but hname is now absolute. */
765 qname
= pvt
->host
.h_name
;
767 ap
= pvt
->host_aliases
;
769 pvt
->host
.h_aliases
= pvt
->host_aliases
;
770 hap
= pvt
->h_addr_ptrs
;
772 pvt
->host
.h_addr_list
= pvt
->h_addr_ptrs
;
775 while (ancount
-- > 0 && cp
< eom
&& !had_error
) {
776 n
= dn_expand(ansbuf
, eom
, cp
, bp
, ep
- bp
);
777 if (n
< 0 || !maybe_ok(pvt
->res
, bp
, name_ok
)) {
781 cp
+= n
; /*%< name */
782 BOUNDS_CHECK(cp
, 3 * INT16SZ
+ INT32SZ
);
784 cp
+= INT16SZ
; /*%< type */
785 class = ns_get16(cp
);
786 cp
+= INT16SZ
+ INT32SZ
; /*%< class, TTL */
788 cp
+= INT16SZ
; /*%< len */
795 if ((qtype
== T_A
|| qtype
== T_AAAA
|| qtype
== T_ANY
) &&
798 int level
= LOG_CRIT
;
800 level
|= LOG_SECURITY
;
803 "gethostans: possible attempt to exploit buffer overflow while looking up %s",
804 *qname
? qname
: ".");
806 n
= dn_expand(ansbuf
, eor
, cp
, tbuf
, sizeof tbuf
);
807 if (n
< 0 || !maybe_ok(pvt
->res
, tbuf
, name_ok
)) {
813 if (ap
>= &pvt
->host_aliases
[MAXALIASES
-1])
816 n
= strlen(bp
) + 1; /*%< for the \\0 */
818 /* Get canonical name. */
819 n
= strlen(tbuf
) + 1; /*%< for the \\0 */
820 if (n
> (ep
- bp
) || n
> MAXHOSTNAMELEN
) {
824 strcpy(bp
, tbuf
); /* (checked) */
825 pvt
->host
.h_name
= bp
;
830 if (qtype
== T_PTR
&& type
== T_CNAME
) {
831 n
= dn_expand(ansbuf
, eor
, cp
, tbuf
, sizeof tbuf
);
832 if (n
< 0 || !maybe_dnok(pvt
->res
, tbuf
)) {
838 if ((pvt
->res
->options
& RES_USE_DNAME
) != 0U)
842 * We may be able to check this regardless
843 * of the USE_DNAME bit, but we add the check
844 * for now since the DNAME support is
847 if (ns_samename(tname
, bp
) != 1)
850 /* Get canonical name. */
851 n
= strlen(tbuf
) + 1; /*%< for the \\0 */
856 strcpy(bp
, tbuf
); /* (checked) */
861 if (qtype
== T_ANY
) {
862 if (!(type
== T_A
|| type
== T_AAAA
)) {
866 } else if (type
!= qtype
) {
872 if (ret_aip
!= NULL
) {
873 /* addrinfo never needs T_PTR */
877 if (ns_samename(tname
, bp
) != 1) {
881 n
= dn_expand(ansbuf
, eor
, cp
, bp
, ep
- bp
);
882 if (n
< 0 || !maybe_hnok(pvt
->res
, bp
) ||
883 n
>= MAXHOSTNAMELEN
) {
889 pvt
->host
.h_name
= bp
;
892 else if (ap
< &pvt
->host_aliases
[MAXALIASES
-1])
897 n
= strlen(bp
) + 1; /*%< for the \\0 */
903 if (ns_samename(hname
, bp
) != 1) {
907 if (type
== T_A
&& n
!= INADDRSZ
) {
911 if (type
== T_AAAA
&& n
!= IN6ADDRSZ
) {
916 /* make addrinfo. don't overwrite constant PAI */
918 ai
.ai_family
= (type
== T_AAAA
) ? AF_INET6
: AF_INET
;
919 cur
->ai_next
= addr2addrinfo(
920 (const struct addrinfo
*)&ai
,
922 if (cur
->ai_next
== NULL
)
928 nn
= strlen(bp
) + 1; /*%< for the \\0 */
929 if (nn
>= MAXHOSTNAMELEN
) {
934 pvt
->host
.h_name
= bp
;
938 /* Ensure alignment. */
939 bp
= (char *)(((u_long
)bp
+ (sizeof(align
) - 1)) &
940 ~(sizeof(align
) - 1));
941 /* Avoid overflows. */
942 if (bp
+ n
> &pvt
->hostbuf
[sizeof(pvt
->hostbuf
) - 1]) {
946 if (ret_aip
) { /*%< need addrinfo. keep it. */
949 } else if (cur
->ai_next
) { /*%< need hostent */
950 struct addrinfo
*aip
= cur
->ai_next
;
952 for (aip
= cur
->ai_next
; aip
;
953 aip
= aip
->ai_next
) {
956 m
= add_hostent(pvt
, bp
, hap
, aip
);
963 if (hap
< &pvt
->h_addr_ptrs
[MAXADDRS
])
969 freeaddrinfo(cur
->ai_next
);
981 if (ret_aip
== NULL
) {
985 if (pvt
->res
->nsort
&& hap
!= pvt
->h_addr_ptrs
&&
987 addrsort(pvt
->res
, pvt
->h_addr_ptrs
,
988 hap
- pvt
->h_addr_ptrs
);
989 if (pvt
->host
.h_name
== NULL
) {
990 n
= strlen(qname
) + 1; /*%< for the \\0 */
991 if (n
> (ep
- bp
) || n
>= MAXHOSTNAMELEN
)
993 strcpy(bp
, qname
); /* (checked) */
994 pvt
->host
.h_name
= bp
;
997 if (pvt
->res
->options
& RES_USE_INET6
)
998 map_v4v6_hostent(&pvt
->host
, &bp
, ep
);
999 RES_SET_H_ERRNO(pvt
->res
, NETDB_SUCCESS
);
1000 return (&pvt
->host
);
1002 if ((pai
->ai_flags
& AI_CANONNAME
) != 0) {
1003 if (pvt
->host
.h_name
== NULL
) {
1004 sentinel
.ai_next
->ai_canonname
=
1008 sentinel
.ai_next
->ai_canonname
=
1009 strdup(pvt
->host
.h_name
);
1012 *ret_aip
= sentinel
.ai_next
;
1017 if (sentinel
.ai_next
) {
1018 /* this should be impossible, but check it for safety */
1019 freeaddrinfo(sentinel
.ai_next
);
1021 if (error
== NETDB_SUCCESS
)
1022 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
1024 RES_SET_H_ERRNO(pvt
->res
, error
);
1029 add_hostent(struct pvt
*pvt
, char *bp
, char **hap
, struct addrinfo
*ai
)
1036 switch(ai
->ai_addr
->sa_family
) {
1038 addrlen
= IN6ADDRSZ
;
1039 addrp
= (char *)&((struct sockaddr_in6
*)ai
->ai_addr
)->sin6_addr
;
1043 addrp
= (char *)&((struct sockaddr_in
*)ai
->ai_addr
)->sin_addr
;
1046 return(-1); /*%< abort? */
1049 /* Ensure alignment. */
1050 bp
= (char *)(((u_long
)bp
+ (sizeof(align
) - 1)) &
1051 ~(sizeof(align
) - 1));
1052 /* Avoid overflows. */
1053 if (bp
+ addrlen
> &pvt
->hostbuf
[sizeof(pvt
->hostbuf
) - 1])
1055 if (hap
>= &pvt
->h_addr_ptrs
[MAXADDRS
])
1056 return(0); /*%< fail, but not treat it as an error. */
1057 /* Suppress duplicates. */
1058 for (tap
= (const char **)pvt
->h_addr_ptrs
;
1061 if (memcmp(*tap
, addrp
, addrlen
) == 0)
1066 memcpy(*hap
= bp
, addrp
, addrlen
);
1067 return((bp
+ addrlen
) - obp
);
1071 map_v4v6_hostent(struct hostent
*hp
, char **bpp
, char *ep
) {
1074 if (hp
->h_addrtype
!= AF_INET
|| hp
->h_length
!= INADDRSZ
)
1076 hp
->h_addrtype
= AF_INET6
;
1077 hp
->h_length
= IN6ADDRSZ
;
1078 for (ap
= hp
->h_addr_list
; *ap
; ap
++) {
1079 int i
= (u_long
)*bpp
% sizeof(align
);
1082 i
= sizeof(align
) - i
;
1084 if ((ep
- *bpp
) < (i
+ IN6ADDRSZ
)) {
1085 /* Out of memory. Truncate address list here. */
1090 map_v4v6_address(*ap
, *bpp
);
1097 addrsort(res_state statp
, char **ap
, int num
) {
1098 int i
, j
, needsort
= 0, aval
[MAXADDRS
];
1102 for (i
= 0; i
< num
; i
++, p
++) {
1103 for (j
= 0 ; (unsigned)j
< statp
->nsort
; j
++)
1104 if (statp
->sort_list
[j
].addr
.s_addr
==
1105 (((struct in_addr
*)(*p
))->s_addr
&
1106 statp
->sort_list
[j
].mask
))
1109 if (needsort
== 0 && i
> 0 && j
< aval
[i
-1])
1115 while (needsort
< num
) {
1116 for (j
= needsort
- 1; j
>= 0; j
--) {
1117 if (aval
[j
] > aval
[j
+1]) {
1121 aval
[j
] = aval
[j
+1];
1136 init(struct irs_ho
*this) {
1137 struct pvt
*pvt
= (struct pvt
*)this->private;
1139 if (!pvt
->res
&& !ho_res_get(this))
1141 if (((pvt
->res
->options
& RES_INIT
) == 0U) &&
1142 res_ninit(pvt
->res
) == -1)