1*0a6a1f1dSLionel Sambuc /* $NetBSD: res_send.c,v 1.30 2015/02/24 17:56:20 christos Exp $ */
22fe8fb19SBen Gras
32fe8fb19SBen Gras /*
42fe8fb19SBen Gras * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC")
52fe8fb19SBen Gras * Portions Copyright (C) 1996-2003 Internet Software Consortium.
62fe8fb19SBen Gras *
72fe8fb19SBen Gras * Permission to use, copy, modify, and/or distribute this software for any
82fe8fb19SBen Gras * purpose with or without fee is hereby granted, provided that the above
92fe8fb19SBen Gras * copyright notice and this permission notice appear in all copies.
102fe8fb19SBen Gras *
112fe8fb19SBen Gras * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
122fe8fb19SBen Gras * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
132fe8fb19SBen Gras * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
142fe8fb19SBen Gras * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
152fe8fb19SBen Gras * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
162fe8fb19SBen Gras * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
172fe8fb19SBen Gras * PERFORMANCE OF THIS SOFTWARE.
182fe8fb19SBen Gras */
192fe8fb19SBen Gras
202fe8fb19SBen Gras /*
212fe8fb19SBen Gras * Copyright (c) 1985, 1989, 1993
222fe8fb19SBen Gras * The Regents of the University of California. All rights reserved.
232fe8fb19SBen Gras *
242fe8fb19SBen Gras * Redistribution and use in source and binary forms, with or without
252fe8fb19SBen Gras * modification, are permitted provided that the following conditions
262fe8fb19SBen Gras * are met:
272fe8fb19SBen Gras * 1. Redistributions of source code must retain the above copyright
282fe8fb19SBen Gras * notice, this list of conditions and the following disclaimer.
292fe8fb19SBen Gras * 2. Redistributions in binary form must reproduce the above copyright
302fe8fb19SBen Gras * notice, this list of conditions and the following disclaimer in the
312fe8fb19SBen Gras * documentation and/or other materials provided with the distribution.
32*0a6a1f1dSLionel Sambuc * 3. Neither the name of the University nor the names of its contributors
332fe8fb19SBen Gras * may be used to endorse or promote products derived from this software
342fe8fb19SBen Gras * without specific prior written permission.
352fe8fb19SBen Gras *
362fe8fb19SBen Gras * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
372fe8fb19SBen Gras * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
382fe8fb19SBen Gras * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
392fe8fb19SBen Gras * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
402fe8fb19SBen Gras * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
412fe8fb19SBen Gras * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
422fe8fb19SBen Gras * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
432fe8fb19SBen Gras * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
442fe8fb19SBen Gras * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
452fe8fb19SBen Gras * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
462fe8fb19SBen Gras * SUCH DAMAGE.
472fe8fb19SBen Gras */
482fe8fb19SBen Gras
492fe8fb19SBen Gras /*
502fe8fb19SBen Gras * Portions Copyright (c) 1993 by Digital Equipment Corporation.
512fe8fb19SBen Gras *
522fe8fb19SBen Gras * Permission to use, copy, modify, and distribute this software for any
532fe8fb19SBen Gras * purpose with or without fee is hereby granted, provided that the above
542fe8fb19SBen Gras * copyright notice and this permission notice appear in all copies, and that
552fe8fb19SBen Gras * the name of Digital Equipment Corporation not be used in advertising or
562fe8fb19SBen Gras * publicity pertaining to distribution of the document or software without
572fe8fb19SBen Gras * specific, written prior permission.
582fe8fb19SBen Gras *
592fe8fb19SBen Gras * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
602fe8fb19SBen Gras * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
612fe8fb19SBen Gras * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
622fe8fb19SBen Gras * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
632fe8fb19SBen Gras * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
642fe8fb19SBen Gras * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
652fe8fb19SBen Gras * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
662fe8fb19SBen Gras * SOFTWARE.
672fe8fb19SBen Gras */
682fe8fb19SBen Gras
692fe8fb19SBen Gras /*
702fe8fb19SBen Gras * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC")
712fe8fb19SBen Gras * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
722fe8fb19SBen Gras *
732fe8fb19SBen Gras * Permission to use, copy, modify, and distribute this software for any
742fe8fb19SBen Gras * purpose with or without fee is hereby granted, provided that the above
752fe8fb19SBen Gras * copyright notice and this permission notice appear in all copies.
762fe8fb19SBen Gras *
772fe8fb19SBen Gras * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
782fe8fb19SBen Gras * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
792fe8fb19SBen Gras * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
802fe8fb19SBen Gras * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
812fe8fb19SBen Gras * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
822fe8fb19SBen Gras * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
832fe8fb19SBen Gras * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
842fe8fb19SBen Gras */
852fe8fb19SBen Gras
862fe8fb19SBen Gras #include <sys/cdefs.h>
872fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
882fe8fb19SBen Gras #ifdef notdef
892fe8fb19SBen Gras static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
902fe8fb19SBen Gras static const char rcsid[] = "Id: res_send.c,v 1.22 2009/01/22 23:49:23 tbox Exp";
912fe8fb19SBen Gras #else
92*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: res_send.c,v 1.30 2015/02/24 17:56:20 christos Exp $");
932fe8fb19SBen Gras #endif
942fe8fb19SBen Gras #endif /* LIBC_SCCS and not lint */
952fe8fb19SBen Gras
962fe8fb19SBen Gras /*! \file
972fe8fb19SBen Gras * \brief
982fe8fb19SBen Gras * Send query to name server and wait for reply.
992fe8fb19SBen Gras */
1002fe8fb19SBen Gras
1012fe8fb19SBen Gras #include "namespace.h"
1022fe8fb19SBen Gras #include "port_before.h"
10384d9c625SLionel Sambuc #ifndef USE_KQUEUE
1042fe8fb19SBen Gras #include "fd_setsize.h"
10584d9c625SLionel Sambuc #endif /* USE_KQUEUE */
1062fe8fb19SBen Gras
1072fe8fb19SBen Gras #include <sys/types.h>
1082fe8fb19SBen Gras #include <sys/param.h>
1092fe8fb19SBen Gras #include <sys/time.h>
1102fe8fb19SBen Gras #include <sys/socket.h>
1112fe8fb19SBen Gras #include <sys/uio.h>
11284d9c625SLionel Sambuc #ifdef USE_KQUEUE
11384d9c625SLionel Sambuc #include <sys/event.h>
11484d9c625SLionel Sambuc #endif /* USE_KQUEUE */
1152fe8fb19SBen Gras
1162fe8fb19SBen Gras #include <netinet/in.h>
1172fe8fb19SBen Gras #include <arpa/nameser.h>
1182fe8fb19SBen Gras #include <arpa/inet.h>
1192fe8fb19SBen Gras
120f14fb602SLionel Sambuc #include <assert.h>
1212fe8fb19SBen Gras #include <errno.h>
1222fe8fb19SBen Gras #include <netdb.h>
1232fe8fb19SBen Gras #include <resolv.h>
1242fe8fb19SBen Gras #include <signal.h>
1252fe8fb19SBen Gras #include <stdio.h>
12684d9c625SLionel Sambuc #include <fcntl.h>
1272fe8fb19SBen Gras #include <stdlib.h>
1282fe8fb19SBen Gras #include <string.h>
1292fe8fb19SBen Gras #include <unistd.h>
1302fe8fb19SBen Gras
1312fe8fb19SBen Gras #include <isc/eventlib.h>
1322fe8fb19SBen Gras
1332fe8fb19SBen Gras #include "port_after.h"
1342fe8fb19SBen Gras
1352fe8fb19SBen Gras #if 0
1362fe8fb19SBen Gras #ifdef __weak_alias
1372fe8fb19SBen Gras __weak_alias(res_ourserver_p,__res_ourserver_p)
1382fe8fb19SBen Gras __weak_alias(res_nameinquery,__res_nameinquery)
1392fe8fb19SBen Gras __weak_alias(res_queriesmatch,__res_queriesmatch)
1402fe8fb19SBen Gras __weak_alias(res_nsend,__res_nsend)
1412fe8fb19SBen Gras #endif
1422fe8fb19SBen Gras #endif
1432fe8fb19SBen Gras
14484d9c625SLionel Sambuc #ifndef SOCK_NOSIGPIPE
14584d9c625SLionel Sambuc #define SOCK_NOSIGPIPE 0
14684d9c625SLionel Sambuc #endif
14784d9c625SLionel Sambuc #ifndef SOCK_NOCLOEXEC
14884d9c625SLionel Sambuc #define SOCK_NOCLOEXEC 0
14984d9c625SLionel Sambuc #endif
1502fe8fb19SBen Gras
1512fe8fb19SBen Gras #ifdef USE_POLL
1522fe8fb19SBen Gras #ifdef HAVE_STROPTS_H
1532fe8fb19SBen Gras #include <stropts.h>
1542fe8fb19SBen Gras #endif
1552fe8fb19SBen Gras #include <poll.h>
1562fe8fb19SBen Gras #endif /* USE_POLL */
1572fe8fb19SBen Gras
1582fe8fb19SBen Gras /* Options. Leave them on. */
1592fe8fb19SBen Gras #ifndef DEBUG
1602fe8fb19SBen Gras #define DEBUG
1612fe8fb19SBen Gras #endif
1622fe8fb19SBen Gras #include "res_debug.h"
1632fe8fb19SBen Gras #include "res_private.h"
1642fe8fb19SBen Gras
1652fe8fb19SBen Gras #define EXT(res) ((res)->_u._ext)
1662fe8fb19SBen Gras
16784d9c625SLionel Sambuc #if !defined(USE_POLL) && !defined(USE_KQUEUE)
1682fe8fb19SBen Gras static const int highestFD = FD_SETSIZE - 1;
1692fe8fb19SBen Gras #endif
1702fe8fb19SBen Gras
1712fe8fb19SBen Gras /* Forward. */
1722fe8fb19SBen Gras
17384d9c625SLionel Sambuc static socklen_t get_salen(const struct sockaddr *);
174f14fb602SLionel Sambuc static struct sockaddr * get_nsaddr(res_state, size_t);
17584d9c625SLionel Sambuc static int send_vc(res_state, const void *, size_t,
1762fe8fb19SBen Gras u_char *, int, int *, int);
17784d9c625SLionel Sambuc static int send_dg(res_state,
17884d9c625SLionel Sambuc #ifdef USE_KQUEUE
17984d9c625SLionel Sambuc int,
18084d9c625SLionel Sambuc #endif
18184d9c625SLionel Sambuc const void *, size_t,
1822fe8fb19SBen Gras u_char *, int, int *, int, int,
1832fe8fb19SBen Gras int *, int *);
1842fe8fb19SBen Gras static void Aerror(const res_state, FILE *, const char *, int,
18584d9c625SLionel Sambuc const struct sockaddr *, socklen_t);
1862fe8fb19SBen Gras static void Perror(const res_state, FILE *, const char *, int);
1872fe8fb19SBen Gras static int sock_eq(struct sockaddr *, struct sockaddr *);
18884d9c625SLionel Sambuc #if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
1892fe8fb19SBen Gras static int pselect(int, void *, void *, void *,
1902fe8fb19SBen Gras struct timespec *,
1912fe8fb19SBen Gras const sigset_t *);
1922fe8fb19SBen Gras #endif
1932fe8fb19SBen Gras void res_pquery(const res_state, const u_char *, int, FILE *);
1942fe8fb19SBen Gras
1952fe8fb19SBen Gras static const int niflags = NI_NUMERICHOST | NI_NUMERICSERV;
1962fe8fb19SBen Gras
1972fe8fb19SBen Gras /* Public. */
1982fe8fb19SBen Gras
1992fe8fb19SBen Gras /*%
2002fe8fb19SBen Gras * looks up "ina" in _res.ns_addr_list[]
2012fe8fb19SBen Gras *
2022fe8fb19SBen Gras * returns:
2032fe8fb19SBen Gras *\li 0 : not found
2042fe8fb19SBen Gras *\li >0 : found
2052fe8fb19SBen Gras *
2062fe8fb19SBen Gras * author:
2072fe8fb19SBen Gras *\li paul vixie, 29may94
2082fe8fb19SBen Gras */
2092fe8fb19SBen Gras int
res_ourserver_p(const res_state statp,const struct sockaddr * sa)2102fe8fb19SBen Gras res_ourserver_p(const res_state statp, const struct sockaddr *sa) {
2112fe8fb19SBen Gras const struct sockaddr_in *inp, *srv;
2122fe8fb19SBen Gras const struct sockaddr_in6 *in6p, *srv6;
2132fe8fb19SBen Gras int ns;
2142fe8fb19SBen Gras
2152fe8fb19SBen Gras switch (sa->sa_family) {
2162fe8fb19SBen Gras case AF_INET:
2172fe8fb19SBen Gras inp = (const struct sockaddr_in *)(const void *)sa;
2182fe8fb19SBen Gras for (ns = 0; ns < statp->nscount; ns++) {
2192fe8fb19SBen Gras srv = (struct sockaddr_in *)(void *)get_nsaddr(statp, (size_t)ns);
2202fe8fb19SBen Gras if (srv->sin_family == inp->sin_family &&
2212fe8fb19SBen Gras srv->sin_port == inp->sin_port &&
2222fe8fb19SBen Gras (srv->sin_addr.s_addr == INADDR_ANY ||
2232fe8fb19SBen Gras srv->sin_addr.s_addr == inp->sin_addr.s_addr))
2242fe8fb19SBen Gras return (1);
2252fe8fb19SBen Gras }
2262fe8fb19SBen Gras break;
2272fe8fb19SBen Gras case AF_INET6:
2282fe8fb19SBen Gras if (EXT(statp).ext == NULL)
2292fe8fb19SBen Gras break;
2302fe8fb19SBen Gras in6p = (const struct sockaddr_in6 *)(const void *)sa;
2312fe8fb19SBen Gras for (ns = 0; ns < statp->nscount; ns++) {
2322fe8fb19SBen Gras srv6 = (struct sockaddr_in6 *)(void *)get_nsaddr(statp, (size_t)ns);
2332fe8fb19SBen Gras if (srv6->sin6_family == in6p->sin6_family &&
2342fe8fb19SBen Gras srv6->sin6_port == in6p->sin6_port &&
2352fe8fb19SBen Gras #ifdef HAVE_SIN6_SCOPE_ID
2362fe8fb19SBen Gras (srv6->sin6_scope_id == 0 ||
2372fe8fb19SBen Gras srv6->sin6_scope_id == in6p->sin6_scope_id) &&
2382fe8fb19SBen Gras #endif
2392fe8fb19SBen Gras (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) ||
2402fe8fb19SBen Gras IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr)))
2412fe8fb19SBen Gras return (1);
2422fe8fb19SBen Gras }
2432fe8fb19SBen Gras break;
2442fe8fb19SBen Gras default:
2452fe8fb19SBen Gras break;
2462fe8fb19SBen Gras }
2472fe8fb19SBen Gras return (0);
2482fe8fb19SBen Gras }
2492fe8fb19SBen Gras
2502fe8fb19SBen Gras /*%
2512fe8fb19SBen Gras * look for (name,type,class) in the query section of packet (buf,eom)
2522fe8fb19SBen Gras *
2532fe8fb19SBen Gras * requires:
2542fe8fb19SBen Gras *\li buf + HFIXEDSZ <= eom
2552fe8fb19SBen Gras *
2562fe8fb19SBen Gras * returns:
2572fe8fb19SBen Gras *\li -1 : format error
2582fe8fb19SBen Gras *\li 0 : not found
2592fe8fb19SBen Gras *\li >0 : found
2602fe8fb19SBen Gras *
2612fe8fb19SBen Gras * author:
2622fe8fb19SBen Gras *\li paul vixie, 29may94
2632fe8fb19SBen Gras */
2642fe8fb19SBen Gras int
res_nameinquery(const char * name,int type,int class,const u_char * buf,const u_char * eom)2652fe8fb19SBen Gras res_nameinquery(const char *name, int type, int class,
2662fe8fb19SBen Gras const u_char *buf, const u_char *eom)
2672fe8fb19SBen Gras {
2682fe8fb19SBen Gras const u_char *cp = buf + HFIXEDSZ;
2692fe8fb19SBen Gras int qdcount = ntohs(((const HEADER*)(const void *)buf)->qdcount);
2702fe8fb19SBen Gras
2712fe8fb19SBen Gras while (qdcount-- > 0) {
2722fe8fb19SBen Gras char tname[MAXDNAME+1];
2732fe8fb19SBen Gras int n, ttype, tclass;
2742fe8fb19SBen Gras
275f14fb602SLionel Sambuc n = dn_expand(buf, eom, cp, tname, (int)sizeof tname);
2762fe8fb19SBen Gras if (n < 0)
2772fe8fb19SBen Gras return (-1);
2782fe8fb19SBen Gras cp += n;
2792fe8fb19SBen Gras if (cp + 2 * INT16SZ > eom)
2802fe8fb19SBen Gras return (-1);
2812fe8fb19SBen Gras ttype = ns_get16(cp); cp += INT16SZ;
2822fe8fb19SBen Gras tclass = ns_get16(cp); cp += INT16SZ;
2832fe8fb19SBen Gras if (ttype == type && tclass == class &&
2842fe8fb19SBen Gras ns_samename(tname, name) == 1)
2852fe8fb19SBen Gras return (1);
2862fe8fb19SBen Gras }
2872fe8fb19SBen Gras return (0);
2882fe8fb19SBen Gras }
2892fe8fb19SBen Gras
2902fe8fb19SBen Gras /*%
2912fe8fb19SBen Gras * is there a 1:1 mapping of (name,type,class)
2922fe8fb19SBen Gras * in (buf1,eom1) and (buf2,eom2)?
2932fe8fb19SBen Gras *
2942fe8fb19SBen Gras * returns:
2952fe8fb19SBen Gras *\li -1 : format error
2962fe8fb19SBen Gras *\li 0 : not a 1:1 mapping
2972fe8fb19SBen Gras *\li >0 : is a 1:1 mapping
2982fe8fb19SBen Gras *
2992fe8fb19SBen Gras * author:
3002fe8fb19SBen Gras *\li paul vixie, 29may94
3012fe8fb19SBen Gras */
3022fe8fb19SBen Gras int
res_queriesmatch(const u_char * buf1,const u_char * eom1,const u_char * buf2,const u_char * eom2)3032fe8fb19SBen Gras res_queriesmatch(const u_char *buf1, const u_char *eom1,
3042fe8fb19SBen Gras const u_char *buf2, const u_char *eom2)
3052fe8fb19SBen Gras {
3062fe8fb19SBen Gras const u_char *cp = buf1 + HFIXEDSZ;
3072fe8fb19SBen Gras int qdcount = ntohs(((const HEADER*)(const void *)buf1)->qdcount);
3082fe8fb19SBen Gras
3092fe8fb19SBen Gras if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
3102fe8fb19SBen Gras return (-1);
3112fe8fb19SBen Gras
3122fe8fb19SBen Gras /*
3132fe8fb19SBen Gras * Only header section present in replies to
3142fe8fb19SBen Gras * dynamic update packets.
3152fe8fb19SBen Gras */
3162fe8fb19SBen Gras if ((((const HEADER *)(const void *)buf1)->opcode == ns_o_update) &&
3172fe8fb19SBen Gras (((const HEADER *)(const void *)buf2)->opcode == ns_o_update))
3182fe8fb19SBen Gras return (1);
3192fe8fb19SBen Gras
3202fe8fb19SBen Gras if (qdcount != ntohs(((const HEADER*)(const void *)buf2)->qdcount))
3212fe8fb19SBen Gras return (0);
3222fe8fb19SBen Gras while (qdcount-- > 0) {
3232fe8fb19SBen Gras char tname[MAXDNAME+1];
3242fe8fb19SBen Gras int n, ttype, tclass;
3252fe8fb19SBen Gras
326f14fb602SLionel Sambuc n = dn_expand(buf1, eom1, cp, tname, (int)sizeof tname);
3272fe8fb19SBen Gras if (n < 0)
3282fe8fb19SBen Gras return (-1);
3292fe8fb19SBen Gras cp += n;
3302fe8fb19SBen Gras if (cp + 2 * INT16SZ > eom1)
3312fe8fb19SBen Gras return (-1);
3322fe8fb19SBen Gras ttype = ns_get16(cp); cp += INT16SZ;
3332fe8fb19SBen Gras tclass = ns_get16(cp); cp += INT16SZ;
3342fe8fb19SBen Gras if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
3352fe8fb19SBen Gras return (0);
3362fe8fb19SBen Gras }
3372fe8fb19SBen Gras return (1);
3382fe8fb19SBen Gras }
3392fe8fb19SBen Gras
3402fe8fb19SBen Gras int
res_nsend(res_state statp,const u_char * buf,int buflen,u_char * ans,int anssiz)3412fe8fb19SBen Gras res_nsend(res_state statp,
3422fe8fb19SBen Gras const u_char *buf, int buflen, u_char *ans, int anssiz)
3432fe8fb19SBen Gras {
3442fe8fb19SBen Gras int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n;
34584d9c625SLionel Sambuc #ifdef USE_KQUEUE
34684d9c625SLionel Sambuc int kq;
34784d9c625SLionel Sambuc #endif
3482fe8fb19SBen Gras char abuf[NI_MAXHOST];
3492fe8fb19SBen Gras
3502fe8fb19SBen Gras (void)res_check(statp, NULL);
3512fe8fb19SBen Gras
3522fe8fb19SBen Gras /* No name servers or res_init() failure */
3532fe8fb19SBen Gras if (statp->nscount == 0 || EXT(statp).ext == NULL) {
3542fe8fb19SBen Gras errno = ESRCH;
3552fe8fb19SBen Gras return (-1);
3562fe8fb19SBen Gras }
3572fe8fb19SBen Gras if (anssiz < HFIXEDSZ) {
3582fe8fb19SBen Gras errno = EINVAL;
3592fe8fb19SBen Gras return (-1);
3602fe8fb19SBen Gras }
3612fe8fb19SBen Gras DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY),
3622fe8fb19SBen Gras (stdout, ";; res_send()\n"), buf, buflen);
3632fe8fb19SBen Gras v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
3642fe8fb19SBen Gras gotsomewhere = 0;
3652fe8fb19SBen Gras terrno = ETIMEDOUT;
3662fe8fb19SBen Gras
36784d9c625SLionel Sambuc #ifdef USE_KQUEUE
36884d9c625SLionel Sambuc if ((kq = kqueue1(O_CLOEXEC)) == -1) {
36984d9c625SLionel Sambuc return (-1);
37084d9c625SLionel Sambuc }
37184d9c625SLionel Sambuc #endif
37284d9c625SLionel Sambuc
3732fe8fb19SBen Gras /*
3742fe8fb19SBen Gras * If the ns_addr_list in the resolver context has changed, then
3752fe8fb19SBen Gras * invalidate our cached copy and the associated timing data.
3762fe8fb19SBen Gras */
3772fe8fb19SBen Gras if (EXT(statp).nscount != 0) {
3782fe8fb19SBen Gras int needclose = 0;
3792fe8fb19SBen Gras struct sockaddr_storage peer;
3802fe8fb19SBen Gras ISC_SOCKLEN_T peerlen;
3812fe8fb19SBen Gras
3822fe8fb19SBen Gras if (EXT(statp).nscount != statp->nscount)
3832fe8fb19SBen Gras needclose++;
3842fe8fb19SBen Gras else
3852fe8fb19SBen Gras for (ns = 0; ns < statp->nscount; ns++) {
3862fe8fb19SBen Gras if (statp->nsaddr_list[ns].sin_family &&
3872fe8fb19SBen Gras !sock_eq((struct sockaddr *)(void *)&statp->nsaddr_list[ns],
3882fe8fb19SBen Gras (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[ns])) {
3892fe8fb19SBen Gras needclose++;
3902fe8fb19SBen Gras break;
3912fe8fb19SBen Gras }
3922fe8fb19SBen Gras
3932fe8fb19SBen Gras if (EXT(statp).nssocks[ns] == -1)
3942fe8fb19SBen Gras continue;
3952fe8fb19SBen Gras peerlen = sizeof(peer);
3962fe8fb19SBen Gras if (getpeername(EXT(statp).nssocks[ns],
3972fe8fb19SBen Gras (struct sockaddr *)(void *)&peer, &peerlen) < 0) {
3982fe8fb19SBen Gras needclose++;
3992fe8fb19SBen Gras break;
4002fe8fb19SBen Gras }
4012fe8fb19SBen Gras if (!sock_eq((struct sockaddr *)(void *)&peer,
4022fe8fb19SBen Gras get_nsaddr(statp, (size_t)ns))) {
4032fe8fb19SBen Gras needclose++;
4042fe8fb19SBen Gras break;
4052fe8fb19SBen Gras }
4062fe8fb19SBen Gras }
4072fe8fb19SBen Gras if (needclose) {
4082fe8fb19SBen Gras res_nclose(statp);
4092fe8fb19SBen Gras EXT(statp).nscount = 0;
4102fe8fb19SBen Gras }
4112fe8fb19SBen Gras }
4122fe8fb19SBen Gras
4132fe8fb19SBen Gras /*
4142fe8fb19SBen Gras * Maybe initialize our private copy of the ns_addr_list.
4152fe8fb19SBen Gras */
4162fe8fb19SBen Gras if (EXT(statp).nscount == 0) {
4172fe8fb19SBen Gras for (ns = 0; ns < statp->nscount; ns++) {
4182fe8fb19SBen Gras EXT(statp).nstimes[ns] = RES_MAXTIME;
4192fe8fb19SBen Gras EXT(statp).nssocks[ns] = -1;
4202fe8fb19SBen Gras if (!statp->nsaddr_list[ns].sin_family)
4212fe8fb19SBen Gras continue;
4222fe8fb19SBen Gras EXT(statp).ext->nsaddrs[ns].sin =
4232fe8fb19SBen Gras statp->nsaddr_list[ns];
4242fe8fb19SBen Gras }
4252fe8fb19SBen Gras EXT(statp).nscount = statp->nscount;
4262fe8fb19SBen Gras }
4272fe8fb19SBen Gras
4282fe8fb19SBen Gras /*
4292fe8fb19SBen Gras * Some resolvers want to even out the load on their nameservers.
4302fe8fb19SBen Gras * Note that RES_BLAST overrides RES_ROTATE.
4312fe8fb19SBen Gras */
4322fe8fb19SBen Gras if ((statp->options & RES_ROTATE) != 0U &&
4332fe8fb19SBen Gras (statp->options & RES_BLAST) == 0U) {
4342fe8fb19SBen Gras union res_sockaddr_union inu;
4352fe8fb19SBen Gras struct sockaddr_in ina;
4362fe8fb19SBen Gras int lastns = statp->nscount - 1;
4372fe8fb19SBen Gras int fd;
4382fe8fb19SBen Gras u_int16_t nstime;
4392fe8fb19SBen Gras
4402fe8fb19SBen Gras if (EXT(statp).ext != NULL)
4412fe8fb19SBen Gras inu = EXT(statp).ext->nsaddrs[0];
4422fe8fb19SBen Gras ina = statp->nsaddr_list[0];
4432fe8fb19SBen Gras fd = EXT(statp).nssocks[0];
4442fe8fb19SBen Gras nstime = EXT(statp).nstimes[0];
4452fe8fb19SBen Gras for (ns = 0; ns < lastns; ns++) {
4462fe8fb19SBen Gras if (EXT(statp).ext != NULL)
4472fe8fb19SBen Gras EXT(statp).ext->nsaddrs[ns] =
4482fe8fb19SBen Gras EXT(statp).ext->nsaddrs[ns + 1];
4492fe8fb19SBen Gras statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
4502fe8fb19SBen Gras EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1];
4512fe8fb19SBen Gras EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1];
4522fe8fb19SBen Gras }
4532fe8fb19SBen Gras if (EXT(statp).ext != NULL)
4542fe8fb19SBen Gras EXT(statp).ext->nsaddrs[lastns] = inu;
4552fe8fb19SBen Gras statp->nsaddr_list[lastns] = ina;
4562fe8fb19SBen Gras EXT(statp).nssocks[lastns] = fd;
4572fe8fb19SBen Gras EXT(statp).nstimes[lastns] = nstime;
4582fe8fb19SBen Gras }
4592fe8fb19SBen Gras
4602fe8fb19SBen Gras /*
4612fe8fb19SBen Gras * Send request, RETRY times, or until successful.
4622fe8fb19SBen Gras */
4632fe8fb19SBen Gras for (tries = 0; tries < statp->retry; tries++) {
4642fe8fb19SBen Gras for (ns = 0; ns < statp->nscount; ns++) {
4652fe8fb19SBen Gras struct sockaddr *nsap;
46684d9c625SLionel Sambuc socklen_t nsaplen;
4672fe8fb19SBen Gras nsap = get_nsaddr(statp, (size_t)ns);
4682fe8fb19SBen Gras nsaplen = get_salen(nsap);
4692fe8fb19SBen Gras statp->_flags &= ~RES_F_LASTMASK;
4702fe8fb19SBen Gras statp->_flags |= (ns << RES_F_LASTSHIFT);
4712fe8fb19SBen Gras same_ns:
4722fe8fb19SBen Gras if (statp->qhook) {
4732fe8fb19SBen Gras int done = 0, loops = 0;
4742fe8fb19SBen Gras
4752fe8fb19SBen Gras do {
4762fe8fb19SBen Gras res_sendhookact act;
4772fe8fb19SBen Gras
4782fe8fb19SBen Gras act = (*statp->qhook)(&nsap, &buf, &buflen,
4792fe8fb19SBen Gras ans, anssiz, &resplen);
4802fe8fb19SBen Gras switch (act) {
4812fe8fb19SBen Gras case res_goahead:
4822fe8fb19SBen Gras done = 1;
4832fe8fb19SBen Gras break;
4842fe8fb19SBen Gras case res_nextns:
4852fe8fb19SBen Gras res_nclose(statp);
4862fe8fb19SBen Gras goto next_ns;
4872fe8fb19SBen Gras case res_done:
48884d9c625SLionel Sambuc #ifdef USE_KQUEUE
48984d9c625SLionel Sambuc close(kq);
49084d9c625SLionel Sambuc #endif
4912fe8fb19SBen Gras return (resplen);
4922fe8fb19SBen Gras case res_modified:
4932fe8fb19SBen Gras /* give the hook another try */
4942fe8fb19SBen Gras if (++loops < 42) /*doug adams*/
4952fe8fb19SBen Gras break;
4962fe8fb19SBen Gras /*FALLTHROUGH*/
4972fe8fb19SBen Gras case res_error:
4982fe8fb19SBen Gras /*FALLTHROUGH*/
4992fe8fb19SBen Gras default:
5002fe8fb19SBen Gras goto fail;
5012fe8fb19SBen Gras }
5022fe8fb19SBen Gras } while (!done);
5032fe8fb19SBen Gras }
5042fe8fb19SBen Gras
5052fe8fb19SBen Gras Dprint(((statp->options & RES_DEBUG) &&
50684d9c625SLionel Sambuc getnameinfo(nsap, nsaplen, abuf,
507f14fb602SLionel Sambuc (socklen_t)sizeof(abuf), NULL, 0, niflags) == 0),
5082fe8fb19SBen Gras (stdout, ";; Querying server (# %d) address = %s\n",
5092fe8fb19SBen Gras ns + 1, abuf));
5102fe8fb19SBen Gras
5112fe8fb19SBen Gras
5122fe8fb19SBen Gras if (v_circuit) {
5132fe8fb19SBen Gras /* Use VC; at most one attempt per server. */
5142fe8fb19SBen Gras tries = statp->retry;
51584d9c625SLionel Sambuc n = send_vc(statp, buf, (size_t)buflen, ans, anssiz, &terrno,
5162fe8fb19SBen Gras ns);
5172fe8fb19SBen Gras if (n < 0)
5182fe8fb19SBen Gras goto fail;
5192fe8fb19SBen Gras if (n == 0)
5202fe8fb19SBen Gras goto next_ns;
5212fe8fb19SBen Gras resplen = n;
5222fe8fb19SBen Gras } else {
5232fe8fb19SBen Gras /* Use datagrams. */
52484d9c625SLionel Sambuc n = send_dg(statp,
52584d9c625SLionel Sambuc #ifdef USE_KQUEUE
52684d9c625SLionel Sambuc kq,
52784d9c625SLionel Sambuc #endif
52884d9c625SLionel Sambuc buf, (size_t)buflen, ans, anssiz, &terrno,
5292fe8fb19SBen Gras ns, tries, &v_circuit, &gotsomewhere);
5302fe8fb19SBen Gras if (n < 0)
5312fe8fb19SBen Gras goto fail;
5322fe8fb19SBen Gras if (n == 0)
5332fe8fb19SBen Gras goto next_ns;
5342fe8fb19SBen Gras if (v_circuit)
5352fe8fb19SBen Gras goto same_ns;
5362fe8fb19SBen Gras resplen = n;
5372fe8fb19SBen Gras }
5382fe8fb19SBen Gras
5392fe8fb19SBen Gras Dprint((statp->options & RES_DEBUG) ||
5402fe8fb19SBen Gras ((statp->pfcode & RES_PRF_REPLY) &&
5412fe8fb19SBen Gras (statp->pfcode & RES_PRF_HEAD1)),
5422fe8fb19SBen Gras (stdout, ";; got answer:\n"));
5432fe8fb19SBen Gras
5442fe8fb19SBen Gras DprintQ((statp->options & RES_DEBUG) ||
5452fe8fb19SBen Gras (statp->pfcode & RES_PRF_REPLY),
5462fe8fb19SBen Gras (stdout, "%s", ""),
5472fe8fb19SBen Gras ans, (resplen > anssiz) ? anssiz : resplen);
5482fe8fb19SBen Gras
5492fe8fb19SBen Gras /*
5502fe8fb19SBen Gras * If we have temporarily opened a virtual circuit,
5512fe8fb19SBen Gras * or if we haven't been asked to keep a socket open,
5522fe8fb19SBen Gras * close the socket.
5532fe8fb19SBen Gras */
5542fe8fb19SBen Gras if ((v_circuit && (statp->options & RES_USEVC) == 0U) ||
5552fe8fb19SBen Gras (statp->options & RES_STAYOPEN) == 0U) {
5562fe8fb19SBen Gras res_nclose(statp);
5572fe8fb19SBen Gras }
5582fe8fb19SBen Gras if (statp->rhook) {
5592fe8fb19SBen Gras int done = 0, loops = 0;
5602fe8fb19SBen Gras
5612fe8fb19SBen Gras do {
5622fe8fb19SBen Gras res_sendhookact act;
5632fe8fb19SBen Gras
5642fe8fb19SBen Gras act = (*statp->rhook)(nsap, buf, buflen,
5652fe8fb19SBen Gras ans, anssiz, &resplen);
5662fe8fb19SBen Gras switch (act) {
5672fe8fb19SBen Gras case res_goahead:
5682fe8fb19SBen Gras case res_done:
5692fe8fb19SBen Gras done = 1;
5702fe8fb19SBen Gras break;
5712fe8fb19SBen Gras case res_nextns:
5722fe8fb19SBen Gras res_nclose(statp);
5732fe8fb19SBen Gras goto next_ns;
5742fe8fb19SBen Gras case res_modified:
5752fe8fb19SBen Gras /* give the hook another try */
5762fe8fb19SBen Gras if (++loops < 42) /*doug adams*/
5772fe8fb19SBen Gras break;
5782fe8fb19SBen Gras /*FALLTHROUGH*/
5792fe8fb19SBen Gras case res_error:
5802fe8fb19SBen Gras /*FALLTHROUGH*/
5812fe8fb19SBen Gras default:
5822fe8fb19SBen Gras goto fail;
5832fe8fb19SBen Gras }
5842fe8fb19SBen Gras } while (!done);
5852fe8fb19SBen Gras
5862fe8fb19SBen Gras }
58784d9c625SLionel Sambuc #ifdef USE_KQUEUE
58884d9c625SLionel Sambuc close(kq);
58984d9c625SLionel Sambuc #endif
5902fe8fb19SBen Gras return (resplen);
5912fe8fb19SBen Gras next_ns: ;
5922fe8fb19SBen Gras } /*foreach ns*/
5932fe8fb19SBen Gras } /*foreach retry*/
5942fe8fb19SBen Gras res_nclose(statp);
59584d9c625SLionel Sambuc #ifdef USE_KQUEUE
59684d9c625SLionel Sambuc close(kq);
59784d9c625SLionel Sambuc #endif
5982fe8fb19SBen Gras if (!v_circuit) {
5992fe8fb19SBen Gras if (!gotsomewhere)
6002fe8fb19SBen Gras errno = ECONNREFUSED; /*%< no nameservers found */
6012fe8fb19SBen Gras else
6022fe8fb19SBen Gras errno = ETIMEDOUT; /*%< no answer obtained */
6032fe8fb19SBen Gras } else
6042fe8fb19SBen Gras errno = terrno;
6052fe8fb19SBen Gras return (-1);
6062fe8fb19SBen Gras fail:
6072fe8fb19SBen Gras res_nclose(statp);
60884d9c625SLionel Sambuc #ifdef USE_KQUEUE
60984d9c625SLionel Sambuc close(kq);
61084d9c625SLionel Sambuc #endif
6112fe8fb19SBen Gras return (-1);
6122fe8fb19SBen Gras }
6132fe8fb19SBen Gras
6142fe8fb19SBen Gras /* Private */
6152fe8fb19SBen Gras
61684d9c625SLionel Sambuc static socklen_t
get_salen(const struct sockaddr * sa)617f14fb602SLionel Sambuc get_salen(const struct sockaddr *sa)
6182fe8fb19SBen Gras {
6192fe8fb19SBen Gras
6202fe8fb19SBen Gras #ifdef HAVE_SA_LEN
6212fe8fb19SBen Gras /* There are people do not set sa_len. Be forgiving to them. */
6222fe8fb19SBen Gras if (sa->sa_len)
62384d9c625SLionel Sambuc return (socklen_t)sa->sa_len;
6242fe8fb19SBen Gras #endif
6252fe8fb19SBen Gras
6262fe8fb19SBen Gras if (sa->sa_family == AF_INET)
62784d9c625SLionel Sambuc return (socklen_t)sizeof(struct sockaddr_in);
6282fe8fb19SBen Gras else if (sa->sa_family == AF_INET6)
62984d9c625SLionel Sambuc return (socklen_t)sizeof(struct sockaddr_in6);
6302fe8fb19SBen Gras else
63184d9c625SLionel Sambuc return 0; /*%< unknown, die on connect */
6322fe8fb19SBen Gras }
6332fe8fb19SBen Gras
6342fe8fb19SBen Gras /*%
6352fe8fb19SBen Gras * pick appropriate nsaddr_list for use. see res_init() for initialization.
6362fe8fb19SBen Gras */
6372fe8fb19SBen Gras static struct sockaddr *
get_nsaddr(res_state statp,size_t n)638f14fb602SLionel Sambuc get_nsaddr(res_state statp, size_t n)
6392fe8fb19SBen Gras {
6402fe8fb19SBen Gras
6412fe8fb19SBen Gras if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) {
6422fe8fb19SBen Gras /*
6432fe8fb19SBen Gras * - EXT(statp).ext->nsaddrs[n] holds an address that is larger
6442fe8fb19SBen Gras * than struct sockaddr, and
6452fe8fb19SBen Gras * - user code did not update statp->nsaddr_list[n].
6462fe8fb19SBen Gras */
6472fe8fb19SBen Gras return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n];
6482fe8fb19SBen Gras } else {
6492fe8fb19SBen Gras /*
6502fe8fb19SBen Gras * - user code updated statp->nsaddr_list[n], or
6512fe8fb19SBen Gras * - statp->nsaddr_list[n] has the same content as
6522fe8fb19SBen Gras * EXT(statp).ext->nsaddrs[n].
6532fe8fb19SBen Gras */
6542fe8fb19SBen Gras return (struct sockaddr *)(void *)&statp->nsaddr_list[n];
6552fe8fb19SBen Gras }
6562fe8fb19SBen Gras }
6572fe8fb19SBen Gras
6582fe8fb19SBen Gras static int
send_vc(res_state statp,const void * buf,size_t buflen,u_char * ans,int anssiz,int * terrno,int ns)6592fe8fb19SBen Gras send_vc(res_state statp,
66084d9c625SLionel Sambuc const void *buf, size_t buflen, u_char *ans, int anssiz,
6612fe8fb19SBen Gras int *terrno, int ns)
6622fe8fb19SBen Gras {
6632fe8fb19SBen Gras const HEADER *hp = (const HEADER *)(const void *)buf;
6642fe8fb19SBen Gras HEADER *anhp = (HEADER *)(void *)ans;
6652fe8fb19SBen Gras struct sockaddr *nsap;
66684d9c625SLionel Sambuc socklen_t nsaplen;
667f14fb602SLionel Sambuc int truncating, connreset, resplen;
668f14fb602SLionel Sambuc ssize_t n;
6692fe8fb19SBen Gras struct iovec iov[2];
6702fe8fb19SBen Gras u_short len;
6712fe8fb19SBen Gras u_char *cp;
6722fe8fb19SBen Gras void *tmp;
67384d9c625SLionel Sambuc #if defined(SO_NOSIGPIPE) && SOCK_NOSIGPIPE == 0
6742fe8fb19SBen Gras int on = 1;
6752fe8fb19SBen Gras #endif
6762fe8fb19SBen Gras
6772fe8fb19SBen Gras nsap = get_nsaddr(statp, (size_t)ns);
6782fe8fb19SBen Gras nsaplen = get_salen(nsap);
6792fe8fb19SBen Gras
6802fe8fb19SBen Gras connreset = 0;
6812fe8fb19SBen Gras same_ns:
6822fe8fb19SBen Gras truncating = 0;
6832fe8fb19SBen Gras
6842fe8fb19SBen Gras /* Are we still talking to whom we want to talk to? */
6852fe8fb19SBen Gras if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) {
6862fe8fb19SBen Gras struct sockaddr_storage peer;
6872fe8fb19SBen Gras ISC_SOCKLEN_T size = sizeof peer;
6882fe8fb19SBen Gras
6892fe8fb19SBen Gras if (getpeername(statp->_vcsock,
6902fe8fb19SBen Gras (struct sockaddr *)(void *)&peer, &size) < 0 ||
6912fe8fb19SBen Gras !sock_eq((struct sockaddr *)(void *)&peer, nsap)) {
6922fe8fb19SBen Gras res_nclose(statp);
6932fe8fb19SBen Gras statp->_flags &= ~RES_F_VC;
6942fe8fb19SBen Gras }
6952fe8fb19SBen Gras }
6962fe8fb19SBen Gras
6972fe8fb19SBen Gras if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) {
6982fe8fb19SBen Gras if (statp->_vcsock >= 0)
6992fe8fb19SBen Gras res_nclose(statp);
7002fe8fb19SBen Gras
70184d9c625SLionel Sambuc statp->_vcsock = socket(nsap->sa_family, SOCK_STREAM
70284d9c625SLionel Sambuc | SOCK_NOSIGPIPE | SOCK_CLOEXEC, 0);
70384d9c625SLionel Sambuc #if SOCK_CLOEXEC == 0
70484d9c625SLionel Sambuc fcntl(statp->_vcsock, F_SETFD, FD_CLOEXEC);
70584d9c625SLionel Sambuc #endif
70684d9c625SLionel Sambuc #if !defined(USE_POLL) && !defined(USE_KQUEUE)
7072fe8fb19SBen Gras if (statp->_vcsock > highestFD) {
7082fe8fb19SBen Gras res_nclose(statp);
7092fe8fb19SBen Gras errno = ENOTSOCK;
7102fe8fb19SBen Gras }
711f14fb602SLionel Sambuc #endif
7122fe8fb19SBen Gras if (statp->_vcsock < 0) {
7132fe8fb19SBen Gras switch (errno) {
7142fe8fb19SBen Gras case EPROTONOSUPPORT:
7152fe8fb19SBen Gras #ifdef EPFNOSUPPORT
7162fe8fb19SBen Gras case EPFNOSUPPORT:
7172fe8fb19SBen Gras #endif
7182fe8fb19SBen Gras case EAFNOSUPPORT:
7192fe8fb19SBen Gras Perror(statp, stderr, "socket(vc)", errno);
7202fe8fb19SBen Gras return (0);
7212fe8fb19SBen Gras default:
7222fe8fb19SBen Gras *terrno = errno;
7232fe8fb19SBen Gras Perror(statp, stderr, "socket(vc)", errno);
7242fe8fb19SBen Gras return (-1);
7252fe8fb19SBen Gras }
7262fe8fb19SBen Gras }
72784d9c625SLionel Sambuc #if defined(SO_NOSIGPIPE) && SOCK_NOSIGPIPE == 0
7282fe8fb19SBen Gras /*
7292fe8fb19SBen Gras * Disable generation of SIGPIPE when writing to a closed
7302fe8fb19SBen Gras * socket. Write should return -1 and set errno to EPIPE
7312fe8fb19SBen Gras * instead.
7322fe8fb19SBen Gras *
7332fe8fb19SBen Gras * Push on even if setsockopt(SO_NOSIGPIPE) fails.
7342fe8fb19SBen Gras */
7352fe8fb19SBen Gras (void)setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on,
73684d9c625SLionel Sambuc (socklen_t)sizeof(on));
7372fe8fb19SBen Gras #endif
7382fe8fb19SBen Gras errno = 0;
73984d9c625SLionel Sambuc if (connect(statp->_vcsock, nsap, nsaplen) < 0) {
7402fe8fb19SBen Gras *terrno = errno;
7412fe8fb19SBen Gras Aerror(statp, stderr, "connect/vc", errno, nsap,
7422fe8fb19SBen Gras nsaplen);
7432fe8fb19SBen Gras res_nclose(statp);
7442fe8fb19SBen Gras return (0);
7452fe8fb19SBen Gras }
7462fe8fb19SBen Gras statp->_flags |= RES_F_VC;
7472fe8fb19SBen Gras }
7482fe8fb19SBen Gras
7492fe8fb19SBen Gras /*
7502fe8fb19SBen Gras * Send length & message
7512fe8fb19SBen Gras */
7522fe8fb19SBen Gras ns_put16((u_short)buflen, (u_char*)(void *)&len);
7532fe8fb19SBen Gras iov[0] = evConsIovec(&len, INT16SZ);
7542fe8fb19SBen Gras DE_CONST(buf, tmp);
7552fe8fb19SBen Gras iov[1] = evConsIovec(tmp, (size_t)buflen);
75684d9c625SLionel Sambuc if (writev(statp->_vcsock, iov, 2) != (ssize_t)(INT16SZ + buflen)) {
7572fe8fb19SBen Gras *terrno = errno;
7582fe8fb19SBen Gras Perror(statp, stderr, "write failed", errno);
7592fe8fb19SBen Gras res_nclose(statp);
7602fe8fb19SBen Gras return (0);
7612fe8fb19SBen Gras }
7622fe8fb19SBen Gras /*
7632fe8fb19SBen Gras * Receive length & response
7642fe8fb19SBen Gras */
7652fe8fb19SBen Gras read_len:
7662fe8fb19SBen Gras cp = ans;
7672fe8fb19SBen Gras len = INT16SZ;
7682fe8fb19SBen Gras while ((n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0) {
7692fe8fb19SBen Gras cp += n;
770f14fb602SLionel Sambuc if ((len -= (u_short)n) == 0)
7712fe8fb19SBen Gras break;
7722fe8fb19SBen Gras }
7732fe8fb19SBen Gras if (n <= 0) {
7742fe8fb19SBen Gras *terrno = errno;
7752fe8fb19SBen Gras Perror(statp, stderr, "read failed", errno);
7762fe8fb19SBen Gras res_nclose(statp);
7772fe8fb19SBen Gras /*
7782fe8fb19SBen Gras * A long running process might get its TCP
7792fe8fb19SBen Gras * connection reset if the remote server was
7802fe8fb19SBen Gras * restarted. Requery the server instead of
7812fe8fb19SBen Gras * trying a new one. When there is only one
7822fe8fb19SBen Gras * server, this means that a query might work
7832fe8fb19SBen Gras * instead of failing. We only allow one reset
7842fe8fb19SBen Gras * per query to prevent looping.
7852fe8fb19SBen Gras */
7862fe8fb19SBen Gras if (*terrno == ECONNRESET && !connreset) {
7872fe8fb19SBen Gras connreset = 1;
7882fe8fb19SBen Gras res_nclose(statp);
7892fe8fb19SBen Gras goto same_ns;
7902fe8fb19SBen Gras }
7912fe8fb19SBen Gras res_nclose(statp);
7922fe8fb19SBen Gras return (0);
7932fe8fb19SBen Gras }
7942fe8fb19SBen Gras resplen = ns_get16(ans);
7952fe8fb19SBen Gras if (resplen > anssiz) {
7962fe8fb19SBen Gras Dprint(statp->options & RES_DEBUG,
7972fe8fb19SBen Gras (stdout, ";; response truncated\n")
7982fe8fb19SBen Gras );
7992fe8fb19SBen Gras truncating = 1;
8002fe8fb19SBen Gras len = anssiz;
8012fe8fb19SBen Gras } else
8022fe8fb19SBen Gras len = resplen;
8032fe8fb19SBen Gras if (len < HFIXEDSZ) {
8042fe8fb19SBen Gras /*
8052fe8fb19SBen Gras * Undersized message.
8062fe8fb19SBen Gras */
8072fe8fb19SBen Gras Dprint(statp->options & RES_DEBUG,
8082fe8fb19SBen Gras (stdout, ";; undersized: %d\n", len));
8092fe8fb19SBen Gras *terrno = EMSGSIZE;
8102fe8fb19SBen Gras res_nclose(statp);
8112fe8fb19SBen Gras return (0);
8122fe8fb19SBen Gras }
8132fe8fb19SBen Gras cp = ans;
8142fe8fb19SBen Gras while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (size_t)len)) > 0){
8152fe8fb19SBen Gras cp += n;
816f14fb602SLionel Sambuc len -= (u_short)n;
8172fe8fb19SBen Gras }
8182fe8fb19SBen Gras if (n <= 0) {
8192fe8fb19SBen Gras *terrno = errno;
8202fe8fb19SBen Gras Perror(statp, stderr, "read(vc)", errno);
8212fe8fb19SBen Gras res_nclose(statp);
8222fe8fb19SBen Gras return (0);
8232fe8fb19SBen Gras }
8242fe8fb19SBen Gras if (truncating) {
8252fe8fb19SBen Gras /*
8262fe8fb19SBen Gras * Flush rest of answer so connection stays in synch.
8272fe8fb19SBen Gras */
8282fe8fb19SBen Gras anhp->tc = 1;
8292fe8fb19SBen Gras len = resplen - anssiz;
8302fe8fb19SBen Gras while (len != 0) {
8312fe8fb19SBen Gras char junk[PACKETSZ];
8322fe8fb19SBen Gras
8332fe8fb19SBen Gras n = read(statp->_vcsock, junk,
8342fe8fb19SBen Gras (len > sizeof junk) ? sizeof junk : len);
8352fe8fb19SBen Gras if (n > 0)
836f14fb602SLionel Sambuc len -= (u_short)n;
8372fe8fb19SBen Gras else
8382fe8fb19SBen Gras break;
8392fe8fb19SBen Gras }
8402fe8fb19SBen Gras }
8412fe8fb19SBen Gras /*
8422fe8fb19SBen Gras * If the calling applicating has bailed out of
8432fe8fb19SBen Gras * a previous call and failed to arrange to have
8442fe8fb19SBen Gras * the circuit closed or the server has got
8452fe8fb19SBen Gras * itself confused, then drop the packet and
8462fe8fb19SBen Gras * wait for the correct one.
8472fe8fb19SBen Gras */
8482fe8fb19SBen Gras if (hp->id != anhp->id) {
8492fe8fb19SBen Gras DprintQ((statp->options & RES_DEBUG) ||
8502fe8fb19SBen Gras (statp->pfcode & RES_PRF_REPLY),
8512fe8fb19SBen Gras (stdout, ";; old answer (unexpected):\n"),
8522fe8fb19SBen Gras ans, (resplen > anssiz) ? anssiz: resplen);
8532fe8fb19SBen Gras goto read_len;
8542fe8fb19SBen Gras }
8552fe8fb19SBen Gras
8562fe8fb19SBen Gras /*
8572fe8fb19SBen Gras * All is well, or the error is fatal. Signal that the
8582fe8fb19SBen Gras * next nameserver ought not be tried.
8592fe8fb19SBen Gras */
8602fe8fb19SBen Gras return (resplen);
8612fe8fb19SBen Gras }
8622fe8fb19SBen Gras
8632fe8fb19SBen Gras 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)86484d9c625SLionel Sambuc send_dg(res_state statp,
86584d9c625SLionel Sambuc #ifdef USE_KQUEUE
86684d9c625SLionel Sambuc int kq,
86784d9c625SLionel Sambuc #endif
86884d9c625SLionel Sambuc const void *buf, size_t buflen, u_char *ans,
8692fe8fb19SBen Gras int anssiz, int *terrno, int ns, int tries, int *v_circuit,
8702fe8fb19SBen Gras int *gotsomewhere)
8712fe8fb19SBen Gras {
8722fe8fb19SBen Gras const HEADER *hp = (const HEADER *)(const void *)buf;
8732fe8fb19SBen Gras HEADER *anhp = (HEADER *)(void *)ans;
8742fe8fb19SBen Gras const struct sockaddr *nsap;
87584d9c625SLionel Sambuc socklen_t nsaplen;
8762fe8fb19SBen Gras struct timespec now, timeout, finish;
8772fe8fb19SBen Gras struct sockaddr_storage from;
8782fe8fb19SBen Gras ISC_SOCKLEN_T fromlen;
879f14fb602SLionel Sambuc ssize_t resplen;
880f14fb602SLionel Sambuc int seconds, n, s;
88184d9c625SLionel Sambuc #ifdef USE_KQUEUE
88284d9c625SLionel Sambuc struct kevent kv;
88384d9c625SLionel Sambuc #else
8842fe8fb19SBen Gras #ifdef USE_POLL
8852fe8fb19SBen Gras int polltimeout;
8862fe8fb19SBen Gras struct pollfd pollfd;
8872fe8fb19SBen Gras #else
8882fe8fb19SBen Gras fd_set dsmask;
8892fe8fb19SBen Gras #endif
89084d9c625SLionel Sambuc #endif
8912fe8fb19SBen Gras
8922fe8fb19SBen Gras nsap = get_nsaddr(statp, (size_t)ns);
8932fe8fb19SBen Gras nsaplen = get_salen(nsap);
8942fe8fb19SBen Gras if (EXT(statp).nssocks[ns] == -1) {
89584d9c625SLionel Sambuc EXT(statp).nssocks[ns] = socket(nsap->sa_family, SOCK_DGRAM
89684d9c625SLionel Sambuc | SOCK_CLOEXEC, 0);
89784d9c625SLionel Sambuc #if SOCK_CLOEXEC == 0
89884d9c625SLionel Sambuc fcntl(EXT(statp)nssocks[ns], F_SETFD, FD_CLOEXEC);
89984d9c625SLionel Sambuc #endif
90084d9c625SLionel Sambuc #if !defined(USE_POLL) && !defined(USE_KQUEUE)
9012fe8fb19SBen Gras if (EXT(statp).nssocks[ns] > highestFD) {
9022fe8fb19SBen Gras res_nclose(statp);
9032fe8fb19SBen Gras errno = ENOTSOCK;
9042fe8fb19SBen Gras }
905f14fb602SLionel Sambuc #endif
9062fe8fb19SBen Gras if (EXT(statp).nssocks[ns] < 0) {
9072fe8fb19SBen Gras switch (errno) {
9082fe8fb19SBen Gras case EPROTONOSUPPORT:
9092fe8fb19SBen Gras #ifdef EPFNOSUPPORT
9102fe8fb19SBen Gras case EPFNOSUPPORT:
9112fe8fb19SBen Gras #endif
9122fe8fb19SBen Gras case EAFNOSUPPORT:
9132fe8fb19SBen Gras Perror(statp, stderr, "socket(dg)", errno);
9142fe8fb19SBen Gras return (0);
9152fe8fb19SBen Gras default:
9162fe8fb19SBen Gras *terrno = errno;
9172fe8fb19SBen Gras Perror(statp, stderr, "socket(dg)", errno);
9182fe8fb19SBen Gras return (-1);
9192fe8fb19SBen Gras }
9202fe8fb19SBen Gras }
9212fe8fb19SBen Gras #ifndef CANNOT_CONNECT_DGRAM
9222fe8fb19SBen Gras /*
9232fe8fb19SBen Gras * On a 4.3BSD+ machine (client and server,
9242fe8fb19SBen Gras * actually), sending to a nameserver datagram
9252fe8fb19SBen Gras * port with no nameserver will cause an
9262fe8fb19SBen Gras * ICMP port unreachable message to be returned.
9272fe8fb19SBen Gras * If our datagram socket is "connected" to the
9282fe8fb19SBen Gras * server, we get an ECONNREFUSED error on the next
9292fe8fb19SBen Gras * socket operation, and select returns if the
9302fe8fb19SBen Gras * error message is received. We can thus detect
9312fe8fb19SBen Gras * the absence of a nameserver without timing out.
93284d9c625SLionel Sambuc *
93384d9c625SLionel Sambuc * When the option "insecure1" is specified, we'd
93484d9c625SLionel Sambuc * rather expect to see responses from an "unknown"
93584d9c625SLionel Sambuc * address. In order to let the kernel accept such
93684d9c625SLionel Sambuc * responses, do not connect the socket here.
93784d9c625SLionel Sambuc * XXX: or do we need an explicit option to disable
93884d9c625SLionel Sambuc * connecting?
9392fe8fb19SBen Gras */
94084d9c625SLionel Sambuc if (!(statp->options & RES_INSECURE1) &&
94184d9c625SLionel Sambuc connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) {
9422fe8fb19SBen Gras Aerror(statp, stderr, "connect(dg)", errno, nsap,
9432fe8fb19SBen Gras nsaplen);
9442fe8fb19SBen Gras res_nclose(statp);
9452fe8fb19SBen Gras return (0);
9462fe8fb19SBen Gras }
9472fe8fb19SBen Gras #endif /* !CANNOT_CONNECT_DGRAM */
9482fe8fb19SBen Gras Dprint(statp->options & RES_DEBUG,
9492fe8fb19SBen Gras (stdout, ";; new DG socket\n"))
9502fe8fb19SBen Gras }
9512fe8fb19SBen Gras s = EXT(statp).nssocks[ns];
9522fe8fb19SBen Gras #ifndef CANNOT_CONNECT_DGRAM
95384d9c625SLionel Sambuc if (statp->options & RES_INSECURE1) {
95484d9c625SLionel Sambuc if (sendto(s, buf, buflen, 0, nsap, nsaplen) !=
95584d9c625SLionel Sambuc (ssize_t)buflen) {
95684d9c625SLionel Sambuc Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
95784d9c625SLionel Sambuc res_nclose(statp);
95884d9c625SLionel Sambuc return (0);
95984d9c625SLionel Sambuc }
96084d9c625SLionel Sambuc } else if (send(s, buf, buflen, 0) != (ssize_t)buflen) {
9612fe8fb19SBen Gras Perror(statp, stderr, "send", errno);
9622fe8fb19SBen Gras res_nclose(statp);
9632fe8fb19SBen Gras return (0);
9642fe8fb19SBen Gras }
9652fe8fb19SBen Gras #else /* !CANNOT_CONNECT_DGRAM */
96684d9c625SLionel Sambuc if (sendto(s, buf, buflen, 0, nsap, nsaplen) != (ssize_t)buflen)
9672fe8fb19SBen Gras {
9682fe8fb19SBen Gras Aerror(statp, stderr, "sendto", errno, nsap, nsaplen);
9692fe8fb19SBen Gras res_nclose(statp);
9702fe8fb19SBen Gras return (0);
9712fe8fb19SBen Gras }
9722fe8fb19SBen Gras #endif /* !CANNOT_CONNECT_DGRAM */
9732fe8fb19SBen Gras
9742fe8fb19SBen Gras /*
9752fe8fb19SBen Gras * Wait for reply.
9762fe8fb19SBen Gras */
9772fe8fb19SBen Gras seconds = (statp->retrans << tries);
9782fe8fb19SBen Gras if (ns > 0)
9792fe8fb19SBen Gras seconds /= statp->nscount;
9802fe8fb19SBen Gras if (seconds <= 0)
9812fe8fb19SBen Gras seconds = 1;
9822fe8fb19SBen Gras now = evNowTime();
983f14fb602SLionel Sambuc timeout = evConsTime((time_t)seconds, 0L);
9842fe8fb19SBen Gras finish = evAddTime(now, timeout);
9852fe8fb19SBen Gras goto nonow;
9862fe8fb19SBen Gras wait:
9872fe8fb19SBen Gras now = evNowTime();
9882fe8fb19SBen Gras nonow:
9892fe8fb19SBen Gras #ifndef USE_POLL
9902fe8fb19SBen Gras if (evCmpTime(finish, now) > 0)
9912fe8fb19SBen Gras timeout = evSubTime(finish, now);
9922fe8fb19SBen Gras else
9932fe8fb19SBen Gras timeout = evConsTime(0L, 0L);
99484d9c625SLionel Sambuc #ifdef USE_KQUEUE
99584d9c625SLionel Sambuc EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0);
99684d9c625SLionel Sambuc n = kevent(kq, &kv, 1, &kv, 1, &timeout);
99784d9c625SLionel Sambuc #else
99884d9c625SLionel Sambuc FD_ZERO(&dsmask);
99984d9c625SLionel Sambuc FD_SET(s, &dsmask);
10002fe8fb19SBen Gras n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL);
100184d9c625SLionel Sambuc #endif
10022fe8fb19SBen Gras #else
10032fe8fb19SBen Gras timeout = evSubTime(finish, now);
10042fe8fb19SBen Gras if (timeout.tv_sec < 0)
1005f14fb602SLionel Sambuc timeout = evConsTime((time_t)0, 0L);
10062fe8fb19SBen Gras polltimeout = 1000*(int)timeout.tv_sec +
10072fe8fb19SBen Gras (int)timeout.tv_nsec/1000000;
10082fe8fb19SBen Gras pollfd.fd = s;
10092fe8fb19SBen Gras pollfd.events = POLLRDNORM;
10102fe8fb19SBen Gras n = poll(&pollfd, 1, polltimeout);
10112fe8fb19SBen Gras #endif /* USE_POLL */
10122fe8fb19SBen Gras
10132fe8fb19SBen Gras if (n == 0) {
10142fe8fb19SBen Gras Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n"));
10152fe8fb19SBen Gras *gotsomewhere = 1;
10162fe8fb19SBen Gras return (0);
10172fe8fb19SBen Gras }
10182fe8fb19SBen Gras if (n < 0) {
101984d9c625SLionel Sambuc #if defined(USE_POLL)
102084d9c625SLionel Sambuc static const char *fun = "poll";
102184d9c625SLionel Sambuc #elif defined(USE_SELECT)
102284d9c625SLionel Sambuc static const char *fun = "select";
102384d9c625SLionel Sambuc #elif defined(USE_KQUEUE)
102484d9c625SLionel Sambuc static const char *fun = "kevent";
102584d9c625SLionel Sambuc #endif
10262fe8fb19SBen Gras if (errno == EINTR)
10272fe8fb19SBen Gras goto wait;
102884d9c625SLionel Sambuc Perror(statp, stderr, fun, errno);
10292fe8fb19SBen Gras res_nclose(statp);
10302fe8fb19SBen Gras return (0);
10312fe8fb19SBen Gras }
103284d9c625SLionel Sambuc #ifdef USE_KQUEUE
103384d9c625SLionel Sambuc if ((int)kv.ident != s)
103484d9c625SLionel Sambuc goto wait;
103584d9c625SLionel Sambuc #endif
10362fe8fb19SBen Gras errno = 0;
10372fe8fb19SBen Gras fromlen = sizeof(from);
10382fe8fb19SBen Gras resplen = recvfrom(s, (char*)ans, (size_t)anssiz,0,
10392fe8fb19SBen Gras (struct sockaddr *)(void *)&from, &fromlen);
10402fe8fb19SBen Gras if (resplen <= 0) {
10412fe8fb19SBen Gras Perror(statp, stderr, "recvfrom", errno);
10422fe8fb19SBen Gras res_nclose(statp);
10432fe8fb19SBen Gras return (0);
10442fe8fb19SBen Gras }
10452fe8fb19SBen Gras *gotsomewhere = 1;
10462fe8fb19SBen Gras if (resplen < HFIXEDSZ) {
10472fe8fb19SBen Gras /*
10482fe8fb19SBen Gras * Undersized message.
10492fe8fb19SBen Gras */
10502fe8fb19SBen Gras Dprint(statp->options & RES_DEBUG,
1051f14fb602SLionel Sambuc (stdout, ";; undersized: %zd\n",
10522fe8fb19SBen Gras resplen));
10532fe8fb19SBen Gras *terrno = EMSGSIZE;
10542fe8fb19SBen Gras res_nclose(statp);
10552fe8fb19SBen Gras return (0);
10562fe8fb19SBen Gras }
10572fe8fb19SBen Gras if (hp->id != anhp->id) {
10582fe8fb19SBen Gras /*
10592fe8fb19SBen Gras * response from old query, ignore it.
10602fe8fb19SBen Gras * XXX - potential security hazard could
10612fe8fb19SBen Gras * be detected here.
10622fe8fb19SBen Gras */
10632fe8fb19SBen Gras DprintQ((statp->options & RES_DEBUG) ||
10642fe8fb19SBen Gras (statp->pfcode & RES_PRF_REPLY),
10652fe8fb19SBen Gras (stdout, ";; old answer:\n"),
10662fe8fb19SBen Gras ans, (resplen > anssiz) ? anssiz : resplen);
10672fe8fb19SBen Gras goto wait;
10682fe8fb19SBen Gras }
10692fe8fb19SBen Gras if (!(statp->options & RES_INSECURE1) &&
10702fe8fb19SBen Gras !res_ourserver_p(statp, (struct sockaddr *)(void *)&from)) {
10712fe8fb19SBen Gras /*
10722fe8fb19SBen Gras * response from wrong server? ignore it.
10732fe8fb19SBen Gras * XXX - potential security hazard could
10742fe8fb19SBen Gras * be detected here.
10752fe8fb19SBen Gras */
10762fe8fb19SBen Gras DprintQ((statp->options & RES_DEBUG) ||
10772fe8fb19SBen Gras (statp->pfcode & RES_PRF_REPLY),
10782fe8fb19SBen Gras (stdout, ";; not our server:\n"),
10792fe8fb19SBen Gras ans, (resplen > anssiz) ? anssiz : resplen);
10802fe8fb19SBen Gras goto wait;
10812fe8fb19SBen Gras }
10822fe8fb19SBen Gras #ifdef RES_USE_EDNS0
10832fe8fb19SBen Gras if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) {
10842fe8fb19SBen Gras /*
10852fe8fb19SBen Gras * Do not retry if the server do not understand EDNS0.
10862fe8fb19SBen Gras * The case has to be captured here, as FORMERR packet do not
10872fe8fb19SBen Gras * carry query section, hence res_queriesmatch() returns 0.
10882fe8fb19SBen Gras */
10892fe8fb19SBen Gras DprintQ(statp->options & RES_DEBUG,
10902fe8fb19SBen Gras (stdout, "server rejected query with EDNS0:\n"),
10912fe8fb19SBen Gras ans, (resplen > anssiz) ? anssiz : resplen);
10922fe8fb19SBen Gras /* record the error */
10932fe8fb19SBen Gras statp->_flags |= RES_F_EDNS0ERR;
10942fe8fb19SBen Gras res_nclose(statp);
10952fe8fb19SBen Gras return (0);
10962fe8fb19SBen Gras }
10972fe8fb19SBen Gras #endif
10982fe8fb19SBen Gras if (!(statp->options & RES_INSECURE2) &&
109984d9c625SLionel Sambuc !res_queriesmatch(buf, (const u_char *)buf + buflen,
11002fe8fb19SBen Gras ans, ans + anssiz)) {
11012fe8fb19SBen Gras /*
11022fe8fb19SBen Gras * response contains wrong query? ignore it.
11032fe8fb19SBen Gras * XXX - potential security hazard could
11042fe8fb19SBen Gras * be detected here.
11052fe8fb19SBen Gras */
11062fe8fb19SBen Gras DprintQ((statp->options & RES_DEBUG) ||
11072fe8fb19SBen Gras (statp->pfcode & RES_PRF_REPLY),
11082fe8fb19SBen Gras (stdout, ";; wrong query name:\n"),
1109f14fb602SLionel Sambuc ans, (int)(resplen > anssiz) ? anssiz : resplen);
11102fe8fb19SBen Gras goto wait;
11112fe8fb19SBen Gras }
11122fe8fb19SBen Gras if (anhp->rcode == SERVFAIL ||
11132fe8fb19SBen Gras anhp->rcode == NOTIMP ||
11142fe8fb19SBen Gras anhp->rcode == REFUSED) {
11152fe8fb19SBen Gras DprintQ(statp->options & RES_DEBUG,
11162fe8fb19SBen Gras (stdout, "server rejected query:\n"),
1117f14fb602SLionel Sambuc ans, (int)(resplen > anssiz) ? anssiz : resplen);
11182fe8fb19SBen Gras res_nclose(statp);
11192fe8fb19SBen Gras /* don't retry if called from dig */
11202fe8fb19SBen Gras if (!statp->pfcode)
11212fe8fb19SBen Gras return (0);
11222fe8fb19SBen Gras }
11232fe8fb19SBen Gras if (!(statp->options & RES_IGNTC) && anhp->tc) {
11242fe8fb19SBen Gras /*
11252fe8fb19SBen Gras * To get the rest of answer,
11262fe8fb19SBen Gras * use TCP with same server.
11272fe8fb19SBen Gras */
11282fe8fb19SBen Gras Dprint(statp->options & RES_DEBUG,
11292fe8fb19SBen Gras (stdout, ";; truncated answer\n"));
11302fe8fb19SBen Gras *v_circuit = 1;
11312fe8fb19SBen Gras res_nclose(statp);
11322fe8fb19SBen Gras return (1);
11332fe8fb19SBen Gras }
11342fe8fb19SBen Gras /*
11352fe8fb19SBen Gras * All is well, or the error is fatal. Signal that the
11362fe8fb19SBen Gras * next nameserver ought not be tried.
11372fe8fb19SBen Gras */
1138f14fb602SLionel Sambuc _DIAGASSERT(__type_fit(int, resplen));
1139f14fb602SLionel Sambuc return (int)resplen;
11402fe8fb19SBen Gras }
11412fe8fb19SBen Gras
11422fe8fb19SBen Gras static void
Aerror(const res_state statp,FILE * file,const char * string,int error,const struct sockaddr * address,socklen_t alen)11432fe8fb19SBen Gras Aerror(const res_state statp, FILE *file, const char *string, int error,
114484d9c625SLionel Sambuc const struct sockaddr *address, socklen_t alen)
11452fe8fb19SBen Gras {
11462fe8fb19SBen Gras int save = errno;
11472fe8fb19SBen Gras char hbuf[NI_MAXHOST];
11482fe8fb19SBen Gras char sbuf[NI_MAXSERV];
11492fe8fb19SBen Gras
11502fe8fb19SBen Gras if ((statp->options & RES_DEBUG) != 0U) {
115184d9c625SLionel Sambuc if (getnameinfo(address, alen, hbuf,
1152f14fb602SLionel Sambuc (socklen_t)sizeof(hbuf), sbuf, (socklen_t)sizeof(sbuf),
1153f14fb602SLionel Sambuc niflags)) {
11542fe8fb19SBen Gras strncpy(hbuf, "?", sizeof(hbuf) - 1);
11552fe8fb19SBen Gras hbuf[sizeof(hbuf) - 1] = '\0';
11562fe8fb19SBen Gras strncpy(sbuf, "?", sizeof(sbuf) - 1);
11572fe8fb19SBen Gras sbuf[sizeof(sbuf) - 1] = '\0';
11582fe8fb19SBen Gras }
11592fe8fb19SBen Gras fprintf(file, "res_send: %s ([%s].%s): %s\n",
11602fe8fb19SBen Gras string, hbuf, sbuf, strerror(error));
11612fe8fb19SBen Gras }
11622fe8fb19SBen Gras errno = save;
11632fe8fb19SBen Gras }
11642fe8fb19SBen Gras
11652fe8fb19SBen Gras static void
Perror(const res_state statp,FILE * file,const char * string,int error)11662fe8fb19SBen Gras Perror(const res_state statp, FILE *file, const char *string, int error) {
11672fe8fb19SBen Gras int save = errno;
11682fe8fb19SBen Gras
11692fe8fb19SBen Gras if ((statp->options & RES_DEBUG) != 0U)
11702fe8fb19SBen Gras fprintf(file, "res_send: %s: %s\n",
11712fe8fb19SBen Gras string, strerror(error));
11722fe8fb19SBen Gras errno = save;
11732fe8fb19SBen Gras }
11742fe8fb19SBen Gras
11752fe8fb19SBen Gras static int
sock_eq(struct sockaddr * a,struct sockaddr * b)11762fe8fb19SBen Gras sock_eq(struct sockaddr *a, struct sockaddr *b) {
11772fe8fb19SBen Gras struct sockaddr_in *a4, *b4;
11782fe8fb19SBen Gras struct sockaddr_in6 *a6, *b6;
11792fe8fb19SBen Gras
11802fe8fb19SBen Gras if (a->sa_family != b->sa_family)
11812fe8fb19SBen Gras return 0;
11822fe8fb19SBen Gras switch (a->sa_family) {
11832fe8fb19SBen Gras case AF_INET:
11842fe8fb19SBen Gras a4 = (struct sockaddr_in *)(void *)a;
11852fe8fb19SBen Gras b4 = (struct sockaddr_in *)(void *)b;
11862fe8fb19SBen Gras return a4->sin_port == b4->sin_port &&
11872fe8fb19SBen Gras a4->sin_addr.s_addr == b4->sin_addr.s_addr;
11882fe8fb19SBen Gras case AF_INET6:
11892fe8fb19SBen Gras a6 = (struct sockaddr_in6 *)(void *)a;
11902fe8fb19SBen Gras b6 = (struct sockaddr_in6 *)(void *)b;
11912fe8fb19SBen Gras return a6->sin6_port == b6->sin6_port &&
11922fe8fb19SBen Gras #ifdef HAVE_SIN6_SCOPE_ID
11932fe8fb19SBen Gras a6->sin6_scope_id == b6->sin6_scope_id &&
11942fe8fb19SBen Gras #endif
11952fe8fb19SBen Gras IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr);
11962fe8fb19SBen Gras default:
11972fe8fb19SBen Gras return 0;
11982fe8fb19SBen Gras }
11992fe8fb19SBen Gras }
12002fe8fb19SBen Gras
120184d9c625SLionel Sambuc #if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE)
12022fe8fb19SBen Gras /* XXX needs to move to the porting library. */
12032fe8fb19SBen Gras static int
pselect(int nfds,void * rfds,void * wfds,void * efds,struct timespec * tsp,const sigset_t * sigmask)12042fe8fb19SBen Gras pselect(int nfds, void *rfds, void *wfds, void *efds,
12052fe8fb19SBen Gras struct timespec *tsp, const sigset_t *sigmask)
12062fe8fb19SBen Gras {
12072fe8fb19SBen Gras struct timeval tv, *tvp;
12082fe8fb19SBen Gras sigset_t sigs;
12092fe8fb19SBen Gras int n;
12102fe8fb19SBen Gras
12112fe8fb19SBen Gras if (tsp) {
12122fe8fb19SBen Gras tvp = &tv;
12132fe8fb19SBen Gras tv = evTimeVal(*tsp);
12142fe8fb19SBen Gras } else
12152fe8fb19SBen Gras tvp = NULL;
12162fe8fb19SBen Gras if (sigmask)
12172fe8fb19SBen Gras sigprocmask(SIG_SETMASK, sigmask, &sigs);
12182fe8fb19SBen Gras n = select(nfds, rfds, wfds, efds, tvp);
12192fe8fb19SBen Gras if (sigmask)
12202fe8fb19SBen Gras sigprocmask(SIG_SETMASK, &sigs, NULL);
12212fe8fb19SBen Gras if (tsp)
12222fe8fb19SBen Gras *tsp = evTimeSpec(tv);
12232fe8fb19SBen Gras return (n);
12242fe8fb19SBen Gras }
12252fe8fb19SBen Gras #endif
1226