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