Annotation of embedaddon/dhcp/minires/res_send.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (c) 1985, 1989, 1993
! 3: * The Regents of the University of California. All rights reserved.
! 4: *
! 5: * Redistribution and use in source and binary forms, with or without
! 6: * modification, are permitted provided that the following conditions
! 7: * are met:
! 8: * 1. Redistributions of source code must retain the above copyright
! 9: * notice, this list of conditions and the following disclaimer.
! 10: * 2. Redistributions in binary form must reproduce the above copyright
! 11: * notice, this list of conditions and the following disclaimer in the
! 12: * documentation and/or other materials provided with the distribution.
! 13: * 3. All advertising materials mentioning features or use of this software
! 14: * must display the following acknowledgement:
! 15: * This product includes software developed by the University of
! 16: * California, Berkeley and its contributors.
! 17: * 4. Neither the name of the University nor the names of its contributors
! 18: * may be used to endorse or promote products derived from this software
! 19: * without specific prior written permission.
! 20: *
! 21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
! 22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
! 23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
! 24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
! 25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
! 26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
! 27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
! 28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
! 29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
! 30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
! 31: * SUCH DAMAGE.
! 32: */
! 33:
! 34: /*
! 35: * Portions Copyright (c) 1993 by Digital Equipment Corporation.
! 36: *
! 37: * Permission to use, copy, modify, and distribute this software for any
! 38: * purpose with or without fee is hereby granted, provided that the above
! 39: * copyright notice and this permission notice appear in all copies, and that
! 40: * the name of Digital Equipment Corporation not be used in advertising or
! 41: * publicity pertaining to distribution of the document or software without
! 42: * specific, written prior permission.
! 43: *
! 44: * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
! 45: * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
! 46: * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
! 47: * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
! 48: * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
! 49: * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
! 50: * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
! 51: * SOFTWARE.
! 52: */
! 53:
! 54: /*
! 55: * Portions Copyright (c) 2004,2008-2009
! 56: * by Internet Systems Consortium, Inc. ("ISC")
! 57: * Portions Copyright (c) 1996-2003 by Internet Software Consortium
! 58: *
! 59: * Permission to use, copy, modify, and distribute this software for any
! 60: * purpose with or without fee is hereby granted, provided that the above
! 61: * copyright notice and this permission notice appear in all copies.
! 62: *
! 63: * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
! 64: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 65: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
! 66: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 67: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 68: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
! 69: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 70: *
! 71: * Internet Systems Consortium, Inc.
! 72: * 950 Charter Street
! 73: * Redwood City, CA 94063
! 74: * <info@isc.org>
! 75: * https://www.isc.org/
! 76: */
! 77:
! 78: #if defined(LIBC_SCCS) && !defined(lint)
! 79: static const char sccsid[] = "@(#)res_send.c 8.1 (Berkeley) 6/4/93";
! 80: static const char rcsid[] = "$Id: res_send.c,v 1.11.116.2 2009-07-24 22:04:52 sar Exp $";
! 81: #endif /* LIBC_SCCS and not lint */
! 82:
! 83: /*
! 84: * Send query to name server and wait for reply.
! 85: */
! 86:
! 87: #include <sys/types.h>
! 88: #include <sys/param.h>
! 89: #include <sys/time.h>
! 90: #include <sys/socket.h>
! 91: #include <sys/uio.h>
! 92:
! 93: #include <netinet/in.h>
! 94: #include <arpa/inet.h>
! 95:
! 96: #include <errno.h>
! 97: #include <netdb.h>
! 98: #include <signal.h>
! 99: #include <stdio.h>
! 100: #include <stdlib.h>
! 101: #include <string.h>
! 102: #include <unistd.h>
! 103:
! 104: #include "minires/minires.h"
! 105: #include "arpa/nameser.h"
! 106:
! 107: /* Rename the I/O functions in case we're tracing. */
! 108: #include <omapip/omapip_p.h>
! 109:
! 110: ssize_t trace_mr_send(int, const void *, size_t, int);
! 111: ssize_t trace_mr_recvfrom(int s, void *, size_t, int,
! 112: struct sockaddr *, socklen_t *);
! 113: ssize_t trace_mr_read(int, void *, size_t);
! 114: int trace_mr_connect(int s, struct sockaddr *, socklen_t);
! 115: int trace_mr_socket(int, int, int);
! 116: int trace_mr_bind(int, struct sockaddr *, socklen_t);
! 117: int trace_mr_close(int);
! 118: time_t trace_mr_time(time_t *);
! 119: int trace_mr_select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
! 120: unsigned int trace_mr_res_randomid(unsigned int);
! 121:
! 122: #undef send
! 123: #define send trace_mr_send
! 124: #undef recvfrom
! 125: #define recvfrom trace_mr_recvfrom
! 126: #undef read
! 127: #define read trace_mr_read
! 128: #undef connect
! 129: #define connect trace_mr_connect
! 130: #undef socket
! 131: #define socket trace_mr_socket
! 132: #undef bind
! 133: #define bind trace_mr_bind
! 134: #undef close
! 135: #define close trace_mr_close
! 136: #undef select
! 137: #define select trace_mr_select
! 138: #undef time
! 139: #define time trace_mr_time
! 140:
! 141: #define CHECK_SRVR_ADDR
! 142:
! 143: static int cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2);
! 144: void res_pquery(const res_state, const u_char *, int, FILE *);
! 145:
! 146: /* int
! 147: * res_isourserver(ina)
! 148: * looks up "ina" in _res.ns_addr_list[]
! 149: * returns:
! 150: * 0 : not found
! 151: * >0 : found
! 152: * author:
! 153: * paul vixie, 29may94
! 154: */
! 155: int
! 156: res_ourserver_p(const res_state statp, const struct sockaddr_in *inp) {
! 157: struct sockaddr_in ina;
! 158: int ns;
! 159:
! 160: ina = *inp;
! 161: for (ns = 0; ns < statp->nscount; ns++) {
! 162: const struct sockaddr_in *srv = &statp->nsaddr_list[ns];
! 163:
! 164: if (srv->sin_family == ina.sin_family &&
! 165: srv->sin_port == ina.sin_port &&
! 166: (srv->sin_addr.s_addr == INADDR_ANY ||
! 167: srv->sin_addr.s_addr == ina.sin_addr.s_addr))
! 168: return (1);
! 169: }
! 170: return (0);
! 171: }
! 172:
! 173: /* int
! 174: * res_nameinquery(name, type, class, buf, eom)
! 175: * look for (name,type,class) in the query section of packet (buf,eom)
! 176: * requires:
! 177: * buf + HFIXEDSZ <= eom
! 178: * returns:
! 179: * -1 : format error
! 180: * 0 : not found
! 181: * >0 : found
! 182: * author:
! 183: * paul vixie, 29may94
! 184: */
! 185: int
! 186: res_nameinquery(const char *name, int type, int class,
! 187: const u_char *buf, const u_char *eom)
! 188: {
! 189: const u_char *cp = buf + HFIXEDSZ;
! 190: int qdcount = ntohs(((const HEADER *)buf)->qdcount);
! 191:
! 192: while (qdcount-- > 0) {
! 193: char tname[MAXDNAME+1];
! 194: int n, ttype, tclass;
! 195:
! 196: n = dn_expand(buf, eom, cp, tname, sizeof tname);
! 197: if (n < 0)
! 198: return (-1);
! 199: cp += n;
! 200: if (cp + 2 * INT16SZ > eom)
! 201: return (-1);
! 202: ttype = getUShort(cp); cp += INT16SZ;
! 203: tclass = getUShort(cp); cp += INT16SZ;
! 204: if (ttype == type && tclass == class &&
! 205: ns_samename(tname, name) == 1)
! 206: return (1);
! 207: }
! 208: return (0);
! 209: }
! 210:
! 211: /* int
! 212: * res_queriesmatch(buf1, eom1, buf2, eom2)
! 213: * is there a 1:1 mapping of (name,type,class)
! 214: * in (buf1,eom1) and (buf2,eom2)?
! 215: * returns:
! 216: * -1 : format error
! 217: * 0 : not a 1:1 mapping
! 218: * >0 : is a 1:1 mapping
! 219: * author:
! 220: * paul vixie, 29may94
! 221: */
! 222: int
! 223: res_queriesmatch(const u_char *buf1, const u_char *eom1,
! 224: const u_char *buf2, const u_char *eom2)
! 225: {
! 226: const u_char *cp = buf1 + HFIXEDSZ;
! 227: int qdcount = ntohs(((const HEADER *)buf1)->qdcount);
! 228:
! 229: if (buf1 + HFIXEDSZ > eom1 || buf2 + HFIXEDSZ > eom2)
! 230: return (-1);
! 231:
! 232: /*
! 233: * Only header section present in replies to
! 234: * dynamic update packets.
! 235: */
! 236: if ( (((const HEADER *)buf1)->opcode == ns_o_update) &&
! 237: (((const HEADER *)buf2)->opcode == ns_o_update) )
! 238: return (1);
! 239:
! 240: if (qdcount != ntohs(((const HEADER*)buf2)->qdcount))
! 241: return (0);
! 242: while (qdcount-- > 0) {
! 243: char tname[MAXDNAME+1];
! 244: int n, ttype, tclass;
! 245:
! 246: n = dn_expand(buf1, eom1, cp, tname, sizeof tname);
! 247: if (n < 0)
! 248: return (-1);
! 249: cp += n;
! 250: if (cp + 2 * INT16SZ > eom1)
! 251: return (-1);
! 252: ttype = getUShort(cp); cp += INT16SZ;
! 253: tclass = getUShort(cp); cp += INT16SZ;
! 254: if (!res_nameinquery(tname, ttype, tclass, buf2, eom2))
! 255: return (0);
! 256: }
! 257: return (1);
! 258: }
! 259:
! 260: isc_result_t
! 261: res_nsend(res_state statp,
! 262: double *buf, unsigned buflen,
! 263: double *ans, unsigned anssiz, unsigned *ansret)
! 264: {
! 265: HEADER *hp = (HEADER *) buf;
! 266: HEADER *anhp = (HEADER *) ans;
! 267: int gotsomewhere, connreset, terrno, try, v_circuit, resplen, ns, n;
! 268: u_int badns; /* XXX NSMAX can't exceed #/bits in this variable */
! 269: static int highestFD = FD_SETSIZE - 1;
! 270:
! 271: if (anssiz < HFIXEDSZ) {
! 272: return ISC_R_INVALIDARG;
! 273: }
! 274: DprintQ((statp->options & RES_DEBUG) ||
! 275: (statp->pfcode & RES_PRF_QUERY),
! 276: (stdout, ";; res_send()\n"), buf, buflen);
! 277: v_circuit = (statp->options & RES_USEVC) || buflen > PACKETSZ;
! 278: gotsomewhere = 0;
! 279: connreset = 0;
! 280: terrno = ISC_R_TIMEDOUT;
! 281: badns = 0;
! 282:
! 283: /*
! 284: * Some callers want to even out the load on their resolver list.
! 285: */
! 286: if (statp->nscount > 0 && (statp->options & RES_ROTATE) != 0) {
! 287: struct sockaddr_in ina;
! 288: int lastns = statp->nscount - 1;
! 289:
! 290: ina = statp->nsaddr_list[0];
! 291: for (ns = 0; ns < lastns; ns++)
! 292: statp->nsaddr_list[ns] = statp->nsaddr_list[ns + 1];
! 293: statp->nsaddr_list[lastns] = ina;
! 294: }
! 295:
! 296: #if defined (TRACING)
! 297: trace_mr_statp_setup (statp);
! 298: #endif
! 299:
! 300: /*
! 301: * Send request, RETRY times, or until successful
! 302: */
! 303: for (try = 0; try < statp->retry; try++) {
! 304: for (ns = 0; ns < statp->nscount; ns++) {
! 305: struct sockaddr_in *nsap = &statp->nsaddr_list[ns];
! 306: same_ns:
! 307: if (badns & (1 << ns)) {
! 308: res_nclose(statp);
! 309: goto next_ns;
! 310: }
! 311:
! 312: if (statp->qhook) {
! 313: int done = 0, loops = 0;
! 314:
! 315: do {
! 316: res_sendhookact act;
! 317:
! 318: act = (*statp->qhook)(&nsap, &buf, &buflen,
! 319: ans, anssiz, &resplen);
! 320: switch (act) {
! 321: case res_goahead:
! 322: done = 1;
! 323: break;
! 324: case res_nextns:
! 325: res_nclose(statp);
! 326: goto next_ns;
! 327: case res_done:
! 328: return (resplen);
! 329: case res_modified:
! 330: /* give the hook another try */
! 331: if (++loops < 42) /*doug adams*/
! 332: break;
! 333: /*FALLTHROUGH*/
! 334: case res_error:
! 335: /*FALLTHROUGH*/
! 336: default:
! 337: return ISC_R_UNEXPECTED;
! 338: }
! 339: } while (!done);
! 340: }
! 341:
! 342: Dprint(statp->options & RES_DEBUG,
! 343: (stdout, ";; Querying server (# %d) address = %s\n",
! 344: ns + 1, inet_ntoa(nsap->sin_addr)));
! 345:
! 346: if (v_circuit) {
! 347: int truncated;
! 348: struct iovec iov[2];
! 349: u_short len;
! 350: u_char *cp;
! 351:
! 352: /* Use VC; at most one attempt per server. */
! 353: try = statp->retry;
! 354: truncated = 0;
! 355:
! 356: /* Are we still talking to whom we want to talk to? */
! 357: if (statp->_sock >= 0 &&
! 358: (statp->_flags & RES_F_VC) != 0) {
! 359: struct sockaddr_in peer;
! 360: SOCKLEN_T size = sizeof(peer);
! 361:
! 362: if (getpeername(statp->_sock,
! 363: (struct sockaddr *)&peer,
! 364: &size) < 0) {
! 365: res_nclose(statp);
! 366: statp->_flags &= ~RES_F_VC;
! 367: } else if (!cmpsock(&peer, nsap)) {
! 368: res_nclose(statp);
! 369: statp->_flags &= ~RES_F_VC;
! 370: }
! 371: }
! 372:
! 373: if (statp->_sock < 0 ||
! 374: (statp->_flags & RES_F_VC) == 0) {
! 375: if (statp->_sock >= 0)
! 376: res_nclose(statp);
! 377:
! 378: statp->_sock = socket(PF_INET,
! 379: SOCK_STREAM, 0);
! 380: if (statp->_sock < 0 ||
! 381: statp->_sock > highestFD) {
! 382: terrno = uerr2isc (errno);
! 383: Perror(statp, stderr,
! 384: "socket(vc)", errno);
! 385: return (-1);
! 386: }
! 387: errno = 0;
! 388: if (connect(statp->_sock,
! 389: (struct sockaddr *)nsap,
! 390: sizeof *nsap) < 0) {
! 391: terrno = uerr2isc (errno);
! 392: Aerror(statp, stderr, "connect/vc",
! 393: errno, *nsap);
! 394: badns |= (1 << ns);
! 395: res_nclose(statp);
! 396: goto next_ns;
! 397: }
! 398: statp->_flags |= RES_F_VC;
! 399: }
! 400: /*
! 401: * Send length & message
! 402: */
! 403: putUShort((u_char*)&len, buflen);
! 404: iov[0].iov_base = (caddr_t)&len;
! 405: iov[0].iov_len = INT16SZ;
! 406: iov[1].iov_base = (const caddr_t)buf;
! 407: iov[1].iov_len = buflen;
! 408: if (writev(statp->_sock, iov, 2) !=
! 409: (INT16SZ + buflen)) {
! 410: terrno = uerr2isc (errno);
! 411: Perror(statp, stderr, "write failed", errno);
! 412: badns |= (1 << ns);
! 413: res_nclose(statp);
! 414: goto next_ns;
! 415: }
! 416: /*
! 417: * Receive length & response
! 418: */
! 419: read_len:
! 420: cp = (u_char *)ans;
! 421: len = INT16SZ;
! 422: while ((n = read(statp->_sock,
! 423: (char *)cp, (unsigned)len)) > 0) {
! 424: cp += n;
! 425: if ((len -= n) <= 0)
! 426: break;
! 427: }
! 428: if (n <= 0) {
! 429: terrno = uerr2isc (errno);
! 430: Perror(statp, stderr, "read failed", errno);
! 431: res_nclose(statp);
! 432: /*
! 433: * A long running process might get its TCP
! 434: * connection reset if the remote server was
! 435: * restarted. Requery the server instead of
! 436: * trying a new one. When there is only one
! 437: * server, this means that a query might work
! 438: * instead of failing. We only allow one reset
! 439: * per query to prevent looping.
! 440: */
! 441: if (terrno == ISC_R_CONNREFUSED &&
! 442: !connreset) {
! 443: connreset = 1;
! 444: res_nclose(statp);
! 445: goto same_ns;
! 446: }
! 447: res_nclose(statp);
! 448: goto next_ns;
! 449: }
! 450: resplen = getUShort ((unsigned char *)ans);
! 451: if (resplen > anssiz) {
! 452: Dprint(statp->options & RES_DEBUG,
! 453: (stdout, ";; response truncated\n")
! 454: );
! 455: truncated = 1;
! 456: len = anssiz;
! 457: } else
! 458: len = resplen;
! 459: if (len < HFIXEDSZ) {
! 460: /*
! 461: * Undersized message.
! 462: */
! 463: Dprint(statp->options & RES_DEBUG,
! 464: (stdout, ";; undersized: %d\n", len));
! 465: terrno = ISC_R_NOSPACE;
! 466: badns |= (1 << ns);
! 467: res_nclose(statp);
! 468: goto next_ns;
! 469: }
! 470: cp = (u_char *)ans;
! 471: while (len != 0 &&
! 472: (n = read(statp->_sock,
! 473: (char *)cp, (unsigned)len))
! 474: > 0) {
! 475: cp += n;
! 476: len -= n;
! 477: }
! 478: if (n <= 0) {
! 479: terrno = uerr2isc (errno);
! 480: Perror(statp, stderr, "read(vc)", errno);
! 481: res_nclose(statp);
! 482: goto next_ns;
! 483: }
! 484: if (truncated) {
! 485: /*
! 486: * Flush rest of answer
! 487: * so connection stays in synch.
! 488: */
! 489: anhp->tc = 1;
! 490: len = resplen - anssiz;
! 491: while (len != 0) {
! 492: char junk[PACKETSZ];
! 493:
! 494: n = (len > sizeof(junk)
! 495: ? sizeof(junk)
! 496: : len);
! 497: n = read(statp->_sock,
! 498: junk, (unsigned)n);
! 499: if (n > 0)
! 500: len -= n;
! 501: else
! 502: break;
! 503: }
! 504: }
! 505: /*
! 506: * The calling applicating has bailed out of
! 507: * a previous call and failed to arrange to have
! 508: * the circuit closed or the server has got
! 509: * itself confused. Anyway drop the packet and
! 510: * wait for the correct one.
! 511: */
! 512: if (hp->id != anhp->id) {
! 513: DprintQ((statp->options & RES_DEBUG) ||
! 514: (statp->pfcode & RES_PRF_REPLY),
! 515: (stdout,
! 516: ";; old answer (unexpected):\n"),
! 517: ans, (resplen>anssiz)?anssiz:resplen);
! 518: goto read_len;
! 519: }
! 520: } else {
! 521: /*
! 522: * Use datagrams.
! 523: */
! 524: int start, timeout, finish;
! 525: fd_set dsmask;
! 526: struct sockaddr_in from;
! 527: SOCKLEN_T fromlen;
! 528: int seconds;
! 529:
! 530: if (statp->_sock < 0 ||
! 531: (statp->_flags & RES_F_VC) != 0) {
! 532: if ((statp->_flags & RES_F_VC) != 0)
! 533: res_nclose(statp);
! 534: statp->_sock = socket(PF_INET, SOCK_DGRAM, 0);
! 535: if (statp->_sock < 0 ||
! 536: statp->_sock > highestFD) {
! 537: #ifndef CAN_RECONNECT
! 538: bad_dg_sock:
! 539: #endif
! 540: terrno = uerr2isc (errno);
! 541: Perror(statp, stderr,
! 542: "socket(dg)", errno);
! 543: return terrno;
! 544: }
! 545: statp->_flags &= ~RES_F_CONN;
! 546: }
! 547: #ifndef CANNOT_CONNECT_DGRAM
! 548: /*
! 549: * On a 4.3BSD+ machine (client and server,
! 550: * actually), sending to a nameserver datagram
! 551: * port with no nameserver will cause an
! 552: * ICMP port unreachable message to be returned.
! 553: * If our datagram socket is "connected" to the
! 554: * server, we get an ECONNREFUSED error on the next
! 555: * socket operation, and select returns if the
! 556: * error message is received. We can thus detect
! 557: * the absence of a nameserver without timing out.
! 558: * If we have sent queries to at least two servers,
! 559: * however, we don't want to remain connected,
! 560: * as we wish to receive answers from the first
! 561: * server to respond.
! 562: */
! 563: if (statp->nscount == 1 || (try == 0 && ns == 0)) {
! 564: /*
! 565: * Connect only if we are sure we won't
! 566: * receive a response from another server.
! 567: */
! 568: if ((statp->_flags & RES_F_CONN) == 0) {
! 569: if (connect(statp->_sock,
! 570: (struct sockaddr *)nsap,
! 571: sizeof *nsap) < 0) {
! 572: Aerror(statp, stderr,
! 573: "connect(dg)",
! 574: errno, *nsap);
! 575: badns |= (1 << ns);
! 576: res_nclose(statp);
! 577: goto next_ns;
! 578: }
! 579: statp->_flags |= RES_F_CONN;
! 580: }
! 581: if (send(statp->_sock,
! 582: (const char*)buf, (unsigned)buflen, 0)
! 583: != buflen) {
! 584: Perror(statp, stderr, "send", errno);
! 585: badns |= (1 << ns);
! 586: res_nclose(statp);
! 587: goto next_ns;
! 588: }
! 589: } else {
! 590: /*
! 591: * Disconnect if we want to listen
! 592: * for responses from more than one server.
! 593: */
! 594: if ((statp->_flags & RES_F_CONN) != 0) {
! 595: #ifdef CAN_RECONNECT
! 596: struct sockaddr_in no_addr;
! 597:
! 598: no_addr.sin_family = AF_INET;
! 599: no_addr.sin_addr.s_addr = INADDR_ANY;
! 600: no_addr.sin_port = 0;
! 601: (void) connect(statp->_sock,
! 602: (struct sockaddr *)
! 603: &no_addr,
! 604: sizeof no_addr);
! 605: #else
! 606: struct sockaddr_in local_addr;
! 607: SOCKLEN_T len;
! 608: int result, s1;
! 609:
! 610: len = sizeof(local_addr);
! 611: s1 = socket(PF_INET, SOCK_DGRAM, 0);
! 612: result = getsockname(statp->_sock,
! 613: (struct sockaddr *)&local_addr,
! 614: &len);
! 615: if (s1 < 0)
! 616: goto bad_dg_sock;
! 617: (void) dup2(s1, statp->_sock);
! 618: (void) close(s1);
! 619: if (result == 0) {
! 620: /*
! 621: * Attempt to rebind to old
! 622: * port. Note connected socket
! 623: * has an sin_addr set.
! 624: */
! 625: local_addr.sin_addr.s_addr =
! 626: htonl(0);
! 627: (void)bind(statp->_sock,
! 628: (struct sockaddr *)
! 629: &local_addr,
! 630: (unsigned)len);
! 631: }
! 632: Dprint(statp->options & RES_DEBUG,
! 633: (stdout, ";; new DG socket\n"));
! 634: #endif /* CAN_RECONNECT */
! 635: statp->_flags &= ~RES_F_CONN;
! 636: errno = 0;
! 637: }
! 638: #endif /* !CANNOT_CONNECT_DGRAM */
! 639: if (sendto(statp->_sock,
! 640: (const char *)buf, buflen, 0,
! 641: (struct sockaddr *)nsap,
! 642: sizeof *nsap)
! 643: != buflen) {
! 644: Aerror(statp, stderr, "sendto", errno, *nsap);
! 645: badns |= (1 << ns);
! 646: res_nclose(statp);
! 647: goto next_ns;
! 648: }
! 649: #ifndef CANNOT_CONNECT_DGRAM
! 650: }
! 651: #endif /* !CANNOT_CONNECT_DGRAM */
! 652:
! 653: if (statp->_sock < 0 || statp->_sock > highestFD) {
! 654: Perror(statp, stderr,
! 655: "fd out-of-bounds", EMFILE);
! 656: res_nclose(statp);
! 657: goto next_ns;
! 658: }
! 659:
! 660: /*
! 661: * Wait for reply
! 662: */
! 663: seconds = (statp->retrans << try);
! 664: if (try > 0)
! 665: seconds /= statp->nscount;
! 666: if (seconds <= 0)
! 667: seconds = 1;
! 668: start = cur_time;
! 669: timeout = seconds;
! 670: finish = start + timeout;
! 671: wait:
! 672: FD_ZERO(&dsmask);
! 673: FD_SET(statp->_sock, &dsmask);
! 674: {
! 675: struct timeval t;
! 676: t.tv_sec = timeout;
! 677: t.tv_usec = 0;
! 678: n = select(statp->_sock + 1,
! 679: &dsmask, NULL, NULL, &t);
! 680: }
! 681: if (n == 0) {
! 682: Dprint(statp->options & RES_DEBUG,
! 683: (stdout, ";; timeout\n"));
! 684: gotsomewhere = 1;
! 685: goto next_ns;
! 686: }
! 687: if (n < 0) {
! 688: if (errno == EINTR) {
! 689: if (finish >= cur_time) {
! 690: timeout = finish - cur_time;
! 691: goto wait;
! 692: }
! 693: }
! 694: Perror(statp, stderr, "select", errno);
! 695: res_nclose(statp);
! 696: goto next_ns;
! 697: }
! 698: errno = 0;
! 699: fromlen = sizeof(struct sockaddr_in);
! 700: resplen = recvfrom(statp->_sock,
! 701: (char *)ans, anssiz, 0,
! 702: (struct sockaddr *)&from, &fromlen);
! 703: if (resplen <= 0) {
! 704: Perror(statp, stderr, "recvfrom", errno);
! 705: res_nclose(statp);
! 706: goto next_ns;
! 707: }
! 708: gotsomewhere = 1;
! 709: if (resplen < HFIXEDSZ) {
! 710: /*
! 711: * Undersized message.
! 712: */
! 713: Dprint(statp->options & RES_DEBUG,
! 714: (stdout, ";; undersized: %d\n",
! 715: resplen));
! 716: terrno = ISC_R_NOSPACE;
! 717: badns |= (1 << ns);
! 718: res_nclose(statp);
! 719: goto next_ns;
! 720: }
! 721: if (hp->id != anhp->id) {
! 722: /*
! 723: * response from old query, ignore it.
! 724: * XXX - potential security hazard could
! 725: * be detected here.
! 726: */
! 727: DprintQ((statp->options & RES_DEBUG) ||
! 728: (statp->pfcode & RES_PRF_REPLY),
! 729: (stdout, ";; old answer:\n"),
! 730: ans, (resplen>anssiz)?anssiz:resplen);
! 731: goto wait;
! 732: }
! 733: #ifdef CHECK_SRVR_ADDR
! 734: if (!(statp->options & RES_INSECURE1) &&
! 735: !res_ourserver_p(statp, &from)) {
! 736: /*
! 737: * response from wrong server? ignore it.
! 738: * XXX - potential security hazard could
! 739: * be detected here.
! 740: */
! 741: DprintQ((statp->options & RES_DEBUG) ||
! 742: (statp->pfcode & RES_PRF_REPLY),
! 743: (stdout, ";; not our server:\n"),
! 744: ans, (resplen>anssiz)?anssiz:resplen);
! 745: goto wait;
! 746: }
! 747: #endif
! 748: if (!(statp->options & RES_INSECURE2) &&
! 749: !res_queriesmatch((u_char *)buf,
! 750: ((u_char *)buf) + buflen,
! 751: (u_char *)ans,
! 752: ((u_char *)ans) + anssiz)) {
! 753: /*
! 754: * response contains wrong query? ignore it.
! 755: * XXX - potential security hazard could
! 756: * be detected here.
! 757: */
! 758: DprintQ((statp->options & RES_DEBUG) ||
! 759: (statp->pfcode & RES_PRF_REPLY),
! 760: (stdout, ";; wrong query name:\n"),
! 761: ans, (resplen>anssiz)?anssiz:resplen);
! 762: goto wait;
! 763: }
! 764: if (anhp->rcode == SERVFAIL ||
! 765: anhp->rcode == NOTIMP ||
! 766: anhp->rcode == REFUSED) {
! 767: DprintQ(statp->options & RES_DEBUG,
! 768: (stdout, "server rejected query:\n"),
! 769: ans, (resplen>anssiz)?anssiz:resplen);
! 770: badns |= (1 << ns);
! 771: res_nclose(statp);
! 772: /* don't retry if called from dig */
! 773: if (!statp->pfcode)
! 774: goto next_ns;
! 775: }
! 776: if (!(statp->options & RES_IGNTC) && anhp->tc) {
! 777: /*
! 778: * get rest of answer;
! 779: * use TCP with same server.
! 780: */
! 781: Dprint(statp->options & RES_DEBUG,
! 782: (stdout, ";; truncated answer\n"));
! 783: v_circuit = 1;
! 784: res_nclose(statp);
! 785: goto same_ns;
! 786: }
! 787: } /*if vc/dg*/
! 788: Dprint((statp->options & RES_DEBUG) ||
! 789: ((statp->pfcode & RES_PRF_REPLY) &&
! 790: (statp->pfcode & RES_PRF_HEAD1)),
! 791: (stdout, ";; got answer:\n"));
! 792: DprintQ((statp->options & RES_DEBUG) ||
! 793: (statp->pfcode & RES_PRF_REPLY),
! 794: (stdout, ""),
! 795: ans, (resplen>anssiz)?anssiz:resplen);
! 796: /*
! 797: * If using virtual circuits, we assume that the first server
! 798: * is preferred over the rest (i.e. it is on the local
! 799: * machine) and only keep that one open.
! 800: * If we have temporarily opened a virtual circuit,
! 801: * or if we haven't been asked to keep a socket open,
! 802: * close the socket.
! 803: */
! 804: if ((v_circuit && (!(statp->options & RES_USEVC) || ns != 0)) ||
! 805: !(statp->options & RES_STAYOPEN)) {
! 806: res_nclose(statp);
! 807: }
! 808: if (statp->rhook) {
! 809: int done = 0, loops = 0;
! 810:
! 811: do {
! 812: res_sendhookact act;
! 813:
! 814: act = (*statp->rhook)(nsap, buf, buflen,
! 815: ans, anssiz, &resplen);
! 816: switch (act) {
! 817: case res_goahead:
! 818: case res_done:
! 819: done = 1;
! 820: break;
! 821: case res_nextns:
! 822: res_nclose(statp);
! 823: goto next_ns;
! 824: case res_modified:
! 825: /* give the hook another try */
! 826: if (++loops < 42) /*doug adams*/
! 827: break;
! 828: /*FALLTHROUGH*/
! 829: case res_error:
! 830: /*FALLTHROUGH*/
! 831: default:
! 832: return ISC_R_UNEXPECTED;
! 833: }
! 834: } while (!done);
! 835:
! 836: }
! 837: *ansret = resplen;
! 838: return ISC_R_SUCCESS;
! 839: next_ns: ;
! 840: } /*foreach ns*/
! 841: } /*foreach retry*/
! 842: res_nclose(statp);
! 843: if (!v_circuit) {
! 844: if (!gotsomewhere)
! 845: terrno = ISC_R_CONNREFUSED; /* no nameservers found */
! 846: else
! 847: errno = ISC_R_TIMEDOUT; /* no answer obtained */
! 848: }
! 849: return terrno;
! 850: }
! 851:
! 852: /*
! 853: * This routine is for closing the socket if a virtual circuit is used and
! 854: * the program wants to close it. This provides support for endhostent()
! 855: * which expects to close the socket.
! 856: *
! 857: * This routine is not expected to be user visible.
! 858: */
! 859: void
! 860: res_nclose(res_state statp) {
! 861: if (statp->_sock >= 0) {
! 862: (void) close(statp->_sock);
! 863: statp->_sock = -1;
! 864: statp->_flags &= ~(RES_F_VC | RES_F_CONN);
! 865: }
! 866: }
! 867:
! 868: /* Private */
! 869: static int
! 870: cmpsock(struct sockaddr_in *a1, struct sockaddr_in *a2) {
! 871: return ((a1->sin_family == a2->sin_family) &&
! 872: (a1->sin_port == a2->sin_port) &&
! 873: (a1->sin_addr.s_addr == a2->sin_addr.s_addr));
! 874: }
! 875:
! 876: #ifdef NEED_PSELECT
! 877: /* XXX needs to move to the porting library. */
! 878: static int
! 879: pselect(int nfds, void *rfds, void *wfds, void *efds,
! 880: struct timespec *tsp,
! 881: const sigset_t *sigmask)
! 882: {
! 883: struct timeval tv, *tvp;
! 884: sigset_t sigs;
! 885: int n;
! 886:
! 887: if (tsp) {
! 888: tvp = &tv;
! 889: tv = evTimeVal(*tsp);
! 890: } else
! 891: tvp = NULL;
! 892: if (sigmask)
! 893: sigprocmask(SIG_SETMASK, sigmask, &sigs);
! 894: n = select(nfds, rfds, wfds, efds, tvp);
! 895: if (sigmask)
! 896: sigprocmask(SIG_SETMASK, &sigs, NULL);
! 897: if (tsp)
! 898: *tsp = evTimeSpec(tv);
! 899: return (n);
! 900: }
! 901: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>