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