Fix some errors in declarations in the manual.
[glibc.git] / resolv / res_query.c
blob1325f9772ddcffc9aaa1b3a81a73fbce161e9b3c
1 /*
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
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.
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.
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
47 * SOFTWARE.
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
64 * SOFTWARE.
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 */
72 #include <assert.h>
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>
78 #include <ctype.h>
79 #include <errno.h>
80 #include <netdb.h>
81 #include <resolv.h>
82 #include <stdio.h>
83 #include <stdlib.h>
84 #include <string.h>
86 /* Options. Leave them on. */
87 /* #undef DEBUG */
89 #if PACKETSZ > 65536
90 #define MAXPACKET PACKETSZ
91 #else
92 #define MAXPACKET 65536
93 #endif
95 #define QUERYSIZE (HFIXEDSZ + QFIXEDSZ + MAXCDNAME + 1)
97 static int
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);
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 */
120 u_char **answerp2,
121 int *nanswerp2,
122 int *resplen2)
124 HEADER *hp = (HEADER *) answer;
125 HEADER *hp2;
126 int n, use_malloc = 0;
127 u_int oflags = statp->_flags;
129 size_t bufsize = (type == T_UNSPEC ? 2 : 1) * QUERYSIZE;
130 u_char *buf = alloca (bufsize);
131 u_char *query1 = buf;
132 int nquery1 = -1;
133 u_char *query2 = NULL;
134 int nquery2 = 0;
136 again:
137 hp->rcode = NOERROR; /* default */
139 #ifdef DEBUG
140 if (statp->options & RES_DEBUG)
141 printf(";; res_query(%s, %d, %d)\n", name, class, type);
142 #endif
144 if (type == T_UNSPEC)
146 n = res_nmkquery(statp, QUERY, name, class, T_A, NULL, 0, NULL,
147 query1, bufsize);
148 if (n > 0)
150 if ((oflags & RES_F_EDNS0ERR) == 0
151 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
153 n = __res_nopt(statp, n, query1, bufsize, anslen / 2);
154 if (n < 0)
155 goto unspec_nomem;
158 nquery1 = n;
159 /* Align the buffer. */
160 int npad = ((nquery1 + __alignof__ (HEADER) - 1)
161 & ~(__alignof__ (HEADER) - 1)) - nquery1;
162 if (n > bufsize - npad)
164 n = -1;
165 goto unspec_nomem;
167 int nused = n + npad;
168 query2 = buf + nused;
169 n = res_nmkquery(statp, QUERY, name, class, T_AAAA, NULL, 0,
170 NULL, query2, bufsize - nused);
171 if (n > 0
172 && (oflags & RES_F_EDNS0ERR) == 0
173 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
174 n = __res_nopt(statp, n, query2, bufsize - nused - n,
175 anslen / 2);
176 nquery2 = n;
179 unspec_nomem:;
181 else
183 n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
184 query1, bufsize);
186 if (n > 0
187 && (oflags & RES_F_EDNS0ERR) == 0
188 && (statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0)
189 n = __res_nopt(statp, n, query1, bufsize, anslen);
191 nquery1 = n;
194 if (__builtin_expect (n <= 0, 0) && !use_malloc) {
195 /* Retry just in case res_nmkquery failed because of too
196 short buffer. Shouldn't happen. */
197 bufsize = (type == T_UNSPEC ? 2 : 1) * MAXPACKET;
198 buf = malloc (bufsize);
199 if (buf != NULL) {
200 query1 = buf;
201 use_malloc = 1;
202 goto again;
205 if (__builtin_expect (n <= 0, 0)) {
206 /* If the query choked with EDNS0, retry without EDNS0. */
207 if ((statp->options & (RES_USE_EDNS0|RES_USE_DNSSEC)) != 0
208 && ((oflags ^ statp->_flags) & RES_F_EDNS0ERR) != 0) {
209 statp->_flags |= RES_F_EDNS0ERR;
210 #ifdef DEBUG
211 if (statp->options & RES_DEBUG)
212 printf(";; res_nquery: retry without EDNS0\n");
213 #endif
214 goto again;
216 #ifdef DEBUG
217 if (statp->options & RES_DEBUG)
218 printf(";; res_query: mkquery failed\n");
219 #endif
220 RES_SET_H_ERRNO(statp, NO_RECOVERY);
221 if (use_malloc)
222 free (buf);
223 return (n);
225 assert (answerp == NULL || (void *) *answerp == (void *) answer);
226 n = __libc_res_nsend(statp, query1, nquery1, query2, nquery2, answer,
227 anslen, answerp, answerp2, nanswerp2, resplen2);
228 if (use_malloc)
229 free (buf);
230 if (n < 0) {
231 #ifdef DEBUG
232 if (statp->options & RES_DEBUG)
233 printf(";; res_query: send error\n");
234 #endif
235 RES_SET_H_ERRNO(statp, TRY_AGAIN);
236 return (n);
239 if (answerp != NULL)
240 /* __libc_res_nsend might have reallocated the buffer. */
241 hp = (HEADER *) *answerp;
243 /* We simplify the following tests by assigning HP to HP2 or
244 vice versa. It is easy to verify that this is the same as
245 ignoring all tests of HP or HP2. */
246 if (answerp2 == NULL || *resplen2 < (int) sizeof (HEADER))
248 hp2 = hp;
250 else
252 hp2 = (HEADER *) *answerp2;
253 if (n < (int) sizeof (HEADER))
255 hp = hp2;
259 /* Make sure both hp and hp2 are defined */
260 assert((hp != NULL) && (hp2 != NULL));
262 if ((hp->rcode != NOERROR || ntohs(hp->ancount) == 0)
263 && (hp2->rcode != NOERROR || ntohs(hp2->ancount) == 0)) {
264 #ifdef DEBUG
265 if (statp->options & RES_DEBUG) {
266 printf(";; rcode = %d, ancount=%d\n", hp->rcode,
267 ntohs(hp->ancount));
268 if (hp != hp2)
269 printf(";; rcode2 = %d, ancount2=%d\n", hp2->rcode,
270 ntohs(hp2->ancount));
272 #endif
273 switch (hp->rcode == NOERROR ? hp2->rcode : hp->rcode) {
274 case NXDOMAIN:
275 if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
276 || (hp2->rcode == NOERROR
277 && ntohs (hp2->ancount) != 0))
278 goto success;
279 RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
280 break;
281 case SERVFAIL:
282 RES_SET_H_ERRNO(statp, TRY_AGAIN);
283 break;
284 case NOERROR:
285 if (ntohs (hp->ancount) != 0
286 || ntohs (hp2->ancount) != 0)
287 goto success;
288 RES_SET_H_ERRNO(statp, NO_DATA);
289 break;
290 case FORMERR:
291 case NOTIMP:
292 /* Servers must not reply to AAAA queries with
293 NOTIMP etc but some of them do. */
294 if ((hp->rcode == NOERROR && ntohs (hp->ancount) != 0)
295 || (hp2->rcode == NOERROR
296 && ntohs (hp2->ancount) != 0))
297 goto success;
298 /* FALLTHROUGH */
299 case REFUSED:
300 default:
301 RES_SET_H_ERRNO(statp, NO_RECOVERY);
302 break;
304 return (-1);
306 success:
307 return (n);
309 libresolv_hidden_def (__libc_res_nquery)
312 res_nquery(res_state statp,
313 const char *name, /* domain name */
314 int class, int type, /* class and type of query */
315 u_char *answer, /* buffer to put answer */
316 int anslen) /* size of answer buffer */
318 return __libc_res_nquery(statp, name, class, type, answer, anslen,
319 NULL, NULL, NULL, NULL);
321 libresolv_hidden_def (res_nquery)
324 * Formulate a normal query, send, and retrieve answer in supplied buffer.
325 * Return the size of the response on success, -1 on error.
326 * If enabled, implement search rules until answer or unrecoverable failure
327 * is detected. Error code, if any, is left in H_ERRNO.
330 __libc_res_nsearch(res_state statp,
331 const char *name, /* domain name */
332 int class, int type, /* class and type of query */
333 u_char *answer, /* buffer to put answer */
334 int anslen, /* size of answer */
335 u_char **answerp,
336 u_char **answerp2,
337 int *nanswerp2,
338 int *resplen2)
340 const char *cp, * const *domain;
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;
349 __set_errno (0);
350 RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /* True if we never query. */
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++;
359 /* If there aren't any dots, it could be a user-level alias. */
360 if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
361 return (__libc_res_nquery(statp, cp, class, type, answer,
362 anslen, answerp, answerp2,
363 nanswerp2, resplen2));
365 #ifdef DEBUG
366 if (statp->options & RES_DEBUG)
367 printf("dots=%d, statp->ndots=%d, trailing_dot=%d, name=%s\n",
368 (int)dots,(int)statp->ndots,(int)trailing_dot,name);
369 #endif
372 * If there are enough dots in the name, let's just give it a
373 * try 'as is'. The threshold can be set with the "ndots" option.
374 * Also, query 'as is', if there is a trailing dot in the name.
376 saved_herrno = -1;
377 if (dots >= statp->ndots || trailing_dot) {
378 ret = __libc_res_nquerydomain(statp, name, NULL, class, type,
379 answer, anslen, answerp,
380 answerp2, nanswerp2, resplen2);
381 if (ret > 0 || trailing_dot)
382 return (ret);
383 saved_herrno = h_errno;
384 tried_as_is++;
385 if (answerp && *answerp != answer) {
386 answer = *answerp;
387 anslen = MAXPACKET;
389 if (answerp2
390 && (*answerp2 < answer || *answerp2 >= answer + anslen))
392 free (*answerp2);
393 *answerp2 = NULL;
398 * We do at least one level of search if
399 * - there is no dot and RES_DEFNAME is set, or
400 * - there is at least one dot, there is no trailing dot,
401 * and RES_DNSRCH is set.
403 if ((!dots && (statp->options & RES_DEFNAMES) != 0) ||
404 (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
405 int done = 0;
407 for (domain = (const char * const *)statp->dnsrch;
408 *domain && !done;
409 domain++) {
410 searched = 1;
412 if (domain[0][0] == '\0' ||
413 (domain[0][0] == '.' && domain[0][1] == '\0'))
414 root_on_list++;
416 ret = __libc_res_nquerydomain(statp, name, *domain,
417 class, type,
418 answer, anslen, answerp,
419 answerp2, nanswerp2,
420 resplen2);
421 if (ret > 0)
422 return (ret);
424 if (answerp && *answerp != answer) {
425 answer = *answerp;
426 anslen = MAXPACKET;
428 if (answerp2
429 && (*answerp2 < answer
430 || *answerp2 >= answer + anslen))
432 free (*answerp2);
433 *answerp2 = NULL;
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
447 * fully-qualified.
449 if (errno == ECONNREFUSED) {
450 RES_SET_H_ERRNO(statp, TRY_AGAIN);
451 return (-1);
454 switch (statp->res_h_errno) {
455 case NO_DATA:
456 got_nodata++;
457 /* FALLTHROUGH */
458 case HOST_NOT_FOUND:
459 /* keep trying */
460 break;
461 case TRY_AGAIN:
462 if (hp->rcode == SERVFAIL) {
463 /* try next search element, if any */
464 got_servfail++;
465 break;
467 /* FALLTHROUGH */
468 default:
469 /* anything else implies that we're done */
470 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)
477 done++;
482 * f 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 = __libc_res_nquerydomain(statp, name, NULL, class, type,
488 answer, anslen, answerp,
489 answerp2, nanswerp2, resplen2);
490 if (ret > 0)
491 return (ret);
494 /* if we got here, we didn't satisfy the search.
495 * if we did an initial full query, return that query's H_ERRNO
496 * (note that we wouldn't be here if that query had succeeded).
497 * else if we ever got a nodata, send that back as the reason.
498 * else send back meaningless H_ERRNO, that being the one from
499 * the last DNSRCH we did.
501 if (answerp2 && (*answerp2 < answer || *answerp2 >= answer + anslen))
503 free (*answerp2);
504 *answerp2 = NULL;
506 if (saved_herrno != -1)
507 RES_SET_H_ERRNO(statp, saved_herrno);
508 else if (got_nodata)
509 RES_SET_H_ERRNO(statp, NO_DATA);
510 else if (got_servfail)
511 RES_SET_H_ERRNO(statp, TRY_AGAIN);
512 return (-1);
514 libresolv_hidden_def (__libc_res_nsearch)
517 res_nsearch(res_state statp,
518 const char *name, /* domain name */
519 int class, int type, /* class and type of query */
520 u_char *answer, /* buffer to put answer */
521 int anslen) /* size of answer */
523 return __libc_res_nsearch(statp, name, class, type, answer,
524 anslen, NULL, NULL, NULL, NULL);
526 libresolv_hidden_def (res_nsearch)
529 * Perform a call on res_query on the concatenation of name and domain,
530 * removing a trailing dot from name if domain is NULL.
532 static int
533 __libc_res_nquerydomain(res_state statp,
534 const char *name,
535 const char *domain,
536 int class, int type, /* class and type of query */
537 u_char *answer, /* buffer to put answer */
538 int anslen, /* size of answer */
539 u_char **answerp,
540 u_char **answerp2,
541 int *nanswerp2,
542 int *resplen2)
544 char nbuf[MAXDNAME];
545 const char *longname = nbuf;
546 size_t n, d;
548 #ifdef DEBUG
549 if (statp->options & RES_DEBUG)
550 printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
551 name, domain?domain:"<Nil>", class, type);
552 #endif
553 if (domain == NULL) {
555 * Check for trailing '.';
556 * copy without '.' if present.
558 n = strlen(name);
560 /* Decrement N prior to checking it against MAXDNAME
561 so that we detect a wrap to SIZE_MAX and return
562 a reasonable error. */
563 n--;
564 if (n >= MAXDNAME - 1) {
565 RES_SET_H_ERRNO(statp, NO_RECOVERY);
566 return (-1);
568 if (name[n] == '.') {
569 strncpy(nbuf, name, n);
570 nbuf[n] = '\0';
571 } else
572 longname = name;
573 } else {
574 n = strlen(name);
575 d = strlen(domain);
576 if (n + d + 1 >= MAXDNAME) {
577 RES_SET_H_ERRNO(statp, NO_RECOVERY);
578 return (-1);
580 sprintf(nbuf, "%s.%s", name, domain);
582 return (__libc_res_nquery(statp, longname, class, type, answer,
583 anslen, answerp, answerp2, nanswerp2,
584 resplen2));
588 res_nquerydomain(res_state statp,
589 const char *name,
590 const char *domain,
591 int class, int type, /* class and type of query */
592 u_char *answer, /* buffer to put answer */
593 int anslen) /* size of answer */
595 return __libc_res_nquerydomain(statp, name, domain, class, type,
596 answer, anslen, NULL, NULL, NULL, NULL);
598 libresolv_hidden_def (res_nquerydomain)
600 const char *
601 res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
602 char *file, *cp1, *cp2;
603 char buf[BUFSIZ];
604 FILE *fp;
606 if (statp->options & RES_NOALIASES)
607 return (NULL);
608 file = getenv("HOSTALIASES");
609 if (file == NULL || (fp = fopen(file, "rce")) == NULL)
610 return (NULL);
611 setbuf(fp, NULL);
612 buf[sizeof(buf) - 1] = '\0';
613 while (fgets(buf, sizeof(buf), fp)) {
614 for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1)
616 if (!*cp1)
617 break;
618 *cp1 = '\0';
619 if (ns_samename(buf, name) == 1) {
620 while (isspace(*++cp1))
622 if (!*cp1)
623 break;
624 for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2)
626 *cp2 = '\0';
627 strncpy(dst, cp1, siz - 1);
628 dst[siz - 1] = '\0';
629 fclose(fp);
630 return (dst);
633 fclose(fp);
634 return (NULL);
636 libresolv_hidden_def (res_hostalias)