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