118144Sralph /* 238214Skarels * Copyright (c) 1985, 1989 Regents of the University of California. 333679Sbostic * All rights reserved. 433679Sbostic * 542627Sbostic * %sccs.include.redist.c% 618548Sralph */ 718548Sralph 826635Sdonn #if defined(LIBC_SCCS) && !defined(lint) 9*46496Sbostic static char sccsid[] = "@(#)res_send.c 6.26 (Berkeley) 02/21/91"; 1033679Sbostic #endif /* LIBC_SCCS and not lint */ 1121388Sdist 1218548Sralph /* 1318144Sralph * Send query to name server and wait for reply. 1418144Sralph */ 1518144Sralph 1626886Skjd #include <sys/param.h> 1718144Sralph #include <sys/time.h> 1818144Sralph #include <sys/socket.h> 1927664Sbloom #include <sys/uio.h> 2018144Sralph #include <netinet/in.h> 2118144Sralph #include <stdio.h> 2218144Sralph #include <errno.h> 2324083Skjd #include <arpa/nameser.h> 2426896Skjd #include <resolv.h> 2518144Sralph 2618144Sralph extern int errno; 2718144Sralph 2827025Sbloom static int s = -1; /* socket used for communications */ 2931113Skarels static struct sockaddr no_addr; 3030100Skjd 3127025Sbloom 3230100Skjd #ifndef FD_SET 3330100Skjd #define NFDBITS 32 3430100Skjd #define FD_SETSIZE 32 3530100Skjd #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 3630100Skjd #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 3730100Skjd #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 3830100Skjd #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 3930100Skjd #endif 4030100Skjd 4118531Sralph res_send(buf, buflen, answer, anslen) 4218144Sralph char *buf; 4318144Sralph int buflen; 4418144Sralph char *answer; 4518144Sralph int anslen; 4618144Sralph { 4718144Sralph register int n; 4838214Skarels int try, v_circuit, resplen, ns; 4932603Skarels int gotsomewhere = 0, connected = 0; 5039703Sbloom int connreset = 0; 5118144Sralph u_short id, len; 5218144Sralph char *cp; 5327796Skjd fd_set dsmask; 5418144Sralph struct timeval timeout; 5518144Sralph HEADER *hp = (HEADER *) buf; 5618144Sralph HEADER *anhp = (HEADER *) answer; 5727664Sbloom struct iovec iov[2]; 5829434Sbloom int terrno = ETIMEDOUT; 5932603Skarels char junk[512]; 6018144Sralph 6124734Sbloom #ifdef DEBUG 6218144Sralph if (_res.options & RES_DEBUG) { 6318531Sralph printf("res_send()\n"); 64*46496Sbostic __p_query(buf); 6518144Sralph } 6625243Skjd #endif DEBUG 6718531Sralph if (!(_res.options & RES_INIT)) 6824734Sbloom if (res_init() == -1) { 6924734Sbloom return(-1); 7024734Sbloom } 7118144Sralph v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 7218144Sralph id = hp->id; 7318144Sralph /* 7418144Sralph * Send request, RETRY times, or until successful 7518144Sralph */ 7638214Skarels for (try = 0; try < _res.retry; try++) { 7725243Skjd for (ns = 0; ns < _res.nscount; ns++) { 7825243Skjd #ifdef DEBUG 7925243Skjd if (_res.options & RES_DEBUG) 8025243Skjd printf("Querying server (# %d) address = %s\n", ns+1, 8132603Skarels inet_ntoa(_res.nsaddr_list[ns].sin_addr)); 8225243Skjd #endif DEBUG 8338214Skarels usevc: 8418144Sralph if (v_circuit) { 8532603Skarels int truncated = 0; 8632603Skarels 8718144Sralph /* 8838214Skarels * Use virtual circuit; 8938214Skarels * at most one attempt per server. 9018144Sralph */ 9138214Skarels try = _res.retry; 9226322Sbloom if (s < 0) { 9318144Sralph s = socket(AF_INET, SOCK_STREAM, 0); 9426483Skarels if (s < 0) { 9529434Sbloom terrno = errno; 9626483Skarels #ifdef DEBUG 9726483Skarels if (_res.options & RES_DEBUG) 9839790Sbloom perror("socket (vc) failed"); 9926483Skarels #endif DEBUG 10026483Skarels continue; 10126483Skarels } 10227031Skjd if (connect(s, &(_res.nsaddr_list[ns]), 10326322Sbloom sizeof(struct sockaddr)) < 0) { 10429434Sbloom terrno = errno; 10524734Sbloom #ifdef DEBUG 10626322Sbloom if (_res.options & RES_DEBUG) 10727031Skjd perror("connect failed"); 10825243Skjd #endif DEBUG 10926322Sbloom (void) close(s); 11026322Sbloom s = -1; 11126322Sbloom continue; 11226322Sbloom } 11318144Sralph } 11418144Sralph /* 11518144Sralph * Send length & message 11618144Sralph */ 11727025Sbloom len = htons((u_short)buflen); 11827664Sbloom iov[0].iov_base = (caddr_t)&len; 11927664Sbloom iov[0].iov_len = sizeof(len); 12027664Sbloom iov[1].iov_base = buf; 12127664Sbloom iov[1].iov_len = buflen; 12227664Sbloom if (writev(s, iov, 2) != sizeof(len) + buflen) { 12329434Sbloom terrno = errno; 12424734Sbloom #ifdef DEBUG 12518144Sralph if (_res.options & RES_DEBUG) 12627031Skjd perror("write failed"); 12725243Skjd #endif DEBUG 12818144Sralph (void) close(s); 12918144Sralph s = -1; 13018144Sralph continue; 13118144Sralph } 13218144Sralph /* 13318144Sralph * Receive length & response 13418144Sralph */ 13518144Sralph cp = answer; 13618144Sralph len = sizeof(short); 13727664Sbloom while (len != 0 && 13827031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 13918144Sralph cp += n; 14018144Sralph len -= n; 14118144Sralph } 14218144Sralph if (n <= 0) { 14329434Sbloom terrno = errno; 14424734Sbloom #ifdef DEBUG 14518144Sralph if (_res.options & RES_DEBUG) 14627031Skjd perror("read failed"); 14725243Skjd #endif DEBUG 14818144Sralph (void) close(s); 14918144Sralph s = -1; 15039703Sbloom /* 15139703Sbloom * A long running process might get its TCP 15239703Sbloom * connection reset if the remote server was 15339703Sbloom * restarted. Requery the server instead of 15439703Sbloom * trying a new one. When there is only one 15539703Sbloom * server, this means that a query might work 15639703Sbloom * instead of failing. We only allow one reset 15739703Sbloom * per query to prevent looping. 15839703Sbloom */ 15939703Sbloom if (terrno == ECONNRESET && !connreset) { 16039703Sbloom connreset = 1; 16139703Sbloom ns--; 16239703Sbloom } 16318144Sralph continue; 16418144Sralph } 16518144Sralph cp = answer; 16632603Skarels if ((resplen = ntohs(*(u_short *)cp)) > anslen) { 16732603Skarels #ifdef DEBUG 16832603Skarels if (_res.options & RES_DEBUG) 16932603Skarels fprintf(stderr, "response truncated\n"); 17032603Skarels #endif DEBUG 17132603Skarels len = anslen; 17232603Skarels truncated = 1; 17332603Skarels } else 17432603Skarels len = resplen; 17527664Sbloom while (len != 0 && 17627031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 17718144Sralph cp += n; 17818144Sralph len -= n; 17918144Sralph } 18018144Sralph if (n <= 0) { 18129434Sbloom terrno = errno; 18224734Sbloom #ifdef DEBUG 18318144Sralph if (_res.options & RES_DEBUG) 18427031Skjd perror("read failed"); 18525243Skjd #endif DEBUG 18618144Sralph (void) close(s); 18718144Sralph s = -1; 18818144Sralph continue; 18918144Sralph } 19032603Skarels if (truncated) { 19132603Skarels /* 19232603Skarels * Flush rest of answer 19332603Skarels * so connection stays in synch. 19432603Skarels */ 19532603Skarels anhp->tc = 1; 19632603Skarels len = resplen - anslen; 19732603Skarels while (len != 0) { 19832603Skarels n = (len > sizeof(junk) ? 19932603Skarels sizeof(junk) : len); 20032603Skarels if ((n = read(s, junk, n)) > 0) 20132603Skarels len -= n; 20232603Skarels else 20332603Skarels break; 20432603Skarels } 20532603Skarels } 20618144Sralph } else { 20718144Sralph /* 20818144Sralph * Use datagrams. 20918144Sralph */ 21039790Sbloom if (s < 0) { 21118144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 21239790Sbloom if (s < 0) { 21339790Sbloom terrno = errno; 21439790Sbloom #ifdef DEBUG 21539790Sbloom if (_res.options & RES_DEBUG) 21639790Sbloom perror("socket (dg) failed"); 21739790Sbloom #endif DEBUG 21839790Sbloom continue; 21939790Sbloom } 22039790Sbloom } 22126483Skarels #if BSD >= 43 22238214Skarels /* 22338214Skarels * I'm tired of answering this question, so: 22438214Skarels * On a 4.3BSD+ machine (client and server, 22538214Skarels * actually), sending to a nameserver datagram 22638214Skarels * port with no nameserver will cause an 22738214Skarels * ICMP port unreachable message to be returned. 22838214Skarels * If our datagram socket is "connected" to the 22938214Skarels * server, we get an ECONNREFUSED error on the next 23038214Skarels * socket operation, and select returns if the 23138214Skarels * error message is received. We can thus detect 23238214Skarels * the absence of a nameserver without timing out. 23338214Skarels * If we have sent queries to at least two servers, 23438214Skarels * however, we don't want to remain connected, 23538214Skarels * as we wish to receive answers from the first 23638214Skarels * server to respond. 23738214Skarels */ 23838214Skarels if (_res.nscount == 1 || (try == 0 && ns == 0)) { 23930394Skjd /* 24031113Skarels * Don't use connect if we might 24131113Skarels * still receive a response 24231113Skarels * from another server. 24330394Skjd */ 24432603Skarels if (connected == 0) { 24532603Skarels if (connect(s, &_res.nsaddr_list[ns], 24632603Skarels sizeof(struct sockaddr)) < 0) { 24724734Sbloom #ifdef DEBUG 24832603Skarels if (_res.options & RES_DEBUG) 24932603Skarels perror("connect"); 25032603Skarels #endif DEBUG 25132603Skarels continue; 25232603Skarels } 25332603Skarels connected = 1; 25432603Skarels } 25532603Skarels if (send(s, buf, buflen, 0) != buflen) { 25632603Skarels #ifdef DEBUG 25730394Skjd if (_res.options & RES_DEBUG) 25832603Skarels perror("send"); 25925243Skjd #endif DEBUG 26030394Skjd continue; 26130394Skjd } 26234341Skarels } else { 26334341Skarels /* 26434341Skarels * Disconnect if we want to listen 26534341Skarels * for responses from more than one server. 26634341Skarels */ 26734341Skarels if (connected) { 26834341Skarels (void) connect(s, &no_addr, 26934341Skarels sizeof(no_addr)); 27034341Skarels connected = 0; 27134341Skarels } 27230394Skjd #endif BSD 27334341Skarels if (sendto(s, buf, buflen, 0, 27434341Skarels &_res.nsaddr_list[ns], 27534341Skarels sizeof(struct sockaddr)) != buflen) { 27626483Skarels #ifdef DEBUG 27734341Skarels if (_res.options & RES_DEBUG) 27834341Skarels perror("sendto"); 27926483Skarels #endif DEBUG 28034341Skarels continue; 28134341Skarels } 28234341Skarels #if BSD >= 43 28326483Skarels } 28434341Skarels #endif 28530394Skjd 28618144Sralph /* 28727031Skjd * Wait for reply 28818144Sralph */ 28938214Skarels timeout.tv_sec = (_res.retrans << try); 29038214Skarels if (try > 0) 29138214Skarels timeout.tv_sec /= _res.nscount; 29227031Skjd if (timeout.tv_sec <= 0) 29327031Skjd timeout.tv_sec = 1; 29418144Sralph timeout.tv_usec = 0; 29526323Skarels wait: 29627796Skjd FD_ZERO(&dsmask); 29727796Skjd FD_SET(s, &dsmask); 29827664Sbloom n = select(s+1, &dsmask, (fd_set *)NULL, 29927664Sbloom (fd_set *)NULL, &timeout); 30018144Sralph if (n < 0) { 30124734Sbloom #ifdef DEBUG 30218144Sralph if (_res.options & RES_DEBUG) 30327031Skjd perror("select"); 30425243Skjd #endif DEBUG 30518144Sralph continue; 30618144Sralph } 30718144Sralph if (n == 0) { 30818144Sralph /* 30918144Sralph * timeout 31018144Sralph */ 31124734Sbloom #ifdef DEBUG 31218144Sralph if (_res.options & RES_DEBUG) 31318144Sralph printf("timeout\n"); 31425243Skjd #endif DEBUG 31538214Skarels #if BSD >= 43 31626483Skarels gotsomewhere = 1; 31738214Skarels #endif 31818144Sralph continue; 31918144Sralph } 32025332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 32124734Sbloom #ifdef DEBUG 32218144Sralph if (_res.options & RES_DEBUG) 32327031Skjd perror("recvfrom"); 32425243Skjd #endif DEBUG 32518144Sralph continue; 32618144Sralph } 32726483Skarels gotsomewhere = 1; 32818144Sralph if (id != anhp->id) { 32918144Sralph /* 33018144Sralph * response from old query, ignore it 33118144Sralph */ 33224734Sbloom #ifdef DEBUG 33318144Sralph if (_res.options & RES_DEBUG) { 33418144Sralph printf("old answer:\n"); 335*46496Sbostic __p_query(answer); 33618144Sralph } 33725243Skjd #endif DEBUG 33826323Skarels goto wait; 33918144Sralph } 34018144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 34118144Sralph /* 34238214Skarels * get rest of answer; 34338214Skarels * use TCP with same server. 34418144Sralph */ 34524734Sbloom #ifdef DEBUG 34618144Sralph if (_res.options & RES_DEBUG) 34718144Sralph printf("truncated answer\n"); 34825243Skjd #endif DEBUG 34918144Sralph (void) close(s); 35018144Sralph s = -1; 35118144Sralph v_circuit = 1; 35238214Skarels goto usevc; 35318144Sralph } 35418144Sralph } 35524734Sbloom #ifdef DEBUG 35618144Sralph if (_res.options & RES_DEBUG) { 35718144Sralph printf("got answer:\n"); 358*46496Sbostic __p_query(answer); 35918144Sralph } 36025243Skjd #endif DEBUG 36126322Sbloom /* 36238214Skarels * If using virtual circuits, we assume that the first server 36338214Skarels * is preferred * over the rest (i.e. it is on the local 36438214Skarels * machine) and only keep that one open. 36538214Skarels * If we have temporarily opened a virtual circuit, 36638214Skarels * or if we haven't been asked to keep a socket open, 36738214Skarels * close the socket. 36826322Sbloom */ 36938214Skarels if ((v_circuit && 37038214Skarels ((_res.options & RES_USEVC) == 0 || ns != 0)) || 37138214Skarels (_res.options & RES_STAYOPEN) == 0) { 37226322Sbloom (void) close(s); 37326322Sbloom s = -1; 37426322Sbloom } 37534341Skarels return (resplen); 37625243Skjd } 37718144Sralph } 37829434Sbloom if (s >= 0) { 37929434Sbloom (void) close(s); 38029434Sbloom s = -1; 38129434Sbloom } 38229434Sbloom if (v_circuit == 0) 38329434Sbloom if (gotsomewhere == 0) 38438214Skarels errno = ECONNREFUSED; /* no nameservers found */ 38529434Sbloom else 38638214Skarels errno = ETIMEDOUT; /* no answer obtained */ 38726483Skarels else 38829434Sbloom errno = terrno; 38918144Sralph return (-1); 39018144Sralph } 39127025Sbloom 39227025Sbloom /* 39327025Sbloom * This routine is for closing the socket if a virtual circuit is used and 39427025Sbloom * the program wants to close it. This provides support for endhostent() 39527025Sbloom * which expects to close the socket. 39627025Sbloom * 39727025Sbloom * This routine is not expected to be user visible. 39827025Sbloom */ 39927025Sbloom _res_close() 40027025Sbloom { 40127025Sbloom if (s != -1) { 40227025Sbloom (void) close(s); 40327025Sbloom s = -1; 40427025Sbloom } 40527025Sbloom } 406