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.c718
1 files changed, 499 insertions, 219 deletions
diff --git a/src/lib/libc/net/res_send.c b/src/lib/libc/net/res_send.c
index e608358180..f0e9b098b6 100644
--- a/src/lib/libc/net/res_send.c
+++ b/src/lib/libc/net/res_send.c
@@ -1,9 +1,9 @@
1/* $NetBSD: res_send.c,v 1.4 1995/02/25 06:21:01 cgd Exp $ */ 1/* $NetBSD: res_send.c,v 1.5 1996/02/02 15:22:36 mrg Exp $ */
2 2
3/*- 3/*-
4 * Copyright (c) 1985, 1989, 1993 4 * Copyright (c) 1985, 1989, 1993
5 * The Regents of the University of California. All rights reserved. 5 * The Regents of the University of California. All rights reserved.
6 * 6 *
7 * Redistribution and use in source and binary forms, with or without 7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions 8 * modification, are permitted provided that the following conditions
9 * are met: 9 * are met:
@@ -14,12 +14,12 @@
14 * documentation and/or other materials provided with the distribution. 14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software 15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement: 16 * must display the following acknowledgement:
17 * This product includes software developed by the University of 17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors. 18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of 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 20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission. 21 * without specific prior written permission.
22 * 22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
@@ -56,12 +56,19 @@
56#if defined(LIBC_SCCS) && !defined(lint) 56#if defined(LIBC_SCCS) && !defined(lint)
57#if 0 57#if 0
58static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; 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 "; 59static char rcsid[] = "$Id: res_send.c,v 8.7 1995/12/03 08:31:17 vixie Exp ";
60#else 60#else
61static char rcsid[] = "$NetBSD: res_send.c,v 1.4 1995/02/25 06:21:01 cgd Exp $"; 61static char rcsid[] = "$NetBSD: res_send.c,v 1.5 1996/02/02 15:22:36 mrg Exp $";
62#endif 62#endif
63#endif /* LIBC_SCCS and not lint */ 63#endif /* LIBC_SCCS and not lint */
64 64
65 /* change this to "0"
66 * if you talk to a lot
67 * of multi-homed SunOS
68 * ("broken") name servers.
69 */
70#define CHECK_SRVR_ADDR 1 /* XXX - should be in options.h */
71
65/* 72/*
66 * Send query to name server and wait for reply. 73 * Send query to name server and wait for reply.
67 */ 74 */
@@ -73,139 +80,335 @@ static char rcsid[] = "$NetBSD: res_send.c,v 1.4 1995/02/25 06:21:01 cgd Exp $";
73#include <netinet/in.h> 80#include <netinet/in.h>
74#include <arpa/nameser.h> 81#include <arpa/nameser.h>
75#include <arpa/inet.h> 82#include <arpa/inet.h>
83
76#include <stdio.h> 84#include <stdio.h>
85#include <netdb.h>
77#include <errno.h> 86#include <errno.h>
78#include <resolv.h> 87#include <resolv.h>
79#include <unistd.h> 88#if defined(BSD) && (BSD >= 199306)
80#include <string.h> 89# include <stdlib.h>
90# include <string.h>
91# include <unistd.h>
92#else
93# include "../conf/portability.h"
94#endif
95
96#if defined(USE_OPTIONS_H)
97# include <../conf/options.h>
98#endif
99
100void _res_close __P((void));
81 101
82static int s = -1; /* socket used for communications */ 102static int s = -1; /* socket used for communications */
83static struct sockaddr no_addr; 103static int connected = 0; /* is the socket connected */
84 104static int vc = 0; /* is the socket a virtual ciruit? */
85#ifndef FD_SET 105
86#define NFDBITS 32 106#define CAN_RECONNECT 1
87#define FD_SETSIZE 32 107
88#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 108#ifndef DEBUG
89#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 109# define Dprint(cond, args) /*empty*/
90#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 110# define DprintQ(cond, args, query, size) /*empty*/
91#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 111# define Aerror(file, string, error, address) /*empty*/
112# define Perror(file, string, error) /*empty*/
113#else
114# define Dprint(cond, args) if (cond) {fprintf args;} else {}
115# define DprintQ(cond, args, query, size) if (cond) {\
116 fprintf args;\
117 __fp_nquery(query, size, stdout);\
118 } else {}
119 static void
120 Aerror(file, string, error, address)
121 FILE *file;
122 char *string;
123 int error;
124 struct sockaddr_in address;
125 {
126 int save = errno;
127
128 if (_res.options & RES_DEBUG) {
129 fprintf(file, "res_send: %s ([%s].%u): %s\n",
130 string,
131 inet_ntoa(address.sin_addr),
132 ntohs(address.sin_port),
133 strerror(error));
134 }
135 errno = save;
136 }
137 static void
138 Perror(file, string, error)
139 FILE *file;
140 char *string;
141 int error;
142 {
143 int save = errno;
144
145 if (_res.options & RES_DEBUG) {
146 fprintf(file, "res_send: %s: %s\n",
147 string, strerror(error));
148 }
149 errno = save;
150 }
92#endif 151#endif
93 152
94res_send(buf, buflen, answer, anslen) 153static res_send_qhook Qhook = NULL;
95 const char *buf; 154static res_send_rhook Rhook = NULL;
155
156void
157res_send_setqhook(hook)
158 res_send_qhook hook;
159{
160
161 Qhook = hook;
162}
163
164void
165res_send_setrhook(hook)
166 res_send_rhook hook;
167{
168
169 Rhook = hook;
170}
171
172/* int
173 * res_isourserver(ina)
174 * looks up "ina" in _res.ns_addr_list[]
175 * returns:
176 * 0 : not found
177 * >0 : found
178 * author:
179 * paul vixie, 29may94
180 */
181int
182res_isourserver(inp)
183 const struct sockaddr_in *inp;
184{
185 struct sockaddr_in ina;
186 register int ns, ret;
187
188 ina = *inp;
189 ret = 0;
190 for (ns = 0; ns < _res.nscount; ns++) {
191 register const struct sockaddr_in *srv = &_res.nsaddr_list[ns];
192
193 if (srv->sin_family == ina.sin_family &&
194 srv->sin_port == ina.sin_port &&
195 (srv->sin_addr.s_addr == INADDR_ANY ||
196 srv->sin_addr.s_addr == ina.sin_addr.s_addr)) {
197 ret++;
198 break;
199 }
200 }
201 return (ret);
202}
203
204/* int
205 * res_nameinquery(name, type, class, buf, eom)
206 * look for (name,type,class) in the query section of packet (buf,eom)
207 * returns:
208 * -1 : format error
209 * 0 : not found
210 * >0 : found
211 * author:
212 * paul vixie, 29may94
213 */
214int
215res_nameinquery(name, type, class, buf, eom)
216 const char *name;
217 register int type, class;
218 const u_char *buf, *eom;
219{
220 register const u_char *cp = buf + HFIXEDSZ;
221 int qdcount = ntohs(((HEADER*)buf)->qdcount);
222
223 while (qdcount-- > 0) {
224 char tname[MAXDNAME+1];
225 register int n, ttype, tclass;
226
227 n = dn_expand(buf, eom, cp, tname, sizeof tname);
228 if (n < 0)
229 return (-1);
230 cp += n;
231 ttype = _getshort(cp); cp += INT16SZ;
232 tclass = _getshort(cp); cp += INT16SZ;
233 if (ttype == type &&
234 tclass == class &&
235 strcasecmp(tname, name) == 0)
236 return (1);
237 }
238 return (0);
239}
240
241/* int
242 * res_queriesmatch(buf1, eom1, buf2, eom2)
243 * is there a 1:1 mapping of (name,type,class)
244 * in (buf1,eom1) and (buf2,eom2)?
245 * returns:
246 * -1 : format error
247 * 0 : not a 1:1 mapping
248 * >0 : is a 1:1 mapping
249 * author:
250 * paul vixie, 29may94
251 */
252int
253res_queriesmatch(buf1, eom1, buf2, eom2)
254 const u_char *buf1, *eom1;
255 const u_char *buf2, *eom2;
256{
257 register const u_char *cp = buf1 + HFIXEDSZ;
258 int qdcount = ntohs(((HEADER*)buf1)->qdcount);
259
260 if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
261 return (0);
262 while (qdcount-- > 0) {
263 char tname[MAXDNAME+1];
264 register int n, ttype, tclass;
265
266 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
267 if (n < 0)
268 return (-1);
269 cp += n;
270 ttype = _getshort(cp); cp += INT16SZ;
271 tclass = _getshort(cp); cp += INT16SZ;
272 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
273 return (0);
274 }
275 return (1);
276}
277
278int
279res_send(buf, buflen, ans, anssiz)
280 const u_char *buf;
96 int buflen; 281 int buflen;
97 char *answer; 282 u_char *ans;
98 int anslen; 283 int anssiz;
99{ 284{
100 register int n;
101 int try, v_circuit, resplen, ns;
102 int gotsomewhere = 0, connected = 0;
103 int connreset = 0;
104 u_short id, len;
105 char *cp;
106 fd_set dsmask;
107 struct timeval timeout;
108 HEADER *hp = (HEADER *) buf; 285 HEADER *hp = (HEADER *) buf;
109 HEADER *anhp = (HEADER *) answer; 286 HEADER *anhp = (HEADER *) ans;
110 u_int badns; /* XXX NSMAX can't exceed #/bits per this */ 287 int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns;
111 struct iovec iov[2]; 288 register int n;
112 int terrno = ETIMEDOUT; 289 u_int badns; /* XXX NSMAX can't exceed #/bits in this var */
113 char junk[512]; 290
114 291 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
115#ifdef DEBUG 292 /* errno should have been set by res_init() in this case. */
116 if ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY)) { 293 return (-1);
117 printf(";; res_send()\n");
118 __p_query(buf);
119 } 294 }
120#endif 295 DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),
121 if (!(_res.options & RES_INIT)) 296 (stdout, ";; res_send()\n"), buf, buflen);
122 if (res_init() == -1) {
123 return(-1);
124 }
125 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 297 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
126 id = hp->id; 298 gotsomewhere = 0;
299 connreset = 0;
300 terrno = ETIMEDOUT;
127 badns = 0; 301 badns = 0;
302
128 /* 303 /*
129 * Send request, RETRY times, or until successful 304 * Send request, RETRY times, or until successful
130 */ 305 */
131 for (try = 0; try < _res.retry; try++) { 306 for (try = 0; try < _res.retry; try++) {
132 for (ns = 0; ns < _res.nscount; ns++) { 307 for (ns = 0; ns < _res.nscount; ns++) {
133 if (badns & (1<<ns)) 308 struct sockaddr_in *nsap = &_res.nsaddr_list[ns];
134 continue; 309 same_ns:
135#ifdef DEBUG 310 if (badns & (1 << ns)) {
136 if (_res.options & RES_DEBUG) 311 _res_close();
137 printf(";; Querying server (# %d) address = %s\n", 312 goto next_ns;
138 ns+1, 313 }
139 inet_ntoa(_res.nsaddr_list[ns].sin_addr)); 314
140#endif 315 if (Qhook) {
141 usevc: 316 int done = 0, loops = 0;
317
318 do {
319 res_sendhookact act;
320
321 act = (*Qhook)(&nsap, &buf, &buflen,
322 ans, anssiz, &resplen);
323 switch (act) {
324 case res_goahead:
325 done = 1;
326 break;
327 case res_nextns:
328 _res_close();
329 goto next_ns;
330 case res_done:
331 return (resplen);
332 case res_modified:
333 /* give the hook another try */
334 if (++loops < 42) /*doug adams*/
335 break;
336 /*FALLTHROUGH*/
337 case res_error:
338 /*FALLTHROUGH*/
339 default:
340 return (-1);
341 }
342 } while (!done);
343 }
344
345 Dprint(_res.options & RES_DEBUG,
346 (stdout, ";; Querying server (# %d) address = %s\n",
347 ns + 1, inet_ntoa(nsap->sin_addr)));
348
142 if (v_circuit) { 349 if (v_circuit) {
143 int truncated = 0; 350 int truncated;
351 struct iovec iov[2];
352 u_short len;
353 u_char *cp;
144 354
145 /* 355 /*
146 * Use virtual circuit; 356 * Use virtual circuit;
147 * at most one attempt per server. 357 * at most one attempt per server.
148 */ 358 */
149 try = _res.retry; 359 try = _res.retry;
150 if (s < 0) { 360 truncated = 0;
151 s = socket(AF_INET, SOCK_STREAM, 0); 361 if ((s < 0) || (!vc)) {
362 if (s >= 0)
363 _res_close();
364
365 s = socket(PF_INET, SOCK_STREAM, 0);
152 if (s < 0) { 366 if (s < 0) {
153 terrno = errno; 367 terrno = errno;
154#ifdef DEBUG 368 Perror(stderr, "socket(vc)", errno);
155 if (_res.options & RES_DEBUG) 369 return (-1);
156 perror("socket (vc) failed");
157#endif
158 continue;
159 } 370 }
160 if (connect(s, 371 errno = 0;
161 (struct sockaddr *)&(_res.nsaddr_list[ns]), 372 if (connect(s, (struct sockaddr *)nsap,
162 sizeof(struct sockaddr)) < 0) { 373 sizeof(struct sockaddr)) < 0) {
163 terrno = errno; 374 terrno = errno;
164#ifdef DEBUG 375 Aerror(stderr, "connect/vc",
165 if (_res.options & RES_DEBUG) 376 errno, *nsap);
166 perror("connect failed"); 377 badns |= (1 << ns);
167#endif 378 _res_close();
168 (void) close(s); 379 goto next_ns;
169 s = -1;
170 continue;
171 } 380 }
381 vc = 1;
172 } 382 }
173 /* 383 /*
174 * Send length & message 384 * Send length & message
175 */ 385 */
176 len = htons((u_short)buflen); 386 putshort((u_short)buflen, (u_char*)&len);
177 iov[0].iov_base = (caddr_t)&len; 387 iov[0].iov_base = (caddr_t)&len;
178 iov[0].iov_len = sizeof(len); 388 iov[0].iov_len = INT16SZ;
179 iov[1].iov_base = (char *)buf; 389 iov[1].iov_base = (caddr_t)buf;
180 iov[1].iov_len = buflen; 390 iov[1].iov_len = buflen;
181 if (writev(s, iov, 2) != sizeof(len) + buflen) { 391 if (writev(s, iov, 2) != (INT16SZ + buflen)) {
182 terrno = errno; 392 terrno = errno;
183#ifdef DEBUG 393 Perror(stderr, "write failed", errno);
184 if (_res.options & RES_DEBUG) 394 badns |= (1 << ns);
185 perror("write failed"); 395 _res_close();
186#endif 396 goto next_ns;
187 (void) close(s);
188 s = -1;
189 continue;
190 } 397 }
191 /* 398 /*
192 * Receive length & response 399 * Receive length & response
193 */ 400 */
194 cp = answer; 401 cp = ans;
195 len = sizeof(short); 402 len = INT16SZ;
196 while (len != 0 && 403 while ((n = read(s, (char *)cp, (int)len)) > 0) {
197 (n = read(s, (char *)cp, (int)len)) > 0) {
198 cp += n; 404 cp += n;
199 len -= n; 405 if ((len -= n) <= 0)
406 break;
200 } 407 }
201 if (n <= 0) { 408 if (n <= 0) {
202 terrno = errno; 409 terrno = errno;
203#ifdef DEBUG 410 Perror(stderr, "read failed", errno);
204 if (_res.options & RES_DEBUG) 411 _res_close();
205 perror("read failed");
206#endif
207 (void) close(s);
208 s = -1;
209 /* 412 /*
210 * A long running process might get its TCP 413 * A long running process might get its TCP
211 * connection reset if the remote server was 414 * connection reset if the remote server was
@@ -217,35 +420,32 @@ res_send(buf, buflen, answer, anslen)
217 */ 420 */
218 if (terrno == ECONNRESET && !connreset) { 421 if (terrno == ECONNRESET && !connreset) {
219 connreset = 1; 422 connreset = 1;
220 ns--; 423 _res_close();
424 goto same_ns;
221 } 425 }
222 continue; 426 _res_close();
427 goto next_ns;
223 } 428 }
224 cp = answer; 429 resplen = _getshort(ans);
225 if ((resplen = ntohs(*(u_short *)cp)) > anslen) { 430 if (resplen > anssiz) {
226#ifdef DEBUG 431 Dprint(_res.options & RES_DEBUG,
227 if (_res.options & RES_DEBUG) 432 (stdout, ";; response truncated\n")
228 fprintf(stderr, 433 );
229 ";; response truncated\n");
230#endif
231 len = anslen;
232 truncated = 1; 434 truncated = 1;
435 len = anssiz;
233 } else 436 } else
234 len = resplen; 437 len = resplen;
438 cp = ans;
235 while (len != 0 && 439 while (len != 0 &&
236 (n = read(s, (char *)cp, (int)len)) > 0) { 440 (n = read(s, (char *)cp, (int)len)) > 0) {
237 cp += n; 441 cp += n;
238 len -= n; 442 len -= n;
239 } 443 }
240 if (n <= 0) { 444 if (n <= 0) {
241 terrno = errno; 445 terrno = errno;
242#ifdef DEBUG 446 Perror(stderr, "read(vc)", errno);
243 if (_res.options & RES_DEBUG) 447 _res_close();
244 perror("read failed"); 448 goto next_ns;
245#endif
246 (void) close(s);
247 s = -1;
248 continue;
249 } 449 }
250 if (truncated) { 450 if (truncated) {
251 /* 451 /*
@@ -253,10 +453,13 @@ res_send(buf, buflen, answer, anslen)
253 * so connection stays in synch. 453 * so connection stays in synch.
254 */ 454 */
255 anhp->tc = 1; 455 anhp->tc = 1;
256 len = resplen - anslen; 456 len = resplen - anssiz;
257 while (len != 0) { 457 while (len != 0) {
258 n = (len > sizeof(junk) ? 458 char junk[PACKETSZ];
259 sizeof(junk) : len); 459
460 n = (len > sizeof(junk)
461 ? sizeof(junk)
462 : len);
260 if ((n = read(s, junk, n)) > 0) 463 if ((n = read(s, junk, n)) > 0)
261 len -= n; 464 len -= n;
262 else 465 else
@@ -267,19 +470,26 @@ res_send(buf, buflen, answer, anslen)
267 /* 470 /*
268 * Use datagrams. 471 * Use datagrams.
269 */ 472 */
270 if (s < 0) { 473 struct timeval timeout;
271 s = socket(AF_INET, SOCK_DGRAM, 0); 474 fd_set dsmask;
475 struct sockaddr_in from;
476 int fromlen;
477
478 if ((s < 0) || vc) {
479 if (vc)
480 _res_close();
481 s = socket(PF_INET, SOCK_DGRAM, 0);
272 if (s < 0) { 482 if (s < 0) {
273 terrno = errno; 483#if !CAN_RECONNECT
274#ifdef DEBUG 484 bad_dg_sock:
275 if (_res.options & RES_DEBUG)
276 perror("socket (dg) failed");
277#endif 485#endif
278 continue; 486 terrno = errno;
487 Perror(stderr, "socket(dg)", errno);
488 return (-1);
279 } 489 }
490 connected = 0;
280 } 491 }
281 /* 492 /*
282 * I'm tired of answering this question, so:
283 * On a 4.3BSD+ machine (client and server, 493 * On a 4.3BSD+ machine (client and server,
284 * actually), sending to a nameserver datagram 494 * actually), sending to a nameserver datagram
285 * port with no nameserver will cause an 495 * port with no nameserver will cause an
@@ -296,29 +506,27 @@ res_send(buf, buflen, answer, anslen)
296 */ 506 */
297 if (_res.nscount == 1 || (try == 0 && ns == 0)) { 507 if (_res.nscount == 1 || (try == 0 && ns == 0)) {
298 /* 508 /*
299 * Don't use connect if we might 509 * Connect only if we are sure we won't
300 * still receive a response 510 * receive a response from another server.
301 * from another server.
302 */ 511 */
303 if (connected == 0) { 512 if (!connected) {
304 if (connect(s, 513 if (connect(s, (struct sockaddr *)nsap,
305 (struct sockaddr *) 514 sizeof(struct sockaddr)
306 &_res.nsaddr_list[ns], 515 ) < 0) {
307 sizeof(struct sockaddr)) < 0) { 516 Aerror(stderr,
308#ifdef DEBUG 517 "connect(dg)",
309 if (_res.options & RES_DEBUG) 518 errno, *nsap);
310 perror("connect"); 519 badns |= (1 << ns);
311#endif 520 _res_close();
312 continue; 521 goto next_ns;
313 } 522 }
314 connected = 1; 523 connected = 1;
315 } 524 }
316 if (send(s, buf, buflen, 0) != buflen) { 525 if (send(s, (char*)buf, buflen, 0) != buflen) {
317#ifdef DEBUG 526 Perror(stderr, "send", errno);
318 if (_res.options & RES_DEBUG) 527 badns |= (1 << ns);
319 perror("send"); 528 _res_close();
320#endif 529 goto next_ns;
321 continue;
322 } 530 }
323 } else { 531 } else {
324 /* 532 /*
@@ -326,18 +534,36 @@ res_send(buf, buflen, answer, anslen)
326 * for responses from more than one server. 534 * for responses from more than one server.
327 */ 535 */
328 if (connected) { 536 if (connected) {
329 (void) connect(s, &no_addr, 537#if CAN_RECONNECT
330 sizeof(no_addr)); 538 struct sockaddr_in no_addr;
539
540 no_addr.sin_family = AF_INET;
541 no_addr.sin_addr.s_addr = INADDR_ANY;
542 no_addr.sin_port = 0;
543 (void) connect(s,
544 (struct sockaddr *)
545 &no_addr,
546 sizeof(no_addr));
547#else
548 int s1 = socket(PF_INET, SOCK_DGRAM,0);
549 if (s1 < 0)
550 goto bad_dg_sock;
551 (void) dup2(s1, s);
552 (void) close(s1);
553 Dprint(_res.options & RES_DEBUG,
554 (stdout, ";; new DG socket\n"))
555#endif
331 connected = 0; 556 connected = 0;
557 errno = 0;
332 } 558 }
333 if (sendto(s, buf, buflen, 0, 559 if (sendto(s, (char*)buf, buflen, 0,
334 (struct sockaddr *)&_res.nsaddr_list[ns], 560 (struct sockaddr *)nsap,
335 sizeof(struct sockaddr)) != buflen) { 561 sizeof(struct sockaddr))
336#ifdef DEBUG 562 != buflen) {
337 if (_res.options & RES_DEBUG) 563 Aerror(stderr, "sendto", errno, *nsap);
338 perror("sendto"); 564 badns |= (1 << ns);
339#endif 565 _res_close();
340 continue; 566 goto next_ns;
341 } 567 }
342 } 568 }
343 569
@@ -350,106 +576,157 @@ res_send(buf, buflen, answer, anslen)
350 if ((long) timeout.tv_sec <= 0) 576 if ((long) timeout.tv_sec <= 0)
351 timeout.tv_sec = 1; 577 timeout.tv_sec = 1;
352 timeout.tv_usec = 0; 578 timeout.tv_usec = 0;
353wait: 579 wait:
354 FD_ZERO(&dsmask); 580 FD_ZERO(&dsmask);
355 FD_SET(s, &dsmask); 581 FD_SET(s, &dsmask);
356 n = select(s+1, &dsmask, (fd_set *)NULL, 582 n = select(s+1, &dsmask, (fd_set *)NULL,
357 (fd_set *)NULL, &timeout); 583 (fd_set *)NULL, &timeout);
358 if (n < 0) { 584 if (n < 0) {
359#ifdef DEBUG 585 Perror(stderr, "select", errno);
360 if (_res.options & RES_DEBUG) 586 _res_close();
361 perror("select"); 587 goto next_ns;
362#endif
363 continue;
364 } 588 }
365 if (n == 0) { 589 if (n == 0) {
366 /* 590 /*
367 * timeout 591 * timeout
368 */ 592 */
369#ifdef DEBUG 593 Dprint(_res.options & RES_DEBUG,
370 if (_res.options & RES_DEBUG) 594 (stdout, ";; timeout\n"));
371 printf(";; timeout\n");
372#endif
373 gotsomewhere = 1; 595 gotsomewhere = 1;
374 continue; 596 _res_close();
597 goto next_ns;
375 } 598 }
376 if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 599 errno = 0;
377#ifdef DEBUG 600 fromlen = sizeof(struct sockaddr_in);
378 if (_res.options & RES_DEBUG) 601 resplen = recvfrom(s, (char*)ans, anssiz, 0,
379 perror("recvfrom"); 602 (struct sockaddr *)&from, &fromlen);
380#endif 603 if (resplen <= 0) {
381 continue; 604 Perror(stderr, "recvfrom", errno);
605 _res_close();
606 goto next_ns;
382 } 607 }
383 gotsomewhere = 1; 608 gotsomewhere = 1;
384 if (id != anhp->id) { 609 if (hp->id != anhp->id) {
385 /* 610 /*
386 * response from old query, ignore it 611 * response from old query, ignore it.
612 * XXX - potential security hazard could
613 * be detected here.
387 */ 614 */
388#ifdef DEBUG 615 DprintQ((_res.options & RES_DEBUG) ||
389 if ((_res.options & RES_DEBUG) || 616 (_res.pfcode & RES_PRF_REPLY),
390 (_res.pfcode & RES_PRF_REPLY)) { 617 (stdout, ";; old answer:\n"),
391 printf(";; old answer:\n"); 618 ans, resplen);
392 __p_query(answer); 619 goto wait;
393 } 620 }
621#if CHECK_SRVR_ADDR
622 if (!(_res.options & RES_INSECURE1) &&
623 !res_isourserver(&from)) {
624 /*
625 * response from wrong server? ignore it.
626 * XXX - potential security hazard could
627 * be detected here.
628 */
629 DprintQ((_res.options & RES_DEBUG) ||
630 (_res.pfcode & RES_PRF_REPLY),
631 (stdout, ";; not our server:\n"),
632 ans, resplen);
633 goto wait;
634 }
394#endif 635#endif
636 if (!(_res.options & RES_INSECURE2) &&
637 !res_queriesmatch(buf, buf + buflen,
638 ans, ans + anssiz)) {
639 /*
640 * response contains wrong query? ignore it.
641 * XXX - potential security hazard could
642 * be detected here.
643 */
644 DprintQ((_res.options & RES_DEBUG) ||
645 (_res.pfcode & RES_PRF_REPLY),
646 (stdout, ";; wrong query name:\n"),
647 ans, resplen);
395 goto wait; 648 goto wait;
396 } 649 }
397 if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || 650 if (anhp->rcode == SERVFAIL ||
651 anhp->rcode == NOTIMP ||
398 anhp->rcode == REFUSED) { 652 anhp->rcode == REFUSED) {
399#ifdef DEBUG 653 DprintQ(_res.options & RES_DEBUG,
400 if (_res.options & RES_DEBUG) { 654 (stdout, "server rejected query:\n"),
401 printf("server rejected query:\n"); 655 ans, resplen);
402 __p_query(answer); 656 badns |= (1 << ns);
403 } 657 _res_close();
404#endif 658 /* don't retry if called from dig */
405 badns |= (1<<ns); 659 if (!_res.pfcode)
406 continue; 660 goto next_ns;
407 } 661 }
408 if (!(_res.options & RES_IGNTC) && anhp->tc) { 662 if (!(_res.options & RES_IGNTC) && anhp->tc) {
409 /* 663 /*
410 * get rest of answer; 664 * get rest of answer;
411 * use TCP with same server. 665 * use TCP with same server.
412 */ 666 */
413#ifdef DEBUG 667 Dprint(_res.options & RES_DEBUG,
414 if (_res.options & RES_DEBUG) 668 (stdout, ";; truncated answer\n"));
415 printf(";; truncated answer\n");
416#endif
417 (void) close(s);
418 s = -1;
419 v_circuit = 1; 669 v_circuit = 1;
420 goto usevc; 670 _res_close();
671 goto same_ns;
421 } 672 }
422 } 673 } /*if vc/dg*/
423#ifdef DEBUG 674 Dprint((_res.options & RES_DEBUG) ||
424 if (_res.options & RES_DEBUG) 675 ((_res.pfcode & RES_PRF_REPLY) &&
425 printf(";; got answer:\n"); 676 (_res.pfcode & RES_PRF_HEAD1)),
426 if ((_res.options & RES_DEBUG) || 677 (stdout, ";; got answer:\n"));
427 (_res.pfcode & RES_PRF_REPLY)) 678 DprintQ((_res.options & RES_DEBUG) ||
428 __p_query(answer); 679 (_res.pfcode & RES_PRF_REPLY),
429#endif 680 (stdout, ""),
681 ans, resplen);
430 /* 682 /*
431 * If using virtual circuits, we assume that the first server 683 * If using virtual circuits, we assume that the first server
432 * is preferred * over the rest (i.e. it is on the local 684 * is preferred over the rest (i.e. it is on the local
433 * machine) and only keep that one open. 685 * machine) and only keep that one open.
434 * If we have temporarily opened a virtual circuit, 686 * If we have temporarily opened a virtual circuit,
435 * or if we haven't been asked to keep a socket open, 687 * or if we haven't been asked to keep a socket open,
436 * close the socket. 688 * close the socket.
437 */ 689 */
438 if ((v_circuit && 690 if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
439 ((_res.options & RES_USEVC) == 0 || ns != 0)) || 691 !(_res.options & RES_STAYOPEN)) {
440 (_res.options & RES_STAYOPEN) == 0) { 692 _res_close();
441 (void) close(s); 693 }
442 s = -1; 694 if (Rhook) {
695 int done = 0, loops = 0;
696
697 do {
698 res_sendhookact act;
699
700 act = (*Rhook)(nsap, buf, buflen,
701 ans, anssiz, &resplen);
702 switch (act) {
703 case res_goahead:
704 case res_done:
705 done = 1;
706 break;
707 case res_nextns:
708 _res_close();
709 goto next_ns;
710 case res_modified:
711 /* give the hook another try */
712 if (++loops < 42) /*doug adams*/
713 break;
714 /*FALLTHROUGH*/
715 case res_error:
716 /*FALLTHROUGH*/
717 default:
718 return (-1);
719 }
720 } while (!done);
721
443 } 722 }
444 return (resplen); 723 return (resplen);
445 } 724 next_ns: ;
446 } 725 } /*foreach ns*/
447 if (s >= 0) { 726 } /*foreach retry*/
448 (void) close(s); 727 _res_close();
449 s = -1; 728 if (!v_circuit)
450 } 729 if (!gotsomewhere)
451 if (v_circuit == 0)
452 if (gotsomewhere == 0)
453 errno = ECONNREFUSED; /* no nameservers found */ 730 errno = ECONNREFUSED; /* no nameservers found */
454 else 731 else
455 errno = ETIMEDOUT; /* no answer obtained */ 732 errno = ETIMEDOUT; /* no answer obtained */
@@ -465,10 +742,13 @@ wait:
465 * 742 *
466 * This routine is not expected to be user visible. 743 * This routine is not expected to be user visible.
467 */ 744 */
745void
468_res_close() 746_res_close()
469{ 747{
470 if (s != -1) { 748 if (s >= 0) {
471 (void) close(s); 749 (void) close(s);
472 s = -1; 750 s = -1;
751 connected = 0;
752 vc = 0;
473 } 753 }
474} 754}