res_send.c revision 165258
1156952Sume/* 2156952Sume * Copyright (c) 1985, 1989, 1993 3156952Sume * The Regents of the University of California. All rights reserved. 4156952Sume * 5156952Sume * Redistribution and use in source and binary forms, with or without 6156952Sume * modification, are permitted provided that the following conditions 7156952Sume * are met: 8156952Sume * 1. Redistributions of source code must retain the above copyright 9156952Sume * notice, this list of conditions and the following disclaimer. 10156952Sume * 2. Redistributions in binary form must reproduce the above copyright 11156952Sume * notice, this list of conditions and the following disclaimer in the 12156952Sume * documentation and/or other materials provided with the distribution. 13156952Sume * 3. All advertising materials mentioning features or use of this software 14156952Sume * must display the following acknowledgement: 15156952Sume * This product includes software developed by the University of 16156952Sume * California, Berkeley and its contributors. 17156952Sume * 4. Neither the name of the University nor the names of its contributors 18156952Sume * may be used to endorse or promote products derived from this software 19156952Sume * without specific prior written permission. 20156952Sume * 21156952Sume * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22156952Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23156952Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24156952Sume * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25156952Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26156952Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27156952Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28156952Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29156952Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30156952Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31156952Sume * SUCH DAMAGE. 32156952Sume */ 33156952Sume 34156952Sume/* 35156952Sume * Portions Copyright (c) 1993 by Digital Equipment Corporation. 36156952Sume * 37156952Sume * Permission to use, copy, modify, and distribute this software for any 38156952Sume * purpose with or without fee is hereby granted, provided that the above 39156952Sume * copyright notice and this permission notice appear in all copies, and that 40156952Sume * the name of Digital Equipment Corporation not be used in advertising or 41156952Sume * publicity pertaining to distribution of the document or software without 42156952Sume * specific, written prior permission. 43156952Sume * 44156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 45156952Sume * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 46156952Sume * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 47156952Sume * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 48156952Sume * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 49156952Sume * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 50156952Sume * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 51156952Sume * SOFTWARE. 52156952Sume */ 53156952Sume 54156952Sume/* 55156952Sume * Copyright (c) 2005 by Internet Systems Consortium, Inc. ("ISC") 56156952Sume * Portions Copyright (c) 1996-1999 by Internet Software Consortium. 57156952Sume * 58156952Sume * Permission to use, copy, modify, and distribute this software for any 59156952Sume * purpose with or without fee is hereby granted, provided that the above 60156952Sume * copyright notice and this permission notice appear in all copies. 61156952Sume * 62156952Sume * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 63156952Sume * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 64156952Sume * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 65156952Sume * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 66156952Sume * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 67156952Sume * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 68156952Sume * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 69156952Sume */ 70156952Sume 71156952Sume#if defined(LIBC_SCCS) && !defined(lint) 72156952Sumestatic const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93"; 73165258Sumestatic const char rcsid[] = "$Id: res_send.c,v 1.5.2.2.4.9 2006/10/16 23:00:50 marka Exp $"; 74156952Sume#endif /* LIBC_SCCS and not lint */ 75156956Sume#include <sys/cdefs.h> 76156956Sume__FBSDID("$FreeBSD: head/lib/libc/resolv/res_send.c 165258 2006-12-15 20:59:55Z ume $"); 77156952Sume 78156952Sume/* 79156952Sume * Send query to name server and wait for reply. 80156952Sume */ 81156952Sume 82156952Sume#include "port_before.h" 83156956Sume#ifndef USE_KQUEUE 84156952Sume#include "fd_setsize.h" 85156956Sume#endif 86156952Sume 87156956Sume#include "namespace.h" 88156952Sume#include <sys/types.h> 89156952Sume#include <sys/param.h> 90156952Sume#include <sys/time.h> 91156952Sume#include <sys/socket.h> 92156952Sume#include <sys/uio.h> 93156952Sume 94156952Sume#include <netinet/in.h> 95156952Sume#include <arpa/nameser.h> 96156952Sume#include <arpa/inet.h> 97156952Sume 98156952Sume#include <errno.h> 99156952Sume#include <netdb.h> 100156952Sume#include <resolv.h> 101156952Sume#include <signal.h> 102156952Sume#include <stdio.h> 103156952Sume#include <stdlib.h> 104156952Sume#include <string.h> 105156952Sume#include <unistd.h> 106156952Sume 107156952Sume#include <isc/eventlib.h> 108156952Sume 109156952Sume#include "port_after.h" 110156952Sume 111156956Sume#ifdef USE_KQUEUE 112156956Sume#include <sys/event.h> 113156956Sume#else 114156952Sume#ifdef USE_POLL 115156952Sume#ifdef HAVE_STROPTS_H 116156952Sume#include <stropts.h> 117156952Sume#endif 118156952Sume#include <poll.h> 119156952Sume#endif /* USE_POLL */ 120156956Sume#endif 121156952Sume 122156956Sume#include "un-namespace.h" 123156956Sume 124156952Sume/* Options. Leave them on. */ 125156952Sume#define DEBUG 126156952Sume#include "res_debug.h" 127156952Sume#include "res_private.h" 128156952Sume 129156952Sume#define EXT(res) ((res)->_u._ext) 130156952Sume 131156952Sume#ifndef USE_POLL 132156952Sumestatic const int highestFD = FD_SETSIZE - 1; 133156952Sume#else 134156952Sumestatic int highestFD = 0; 135156952Sume#endif 136156952Sume 137156952Sume/* Forward. */ 138156952Sume 139156956Sumestatic int get_salen(const struct sockaddr *); 140156956Sumestatic struct sockaddr * get_nsaddr(res_state, size_t); 141156952Sumestatic int send_vc(res_state, const u_char *, int, 142156952Sume u_char *, int, int *, int); 143156956Sumestatic int send_dg(res_state, 144156956Sume#ifdef USE_KQUEUE 145156956Sume int kq, 146156956Sume#endif 147156956Sume const u_char *, int, 148163661Sume u_char *, int, int *, int, int, 149156952Sume int *, int *); 150156952Sumestatic void Aerror(const res_state, FILE *, const char *, int, 151156952Sume const struct sockaddr *, int); 152156952Sumestatic void Perror(const res_state, FILE *, const char *, int); 153156952Sumestatic int sock_eq(struct sockaddr *, struct sockaddr *); 154156956Sume#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE) 155156952Sumestatic int pselect(int, void *, void *, void *, 156156952Sume struct timespec *, 157156952Sume const sigset_t *); 158156952Sume#endif 159156952Sumevoid res_pquery(const res_state, const u_char *, int, FILE *); 160156952Sume 161156952Sumestatic const int niflags = NI_NUMERICHOST | NI_NUMERICSERV; 162156952Sume 163156952Sume/* Public. */ 164156952Sume 165156952Sume/* int 166156952Sume * res_isourserver(ina) 167156952Sume * looks up "ina" in _res.ns_addr_list[] 168156952Sume * returns: 169156952Sume * 0 : not found 170156952Sume * >0 : found 171156952Sume * author: 172156952Sume * paul vixie, 29may94 173156952Sume */ 174156952Sumeint 175156952Sumeres_ourserver_p(const res_state statp, const struct sockaddr *sa) { 176156952Sume const struct sockaddr_in *inp, *srv; 177156952Sume const struct sockaddr_in6 *in6p, *srv6; 178156952Sume int ns; 179156952Sume 180156952Sume switch (sa->sa_family) { 181156952Sume case AF_INET: 182156952Sume inp = (const struct sockaddr_in *)sa; 183156952Sume for (ns = 0; ns < statp->nscount; ns++) { 184156952Sume srv = (struct sockaddr_in *)get_nsaddr(statp, ns); 185156952Sume if (srv->sin_family == inp->sin_family && 186156952Sume srv->sin_port == inp->sin_port && 187156952Sume (srv->sin_addr.s_addr == INADDR_ANY || 188156952Sume srv->sin_addr.s_addr == inp->sin_addr.s_addr)) 189156952Sume return (1); 190156952Sume } 191156952Sume break; 192156952Sume case AF_INET6: 193156952Sume if (EXT(statp).ext == NULL) 194156952Sume break; 195156952Sume in6p = (const struct sockaddr_in6 *)sa; 196156952Sume for (ns = 0; ns < statp->nscount; ns++) { 197156952Sume srv6 = (struct sockaddr_in6 *)get_nsaddr(statp, ns); 198156952Sume if (srv6->sin6_family == in6p->sin6_family && 199156952Sume srv6->sin6_port == in6p->sin6_port && 200156952Sume#ifdef HAVE_SIN6_SCOPE_ID 201156952Sume (srv6->sin6_scope_id == 0 || 202156952Sume srv6->sin6_scope_id == in6p->sin6_scope_id) && 203156952Sume#endif 204156952Sume (IN6_IS_ADDR_UNSPECIFIED(&srv6->sin6_addr) || 205156952Sume IN6_ARE_ADDR_EQUAL(&srv6->sin6_addr, &in6p->sin6_addr))) 206156952Sume return (1); 207156952Sume } 208156952Sume break; 209156952Sume default: 210156952Sume break; 211156952Sume } 212156952Sume return (0); 213156952Sume} 214156952Sume 215156952Sume/* int 216156952Sume * res_nameinquery(name, type, class, buf, eom) 217156952Sume * look for (name,type,class) in the query section of packet (buf,eom) 218156952Sume * requires: 219156952Sume * buf + HFIXEDSZ <= eom 220156952Sume * returns: 221156952Sume * -1 : format error 222156952Sume * 0 : not found 223156952Sume * >0 : found 224156952Sume * author: 225156952Sume * paul vixie, 29may94 226156952Sume */ 227156952Sumeint 228156952Sumeres_nameinquery(const char *name, int type, int class, 229156952Sume const u_char *buf, const u_char *eom) 230156952Sume{ 231156952Sume const u_char *cp = buf + HFIXEDSZ; 232156952Sume int qdcount = ntohs(((const HEADER*)buf)->qdcount); 233156952Sume 234156952Sume while (qdcount-- > 0) { 235156952Sume char tname[MAXDNAME+1]; 236156952Sume int n, ttype, tclass; 237156952Sume 238156952Sume n = dn_expand(buf, eom, cp, tname, sizeof tname); 239156952Sume if (n < 0) 240156952Sume return (-1); 241156952Sume cp += n; 242156952Sume if (cp + 2 * INT16SZ > eom) 243156952Sume return (-1); 244156952Sume ttype = ns_get16(cp); cp += INT16SZ; 245156952Sume tclass = ns_get16(cp); cp += INT16SZ; 246156952Sume if (ttype == type && tclass == class && 247156952Sume ns_samename(tname, name) == 1) 248156952Sume return (1); 249156952Sume } 250156952Sume return (0); 251156952Sume} 252156952Sume 253156952Sume/* int 254156952Sume * res_queriesmatch(buf1, eom1, buf2, eom2) 255156952Sume * is there a 1:1 mapping of (name,type,class) 256156952Sume * in (buf1,eom1) and (buf2,eom2)? 257156952Sume * returns: 258156952Sume * -1 : format error 259156952Sume * 0 : not a 1:1 mapping 260156952Sume * >0 : is a 1:1 mapping 261156952Sume * author: 262156952Sume * 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{ 306156952Sume int gotsomewhere, terrno, try, v_circuit, resplen, ns, n; 307156956Sume#ifdef USE_KQUEUE 308156956Sume int kq; 309156956Sume#endif 310156952Sume char abuf[NI_MAXHOST]; 311156952Sume 312156952Sume#ifdef USE_POLL 313156952Sume highestFD = sysconf(_SC_OPEN_MAX) - 1; 314156952Sume#endif 315156952Sume 316165258Sume /* No name servers or res_init() failure */ 317165258Sume if (statp->nscount == 0 || EXT(statp).ext == NULL) { 318156952Sume errno = ESRCH; 319156952Sume return (-1); 320156952Sume } 321156952Sume if (anssiz < HFIXEDSZ) { 322156952Sume errno = EINVAL; 323156952Sume return (-1); 324156952Sume } 325156952Sume DprintQ((statp->options & RES_DEBUG) || (statp->pfcode & RES_PRF_QUERY), 326156952Sume (stdout, ";; res_send()\n"), buf, buflen); 327156952Sume v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ; 328156952Sume gotsomewhere = 0; 329156952Sume terrno = ETIMEDOUT; 330156952Sume 331156956Sume#ifdef USE_KQUEUE 332156956Sume if ((kq = kqueue()) < 0) { 333156956Sume Perror(statp, stderr, "kqueue", errno); 334156956Sume return (-1); 335156956Sume } 336156956Sume#endif 337156956Sume 338156952Sume /* 339156952Sume * If the ns_addr_list in the resolver context has changed, then 340156952Sume * invalidate our cached copy and the associated timing data. 341156952Sume */ 342156952Sume if (EXT(statp).nscount != 0) { 343156952Sume int needclose = 0; 344156952Sume struct sockaddr_storage peer; 345156952Sume ISC_SOCKLEN_T peerlen; 346156952Sume 347156952Sume if (EXT(statp).nscount != statp->nscount) 348156952Sume needclose++; 349156952Sume else 350156952Sume for (ns = 0; ns < statp->nscount; ns++) { 351156952Sume if (statp->nsaddr_list[ns].sin_family && 352156952Sume !sock_eq((struct sockaddr *)&statp->nsaddr_list[ns], 353156952Sume (struct sockaddr *)&EXT(statp).ext->nsaddrs[ns])) { 354156952Sume needclose++; 355156952Sume break; 356156952Sume } 357156952Sume 358156952Sume if (EXT(statp).nssocks[ns] == -1) 359156952Sume continue; 360156952Sume peerlen = sizeof(peer); 361156956Sume if (_getsockname(EXT(statp).nssocks[ns], 362156952Sume (struct sockaddr *)&peer, &peerlen) < 0) { 363156952Sume needclose++; 364156952Sume break; 365156952Sume } 366156952Sume if (!sock_eq((struct sockaddr *)&peer, 367156952Sume get_nsaddr(statp, ns))) { 368156952Sume needclose++; 369156952Sume break; 370156952Sume } 371156952Sume } 372156952Sume if (needclose) { 373156952Sume res_nclose(statp); 374156952Sume EXT(statp).nscount = 0; 375156952Sume } 376156952Sume } 377156952Sume 378156952Sume /* 379156952Sume * Maybe initialize our private copy of the ns_addr_list. 380156952Sume */ 381156952Sume if (EXT(statp).nscount == 0) { 382156952Sume for (ns = 0; ns < statp->nscount; ns++) { 383156952Sume EXT(statp).nstimes[ns] = RES_MAXTIME; 384156952Sume EXT(statp).nssocks[ns] = -1; 385156952Sume if (!statp->nsaddr_list[ns].sin_family) 386156952Sume continue; 387156952Sume EXT(statp).ext->nsaddrs[ns].sin = 388156952Sume statp->nsaddr_list[ns]; 389156952Sume } 390156952Sume EXT(statp).nscount = statp->nscount; 391156952Sume } 392156952Sume 393156952Sume /* 394156952Sume * Some resolvers want to even out the load on their nameservers. 395156952Sume * Note that RES_BLAST overrides RES_ROTATE. 396156952Sume */ 397156952Sume if ((statp->options & RES_ROTATE) != 0U && 398156952Sume (statp->options & RES_BLAST) == 0U) { 399156952Sume union res_sockaddr_union inu; 400156952Sume struct sockaddr_in ina; 401156952Sume int lastns = statp->nscount - 1; 402156952Sume int fd; 403156952Sume u_int16_t nstime; 404156952Sume 405156952Sume if (EXT(statp).ext != NULL) 406156952Sume inu = EXT(statp).ext->nsaddrs[0]; 407156952Sume ina = statp->nsaddr_list[0]; 408156952Sume fd = EXT(statp).nssocks[0]; 409156952Sume nstime = EXT(statp).nstimes[0]; 410156952Sume for (ns = 0; ns < lastns; ns++) { 411156952Sume if (EXT(statp).ext != NULL) 412156952Sume EXT(statp).ext->nsaddrs[ns] = 413156952Sume EXT(statp).ext->nsaddrs[ns + 1]; 414156952Sume statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1]; 415156952Sume EXT(statp).nssocks[ns] = EXT(statp).nssocks[ns + 1]; 416156952Sume EXT(statp).nstimes[ns] = EXT(statp).nstimes[ns + 1]; 417156952Sume } 418156952Sume if (EXT(statp).ext != NULL) 419156952Sume EXT(statp).ext->nsaddrs[lastns] = inu; 420156952Sume statp->nsaddr_list[lastns] = ina; 421156952Sume EXT(statp).nssocks[lastns] = fd; 422156952Sume EXT(statp).nstimes[lastns] = nstime; 423156952Sume } 424156952Sume 425156952Sume /* 426156952Sume * Send request, RETRY times, or until successful. 427156952Sume */ 428156952Sume for (try = 0; try < statp->retry; try++) { 429156952Sume for (ns = 0; ns < statp->nscount; ns++) { 430156952Sume struct sockaddr *nsap; 431156952Sume int nsaplen; 432156952Sume nsap = get_nsaddr(statp, ns); 433156952Sume nsaplen = get_salen(nsap); 434156952Sume statp->_flags &= ~RES_F_LASTMASK; 435156952Sume statp->_flags |= (ns << RES_F_LASTSHIFT); 436156952Sume same_ns: 437156952Sume if (statp->qhook) { 438156952Sume int done = 0, loops = 0; 439156952Sume 440156952Sume do { 441156952Sume res_sendhookact act; 442156952Sume 443156952Sume act = (*statp->qhook)(&nsap, &buf, &buflen, 444156952Sume ans, anssiz, &resplen); 445156952Sume switch (act) { 446156952Sume case res_goahead: 447156952Sume done = 1; 448156952Sume break; 449156952Sume case res_nextns: 450156952Sume res_nclose(statp); 451156952Sume goto next_ns; 452156952Sume case res_done: 453156956Sume#ifdef USE_KQUEUE 454156956Sume _close(kq); 455156956Sume#endif 456156952Sume return (resplen); 457156952Sume case res_modified: 458156952Sume /* give the hook another try */ 459156952Sume if (++loops < 42) /*doug adams*/ 460156952Sume break; 461156952Sume /*FALLTHROUGH*/ 462156952Sume case res_error: 463156952Sume /*FALLTHROUGH*/ 464156952Sume default: 465156952Sume goto fail; 466156952Sume } 467156952Sume } while (!done); 468156952Sume } 469156952Sume 470156952Sume Dprint(((statp->options & RES_DEBUG) && 471156952Sume getnameinfo(nsap, nsaplen, abuf, sizeof(abuf), 472156952Sume NULL, 0, niflags) == 0), 473156952Sume (stdout, ";; Querying server (# %d) address = %s\n", 474156952Sume ns + 1, abuf)); 475156952Sume 476156952Sume 477156952Sume if (v_circuit) { 478156952Sume /* Use VC; at most one attempt per server. */ 479156952Sume try = statp->retry; 480156952Sume n = send_vc(statp, buf, buflen, ans, anssiz, &terrno, 481156952Sume ns); 482156952Sume if (n < 0) 483156952Sume goto fail; 484156952Sume if (n == 0) 485156952Sume goto next_ns; 486156952Sume resplen = n; 487156952Sume } else { 488156952Sume /* Use datagrams. */ 489156956Sume n = send_dg(statp, 490156956Sume#ifdef USE_KQUEUE 491156956Sume kq, 492156956Sume#endif 493156956Sume buf, buflen, ans, anssiz, &terrno, 494163661Sume ns, try, &v_circuit, &gotsomewhere); 495156952Sume if (n < 0) 496156952Sume goto fail; 497156952Sume if (n == 0) 498156952Sume goto next_ns; 499156952Sume if (v_circuit) 500156952Sume goto same_ns; 501156952Sume resplen = n; 502156952Sume } 503156952Sume 504156952Sume Dprint((statp->options & RES_DEBUG) || 505156952Sume ((statp->pfcode & RES_PRF_REPLY) && 506156952Sume (statp->pfcode & RES_PRF_HEAD1)), 507156952Sume (stdout, ";; got answer:\n")); 508156952Sume 509156952Sume DprintQ((statp->options & RES_DEBUG) || 510156952Sume (statp->pfcode & RES_PRF_REPLY), 511156952Sume (stdout, "%s", ""), 512156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 513156952Sume 514156952Sume /* 515156952Sume * If we have temporarily opened a virtual circuit, 516156952Sume * or if we haven't been asked to keep a socket open, 517156952Sume * close the socket. 518156952Sume */ 519156952Sume if ((v_circuit && (statp->options & RES_USEVC) == 0U) || 520156952Sume (statp->options & RES_STAYOPEN) == 0U) { 521156952Sume res_nclose(statp); 522156952Sume } 523156952Sume if (statp->rhook) { 524156952Sume int done = 0, loops = 0; 525156952Sume 526156952Sume do { 527156952Sume res_sendhookact act; 528156952Sume 529156952Sume act = (*statp->rhook)(nsap, buf, buflen, 530156952Sume ans, anssiz, &resplen); 531156952Sume switch (act) { 532156952Sume case res_goahead: 533156952Sume case res_done: 534156952Sume done = 1; 535156952Sume break; 536156952Sume case res_nextns: 537156952Sume res_nclose(statp); 538156952Sume goto next_ns; 539156952Sume case res_modified: 540156952Sume /* give the hook another try */ 541156952Sume if (++loops < 42) /*doug adams*/ 542156952Sume break; 543156952Sume /*FALLTHROUGH*/ 544156952Sume case res_error: 545156952Sume /*FALLTHROUGH*/ 546156952Sume default: 547156952Sume goto fail; 548156952Sume } 549156952Sume } while (!done); 550156952Sume 551156952Sume } 552156956Sume#ifdef USE_KQUEUE 553156956Sume _close(kq); 554156956Sume#endif 555156952Sume return (resplen); 556156952Sume next_ns: ; 557156952Sume } /*foreach ns*/ 558156952Sume } /*foreach retry*/ 559156952Sume res_nclose(statp); 560156956Sume#ifdef USE_KQUEUE 561156956Sume _close(kq); 562156956Sume#endif 563156952Sume if (!v_circuit) { 564156952Sume if (!gotsomewhere) 565156952Sume errno = ECONNREFUSED; /* no nameservers found */ 566156952Sume else 567156952Sume errno = ETIMEDOUT; /* no answer obtained */ 568156952Sume } else 569156952Sume errno = terrno; 570156952Sume return (-1); 571156952Sume fail: 572156952Sume res_nclose(statp); 573156956Sume#ifdef USE_KQUEUE 574156956Sume _close(kq); 575156956Sume#endif 576156952Sume return (-1); 577156952Sume} 578156952Sume 579156952Sume/* Private */ 580156952Sume 581156952Sumestatic int 582156952Sumeget_salen(sa) 583156952Sume const struct sockaddr *sa; 584156952Sume{ 585156952Sume 586156952Sume#ifdef HAVE_SA_LEN 587156952Sume /* There are people do not set sa_len. Be forgiving to them. */ 588156952Sume if (sa->sa_len) 589156952Sume return (sa->sa_len); 590156952Sume#endif 591156952Sume 592156952Sume if (sa->sa_family == AF_INET) 593156952Sume return (sizeof(struct sockaddr_in)); 594156952Sume else if (sa->sa_family == AF_INET6) 595156952Sume return (sizeof(struct sockaddr_in6)); 596156952Sume else 597156952Sume return (0); /* unknown, die on connect */ 598156952Sume} 599156952Sume 600156952Sume/* 601156952Sume * pick appropriate nsaddr_list for use. see res_init() for initialization. 602156952Sume */ 603156952Sumestatic struct sockaddr * 604156952Sumeget_nsaddr(statp, n) 605156952Sume res_state statp; 606156952Sume size_t n; 607156952Sume{ 608156952Sume 609156952Sume if (!statp->nsaddr_list[n].sin_family && EXT(statp).ext) { 610156952Sume /* 611156952Sume * - EXT(statp).ext->nsaddrs[n] holds an address that is larger 612156952Sume * than struct sockaddr, and 613156952Sume * - user code did not update statp->nsaddr_list[n]. 614156952Sume */ 615156952Sume return (struct sockaddr *)(void *)&EXT(statp).ext->nsaddrs[n]; 616156952Sume } else { 617156952Sume /* 618156952Sume * - user code updated statp->nsaddr_list[n], or 619156952Sume * - statp->nsaddr_list[n] has the same content as 620156952Sume * EXT(statp).ext->nsaddrs[n]. 621156952Sume */ 622156952Sume return (struct sockaddr *)(void *)&statp->nsaddr_list[n]; 623156952Sume } 624156952Sume} 625156952Sume 626156952Sumestatic int 627156952Sumesend_vc(res_state statp, 628156952Sume const u_char *buf, int buflen, u_char *ans, int anssiz, 629156952Sume int *terrno, int ns) 630156952Sume{ 631156952Sume const HEADER *hp = (const HEADER *) buf; 632156952Sume HEADER *anhp = (HEADER *) ans; 633156952Sume struct sockaddr *nsap; 634156952Sume int nsaplen; 635156952Sume int truncating, connreset, resplen, n; 636156952Sume struct iovec iov[2]; 637156952Sume u_short len; 638156952Sume u_char *cp; 639156952Sume void *tmp; 640156952Sume 641156952Sume nsap = get_nsaddr(statp, ns); 642156952Sume nsaplen = get_salen(nsap); 643156952Sume 644156952Sume connreset = 0; 645156952Sume same_ns: 646156952Sume truncating = 0; 647156952Sume 648156952Sume /* Are we still talking to whom we want to talk to? */ 649156952Sume if (statp->_vcsock >= 0 && (statp->_flags & RES_F_VC) != 0) { 650156952Sume struct sockaddr_storage peer; 651156952Sume ISC_SOCKLEN_T size = sizeof peer; 652156952Sume 653156956Sume if (_getpeername(statp->_vcsock, 654156952Sume (struct sockaddr *)&peer, &size) < 0 || 655156952Sume !sock_eq((struct sockaddr *)&peer, nsap)) { 656156952Sume res_nclose(statp); 657156952Sume statp->_flags &= ~RES_F_VC; 658156952Sume } 659156952Sume } 660156952Sume 661156952Sume if (statp->_vcsock < 0 || (statp->_flags & RES_F_VC) == 0) { 662156952Sume if (statp->_vcsock >= 0) 663156952Sume res_nclose(statp); 664156952Sume 665156956Sume statp->_vcsock = _socket(nsap->sa_family, SOCK_STREAM, 0); 666156952Sume if (statp->_vcsock > highestFD) { 667156952Sume res_nclose(statp); 668156952Sume errno = ENOTSOCK; 669156952Sume } 670156952Sume if (statp->_vcsock < 0) { 671156952Sume switch (errno) { 672156952Sume case EPROTONOSUPPORT: 673156952Sume#ifdef EPFNOSUPPORT 674156952Sume case EPFNOSUPPORT: 675156952Sume#endif 676156952Sume case EAFNOSUPPORT: 677156952Sume Perror(statp, stderr, "socket(vc)", errno); 678156952Sume return (0); 679156952Sume default: 680156952Sume *terrno = errno; 681156952Sume Perror(statp, stderr, "socket(vc)", errno); 682156952Sume return (-1); 683156952Sume } 684156952Sume } 685156952Sume errno = 0; 686156956Sume if (_connect(statp->_vcsock, nsap, nsaplen) < 0) { 687156952Sume *terrno = errno; 688156952Sume Aerror(statp, stderr, "connect/vc", errno, nsap, 689156952Sume nsaplen); 690156952Sume res_nclose(statp); 691156952Sume return (0); 692156952Sume } 693156952Sume statp->_flags |= RES_F_VC; 694156952Sume } 695156952Sume 696156952Sume /* 697156952Sume * Send length & message 698156952Sume */ 699156952Sume ns_put16((u_short)buflen, (u_char*)&len); 700156952Sume iov[0] = evConsIovec(&len, INT16SZ); 701156952Sume DE_CONST(buf, tmp); 702156952Sume iov[1] = evConsIovec(tmp, buflen); 703156956Sume if (_writev(statp->_vcsock, iov, 2) != (INT16SZ + buflen)) { 704156952Sume *terrno = errno; 705156952Sume Perror(statp, stderr, "write failed", errno); 706156952Sume res_nclose(statp); 707156952Sume return (0); 708156952Sume } 709156952Sume /* 710156952Sume * Receive length & response 711156952Sume */ 712156952Sume read_len: 713156952Sume cp = ans; 714156952Sume len = INT16SZ; 715156956Sume while ((n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) { 716156952Sume cp += n; 717156952Sume if ((len -= n) == 0) 718156952Sume break; 719156952Sume } 720156952Sume if (n <= 0) { 721156952Sume *terrno = errno; 722156952Sume Perror(statp, stderr, "read failed", errno); 723156952Sume res_nclose(statp); 724156952Sume /* 725156952Sume * A long running process might get its TCP 726156952Sume * connection reset if the remote server was 727156952Sume * restarted. Requery the server instead of 728156952Sume * trying a new one. When there is only one 729156952Sume * server, this means that a query might work 730156952Sume * instead of failing. We only allow one reset 731156952Sume * per query to prevent looping. 732156952Sume */ 733156952Sume if (*terrno == ECONNRESET && !connreset) { 734156952Sume connreset = 1; 735156952Sume res_nclose(statp); 736156952Sume goto same_ns; 737156952Sume } 738156952Sume res_nclose(statp); 739156952Sume return (0); 740156952Sume } 741156952Sume resplen = ns_get16(ans); 742156952Sume if (resplen > anssiz) { 743156952Sume Dprint(statp->options & RES_DEBUG, 744156952Sume (stdout, ";; response truncated\n") 745156952Sume ); 746156952Sume truncating = 1; 747156952Sume len = anssiz; 748156952Sume } else 749156952Sume len = resplen; 750156952Sume if (len < HFIXEDSZ) { 751156952Sume /* 752156952Sume * Undersized message. 753156952Sume */ 754156952Sume Dprint(statp->options & RES_DEBUG, 755156952Sume (stdout, ";; undersized: %d\n", len)); 756156952Sume *terrno = EMSGSIZE; 757156952Sume res_nclose(statp); 758156952Sume return (0); 759156952Sume } 760156952Sume cp = ans; 761156956Sume while (len != 0 && 762156956Sume (n = _read(statp->_vcsock, (char *)cp, (int)len)) > 0) { 763156952Sume cp += n; 764156952Sume len -= n; 765156952Sume } 766156952Sume if (n <= 0) { 767156952Sume *terrno = errno; 768156952Sume Perror(statp, stderr, "read(vc)", errno); 769156952Sume res_nclose(statp); 770156952Sume return (0); 771156952Sume } 772156952Sume if (truncating) { 773156952Sume /* 774156952Sume * Flush rest of answer so connection stays in synch. 775156952Sume */ 776156952Sume anhp->tc = 1; 777156952Sume len = resplen - anssiz; 778156952Sume while (len != 0) { 779156952Sume char junk[PACKETSZ]; 780156952Sume 781156956Sume n = _read(statp->_vcsock, junk, 782156956Sume (len > sizeof junk) ? sizeof junk : len); 783156952Sume if (n > 0) 784156952Sume len -= n; 785156952Sume else 786156952Sume break; 787156952Sume } 788156952Sume } 789156952Sume /* 790156952Sume * If the calling applicating has bailed out of 791156952Sume * a previous call and failed to arrange to have 792156952Sume * the circuit closed or the server has got 793156952Sume * itself confused, then drop the packet and 794156952Sume * wait for the correct one. 795156952Sume */ 796156952Sume if (hp->id != anhp->id) { 797156952Sume DprintQ((statp->options & RES_DEBUG) || 798156952Sume (statp->pfcode & RES_PRF_REPLY), 799156952Sume (stdout, ";; old answer (unexpected):\n"), 800156952Sume ans, (resplen > anssiz) ? anssiz: resplen); 801156952Sume goto read_len; 802156952Sume } 803156952Sume 804156952Sume /* 805156952Sume * All is well, or the error is fatal. Signal that the 806156952Sume * next nameserver ought not be tried. 807156952Sume */ 808156952Sume return (resplen); 809156952Sume} 810156952Sume 811156952Sumestatic int 812156952Sumesend_dg(res_state statp, 813156956Sume#ifdef USE_KQUEUE 814156956Sume int kq, 815156956Sume#endif 816163661Sume const u_char *buf, int buflen, u_char *ans, 817163661Sume int anssiz, int *terrno, int ns, int try, int *v_circuit, 818163661Sume int *gotsomewhere) 819156952Sume{ 820156952Sume const HEADER *hp = (const HEADER *) buf; 821156952Sume HEADER *anhp = (HEADER *) ans; 822156952Sume const struct sockaddr *nsap; 823156952Sume int nsaplen; 824156952Sume struct timespec now, timeout, finish; 825156952Sume struct sockaddr_storage from; 826156952Sume ISC_SOCKLEN_T fromlen; 827156952Sume int resplen, seconds, n, s; 828156956Sume#ifdef USE_KQUEUE 829156956Sume struct kevent kv; 830156956Sume#else 831156952Sume#ifdef USE_POLL 832156952Sume int polltimeout; 833156952Sume struct pollfd pollfd; 834156952Sume#else 835156952Sume fd_set dsmask; 836156952Sume#endif 837156956Sume#endif 838156952Sume 839156952Sume nsap = get_nsaddr(statp, ns); 840156952Sume nsaplen = get_salen(nsap); 841156952Sume if (EXT(statp).nssocks[ns] == -1) { 842156956Sume EXT(statp).nssocks[ns] = _socket(nsap->sa_family, 843156956Sume SOCK_DGRAM, 0); 844156952Sume if (EXT(statp).nssocks[ns] > highestFD) { 845156952Sume res_nclose(statp); 846156952Sume errno = ENOTSOCK; 847156952Sume } 848156952Sume if (EXT(statp).nssocks[ns] < 0) { 849156952Sume switch (errno) { 850156952Sume case EPROTONOSUPPORT: 851156952Sume#ifdef EPFNOSUPPORT 852156952Sume case EPFNOSUPPORT: 853156952Sume#endif 854156952Sume case EAFNOSUPPORT: 855156952Sume Perror(statp, stderr, "socket(dg)", errno); 856156952Sume return (0); 857156952Sume default: 858156952Sume *terrno = errno; 859156952Sume Perror(statp, stderr, "socket(dg)", errno); 860156952Sume return (-1); 861156952Sume } 862156952Sume } 863156952Sume#ifndef CANNOT_CONNECT_DGRAM 864156952Sume /* 865156952Sume * On a 4.3BSD+ machine (client and server, 866156952Sume * actually), sending to a nameserver datagram 867156952Sume * port with no nameserver will cause an 868156952Sume * ICMP port unreachable message to be returned. 869156952Sume * If our datagram socket is "connected" to the 870156952Sume * server, we get an ECONNREFUSED error on the next 871156952Sume * socket operation, and select returns if the 872156952Sume * error message is received. We can thus detect 873156952Sume * the absence of a nameserver without timing out. 874156956Sume * 875156956Sume * When the option "insecure1" is specified, we'd 876156956Sume * rather expect to see responses from an "unknown" 877156956Sume * address. In order to let the kernel accept such 878156956Sume * responses, do not connect the socket here. 879156956Sume * XXX: or do we need an explicit option to disable 880156956Sume * connecting? 881156952Sume */ 882156956Sume if (!(statp->options & RES_INSECURE1) && 883156956Sume _connect(EXT(statp).nssocks[ns], nsap, nsaplen) < 0) { 884156952Sume Aerror(statp, stderr, "connect(dg)", errno, nsap, 885156952Sume nsaplen); 886156952Sume res_nclose(statp); 887156952Sume return (0); 888156952Sume } 889156952Sume#endif /* !CANNOT_CONNECT_DGRAM */ 890156952Sume Dprint(statp->options & RES_DEBUG, 891156952Sume (stdout, ";; new DG socket\n")) 892156952Sume } 893156952Sume s = EXT(statp).nssocks[ns]; 894156952Sume#ifndef CANNOT_CONNECT_DGRAM 895156956Sume if (statp->options & RES_INSECURE1) { 896156956Sume if (_sendto(s, 897156956Sume (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) { 898156956Sume Aerror(statp, stderr, "sendto", errno, nsap, nsaplen); 899156956Sume res_nclose(statp); 900156956Sume return (0); 901156956Sume } 902156956Sume } else if (send(s, (const char*)buf, buflen, 0) != buflen) { 903156952Sume Perror(statp, stderr, "send", errno); 904156952Sume res_nclose(statp); 905156952Sume return (0); 906156952Sume } 907156952Sume#else /* !CANNOT_CONNECT_DGRAM */ 908156956Sume if (_sendto(s, (const char*)buf, buflen, 0, nsap, nsaplen) != buflen) 909156952Sume { 910156952Sume Aerror(statp, stderr, "sendto", errno, nsap, nsaplen); 911156952Sume res_nclose(statp); 912156952Sume return (0); 913156952Sume } 914156952Sume#endif /* !CANNOT_CONNECT_DGRAM */ 915156952Sume 916156952Sume /* 917156952Sume * Wait for reply. 918156952Sume */ 919163661Sume seconds = (statp->retrans << try); 920156952Sume if (ns > 0) 921156952Sume seconds /= statp->nscount; 922156952Sume if (seconds <= 0) 923156952Sume seconds = 1; 924156952Sume now = evNowTime(); 925156952Sume timeout = evConsTime(seconds, 0); 926156952Sume finish = evAddTime(now, timeout); 927156952Sume goto nonow; 928156952Sume wait: 929156952Sume now = evNowTime(); 930156952Sume nonow: 931156952Sume#ifndef USE_POLL 932156952Sume if (evCmpTime(finish, now) > 0) 933156952Sume timeout = evSubTime(finish, now); 934156952Sume else 935156952Sume timeout = evConsTime(0, 0); 936156956Sume#ifdef USE_KQUEUE 937156956Sume EV_SET(&kv, s, EVFILT_READ, EV_ADD | EV_ONESHOT, 0, 0, 0); 938156956Sume n = _kevent(kq, &kv, 1, &kv, 1, &timeout); 939156956Sume#else 940156956Sume FD_ZERO(&dsmask); 941156956Sume FD_SET(s, &dsmask); 942156952Sume n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL); 943156956Sume#endif 944156952Sume#else 945156952Sume timeout = evSubTime(finish, now); 946156952Sume if (timeout.tv_sec < 0) 947156952Sume timeout = evConsTime(0, 0); 948156952Sume polltimeout = 1000*timeout.tv_sec + 949156952Sume timeout.tv_nsec/1000000; 950156952Sume pollfd.fd = s; 951156952Sume pollfd.events = POLLRDNORM; 952156952Sume n = poll(&pollfd, 1, polltimeout); 953156952Sume#endif /* USE_POLL */ 954156952Sume 955156952Sume if (n == 0) { 956156952Sume Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n")); 957156952Sume *gotsomewhere = 1; 958156952Sume return (0); 959156952Sume } 960156952Sume if (n < 0) { 961156952Sume if (errno == EINTR) 962156952Sume goto wait; 963156956Sume#ifdef USE_KQUEUE 964156956Sume Perror(statp, stderr, "kevent", errno); 965156956Sume#else 966156952Sume#ifndef USE_POLL 967156952Sume Perror(statp, stderr, "select", errno); 968156952Sume#else 969156952Sume Perror(statp, stderr, "poll", errno); 970156952Sume#endif /* USE_POLL */ 971156956Sume#endif 972156952Sume res_nclose(statp); 973156952Sume return (0); 974156952Sume } 975160967Sume#ifdef USE_KQUEUE 976160967Sume if (kv.ident != s) 977160967Sume goto wait; 978160967Sume#endif 979156952Sume errno = 0; 980156952Sume fromlen = sizeof(from); 981156956Sume resplen = _recvfrom(s, (char*)ans, anssiz,0, 982156952Sume (struct sockaddr *)&from, &fromlen); 983156952Sume if (resplen <= 0) { 984156952Sume Perror(statp, stderr, "recvfrom", errno); 985156952Sume res_nclose(statp); 986156952Sume return (0); 987156952Sume } 988156952Sume *gotsomewhere = 1; 989156952Sume if (resplen < HFIXEDSZ) { 990156952Sume /* 991156952Sume * Undersized message. 992156952Sume */ 993156952Sume Dprint(statp->options & RES_DEBUG, 994156952Sume (stdout, ";; undersized: %d\n", 995156952Sume resplen)); 996156952Sume *terrno = EMSGSIZE; 997156952Sume res_nclose(statp); 998156952Sume return (0); 999156952Sume } 1000156952Sume if (hp->id != anhp->id) { 1001156952Sume /* 1002156952Sume * response from old query, ignore it. 1003156952Sume * XXX - potential security hazard could 1004156952Sume * be detected here. 1005156952Sume */ 1006156952Sume DprintQ((statp->options & RES_DEBUG) || 1007156952Sume (statp->pfcode & RES_PRF_REPLY), 1008156952Sume (stdout, ";; old answer:\n"), 1009156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 1010156952Sume goto wait; 1011156952Sume } 1012156952Sume if (!(statp->options & RES_INSECURE1) && 1013156952Sume !res_ourserver_p(statp, (struct sockaddr *)&from)) { 1014156952Sume /* 1015156952Sume * response from wrong server? ignore it. 1016156952Sume * XXX - potential security hazard could 1017156952Sume * be detected here. 1018156952Sume */ 1019156952Sume DprintQ((statp->options & RES_DEBUG) || 1020156952Sume (statp->pfcode & RES_PRF_REPLY), 1021156952Sume (stdout, ";; not our server:\n"), 1022156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 1023156952Sume goto wait; 1024156952Sume } 1025156952Sume#ifdef RES_USE_EDNS0 1026156952Sume if (anhp->rcode == FORMERR && (statp->options & RES_USE_EDNS0) != 0U) { 1027156952Sume /* 1028156952Sume * Do not retry if the server do not understand EDNS0. 1029156952Sume * The case has to be captured here, as FORMERR packet do not 1030156952Sume * carry query section, hence res_queriesmatch() returns 0. 1031156952Sume */ 1032156952Sume DprintQ(statp->options & RES_DEBUG, 1033156952Sume (stdout, "server rejected query with EDNS0:\n"), 1034156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 1035156952Sume /* record the error */ 1036156952Sume statp->_flags |= RES_F_EDNS0ERR; 1037156952Sume res_nclose(statp); 1038156952Sume return (0); 1039156952Sume } 1040156952Sume#endif 1041156952Sume if (!(statp->options & RES_INSECURE2) && 1042156952Sume !res_queriesmatch(buf, buf + buflen, 1043156952Sume ans, ans + anssiz)) { 1044156952Sume /* 1045156952Sume * response contains wrong query? ignore it. 1046156952Sume * XXX - potential security hazard could 1047156952Sume * be detected here. 1048156952Sume */ 1049156952Sume DprintQ((statp->options & RES_DEBUG) || 1050156952Sume (statp->pfcode & RES_PRF_REPLY), 1051156952Sume (stdout, ";; wrong query name:\n"), 1052156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 1053156952Sume goto wait; 1054156952Sume } 1055156952Sume if (anhp->rcode == SERVFAIL || 1056156952Sume anhp->rcode == NOTIMP || 1057156952Sume anhp->rcode == REFUSED) { 1058156952Sume DprintQ(statp->options & RES_DEBUG, 1059156952Sume (stdout, "server rejected query:\n"), 1060156952Sume ans, (resplen > anssiz) ? anssiz : resplen); 1061156952Sume res_nclose(statp); 1062156952Sume /* don't retry if called from dig */ 1063156952Sume if (!statp->pfcode) 1064156952Sume return (0); 1065156952Sume } 1066156952Sume if (!(statp->options & RES_IGNTC) && anhp->tc) { 1067156952Sume /* 1068156952Sume * To get the rest of answer, 1069156952Sume * use TCP with same server. 1070156952Sume */ 1071156952Sume Dprint(statp->options & RES_DEBUG, 1072156952Sume (stdout, ";; truncated answer\n")); 1073156952Sume *v_circuit = 1; 1074156952Sume res_nclose(statp); 1075156952Sume return (1); 1076156952Sume } 1077156952Sume /* 1078156952Sume * All is well, or the error is fatal. Signal that the 1079156952Sume * next nameserver ought not be tried. 1080156952Sume */ 1081156952Sume return (resplen); 1082156952Sume} 1083156952Sume 1084156952Sumestatic void 1085156952SumeAerror(const res_state statp, FILE *file, const char *string, int error, 1086156952Sume const struct sockaddr *address, int alen) 1087156952Sume{ 1088156952Sume int save = errno; 1089156952Sume char hbuf[NI_MAXHOST]; 1090156952Sume char sbuf[NI_MAXSERV]; 1091156952Sume 1092156952Sume alen = alen; 1093156952Sume 1094156952Sume if ((statp->options & RES_DEBUG) != 0U) { 1095156952Sume if (getnameinfo(address, alen, hbuf, sizeof(hbuf), 1096156952Sume sbuf, sizeof(sbuf), niflags)) { 1097156952Sume strncpy(hbuf, "?", sizeof(hbuf) - 1); 1098156952Sume hbuf[sizeof(hbuf) - 1] = '\0'; 1099156952Sume strncpy(sbuf, "?", sizeof(sbuf) - 1); 1100156952Sume sbuf[sizeof(sbuf) - 1] = '\0'; 1101156952Sume } 1102156952Sume fprintf(file, "res_send: %s ([%s].%s): %s\n", 1103156952Sume string, hbuf, sbuf, strerror(error)); 1104156952Sume } 1105156952Sume errno = save; 1106156952Sume} 1107156952Sume 1108156952Sumestatic void 1109156952SumePerror(const res_state statp, FILE *file, const char *string, int error) { 1110156952Sume int save = errno; 1111156952Sume 1112156952Sume if ((statp->options & RES_DEBUG) != 0U) 1113156952Sume fprintf(file, "res_send: %s: %s\n", 1114156952Sume string, strerror(error)); 1115156952Sume errno = save; 1116156952Sume} 1117156952Sume 1118156952Sumestatic int 1119156952Sumesock_eq(struct sockaddr *a, struct sockaddr *b) { 1120156952Sume struct sockaddr_in *a4, *b4; 1121156952Sume struct sockaddr_in6 *a6, *b6; 1122156952Sume 1123156952Sume if (a->sa_family != b->sa_family) 1124156952Sume return 0; 1125156952Sume switch (a->sa_family) { 1126156952Sume case AF_INET: 1127156952Sume a4 = (struct sockaddr_in *)a; 1128156952Sume b4 = (struct sockaddr_in *)b; 1129156952Sume return a4->sin_port == b4->sin_port && 1130156952Sume a4->sin_addr.s_addr == b4->sin_addr.s_addr; 1131156952Sume case AF_INET6: 1132156952Sume a6 = (struct sockaddr_in6 *)a; 1133156952Sume b6 = (struct sockaddr_in6 *)b; 1134156952Sume return a6->sin6_port == b6->sin6_port && 1135156952Sume#ifdef HAVE_SIN6_SCOPE_ID 1136156952Sume a6->sin6_scope_id == b6->sin6_scope_id && 1137156952Sume#endif 1138156952Sume IN6_ARE_ADDR_EQUAL(&a6->sin6_addr, &b6->sin6_addr); 1139156952Sume default: 1140156952Sume return 0; 1141156952Sume } 1142156952Sume} 1143156952Sume 1144156956Sume#if defined(NEED_PSELECT) && !defined(USE_POLL) && !defined(USE_KQUEUE) 1145156952Sume/* XXX needs to move to the porting library. */ 1146156952Sumestatic int 1147156952Sumepselect(int nfds, void *rfds, void *wfds, void *efds, 1148156952Sume struct timespec *tsp, const sigset_t *sigmask) 1149156952Sume{ 1150156952Sume struct timeval tv, *tvp; 1151156952Sume sigset_t sigs; 1152156952Sume int n; 1153156952Sume 1154156952Sume if (tsp) { 1155156952Sume tvp = &tv; 1156156952Sume tv = evTimeVal(*tsp); 1157156952Sume } else 1158156952Sume tvp = NULL; 1159156952Sume if (sigmask) 1160156952Sume sigprocmask(SIG_SETMASK, sigmask, &sigs); 1161156952Sume n = select(nfds, rfds, wfds, efds, tvp); 1162156952Sume if (sigmask) 1163156952Sume sigprocmask(SIG_SETMASK, &sigs, NULL); 1164156952Sume if (tsp) 1165156952Sume *tsp = evTimeSpec(tv); 1166156952Sume return (n); 1167156952Sume} 1168156952Sume#endif 1169