Libinfo-173.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/nameser8_compat.h>
101 #include <arpa/inet.h>
102 #include <ifaddrs.h>
103 #include <net/if.h>
104
105 #include <stdio.h>
106 #include <netdb.h>
107 #include <errno.h>
108 #include <resolv8_compat.h>
109 #if defined(BSD) && (BSD >= 199306)
110 # include <stdlib.h>
111 # include <string.h>
112 # include <unistd.h>
113 #else
114 # include "portability.h"
115 #endif
116
117 #if defined(USE_OPTIONS_H)
118 # include "options.h"
119 #endif
120
121 void _res_close __P((void));
122
123 static int s = -1; /* socket used for communications */
124 static int connected = 0; /* is the socket connected */
125 static int vc = 0; /* is the socket a virtual ciruit? */
126
127 #ifndef FD_SET
128 /* XXX - should be in portability.h */
129 #define NFDBITS 32
130 #define FD_SETSIZE 32
131 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
132 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
133 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
134 #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
135 #endif
136
137 /* XXX - this should be done in portability.h */
138 #if (defined(BSD) && (BSD >= 199103)) || defined(linux)
139 # define CAN_RECONNECT 1
140 #else
141 # define CAN_RECONNECT 0
142 #endif
143
144 #ifndef DEBUG
145 # define Dprint(cond, args) /*empty*/
146 # define DprintQ(cond, args, query, size) /*empty*/
147 # define Aerror(file, string, error, address) /*empty*/
148 # define Perror(file, string, error) /*empty*/
149 #else
150 # define Dprint(cond, args) if (cond) {fprintf args;} else {}
151 # define DprintQ(cond, args, query, size) if (cond) {\
152 fprintf args;\
153 __fp_nquery(query, size, stdout);\
154 } else {}
155 static void
156 Aerror(file, string, error, address)
157 FILE *file;
158 char *string;
159 int error;
160 struct sockaddr_in address;
161 {
162 int save = errno;
163
164 if (_res.options & RES_DEBUG) {
165 fprintf(file, "res_send: %s ([%s].%u): %s\n",
166 string,
167 inet_ntoa(address.sin_addr),
168 ntohs(address.sin_port),
169 strerror(error));
170 }
171 errno = save;
172 }
173 static void
174 Perror(file, string, error)
175 FILE *file;
176 char *string;
177 int error;
178 {
179 int save = errno;
180
181 if (_res.options & RES_DEBUG) {
182 fprintf(file, "res_send: %s: %s\n",
183 string, strerror(error));
184 }
185 errno = save;
186 }
187 #endif
188
189 static res_send_qhook Qhook = NULL;
190 static res_send_rhook Rhook = NULL;
191
192 void
193 res_send_setqhook(hook)
194 res_send_qhook hook;
195 {
196
197 Qhook = hook;
198 }
199
200 void
201 res_send_setrhook(hook)
202 res_send_rhook hook;
203 {
204
205 Rhook = hook;
206 }
207
208 /* int
209 * res_isourserver(ina)
210 * looks up "ina" in _res.ns_addr_list[]
211 * returns:
212 * 0 : not found
213 * >0 : found
214 * author:
215 * paul vixie, 29may94
216 */
217 int
218 res_isourserver(inp)
219 const struct sockaddr_in *inp;
220 {
221 struct sockaddr_in ina;
222 register int ns, ret;
223
224 ina = *inp;
225 ret = 0;
226 for (ns = 0; ns < _res.nscount; ns++) {
227 register const struct sockaddr_in *srv = &_res.nsaddr_list[ns];
228
229 if (srv->sin_family == ina.sin_family &&
230 srv->sin_port == ina.sin_port &&
231 (srv->sin_addr.s_addr == INADDR_ANY ||
232 srv->sin_addr.s_addr == ina.sin_addr.s_addr)) {
233 ret++;
234 break;
235 }
236 }
237 return (ret);
238 }
239
240 /* int
241 * res_nameinquery(name, type, class, buf, eom)
242 * look for (name,type,class) in the query section of packet (buf,eom)
243 * returns:
244 * -1 : format error
245 * 0 : not found
246 * >0 : found
247 * author:
248 * paul vixie, 29may94
249 */
250 int
251 res_nameinquery(name, type, class, buf, eom)
252 const char *name;
253 register int type, class;
254 const u_char *buf, *eom;
255 {
256 register const u_char *cp = buf + HFIXEDSZ;
257 int qdcount = ntohs(((HEADER*)buf)->qdcount);
258
259 while (qdcount-- > 0) {
260 char tname[MAXDNAME+1];
261 register int n, ttype, tclass;
262
263 n = dn_expand(buf, eom, cp, tname, sizeof tname);
264 if (n < 0)
265 return (-1);
266 cp += n;
267 ttype = _getshort(cp); cp += INT16SZ;
268 tclass = _getshort(cp); cp += INT16SZ;
269 if (ttype == type &&
270 tclass == class &&
271 strcasecmp(tname, name) == 0)
272 return (1);
273 }
274 return (0);
275 }
276
277 /* int
278 * res_queriesmatch(buf1, eom1, buf2, eom2)
279 * is there a 1:1 mapping of (name,type,class)
280 * in (buf1,eom1) and (buf2,eom2)?
281 * returns:
282 * -1 : format error
283 * 0 : not a 1:1 mapping
284 * >0 : is a 1:1 mapping
285 * author:
286 * paul vixie, 29may94
287 */
288 int
289 res_queriesmatch(buf1, eom1, buf2, eom2)
290 const u_char *buf1, *eom1;
291 const u_char *buf2, *eom2;
292 {
293 register const u_char *cp = buf1 + HFIXEDSZ;
294 int qdcount = ntohs(((HEADER*)buf1)->qdcount);
295
296 if (qdcount != ntohs(((HEADER*)buf2)->qdcount))
297 return (0);
298 while (qdcount-- > 0) {
299 char tname[MAXDNAME+1];
300 register int n, ttype, tclass;
301
302 n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
303 if (n < 0)
304 return (-1);
305 cp += n;
306 ttype = _getshort(cp); cp += INT16SZ;
307 tclass = _getshort(cp); cp += INT16SZ;
308 if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
309 return (0);
310 }
311 return (1);
312 }
313
314 /* Returns whether a dns encoded name should be sent to multicast or not */
315 static int dns_is_local_name(const u_int8_t *name)
316 {
317 const u_int8_t *d0 = NULL; // Top-Level Domain
318 const u_int8_t *d1 = NULL; // Second-Level Domain
319 const u_int8_t *d2 = NULL; // etc.
320 const u_int8_t *d3 = NULL;
321
322 if (name == NULL) return 0;
323
324 while (*name)
325 {
326 d3 = d2;
327 d2 = d1;
328 d1 = d0;
329 d0 = name;
330 name += 1 + *name;
331 }
332
333 // "local" domains need to be resolved with multicast
334 // "local."
335 if (d0[0] == 5 && strncasecmp((char *)d0+1, "local", 5) == 0) return 1;
336
337 // "local.arpa."
338 if (d1 && d1[0] == 5 && strncasecmp((char *)d1+1, "local", 5) == 0 &&
339 d0[0] == 4 && strncasecmp((char *)d0+1, "arpa", 4) == 0) return 1;
340
341 // "local.int."
342 if (d1 && d1[0] == 5 && strncasecmp((char *)d1+1, "local", 5) == 0 &&
343 d0[0] == 3 && strncasecmp((char *)d0+1, "int", 3) == 0) return 1;
344
345 // The network 169.254/16 is defined to be link-local,
346 // so lookups in 254.169.in-addr.arpa. also need to be resolved with local multicast
347 if (d3 && d3[0] == 3 && strncasecmp((char *)d3+1, "254", 3) == 0 &&
348 d2 && d2[0] == 3 && strncasecmp((char *)d2+1, "169", 3) == 0 &&
349 d1 && d1[0] == 7 && strncasecmp((char *)d1+1, "in-addr", 7) == 0 &&
350 d0[0] == 4 && strncasecmp((char *)d0+1, "arpa", 4) == 0) return 1;
351
352 return 0;
353 }
354
355 #define DNS_LOCAL_DOMAIN_SERVICE_PORT 5353
356 #define DNS_HEADER_SIZE 12
357
358 #if BYTE_ORDER == BIG_ENDIAN
359 #define my_htons(x) (x)
360 #define my_htonl(x) (x)
361 #else
362 #define my_htons(x) ((((u_int16_t)x) >> 8) | (((u_int16_t)x) << 8))
363 #define my_htonl(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 16) | \
364 (((x) & 0x0000FF00) << 16) | ((x) << 24))
365 #endif
366
367 static const struct sockaddr_in mDNS_addr =
368 {
369 sizeof(mDNS_addr),
370 AF_INET,
371 my_htons(DNS_LOCAL_DOMAIN_SERVICE_PORT),
372 {my_htonl(0xE00000FB)} /* 224.0.0.251 */
373 };
374
375 int
376 res_send(buf, buflen, ans, anssiz)
377 const u_char *buf;
378 int buflen;
379 u_char *ans;
380 int anssiz;
381 {
382 HEADER *hp = (HEADER *) buf;
383 HEADER *anhp = (HEADER *) ans;
384 int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns;
385 register int n;
386 u_int badns; /* XXX NSMAX can't exceed #/bits in this var */
387 int multicast;
388
389 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
390 /* errno should have been set by res_init() in this case. */
391 return (-1);
392 }
393 DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),
394 (stdout, ";; res_send()\n"), buf, buflen);
395 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
396 gotsomewhere = 0;
397 connreset = 0;
398 terrno = ETIMEDOUT;
399 badns = 0;
400
401 if (dns_is_local_name((u_int8_t*)(buf + DNS_HEADER_SIZE))) {
402 multicast = 1;
403 v_circuit = 0;
404 } else {
405 multicast = 0;
406 }
407
408
409 /*
410 * Send request, RETRY times, or until successful
411 */
412 for (try = 0; try < _res.retry; try++) {
413 for (ns = 0; (multicast == 0 && ns < _res.nscount) ||
414 (multicast == 1 && ns < 1) ; ns++) {
415 struct sockaddr_in *nsap;
416 if (multicast == 0)
417 nsap = &_res.nsaddr_list[ns];
418 else
419 nsap = (struct sockaddr_in*)&mDNS_addr; /* const cast */
420 same_ns:
421 if (badns & (1 << ns)) {
422 _res_close();
423 goto next_ns;
424 }
425
426 if (Qhook) {
427 int done = 0, loops = 0;
428
429 do {
430 res_sendhookact act;
431
432 act = (*Qhook)(&nsap, &buf, &buflen,
433 ans, anssiz, &resplen);
434 switch (act) {
435 case res_goahead:
436 done = 1;
437 break;
438 case res_nextns:
439 _res_close();
440 goto next_ns;
441 case res_done:
442 return (resplen);
443 case res_modified:
444 /* give the hook another try */
445 if (++loops < 42) /*doug adams*/
446 break;
447 /*FALLTHROUGH*/
448 case res_error:
449 /*FALLTHROUGH*/
450 default:
451 return (-1);
452 }
453 } while (!done);
454 }
455
456 Dprint(_res.options & RES_DEBUG,
457 (stdout, ";; Querying server (# %d) address = %s\n",
458 ns + 1, inet_ntoa(nsap->sin_addr)));
459
460 if (v_circuit) {
461 int truncated;
462 struct iovec iov[2];
463 u_short len;
464 u_char *cp;
465
466 /*
467 * Use virtual circuit;
468 * at most one attempt per server.
469 */
470 try = _res.retry;
471 truncated = 0;
472 if ((s < 0) || (!vc)) {
473 if (s >= 0)
474 _res_close();
475
476 s = socket(PF_INET, SOCK_STREAM, 0);
477 if (s < 0) {
478 terrno = errno;
479 Perror(stderr, "socket(vc)", errno);
480 return (-1);
481 }
482 errno = 0;
483 if (connect(s, (struct sockaddr *)nsap,
484 sizeof(struct sockaddr)) < 0) {
485 terrno = errno;
486 Aerror(stderr, "connect/vc",
487 errno, *nsap);
488 badns |= (1 << ns);
489 _res_close();
490 goto next_ns;
491 }
492 vc = 1;
493 }
494 /*
495 * Send length & message
496 */
497 putshort((u_short)buflen, (u_char*)&len);
498 iov[0].iov_base = (caddr_t)&len;
499 iov[0].iov_len = INT16SZ;
500 iov[1].iov_base = (caddr_t)buf;
501 iov[1].iov_len = buflen;
502 if (writev(s, iov, 2) != (INT16SZ + buflen)) {
503 terrno = errno;
504 Perror(stderr, "write failed", errno);
505 badns |= (1 << ns);
506 _res_close();
507 goto next_ns;
508 }
509 /*
510 * Receive length & response
511 */
512 cp = ans;
513 len = INT16SZ;
514 while ((n = read(s, (char *)cp, (int)len)) > 0) {
515 cp += n;
516 if ((len -= n) <= 0)
517 break;
518 }
519 if (n <= 0) {
520 terrno = errno;
521 Perror(stderr, "read failed", errno);
522 _res_close();
523 /*
524 * A long running process might get its TCP
525 * connection reset if the remote server was
526 * restarted. Requery the server instead of
527 * trying a new one. When there is only one
528 * server, this means that a query might work
529 * instead of failing. We only allow one reset
530 * per query to prevent looping.
531 */
532 if (terrno == ECONNRESET && !connreset) {
533 connreset = 1;
534 _res_close();
535 goto same_ns;
536 }
537 _res_close();
538 goto next_ns;
539 }
540 resplen = _getshort(ans);
541 if (resplen > anssiz) {
542 Dprint(_res.options & RES_DEBUG,
543 (stdout, ";; response truncated\n")
544 );
545 truncated = 1;
546 len = anssiz;
547 } else
548 len = resplen;
549 cp = ans;
550 while (len != 0 &&
551 (n = read(s, (char *)cp, (int)len)) > 0) {
552 cp += n;
553 len -= n;
554 }
555 if (n <= 0) {
556 terrno = errno;
557 Perror(stderr, "read(vc)", errno);
558 _res_close();
559 goto next_ns;
560 }
561 if (truncated) {
562 /*
563 * Flush rest of answer
564 * so connection stays in synch.
565 */
566 anhp->tc = 1;
567 len = resplen - anssiz;
568 while (len != 0) {
569 char junk[PACKETSZ];
570
571 n = (len > sizeof(junk)
572 ? sizeof(junk)
573 : len);
574 if ((n = read(s, junk, n)) > 0)
575 len -= n;
576 else
577 break;
578 }
579 }
580 } else {
581 /*
582 * Use datagrams.
583 */
584 struct timeval timeout;
585 fd_set dsmask;
586 struct sockaddr_in from;
587 int fromlen;
588
589 if ((s < 0) || vc) {
590 if (vc)
591 _res_close();
592 s = socket(PF_INET, SOCK_DGRAM, 0);
593 if (s < 0) {
594 #if !CAN_RECONNECT
595 bad_dg_sock:
596 #endif
597 terrno = errno;
598 Perror(stderr, "socket(dg)", errno);
599 return (-1);
600 }
601 connected = 0;
602 }
603 /*
604 * On a 4.3BSD+ machine (client and server,
605 * actually), sending to a nameserver datagram
606 * port with no nameserver will cause an
607 * ICMP port unreachable message to be returned.
608 * If our datagram socket is "connected" to the
609 * server, we get an ECONNREFUSED error on the next
610 * socket operation, and select returns if the
611 * error message is received. We can thus detect
612 * the absence of a nameserver without timing out.
613 * If we have sent queries to at least two servers,
614 * however, we don't want to remain connected,
615 * as we wish to receive answers from the first
616 * server to respond.
617 */
618 if ((_res.nscount == 1 || (try == 0 && ns == 0)) && multicast == 0) {
619 /*
620 * Connect only if we are sure we won't
621 * receive a response from another server.
622 */
623 if (!connected) {
624 if (connect(s, (struct sockaddr *)nsap,
625 sizeof(struct sockaddr)
626 ) < 0) {
627 Aerror(stderr,
628 "connect(dg)",
629 errno, *nsap);
630 badns |= (1 << ns);
631 _res_close();
632 goto next_ns;
633 }
634 connected = 1;
635 }
636 if (send(s, (char*)buf, buflen, 0) != buflen) {
637 Perror(stderr, "send", errno);
638 badns |= (1 << ns);
639 _res_close();
640 goto next_ns;
641 }
642 } else {
643 /*
644 * Disconnect if we want to listen
645 * for responses from more than one server.
646 */
647 if (connected) {
648 #if CAN_RECONNECT
649 struct sockaddr_in no_addr;
650
651 no_addr.sin_family = AF_INET;
652 no_addr.sin_addr.s_addr = INADDR_ANY;
653 no_addr.sin_port = 0;
654 (void) connect(s,
655 (struct sockaddr *)
656 &no_addr,
657 sizeof(no_addr));
658 #else
659 int s1 = socket(PF_INET, SOCK_DGRAM,0);
660 if (s1 < 0)
661 goto bad_dg_sock;
662 (void) dup2(s1, s);
663 (void) close(s1);
664 Dprint(_res.options & RES_DEBUG,
665 (stdout, ";; new DG socket\n"))
666 #endif
667 connected = 0;
668 errno = 0;
669 }
670
671 if (multicast) {
672 struct ifaddrs* addrs;
673 struct ifaddrs* curAddr;
674 const int twofivefive = 255;
675
676 // multicast packets with TTL 255
677 if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive))) {
678 Perror(stderr, "setsocketopt - IP_MULTICAST_TTL", errno);
679 _res_close();
680 return (0);
681 }
682
683 if (getifaddrs(&addrs) != 0)
684 {
685 Perror(stderr, "getifaddrs", errno);
686 _res_close();
687 return (0);
688 }
689
690 /* multicast should send request on all multicast capable interfaces */
691 for (curAddr = addrs; curAddr != NULL; curAddr = curAddr->ifa_next) {
692 if ((curAddr->ifa_addr->sa_family) == AF_INET &&
693 (curAddr->ifa_flags & IFF_MULTICAST) != 0 &&
694 (curAddr->ifa_flags & IFF_POINTOPOINT) == 0) {
695 struct in_addr* if_ip_addr = &((struct sockaddr_in*)curAddr->ifa_addr)->sin_addr;
696
697 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
698 if_ip_addr, sizeof(*if_ip_addr)) != 0) {
699 freeifaddrs(addrs);
700 Perror(stderr, "setsocketopt - IP_MULTICAST_IF", errno);
701 _res_close();
702 return (0);
703 }
704
705 if (sendto(s, (char*)buf, buflen, 0,
706 (struct sockaddr *)nsap, sizeof *nsap) != buflen)
707 {
708 freeifaddrs(addrs);
709 Aerror(stderr, "sendto", errno, *nsap);
710 _res_close();
711 return (0);
712 }
713 }
714 }
715
716 freeifaddrs(addrs);
717 } else {
718 if (sendto(s, (char*)buf, buflen, 0,
719 (struct sockaddr *)nsap,
720 sizeof(struct sockaddr))
721 != buflen) {
722 Aerror(stderr, "sendto", errno, *nsap);
723 badns |= (1 << ns);
724 _res_close();
725 goto next_ns;
726 }
727 }
728 }
729
730 /*
731 * Wait for reply
732 */
733 timeout.tv_sec = (_res.retrans << try);
734 if (try > 0)
735 timeout.tv_sec /= _res.nscount;
736 if ((long) timeout.tv_sec <= 0 || multicast)
737 timeout.tv_sec = 1;
738 timeout.tv_usec = 0;
739 wait:
740 FD_ZERO(&dsmask);
741 FD_SET(s, &dsmask);
742 n = select(s+1, &dsmask, (fd_set *)NULL,
743 (fd_set *)NULL, &timeout);
744 if (n < 0) {
745 Perror(stderr, "select", errno);
746 _res_close();
747 goto next_ns;
748 }
749 if (n == 0) {
750 /*
751 * timeout
752 */
753 Dprint(_res.options & RES_DEBUG,
754 (stdout, ";; timeout\n"));
755 gotsomewhere = 1;
756 _res_close();
757 goto next_ns;
758 }
759 errno = 0;
760 fromlen = sizeof(struct sockaddr_in);
761 resplen = recvfrom(s, (char*)ans, anssiz, 0,
762 (struct sockaddr *)&from, &fromlen);
763 if (resplen <= 0) {
764 Perror(stderr, "recvfrom", errno);
765 _res_close();
766 goto next_ns;
767 }
768 gotsomewhere = 1;
769 if (hp->id != anhp->id) {
770 /*
771 * response from old query, ignore it.
772 * XXX - potential security hazard could
773 * be detected here.
774 */
775 DprintQ((_res.options & RES_DEBUG) ||
776 (_res.pfcode & RES_PRF_REPLY),
777 (stdout, ";; old answer:\n"),
778 ans, resplen);
779 goto wait;
780 }
781 #if CHECK_SRVR_ADDR
782 if (!(_res.options & RES_INSECURE1) &&
783 multicast == 0 && !res_isourserver(&from)) {
784 /*
785 * response from wrong server? ignore it.
786 * XXX - potential security hazard could
787 * be detected here.
788 */
789 DprintQ((_res.options & RES_DEBUG) ||
790 (_res.pfcode & RES_PRF_REPLY),
791 (stdout, ";; not our server:\n"),
792 ans, resplen);
793 goto wait;
794 }
795 #endif
796 if (!(_res.options & RES_INSECURE2) &&
797 !res_queriesmatch(buf, buf + buflen,
798 ans, ans + anssiz)) {
799 /*
800 * response contains wrong query? ignore it.
801 * XXX - potential security hazard could
802 * be detected here.
803 */
804 DprintQ((_res.options & RES_DEBUG) ||
805 (_res.pfcode & RES_PRF_REPLY),
806 (stdout, ";; wrong query name:\n"),
807 ans, resplen);
808 goto wait;
809 }
810 if (anhp->rcode == SERVFAIL ||
811 anhp->rcode == NOTIMP ||
812 anhp->rcode == REFUSED) {
813 DprintQ(_res.options & RES_DEBUG,
814 (stdout, "server rejected query:\n"),
815 ans, resplen);
816 badns |= (1 << ns);
817 _res_close();
818 /* don't retry if called from dig */
819 if (!_res.pfcode)
820 goto next_ns;
821 }
822 if (!(_res.options & RES_IGNTC) && anhp->tc) {
823 /*
824 * get rest of answer;
825 * use TCP with same server.
826 */
827 Dprint(_res.options & RES_DEBUG,
828 (stdout, ";; truncated answer\n"));
829 v_circuit = 1;
830 _res_close();
831 goto same_ns;
832 }
833 } /*if vc/dg*/
834 DprintQ((_res.options & RES_DEBUG) ||
835 (_res.pfcode & RES_PRF_REPLY),
836 (stdout, ";; got answer:\n"),
837 ans, resplen);
838 /*
839 * If using virtual circuits, we assume that the first server
840 * is preferred over the rest (i.e. it is on the local
841 * machine) and only keep that one open.
842 * If we have temporarily opened a virtual circuit,
843 * or if we haven't been asked to keep a socket open,
844 * close the socket.
845 */
846 if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
847 !(_res.options & RES_STAYOPEN)) {
848 _res_close();
849 }
850 if (Rhook) {
851 int done = 0, loops = 0;
852
853 do {
854 res_sendhookact act;
855
856 act = (*Rhook)(nsap, buf, buflen,
857 ans, anssiz, &resplen);
858 switch (act) {
859 case res_goahead:
860 case res_done:
861 done = 1;
862 break;
863 case res_nextns:
864 _res_close();
865 goto next_ns;
866 case res_modified:
867 /* give the hook another try */
868 if (++loops < 42) /*doug adams*/
869 break;
870 /*FALLTHROUGH*/
871 case res_error:
872 /*FALLTHROUGH*/
873 default:
874 return (-1);
875 }
876 } while (!done);
877
878 }
879 return (resplen);
880 next_ns: ;
881 } /*foreach ns*/
882 } /*foreach retry*/
883 _res_close();
884 if (!v_circuit)
885 if (!gotsomewhere)
886 errno = ECONNREFUSED; /* no nameservers found */
887 else
888 errno = ETIMEDOUT; /* no answer obtained */
889 else
890 errno = terrno;
891 return (-1);
892 }
893
894 /*
895 * This routine is for closing the socket if a virtual circuit is used and
896 * the program wants to close it. This provides support for endhostent()
897 * which expects to close the socket.
898 *
899 * This routine is not expected to be user visible.
900 */
901 void
902 _res_close()
903 {
904 if (s >= 0) {
905 (void) close(s);
906 s = -1;
907 connected = 0;
908 vc = 0;
909 }
910 }