]> git.ipfire.org Git - thirdparty/glibc.git/blame - resolv/res_query.c
Update copyright dates with scripts/update-copyrights
[thirdparty/glibc.git] / resolv / res_query.c
CommitLineData
28f540f4 1/*
28f540f4
RM
2 * Copyright (c) 1988, 1993
3 * The Regents of the University of California. All rights reserved.
52ee6223 4 *
28f540f4
RM
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
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.
28f540f4
RM
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.
52ee6223 16 *
28f540f4
RM
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
27 * SUCH DAMAGE.
b43b13ac
UD
28 */
29
30/*
28f540f4 31 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
52ee6223 32 *
28f540f4
RM
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.
52ee6223 39 *
28f540f4
RM
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
47 * SOFTWARE.
b43b13ac
UD
48 */
49
50/*
51 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
52 *
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.
56 *
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
64 * SOFTWARE.
28f540f4
RM
65 */
66
acf82eaf 67#include <assert.h>
df21c858 68#include <sys/types.h>
28f540f4
RM
69#include <sys/param.h>
70#include <netinet/in.h>
71#include <arpa/inet.h>
72#include <arpa/nameser.h>
28f540f4
RM
73#include <ctype.h>
74#include <errno.h>
b43b13ac
UD
75#include <netdb.h>
76#include <resolv.h>
a7ff1da8 77#include <resolv/resolv-internal.h>
352f4ff9 78#include <resolv/resolv_context.h>
b43b13ac
UD
79#include <stdio.h>
80#include <stdlib.h>
81#include <string.h>
03775117 82#include <shlib-compat.h>
40c0add7 83#include <scratch_buffer.h>
28f540f4 84
e2dced82 85#if PACKETSZ > 65536
28f540f4
RM
86#define MAXPACKET PACKETSZ
87#else
e2dced82 88#define MAXPACKET 65536
28f540f4
RM
89#endif
90
0420d888
UD
91#define QUERYSIZE (HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1)
92
93static int
352f4ff9
FW
94__res_context_querydomain (struct resolv_context *,
95 const char *name, const char *domain,
96 int class, int type, unsigned char *answer, int anslen,
97 unsigned char **answerp, unsigned char **answerp2, int *nanswerp2,
98 int *resplen2, int *answerp2_malloced);
99
100/* Formulate a normal query, send, and await answer. Returned answer
101 is placed in supplied buffer ANSWER. Perform preliminary check of
102 answer, returning success only if no error is indicated and the
103 answer count is nonzero. Return the size of the response on
104 success, -1 on error. Error number is left in h_errno.
105
106 Caller must parse answer and determine whether it answers the
107 question. */
28f540f4 108int
352f4ff9
FW
109__res_context_query (struct resolv_context *ctx, const char *name,
110 int class, int type,
111 unsigned char *answer, int anslen,
112 unsigned char **answerp, unsigned char **answerp2,
113 int *nanswerp2, int *resplen2, int *answerp2_malloced)
28f540f4 114{
352f4ff9 115 struct __res_state *statp = ctx->resp;
05dec22d
JDA
116 UHEADER *hp = (UHEADER *) answer;
117 UHEADER *hp2;
40c0add7
AZ
118 int n;
119
120 /* It requires 2 times QUERYSIZE for type == T_QUERY_A_AND_AAAA. */
121 struct scratch_buffer buf;
122 scratch_buffer_init (&buf);
123 _Static_assert (2 * QUERYSIZE <= sizeof (buf.__space.__c),
124 "scratch_buffer too small");
125 u_char *query1 = buf.data;
1eb946b9
UD
126 int nquery1 = -1;
127 u_char *query2 = NULL;
128 int nquery2 = 0;
28f540f4 129
2bbb7d5b
UD
130 again:
131 hp->rcode = NOERROR; /* default */
6166815d 132
fc82b0a2 133 if (type == T_QUERY_A_AND_AAAA)
1eb946b9 134 {
352f4ff9 135 n = __res_context_mkquery (ctx, QUERY, name, class, T_A, NULL,
40c0add7 136 query1, buf.length);
1eb946b9
UD
137 if (n > 0)
138 {
44500cbb 139 if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
44abc397 140 {
e14a2772
FW
141 /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
142 buffer can be reallocated. */
40c0add7 143 n = __res_nopt (ctx, n, query1, buf.length,
e14a2772 144 RESOLV_EDNS_BUFFER_SIZE);
44abc397
UD
145 if (n < 0)
146 goto unspec_nomem;
147 }
1eb946b9
UD
148
149 nquery1 = n;
40c0add7 150 query2 = buf.data + n;
352f4ff9 151 n = __res_context_mkquery (ctx, QUERY, name, class, T_AAAA,
40c0add7 152 NULL, query2, buf.length - n);
1eb946b9 153 if (n > 0
2d0671cb 154 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
e14a2772
FW
155 /* Use RESOLV_EDNS_BUFFER_SIZE because the receive
156 buffer can be reallocated. */
40c0add7 157 n = __res_nopt (ctx, n, query2, buf.length,
e14a2772 158 RESOLV_EDNS_BUFFER_SIZE);
1eb946b9
UD
159 nquery2 = n;
160 }
44abc397
UD
161
162 unspec_nomem:;
1eb946b9
UD
163 }
164 else
165 {
352f4ff9 166 n = __res_context_mkquery (ctx, QUERY, name, class, type, NULL,
40c0add7 167 query1, buf.length);
1eb946b9
UD
168
169 if (n > 0
2d0671cb 170 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
e14a2772
FW
171 {
172 /* Use RESOLV_EDNS_BUFFER_SIZE if the receive buffer
173 can be reallocated. */
174 size_t advertise;
175 if (answerp == NULL)
176 advertise = anslen;
177 else
178 advertise = RESOLV_EDNS_BUFFER_SIZE;
40c0add7 179 n = __res_nopt (ctx, n, query1, buf.length, advertise);
e14a2772 180 }
1eb946b9
UD
181
182 nquery1 = n;
183 }
184
40c0add7 185 if (__glibc_unlikely (n <= 0)) {
0420d888
UD
186 /* Retry just in case res_nmkquery failed because of too
187 short buffer. Shouldn't happen. */
40c0add7
AZ
188 if (scratch_buffer_set_array_size (&buf,
189 T_QUERY_A_AND_AAAA ? 2 : 1,
190 MAXPACKET)) {
191 query1 = buf.data;
2bbb7d5b 192 goto again;
78512c00 193 }
0420d888 194 }
a1ffb40e 195 if (__glibc_unlikely (n <= 0)) {
b43b13ac 196 RES_SET_H_ERRNO(statp, NO_RECOVERY);
40c0add7 197 scratch_buffer_free (&buf);
28f540f4
RM
198 return (n);
199 }
f282cdbe
FW
200
201 /* Suppress AAAA lookups if required. __res_handle_no_aaaa
202 checks RES_NOAAAA first, so avoids parsing the
203 just-generated query packet in most cases. nss_dns avoids
204 using T_QUERY_A_AND_AAAA in RES_NOAAAA mode, so there is no
205 need to handle it here. */
206 if (type == T_AAAA && __res_handle_no_aaaa (ctx, query1, nquery1,
207 answer, anslen, &n))
208 /* There must be no second query for AAAA queries. The code
209 below is still needed to translate NODATA responses. */
210 assert (query2 == NULL);
211 else
212 {
213 assert (answerp == NULL || (void *) *answerp == (void *) answer);
214 n = __res_context_send (ctx, query1, nquery1, query2, nquery2,
215 answer, anslen,
216 answerp, answerp2, nanswerp2, resplen2,
217 answerp2_malloced);
218 }
219
40c0add7 220 scratch_buffer_free (&buf);
28f540f4 221 if (n < 0) {
b43b13ac 222 RES_SET_H_ERRNO(statp, TRY_AGAIN);
28f540f4
RM
223 return (n);
224 }
225
acf82eaf 226 if (answerp != NULL)
352f4ff9 227 /* __res_context_send might have reallocated the buffer. */
05dec22d 228 hp = (UHEADER *) *answerp;
acf82eaf 229
cc8bb21c
AJ
230 /* We simplify the following tests by assigning HP to HP2 or
231 vice versa. It is easy to verify that this is the same as
232 ignoring all tests of HP or HP2. */
233 if (answerp2 == NULL || *resplen2 < (int) sizeof (HEADER))
5908f779 234 {
cc8bb21c 235 hp2 = hp;
5908f779 236 }
cc8bb21c 237 else
5908f779 238 {
05dec22d 239 hp2 = (UHEADER *) *answerp2;
cc8bb21c
AJ
240 if (n < (int) sizeof (HEADER))
241 {
242 hp = hp2;
243 }
5908f779
UD
244 }
245
cc8bb21c
AJ
246 /* Make sure both hp and hp2 are defined */
247 assert((hp != NULL) && (hp2 != NULL));
248
1eb946b9
UD
249 if ((hp->rcode != NOERROR || ntohs(hp->ancount) == 0)
250 && (hp2->rcode != NOERROR || ntohs(hp2->ancount) == 0)) {
1eb946b9 251 switch (hp->rcode == NOERROR ? hp2->rcode : hp->rcode) {
28f540f4 252 case NXDOMAIN:
1eb946b9
UD
253 if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
254 || (hp2->rcode == NOERROR
255 && ntohs (hp2->ancount) != 0))
256 goto success;
b43b13ac 257 RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
28f540f4
RM
258 break;
259 case SERVFAIL:
b43b13ac 260 RES_SET_H_ERRNO(statp, TRY_AGAIN);
28f540f4
RM
261 break;
262 case NOERROR:
1eb946b9
UD
263 if (ntohs (hp->ancount) != 0
264 || ntohs (hp2->ancount) != 0)
265 goto success;
b43b13ac 266 RES_SET_H_ERRNO(statp, NO_DATA);
28f540f4
RM
267 break;
268 case FORMERR:
269 case NOTIMP:
cf4f16cc
UD
270 /* Servers must not reply to AAAA queries with
271 NOTIMP etc but some of them do. */
272 if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
273 || (hp2->rcode == NOERROR
274 && ntohs (hp2->ancount) != 0))
275 goto success;
276 /* FALLTHROUGH */
28f540f4
RM
277 case REFUSED:
278 default:
b43b13ac 279 RES_SET_H_ERRNO(statp, NO_RECOVERY);
28f540f4
RM
280 break;
281 }
282 return (-1);
283 }
1eb946b9 284 success:
28f540f4
RM
285 return (n);
286}
ea9878ec 287libc_hidden_def (__res_context_query)
352f4ff9
FW
288
289/* Common part of res_nquery and res_query. */
290static int
291context_query_common (struct resolv_context *ctx,
292 const char *name, int class, int type,
293 unsigned char *answer, int anslen)
294{
295 if (ctx == NULL)
296 {
297 RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
298 return -1;
299 }
300 int result = __res_context_query (ctx, name, class, type, answer, anslen,
301 NULL, NULL, NULL, NULL, NULL);
302 __resolv_context_put (ctx);
303 return result;
304}
28f540f4 305
0420d888 306int
ea9878ec
FW
307___res_nquery (res_state statp,
308 const char *name, /* Domain name. */
309 int class, int type, /* Class and type of query. */
310 unsigned char *answer, /* Buffer to put answer. */
311 int anslen) /* Size of answer buffer. */
0420d888 312{
352f4ff9
FW
313 return context_query_common
314 (__resolv_context_get_override (statp), name, class, type, answer, anslen);
0420d888 315}
ea9878ec
FW
316versioned_symbol (libc, ___res_nquery, res_nquery, GLIBC_2_34);
317#if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_2, GLIBC_2_34)
318compat_symbol (libresolv, ___res_nquery, __res_nquery, GLIBC_2_2);
319#endif
0420d888 320
03775117 321int
ea9878ec
FW
322___res_query (const char *name, int class, int type,
323 unsigned char *answer, int anslen)
03775117 324{
352f4ff9
FW
325 return context_query_common
326 (__resolv_context_get (), name, class, type, answer, anslen);
03775117 327}
ea9878ec
FW
328versioned_symbol (libc, ___res_query, res_query, GLIBC_2_34);
329#if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
330compat_symbol (libresolv, ___res_query, res_query, GLIBC_2_0);
331#endif
332#if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_2, GLIBC_2_34)
333compat_symbol (libresolv, ___res_query, __res_query, GLIBC_2_2);
334#endif
03775117 335
352f4ff9
FW
336/* Formulate a normal query, send, and retrieve answer in supplied
337 buffer. Return the size of the response on success, -1 on error.
338 If enabled, implement search rules until answer or unrecoverable
339 failure is detected. Error code, if any, is left in h_errno. */
28f540f4 340int
352f4ff9
FW
341__res_context_search (struct resolv_context *ctx,
342 const char *name, int class, int type,
343 unsigned char *answer, int anslen,
344 unsigned char **answerp, unsigned char **answerp2,
345 int *nanswerp2, int *resplen2, int *answerp2_malloced)
28f540f4 346{
352f4ff9 347 struct __res_state *statp = ctx->resp;
3f853f22 348 const char *cp;
05dec22d 349 UHEADER *hp = (UHEADER *) answer;
b43b13ac 350 char tmp[NS_MAXDNAME];
28f540f4 351 u_int dots;
e685e07d 352 int trailing_dot, ret, saved_herrno;
b43b13ac 353 int got_nodata = 0, got_servfail = 0, root_on_list = 0;
e685e07d 354 int tried_as_is = 0;
f87dfb1f 355 int searched = 0;
28f540f4 356
c4029823 357 __set_errno (0);
b43b13ac
UD
358 RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /* True if we never query. */
359
28f540f4 360 dots = 0;
b43b13ac 361 for (cp = name; *cp != '\0'; cp++)
28f540f4
RM
362 dots += (*cp == '.');
363 trailing_dot = 0;
364 if (cp > name && *--cp == '.')
365 trailing_dot++;
366
b43b13ac 367 /* If there aren't any dots, it could be a user-level alias. */
352f4ff9
FW
368 if (!dots && (cp = __res_context_hostalias
369 (ctx, name, tmp, sizeof tmp))!= NULL)
370 return __res_context_query (ctx, cp, class, type, answer,
371 anslen, answerp, answerp2,
372 nanswerp2, resplen2, answerp2_malloced);
28f540f4
RM
373
374 /*
e685e07d
UD
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.
28f540f4 378 */
e685e07d
UD
379 saved_herrno = -1;
380 if (dots >= statp->ndots || trailing_dot) {
352f4ff9
FW
381 ret = __res_context_querydomain (ctx, name, NULL, class, type,
382 answer, anslen, answerp,
383 answerp2, nanswerp2, resplen2,
384 answerp2_malloced);
16b293a7
SP
385 if (ret > 0 || trailing_dot
386 /* If the second response is valid then we use that. */
e35c53e3 387 || (ret == 0 && resplen2 != NULL && *resplen2 > 0))
e685e07d
UD
388 return (ret);
389 saved_herrno = h_errno;
390 tried_as_is++;
0420d888
UD
391 if (answerp && *answerp != answer) {
392 answer = *answerp;
393 anslen = MAXPACKET;
394 }
ab09bf61 395 if (answerp2 && *answerp2_malloced)
1eb946b9
UD
396 {
397 free (*answerp2);
398 *answerp2 = NULL;
e9db92d3 399 *nanswerp2 = 0;
ab09bf61 400 *answerp2_malloced = 0;
1eb946b9 401 }
e685e07d 402 }
28f540f4
RM
403
404 /*
405 * We do at least one level of search if
406 * - there is no dot and RES_DEFNAME is set, or
407 * - there is at least one dot, there is no trailing dot,
408 * and RES_DNSRCH is set.
409 */
b43b13ac
UD
410 if ((!dots && (statp->options & RES_DEFNAMES) != 0) ||
411 (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
28f540f4
RM
412 int done = 0;
413
3f853f22
FW
414 for (size_t domain_index = 0; !done; ++domain_index) {
415 const char *dname = __resolv_context_search_list
416 (ctx, domain_index);
417 if (dname == NULL)
418 break;
f87dfb1f 419 searched = 1;
28f540f4 420
352f4ff9 421 /* __res_context_querydoman concatenates name
b59d114b
AO
422 with dname with a "." in between. If we
423 pass it in dname the "." we got from the
424 configured default search path, we'll end
425 up with "name..", which won't resolve.
426 OTOH, passing it "" will result in "name.",
427 which has the intended effect for both
428 possible representations of the root
429 domain. */
430 if (dname[0] == '.')
431 dname++;
432 if (dname[0] == '\0')
b43b13ac
UD
433 root_on_list++;
434
352f4ff9
FW
435 ret = __res_context_querydomain
436 (ctx, name, dname, class, type,
437 answer, anslen, answerp, answerp2, nanswerp2,
438 resplen2, answerp2_malloced);
e35c53e3
SP
439 if (ret > 0 || (ret == 0 && resplen2 != NULL
440 && *resplen2 > 0))
28f540f4
RM
441 return (ret);
442
0420d888
UD
443 if (answerp && *answerp != answer) {
444 answer = *answerp;
445 anslen = MAXPACKET;
446 }
ab09bf61 447 if (answerp2 && *answerp2_malloced)
1eb946b9
UD
448 {
449 free (*answerp2);
450 *answerp2 = NULL;
e9db92d3 451 *nanswerp2 = 0;
ab09bf61 452 *answerp2_malloced = 0;
1eb946b9 453 }
0420d888 454
28f540f4
RM
455 /*
456 * If no server present, give up.
457 * If name isn't found in this domain,
458 * keep trying higher domains in the search list
459 * (if that's enabled).
460 * On a NO_DATA error, keep trying, otherwise
461 * a wildcard entry of another type could keep us
462 * from finding this entry higher in the domain.
463 * If we get some other error (negative answer or
464 * server failure), then stop searching up,
465 * but try the input name below in case it's
466 * fully-qualified.
467 */
468 if (errno == ECONNREFUSED) {
b43b13ac 469 RES_SET_H_ERRNO(statp, TRY_AGAIN);
28f540f4
RM
470 return (-1);
471 }
472
b43b13ac 473 switch (statp->res_h_errno) {
28f540f4
RM
474 case NO_DATA:
475 got_nodata++;
476 /* FALLTHROUGH */
477 case HOST_NOT_FOUND:
478 /* keep trying */
479 break;
480 case TRY_AGAIN:
481 if (hp->rcode == SERVFAIL) {
482 /* try next search element, if any */
483 got_servfail++;
484 break;
485 }
486 /* FALLTHROUGH */
487 default:
488 /* anything else implies that we're done */
489 done++;
490 }
491
492 /* if we got here for some reason other than DNSRCH,
493 * we only wanted one iteration of the loop, so stop.
494 */
b43b13ac 495 if ((statp->options & RES_DNSRCH) == 0)
28f540f4
RM
496 done++;
497 }
498 }
499
b43b13ac 500 /*
c12e9f37 501 * If the query has not already been tried as is then try it
f87dfb1f 502 * unless RES_NOTLDQUERY is set and there were no dots.
28f540f4 503 */
f87dfb1f
UD
504 if ((dots || !searched || (statp->options & RES_NOTLDQUERY) == 0)
505 && !(tried_as_is || root_on_list)) {
352f4ff9
FW
506 ret = __res_context_querydomain
507 (ctx, name, NULL, class, type,
508 answer, anslen, answerp, answerp2, nanswerp2,
509 resplen2, answerp2_malloced);
e35c53e3
SP
510 if (ret > 0 || (ret == 0 && resplen2 != NULL
511 && *resplen2 > 0))
28f540f4
RM
512 return (ret);
513 }
514
515 /* if we got here, we didn't satisfy the search.
b43b13ac 516 * if we did an initial full query, return that query's H_ERRNO
28f540f4
RM
517 * (note that we wouldn't be here if that query had succeeded).
518 * else if we ever got a nodata, send that back as the reason.
b43b13ac 519 * else send back meaningless H_ERRNO, that being the one from
28f540f4
RM
520 * the last DNSRCH we did.
521 */
ab09bf61 522 if (answerp2 && *answerp2_malloced)
1eb946b9
UD
523 {
524 free (*answerp2);
525 *answerp2 = NULL;
e9db92d3 526 *nanswerp2 = 0;
ab09bf61 527 *answerp2_malloced = 0;
1eb946b9 528 }
e685e07d
UD
529 if (saved_herrno != -1)
530 RES_SET_H_ERRNO(statp, saved_herrno);
531 else if (got_nodata)
b43b13ac 532 RES_SET_H_ERRNO(statp, NO_DATA);
28f540f4 533 else if (got_servfail)
b43b13ac 534 RES_SET_H_ERRNO(statp, TRY_AGAIN);
28f540f4
RM
535 return (-1);
536}
ea9878ec 537libc_hidden_def (__res_context_search)
352f4ff9
FW
538
539/* Common part of res_nsearch and res_search. */
540static int
541context_search_common (struct resolv_context *ctx,
542 const char *name, int class, int type,
543 unsigned char *answer, int anslen)
544{
545 if (ctx == NULL)
546 {
547 RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
548 return -1;
549 }
550 int result = __res_context_search (ctx, name, class, type, answer, anslen,
551 NULL, NULL, NULL, NULL, NULL);
552 __resolv_context_put (ctx);
553 return result;
554}
28f540f4 555
0420d888 556int
ea9878ec
FW
557___res_nsearch (res_state statp,
558 const char *name, /* Domain name. */
559 int class, int type, /* Class and type of query. */
560 unsigned char *answer, /* Buffer to put answer. */
561 int anslen) /* Size of answer. */
0420d888 562{
352f4ff9
FW
563 return context_search_common
564 (__resolv_context_get_override (statp), name, class, type, answer, anslen);
0420d888 565}
ea9878ec
FW
566versioned_symbol (libc, ___res_nsearch, res_nsearch, GLIBC_2_34);
567#if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_2, GLIBC_2_34)
568compat_symbol (libresolv, ___res_nsearch, __res_nsearch, GLIBC_2_2);
569#endif
0420d888 570
03775117 571int
ea9878ec
FW
572___res_search (const char *name, int class, int type,
573 unsigned char *answer, int anslen)
03775117 574{
352f4ff9
FW
575 return context_search_common
576 (__resolv_context_get (), name, class, type, answer, anslen);
03775117 577}
ea9878ec
FW
578versioned_symbol (libc, ___res_search, res_search, GLIBC_2_34);
579#if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
580compat_symbol (libresolv, ___res_search, res_search, GLIBC_2_0);
581#endif
582#if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_2, GLIBC_2_34)
583compat_symbol (libresolv, ___res_search, __res_search, GLIBC_2_2);
584#endif
03775117 585
352f4ff9
FW
586/* Perform a call on res_query on the concatenation of name and
587 domain. */
0420d888 588static int
352f4ff9
FW
589__res_context_querydomain (struct resolv_context *ctx,
590 const char *name, const char *domain,
591 int class, int type,
592 unsigned char *answer, int anslen,
593 unsigned char **answerp, unsigned char **answerp2,
594 int *nanswerp2, int *resplen2,
595 int *answerp2_malloced)
28f540f4 596{
352f4ff9 597 struct __res_state *statp = ctx->resp;
b43b13ac 598 char nbuf[MAXDNAME];
28f540f4 599 const char *longname = nbuf;
28b59fca 600 size_t n, d;
28f540f4 601
28f540f4 602 if (domain == NULL) {
b43b13ac 603 n = strlen(name);
8fdceb2e
JL
604
605 /* Decrement N prior to checking it against MAXDNAME
606 so that we detect a wrap to SIZE_MAX and return
607 a reasonable error. */
608 n--;
609 if (n >= MAXDNAME - 1) {
b43b13ac
UD
610 RES_SET_H_ERRNO(statp, NO_RECOVERY);
611 return (-1);
612 }
f3d945d5 613 longname = name;
b43b13ac
UD
614 } else {
615 n = strlen(name);
616 d = strlen(domain);
617 if (n + d + 1 >= MAXDNAME) {
618 RES_SET_H_ERRNO(statp, NO_RECOVERY);
619 return (-1);
620 }
eb73b878
MS
621 char *p = __stpcpy (nbuf, name);
622 *p++ = '.';
623 strcpy (p, domain);
b43b13ac 624 }
352f4ff9
FW
625 return __res_context_query (ctx, longname, class, type, answer,
626 anslen, answerp, answerp2, nanswerp2,
627 resplen2, answerp2_malloced);
628}
629
630/* Common part of res_nquerydomain and res_querydomain. */
631static int
632context_querydomain_common (struct resolv_context *ctx,
633 const char *name, const char *domain,
634 int class, int type,
635 unsigned char *answer, int anslen)
636{
637 if (ctx == NULL)
638 {
639 RES_SET_H_ERRNO (&_res, NETDB_INTERNAL);
640 return -1;
641 }
642 int result = __res_context_querydomain (ctx, name, domain, class, type,
643 answer, anslen,
644 NULL, NULL, NULL, NULL, NULL);
645 __resolv_context_put (ctx);
646 return result;
0420d888
UD
647}
648
649int
ea9878ec
FW
650___res_nquerydomain (res_state statp,
651 const char *name,
652 const char *domain,
653 int class, int type, /* Class and type of query. */
654 unsigned char *answer, /* Buffer to put answer. */
655 int anslen) /* Size of answer. */
0420d888 656{
352f4ff9
FW
657 return context_querydomain_common
658 (__resolv_context_get_override (statp),
659 name, domain, class, type, answer, anslen);
28f540f4 660}
ea9878ec
FW
661versioned_symbol (libc, ___res_nquerydomain, res_nquerydomain, GLIBC_2_34);
662#if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_2, GLIBC_2_34)
663compat_symbol (libresolv, ___res_nquerydomain, __res_nquerydomain, GLIBC_2_2);
664#endif
28f540f4 665
03775117 666int
ea9878ec
FW
667___res_querydomain (const char *name, const char *domain, int class, int type,
668 unsigned char *answer, int anslen)
03775117 669{
352f4ff9
FW
670 return context_querydomain_common
671 (__resolv_context_get (), name, domain, class, type, answer, anslen);
03775117 672}
ea9878ec
FW
673versioned_symbol (libc, ___res_querydomain, res_querydomain, GLIBC_2_34);
674#if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
675compat_symbol (libresolv, ___res_querydomain, res_querydomain, GLIBC_2_0);
676#endif
677#if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_2, GLIBC_2_34)
678compat_symbol (libresolv, ___res_querydomain, __res_querydomain, GLIBC_2_2);
03775117 679#endif