diff options
Diffstat (limited to 'src/lib/libc/net/res_send.c')
-rw-r--r-- | src/lib/libc/net/res_send.c | 718 |
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 |
58 | static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; | 58 | static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; |
59 | static char rcsid[] = "$Id: res_send.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel "; | 59 | static char rcsid[] = "$Id: res_send.c,v 8.7 1995/12/03 08:31:17 vixie Exp "; |
60 | #else | 60 | #else |
61 | static char rcsid[] = "$NetBSD: res_send.c,v 1.4 1995/02/25 06:21:01 cgd Exp $"; | 61 | static 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 | |||
100 | void _res_close __P((void)); | ||
81 | 101 | ||
82 | static int s = -1; /* socket used for communications */ | 102 | static int s = -1; /* socket used for communications */ |
83 | static struct sockaddr no_addr; | 103 | static int connected = 0; /* is the socket connected */ |
84 | 104 | static 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 | ||
94 | res_send(buf, buflen, answer, anslen) | 153 | static res_send_qhook Qhook = NULL; |
95 | const char *buf; | 154 | static res_send_rhook Rhook = NULL; |
155 | |||
156 | void | ||
157 | res_send_setqhook(hook) | ||
158 | res_send_qhook hook; | ||
159 | { | ||
160 | |||
161 | Qhook = hook; | ||
162 | } | ||
163 | |||
164 | void | ||
165 | res_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 | */ | ||
181 | int | ||
182 | res_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 | */ | ||
214 | int | ||
215 | res_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 | */ | ||
252 | int | ||
253 | res_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 | |||
278 | int | ||
279 | res_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; |
353 | wait: | 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 | */ |
745 | void | ||
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 | } |