Libinfo-129.4.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.2.202.1 2002/11/06 17:30:17 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/nameser.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 <resolv.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 extern struct __res_state _res_shadow;
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 static int res_using_defaults()
317 {
318 int i;
319
320 if (_res.nscount != _res_shadow.nscount)
321 return 0;
322
323 for (i = 0; i < _res.nscount; i++) {
324 /* Check that the address and port have not changed */
325 if ((_res.nsaddr_list[i].sin_addr.s_addr !=
326 _res_shadow.nsaddr_list[i].sin_addr.s_addr) ||
327 (_res.nsaddr_list[i].sin_port !=
328 _res_shadow.nsaddr_list[i].sin_port)) {
329 return 0;
330 }
331 }
332
333 return 1;
334 }
335
336 /* Returns whether a dns encoded name should be sent to multicast or not */
337 static int dns_is_local_name(const u_int8_t *name)
338 {
339 const u_int8_t *d0 = NULL; // Top-Level Domain
340 const u_int8_t *d1 = NULL; // Second-Level Domain
341 const u_int8_t *d2 = NULL; // etc.
342 const u_int8_t *d3 = NULL;
343
344 while (*name)
345 {
346 d3 = d2;
347 d2 = d1;
348 d1 = d0;
349 d0 = name;
350 name += 1 + *name;
351 }
352
353 // "local" domains need to be resolved with multicast
354 // "local."
355 if (d0[0] == 5 && strncasecmp((char *)d0+1, "local", 5) == 0) return 1;
356
357 // "local.arpa."
358 if (d1 && d1[0] == 5 && strncasecmp((char *)d1+1, "local", 5) == 0 &&
359 d0[0] == 4 && strncasecmp((char *)d0+1, "arpa", 4) == 0) return 1;
360
361 // "local.int."
362 if (d1 && d1[0] == 5 && strncasecmp((char *)d1+1, "local", 5) == 0 &&
363 d0[0] == 3 && strncasecmp((char *)d0+1, "int", 3) == 0) return 1;
364
365 // The network 169.254/16 is defined to be link-local,
366 // so lookups in 254.169.in-addr.arpa. also need to be resolved with local multicast
367 if (d3 && d3[0] == 3 && strncasecmp((char *)d3+1, "254", 3) == 0 &&
368 d2 && d2[0] == 3 && strncasecmp((char *)d2+1, "169", 3) == 0 &&
369 d1 && d1[0] == 7 && strncasecmp((char *)d1+1, "in-addr", 7) == 0 &&
370 d0[0] == 4 && strncasecmp((char *)d0+1, "arpa", 4) == 0) return 1;
371
372 return 0;
373 }
374
375 #define DNS_LOCAL_DOMAIN_SERVICE_PORT 5353
376 #define DNS_HEADER_SIZE 12
377
378 #if BYTE_ORDER == BIG_ENDIAN
379 #define my_htons(x) (x)
380 #define my_htonl(x) (x)
381 #else
382 #define my_htons(x) ((((u_int16_t)x) >> 8) | (((u_int16_t)x) << 8))
383 #define my_htonl(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 16) | \
384 (((x) & 0x0000FF00) << 16) | ((x) << 24))
385 #endif
386
387 static const struct sockaddr_in mDNS_addr =
388 {
389 sizeof(mDNS_addr),
390 AF_INET,
391 my_htons(DNS_LOCAL_DOMAIN_SERVICE_PORT),
392 {my_htonl(0xE00000FB)} /* 224.0.0.251 */
393 };
394
395 int
396 res_send(buf, buflen, ans, anssiz)
397 const u_char *buf;
398 int buflen;
399 u_char *ans;
400 int anssiz;
401 {
402 HEADER *hp = (HEADER *) buf;
403 HEADER *anhp = (HEADER *) ans;
404 int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns;
405 register int n;
406 u_int badns; /* XXX NSMAX can't exceed #/bits in this var */
407 int multicast;
408
409 if ((_res.options & RES_INIT) == 0 && res_init() == -1) {
410 /* errno should have been set by res_init() in this case. */
411 return (-1);
412 }
413 DprintQ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY),
414 (stdout, ";; res_send()\n"), buf, buflen);
415 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
416 gotsomewhere = 0;
417 connreset = 0;
418 terrno = ETIMEDOUT;
419 badns = 0;
420
421 if (res_using_defaults() &&
422 dns_is_local_name((u_int8_t*)(buf + DNS_HEADER_SIZE))) {
423 multicast = 1;
424 v_circuit = 0;
425 } else {
426 multicast = 0;
427 }
428
429
430 /*
431 * Send request, RETRY times, or until successful
432 */
433 for (try = 0; try < _res.retry; try++) {
434 for (ns = 0; (multicast == 0 && ns < _res.nscount) ||
435 (multicast == 1 && ns < 1) ; ns++) {
436 struct sockaddr_in *nsap;
437 if (multicast == 0)
438 nsap = &_res.nsaddr_list[ns];
439 else
440 nsap = (struct sockaddr_in*)&mDNS_addr; /* const cast */
441 same_ns:
442 if (badns & (1 << ns)) {
443 _res_close();
444 goto next_ns;
445 }
446
447 if (Qhook) {
448 int done = 0, loops = 0;
449
450 do {
451 res_sendhookact act;
452
453 act = (*Qhook)(&nsap, &buf, &buflen,
454 ans, anssiz, &resplen);
455 switch (act) {
456 case res_goahead:
457 done = 1;
458 break;
459 case res_nextns:
460 _res_close();
461 goto next_ns;
462 case res_done:
463 return (resplen);
464 case res_modified:
465 /* give the hook another try */
466 if (++loops < 42) /*doug adams*/
467 break;
468 /*FALLTHROUGH*/
469 case res_error:
470 /*FALLTHROUGH*/
471 default:
472 return (-1);
473 }
474 } while (!done);
475 }
476
477 Dprint(_res.options & RES_DEBUG,
478 (stdout, ";; Querying server (# %d) address = %s\n",
479 ns + 1, inet_ntoa(nsap->sin_addr)));
480
481 if (v_circuit) {
482 int truncated;
483 struct iovec iov[2];
484 u_short len;
485 u_char *cp;
486
487 /*
488 * Use virtual circuit;
489 * at most one attempt per server.
490 */
491 try = _res.retry;
492 truncated = 0;
493 if ((s < 0) || (!vc)) {
494 if (s >= 0)
495 _res_close();
496
497 s = socket(PF_INET, SOCK_STREAM, 0);
498 if (s < 0) {
499 terrno = errno;
500 Perror(stderr, "socket(vc)", errno);
501 return (-1);
502 }
503 errno = 0;
504 if (connect(s, (struct sockaddr *)nsap,
505 sizeof(struct sockaddr)) < 0) {
506 terrno = errno;
507 Aerror(stderr, "connect/vc",
508 errno, *nsap);
509 badns |= (1 << ns);
510 _res_close();
511 goto next_ns;
512 }
513 vc = 1;
514 }
515 /*
516 * Send length & message
517 */
518 putshort((u_short)buflen, (u_char*)&len);
519 iov[0].iov_base = (caddr_t)&len;
520 iov[0].iov_len = INT16SZ;
521 iov[1].iov_base = (caddr_t)buf;
522 iov[1].iov_len = buflen;
523 if (writev(s, iov, 2) != (INT16SZ + buflen)) {
524 terrno = errno;
525 Perror(stderr, "write failed", errno);
526 badns |= (1 << ns);
527 _res_close();
528 goto next_ns;
529 }
530 /*
531 * Receive length & response
532 */
533 cp = ans;
534 len = INT16SZ;
535 while ((n = read(s, (char *)cp, (int)len)) > 0) {
536 cp += n;
537 if ((len -= n) <= 0)
538 break;
539 }
540 if (n <= 0) {
541 terrno = errno;
542 Perror(stderr, "read failed", errno);
543 _res_close();
544 /*
545 * A long running process might get its TCP
546 * connection reset if the remote server was
547 * restarted. Requery the server instead of
548 * trying a new one. When there is only one
549 * server, this means that a query might work
550 * instead of failing. We only allow one reset
551 * per query to prevent looping.
552 */
553 if (terrno == ECONNRESET && !connreset) {
554 connreset = 1;
555 _res_close();
556 goto same_ns;
557 }
558 _res_close();
559 goto next_ns;
560 }
561 resplen = _getshort(ans);
562 if (resplen > anssiz) {
563 Dprint(_res.options & RES_DEBUG,
564 (stdout, ";; response truncated\n")
565 );
566 truncated = 1;
567 len = anssiz;
568 } else
569 len = resplen;
570 cp = ans;
571 while (len != 0 &&
572 (n = read(s, (char *)cp, (int)len)) > 0) {
573 cp += n;
574 len -= n;
575 }
576 if (n <= 0) {
577 terrno = errno;
578 Perror(stderr, "read(vc)", errno);
579 _res_close();
580 goto next_ns;
581 }
582 if (truncated) {
583 /*
584 * Flush rest of answer
585 * so connection stays in synch.
586 */
587 anhp->tc = 1;
588 len = resplen - anssiz;
589 while (len != 0) {
590 char junk[PACKETSZ];
591
592 n = (len > sizeof(junk)
593 ? sizeof(junk)
594 : len);
595 if ((n = read(s, junk, n)) > 0)
596 len -= n;
597 else
598 break;
599 }
600 }
601 } else {
602 /*
603 * Use datagrams.
604 */
605 struct timeval timeout;
606 fd_set dsmask;
607 struct sockaddr_in from;
608 int fromlen;
609
610 if ((s < 0) || vc) {
611 if (vc)
612 _res_close();
613 s = socket(PF_INET, SOCK_DGRAM, 0);
614 if (s < 0) {
615 #if !CAN_RECONNECT
616 bad_dg_sock:
617 #endif
618 terrno = errno;
619 Perror(stderr, "socket(dg)", errno);
620 return (-1);
621 }
622 connected = 0;
623 }
624 /*
625 * On a 4.3BSD+ machine (client and server,
626 * actually), sending to a nameserver datagram
627 * port with no nameserver will cause an
628 * ICMP port unreachable message to be returned.
629 * If our datagram socket is "connected" to the
630 * server, we get an ECONNREFUSED error on the next
631 * socket operation, and select returns if the
632 * error message is received. We can thus detect
633 * the absence of a nameserver without timing out.
634 * If we have sent queries to at least two servers,
635 * however, we don't want to remain connected,
636 * as we wish to receive answers from the first
637 * server to respond.
638 */
639 if ((_res.nscount == 1 || (try == 0 && ns == 0)) && multicast == 0) {
640 /*
641 * Connect only if we are sure we won't
642 * receive a response from another server.
643 */
644 if (!connected) {
645 if (connect(s, (struct sockaddr *)nsap,
646 sizeof(struct sockaddr)
647 ) < 0) {
648 Aerror(stderr,
649 "connect(dg)",
650 errno, *nsap);
651 badns |= (1 << ns);
652 _res_close();
653 goto next_ns;
654 }
655 connected = 1;
656 }
657 if (send(s, (char*)buf, buflen, 0) != buflen) {
658 Perror(stderr, "send", errno);
659 badns |= (1 << ns);
660 _res_close();
661 goto next_ns;
662 }
663 } else {
664 /*
665 * Disconnect if we want to listen
666 * for responses from more than one server.
667 */
668 if (connected) {
669 #if CAN_RECONNECT
670 struct sockaddr_in no_addr;
671
672 no_addr.sin_family = AF_INET;
673 no_addr.sin_addr.s_addr = INADDR_ANY;
674 no_addr.sin_port = 0;
675 (void) connect(s,
676 (struct sockaddr *)
677 &no_addr,
678 sizeof(no_addr));
679 #else
680 int s1 = socket(PF_INET, SOCK_DGRAM,0);
681 if (s1 < 0)
682 goto bad_dg_sock;
683 (void) dup2(s1, s);
684 (void) close(s1);
685 Dprint(_res.options & RES_DEBUG,
686 (stdout, ";; new DG socket\n"))
687 #endif
688 connected = 0;
689 errno = 0;
690 }
691
692 if (multicast) {
693 struct ifaddrs* addrs;
694 struct ifaddrs* curAddr;
695 const int twofivefive = 255;
696
697 // multicast packets with TTL 255
698 if(setsockopt(s, IPPROTO_IP, IP_MULTICAST_TTL, &twofivefive, sizeof(twofivefive))) {
699 Perror(stderr, "setsocketopt - IP_MULTICAST_TTL", errno);
700 _res_close();
701 return (0);
702 }
703
704 if (getifaddrs(&addrs) != 0)
705 {
706 Perror(stderr, "getifaddrs", errno);
707 _res_close();
708 return (0);
709 }
710
711 /* multicast should send request on all multicast capable interfaces */
712 for (curAddr = addrs; curAddr != NULL; curAddr = curAddr->ifa_next) {
713 if ((curAddr->ifa_addr->sa_family) == AF_INET &&
714 (curAddr->ifa_flags & IFF_MULTICAST) != 0 &&
715 (curAddr->ifa_flags & IFF_POINTOPOINT) == 0) {
716 struct in_addr* if_ip_addr = &((struct sockaddr_in*)curAddr->ifa_addr)->sin_addr;
717
718 if (setsockopt(s, IPPROTO_IP, IP_MULTICAST_IF,
719 if_ip_addr, sizeof(*if_ip_addr)) != 0) {
720 freeifaddrs(addrs);
721 Perror(stderr, "setsocketopt - IP_MULTICAST_IF", errno);
722 _res_close();
723 return (0);
724 }
725
726 if (sendto(s, (char*)buf, buflen, 0,
727 (struct sockaddr *)nsap, sizeof *nsap) != buflen)
728 {
729 freeifaddrs(addrs);
730 Aerror(stderr, "sendto", errno, *nsap);
731 _res_close();
732 return (0);
733 }
734 }
735 }
736
737 freeifaddrs(addrs);
738 } else {
739 if (sendto(s, (char*)buf, buflen, 0,
740 (struct sockaddr *)nsap,
741 sizeof(struct sockaddr))
742 != buflen) {
743 Aerror(stderr, "sendto", errno, *nsap);
744 badns |= (1 << ns);
745 _res_close();
746 goto next_ns;
747 }
748 }
749 }
750
751 /*
752 * Wait for reply
753 */
754 timeout.tv_sec = (_res.retrans << try);
755 if (try > 0)
756 timeout.tv_sec /= _res.nscount;
757 if ((long) timeout.tv_sec <= 0 || multicast)
758 timeout.tv_sec = 1;
759 timeout.tv_usec = 0;
760 wait:
761 FD_ZERO(&dsmask);
762 FD_SET(s, &dsmask);
763 n = select(s+1, &dsmask, (fd_set *)NULL,
764 (fd_set *)NULL, &timeout);
765 if (n < 0) {
766 Perror(stderr, "select", errno);
767 _res_close();
768 goto next_ns;
769 }
770 if (n == 0) {
771 /*
772 * timeout
773 */
774 Dprint(_res.options & RES_DEBUG,
775 (stdout, ";; timeout\n"));
776 gotsomewhere = 1;
777 _res_close();
778 goto next_ns;
779 }
780 errno = 0;
781 fromlen = sizeof(struct sockaddr_in);
782 resplen = recvfrom(s, (char*)ans, anssiz, 0,
783 (struct sockaddr *)&from, &fromlen);
784 if (resplen <= 0) {
785 Perror(stderr, "recvfrom", errno);
786 _res_close();
787 goto next_ns;
788 }
789 gotsomewhere = 1;
790 if (hp->id != anhp->id) {
791 /*
792 * response from old query, ignore it.
793 * XXX - potential security hazard could
794 * be detected here.
795 */
796 DprintQ((_res.options & RES_DEBUG) ||
797 (_res.pfcode & RES_PRF_REPLY),
798 (stdout, ";; old answer:\n"),
799 ans, resplen);
800 goto wait;
801 }
802 #if CHECK_SRVR_ADDR
803 if (!(_res.options & RES_INSECURE1) &&
804 multicast == 0 && !res_isourserver(&from)) {
805 /*
806 * response from wrong server? ignore it.
807 * XXX - potential security hazard could
808 * be detected here.
809 */
810 DprintQ((_res.options & RES_DEBUG) ||
811 (_res.pfcode & RES_PRF_REPLY),
812 (stdout, ";; not our server:\n"),
813 ans, resplen);
814 goto wait;
815 }
816 #endif
817 if (!(_res.options & RES_INSECURE2) &&
818 !res_queriesmatch(buf, buf + buflen,
819 ans, ans + anssiz)) {
820 /*
821 * response contains wrong query? ignore it.
822 * XXX - potential security hazard could
823 * be detected here.
824 */
825 DprintQ((_res.options & RES_DEBUG) ||
826 (_res.pfcode & RES_PRF_REPLY),
827 (stdout, ";; wrong query name:\n"),
828 ans, resplen);
829 goto wait;
830 }
831 if (anhp->rcode == SERVFAIL ||
832 anhp->rcode == NOTIMP ||
833 anhp->rcode == REFUSED) {
834 DprintQ(_res.options & RES_DEBUG,
835 (stdout, "server rejected query:\n"),
836 ans, resplen);
837 badns |= (1 << ns);
838 _res_close();
839 /* don't retry if called from dig */
840 if (!_res.pfcode)
841 goto next_ns;
842 }
843 if (!(_res.options & RES_IGNTC) && anhp->tc) {
844 /*
845 * get rest of answer;
846 * use TCP with same server.
847 */
848 Dprint(_res.options & RES_DEBUG,
849 (stdout, ";; truncated answer\n"));
850 v_circuit = 1;
851 _res_close();
852 goto same_ns;
853 }
854 } /*if vc/dg*/
855 DprintQ((_res.options & RES_DEBUG) ||
856 (_res.pfcode & RES_PRF_REPLY),
857 (stdout, ";; got answer:\n"),
858 ans, resplen);
859 /*
860 * If using virtual circuits, we assume that the first server
861 * is preferred over the rest (i.e. it is on the local
862 * machine) and only keep that one open.
863 * If we have temporarily opened a virtual circuit,
864 * or if we haven't been asked to keep a socket open,
865 * close the socket.
866 */
867 if ((v_circuit && (!(_res.options & RES_USEVC) || ns != 0)) ||
868 !(_res.options & RES_STAYOPEN)) {
869 _res_close();
870 }
871 if (Rhook) {
872 int done = 0, loops = 0;
873
874 do {
875 res_sendhookact act;
876
877 act = (*Rhook)(nsap, buf, buflen,
878 ans, anssiz, &resplen);
879 switch (act) {
880 case res_goahead:
881 case res_done:
882 done = 1;
883 break;
884 case res_nextns:
885 _res_close();
886 goto next_ns;
887 case res_modified:
888 /* give the hook another try */
889 if (++loops < 42) /*doug adams*/
890 break;
891 /*FALLTHROUGH*/
892 case res_error:
893 /*FALLTHROUGH*/
894 default:
895 return (-1);
896 }
897 } while (!done);
898
899 }
900 return (resplen);
901 next_ns: ;
902 } /*foreach ns*/
903 } /*foreach retry*/
904 _res_close();
905 if (!v_circuit)
906 if (!gotsomewhere)
907 errno = ECONNREFUSED; /* no nameservers found */
908 else
909 errno = ETIMEDOUT; /* no answer obtained */
910 else
911 errno = terrno;
912 return (-1);
913 }
914
915 /*
916 * This routine is for closing the socket if a virtual circuit is used and
917 * the program wants to close it. This provides support for endhostent()
918 * which expects to close the socket.
919 *
920 * This routine is not expected to be user visible.
921 */
922 void
923 _res_close()
924 {
925 if (s >= 0) {
926 (void) close(s);
927 s = -1;
928 connected = 0;
929 vc = 0;
930 }
931 }