1*61023Skarels /*- 238214Skarels * Copyright (c) 1985, 1989 Regents of the University of California. 333679Sbostic * All rights reserved. 433679Sbostic * 542627Sbostic * %sccs.include.redist.c% 6*61023Skarels * - 7*61023Skarels * Portions Copyright (c) 1993 by Digital Equipment Corporation. 8*61023Skarels * 9*61023Skarels * Permission to use, copy, modify, and distribute this software for any 10*61023Skarels * purpose with or without fee is hereby granted, provided that the above 11*61023Skarels * copyright notice and this permission notice appear in all copies, and that 12*61023Skarels * the name of Digital Equipment Corporation not be used in advertising or 13*61023Skarels * publicity pertaining to distribution of the document or software without 14*61023Skarels * specific, written prior permission. 15*61023Skarels * 16*61023Skarels * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 17*61023Skarels * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 18*61023Skarels * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 19*61023Skarels * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 20*61023Skarels * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 21*61023Skarels * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 22*61023Skarels * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 23*61023Skarels * SOFTWARE. 24*61023Skarels * - 25*61023Skarels * --Copyright-- 2618548Sralph */ 2718548Sralph 2826635Sdonn #if defined(LIBC_SCCS) && !defined(lint) 29*61023Skarels static char sccsid[] = "@(#)res_send.c 6.28 (Berkeley) 06/02/93"; 30*61023Skarels static char rcsid[] = "$Id: res_send.c,v 4.9.1.1 1993/05/02 22:43:03 vixie Rel $"; 3133679Sbostic #endif /* LIBC_SCCS and not lint */ 3221388Sdist 3318548Sralph /* 3418144Sralph * Send query to name server and wait for reply. 3518144Sralph */ 3618144Sralph 3726886Skjd #include <sys/param.h> 3818144Sralph #include <sys/time.h> 3918144Sralph #include <sys/socket.h> 4027664Sbloom #include <sys/uio.h> 4118144Sralph #include <netinet/in.h> 4246604Sbostic #include <arpa/nameser.h> 43*61023Skarels #include <arpa/inet.h> 4418144Sralph #include <stdio.h> 4518144Sralph #include <errno.h> 4626896Skjd #include <resolv.h> 4746604Sbostic #include <unistd.h> 4846604Sbostic #include <string.h> 4918144Sralph 5027025Sbloom static int s = -1; /* socket used for communications */ 5131113Skarels static struct sockaddr no_addr; 5227025Sbloom 5330100Skjd #ifndef FD_SET 5430100Skjd #define NFDBITS 32 5530100Skjd #define FD_SETSIZE 32 5630100Skjd #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 5730100Skjd #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 5830100Skjd #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 5930100Skjd #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 6030100Skjd #endif 6130100Skjd 6218531Sralph res_send(buf, buflen, answer, anslen) 6346604Sbostic const char *buf; 6418144Sralph int buflen; 6518144Sralph char *answer; 6618144Sralph int anslen; 6718144Sralph { 6818144Sralph register int n; 6938214Skarels int try, v_circuit, resplen, ns; 7032603Skarels int gotsomewhere = 0, connected = 0; 7139703Sbloom int connreset = 0; 7218144Sralph u_short id, len; 7318144Sralph char *cp; 7427796Skjd fd_set dsmask; 7518144Sralph struct timeval timeout; 7618144Sralph HEADER *hp = (HEADER *) buf; 7718144Sralph HEADER *anhp = (HEADER *) answer; 78*61023Skarels u_int badns; /* XXX NSMAX can't exceed #/bits per this */ 7927664Sbloom struct iovec iov[2]; 8029434Sbloom int terrno = ETIMEDOUT; 8132603Skarels char junk[512]; 8218144Sralph 8324734Sbloom #ifdef DEBUG 84*61023Skarels if ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY)) { 85*61023Skarels printf(";; res_send()\n"); 8646496Sbostic __p_query(buf); 8718144Sralph } 88*61023Skarels #endif 8918531Sralph if (!(_res.options & RES_INIT)) 9024734Sbloom if (res_init() == -1) { 9124734Sbloom return(-1); 9224734Sbloom } 9318144Sralph v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 9418144Sralph id = hp->id; 95*61023Skarels badns = 0; 9618144Sralph /* 9718144Sralph * Send request, RETRY times, or until successful 9818144Sralph */ 9938214Skarels for (try = 0; try < _res.retry; try++) { 100*61023Skarels for (ns = 0; ns < _res.nscount; ns++) { 101*61023Skarels if (badns & (1<<ns)) 102*61023Skarels continue; 10325243Skjd #ifdef DEBUG 10425243Skjd if (_res.options & RES_DEBUG) 105*61023Skarels printf(";; Querying server (# %d) address = %s\n", 106*61023Skarels ns+1, 107*61023Skarels inet_ntoa(_res.nsaddr_list[ns].sin_addr)); 108*61023Skarels #endif 10938214Skarels usevc: 11018144Sralph if (v_circuit) { 11132603Skarels int truncated = 0; 11232603Skarels 11318144Sralph /* 11438214Skarels * Use virtual circuit; 11538214Skarels * at most one attempt per server. 11618144Sralph */ 11738214Skarels try = _res.retry; 11826322Sbloom if (s < 0) { 11918144Sralph s = socket(AF_INET, SOCK_STREAM, 0); 12026483Skarels if (s < 0) { 12129434Sbloom terrno = errno; 12226483Skarels #ifdef DEBUG 12326483Skarels if (_res.options & RES_DEBUG) 12439790Sbloom perror("socket (vc) failed"); 125*61023Skarels #endif 12626483Skarels continue; 12726483Skarels } 12846604Sbostic if (connect(s, 12946604Sbostic (struct sockaddr *)&(_res.nsaddr_list[ns]), 13046604Sbostic sizeof(struct sockaddr)) < 0) { 13129434Sbloom terrno = errno; 13224734Sbloom #ifdef DEBUG 13326322Sbloom if (_res.options & RES_DEBUG) 13427031Skjd perror("connect failed"); 135*61023Skarels #endif 13626322Sbloom (void) close(s); 13726322Sbloom s = -1; 13826322Sbloom continue; 13926322Sbloom } 14018144Sralph } 14118144Sralph /* 14218144Sralph * Send length & message 14318144Sralph */ 14427025Sbloom len = htons((u_short)buflen); 14527664Sbloom iov[0].iov_base = (caddr_t)&len; 14627664Sbloom iov[0].iov_len = sizeof(len); 14746604Sbostic iov[1].iov_base = (char *)buf; 14827664Sbloom iov[1].iov_len = buflen; 14927664Sbloom if (writev(s, iov, 2) != sizeof(len) + buflen) { 15029434Sbloom terrno = errno; 15124734Sbloom #ifdef DEBUG 15218144Sralph if (_res.options & RES_DEBUG) 15327031Skjd perror("write failed"); 154*61023Skarels #endif 15518144Sralph (void) close(s); 15618144Sralph s = -1; 15718144Sralph continue; 15818144Sralph } 15918144Sralph /* 16018144Sralph * Receive length & response 16118144Sralph */ 16218144Sralph cp = answer; 16318144Sralph len = sizeof(short); 16427664Sbloom while (len != 0 && 16527031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 16618144Sralph cp += n; 16718144Sralph len -= n; 16818144Sralph } 16918144Sralph if (n <= 0) { 17029434Sbloom terrno = errno; 17124734Sbloom #ifdef DEBUG 17218144Sralph if (_res.options & RES_DEBUG) 17327031Skjd perror("read failed"); 174*61023Skarels #endif 17518144Sralph (void) close(s); 17618144Sralph s = -1; 17739703Sbloom /* 17839703Sbloom * A long running process might get its TCP 17939703Sbloom * connection reset if the remote server was 18039703Sbloom * restarted. Requery the server instead of 18139703Sbloom * trying a new one. When there is only one 18239703Sbloom * server, this means that a query might work 18339703Sbloom * instead of failing. We only allow one reset 18439703Sbloom * per query to prevent looping. 18539703Sbloom */ 18639703Sbloom if (terrno == ECONNRESET && !connreset) { 18739703Sbloom connreset = 1; 18839703Sbloom ns--; 18939703Sbloom } 19018144Sralph continue; 19118144Sralph } 19218144Sralph cp = answer; 19332603Skarels if ((resplen = ntohs(*(u_short *)cp)) > anslen) { 19432603Skarels #ifdef DEBUG 19532603Skarels if (_res.options & RES_DEBUG) 196*61023Skarels fprintf(stderr, 197*61023Skarels ";; response truncated\n"); 198*61023Skarels #endif 19932603Skarels len = anslen; 20032603Skarels truncated = 1; 20132603Skarels } else 20232603Skarels len = resplen; 20327664Sbloom while (len != 0 && 20427031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 20518144Sralph cp += n; 20618144Sralph len -= n; 20718144Sralph } 20818144Sralph if (n <= 0) { 20929434Sbloom terrno = errno; 21024734Sbloom #ifdef DEBUG 21118144Sralph if (_res.options & RES_DEBUG) 21227031Skjd perror("read failed"); 213*61023Skarels #endif 21418144Sralph (void) close(s); 21518144Sralph s = -1; 21618144Sralph continue; 21718144Sralph } 21832603Skarels if (truncated) { 21932603Skarels /* 22032603Skarels * Flush rest of answer 22132603Skarels * so connection stays in synch. 22232603Skarels */ 22332603Skarels anhp->tc = 1; 22432603Skarels len = resplen - anslen; 22532603Skarels while (len != 0) { 22632603Skarels n = (len > sizeof(junk) ? 22732603Skarels sizeof(junk) : len); 22832603Skarels if ((n = read(s, junk, n)) > 0) 22932603Skarels len -= n; 23032603Skarels else 23132603Skarels break; 23232603Skarels } 23332603Skarels } 23418144Sralph } else { 23518144Sralph /* 23618144Sralph * Use datagrams. 23718144Sralph */ 23839790Sbloom if (s < 0) { 23918144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 24039790Sbloom if (s < 0) { 24139790Sbloom terrno = errno; 24239790Sbloom #ifdef DEBUG 24339790Sbloom if (_res.options & RES_DEBUG) 24439790Sbloom perror("socket (dg) failed"); 245*61023Skarels #endif 24639790Sbloom continue; 24739790Sbloom } 24839790Sbloom } 24938214Skarels /* 25038214Skarels * I'm tired of answering this question, so: 25138214Skarels * On a 4.3BSD+ machine (client and server, 25238214Skarels * actually), sending to a nameserver datagram 25338214Skarels * port with no nameserver will cause an 25438214Skarels * ICMP port unreachable message to be returned. 25538214Skarels * If our datagram socket is "connected" to the 25638214Skarels * server, we get an ECONNREFUSED error on the next 25738214Skarels * socket operation, and select returns if the 25838214Skarels * error message is received. We can thus detect 25938214Skarels * the absence of a nameserver without timing out. 26038214Skarels * If we have sent queries to at least two servers, 26138214Skarels * however, we don't want to remain connected, 26238214Skarels * as we wish to receive answers from the first 26338214Skarels * server to respond. 26438214Skarels */ 26538214Skarels if (_res.nscount == 1 || (try == 0 && ns == 0)) { 26630394Skjd /* 26731113Skarels * Don't use connect if we might 26831113Skarels * still receive a response 26931113Skarels * from another server. 27030394Skjd */ 27132603Skarels if (connected == 0) { 272*61023Skarels if (connect(s, 273*61023Skarels (struct sockaddr *) 274*61023Skarels &_res.nsaddr_list[ns], 27532603Skarels sizeof(struct sockaddr)) < 0) { 27624734Sbloom #ifdef DEBUG 27732603Skarels if (_res.options & RES_DEBUG) 27832603Skarels perror("connect"); 279*61023Skarels #endif 28032603Skarels continue; 28132603Skarels } 28232603Skarels connected = 1; 28332603Skarels } 28432603Skarels if (send(s, buf, buflen, 0) != buflen) { 28532603Skarels #ifdef DEBUG 28630394Skjd if (_res.options & RES_DEBUG) 28732603Skarels perror("send"); 288*61023Skarels #endif 28930394Skjd continue; 29030394Skjd } 29134341Skarels } else { 29234341Skarels /* 29334341Skarels * Disconnect if we want to listen 29434341Skarels * for responses from more than one server. 29534341Skarels */ 29634341Skarels if (connected) { 29734341Skarels (void) connect(s, &no_addr, 29834341Skarels sizeof(no_addr)); 29934341Skarels connected = 0; 30034341Skarels } 30134341Skarels if (sendto(s, buf, buflen, 0, 30246604Sbostic (struct sockaddr *)&_res.nsaddr_list[ns], 30334341Skarels sizeof(struct sockaddr)) != buflen) { 30426483Skarels #ifdef DEBUG 30534341Skarels if (_res.options & RES_DEBUG) 30634341Skarels perror("sendto"); 307*61023Skarels #endif 30834341Skarels continue; 30934341Skarels } 31026483Skarels } 31130394Skjd 31218144Sralph /* 31327031Skjd * Wait for reply 31418144Sralph */ 31538214Skarels timeout.tv_sec = (_res.retrans << try); 31638214Skarels if (try > 0) 31738214Skarels timeout.tv_sec /= _res.nscount; 318*61023Skarels if ((long) timeout.tv_sec <= 0) 31927031Skjd timeout.tv_sec = 1; 32018144Sralph timeout.tv_usec = 0; 32126323Skarels wait: 32227796Skjd FD_ZERO(&dsmask); 32327796Skjd FD_SET(s, &dsmask); 32427664Sbloom n = select(s+1, &dsmask, (fd_set *)NULL, 32527664Sbloom (fd_set *)NULL, &timeout); 32618144Sralph if (n < 0) { 32724734Sbloom #ifdef DEBUG 32818144Sralph if (_res.options & RES_DEBUG) 32927031Skjd perror("select"); 330*61023Skarels #endif 33118144Sralph continue; 33218144Sralph } 33318144Sralph if (n == 0) { 33418144Sralph /* 33518144Sralph * timeout 33618144Sralph */ 33724734Sbloom #ifdef DEBUG 33818144Sralph if (_res.options & RES_DEBUG) 339*61023Skarels printf(";; timeout\n"); 340*61023Skarels #endif 34126483Skarels gotsomewhere = 1; 34218144Sralph continue; 34318144Sralph } 34425332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 34524734Sbloom #ifdef DEBUG 34618144Sralph if (_res.options & RES_DEBUG) 34727031Skjd perror("recvfrom"); 348*61023Skarels #endif 34918144Sralph continue; 35018144Sralph } 35126483Skarels gotsomewhere = 1; 35218144Sralph if (id != anhp->id) { 35318144Sralph /* 35418144Sralph * response from old query, ignore it 35518144Sralph */ 35624734Sbloom #ifdef DEBUG 357*61023Skarels if ((_res.options & RES_DEBUG) || 358*61023Skarels (_res.pfcode & RES_PRF_REPLY)) { 359*61023Skarels printf(";; old answer:\n"); 36046496Sbostic __p_query(answer); 36118144Sralph } 362*61023Skarels #endif 36326323Skarels goto wait; 36418144Sralph } 365*61023Skarels if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP || 366*61023Skarels anhp->rcode == REFUSED) { 367*61023Skarels #ifdef DEBUG 368*61023Skarels if (_res.options & RES_DEBUG) { 369*61023Skarels printf("server rejected query:\n"); 370*61023Skarels __p_query(answer); 371*61023Skarels } 372*61023Skarels #endif 373*61023Skarels badns |= (1<<ns); 374*61023Skarels continue; 375*61023Skarels } 37618144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 37718144Sralph /* 37838214Skarels * get rest of answer; 37938214Skarels * use TCP with same server. 38018144Sralph */ 38124734Sbloom #ifdef DEBUG 38218144Sralph if (_res.options & RES_DEBUG) 383*61023Skarels printf(";; truncated answer\n"); 384*61023Skarels #endif 38518144Sralph (void) close(s); 38618144Sralph s = -1; 38718144Sralph v_circuit = 1; 38838214Skarels goto usevc; 38918144Sralph } 39018144Sralph } 39124734Sbloom #ifdef DEBUG 392*61023Skarels if (_res.options & RES_DEBUG) 393*61023Skarels printf(";; got answer:\n"); 394*61023Skarels if ((_res.options & RES_DEBUG) || 395*61023Skarels (_res.pfcode & RES_PRF_REPLY)) 39646496Sbostic __p_query(answer); 397*61023Skarels #endif 39826322Sbloom /* 39938214Skarels * If using virtual circuits, we assume that the first server 40038214Skarels * is preferred * over the rest (i.e. it is on the local 40138214Skarels * machine) and only keep that one open. 40238214Skarels * If we have temporarily opened a virtual circuit, 40338214Skarels * or if we haven't been asked to keep a socket open, 40438214Skarels * close the socket. 40526322Sbloom */ 40638214Skarels if ((v_circuit && 40738214Skarels ((_res.options & RES_USEVC) == 0 || ns != 0)) || 40838214Skarels (_res.options & RES_STAYOPEN) == 0) { 40926322Sbloom (void) close(s); 41026322Sbloom s = -1; 41126322Sbloom } 41234341Skarels return (resplen); 41325243Skjd } 41418144Sralph } 41529434Sbloom if (s >= 0) { 41629434Sbloom (void) close(s); 41729434Sbloom s = -1; 41829434Sbloom } 41929434Sbloom if (v_circuit == 0) 42029434Sbloom if (gotsomewhere == 0) 42138214Skarels errno = ECONNREFUSED; /* no nameservers found */ 42229434Sbloom else 42338214Skarels errno = ETIMEDOUT; /* no answer obtained */ 42426483Skarels else 42529434Sbloom errno = terrno; 42618144Sralph return (-1); 42718144Sralph } 42827025Sbloom 42927025Sbloom /* 43027025Sbloom * This routine is for closing the socket if a virtual circuit is used and 43127025Sbloom * the program wants to close it. This provides support for endhostent() 43227025Sbloom * which expects to close the socket. 43327025Sbloom * 43427025Sbloom * This routine is not expected to be user visible. 43527025Sbloom */ 43627025Sbloom _res_close() 43727025Sbloom { 43827025Sbloom if (s != -1) { 43927025Sbloom (void) close(s); 44027025Sbloom s = -1; 44127025Sbloom } 44227025Sbloom } 443