summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/res_query.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/net/res_query.c')
-rw-r--r--src/lib/libc/net/res_query.c225
1 files changed, 133 insertions, 92 deletions
diff --git a/src/lib/libc/net/res_query.c b/src/lib/libc/net/res_query.c
index 7649462e56..3cdb7a7477 100644
--- a/src/lib/libc/net/res_query.c
+++ b/src/lib/libc/net/res_query.c
@@ -1,9 +1,11 @@
1/* $NetBSD: res_query.c,v 1.9 1995/02/25 06:58:58 cgd Exp $ */ 1/* $OpenBSD: res_query.c,v 1.21 2003/06/02 20:18:36 millert Exp $ */
2 2
3/*- 3/*
4 * ++Copyright++ 1988, 1993
5 * -
4 * Copyright (c) 1988, 1993 6 * Copyright (c) 1988, 1993
5 * The Regents of the University of California. All rights reserved. 7 * The Regents of the University of California. All rights reserved.
6 * 8 *
7 * Redistribution and use in source and binary forms, with or without 9 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 10 * modification, are permitted provided that the following conditions
9 * are met: 11 * are met:
@@ -12,14 +14,10 @@
12 * 2. Redistributions in binary form must reproduce the above copyright 14 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the 15 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution. 16 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software 17 * 3. Neither the name of the University nor the names of its contributors
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software 18 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission. 19 * without specific prior written permission.
22 * 20 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -56,23 +54,28 @@
56#if defined(LIBC_SCCS) && !defined(lint) 54#if defined(LIBC_SCCS) && !defined(lint)
57#if 0 55#if 0
58static char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93"; 56static char sccsid[] = "@(#)res_query.c 8.1 (Berkeley) 6/4/93";
59static char rcsid[] = "$Id: res_query.c,v 1.1 1993/06/01 09:42:14 vixie Exp vixie "; 57static char rcsid[] = "$From: res_query.c,v 8.9 1996/09/22 00:13:28 vixie Exp $";
60#else 58#else
61static char rcsid[] = "$NetBSD: res_query.c,v 1.9 1995/02/25 06:58:58 cgd Exp $"; 59static char rcsid[] = "$OpenBSD: res_query.c,v 1.21 2003/06/02 20:18:36 millert Exp $";
62#endif 60#endif
63#endif /* LIBC_SCCS and not lint */ 61#endif /* LIBC_SCCS and not lint */
64 62
63#include <sys/types.h>
65#include <sys/param.h> 64#include <sys/param.h>
66#include <netinet/in.h> 65#include <netinet/in.h>
67#include <arpa/inet.h> 66#include <arpa/inet.h>
68#include <arpa/nameser.h> 67#include <arpa/nameser.h>
68
69#include <stdio.h>
69#include <netdb.h> 70#include <netdb.h>
70#include <resolv.h> 71#include <resolv.h>
71#include <stdio.h>
72#include <ctype.h> 72#include <ctype.h>
73#include <errno.h> 73#include <errno.h>
74#include <stdlib.h> 74#include <stdlib.h>
75#include <string.h> 75#include <string.h>
76#include <unistd.h>
77
78#include "thread_private.h"
76 79
77#if PACKETSZ > 1024 80#if PACKETSZ > 1024
78#define MAXPACKET PACKETSZ 81#define MAXPACKET PACKETSZ
@@ -80,8 +83,9 @@ static char rcsid[] = "$NetBSD: res_query.c,v 1.9 1995/02/25 06:58:58 cgd Exp $"
80#define MAXPACKET 1024 83#define MAXPACKET 1024
81#endif 84#endif
82 85
83char *__hostalias __P((const char *)); 86const char *hostalias(const char *);
84int h_errno; 87int h_errno;
88extern int res_opt(int, u_char *, int, int);
85 89
86/* 90/*
87 * Formulate a normal query, send, and await answer. 91 * Formulate a normal query, send, and await answer.
@@ -90,68 +94,79 @@ int h_errno;
90 * if no error is indicated and the answer count is nonzero. 94 * if no error is indicated and the answer count is nonzero.
91 * Return the size of the response on success, -1 on error. 95 * Return the size of the response on success, -1 on error.
92 * Error number is left in h_errno. 96 * Error number is left in h_errno.
97 *
93 * Caller must parse answer and determine whether it answers the question. 98 * Caller must parse answer and determine whether it answers the question.
94 */ 99 */
100int
95res_query(name, class, type, answer, anslen) 101res_query(name, class, type, answer, anslen)
96 char *name; /* domain name */ 102 const char *name; /* domain name */
97 int class, type; /* class and type of query */ 103 int class, type; /* class and type of query */
98 u_char *answer; /* buffer to put answer */ 104 u_char *answer; /* buffer to put answer */
99 int anslen; /* size of answer buffer */ 105 int anslen; /* size of answer buffer */
100{ 106{
101 char buf[MAXPACKET]; 107 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
102 HEADER *hp; 108 u_char buf[MAXPACKET];
109 register HEADER *hp = (HEADER *) answer;
103 int n; 110 int n;
104 111
105 if ((_res.options & RES_INIT) == 0 && res_init() == -1) 112 hp->rcode = NOERROR; /* default */
113
114 if ((_resp->options & RES_INIT) == 0 && res_init() == -1) {
115 h_errno = NETDB_INTERNAL;
106 return (-1); 116 return (-1);
117 }
107#ifdef DEBUG 118#ifdef DEBUG
108 if (_res.options & RES_DEBUG) 119 if (_resp->options & RES_DEBUG)
109 printf(";; res_query(%s, %d, %d)\n", name, class, type); 120 printf(";; res_query(%s, %d, %d)\n", name, class, type);
110#endif 121#endif
111 n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL, 122
112 buf, sizeof(buf)); 123 n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
124 buf, sizeof(buf));
125 if (n > 0 && ((_resp->options & RES_USE_EDNS0) ||
126 (_resp->options & RES_USE_DNSSEC))) {
127 n = res_opt(n, buf, sizeof(buf), anslen);
128 }
113 129
114 if (n <= 0) { 130 if (n <= 0) {
115#ifdef DEBUG 131#ifdef DEBUG
116 if (_res.options & RES_DEBUG) 132 if (_resp->options & RES_DEBUG)
117 printf(";; res_query: mkquery failed\n"); 133 printf(";; res_query: mkquery failed\n");
118#endif 134#endif
119 h_errno = NO_RECOVERY; 135 h_errno = NO_RECOVERY;
120 return (n); 136 return (n);
121 } 137 }
122 n = res_send(buf, n, (char *)answer, anslen); 138 n = res_send(buf, n, answer, anslen);
123 if (n < 0) { 139 if (n < 0) {
124#ifdef DEBUG 140#ifdef DEBUG
125 if (_res.options & RES_DEBUG) 141 if (_resp->options & RES_DEBUG)
126 printf(";; res_query: send error\n"); 142 printf(";; res_query: send error\n");
127#endif 143#endif
128 h_errno = TRY_AGAIN; 144 h_errno = TRY_AGAIN;
129 return (n); 145 return (n);
130 } 146 }
131 147
132 hp = (HEADER *) answer;
133 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 148 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
134#ifdef DEBUG 149#ifdef DEBUG
135 if (_res.options & RES_DEBUG) 150 if (_resp->options & RES_DEBUG)
136 printf(";; rcode = %d, ancount=%d\n", hp->rcode, 151 printf(";; rcode = %u, ancount=%u\n", hp->rcode,
137 ntohs(hp->ancount)); 152 ntohs(hp->ancount));
138#endif 153#endif
139 switch (hp->rcode) { 154 switch (hp->rcode) {
140 case NXDOMAIN: 155 case NXDOMAIN:
141 h_errno = HOST_NOT_FOUND; 156 h_errno = HOST_NOT_FOUND;
142 break; 157 break;
143 case SERVFAIL: 158 case SERVFAIL:
144 h_errno = TRY_AGAIN; 159 h_errno = TRY_AGAIN;
145 break; 160 break;
146 case NOERROR: 161 case NOERROR:
147 h_errno = NO_DATA; 162 h_errno = NO_DATA;
148 break; 163 break;
149 case FORMERR: 164 case FORMERR:
150 case NOTIMP: 165 case NOTIMP:
151 case REFUSED: 166 case REFUSED:
152 default: 167 default:
153 h_errno = NO_RECOVERY; 168 h_errno = NO_RECOVERY;
154 break; 169 break;
155 } 170 }
156 return (-1); 171 return (-1);
157 } 172 }
@@ -162,9 +177,7 @@ res_query(name, class, type, answer, anslen)
162 * Formulate a normal query, send, and retrieve answer in supplied buffer. 177 * Formulate a normal query, send, and retrieve answer in supplied buffer.
163 * Return the size of the response on success, -1 on error. 178 * Return the size of the response on success, -1 on error.
164 * If enabled, implement search rules until answer or unrecoverable failure 179 * If enabled, implement search rules until answer or unrecoverable failure
165 * is detected. Error number is left in h_errno. 180 * is detected. Error code, if any, is left in h_errno.
166 * Only useful for queries in the same name hierarchy as the local host
167 * (not, for example, for host address-to-name lookups in domain in-addr.arpa).
168 */ 181 */
169int 182int
170res_search(name, class, type, answer, anslen) 183res_search(name, class, type, answer, anslen)
@@ -173,28 +186,30 @@ res_search(name, class, type, answer, anslen)
173 u_char *answer; /* buffer to put answer */ 186 u_char *answer; /* buffer to put answer */
174 int anslen; /* size of answer */ 187 int anslen; /* size of answer */
175{ 188{
176 register char *cp, **domain; 189 register const char *cp, * const *domain;
177 int dots, trailing_dot, ret, got_nodata, saved_herrno, tried_as_is; 190 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
191 HEADER *hp = (HEADER *) answer;
192 u_int dots;
193 int trailing_dot, ret, saved_herrno;
194 int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
178 195
179 if ((_res.options & RES_INIT) == 0 && res_init() == -1) 196 if ((_resp->options & RES_INIT) == 0 && res_init() == -1) {
197 h_errno = NETDB_INTERNAL;
180 return (-1); 198 return (-1);
181 199 }
182 got_nodata = 0;
183 errno = 0; 200 errno = 0;
184 h_errno = HOST_NOT_FOUND; /* default, if we never query */ 201 h_errno = HOST_NOT_FOUND; /* default, if we never query */
185 dots = 0; 202 dots = 0;
186 for (cp = (char *)name; *cp; cp++) { 203 for (cp = name; *cp; cp++)
187 if (*cp == '.') 204 dots += (*cp == '.');
188 dots++;
189 }
190 trailing_dot = 0; 205 trailing_dot = 0;
191 if ((cp > name) && (*--cp == '.')) 206 if (cp > name && *--cp == '.')
192 trailing_dot++; 207 trailing_dot++;
193 208
194 /* 209 /*
195 * if there aren't any dots, it could be a user-level alias 210 * if there aren't any dots, it could be a user-level alias
196 */ 211 */
197 if (!dots && (cp = __hostalias(name))) 212 if (!dots && (cp = __hostalias(name)) != NULL)
198 return (res_query(cp, class, type, answer, anslen)); 213 return (res_query(cp, class, type, answer, anslen));
199 214
200 /* 215 /*
@@ -202,8 +217,7 @@ res_search(name, class, type, answer, anslen)
202 * 'as is'. The threshold can be set with the "ndots" option. 217 * 'as is'. The threshold can be set with the "ndots" option.
203 */ 218 */
204 saved_herrno = -1; 219 saved_herrno = -1;
205 tried_as_is = 0; 220 if (dots >= _resp->ndots) {
206 if (dots >= _res.ndots) {
207 ret = res_querydomain(name, NULL, class, type, answer, anslen); 221 ret = res_querydomain(name, NULL, class, type, answer, anslen);
208 if (ret > 0) 222 if (ret > 0)
209 return (ret); 223 return (ret);
@@ -217,15 +231,19 @@ res_search(name, class, type, answer, anslen)
217 * - there is at least one dot, there is no trailing dot, 231 * - there is at least one dot, there is no trailing dot,
218 * and RES_DNSRCH is set. 232 * and RES_DNSRCH is set.
219 */ 233 */
220 if ((!dots && (_res.options & RES_DEFNAMES)) || 234 if ((!dots && (_resp->options & RES_DEFNAMES)) ||
221 (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { 235 (dots && !trailing_dot && (_resp->options & RES_DNSRCH))) {
222 for (domain = _res.dnsrch; *domain; domain++) { 236 int done = 0;
223 int done = 0; 237
238 for (domain = (const char * const *)_resp->dnsrch;
239 *domain && !done;
240 domain++) {
224 241
225 ret = res_querydomain(name, *domain, class, type, 242 ret = res_querydomain(name, *domain, class, type,
226 answer, anslen); 243 answer, anslen);
227 if (ret > 0) 244 if (ret > 0)
228 return (ret); 245 return (ret);
246
229 /* 247 /*
230 * If no server present, give up. 248 * If no server present, give up.
231 * If name isn't found in this domain, 249 * If name isn't found in this domain,
@@ -251,24 +269,27 @@ res_search(name, class, type, answer, anslen)
251 case HOST_NOT_FOUND: 269 case HOST_NOT_FOUND:
252 /* keep trying */ 270 /* keep trying */
253 break; 271 break;
272 case TRY_AGAIN:
273 if (hp->rcode == SERVFAIL) {
274 /* try next search element, if any */
275 got_servfail++;
276 break;
277 }
278 /* FALLTHROUGH */
254 default: 279 default:
255 /* anything else implies that we're done */ 280 /* anything else implies that we're done */
256 done++; 281 done++;
257 } 282 }
258 /* 283
259 * if we got here for some reason other than DNSRCH, 284 /* if we got here for some reason other than DNSRCH,
260 * we only wanted one iteration of the loop, so stop. 285 * we only wanted one iteration of the loop, so stop.
261 */ 286 */
262 if (!(_res.options & RES_DNSRCH)) 287 if (!(_resp->options & RES_DNSRCH))
263 done++; 288 done++;
264
265 if (done)
266 break;
267 } 289 }
268 } 290 }
269 291
270 /* 292 /* if we have not already tried the name "as is", do that now.
271 * if we have not already tried the name "as is", do that now.
272 * note that we do this regardless of how many dots were in the 293 * note that we do this regardless of how many dots were in the
273 * name or whether it ends with a dot. 294 * name or whether it ends with a dot.
274 */ 295 */
@@ -276,11 +297,9 @@ res_search(name, class, type, answer, anslen)
276 ret = res_querydomain(name, NULL, class, type, answer, anslen); 297 ret = res_querydomain(name, NULL, class, type, answer, anslen);
277 if (ret > 0) 298 if (ret > 0)
278 return (ret); 299 return (ret);
279 saved_herrno = h_errno;
280 } 300 }
281 301
282 /* 302 /* if we got here, we didn't satisfy the search.
283 * if we got here, we didn't satisfy the search.
284 * if we did an initial full query, return that query's h_errno 303 * if we did an initial full query, return that query's h_errno
285 * (note that we wouldn't be here if that query had succeeded). 304 * (note that we wouldn't be here if that query had succeeded).
286 * else if we ever got a nodata, send that back as the reason. 305 * else if we ever got a nodata, send that back as the reason.
@@ -291,6 +310,8 @@ res_search(name, class, type, answer, anslen)
291 h_errno = saved_herrno; 310 h_errno = saved_herrno;
292 else if (got_nodata) 311 else if (got_nodata)
293 h_errno = NO_DATA; 312 h_errno = NO_DATA;
313 else if (got_servfail)
314 h_errno = TRY_AGAIN;
294 return (-1); 315 return (-1);
295} 316}
296 317
@@ -298,20 +319,26 @@ res_search(name, class, type, answer, anslen)
298 * Perform a call on res_query on the concatenation of name and domain, 319 * Perform a call on res_query on the concatenation of name and domain,
299 * removing a trailing dot from name if domain is NULL. 320 * removing a trailing dot from name if domain is NULL.
300 */ 321 */
322int
301res_querydomain(name, domain, class, type, answer, anslen) 323res_querydomain(name, domain, class, type, answer, anslen)
302 char *name, *domain; 324 const char *name, *domain;
303 int class, type; /* class and type of query */ 325 int class, type; /* class and type of query */
304 u_char *answer; /* buffer to put answer */ 326 u_char *answer; /* buffer to put answer */
305 int anslen; /* size of answer */ 327 int anslen; /* size of answer */
306{ 328{
307 char nbuf[2*MAXDNAME+2]; 329 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
308 char *longname = nbuf; 330 char nbuf[MAXDNAME*2+1+1];
331 const char *longname = nbuf;
309 int n; 332 int n;
310 333
334 if ((_resp->options & RES_INIT) == 0 && res_init() == -1) {
335 h_errno = NETDB_INTERNAL;
336 return (-1);
337 }
311#ifdef DEBUG 338#ifdef DEBUG
312 if (_res.options & RES_DEBUG) 339 if (_resp->options & RES_DEBUG)
313 printf(";; res_querydomain(%s, %s, %d, %d)\n", 340 printf(";; res_querydomain(%s, %s, %d, %d)\n",
314 name, domain, class, type); 341 name, domain?domain:"<Nil>", class, type);
315#endif 342#endif
316 if (domain == NULL) { 343 if (domain == NULL) {
317 /* 344 /*
@@ -325,38 +352,52 @@ res_querydomain(name, domain, class, type, answer, anslen)
325 } else 352 } else
326 longname = name; 353 longname = name;
327 } else 354 } else
328 (void)sprintf(nbuf, "%.*s.%.*s", 355 snprintf(nbuf, sizeof nbuf, "%.*s.%.*s",
329 MAXDNAME, name, MAXDNAME, domain); 356 MAXDNAME, name, MAXDNAME, domain);
330 357
331 return (res_query(longname, class, type, answer, anslen)); 358 return (res_query(longname, class, type, answer, anslen));
332} 359}
333 360
334char * 361const char *
335__hostalias(name) 362hostalias(name)
336 register const char *name; 363 register const char *name;
337{ 364{
365 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
338 register char *cp1, *cp2; 366 register char *cp1, *cp2;
339 FILE *fp; 367 FILE *fp;
340 char *file, *getenv(), *strcpy(), *strncpy(); 368 char *file;
341 char buf[BUFSIZ]; 369 char buf[BUFSIZ];
342 static char abuf[MAXDNAME]; 370 static char abuf[MAXDNAME];
371 size_t len;
343 372
373 if (_resp->options & RES_NOALIASES)
374 return (NULL);
344 file = getenv("HOSTALIASES"); 375 file = getenv("HOSTALIASES");
345 if (file == NULL || (fp = fopen(file, "r")) == NULL) 376 if (issetugid() != 0 || file == NULL || (fp = fopen(file, "r")) == NULL)
346 return (NULL); 377 return (NULL);
347 buf[sizeof(buf) - 1] = '\0'; 378 setbuf(fp, NULL);
348 while (fgets(buf, sizeof(buf), fp)) { 379 while ((cp1 = fgetln(fp, &len)) != NULL) {
349 for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1); 380 if (cp1[len-1] == '\n')
381 len--;
382 if (len >= sizeof(buf) || len == 0)
383 continue;
384 (void)memcpy(buf, cp1, len);
385 buf[len] = '\0';
386
387 for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1)
388 ;
350 if (!*cp1) 389 if (!*cp1)
351 break; 390 break;
352 *cp1 = '\0'; 391 *cp1 = '\0';
353 if (!strcasecmp(buf, name)) { 392 if (!strcasecmp(buf, name)) {
354 while (isspace(*++cp1)); 393 while (isspace(*++cp1))
394 ;
355 if (!*cp1) 395 if (!*cp1)
356 break; 396 break;
357 for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2); 397 for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2)
358 abuf[sizeof(abuf) - 1] = *cp2 = '\0'; 398 ;
359 (void)strncpy(abuf, cp1, sizeof(abuf) - 1); 399 *cp2 = '\0';
400 strlcpy(abuf, cp1, sizeof(abuf));
360 fclose(fp); 401 fclose(fp);
361 return (abuf); 402 return (abuf);
362 } 403 }