2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * 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 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
53 * Permission to use, copy, modify, and distribute this software for any
54 * purpose with or without fee is hereby granted, provided that the above
55 * copyright notice and this permission notice appear in all copies.
57 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
58 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
60 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
61 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
62 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
63 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
67 #if defined(LIBC_SCCS) && !defined(lint)
68 static const char sccsid
[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93";
69 static const char rcsid
[] = "$BINDId: res_query.c,v 8.20 2000/02/29 05:39:12 vixie Exp $";
70 #endif /* LIBC_SCCS and not lint */
73 #include <sys/types.h>
74 #include <sys/param.h>
75 #include <netinet/in.h>
76 #include <arpa/inet.h>
77 #include <arpa/nameser.h>
86 /* Options. Leave them on. */
90 #define MAXPACKET PACKETSZ
92 #define MAXPACKET 65536
95 #define QUERYSIZE (HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1)
98 __libc_res_nquerydomain(res_state statp
, const char *name
, const char *domain
,
99 int class, int type
, u_char
*answer
, int anslen
,
100 u_char
**answerp
, u_char
**answerp2
, int *nanswerp2
,
101 int *resplen2
, int *answerp2_malloced
);
104 * Formulate a normal query, send, and await answer.
105 * Returned answer is placed in supplied buffer "answer".
106 * Perform preliminary check of answer, returning success only
107 * if no error is indicated and the answer count is nonzero.
108 * Return the size of the response on success, -1 on error.
109 * Error number is left in H_ERRNO.
111 * Caller must parse answer and determine whether it answers the question.
114 __libc_res_nquery(res_state statp
,
115 const char *name
, /* domain name */
116 int class, int type
, /* class and type of query */
117 u_char
*answer
, /* buffer to put answer */
118 int anslen
, /* size of answer buffer */
119 u_char
**answerp
, /* if buffer needs to be enlarged */
123 int *answerp2_malloced
)
125 HEADER
*hp
= (HEADER
*) answer
;
127 int n
, use_malloc
= 0;
128 u_int oflags
= statp
->_flags
;
130 size_t bufsize
= (type
== T_UNSPEC
? 2 : 1) * QUERYSIZE
;
131 u_char
*buf
= alloca (bufsize
);
132 u_char
*query1
= buf
;
134 u_char
*query2
= NULL
;
138 hp
->rcode
= NOERROR
; /* default */
141 if (statp
->options
& RES_DEBUG
)
142 printf(";; res_query(%s, %d, %d)\n", name
, class, type
);
145 if (type
== T_UNSPEC
)
147 n
= res_nmkquery(statp
, QUERY
, name
, class, T_A
, NULL
, 0, NULL
,
151 if ((oflags
& RES_F_EDNS0ERR
) == 0
152 && (statp
->options
& (RES_USE_EDNS0
|RES_USE_DNSSEC
)) != 0)
154 n
= __res_nopt(statp
, n
, query1
, bufsize
, anslen
/ 2);
160 /* Align the buffer. */
161 int npad
= ((nquery1
+ __alignof__ (HEADER
) - 1)
162 & ~(__alignof__ (HEADER
) - 1)) - nquery1
;
163 if (n
> bufsize
- npad
)
168 int nused
= n
+ npad
;
169 query2
= buf
+ nused
;
170 n
= res_nmkquery(statp
, QUERY
, name
, class, T_AAAA
, NULL
, 0,
171 NULL
, query2
, bufsize
- nused
);
173 && (oflags
& RES_F_EDNS0ERR
) == 0
174 && (statp
->options
& (RES_USE_EDNS0
|RES_USE_DNSSEC
)) != 0)
175 n
= __res_nopt(statp
, n
, query2
, bufsize
- nused
- n
,
184 n
= res_nmkquery(statp
, QUERY
, name
, class, type
, NULL
, 0, NULL
,
188 && (oflags
& RES_F_EDNS0ERR
) == 0
189 && (statp
->options
& (RES_USE_EDNS0
|RES_USE_DNSSEC
)) != 0)
190 n
= __res_nopt(statp
, n
, query1
, bufsize
, anslen
);
195 if (__builtin_expect (n
<= 0, 0) && !use_malloc
) {
196 /* Retry just in case res_nmkquery failed because of too
197 short buffer. Shouldn't happen. */
198 bufsize
= (type
== T_UNSPEC
? 2 : 1) * MAXPACKET
;
199 buf
= malloc (bufsize
);
206 if (__glibc_unlikely (n
<= 0)) {
207 /* If the query choked with EDNS0, retry without EDNS0. */
208 if ((statp
->options
& (RES_USE_EDNS0
|RES_USE_DNSSEC
)) != 0
209 && ((oflags
^ statp
->_flags
) & RES_F_EDNS0ERR
) != 0) {
210 statp
->_flags
|= RES_F_EDNS0ERR
;
212 if (statp
->options
& RES_DEBUG
)
213 printf(";; res_nquery: retry without EDNS0\n");
218 if (statp
->options
& RES_DEBUG
)
219 printf(";; res_query: mkquery failed\n");
221 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
226 assert (answerp
== NULL
|| (void *) *answerp
== (void *) answer
);
227 n
= __libc_res_nsend(statp
, query1
, nquery1
, query2
, nquery2
, answer
,
228 anslen
, answerp
, answerp2
, nanswerp2
, resplen2
,
234 if (statp
->options
& RES_DEBUG
)
235 printf(";; res_query: send error\n");
237 RES_SET_H_ERRNO(statp
, TRY_AGAIN
);
242 /* __libc_res_nsend might have reallocated the buffer. */
243 hp
= (HEADER
*) *answerp
;
245 /* We simplify the following tests by assigning HP to HP2 or
246 vice versa. It is easy to verify that this is the same as
247 ignoring all tests of HP or HP2. */
248 if (answerp2
== NULL
|| *resplen2
< (int) sizeof (HEADER
))
254 hp2
= (HEADER
*) *answerp2
;
255 if (n
< (int) sizeof (HEADER
))
261 /* Make sure both hp and hp2 are defined */
262 assert((hp
!= NULL
) && (hp2
!= NULL
));
264 if ((hp
->rcode
!= NOERROR
|| ntohs(hp
->ancount
) == 0)
265 && (hp2
->rcode
!= NOERROR
|| ntohs(hp2
->ancount
) == 0)) {
267 if (statp
->options
& RES_DEBUG
) {
268 printf(";; rcode = %d, ancount=%d\n", hp
->rcode
,
271 printf(";; rcode2 = %d, ancount2=%d\n", hp2
->rcode
,
272 ntohs(hp2
->ancount
));
275 switch (hp
->rcode
== NOERROR
? hp2
->rcode
: hp
->rcode
) {
277 if ((hp
->rcode
== NOERROR
&& ntohs (hp
->ancount
) != 0)
278 || (hp2
->rcode
== NOERROR
279 && ntohs (hp2
->ancount
) != 0))
281 RES_SET_H_ERRNO(statp
, HOST_NOT_FOUND
);
284 RES_SET_H_ERRNO(statp
, TRY_AGAIN
);
287 if (ntohs (hp
->ancount
) != 0
288 || ntohs (hp2
->ancount
) != 0)
290 RES_SET_H_ERRNO(statp
, NO_DATA
);
294 /* Servers must not reply to AAAA queries with
295 NOTIMP etc but some of them do. */
296 if ((hp
->rcode
== NOERROR
&& ntohs (hp
->ancount
) != 0)
297 || (hp2
->rcode
== NOERROR
298 && ntohs (hp2
->ancount
) != 0))
303 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
311 libresolv_hidden_def (__libc_res_nquery
)
314 res_nquery(res_state statp
,
315 const char *name
, /* domain name */
316 int class, int type
, /* class and type of query */
317 u_char
*answer
, /* buffer to put answer */
318 int anslen
) /* size of answer buffer */
320 return __libc_res_nquery(statp
, name
, class, type
, answer
, anslen
,
321 NULL
, NULL
, NULL
, NULL
, NULL
);
323 libresolv_hidden_def (res_nquery
)
326 * Formulate a normal query, send, and retrieve answer in supplied buffer.
327 * Return the size of the response on success, -1 on error.
328 * If enabled, implement search rules until answer or unrecoverable failure
329 * is detected. Error code, if any, is left in H_ERRNO.
332 __libc_res_nsearch(res_state statp
,
333 const char *name
, /* domain name */
334 int class, int type
, /* class and type of query */
335 u_char
*answer
, /* buffer to put answer */
336 int anslen
, /* size of answer */
341 int *answerp2_malloced
)
343 const char *cp
, * const *domain
;
344 HEADER
*hp
= (HEADER
*) answer
;
345 char tmp
[NS_MAXDNAME
];
347 int trailing_dot
, ret
, saved_herrno
;
348 int got_nodata
= 0, got_servfail
= 0, root_on_list
= 0;
353 RES_SET_H_ERRNO(statp
, HOST_NOT_FOUND
); /* True if we never query. */
356 for (cp
= name
; *cp
!= '\0'; cp
++)
357 dots
+= (*cp
== '.');
359 if (cp
> name
&& *--cp
== '.')
362 /* If there aren't any dots, it could be a user-level alias. */
363 if (!dots
&& (cp
= res_hostalias(statp
, name
, tmp
, sizeof tmp
))!= NULL
)
364 return (__libc_res_nquery(statp
, cp
, class, type
, answer
,
365 anslen
, answerp
, answerp2
,
366 nanswerp2
, resplen2
, answerp2_malloced
));
369 if (statp
->options
& RES_DEBUG
)
370 printf("dots=%d, statp->ndots=%d, trailing_dot=%d, name=%s\n",
371 (int)dots
,(int)statp
->ndots
,(int)trailing_dot
,name
);
375 * If there are enough dots in the name, let's just give it a
376 * try 'as is'. The threshold can be set with the "ndots" option.
377 * Also, query 'as is', if there is a trailing dot in the name.
380 if (dots
>= statp
->ndots
|| trailing_dot
) {
381 ret
= __libc_res_nquerydomain(statp
, name
, NULL
, class, type
,
382 answer
, anslen
, answerp
,
383 answerp2
, nanswerp2
, resplen2
,
385 if (ret
> 0 || trailing_dot
386 /* If the second response is valid then we use that. */
387 || (ret
== 0 && resplen2
!= NULL
&& *resplen2
> 0))
389 saved_herrno
= h_errno
;
391 if (answerp
&& *answerp
!= answer
) {
395 if (answerp2
&& *answerp2_malloced
)
399 *answerp2_malloced
= 0;
404 * We do at least one level of search if
405 * - there is no dot and RES_DEFNAME is set, or
406 * - there is at least one dot, there is no trailing dot,
407 * and RES_DNSRCH is set.
409 if ((!dots
&& (statp
->options
& RES_DEFNAMES
) != 0) ||
410 (dots
&& !trailing_dot
&& (statp
->options
& RES_DNSRCH
) != 0)) {
413 for (domain
= (const char * const *)statp
->dnsrch
;
418 if (domain
[0][0] == '\0' ||
419 (domain
[0][0] == '.' && domain
[0][1] == '\0'))
422 ret
= __libc_res_nquerydomain(statp
, name
, *domain
,
424 answer
, anslen
, answerp
,
426 resplen2
, answerp2_malloced
);
427 if (ret
> 0 || (ret
== 0 && resplen2
!= NULL
431 if (answerp
&& *answerp
!= answer
) {
435 if (answerp2
&& *answerp2_malloced
)
439 *answerp2_malloced
= 0;
443 * If no server present, give up.
444 * If name isn't found in this domain,
445 * keep trying higher domains in the search list
446 * (if that's enabled).
447 * On a NO_DATA error, keep trying, otherwise
448 * a wildcard entry of another type could keep us
449 * from finding this entry higher in the domain.
450 * If we get some other error (negative answer or
451 * server failure), then stop searching up,
452 * but try the input name below in case it's
455 if (errno
== ECONNREFUSED
) {
456 RES_SET_H_ERRNO(statp
, TRY_AGAIN
);
460 switch (statp
->res_h_errno
) {
468 if (hp
->rcode
== SERVFAIL
) {
469 /* try next search element, if any */
475 /* anything else implies that we're done */
479 /* if we got here for some reason other than DNSRCH,
480 * we only wanted one iteration of the loop, so stop.
482 if ((statp
->options
& RES_DNSRCH
) == 0)
488 * If the query has not already been tried as is then try it
489 * unless RES_NOTLDQUERY is set and there were no dots.
491 if ((dots
|| !searched
|| (statp
->options
& RES_NOTLDQUERY
) == 0)
492 && !(tried_as_is
|| root_on_list
)) {
493 ret
= __libc_res_nquerydomain(statp
, name
, NULL
, class, type
,
494 answer
, anslen
, answerp
,
495 answerp2
, nanswerp2
, resplen2
,
497 if (ret
> 0 || (ret
== 0 && resplen2
!= NULL
502 /* if we got here, we didn't satisfy the search.
503 * if we did an initial full query, return that query's H_ERRNO
504 * (note that we wouldn't be here if that query had succeeded).
505 * else if we ever got a nodata, send that back as the reason.
506 * else send back meaningless H_ERRNO, that being the one from
507 * the last DNSRCH we did.
509 if (answerp2
&& *answerp2_malloced
)
513 *answerp2_malloced
= 0;
515 if (saved_herrno
!= -1)
516 RES_SET_H_ERRNO(statp
, saved_herrno
);
518 RES_SET_H_ERRNO(statp
, NO_DATA
);
519 else if (got_servfail
)
520 RES_SET_H_ERRNO(statp
, TRY_AGAIN
);
523 libresolv_hidden_def (__libc_res_nsearch
)
526 res_nsearch(res_state statp
,
527 const char *name
, /* domain name */
528 int class, int type
, /* class and type of query */
529 u_char
*answer
, /* buffer to put answer */
530 int anslen
) /* size of answer */
532 return __libc_res_nsearch(statp
, name
, class, type
, answer
,
533 anslen
, NULL
, NULL
, NULL
, NULL
, NULL
);
535 libresolv_hidden_def (res_nsearch
)
538 * Perform a call on res_query on the concatenation of name and domain,
539 * removing a trailing dot from name if domain is NULL.
542 __libc_res_nquerydomain(res_state statp
,
545 int class, int type
, /* class and type of query */
546 u_char
*answer
, /* buffer to put answer */
547 int anslen
, /* size of answer */
552 int *answerp2_malloced
)
555 const char *longname
= nbuf
;
559 if (statp
->options
& RES_DEBUG
)
560 printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
561 name
, domain
?domain
:"<Nil>", class, type
);
563 if (domain
== NULL
) {
565 * Check for trailing '.';
566 * copy without '.' if present.
570 /* Decrement N prior to checking it against MAXDNAME
571 so that we detect a wrap to SIZE_MAX and return
572 a reasonable error. */
574 if (n
>= MAXDNAME
- 1) {
575 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
578 if (name
[n
] == '.') {
579 strncpy(nbuf
, name
, n
);
586 if (n
+ d
+ 1 >= MAXDNAME
) {
587 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
590 sprintf(nbuf
, "%s.%s", name
, domain
);
592 return (__libc_res_nquery(statp
, longname
, class, type
, answer
,
593 anslen
, answerp
, answerp2
, nanswerp2
,
594 resplen2
, answerp2_malloced
));
598 res_nquerydomain(res_state statp
,
601 int class, int type
, /* class and type of query */
602 u_char
*answer
, /* buffer to put answer */
603 int anslen
) /* size of answer */
605 return __libc_res_nquerydomain(statp
, name
, domain
, class, type
,
606 answer
, anslen
, NULL
, NULL
, NULL
, NULL
,
609 libresolv_hidden_def (res_nquerydomain
)
612 res_hostalias(const res_state statp
, const char *name
, char *dst
, size_t siz
) {
613 char *file
, *cp1
, *cp2
;
617 if (statp
->options
& RES_NOALIASES
)
619 file
= getenv("HOSTALIASES");
620 if (file
== NULL
|| (fp
= fopen(file
, "rce")) == NULL
)
623 buf
[sizeof(buf
) - 1] = '\0';
624 while (fgets(buf
, sizeof(buf
), fp
)) {
625 for (cp1
= buf
; *cp1
&& !isspace(*cp1
); ++cp1
)
630 if (ns_samename(buf
, name
) == 1) {
631 while (isspace(*++cp1
))
635 for (cp2
= cp1
+ 1; *cp2
&& !isspace(*cp2
); ++cp2
)
638 strncpy(dst
, cp1
, siz
- 1);
647 libresolv_hidden_def (res_hostalias
)