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