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