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

source code of glibc/resolv/res_query.c