Annotation of src/lib/libc/resolv/res_send.c, Revision 1.20
1.20 ! christos 1: /* $NetBSD: res_send.c,v 1.19 2009/10/24 05:35:37 christos Exp $ */
1.18 christos 2:
3: /*
4: * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
5: * Portions Copyright (C) 1996-2003 Internet Software Consortium.
6: *
7: * Permission to use, copy, modify, and/or distribute this software for any
8: * purpose with or without fee is hereby granted, provided that the above
9: * copyright notice and this permission notice appear in all copies.
10: *
11: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12: * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13: * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14: * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15: * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16: * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17: * PERFORMANCE OF THIS SOFTWARE.
18: */
1.1 christos 19:
20: /*
21: * Copyright (c) 1985, 1989, 1993
22: * The Regents of the University of California. All rights reserved.
1.18 christos 23: *
1.1 christos 24: * Redistribution and use in source and binary forms, with or without
25: * modification, are permitted provided that the following conditions
26: * are met:
27: * 1. Redistributions of source code must retain the above copyright
28: * notice, this list of conditions and the following disclaimer.
29: * 2. Redistributions in binary form must reproduce the above copyright
30: * notice, this list of conditions and the following disclaimer in the
31: * documentation and/or other materials provided with the distribution.
32: * 3. All advertising materials mentioning features or use of this software
33: * must display the following acknowledgement:
34: * This product includes software developed by the University of
35: * California, Berkeley and its contributors.
36: * 4. Neither the name of the University nor the names of its contributors
37: * may be used to endorse or promote products derived from this software
38: * without specific prior written permission.
1.18 christos 39: *
1.1 christos 40: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
41: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
44: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50: * SUCH DAMAGE.
51: */
52:
53: /*
54: * Portions Copyright (c) 1993 by Digital Equipment Corporation.
1.18 christos 55: *
1.1 christos 56: * Permission to use, copy, modify, and distribute this software for any
57: * purpose with or without fee is hereby granted, provided that the above
58: * copyright notice and this permission notice appear in all copies, and that
59: * the name of Digital Equipment Corporation not be used in advertising or
60: * publicity pertaining to distribution of the document or software without
61: * specific, written prior permission.
1.18 christos 62: *
1.1 christos 63: * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
64: * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
65: * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
66: * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
67: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
68: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
69: * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
70: * SOFTWARE.
71: */
72:
73: /*
1.10 christos 74: * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
1.1 christos 75: * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
76: *
77: * Permission to use, copy, modify, and distribute this software for any
78: * purpose with or without fee is hereby granted, provided that the above
79: * copyright notice and this permission notice appear in all copies.
80: *
81: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
82: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
83: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
84: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
85: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
86: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
87: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
88: */
89:
1.4 christos 90: #include <sys/cdefs.h>
1.1 christos 91: #if defined(LIBC_SCCS) && !defined(lint)
1.4 christos 92: #ifdef notdef
1.1 christos 93: static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
1.18 christos 94: static const char rcsid[] = "Id: res_send.c,v 1.22 2009/01/22 23:49:23 tbox Exp";
1.4 christos 95: #else
1.20 ! christos 96: __RCSID("$NetBSD: res_send.c,v 1.19 2009/10/24 05:35:37 christos Exp $");
1.4 christos 97: #endif
1.1 christos 98: #endif /* LIBC_SCCS and not lint */
99:
1.10 christos 100: /*! \file
101: * \brief
1.1 christos 102: * Send query to name server and wait for reply.
103: */
104:
1.8 kleink 105: #include "namespace.h"
1.1 christos 106: #include "port_before.h"
107: #include "fd_setsize.h"
108:
109: #include <sys/types.h>
110: #include <sys/param.h>
111: #include <sys/time.h>
112: #include <sys/socket.h>
113: #include <sys/uio.h>
114:
115: #include <netinet/in.h>
116: #include <arpa/nameser.h>
117: #include <arpa/inet.h>
118:
119: #include <errno.h>
120: #include <netdb.h>
121: #include <resolv.h>
122: #include <signal.h>
123: #include <stdio.h>
124: #include <stdlib.h>
125: #include <string.h>
126: #include <unistd.h>
127:
128: #include <isc/eventlib.h>
129:
130: #include "port_after.h"
131:
1.6 christos 132: #if 0
1.5 christos 133: #ifdef __weak_alias
134: __weak_alias(res_ourserver_p,__res_ourserver_p)
135: __weak_alias(res_nameinquery,__res_nameinquery)
136: __weak_alias(res_queriesmatch,__res_queriesmatch)
137: __weak_alias(res_nsend,__res_nsend)
138: #endif
1.6 christos 139: #endif
1.5 christos 140:
1.10 christos 141:
142: #ifdef USE_POLL
143: #ifdef HAVE_STROPTS_H
144: #include <stropts.h>
145: #endif
146: #include <poll.h>
147: #endif /* USE_POLL */
148:
1.1 christos 149: /* Options. Leave them on. */
1.15 christos 150: #ifndef DEBUG
1.1 christos 151: #define DEBUG
1.15 christos 152: #endif
1.1 christos 153: #include "res_debug.h"
154: #include "res_private.h"
155:
156: #define EXT(res) ((res)->_u._ext)
157:
1.10 christos 158: #ifndef USE_POLL
1.1 christos 159: static const int highestFD = FD_SETSIZE - 1;
1.14 christos 160: #else
161: static int highestFD = 0;
1.10 christos 162: #endif
1.1 christos 163:
164: /* Forward. */
165:
166: static int get_salen __P((const struct sockaddr *));
167: static struct sockaddr * get_nsaddr __P((res_state, size_t));
168: static int send_vc(res_state, const u_char *, int,
169: u_char *, int, int *, int);
170: static int send_dg(res_state, const u_char *, int,
1.10 christos 171: u_char *, int, int *, int, int,
1.1 christos 172: int *, int *);
173: static void Aerror(const res_state, FILE *, const char *, int,
174: const struct sockaddr *, int);
175: static void Perror(const res_state, FILE *, const char *, int);
176: static int sock_eq(struct sockaddr *, struct sockaddr *);
1.10 christos 177: #if defined(NEED_PSELECT) && !defined(USE_POLL)
1.1 christos 178: static int pselect(int, void *, void *, void *,
179: struct timespec *,
180: const sigset_t *);
181: #endif
182: void res_pquery(const res_state, const u_char *, int, FILE *);
183:
184: static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
185:
186: /* Public. */
187:
1.10 christos 188: /*%
1.1 christos 189: * looks up "ina" in _res.ns_addr_list[]
1.10 christos 190: *
1.1 christos 191: * returns:
1.10 christos 192: *\li 0 : not found
193: *\li >0 : found
194: *
1.1 christos 195: * author:
1.10 christos 196: *\li paul vixie, 29may94
1.1 christos 197: */
198: int
199: res_ourserver_p(const res_state statp, const struct sockaddr *sa) {
200: const struct sockaddr_in *inp, *srv;
201: const struct sockaddr_in6 *in6p, *srv6;
202: int ns;
203:
204: switch (sa->sa_family) {
205: case AF_INET:
1.3 christos 206: inp = (const struct sockaddr_in *)(const void *)sa;
1.1 christos 207: for (ns = 0; ns < statp->nscount; ns++) {
1.2 christos 208: srv = (struct sockaddr_in *)(void *)get_nsaddr(statp, (size_t)ns);
1.1 christos 209: if (srv->sin_family == inp->sin_family &&
210: srv->sin_port == inp->sin_port &&
211: (srv->sin_addr.s_addr == INADDR_ANY ||
212: srv->sin_addr.s_addr == inp->sin_addr.s_addr))
213: return (1);
214: }
215: break;
216: case AF_INET6:
217: if (EXT(statp).ext == NULL)
218: break;
1.3 christos 219: in6p = (const struct sockaddr_in6 *)(const void *)sa;
1.1 christos 220: for (ns = 0; ns < statp->nscount; ns++) {
1.2 christos 221: srv6 = (struct sockaddr_in6 *)(void *)get_nsaddr(statp, (size_t)ns);
1.1 christos 222: if (srv6->sin6_family == in6p->sin6_family &&
223: srv6->sin6_port == in6p->sin6_port &&
224: #ifdef HAVE_SIN6_SCOPE_ID
1.7 christos 225: (srv6->sin6_scope_id == 0 ||
226: srv6->sin6_scope_id == in6p->sin6_scope_id) &&
1.1 christos 227: #endif
228: (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
229: IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
230: return (1);
231: }
232: break;
233: default:
234: break;
235: }
236: return (0);
237: }
238:
1.10 christos 239: /*%
1.1 christos 240: * look for (name,type,class) in the query section of packet (buf,eom)
1.10 christos 241: *
1.1 christos 242: * requires:
1.10 christos 243: *\li buf + HFIXEDSZ <= eom
244: *
1.1 christos 245: * returns:
1.10 christos 246: *\li -1 : format error
247: *\li 0 : not found
248: *\li >0 : found
249: *
1.1 christos 250: * author:
1.10 christos 251: *\li paul vixie, 29may94
1.1 christos 252: */
253: int
254: res_nameinquery(const char *name, int type, int class,
255: const u_char *buf, const u_char *eom)
256: {
257: const u_char *cp = buf + HFIXEDSZ;
1.2 christos 258: int qdcount = ntohs(((const HEADER*)(const void *)buf)->qdcount);
1.1 christos 259:
260: while (qdcount-- > 0) {
261: char tname[MAXDNAME+1];
262: 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: if (cp + 2 * INT16SZ > eom)
269: return (-1);
270: ttype = ns_get16(cp); cp += INT16SZ;
271: tclass = ns_get16(cp); cp += INT16SZ;
272: if (ttype == type && tclass == class &&
273: ns_samename(tname, name) == 1)
274: return (1);
275: }
276: return (0);
277: }
278:
1.10 christos 279: /*%
1.1 christos 280: * is there a 1:1 mapping of (name,type,class)
281: * in (buf1,eom1) and (buf2,eom2)?
1.10 christos 282: *
1.1 christos 283: * returns:
1.10 christos 284: *\li -1 : format error
285: *\li 0 : not a 1:1 mapping
286: *\li >0 : is a 1:1 mapping
287: *
1.1 christos 288: * author:
1.10 christos 289: *\li paul vixie, 29may94
1.1 christos 290: */
291: int
292: res_queriesmatch(const u_char *buf1, const u_char *eom1,
293: const u_char *buf2, const u_char *eom2)
294: {
295: const u_char *cp = buf1 + HFIXEDSZ;
1.2 christos 296: int qdcount = ntohs(((const HEADER*)(const void *)buf1)->qdcount);
1.1 christos 297:
298: if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
299: return (-1);
300:
301: /*
302: * Only header section present in replies to
303: * dynamic update packets.
304: */
1.2 christos 305: if ((((const HEADER *)(const void *)buf1)->opcode == ns_o_update) &&
306: (((const HEADER *)(const void *)buf2)->opcode == ns_o_update))
1.1 christos 307: return (1);
308:
1.2 christos 309: if (qdcount != ntohs(((const HEADER*)(const void *)buf2)->qdcount))
1.1 christos 310: return (0);
311: while (qdcount-- > 0) {
312: char tname[MAXDNAME+1];
313: int n, ttype, tclass;
314:
315: n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
316: if (n < 0)
317: return (-1);
318: cp += n;
319: if (cp + 2 * INT16SZ > eom1)
320: return (-1);
321: ttype = ns_get16(cp); cp += INT16SZ;
322: tclass = ns_get16(cp); cp += INT16SZ;
323: if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
324: return (0);
325: }
326: return (1);
327: }
328:
329: int
330: res_nsend(res_state statp,
331: const u_char *buf, int buflen, u_char *ans, int anssiz)
332: {
1.14 christos 333: int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n;
1.1 christos 334: char abuf[NI_MAXHOST];
335:
1.14 christos 336: #ifdef USE_POLL
337: highestFD = sysconf(_SC_OPEN_MAX) - 1;
338: #endif
339:
1.20 ! christos 340: (void)res_check(statp, NULL);
1.19 christos 341:
1.10 christos 342: /* No name servers or res_init() failure */
343: if (statp->nscount == 0 || EXT(statp).ext == NULL) {
1.1 christos 344: errno = ESRCH;
345: return (-1);
346: }
347: if (anssiz < HFIXEDSZ) {
348: errno = EINVAL;
349: return (-1);
350: }
351: DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
352: (stdout, ";; res_send()\n"), buf, buflen);
353: v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
354: gotsomewhere = 0;
355: terrno = ETIMEDOUT;
356:
357: /*
358: * If the ns_addr_list in the resolver context has changed, then
359: * invalidate our cached copy and the associated timing data.
360: */
361: if (EXT(statp).nscount != 0) {
362: int needclose = 0;
363: struct sockaddr_storage peer;
364: ISC_SOCKLEN_T peerlen;
365:
366: if (EXT(statp).nscount != statp->nscount)
367: needclose++;
368: else
369: for (ns = 0; ns < statp->nscount; ns++) {
370: if (statp->nsaddr_list[ns].sin_family &&
1.2 christos 371: !sock_eq((struct sockaddr *)(void *)&statp->nsaddr_list[ns],
372: (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[ns])) {
1.1 christos 373: needclose++;
374: break;
375: }
376:
377: if (EXT(statp).nssocks[ns] == -1)
378: continue;
379: peerlen = sizeof(peer);
1.17 mrg 380: if (getpeername(EXT(statp).nssocks[ns],
1.2 christos 381: (struct sockaddr *)(void *)&peer, &peerlen) < 0) {
1.1 christos 382: needclose++;
383: break;
384: }
1.2 christos 385: if (!sock_eq((struct sockaddr *)(void *)&peer,
386: get_nsaddr(statp, (size_t)ns))) {
1.1 christos 387: needclose++;
388: break;
389: }
390: }
391: if (needclose) {
392: res_nclose(statp);
393: EXT(statp).nscount = 0;
394: }
395: }
396:
397: /*
398: * Maybe initialize our private copy of the ns_addr_list.
399: */
400: if (EXT(statp).nscount == 0) {
401: for (ns = 0; ns < statp->nscount; ns++) {
402: EXT(statp).nstimes[ns] = RES_MAXTIME;
403: EXT(statp).nssocks[ns] = -1;
404: if (!statp->nsaddr_list[ns].sin_family)
405: continue;
406: EXT(statp).ext->nsaddrs[ns].sin =
407: statp->nsaddr_list[ns];
408: }
409: EXT(statp).nscount = statp->nscount;
410: }
411:
412: /*
413: * Some resolvers want to even out the load on their nameservers.
414: * Note that RES_BLAST overrides RES_ROTATE.
415: */
416: if ((statp->options & RES_ROTATE) != 0U &&
417: (statp->options & RES_BLAST) == 0U) {
418: union res_sockaddr_union inu;
419: struct sockaddr_in ina;
420: int lastns = statp->nscount - 1;
421: int fd;
422: u_int16_t nstime;
423:
424: if (EXT(statp).ext != NULL)
425: inu = EXT(statp).ext->nsaddrs[0];
426: ina = statp->nsaddr_list[0];
427: fd = EXT(statp).nssocks[0];
428: nstime = EXT(statp).nstimes[0];
429: for (ns = 0; ns < lastns; ns++) {
430: if (EXT(statp).ext != NULL)
1.18 christos 431: EXT(statp).ext->nsaddrs[ns] =
1.1 christos 432: EXT(statp).ext->nsaddrs[ns + 1];
433: statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
434: EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
435: EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
436: }
437: if (EXT(statp).ext != NULL)
438: EXT(statp).ext->nsaddrs[lastns] = inu;
439: statp->nsaddr_list[lastns] = ina;
440: EXT(statp).nssocks[lastns] = fd;
441: EXT(statp).nstimes[lastns] = nstime;
442: }
443:
444: /*
445: * Send request, RETRY times, or until successful.
446: */
1.14 christos 447: for (tries = 0; tries < statp->retry; tries++) {
1.1 christos 448: for (ns = 0; ns < statp->nscount; ns++) {
449: struct sockaddr *nsap;
450: int nsaplen;
1.2 christos 451: nsap = get_nsaddr(statp, (size_t)ns);
1.1 christos 452: nsaplen = get_salen(nsap);
453: statp->_flags &= ~RES_F_LASTMASK;
454: statp->_flags |= (ns << RES_F_LASTSHIFT);
455: same_ns:
456: if (statp->qhook) {
457: int done = 0, loops = 0;
458:
459: do {
460: res_sendhookact act;
461:
462: act = (*statp->qhook)(&nsap, &buf, &buflen,
463: ans, anssiz, &resplen);
464: switch (act) {
465: case res_goahead:
466: done = 1;
467: break;
468: case res_nextns:
469: res_nclose(statp);
470: goto next_ns;
471: case res_done:
472: return (resplen);
473: case res_modified:
474: /* give the hook another try */
475: if (++loops < 42) /*doug adams*/
476: break;
477: /*FALLTHROUGH*/
478: case res_error:
479: /*FALLTHROUGH*/
480: default:
481: goto fail;
482: }
483: } while (!done);
484: }
485:
486: Dprint(((statp->options & RES_DEBUG) &&
1.2 christos 487: getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf),
1.1 christos 488: NULL, 0, niflags) == 0),
489: (stdout, ";; Querying server (# %d) address = %s\n",
490: ns + 1, abuf));
491:
492:
493: if (v_circuit) {
494: /* Use VC; at most one attempt per server. */
1.14 christos 495: tries = statp->retry;
1.1 christos 496: n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
497: ns);
498: if (n < 0)
499: goto fail;
500: if (n == 0)
501: goto next_ns;
502: resplen = n;
503: } else {
504: /* Use datagrams. */
505: n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
1.14 christos 506: ns, tries, &v_circuit, &gotsomewhere);
1.1 christos 507: if (n < 0)
508: goto fail;
509: if (n == 0)
510: goto next_ns;
511: if (v_circuit)
512: goto same_ns;
513: resplen = n;
514: }
515:
516: Dprint((statp->options & RES_DEBUG) ||
517: ((statp->pfcode & RES_PRF_REPLY) &&
518: (statp->pfcode & RES_PRF_HEAD1)),
519: (stdout, ";; got answer:\n"));
520:
521: DprintQ((statp->options & RES_DEBUG) ||
522: (statp->pfcode & RES_PRF_REPLY),
523: (stdout, "%s", ""),
524: ans, (resplen > anssiz) ? anssiz : resplen);
525:
526: /*
527: * If we have temporarily opened a virtual circuit,
528: * or if we haven't been asked to keep a socket open,
529: * close the socket.
530: */
531: if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
532: (statp->options & RES_STAYOPEN) == 0U) {
533: res_nclose(statp);
534: }
535: if (statp->rhook) {
536: int done = 0, loops = 0;
537:
538: do {
539: res_sendhookact act;
540:
541: act = (*statp->rhook)(nsap, buf, buflen,
542: ans, anssiz, &resplen);
543: switch (act) {
544: case res_goahead:
545: case res_done:
546: done = 1;
547: break;
548: case res_nextns:
549: res_nclose(statp);
550: goto next_ns;
551: case res_modified:
552: /* give the hook another try */
553: if (++loops < 42) /*doug adams*/
554: break;
555: /*FALLTHROUGH*/
556: case res_error:
557: /*FALLTHROUGH*/
558: default:
559: goto fail;
560: }
561: } while (!done);
562:
563: }
564: return (resplen);
565: next_ns: ;
566: } /*foreach ns*/
567: } /*foreach retry*/
568: res_nclose(statp);
569: if (!v_circuit) {
570: if (!gotsomewhere)
1.10 christos 571: errno = ECONNREFUSED; /*%< no nameservers found */
1.1 christos 572: else
1.10 christos 573: errno = ETIMEDOUT; /*%< no answer obtained */
1.1 christos 574: } else
575: errno = terrno;
576: return (-1);
577: fail:
578: res_nclose(statp);
579: return (-1);
580: }
581:
582: /* Private */
583:
584: static int
585: get_salen(sa)
586: const struct sockaddr *sa;
587: {
588:
589: #ifdef HAVE_SA_LEN
590: /* There are people do not set sa_len. Be forgiving to them. */
591: if (sa->sa_len)
592: return (sa->sa_len);
593: #endif
594:
595: if (sa->sa_family == AF_INET)
596: return (sizeof(struct sockaddr_in));
597: else if (sa->sa_family == AF_INET6)
598: return (sizeof(struct sockaddr_in6));
599: else
1.10 christos 600: return (0); /*%< unknown, die on connect */
1.1 christos 601: }
602:
1.10 christos 603: /*%
1.1 christos 604: * pick appropriate nsaddr_list for use. see res_init() for initialization.
605: */
606: static struct sockaddr *
607: get_nsaddr(statp, n)
608: res_state statp;
609: size_t n;
610: {
611:
612: if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
613: /*
614: * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
615: * than struct sockaddr, and
616: * - user code did not update statp->nsaddr_list[n].
617: */
618: return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
619: } else {
620: /*
621: * - user code updated statp->nsaddr_list[n], or
622: * - statp->nsaddr_list[n] has the same content as
623: * EXT(statp).ext->nsaddrs[n].
624: */
625: return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
626: }
627: }
628:
629: static int
630: send_vc(res_state statp,
631: const u_char *buf, int buflen, u_char *ans, int anssiz,
632: int *terrno, int ns)
633: {
1.3 christos 634: const HEADER *hp = (const HEADER *)(const void *)buf;
635: HEADER *anhp = (HEADER *)(void *)ans;
1.1 christos 636: struct sockaddr *nsap;
637: int nsaplen;
638: int truncating, connreset, resplen, n;
639: struct iovec iov[2];
640: u_short len;
641: u_char *cp;
642: void *tmp;
1.14 christos 643: #ifdef SO_NOSIGPIPE
644: int on = 1;
645: #endif
1.1 christos 646:
1.2 christos 647: nsap = get_nsaddr(statp, (size_t)ns);
1.1 christos 648: nsaplen = get_salen(nsap);
649:
650: connreset = 0;
651: same_ns:
652: truncating = 0;
653:
654: /* Are we still talking to whom we want to talk to? */
655: if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
656: struct sockaddr_storage peer;
657: ISC_SOCKLEN_T size = sizeof peer;
658:
659: if (getpeername(statp->_vcsock,
1.2 christos 660: (struct sockaddr *)(void *)&peer, &size) < 0 ||
661: !sock_eq((struct sockaddr *)(void *)&peer, nsap)) {
1.1 christos 662: res_nclose(statp);
663: statp->_flags &= ~RES_F_VC;
664: }
665: }
666:
667: if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
668: if (statp->_vcsock >= 0)
669: res_nclose(statp);
670:
671: statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
672: if (statp->_vcsock > highestFD) {
673: res_nclose(statp);
674: errno = ENOTSOCK;
675: }
676: if (statp->_vcsock < 0) {
677: switch (errno) {
678: case EPROTONOSUPPORT:
679: #ifdef EPFNOSUPPORT
680: case EPFNOSUPPORT:
681: #endif
682: case EAFNOSUPPORT:
683: Perror(statp, stderr, "socket(vc)", errno);
684: return (0);
685: default:
686: *terrno = errno;
687: Perror(statp, stderr, "socket(vc)", errno);
688: return (-1);
689: }
690: }
1.14 christos 691: #ifdef SO_NOSIGPIPE
692: /*
693: * Disable generation of SIGPIPE when writing to a closed
694: * socket. Write should return -1 and set errno to EPIPE
1.18 christos 695: * instead.
1.14 christos 696: *
697: * Push on even if setsockopt(SO_NOSIGPIPE) fails.
698: */
699: (void)setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
1.18 christos 700: sizeof(on));
1.14 christos 701: #endif
1.1 christos 702: errno = 0;
1.2 christos 703: if (connect(statp->_vcsock, nsap, (socklen_t)nsaplen) < 0) {
1.1 christos 704: *terrno = errno;
705: Aerror(statp, stderr, "connect/vc", errno, nsap,
706: nsaplen);
707: res_nclose(statp);
708: return (0);
709: }
710: statp->_flags |= RES_F_VC;
711: }
712:
713: /*
714: * Send length & message
715: */
1.2 christos 716: ns_put16((u_short)buflen, (u_char*)(void *)&len);
1.1 christos 717: iov[0] = evConsIovec(&len, INT16SZ);
718: DE_CONST(buf, tmp);
1.2 christos 719: iov[1] = evConsIovec(tmp, (size_t)buflen);
1.1 christos 720: if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
721: *terrno = errno;
722: Perror(statp, stderr, "write failed", errno);
723: res_nclose(statp);
724: return (0);
725: }
726: /*
727: * Receive length & response
728: */
729: read_len:
730: cp = ans;
731: len = INT16SZ;
1.2 christos 732: while ((n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0) {
1.1 christos 733: cp += n;
1.2 christos 734: if ((len -= n) == 0)
1.1 christos 735: break;
736: }
737: if (n <= 0) {
738: *terrno = errno;
739: Perror(statp, stderr, "read failed", errno);
740: res_nclose(statp);
741: /*
742: * A long running process might get its TCP
743: * connection reset if the remote server was
744: * restarted. Requery the server instead of
745: * trying a new one. When there is only one
746: * server, this means that a query might work
747: * instead of failing. We only allow one reset
748: * per query to prevent looping.
749: */
750: if (*terrno == ECONNRESET && !connreset) {
751: connreset = 1;
752: res_nclose(statp);
753: goto same_ns;
754: }
755: res_nclose(statp);
756: return (0);
757: }
758: resplen = ns_get16(ans);
759: if (resplen > anssiz) {
760: Dprint(statp->options & RES_DEBUG,
761: (stdout, ";; response truncated\n")
762: );
763: truncating = 1;
764: len = anssiz;
765: } else
766: len = resplen;
767: if (len < HFIXEDSZ) {
768: /*
769: * Undersized message.
770: */
771: Dprint(statp->options & RES_DEBUG,
772: (stdout, ";; undersized: %d\n", len));
773: *terrno = EMSGSIZE;
774: res_nclose(statp);
775: return (0);
776: }
777: cp = ans;
1.2 christos 778: while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0){
1.1 christos 779: cp += n;
780: len -= n;
781: }
782: if (n <= 0) {
783: *terrno = errno;
784: Perror(statp, stderr, "read(vc)", errno);
785: res_nclose(statp);
786: return (0);
787: }
788: if (truncating) {
789: /*
790: * Flush rest of answer so connection stays in synch.
791: */
792: anhp->tc = 1;
793: len = resplen - anssiz;
794: while (len != 0) {
795: char junk[PACKETSZ];
796:
797: n = read(statp->_vcsock, junk,
798: (len > sizeof junk) ? sizeof junk : len);
799: if (n > 0)
800: len -= n;
801: else
802: break;
803: }
804: }
805: /*
806: * If the calling applicating has bailed out of
807: * a previous call and failed to arrange to have
808: * the circuit closed or the server has got
809: * itself confused, then drop the packet and
810: * wait for the correct one.
811: */
812: if (hp->id != anhp->id) {
813: DprintQ((statp->options & RES_DEBUG) ||
814: (statp->pfcode & RES_PRF_REPLY),
815: (stdout, ";; old answer (unexpected):\n"),
816: ans, (resplen > anssiz) ? anssiz: resplen);
817: goto read_len;
818: }
819:
820: /*
821: * All is well, or the error is fatal. Signal that the
822: * next nameserver ought not be tried.
823: */
824: return (resplen);
825: }
826:
827: static int
1.10 christos 828: send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans,
1.14 christos 829: int anssiz, int *terrno, int ns, int tries, int *v_circuit,
1.10 christos 830: int *gotsomewhere)
1.1 christos 831: {
1.2 christos 832: const HEADER *hp = (const HEADER *)(const void *)buf;
833: HEADER *anhp = (HEADER *)(void *)ans;
1.1 christos 834: const struct sockaddr *nsap;
835: int nsaplen;
836: struct timespec now, timeout, finish;
837: struct sockaddr_storage from;
838: ISC_SOCKLEN_T fromlen;
839: int resplen, seconds, n, s;
1.10 christos 840: #ifdef USE_POLL
841: int polltimeout;
842: struct pollfd pollfd;
843: #else
844: fd_set dsmask;
845: #endif
1.1 christos 846:
1.2 christos 847: nsap = get_nsaddr(statp, (size_t)ns);
1.1 christos 848: nsaplen = get_salen(nsap);
849: if (EXT(statp).nssocks[ns] == -1) {
850: EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
851: if (EXT(statp).nssocks[ns] > highestFD) {
852: res_nclose(statp);
853: errno = ENOTSOCK;
854: }
855: if (EXT(statp).nssocks[ns] < 0) {
856: switch (errno) {
857: case EPROTONOSUPPORT:
858: #ifdef EPFNOSUPPORT
859: case EPFNOSUPPORT:
860: #endif
861: case EAFNOSUPPORT:
862: Perror(statp, stderr, "socket(dg)", errno);
863: return (0);
864: default:
865: *terrno = errno;
866: Perror(statp, stderr, "socket(dg)", errno);
867: return (-1);
868: }
869: }
870: #ifndef CANNOT_CONNECT_DGRAM
871: /*
872: * On a 4.3BSD+ machine (client and server,
873: * actually), sending to a nameserver datagram
874: * port with no nameserver will cause an
875: * ICMP port unreachable message to be returned.
876: * If our datagram socket is "connected" to the
877: * server, we get an ECONNREFUSED error on the next
878: * socket operation, and select returns if the
879: * error message is received. We can thus detect
880: * the absence of a nameserver without timing out.
881: */
1.2 christos 882: if (connect(EXT(statp).nssocks[ns], nsap, (socklen_t)nsaplen) < 0) {
1.1 christos 883: Aerror(statp, stderr, "connect(dg)", errno, nsap,
884: nsaplen);
885: res_nclose(statp);
886: return (0);
887: }
888: #endif /* !CANNOT_CONNECT_DGRAM */
889: Dprint(statp->options & RES_DEBUG,
890: (stdout, ";; new DG socket\n"))
891: }
892: s = EXT(statp).nssocks[ns];
893: #ifndef CANNOT_CONNECT_DGRAM
1.2 christos 894: if (send(s, (const char*)buf, (size_t)buflen, 0) != buflen) {
1.1 christos 895: Perror(statp, stderr, "send", errno);
896: res_nclose(statp);
897: return (0);
898: }
899: #else /* !CANNOT_CONNECT_DGRAM */
900: if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
901: {
902: Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
903: res_nclose(statp);
904: return (0);
905: }
906: #endif /* !CANNOT_CONNECT_DGRAM */
907:
908: /*
909: * Wait for reply.
910: */
1.14 christos 911: seconds = (statp->retrans << tries);
1.1 christos 912: if (ns > 0)
913: seconds /= statp->nscount;
914: if (seconds <= 0)
915: seconds = 1;
916: now = evNowTime();
1.3 christos 917: timeout = evConsTime((long)seconds, 0L);
1.1 christos 918: finish = evAddTime(now, timeout);
919: goto nonow;
920: wait:
921: now = evNowTime();
922: nonow:
1.10 christos 923: #ifndef USE_POLL
1.1 christos 924: FD_ZERO(&dsmask);
925: FD_SET(s, &dsmask);
926: if (evCmpTime(finish, now) > 0)
927: timeout = evSubTime(finish, now);
928: else
1.3 christos 929: timeout = evConsTime(0L, 0L);
1.1 christos 930: n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
1.10 christos 931: #else
932: timeout = evSubTime(finish, now);
933: if (timeout.tv_sec < 0)
1.11 christos 934: timeout = evConsTime(0L, 0L);
1.16 christos 935: polltimeout = 1000*(int)timeout.tv_sec +
936: (int)timeout.tv_nsec/1000000;
1.10 christos 937: pollfd.fd = s;
938: pollfd.events = POLLRDNORM;
939: n = poll(&pollfd, 1, polltimeout);
940: #endif /* USE_POLL */
941:
1.1 christos 942: if (n == 0) {
943: Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
944: *gotsomewhere = 1;
945: return (0);
946: }
947: if (n < 0) {
948: if (errno == EINTR)
949: goto wait;
1.10 christos 950: #ifndef USE_POLL
1.1 christos 951: Perror(statp, stderr, "select", errno);
1.10 christos 952: #else
953: Perror(statp, stderr, "poll", errno);
954: #endif /* USE_POLL */
1.1 christos 955: res_nclose(statp);
956: return (0);
957: }
958: errno = 0;
959: fromlen = sizeof(from);
1.2 christos 960: resplen = recvfrom(s, (char*)ans, (size_t)anssiz,0,
961: (struct sockaddr *)(void *)&from, &fromlen);
1.1 christos 962: if (resplen <= 0) {
963: Perror(statp, stderr, "recvfrom", errno);
964: res_nclose(statp);
965: return (0);
966: }
967: *gotsomewhere = 1;
968: if (resplen < HFIXEDSZ) {
969: /*
970: * Undersized message.
971: */
972: Dprint(statp->options & RES_DEBUG,
973: (stdout, ";; undersized: %d\n",
974: resplen));
975: *terrno = EMSGSIZE;
976: res_nclose(statp);
977: return (0);
978: }
979: if (hp->id != anhp->id) {
980: /*
981: * response from old query, ignore it.
982: * XXX - potential security hazard could
983: * be detected here.
984: */
985: DprintQ((statp->options & RES_DEBUG) ||
986: (statp->pfcode & RES_PRF_REPLY),
987: (stdout, ";; old answer:\n"),
988: ans, (resplen > anssiz) ? anssiz : resplen);
989: goto wait;
990: }
991: if (!(statp->options & RES_INSECURE1) &&
1.2 christos 992: !res_ourserver_p(statp, (struct sockaddr *)(void *)&from)) {
1.1 christos 993: /*
994: * response from wrong server? ignore it.
995: * XXX - potential security hazard could
996: * be detected here.
997: */
998: DprintQ((statp->options & RES_DEBUG) ||
999: (statp->pfcode & RES_PRF_REPLY),
1000: (stdout, ";; not our server:\n"),
1001: ans, (resplen > anssiz) ? anssiz : resplen);
1002: goto wait;
1003: }
1004: #ifdef RES_USE_EDNS0
1005: if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
1006: /*
1007: * Do not retry if the server do not understand EDNS0.
1008: * The case has to be captured here, as FORMERR packet do not
1009: * carry query section, hence res_queriesmatch() returns 0.
1010: */
1011: DprintQ(statp->options & RES_DEBUG,
1012: (stdout, "server rejected query with EDNS0:\n"),
1013: ans, (resplen > anssiz) ? anssiz : resplen);
1014: /* record the error */
1015: statp->_flags |= RES_F_EDNS0ERR;
1016: res_nclose(statp);
1017: return (0);
1018: }
1019: #endif
1020: if (!(statp->options & RES_INSECURE2) &&
1021: !res_queriesmatch(buf, buf + buflen,
1022: ans, ans + anssiz)) {
1023: /*
1024: * response contains wrong query? ignore it.
1025: * XXX - potential security hazard could
1026: * be detected here.
1027: */
1028: DprintQ((statp->options & RES_DEBUG) ||
1029: (statp->pfcode & RES_PRF_REPLY),
1030: (stdout, ";; wrong query name:\n"),
1031: ans, (resplen > anssiz) ? anssiz : resplen);
1032: goto wait;
1033: }
1034: if (anhp->rcode == SERVFAIL ||
1035: anhp->rcode == NOTIMP ||
1036: anhp->rcode == REFUSED) {
1037: DprintQ(statp->options & RES_DEBUG,
1038: (stdout, "server rejected query:\n"),
1039: ans, (resplen > anssiz) ? anssiz : resplen);
1040: res_nclose(statp);
1041: /* don't retry if called from dig */
1042: if (!statp->pfcode)
1043: return (0);
1044: }
1045: if (!(statp->options & RES_IGNTC) && anhp->tc) {
1046: /*
1047: * To get the rest of answer,
1048: * use TCP with same server.
1049: */
1050: Dprint(statp->options & RES_DEBUG,
1051: (stdout, ";; truncated answer\n"));
1052: *v_circuit = 1;
1053: res_nclose(statp);
1054: return (1);
1055: }
1056: /*
1057: * All is well, or the error is fatal. Signal that the
1058: * next nameserver ought not be tried.
1059: */
1060: return (resplen);
1061: }
1062:
1063: static void
1064: Aerror(const res_state statp, FILE *file, const char *string, int error,
1065: const struct sockaddr *address, int alen)
1066: {
1067: int save = errno;
1068: char hbuf[NI_MAXHOST];
1069: char sbuf[NI_MAXSERV];
1070:
1071: alen = alen;
1072:
1073: if ((statp->options & RES_DEBUG) != 0U) {
1.2 christos 1074: if (getnameinfo(address, (socklen_t)alen, hbuf, sizeof(hbuf),
1.1 christos 1075: sbuf, sizeof(sbuf), niflags)) {
1076: strncpy(hbuf, "?", sizeof(hbuf) - 1);
1077: hbuf[sizeof(hbuf) - 1] = '\0';
1078: strncpy(sbuf, "?", sizeof(sbuf) - 1);
1079: sbuf[sizeof(sbuf) - 1] = '\0';
1080: }
1081: fprintf(file, "res_send: %s ([%s].%s): %s\n",
1082: string, hbuf, sbuf, strerror(error));
1083: }
1084: errno = save;
1085: }
1086:
1087: static void
1088: Perror(const res_state statp, FILE *file, const char *string, int error) {
1089: int save = errno;
1090:
1091: if ((statp->options & RES_DEBUG) != 0U)
1092: fprintf(file, "res_send: %s: %s\n",
1093: string, strerror(error));
1094: errno = save;
1095: }
1096:
1097: static int
1098: sock_eq(struct sockaddr *a, struct sockaddr *b) {
1099: struct sockaddr_in *a4, *b4;
1100: struct sockaddr_in6 *a6, *b6;
1101:
1102: if (a->sa_family != b->sa_family)
1103: return 0;
1104: switch (a->sa_family) {
1105: case AF_INET:
1.2 christos 1106: a4 = (struct sockaddr_in *)(void *)a;
1107: b4 = (struct sockaddr_in *)(void *)b;
1.1 christos 1108: return a4->sin_port == b4->sin_port &&
1109: a4->sin_addr.s_addr == b4->sin_addr.s_addr;
1110: case AF_INET6:
1.2 christos 1111: a6 = (struct sockaddr_in6 *)(void *)a;
1112: b6 = (struct sockaddr_in6 *)(void *)b;
1.1 christos 1113: return a6->sin6_port == b6->sin6_port &&
1114: #ifdef HAVE_SIN6_SCOPE_ID
1115: a6->sin6_scope_id == b6->sin6_scope_id &&
1116: #endif
1117: IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
1118: default:
1119: return 0;
1120: }
1121: }
1122:
1.10 christos 1123: #if defined(NEED_PSELECT) && !defined(USE_POLL)
1.1 christos 1124: /* XXX needs to move to the porting library. */
1125: static int
1126: pselect(int nfds, void *rfds, void *wfds, void *efds,
1127: struct timespec *tsp, const sigset_t *sigmask)
1128: {
1129: struct timeval tv, *tvp;
1130: sigset_t sigs;
1131: int n;
1132:
1133: if (tsp) {
1134: tvp = &tv;
1135: tv = evTimeVal(*tsp);
1136: } else
1137: tvp = NULL;
1138: if (sigmask)
1139: sigprocmask(SIG_SETMASK, sigmask, &sigs);
1140: n = select(nfds, rfds, wfds, efds, tvp);
1141: if (sigmask)
1142: sigprocmask(SIG_SETMASK, &sigs, NULL);
1143: if (tsp)
1144: *tsp = evTimeSpec(tv);
1145: return (n);
1146: }
1147: #endif
CVSweb <webmaster@jp.NetBSD.org>