]> git.ipfire.org Git - thirdparty/glibc.git/blame - resolv/res_query.c
Update.
[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.
df21c858 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.
df21c858 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.
df21c858 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.
df21c858 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
67#if defined(LIBC_SCCS) && !defined(lint)
b43b13ac
UD
68static const char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93";
69static const char rcsid[] = "$Id$";
28f540f4
RM
70#endif /* LIBC_SCCS and not lint */
71
df21c858 72#include <sys/types.h>
28f540f4
RM
73#include <sys/param.h>
74#include <netinet/in.h>
75#include <arpa/inet.h>
76#include <arpa/nameser.h>
28f540f4
RM
77#include <ctype.h>
78#include <errno.h>
b43b13ac
UD
79#include <netdb.h>
80#include <resolv.h>
81#include <stdio.h>
82#include <stdlib.h>
83#include <string.h>
28f540f4 84
b43b13ac
UD
85/* Options. Leave them on. */
86/* #undef DEBUG */
28f540f4
RM
87
88#if PACKETSZ > 1024
89#define MAXPACKET PACKETSZ
90#else
91#define MAXPACKET 1024
92#endif
93
28f540f4
RM
94/*
95 * Formulate a normal query, send, and await answer.
96 * Returned answer is placed in supplied buffer "answer".
97 * Perform preliminary check of answer, returning success only
98 * if no error is indicated and the answer count is nonzero.
99 * Return the size of the response on success, -1 on error.
b43b13ac 100 * Error number is left in H_ERRNO.
28f540f4
RM
101 *
102 * Caller must parse answer and determine whether it answers the question.
103 */
104int
b43b13ac
UD
105res_nquery(res_state statp,
106 const char *name, /* domain name */
107 int class, int type, /* class and type of query */
108 u_char *answer, /* buffer to put answer */
109 int anslen) /* size of answer buffer */
28f540f4
RM
110{
111 u_char buf[MAXPACKET];
b43b13ac 112 HEADER *hp = (HEADER *) answer;
28f540f4
RM
113 int n;
114
115 hp->rcode = NOERROR; /* default */
116
28f540f4 117#ifdef DEBUG
b43b13ac 118 if (statp->options & RES_DEBUG)
28f540f4
RM
119 printf(";; res_query(%s, %d, %d)\n", name, class, type);
120#endif
121
b43b13ac
UD
122 n = res_nmkquery(statp, QUERY, name, class, type, NULL, 0, NULL,
123 buf, sizeof(buf));
28f540f4
RM
124 if (n <= 0) {
125#ifdef DEBUG
b43b13ac 126 if (statp->options & RES_DEBUG)
28f540f4
RM
127 printf(";; res_query: mkquery failed\n");
128#endif
b43b13ac 129 RES_SET_H_ERRNO(statp, NO_RECOVERY);
28f540f4
RM
130 return (n);
131 }
b43b13ac 132 n = res_nsend(statp, buf, n, answer, anslen);
28f540f4
RM
133 if (n < 0) {
134#ifdef DEBUG
b43b13ac 135 if (statp->options & RES_DEBUG)
28f540f4
RM
136 printf(";; res_query: send error\n");
137#endif
b43b13ac 138 RES_SET_H_ERRNO(statp, TRY_AGAIN);
28f540f4
RM
139 return (n);
140 }
141
142 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
143#ifdef DEBUG
b43b13ac 144 if (statp->options & RES_DEBUG)
28f540f4
RM
145 printf(";; rcode = %d, ancount=%d\n", hp->rcode,
146 ntohs(hp->ancount));
147#endif
148 switch (hp->rcode) {
149 case NXDOMAIN:
b43b13ac 150 RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
28f540f4
RM
151 break;
152 case SERVFAIL:
b43b13ac 153 RES_SET_H_ERRNO(statp, TRY_AGAIN);
28f540f4
RM
154 break;
155 case NOERROR:
b43b13ac 156 RES_SET_H_ERRNO(statp, NO_DATA);
28f540f4
RM
157 break;
158 case FORMERR:
159 case NOTIMP:
160 case REFUSED:
161 default:
b43b13ac 162 RES_SET_H_ERRNO(statp, NO_RECOVERY);
28f540f4
RM
163 break;
164 }
165 return (-1);
166 }
167 return (n);
168}
169
170/*
171 * Formulate a normal query, send, and retrieve answer in supplied buffer.
172 * Return the size of the response on success, -1 on error.
173 * If enabled, implement search rules until answer or unrecoverable failure
b43b13ac 174 * is detected. Error code, if any, is left in H_ERRNO.
28f540f4
RM
175 */
176int
b43b13ac
UD
177res_nsearch(res_state statp,
178 const char *name, /* domain name */
179 int class, int type, /* class and type of query */
180 u_char *answer, /* buffer to put answer */
181 int anslen) /* size of answer */
28f540f4 182{
b43b13ac 183 const char *cp, * const *domain;
28f540f4 184 HEADER *hp = (HEADER *) answer;
b43b13ac 185 char tmp[NS_MAXDNAME];
28f540f4 186 u_int dots;
b43b13ac
UD
187 int trailing_dot, ret;
188 int got_nodata = 0, got_servfail = 0, root_on_list = 0;
28f540f4 189
c4029823 190 __set_errno (0);
b43b13ac
UD
191 RES_SET_H_ERRNO(statp, HOST_NOT_FOUND); /* True if we never query. */
192
28f540f4 193 dots = 0;
b43b13ac 194 for (cp = name; *cp != '\0'; cp++)
28f540f4
RM
195 dots += (*cp == '.');
196 trailing_dot = 0;
197 if (cp > name && *--cp == '.')
198 trailing_dot++;
199
b43b13ac
UD
200 /* If there aren't any dots, it could be a user-level alias. */
201 if (!dots && (cp = res_hostalias(statp, name, tmp, sizeof tmp))!= NULL)
202 return (res_nquery(statp, cp, class, type, answer, anslen));
28f540f4
RM
203
204 /*
b43b13ac
UD
205 * If there are enough dots in the name, do no searching.
206 * (The threshold can be set with the "ndots" option.)
28f540f4 207 */
b43b13ac
UD
208 if (dots >= statp->ndots || trailing_dot)
209 return (res_nquerydomain(statp, name, NULL, class, type,
210 answer, anslen));
28f540f4
RM
211
212 /*
213 * We do at least one level of search if
214 * - there is no dot and RES_DEFNAME is set, or
215 * - there is at least one dot, there is no trailing dot,
216 * and RES_DNSRCH is set.
217 */
b43b13ac
UD
218 if ((!dots && (statp->options & RES_DEFNAMES) != 0) ||
219 (dots && !trailing_dot && (statp->options & RES_DNSRCH) != 0)) {
28f540f4
RM
220 int done = 0;
221
b43b13ac 222 for (domain = (const char * const *)statp->dnsrch;
28f540f4
RM
223 *domain && !done;
224 domain++) {
225
b43b13ac
UD
226 if (domain[0][0] == '\0' ||
227 (domain[0][0] == '.' && domain[0][1] == '\0'))
228 root_on_list++;
229
230 ret = res_nquerydomain(statp, name, *domain,
231 class, type,
232 answer, anslen);
28f540f4
RM
233 if (ret > 0)
234 return (ret);
235
236 /*
237 * If no server present, give up.
238 * If name isn't found in this domain,
239 * keep trying higher domains in the search list
240 * (if that's enabled).
241 * On a NO_DATA error, keep trying, otherwise
242 * a wildcard entry of another type could keep us
243 * from finding this entry higher in the domain.
244 * If we get some other error (negative answer or
245 * server failure), then stop searching up,
246 * but try the input name below in case it's
247 * fully-qualified.
248 */
249 if (errno == ECONNREFUSED) {
b43b13ac 250 RES_SET_H_ERRNO(statp, TRY_AGAIN);
28f540f4
RM
251 return (-1);
252 }
253
b43b13ac 254 switch (statp->res_h_errno) {
28f540f4
RM
255 case NO_DATA:
256 got_nodata++;
257 /* FALLTHROUGH */
258 case HOST_NOT_FOUND:
259 /* keep trying */
260 break;
261 case TRY_AGAIN:
262 if (hp->rcode == SERVFAIL) {
263 /* try next search element, if any */
264 got_servfail++;
265 break;
266 }
267 /* FALLTHROUGH */
268 default:
269 /* anything else implies that we're done */
270 done++;
271 }
272
273 /* if we got here for some reason other than DNSRCH,
274 * we only wanted one iteration of the loop, so stop.
275 */
b43b13ac 276 if ((statp->options & RES_DNSRCH) == 0)
28f540f4
RM
277 done++;
278 }
279 }
280
b43b13ac
UD
281 /*
282 * If the name has any dots at all, and "." is not on the search
283 * list, then try an as-is query now.
28f540f4 284 */
b43b13ac
UD
285 if (statp->ndots) {
286 ret = res_nquerydomain(statp, name, NULL, class, type,
287 answer, anslen);
28f540f4
RM
288 if (ret > 0)
289 return (ret);
290 }
291
292 /* if we got here, we didn't satisfy the search.
b43b13ac 293 * if we did an initial full query, return that query's H_ERRNO
28f540f4
RM
294 * (note that we wouldn't be here if that query had succeeded).
295 * else if we ever got a nodata, send that back as the reason.
b43b13ac 296 * else send back meaningless H_ERRNO, that being the one from
28f540f4
RM
297 * the last DNSRCH we did.
298 */
b43b13ac
UD
299 if (got_nodata)
300 RES_SET_H_ERRNO(statp, NO_DATA);
28f540f4 301 else if (got_servfail)
b43b13ac 302 RES_SET_H_ERRNO(statp, TRY_AGAIN);
28f540f4
RM
303 return (-1);
304}
305
306/*
307 * Perform a call on res_query on the concatenation of name and domain,
308 * removing a trailing dot from name if domain is NULL.
309 */
310int
b43b13ac
UD
311res_nquerydomain(res_state statp,
312 const char *name,
313 const char *domain,
314 int class, int type, /* class and type of query */
315 u_char *answer, /* buffer to put answer */
316 int anslen) /* size of answer */
28f540f4 317{
b43b13ac 318 char nbuf[MAXDNAME];
28f540f4 319 const char *longname = nbuf;
b43b13ac 320 int n, d;
28f540f4
RM
321
322#ifdef DEBUG
b43b13ac
UD
323 if (statp->options & RES_DEBUG)
324 printf(";; res_nquerydomain(%s, %s, %d, %d)\n",
28f540f4
RM
325 name, domain?domain:"<Nil>", class, type);
326#endif
327 if (domain == NULL) {
328 /*
329 * Check for trailing '.';
330 * copy without '.' if present.
331 */
b43b13ac
UD
332 n = strlen(name);
333 if (n >= MAXDNAME) {
334 RES_SET_H_ERRNO(statp, NO_RECOVERY);
335 return (-1);
336 }
337 n--;
338 if (n >= 0 && name[n] == '.') {
339 strncpy(nbuf, name, n);
28f540f4
RM
340 nbuf[n] = '\0';
341 } else
342 longname = name;
b43b13ac
UD
343 } else {
344 n = strlen(name);
345 d = strlen(domain);
346 if (n + d + 1 >= MAXDNAME) {
347 RES_SET_H_ERRNO(statp, NO_RECOVERY);
348 return (-1);
349 }
350 sprintf(nbuf, "%s.%s", name, domain);
351 }
352 return (res_nquery(statp, longname, class, type, answer, anslen));
28f540f4
RM
353}
354
845dcb57 355const char *
b43b13ac
UD
356res_hostalias(const res_state statp, const char *name, char *dst, size_t siz) {
357 char *file, *cp1, *cp2;
28f540f4 358 char buf[BUFSIZ];
b43b13ac 359 FILE *fp;
28f540f4 360
b43b13ac 361 if (statp->options & RES_NOALIASES)
3d61b63c 362 return (NULL);
d68171ed 363 file = __secure_getenv("HOSTALIASES");
28f540f4
RM
364 if (file == NULL || (fp = fopen(file, "r")) == NULL)
365 return (NULL);
3d61b63c 366 setbuf(fp, NULL);
28f540f4
RM
367 buf[sizeof(buf) - 1] = '\0';
368 while (fgets(buf, sizeof(buf), fp)) {
369 for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1)
370 ;
371 if (!*cp1)
372 break;
373 *cp1 = '\0';
b43b13ac 374 if (ns_samename(buf, name) == 1) {
28f540f4
RM
375 while (isspace(*++cp1))
376 ;
377 if (!*cp1)
378 break;
379 for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2)
380 ;
b43b13ac
UD
381 *cp2 = '\0';
382 strncpy(dst, cp1, siz - 1);
383 dst[siz - 1] = '\0';
28f540f4 384 fclose(fp);
b43b13ac 385 return (dst);
28f540f4
RM
386 }
387 }
388 fclose(fp);
389 return (NULL);
390}