]>
Commit | Line | Data |
---|---|---|
d7ce7006 | 1 | /*\r |
2 | * Copyright (c) 1985, 1989, 1993\r | |
3 | * The Regents of the University of California. All rights reserved.\r | |
4 | *\r | |
5 | * Portions copyright (c) 1999, 2000\r | |
6 | * Intel Corporation.\r | |
7 | * All rights reserved.\r | |
8 | *\r | |
9 | * Redistribution and use in source and binary forms, with or without\r | |
10 | * modification, are permitted provided that the following conditions\r | |
11 | * are met:\r | |
12 | *\r | |
13 | * 1. Redistributions of source code must retain the above copyright\r | |
14 | * notice, this list of conditions and the following disclaimer.\r | |
15 | *\r | |
16 | * 2. Redistributions in binary form must reproduce the above copyright\r | |
17 | * notice, this list of conditions and the following disclaimer in the\r | |
18 | * documentation and/or other materials provided with the distribution.\r | |
19 | *\r | |
20 | * 3. All advertising materials mentioning features or use of this software\r | |
21 | * must display the following acknowledgement:\r | |
22 | *\r | |
23 | * This product includes software developed by the University of\r | |
24 | * California, Berkeley, Intel Corporation, and its contributors.\r | |
25 | *\r | |
26 | * 4. Neither the name of University, Intel Corporation, or their respective\r | |
27 | * contributors may be used to endorse or promote products derived from\r | |
28 | * this software without specific prior written permission.\r | |
29 | *\r | |
30 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS, INTEL CORPORATION AND\r | |
31 | * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,\r | |
32 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS\r | |
33 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS,\r | |
34 | * INTEL CORPORATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r | |
35 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r | |
36 | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r | |
37 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r | |
38 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r | |
39 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r | |
40 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r | |
41 | *\r | |
42 | */\r | |
43 | \r | |
44 | /*\r | |
45 | * Portions Copyright (c) 1993 by Digital Equipment Corporation.\r | |
46 | *\r | |
47 | * Permission to use, copy, modify, and distribute this software for any\r | |
48 | * purpose with or without fee is hereby granted, provided that the above\r | |
49 | * copyright notice and this permission notice appear in all copies, and that\r | |
50 | * the name of Digital Equipment Corporation not be used in advertising or\r | |
51 | * publicity pertaining to distribution of the document or software without\r | |
52 | * specific, written prior permission.\r | |
53 | *\r | |
54 | * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL\r | |
55 | * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES\r | |
56 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT\r | |
57 | * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\r | |
58 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\r | |
59 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\r | |
60 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\r | |
61 | * SOFTWARE.\r | |
62 | */\r | |
63 | \r | |
64 | /*\r | |
65 | * Portions Copyright (c) 1996 by Internet Software Consortium.\r | |
66 | *\r | |
67 | * Permission to use, copy, modify, and distribute this software for any\r | |
68 | * purpose with or without fee is hereby granted, provided that the above\r | |
69 | * copyright notice and this permission notice appear in all copies.\r | |
70 | *\r | |
71 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS\r | |
72 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES\r | |
73 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE\r | |
74 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL\r | |
75 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR\r | |
76 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS\r | |
77 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS\r | |
78 | * SOFTWARE.\r | |
79 | */\r | |
80 | \r | |
81 | #if defined(LIBC_SCCS) && !defined(lint)\r | |
82 | static char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";\r | |
83 | static char orig_rcsid[] = "From: Id: res_send.c,v 8.20 1998/04/06 23:27:51 halley Exp $";\r | |
84 | static char rcsid[] = "$Id: res_send.c,v 1.1.1.1 2003/11/19 01:51:39 kyu3 Exp $";\r | |
85 | #endif /* LIBC_SCCS and not lint */\r | |
86 | \r | |
87 | /*\r | |
88 | * Send query to name server and wait for reply.\r | |
89 | */\r | |
90 | \r | |
91 | #include <sys/types.h>\r | |
92 | #include <sys/param.h>\r | |
93 | #include <sys/select.h>\r | |
94 | #include <sys/socket.h>\r | |
95 | #include <sys/time.h>\r | |
96 | #include <sys/uio.h>\r | |
97 | \r | |
98 | #include <netinet/in.h>\r | |
99 | #include <arpa/nameser.h>\r | |
100 | #include <arpa/inet.h>\r | |
101 | \r | |
102 | #include <errno.h>\r | |
103 | #include <netdb.h>\r | |
104 | #include <resolv.h>\r | |
105 | #include <stdio.h>\r | |
106 | #include <stdlib.h>\r | |
107 | #include <string.h>\r | |
108 | #include <unistd.h>\r | |
109 | \r | |
110 | #include "res_config.h"\r | |
111 | \r | |
112 | #ifndef _ORG_FREEBSD_\r | |
113 | #define NOPOLL\r | |
114 | #endif\r | |
115 | \r | |
116 | #ifdef NOPOLL /* libc_r doesn't wrap poll yet() */\r | |
d7ce7006 | 117 | #else\r |
118 | #include <poll.h>\r | |
119 | static int use_poll = 1; /* adapt to poll() syscall availability */\r | |
120 | /* 0 = not present, 1 = try it, 2 = exists */\r | |
121 | #endif\r | |
122 | \r | |
123 | static int s = -1; /* socket used for communications */\r | |
124 | static int connected = 0; /* is the socket connected */\r | |
125 | static int vc = 0; /* is the socket a virtual circuit? */\r | |
126 | static res_send_qhook Qhook = NULL;\r | |
127 | static res_send_rhook Rhook = NULL;\r | |
128 | \r | |
129 | \r | |
130 | #define CAN_RECONNECT 1\r | |
131 | \r | |
132 | #ifndef DEBUG\r | |
133 | # define Dprint(cond, args) /*empty*/\r | |
134 | # define DprintQ(cond, args, query, size) /*empty*/\r | |
135 | # define Aerror(file, string, error, address) /*empty*/\r | |
136 | # define Perror(file, string, error) /*empty*/\r | |
137 | #else\r | |
138 | # define Dprint(cond, args) if (cond) {fprintf args;} else {}\r | |
139 | # define DprintQ(cond, args, query, size) if (cond) {\\r | |
140 | fprintf args;\\r | |
141 | __fp_nquery(query, size, stdout);\\r | |
142 | } else {}\r | |
143 | \r | |
144 | static void\r | |
145 | Aerror(\r | |
146 | FILE *file,\r | |
147 | char *string,\r | |
148 | int error,\r | |
149 | struct sockaddr_in address\r | |
150 | )\r | |
151 | {\r | |
152 | int save = errno;\r | |
153 | \r | |
154 | if (_res.options & RES_DEBUG) {\r | |
155 | fprintf(file, "res_send: %s ([%s].%u): %s\n",\r | |
156 | string,\r | |
157 | inet_ntoa(address.sin_addr),\r | |
158 | ntohs(address.sin_port),\r | |
159 | strerror(error));\r | |
160 | }\r | |
161 | errno = save;\r | |
162 | }\r | |
163 | \r | |
164 | \r | |
165 | static void\r | |
166 | Perror(\r | |
167 | FILE *file,\r | |
168 | char *string,\r | |
169 | int error\r | |
170 | )\r | |
171 | {\r | |
172 | int save = errno;\r | |
173 | \r | |
174 | if (_res.options & RES_DEBUG) {\r | |
175 | fprintf(file, "res_send: %s: %s\n",\r | |
176 | string, strerror(error));\r | |
177 | }\r | |
178 | errno = save;\r | |
179 | }\r | |
180 | #endif\r | |
181 | \r | |
182 | void\r | |
183 | res_send_setqhook(\r | |
184 | res_send_qhook hook\r | |
185 | )\r | |
186 | {\r | |
187 | \r | |
188 | Qhook = hook;\r | |
189 | }\r | |
190 | \r | |
191 | void\r | |
192 | res_send_setrhook(\r | |
193 | res_send_rhook hook\r | |
194 | )\r | |
195 | {\r | |
196 | \r | |
197 | Rhook = hook;\r | |
198 | }\r | |
199 | \r | |
200 | /* int\r | |
201 | * res_isourserver(ina)\r | |
202 | * looks up "ina" in _res.ns_addr_list[]\r | |
203 | * returns:\r | |
204 | * 0 : not found\r | |
205 | * >0 : found\r | |
206 | * author:\r | |
207 | * paul vixie, 29may94\r | |
208 | */\r | |
209 | int\r | |
210 | res_isourserver(\r | |
211 | const struct sockaddr_in *inp\r | |
212 | )\r | |
213 | {\r | |
214 | struct sockaddr_in ina;\r | |
215 | int ns, ret;\r | |
216 | \r | |
217 | ina = *inp;\r | |
218 | ret = 0;\r | |
219 | for (ns = 0; ns < _res.nscount; ns++) {\r | |
220 | const struct sockaddr_in *srv = &_res.nsaddr_list[ns];\r | |
221 | \r | |
222 | if (srv->sin_family == ina.sin_family &&\r | |
223 | srv->sin_port == ina.sin_port &&\r | |
224 | (srv->sin_addr.s_addr == INADDR_ANY ||\r | |
225 | srv->sin_addr.s_addr == ina.sin_addr.s_addr)) {\r | |
226 | ret++;\r | |
227 | break;\r | |
228 | }\r | |
229 | }\r | |
230 | return (ret);\r | |
231 | }\r | |
232 | \r | |
233 | /* int\r | |
234 | * res_nameinquery(name, type, class, buf, eom)\r | |
235 | * look for (name,type,class) in the query section of packet (buf,eom)\r | |
236 | * requires:\r | |
237 | * buf + HFIXEDSZ <= eom\r | |
238 | * returns:\r | |
239 | * -1 : format error\r | |
240 | * 0 : not found\r | |
241 | * >0 : found\r | |
242 | * author:\r | |
243 | * paul vixie, 29may94\r | |
244 | */\r | |
245 | int\r | |
246 | res_nameinquery(\r | |
247 | const char *name,\r | |
248 | int type,\r | |
249 | int class,\r | |
250 | const u_char *buf,\r | |
251 | const u_char *eom\r | |
252 | )\r | |
253 | {\r | |
254 | const u_char *cp = buf + HFIXEDSZ;\r | |
255 | int qdcount = ntohs(((HEADER*)buf)->qdcount);\r | |
256 | \r | |
257 | while (qdcount-- > 0) {\r | |
258 | char tname[MAXDNAME+1];\r | |
259 | int n, ttype, tclass;\r | |
260 | \r | |
261 | n = dn_expand(buf, eom, cp, tname, sizeof tname);\r | |
262 | if (n < 0)\r | |
263 | return (-1);\r | |
264 | cp += n;\r | |
265 | if (cp + 2 * INT16SZ > eom)\r | |
266 | return (-1);\r | |
267 | ttype = ns_get16(cp); cp += INT16SZ;\r | |
268 | tclass = ns_get16(cp); cp += INT16SZ;\r | |
269 | if (ttype == type &&\r | |
270 | tclass == class &&\r | |
271 | strcasecmp(tname, name) == 0)\r | |
272 | return (1);\r | |
273 | }\r | |
274 | return (0);\r | |
275 | }\r | |
276 | \r | |
277 | /* int\r | |
278 | * res_queriesmatch(buf1, eom1, buf2, eom2)\r | |
279 | * is there a 1:1 mapping of (name,type,class)\r | |
280 | * in (buf1,eom1) and (buf2,eom2)?\r | |
281 | * returns:\r | |
282 | * -1 : format error\r | |
283 | * 0 : not a 1:1 mapping\r | |
284 | * >0 : is a 1:1 mapping\r | |
285 | * author:\r | |
286 | * paul vixie, 29may94\r | |
287 | */\r | |
288 | int\r | |
289 | res_queriesmatch(\r | |
290 | const u_char *buf1,\r | |
291 | const u_char *eom1,\r | |
292 | const u_char *buf2,\r | |
293 | const u_char *eom2\r | |
294 | )\r | |
295 | {\r | |
296 | const u_char *cp = buf1 + HFIXEDSZ;\r | |
297 | int qdcount = ntohs(((HEADER*)buf1)->qdcount);\r | |
298 | \r | |
299 | if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)\r | |
300 | return (-1);\r | |
301 | \r | |
302 | /*\r | |
303 | * Only header section present in replies to\r | |
304 | * dynamic update packets.\r | |
305 | */\r | |
306 | if ( (((HEADER *)buf1)->opcode == ns_o_update) &&\r | |
307 | (((HEADER *)buf2)->opcode == ns_o_update) )\r | |
308 | return (1);\r | |
309 | \r | |
310 | if (qdcount != ntohs(((HEADER*)buf2)->qdcount))\r | |
311 | return (0);\r | |
312 | while (qdcount-- > 0) {\r | |
313 | char tname[MAXDNAME+1];\r | |
314 | int n, ttype, tclass;\r | |
315 | \r | |
316 | n = dn_expand(buf1, eom1, cp, tname, sizeof tname);\r | |
317 | if (n < 0)\r | |
318 | return (-1);\r | |
319 | cp += n;\r | |
320 | if (cp + 2 * INT16SZ > eom1)\r | |
321 | return (-1);\r | |
322 | ttype = ns_get16(cp); cp += INT16SZ;\r | |
323 | tclass = ns_get16(cp); cp += INT16SZ;\r | |
324 | if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))\r | |
325 | return (0);\r | |
326 | }\r | |
327 | return (1);\r | |
328 | }\r | |
329 | \r | |
330 | int\r | |
331 | res_send(\r | |
332 | const u_char *buf,\r | |
333 | int buflen,\r | |
334 | u_char *ans,\r | |
335 | int anssiz\r | |
336 | )\r | |
337 | {\r | |
338 | HEADER *hp = (HEADER *) buf;\r | |
339 | HEADER *anhp = (HEADER *) ans;\r | |
340 | int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns;\r | |
341 | ssize_t n;\r | |
342 | u_int32_t badns; /* XXX NSMAX can't exceed #/bits in this variable */\r | |
343 | \r | |
344 | if ((_res.options & RES_INIT) == 0 && res_init() == -1) {\r | |
345 | /* errno should have been set by res_init() in this case. */\r | |
346 | return (-1);\r | |
347 | }\r | |
348 | if (anssiz < HFIXEDSZ) {\r | |
349 | errno = EINVAL;\r | |
350 | return (-1);\r | |
351 | }\r | |
352 | DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),\r | |
353 | (stdout, ";; res_send()\n"), buf, buflen);\r | |
354 | v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;\r | |
355 | gotsomewhere = 0;\r | |
356 | connreset = 0;\r | |
357 | terrno = ETIMEDOUT;\r | |
358 | badns = 0;\r | |
359 | \r | |
360 | /*\r | |
361 | * Send request, RETRY times, or until successful\r | |
362 | */\r | |
363 | for (try = 0; try < _res.retry; try++) {\r | |
364 | for (ns = 0; ns < _res.nscount; ns++) {\r | |
365 | struct sockaddr_in *nsap = &_res.nsaddr_list[ns];\r | |
366 | same_ns:\r | |
367 | if (badns & (1 << ns)) {\r | |
368 | res_close();\r | |
369 | goto next_ns;\r | |
370 | }\r | |
371 | \r | |
372 | if (Qhook) {\r | |
373 | int done = 0, loops = 0;\r | |
374 | \r | |
375 | do {\r | |
376 | res_sendhookact act;\r | |
377 | \r | |
378 | act = (*Qhook)(&nsap, &buf, &buflen,\r | |
379 | ans, anssiz, &resplen);\r | |
380 | switch (act) {\r | |
381 | case res_goahead:\r | |
382 | done = 1;\r | |
383 | break;\r | |
384 | case res_nextns:\r | |
385 | res_close();\r | |
386 | goto next_ns;\r | |
387 | case res_done:\r | |
388 | return (resplen);\r | |
389 | case res_modified:\r | |
390 | /* give the hook another try */\r | |
391 | if (++loops < 42) /*doug adams*/\r | |
392 | break;\r | |
393 | /*FALLTHROUGH*/\r | |
394 | case res_error:\r | |
395 | /*FALLTHROUGH*/\r | |
396 | default:\r | |
397 | return (-1);\r | |
398 | }\r | |
399 | } while (!done);\r | |
400 | }\r | |
401 | \r | |
402 | Dprint(_res.options & RES_DEBUG,\r | |
403 | (stdout, ";; Querying server (# %d) address = %s\n",\r | |
404 | ns + 1, inet_ntoa(nsap->sin_addr)));\r | |
405 | \r | |
406 | if (v_circuit) {\r | |
407 | int truncated;\r | |
408 | struct iovec iov[2];\r | |
409 | u_short len;\r | |
410 | u_char *cp;\r | |
411 | \r | |
412 | /*\r | |
413 | * Use virtual circuit;\r | |
414 | * at most one attempt per server.\r | |
415 | */\r | |
416 | try = _res.retry;\r | |
417 | truncated = 0;\r | |
418 | if (s < 0 || !vc || hp->opcode == ns_o_update) {\r | |
419 | if (s >= 0)\r | |
420 | res_close();\r | |
421 | \r | |
422 | s = socket(PF_INET, SOCK_STREAM, 0);\r | |
423 | if (s < 0) {\r | |
424 | terrno = errno;\r | |
425 | Perror(stderr, "socket(vc)", errno);\r | |
426 | return (-1);\r | |
427 | }\r | |
428 | errno = 0;\r | |
429 | nsap->sin_len = sizeof ( *nsap );\r | |
430 | if (connect(s, (struct sockaddr *)nsap,\r | |
431 | sizeof *nsap) < 0) {\r | |
432 | terrno = errno;\r | |
433 | Aerror(stderr, "connect/vc",\r | |
434 | errno, *nsap);\r | |
435 | badns |= (1 << ns);\r | |
436 | res_close();\r | |
437 | goto next_ns;\r | |
438 | }\r | |
439 | vc = 1;\r | |
440 | }\r | |
441 | /*\r | |
442 | * Send length & message\r | |
443 | */\r | |
444 | putshort((u_short)buflen, (u_char*)&len);\r | |
445 | iov[0].iov_base = (caddr_t)&len;\r | |
446 | iov[0].iov_len = INT16SZ;\r | |
447 | iov[1].iov_base = (caddr_t)buf;\r | |
448 | iov[1].iov_len = buflen;\r | |
449 | if (writev(s, iov, 2) != (INT16SZ + buflen)) {\r | |
450 | terrno = errno;\r | |
451 | Perror(stderr, "write failed", errno);\r | |
452 | badns |= (1 << ns);\r | |
453 | res_close();\r | |
454 | goto next_ns;\r | |
455 | }\r | |
456 | /*\r | |
457 | * Receive length & response\r | |
458 | */\r | |
459 | read_len:\r | |
460 | cp = ans;\r | |
461 | len = INT16SZ;\r | |
462 | while ((n = read(s, (char *)cp, (int)len)) > 0) {\r | |
463 | cp += n;\r | |
464 | len = (u_short)( len - n );\r | |
465 | if (len <= 0)\r | |
466 | break;\r | |
467 | }\r | |
468 | if (n <= 0) {\r | |
469 | terrno = errno;\r | |
470 | Perror(stderr, "read failed", errno);\r | |
471 | res_close();\r | |
472 | /*\r | |
473 | * A long running process might get its TCP\r | |
474 | * connection reset if the remote server was\r | |
475 | * restarted. Requery the server instead of\r | |
476 | * trying a new one. When there is only one\r | |
477 | * server, this means that a query might work\r | |
478 | * instead of failing. We only allow one reset\r | |
479 | * per query to prevent looping.\r | |
480 | */\r | |
481 | if (terrno == ECONNRESET && !connreset) {\r | |
482 | connreset = 1;\r | |
483 | res_close();\r | |
484 | goto same_ns;\r | |
485 | }\r | |
486 | res_close();\r | |
487 | goto next_ns;\r | |
488 | }\r | |
489 | resplen = ns_get16(ans);\r | |
490 | if (resplen > anssiz) {\r | |
491 | Dprint(_res.options & RES_DEBUG,\r | |
492 | (stdout, ";; response truncated\n")\r | |
493 | );\r | |
494 | truncated = 1;\r | |
495 | len = (ushort)anssiz;\r | |
496 | } else\r | |
497 | len = (ushort)resplen;\r | |
498 | if (len < HFIXEDSZ) {\r | |
499 | /*\r | |
500 | * Undersized message.\r | |
501 | */\r | |
502 | Dprint(_res.options & RES_DEBUG,\r | |
503 | (stdout, ";; undersized: %d\n", len));\r | |
504 | terrno = EMSGSIZE;\r | |
505 | badns |= (1 << ns);\r | |
506 | res_close();\r | |
507 | goto next_ns;\r | |
508 | }\r | |
509 | cp = ans;\r | |
510 | while (len != 0 &&\r | |
511 | (n = read(s, (char *)cp, (int)len)) > 0) {\r | |
512 | cp += n;\r | |
513 | len = (u_short)( len - n );\r | |
514 | }\r | |
515 | if (n <= 0) {\r | |
516 | terrno = errno;\r | |
517 | Perror(stderr, "read(vc)", errno);\r | |
518 | res_close();\r | |
519 | goto next_ns;\r | |
520 | }\r | |
521 | if (truncated) {\r | |
522 | /*\r | |
523 | * Flush rest of answer\r | |
524 | * so connection stays in synch.\r | |
525 | */\r | |
526 | anhp->tc = 1;\r | |
527 | len = (ushort)( resplen - anssiz );\r | |
528 | while (len != 0) {\r | |
529 | char junk[PACKETSZ];\r | |
530 | \r | |
531 | n = (len > sizeof(junk)\r | |
532 | ? sizeof(junk)\r | |
533 | : len);\r | |
534 | if ((n = read(s, junk, n)) > 0)\r | |
535 | len = (u_short)( len - n );\r | |
536 | else\r | |
537 | break;\r | |
538 | }\r | |
539 | }\r | |
540 | /*\r | |
541 | * The calling applicating has bailed out of\r | |
542 | * a previous call and failed to arrange to have\r | |
543 | * the circuit closed or the server has got\r | |
544 | * itself confused. Anyway drop the packet and\r | |
545 | * wait for the correct one.\r | |
546 | */\r | |
547 | if (hp->id != anhp->id) {\r | |
548 | DprintQ((_res.options & RES_DEBUG) ||\r | |
549 | (_res.pfcode & RES_PRF_REPLY),\r | |
550 | (stdout, ";; old answer (unexpected):\n"),\r | |
551 | ans, (resplen>anssiz)?anssiz:resplen);\r | |
552 | goto read_len;\r | |
553 | }\r | |
554 | } else {\r | |
555 | /*\r | |
556 | * Use datagrams.\r | |
557 | */\r | |
558 | #ifndef NOPOLL\r | |
559 | struct pollfd pfd;\r | |
560 | int msec;\r | |
561 | #endif\r | |
562 | struct timeval timeout;\r | |
563 | fd_set dsmask, *dsmaskp;\r | |
564 | int dsmasklen;\r | |
565 | struct sockaddr_in from;\r | |
566 | int fromlen;\r | |
567 | \r | |
568 | if ((s < 0) || vc) {\r | |
569 | if (vc)\r | |
570 | res_close();\r | |
571 | s = socket(PF_INET, SOCK_DGRAM, 0);\r | |
572 | if (s < 0) {\r | |
573 | #ifndef CAN_RECONNECT\r | |
574 | bad_dg_sock:\r | |
575 | #endif\r | |
576 | terrno = errno;\r | |
577 | Perror(stderr, "socket(dg)", errno);\r | |
578 | return (-1);\r | |
579 | }\r | |
580 | connected = 0;\r | |
581 | }\r | |
582 | #ifndef CANNOT_CONNECT_DGRAM\r | |
583 | /*\r | |
584 | * On a 4.3BSD+ machine (client and server,\r | |
585 | * actually), sending to a nameserver datagram\r | |
586 | * port with no nameserver will cause an\r | |
587 | * ICMP port unreachable message to be returned.\r | |
588 | * If our datagram socket is "connected" to the\r | |
589 | * server, we get an ECONNREFUSED error on the next\r | |
590 | * socket operation, and select returns if the\r | |
591 | * error message is received. We can thus detect\r | |
592 | * the absence of a nameserver without timing out.\r | |
593 | * If we have sent queries to at least two servers,\r | |
594 | * however, we don't want to remain connected,\r | |
595 | * as we wish to receive answers from the first\r | |
596 | * server to respond.\r | |
597 | */\r | |
598 | if (_res.nscount == 1 || (try == 0 && ns == 0)) {\r | |
599 | /*\r | |
600 | * Connect only if we are sure we won't\r | |
601 | * receive a response from another server.\r | |
602 | */\r | |
603 | if (!connected) {\r | |
604 | nsap->sin_len = sizeof ( *nsap );\r | |
605 | if (connect(s, (struct sockaddr *)nsap,\r | |
606 | sizeof *nsap\r | |
607 | ) < 0) {\r | |
608 | Aerror(stderr,\r | |
609 | "connect(dg)",\r | |
610 | errno, *nsap);\r | |
611 | badns |= (1 << ns);\r | |
612 | res_close();\r | |
613 | goto next_ns;\r | |
614 | }\r | |
615 | connected = 1;\r | |
616 | }\r | |
617 | if (send(s, (char*)buf, buflen, 0) != buflen) {\r | |
618 | Perror(stderr, "send", errno);\r | |
619 | badns |= (1 << ns);\r | |
620 | res_close();\r | |
621 | goto next_ns;\r | |
622 | }\r | |
623 | } else {\r | |
624 | /*\r | |
625 | * Disconnect if we want to listen\r | |
626 | * for responses from more than one server.\r | |
627 | */\r | |
628 | if (connected) {\r | |
629 | #ifdef CAN_RECONNECT\r | |
630 | struct sockaddr_in no_addr;\r | |
631 | \r | |
632 | no_addr.sin_family = AF_INET;\r | |
633 | no_addr.sin_addr.s_addr = INADDR_ANY;\r | |
634 | no_addr.sin_port = 0;\r | |
635 | (void) connect(s,\r | |
636 | (struct sockaddr *)\r | |
637 | &no_addr,\r | |
638 | sizeof no_addr);\r | |
639 | #else\r | |
640 | int s1 = socket(PF_INET, SOCK_DGRAM,0);\r | |
641 | if (s1 < 0)\r | |
642 | goto bad_dg_sock;\r | |
643 | (void) dup2(s1, s);\r | |
644 | (void) close(s1);\r | |
645 | Dprint(_res.options & RES_DEBUG,\r | |
646 | (stdout, ";; new DG socket\n"))\r | |
647 | #endif /* CAN_RECONNECT */\r | |
648 | connected = 0;\r | |
649 | errno = 0;\r | |
650 | }\r | |
651 | #endif /* !CANNOT_CONNECT_DGRAM */\r | |
652 | if (sendto(s, (char*)buf, buflen, 0,\r | |
653 | (struct sockaddr *)nsap,\r | |
654 | sizeof *nsap)\r | |
655 | != buflen) {\r | |
656 | Aerror(stderr, "sendto", errno, *nsap);\r | |
657 | badns |= (1 << ns);\r | |
658 | res_close();\r | |
659 | goto next_ns;\r | |
660 | }\r | |
661 | #ifndef CANNOT_CONNECT_DGRAM\r | |
662 | }\r | |
663 | #endif /* !CANNOT_CONNECT_DGRAM */\r | |
664 | \r | |
665 | /*\r | |
666 | * Wait for reply\r | |
667 | */\r | |
668 | #ifndef NOPOLL\r | |
669 | othersyscall:\r | |
670 | if (use_poll) {\r | |
671 | msec = (_res.retrans << try) * 1000;\r | |
672 | if (try > 0)\r | |
673 | msec /= _res.nscount;\r | |
674 | if (msec <= 0)\r | |
675 | msec = 1000;\r | |
676 | } else {\r | |
677 | #endif\r | |
678 | timeout.tv_sec = (_res.retrans << try);\r | |
679 | if (try > 0)\r | |
680 | timeout.tv_sec /= _res.nscount;\r | |
681 | if ((long) timeout.tv_sec <= 0)\r | |
682 | timeout.tv_sec = 1;\r | |
683 | timeout.tv_usec = 0;\r | |
684 | #ifndef NOPOLL\r | |
685 | }\r | |
686 | #endif\r | |
687 | wait:\r | |
688 | if (s < 0) {\r | |
689 | Perror(stderr, "s out-of-bounds", EMFILE);\r | |
690 | res_close();\r | |
691 | goto next_ns;\r | |
692 | }\r | |
693 | #ifndef NOPOLL\r | |
694 | if (use_poll) {\r | |
695 | struct sigaction sa, osa;\r | |
696 | int sigsys_installed = 0;\r | |
697 | \r | |
698 | pfd.fd = s;\r | |
699 | pfd.events = POLLIN;\r | |
700 | if (use_poll == 1) {\r | |
701 | bzero(&sa, sizeof(sa));\r | |
702 | sa.sa_handler = SIG_IGN;\r | |
703 | if (sigaction(SIGSYS, &sa, &osa) >= 0)\r | |
704 | sigsys_installed = 1;\r | |
705 | }\r | |
706 | n = poll(&pfd, 1, msec);\r | |
707 | if (sigsys_installed == 1) {\r | |
708 | int oerrno = errno;\r | |
709 | sigaction(SIGSYS, &osa, NULL);\r | |
710 | errno = oerrno;\r | |
711 | }\r | |
712 | /* XXX why does nosys() return EINVAL? */\r | |
713 | if (n < 0 && (errno == ENOSYS ||\r | |
714 | errno == EINVAL)) {\r | |
715 | use_poll = 0;\r | |
716 | goto othersyscall;\r | |
717 | } else if (use_poll == 1)\r | |
718 | use_poll = 2;\r | |
719 | if (n < 0) {\r | |
720 | if (errno == EINTR)\r | |
721 | goto wait;\r | |
722 | Perror(stderr, "poll", errno);\r | |
723 | res_close();\r | |
724 | goto next_ns;\r | |
725 | }\r | |
726 | } else {\r | |
727 | #endif\r | |
728 | dsmasklen = howmany(s + 1, NFDBITS) *\r | |
729 | sizeof(fd_mask);\r | |
730 | if (dsmasklen > sizeof(fd_set)) {\r | |
731 | dsmaskp = (fd_set *)malloc(dsmasklen);\r | |
732 | if (dsmaskp == NULL) {\r | |
733 | res_close();\r | |
734 | goto next_ns;\r | |
735 | }\r | |
736 | } else\r | |
737 | dsmaskp = &dsmask;\r | |
738 | /* only zero what we need */\r | |
739 | memset((char *)dsmaskp, 0, dsmasklen);\r | |
740 | FD_SET(s, dsmaskp);\r | |
741 | n = select(s + 1, dsmaskp, (fd_set *)NULL,\r | |
742 | (fd_set *)NULL, &timeout);\r | |
743 | if (dsmaskp != &dsmask)\r | |
744 | free(dsmaskp);\r | |
745 | if (n < 0) {\r | |
746 | if (errno == EINTR)\r | |
747 | goto wait;\r | |
748 | Perror(stderr, "select", errno);\r | |
749 | res_close();\r | |
750 | goto next_ns;\r | |
751 | }\r | |
752 | #ifndef NOPOLL\r | |
753 | }\r | |
754 | #endif\r | |
755 | \r | |
756 | if (n == 0) {\r | |
757 | /*\r | |
758 | * timeout\r | |
759 | */\r | |
760 | Dprint(_res.options & RES_DEBUG,\r | |
761 | (stdout, ";; timeout\n"));\r | |
762 | gotsomewhere = 1;\r | |
763 | res_close();\r | |
764 | goto next_ns;\r | |
765 | }\r | |
766 | errno = 0;\r | |
767 | fromlen = sizeof(struct sockaddr_in);\r | |
768 | resplen = (int)recvfrom(s, (char*)ans, anssiz, 0,\r | |
a88c3163 | 769 | (struct sockaddr *)&from, (socklen_t *)&fromlen);\r |
d7ce7006 | 770 | if (resplen <= 0) {\r |
771 | Perror(stderr, "recvfrom", errno);\r | |
772 | res_close();\r | |
773 | goto next_ns;\r | |
774 | }\r | |
775 | gotsomewhere = 1;\r | |
776 | if (resplen < HFIXEDSZ) {\r | |
777 | /*\r | |
778 | * Undersized message.\r | |
779 | */\r | |
780 | Dprint(_res.options & RES_DEBUG,\r | |
781 | (stdout, ";; undersized: %d\n",\r | |
782 | resplen));\r | |
783 | terrno = EMSGSIZE;\r | |
784 | badns |= (1 << ns);\r | |
785 | res_close();\r | |
786 | goto next_ns;\r | |
787 | }\r | |
788 | if (hp->id != anhp->id) {\r | |
789 | /*\r | |
790 | * response from old query, ignore it.\r | |
791 | * XXX - potential security hazard could\r | |
792 | * be detected here.\r | |
793 | */\r | |
794 | DprintQ((_res.options & RES_DEBUG) ||\r | |
795 | (_res.pfcode & RES_PRF_REPLY),\r | |
796 | (stdout, ";; old answer:\n"),\r | |
797 | ans, (resplen>anssiz)?anssiz:resplen);\r | |
798 | goto wait;\r | |
799 | }\r | |
800 | #ifdef CHECK_SRVR_ADDR\r | |
801 | if (!(_res.options & RES_INSECURE1) &&\r | |
802 | !res_isourserver(&from)) {\r | |
803 | /*\r | |
804 | * response from wrong server? ignore it.\r | |
805 | * XXX - potential security hazard could\r | |
806 | * be detected here.\r | |
807 | */\r | |
808 | DprintQ((_res.options & RES_DEBUG) ||\r | |
809 | (_res.pfcode & RES_PRF_REPLY),\r | |
810 | (stdout, ";; not our server:\n"),\r | |
811 | ans, (resplen>anssiz)?anssiz:resplen);\r | |
812 | goto wait;\r | |
813 | }\r | |
814 | #endif\r | |
815 | if (!(_res.options & RES_INSECURE2) &&\r | |
816 | !res_queriesmatch(buf, buf + buflen,\r | |
817 | ans, ans + anssiz)) {\r | |
818 | /*\r | |
819 | * response contains wrong query? ignore it.\r | |
820 | * XXX - potential security hazard could\r | |
821 | * be detected here.\r | |
822 | */\r | |
823 | DprintQ((_res.options & RES_DEBUG) ||\r | |
824 | (_res.pfcode & RES_PRF_REPLY),\r | |
825 | (stdout, ";; wrong query name:\n"),\r | |
826 | ans, (resplen>anssiz)?anssiz:resplen);\r | |
827 | goto wait;\r | |
828 | }\r | |
829 | if (anhp->rcode == SERVFAIL ||\r | |
830 | anhp->rcode == NOTIMP ||\r | |
831 | anhp->rcode == REFUSED) {\r | |
832 | DprintQ(_res.options & RES_DEBUG,\r | |
833 | (stdout, "server rejected query:\n"),\r | |
834 | ans, (resplen>anssiz)?anssiz:resplen);\r | |
835 | badns |= (1 << ns);\r | |
836 | res_close();\r | |
837 | /* don't retry if called from dig */\r | |
838 | if (!_res.pfcode)\r | |
839 | goto next_ns;\r | |
840 | }\r | |
841 | if (!(_res.options & RES_IGNTC) && anhp->tc) {\r | |
842 | /*\r | |
843 | * get rest of answer;\r | |
844 | * use TCP with same server.\r | |
845 | */\r | |
846 | Dprint(_res.options & RES_DEBUG,\r | |
847 | (stdout, ";; truncated answer\n"));\r | |
848 | v_circuit = 1;\r | |
849 | res_close();\r | |
850 | goto same_ns;\r | |
851 | }\r | |
852 | } /*if vc/dg*/\r | |
853 | Dprint((_res.options & RES_DEBUG) ||\r | |
854 | ((_res.pfcode & RES_PRF_REPLY) &&\r | |
855 | (_res.pfcode & RES_PRF_HEAD1)),\r | |
856 | (stdout, ";; got answer:\n"));\r | |
7700f0f5 | 857 | if((_res.options & RES_DEBUG) ||\r |
858 | (_res.pfcode & RES_PRF_REPLY)) {\r | |
859 | __fp_nquery(ans, (resplen>anssiz)?anssiz:resplen, stdout);\r | |
860 | }\r | |
d7ce7006 | 861 | /*\r |
862 | * If using virtual circuits, we assume that the first server\r | |
863 | * is preferred over the rest (i.e. it is on the local\r | |
864 | * machine) and only keep that one open.\r | |
865 | * If we have temporarily opened a virtual circuit,\r | |
866 | * or if we haven't been asked to keep a socket open,\r | |
867 | * close the socket.\r | |
868 | */\r | |
869 | if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||\r | |
870 | !(_res.options & RES_STAYOPEN)) {\r | |
871 | res_close();\r | |
872 | }\r | |
873 | if (Rhook) {\r | |
874 | int done = 0, loops = 0;\r | |
875 | \r | |
876 | do {\r | |
877 | res_sendhookact act;\r | |
878 | \r | |
879 | act = (*Rhook)(nsap, buf, buflen,\r | |
880 | ans, anssiz, &resplen);\r | |
881 | switch (act) {\r | |
882 | case res_goahead:\r | |
883 | case res_done:\r | |
884 | done = 1;\r | |
885 | break;\r | |
886 | case res_nextns:\r | |
887 | res_close();\r | |
888 | goto next_ns;\r | |
889 | case res_modified:\r | |
890 | /* give the hook another try */\r | |
891 | if (++loops < 42) /*doug adams*/\r | |
892 | break;\r | |
893 | /*FALLTHROUGH*/\r | |
894 | case res_error:\r | |
895 | /*FALLTHROUGH*/\r | |
896 | default:\r | |
897 | return (-1);\r | |
898 | }\r | |
899 | } while (!done);\r | |
900 | \r | |
901 | }\r | |
902 | return (resplen);\r | |
903 | next_ns: ;\r | |
904 | } /*foreach ns*/\r | |
905 | } /*foreach retry*/\r | |
906 | res_close();\r | |
907 | if (!v_circuit) {\r | |
908 | if (!gotsomewhere)\r | |
909 | errno = ECONNREFUSED; /* no nameservers found */\r | |
910 | else\r | |
911 | errno = ETIMEDOUT; /* no answer obtained */\r | |
912 | } else\r | |
913 | errno = terrno;\r | |
914 | return (-1);\r | |
915 | }\r | |
916 | \r | |
917 | /*\r | |
918 | * This routine is for closing the socket if a virtual circuit is used and\r | |
919 | * the program wants to close it. This provides support for endhostent()\r | |
920 | * which expects to close the socket.\r | |
921 | *\r | |
922 | * This routine is not expected to be user visible.\r | |
923 | */\r | |
924 | void\r | |
925 | res_close()\r | |
926 | {\r | |
927 | if (s >= 0) {\r | |
928 | (void) close(s);\r | |
929 | s = -1;\r | |
930 | connected = 0;\r | |
931 | vc = 0;\r | |
932 | }\r | |
933 | }\r |