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