118144Sralph /* 238214Skarels * 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*39790Sbloom static char sccsid[] = "@(#)res_send.c 6.24 (Berkeley) 12/27/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; 5838214Skarels int try, v_circuit, resplen, ns; 5932603Skarels int gotsomewhere = 0, connected = 0; 6039703Sbloom int connreset = 0; 6118144Sralph u_short id, len; 6218144Sralph char *cp; 6327796Skjd fd_set dsmask; 6418144Sralph struct timeval timeout; 6518144Sralph HEADER *hp = (HEADER *) buf; 6618144Sralph HEADER *anhp = (HEADER *) answer; 6727664Sbloom struct iovec iov[2]; 6829434Sbloom int terrno = ETIMEDOUT; 6932603Skarels char junk[512]; 7018144Sralph 7124734Sbloom #ifdef DEBUG 7218144Sralph if (_res.options & RES_DEBUG) { 7318531Sralph printf("res_send()\n"); 7418144Sralph p_query(buf); 7518144Sralph } 7625243Skjd #endif DEBUG 7718531Sralph if (!(_res.options & RES_INIT)) 7824734Sbloom if (res_init() == -1) { 7924734Sbloom return(-1); 8024734Sbloom } 8118144Sralph v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 8218144Sralph id = hp->id; 8318144Sralph /* 8418144Sralph * Send request, RETRY times, or until successful 8518144Sralph */ 8638214Skarels for (try = 0; try < _res.retry; try++) { 8725243Skjd for (ns = 0; ns < _res.nscount; ns++) { 8825243Skjd #ifdef DEBUG 8925243Skjd if (_res.options & RES_DEBUG) 9025243Skjd printf("Querying server (# %d) address = %s\n", ns+1, 9132603Skarels inet_ntoa(_res.nsaddr_list[ns].sin_addr)); 9225243Skjd #endif DEBUG 9338214Skarels usevc: 9418144Sralph if (v_circuit) { 9532603Skarels int truncated = 0; 9632603Skarels 9718144Sralph /* 9838214Skarels * Use virtual circuit; 9938214Skarels * at most one attempt per server. 10018144Sralph */ 10138214Skarels try = _res.retry; 10226322Sbloom if (s < 0) { 10318144Sralph s = socket(AF_INET, SOCK_STREAM, 0); 10426483Skarels if (s < 0) { 10529434Sbloom terrno = errno; 10626483Skarels #ifdef DEBUG 10726483Skarels if (_res.options & RES_DEBUG) 108*39790Sbloom perror("socket (vc) failed"); 10926483Skarels #endif DEBUG 11026483Skarels continue; 11126483Skarels } 11227031Skjd if (connect(s, &(_res.nsaddr_list[ns]), 11326322Sbloom sizeof(struct sockaddr)) < 0) { 11429434Sbloom terrno = errno; 11524734Sbloom #ifdef DEBUG 11626322Sbloom if (_res.options & RES_DEBUG) 11727031Skjd perror("connect failed"); 11825243Skjd #endif DEBUG 11926322Sbloom (void) close(s); 12026322Sbloom s = -1; 12126322Sbloom continue; 12226322Sbloom } 12318144Sralph } 12418144Sralph /* 12518144Sralph * Send length & message 12618144Sralph */ 12727025Sbloom len = htons((u_short)buflen); 12827664Sbloom iov[0].iov_base = (caddr_t)&len; 12927664Sbloom iov[0].iov_len = sizeof(len); 13027664Sbloom iov[1].iov_base = buf; 13127664Sbloom iov[1].iov_len = buflen; 13227664Sbloom if (writev(s, iov, 2) != sizeof(len) + buflen) { 13329434Sbloom terrno = errno; 13424734Sbloom #ifdef DEBUG 13518144Sralph if (_res.options & RES_DEBUG) 13627031Skjd perror("write failed"); 13725243Skjd #endif DEBUG 13818144Sralph (void) close(s); 13918144Sralph s = -1; 14018144Sralph continue; 14118144Sralph } 14218144Sralph /* 14318144Sralph * Receive length & response 14418144Sralph */ 14518144Sralph cp = answer; 14618144Sralph len = sizeof(short); 14727664Sbloom while (len != 0 && 14827031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 14918144Sralph cp += n; 15018144Sralph len -= n; 15118144Sralph } 15218144Sralph if (n <= 0) { 15329434Sbloom terrno = errno; 15424734Sbloom #ifdef DEBUG 15518144Sralph if (_res.options & RES_DEBUG) 15627031Skjd perror("read failed"); 15725243Skjd #endif DEBUG 15818144Sralph (void) close(s); 15918144Sralph s = -1; 16039703Sbloom /* 16139703Sbloom * A long running process might get its TCP 16239703Sbloom * connection reset if the remote server was 16339703Sbloom * restarted. Requery the server instead of 16439703Sbloom * trying a new one. When there is only one 16539703Sbloom * server, this means that a query might work 16639703Sbloom * instead of failing. We only allow one reset 16739703Sbloom * per query to prevent looping. 16839703Sbloom */ 16939703Sbloom if (terrno == ECONNRESET && !connreset) { 17039703Sbloom connreset = 1; 17139703Sbloom ns--; 17239703Sbloom } 17318144Sralph continue; 17418144Sralph } 17518144Sralph cp = answer; 17632603Skarels if ((resplen = ntohs(*(u_short *)cp)) > anslen) { 17732603Skarels #ifdef DEBUG 17832603Skarels if (_res.options & RES_DEBUG) 17932603Skarels fprintf(stderr, "response truncated\n"); 18032603Skarels #endif DEBUG 18132603Skarels len = anslen; 18232603Skarels truncated = 1; 18332603Skarels } else 18432603Skarels len = resplen; 18527664Sbloom while (len != 0 && 18627031Skjd (n = read(s, (char *)cp, (int)len)) > 0) { 18718144Sralph cp += n; 18818144Sralph len -= n; 18918144Sralph } 19018144Sralph if (n <= 0) { 19129434Sbloom terrno = errno; 19224734Sbloom #ifdef DEBUG 19318144Sralph if (_res.options & RES_DEBUG) 19427031Skjd perror("read failed"); 19525243Skjd #endif DEBUG 19618144Sralph (void) close(s); 19718144Sralph s = -1; 19818144Sralph continue; 19918144Sralph } 20032603Skarels if (truncated) { 20132603Skarels /* 20232603Skarels * Flush rest of answer 20332603Skarels * so connection stays in synch. 20432603Skarels */ 20532603Skarels anhp->tc = 1; 20632603Skarels len = resplen - anslen; 20732603Skarels while (len != 0) { 20832603Skarels n = (len > sizeof(junk) ? 20932603Skarels sizeof(junk) : len); 21032603Skarels if ((n = read(s, junk, n)) > 0) 21132603Skarels len -= n; 21232603Skarels else 21332603Skarels break; 21432603Skarels } 21532603Skarels } 21618144Sralph } else { 21718144Sralph /* 21818144Sralph * Use datagrams. 21918144Sralph */ 220*39790Sbloom if (s < 0) { 22118144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 222*39790Sbloom if (s < 0) { 223*39790Sbloom terrno = errno; 224*39790Sbloom #ifdef DEBUG 225*39790Sbloom if (_res.options & RES_DEBUG) 226*39790Sbloom perror("socket (dg) failed"); 227*39790Sbloom #endif DEBUG 228*39790Sbloom continue; 229*39790Sbloom } 230*39790Sbloom } 23126483Skarels #if BSD >= 43 23238214Skarels /* 23338214Skarels * I'm tired of answering this question, so: 23438214Skarels * On a 4.3BSD+ machine (client and server, 23538214Skarels * actually), sending to a nameserver datagram 23638214Skarels * port with no nameserver will cause an 23738214Skarels * ICMP port unreachable message to be returned. 23838214Skarels * If our datagram socket is "connected" to the 23938214Skarels * server, we get an ECONNREFUSED error on the next 24038214Skarels * socket operation, and select returns if the 24138214Skarels * error message is received. We can thus detect 24238214Skarels * the absence of a nameserver without timing out. 24338214Skarels * If we have sent queries to at least two servers, 24438214Skarels * however, we don't want to remain connected, 24538214Skarels * as we wish to receive answers from the first 24638214Skarels * server to respond. 24738214Skarels */ 24838214Skarels if (_res.nscount == 1 || (try == 0 && ns == 0)) { 24930394Skjd /* 25031113Skarels * Don't use connect if we might 25131113Skarels * still receive a response 25231113Skarels * from another server. 25330394Skjd */ 25432603Skarels if (connected == 0) { 25532603Skarels if (connect(s, &_res.nsaddr_list[ns], 25632603Skarels sizeof(struct sockaddr)) < 0) { 25724734Sbloom #ifdef DEBUG 25832603Skarels if (_res.options & RES_DEBUG) 25932603Skarels perror("connect"); 26032603Skarels #endif DEBUG 26132603Skarels continue; 26232603Skarels } 26332603Skarels connected = 1; 26432603Skarels } 26532603Skarels if (send(s, buf, buflen, 0) != buflen) { 26632603Skarels #ifdef DEBUG 26730394Skjd if (_res.options & RES_DEBUG) 26832603Skarels perror("send"); 26925243Skjd #endif DEBUG 27030394Skjd continue; 27130394Skjd } 27234341Skarels } else { 27334341Skarels /* 27434341Skarels * Disconnect if we want to listen 27534341Skarels * for responses from more than one server. 27634341Skarels */ 27734341Skarels if (connected) { 27834341Skarels (void) connect(s, &no_addr, 27934341Skarels sizeof(no_addr)); 28034341Skarels connected = 0; 28134341Skarels } 28230394Skjd #endif BSD 28334341Skarels if (sendto(s, buf, buflen, 0, 28434341Skarels &_res.nsaddr_list[ns], 28534341Skarels sizeof(struct sockaddr)) != buflen) { 28626483Skarels #ifdef DEBUG 28734341Skarels if (_res.options & RES_DEBUG) 28834341Skarels perror("sendto"); 28926483Skarels #endif DEBUG 29034341Skarels continue; 29134341Skarels } 29234341Skarels #if BSD >= 43 29326483Skarels } 29434341Skarels #endif 29530394Skjd 29618144Sralph /* 29727031Skjd * Wait for reply 29818144Sralph */ 29938214Skarels timeout.tv_sec = (_res.retrans << try); 30038214Skarels if (try > 0) 30138214Skarels timeout.tv_sec /= _res.nscount; 30227031Skjd if (timeout.tv_sec <= 0) 30327031Skjd timeout.tv_sec = 1; 30418144Sralph timeout.tv_usec = 0; 30526323Skarels wait: 30627796Skjd FD_ZERO(&dsmask); 30727796Skjd FD_SET(s, &dsmask); 30827664Sbloom n = select(s+1, &dsmask, (fd_set *)NULL, 30927664Sbloom (fd_set *)NULL, &timeout); 31018144Sralph if (n < 0) { 31124734Sbloom #ifdef DEBUG 31218144Sralph if (_res.options & RES_DEBUG) 31327031Skjd perror("select"); 31425243Skjd #endif DEBUG 31518144Sralph continue; 31618144Sralph } 31718144Sralph if (n == 0) { 31818144Sralph /* 31918144Sralph * timeout 32018144Sralph */ 32124734Sbloom #ifdef DEBUG 32218144Sralph if (_res.options & RES_DEBUG) 32318144Sralph printf("timeout\n"); 32425243Skjd #endif DEBUG 32538214Skarels #if BSD >= 43 32626483Skarels gotsomewhere = 1; 32738214Skarels #endif 32818144Sralph continue; 32918144Sralph } 33025332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 33124734Sbloom #ifdef DEBUG 33218144Sralph if (_res.options & RES_DEBUG) 33327031Skjd perror("recvfrom"); 33425243Skjd #endif DEBUG 33518144Sralph continue; 33618144Sralph } 33726483Skarels gotsomewhere = 1; 33818144Sralph if (id != anhp->id) { 33918144Sralph /* 34018144Sralph * response from old query, ignore it 34118144Sralph */ 34224734Sbloom #ifdef DEBUG 34318144Sralph if (_res.options & RES_DEBUG) { 34418144Sralph printf("old answer:\n"); 34518144Sralph p_query(answer); 34618144Sralph } 34725243Skjd #endif DEBUG 34826323Skarels goto wait; 34918144Sralph } 35018144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 35118144Sralph /* 35238214Skarels * get rest of answer; 35338214Skarels * use TCP with same server. 35418144Sralph */ 35524734Sbloom #ifdef DEBUG 35618144Sralph if (_res.options & RES_DEBUG) 35718144Sralph printf("truncated answer\n"); 35825243Skjd #endif DEBUG 35918144Sralph (void) close(s); 36018144Sralph s = -1; 36118144Sralph v_circuit = 1; 36238214Skarels goto usevc; 36318144Sralph } 36418144Sralph } 36524734Sbloom #ifdef DEBUG 36618144Sralph if (_res.options & RES_DEBUG) { 36718144Sralph printf("got answer:\n"); 36818144Sralph p_query(answer); 36918144Sralph } 37025243Skjd #endif DEBUG 37126322Sbloom /* 37238214Skarels * If using virtual circuits, we assume that the first server 37338214Skarels * is preferred * over the rest (i.e. it is on the local 37438214Skarels * machine) and only keep that one open. 37538214Skarels * If we have temporarily opened a virtual circuit, 37638214Skarels * or if we haven't been asked to keep a socket open, 37738214Skarels * close the socket. 37826322Sbloom */ 37938214Skarels if ((v_circuit && 38038214Skarels ((_res.options & RES_USEVC) == 0 || ns != 0)) || 38138214Skarels (_res.options & RES_STAYOPEN) == 0) { 38226322Sbloom (void) close(s); 38326322Sbloom s = -1; 38426322Sbloom } 38534341Skarels return (resplen); 38625243Skjd } 38718144Sralph } 38829434Sbloom if (s >= 0) { 38929434Sbloom (void) close(s); 39029434Sbloom s = -1; 39129434Sbloom } 39229434Sbloom if (v_circuit == 0) 39329434Sbloom if (gotsomewhere == 0) 39438214Skarels errno = ECONNREFUSED; /* no nameservers found */ 39529434Sbloom else 39638214Skarels errno = ETIMEDOUT; /* no answer obtained */ 39726483Skarels else 39829434Sbloom errno = terrno; 39918144Sralph return (-1); 40018144Sralph } 40127025Sbloom 40227025Sbloom /* 40327025Sbloom * This routine is for closing the socket if a virtual circuit is used and 40427025Sbloom * the program wants to close it. This provides support for endhostent() 40527025Sbloom * which expects to close the socket. 40627025Sbloom * 40727025Sbloom * This routine is not expected to be user visible. 40827025Sbloom */ 40927025Sbloom _res_close() 41027025Sbloom { 41127025Sbloom if (s != -1) { 41227025Sbloom (void) close(s); 41327025Sbloom s = -1; 41427025Sbloom } 41527025Sbloom } 416