2 * Portions Copyright (C) 2004-2006, 2008 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1996-2003 Internet Software Consortium.
5 * Permission to use, copy, modify, and/or distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
19 * Copyright (c) 1985, 1988, 1993
20 * The Regents of the University of California. All rights reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
25 * 1. Redistributions of source code must retain the above copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 * must display the following acknowledgement:
32 * This product includes software developed by the University of
33 * California, Berkeley and its contributors.
34 * 4. Neither the name of the University nor the names of its contributors
35 * may be used to endorse or promote products derived from this software
36 * without specific prior written permission.
38 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
39 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
40 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
41 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
42 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
43 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
44 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
46 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
47 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51 /* from gethostnamadr.c 8.1 (Berkeley) 6/4/93 */
52 /* BIND Id: gethnamaddr.c,v 8.15 1996/05/22 04:56:30 vixie Exp $ */
56 #include "port_before.h"
58 #include <sys/types.h>
59 #include <sys/param.h>
60 #include <sys/socket.h>
62 #include <netinet/in.h>
63 #include <arpa/inet.h>
64 #include <arpa/nameser.h>
75 #include <isc/memcluster.h>
78 #include "port_after.h"
84 # define SPRINTF(x) strlen(sprintf/**/x)
86 # define SPRINTF(x) sprintf x
94 #define MAXPACKET (65535) /*%< Maximum TCP message size */
95 #define BOUNDS_CHECK(ptr, count) \
96 if ((ptr) + (count) > eom) { \
103 u_char buf
[MAXPACKET
];
106 struct dns_res_target
{
107 struct dns_res_target
*next
;
108 querybuf qbuf
; /*%< query buffer */
109 u_char
*answer
; /*%< buffer to put answer */
110 int anslen
; /*%< size of answer buffer */
111 int qclass
, qtype
; /*%< class and type of query */
112 int action
; /*%< condition whether query is really issued */
113 char qname
[MAXDNAME
+1]; /*%< domain name */
115 int n
; /*%< result length */
118 enum {RESTGT_DOALWAYS
, RESTGT_AFTERFAILURE
, RESTGT_IGNORE
};
119 enum {RESQRY_SUCCESS
, RESQRY_FAIL
};
123 char * h_addr_ptrs
[MAXADDRS
+ 1];
124 char * host_aliases
[MAXALIASES
];
125 char hostbuf
[8*1024];
126 u_char host_addr
[16]; /*%< IPv4 or IPv6 */
127 struct __res_state
*res
;
128 void (*free_res
)(void *);
136 static const u_char mapped
[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0xff,0xff };
137 static const u_char tunnelled
[] = { 0,0, 0,0, 0,0, 0,0, 0,0, 0,0 };
138 /* Note: the IPv6 loopback address is in the "tunnel" space */
139 static const u_char v6local
[] = { 0,0, 0,1 }; /*%< last 4 bytes of IPv6 addr */
142 static void ho_close(struct irs_ho
*this);
143 static struct hostent
* ho_byname(struct irs_ho
*this, const char *name
);
144 static struct hostent
* ho_byname2(struct irs_ho
*this, const char *name
,
146 static struct hostent
* ho_byaddr(struct irs_ho
*this, const void *addr
,
148 static struct hostent
* ho_next(struct irs_ho
*this);
149 static void ho_rewind(struct irs_ho
*this);
150 static void ho_minimize(struct irs_ho
*this);
151 static struct __res_state
* ho_res_get(struct irs_ho
*this);
152 static void ho_res_set(struct irs_ho
*this,
153 struct __res_state
*res
,
154 void (*free_res
)(void *));
155 static struct addrinfo
* ho_addrinfo(struct irs_ho
*this, const char *name
,
156 const struct addrinfo
*pai
);
158 static void map_v4v6_hostent(struct hostent
*hp
, char **bp
,
160 static void addrsort(res_state
, char **, int);
161 static struct hostent
* gethostans(struct irs_ho
*this,
162 const u_char
*ansbuf
, int anslen
,
163 const char *qname
, int qtype
,
165 struct addrinfo
**ret_aip
,
166 const struct addrinfo
*pai
);
167 static int add_hostent(struct pvt
*pvt
, char *bp
, char **hap
,
168 struct addrinfo
*ai
);
169 static int init(struct irs_ho
*this);
174 irs_dns_ho(struct irs_acc
*this) {
180 if (!(pvt
= memget(sizeof *pvt
))) {
184 memset(pvt
, 0, sizeof *pvt
);
186 if (!(ho
= memget(sizeof *ho
))) {
187 memput(pvt
, sizeof *pvt
);
191 memset(ho
, 0x5e, sizeof *ho
);
193 ho
->close
= ho_close
;
194 ho
->byname
= ho_byname
;
195 ho
->byname2
= ho_byname2
;
196 ho
->byaddr
= ho_byaddr
;
198 ho
->rewind
= ho_rewind
;
199 ho
->minimize
= ho_minimize
;
200 ho
->res_get
= ho_res_get
;
201 ho
->res_set
= ho_res_set
;
202 ho
->addrinfo
= ho_addrinfo
;
209 ho_close(struct irs_ho
*this) {
210 struct pvt
*pvt
= (struct pvt
*)this->private;
213 if (pvt
->res
&& pvt
->free_res
)
214 (*pvt
->free_res
)(pvt
->res
);
215 memput(pvt
, sizeof *pvt
);
216 memput(this, sizeof *this);
219 static struct hostent
*
220 ho_byname(struct irs_ho
*this, const char *name
) {
221 struct pvt
*pvt
= (struct pvt
*)this->private;
224 if (init(this) == -1)
227 if (pvt
->res
->options
& RES_USE_INET6
) {
228 hp
= ho_byname2(this, name
, AF_INET6
);
232 return (ho_byname2(this, name
, AF_INET
));
235 static struct hostent
*
236 ho_byname2(struct irs_ho
*this, const char *name
, int af
)
238 struct pvt
*pvt
= (struct pvt
*)this->private;
239 struct hostent
*hp
= NULL
;
241 char tmp
[NS_MAXDNAME
];
244 struct dns_res_target
*q
, *p
;
245 int querystate
= RESQRY_FAIL
;
247 if (init(this) == -1)
250 q
= memget(sizeof(*q
));
252 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
256 memset(q
, 0, sizeof(*q
));
263 q
->answer
= q
->qbuf
.buf
;
264 q
->anslen
= sizeof(q
->qbuf
);
265 q
->action
= RESTGT_DOALWAYS
;
271 q
->answer
= q
->qbuf
.buf
;
272 q
->anslen
= sizeof(q
->qbuf
);
273 q
->action
= RESTGT_DOALWAYS
;
276 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
277 errno
= EAFNOSUPPORT
;
283 * if there aren't any dots, it could be a user-level alias.
284 * this is also done in res_nquery() since we are not the only
285 * function that looks up host names.
287 if (!strchr(name
, '.') && (cp
= res_hostalias(pvt
->res
, name
,
291 for (p
= q
; p
; p
= p
->next
) {
293 case RESTGT_DOALWAYS
:
295 case RESTGT_AFTERFAILURE
:
296 if (querystate
== RESQRY_SUCCESS
)
303 if ((n
= res_nsearch(pvt
->res
, name
, p
->qclass
, p
->qtype
,
304 p
->answer
, p
->anslen
)) < 0) {
305 querystate
= RESQRY_FAIL
;
309 memset(&ai
, 0, sizeof(ai
));
311 if ((hp
= gethostans(this, p
->answer
, n
, name
, p
->qtype
,
313 (const struct addrinfo
*)&ai
)) != NULL
)
314 goto cleanup
; /*%< no more loop is necessary */
315 querystate
= RESQRY_FAIL
;
321 memput(q
, sizeof(*q
));
325 static struct hostent
*
326 ho_byaddr(struct irs_ho
*this, const void *addr
, int len
, int af
)
328 struct pvt
*pvt
= (struct pvt
*)this->private;
329 const u_char
*uaddr
= addr
;
331 struct hostent
*hp
= NULL
;
333 struct dns_res_target
*q
, *q2
, *p
;
335 int querystate
= RESQRY_FAIL
;
337 if (init(this) == -1)
340 q
= memget(sizeof(*q
));
341 q2
= memget(sizeof(*q2
));
342 if (q
== NULL
|| q2
== NULL
) {
343 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
347 memset(q
, 0, sizeof(*q
));
348 memset(q2
, 0, sizeof(*q2
));
350 if (af
== AF_INET6
&& len
== IN6ADDRSZ
&&
351 (!memcmp(uaddr
, mapped
, sizeof mapped
) ||
352 (!memcmp(uaddr
, tunnelled
, sizeof tunnelled
) &&
353 memcmp(&uaddr
[sizeof tunnelled
], v6local
, sizeof(v6local
))))) {
355 addr
= (const char *)addr
+ sizeof mapped
;
356 uaddr
+= sizeof mapped
;
365 q
->answer
= q
->qbuf
.buf
;
366 q
->anslen
= sizeof(q
->qbuf
);
367 q
->action
= RESTGT_DOALWAYS
;
373 q
->answer
= q
->qbuf
.buf
;
374 q
->anslen
= sizeof(q
->qbuf
);
376 q
->action
= RESTGT_DOALWAYS
;
379 q2
->answer
= q2
->qbuf
.buf
;
380 q2
->anslen
= sizeof(q2
->qbuf
);
381 if ((pvt
->res
->options
& RES_NO_NIBBLE2
) != 0U)
382 q2
->action
= RESTGT_IGNORE
;
384 q2
->action
= RESTGT_AFTERFAILURE
;
387 errno
= EAFNOSUPPORT
;
388 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
394 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
401 (void) sprintf(qp
, "%u.%u.%u.%u.in-addr.arpa",
408 if (q
->action
!= RESTGT_IGNORE
) {
409 const char *nibsuff
= res_get_nibblesuffix(pvt
->res
);
411 for (n
= IN6ADDRSZ
- 1; n
>= 0; n
--) {
412 i
= SPRINTF((qp
, "%x.%x.",
414 (uaddr
[n
] >> 4) & 0xf));
419 if (strlen(q
->qname
) + strlen(nibsuff
) + 1 >
421 errno
= ENAMETOOLONG
;
422 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
426 strcpy(qp
, nibsuff
); /* (checked) */
428 if (q2
->action
!= RESTGT_IGNORE
) {
429 const char *nibsuff2
= res_get_nibblesuffix2(pvt
->res
);
431 for (n
= IN6ADDRSZ
- 1; n
>= 0; n
--) {
432 i
= SPRINTF((qp
, "%x.%x.",
434 (uaddr
[n
] >> 4) & 0xf));
439 if (strlen(q2
->qname
) + strlen(nibsuff2
) + 1 >
441 errno
= ENAMETOOLONG
;
442 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
446 strcpy(qp
, nibsuff2
); /* (checked) */
453 for (p
= q
; p
; p
= p
->next
) {
455 case RESTGT_DOALWAYS
:
457 case RESTGT_AFTERFAILURE
:
458 if (querystate
== RESQRY_SUCCESS
)
465 if ((n
= res_nquery(pvt
->res
, p
->qname
, p
->qclass
, p
->qtype
,
466 p
->answer
, p
->anslen
)) < 0) {
467 querystate
= RESQRY_FAIL
;
471 memset(&ai
, 0, sizeof(ai
));
473 hp
= gethostans(this, p
->answer
, n
, p
->qname
, T_PTR
, af
, size
,
474 NULL
, (const struct addrinfo
*)&ai
);
476 querystate
= RESQRY_FAIL
;
480 memcpy(pvt
->host_addr
, addr
, len
);
481 pvt
->h_addr_ptrs
[0] = (char *)pvt
->host_addr
;
482 pvt
->h_addr_ptrs
[1] = NULL
;
483 if (af
== AF_INET
&& (pvt
->res
->options
& RES_USE_INET6
)) {
484 map_v4v6_address((char*)pvt
->host_addr
,
485 (char*)pvt
->host_addr
);
486 pvt
->host
.h_addrtype
= AF_INET6
;
487 pvt
->host
.h_length
= IN6ADDRSZ
;
490 RES_SET_H_ERRNO(pvt
->res
, NETDB_SUCCESS
);
491 goto cleanup
; /*%< no more loop is necessary. */
493 hp
= NULL
; /*%< H_ERRNO was set by subroutines */
496 memput(q
, sizeof(*q
));
498 memput(q2
, sizeof(*q2
));
502 static struct hostent
*
503 ho_next(struct irs_ho
*this) {
511 ho_rewind(struct irs_ho
*this) {
519 ho_minimize(struct irs_ho
*this) {
520 struct pvt
*pvt
= (struct pvt
*)this->private;
523 res_nclose(pvt
->res
);
526 static struct __res_state
*
527 ho_res_get(struct irs_ho
*this) {
528 struct pvt
*pvt
= (struct pvt
*)this->private;
531 struct __res_state
*res
;
532 res
= (struct __res_state
*)malloc(sizeof *res
);
537 memset(res
, 0, sizeof *res
);
538 ho_res_set(this, res
, free
);
545 extern struct addrinfo
*addr2addrinfo
__P((const struct addrinfo
*,
548 static struct addrinfo
*
549 ho_addrinfo(struct irs_ho
*this, const char *name
, const struct addrinfo
*pai
)
551 struct pvt
*pvt
= (struct pvt
*)this->private;
553 char tmp
[NS_MAXDNAME
];
555 struct dns_res_target
*q
, *q2
, *p
;
556 struct addrinfo sentinel
, *cur
;
557 int querystate
= RESQRY_FAIL
;
559 if (init(this) == -1)
562 memset(&sentinel
, 0, sizeof(sentinel
));
565 q
= memget(sizeof(*q
));
566 q2
= memget(sizeof(*q2
));
567 if (q
== NULL
|| q2
== NULL
) {
568 RES_SET_H_ERRNO(pvt
->res
, NETDB_INTERNAL
);
572 memset(q
, 0, sizeof(*q2
));
573 memset(q2
, 0, sizeof(*q2
));
575 switch (pai
->ai_family
) {
580 q
->answer
= q
->qbuf
.buf
;
581 q
->anslen
= sizeof(q
->qbuf
);
583 q
->action
= RESTGT_DOALWAYS
;
586 q2
->answer
= q2
->qbuf
.buf
;
587 q2
->anslen
= sizeof(q2
->qbuf
);
588 q2
->action
= RESTGT_DOALWAYS
;
593 q
->answer
= q
->qbuf
.buf
;
594 q
->anslen
= sizeof(q
->qbuf
);
595 q
->action
= RESTGT_DOALWAYS
;
600 q
->answer
= q
->qbuf
.buf
;
601 q
->anslen
= sizeof(q
->qbuf
);
602 q
->action
= RESTGT_DOALWAYS
;
605 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
); /*%< better error? */
610 * if there aren't any dots, it could be a user-level alias.
611 * this is also done in res_nquery() since we are not the only
612 * function that looks up host names.
614 if (!strchr(name
, '.') && (cp
= res_hostalias(pvt
->res
, name
,
618 for (p
= q
; p
; p
= p
->next
) {
622 case RESTGT_DOALWAYS
:
624 case RESTGT_AFTERFAILURE
:
625 if (querystate
== RESQRY_SUCCESS
)
632 if ((n
= res_nsearch(pvt
->res
, name
, p
->qclass
, p
->qtype
,
633 p
->answer
, p
->anslen
)) < 0) {
634 querystate
= RESQRY_FAIL
;
637 (void)gethostans(this, p
->answer
, n
, name
, p
->qtype
,
638 pai
->ai_family
, /*%< XXX: meaningless */
641 querystate
= RESQRY_SUCCESS
;
646 querystate
= RESQRY_FAIL
;
651 memput(q
, sizeof(*q
));
653 memput(q2
, sizeof(*q2
));
654 return(sentinel
.ai_next
);
658 ho_res_set(struct irs_ho
*this, struct __res_state
*res
,
659 void (*free_res
)(void *)) {
660 struct pvt
*pvt
= (struct pvt
*)this->private;
662 if (pvt
->res
&& pvt
->free_res
) {
663 res_nclose(pvt
->res
);
664 (*pvt
->free_res
)(pvt
->res
);
668 pvt
->free_res
= free_res
;
673 static struct hostent
*
674 gethostans(struct irs_ho
*this,
675 const u_char
*ansbuf
, int anslen
, const char *qname
, int qtype
,
676 int af
, int size
, /*!< meaningless for addrinfo cases */
677 struct addrinfo
**ret_aip
, const struct addrinfo
*pai
)
679 struct pvt
*pvt
= (struct pvt
*)this->private;
680 int type
, class, ancount
, qdcount
, n
, haveanswer
, had_error
;
681 int error
= NETDB_SUCCESS
;
682 int (*name_ok
)(const char *);
689 char *bp
, *ep
, **ap
, **hap
;
690 char tbuf
[MAXDNAME
+1];
691 struct addrinfo sentinel
, *cur
, ai
;
693 if (pai
== NULL
) abort();
696 memset(&sentinel
, 0, sizeof(sentinel
));
700 eom
= ansbuf
+ anslen
;
704 case T_ANY
: /*%< use T_ANY only for T_A/T_AAAA lookup */
714 pvt
->host
.h_addrtype
= af
;
715 pvt
->host
.h_length
= size
;
716 hname
= pvt
->host
.h_name
= NULL
;
719 * Find first satisfactory answer.
721 if (ansbuf
+ HFIXEDSZ
> eom
) {
722 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
725 hp
= (const HEADER
*)ansbuf
;
726 ancount
= ntohs(hp
->ancount
);
727 qdcount
= ntohs(hp
->qdcount
);
729 ep
= pvt
->hostbuf
+ sizeof(pvt
->hostbuf
);
730 cp
= ansbuf
+ HFIXEDSZ
;
732 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
735 n
= dn_expand(ansbuf
, eom
, cp
, bp
, ep
- bp
);
736 if (n
< 0 || !maybe_ok(pvt
->res
, bp
, name_ok
)) {
737 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
742 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
745 if (qtype
== T_A
|| qtype
== T_AAAA
|| qtype
== T_ANY
) {
746 /* res_nsend() has already verified that the query name is the
747 * same as the one we sent; this just gets the expanded name
748 * (i.e., with the succeeding search-domain tacked on).
750 n
= strlen(bp
) + 1; /*%< for the \\0 */
751 if (n
> MAXHOSTNAMELEN
) {
752 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
755 pvt
->host
.h_name
= bp
;
758 /* The qname can be abbreviated, but hname is now absolute. */
759 qname
= pvt
->host
.h_name
;
761 ap
= pvt
->host_aliases
;
763 pvt
->host
.h_aliases
= pvt
->host_aliases
;
764 hap
= pvt
->h_addr_ptrs
;
766 pvt
->host
.h_addr_list
= pvt
->h_addr_ptrs
;
769 while (ancount
-- > 0 && cp
< eom
&& !had_error
) {
770 n
= dn_expand(ansbuf
, eom
, cp
, bp
, ep
- bp
);
771 if (n
< 0 || !maybe_ok(pvt
->res
, bp
, name_ok
)) {
775 cp
+= n
; /*%< name */
776 BOUNDS_CHECK(cp
, 3 * INT16SZ
+ INT32SZ
);
778 cp
+= INT16SZ
; /*%< type */
779 class = ns_get16(cp
);
780 cp
+= INT16SZ
+ INT32SZ
; /*%< class, TTL */
782 cp
+= INT16SZ
; /*%< len */
789 if ((qtype
== T_A
|| qtype
== T_AAAA
|| qtype
== T_ANY
) &&
792 int level
= LOG_CRIT
;
794 level
|= LOG_SECURITY
;
797 "gethostans: possible attempt to exploit buffer overflow while looking up %s",
798 *qname
? qname
: ".");
800 n
= dn_expand(ansbuf
, eor
, cp
, tbuf
, sizeof tbuf
);
801 if (n
< 0 || !maybe_ok(pvt
->res
, tbuf
, name_ok
)) {
807 if (ap
>= &pvt
->host_aliases
[MAXALIASES
-1])
810 n
= strlen(bp
) + 1; /*%< for the \\0 */
812 /* Get canonical name. */
813 n
= strlen(tbuf
) + 1; /*%< for the \\0 */
814 if (n
> (ep
- bp
) || n
> MAXHOSTNAMELEN
) {
818 strcpy(bp
, tbuf
); /* (checked) */
819 pvt
->host
.h_name
= bp
;
824 if (qtype
== T_PTR
&& type
== T_CNAME
) {
825 n
= dn_expand(ansbuf
, eor
, cp
, tbuf
, sizeof tbuf
);
826 if (n
< 0 || !maybe_dnok(pvt
->res
, tbuf
)) {
832 if ((pvt
->res
->options
& RES_USE_DNAME
) != 0U)
836 * We may be able to check this regardless
837 * of the USE_DNAME bit, but we add the check
838 * for now since the DNAME support is
841 if (ns_samename(tname
, bp
) != 1)
844 /* Get canonical name. */
845 n
= strlen(tbuf
) + 1; /*%< for the \\0 */
850 strcpy(bp
, tbuf
); /* (checked) */
855 if (qtype
== T_ANY
) {
856 if (!(type
== T_A
|| type
== T_AAAA
)) {
860 } else if (type
!= qtype
) {
866 if (ret_aip
!= NULL
) {
867 /* addrinfo never needs T_PTR */
871 if (ns_samename(tname
, bp
) != 1) {
875 n
= dn_expand(ansbuf
, eor
, cp
, bp
, ep
- bp
);
876 if (n
< 0 || !maybe_hnok(pvt
->res
, bp
) ||
877 n
>= MAXHOSTNAMELEN
) {
883 pvt
->host
.h_name
= bp
;
886 else if (ap
< &pvt
->host_aliases
[MAXALIASES
-1])
891 n
= strlen(bp
) + 1; /*%< for the \\0 */
897 if (ns_samename(hname
, bp
) != 1) {
901 if (type
== T_A
&& n
!= INADDRSZ
) {
905 if (type
== T_AAAA
&& n
!= IN6ADDRSZ
) {
910 /* make addrinfo. don't overwrite constant PAI */
912 ai
.ai_family
= (type
== T_AAAA
) ? AF_INET6
: AF_INET
;
913 cur
->ai_next
= addr2addrinfo(
914 (const struct addrinfo
*)&ai
,
916 if (cur
->ai_next
== NULL
)
922 nn
= strlen(bp
) + 1; /*%< for the \\0 */
923 if (nn
>= MAXHOSTNAMELEN
) {
928 pvt
->host
.h_name
= bp
;
932 /* Ensure alignment. */
933 bp
= (char *)(((u_long
)bp
+ (sizeof(align
) - 1)) &
934 ~(sizeof(align
) - 1));
935 /* Avoid overflows. */
936 if (bp
+ n
> &pvt
->hostbuf
[sizeof(pvt
->hostbuf
) - 1]) {
940 if (ret_aip
) { /*%< need addrinfo. keep it. */
943 } else if (cur
->ai_next
) { /*%< need hostent */
944 struct addrinfo
*aip
= cur
->ai_next
;
946 for (aip
= cur
->ai_next
; aip
;
947 aip
= aip
->ai_next
) {
950 m
= add_hostent(pvt
, bp
, hap
, aip
);
957 if (hap
< &pvt
->h_addr_ptrs
[MAXADDRS
])
963 freeaddrinfo(cur
->ai_next
);
975 if (ret_aip
== NULL
) {
979 if (pvt
->res
->nsort
&& hap
!= pvt
->h_addr_ptrs
&&
981 addrsort(pvt
->res
, pvt
->h_addr_ptrs
,
982 hap
- pvt
->h_addr_ptrs
);
983 if (pvt
->host
.h_name
== NULL
) {
984 n
= strlen(qname
) + 1; /*%< for the \\0 */
985 if (n
> (ep
- bp
) || n
>= MAXHOSTNAMELEN
)
987 strcpy(bp
, qname
); /* (checked) */
988 pvt
->host
.h_name
= bp
;
991 if (pvt
->res
->options
& RES_USE_INET6
)
992 map_v4v6_hostent(&pvt
->host
, &bp
, ep
);
993 RES_SET_H_ERRNO(pvt
->res
, NETDB_SUCCESS
);
996 if ((pai
->ai_flags
& AI_CANONNAME
) != 0) {
997 if (pvt
->host
.h_name
== NULL
) {
998 sentinel
.ai_next
->ai_canonname
=
1002 sentinel
.ai_next
->ai_canonname
=
1003 strdup(pvt
->host
.h_name
);
1006 *ret_aip
= sentinel
.ai_next
;
1011 if (sentinel
.ai_next
) {
1012 /* this should be impossible, but check it for safety */
1013 freeaddrinfo(sentinel
.ai_next
);
1015 if (error
== NETDB_SUCCESS
)
1016 RES_SET_H_ERRNO(pvt
->res
, NO_RECOVERY
);
1018 RES_SET_H_ERRNO(pvt
->res
, error
);
1023 add_hostent(struct pvt
*pvt
, char *bp
, char **hap
, struct addrinfo
*ai
)
1030 switch(ai
->ai_addr
->sa_family
) {
1032 addrlen
= IN6ADDRSZ
;
1033 addrp
= (char *)&((struct sockaddr_in6
*)ai
->ai_addr
)->sin6_addr
;
1037 addrp
= (char *)&((struct sockaddr_in
*)ai
->ai_addr
)->sin_addr
;
1040 return(-1); /*%< abort? */
1043 /* Ensure alignment. */
1044 bp
= (char *)(((u_long
)bp
+ (sizeof(align
) - 1)) &
1045 ~(sizeof(align
) - 1));
1046 /* Avoid overflows. */
1047 if (bp
+ addrlen
> &pvt
->hostbuf
[sizeof(pvt
->hostbuf
) - 1])
1049 if (hap
>= &pvt
->h_addr_ptrs
[MAXADDRS
])
1050 return(0); /*%< fail, but not treat it as an error. */
1051 /* Suppress duplicates. */
1052 for (tap
= (const char **)pvt
->h_addr_ptrs
;
1055 if (memcmp(*tap
, addrp
, addrlen
) == 0)
1060 memcpy(*hap
= bp
, addrp
, addrlen
);
1061 return((bp
+ addrlen
) - obp
);
1065 map_v4v6_hostent(struct hostent
*hp
, char **bpp
, char *ep
) {
1068 if (hp
->h_addrtype
!= AF_INET
|| hp
->h_length
!= INADDRSZ
)
1070 hp
->h_addrtype
= AF_INET6
;
1071 hp
->h_length
= IN6ADDRSZ
;
1072 for (ap
= hp
->h_addr_list
; *ap
; ap
++) {
1073 int i
= (u_long
)*bpp
% sizeof(align
);
1076 i
= sizeof(align
) - i
;
1078 if ((ep
- *bpp
) < (i
+ IN6ADDRSZ
)) {
1079 /* Out of memory. Truncate address list here. */
1084 map_v4v6_address(*ap
, *bpp
);
1091 addrsort(res_state statp
, char **ap
, int num
) {
1092 int i
, j
, needsort
= 0, aval
[MAXADDRS
];
1096 for (i
= 0; i
< num
; i
++, p
++) {
1097 for (j
= 0 ; (unsigned)j
< statp
->nsort
; j
++)
1098 if (statp
->sort_list
[j
].addr
.s_addr
==
1099 (((struct in_addr
*)(*p
))->s_addr
&
1100 statp
->sort_list
[j
].mask
))
1103 if (needsort
== 0 && i
> 0 && j
< aval
[i
-1])
1109 while (needsort
< num
) {
1110 for (j
= needsort
- 1; j
>= 0; j
--) {
1111 if (aval
[j
] > aval
[j
+1]) {
1115 aval
[j
] = aval
[j
+1];
1130 init(struct irs_ho
*this) {
1131 struct pvt
*pvt
= (struct pvt
*)this->private;
1133 if (!pvt
->res
&& !ho_res_get(this))
1135 if (((pvt
->res
->options
& RES_INIT
) == 0U) &&
1136 res_ninit(pvt
->res
) == -1)