1331722Seadler/* 2269867Sume * Portions Copyright (C) 2004-2009 Internet Systems Consortium, Inc. ("ISC") 3269867Sume * Portions Copyright (C) 1996-2003 Internet Software Consortium. 4269867Sume * 5269867Sume * Permission to use, copy, modify, and/or distribute this software for any 6269867Sume * purpose with or without fee is hereby granted, provided that the above 7269867Sume * copyright notice and this permission notice appear in all copies. 8269867Sume * 9269867Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10269867Sume * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11269867Sume * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12269867Sume * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13269867Sume * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14269867Sume * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15269867Sume * PERFORMANCE OF THIS SOFTWARE. 16269867Sume */ 17269867Sume 18269867Sume/* 19156952Sume * Copyright (c) 1985, 1989, 1993 20156952Sume * The Regents of the University of California. All rights reserved. 21269867Sume * 22156952Sume * Redistribution and use in source and binary forms, with or without 23156952Sume * modification, are permitted provided that the following conditions 24156952Sume * are met: 25156952Sume * 1. Redistributions of source code must retain the above copyright 26156952Sume * notice, this list of conditions and the following disclaimer. 27156952Sume * 2. Redistributions in binary form must reproduce the above copyright 28156952Sume * notice, this list of conditions and the following disclaimer in the 29156952Sume * documentation and/or other materials provided with the distribution. 30156952Sume * 4. Neither the name of the University nor the names of its contributors 31156952Sume * may be used to endorse or promote products derived from this software 32156952Sume * without specific prior written permission. 33269867Sume * 34156952Sume * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 35156952Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 36156952Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 37156952Sume * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 38156952Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 39156952Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 40156952Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 41156952Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 42156952Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 43156952Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 44156952Sume * SUCH DAMAGE. 45156952Sume */ 46156952Sume 47156952Sume/* 48156952Sume * Portions Copyright (c) 1993 by Digital Equipment Corporation. 49269867Sume * 50156952Sume * Permission to use, copy, modify, and distribute this software for any 51156952Sume * purpose with or without fee is hereby granted, provided that the above 52156952Sume * copyright notice and this permission notice appear in all copies, and that 53156952Sume * the name of Digital Equipment Corporation not be used in advertising or 54156952Sume * publicity pertaining to distribution of the document or software without 55156952Sume * specific, written prior permission. 56269867Sume * 57156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 58156952Sume * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 59156952Sume * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 60156952Sume * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 61156952Sume * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 62156952Sume * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 63156952Sume * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 64156952Sume * SOFTWARE. 65156952Sume */ 66156952Sume 67156952Sume#if defined(LIBC_SCCS) && !defined(lint) 68156952Sumestatic const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; 69269867Sumestatic const char rcsid[] = "$Id: res_send.c,v 1.22 2009/01/22 23:49:23 tbox Exp $"; 70156952Sume#endif /* LIBC_SCCS and not lint */ 71156956Sume#include <sys/cdefs.h> 72156956Sume__FBSDID("$FreeBSD$"); 73156952Sume 74170244Sume/*! \file 75170244Sume * \brief 76156952Sume * Send query to name server and wait for reply. 77156952Sume */ 78156952Sume 79156952Sume#include "port_before.h" 80260652Sjilles#if !defined(USE_KQUEUE) && !defined(USE_POLL) 81156952Sume#include "fd_setsize.h" 82156956Sume#endif 83156952Sume 84156956Sume#include "namespace.h" 85156952Sume#include <sys/param.h> 86156952Sume#include <sys/time.h> 87156952Sume#include <sys/socket.h> 88156952Sume#include <sys/uio.h> 89156952Sume 90156952Sume#include <netinet/in.h> 91156952Sume#include <arpa/nameser.h> 92156952Sume#include <arpa/inet.h> 93156952Sume 94156952Sume#include <errno.h> 95156952Sume#include <netdb.h> 96156952Sume#include <resolv.h> 97156952Sume#include <signal.h> 98156952Sume#include <stdio.h> 99156952Sume#include <stdlib.h> 100156952Sume#include <string.h> 101156952Sume#include <unistd.h> 102156952Sume 103156952Sume#include <isc/eventlib.h> 104156952Sume 105156952Sume#include "port_after.h" 106156952Sume 107156956Sume#ifdef USE_KQUEUE 108156956Sume#include <sys/event.h> 109156956Sume#else 110156952Sume#ifdef USE_POLL 111156952Sume#ifdef HAVE_STROPTS_H 112156952Sume#include <stropts.h> 113156952Sume#endif 114156952Sume#include <poll.h> 115156952Sume#endif /* USE_POLL */ 116156956Sume#endif 117156952Sume 118156956Sume#include "un-namespace.h" 119156956Sume 120156952Sume/* Options. Leave them on. */ 121292250Sngie#ifndef DEBUG 122292250Sngie#define DEBUG 123292250Sngie#endif 124156952Sume#include "res_debug.h" 125156952Sume#include "res_private.h" 126156952Sume 127156952Sume#define EXT(res) ((res)->_u._ext) 128156952Sume 129167246Sjhb#if !defined(USE_POLL) && !defined(USE_KQUEUE) 130156952Sumestatic const int highestFD = FD_SETSIZE - 1; 131156952Sume#endif 132156952Sume 133156952Sume/* Forward. */ 134156952Sume 135156956Sumestatic int get_salen(const struct sockaddr *); 136156956Sumestatic struct sockaddr * get_nsaddr(res_state, size_t); 137156952Sumestatic int send_vc(res_state, const u_char *, int, 138156952Sume u_char *, int, int *, int); 139156956Sumestatic int send_dg(res_state, 140156956Sume#ifdef USE_KQUEUE 141156956Sume int kq, 142156956Sume#endif 143156956Sume const u_char *, int, 144163661Sume u_char *, int, int *, int, int, 145156952Sume int *, int *); 146156952Sumestatic void Aerror(const res_state, FILE *, const char *, int, 147156952Sume const struct sockaddr *, int); 148156952Sumestatic void Perror(const res_state, FILE *, const char *, int); 149156952Sumestatic int sock_eq(struct sockaddr *, struct sockaddr *); 150156956Sume#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE) 151156952Sumestatic int pselect(int, void *, void *, void *, 152156952Sume struct timespec *, 153156952Sume const sigset_t *); 154156952Sume#endif 155156952Sumevoid res_pquery(const res_state, const u_char *, int, FILE *); 156156952Sume 157156952Sumestatic const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; 158156952Sume 159156952Sume/* Public. */ 160156952Sume 161170244Sume/*% 162156952Sume * looks up "ina" in _res.ns_addr_list[] 163170244Sume * 164156952Sume * returns: 165170244Sume *\li 0 : not found 166170244Sume *\li >0 : found 167170244Sume * 168156952Sume * author: 169170244Sume *\li paul vixie, 29may94 170156952Sume */ 171156952Sumeint 172156952Sumeres_ourserver_p(const res_state statp, const struct sockaddr *sa) { 173156952Sume const struct sockaddr_in *inp, *srv; 174156952Sume const struct sockaddr_in6 *in6p, *srv6; 175156952Sume int ns; 176156952Sume 177156952Sume switch (sa->sa_family) { 178156952Sume case AF_INET: 179156952Sume inp = (const struct sockaddr_in *)sa; 180156952Sume for (ns = 0; ns < statp->nscount; ns++) { 181156952Sume srv = (struct sockaddr_in *)get_nsaddr(statp, ns); 182156952Sume if (srv->sin_family == inp->sin_family && 183156952Sume srv->sin_port == inp->sin_port && 184156952Sume (srv->sin_addr.s_addr == INADDR_ANY || 185156952Sume srv->sin_addr.s_addr == inp->sin_addr.s_addr)) 186156952Sume return (1); 187156952Sume } 188156952Sume break; 189156952Sume case AF_INET6: 190156952Sume if (EXT(statp).ext == NULL) 191156952Sume break; 192156952Sume in6p = (const struct sockaddr_in6 *)sa; 193156952Sume for (ns = 0; ns < statp->nscount; ns++) { 194156952Sume srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns); 195156952Sume if (srv6->sin6_family == in6p->sin6_family && 196156952Sume srv6->sin6_port == in6p->sin6_port && 197156952Sume#ifdef HAVE_SIN6_SCOPE_ID 198156952Sume (srv6->sin6_scope_id == 0 || 199156952Sume srv6->sin6_scope_id == in6p->sin6_scope_id) && 200156952Sume#endif 201156952Sume (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) || 202156952Sume IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr))) 203156952Sume return (1); 204156952Sume } 205156952Sume break; 206156952Sume default: 207156952Sume break; 208156952Sume } 209156952Sume return (0); 210156952Sume} 211156952Sume 212170244Sume/*% 213156952Sume * look for (name,type,class) in the query section of packet (buf,eom) 214170244Sume * 215156952Sume * requires: 216170244Sume *\li buf + HFIXEDSZ <= eom 217170244Sume * 218156952Sume * returns: 219170244Sume *\li -1 : format error 220170244Sume *\li 0 : not found 221170244Sume *\li >0 : found 222170244Sume * 223156952Sume * author: 224170244Sume *\li paul vixie, 29may94 225156952Sume */ 226156952Sumeint 227156952Sumeres_nameinquery(const char *name, int type, int class, 228156952Sume const u_char *buf, const u_char *eom) 229156952Sume{ 230156952Sume const u_char *cp = buf + HFIXEDSZ; 231156952Sume int qdcount = ntohs(((const HEADER*)buf)->qdcount); 232156952Sume 233156952Sume while (qdcount-- > 0) { 234156952Sume char tname[MAXDNAME+1]; 235156952Sume int n, ttype, tclass; 236156952Sume 237156952Sume n = dn_expand(buf, eom, cp, tname, sizeof tname); 238156952Sume if (n < 0) 239156952Sume return (-1); 240156952Sume cp += n; 241156952Sume if (cp + 2 * INT16SZ > eom) 242156952Sume return (-1); 243156952Sume ttype = ns_get16(cp); cp += INT16SZ; 244156952Sume tclass = ns_get16(cp); cp += INT16SZ; 245156952Sume if (ttype == type && tclass == class && 246156952Sume ns_samename(tname, name) == 1) 247156952Sume return (1); 248156952Sume } 249156952Sume return (0); 250156952Sume} 251156952Sume 252170244Sume/*% 253156952Sume * is there a 1:1 mapping of (name,type,class) 254156952Sume * in (buf1,eom1) and (buf2,eom2)? 255170244Sume * 256156952Sume * returns: 257170244Sume *\li -1 : format error 258170244Sume *\li 0 : not a 1:1 mapping 259170244Sume *\li >0 : is a 1:1 mapping 260170244Sume * 261156952Sume * author: 262170244Sume *\li paul vixie, 29may94 263156952Sume */ 264156952Sumeint 265156952Sumeres_queriesmatch(const u_char *buf1, const u_char *eom1, 266156952Sume const u_char *buf2, const u_char *eom2) 267156952Sume{ 268156952Sume const u_char *cp = buf1 + HFIXEDSZ; 269156952Sume int qdcount = ntohs(((const HEADER*)buf1)->qdcount); 270156952Sume 271156952Sume if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2) 272156952Sume return (-1); 273156952Sume 274156952Sume /* 275156952Sume * Only header section present in replies to 276156952Sume * dynamic update packets. 277156952Sume */ 278156952Sume if ((((const HEADER *)buf1)->opcode == ns_o_update) && 279156952Sume (((const HEADER *)buf2)->opcode == ns_o_update)) 280156952Sume return (1); 281156952Sume 282156952Sume if (qdcount != ntohs(((const HEADER*)buf2)->qdcount)) 283156952Sume return (0); 284156952Sume while (qdcount-- > 0) { 285156952Sume char tname[MAXDNAME+1]; 286156952Sume int n, ttype, tclass; 287156952Sume 288156952Sume n = dn_expand(buf1, eom1, cp, tname, sizeof tname); 289156952Sume if (n < 0) 290156952Sume return (-1); 291156952Sume cp += n; 292156952Sume if (cp + 2 * INT16SZ > eom1) 293156952Sume return (-1); 294156952Sume ttype = ns_get16(cp); cp += INT16SZ; 295156952Sume tclass = ns_get16(cp); cp += INT16SZ; 296156952Sume if (!res_nameinquery(tname, ttype, tclass, buf2, eom2)) 297156952Sume return (0); 298156952Sume } 299156952Sume return (1); 300156952Sume} 301156952Sume 302156952Sumeint 303156952Sumeres_nsend(res_state statp, 304156952Sume const u_char *buf, int buflen, u_char *ans, int anssiz) 305156952Sume{ 306186090Sume int gotsomewhere, terrno, tries, v_circuit, resplen, ns, n; 307156956Sume#ifdef USE_KQUEUE 308156956Sume int kq; 309156956Sume#endif 310156952Sume char abuf[NI_MAXHOST]; 311156952Sume 312165258Sume /* No name servers or res_init() failure */ 313165258Sume if (statp->nscount == 0 || EXT(statp).ext == NULL) { 314156952Sume errno = ESRCH; 315156952Sume return (-1); 316156952Sume } 317156952Sume if (anssiz < HFIXEDSZ) { 318156952Sume errno = EINVAL; 319156952Sume return (-1); 320156952Sume } 321156952Sume DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), 322156952Sume (stdout, ";; res_send()\n"), buf, buflen); 323156952Sume v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ; 324156952Sume gotsomewhere = 0; 325156952Sume terrno = ETIMEDOUT; 326156952Sume 327156956Sume#ifdef USE_KQUEUE 328156956Sume if ((kq = kqueue()) < 0) { 329156956Sume Perror(statp, stderr, "kqueue", errno); 330156956Sume return (-1); 331156956Sume } 332156956Sume#endif 333156956Sume 334156952Sume /* 335156952Sume * If the ns_addr_list in the resolver context has changed, then 336156952Sume * invalidate our cached copy and the associated timing data. 337156952Sume */ 338156952Sume if (EXT(statp).nscount != 0) { 339156952Sume int needclose = 0; 340156952Sume struct sockaddr_storage peer; 341156952Sume ISC_SOCKLEN_T peerlen; 342156952Sume 343156952Sume if (EXT(statp).nscount != statp->nscount) 344156952Sume needclose++; 345156952Sume else 346156952Sume for (ns = 0; ns < statp->nscount; ns++) { 347156952Sume if (statp->nsaddr_list[ns].sin_family && 348156952Sume !sock_eq((struct sockaddr *)&statp->nsaddr_list[ns], 349156952Sume (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) { 350156952Sume needclose++; 351156952Sume break; 352156952Sume } 353156952Sume 354156952Sume if (EXT(statp).nssocks[ns] == -1) 355156952Sume continue; 356156952Sume peerlen = sizeof(peer); 357269867Sume if (_getpeername(EXT(statp).nssocks[ns], 358156952Sume (struct sockaddr *)&peer, &peerlen) < 0) { 359156952Sume needclose++; 360156952Sume break; 361156952Sume } 362156952Sume if (!sock_eq((struct sockaddr *)&peer, 363156952Sume get_nsaddr(statp, ns))) { 364156952Sume needclose++; 365156952Sume break; 366156952Sume } 367156952Sume } 368156952Sume if (needclose) { 369156952Sume res_nclose(statp); 370156952Sume EXT(statp).nscount = 0; 371156952Sume } 372156952Sume } 373156952Sume 374156952Sume /* 375156952Sume * Maybe initialize our private copy of the ns_addr_list. 376156952Sume */ 377156952Sume if (EXT(statp).nscount == 0) { 378156952Sume for (ns = 0; ns < statp->nscount; ns++) { 379156952Sume EXT(statp).nstimes[ns] = RES_MAXTIME; 380156952Sume EXT(statp).nssocks[ns] = -1; 381156952Sume if (!statp->nsaddr_list[ns].sin_family) 382156952Sume continue; 383156952Sume EXT(statp).ext->nsaddrs[ns].sin = 384156952Sume statp->nsaddr_list[ns]; 385156952Sume } 386156952Sume EXT(statp).nscount = statp->nscount; 387156952Sume } 388156952Sume 389156952Sume /* 390156952Sume * Some resolvers want to even out the load on their nameservers. 391156952Sume * Note that RES_BLAST overrides RES_ROTATE. 392156952Sume */ 393156952Sume if ((statp->options & RES_ROTATE) != 0U && 394156952Sume (statp->options & RES_BLAST) == 0U) { 395156952Sume union res_sockaddr_union inu; 396156952Sume struct sockaddr_in ina; 397156952Sume int lastns = statp->nscount - 1; 398156952Sume int fd; 399156952Sume u_int16_t nstime; 400156952Sume 401156952Sume if (EXT(statp).ext != NULL) 402156952Sume inu = EXT(statp).ext->nsaddrs[0]; 403156952Sume ina = statp->nsaddr_list[0]; 404156952Sume fd = EXT(statp).nssocks[0]; 405156952Sume nstime = EXT(statp).nstimes[0]; 406156952Sume for (ns = 0; ns < lastns; ns++) { 407156952Sume if (EXT(statp).ext != NULL) 408269867Sume EXT(statp).ext->nsaddrs[ns] = 409156952Sume EXT(statp).ext->nsaddrs[ns + 1]; 410156952Sume statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1]; 411156952Sume EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1]; 412156952Sume EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1]; 413156952Sume } 414156952Sume if (EXT(statp).ext != NULL) 415156952Sume EXT(statp).ext->nsaddrs[lastns] = inu; 416156952Sume statp->nsaddr_list[lastns] = ina; 417156952Sume EXT(statp).nssocks[lastns] = fd; 418156952Sume EXT(statp).nstimes[lastns] = nstime; 419156952Sume } 420156952Sume 421156952Sume /* 422156952Sume * Send request, RETRY times, or until successful. 423156952Sume */ 424186090Sume for (tries = 0; tries < statp->retry; tries++) { 425156952Sume for (ns = 0; ns < statp->nscount; ns++) { 426156952Sume struct sockaddr *nsap; 427156952Sume int nsaplen; 428156952Sume nsap = get_nsaddr(statp, ns); 429156952Sume nsaplen = get_salen(nsap); 430156952Sume statp->_flags &= ~RES_F_LASTMASK; 431156952Sume statp->_flags |= (ns << RES_F_LASTSHIFT); 432156952Sume same_ns: 433156952Sume if (statp->qhook) { 434156952Sume int done = 0, loops = 0; 435156952Sume 436156952Sume do { 437156952Sume res_sendhookact act; 438156952Sume 439156952Sume act = (*statp->qhook)(&nsap, &buf, &buflen, 440156952Sume ans, anssiz, &resplen); 441156952Sume switch (act) { 442156952Sume case res_goahead: 443156952Sume done = 1; 444156952Sume break; 445156952Sume case res_nextns: 446156952Sume res_nclose(statp); 447156952Sume goto next_ns; 448156952Sume case res_done: 449156956Sume#ifdef USE_KQUEUE 450156956Sume _close(kq); 451156956Sume#endif 452156952Sume return (resplen); 453156952Sume case res_modified: 454156952Sume /* give the hook another try */ 455156952Sume if (++loops < 42) /*doug adams*/ 456156952Sume break; 457156952Sume /*FALLTHROUGH*/ 458156952Sume case res_error: 459156952Sume /*FALLTHROUGH*/ 460156952Sume default: 461156952Sume goto fail; 462156952Sume } 463156952Sume } while (!done); 464156952Sume } 465156952Sume 466156952Sume Dprint(((statp->options & RES_DEBUG) && 467156952Sume getnameinfo(nsap, nsaplen, abuf, sizeof(abuf), 468156952Sume NULL, 0, niflags) == 0), 469156952Sume (stdout, ";; Querying server (# %d) address = %s\n", 470156952Sume ns + 1, abuf)); 471156952Sume 472156952Sume 473156952Sume if (v_circuit) { 474156952Sume /* Use VC; at most one attempt per server. */ 475186090Sume tries = statp->retry; 476156952Sume n = send_vc(statp, buf, buflen, ans, anssiz, &terrno, 477156952Sume ns); 478156952Sume if (n < 0) 479156952Sume goto fail; 480156952Sume if (n == 0) 481156952Sume goto next_ns; 482156952Sume resplen = n; 483156952Sume } else { 484156952Sume /* Use datagrams. */ 485156956Sume n = send_dg(statp, 486156956Sume#ifdef USE_KQUEUE 487156956Sume kq, 488156956Sume#endif 489156956Sume buf, buflen, ans, anssiz, &terrno, 490186090Sume ns, tries, &v_circuit, &gotsomewhere); 491156952Sume if (n < 0) 492156952Sume goto fail; 493156952Sume if (n == 0) 494156952Sume goto next_ns; 495156952Sume if (v_circuit) 496156952Sume goto same_ns; 497156952Sume resplen = n; 498156952Sume } 499156952Sume 500156952Sume Dprint((statp->options & RES_DEBUG) || 501156952Sume ((statp->pfcode & RES_PRF_REPLY) && 502156952Sume (statp->pfcode & RES_PRF_HEAD1)), 503156952Sume (stdout, ";; got answer:\n")); 504156952Sume 505156952Sume DprintQ((statp->options & RES_DEBUG) || 506156952Sume (statp->pfcode & RES_PRF_REPLY), 507156952Sume (stdout, "%s", ""), 508156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 509156952Sume 510156952Sume /* 511156952Sume * If we have temporarily opened a virtual circuit, 512156952Sume * or if we haven't been asked to keep a socket open, 513156952Sume * close the socket. 514156952Sume */ 515156952Sume if ((v_circuit && (statp->options & RES_USEVC) == 0U) || 516156952Sume (statp->options & RES_STAYOPEN) == 0U) { 517156952Sume res_nclose(statp); 518156952Sume } 519156952Sume if (statp->rhook) { 520156952Sume int done = 0, loops = 0; 521156952Sume 522156952Sume do { 523156952Sume res_sendhookact act; 524156952Sume 525156952Sume act = (*statp->rhook)(nsap, buf, buflen, 526156952Sume ans, anssiz, &resplen); 527156952Sume switch (act) { 528156952Sume case res_goahead: 529156952Sume case res_done: 530156952Sume done = 1; 531156952Sume break; 532156952Sume case res_nextns: 533156952Sume res_nclose(statp); 534156952Sume goto next_ns; 535156952Sume case res_modified: 536156952Sume /* give the hook another try */ 537156952Sume if (++loops < 42) /*doug adams*/ 538156952Sume break; 539156952Sume /*FALLTHROUGH*/ 540156952Sume case res_error: 541156952Sume /*FALLTHROUGH*/ 542156952Sume default: 543156952Sume goto fail; 544156952Sume } 545156952Sume } while (!done); 546156952Sume 547156952Sume } 548156956Sume#ifdef USE_KQUEUE 549156956Sume _close(kq); 550156956Sume#endif 551156952Sume return (resplen); 552156952Sume next_ns: ; 553156952Sume } /*foreach ns*/ 554156952Sume } /*foreach retry*/ 555156952Sume res_nclose(statp); 556156956Sume#ifdef USE_KQUEUE 557156956Sume _close(kq); 558156956Sume#endif 559156952Sume if (!v_circuit) { 560156952Sume if (!gotsomewhere) 561170244Sume errno = ECONNREFUSED; /*%< no nameservers found */ 562156952Sume else 563170244Sume errno = ETIMEDOUT; /*%< no answer obtained */ 564156952Sume } else 565156952Sume errno = terrno; 566156952Sume return (-1); 567156952Sume fail: 568156952Sume res_nclose(statp); 569156956Sume#ifdef USE_KQUEUE 570156956Sume _close(kq); 571156956Sume#endif 572156952Sume return (-1); 573156952Sume} 574156952Sume 575156952Sume/* Private */ 576156952Sume 577156952Sumestatic int 578288114Srodrigcget_salen(const struct sockaddr *sa) 579156952Sume{ 580156952Sume 581156952Sume#ifdef HAVE_SA_LEN 582156952Sume /* There are people do not set sa_len. Be forgiving to them. */ 583156952Sume if (sa->sa_len) 584156952Sume return (sa->sa_len); 585156952Sume#endif 586156952Sume 587156952Sume if (sa->sa_family == AF_INET) 588156952Sume return (sizeof(struct sockaddr_in)); 589156952Sume else if (sa->sa_family == AF_INET6) 590156952Sume return (sizeof(struct sockaddr_in6)); 591156952Sume else 592170244Sume return (0); /*%< unknown, die on connect */ 593156952Sume} 594156952Sume 595170244Sume/*% 596156952Sume * pick appropriate nsaddr_list for use. see res_init() for initialization. 597156952Sume */ 598156952Sumestatic struct sockaddr * 599288114Srodrigcget_nsaddr(res_state statp, size_t n) 600156952Sume{ 601156952Sume 602156952Sume if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) { 603156952Sume /* 604156952Sume * - EXT(statp).ext->nsaddrs[n] holds an address that is larger 605156952Sume * than struct sockaddr, and 606156952Sume * - user code did not update statp->nsaddr_list[n]. 607156952Sume */ 608156952Sume return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n]; 609156952Sume } else { 610156952Sume /* 611156952Sume * - user code updated statp->nsaddr_list[n], or 612156952Sume * - statp->nsaddr_list[n] has the same content as 613156952Sume * EXT(statp).ext->nsaddrs[n]. 614156952Sume */ 615156952Sume return (struct sockaddr *)(void *)&statp->nsaddr_list[n]; 616156952Sume } 617156952Sume} 618156952Sume 619156952Sumestatic int 620156952Sumesend_vc(res_state statp, 621156952Sume const u_char *buf, int buflen, u_char *ans, int anssiz, 622156952Sume int *terrno, int ns) 623156952Sume{ 624156952Sume const HEADER *hp = (const HEADER *) buf; 625156952Sume HEADER *anhp = (HEADER *) ans; 626156952Sume struct sockaddr *nsap; 627156952Sume int nsaplen; 628156952Sume int truncating, connreset, resplen, n; 629156952Sume struct iovec iov[2]; 630156952Sume u_short len; 631156952Sume u_char *cp; 632156952Sume void *tmp; 633186090Sume#ifdef SO_NOSIGPIPE 634186090Sume int on = 1; 635186090Sume#endif 636156952Sume 637156952Sume nsap = get_nsaddr(statp, ns); 638156952Sume nsaplen = get_salen(nsap); 639156952Sume 640156952Sume connreset = 0; 641156952Sume same_ns: 642156952Sume truncating = 0; 643156952Sume 644156952Sume /* Are we still talking to whom we want to talk to? */ 645156952Sume if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) { 646156952Sume struct sockaddr_storage peer; 647156952Sume ISC_SOCKLEN_T size = sizeof peer; 648156952Sume 649156956Sume if (_getpeername(statp->_vcsock, 650156952Sume (struct sockaddr *)&peer, &size) < 0 || 651156952Sume !sock_eq((struct sockaddr *)&peer, nsap)) { 652156952Sume res_nclose(statp); 653156952Sume statp->_flags &= ~RES_F_VC; 654156952Sume } 655156952Sume } 656156952Sume 657156952Sume if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) { 658156952Sume if (statp->_vcsock >= 0) 659156952Sume res_nclose(statp); 660156952Sume 661255336Sjilles statp->_vcsock = _socket(nsap->sa_family, SOCK_STREAM | 662255336Sjilles SOCK_CLOEXEC, 0); 663167246Sjhb#if !defined(USE_POLL) && !defined(USE_KQUEUE) 664156952Sume if (statp->_vcsock > highestFD) { 665156952Sume res_nclose(statp); 666156952Sume errno = ENOTSOCK; 667156952Sume } 668167246Sjhb#endif 669156952Sume if (statp->_vcsock < 0) { 670156952Sume switch (errno) { 671156952Sume case EPROTONOSUPPORT: 672156952Sume#ifdef EPFNOSUPPORT 673156952Sume case EPFNOSUPPORT: 674156952Sume#endif 675156952Sume case EAFNOSUPPORT: 676156952Sume Perror(statp, stderr, "socket(vc)", errno); 677156952Sume return (0); 678156952Sume default: 679156952Sume *terrno = errno; 680156952Sume Perror(statp, stderr, "socket(vc)", errno); 681156952Sume return (-1); 682156952Sume } 683156952Sume } 684186090Sume#ifdef SO_NOSIGPIPE 685186090Sume /* 686186090Sume * Disable generation of SIGPIPE when writing to a closed 687186090Sume * socket. Write should return -1 and set errno to EPIPE 688269867Sume * instead. 689186090Sume * 690186090Sume * Push on even if setsockopt(SO_NOSIGPIPE) fails. 691186090Sume */ 692186090Sume (void)_setsockopt(statp->_vcsock, SOL_SOCKET, SO_NOSIGPIPE, &on, 693269867Sume sizeof(on)); 694186090Sume#endif 695156952Sume errno = 0; 696156956Sume if (_connect(statp->_vcsock, nsap, nsaplen) < 0) { 697156952Sume *terrno = errno; 698156952Sume Aerror(statp, stderr, "connect/vc", errno, nsap, 699156952Sume nsaplen); 700156952Sume res_nclose(statp); 701156952Sume return (0); 702156952Sume } 703156952Sume statp->_flags |= RES_F_VC; 704156952Sume } 705156952Sume 706156952Sume /* 707156952Sume * Send length & message 708156952Sume */ 709156952Sume ns_put16((u_short)buflen, (u_char*)&len); 710156952Sume iov[0] = evConsIovec(&len, INT16SZ); 711156952Sume DE_CONST(buf, tmp); 712156952Sume iov[1] = evConsIovec(tmp, buflen); 713156956Sume if (_writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) { 714156952Sume *terrno = errno; 715156952Sume Perror(statp, stderr, "write failed", errno); 716156952Sume res_nclose(statp); 717156952Sume return (0); 718156952Sume } 719156952Sume /* 720156952Sume * Receive length & response 721156952Sume */ 722156952Sume read_len: 723156952Sume cp = ans; 724156952Sume len = INT16SZ; 725156956Sume while ((n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) { 726156952Sume cp += n; 727156952Sume if ((len -= n) == 0) 728156952Sume break; 729156952Sume } 730156952Sume if (n <= 0) { 731156952Sume *terrno = errno; 732156952Sume Perror(statp, stderr, "read failed", errno); 733156952Sume res_nclose(statp); 734156952Sume /* 735156952Sume * A long running process might get its TCP 736156952Sume * connection reset if the remote server was 737156952Sume * restarted. Requery the server instead of 738156952Sume * trying a new one. When there is only one 739156952Sume * server, this means that a query might work 740156952Sume * instead of failing. We only allow one reset 741156952Sume * per query to prevent looping. 742156952Sume */ 743156952Sume if (*terrno == ECONNRESET && !connreset) { 744156952Sume connreset = 1; 745156952Sume res_nclose(statp); 746156952Sume goto same_ns; 747156952Sume } 748156952Sume res_nclose(statp); 749156952Sume return (0); 750156952Sume } 751156952Sume resplen = ns_get16(ans); 752156952Sume if (resplen > anssiz) { 753156952Sume Dprint(statp->options & RES_DEBUG, 754156952Sume (stdout, ";; response truncated\n") 755156952Sume ); 756156952Sume truncating = 1; 757156952Sume len = anssiz; 758156952Sume } else 759156952Sume len = resplen; 760156952Sume if (len < HFIXEDSZ) { 761156952Sume /* 762156952Sume * Undersized message. 763156952Sume */ 764156952Sume Dprint(statp->options & RES_DEBUG, 765156952Sume (stdout, ";; undersized: %d\n", len)); 766156952Sume *terrno = EMSGSIZE; 767156952Sume res_nclose(statp); 768156952Sume return (0); 769156952Sume } 770156952Sume cp = ans; 771156956Sume while (len != 0 && 772156956Sume (n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) { 773156952Sume cp += n; 774156952Sume len -= n; 775156952Sume } 776156952Sume if (n <= 0) { 777156952Sume *terrno = errno; 778156952Sume Perror(statp, stderr, "read(vc)", errno); 779156952Sume res_nclose(statp); 780156952Sume return (0); 781156952Sume } 782156952Sume if (truncating) { 783156952Sume /* 784156952Sume * Flush rest of answer so connection stays in synch. 785156952Sume */ 786156952Sume anhp->tc = 1; 787156952Sume len = resplen - anssiz; 788156952Sume while (len != 0) { 789156952Sume char junk[PACKETSZ]; 790156952Sume 791156956Sume n = _read(statp->_vcsock, junk, 792156956Sume (len > sizeof junk) ? sizeof junk : len); 793156952Sume if (n > 0) 794156952Sume len -= n; 795156952Sume else 796156952Sume break; 797156952Sume } 798156952Sume } 799156952Sume /* 800156952Sume * If the calling applicating has bailed out of 801156952Sume * a previous call and failed to arrange to have 802156952Sume * the circuit closed or the server has got 803156952Sume * itself confused, then drop the packet and 804156952Sume * wait for the correct one. 805156952Sume */ 806156952Sume if (hp->id != anhp->id) { 807156952Sume DprintQ((statp->options & RES_DEBUG) || 808156952Sume (statp->pfcode & RES_PRF_REPLY), 809156952Sume (stdout, ";; old answer (unexpected):\n"), 810156952Sume ans, (resplen > anssiz) ? anssiz: resplen); 811156952Sume goto read_len; 812156952Sume } 813156952Sume 814156952Sume /* 815156952Sume * All is well, or the error is fatal. Signal that the 816156952Sume * next nameserver ought not be tried. 817156952Sume */ 818156952Sume return (resplen); 819156952Sume} 820156952Sume 821156952Sumestatic int 822156952Sumesend_dg(res_state statp, 823156956Sume#ifdef USE_KQUEUE 824156956Sume int kq, 825156956Sume#endif 826163661Sume const u_char *buf, int buflen, u_char *ans, 827186090Sume int anssiz, int *terrno, int ns, int tries, int *v_circuit, 828163661Sume int *gotsomewhere) 829156952Sume{ 830156952Sume const HEADER *hp = (const HEADER *) buf; 831156952Sume HEADER *anhp = (HEADER *) ans; 832156952Sume const struct sockaddr *nsap; 833156952Sume int nsaplen; 834156952Sume struct timespec now, timeout, finish; 835156952Sume struct sockaddr_storage from; 836156952Sume ISC_SOCKLEN_T fromlen; 837156952Sume int resplen, seconds, n, s; 838156956Sume#ifdef USE_KQUEUE 839156956Sume struct kevent kv; 840156956Sume#else 841156952Sume#ifdef USE_POLL 842156952Sume int polltimeout; 843156952Sume struct pollfd pollfd; 844156952Sume#else 845156952Sume fd_set dsmask; 846156952Sume#endif 847156956Sume#endif 848156952Sume 849156952Sume nsap = get_nsaddr(statp, ns); 850156952Sume nsaplen = get_salen(nsap); 851156952Sume if (EXT(statp).nssocks[ns] == -1) { 852156956Sume EXT(statp).nssocks[ns] = _socket(nsap->sa_family, 853255336Sjilles SOCK_DGRAM | SOCK_CLOEXEC, 0); 854167246Sjhb#if !defined(USE_POLL) && !defined(USE_KQUEUE) 855156952Sume if (EXT(statp).nssocks[ns] > highestFD) { 856156952Sume res_nclose(statp); 857156952Sume errno = ENOTSOCK; 858156952Sume } 859167246Sjhb#endif 860156952Sume if (EXT(statp).nssocks[ns] < 0) { 861156952Sume switch (errno) { 862156952Sume case EPROTONOSUPPORT: 863156952Sume#ifdef EPFNOSUPPORT 864156952Sume case EPFNOSUPPORT: 865156952Sume#endif 866156952Sume case EAFNOSUPPORT: 867156952Sume Perror(statp, stderr, "socket(dg)", errno); 868156952Sume return (0); 869156952Sume default: 870156952Sume *terrno = errno; 871156952Sume Perror(statp, stderr, "socket(dg)", errno); 872156952Sume return (-1); 873156952Sume } 874156952Sume } 875156952Sume#ifndef CANNOT_CONNECT_DGRAM 876156952Sume /* 877156952Sume * On a 4.3BSD+ machine (client and server, 878156952Sume * actually), sending to a nameserver datagram 879156952Sume * port with no nameserver will cause an 880156952Sume * ICMP port unreachable message to be returned. 881156952Sume * If our datagram socket is "connected" to the 882156952Sume * server, we get an ECONNREFUSED error on the next 883156952Sume * socket operation, and select returns if the 884156952Sume * error message is received. We can thus detect 885156952Sume * the absence of a nameserver without timing out. 886156956Sume * 887156956Sume * When the option "insecure1" is specified, we'd 888156956Sume * rather expect to see responses from an "unknown" 889156956Sume * address. In order to let the kernel accept such 890156956Sume * responses, do not connect the socket here. 891156956Sume * XXX: or do we need an explicit option to disable 892156956Sume * connecting? 893156952Sume */ 894156956Sume if (!(statp->options & RES_INSECURE1) && 895156956Sume _connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) { 896156952Sume Aerror(statp, stderr, "connect(dg)", errno, nsap, 897156952Sume nsaplen); 898156952Sume res_nclose(statp); 899156952Sume return (0); 900156952Sume } 901156952Sume#endif /* !CANNOT_CONNECT_DGRAM */ 902156952Sume Dprint(statp->options & RES_DEBUG, 903156952Sume (stdout, ";; new DG socket\n")) 904156952Sume } 905156952Sume s = EXT(statp).nssocks[ns]; 906156952Sume#ifndef CANNOT_CONNECT_DGRAM 907156956Sume if (statp->options & RES_INSECURE1) { 908156956Sume if (_sendto(s, 909156956Sume (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) { 910156956Sume Aerror(statp, stderr, "sendto", errno, nsap, nsaplen); 911156956Sume res_nclose(statp); 912156956Sume return (0); 913156956Sume } 914156956Sume } else if (send(s, (const char*)buf, buflen, 0) != buflen) { 915156952Sume Perror(statp, stderr, "send", errno); 916156952Sume res_nclose(statp); 917156952Sume return (0); 918156952Sume } 919156952Sume#else /* !CANNOT_CONNECT_DGRAM */ 920156956Sume if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) 921156952Sume { 922156952Sume Aerror(statp, stderr, "sendto", errno, nsap, nsaplen); 923156952Sume res_nclose(statp); 924156952Sume return (0); 925156952Sume } 926156952Sume#endif /* !CANNOT_CONNECT_DGRAM */ 927156952Sume 928156952Sume /* 929156952Sume * Wait for reply. 930156952Sume */ 931186090Sume seconds = (statp->retrans << tries); 932156952Sume if (ns > 0) 933156952Sume seconds /= statp->nscount; 934156952Sume if (seconds <= 0) 935156952Sume seconds = 1; 936156952Sume now = evNowTime(); 937156952Sume timeout = evConsTime(seconds, 0); 938156952Sume finish = evAddTime(now, timeout); 939156952Sume goto nonow; 940156952Sume wait: 941156952Sume now = evNowTime(); 942156952Sume nonow: 943156952Sume#ifndef USE_POLL 944156952Sume if (evCmpTime(finish, now) > 0) 945156952Sume timeout = evSubTime(finish, now); 946156952Sume else 947156952Sume timeout = evConsTime(0, 0); 948156956Sume#ifdef USE_KQUEUE 949156956Sume EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0); 950156956Sume n = _kevent(kq, &kv, 1, &kv, 1, &timeout); 951156956Sume#else 952156956Sume FD_ZERO(&dsmask); 953156956Sume FD_SET(s, &dsmask); 954156952Sume n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL); 955156956Sume#endif 956156952Sume#else 957156952Sume timeout = evSubTime(finish, now); 958156952Sume if (timeout.tv_sec < 0) 959156952Sume timeout = evConsTime(0, 0); 960156952Sume polltimeout = 1000*timeout.tv_sec + 961156952Sume timeout.tv_nsec/1000000; 962156952Sume pollfd.fd = s; 963156952Sume pollfd.events = POLLRDNORM; 964260652Sjilles n = _poll(&pollfd, 1, polltimeout); 965156952Sume#endif /* USE_POLL */ 966156952Sume 967156952Sume if (n == 0) { 968156952Sume Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n")); 969156952Sume *gotsomewhere = 1; 970156952Sume return (0); 971156952Sume } 972156952Sume if (n < 0) { 973156952Sume if (errno == EINTR) 974156952Sume goto wait; 975156956Sume#ifdef USE_KQUEUE 976156956Sume Perror(statp, stderr, "kevent", errno); 977156956Sume#else 978156952Sume#ifndef USE_POLL 979156952Sume Perror(statp, stderr, "select", errno); 980156952Sume#else 981156952Sume Perror(statp, stderr, "poll", errno); 982156952Sume#endif /* USE_POLL */ 983156956Sume#endif 984156952Sume res_nclose(statp); 985156952Sume return (0); 986156952Sume } 987160967Sume#ifdef USE_KQUEUE 988160967Sume if (kv.ident != s) 989160967Sume goto wait; 990160967Sume#endif 991156952Sume errno = 0; 992156952Sume fromlen = sizeof(from); 993156956Sume resplen = _recvfrom(s, (char*)ans, anssiz,0, 994156952Sume (struct sockaddr *)&from, &fromlen); 995156952Sume if (resplen <= 0) { 996156952Sume Perror(statp, stderr, "recvfrom", errno); 997156952Sume res_nclose(statp); 998156952Sume return (0); 999156952Sume } 1000156952Sume *gotsomewhere = 1; 1001156952Sume if (resplen < HFIXEDSZ) { 1002156952Sume /* 1003156952Sume * Undersized message. 1004156952Sume */ 1005156952Sume Dprint(statp->options & RES_DEBUG, 1006156952Sume (stdout, ";; undersized: %d\n", 1007156952Sume resplen)); 1008156952Sume *terrno = EMSGSIZE; 1009156952Sume res_nclose(statp); 1010156952Sume return (0); 1011156952Sume } 1012156952Sume if (hp->id != anhp->id) { 1013156952Sume /* 1014156952Sume * response from old query, ignore it. 1015156952Sume * XXX - potential security hazard could 1016156952Sume * be detected here. 1017156952Sume */ 1018156952Sume DprintQ((statp->options & RES_DEBUG) || 1019156952Sume (statp->pfcode & RES_PRF_REPLY), 1020156952Sume (stdout, ";; old answer:\n"), 1021156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 1022156952Sume goto wait; 1023156952Sume } 1024156952Sume if (!(statp->options & RES_INSECURE1) && 1025156952Sume !res_ourserver_p(statp, (struct sockaddr *)&from)) { 1026156952Sume /* 1027156952Sume * response from wrong server? ignore it. 1028156952Sume * XXX - potential security hazard could 1029156952Sume * be detected here. 1030156952Sume */ 1031156952Sume DprintQ((statp->options & RES_DEBUG) || 1032156952Sume (statp->pfcode & RES_PRF_REPLY), 1033156952Sume (stdout, ";; not our server:\n"), 1034156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 1035156952Sume goto wait; 1036156952Sume } 1037156952Sume#ifdef RES_USE_EDNS0 1038156952Sume if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) { 1039156952Sume /* 1040156952Sume * Do not retry if the server do not understand EDNS0. 1041156952Sume * The case has to be captured here, as FORMERR packet do not 1042156952Sume * carry query section, hence res_queriesmatch() returns 0. 1043156952Sume */ 1044156952Sume DprintQ(statp->options & RES_DEBUG, 1045156952Sume (stdout, "server rejected query with EDNS0:\n"), 1046156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 1047156952Sume /* record the error */ 1048156952Sume statp->_flags |= RES_F_EDNS0ERR; 1049156952Sume res_nclose(statp); 1050156952Sume return (0); 1051156952Sume } 1052156952Sume#endif 1053156952Sume if (!(statp->options & RES_INSECURE2) && 1054156952Sume !res_queriesmatch(buf, buf + buflen, 1055156952Sume ans, ans + anssiz)) { 1056156952Sume /* 1057156952Sume * response contains wrong query? ignore it. 1058156952Sume * XXX - potential security hazard could 1059156952Sume * be detected here. 1060156952Sume */ 1061156952Sume DprintQ((statp->options & RES_DEBUG) || 1062156952Sume (statp->pfcode & RES_PRF_REPLY), 1063156952Sume (stdout, ";; wrong query name:\n"), 1064156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 1065156952Sume goto wait; 1066156952Sume } 1067156952Sume if (anhp->rcode == SERVFAIL || 1068156952Sume anhp->rcode == NOTIMP || 1069156952Sume anhp->rcode == REFUSED) { 1070156952Sume DprintQ(statp->options & RES_DEBUG, 1071156952Sume (stdout, "server rejected query:\n"), 1072156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 1073156952Sume res_nclose(statp); 1074156952Sume /* don't retry if called from dig */ 1075156952Sume if (!statp->pfcode) 1076156952Sume return (0); 1077156952Sume } 1078156952Sume if (!(statp->options & RES_IGNTC) && anhp->tc) { 1079156952Sume /* 1080156952Sume * To get the rest of answer, 1081156952Sume * use TCP with same server. 1082156952Sume */ 1083156952Sume Dprint(statp->options & RES_DEBUG, 1084156952Sume (stdout, ";; truncated answer\n")); 1085156952Sume *v_circuit = 1; 1086156952Sume res_nclose(statp); 1087156952Sume return (1); 1088156952Sume } 1089156952Sume /* 1090156952Sume * All is well, or the error is fatal. Signal that the 1091156952Sume * next nameserver ought not be tried. 1092156952Sume */ 1093156952Sume return (resplen); 1094156952Sume} 1095156952Sume 1096156952Sumestatic void 1097156952SumeAerror(const res_state statp, FILE *file, const char *string, int error, 1098156952Sume const struct sockaddr *address, int alen) 1099156952Sume{ 1100156952Sume int save = errno; 1101156952Sume char hbuf[NI_MAXHOST]; 1102156952Sume char sbuf[NI_MAXSERV]; 1103156952Sume 1104156952Sume if ((statp->options & RES_DEBUG) != 0U) { 1105156952Sume if (getnameinfo(address, alen, hbuf, sizeof(hbuf), 1106156952Sume sbuf, sizeof(sbuf), niflags)) { 1107156952Sume strncpy(hbuf, "?", sizeof(hbuf) - 1); 1108156952Sume hbuf[sizeof(hbuf) - 1] = '\0'; 1109156952Sume strncpy(sbuf, "?", sizeof(sbuf) - 1); 1110156952Sume sbuf[sizeof(sbuf) - 1] = '\0'; 1111156952Sume } 1112156952Sume fprintf(file, "res_send: %s ([%s].%s): %s\n", 1113156952Sume string, hbuf, sbuf, strerror(error)); 1114156952Sume } 1115156952Sume errno = save; 1116156952Sume} 1117156952Sume 1118156952Sumestatic void 1119156952SumePerror(const res_state statp, FILE *file, const char *string, int error) { 1120156952Sume int save = errno; 1121156952Sume 1122156952Sume if ((statp->options & RES_DEBUG) != 0U) 1123156952Sume fprintf(file, "res_send: %s: %s\n", 1124156952Sume string, strerror(error)); 1125156952Sume errno = save; 1126156952Sume} 1127156952Sume 1128156952Sumestatic int 1129156952Sumesock_eq(struct sockaddr *a, struct sockaddr *b) { 1130156952Sume struct sockaddr_in *a4, *b4; 1131156952Sume struct sockaddr_in6 *a6, *b6; 1132156952Sume 1133156952Sume if (a->sa_family != b->sa_family) 1134156952Sume return 0; 1135156952Sume switch (a->sa_family) { 1136156952Sume case AF_INET: 1137156952Sume a4 = (struct sockaddr_in *)a; 1138156952Sume b4 = (struct sockaddr_in *)b; 1139156952Sume return a4->sin_port == b4->sin_port && 1140156952Sume a4->sin_addr.s_addr == b4->sin_addr.s_addr; 1141156952Sume case AF_INET6: 1142156952Sume a6 = (struct sockaddr_in6 *)a; 1143156952Sume b6 = (struct sockaddr_in6 *)b; 1144156952Sume return a6->sin6_port == b6->sin6_port && 1145156952Sume#ifdef HAVE_SIN6_SCOPE_ID 1146156952Sume a6->sin6_scope_id == b6->sin6_scope_id && 1147156952Sume#endif 1148156952Sume IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr); 1149156952Sume default: 1150156952Sume return 0; 1151156952Sume } 1152156952Sume} 1153156952Sume 1154156956Sume#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE) 1155156952Sume/* XXX needs to move to the porting library. */ 1156156952Sumestatic int 1157156952Sumepselect(int nfds, void *rfds, void *wfds, void *efds, 1158156952Sume struct timespec *tsp, const sigset_t *sigmask) 1159156952Sume{ 1160156952Sume struct timeval tv, *tvp; 1161156952Sume sigset_t sigs; 1162156952Sume int n; 1163156952Sume 1164156952Sume if (tsp) { 1165156952Sume tvp = &tv; 1166156952Sume tv = evTimeVal(*tsp); 1167156952Sume } else 1168156952Sume tvp = NULL; 1169156952Sume if (sigmask) 1170156952Sume sigprocmask(SIG_SETMASK, sigmask, &sigs); 1171156952Sume n = select(nfds, rfds, wfds, efds, tvp); 1172156952Sume if (sigmask) 1173156952Sume sigprocmask(SIG_SETMASK, &sigs, NULL); 1174156952Sume if (tsp) 1175156952Sume *tsp = evTimeSpec(tv); 1176156952Sume return (n); 1177156952Sume} 1178156952Sume#endif 1179