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