xref: /csrg-svn/lib/libc/net/res_send.c (revision 61151)
161023Skarels /*-
2*61151Sbostic  * Copyright (c) 1985, 1989, 1993
3*61151Sbostic  *	The Regents of the University of California.  All rights reserved.
433679Sbostic  *
542627Sbostic  * %sccs.include.redist.c%
661023Skarels  * -
761023Skarels  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
861023Skarels  *
961023Skarels  * Permission to use, copy, modify, and distribute this software for any
1061023Skarels  * purpose with or without fee is hereby granted, provided that the above
1161023Skarels  * copyright notice and this permission notice appear in all copies, and that
1261023Skarels  * the name of Digital Equipment Corporation not be used in advertising or
1361023Skarels  * publicity pertaining to distribution of the document or software without
1461023Skarels  * specific, written prior permission.
1561023Skarels  *
1661023Skarels  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
1761023Skarels  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
1861023Skarels  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
1961023Skarels  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
2061023Skarels  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
2161023Skarels  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
2261023Skarels  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
2361023Skarels  * SOFTWARE.
2461023Skarels  * -
2561023Skarels  * --Copyright--
2618548Sralph  */
2718548Sralph 
2826635Sdonn #if defined(LIBC_SCCS) && !defined(lint)
29*61151Sbostic static char sccsid[] = "@(#)res_send.c	8.1 (Berkeley) 06/04/93";
3061023Skarels 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>
4361023Skarels #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 
res_send(buf,buflen,answer,anslen)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;
7861023Skarels 	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
8461023Skarels 	if ((_res.options & RES_DEBUG) || (_res.pfcode & RES_PRF_QUERY)) {
8561023Skarels 		printf(";; res_send()\n");
8646496Sbostic 		__p_query(buf);
8718144Sralph 	}
8861023Skarels #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;
9561023Skarels 	badns = 0;
9618144Sralph 	/*
9718144Sralph 	 * Send request, RETRY times, or until successful
9818144Sralph 	 */
9938214Skarels 	for (try = 0; try < _res.retry; try++) {
10061023Skarels 	    for (ns = 0; ns < _res.nscount; ns++) {
10161023Skarels 		if (badns & (1<<ns))
10261023Skarels 			continue;
10325243Skjd #ifdef DEBUG
10425243Skjd 		if (_res.options & RES_DEBUG)
10561023Skarels 			printf(";; Querying server (# %d) address = %s\n",
10661023Skarels 			       ns+1,
10761023Skarels 			       inet_ntoa(_res.nsaddr_list[ns].sin_addr));
10861023Skarels #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");
12561023Skarels #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");
13561023Skarels #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");
15461023Skarels #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");
17461023Skarels #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)
19661023Skarels 					fprintf(stderr,
19761023Skarels 						";; response truncated\n");
19861023Skarels #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");
21361023Skarels #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");
24561023Skarels #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) {
27261023Skarels 					if (connect(s,
27361023Skarels 					    (struct sockaddr *)
27461023Skarels 					    &_res.nsaddr_list[ns],
27532603Skarels 					    sizeof(struct sockaddr)) < 0) {
27624734Sbloom #ifdef DEBUG
27732603Skarels 						if (_res.options & RES_DEBUG)
27832603Skarels 							perror("connect");
27961023Skarels #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");
28861023Skarels #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");
30761023Skarels #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;
31861023Skarels 			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");
33061023Skarels #endif
33118144Sralph 				continue;
33218144Sralph 			}
33318144Sralph 			if (n == 0) {
33418144Sralph 				/*
33518144Sralph 				 * timeout
33618144Sralph 				 */
33724734Sbloom #ifdef DEBUG
33818144Sralph 				if (_res.options & RES_DEBUG)
33961023Skarels 					printf(";; timeout\n");
34061023Skarels #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");
34861023Skarels #endif
34918144Sralph 				continue;
35018144Sralph 			}
35126483Skarels 			gotsomewhere = 1;
35218144Sralph 			if (id != anhp->id) {
35318144Sralph 				/*
35418144Sralph 				 * response from old query, ignore it
35518144Sralph 				 */
35624734Sbloom #ifdef DEBUG
35761023Skarels 				if ((_res.options & RES_DEBUG) ||
35861023Skarels 				    (_res.pfcode & RES_PRF_REPLY)) {
35961023Skarels 					printf(";; old answer:\n");
36046496Sbostic 					__p_query(answer);
36118144Sralph 				}
36261023Skarels #endif
36326323Skarels 				goto wait;
36418144Sralph 			}
36561023Skarels 			if (anhp->rcode == SERVFAIL || anhp->rcode == NOTIMP ||
36661023Skarels 			    anhp->rcode == REFUSED) {
36761023Skarels #ifdef DEBUG
36861023Skarels 				if (_res.options & RES_DEBUG) {
36961023Skarels 					printf("server rejected query:\n");
37061023Skarels 					__p_query(answer);
37161023Skarels 				}
37261023Skarels #endif
37361023Skarels 				badns |= (1<<ns);
37461023Skarels 				continue;
37561023Skarels 			}
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)
38361023Skarels 					printf(";; truncated answer\n");
38461023Skarels #endif
38518144Sralph 				(void) close(s);
38618144Sralph 				s = -1;
38718144Sralph 				v_circuit = 1;
38838214Skarels 				goto usevc;
38918144Sralph 			}
39018144Sralph 		}
39124734Sbloom #ifdef DEBUG
39261023Skarels 		if (_res.options & RES_DEBUG)
39361023Skarels 			printf(";; got answer:\n");
39461023Skarels 		if ((_res.options & RES_DEBUG) ||
39561023Skarels 		    (_res.pfcode & RES_PRF_REPLY))
39646496Sbostic 			__p_query(answer);
39761023Skarels #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  */
_res_close()43627025Sbloom _res_close()
43727025Sbloom {
43827025Sbloom 	if (s != -1) {
43927025Sbloom 		(void) close(s);
44027025Sbloom 		s = -1;
44127025Sbloom 	}
44227025Sbloom }
443