summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/res_send.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/net/res_send.c')
-rw-r--r--src/lib/libc/net/res_send.c863
1 files changed, 621 insertions, 242 deletions
diff --git a/src/lib/libc/net/res_send.c b/src/lib/libc/net/res_send.c
index e608358180..09b1385892 100644
--- a/src/lib/libc/net/res_send.c
+++ b/src/lib/libc/net/res_send.c
@@ -1,9 +1,11 @@
1/* $NetBSD: res_send.c,v 1.4 1995/02/25 06:21:01 cgd Exp $ */ 1/* $OpenBSD: res_send.c,v 1.21 2008/05/11 05:03:03 brad Exp $ */
2 2
3/*- 3/*
4 * ++Copyright++ 1985, 1989, 1993
5 * -
4 * Copyright (c) 1985, 1989, 1993 6 * Copyright (c) 1985, 1989, 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,19 +51,22 @@
53 * --Copyright-- 51 * --Copyright--
54 */ 52 */
55 53
56#if defined(LIBC_SCCS) && !defined(lint) 54#ifndef INET6
57#if 0 55#define INET6
58static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
59static char rcsid[] = "$Id: res_send.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel ";
60#else
61static char rcsid[] = "$NetBSD: res_send.c,v 1.4 1995/02/25 06:21:01 cgd Exp $";
62#endif 56#endif
63#endif /* LIBC_SCCS and not lint */ 57
58 /* change this to "0"
59 * if you talk to a lot
60 * of multi-homed SunOS
61 * ("broken") name servers.
62 */
63#define CHECK_SRVR_ADDR 1 /* XXX - should be in options.h */
64 64
65/* 65/*
66 * Send query to name server and wait for reply. 66 * Send query to name server and wait for reply.
67 */ 67 */
68 68
69#include <sys/types.h>
69#include <sys/param.h> 70#include <sys/param.h>
70#include <sys/time.h> 71#include <sys/time.h>
71#include <sys/socket.h> 72#include <sys/socket.h>
@@ -73,139 +74,401 @@ static char rcsid[] = "$NetBSD: res_send.c,v 1.4 1995/02/25 06:21:01 cgd Exp $";
73#include <netinet/in.h> 74#include <netinet/in.h>
74#include <arpa/nameser.h> 75#include <arpa/nameser.h>
75#include <arpa/inet.h> 76#include <arpa/inet.h>
76#include <stdio.h> 77
77#include <errno.h> 78#include <errno.h>
79#include <netdb.h>
80#include <poll.h>
78#include <resolv.h> 81#include <resolv.h>
79#include <unistd.h> 82#include <stdio.h>
83#include <stdlib.h>
80#include <string.h> 84#include <string.h>
85#include <unistd.h>
86
87#include "thread_private.h"
81 88
82static int s = -1; /* socket used for communications */ 89static int s = -1; /* socket used for communications */
83static struct sockaddr no_addr; 90static int connected = 0; /* is the socket connected */
84 91static int vc = 0; /* is the socket a virtual ciruit? */
85#ifndef FD_SET 92static int af = 0; /* address family of socket */
86#define NFDBITS 32 93
87#define FD_SETSIZE 32 94#define CAN_RECONNECT 1
88#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 95
89#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 96#ifndef DEBUG
90#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 97# define Dprint(cond, args) /*empty*/
91#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 98# define DprintQ(cond, args, query, size) /*empty*/
99# define Aerror(file, string, error, address) /*empty*/
100# define Perror(file, string, error) /*empty*/
101#else
102# define Dprint(cond, args) if (cond) {fprintf args;} else {}
103# define DprintQ(cond, args, query, size) if (cond) {\
104 fprintf args;\
105 __fp_nquery(query, size, stdout);\
106 } else {}
107static char abuf[NI_MAXHOST];
108static char pbuf[NI_MAXSERV];
109static void Aerror(FILE *, char *, int, struct sockaddr *);
110static void Perror(FILE *, char *, int);
111
112 static void
113 Aerror(FILE *file, char *string, int error, struct sockaddr *address)
114 {
115 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
116 int save = errno;
117
118 if (_resp->options & RES_DEBUG) {
119 if (getnameinfo(address, address->sa_len, abuf, sizeof(abuf),
120 pbuf, sizeof(pbuf), NI_NUMERICHOST | NI_NUMERICSERV) != 0) {
121 strlcpy(abuf, "?", sizeof(abuf));
122 strlcpy(pbuf, "?", sizeof(pbuf));
123 }
124 fprintf(file, "res_send: %s ([%s].%s): %s\n",
125 string, abuf, pbuf, strerror(error));
126 }
127 errno = save;
128 }
129 static void
130 Perror(FILE *file, char *string, int error)
131 {
132 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
133 int save = errno;
134
135 if (_resp->options & RES_DEBUG) {
136 fprintf(file, "res_send: %s: %s\n",
137 string, strerror(error));
138 }
139 errno = save;
140 }
92#endif 141#endif
93 142
94res_send(buf, buflen, answer, anslen) 143static res_send_qhook Qhook = NULL;
95 const char *buf; 144static res_send_rhook Rhook = NULL;
96 int buflen; 145
97 char *answer; 146void
98 int anslen; 147res_send_setqhook(res_send_qhook hook)
99{ 148{
100 register int n; 149
101 int try, v_circuit, resplen, ns; 150 Qhook = hook;
102 int gotsomewhere = 0, connected = 0; 151}
103 int connreset = 0; 152
104 u_short id, len; 153void
105 char *cp; 154res_send_setrhook(res_send_rhook hook)
106 fd_set dsmask; 155{
107 struct timeval timeout; 156
108 HEADER *hp = (HEADER *) buf; 157 Rhook = hook;
109 HEADER *anhp = (HEADER *) answer; 158}
110 u_int badns; /* XXX NSMAX can't exceed #/bits per this */ 159
111 struct iovec iov[2]; 160#ifdef INET6
112 int terrno = ETIMEDOUT; 161static struct sockaddr * get_nsaddr(size_t);
113 char junk[512]; 162
114 163/*
115#ifdef DEBUG 164 * pick appropriate nsaddr_list for use. see res_init() for initialization.
116 if ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY)) { 165 */
117 printf(";; res_send()\n"); 166static struct sockaddr *
118 __p_query(buf); 167get_nsaddr(size_t n)
168{
169 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
170 struct __res_state_ext *_res_extp = _THREAD_PRIVATE(_res_ext, _res_ext,
171 &_res_ext);
172
173 if (!_resp->nsaddr_list[n].sin_family) {
174 /*
175 * - _res_extp->nsaddr_list[n] holds an address that is larger
176 * than struct sockaddr, and
177 * - user code did not update _resp->nsaddr_list[n].
178 */
179 return (struct sockaddr *)&_res_extp->nsaddr_list[n];
180 } else {
181 /*
182 * - user code updated _res.nsaddr_list[n], or
183 * - _resp->nsaddr_list[n] has the same content as
184 * _res_extp->nsaddr_list[n].
185 */
186 return (struct sockaddr *)&_resp->nsaddr_list[n];
119 } 187 }
188}
189#else
190#define get_nsaddr(n) ((struct sockaddr *)&_resp->nsaddr_list[(n)])
191#endif
192
193/* int
194 * res_isourserver(ina)
195 * looks up "ina" in _resp->ns_addr_list[]
196 * returns:
197 * 0 : not found
198 * >0 : found
199 * author:
200 * paul vixie, 29may94
201 */
202int
203res_isourserver(const struct sockaddr_in *inp)
204{
205 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
206#ifdef INET6
207 const struct sockaddr_in6 *in6p = (const struct sockaddr_in6 *)inp;
208 const struct sockaddr_in6 *srv6;
120#endif 209#endif
121 if (!(_res.options & RES_INIT)) 210 const struct sockaddr_in *srv;
122 if (res_init() == -1) { 211 int ns, ret;
123 return(-1); 212
213 ret = 0;
214 switch (inp->sin_family) {
215#ifdef INET6
216 case AF_INET6:
217 for (ns = 0; ns < _resp->nscount; ns++) {
218 srv6 = (struct sockaddr_in6 *)get_nsaddr(ns);
219 if (srv6->sin6_family == in6p->sin6_family &&
220 srv6->sin6_port == in6p->sin6_port &&
221 srv6->sin6_scope_id == in6p->sin6_scope_id &&
222 (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
223 IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr,
224 &in6p->sin6_addr))) {
225 ret++;
226 break;
227 }
124 } 228 }
125 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 229 break;
126 id = hp->id; 230#endif
231 case AF_INET:
232 for (ns = 0; ns < _resp->nscount; ns++) {
233 srv = (struct sockaddr_in *)get_nsaddr(ns);
234 if (srv->sin_family == inp->sin_family &&
235 srv->sin_port == inp->sin_port &&
236 (srv->sin_addr.s_addr == INADDR_ANY ||
237 srv->sin_addr.s_addr == inp->sin_addr.s_addr)) {
238 ret++;
239 break;
240 }
241 }
242 break;
243 }
244 return (ret);
245}
246
247/* int
248 * res_nameinquery(name, type, class, buf, eom)
249 * look for (name,type,class) in the query section of packet (buf,eom)
250 * returns:
251 * -1 : format error
252 * 0 : not found
253 * >0 : found
254 * author:
255 * paul vixie, 29may94
256 */
257int
258res_nameinquery(const char *name, int type, int class, const u_char *buf,
259 const u_char *eom)
260{
261 const u_char *cp = buf + HFIXEDSZ;
262 int qdcount = ntohs(((HEADER*)buf)->qdcount);
263
264 while (qdcount-- > 0) {
265 char tname[MAXDNAME+1];
266 int n, ttype, tclass;
267
268 n = dn_expand(buf, eom, cp, tname, sizeof tname);
269 if (n < 0)
270 return (-1);
271 cp += n;
272 ttype = _getshort(cp); cp += INT16SZ;
273 tclass = _getshort(cp); cp += INT16SZ;
274 if (ttype == type &&
275 tclass == class &&
276 strcasecmp(tname, name) == 0)
277 return (1);
278 }
279 return (0);
280}
281
282/* int
283 * res_queriesmatch(buf1, eom1, buf2, eom2)
284 * is there a 1:1 mapping of (name,type,class)
285 * in (buf1,eom1) and (buf2,eom2)?
286 * returns:
287 * -1 : format error
288 * 0 : not a 1:1 mapping
289 * >0 : is a 1:1 mapping
290 * author:
291 * paul vixie, 29may94
292 */
293int
294res_queriesmatch(const u_char *buf1, const u_char *eom1, const u_char *buf2,
295 const u_char *eom2)
296{
297 const u_char *cp = buf1 + HFIXEDSZ;
298 int qdcount = ntohs(((HEADER*)buf1)->qdcount);
299
300 if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
301 return (0);
302 while (qdcount-- > 0) {
303 char tname[MAXDNAME+1];
304 int n, ttype, tclass;
305
306 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
307 if (n < 0)
308 return (-1);
309 cp += n;
310 ttype = _getshort(cp); cp += INT16SZ;
311 tclass = _getshort(cp); cp += INT16SZ;
312 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
313 return (0);
314 }
315 return (1);
316}
317
318int
319res_send(const u_char *buf, int buflen, u_char *ans, int anssiz)
320{
321 struct __res_state *_resp = _THREAD_PRIVATE(_res, _res, &_res);
322 HEADER *hp = (HEADER *) buf;
323 HEADER *anhp = (HEADER *) ans;
324 int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns;
325 int n;
326 u_int badns; /* XXX NSMAX can't exceed #/bits in this var */
327
328 if (_res_init(0) == -1) {
329 /* errno should have been set by res_init() in this case. */
330 return (-1);
331 }
332 DprintQ((_resp->options & RES_DEBUG) || (_resp->pfcode & RES_PRF_QUERY),
333 (stdout, ";; res_send()\n"), buf, buflen);
334 v_circuit = (_resp->options & RES_USEVC) || buflen > PACKETSZ;
335 gotsomewhere = 0;
336 connreset = 0;
337 terrno = ETIMEDOUT;
127 badns = 0; 338 badns = 0;
339
128 /* 340 /*
129 * Send request, RETRY times, or until successful 341 * Send request, RETRY times, or until successful
130 */ 342 */
131 for (try = 0; try < _res.retry; try++) { 343 for (try = 0; try < _resp->retry; try++) {
132 for (ns = 0; ns < _res.nscount; ns++) { 344 for (ns = 0; ns < _resp->nscount; ns++) {
133 if (badns & (1<<ns)) 345 struct sockaddr *nsap = get_nsaddr(ns);
134 continue; 346 socklen_t salen;
135#ifdef DEBUG 347
136 if (_res.options & RES_DEBUG) 348 if (nsap->sa_len)
137 printf(";; Querying server (# %d) address = %s\n", 349 salen = nsap->sa_len;
138 ns+1, 350#ifdef INET6
139 inet_ntoa(_res.nsaddr_list[ns].sin_addr)); 351 else if (nsap->sa_family == AF_INET6)
352 salen = sizeof(struct sockaddr_in6);
140#endif 353#endif
141 usevc: 354 else if (nsap->sa_family == AF_INET)
355 salen = sizeof(struct sockaddr_in);
356 else
357 salen = 0; /*unknown, die on connect*/
358
359 same_ns:
360 if (badns & (1 << ns)) {
361 res_close();
362 goto next_ns;
363 }
364
365 if (Qhook) {
366 int done = 0, loops = 0;
367
368 do {
369 res_sendhookact act;
370
371 act = (*Qhook)((struct sockaddr_in **)&nsap,
372 &buf, &buflen,
373 ans, anssiz, &resplen);
374 switch (act) {
375 case res_goahead:
376 done = 1;
377 break;
378 case res_nextns:
379 res_close();
380 goto next_ns;
381 case res_done:
382 return (resplen);
383 case res_modified:
384 /* give the hook another try */
385 if (++loops < 42) /*doug adams*/
386 break;
387 /*FALLTHROUGH*/
388 case res_error:
389 /*FALLTHROUGH*/
390 default:
391 return (-1);
392 }
393 } while (!done);
394 }
395
396 Dprint((_resp->options & RES_DEBUG) &&
397 getnameinfo(nsap, salen, abuf, sizeof(abuf),
398 NULL, 0, NI_NUMERICHOST) == 0,
399 (stdout, ";; Querying server (# %d) address = %s\n",
400 ns + 1, abuf));
401
142 if (v_circuit) { 402 if (v_circuit) {
143 int truncated = 0; 403 int truncated;
404 struct iovec iov[2];
405 u_short len;
406 u_char *cp;
144 407
145 /* 408 /*
146 * Use virtual circuit; 409 * Use virtual circuit;
147 * at most one attempt per server. 410 * at most one attempt per server.
148 */ 411 */
149 try = _res.retry; 412 try = _resp->retry;
150 if (s < 0) { 413 truncated = 0;
151 s = socket(AF_INET, SOCK_STREAM, 0); 414 if ((s < 0) || (!vc) || (af != nsap->sa_family)) {
415 if (s >= 0)
416 res_close();
417
418 af = nsap->sa_family;
419 s = socket(af, SOCK_STREAM, 0);
152 if (s < 0) { 420 if (s < 0) {
153 terrno = errno; 421 terrno = errno;
154#ifdef DEBUG 422 Perror(stderr, "socket(vc)", errno);
155 if (_res.options & RES_DEBUG) 423#if 0
156 perror("socket (vc) failed"); 424 return (-1);
425#else
426 badns |= (1 << ns);
427 res_close();
428 goto next_ns;
157#endif 429#endif
158 continue;
159 } 430 }
160 if (connect(s, 431 errno = 0;
161 (struct sockaddr *)&(_res.nsaddr_list[ns]), 432 if (connect(s, nsap, salen) < 0) {
162 sizeof(struct sockaddr)) < 0) {
163 terrno = errno; 433 terrno = errno;
164#ifdef DEBUG 434 Aerror(stderr, "connect/vc",
165 if (_res.options & RES_DEBUG) 435 errno, nsap);
166 perror("connect failed"); 436 badns |= (1 << ns);
167#endif 437 res_close();
168 (void) close(s); 438 goto next_ns;
169 s = -1;
170 continue;
171 } 439 }
440 vc = 1;
172 } 441 }
173 /* 442 /*
174 * Send length & message 443 * Send length & message
175 */ 444 */
176 len = htons((u_short)buflen); 445 putshort((u_short)buflen, (u_char*)&len);
177 iov[0].iov_base = (caddr_t)&len; 446 iov[0].iov_base = (caddr_t)&len;
178 iov[0].iov_len = sizeof(len); 447 iov[0].iov_len = INT16SZ;
179 iov[1].iov_base = (char *)buf; 448 iov[1].iov_base = (caddr_t)buf;
180 iov[1].iov_len = buflen; 449 iov[1].iov_len = buflen;
181 if (writev(s, iov, 2) != sizeof(len) + buflen) { 450 if (writev(s, iov, 2) != (INT16SZ + buflen)) {
182 terrno = errno; 451 terrno = errno;
183#ifdef DEBUG 452 Perror(stderr, "write failed", errno);
184 if (_res.options & RES_DEBUG) 453 badns |= (1 << ns);
185 perror("write failed"); 454 res_close();
186#endif 455 goto next_ns;
187 (void) close(s);
188 s = -1;
189 continue;
190 } 456 }
191 /* 457 /*
192 * Receive length & response 458 * Receive length & response
193 */ 459 */
194 cp = answer; 460 read_len:
195 len = sizeof(short); 461 cp = ans;
196 while (len != 0 && 462 len = INT16SZ;
197 (n = read(s, (char *)cp, (int)len)) > 0) { 463 while ((n = read(s, (char *)cp, (int)len)) > 0) {
198 cp += n; 464 cp += n;
199 len -= n; 465 if ((len -= n) <= 0)
466 break;
200 } 467 }
201 if (n <= 0) { 468 if (n <= 0) {
202 terrno = errno; 469 terrno = errno;
203#ifdef DEBUG 470 Perror(stderr, "read failed", errno);
204 if (_res.options & RES_DEBUG) 471 res_close();
205 perror("read failed");
206#endif
207 (void) close(s);
208 s = -1;
209 /* 472 /*
210 * A long running process might get its TCP 473 * A long running process might get its TCP
211 * connection reset if the remote server was 474 * connection reset if the remote server was
@@ -217,35 +480,32 @@ res_send(buf, buflen, answer, anslen)
217 */ 480 */
218 if (terrno == ECONNRESET && !connreset) { 481 if (terrno == ECONNRESET && !connreset) {
219 connreset = 1; 482 connreset = 1;
220 ns--; 483 res_close();
484 goto same_ns;
221 } 485 }
222 continue; 486 res_close();
487 goto next_ns;
223 } 488 }
224 cp = answer; 489 resplen = _getshort(ans);
225 if ((resplen = ntohs(*(u_short *)cp)) > anslen) { 490 if (resplen > anssiz) {
226#ifdef DEBUG 491 Dprint(_resp->options & RES_DEBUG,
227 if (_res.options & RES_DEBUG) 492 (stdout, ";; response truncated\n")
228 fprintf(stderr, 493 );
229 ";; response truncated\n");
230#endif
231 len = anslen;
232 truncated = 1; 494 truncated = 1;
495 len = anssiz;
233 } else 496 } else
234 len = resplen; 497 len = resplen;
498 cp = ans;
235 while (len != 0 && 499 while (len != 0 &&
236 (n = read(s, (char *)cp, (int)len)) > 0) { 500 (n = read(s, (char *)cp, (int)len)) > 0) {
237 cp += n; 501 cp += n;
238 len -= n; 502 len -= n;
239 } 503 }
240 if (n <= 0) { 504 if (n <= 0) {
241 terrno = errno; 505 terrno = errno;
242#ifdef DEBUG 506 Perror(stderr, "read(vc)", errno);
243 if (_res.options & RES_DEBUG) 507 res_close();
244 perror("read failed"); 508 goto next_ns;
245#endif
246 (void) close(s);
247 s = -1;
248 continue;
249 } 509 }
250 if (truncated) { 510 if (truncated) {
251 /* 511 /*
@@ -253,40 +513,79 @@ res_send(buf, buflen, answer, anslen)
253 * so connection stays in synch. 513 * so connection stays in synch.
254 */ 514 */
255 anhp->tc = 1; 515 anhp->tc = 1;
256 len = resplen - anslen; 516 len = resplen - anssiz;
257 while (len != 0) { 517 while (len != 0) {
258 n = (len > sizeof(junk) ? 518 char junk[PACKETSZ];
259 sizeof(junk) : len); 519
520 n = (len > sizeof(junk)
521 ? sizeof(junk)
522 : len);
260 if ((n = read(s, junk, n)) > 0) 523 if ((n = read(s, junk, n)) > 0)
261 len -= n; 524 len -= n;
262 else 525 else
263 break; 526 break;
264 } 527 }
265 } 528 }
529 /*
530 * The calling applicating has bailed out of
531 * a previous call and failed to arrange to have
532 * the circuit closed or the server has got
533 * itself confused. Anyway drop the packet and
534 * wait for the correct one.
535 */
536 if (hp->id != anhp->id) {
537 DprintQ((_resp->options & RES_DEBUG) ||
538 (_resp->pfcode & RES_PRF_REPLY),
539 (stdout, ";; old answer (unexpected):\n"),
540 ans, (resplen>anssiz)?anssiz:resplen);
541 goto read_len;
542 }
266 } else { 543 } else {
267 /* 544 /*
268 * Use datagrams. 545 * Use datagrams.
269 */ 546 */
270 if (s < 0) { 547 struct pollfd pfd;
271 s = socket(AF_INET, SOCK_DGRAM, 0); 548 int timeout;
549 struct sockaddr_storage from;
550 socklen_t fromlen;
551
552 if ((s < 0) || vc || (af != nsap->sa_family)) {
553 if (vc)
554 res_close();
555 af = nsap->sa_family;
556 s = socket(af, SOCK_DGRAM, 0);
272 if (s < 0) { 557 if (s < 0) {
558#if !CAN_RECONNECT
559 bad_dg_sock:
560#endif
273 terrno = errno; 561 terrno = errno;
274#ifdef DEBUG 562 Perror(stderr, "socket(dg)", errno);
275 if (_res.options & RES_DEBUG) 563#if 0
276 perror("socket (dg) failed"); 564 return (-1);
565#else
566 badns |= (1 << ns);
567 res_close();
568 goto next_ns;
277#endif 569#endif
278 continue;
279 } 570 }
571#ifdef IPV6_MINMTU
572 if (af == AF_INET6) {
573 const int yes = 1;
574 (void)setsockopt(s, IPPROTO_IPV6,
575 IPV6_USE_MIN_MTU, &yes,
576 sizeof(yes));
577 }
578#endif
579 connected = 0;
280 } 580 }
281 /* 581 /*
282 * I'm tired of answering this question, so:
283 * On a 4.3BSD+ machine (client and server, 582 * On a 4.3BSD+ machine (client and server,
284 * actually), sending to a nameserver datagram 583 * actually), sending to a nameserver datagram
285 * port with no nameserver will cause an 584 * port with no nameserver will cause an
286 * ICMP port unreachable message to be returned. 585 * ICMP port unreachable message to be returned.
287 * If our datagram socket is "connected" to the 586 * If our datagram socket is "connected" to the
288 * server, we get an ECONNREFUSED error on the next 587 * server, we get an ECONNREFUSED error on the next
289 * socket operation, and select returns if the 588 * socket operation, and poll returns if the
290 * error message is received. We can thus detect 589 * error message is received. We can thus detect
291 * the absence of a nameserver without timing out. 590 * the absence of a nameserver without timing out.
292 * If we have sent queries to at least two servers, 591 * If we have sent queries to at least two servers,
@@ -294,31 +593,28 @@ res_send(buf, buflen, answer, anslen)
294 * as we wish to receive answers from the first 593 * as we wish to receive answers from the first
295 * server to respond. 594 * server to respond.
296 */ 595 */
297 if (_res.nscount == 1 || (try == 0 && ns == 0)) { 596 if (!(_resp->options & RES_INSECURE1) &&
597 (_resp->nscount == 1 || (try == 0 && ns == 0))) {
298 /* 598 /*
299 * Don't use connect if we might 599 * Connect only if we are sure we won't
300 * still receive a response 600 * receive a response from another server.
301 * from another server.
302 */ 601 */
303 if (connected == 0) { 602 if (!connected) {
304 if (connect(s, 603 if (connect(s, nsap, salen) < 0) {
305 (struct sockaddr *) 604 Aerror(stderr,
306 &_res.nsaddr_list[ns], 605 "connect(dg)",
307 sizeof(struct sockaddr)) < 0) { 606 errno, nsap);
308#ifdef DEBUG 607 badns |= (1 << ns);
309 if (_res.options & RES_DEBUG) 608 res_close();
310 perror("connect"); 609 goto next_ns;
311#endif
312 continue;
313 } 610 }
314 connected = 1; 611 connected = 1;
315 } 612 }
316 if (send(s, buf, buflen, 0) != buflen) { 613 if (send(s, (char*)buf, buflen, 0) != buflen) {
317#ifdef DEBUG 614 Perror(stderr, "send", errno);
318 if (_res.options & RES_DEBUG) 615 badns |= (1 << ns);
319 perror("send"); 616 res_close();
320#endif 617 goto next_ns;
321 continue;
322 } 618 }
323 } else { 619 } else {
324 /* 620 /*
@@ -326,134 +622,213 @@ res_send(buf, buflen, answer, anslen)
326 * for responses from more than one server. 622 * for responses from more than one server.
327 */ 623 */
328 if (connected) { 624 if (connected) {
329 (void) connect(s, &no_addr, 625#if CAN_RECONNECT
330 sizeof(no_addr)); 626#ifdef INET6
627 /* XXX: any errornous address */
628#endif /* INET6 */
629 struct sockaddr_in no_addr;
630
631 no_addr.sin_family = AF_INET;
632 no_addr.sin_addr.s_addr = INADDR_ANY;
633 no_addr.sin_port = 0;
634 (void) connect(s,
635 (struct sockaddr *)
636 &no_addr,
637 sizeof(no_addr));
638#else
639 int s1 = socket(af, SOCK_DGRAM,0);
640 if (s1 < 0)
641 goto bad_dg_sock;
642 (void) dup2(s1, s);
643 (void) close(s1);
644 Dprint(_resp->options & RES_DEBUG,
645 (stdout, ";; new DG socket\n"))
646#endif
647#ifdef IPV6_MINMTU
648 if (af == AF_INET6) {
649 const int yes = 1;
650 (void)setsockopt(s, IPPROTO_IPV6,
651 IPV6_USE_MIN_MTU, &yes,
652 sizeof(yes));
653 }
654#endif
331 connected = 0; 655 connected = 0;
656 errno = 0;
332 } 657 }
333 if (sendto(s, buf, buflen, 0, 658 if (sendto(s, (char*)buf, buflen, 0,
334 (struct sockaddr *)&_res.nsaddr_list[ns], 659 nsap, salen) != buflen) {
335 sizeof(struct sockaddr)) != buflen) { 660 Aerror(stderr, "sendto", errno, nsap);
336#ifdef DEBUG 661 badns |= (1 << ns);
337 if (_res.options & RES_DEBUG) 662 res_close();
338 perror("sendto"); 663 goto next_ns;
339#endif
340 continue;
341 } 664 }
342 } 665 }
343 666
344 /* 667 /*
345 * Wait for reply 668 * Wait for reply
346 */ 669 */
347 timeout.tv_sec = (_res.retrans << try); 670 timeout = 1000 * (_resp->retrans << try);
348 if (try > 0) 671 if (try > 0)
349 timeout.tv_sec /= _res.nscount; 672 timeout /= _resp->nscount;
350 if ((long) timeout.tv_sec <= 0) 673 if (timeout < 1000)
351 timeout.tv_sec = 1; 674 timeout = 1000;
352 timeout.tv_usec = 0; 675 wait:
353wait: 676 pfd.fd = s;
354 FD_ZERO(&dsmask); 677 pfd.events = POLLIN;
355 FD_SET(s, &dsmask); 678 n = poll(&pfd, 1, timeout);
356 n = select(s+1, &dsmask, (fd_set *)NULL,
357 (fd_set *)NULL, &timeout);
358 if (n < 0) { 679 if (n < 0) {
359#ifdef DEBUG 680 if (errno == EINTR)
360 if (_res.options & RES_DEBUG) 681 goto wait;
361 perror("select"); 682 Perror(stderr, "poll", errno);
362#endif 683 res_close();
363 continue; 684 goto next_ns;
364 } 685 }
365 if (n == 0) { 686 if (n == 0) {
366 /* 687 /*
367 * timeout 688 * timeout
368 */ 689 */
369#ifdef DEBUG 690 Dprint(_resp->options & RES_DEBUG,
370 if (_res.options & RES_DEBUG) 691 (stdout, ";; timeout\n"));
371 printf(";; timeout\n");
372#endif
373 gotsomewhere = 1; 692 gotsomewhere = 1;
374 continue; 693 res_close();
694 goto next_ns;
375 } 695 }
376 if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 696 errno = 0;
377#ifdef DEBUG 697 fromlen = sizeof(from);
378 if (_res.options & RES_DEBUG) 698 resplen = recvfrom(s, (char*)ans, anssiz, 0,
379 perror("recvfrom"); 699 (struct sockaddr *)&from, &fromlen);
380#endif 700 if (resplen <= 0) {
381 continue; 701 Perror(stderr, "recvfrom", errno);
702 res_close();
703 goto next_ns;
382 } 704 }
383 gotsomewhere = 1; 705 gotsomewhere = 1;
384 if (id != anhp->id) { 706 if (hp->id != anhp->id) {
385 /* 707 /*
386 * response from old query, ignore it 708 * response from old query, ignore it.
709 * XXX - potential security hazard could
710 * be detected here.
387 */ 711 */
388#ifdef DEBUG 712 DprintQ((_resp->options & RES_DEBUG) ||
389 if ((_res.options & RES_DEBUG) || 713 (_resp->pfcode & RES_PRF_REPLY),
390 (_res.pfcode & RES_PRF_REPLY)) { 714 (stdout, ";; old answer:\n"),
391 printf(";; old answer:\n"); 715 ans, (resplen>anssiz)?anssiz:resplen);
392 __p_query(answer); 716 goto wait;
393 } 717 }
718#if CHECK_SRVR_ADDR
719 if (!(_resp->options & RES_INSECURE1) &&
720 !res_isourserver((struct sockaddr_in *)&from)) {
721 /*
722 * response from wrong server? ignore it.
723 * XXX - potential security hazard could
724 * be detected here.
725 */
726 DprintQ((_resp->options & RES_DEBUG) ||
727 (_resp->pfcode & RES_PRF_REPLY),
728 (stdout, ";; not our server:\n"),
729 ans, (resplen>anssiz)?anssiz:resplen);
730 goto wait;
731 }
394#endif 732#endif
733 if (!(_resp->options & RES_INSECURE2) &&
734 !res_queriesmatch(buf, buf + buflen,
735 ans, ans + anssiz)) {
736 /*
737 * response contains wrong query? ignore it.
738 * XXX - potential security hazard could
739 * be detected here.
740 */
741 DprintQ((_resp->options & RES_DEBUG) ||
742 (_resp->pfcode & RES_PRF_REPLY),
743 (stdout, ";; wrong query name:\n"),
744 ans, (resplen>anssiz)?anssiz:resplen);
395 goto wait; 745 goto wait;
396 } 746 }
397 if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || 747 if (anhp->rcode == SERVFAIL ||
748 anhp->rcode == NOTIMP ||
398 anhp->rcode == REFUSED) { 749 anhp->rcode == REFUSED) {
399#ifdef DEBUG 750 DprintQ(_resp->options & RES_DEBUG,
400 if (_res.options & RES_DEBUG) { 751 (stdout, "server rejected query:\n"),
401 printf("server rejected query:\n"); 752 ans, (resplen>anssiz)?anssiz:resplen);
402 __p_query(answer); 753 badns |= (1 << ns);
403 } 754 res_close();
404#endif 755 /* don't retry if called from dig */
405 badns |= (1<<ns); 756 if (!_resp->pfcode)
406 continue; 757 goto next_ns;
407 } 758 }
408 if (!(_res.options & RES_IGNTC) && anhp->tc) { 759 if (!(_resp->options & RES_IGNTC) && anhp->tc) {
409 /* 760 /*
410 * get rest of answer; 761 * get rest of answer;
411 * use TCP with same server. 762 * use TCP with same server.
412 */ 763 */
413#ifdef DEBUG 764 Dprint(_resp->options & RES_DEBUG,
414 if (_res.options & RES_DEBUG) 765 (stdout, ";; truncated answer\n"));
415 printf(";; truncated answer\n");
416#endif
417 (void) close(s);
418 s = -1;
419 v_circuit = 1; 766 v_circuit = 1;
420 goto usevc; 767 res_close();
768 goto same_ns;
421 } 769 }
422 } 770 } /*if vc/dg*/
423#ifdef DEBUG 771 Dprint((_resp->options & RES_DEBUG) ||
424 if (_res.options & RES_DEBUG) 772 ((_resp->pfcode & RES_PRF_REPLY) &&
425 printf(";; got answer:\n"); 773 (_resp->pfcode & RES_PRF_HEAD1)),
426 if ((_res.options & RES_DEBUG) || 774 (stdout, ";; got answer:\n"));
427 (_res.pfcode & RES_PRF_REPLY)) 775 DprintQ((_resp->options & RES_DEBUG) ||
428 __p_query(answer); 776 (_resp->pfcode & RES_PRF_REPLY),
429#endif 777 (stdout, "%s", ""),
778 ans, (resplen>anssiz)?anssiz:resplen);
430 /* 779 /*
431 * If using virtual circuits, we assume that the first server 780 * If using virtual circuits, we assume that the first server
432 * is preferred * over the rest (i.e. it is on the local 781 * is preferred over the rest (i.e. it is on the local
433 * machine) and only keep that one open. 782 * machine) and only keep that one open.
434 * If we have temporarily opened a virtual circuit, 783 * If we have temporarily opened a virtual circuit,
435 * or if we haven't been asked to keep a socket open, 784 * or if we haven't been asked to keep a socket open,
436 * close the socket. 785 * close the socket.
437 */ 786 */
438 if ((v_circuit && 787 if ((v_circuit && (!(_resp->options & RES_USEVC) || ns != 0)) ||
439 ((_res.options & RES_USEVC) == 0 || ns != 0)) || 788 !(_resp->options & RES_STAYOPEN)) {
440 (_res.options & RES_STAYOPEN) == 0) { 789 res_close();
441 (void) close(s); 790 }
442 s = -1; 791 if (Rhook) {
792 int done = 0, loops = 0;
793
794 do {
795 res_sendhookact act;
796
797 act = (*Rhook)((struct sockaddr_in *)nsap,
798 buf, buflen,
799 ans, anssiz, &resplen);
800 switch (act) {
801 case res_goahead:
802 case res_done:
803 done = 1;
804 break;
805 case res_nextns:
806 res_close();
807 goto next_ns;
808 case res_modified:
809 /* give the hook another try */
810 if (++loops < 42) /*doug adams*/
811 break;
812 /*FALLTHROUGH*/
813 case res_error:
814 /*FALLTHROUGH*/
815 default:
816 return (-1);
817 }
818 } while (!done);
819
443 } 820 }
444 return (resplen); 821 return (resplen);
445 } 822 next_ns: ;
446 } 823 } /*foreach ns*/
447 if (s >= 0) { 824 } /*foreach retry*/
448 (void) close(s); 825 res_close();
449 s = -1; 826 if (!v_circuit) {
450 } 827 if (!gotsomewhere)
451 if (v_circuit == 0)
452 if (gotsomewhere == 0)
453 errno = ECONNREFUSED; /* no nameservers found */ 828 errno = ECONNREFUSED; /* no nameservers found */
454 else 829 else
455 errno = ETIMEDOUT; /* no answer obtained */ 830 errno = ETIMEDOUT; /* no answer obtained */
456 else 831 } else
457 errno = terrno; 832 errno = terrno;
458 return (-1); 833 return (-1);
459} 834}
@@ -465,10 +840,14 @@ wait:
465 * 840 *
466 * This routine is not expected to be user visible. 841 * This routine is not expected to be user visible.
467 */ 842 */
468_res_close() 843void
844res_close(void)
469{ 845{
470 if (s != -1) { 846 if (s >= 0) {
471 (void) close(s); 847 (void) close(s);
472 s = -1; 848 s = -1;
849 connected = 0;
850 vc = 0;
851 af = 0;
473 } 852 }
474} 853}