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.c265
1 files changed, 151 insertions, 114 deletions
diff --git a/src/lib/libc/net/res_query.c b/src/lib/libc/net/res_query.c
index 7649462e56..1485abb2d7 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.26 2010/06/29 21:08:54 deraadt 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
@@ -53,26 +51,22 @@
53 * --Copyright-- 51 * --Copyright--
54 */ 52 */
55 53
56#if defined(LIBC_SCCS) && !defined(lint) 54#include <sys/types.h>
57#if 0
58static 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 ";
60#else
61static char rcsid[] = "$NetBSD: res_query.c,v 1.9 1995/02/25 06:58:58 cgd Exp $";
62#endif
63#endif /* LIBC_SCCS and not lint */
64
65#include <sys/param.h> 55#include <sys/param.h>
66#include <netinet/in.h> 56#include <netinet/in.h>
67#include <arpa/inet.h> 57#include <arpa/inet.h>
68#include <arpa/nameser.h> 58#include <arpa/nameser.h>
59
60#include <stdio.h>
69#include <netdb.h> 61#include <netdb.h>
70#include <resolv.h> 62#include <resolv.h>
71#include <stdio.h>
72#include <ctype.h> 63#include <ctype.h>
73#include <errno.h> 64#include <errno.h>
74#include <stdlib.h> 65#include <stdlib.h>
75#include <string.h> 66#include <string.h>
67#include <unistd.h>
68
69#include "thread_private.h"
76 70
77#if PACKETSZ > 1024 71#if PACKETSZ > 1024
78#define MAXPACKET PACKETSZ 72#define MAXPACKET PACKETSZ
@@ -80,8 +74,9 @@ static char rcsid[] = "$NetBSD: res_query.c,v 1.9 1995/02/25 06:58:58 cgd Exp $"
80#define MAXPACKET 1024 74#define MAXPACKET 1024
81#endif 75#endif
82 76
83char *__hostalias __P((const char *)); 77const char *hostalias(const char *);
84int h_errno; 78int h_errno;
79extern int res_opt(int, u_char *, int, int);
85 80
86/* 81/*
87 * Formulate a normal query, send, and await answer. 82 * Formulate a normal query, send, and await answer.
@@ -90,68 +85,82 @@ int h_errno;
90 * if no error is indicated and the answer count is nonzero. 85 * if no error is indicated and the answer count is nonzero.
91 * Return the size of the response on success, -1 on error. 86 * Return the size of the response on success, -1 on error.
92 * Error number is left in h_errno. 87 * Error number is left in h_errno.
88 *
93 * Caller must parse answer and determine whether it answers the question. 89 * Caller must parse answer and determine whether it answers the question.
94 */ 90 */
95res_query(name, class, type, answer, anslen) 91int
96 char *name; /* domain name */ 92res_query(const char *name,
97 int class, type; /* class and type of query */ 93 int class, /* domain name */
98 u_char *answer; /* buffer to put answer */ 94 int type, /* class and type of query */
99 int anslen; /* size of answer buffer */ 95 u_char *answer, /* buffer to put answer */
96 int anslen) /* size of answer buffer */
100{ 97{
101 char buf[MAXPACKET]; 98 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
102 HEADER *hp; 99 union {
100 HEADER hdr;
101 u_char buf[MAXPACKET];
102 } buf;
103 HEADER *hp = (HEADER *) answer;
103 int n; 104 int n;
104 105
105 if ((_res.options & RES_INIT) == 0 && res_init() == -1) 106 hp->rcode = NOERROR; /* default */
107
108 if (_res_init(0) == -1) {
109 h_errno = NETDB_INTERNAL;
106 return (-1); 110 return (-1);
111 }
107#ifdef DEBUG 112#ifdef DEBUG
108 if (_res.options & RES_DEBUG) 113 if (_resp->options & RES_DEBUG)
109 printf(";; res_query(%s, %d, %d)\n", name, class, type); 114 printf(";; res_query(%s, %d, %d)\n", name, class, type);
110#endif 115#endif
111 n = res_mkquery(QUERY, name, class, type, (char *)NULL, 0, NULL, 116
112 buf, sizeof(buf)); 117 n = res_mkquery(QUERY, name, class, type, NULL, 0, NULL,
118 buf.buf, sizeof(buf.buf));
119 if (n > 0 && ((_resp->options & RES_USE_EDNS0) ||
120 (_resp->options & RES_USE_DNSSEC))) {
121 n = res_opt(n, buf.buf, sizeof(buf.buf), anslen);
122 }
113 123
114 if (n <= 0) { 124 if (n <= 0) {
115#ifdef DEBUG 125#ifdef DEBUG
116 if (_res.options & RES_DEBUG) 126 if (_resp->options & RES_DEBUG)
117 printf(";; res_query: mkquery failed\n"); 127 printf(";; res_query: mkquery failed\n");
118#endif 128#endif
119 h_errno = NO_RECOVERY; 129 h_errno = NO_RECOVERY;
120 return (n); 130 return (n);
121 } 131 }
122 n = res_send(buf, n, (char *)answer, anslen); 132 n = res_send(buf.buf, n, answer, anslen);
123 if (n < 0) { 133 if (n < 0) {
124#ifdef DEBUG 134#ifdef DEBUG
125 if (_res.options & RES_DEBUG) 135 if (_resp->options & RES_DEBUG)
126 printf(";; res_query: send error\n"); 136 printf(";; res_query: send error\n");
127#endif 137#endif
128 h_errno = TRY_AGAIN; 138 h_errno = TRY_AGAIN;
129 return (n); 139 return (n);
130 } 140 }
131 141
132 hp = (HEADER *) answer;
133 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) { 142 if (hp->rcode != NOERROR || ntohs(hp->ancount) == 0) {
134#ifdef DEBUG 143#ifdef DEBUG
135 if (_res.options & RES_DEBUG) 144 if (_resp->options & RES_DEBUG)
136 printf(";; rcode = %d, ancount=%d\n", hp->rcode, 145 printf(";; rcode = %u, ancount=%u\n", hp->rcode,
137 ntohs(hp->ancount)); 146 ntohs(hp->ancount));
138#endif 147#endif
139 switch (hp->rcode) { 148 switch (hp->rcode) {
140 case NXDOMAIN: 149 case NXDOMAIN:
141 h_errno = HOST_NOT_FOUND; 150 h_errno = HOST_NOT_FOUND;
142 break; 151 break;
143 case SERVFAIL: 152 case SERVFAIL:
144 h_errno = TRY_AGAIN; 153 h_errno = TRY_AGAIN;
145 break; 154 break;
146 case NOERROR: 155 case NOERROR:
147 h_errno = NO_DATA; 156 h_errno = NO_DATA;
148 break; 157 break;
149 case FORMERR: 158 case FORMERR:
150 case NOTIMP: 159 case NOTIMP:
151 case REFUSED: 160 case REFUSED:
152 default: 161 default:
153 h_errno = NO_RECOVERY; 162 h_errno = NO_RECOVERY;
154 break; 163 break;
155 } 164 }
156 return (-1); 165 return (-1);
157 } 166 }
@@ -162,39 +171,39 @@ res_query(name, class, type, answer, anslen)
162 * Formulate a normal query, send, and retrieve answer in supplied buffer. 171 * Formulate a normal query, send, and retrieve answer in supplied buffer.
163 * Return the size of the response on success, -1 on error. 172 * Return the size of the response on success, -1 on error.
164 * If enabled, implement search rules until answer or unrecoverable failure 173 * If enabled, implement search rules until answer or unrecoverable failure
165 * is detected. Error number is left in h_errno. 174 * 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 */ 175 */
169int 176int
170res_search(name, class, type, answer, anslen) 177res_search(const char *name,
171 const char *name; /* domain name */ 178 int class, /* domain name */
172 int class, type; /* class and type of query */ 179 int type, /* class and type of query */
173 u_char *answer; /* buffer to put answer */ 180 u_char *answer, /* buffer to put answer */
174 int anslen; /* size of answer */ 181 int anslen) /* size of answer */
175{ 182{
176 register char *cp, **domain; 183 const char *cp, * const *domain;
177 int dots, trailing_dot, ret, got_nodata, saved_herrno, tried_as_is; 184 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
185 HEADER *hp = (HEADER *) answer;
186 u_int dots;
187 int trailing_dot, ret, saved_herrno;
188 int got_nodata = 0, got_servfail = 0, tried_as_is = 0;
178 189
179 if ((_res.options & RES_INIT) == 0 && res_init() == -1) 190 if (_res_init(0) == -1) {
191 h_errno = NETDB_INTERNAL;
180 return (-1); 192 return (-1);
181 193 }
182 got_nodata = 0;
183 errno = 0; 194 errno = 0;
184 h_errno = HOST_NOT_FOUND; /* default, if we never query */ 195 h_errno = HOST_NOT_FOUND; /* default, if we never query */
185 dots = 0; 196 dots = 0;
186 for (cp = (char *)name; *cp; cp++) { 197 for (cp = name; *cp; cp++)
187 if (*cp == '.') 198 dots += (*cp == '.');
188 dots++;
189 }
190 trailing_dot = 0; 199 trailing_dot = 0;
191 if ((cp > name) && (*--cp == '.')) 200 if (cp > name && *--cp == '.')
192 trailing_dot++; 201 trailing_dot++;
193 202
194 /* 203 /*
195 * if there aren't any dots, it could be a user-level alias 204 * if there aren't any dots, it could be a user-level alias
196 */ 205 */
197 if (!dots && (cp = __hostalias(name))) 206 if (!dots && (cp = __hostalias(name)) != NULL)
198 return (res_query(cp, class, type, answer, anslen)); 207 return (res_query(cp, class, type, answer, anslen));
199 208
200 /* 209 /*
@@ -202,8 +211,7 @@ res_search(name, class, type, answer, anslen)
202 * 'as is'. The threshold can be set with the "ndots" option. 211 * 'as is'. The threshold can be set with the "ndots" option.
203 */ 212 */
204 saved_herrno = -1; 213 saved_herrno = -1;
205 tried_as_is = 0; 214 if (dots >= _resp->ndots) {
206 if (dots >= _res.ndots) {
207 ret = res_querydomain(name, NULL, class, type, answer, anslen); 215 ret = res_querydomain(name, NULL, class, type, answer, anslen);
208 if (ret > 0) 216 if (ret > 0)
209 return (ret); 217 return (ret);
@@ -217,15 +225,19 @@ res_search(name, class, type, answer, anslen)
217 * - there is at least one dot, there is no trailing dot, 225 * - there is at least one dot, there is no trailing dot,
218 * and RES_DNSRCH is set. 226 * and RES_DNSRCH is set.
219 */ 227 */
220 if ((!dots && (_res.options & RES_DEFNAMES)) || 228 if ((!dots && (_resp->options & RES_DEFNAMES)) ||
221 (dots && !trailing_dot && (_res.options & RES_DNSRCH))) { 229 (dots && !trailing_dot && (_resp->options & RES_DNSRCH))) {
222 for (domain = _res.dnsrch; *domain; domain++) { 230 int done = 0;
223 int done = 0; 231
232 for (domain = (const char * const *)_resp->dnsrch;
233 *domain && !done;
234 domain++) {
224 235
225 ret = res_querydomain(name, *domain, class, type, 236 ret = res_querydomain(name, *domain, class, type,
226 answer, anslen); 237 answer, anslen);
227 if (ret > 0) 238 if (ret > 0)
228 return (ret); 239 return (ret);
240
229 /* 241 /*
230 * If no server present, give up. 242 * If no server present, give up.
231 * If name isn't found in this domain, 243 * If name isn't found in this domain,
@@ -251,24 +263,27 @@ res_search(name, class, type, answer, anslen)
251 case HOST_NOT_FOUND: 263 case HOST_NOT_FOUND:
252 /* keep trying */ 264 /* keep trying */
253 break; 265 break;
266 case TRY_AGAIN:
267 if (hp->rcode == SERVFAIL) {
268 /* try next search element, if any */
269 got_servfail++;
270 break;
271 }
272 /* FALLTHROUGH */
254 default: 273 default:
255 /* anything else implies that we're done */ 274 /* anything else implies that we're done */
256 done++; 275 done++;
257 } 276 }
258 /* 277
259 * if we got here for some reason other than DNSRCH, 278 /* if we got here for some reason other than DNSRCH,
260 * we only wanted one iteration of the loop, so stop. 279 * we only wanted one iteration of the loop, so stop.
261 */ 280 */
262 if (!(_res.options & RES_DNSRCH)) 281 if (!(_resp->options & RES_DNSRCH))
263 done++; 282 done++;
264
265 if (done)
266 break;
267 } 283 }
268 } 284 }
269 285
270 /* 286 /* 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 287 * note that we do this regardless of how many dots were in the
273 * name or whether it ends with a dot. 288 * name or whether it ends with a dot.
274 */ 289 */
@@ -276,11 +291,9 @@ res_search(name, class, type, answer, anslen)
276 ret = res_querydomain(name, NULL, class, type, answer, anslen); 291 ret = res_querydomain(name, NULL, class, type, answer, anslen);
277 if (ret > 0) 292 if (ret > 0)
278 return (ret); 293 return (ret);
279 saved_herrno = h_errno;
280 } 294 }
281 295
282 /* 296 /* 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 297 * 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). 298 * (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. 299 * else if we ever got a nodata, send that back as the reason.
@@ -291,6 +304,8 @@ res_search(name, class, type, answer, anslen)
291 h_errno = saved_herrno; 304 h_errno = saved_herrno;
292 else if (got_nodata) 305 else if (got_nodata)
293 h_errno = NO_DATA; 306 h_errno = NO_DATA;
307 else if (got_servfail)
308 h_errno = TRY_AGAIN;
294 return (-1); 309 return (-1);
295} 310}
296 311
@@ -298,20 +313,29 @@ res_search(name, class, type, answer, anslen)
298 * Perform a call on res_query on the concatenation of name and domain, 313 * Perform a call on res_query on the concatenation of name and domain,
299 * removing a trailing dot from name if domain is NULL. 314 * removing a trailing dot from name if domain is NULL.
300 */ 315 */
301res_querydomain(name, domain, class, type, answer, anslen) 316int
302 char *name, *domain; 317res_querydomain(const char *name,
303 int class, type; /* class and type of query */ 318 const char *domain,
304 u_char *answer; /* buffer to put answer */ 319 int class, /* class and type of query */
305 int anslen; /* size of answer */ 320 int type,
321 u_char *answer, /* buffer to put answer */
322 int anslen) /* size of answer */
306{ 323{
307 char nbuf[2*MAXDNAME+2]; 324#ifdef DEBUG
308 char *longname = nbuf; 325 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
326#endif
327 char nbuf[MAXDNAME*2+1+1];
328 const char *longname = nbuf;
309 int n; 329 int n;
310 330
331 if (_res_init(0) == -1) {
332 h_errno = NETDB_INTERNAL;
333 return (-1);
334 }
311#ifdef DEBUG 335#ifdef DEBUG
312 if (_res.options & RES_DEBUG) 336 if (_resp->options & RES_DEBUG)
313 printf(";; res_querydomain(%s, %s, %d, %d)\n", 337 printf(";; res_querydomain(%s, %s, %d, %d)\n",
314 name, domain, class, type); 338 name, domain?domain:"<Nil>", class, type);
315#endif 339#endif
316 if (domain == NULL) { 340 if (domain == NULL) {
317 /* 341 /*
@@ -325,38 +349,51 @@ res_querydomain(name, domain, class, type, answer, anslen)
325 } else 349 } else
326 longname = name; 350 longname = name;
327 } else 351 } else
328 (void)sprintf(nbuf, "%.*s.%.*s", 352 snprintf(nbuf, sizeof nbuf, "%.*s.%.*s",
329 MAXDNAME, name, MAXDNAME, domain); 353 MAXDNAME, name, MAXDNAME, domain);
330 354
331 return (res_query(longname, class, type, answer, anslen)); 355 return (res_query(longname, class, type, answer, anslen));
332} 356}
333 357
334char * 358const char *
335__hostalias(name) 359hostalias(const char *name)
336 register const char *name;
337{ 360{
338 register char *cp1, *cp2; 361 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
362 char *cp1, *cp2;
339 FILE *fp; 363 FILE *fp;
340 char *file, *getenv(), *strcpy(), *strncpy(); 364 char *file;
341 char buf[BUFSIZ]; 365 char buf[BUFSIZ];
342 static char abuf[MAXDNAME]; 366 static char abuf[MAXDNAME];
367 size_t len;
343 368
369 if (_resp->options & RES_NOALIASES)
370 return (NULL);
344 file = getenv("HOSTALIASES"); 371 file = getenv("HOSTALIASES");
345 if (file == NULL || (fp = fopen(file, "r")) == NULL) 372 if (issetugid() != 0 || file == NULL || (fp = fopen(file, "r")) == NULL)
346 return (NULL); 373 return (NULL);
347 buf[sizeof(buf) - 1] = '\0'; 374 setbuf(fp, NULL);
348 while (fgets(buf, sizeof(buf), fp)) { 375 while ((cp1 = fgetln(fp, &len)) != NULL) {
349 for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1); 376 if (cp1[len-1] == '\n')
377 len--;
378 if (len >= sizeof(buf) || len == 0)
379 continue;
380 (void)memcpy(buf, cp1, len);
381 buf[len] = '\0';
382
383 for (cp1 = buf; *cp1 && !isspace(*cp1); ++cp1)
384 ;
350 if (!*cp1) 385 if (!*cp1)
351 break; 386 break;
352 *cp1 = '\0'; 387 *cp1 = '\0';
353 if (!strcasecmp(buf, name)) { 388 if (!strcasecmp(buf, name)) {
354 while (isspace(*++cp1)); 389 while (isspace(*++cp1))
390 ;
355 if (!*cp1) 391 if (!*cp1)
356 break; 392 break;
357 for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2); 393 for (cp2 = cp1 + 1; *cp2 && !isspace(*cp2); ++cp2)
358 abuf[sizeof(abuf) - 1] = *cp2 = '\0'; 394 ;
359 (void)strncpy(abuf, cp1, sizeof(abuf) - 1); 395 *cp2 = '\0';
396 strlcpy(abuf, cp1, sizeof(abuf));
360 fclose(fp); 397 fclose(fp);
361 return (abuf); 398 return (abuf);
362 } 399 }