Annotation of src/lib/libc/resolv/res_send.c, Revision 1.21
1.21 ! pooka 1: /* $NetBSD: res_send.c,v 1.20 2009/10/24 17:24:01 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.21 ! pooka 96: __RCSID("$NetBSD: res_send.c,v 1.20 2009/10/24 17:24:01 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.10 christos 160: #endif
1.1 christos 161:
162: /* Forward. */
163:
164: static int get_salen __P((const struct sockaddr *));
165: static struct sockaddr * get_nsaddr __P((res_state, size_t));
166: static int send_vc(res_state, const u_char *, int,
167: u_char *, int, int *, int);
168: static int send_dg(res_state, const u_char *, int,
1.10 christos 169: u_char *, int, int *, int, int,
1.1 christos 170: int *, int *);
171: static void Aerror(const res_state, FILE *, const char *, int,
172: const struct sockaddr *, int);
173: static void Perror(const res_state, FILE *, const char *, int);
174: static int sock_eq(struct sockaddr *, struct sockaddr *);
1.10 christos 175: #if defined(NEED_PSELECT) && !defined(USE_POLL)
1.1 christos 176: static int pselect(int, void *, void *, void *,
177: struct timespec *,
178: const sigset_t *);
179: #endif
180: void res_pquery(const res_state, const u_char *, int, FILE *);
181:
182: static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
183:
184: /* Public. */
185:
1.10 christos 186: /*%
1.1 christos 187: * looks up "ina" in _res.ns_addr_list[]
1.10 christos 188: *
1.1 christos 189: * returns:
1.10 christos 190: *\li 0 : not found
191: *\li >0 : found
192: *
1.1 christos 193: * author:
1.10 christos 194: *\li paul vixie, 29may94
1.1 christos 195: */
196: int
197: res_ourserver_p(const res_state statp, const struct sockaddr *sa) {
198: const struct sockaddr_in *inp, *srv;
199: const struct sockaddr_in6 *in6p, *srv6;
200: int ns;
201:
202: switch (sa->sa_family) {
203: case AF_INET:
1.3 christos 204: inp = (const struct sockaddr_in *)(const void *)sa;
1.1 christos 205: for (ns = 0; ns < statp->nscount; ns++) {
1.2 christos 206: srv = (struct sockaddr_in *)(void *)get_nsaddr(statp, (size_t)ns);
1.1 christos 207: if (srv->sin_family == inp->sin_family &&
208: srv->sin_port == inp->sin_port &&
209: (srv->sin_addr.s_addr == INADDR_ANY ||
210: srv->sin_addr.s_addr == inp->sin_addr.s_addr))
211: return (1);
212: }
213: break;
214: case AF_INET6:
215: if (EXT(statp).ext == NULL)
216: break;
1.3 christos 217: in6p = (const struct sockaddr_in6 *)(const void *)sa;
1.1 christos 218: for (ns = 0; ns < statp->nscount; ns++) {
1.2 christos 219: srv6 = (struct sockaddr_in6 *)(void *)get_nsaddr(statp, (size_t)ns);
1.1 christos 220: if (srv6->sin6_family == in6p->sin6_family &&
221: srv6->sin6_port == in6p->sin6_port &&
222: #ifdef HAVE_SIN6_SCOPE_ID
1.7 christos 223: (srv6->sin6_scope_id == 0 ||
224: srv6->sin6_scope_id == in6p->sin6_scope_id) &&
1.1 christos 225: #endif
226: (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
227: IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
228: return (1);
229: }
230: break;
231: default:
232: break;
233: }
234: return (0);
235: }
236:
1.10 christos 237: /*%
1.1 christos 238: * look for (name,type,class) in the query section of packet (buf,eom)
1.10 christos 239: *
1.1 christos 240: * requires:
1.10 christos 241: *\li buf + HFIXEDSZ <= eom
242: *
1.1 christos 243: * returns:
1.10 christos 244: *\li -1 : format error
245: *\li 0 : not found
246: *\li >0 : found
247: *
1.1 christos 248: * author:
1.10 christos 249: *\li paul vixie, 29may94
1.1 christos 250: */
251: int
252: res_nameinquery(const char *name, int type, int class,
253: const u_char *buf, const u_char *eom)
254: {
255: const u_char *cp = buf + HFIXEDSZ;
1.2 christos 256: int qdcount = ntohs(((const HEADER*)(const void *)buf)->qdcount);
1.1 christos 257:
258: while (qdcount-- > 0) {
259: char tname[MAXDNAME+1];
260: int n, ttype, tclass;
261:
262: n = dn_expand(buf, eom, cp, tname, sizeof tname);
263: if (n < 0)
264: return (-1);
265: cp += n;
266: if (cp + 2 * INT16SZ > eom)
267: return (-1);
268: ttype = ns_get16(cp); cp += INT16SZ;
269: tclass = ns_get16(cp); cp += INT16SZ;
270: if (ttype == type && tclass == class &&
271: ns_samename(tname, name) == 1)
272: return (1);
273: }
274: return (0);
275: }
276:
1.10 christos 277: /*%
1.1 christos 278: * is there a 1:1 mapping of (name,type,class)
279: * in (buf1,eom1) and (buf2,eom2)?
1.10 christos 280: *
1.1 christos 281: * returns:
1.10 christos 282: *\li -1 : format error
283: *\li 0 : not a 1:1 mapping
284: *\li >0 : is a 1:1 mapping
285: *
1.1 christos 286: * author:
1.10 christos 287: *\li paul vixie, 29may94
1.1 christos 288: */
289: int
290: res_queriesmatch(const u_char *buf1, const u_char *eom1,
291: const u_char *buf2, const u_char *eom2)
292: {
293: const u_char *cp = buf1 + HFIXEDSZ;
1.2 christos 294: int qdcount = ntohs(((const HEADER*)(const void *)buf1)->qdcount);
1.1 christos 295:
296: if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
297: return (-1);
298:
299: /*
300: * Only header section present in replies to
301: * dynamic update packets.
302: */
1.2 christos 303: if ((((const HEADER *)(const void *)buf1)->opcode == ns_o_update) &&
304: (((const HEADER *)(const void *)buf2)->opcode == ns_o_update))
1.1 christos 305: return (1);
306:
1.2 christos 307: if (qdcount != ntohs(((const HEADER*)(const void *)buf2)->qdcount))
1.1 christos 308: return (0);
309: while (qdcount-- > 0) {
310: char tname[MAXDNAME+1];
311: int n, ttype, tclass;
312:
313: n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
314: if (n < 0)
315: return (-1);
316: cp += n;
317: if (cp + 2 * INT16SZ > eom1)
318: return (-1);
319: ttype = ns_get16(cp); cp += INT16SZ;
320: tclass = ns_get16(cp); cp += INT16SZ;
321: if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
322: return (0);
323: }
324: return (1);
325: }
326:
327: int
328: res_nsend(res_state statp,
329: const u_char *buf, int buflen, u_char *ans, int anssiz)
330: {
1.14 christos 331: int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n;
1.1 christos 332: char abuf[NI_MAXHOST];
333:
1.20 christos 334: (void)res_check(statp, NULL);
1.19 christos 335:
1.10 christos 336: /* No name servers or res_init() failure */
337: if (statp->nscount == 0 || EXT(statp).ext == NULL) {
1.1 christos 338: errno = ESRCH;
339: return (-1);
340: }
341: if (anssiz < HFIXEDSZ) {
342: errno = EINVAL;
343: return (-1);
344: }
345: DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
346: (stdout, ";; res_send()\n"), buf, buflen);
347: v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
348: gotsomewhere = 0;
349: terrno = ETIMEDOUT;
350:
351: /*
352: * If the ns_addr_list in the resolver context has changed, then
353: * invalidate our cached copy and the associated timing data.
354: */
355: if (EXT(statp).nscount != 0) {
356: int needclose = 0;
357: struct sockaddr_storage peer;
358: ISC_SOCKLEN_T peerlen;
359:
360: if (EXT(statp).nscount != statp->nscount)
361: needclose++;
362: else
363: for (ns = 0; ns < statp->nscount; ns++) {
364: if (statp->nsaddr_list[ns].sin_family &&
1.2 christos 365: !sock_eq((struct sockaddr *)(void *)&statp->nsaddr_list[ns],
366: (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[ns])) {
1.1 christos 367: needclose++;
368: break;
369: }
370:
371: if (EXT(statp).nssocks[ns] == -1)
372: continue;
373: peerlen = sizeof(peer);
1.17 mrg 374: if (getpeername(EXT(statp).nssocks[ns],
1.2 christos 375: (struct sockaddr *)(void *)&peer, &peerlen) < 0) {
1.1 christos 376: needclose++;
377: break;
378: }
1.2 christos 379: if (!sock_eq((struct sockaddr *)(void *)&peer,
380: get_nsaddr(statp, (size_t)ns))) {
1.1 christos 381: needclose++;
382: break;
383: }
384: }
385: if (needclose) {
386: res_nclose(statp);
387: EXT(statp).nscount = 0;
388: }
389: }
390:
391: /*
392: * Maybe initialize our private copy of the ns_addr_list.
393: */
394: if (EXT(statp).nscount == 0) {
395: for (ns = 0; ns < statp->nscount; ns++) {
396: EXT(statp).nstimes[ns] = RES_MAXTIME;
397: EXT(statp).nssocks[ns] = -1;
398: if (!statp->nsaddr_list[ns].sin_family)
399: continue;
400: EXT(statp).ext->nsaddrs[ns].sin =
401: statp->nsaddr_list[ns];
402: }
403: EXT(statp).nscount = statp->nscount;
404: }
405:
406: /*
407: * Some resolvers want to even out the load on their nameservers.
408: * Note that RES_BLAST overrides RES_ROTATE.
409: */
410: if ((statp->options & RES_ROTATE) != 0U &&
411: (statp->options & RES_BLAST) == 0U) {
412: union res_sockaddr_union inu;
413: struct sockaddr_in ina;
414: int lastns = statp->nscount - 1;
415: int fd;
416: u_int16_t nstime;
417:
418: if (EXT(statp).ext != NULL)
419: inu = EXT(statp).ext->nsaddrs[0];
420: ina = statp->nsaddr_list[0];
421: fd = EXT(statp).nssocks[0];
422: nstime = EXT(statp).nstimes[0];
423: for (ns = 0; ns < lastns; ns++) {
424: if (EXT(statp).ext != NULL)
1.18 christos 425: EXT(statp).ext->nsaddrs[ns] =
1.1 christos 426: EXT(statp).ext->nsaddrs[ns + 1];
427: statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
428: EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
429: EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
430: }
431: if (EXT(statp).ext != NULL)
432: EXT(statp).ext->nsaddrs[lastns] = inu;
433: statp->nsaddr_list[lastns] = ina;
434: EXT(statp).nssocks[lastns] = fd;
435: EXT(statp).nstimes[lastns] = nstime;
436: }
437:
438: /*
439: * Send request, RETRY times, or until successful.
440: */
1.14 christos 441: for (tries = 0; tries < statp->retry; tries++) {
1.1 christos 442: for (ns = 0; ns < statp->nscount; ns++) {
443: struct sockaddr *nsap;
444: int nsaplen;
1.2 christos 445: nsap = get_nsaddr(statp, (size_t)ns);
1.1 christos 446: nsaplen = get_salen(nsap);
447: statp->_flags &= ~RES_F_LASTMASK;
448: statp->_flags |= (ns << RES_F_LASTSHIFT);
449: same_ns:
450: if (statp->qhook) {
451: int done = 0, loops = 0;
452:
453: do {
454: res_sendhookact act;
455:
456: act = (*statp->qhook)(&nsap, &buf, &buflen,
457: ans, anssiz, &resplen);
458: switch (act) {
459: case res_goahead:
460: done = 1;
461: break;
462: case res_nextns:
463: res_nclose(statp);
464: goto next_ns;
465: case res_done:
466: return (resplen);
467: case res_modified:
468: /* give the hook another try */
469: if (++loops < 42) /*doug adams*/
470: break;
471: /*FALLTHROUGH*/
472: case res_error:
473: /*FALLTHROUGH*/
474: default:
475: goto fail;
476: }
477: } while (!done);
478: }
479:
480: Dprint(((statp->options & RES_DEBUG) &&
1.2 christos 481: getnameinfo(nsap, (socklen_t)nsaplen, abuf, sizeof(abuf),
1.1 christos 482: NULL, 0, niflags) == 0),
483: (stdout, ";; Querying server (# %d) address = %s\n",
484: ns + 1, abuf));
485:
486:
487: if (v_circuit) {
488: /* Use VC; at most one attempt per server. */
1.14 christos 489: tries = statp->retry;
1.1 christos 490: n = send_vc(statp, buf, buflen, ans, anssiz, &terrno,
491: ns);
492: if (n < 0)
493: goto fail;
494: if (n == 0)
495: goto next_ns;
496: resplen = n;
497: } else {
498: /* Use datagrams. */
499: n = send_dg(statp, buf, buflen, ans, anssiz, &terrno,
1.14 christos 500: ns, tries, &v_circuit, &gotsomewhere);
1.1 christos 501: if (n < 0)
502: goto fail;
503: if (n == 0)
504: goto next_ns;
505: if (v_circuit)
506: goto same_ns;
507: resplen = n;
508: }
509:
510: Dprint((statp->options & RES_DEBUG) ||
511: ((statp->pfcode & RES_PRF_REPLY) &&
512: (statp->pfcode & RES_PRF_HEAD1)),
513: (stdout, ";; got answer:\n"));
514:
515: DprintQ((statp->options & RES_DEBUG) ||
516: (statp->pfcode & RES_PRF_REPLY),
517: (stdout, "%s", ""),
518: ans, (resplen > anssiz) ? anssiz : resplen);
519:
520: /*
521: * If we have temporarily opened a virtual circuit,
522: * or if we haven't been asked to keep a socket open,
523: * close the socket.
524: */
525: if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
526: (statp->options & RES_STAYOPEN) == 0U) {
527: res_nclose(statp);
528: }
529: if (statp->rhook) {
530: int done = 0, loops = 0;
531:
532: do {
533: res_sendhookact act;
534:
535: act = (*statp->rhook)(nsap, buf, buflen,
536: ans, anssiz, &resplen);
537: switch (act) {
538: case res_goahead:
539: case res_done:
540: done = 1;
541: break;
542: case res_nextns:
543: res_nclose(statp);
544: goto next_ns;
545: case res_modified:
546: /* give the hook another try */
547: if (++loops < 42) /*doug adams*/
548: break;
549: /*FALLTHROUGH*/
550: case res_error:
551: /*FALLTHROUGH*/
552: default:
553: goto fail;
554: }
555: } while (!done);
556:
557: }
558: return (resplen);
559: next_ns: ;
560: } /*foreach ns*/
561: } /*foreach retry*/
562: res_nclose(statp);
563: if (!v_circuit) {
564: if (!gotsomewhere)
1.10 christos 565: errno = ECONNREFUSED; /*%< no nameservers found */
1.1 christos 566: else
1.10 christos 567: errno = ETIMEDOUT; /*%< no answer obtained */
1.1 christos 568: } else
569: errno = terrno;
570: return (-1);
571: fail:
572: res_nclose(statp);
573: return (-1);
574: }
575:
576: /* Private */
577:
578: static int
579: get_salen(sa)
580: const struct sockaddr *sa;
581: {
582:
583: #ifdef HAVE_SA_LEN
584: /* There are people do not set sa_len. Be forgiving to them. */
585: if (sa->sa_len)
586: return (sa->sa_len);
587: #endif
588:
589: if (sa->sa_family == AF_INET)
590: return (sizeof(struct sockaddr_in));
591: else if (sa->sa_family == AF_INET6)
592: return (sizeof(struct sockaddr_in6));
593: else
1.10 christos 594: return (0); /*%< unknown, die on connect */
1.1 christos 595: }
596:
1.10 christos 597: /*%
1.1 christos 598: * pick appropriate nsaddr_list for use. see res_init() for initialization.
599: */
600: static struct sockaddr *
601: get_nsaddr(statp, n)
602: res_state statp;
603: size_t n;
604: {
605:
606: if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
607: /*
608: * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
609: * than struct sockaddr, and
610: * - user code did not update statp->nsaddr_list[n].
611: */
612: return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
613: } else {
614: /*
615: * - user code updated statp->nsaddr_list[n], or
616: * - statp->nsaddr_list[n] has the same content as
617: * EXT(statp).ext->nsaddrs[n].
618: */
619: return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
620: }
621: }
622:
623: static int
624: send_vc(res_state statp,
625: const u_char *buf, int buflen, u_char *ans, int anssiz,
626: int *terrno, int ns)
627: {
1.3 christos 628: const HEADER *hp = (const HEADER *)(const void *)buf;
629: HEADER *anhp = (HEADER *)(void *)ans;
1.1 christos 630: struct sockaddr *nsap;
631: int nsaplen;
632: int truncating, connreset, resplen, n;
633: struct iovec iov[2];
634: u_short len;
635: u_char *cp;
636: void *tmp;
1.14 christos 637: #ifdef SO_NOSIGPIPE
638: int on = 1;
639: #endif
1.1 christos 640:
1.2 christos 641: nsap = get_nsaddr(statp, (size_t)ns);
1.1 christos 642: nsaplen = get_salen(nsap);
643:
644: connreset = 0;
645: same_ns:
646: truncating = 0;
647:
648: /* Are we still talking to whom we want to talk to? */
649: if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
650: struct sockaddr_storage peer;
651: ISC_SOCKLEN_T size = sizeof peer;
652:
653: if (getpeername(statp->_vcsock,
1.2 christos 654: (struct sockaddr *)(void *)&peer, &size) < 0 ||
655: !sock_eq((struct sockaddr *)(void *)&peer, nsap)) {
1.1 christos 656: res_nclose(statp);
657: statp->_flags &= ~RES_F_VC;
658: }
659: }
660:
661: if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
662: if (statp->_vcsock >= 0)
663: res_nclose(statp);
664:
665: statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM, 0);
1.21 ! pooka 666: #ifndef USE_POLL
1.1 christos 667: if (statp->_vcsock > highestFD) {
668: res_nclose(statp);
669: errno = ENOTSOCK;
670: }
1.21 ! pooka 671: #endif
1.1 christos 672: if (statp->_vcsock < 0) {
673: switch (errno) {
674: case EPROTONOSUPPORT:
675: #ifdef EPFNOSUPPORT
676: case EPFNOSUPPORT:
677: #endif
678: case EAFNOSUPPORT:
679: Perror(statp, stderr, "socket(vc)", errno);
680: return (0);
681: default:
682: *terrno = errno;
683: Perror(statp, stderr, "socket(vc)", errno);
684: return (-1);
685: }
686: }
1.14 christos 687: #ifdef SO_NOSIGPIPE
688: /*
689: * Disable generation of SIGPIPE when writing to a closed
690: * socket. Write should return -1 and set errno to EPIPE
1.18 christos 691: * instead.
1.14 christos 692: *
693: * Push on even if setsockopt(SO_NOSIGPIPE) fails.
694: */
695: (void)setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
1.18 christos 696: sizeof(on));
1.14 christos 697: #endif
1.1 christos 698: errno = 0;
1.2 christos 699: if (connect(statp->_vcsock, nsap, (socklen_t)nsaplen) < 0) {
1.1 christos 700: *terrno = errno;
701: Aerror(statp, stderr, "connect/vc", errno, nsap,
702: nsaplen);
703: res_nclose(statp);
704: return (0);
705: }
706: statp->_flags |= RES_F_VC;
707: }
708:
709: /*
710: * Send length & message
711: */
1.2 christos 712: ns_put16((u_short)buflen, (u_char*)(void *)&len);
1.1 christos 713: iov[0] = evConsIovec(&len, INT16SZ);
714: DE_CONST(buf, tmp);
1.2 christos 715: iov[1] = evConsIovec(tmp, (size_t)buflen);
1.1 christos 716: if (writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) {
717: *terrno = errno;
718: Perror(statp, stderr, "write failed", errno);
719: res_nclose(statp);
720: return (0);
721: }
722: /*
723: * Receive length & response
724: */
725: read_len:
726: cp = ans;
727: len = INT16SZ;
1.2 christos 728: while ((n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0) {
1.1 christos 729: cp += n;
1.2 christos 730: if ((len -= n) == 0)
1.1 christos 731: break;
732: }
733: if (n <= 0) {
734: *terrno = errno;
735: Perror(statp, stderr, "read failed", errno);
736: res_nclose(statp);
737: /*
738: * A long running process might get its TCP
739: * connection reset if the remote server was
740: * restarted. Requery the server instead of
741: * trying a new one. When there is only one
742: * server, this means that a query might work
743: * instead of failing. We only allow one reset
744: * per query to prevent looping.
745: */
746: if (*terrno == ECONNRESET && !connreset) {
747: connreset = 1;
748: res_nclose(statp);
749: goto same_ns;
750: }
751: res_nclose(statp);
752: return (0);
753: }
754: resplen = ns_get16(ans);
755: if (resplen > anssiz) {
756: Dprint(statp->options & RES_DEBUG,
757: (stdout, ";; response truncated\n")
758: );
759: truncating = 1;
760: len = anssiz;
761: } else
762: len = resplen;
763: if (len < HFIXEDSZ) {
764: /*
765: * Undersized message.
766: */
767: Dprint(statp->options & RES_DEBUG,
768: (stdout, ";; undersized: %d\n", len));
769: *terrno = EMSGSIZE;
770: res_nclose(statp);
771: return (0);
772: }
773: cp = ans;
1.2 christos 774: while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0){
1.1 christos 775: cp += n;
776: len -= n;
777: }
778: if (n <= 0) {
779: *terrno = errno;
780: Perror(statp, stderr, "read(vc)", errno);
781: res_nclose(statp);
782: return (0);
783: }
784: if (truncating) {
785: /*
786: * Flush rest of answer so connection stays in synch.
787: */
788: anhp->tc = 1;
789: len = resplen - anssiz;
790: while (len != 0) {
791: char junk[PACKETSZ];
792:
793: n = read(statp->_vcsock, junk,
794: (len > sizeof junk) ? sizeof junk : len);
795: if (n > 0)
796: len -= n;
797: else
798: break;
799: }
800: }
801: /*
802: * If the calling applicating has bailed out of
803: * a previous call and failed to arrange to have
804: * the circuit closed or the server has got
805: * itself confused, then drop the packet and
806: * wait for the correct one.
807: */
808: if (hp->id != anhp->id) {
809: DprintQ((statp->options & RES_DEBUG) ||
810: (statp->pfcode & RES_PRF_REPLY),
811: (stdout, ";; old answer (unexpected):\n"),
812: ans, (resplen > anssiz) ? anssiz: resplen);
813: goto read_len;
814: }
815:
816: /*
817: * All is well, or the error is fatal. Signal that the
818: * next nameserver ought not be tried.
819: */
820: return (resplen);
821: }
822:
823: static int
1.10 christos 824: send_dg(res_state statp, const u_char *buf, int buflen, u_char *ans,
1.14 christos 825: int anssiz, int *terrno, int ns, int tries, int *v_circuit,
1.10 christos 826: int *gotsomewhere)
1.1 christos 827: {
1.2 christos 828: const HEADER *hp = (const HEADER *)(const void *)buf;
829: HEADER *anhp = (HEADER *)(void *)ans;
1.1 christos 830: const struct sockaddr *nsap;
831: int nsaplen;
832: struct timespec now, timeout, finish;
833: struct sockaddr_storage from;
834: ISC_SOCKLEN_T fromlen;
835: int resplen, seconds, n, s;
1.10 christos 836: #ifdef USE_POLL
837: int polltimeout;
838: struct pollfd pollfd;
839: #else
840: fd_set dsmask;
841: #endif
1.1 christos 842:
1.2 christos 843: nsap = get_nsaddr(statp, (size_t)ns);
1.1 christos 844: nsaplen = get_salen(nsap);
845: if (EXT(statp).nssocks[ns] == -1) {
846: EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM, 0);
1.21 ! pooka 847: #ifndef USE_POLL
1.1 christos 848: if (EXT(statp).nssocks[ns] > highestFD) {
849: res_nclose(statp);
850: errno = ENOTSOCK;
851: }
1.21 ! pooka 852: #endif
1.1 christos 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>