import less(1)
[unleashed/tickless.git] / usr / src / lib / libresolv / res_send.c
blob0aa01a677702b6f742103585542ba94ea0e5a1d8
1 /*
2 * CDDL HEADER START
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
19 * CDDL HEADER END
23 * Copyright 2015 Gary Mills
24 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
25 * Use is subject to license terms.
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29 /* All Rights Reserved */
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
42 * Send query to name server and wait for reply.
45 #include <sys/param.h>
46 #include <sys/time.h>
47 #include <sys/socket.h>
48 #include <sys/uio.h>
49 #include <sys/stat.h>
50 #include <netinet/in.h>
51 #include <stdio.h>
52 #include <string.h>
53 #include <unistd.h>
54 #include <errno.h>
55 #include <arpa/nameser.h>
56 #include <arpa/inet.h>
57 #include <resolv.h>
58 #include "crossl.h"
60 static int s = -1; /* socket used for communications */
61 #if BSD >= 43
62 static struct sockaddr no_addr;
63 #endif /* BSD */
66 #ifndef FD_SET
67 #define NFDBITS 32
68 #define FD_SETSIZE 32
69 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
70 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
71 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
72 #ifdef SYSV
73 #define FD_ZERO(p) (void) memset((p), 0, sizeof (*(p)))
74 #else
75 #define FD_ZERO(p) bzero((char *)(p), sizeof (*(p)))
76 #endif
77 #endif
80 * 1247019: Kludge to time out quickly if there is no /etc/resolv.conf
81 * and a TCP connection to the local DNS server fails.
84 static int _confcheck()
86 int ns;
87 struct stat rc_stat;
88 struct sockaddr_in ns_sin;
91 /* First, we check to see if /etc/resolv.conf exists.
92 * If it doesn't, then localhost is mostlikely to be
93 * the nameserver.
95 if (stat(_PATH_RESCONF, &rc_stat) == -1 && errno == ENOENT) {
97 /* Next, we check to see if _res.nsaddr is set to loopback.
98 * If it isn't, it has been altered by the application
99 * explicitly and we then want to bail with success.
101 if (_res.nsaddr.sin_addr.S_un.S_addr == htonl(INADDR_LOOPBACK)) {
103 /* Lastly, we try to connect to the TCP port of the
104 * nameserver. If this fails, then we know that
105 * DNS is misconfigured and we can quickly exit.
107 ns = socket(AF_INET, SOCK_STREAM, 0);
108 IN_SET_LOOPBACK_ADDR(&ns_sin);
109 ns_sin.sin_port = htons(NAMESERVER_PORT);
110 if (connect(ns, (struct sockaddr *) &ns_sin,
111 sizeof ns_sin) == -1) {
112 close(ns);
113 return(-1);
115 else {
116 close(ns);
117 return(0);
121 return(0);
124 return (0);
128 res_send(buf, buflen, answer, anslen)
129 char *buf;
130 int buflen;
131 char *answer;
132 int anslen;
134 register int n;
135 int try, v_circuit, resplen, ns;
136 int gotsomewhere = 0;
137 #if BSD >= 43
138 int connected = 0;
139 #endif /* BSD */
140 int connreset = 0;
141 u_short id, len;
142 char *cp;
143 fd_set dsmask;
144 struct timeval timeout;
145 HEADER *hp = (HEADER *) buf;
146 HEADER *anhp = (HEADER *) answer;
147 struct iovec iov[2];
148 int terrno = ETIMEDOUT;
149 char junk[512];
151 #ifdef DEBUG
152 if (_res.options & RES_DEBUG) {
153 printf("res_send()\n");
154 p_query(buf);
156 #endif
157 if (!(_res.options & RES_INIT))
158 if (res_init() == -1) {
159 return (-1);
162 /* 1247019: Check to see if we can bailout quickly. */
163 if (_confcheck() == -1)
164 return(-1);
166 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
167 id = hp->id;
169 * Send request, RETRY times, or until successful
171 for (try = 0; try < _res.retry; try++) {
172 for (ns = 0; ns < _res.nscount; ns++) {
173 #ifdef DEBUG
174 if (_res.options & RES_DEBUG)
175 printf("Querying server (# %d) address = %s\n",
176 ns+1, inet_ntoa(_res.nsaddr_list[ns].sin_addr));
177 #endif
178 usevc:
179 if (v_circuit) {
180 int truncated = 0;
183 * Use virtual circuit;
184 * at most one attempt per server.
186 try = _res.retry;
187 if (s < 0) {
188 s = socket(AF_INET, SOCK_STREAM, 0);
189 if (s < 0) {
190 terrno = errno;
191 #ifdef DEBUG
192 if (_res.options & RES_DEBUG) {
193 perror("socket (vc) failed");
195 #endif
196 continue;
198 if (connect(s, (struct sockaddr *) &_res.nsaddr_list[ns],
199 sizeof (struct sockaddr)) < 0) {
200 terrno = errno;
201 #ifdef DEBUG
202 if (_res.options & RES_DEBUG) {
203 perror("connect failed");
205 #endif
206 (void) close(s);
207 s = -1;
208 continue;
212 * Send length & message
214 len = htons((u_short)buflen);
215 iov[0].iov_base = (caddr_t)&len;
216 iov[0].iov_len = sizeof (len);
217 iov[1].iov_base = buf;
218 iov[1].iov_len = buflen;
219 if (writev(s, iov, 2) != sizeof (len) +
220 buflen) {
221 terrno = errno;
222 #ifdef DEBUG
223 if (_res.options & RES_DEBUG)
224 perror("write failed");
225 #endif
226 (void) close(s);
227 s = -1;
228 continue;
231 * Receive length & response
233 cp = answer;
234 len = sizeof (short);
235 while (len != 0 && (n = read
236 (s, (char *)cp, (int)len)) > 0) {
237 cp += n;
238 len -= n;
240 if (n <= 0) {
241 terrno = errno;
242 #ifdef DEBUG
243 if (_res.options & RES_DEBUG)
244 perror("read failed");
245 #endif
246 (void) close(s);
247 s = -1;
249 * A long running process might get its TCP
250 * connection reset if the remote server was
251 * restarted. Requery the server instead of
252 * trying a new one. When there is only one
253 * server, this means that a query might work
254 * instead of failing. We only allow one reset
255 * per query to prevent looping.
257 if (terrno == ECONNRESET &&
258 !connreset) {
259 connreset = 1;
260 ns--;
262 continue;
264 cp = answer;
265 if ((resplen = ntohs(*(u_short *)cp)) >
266 anslen) {
267 #ifdef DEBUG
268 if (_res.options & RES_DEBUG)
269 fprintf(stderr,
270 "response truncated\n");
271 #endif
272 len = anslen;
273 truncated = 1;
274 } else
275 len = resplen;
276 while (len != 0 &&
277 (n = read(s, (char *)cp,
278 (int)len)) > 0) {
279 cp += n;
280 len -= n;
282 if (n <= 0) {
283 terrno = errno;
284 #ifdef DEBUG
285 if (_res.options & RES_DEBUG)
286 perror("read failed");
287 #endif
288 (void) close(s);
289 s = -1;
290 continue;
292 if (truncated) {
294 * Flush rest of answer
295 * so connection stays in synch.
297 anhp->tc = 1;
298 len = resplen - anslen;
300 * set the value of resplen to anslen,
301 * this is done because the caller
302 * assumes resplen contains the size of
303 * message read into the "answer" buffer
304 * passed in.
306 resplen = anslen;
308 while (len != 0) {
309 n = (len > sizeof (junk) ?
310 sizeof (junk) : len);
311 if ((n = read(s, junk, n)) > 0)
312 len -= n;
313 else
314 break;
317 } else {
319 * Use datagrams.
321 if (s < 0) {
322 s = socket(AF_INET, SOCK_DGRAM, 0);
323 if (s < 0) {
324 terrno = errno;
325 #ifdef DEBUG
326 if (_res.options & RES_DEBUG) {
327 perror("socket (dg) failed");
329 #endif
330 continue;
333 #if BSD >= 43
335 * I'm tired of answering this question, so:
336 * On a 4.3BSD+ machine (client and server,
337 * actually), sending to a nameserver datagram
338 * port with no nameserver will cause an
339 * ICMP port unreachable message to be returned.
340 * If our datagram socket is "connected" to the
341 * server, we get an ECONNREFUSED error on the next
342 * socket operation, and select returns if the
343 * error message is received. We can thus detect
344 * the absence of a nameserver without timing out.
345 * If we have sent queries to at least two servers,
346 * however, we don't want to remain connected,
347 * as we wish to receive answers from the first
348 * server to respond.
350 if (_res.nscount == 1 ||
351 (try == 0 && ns == 0)) {
353 * Don't use connect if we might
354 * still receive a response
355 * from another server.
357 if (connected == 0) {
358 if (connect(s,
359 (struct sockaddr *) &_res.nsaddr_list[ns],
360 sizeof (struct sockaddr)) < 0) {
361 #ifdef DEBUG
362 if (_res.options &
363 RES_DEBUG) {
364 perror("connect");
366 #endif
367 continue;
369 connected = 1;
371 if (send(s, buf, buflen, 0) != buflen) {
372 #ifdef DEBUG
373 if (_res.options & RES_DEBUG)
374 perror("send");
375 #endif
376 continue;
378 } else {
380 * Disconnect if we want to listen for
381 * responses from more than one server.
383 if (connected) {
384 (void) connect(s, &no_addr,
385 sizeof (no_addr));
386 connected = 0;
388 #endif /* BSD */
389 if (sendto(s, buf, buflen, 0,
390 (struct sockaddr *) &_res.nsaddr_list[ns],
391 sizeof (struct sockaddr)) != buflen) {
392 #ifdef DEBUG
393 if (_res.options & RES_DEBUG)
394 perror("sendto");
395 #endif
396 continue;
398 #if BSD >= 43
400 #endif
403 * Wait for reply
405 timeout.tv_sec = (_res.retrans << try);
406 if (try > 0)
407 timeout.tv_sec /= _res.nscount;
408 if (timeout.tv_sec <= 0)
409 timeout.tv_sec = 1;
410 timeout.tv_usec = 0;
411 wait:
412 FD_ZERO(&dsmask);
413 FD_SET(s, &dsmask);
414 n = select(s+1, &dsmask, (fd_set *)NULL,
415 (fd_set *)NULL, &timeout);
416 if (n < 0) {
417 #ifdef DEBUG
418 if (_res.options & RES_DEBUG)
419 perror("select");
420 #endif
421 continue;
423 if (n == 0) {
425 * timeout
427 #ifdef DEBUG
428 if (_res.options & RES_DEBUG)
429 printf("timeout\n");
430 #endif
431 #if BSD >= 43
432 gotsomewhere = 1;
433 #endif
434 continue;
436 if ((resplen = recv(s, answer, anslen, 0))
437 <= 0) {
438 #ifdef DEBUG
439 if (_res.options & RES_DEBUG)
440 perror("recvfrom");
441 #endif
442 continue;
444 gotsomewhere = 1;
445 if (id != anhp->id) {
447 * response from old query, ignore it
449 #ifdef DEBUG
450 if (_res.options & RES_DEBUG) {
451 printf("old answer:\n");
452 p_query(answer);
454 #endif
455 goto wait;
457 if (!(_res.options & RES_IGNTC) && anhp->tc) {
459 * get rest of answer;
460 * use TCP with same server.
462 #ifdef DEBUG
463 if (_res.options & RES_DEBUG)
464 printf("truncated answer\n");
465 #endif
466 (void) close(s);
467 s = -1;
468 v_circuit = 1;
469 goto usevc;
472 #ifdef DEBUG
473 if (_res.options & RES_DEBUG) {
474 printf("got answer:\n");
475 p_query(answer);
477 #endif
479 * If using virtual circuits, we assume that the first server
480 * is preferred * over the rest (i.e. it is on the local
481 * machine) and only keep that one open.
482 * If we have temporarily opened a virtual circuit,
483 * or if we haven't been asked to keep a socket open,
484 * close the socket.
486 if ((v_circuit &&
487 ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
488 (_res.options & RES_STAYOPEN) == 0) {
489 (void) close(s);
490 s = -1;
492 return (resplen);
495 if (s >= 0) {
496 (void) close(s);
497 s = -1;
499 if (v_circuit == 0)
500 if (gotsomewhere == 0)
501 errno = ECONNREFUSED; /* no nameservers found */
502 else
503 errno = ETIMEDOUT; /* no answer obtained */
504 else
505 errno = terrno;
506 return (-1);
510 * This routine is for closing the socket if a virtual circuit is used and
511 * the program wants to close it. This provides support for endhostent()
512 * which expects to close the socket.
514 * This routine is not expected to be user visible.
516 void
517 _res_close()
519 if (s != -1) {
520 (void) close(s);
521 s = -1;