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

source code of glibc/resolv/res_query.c