Annotation of src/lib/libc/resolv/res_send.c, Revision 1.18
1.18 ! christos 1: /* $NetBSD: res_send.c,v 1.1.1.5 2009/04/12 16:35:49 christos Exp $ */
! 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.18 ! christos 96: __RCSID("$NetBSD: res_send.c,v 1.17 2009/01/27 05:13:23 mrg 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.10 christos 340: /* No name servers or res_init() failure */
341: if (statp->nscount == 0 || EXT(statp).ext == NULL) {
1.1 christos 342: errno = ESRCH;
343: return (-1);
344: }
345: if (anssiz < HFIXEDSZ) {
346: errno = EINVAL;
347: return (-1);
348: }
349: DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
350: (stdout, ";; res_send()\n"), buf, buflen);
351: v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
352: gotsomewhere = 0;
353: terrno = ETIMEDOUT;
354:
355: /*
356: * If the ns_addr_list in the resolver context has changed, then
357: * invalidate our cached copy and the associated timing data.
358: */
359: if (EXT(statp).nscount != 0) {
360: int needclose = 0;
361: struct sockaddr_storage peer;
362: ISC_SOCKLEN_T peerlen;
363:
364: if (EXT(statp).nscount != statp->nscount)
365: needclose++;
366: else
367: for (ns = 0; ns < statp->nscount; ns++) {
368: if (statp->nsaddr_list[ns].sin_family &&
1.2 christos 369: !sock_eq((struct sockaddr *)(void *)&statp->nsaddr_list[ns],
370: (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[ns])) {
1.1 christos 371: needclose++;
372: break;
373: }
374:
375: if (EXT(statp).nssocks[ns] == -1)
376: continue;
377: peerlen = sizeof(peer);
1.17 mrg 378: if (getpeername(EXT(statp).nssocks[ns],
1.2 christos 379: (struct sockaddr *)(void *)&peer, &peerlen) < 0) {
1.1 christos 380: needclose++;
381: break;
382: }
1.2 christos 383: if (!sock_eq((struct sockaddr *)(void *)&peer,
384: get_nsaddr(statp, (size_t)ns))) {
1.1 christos 385: needclose++;
386: break;
387: }
388: }
389: if (needclose) {
390: res_nclose(statp);
391: EXT(statp).nscount = 0;
392: }
393: }
394:
395: /*
396: * Maybe initialize our private copy of the ns_addr_list.
397: */
398: if (EXT(statp).nscount == 0) {
399: for (ns = 0; ns < statp->nscount; ns++) {
400: EXT(statp).nstimes[ns] = RES_MAXTIME;
401: EXT(statp).nssocks[ns] = -1;
402: if (!statp->nsaddr_list[ns].sin_family)
403: continue;
404: EXT(statp).ext->nsaddrs[ns].sin =
405: statp->nsaddr_list[ns];
406: }
407: EXT(statp).nscount = statp->nscount;
408: }
409:
410: /*
411: * Some resolvers want to even out the load on their nameservers.
412: * Note that RES_BLAST overrides RES_ROTATE.
413: */
414: if ((statp->options & RES_ROTATE) != 0U &&
415: (statp->options & RES_BLAST) == 0U) {
416: union res_sockaddr_union inu;
417: struct sockaddr_in ina;
418: int lastns = statp->nscount - 1;
419: int fd;
420: u_int16_t nstime;
421:
422: if (EXT(statp).ext != NULL)
423: inu = EXT(statp).ext->nsaddrs[0];
424: ina = statp->nsaddr_list[0];
425: fd = EXT(statp).nssocks[0];
426: nstime = EXT(statp).nstimes[0];
427: for (ns = 0; ns < lastns; ns++) {
428: if (EXT(statp).ext != NULL)
1.18 ! christos 429: EXT(statp).ext->nsaddrs[ns] =
1.1 christos 430: EXT(statp).ext->nsaddrs[ns + 1];
431: statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
432: EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
433: EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
434: }
435: if (EXT(statp).ext != NULL)
436: EXT(statp).ext->nsaddrs[lastns] = inu;
437: statp->nsaddr_list[lastns] = ina;
438: EXT(statp).nssocks[lastns] = fd;
439: EXT(statp).nstimes[lastns] = nstime;
440: }
441:
442: /*
443: * Send request, RETRY times, or until successful.
444: */
1.14 christos 445: for (tries = 0; tries < statp->retry; tries++) {
1.1 christos 446: for (ns = 0; ns < statp->nscount; ns++) {
447: struct sockaddr *nsap;
448: int nsaplen;
1.2 christos 449: nsap = get_nsaddr(statp, (size_t)ns);
1.1 christos 450: nsaplen = get_salen(nsap);
451: statp->_flags &= ~RES_F_LASTMASK;
452: statp->_flags |= (ns << RES_F_LASTSHIFT);
453: same_ns:
454: if (statp->qhook) {
455: int done = 0, loops = 0;
456:
457: do {
458: res_sendhookact act;
459:
460: act = (*statp->qhook)(&nsap, &buf, &buflen,
461: ans, anssiz, &resplen);
462: switch (act) {
463: case res_goahead:
464: done = 1;
465: break;
466: case res_nextns:
467: res_nclose(statp);
468: goto next_ns;
469: case res_done:
470: return (resplen);
471: case res_modified:
472: /* give the hook another try */
473: if (++loops < 42) /*doug adams*/
474: break;
475: /*FALLTHROUGH*/
476: case res_error:
477: /*FALLTHROUGH*/
478: default:
479: goto fail;
480: }
481: } while (!done);
482: }
483:
484: Dprint(((statp->options & RES_DEBUG) &&
1.2 christos 485: getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf),
1.1 christos 486: NULL, 0, niflags) == 0),
487: (stdout, ";; Querying server (# %d) address = %s\n",
488: ns + 1, abuf));
489:
490:
491: if (v_circuit) {
492: /* Use VC; at most one attempt per server. */
1.14 christos 493: tries = statp->retry;
1.1 christos 494: n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
495: ns);
496: if (n < 0)
497: goto fail;
498: if (n == 0)
499: goto next_ns;
500: resplen = n;
501: } else {
502: /* Use datagrams. */
503: n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
1.14 christos 504: ns, tries, &v_circuit, &gotsomewhere);
1.1 christos 505: if (n < 0)
506: goto fail;
507: if (n == 0)
508: goto next_ns;
509: if (v_circuit)
510: goto same_ns;
511: resplen = n;
512: }
513:
514: Dprint((statp->options & RES_DEBUG) ||
515: ((statp->pfcode & RES_PRF_REPLY) &&
516: (statp->pfcode & RES_PRF_HEAD1)),
517: (stdout, ";; got answer:\n"));
518:
519: DprintQ((statp->options & RES_DEBUG) ||
520: (statp->pfcode & RES_PRF_REPLY),
521: (stdout, "%s", ""),
522: ans, (resplen > anssiz) ? anssiz : resplen);
523:
524: /*
525: * If we have temporarily opened a virtual circuit,
526: * or if we haven't been asked to keep a socket open,
527: * close the socket.
528: */
529: if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
530: (statp->options & RES_STAYOPEN) == 0U) {
531: res_nclose(statp);
532: }
533: if (statp->rhook) {
534: int done = 0, loops = 0;
535:
536: do {
537: res_sendhookact act;
538:
539: act = (*statp->rhook)(nsap, buf, buflen,
540: ans, anssiz, &resplen);
541: switch (act) {
542: case res_goahead:
543: case res_done:
544: done = 1;
545: break;
546: case res_nextns:
547: res_nclose(statp);
548: goto next_ns;
549: case res_modified:
550: /* give the hook another try */
551: if (++loops < 42) /*doug adams*/
552: break;
553: /*FALLTHROUGH*/
554: case res_error:
555: /*FALLTHROUGH*/
556: default:
557: goto fail;
558: }
559: } while (!done);
560:
561: }
562: return (resplen);
563: next_ns: ;
564: } /*foreach ns*/
565: } /*foreach retry*/
566: res_nclose(statp);
567: if (!v_circuit) {
568: if (!gotsomewhere)
1.10 christos 569: errno = ECONNREFUSED; /*%< no nameservers found */
1.1 christos 570: else
1.10 christos 571: errno = ETIMEDOUT; /*%< no answer obtained */
1.1 christos 572: } else
573: errno = terrno;
574: return (-1);
575: fail:
576: res_nclose(statp);
577: return (-1);
578: }
579:
580: /* Private */
581:
582: static int
583: get_salen(sa)
584: const struct sockaddr *sa;
585: {
586:
587: #ifdef HAVE_SA_LEN
588: /* There are people do not set sa_len. Be forgiving to them. */
589: if (sa->sa_len)
590: return (sa->sa_len);
591: #endif
592:
593: if (sa->sa_family == AF_INET)
594: return (sizeof(struct sockaddr_in));
595: else if (sa->sa_family == AF_INET6)
596: return (sizeof(struct sockaddr_in6));
597: else
1.10 christos 598: return (0); /*%< unknown, die on connect */
1.1 christos 599: }
600:
1.10 christos 601: /*%
1.1 christos 602: * pick appropriate nsaddr_list for use. see res_init() for initialization.
603: */
604: static struct sockaddr *
605: get_nsaddr(statp, n)
606: res_state statp;
607: size_t n;
608: {
609:
610: if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
611: /*
612: * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
613: * than struct sockaddr, and
614: * - user code did not update statp->nsaddr_list[n].
615: */
616: return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
617: } else {
618: /*
619: * - user code updated statp->nsaddr_list[n], or
620: * - statp->nsaddr_list[n] has the same content as
621: * EXT(statp).ext->nsaddrs[n].
622: */
623: return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
624: }
625: }
626:
627: static int
628: send_vc(res_state statp,
629: const u_char *buf, int buflen, u_char *ans, int anssiz,
630: int *terrno, int ns)
631: {
1.3 christos 632: const HEADER *hp = (const HEADER *)(const void *)buf;
633: HEADER *anhp = (HEADER *)(void *)ans;
1.1 christos 634: struct sockaddr *nsap;
635: int nsaplen;
636: int truncating, connreset, resplen, n;
637: struct iovec iov[2];
638: u_short len;
639: u_char *cp;
640: void *tmp;
1.14 christos 641: #ifdef SO_NOSIGPIPE
642: int on = 1;
643: #endif
1.1 christos 644:
1.2 christos 645: nsap = get_nsaddr(statp, (size_t)ns);
1.1 christos 646: nsaplen = get_salen(nsap);
647:
648: connreset = 0;
649: same_ns:
650: truncating = 0;
651:
652: /* Are we still talking to whom we want to talk to? */
653: if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
654: struct sockaddr_storage peer;
655: ISC_SOCKLEN_T size = sizeof peer;
656:
657: if (getpeername(statp->_vcsock,
1.2 christos 658: (struct sockaddr *)(void *)&peer, &size) < 0 ||
659: !sock_eq((struct sockaddr *)(void *)&peer, nsap)) {
1.1 christos 660: res_nclose(statp);
661: statp->_flags &= ~RES_F_VC;
662: }
663: }
664:
665: if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
666: if (statp->_vcsock >= 0)
667: res_nclose(statp);
668:
669: statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
670: if (statp->_vcsock > highestFD) {
671: res_nclose(statp);
672: errno = ENOTSOCK;
673: }
674: if (statp->_vcsock < 0) {
675: switch (errno) {
676: case EPROTONOSUPPORT:
677: #ifdef EPFNOSUPPORT
678: case EPFNOSUPPORT:
679: #endif
680: case EAFNOSUPPORT:
681: Perror(statp, stderr, "socket(vc)", errno);
682: return (0);
683: default:
684: *terrno = errno;
685: Perror(statp, stderr, "socket(vc)", errno);
686: return (-1);
687: }
688: }
1.14 christos 689: #ifdef SO_NOSIGPIPE
690: /*
691: * Disable generation of SIGPIPE when writing to a closed
692: * socket. Write should return -1 and set errno to EPIPE
1.18 ! christos 693: * instead.
1.14 christos 694: *
695: * Push on even if setsockopt(SO_NOSIGPIPE) fails.
696: */
697: (void)setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
1.18 ! christos 698: sizeof(on));
1.14 christos 699: #endif
1.1 christos 700: errno = 0;
1.2 christos 701: if (connect(statp->_vcsock, nsap, (socklen_t)nsaplen) < 0) {
1.1 christos 702: *terrno = errno;
703: Aerror(statp, stderr, "connect/vc", errno, nsap,
704: nsaplen);
705: res_nclose(statp);
706: return (0);
707: }
708: statp->_flags |= RES_F_VC;
709: }
710:
711: /*
712: * Send length & message
713: */
1.2 christos 714: ns_put16((u_short)buflen, (u_char*)(void *)&len);
1.1 christos 715: iov[0] = evConsIovec(&len, INT16SZ);
716: DE_CONST(buf, tmp);
1.2 christos 717: iov[1] = evConsIovec(tmp, (size_t)buflen);
1.1 christos 718: if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
719: *terrno = errno;
720: Perror(statp, stderr, "write failed", errno);
721: res_nclose(statp);
722: return (0);
723: }
724: /*
725: * Receive length & response
726: */
727: read_len:
728: cp = ans;
729: len = INT16SZ;
1.2 christos 730: while ((n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0) {
1.1 christos 731: cp += n;
1.2 christos 732: if ((len -= n) == 0)
1.1 christos 733: break;
734: }
735: if (n <= 0) {
736: *terrno = errno;
737: Perror(statp, stderr, "read failed", errno);
738: res_nclose(statp);
739: /*
740: * A long running process might get its TCP
741: * connection reset if the remote server was
742: * restarted. Requery the server instead of
743: * trying a new one. When there is only one
744: * server, this means that a query might work
745: * instead of failing. We only allow one reset
746: * per query to prevent looping.
747: */
748: if (*terrno == ECONNRESET && !connreset) {
749: connreset = 1;
750: res_nclose(statp);
751: goto same_ns;
752: }
753: res_nclose(statp);
754: return (0);
755: }
756: resplen = ns_get16(ans);
757: if (resplen > anssiz) {
758: Dprint(statp->options & RES_DEBUG,
759: (stdout, ";; response truncated\n")
760: );
761: truncating = 1;
762: len = anssiz;
763: } else
764: len = resplen;
765: if (len < HFIXEDSZ) {
766: /*
767: * Undersized message.
768: */
769: Dprint(statp->options & RES_DEBUG,
770: (stdout, ";; undersized: %d\n", len));
771: *terrno = EMSGSIZE;
772: res_nclose(statp);
773: return (0);
774: }
775: cp = ans;
1.2 christos 776: while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0){
1.1 christos 777: cp += n;
778: len -= n;
779: }
780: if (n <= 0) {
781: *terrno = errno;
782: Perror(statp, stderr, "read(vc)", errno);
783: res_nclose(statp);
784: return (0);
785: }
786: if (truncating) {
787: /*
788: * Flush rest of answer so connection stays in synch.
789: */
790: anhp->tc = 1;
791: len = resplen - anssiz;
792: while (len != 0) {
793: char junk[PACKETSZ];
794:
795: n = read(statp->_vcsock, junk,
796: (len > sizeof junk) ? sizeof junk : len);
797: if (n > 0)
798: len -= n;
799: else
800: break;
801: }
802: }
803: /*
804: * If the calling applicating has bailed out of
805: * a previous call and failed to arrange to have
806: * the circuit closed or the server has got
807: * itself confused, then drop the packet and
808: * wait for the correct one.
809: */
810: if (hp->id != anhp->id) {
811: DprintQ((statp->options & RES_DEBUG) ||
812: (statp->pfcode & RES_PRF_REPLY),
813: (stdout, ";; old answer (unexpected):\n"),
814: ans, (resplen > anssiz) ? anssiz: resplen);
815: goto read_len;
816: }
817:
818: /*
819: * All is well, or the error is fatal. Signal that the
820: * next nameserver ought not be tried.
821: */
822: return (resplen);
823: }
824:
825: static int
1.10 christos 826: send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans,
1.14 christos 827: int anssiz, int *terrno, int ns, int tries, int *v_circuit,
1.10 christos 828: int *gotsomewhere)
1.1 christos 829: {
1.2 christos 830: const HEADER *hp = (const HEADER *)(const void *)buf;
831: HEADER *anhp = (HEADER *)(void *)ans;
1.1 christos 832: const struct sockaddr *nsap;
833: int nsaplen;
834: struct timespec now, timeout, finish;
835: struct sockaddr_storage from;
836: ISC_SOCKLEN_T fromlen;
837: int resplen, seconds, n, s;
1.10 christos 838: #ifdef USE_POLL
839: int polltimeout;
840: struct pollfd pollfd;
841: #else
842: fd_set dsmask;
843: #endif
1.1 christos 844:
1.2 christos 845: nsap = get_nsaddr(statp, (size_t)ns);
1.1 christos 846: nsaplen = get_salen(nsap);
847: if (EXT(statp).nssocks[ns] == -1) {
848: EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
849: if (EXT(statp).nssocks[ns] > highestFD) {
850: res_nclose(statp);
851: errno = ENOTSOCK;
852: }
853: if (EXT(statp).nssocks[ns] < 0) {
854: switch (errno) {
855: case EPROTONOSUPPORT:
856: #ifdef EPFNOSUPPORT
857: case EPFNOSUPPORT:
858: #endif
859: case EAFNOSUPPORT:
860: Perror(statp, stderr, "socket(dg)", errno);
861: return (0);
862: default:
863: *terrno = errno;
864: Perror(statp, stderr, "socket(dg)", errno);
865: return (-1);
866: }
867: }
868: #ifndef CANNOT_CONNECT_DGRAM
869: /*
870: * On a 4.3BSD+ machine (client and server,
871: * actually), sending to a nameserver datagram
872: * port with no nameserver will cause an
873: * ICMP port unreachable message to be returned.
874: * If our datagram socket is "connected" to the
875: * server, we get an ECONNREFUSED error on the next
876: * socket operation, and select returns if the
877: * error message is received. We can thus detect
878: * the absence of a nameserver without timing out.
879: */
1.2 christos 880: if (connect(EXT(statp).nssocks[ns], nsap, (socklen_t)nsaplen) < 0) {
1.1 christos 881: Aerror(statp, stderr, "connect(dg)", errno, nsap,
882: nsaplen);
883: res_nclose(statp);
884: return (0);
885: }
886: #endif /* !CANNOT_CONNECT_DGRAM */
887: Dprint(statp->options & RES_DEBUG,
888: (stdout, ";; new DG socket\n"))
889: }
890: s = EXT(statp).nssocks[ns];
891: #ifndef CANNOT_CONNECT_DGRAM
1.2 christos 892: if (send(s, (const char*)buf, (size_t)buflen, 0) != buflen) {
1.1 christos 893: Perror(statp, stderr, "send", errno);
894: res_nclose(statp);
895: return (0);
896: }
897: #else /* !CANNOT_CONNECT_DGRAM */
898: if (sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen)
899: {
900: Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
901: res_nclose(statp);
902: return (0);
903: }
904: #endif /* !CANNOT_CONNECT_DGRAM */
905:
906: /*
907: * Wait for reply.
908: */
1.14 christos 909: seconds = (statp->retrans << tries);
1.1 christos 910: if (ns > 0)
911: seconds /= statp->nscount;
912: if (seconds <= 0)
913: seconds = 1;
914: now = evNowTime();
1.3 christos 915: timeout = evConsTime((long)seconds, 0L);
1.1 christos 916: finish = evAddTime(now, timeout);
917: goto nonow;
918: wait:
919: now = evNowTime();
920: nonow:
1.10 christos 921: #ifndef USE_POLL
1.1 christos 922: FD_ZERO(&dsmask);
923: FD_SET(s, &dsmask);
924: if (evCmpTime(finish, now) > 0)
925: timeout = evSubTime(finish, now);
926: else
1.3 christos 927: timeout = evConsTime(0L, 0L);
1.1 christos 928: n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
1.10 christos 929: #else
930: timeout = evSubTime(finish, now);
931: if (timeout.tv_sec < 0)
1.11 christos 932: timeout = evConsTime(0L, 0L);
1.16 christos 933: polltimeout = 1000*(int)timeout.tv_sec +
934: (int)timeout.tv_nsec/1000000;
1.10 christos 935: pollfd.fd = s;
936: pollfd.events = POLLRDNORM;
937: n = poll(&pollfd, 1, polltimeout);
938: #endif /* USE_POLL */
939:
1.1 christos 940: if (n == 0) {
941: Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
942: *gotsomewhere = 1;
943: return (0);
944: }
945: if (n < 0) {
946: if (errno == EINTR)
947: goto wait;
1.10 christos 948: #ifndef USE_POLL
1.1 christos 949: Perror(statp, stderr, "select", errno);
1.10 christos 950: #else
951: Perror(statp, stderr, "poll", errno);
952: #endif /* USE_POLL */
1.1 christos 953: res_nclose(statp);
954: return (0);
955: }
956: errno = 0;
957: fromlen = sizeof(from);
1.2 christos 958: resplen = recvfrom(s, (char*)ans, (size_t)anssiz,0,
959: (struct sockaddr *)(void *)&from, &fromlen);
1.1 christos 960: if (resplen <= 0) {
961: Perror(statp, stderr, "recvfrom", errno);
962: res_nclose(statp);
963: return (0);
964: }
965: *gotsomewhere = 1;
966: if (resplen < HFIXEDSZ) {
967: /*
968: * Undersized message.
969: */
970: Dprint(statp->options & RES_DEBUG,
971: (stdout, ";; undersized: %d\n",
972: resplen));
973: *terrno = EMSGSIZE;
974: res_nclose(statp);
975: return (0);
976: }
977: if (hp->id != anhp->id) {
978: /*
979: * response from old query, ignore it.
980: * XXX - potential security hazard could
981: * be detected here.
982: */
983: DprintQ((statp->options & RES_DEBUG) ||
984: (statp->pfcode & RES_PRF_REPLY),
985: (stdout, ";; old answer:\n"),
986: ans, (resplen > anssiz) ? anssiz : resplen);
987: goto wait;
988: }
989: if (!(statp->options & RES_INSECURE1) &&
1.2 christos 990: !res_ourserver_p(statp, (struct sockaddr *)(void *)&from)) {
1.1 christos 991: /*
992: * response from wrong server? ignore it.
993: * XXX - potential security hazard could
994: * be detected here.
995: */
996: DprintQ((statp->options & RES_DEBUG) ||
997: (statp->pfcode & RES_PRF_REPLY),
998: (stdout, ";; not our server:\n"),
999: ans, (resplen > anssiz) ? anssiz : resplen);
1000: goto wait;
1001: }
1002: #ifdef RES_USE_EDNS0
1003: if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
1004: /*
1005: * Do not retry if the server do not understand EDNS0.
1006: * The case has to be captured here, as FORMERR packet do not
1007: * carry query section, hence res_queriesmatch() returns 0.
1008: */
1009: DprintQ(statp->options & RES_DEBUG,
1010: (stdout, "server rejected query with EDNS0:\n"),
1011: ans, (resplen > anssiz) ? anssiz : resplen);
1012: /* record the error */
1013: statp->_flags |= RES_F_EDNS0ERR;
1014: res_nclose(statp);
1015: return (0);
1016: }
1017: #endif
1018: if (!(statp->options & RES_INSECURE2) &&
1019: !res_queriesmatch(buf, buf + buflen,
1020: ans, ans + anssiz)) {
1021: /*
1022: * response contains wrong query? ignore it.
1023: * XXX - potential security hazard could
1024: * be detected here.
1025: */
1026: DprintQ((statp->options & RES_DEBUG) ||
1027: (statp->pfcode & RES_PRF_REPLY),
1028: (stdout, ";; wrong query name:\n"),
1029: ans, (resplen > anssiz) ? anssiz : resplen);
1030: goto wait;
1031: }
1032: if (anhp->rcode == SERVFAIL ||
1033: anhp->rcode == NOTIMP ||
1034: anhp->rcode == REFUSED) {
1035: DprintQ(statp->options & RES_DEBUG,
1036: (stdout, "server rejected query:\n"),
1037: ans, (resplen > anssiz) ? anssiz : resplen);
1038: res_nclose(statp);
1039: /* don't retry if called from dig */
1040: if (!statp->pfcode)
1041: return (0);
1042: }
1043: if (!(statp->options & RES_IGNTC) && anhp->tc) {
1044: /*
1045: * To get the rest of answer,
1046: * use TCP with same server.
1047: */
1048: Dprint(statp->options & RES_DEBUG,
1049: (stdout, ";; truncated answer\n"));
1050: *v_circuit = 1;
1051: res_nclose(statp);
1052: return (1);
1053: }
1054: /*
1055: * All is well, or the error is fatal. Signal that the
1056: * next nameserver ought not be tried.
1057: */
1058: return (resplen);
1059: }
1060:
1061: static void
1062: Aerror(const res_state statp, FILE *file, const char *string, int error,
1063: const struct sockaddr *address, int alen)
1064: {
1065: int save = errno;
1066: char hbuf[NI_MAXHOST];
1067: char sbuf[NI_MAXSERV];
1068:
1069: alen = alen;
1070:
1071: if ((statp->options & RES_DEBUG) != 0U) {
1.2 christos 1072: if (getnameinfo(address, (socklen_t)alen, hbuf, sizeof(hbuf),
1.1 christos 1073: sbuf, sizeof(sbuf), niflags)) {
1074: strncpy(hbuf, "?", sizeof(hbuf) - 1);
1075: hbuf[sizeof(hbuf) - 1] = '\0';
1076: strncpy(sbuf, "?", sizeof(sbuf) - 1);
1077: sbuf[sizeof(sbuf) - 1] = '\0';
1078: }
1079: fprintf(file, "res_send: %s ([%s].%s): %s\n",
1080: string, hbuf, sbuf, strerror(error));
1081: }
1082: errno = save;
1083: }
1084:
1085: static void
1086: Perror(const res_state statp, FILE *file, const char *string, int error) {
1087: int save = errno;
1088:
1089: if ((statp->options & RES_DEBUG) != 0U)
1090: fprintf(file, "res_send: %s: %s\n",
1091: string, strerror(error));
1092: errno = save;
1093: }
1094:
1095: static int
1096: sock_eq(struct sockaddr *a, struct sockaddr *b) {
1097: struct sockaddr_in *a4, *b4;
1098: struct sockaddr_in6 *a6, *b6;
1099:
1100: if (a->sa_family != b->sa_family)
1101: return 0;
1102: switch (a->sa_family) {
1103: case AF_INET:
1.2 christos 1104: a4 = (struct sockaddr_in *)(void *)a;
1105: b4 = (struct sockaddr_in *)(void *)b;
1.1 christos 1106: return a4->sin_port == b4->sin_port &&
1107: a4->sin_addr.s_addr == b4->sin_addr.s_addr;
1108: case AF_INET6:
1.2 christos 1109: a6 = (struct sockaddr_in6 *)(void *)a;
1110: b6 = (struct sockaddr_in6 *)(void *)b;
1.1 christos 1111: return a6->sin6_port == b6->sin6_port &&
1112: #ifdef HAVE_SIN6_SCOPE_ID
1113: a6->sin6_scope_id == b6->sin6_scope_id &&
1114: #endif
1115: IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
1116: default:
1117: return 0;
1118: }
1119: }
1120:
1.10 christos 1121: #if defined(NEED_PSELECT) && !defined(USE_POLL)
1.1 christos 1122: /* XXX needs to move to the porting library. */
1123: static int
1124: pselect(int nfds, void *rfds, void *wfds, void *efds,
1125: struct timespec *tsp, const sigset_t *sigmask)
1126: {
1127: struct timeval tv, *tvp;
1128: sigset_t sigs;
1129: int n;
1130:
1131: if (tsp) {
1132: tvp = &tv;
1133: tv = evTimeVal(*tsp);
1134: } else
1135: tvp = NULL;
1136: if (sigmask)
1137: sigprocmask(SIG_SETMASK, sigmask, &sigs);
1138: n = select(nfds, rfds, wfds, efds, tvp);
1139: if (sigmask)
1140: sigprocmask(SIG_SETMASK, &sigs, NULL);
1141: if (tsp)
1142: *tsp = evTimeSpec(tv);
1143: return (n);
1144: }
1145: #endif
CVSweb <webmaster@jp.NetBSD.org>