2 * ++Copyright++ 1985, 1988, 1993
4 * Copyright (c) 1985, 1988, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 4. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
33 * Permission to use, copy, modify, and distribute this software for any
34 * purpose with or without fee is hereby granted, provided that the above
35 * copyright notice and this permission notice appear in all copies, and that
36 * the name of Digital Equipment Corporation not be used in advertising or
37 * publicity pertaining to distribution of the document or software without
38 * specific, written prior permission.
40 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
43 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
51 * @(#)gethostnamadr.c 8.1 (Berkeley) 6/4/93
52 * From: Id: gethnamaddr.c,v 8.23 1998/04/07 04:59:46 vixie Exp $
53 * $FreeBSD: src/lib/libc/net/gethostbydns.c,v 1.58 2007/01/09 00:28:02 imp Exp $
54 * $DragonFly: src/lib/libc/net/gethostbydns.c,v 1.6 2005/11/13 02:04:47 swildner Exp $
57 #include <sys/types.h>
58 #include <sys/param.h>
59 #include <sys/socket.h>
60 #include <netinet/in.h>
61 #include <arpa/inet.h>
62 #include <arpa/nameser.h>
76 #include "netdb_private.h"
77 #include "res_config.h"
79 #define SPRINTF(x) ((size_t)sprintf x)
81 static const char AskedForGot
[] =
82 "gethostby*.gethostanswer: asked for \"%s\", got \"%s\"";
85 static void addrsort(char **, int, res_state
);
89 static void dprintf(char *, int, res_state
) __printflike(1, 0);
92 #define MAXPACKET (64*1024)
96 u_char buf
[MAXPACKET
];
108 dprintf(char *msg
, int num
, res_state res
)
110 if (res
->options
& RES_DEBUG
) {
118 # define dprintf(msg, num, res) /*nada*/
121 #define BOUNDED_INCR(x) \
125 RES_SET_H_ERRNO(statp, NO_RECOVERY); \
130 #define BOUNDS_CHECK(ptr, count) \
132 if ((ptr) + (count) > eom) { \
133 RES_SET_H_ERRNO(statp, NO_RECOVERY); \
139 gethostanswer(const querybuf
*answer
, int anslen
, const char *qname
, int qtype
,
140 struct hostent
*he
, struct hostent_data
*hed
, res_state statp
)
145 const u_char
*eom
, *erdata
;
146 char *bp
, *ep
, **ap
, **hap
;
147 int type
, class, ancount
, qdcount
;
148 int haveanswer
, had_error
;
152 int (*name_ok
)(const char *);
156 eom
= answer
->buf
+ anslen
;
166 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
167 return (-1); /* XXX should be abort(); */
170 * find first satisfactory answer
173 ancount
= ntohs(hp
->ancount
);
174 qdcount
= ntohs(hp
->qdcount
);
176 ep
= hed
->hostbuf
+ sizeof hed
->hostbuf
;
178 BOUNDED_INCR(HFIXEDSZ
);
180 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
183 n
= dn_expand(answer
->buf
, eom
, cp
, bp
, ep
- bp
);
184 if ((n
< 0) || !(*name_ok
)(bp
)) {
185 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
188 BOUNDED_INCR(n
+ QFIXEDSZ
);
189 if (qtype
== T_A
|| qtype
== T_AAAA
) {
190 /* res_send() has already verified that the query name is the
191 * same as the one we sent; this just gets the expanded name
192 * (i.e., with the succeeding search-domain tacked on).
194 n
= strlen(bp
) + 1; /* for the \0 */
195 if (n
>= MAXHOSTNAMELEN
) {
196 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
201 /* The qname can be abbreviated, but h_name is now absolute. */
204 ap
= hed
->host_aliases
;
206 he
->h_aliases
= hed
->host_aliases
;
207 hap
= hed
->h_addr_ptrs
;
209 he
->h_addr_list
= hed
->h_addr_ptrs
;
213 while (ancount
-- > 0 && cp
< eom
&& !had_error
) {
214 n
= dn_expand(answer
->buf
, eom
, cp
, bp
, ep
- bp
);
215 if ((n
< 0) || !(*name_ok
)(bp
)) {
220 BOUNDS_CHECK(cp
, 3 * INT16SZ
+ INT32SZ
);
221 type
= _getshort(cp
);
222 cp
+= INT16SZ
; /* type */
223 class = _getshort(cp
);
224 cp
+= INT16SZ
; /* class */
225 if (qtype
== T_A
&& type
== T_A
)
226 _dns_ttl_
= _getlong(cp
);
227 cp
+= INT32SZ
; /* TTL */
229 cp
+= INT16SZ
; /* len */
233 /* XXX - debug? syslog? */
235 continue; /* XXX - had_error++ ? */
237 if ((qtype
== T_A
|| qtype
== T_AAAA
) && type
== T_CNAME
) {
238 if (ap
>= &hed
->host_aliases
[_MAXALIASES
-1])
240 n
= dn_expand(answer
->buf
, eom
, cp
, tbuf
, sizeof tbuf
);
241 if ((n
< 0) || !(*name_ok
)(tbuf
)) {
247 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
252 n
= strlen(bp
) + 1; /* for the \0 */
253 if (n
>= MAXHOSTNAMELEN
) {
258 /* Get canonical name. */
259 n
= strlen(tbuf
) + 1; /* for the \0 */
260 if (n
> ep
- bp
|| n
>= MAXHOSTNAMELEN
) {
269 if (qtype
== T_PTR
&& type
== T_CNAME
) {
270 n
= dn_expand(answer
->buf
, eom
, cp
, tbuf
, sizeof tbuf
);
271 if (n
< 0 || !res_dnok(tbuf
)) {
277 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
280 /* Get canonical name. */
281 n
= strlen(tbuf
) + 1; /* for the \0 */
282 if (n
> ep
- bp
|| n
>= MAXHOSTNAMELEN
) {
293 syslog(LOG_NOTICE
|LOG_AUTH
,
294 "gethostby*.gethostanswer: asked for \"%s %s %s\", got type \"%s\"",
295 qname
, p_class(C_IN
), p_type(qtype
),
298 continue; /* XXX - had_error++ ? */
302 if (strcasecmp(tname
, bp
) != 0) {
303 syslog(LOG_NOTICE
|LOG_AUTH
,
304 AskedForGot
, qname
, bp
);
306 continue; /* XXX - had_error++ ? */
308 n
= dn_expand(answer
->buf
, eom
, cp
, bp
, ep
- bp
);
309 if ((n
< 0) || !res_hnok(bp
)) {
313 #if MULTI_PTRS_ARE_ALIASES
316 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
321 else if (ap
< &hed
->host_aliases
[_MAXALIASES
-1])
326 n
= strlen(bp
) + 1; /* for the \0 */
327 if (n
>= MAXHOSTNAMELEN
) {
336 if (statp
->options
& RES_USE_INET6
) {
337 n
= strlen(bp
) + 1; /* for the \0 */
338 if (n
>= MAXHOSTNAMELEN
) {
343 _map_v4v6_hostent(he
, &bp
, ep
);
345 RES_SET_H_ERRNO(statp
, NETDB_SUCCESS
);
350 if (strcasecmp(he
->h_name
, bp
) != 0) {
351 syslog(LOG_NOTICE
|LOG_AUTH
,
352 AskedForGot
, he
->h_name
, bp
);
354 continue; /* XXX - had_error++ ? */
356 if (n
!= he
->h_length
) {
364 nn
= strlen(bp
) + 1; /* for the \0 */
368 bp
+= sizeof(align
) - ((u_long
)bp
% sizeof(align
));
371 dprintf("size (%d) too big\n", n
, statp
);
375 if (hap
>= &hed
->h_addr_ptrs
[_MAXADDRS
-1]) {
377 dprintf("Too many addresses (%d)\n",
382 memcpy(*hap
++ = bp
, cp
, n
);
386 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
391 dprintf("Impossible condition (type=%d)\n", type
,
393 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
395 /* BIND has abort() here, too risky on bad data */
403 # if defined(RESOLVSORT)
405 * Note: we sort even if host can take only one address
406 * in its return structures - should give it the "best"
407 * address in that case, not some random one
409 if (statp
->nsort
&& haveanswer
> 1 && qtype
== T_A
)
410 addrsort(hed
->h_addr_ptrs
, haveanswer
, statp
);
411 # endif /*RESOLVSORT*/
413 n
= strlen(qname
) + 1; /* for the \0 */
414 if (n
> ep
- bp
|| n
>= MAXHOSTNAMELEN
)
420 if (statp
->options
& RES_USE_INET6
)
421 _map_v4v6_hostent(he
, &bp
, ep
);
422 RES_SET_H_ERRNO(statp
, NETDB_SUCCESS
);
426 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
430 /* XXX: for async DNS resolver in ypserv */
432 __dns_getanswer(const char *answer
, int anslen
, const char *qname
, int qtype
)
435 struct hostent_data
*hed
;
439 statp
= __res_state();
440 if ((he
= __hostent_init()) == NULL
||
441 (hed
= __hostent_data_init()) == NULL
) {
442 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
447 he
->h_addrtype
= AF_INET6
;
448 he
->h_length
= NS_IN6ADDRSZ
;
452 he
->h_addrtype
= AF_INET
;
453 he
->h_length
= NS_INADDRSZ
;
457 error
= gethostanswer((const querybuf
*)answer
, anslen
, qname
, qtype
,
459 return (error
== 0) ? he
: NULL
;
463 _dns_gethostbyname(void *rval
, void *cb_data
, va_list ap
)
469 int *errnop
, *h_errnop
;
470 struct hostent
*hptr
, he
;
471 struct hostent_data
*hed
;
476 name
= va_arg(ap
, const char *);
477 af
= va_arg(ap
, int);
478 hptr
= va_arg(ap
, struct hostent
*);
479 buffer
= va_arg(ap
, char *);
480 buflen
= va_arg(ap
, size_t);
481 errnop
= va_arg(ap
, int *);
482 h_errnop
= va_arg(ap
, int *);
484 *((struct hostent
**)rval
) = NULL
;
486 statp
= __res_state();
487 if ((hed
= __hostent_data_init()) == NULL
) {
488 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
489 *h_errnop
= statp
->res_h_errno
;
490 return (NS_NOTFOUND
);
496 he
.h_length
= NS_INADDRSZ
;
500 he
.h_length
= NS_IN6ADDRSZ
;
504 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
505 *h_errnop
= statp
->res_h_errno
;
506 errno
= EAFNOSUPPORT
;
510 if ((buf
= malloc(sizeof(*buf
))) == NULL
) {
511 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
512 *h_errnop
= statp
->res_h_errno
;
513 return (NS_NOTFOUND
);
515 n
= res_nsearch(statp
, name
, C_IN
, type
, buf
->buf
, sizeof(buf
->buf
));
518 dprintf("res_nsearch failed (%d)\n", n
, statp
);
519 *h_errnop
= statp
->res_h_errno
;
521 } else if (n
> sizeof(buf
->buf
)) {
523 dprintf("static buffer is too small (%d)\n", n
, statp
);
524 *h_errnop
= statp
->res_h_errno
;
527 error
= gethostanswer(buf
, n
, name
, type
, &he
, hed
, statp
);
530 *h_errnop
= statp
->res_h_errno
;
531 return (NS_NOTFOUND
);
533 if (__copy_hostent(&he
, hptr
, buffer
, buflen
) != 0) {
534 *h_errnop
= statp
->res_h_errno
;
535 return (NS_NOTFOUND
);
537 *((struct hostent
**)rval
) = hptr
;
542 _dns_gethostbyaddr(void *rval
, void *cb_data
, va_list ap
)
549 int *errnop
, *h_errnop
;
551 struct hostent
*hptr
, he
;
552 struct hostent_data
*hed
;
555 char qbuf
[MAXDNAME
+1], *qp
;
562 char hname2
[MAXDNAME
+1], numaddr
[46];
564 #endif /*SUNSECURITY*/
566 addr
= va_arg(ap
, const void *);
567 len
= va_arg(ap
, socklen_t
);
568 af
= va_arg(ap
, int);
569 hptr
= va_arg(ap
, struct hostent
*);
570 buffer
= va_arg(ap
, char *);
571 buflen
= va_arg(ap
, size_t);
572 errnop
= va_arg(ap
, int *);
573 h_errnop
= va_arg(ap
, int *);
574 uaddr
= (const u_char
*)addr
;
576 *((struct hostent
**)rval
) = NULL
;
578 statp
= __res_state();
579 if ((hed
= __hostent_data_init()) == NULL
) {
580 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
581 *h_errnop
= statp
->res_h_errno
;
582 return (NS_NOTFOUND
);
587 sprintf(qbuf
, "%u.%u.%u.%u.in-addr.arpa",
595 for (n
= NS_IN6ADDRSZ
- 1; n
>= 0; n
--) {
596 qp
+= SPRINTF((qp
, "%x.%x.",
598 (uaddr
[n
] >> 4) & 0xf));
600 strlcat(qbuf
, "ip6.arpa", sizeof(qbuf
));
605 if ((buf
= malloc(sizeof(*buf
))) == NULL
) {
606 RES_SET_H_ERRNO(statp
, NETDB_INTERNAL
);
607 *h_errnop
= statp
->res_h_errno
;
610 n
= res_nquery(statp
, qbuf
, C_IN
, T_PTR
, (u_char
*)buf
->buf
,
614 dprintf("res_nquery failed (%d)\n", n
, statp
);
615 *h_errnop
= statp
->res_h_errno
;
618 if (n
> sizeof buf
->buf
) {
620 dprintf("static buffer is too small (%d)\n", n
, statp
);
621 *h_errnop
= statp
->res_h_errno
;
624 if (gethostanswer(buf
, n
, qbuf
, T_PTR
, &he
, hed
, statp
) != 0) {
626 *h_errnop
= statp
->res_h_errno
;
627 return (NS_NOTFOUND
); /* h_errno was set by gethostanswer() */
633 * turn off search as the name should be absolute,
634 * 'localhost' should be matched by defnames
636 strncpy(hname2
, he
.h_name
, MAXDNAME
);
637 hname2
[MAXDNAME
] = '\0';
638 old_options
= statp
->options
;
639 statp
->options
&= ~RES_DNSRCH
;
640 statp
->options
|= RES_DEFNAMES
;
641 memset(&rhd
, 0, sizeof rhd
);
642 rhe
= gethostbyname_r(hname2
, &rhd
.host
, &rhd
.data
,
643 sizeof(rhd
.data
), &ret_h_error
);
645 if (inet_ntop(af
, addr
, numaddr
, sizeof(numaddr
)) == NULL
)
646 strlcpy(numaddr
, "UNKNOWN", sizeof(numaddr
));
647 syslog(LOG_NOTICE
|LOG_AUTH
,
648 "gethostbyaddr: No A record for %s (verifying [%s])",
650 statp
->options
= old_options
;
651 RES_SET_H_ERRNO(statp
, HOST_NOT_FOUND
);
652 *h_errnop
= statp
->res_h_errno
;
653 return (NS_NOTFOUND
);
655 statp
->options
= old_options
;
656 for (haddr
= rhe
->h_addr_list
; *haddr
; haddr
++)
657 if (!memcmp(*haddr
, addr
, NS_INADDRSZ
))
660 if (inet_ntop(af
, addr
, numaddr
, sizeof(numaddr
)) == NULL
)
661 strlcpy(numaddr
, "UNKNOWN", sizeof(numaddr
));
662 syslog(LOG_NOTICE
|LOG_AUTH
,
663 "gethostbyaddr: A record of %s != PTR record [%s]",
665 RES_SET_H_ERRNO(statp
, HOST_NOT_FOUND
);
666 *h_errnop
= statp
->res_h_errno
;
667 return (NS_NOTFOUND
);
670 #endif /*SUNSECURITY*/
673 memcpy(hed
->host_addr
, uaddr
, len
);
674 hed
->h_addr_ptrs
[0] = (char *)hed
->host_addr
;
675 hed
->h_addr_ptrs
[1] = NULL
;
676 if (af
== AF_INET
&& (statp
->options
& RES_USE_INET6
)) {
677 _map_v4v6_address((char*)hed
->host_addr
, (char*)hed
->host_addr
);
678 he
.h_addrtype
= AF_INET6
;
679 he
.h_length
= NS_IN6ADDRSZ
;
681 RES_SET_H_ERRNO(statp
, NETDB_SUCCESS
);
682 if (__copy_hostent(&he
, hptr
, buffer
, buflen
) != 0) {
683 *h_errnop
= statp
->res_h_errno
;
684 return (NS_NOTFOUND
);
686 *((struct hostent
**)rval
) = hptr
;
692 addrsort(char **ap
, int num
, res_state res
)
696 short aval
[_MAXADDRS
];
700 for (i
= 0; i
< num
; i
++, p
++) {
701 for (j
= 0 ; (unsigned)j
< res
->nsort
; j
++)
702 if (res
->sort_list
[j
].addr
.s_addr
==
703 (((struct in_addr
*)(*p
))->s_addr
& res
->sort_list
[j
].mask
))
706 if (needsort
== 0 && i
> 0 && j
< aval
[i
-1])
712 while (needsort
< num
) {
713 for (j
= needsort
- 1; j
>= 0; j
--) {
714 if (aval
[j
] > aval
[j
+1]) {
734 _sethostdnsent(int stayopen
)
738 statp
= __res_state();
739 if ((statp
->options
& RES_INIT
) == 0 && res_ninit(statp
) == -1)
742 statp
->options
|= RES_STAYOPEN
| RES_USEVC
;
750 statp
= __res_state();
751 statp
->options
&= ~(RES_STAYOPEN
| RES_USEVC
);