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*39703Sbloom static char sccsid[] = "@(#)res_send.c 6.23 (Berkeley) 12/12/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; 60*39703Sbloom 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) 10827031Skjd perror("socket 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; 160*39703Sbloom /* 161*39703Sbloom * A long running process might get its TCP 162*39703Sbloom * connection reset if the remote server was 163*39703Sbloom * restarted. Requery the server instead of 164*39703Sbloom * trying a new one. When there is only one 165*39703Sbloom * server, this means that a query might work 166*39703Sbloom * instead of failing. We only allow one reset 167*39703Sbloom * per query to prevent looping. 168*39703Sbloom */ 169*39703Sbloom if (terrno == ECONNRESET && !connreset) { 170*39703Sbloom connreset = 1; 171*39703Sbloom ns--; 172*39703Sbloom } 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 */ 22018144Sralph if (s < 0) 22118144Sralph s = socket(AF_INET, SOCK_DGRAM, 0); 22226483Skarels #if BSD >= 43 22338214Skarels /* 22438214Skarels * I'm tired of answering this question, so: 22538214Skarels * On a 4.3BSD+ machine (client and server, 22638214Skarels * actually), sending to a nameserver datagram 22738214Skarels * port with no nameserver will cause an 22838214Skarels * ICMP port unreachable message to be returned. 22938214Skarels * If our datagram socket is "connected" to the 23038214Skarels * server, we get an ECONNREFUSED error on the next 23138214Skarels * socket operation, and select returns if the 23238214Skarels * error message is received. We can thus detect 23338214Skarels * the absence of a nameserver without timing out. 23438214Skarels * If we have sent queries to at least two servers, 23538214Skarels * however, we don't want to remain connected, 23638214Skarels * as we wish to receive answers from the first 23738214Skarels * server to respond. 23838214Skarels */ 23938214Skarels if (_res.nscount == 1 || (try == 0 && ns == 0)) { 24030394Skjd /* 24131113Skarels * Don't use connect if we might 24231113Skarels * still receive a response 24331113Skarels * from another server. 24430394Skjd */ 24532603Skarels if (connected == 0) { 24632603Skarels if (connect(s, &_res.nsaddr_list[ns], 24732603Skarels sizeof(struct sockaddr)) < 0) { 24824734Sbloom #ifdef DEBUG 24932603Skarels if (_res.options & RES_DEBUG) 25032603Skarels perror("connect"); 25132603Skarels #endif DEBUG 25232603Skarels continue; 25332603Skarels } 25432603Skarels connected = 1; 25532603Skarels } 25632603Skarels if (send(s, buf, buflen, 0) != buflen) { 25732603Skarels #ifdef DEBUG 25830394Skjd if (_res.options & RES_DEBUG) 25932603Skarels perror("send"); 26025243Skjd #endif DEBUG 26130394Skjd continue; 26230394Skjd } 26334341Skarels } else { 26434341Skarels /* 26534341Skarels * Disconnect if we want to listen 26634341Skarels * for responses from more than one server. 26734341Skarels */ 26834341Skarels if (connected) { 26934341Skarels (void) connect(s, &no_addr, 27034341Skarels sizeof(no_addr)); 27134341Skarels connected = 0; 27234341Skarels } 27330394Skjd #endif BSD 27434341Skarels if (sendto(s, buf, buflen, 0, 27534341Skarels &_res.nsaddr_list[ns], 27634341Skarels sizeof(struct sockaddr)) != buflen) { 27726483Skarels #ifdef DEBUG 27834341Skarels if (_res.options & RES_DEBUG) 27934341Skarels perror("sendto"); 28026483Skarels #endif DEBUG 28134341Skarels continue; 28234341Skarels } 28334341Skarels #if BSD >= 43 28426483Skarels } 28534341Skarels #endif 28630394Skjd 28718144Sralph /* 28827031Skjd * Wait for reply 28918144Sralph */ 29038214Skarels timeout.tv_sec = (_res.retrans << try); 29138214Skarels if (try > 0) 29238214Skarels timeout.tv_sec /= _res.nscount; 29327031Skjd if (timeout.tv_sec <= 0) 29427031Skjd timeout.tv_sec = 1; 29518144Sralph timeout.tv_usec = 0; 29626323Skarels wait: 29727796Skjd FD_ZERO(&dsmask); 29827796Skjd FD_SET(s, &dsmask); 29927664Sbloom n = select(s+1, &dsmask, (fd_set *)NULL, 30027664Sbloom (fd_set *)NULL, &timeout); 30118144Sralph if (n < 0) { 30224734Sbloom #ifdef DEBUG 30318144Sralph if (_res.options & RES_DEBUG) 30427031Skjd perror("select"); 30525243Skjd #endif DEBUG 30618144Sralph continue; 30718144Sralph } 30818144Sralph if (n == 0) { 30918144Sralph /* 31018144Sralph * timeout 31118144Sralph */ 31224734Sbloom #ifdef DEBUG 31318144Sralph if (_res.options & RES_DEBUG) 31418144Sralph printf("timeout\n"); 31525243Skjd #endif DEBUG 31638214Skarels #if BSD >= 43 31726483Skarels gotsomewhere = 1; 31838214Skarels #endif 31918144Sralph continue; 32018144Sralph } 32125332Skjd if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 32224734Sbloom #ifdef DEBUG 32318144Sralph if (_res.options & RES_DEBUG) 32427031Skjd perror("recvfrom"); 32525243Skjd #endif DEBUG 32618144Sralph continue; 32718144Sralph } 32826483Skarels gotsomewhere = 1; 32918144Sralph if (id != anhp->id) { 33018144Sralph /* 33118144Sralph * response from old query, ignore it 33218144Sralph */ 33324734Sbloom #ifdef DEBUG 33418144Sralph if (_res.options & RES_DEBUG) { 33518144Sralph printf("old answer:\n"); 33618144Sralph p_query(answer); 33718144Sralph } 33825243Skjd #endif DEBUG 33926323Skarels goto wait; 34018144Sralph } 34118144Sralph if (!(_res.options & RES_IGNTC) && anhp->tc) { 34218144Sralph /* 34338214Skarels * get rest of answer; 34438214Skarels * use TCP with same server. 34518144Sralph */ 34624734Sbloom #ifdef DEBUG 34718144Sralph if (_res.options & RES_DEBUG) 34818144Sralph printf("truncated answer\n"); 34925243Skjd #endif DEBUG 35018144Sralph (void) close(s); 35118144Sralph s = -1; 35218144Sralph v_circuit = 1; 35338214Skarels goto usevc; 35418144Sralph } 35518144Sralph } 35624734Sbloom #ifdef DEBUG 35718144Sralph if (_res.options & RES_DEBUG) { 35818144Sralph printf("got answer:\n"); 35918144Sralph p_query(answer); 36018144Sralph } 36125243Skjd #endif DEBUG 36226322Sbloom /* 36338214Skarels * If using virtual circuits, we assume that the first server 36438214Skarels * is preferred * over the rest (i.e. it is on the local 36538214Skarels * machine) and only keep that one open. 36638214Skarels * If we have temporarily opened a virtual circuit, 36738214Skarels * or if we haven't been asked to keep a socket open, 36838214Skarels * close the socket. 36926322Sbloom */ 37038214Skarels if ((v_circuit && 37138214Skarels ((_res.options & RES_USEVC) == 0 || ns != 0)) || 37238214Skarels (_res.options & RES_STAYOPEN) == 0) { 37326322Sbloom (void) close(s); 37426322Sbloom s = -1; 37526322Sbloom } 37634341Skarels return (resplen); 37725243Skjd } 37818144Sralph } 37929434Sbloom if (s >= 0) { 38029434Sbloom (void) close(s); 38129434Sbloom s = -1; 38229434Sbloom } 38329434Sbloom if (v_circuit == 0) 38429434Sbloom if (gotsomewhere == 0) 38538214Skarels errno = ECONNREFUSED; /* no nameservers found */ 38629434Sbloom else 38738214Skarels errno = ETIMEDOUT; /* no answer obtained */ 38826483Skarels else 38929434Sbloom errno = terrno; 39018144Sralph return (-1); 39118144Sralph } 39227025Sbloom 39327025Sbloom /* 39427025Sbloom * This routine is for closing the socket if a virtual circuit is used and 39527025Sbloom * the program wants to close it. This provides support for endhostent() 39627025Sbloom * which expects to close the socket. 39727025Sbloom * 39827025Sbloom * This routine is not expected to be user visible. 39927025Sbloom */ 40027025Sbloom _res_close() 40127025Sbloom { 40227025Sbloom if (s != -1) { 40327025Sbloom (void) close(s); 40427025Sbloom s = -1; 40527025Sbloom } 40627025Sbloom } 407