118144Sralph /* 2*38214Skarels * Copyright (c) 1985, 1989 Regents of the University of California. 333679Sbostic * All rights reserved. 433679Sbostic * 533679Sbostic * Redistribution and use in source and binary forms are permitted 634817Sbostic * provided that the above copyright notice and this paragraph are 734817Sbostic * duplicated in all such forms and that any documentation, 834817Sbostic * advertising materials, and other materials related to such 934817Sbostic * distribution and use acknowledge that the software was developed 1034817Sbostic * by the University of California, Berkeley. The name of the 1134817Sbostic * University may not be used to endorse or promote products derived 1234817Sbostic * from this software without specific prior written permission. 1334817Sbostic * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1434817Sbostic * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1534817Sbostic * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1618548Sralph */ 1718548Sralph 1826635Sdonn #if defined(LIBC_SCCS) && !defined(lint) 19*38214Skarels static char sccsid[] = "@(#)res_send.c 6.22 (Berkeley) 06/01/89"; 2033679Sbostic #endif /* LIBC_SCCS and not lint */ 2121388Sdist 2218548Sralph /* 2318144Sralph * Send query to name server and wait for reply. 2418144Sralph */ 2518144Sralph 2626886Skjd #include <sys/param.h> 2718144Sralph #include <sys/time.h> 2818144Sralph #include <sys/socket.h> 2927664Sbloom #include <sys/uio.h> 3018144Sralph #include <netinet/in.h> 3118144Sralph #include <stdio.h> 3218144Sralph #include <errno.h> 3324083Skjd #include <arpa/nameser.h> 3426896Skjd #include <resolv.h> 3518144Sralph 3618144Sralph extern int errno; 3718144Sralph 3827025Sbloom static int s = -1; /* socket used for communications */ 3931113Skarels static struct sockaddr no_addr; 4030100Skjd 4127025Sbloom 4230100Skjd #ifndef FD_SET 4330100Skjd #define NFDBITS 32 4430100Skjd #define FD_SETSIZE 32 4530100Skjd #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 4630100Skjd #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 4730100Skjd #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 4830100Skjd #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 4930100Skjd #endif 5030100Skjd 5118531Sralph res_send(buf, buflen, answer, anslen) 5218144Sralph char *buf; 5318144Sralph int buflen; 5418144Sralph char *answer; 5518144Sralph int anslen; 5618144Sralph { 5718144Sralph register int n; 58*38214Skarels int try, v_circuit, resplen, ns; 5932603Skarels int gotsomewhere = 0, connected = 0; 6018144Sralph u_short id, len; 6118144Sralph char *cp; 6227796Skjd fd_set dsmask; 6318144Sralph struct timeval timeout; 6418144Sralph HEADER *hp = (HEADER *) buf; 6518144Sralph HEADER *anhp = (HEADER *) answer; 6627664Sbloom struct iovec iov[2]; 6729434Sbloom int terrno = ETIMEDOUT; 6832603Skarels char junk[512]; 6918144Sralph 7024734Sbloom #ifdef DEBUG 7118144Sralph if (_res.options & RES_DEBUG) { 7218531Sralph printf("res_send()\n"); 7318144Sralph p_query(buf); 7418144Sralph } 7525243Skjd #endif DEBUG 7618531Sralph if (!(_res.options & RES_INIT)) 7724734Sbloom if (res_init() == -1) { 7824734Sbloom return(-1); 7924734Sbloom } 8018144Sralph v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 8118144Sralph id = hp->id; 8218144Sralph /* 8318144Sralph * Send request, RETRY times, or until successful 8418144Sralph */ 85*38214Skarels for (try = 0; try < _res.retry; try++) { 8625243Skjd for (ns = 0; ns < _res.nscount; ns++) { 8725243Skjd #ifdef DEBUG 8825243Skjd if (_res.options & RES_DEBUG) 8925243Skjd printf("Querying server (# %d) address = %s\n", ns+1, 9032603Skarels inet_ntoa(_res.nsaddr_list[ns].sin_addr)); 9125243Skjd #endif DEBUG 92*38214Skarels usevc: 9318144Sralph if (v_circuit) { 9432603Skarels int truncated = 0; 9532603Skarels 9618144Sralph /* 97*38214Skarels * Use virtual circuit; 98*38214Skarels * at most one attempt per server. 9918144Sralph */ 100*38214Skarels try = _res.retry; 10126322Sbloom if (s < 0) { 10218144Sralph s = socket(AF_INET, SOCK_STREAM, 0); 10326483Skarels if (s < 0) { 10429434Sbloom terrno = errno; 10526483Skarels #ifdef DEBUG 10626483Skarels if (_res.options & RES_DEBUG) 10727031Skjd perror("socket failed"); 10826483Skarels #endif DEBUG 10926483Skarels continue; 11026483Skarels } 11127031Skjd if (connect(s, &(_res.nsaddr_list[ns]), 11226322Sbloom sizeof(struct sockaddr)) < 0) { 11329434Sbloom terrno = errno; 11424734Sbloom #ifdef DEBUG 11526322Sbloom if (_res.options & RES_DEBUG) 11627031Skjd perror("connect failed"); 11725243Skjd #endif DEBUG 11826322Sbloom (void) close(s); 11926322Sbloom s = -1; 12026322Sbloom continue; 12126322Sbloom } 12218144Sralph } 12318144Sralph /* 12418144Sralph * Send length & message 12518144Sralph */ 12627025Sbloom len = htons((u_short)buflen); 12727664Sbloom iov[0].iov_base = (caddr_t)&len; 12827664Sbloom iov[0].iov_len = sizeof(len); 12927664Sbloom iov[1].iov_base = buf; 13027664Sbloom iov[1].iov_len = buflen; 13127664Sbloom if (writev(s, iov, 2) != sizeof(len) + buflen) { 13229434Sbloom terrno = errno; 13324734Sbloom #ifdef DEBUG 13418144Sralph if (_res.options & RES_DEBUG) 13527031Skjd perror("write failed"); 13625243Skjd #endif DEBUG 13718144Sralph (void) close(s); 13818144Sralph s = -1; 13918144Sralph continue; 14018144Sralph } 14118144Sralph /* 14218144Sralph * Receive length & response 14318144Sralph */ 14418144Sralph cp = answer; 14518144Sralph len = sizeof(short); 14627664Sbloom while (len != 0 && 14727031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 14818144Sralph cp += n; 14918144Sralph len -= n; 15018144Sralph } 15118144Sralph if (n <= 0) { 15229434Sbloom terrno = errno; 15324734Sbloom #ifdef DEBUG 15418144Sralph if (_res.options & RES_DEBUG) 15527031Skjd perror("read failed"); 15625243Skjd #endif DEBUG 15718144Sralph (void) close(s); 15818144Sralph s = -1; 15918144Sralph continue; 16018144Sralph } 16118144Sralph cp = answer; 16232603Skarels if ((resplen = ntohs(*(u_short *)cp)) > anslen) { 16332603Skarels #ifdef DEBUG 16432603Skarels if (_res.options & RES_DEBUG) 16532603Skarels fprintf(stderr, "response truncated\n"); 16632603Skarels #endif DEBUG 16732603Skarels len = anslen; 16832603Skarels truncated = 1; 16932603Skarels } else 17032603Skarels len = resplen; 17127664Sbloom while (len != 0 && 17227031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 17318144Sralph cp += n; 17418144Sralph len -= n; 17518144Sralph } 17618144Sralph if (n <= 0) { 17729434Sbloom terrno = errno; 17824734Sbloom #ifdef DEBUG 17918144Sralph if (_res.options & RES_DEBUG) 18027031Skjd perror("read failed"); 18125243Skjd #endif DEBUG 18218144Sralph (void) close(s); 18318144Sralph s = -1; 18418144Sralph continue; 18518144Sralph } 18632603Skarels if (truncated) { 18732603Skarels /* 18832603Skarels * Flush rest of answer 18932603Skarels * so connection stays in synch. 19032603Skarels */ 19132603Skarels anhp->tc = 1; 19232603Skarels len = resplen - anslen; 19332603Skarels while (len != 0) { 19432603Skarels n = (len > sizeof(junk) ? 19532603Skarels sizeof(junk) : len); 19632603Skarels if ((n = read(s, junk, n)) > 0) 19732603Skarels len -= n; 19832603Skarels else 19932603Skarels break; 20032603Skarels } 20132603Skarels } 20218144Sralph } else { 20318144Sralph /* 20418144Sralph * Use datagrams. 20518144Sralph */ 20618144Sralph if (s < 0) 20718144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 20826483Skarels #if BSD >= 43 209*38214Skarels /* 210*38214Skarels * I'm tired of answering this question, so: 211*38214Skarels * On a 4.3BSD+ machine (client and server, 212*38214Skarels * actually), sending to a nameserver datagram 213*38214Skarels * port with no nameserver will cause an 214*38214Skarels * ICMP port unreachable message to be returned. 215*38214Skarels * If our datagram socket is "connected" to the 216*38214Skarels * server, we get an ECONNREFUSED error on the next 217*38214Skarels * socket operation, and select returns if the 218*38214Skarels * error message is received. We can thus detect 219*38214Skarels * the absence of a nameserver without timing out. 220*38214Skarels * If we have sent queries to at least two servers, 221*38214Skarels * however, we don't want to remain connected, 222*38214Skarels * as we wish to receive answers from the first 223*38214Skarels * server to respond. 224*38214Skarels */ 225*38214Skarels if (_res.nscount == 1 || (try == 0 && ns == 0)) { 22630394Skjd /* 22731113Skarels * Don't use connect if we might 22831113Skarels * still receive a response 22931113Skarels * from another server. 23030394Skjd */ 23132603Skarels if (connected == 0) { 23232603Skarels if (connect(s, &_res.nsaddr_list[ns], 23332603Skarels sizeof(struct sockaddr)) < 0) { 23424734Sbloom #ifdef DEBUG 23532603Skarels if (_res.options & RES_DEBUG) 23632603Skarels perror("connect"); 23732603Skarels #endif DEBUG 23832603Skarels continue; 23932603Skarels } 24032603Skarels connected = 1; 24132603Skarels } 24232603Skarels if (send(s, buf, buflen, 0) != buflen) { 24332603Skarels #ifdef DEBUG 24430394Skjd if (_res.options & RES_DEBUG) 24532603Skarels perror("send"); 24625243Skjd #endif DEBUG 24730394Skjd continue; 24830394Skjd } 24934341Skarels } else { 25034341Skarels /* 25134341Skarels * Disconnect if we want to listen 25234341Skarels * for responses from more than one server. 25334341Skarels */ 25434341Skarels if (connected) { 25534341Skarels (void) connect(s, &no_addr, 25634341Skarels sizeof(no_addr)); 25734341Skarels connected = 0; 25834341Skarels } 25930394Skjd #endif BSD 26034341Skarels if (sendto(s, buf, buflen, 0, 26134341Skarels &_res.nsaddr_list[ns], 26234341Skarels sizeof(struct sockaddr)) != buflen) { 26326483Skarels #ifdef DEBUG 26434341Skarels if (_res.options & RES_DEBUG) 26534341Skarels perror("sendto"); 26626483Skarels #endif DEBUG 26734341Skarels continue; 26834341Skarels } 26934341Skarels #if BSD >= 43 27026483Skarels } 27134341Skarels #endif 27230394Skjd 27318144Sralph /* 27427031Skjd * Wait for reply 27518144Sralph */ 276*38214Skarels timeout.tv_sec = (_res.retrans << try); 277*38214Skarels if (try > 0) 278*38214Skarels timeout.tv_sec /= _res.nscount; 27927031Skjd if (timeout.tv_sec <= 0) 28027031Skjd timeout.tv_sec = 1; 28118144Sralph timeout.tv_usec = 0; 28226323Skarels wait: 28327796Skjd FD_ZERO(&dsmask); 28427796Skjd FD_SET(s, &dsmask); 28527664Sbloom n = select(s+1, &dsmask, (fd_set *)NULL, 28627664Sbloom (fd_set *)NULL, &timeout); 28718144Sralph if (n < 0) { 28824734Sbloom #ifdef DEBUG 28918144Sralph if (_res.options & RES_DEBUG) 29027031Skjd perror("select"); 29125243Skjd #endif DEBUG 29218144Sralph continue; 29318144Sralph } 29418144Sralph if (n == 0) { 29518144Sralph /* 29618144Sralph * timeout 29718144Sralph */ 29824734Sbloom #ifdef DEBUG 29918144Sralph if (_res.options & RES_DEBUG) 30018144Sralph printf("timeout\n"); 30125243Skjd #endif DEBUG 302*38214Skarels #if BSD >= 43 30326483Skarels gotsomewhere = 1; 304*38214Skarels #endif 30518144Sralph continue; 30618144Sralph } 30725332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 30824734Sbloom #ifdef DEBUG 30918144Sralph if (_res.options & RES_DEBUG) 31027031Skjd perror("recvfrom"); 31125243Skjd #endif DEBUG 31218144Sralph continue; 31318144Sralph } 31426483Skarels gotsomewhere = 1; 31518144Sralph if (id != anhp->id) { 31618144Sralph /* 31718144Sralph * response from old query, ignore it 31818144Sralph */ 31924734Sbloom #ifdef DEBUG 32018144Sralph if (_res.options & RES_DEBUG) { 32118144Sralph printf("old answer:\n"); 32218144Sralph p_query(answer); 32318144Sralph } 32425243Skjd #endif DEBUG 32526323Skarels goto wait; 32618144Sralph } 32718144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 32818144Sralph /* 329*38214Skarels * get rest of answer; 330*38214Skarels * use TCP with same server. 33118144Sralph */ 33224734Sbloom #ifdef DEBUG 33318144Sralph if (_res.options & RES_DEBUG) 33418144Sralph printf("truncated answer\n"); 33525243Skjd #endif DEBUG 33618144Sralph (void) close(s); 33718144Sralph s = -1; 33818144Sralph v_circuit = 1; 339*38214Skarels goto usevc; 34018144Sralph } 34118144Sralph } 34224734Sbloom #ifdef DEBUG 34318144Sralph if (_res.options & RES_DEBUG) { 34418144Sralph printf("got answer:\n"); 34518144Sralph p_query(answer); 34618144Sralph } 34725243Skjd #endif DEBUG 34826322Sbloom /* 349*38214Skarels * If using virtual circuits, we assume that the first server 350*38214Skarels * is preferred * over the rest (i.e. it is on the local 351*38214Skarels * machine) and only keep that one open. 352*38214Skarels * If we have temporarily opened a virtual circuit, 353*38214Skarels * or if we haven't been asked to keep a socket open, 354*38214Skarels * close the socket. 35526322Sbloom */ 356*38214Skarels if ((v_circuit && 357*38214Skarels ((_res.options & RES_USEVC) == 0 || ns != 0)) || 358*38214Skarels (_res.options & RES_STAYOPEN) == 0) { 35926322Sbloom (void) close(s); 36026322Sbloom s = -1; 36126322Sbloom } 36234341Skarels return (resplen); 36325243Skjd } 36418144Sralph } 36529434Sbloom if (s >= 0) { 36629434Sbloom (void) close(s); 36729434Sbloom s = -1; 36829434Sbloom } 36929434Sbloom if (v_circuit == 0) 37029434Sbloom if (gotsomewhere == 0) 371*38214Skarels errno = ECONNREFUSED; /* no nameservers found */ 37229434Sbloom else 373*38214Skarels errno = ETIMEDOUT; /* no answer obtained */ 37426483Skarels else 37529434Sbloom errno = terrno; 37618144Sralph return (-1); 37718144Sralph } 37827025Sbloom 37927025Sbloom /* 38027025Sbloom * This routine is for closing the socket if a virtual circuit is used and 38127025Sbloom * the program wants to close it. This provides support for endhostent() 38227025Sbloom * which expects to close the socket. 38327025Sbloom * 38427025Sbloom * This routine is not expected to be user visible. 38527025Sbloom */ 38627025Sbloom _res_close() 38727025Sbloom { 38827025Sbloom if (s != -1) { 38927025Sbloom (void) close(s); 39027025Sbloom s = -1; 39127025Sbloom } 39227025Sbloom } 393