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
68 #include <sys/types.h>
69 #include <sys/param.h>
70 #include <netinet/in.h>
71 #include <arpa/inet.h>
72 #include <arpa/nameser.h>
77 #include <resolv/resolv-internal.h>
78 #include <resolv/resolv_context.h>
82 #include <shlib-compat.h>
85 #define MAXPACKET PACKETSZ
87 #define MAXPACKET 65536
90 #define QUERYSIZE (HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1)
93 __res_context_querydomain (struct resolv_context
*,
94 const char *name
, const char *domain
,
95 int class, int type
, unsigned char *answer
, int anslen
,
96 unsigned char **answerp
, unsigned char **answerp2
, int *nanswerp2
,
97 int *resplen2
, int *answerp2_malloced
);
99 /* Formulate a normal query, send, and await answer. Returned answer
100 is placed in supplied buffer ANSWER. Perform preliminary check of
101 answer, returning success only if no error is indicated and the
102 answer count is nonzero. Return the size of the response on
103 success, -1 on error. Error number is left in h_errno.
105 Caller must parse answer and determine whether it answers the
108 __res_context_query (struct resolv_context
*ctx
, const char *name
,
110 unsigned char *answer
, int anslen
,
111 unsigned char **answerp
, unsigned char **answerp2
,
112 int *nanswerp2
, int *resplen2
, int *answerp2_malloced
)
114 struct __res_state
*statp
= ctx
->resp
;
115 HEADER
*hp
= (HEADER
*) answer
;
117 int n
, use_malloc
= 0;
119 size_t bufsize
= (type
== T_QUERY_A_AND_AAAA
? 2 : 1) * QUERYSIZE
;
120 u_char
*buf
= alloca (bufsize
);
121 u_char
*query1
= buf
;
123 u_char
*query2
= NULL
;
127 hp
->rcode
= NOERROR
; /* default */
129 if (type
== T_QUERY_A_AND_AAAA
)
131 n
= __res_context_mkquery (ctx
, QUERY
, name
, class, T_A
, NULL
,
135 if ((statp
->options
& (RES_USE_EDNS0
|RES_USE_DNSSEC
)) != 0)
137 /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
138 buffer can be reallocated. */
139 n
= __res_nopt (ctx
, n
, query1
, bufsize
,
140 RESOLV_EDNS_BUFFER_SIZE
);
146 /* Align the buffer. */
147 int npad
= ((nquery1
+ __alignof__ (HEADER
) - 1)
148 & ~(__alignof__ (HEADER
) - 1)) - nquery1
;
149 if (n
> bufsize
- npad
)
154 int nused
= n
+ npad
;
155 query2
= buf
+ nused
;
156 n
= __res_context_mkquery (ctx
, QUERY
, name
, class, T_AAAA
,
157 NULL
, query2
, bufsize
- nused
);
159 && (statp
->options
& (RES_USE_EDNS0
|RES_USE_DNSSEC
)) != 0)
160 /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
161 buffer can be reallocated. */
162 n
= __res_nopt (ctx
, n
, query2
, bufsize
,
163 RESOLV_EDNS_BUFFER_SIZE
);
171 n
= __res_context_mkquery (ctx
, QUERY
, name
, class, type
, NULL
,
175 && (statp
->options
& (RES_USE_EDNS0
|RES_USE_DNSSEC
)) != 0)
177 /* Use RESOLV_EDNS_BUFFER_SIZE if the receive buffer
178 can be reallocated. */
183 advertise
= RESOLV_EDNS_BUFFER_SIZE
;
184 n
= __res_nopt (ctx
, n
, query1
, bufsize
, advertise
);
190 if (__glibc_unlikely (n
<= 0) && !use_malloc
) {
191 /* Retry just in case res_nmkquery failed because of too
192 short buffer. Shouldn't happen. */
193 bufsize
= (type
== T_QUERY_A_AND_AAAA
? 2 : 1) * MAXPACKET
;
194 buf
= malloc (bufsize
);
201 if (__glibc_unlikely (n
<= 0)) {
202 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
207 assert (answerp
== NULL
|| (void *) *answerp
== (void *) answer
);
208 n
= __res_context_send (ctx
, query1
, nquery1
, query2
, nquery2
, answer
,
209 anslen
, answerp
, answerp2
, nanswerp2
, resplen2
,
214 RES_SET_H_ERRNO(statp
, TRY_AGAIN
);
219 /* __res_context_send might have reallocated the buffer. */
220 hp
= (HEADER
*) *answerp
;
222 /* We simplify the following tests by assigning HP to HP2 or
223 vice versa. It is easy to verify that this is the same as
224 ignoring all tests of HP or HP2. */
225 if (answerp2
== NULL
|| *resplen2
< (int) sizeof (HEADER
))
231 hp2
= (HEADER
*) *answerp2
;
232 if (n
< (int) sizeof (HEADER
))
238 /* Make sure both hp and hp2 are defined */
239 assert((hp
!= NULL
) && (hp2
!= NULL
));
241 if ((hp
->rcode
!= NOERROR
|| ntohs(hp
->ancount
) == 0)
242 && (hp2
->rcode
!= NOERROR
|| ntohs(hp2
->ancount
) == 0)) {
243 switch (hp
->rcode
== NOERROR
? hp2
->rcode
: hp
->rcode
) {
245 if ((hp
->rcode
== NOERROR
&& ntohs (hp
->ancount
) != 0)
246 || (hp2
->rcode
== NOERROR
247 && ntohs (hp2
->ancount
) != 0))
249 RES_SET_H_ERRNO(statp
, HOST_NOT_FOUND
);
252 RES_SET_H_ERRNO(statp
, TRY_AGAIN
);
255 if (ntohs (hp
->ancount
) != 0
256 || ntohs (hp2
->ancount
) != 0)
258 RES_SET_H_ERRNO(statp
, NO_DATA
);
262 /* Servers must not reply to AAAA queries with
263 NOTIMP etc but some of them do. */
264 if ((hp
->rcode
== NOERROR
&& ntohs (hp
->ancount
) != 0)
265 || (hp2
->rcode
== NOERROR
266 && ntohs (hp2
->ancount
) != 0))
271 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
279 libresolv_hidden_def (__res_context_query
)
281 /* Common part of res_nquery and res_query. */
283 context_query_common (struct resolv_context
*ctx
,
284 const char *name
, int class, int type
,
285 unsigned char *answer
, int anslen
)
289 RES_SET_H_ERRNO (&_res
, NETDB_INTERNAL
);
292 int result
= __res_context_query (ctx
, name
, class, type
, answer
, anslen
,
293 NULL
, NULL
, NULL
, NULL
, NULL
);
294 __resolv_context_put (ctx
);
299 res_nquery(res_state statp
,
300 const char *name
, /* domain name */
301 int class, int type
, /* class and type of query */
302 u_char
*answer
, /* buffer to put answer */
303 int anslen
) /* size of answer buffer */
305 return context_query_common
306 (__resolv_context_get_override (statp
), name
, class, type
, answer
, anslen
);
310 res_query (const char *name
, int class, int type
,
311 unsigned char *answer
, int anslen
)
313 return context_query_common
314 (__resolv_context_get (), name
, class, type
, answer
, anslen
);
317 /* Formulate a normal query, send, and retrieve answer in supplied
318 buffer. Return the size of the response on success, -1 on error.
319 If enabled, implement search rules until answer or unrecoverable
320 failure is detected. Error code, if any, is left in h_errno. */
322 __res_context_search (struct resolv_context
*ctx
,
323 const char *name
, int class, int type
,
324 unsigned char *answer
, int anslen
,
325 unsigned char **answerp
, unsigned char **answerp2
,
326 int *nanswerp2
, int *resplen2
, int *answerp2_malloced
)
328 struct __res_state
*statp
= ctx
->resp
;
330 HEADER
*hp
= (HEADER
*) answer
;
331 char tmp
[NS_MAXDNAME
];
333 int trailing_dot
, ret
, saved_herrno
;
334 int got_nodata
= 0, got_servfail
= 0, root_on_list
= 0;
339 RES_SET_H_ERRNO(statp
, HOST_NOT_FOUND
); /* True if we never query. */
342 for (cp
= name
; *cp
!= '\0'; cp
++)
343 dots
+= (*cp
== '.');
345 if (cp
> name
&& *--cp
== '.')
348 /* If there aren't any dots, it could be a user-level alias. */
349 if (!dots
&& (cp
= __res_context_hostalias
350 (ctx
, name
, tmp
, sizeof tmp
))!= NULL
)
351 return __res_context_query (ctx
, cp
, class, type
, answer
,
352 anslen
, answerp
, answerp2
,
353 nanswerp2
, resplen2
, answerp2_malloced
);
356 * If there are enough dots in the name, let's just give it a
357 * try 'as is'. The threshold can be set with the "ndots" option.
358 * Also, query 'as is', if there is a trailing dot in the name.
361 if (dots
>= statp
->ndots
|| trailing_dot
) {
362 ret
= __res_context_querydomain (ctx
, name
, NULL
, class, type
,
363 answer
, anslen
, answerp
,
364 answerp2
, nanswerp2
, resplen2
,
366 if (ret
> 0 || trailing_dot
367 /* If the second response is valid then we use that. */
368 || (ret
== 0 && resplen2
!= NULL
&& *resplen2
> 0))
370 saved_herrno
= h_errno
;
372 if (answerp
&& *answerp
!= answer
) {
376 if (answerp2
&& *answerp2_malloced
)
381 *answerp2_malloced
= 0;
386 * We do at least one level of search if
387 * - there is no dot and RES_DEFNAME is set, or
388 * - there is at least one dot, there is no trailing dot,
389 * and RES_DNSRCH is set.
391 if ((!dots
&& (statp
->options
& RES_DEFNAMES
) != 0) ||
392 (dots
&& !trailing_dot
&& (statp
->options
& RES_DNSRCH
) != 0)) {
395 for (size_t domain_index
= 0; !done
; ++domain_index
) {
396 const char *dname
= __resolv_context_search_list
402 /* __res_context_querydoman concatenates name
403 with dname with a "." in between. If we
404 pass it in dname the "." we got from the
405 configured default search path, we'll end
406 up with "name..", which won't resolve.
407 OTOH, passing it "" will result in "name.",
408 which has the intended effect for both
409 possible representations of the root
413 if (dname
[0] == '\0')
416 ret
= __res_context_querydomain
417 (ctx
, name
, dname
, class, type
,
418 answer
, anslen
, answerp
, answerp2
, nanswerp2
,
419 resplen2
, answerp2_malloced
);
420 if (ret
> 0 || (ret
== 0 && resplen2
!= NULL
424 if (answerp
&& *answerp
!= answer
) {
428 if (answerp2
&& *answerp2_malloced
)
433 *answerp2_malloced
= 0;
437 * If no server present, give up.
438 * If name isn't found in this domain,
439 * keep trying higher domains in the search list
440 * (if that's enabled).
441 * On a NO_DATA error, keep trying, otherwise
442 * a wildcard entry of another type could keep us
443 * from finding this entry higher in the domain.
444 * If we get some other error (negative answer or
445 * server failure), then stop searching up,
446 * but try the input name below in case it's
449 if (errno
== ECONNREFUSED
) {
450 RES_SET_H_ERRNO(statp
, TRY_AGAIN
);
454 switch (statp
->res_h_errno
) {
462 if (hp
->rcode
== SERVFAIL
) {
463 /* try next search element, if any */
469 /* anything else implies that we're done */
473 /* if we got here for some reason other than DNSRCH,
474 * we only wanted one iteration of the loop, so stop.
476 if ((statp
->options
& RES_DNSRCH
) == 0)
482 * If the query has not already been tried as is then try it
483 * unless RES_NOTLDQUERY is set and there were no dots.
485 if ((dots
|| !searched
|| (statp
->options
& RES_NOTLDQUERY
) == 0)
486 && !(tried_as_is
|| root_on_list
)) {
487 ret
= __res_context_querydomain
488 (ctx
, name
, NULL
, class, type
,
489 answer
, anslen
, answerp
, answerp2
, nanswerp2
,
490 resplen2
, answerp2_malloced
);
491 if (ret
> 0 || (ret
== 0 && resplen2
!= NULL
496 /* if we got here, we didn't satisfy the search.
497 * if we did an initial full query, return that query's H_ERRNO
498 * (note that we wouldn't be here if that query had succeeded).
499 * else if we ever got a nodata, send that back as the reason.
500 * else send back meaningless H_ERRNO, that being the one from
501 * the last DNSRCH we did.
503 if (answerp2
&& *answerp2_malloced
)
508 *answerp2_malloced
= 0;
510 if (saved_herrno
!= -1)
511 RES_SET_H_ERRNO(statp
, saved_herrno
);
513 RES_SET_H_ERRNO(statp
, NO_DATA
);
514 else if (got_servfail
)
515 RES_SET_H_ERRNO(statp
, TRY_AGAIN
);
518 libresolv_hidden_def (__res_context_search
)
520 /* Common part of res_nsearch and res_search. */
522 context_search_common (struct resolv_context
*ctx
,
523 const char *name
, int class, int type
,
524 unsigned char *answer
, int anslen
)
528 RES_SET_H_ERRNO (&_res
, NETDB_INTERNAL
);
531 int result
= __res_context_search (ctx
, name
, class, type
, answer
, anslen
,
532 NULL
, NULL
, NULL
, NULL
, NULL
);
533 __resolv_context_put (ctx
);
538 res_nsearch(res_state statp
,
539 const char *name
, /* domain name */
540 int class, int type
, /* class and type of query */
541 u_char
*answer
, /* buffer to put answer */
542 int anslen
) /* size of answer */
544 return context_search_common
545 (__resolv_context_get_override (statp
), name
, class, type
, answer
, anslen
);
549 res_search (const char *name
, int class, int type
,
550 unsigned char *answer
, int anslen
)
552 return context_search_common
553 (__resolv_context_get (), name
, class, type
, answer
, anslen
);
556 /* Perform a call on res_query on the concatenation of name and
559 __res_context_querydomain (struct resolv_context
*ctx
,
560 const char *name
, const char *domain
,
562 unsigned char *answer
, int anslen
,
563 unsigned char **answerp
, unsigned char **answerp2
,
564 int *nanswerp2
, int *resplen2
,
565 int *answerp2_malloced
)
567 struct __res_state
*statp
= ctx
->resp
;
569 const char *longname
= nbuf
;
572 if (domain
== NULL
) {
575 /* Decrement N prior to checking it against MAXDNAME
576 so that we detect a wrap to SIZE_MAX and return
577 a reasonable error. */
579 if (n
>= MAXDNAME
- 1) {
580 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
587 if (n
+ d
+ 1 >= MAXDNAME
) {
588 RES_SET_H_ERRNO(statp
, NO_RECOVERY
);
591 sprintf(nbuf
, "%s.%s", name
, domain
);
593 return __res_context_query (ctx
, longname
, class, type
, answer
,
594 anslen
, answerp
, answerp2
, nanswerp2
,
595 resplen2
, answerp2_malloced
);
598 /* Common part of res_nquerydomain and res_querydomain. */
600 context_querydomain_common (struct resolv_context
*ctx
,
601 const char *name
, const char *domain
,
603 unsigned char *answer
, int anslen
)
607 RES_SET_H_ERRNO (&_res
, NETDB_INTERNAL
);
610 int result
= __res_context_querydomain (ctx
, name
, domain
, class, type
,
612 NULL
, NULL
, NULL
, NULL
, NULL
);
613 __resolv_context_put (ctx
);
618 res_nquerydomain(res_state statp
,
621 int class, int type
, /* class and type of query */
622 u_char
*answer
, /* buffer to put answer */
623 int anslen
) /* size of answer */
625 return context_querydomain_common
626 (__resolv_context_get_override (statp
),
627 name
, domain
, class, type
, answer
, anslen
);
631 res_querydomain (const char *name
, const char *domain
, int class, int type
,
632 unsigned char *answer
, int anslen
)
634 return context_querydomain_common
635 (__resolv_context_get (), name
, domain
, class, type
, answer
, anslen
);
639 __res_context_hostalias (struct resolv_context
*ctx
,
640 const char *name
, char *dst
, size_t siz
)
642 char *file
, *cp1
, *cp2
;
646 if (ctx
->resp
->options
& RES_NOALIASES
)
648 file
= getenv("HOSTALIASES");
649 if (file
== NULL
|| (fp
= fopen(file
, "rce")) == NULL
)
652 buf
[sizeof(buf
) - 1] = '\0';
653 while (fgets(buf
, sizeof(buf
), fp
)) {
654 for (cp1
= buf
; *cp1
&& !isspace(*cp1
); ++cp1
)
659 if (ns_samename(buf
, name
) == 1) {
660 while (isspace(*++cp1
))
664 for (cp2
= cp1
+ 1; *cp2
&& !isspace(*cp2
); ++cp2
)
667 strncpy(dst
, cp1
, siz
- 1);
676 libresolv_hidden_def (__res_context_hostalias
)
678 /* Common part of res_hostalias and hostalias. */
680 context_hostalias_common (struct resolv_context
*ctx
,
681 const char *name
, char *dst
, size_t siz
)
685 RES_SET_H_ERRNO (&_res
, NETDB_INTERNAL
);
688 const char *result
= __res_context_hostalias (ctx
, name
, dst
, siz
);
689 __resolv_context_put (ctx
);
694 res_hostalias (res_state statp
, const char *name
, char *dst
, size_t siz
)
696 return context_hostalias_common
697 (__resolv_context_get_override (statp
), name
, dst
, siz
);
701 hostalias (const char *name
)
703 static char abuf
[MAXDNAME
];
704 return context_hostalias_common
705 (__resolv_context_get (), name
, abuf
, sizeof (abuf
));
708 #if SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
710 # undef res_querydomain
712 weak_alias (__res_query
, res_query
);
713 weak_alias (__res_querydomain
, res_querydomain
);
714 weak_alias (__res_search
, res_search
);