1*4d416d88Schristos /* $NetBSD: res_send.c,v 1.30 2015/02/24 17:56:20 christos Exp $ */
259a755a4Schristos
359a755a4Schristos /*
459a755a4Schristos * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
559a755a4Schristos * Portions Copyright (C) 1996-2003 Internet Software Consortium.
659a755a4Schristos *
759a755a4Schristos * Permission to use, copy, modify, and/or distribute this software for any
859a755a4Schristos * purpose with or without fee is hereby granted, provided that the above
959a755a4Schristos * copyright notice and this permission notice appear in all copies.
1059a755a4Schristos *
1159a755a4Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
1259a755a4Schristos * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
1359a755a4Schristos * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
1459a755a4Schristos * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
1559a755a4Schristos * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
1659a755a4Schristos * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
1759a755a4Schristos * PERFORMANCE OF THIS SOFTWARE.
1859a755a4Schristos */
192b237084Schristos
202b237084Schristos /*
212b237084Schristos * Copyright (c) 1985, 1989, 1993
222b237084Schristos * The Regents of the University of California. All rights reserved.
232b237084Schristos *
242b237084Schristos * Redistribution and use in source and binary forms, with or without
252b237084Schristos * modification, are permitted provided that the following conditions
262b237084Schristos * are met:
272b237084Schristos * 1. Redistributions of source code must retain the above copyright
282b237084Schristos * notice, this list of conditions and the following disclaimer.
292b237084Schristos * 2. Redistributions in binary form must reproduce the above copyright
302b237084Schristos * notice, this list of conditions and the following disclaimer in the
312b237084Schristos * documentation and/or other materials provided with the distribution.
32*4d416d88Schristos * 3. Neither the name of the University nor the names of its contributors
332b237084Schristos * may be used to endorse or promote products derived from this software
342b237084Schristos * without specific prior written permission.
352b237084Schristos *
362b237084Schristos * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
372b237084Schristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
382b237084Schristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
392b237084Schristos * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
402b237084Schristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
412b237084Schristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
422b237084Schristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
432b237084Schristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
442b237084Schristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
452b237084Schristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
462b237084Schristos * SUCH DAMAGE.
472b237084Schristos */
482b237084Schristos
492b237084Schristos /*
502b237084Schristos * Portions Copyright (c) 1993 by Digital Equipment Corporation.
512b237084Schristos *
522b237084Schristos * Permission to use, copy, modify, and distribute this software for any
532b237084Schristos * purpose with or without fee is hereby granted, provided that the above
542b237084Schristos * copyright notice and this permission notice appear in all copies, and that
552b237084Schristos * the name of Digital Equipment Corporation not be used in advertising or
562b237084Schristos * publicity pertaining to distribution of the document or software without
572b237084Schristos * specific, written prior permission.
582b237084Schristos *
592b237084Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
602b237084Schristos * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
612b237084Schristos * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
622b237084Schristos * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
632b237084Schristos * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
642b237084Schristos * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
652b237084Schristos * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
662b237084Schristos * SOFTWARE.
672b237084Schristos */
682b237084Schristos
692b237084Schristos /*
70d73eb73dSchristos * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
712b237084Schristos * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
722b237084Schristos *
732b237084Schristos * Permission to use, copy, modify, and distribute this software for any
742b237084Schristos * purpose with or without fee is hereby granted, provided that the above
752b237084Schristos * copyright notice and this permission notice appear in all copies.
762b237084Schristos *
772b237084Schristos * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
782b237084Schristos * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
792b237084Schristos * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
802b237084Schristos * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
812b237084Schristos * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
822b237084Schristos * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
832b237084Schristos * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
842b237084Schristos */
852b237084Schristos
86ca31adbdSchristos #include <sys/cdefs.h>
872b237084Schristos #if defined(LIBC_SCCS) && !defined(lint)
88ca31adbdSchristos #ifdef notdef
892b237084Schristos static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
9059a755a4Schristos static const char rcsid[] = "Id: res_send.c,v 1.22 2009/01/22 23:49:23 tbox Exp";
91ca31adbdSchristos #else
92*4d416d88Schristos __RCSID("$NetBSD: res_send.c,v 1.30 2015/02/24 17:56:20 christos Exp $");
93ca31adbdSchristos #endif
942b237084Schristos #endif /* LIBC_SCCS and not lint */
952b237084Schristos
96d73eb73dSchristos /*! \file
97d73eb73dSchristos * \brief
982b237084Schristos * Send query to name server and wait for reply.
992b237084Schristos */
1002b237084Schristos
101fd5cb0acSkleink #include "namespace.h"
1022b237084Schristos #include "port_before.h"
103650d1881Schristos #ifndef USE_KQUEUE
1042b237084Schristos #include "fd_setsize.h"
105650d1881Schristos #endif /* USE_KQUEUE */
1062b237084Schristos
1072b237084Schristos #include <sys/types.h>
1082b237084Schristos #include <sys/param.h>
1092b237084Schristos #include <sys/time.h>
1102b237084Schristos #include <sys/socket.h>
1112b237084Schristos #include <sys/uio.h>
112650d1881Schristos #ifdef USE_KQUEUE
113650d1881Schristos #include <sys/event.h>
114650d1881Schristos #endif /* USE_KQUEUE */
1152b237084Schristos
1162b237084Schristos #include <netinet/in.h>
1172b237084Schristos #include <arpa/nameser.h>
1182b237084Schristos #include <arpa/inet.h>
1192b237084Schristos
120c5e820caSchristos #include <assert.h>
1212b237084Schristos #include <errno.h>
1222b237084Schristos #include <netdb.h>
1232b237084Schristos #include <resolv.h>
1242b237084Schristos #include <signal.h>
1252b237084Schristos #include <stdio.h>
126650d1881Schristos #include <fcntl.h>
1272b237084Schristos #include <stdlib.h>
1282b237084Schristos #include <string.h>
1292b237084Schristos #include <unistd.h>
1302b237084Schristos
1312b237084Schristos #include <isc/eventlib.h>
1322b237084Schristos
1332b237084Schristos #include "port_after.h"
1342b237084Schristos
1355ce4c264Schristos #if 0
1366f3786f4Schristos #ifdef __weak_alias
1376f3786f4Schristos __weak_alias(res_ourserver_p,__res_ourserver_p)
1386f3786f4Schristos __weak_alias(res_nameinquery,__res_nameinquery)
1396f3786f4Schristos __weak_alias(res_queriesmatch,__res_queriesmatch)
1406f3786f4Schristos __weak_alias(res_nsend,__res_nsend)
1416f3786f4Schristos #endif
1425ce4c264Schristos #endif
1436f3786f4Schristos
144650d1881Schristos #ifndef SOCK_NOSIGPIPE
145650d1881Schristos #define SOCK_NOSIGPIPE 0
146650d1881Schristos #endif
147650d1881Schristos #ifndef SOCK_NOCLOEXEC
148650d1881Schristos #define SOCK_NOCLOEXEC 0
149650d1881Schristos #endif
150d73eb73dSchristos
151d73eb73dSchristos #ifdef USE_POLL
152d73eb73dSchristos #ifdef HAVE_STROPTS_H
153d73eb73dSchristos #include <stropts.h>
154d73eb73dSchristos #endif
155d73eb73dSchristos #include <poll.h>
156d73eb73dSchristos #endif /* USE_POLL */
157d73eb73dSchristos
1582b237084Schristos /* Options. Leave them on. */
1597ce5e09dSchristos #ifndef DEBUG
1602b237084Schristos #define DEBUG
1617ce5e09dSchristos #endif
1622b237084Schristos #include "res_debug.h"
1632b237084Schristos #include "res_private.h"
1642b237084Schristos
1652b237084Schristos #define EXT(res) ((res)->_u._ext)
1662b237084Schristos
167650d1881Schristos #if !defined(USE_POLL) && !defined(USE_KQUEUE)
1682b237084Schristos static const int highestFD = FD_SETSIZE - 1;
169d73eb73dSchristos #endif
1702b237084Schristos
1712b237084Schristos /* Forward. */
1722b237084Schristos
17372e5329bSchristos static socklen_t get_salen(const struct sockaddr *);
174504f8671Smatt static struct sockaddr * get_nsaddr(res_state, size_t);
17561fab154Schristos static int send_vc(res_state, const void *, size_t,
1762b237084Schristos u_char *, int, int *, int);
177650d1881Schristos static int send_dg(res_state,
178650d1881Schristos #ifdef USE_KQUEUE
179650d1881Schristos int,
180650d1881Schristos #endif
18172e5329bSchristos const void *, size_t,
182d73eb73dSchristos u_char *, int, int *, int, int,
1832b237084Schristos int *, int *);
1842b237084Schristos static void Aerror(const res_state, FILE *, const char *, int,
18572e5329bSchristos const struct sockaddr *, socklen_t);
1862b237084Schristos static void Perror(const res_state, FILE *, const char *, int);
1872b237084Schristos static int sock_eq(struct sockaddr *, struct sockaddr *);
188650d1881Schristos #if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
1892b237084Schristos static int pselect(int, void *, void *, void *,
1902b237084Schristos struct timespec *,
1912b237084Schristos const sigset_t *);
1922b237084Schristos #endif
1932b237084Schristos void res_pquery(const res_state, const u_char *, int, FILE *);
1942b237084Schristos
1952b237084Schristos static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
1962b237084Schristos
1972b237084Schristos /* Public. */
1982b237084Schristos
199d73eb73dSchristos /*%
2002b237084Schristos * looks up "ina" in _res.ns_addr_list[]
201d73eb73dSchristos *
2022b237084Schristos * returns:
203d73eb73dSchristos *\li 0 : not found
204d73eb73dSchristos *\li >0 : found
205d73eb73dSchristos *
2062b237084Schristos * author:
207d73eb73dSchristos *\li paul vixie, 29may94
2082b237084Schristos */
2092b237084Schristos int
res_ourserver_p(const res_state statp,const struct sockaddr * sa)2102b237084Schristos res_ourserver_p(const res_state statp, const struct sockaddr *sa) {
2112b237084Schristos const struct sockaddr_in *inp, *srv;
2122b237084Schristos const struct sockaddr_in6 *in6p, *srv6;
2132b237084Schristos int ns;
2142b237084Schristos
2152b237084Schristos switch (sa->sa_family) {
2162b237084Schristos case AF_INET:
21750d86ec2Schristos inp = (const struct sockaddr_in *)(const void *)sa;
2182b237084Schristos for (ns = 0; ns < statp->nscount; ns++) {
2191ad5eecbSchristos srv = (struct sockaddr_in *)(void *)get_nsaddr(statp, (size_t)ns);
2202b237084Schristos if (srv->sin_family == inp->sin_family &&
2212b237084Schristos srv->sin_port == inp->sin_port &&
2222b237084Schristos (srv->sin_addr.s_addr == INADDR_ANY ||
2232b237084Schristos srv->sin_addr.s_addr == inp->sin_addr.s_addr))
2242b237084Schristos return (1);
2252b237084Schristos }
2262b237084Schristos break;
2272b237084Schristos case AF_INET6:
2282b237084Schristos if (EXT(statp).ext == NULL)
2292b237084Schristos break;
23050d86ec2Schristos in6p = (const struct sockaddr_in6 *)(const void *)sa;
2312b237084Schristos for (ns = 0; ns < statp->nscount; ns++) {
2321ad5eecbSchristos srv6 = (struct sockaddr_in6 *)(void *)get_nsaddr(statp, (size_t)ns);
2332b237084Schristos if (srv6->sin6_family == in6p->sin6_family &&
2342b237084Schristos srv6->sin6_port == in6p->sin6_port &&
2352b237084Schristos #ifdef HAVE_SIN6_SCOPE_ID
2360766545fSchristos (srv6->sin6_scope_id == 0 ||
2370766545fSchristos srv6->sin6_scope_id == in6p->sin6_scope_id) &&
2382b237084Schristos #endif
2392b237084Schristos (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
2402b237084Schristos IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
2412b237084Schristos return (1);
2422b237084Schristos }
2432b237084Schristos break;
2442b237084Schristos default:
2452b237084Schristos break;
2462b237084Schristos }
2472b237084Schristos return (0);
2482b237084Schristos }
2492b237084Schristos
250d73eb73dSchristos /*%
2512b237084Schristos * look for (name,type,class) in the query section of packet (buf,eom)
252d73eb73dSchristos *
2532b237084Schristos * requires:
254d73eb73dSchristos *\li buf + HFIXEDSZ <= eom
255d73eb73dSchristos *
2562b237084Schristos * returns:
257d73eb73dSchristos *\li -1 : format error
258d73eb73dSchristos *\li 0 : not found
259d73eb73dSchristos *\li >0 : found
260d73eb73dSchristos *
2612b237084Schristos * author:
262d73eb73dSchristos *\li paul vixie, 29may94
2632b237084Schristos */
2642b237084Schristos int
res_nameinquery(const char * name,int type,int class,const u_char * buf,const u_char * eom)2652b237084Schristos res_nameinquery(const char *name, int type, int class,
2662b237084Schristos const u_char *buf, const u_char *eom)
2672b237084Schristos {
2682b237084Schristos const u_char *cp = buf + HFIXEDSZ;
2691ad5eecbSchristos int qdcount = ntohs(((const HEADER*)(const void *)buf)->qdcount);
2702b237084Schristos
2712b237084Schristos while (qdcount-- > 0) {
2722b237084Schristos char tname[MAXDNAME+1];
2732b237084Schristos int n, ttype, tclass;
2742b237084Schristos
275c5e820caSchristos n = dn_expand(buf, eom, cp, tname, (int)sizeof tname);
2762b237084Schristos if (n < 0)
2772b237084Schristos return (-1);
2782b237084Schristos cp += n;
2792b237084Schristos if (cp + 2 * INT16SZ > eom)
2802b237084Schristos return (-1);
2812b237084Schristos ttype = ns_get16(cp); cp += INT16SZ;
2822b237084Schristos tclass = ns_get16(cp); cp += INT16SZ;
2832b237084Schristos if (ttype == type && tclass == class &&
2842b237084Schristos ns_samename(tname, name) == 1)
2852b237084Schristos return (1);
2862b237084Schristos }
2872b237084Schristos return (0);
2882b237084Schristos }
2892b237084Schristos
290d73eb73dSchristos /*%
2912b237084Schristos * is there a 1:1 mapping of (name,type,class)
2922b237084Schristos * in (buf1,eom1) and (buf2,eom2)?
293d73eb73dSchristos *
2942b237084Schristos * returns:
295d73eb73dSchristos *\li -1 : format error
296d73eb73dSchristos *\li 0 : not a 1:1 mapping
297d73eb73dSchristos *\li >0 : is a 1:1 mapping
298d73eb73dSchristos *
2992b237084Schristos * author:
300d73eb73dSchristos *\li paul vixie, 29may94
3012b237084Schristos */
3022b237084Schristos int
res_queriesmatch(const u_char * buf1,const u_char * eom1,const u_char * buf2,const u_char * eom2)3032b237084Schristos res_queriesmatch(const u_char *buf1, const u_char *eom1,
3042b237084Schristos const u_char *buf2, const u_char *eom2)
3052b237084Schristos {
3062b237084Schristos const u_char *cp = buf1 + HFIXEDSZ;
3071ad5eecbSchristos int qdcount = ntohs(((const HEADER*)(const void *)buf1)->qdcount);
3082b237084Schristos
3092b237084Schristos if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
3102b237084Schristos return (-1);
3112b237084Schristos
3122b237084Schristos /*
3132b237084Schristos * Only header section present in replies to
3142b237084Schristos * dynamic update packets.
3152b237084Schristos */
3161ad5eecbSchristos if ((((const HEADER *)(const void *)buf1)->opcode == ns_o_update) &&
3171ad5eecbSchristos (((const HEADER *)(const void *)buf2)->opcode == ns_o_update))
3182b237084Schristos return (1);
3192b237084Schristos
3201ad5eecbSchristos if (qdcount != ntohs(((const HEADER*)(const void *)buf2)->qdcount))
3212b237084Schristos return (0);
3222b237084Schristos while (qdcount-- > 0) {
3232b237084Schristos char tname[MAXDNAME+1];
3242b237084Schristos int n, ttype, tclass;
3252b237084Schristos
326c5e820caSchristos n = dn_expand(buf1, eom1, cp, tname, (int)sizeof tname);
3272b237084Schristos if (n < 0)
3282b237084Schristos return (-1);
3292b237084Schristos cp += n;
3302b237084Schristos if (cp + 2 * INT16SZ > eom1)
3312b237084Schristos return (-1);
3322b237084Schristos ttype = ns_get16(cp); cp += INT16SZ;
3332b237084Schristos tclass = ns_get16(cp); cp += INT16SZ;
3342b237084Schristos if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
3352b237084Schristos return (0);
3362b237084Schristos }
3372b237084Schristos return (1);
3382b237084Schristos }
3392b237084Schristos
3402b237084Schristos int
res_nsend(res_state statp,const u_char * buf,int buflen,u_char * ans,int anssiz)3412b237084Schristos res_nsend(res_state statp,
3422b237084Schristos const u_char *buf, int buflen, u_char *ans, int anssiz)
3432b237084Schristos {
3443873655bSchristos int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n;
345650d1881Schristos #ifdef USE_KQUEUE
346650d1881Schristos int kq;
347650d1881Schristos #endif
3482b237084Schristos char abuf[NI_MAXHOST];
3492b237084Schristos
350e942b6ecSchristos (void)res_check(statp, NULL);
351249296c4Schristos
352d73eb73dSchristos /* No name servers or res_init() failure */
353d73eb73dSchristos if (statp->nscount == 0 || EXT(statp).ext == NULL) {
3542b237084Schristos errno = ESRCH;
3552b237084Schristos return (-1);
3562b237084Schristos }
3572b237084Schristos if (anssiz < HFIXEDSZ) {
3582b237084Schristos errno = EINVAL;
3592b237084Schristos return (-1);
3602b237084Schristos }
3612b237084Schristos DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
3622b237084Schristos (stdout, ";; res_send()\n"), buf, buflen);
3632b237084Schristos v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
3642b237084Schristos gotsomewhere = 0;
3652b237084Schristos terrno = ETIMEDOUT;
3662b237084Schristos
367650d1881Schristos #ifdef USE_KQUEUE
368650d1881Schristos if ((kq = kqueue1(O_CLOEXEC)) == -1) {
369650d1881Schristos return (-1);
370650d1881Schristos }
371650d1881Schristos #endif
372650d1881Schristos
3732b237084Schristos /*
3742b237084Schristos * If the ns_addr_list in the resolver context has changed, then
3752b237084Schristos * invalidate our cached copy and the associated timing data.
3762b237084Schristos */
3772b237084Schristos if (EXT(statp).nscount != 0) {
3782b237084Schristos int needclose = 0;
3792b237084Schristos struct sockaddr_storage peer;
3802b237084Schristos ISC_SOCKLEN_T peerlen;
3812b237084Schristos
3822b237084Schristos if (EXT(statp).nscount != statp->nscount)
3832b237084Schristos needclose++;
3842b237084Schristos else
3852b237084Schristos for (ns = 0; ns < statp->nscount; ns++) {
3862b237084Schristos if (statp->nsaddr_list[ns].sin_family &&
3871ad5eecbSchristos !sock_eq((struct sockaddr *)(void *)&statp->nsaddr_list[ns],
3881ad5eecbSchristos (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[ns])) {
3892b237084Schristos needclose++;
3902b237084Schristos break;
3912b237084Schristos }
3922b237084Schristos
3932b237084Schristos if (EXT(statp).nssocks[ns] == -1)
3942b237084Schristos continue;
3952b237084Schristos peerlen = sizeof(peer);
396798e7182Smrg if (getpeername(EXT(statp).nssocks[ns],
3971ad5eecbSchristos (struct sockaddr *)(void *)&peer, &peerlen) < 0) {
3982b237084Schristos needclose++;
3992b237084Schristos break;
4002b237084Schristos }
4011ad5eecbSchristos if (!sock_eq((struct sockaddr *)(void *)&peer,
4021ad5eecbSchristos get_nsaddr(statp, (size_t)ns))) {
4032b237084Schristos needclose++;
4042b237084Schristos break;
4052b237084Schristos }
4062b237084Schristos }
4072b237084Schristos if (needclose) {
4082b237084Schristos res_nclose(statp);
4092b237084Schristos EXT(statp).nscount = 0;
4102b237084Schristos }
4112b237084Schristos }
4122b237084Schristos
4132b237084Schristos /*
4142b237084Schristos * Maybe initialize our private copy of the ns_addr_list.
4152b237084Schristos */
4162b237084Schristos if (EXT(statp).nscount == 0) {
4172b237084Schristos for (ns = 0; ns < statp->nscount; ns++) {
4182b237084Schristos EXT(statp).nstimes[ns] = RES_MAXTIME;
4192b237084Schristos EXT(statp).nssocks[ns] = -1;
4202b237084Schristos if (!statp->nsaddr_list[ns].sin_family)
4212b237084Schristos continue;
4222b237084Schristos EXT(statp).ext->nsaddrs[ns].sin =
4232b237084Schristos statp->nsaddr_list[ns];
4242b237084Schristos }
4252b237084Schristos EXT(statp).nscount = statp->nscount;
4262b237084Schristos }
4272b237084Schristos
4282b237084Schristos /*
4292b237084Schristos * Some resolvers want to even out the load on their nameservers.
4302b237084Schristos * Note that RES_BLAST overrides RES_ROTATE.
4312b237084Schristos */
4322b237084Schristos if ((statp->options & RES_ROTATE) != 0U &&
4332b237084Schristos (statp->options & RES_BLAST) == 0U) {
4342b237084Schristos union res_sockaddr_union inu;
4352b237084Schristos struct sockaddr_in ina;
4362b237084Schristos int lastns = statp->nscount - 1;
4372b237084Schristos int fd;
4382b237084Schristos u_int16_t nstime;
4392b237084Schristos
4402b237084Schristos if (EXT(statp).ext != NULL)
4412b237084Schristos inu = EXT(statp).ext->nsaddrs[0];
4422b237084Schristos ina = statp->nsaddr_list[0];
4432b237084Schristos fd = EXT(statp).nssocks[0];
4442b237084Schristos nstime = EXT(statp).nstimes[0];
4452b237084Schristos for (ns = 0; ns < lastns; ns++) {
4462b237084Schristos if (EXT(statp).ext != NULL)
4472b237084Schristos EXT(statp).ext->nsaddrs[ns] =
4482b237084Schristos EXT(statp).ext->nsaddrs[ns + 1];
4492b237084Schristos statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
4502b237084Schristos EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
4512b237084Schristos EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
4522b237084Schristos }
4532b237084Schristos if (EXT(statp).ext != NULL)
4542b237084Schristos EXT(statp).ext->nsaddrs[lastns] = inu;
4552b237084Schristos statp->nsaddr_list[lastns] = ina;
4562b237084Schristos EXT(statp).nssocks[lastns] = fd;
4572b237084Schristos EXT(statp).nstimes[lastns] = nstime;
4582b237084Schristos }
4592b237084Schristos
4602b237084Schristos /*
4612b237084Schristos * Send request, RETRY times, or until successful.
4622b237084Schristos */
4633873655bSchristos for (tries = 0; tries < statp->retry; tries++) {
4642b237084Schristos for (ns = 0; ns < statp->nscount; ns++) {
4652b237084Schristos struct sockaddr *nsap;
46672e5329bSchristos socklen_t nsaplen;
4671ad5eecbSchristos nsap = get_nsaddr(statp, (size_t)ns);
4682b237084Schristos nsaplen = get_salen(nsap);
4692b237084Schristos statp->_flags &= ~RES_F_LASTMASK;
4702b237084Schristos statp->_flags |= (ns << RES_F_LASTSHIFT);
4712b237084Schristos same_ns:
4722b237084Schristos if (statp->qhook) {
4732b237084Schristos int done = 0, loops = 0;
4742b237084Schristos
4752b237084Schristos do {
4762b237084Schristos res_sendhookact act;
4772b237084Schristos
4782b237084Schristos act = (*statp->qhook)(&nsap, &buf, &buflen,
4792b237084Schristos ans, anssiz, &resplen);
4802b237084Schristos switch (act) {
4812b237084Schristos case res_goahead:
4822b237084Schristos done = 1;
4832b237084Schristos break;
4842b237084Schristos case res_nextns:
4852b237084Schristos res_nclose(statp);
4862b237084Schristos goto next_ns;
4872b237084Schristos case res_done:
488650d1881Schristos #ifdef USE_KQUEUE
489650d1881Schristos close(kq);
490650d1881Schristos #endif
4912b237084Schristos return (resplen);
4922b237084Schristos case res_modified:
4932b237084Schristos /* give the hook another try */
4942b237084Schristos if (++loops < 42) /*doug adams*/
4952b237084Schristos break;
4962b237084Schristos /*FALLTHROUGH*/
4972b237084Schristos case res_error:
4982b237084Schristos /*FALLTHROUGH*/
4992b237084Schristos default:
5002b237084Schristos goto fail;
5012b237084Schristos }
5022b237084Schristos } while (!done);
5032b237084Schristos }
5042b237084Schristos
5052b237084Schristos Dprint(((statp->options & RES_DEBUG) &&
50672e5329bSchristos getnameinfo(nsap, nsaplen, abuf,
507c5e820caSchristos (socklen_t)sizeof(abuf), NULL, 0, niflags) == 0),
5082b237084Schristos (stdout, ";; Querying server (# %d) address = %s\n",
5092b237084Schristos ns + 1, abuf));
5102b237084Schristos
5112b237084Schristos
5122b237084Schristos if (v_circuit) {
5132b237084Schristos /* Use VC; at most one attempt per server. */
5143873655bSchristos tries = statp->retry;
515bc91d7faSpara n = send_vc(statp, buf, (size_t)buflen, ans, anssiz, &terrno,
5162b237084Schristos ns);
5172b237084Schristos if (n < 0)
5182b237084Schristos goto fail;
5192b237084Schristos if (n == 0)
5202b237084Schristos goto next_ns;
5212b237084Schristos resplen = n;
5222b237084Schristos } else {
5232b237084Schristos /* Use datagrams. */
524650d1881Schristos n = send_dg(statp,
525650d1881Schristos #ifdef USE_KQUEUE
526650d1881Schristos kq,
527650d1881Schristos #endif
52872e5329bSchristos buf, (size_t)buflen, ans, anssiz, &terrno,
5293873655bSchristos ns, tries, &v_circuit, &gotsomewhere);
5302b237084Schristos if (n < 0)
5312b237084Schristos goto fail;
5322b237084Schristos if (n == 0)
5332b237084Schristos goto next_ns;
5342b237084Schristos if (v_circuit)
5352b237084Schristos goto same_ns;
5362b237084Schristos resplen = n;
5372b237084Schristos }
5382b237084Schristos
5392b237084Schristos Dprint((statp->options & RES_DEBUG) ||
5402b237084Schristos ((statp->pfcode & RES_PRF_REPLY) &&
5412b237084Schristos (statp->pfcode & RES_PRF_HEAD1)),
5422b237084Schristos (stdout, ";; got answer:\n"));
5432b237084Schristos
5442b237084Schristos DprintQ((statp->options & RES_DEBUG) ||
5452b237084Schristos (statp->pfcode & RES_PRF_REPLY),
5462b237084Schristos (stdout, "%s", ""),
5472b237084Schristos ans, (resplen > anssiz) ? anssiz : resplen);
5482b237084Schristos
5492b237084Schristos /*
5502b237084Schristos * If we have temporarily opened a virtual circuit,
5512b237084Schristos * or if we haven't been asked to keep a socket open,
5522b237084Schristos * close the socket.
5532b237084Schristos */
5542b237084Schristos if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
5552b237084Schristos (statp->options & RES_STAYOPEN) == 0U) {
5562b237084Schristos res_nclose(statp);
5572b237084Schristos }
5582b237084Schristos if (statp->rhook) {
5592b237084Schristos int done = 0, loops = 0;
5602b237084Schristos
5612b237084Schristos do {
5622b237084Schristos res_sendhookact act;
5632b237084Schristos
5642b237084Schristos act = (*statp->rhook)(nsap, buf, buflen,
5652b237084Schristos ans, anssiz, &resplen);
5662b237084Schristos switch (act) {
5672b237084Schristos case res_goahead:
5682b237084Schristos case res_done:
5692b237084Schristos done = 1;
5702b237084Schristos break;
5712b237084Schristos case res_nextns:
5722b237084Schristos res_nclose(statp);
5732b237084Schristos goto next_ns;
5742b237084Schristos case res_modified:
5752b237084Schristos /* give the hook another try */
5762b237084Schristos if (++loops < 42) /*doug adams*/
5772b237084Schristos break;
5782b237084Schristos /*FALLTHROUGH*/
5792b237084Schristos case res_error:
5802b237084Schristos /*FALLTHROUGH*/
5812b237084Schristos default:
5822b237084Schristos goto fail;
5832b237084Schristos }
5842b237084Schristos } while (!done);
5852b237084Schristos
5862b237084Schristos }
587650d1881Schristos #ifdef USE_KQUEUE
588650d1881Schristos close(kq);
589650d1881Schristos #endif
5902b237084Schristos return (resplen);
5912b237084Schristos next_ns: ;
5922b237084Schristos } /*foreach ns*/
5932b237084Schristos } /*foreach retry*/
5942b237084Schristos res_nclose(statp);
595650d1881Schristos #ifdef USE_KQUEUE
596650d1881Schristos close(kq);
597650d1881Schristos #endif
5982b237084Schristos if (!v_circuit) {
5992b237084Schristos if (!gotsomewhere)
600d73eb73dSchristos errno = ECONNREFUSED; /*%< no nameservers found */
6012b237084Schristos else
602d73eb73dSchristos errno = ETIMEDOUT; /*%< no answer obtained */
6032b237084Schristos } else
6042b237084Schristos errno = terrno;
6052b237084Schristos return (-1);
6062b237084Schristos fail:
6072b237084Schristos res_nclose(statp);
608650d1881Schristos #ifdef USE_KQUEUE
609650d1881Schristos close(kq);
610650d1881Schristos #endif
6112b237084Schristos return (-1);
6122b237084Schristos }
6132b237084Schristos
6142b237084Schristos /* Private */
6152b237084Schristos
61672e5329bSchristos static socklen_t
get_salen(const struct sockaddr * sa)617504f8671Smatt get_salen(const struct sockaddr *sa)
6182b237084Schristos {
6192b237084Schristos
6202b237084Schristos #ifdef HAVE_SA_LEN
6212b237084Schristos /* There are people do not set sa_len. Be forgiving to them. */
6222b237084Schristos if (sa->sa_len)
62372e5329bSchristos return (socklen_t)sa->sa_len;
6242b237084Schristos #endif
6252b237084Schristos
6262b237084Schristos if (sa->sa_family == AF_INET)
62772e5329bSchristos return (socklen_t)sizeof(struct sockaddr_in);
6282b237084Schristos else if (sa->sa_family == AF_INET6)
62972e5329bSchristos return (socklen_t)sizeof(struct sockaddr_in6);
6302b237084Schristos else
63172e5329bSchristos return 0; /*%< unknown, die on connect */
6322b237084Schristos }
6332b237084Schristos
634d73eb73dSchristos /*%
6352b237084Schristos * pick appropriate nsaddr_list for use. see res_init() for initialization.
6362b237084Schristos */
6372b237084Schristos static struct sockaddr *
get_nsaddr(res_state statp,size_t n)638504f8671Smatt get_nsaddr(res_state statp, size_t n)
6392b237084Schristos {
6402b237084Schristos
6412b237084Schristos if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
6422b237084Schristos /*
6432b237084Schristos * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
6442b237084Schristos * than struct sockaddr, and
6452b237084Schristos * - user code did not update statp->nsaddr_list[n].
6462b237084Schristos */
6472b237084Schristos return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
6482b237084Schristos } else {
6492b237084Schristos /*
6502b237084Schristos * - user code updated statp->nsaddr_list[n], or
6512b237084Schristos * - statp->nsaddr_list[n] has the same content as
6522b237084Schristos * EXT(statp).ext->nsaddrs[n].
6532b237084Schristos */
6542b237084Schristos return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
6552b237084Schristos }
6562b237084Schristos }
6572b237084Schristos
6582b237084Schristos static int
send_vc(res_state statp,const void * buf,size_t buflen,u_char * ans,int anssiz,int * terrno,int ns)6592b237084Schristos send_vc(res_state statp,
66061fab154Schristos const void *buf, size_t buflen, u_char *ans, int anssiz,
6612b237084Schristos int *terrno, int ns)
6622b237084Schristos {
66350d86ec2Schristos const HEADER *hp = (const HEADER *)(const void *)buf;
66450d86ec2Schristos HEADER *anhp = (HEADER *)(void *)ans;
6652b237084Schristos struct sockaddr *nsap;
66672e5329bSchristos socklen_t nsaplen;
667c5e820caSchristos int truncating, connreset, resplen;
668c5e820caSchristos ssize_t n;
6692b237084Schristos struct iovec iov[2];
6702b237084Schristos u_short len;
6712b237084Schristos u_char *cp;
6722b237084Schristos void *tmp;
673650d1881Schristos #if defined(SO_NOSIGPIPE) && SOCK_NOSIGPIPE == 0
6743873655bSchristos int on = 1;
6753873655bSchristos #endif
6762b237084Schristos
6771ad5eecbSchristos nsap = get_nsaddr(statp, (size_t)ns);
6782b237084Schristos nsaplen = get_salen(nsap);
6792b237084Schristos
6802b237084Schristos connreset = 0;
6812b237084Schristos same_ns:
6822b237084Schristos truncating = 0;
6832b237084Schristos
6842b237084Schristos /* Are we still talking to whom we want to talk to? */
6852b237084Schristos if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
6862b237084Schristos struct sockaddr_storage peer;
6872b237084Schristos ISC_SOCKLEN_T size = sizeof peer;
6882b237084Schristos
6892b237084Schristos if (getpeername(statp->_vcsock,
6901ad5eecbSchristos (struct sockaddr *)(void *)&peer, &size) < 0 ||
6911ad5eecbSchristos !sock_eq((struct sockaddr *)(void *)&peer, nsap)) {
6922b237084Schristos res_nclose(statp);
6932b237084Schristos statp->_flags &= ~RES_F_VC;
6942b237084Schristos }
6952b237084Schristos }
6962b237084Schristos
6972b237084Schristos if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
6982b237084Schristos if (statp->_vcsock >= 0)
6992b237084Schristos res_nclose(statp);
7002b237084Schristos
701650d1881Schristos statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM
702650d1881Schristos | SOCK_NOSIGPIPE | SOCK_CLOEXEC, 0);
703650d1881Schristos #if SOCK_CLOEXEC == 0
704650d1881Schristos fcntl(statp->_vcsock, F_SETFD, FD_CLOEXEC);
705650d1881Schristos #endif
706650d1881Schristos #if !defined(USE_POLL) && !defined(USE_KQUEUE)
7072b237084Schristos if (statp->_vcsock > highestFD) {
7082b237084Schristos res_nclose(statp);
7092b237084Schristos errno = ENOTSOCK;
7102b237084Schristos }
71179b560daSpooka #endif
7122b237084Schristos if (statp->_vcsock < 0) {
7132b237084Schristos switch (errno) {
7142b237084Schristos case EPROTONOSUPPORT:
7152b237084Schristos #ifdef EPFNOSUPPORT
7162b237084Schristos case EPFNOSUPPORT:
7172b237084Schristos #endif
7182b237084Schristos case EAFNOSUPPORT:
7192b237084Schristos Perror(statp, stderr, "socket(vc)", errno);
7202b237084Schristos return (0);
7212b237084Schristos default:
7222b237084Schristos *terrno = errno;
7232b237084Schristos Perror(statp, stderr, "socket(vc)", errno);
7242b237084Schristos return (-1);
7252b237084Schristos }
7262b237084Schristos }
727650d1881Schristos #if defined(SO_NOSIGPIPE) && SOCK_NOSIGPIPE == 0
7283873655bSchristos /*
7293873655bSchristos * Disable generation of SIGPIPE when writing to a closed
7303873655bSchristos * socket. Write should return -1 and set errno to EPIPE
7313873655bSchristos * instead.
7323873655bSchristos *
7333873655bSchristos * Push on even if setsockopt(SO_NOSIGPIPE) fails.
7343873655bSchristos */
7353873655bSchristos (void)setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
736650d1881Schristos (socklen_t)sizeof(on));
7373873655bSchristos #endif
7382b237084Schristos errno = 0;
73972e5329bSchristos if (connect(statp->_vcsock, nsap, nsaplen) < 0) {
7402b237084Schristos *terrno = errno;
7412b237084Schristos Aerror(statp, stderr, "connect/vc", errno, nsap,
7422b237084Schristos nsaplen);
7432b237084Schristos res_nclose(statp);
7442b237084Schristos return (0);
7452b237084Schristos }
7462b237084Schristos statp->_flags |= RES_F_VC;
7472b237084Schristos }
7482b237084Schristos
7492b237084Schristos /*
7502b237084Schristos * Send length & message
7512b237084Schristos */
7521ad5eecbSchristos ns_put16((u_short)buflen, (u_char*)(void *)&len);
7532b237084Schristos iov[0] = evConsIovec(&len, INT16SZ);
7542b237084Schristos DE_CONST(buf, tmp);
755bc91d7faSpara iov[1] = evConsIovec(tmp, (size_t)buflen);
75672e5329bSchristos if (writev(statp->_vcsock, iov, 2) != (ssize_t)(INT16SZ + buflen)) {
7572b237084Schristos *terrno = errno;
7582b237084Schristos Perror(statp, stderr, "write failed", errno);
7592b237084Schristos res_nclose(statp);
7602b237084Schristos return (0);
7612b237084Schristos }
7622b237084Schristos /*
7632b237084Schristos * Receive length & response
7642b237084Schristos */
7652b237084Schristos read_len:
7662b237084Schristos cp = ans;
7672b237084Schristos len = INT16SZ;
7681ad5eecbSchristos while ((n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0) {
7692b237084Schristos cp += n;
770c5e820caSchristos if ((len -= (u_short)n) == 0)
7712b237084Schristos break;
7722b237084Schristos }
7732b237084Schristos if (n <= 0) {
7742b237084Schristos *terrno = errno;
7752b237084Schristos Perror(statp, stderr, "read failed", errno);
7762b237084Schristos res_nclose(statp);
7772b237084Schristos /*
7782b237084Schristos * A long running process might get its TCP
7792b237084Schristos * connection reset if the remote server was
7802b237084Schristos * restarted. Requery the server instead of
7812b237084Schristos * trying a new one. When there is only one
7822b237084Schristos * server, this means that a query might work
7832b237084Schristos * instead of failing. We only allow one reset
7842b237084Schristos * per query to prevent looping.
7852b237084Schristos */
7862b237084Schristos if (*terrno == ECONNRESET && !connreset) {
7872b237084Schristos connreset = 1;
7882b237084Schristos res_nclose(statp);
7892b237084Schristos goto same_ns;
7902b237084Schristos }
7912b237084Schristos res_nclose(statp);
7922b237084Schristos return (0);
7932b237084Schristos }
7942b237084Schristos resplen = ns_get16(ans);
7952b237084Schristos if (resplen > anssiz) {
7962b237084Schristos Dprint(statp->options & RES_DEBUG,
7972b237084Schristos (stdout, ";; response truncated\n")
7982b237084Schristos );
7992b237084Schristos truncating = 1;
8002b237084Schristos len = anssiz;
8012b237084Schristos } else
8022b237084Schristos len = resplen;
8032b237084Schristos if (len < HFIXEDSZ) {
8042b237084Schristos /*
8052b237084Schristos * Undersized message.
8062b237084Schristos */
8072b237084Schristos Dprint(statp->options & RES_DEBUG,
8082b237084Schristos (stdout, ";; undersized: %d\n", len));
8092b237084Schristos *terrno = EMSGSIZE;
8102b237084Schristos res_nclose(statp);
8112b237084Schristos return (0);
8122b237084Schristos }
8132b237084Schristos cp = ans;
8141ad5eecbSchristos while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0){
8152b237084Schristos cp += n;
816c5e820caSchristos len -= (u_short)n;
8172b237084Schristos }
8182b237084Schristos if (n <= 0) {
8192b237084Schristos *terrno = errno;
8202b237084Schristos Perror(statp, stderr, "read(vc)", errno);
8212b237084Schristos res_nclose(statp);
8222b237084Schristos return (0);
8232b237084Schristos }
8242b237084Schristos if (truncating) {
8252b237084Schristos /*
8262b237084Schristos * Flush rest of answer so connection stays in synch.
8272b237084Schristos */
8282b237084Schristos anhp->tc = 1;
8292b237084Schristos len = resplen - anssiz;
8302b237084Schristos while (len != 0) {
8312b237084Schristos char junk[PACKETSZ];
8322b237084Schristos
8332b237084Schristos n = read(statp->_vcsock, junk,
8342b237084Schristos (len > sizeof junk) ? sizeof junk : len);
8352b237084Schristos if (n > 0)
836c5e820caSchristos len -= (u_short)n;
8372b237084Schristos else
8382b237084Schristos break;
8392b237084Schristos }
8402b237084Schristos }
8412b237084Schristos /*
8422b237084Schristos * If the calling applicating has bailed out of
8432b237084Schristos * a previous call and failed to arrange to have
8442b237084Schristos * the circuit closed or the server has got
8452b237084Schristos * itself confused, then drop the packet and
8462b237084Schristos * wait for the correct one.
8472b237084Schristos */
8482b237084Schristos if (hp->id != anhp->id) {
8492b237084Schristos DprintQ((statp->options & RES_DEBUG) ||
8502b237084Schristos (statp->pfcode & RES_PRF_REPLY),
8512b237084Schristos (stdout, ";; old answer (unexpected):\n"),
8522b237084Schristos ans, (resplen > anssiz) ? anssiz: resplen);
8532b237084Schristos goto read_len;
8542b237084Schristos }
8552b237084Schristos
8562b237084Schristos /*
8572b237084Schristos * All is well, or the error is fatal. Signal that the
8582b237084Schristos * next nameserver ought not be tried.
8592b237084Schristos */
8602b237084Schristos return (resplen);
8612b237084Schristos }
8622b237084Schristos
8632b237084Schristos static int
send_dg(res_state statp,int kq,const void * buf,size_t buflen,u_char * ans,int anssiz,int * terrno,int ns,int tries,int * v_circuit,int * gotsomewhere)864650d1881Schristos send_dg(res_state statp,
865650d1881Schristos #ifdef USE_KQUEUE
866650d1881Schristos int kq,
867650d1881Schristos #endif
86872e5329bSchristos const void *buf, size_t buflen, u_char *ans,
8693873655bSchristos int anssiz, int *terrno, int ns, int tries, int *v_circuit,
870d73eb73dSchristos int *gotsomewhere)
8712b237084Schristos {
8721ad5eecbSchristos const HEADER *hp = (const HEADER *)(const void *)buf;
8731ad5eecbSchristos HEADER *anhp = (HEADER *)(void *)ans;
8742b237084Schristos const struct sockaddr *nsap;
87572e5329bSchristos socklen_t nsaplen;
8762b237084Schristos struct timespec now, timeout, finish;
8772b237084Schristos struct sockaddr_storage from;
8782b237084Schristos ISC_SOCKLEN_T fromlen;
879c5e820caSchristos ssize_t resplen;
880c5e820caSchristos int seconds, n, s;
881650d1881Schristos #ifdef USE_KQUEUE
882650d1881Schristos struct kevent kv;
883650d1881Schristos #else
884d73eb73dSchristos #ifdef USE_POLL
885d73eb73dSchristos int polltimeout;
886d73eb73dSchristos struct pollfd pollfd;
887d73eb73dSchristos #else
888d73eb73dSchristos fd_set dsmask;
889d73eb73dSchristos #endif
890650d1881Schristos #endif
8912b237084Schristos
8921ad5eecbSchristos nsap = get_nsaddr(statp, (size_t)ns);
8932b237084Schristos nsaplen = get_salen(nsap);
8942b237084Schristos if (EXT(statp).nssocks[ns] == -1) {
895650d1881Schristos EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM
896650d1881Schristos | SOCK_CLOEXEC, 0);
897650d1881Schristos #if SOCK_CLOEXEC == 0
898650d1881Schristos fcntl(EXT(statp)nssocks[ns], F_SETFD, FD_CLOEXEC);
899650d1881Schristos #endif
900650d1881Schristos #if !defined(USE_POLL) && !defined(USE_KQUEUE)
9012b237084Schristos if (EXT(statp).nssocks[ns] > highestFD) {
9022b237084Schristos res_nclose(statp);
9032b237084Schristos errno = ENOTSOCK;
9042b237084Schristos }
90579b560daSpooka #endif
9062b237084Schristos if (EXT(statp).nssocks[ns] < 0) {
9072b237084Schristos switch (errno) {
9082b237084Schristos case EPROTONOSUPPORT:
9092b237084Schristos #ifdef EPFNOSUPPORT
9102b237084Schristos case EPFNOSUPPORT:
9112b237084Schristos #endif
9122b237084Schristos case EAFNOSUPPORT:
9132b237084Schristos Perror(statp, stderr, "socket(dg)", errno);
9142b237084Schristos return (0);
9152b237084Schristos default:
9162b237084Schristos *terrno = errno;
9172b237084Schristos Perror(statp, stderr, "socket(dg)", errno);
9182b237084Schristos return (-1);
9192b237084Schristos }
9202b237084Schristos }
9212b237084Schristos #ifndef CANNOT_CONNECT_DGRAM
9222b237084Schristos /*
9232b237084Schristos * On a 4.3BSD+ machine (client and server,
9242b237084Schristos * actually), sending to a nameserver datagram
9252b237084Schristos * port with no nameserver will cause an
9262b237084Schristos * ICMP port unreachable message to be returned.
9272b237084Schristos * If our datagram socket is "connected" to the
9282b237084Schristos * server, we get an ECONNREFUSED error on the next
9292b237084Schristos * socket operation, and select returns if the
9302b237084Schristos * error message is received. We can thus detect
9312b237084Schristos * the absence of a nameserver without timing out.
932650d1881Schristos *
933650d1881Schristos * When the option "insecure1" is specified, we'd
934650d1881Schristos * rather expect to see responses from an "unknown"
935650d1881Schristos * address. In order to let the kernel accept such
936650d1881Schristos * responses, do not connect the socket here.
937650d1881Schristos * XXX: or do we need an explicit option to disable
938650d1881Schristos * connecting?
9392b237084Schristos */
940650d1881Schristos if (!(statp->options & RES_INSECURE1) &&
94172e5329bSchristos connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
9422b237084Schristos Aerror(statp, stderr, "connect(dg)", errno, nsap,
9432b237084Schristos nsaplen);
9442b237084Schristos res_nclose(statp);
9452b237084Schristos return (0);
9462b237084Schristos }
9472b237084Schristos #endif /* !CANNOT_CONNECT_DGRAM */
9482b237084Schristos Dprint(statp->options & RES_DEBUG,
9492b237084Schristos (stdout, ";; new DG socket\n"))
9502b237084Schristos }
9512b237084Schristos s = EXT(statp).nssocks[ns];
9522b237084Schristos #ifndef CANNOT_CONNECT_DGRAM
953650d1881Schristos if (statp->options & RES_INSECURE1) {
95472e5329bSchristos if (sendto(s, buf, buflen, 0, nsap, nsaplen) !=
95572e5329bSchristos (ssize_t)buflen) {
956650d1881Schristos Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
957650d1881Schristos res_nclose(statp);
958650d1881Schristos return (0);
959650d1881Schristos }
96072e5329bSchristos } else if (send(s, buf, buflen, 0) != (ssize_t)buflen) {
9612b237084Schristos Perror(statp, stderr, "send", errno);
9622b237084Schristos res_nclose(statp);
9632b237084Schristos return (0);
9642b237084Schristos }
9652b237084Schristos #else /* !CANNOT_CONNECT_DGRAM */
96672e5329bSchristos if (sendto(s, buf, buflen, 0, nsap, nsaplen) != (ssize_t)buflen)
9672b237084Schristos {
9682b237084Schristos Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
9692b237084Schristos res_nclose(statp);
9702b237084Schristos return (0);
9712b237084Schristos }
9722b237084Schristos #endif /* !CANNOT_CONNECT_DGRAM */
9732b237084Schristos
9742b237084Schristos /*
9752b237084Schristos * Wait for reply.
9762b237084Schristos */
9773873655bSchristos seconds = (statp->retrans << tries);
9782b237084Schristos if (ns > 0)
9792b237084Schristos seconds /= statp->nscount;
9802b237084Schristos if (seconds <= 0)
9812b237084Schristos seconds = 1;
9822b237084Schristos now = evNowTime();
983a8d19c80Schristos timeout = evConsTime((time_t)seconds, 0L);
9842b237084Schristos finish = evAddTime(now, timeout);
9852b237084Schristos goto nonow;
9862b237084Schristos wait:
9872b237084Schristos now = evNowTime();
9882b237084Schristos nonow:
989d73eb73dSchristos #ifndef USE_POLL
9902b237084Schristos if (evCmpTime(finish, now) > 0)
9912b237084Schristos timeout = evSubTime(finish, now);
9922b237084Schristos else
99350d86ec2Schristos timeout = evConsTime(0L, 0L);
994650d1881Schristos #ifdef USE_KQUEUE
995650d1881Schristos EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
996650d1881Schristos n = kevent(kq, &kv, 1, &kv, 1, &timeout);
997650d1881Schristos #else
998650d1881Schristos FD_ZERO(&dsmask);
999650d1881Schristos FD_SET(s, &dsmask);
10002b237084Schristos n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
1001650d1881Schristos #endif
1002d73eb73dSchristos #else
1003d73eb73dSchristos timeout = evSubTime(finish, now);
1004d73eb73dSchristos if (timeout.tv_sec < 0)
1005a8d19c80Schristos timeout = evConsTime((time_t)0, 0L);
1006461a86f9Schristos polltimeout = 1000*(int)timeout.tv_sec +
1007461a86f9Schristos (int)timeout.tv_nsec/1000000;
1008d73eb73dSchristos pollfd.fd = s;
1009d73eb73dSchristos pollfd.events = POLLRDNORM;
1010d73eb73dSchristos n = poll(&pollfd, 1, polltimeout);
1011d73eb73dSchristos #endif /* USE_POLL */
1012d73eb73dSchristos
10132b237084Schristos if (n == 0) {
10142b237084Schristos Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
10152b237084Schristos *gotsomewhere = 1;
10162b237084Schristos return (0);
10172b237084Schristos }
10182b237084Schristos if (n < 0) {
1019650d1881Schristos #if defined(USE_POLL)
1020650d1881Schristos static const char *fun = "poll";
1021650d1881Schristos #elif defined(USE_SELECT)
1022650d1881Schristos static const char *fun = "select";
1023650d1881Schristos #elif defined(USE_KQUEUE)
1024650d1881Schristos static const char *fun = "kevent";
1025650d1881Schristos #endif
10262b237084Schristos if (errno == EINTR)
10272b237084Schristos goto wait;
1028650d1881Schristos Perror(statp, stderr, fun, errno);
10292b237084Schristos res_nclose(statp);
10302b237084Schristos return (0);
10312b237084Schristos }
1032650d1881Schristos #ifdef USE_KQUEUE
1033650d1881Schristos if ((int)kv.ident != s)
1034650d1881Schristos goto wait;
1035650d1881Schristos #endif
10362b237084Schristos errno = 0;
10372b237084Schristos fromlen = sizeof(from);
10381ad5eecbSchristos resplen = recvfrom(s, (char*)ans, (size_t)anssiz,0,
10391ad5eecbSchristos (struct sockaddr *)(void *)&from, &fromlen);
10402b237084Schristos if (resplen <= 0) {
10412b237084Schristos Perror(statp, stderr, "recvfrom", errno);
10422b237084Schristos res_nclose(statp);
10432b237084Schristos return (0);
10442b237084Schristos }
10452b237084Schristos *gotsomewhere = 1;
10462b237084Schristos if (resplen < HFIXEDSZ) {
10472b237084Schristos /*
10482b237084Schristos * Undersized message.
10492b237084Schristos */
10502b237084Schristos Dprint(statp->options & RES_DEBUG,
1051c5e820caSchristos (stdout, ";; undersized: %zd\n",
10522b237084Schristos resplen));
10532b237084Schristos *terrno = EMSGSIZE;
10542b237084Schristos res_nclose(statp);
10552b237084Schristos return (0);
10562b237084Schristos }
10572b237084Schristos if (hp->id != anhp->id) {
10582b237084Schristos /*
10592b237084Schristos * response from old query, ignore it.
10602b237084Schristos * XXX - potential security hazard could
10612b237084Schristos * be detected here.
10622b237084Schristos */
10632b237084Schristos DprintQ((statp->options & RES_DEBUG) ||
10642b237084Schristos (statp->pfcode & RES_PRF_REPLY),
10652b237084Schristos (stdout, ";; old answer:\n"),
10662b237084Schristos ans, (resplen > anssiz) ? anssiz : resplen);
10672b237084Schristos goto wait;
10682b237084Schristos }
10692b237084Schristos if (!(statp->options & RES_INSECURE1) &&
10701ad5eecbSchristos !res_ourserver_p(statp, (struct sockaddr *)(void *)&from)) {
10712b237084Schristos /*
10722b237084Schristos * response from wrong server? ignore it.
10732b237084Schristos * XXX - potential security hazard could
10742b237084Schristos * be detected here.
10752b237084Schristos */
10762b237084Schristos DprintQ((statp->options & RES_DEBUG) ||
10772b237084Schristos (statp->pfcode & RES_PRF_REPLY),
10782b237084Schristos (stdout, ";; not our server:\n"),
10792b237084Schristos ans, (resplen > anssiz) ? anssiz : resplen);
10802b237084Schristos goto wait;
10812b237084Schristos }
10822b237084Schristos #ifdef RES_USE_EDNS0
10832b237084Schristos if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
10842b237084Schristos /*
10852b237084Schristos * Do not retry if the server do not understand EDNS0.
10862b237084Schristos * The case has to be captured here, as FORMERR packet do not
10872b237084Schristos * carry query section, hence res_queriesmatch() returns 0.
10882b237084Schristos */
10892b237084Schristos DprintQ(statp->options & RES_DEBUG,
10902b237084Schristos (stdout, "server rejected query with EDNS0:\n"),
10912b237084Schristos ans, (resplen > anssiz) ? anssiz : resplen);
10922b237084Schristos /* record the error */
10932b237084Schristos statp->_flags |= RES_F_EDNS0ERR;
10942b237084Schristos res_nclose(statp);
10952b237084Schristos return (0);
10962b237084Schristos }
10972b237084Schristos #endif
10982b237084Schristos if (!(statp->options & RES_INSECURE2) &&
109972e5329bSchristos !res_queriesmatch(buf, (const u_char *)buf + buflen,
11002b237084Schristos ans, ans + anssiz)) {
11012b237084Schristos /*
11022b237084Schristos * response contains wrong query? ignore it.
11032b237084Schristos * XXX - potential security hazard could
11042b237084Schristos * be detected here.
11052b237084Schristos */
11062b237084Schristos DprintQ((statp->options & RES_DEBUG) ||
11072b237084Schristos (statp->pfcode & RES_PRF_REPLY),
11082b237084Schristos (stdout, ";; wrong query name:\n"),
1109c5e820caSchristos ans, (int)(resplen > anssiz) ? anssiz : resplen);
11102b237084Schristos goto wait;
11112b237084Schristos }
11122b237084Schristos if (anhp->rcode == SERVFAIL ||
11132b237084Schristos anhp->rcode == NOTIMP ||
11142b237084Schristos anhp->rcode == REFUSED) {
11152b237084Schristos DprintQ(statp->options & RES_DEBUG,
11162b237084Schristos (stdout, "server rejected query:\n"),
1117c5e820caSchristos ans, (int)(resplen > anssiz) ? anssiz : resplen);
11182b237084Schristos res_nclose(statp);
11192b237084Schristos /* don't retry if called from dig */
11202b237084Schristos if (!statp->pfcode)
11212b237084Schristos return (0);
11222b237084Schristos }
11232b237084Schristos if (!(statp->options & RES_IGNTC) && anhp->tc) {
11242b237084Schristos /*
11252b237084Schristos * To get the rest of answer,
11262b237084Schristos * use TCP with same server.
11272b237084Schristos */
11282b237084Schristos Dprint(statp->options & RES_DEBUG,
11292b237084Schristos (stdout, ";; truncated answer\n"));
11302b237084Schristos *v_circuit = 1;
11312b237084Schristos res_nclose(statp);
11322b237084Schristos return (1);
11332b237084Schristos }
11342b237084Schristos /*
11352b237084Schristos * All is well, or the error is fatal. Signal that the
11362b237084Schristos * next nameserver ought not be tried.
11372b237084Schristos */
1138c5e820caSchristos _DIAGASSERT(__type_fit(int, resplen));
1139c5e820caSchristos return (int)resplen;
11402b237084Schristos }
11412b237084Schristos
11422b237084Schristos static void
Aerror(const res_state statp,FILE * file,const char * string,int error,const struct sockaddr * address,socklen_t alen)11432b237084Schristos Aerror(const res_state statp, FILE *file, const char *string, int error,
114472e5329bSchristos const struct sockaddr *address, socklen_t alen)
11452b237084Schristos {
11462b237084Schristos int save = errno;
11472b237084Schristos char hbuf[NI_MAXHOST];
11482b237084Schristos char sbuf[NI_MAXSERV];
11492b237084Schristos
11502b237084Schristos if ((statp->options & RES_DEBUG) != 0U) {
115172e5329bSchristos if (getnameinfo(address, alen, hbuf,
1152c5e820caSchristos (socklen_t)sizeof(hbuf), sbuf, (socklen_t)sizeof(sbuf),
1153c5e820caSchristos niflags)) {
11542b237084Schristos strncpy(hbuf, "?", sizeof(hbuf) - 1);
11552b237084Schristos hbuf[sizeof(hbuf) - 1] = '\0';
11562b237084Schristos strncpy(sbuf, "?", sizeof(sbuf) - 1);
11572b237084Schristos sbuf[sizeof(sbuf) - 1] = '\0';
11582b237084Schristos }
11592b237084Schristos fprintf(file, "res_send: %s ([%s].%s): %s\n",
11602b237084Schristos string, hbuf, sbuf, strerror(error));
11612b237084Schristos }
11622b237084Schristos errno = save;
11632b237084Schristos }
11642b237084Schristos
11652b237084Schristos static void
Perror(const res_state statp,FILE * file,const char * string,int error)11662b237084Schristos Perror(const res_state statp, FILE *file, const char *string, int error) {
11672b237084Schristos int save = errno;
11682b237084Schristos
11692b237084Schristos if ((statp->options & RES_DEBUG) != 0U)
11702b237084Schristos fprintf(file, "res_send: %s: %s\n",
11712b237084Schristos string, strerror(error));
11722b237084Schristos errno = save;
11732b237084Schristos }
11742b237084Schristos
11752b237084Schristos static int
sock_eq(struct sockaddr * a,struct sockaddr * b)11762b237084Schristos sock_eq(struct sockaddr *a, struct sockaddr *b) {
11772b237084Schristos struct sockaddr_in *a4, *b4;
11782b237084Schristos struct sockaddr_in6 *a6, *b6;
11792b237084Schristos
11802b237084Schristos if (a->sa_family != b->sa_family)
11812b237084Schristos return 0;
11822b237084Schristos switch (a->sa_family) {
11832b237084Schristos case AF_INET:
11841ad5eecbSchristos a4 = (struct sockaddr_in *)(void *)a;
11851ad5eecbSchristos b4 = (struct sockaddr_in *)(void *)b;
11862b237084Schristos return a4->sin_port == b4->sin_port &&
11872b237084Schristos a4->sin_addr.s_addr == b4->sin_addr.s_addr;
11882b237084Schristos case AF_INET6:
11891ad5eecbSchristos a6 = (struct sockaddr_in6 *)(void *)a;
11901ad5eecbSchristos b6 = (struct sockaddr_in6 *)(void *)b;
11912b237084Schristos return a6->sin6_port == b6->sin6_port &&
11922b237084Schristos #ifdef HAVE_SIN6_SCOPE_ID
11932b237084Schristos a6->sin6_scope_id == b6->sin6_scope_id &&
11942b237084Schristos #endif
11952b237084Schristos IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
11962b237084Schristos default:
11972b237084Schristos return 0;
11982b237084Schristos }
11992b237084Schristos }
12002b237084Schristos
1201650d1881Schristos #if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
12022b237084Schristos /* XXX needs to move to the porting library. */
12032b237084Schristos static int
pselect(int nfds,void * rfds,void * wfds,void * efds,struct timespec * tsp,const sigset_t * sigmask)12042b237084Schristos pselect(int nfds, void *rfds, void *wfds, void *efds,
12052b237084Schristos struct timespec *tsp, const sigset_t *sigmask)
12062b237084Schristos {
12072b237084Schristos struct timeval tv, *tvp;
12082b237084Schristos sigset_t sigs;
12092b237084Schristos int n;
12102b237084Schristos
12112b237084Schristos if (tsp) {
12122b237084Schristos tvp = &tv;
12132b237084Schristos tv = evTimeVal(*tsp);
12142b237084Schristos } else
12152b237084Schristos tvp = NULL;
12162b237084Schristos if (sigmask)
12172b237084Schristos sigprocmask(SIG_SETMASK, sigmask, &sigs);
12182b237084Schristos n = select(nfds, rfds, wfds, efds, tvp);
12192b237084Schristos if (sigmask)
12202b237084Schristos sigprocmask(SIG_SETMASK, &sigs, NULL);
12212b237084Schristos if (tsp)
12222b237084Schristos *tsp = evTimeSpec(tv);
12232b237084Schristos return (n);
12242b237084Schristos }
12252b237084Schristos #endif
1226