BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.sbin / named / tools / nslookup / send.c
CommitLineData
b423e985 1/*
e9e1a1f3 2 * Copyright (c) 1985, 1989 Regents of the University of California.
6b2f9dd0
KB
3 * All rights reserved.
4 *
af359dea
C
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
1c15e888
C
32 */
33
34#ifndef lint
af359dea 35static char sccsid[] = "@(#)send.c 5.18 (Berkeley) 3/2/91";
1c15e888
C
36#endif /* not lint */
37
38/*
39 *******************************************************************************
40 *
41 * send.c --
42 *
43 * Routine to send request packets to a name server.
44 *
45 * Based on "@(#)res_send.c 6.25 (Berkeley) 6/1/90".
46 *
47 *******************************************************************************
b423e985
RC
48 */
49
8ea4199d 50
616a94ba
RC
51/*
52 * Send query to name server and wait for reply.
53 */
54
04a773cb 55#include <sys/param.h>
616a94ba
RC
56#include <sys/time.h>
57#include <sys/socket.h>
679f3274 58#include <sys/uio.h>
616a94ba
RC
59#include <netinet/in.h>
60#include <stdio.h>
61#include <errno.h>
27df2740 62#include <arpa/nameser.h>
1c15e888 63#include <arpa/inet.h>
f94b2f50 64#include <resolv.h>
1c15e888 65#include "res.h"
616a94ba
RC
66
67extern int errno;
68
3126f4c0 69static int s = -1; /* socket used for communications */
1c15e888 70
15537e14
KD
71
72#ifndef FD_SET
73#define NFDBITS 32
74#define FD_SETSIZE 32
75#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
76#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
77#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
78#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
79#endif
3126f4c0 80
1c15e888
C
81#define SR 1 /* SendRequest style */
82
83#ifndef DEBUG
84#define DEBUG
85#endif
86
87unsigned short nsport = NAMESERVER_PORT;
88
89
90\f
91/*
92 *******************************************************************************
93 *
94 * SendRequest --
95 *
96 * Sends a request packet to a name server whose address
97 * is specified by the first argument and returns with
98 * the answer packet.
99 *
100 * Results:
101 * SUCCESS - the request was sent and an answer
102 * was received.
103 * TIME_OUT - the virtual circuit connection timed-out
104 * or a reply to a datagram wasn't received.
105 *
106 *
107 *******************************************************************************
108 */
109
110int
111SendRequest(nsAddrPtr, buf, buflen, answer, anslen, trueLenPtr)
112 struct in_addr *nsAddrPtr;
113 char *buf;
114 int buflen;
115 char *answer;
116 u_int anslen;
117 int *trueLenPtr;
616a94ba
RC
118{
119 register int n;
e9e1a1f3 120 int try, v_circuit, resplen, ns;
2344735f 121 int gotsomewhere = 0, connected = 0;
17b5e053 122 int connreset = 0;
616a94ba
RC
123 u_short id, len;
124 char *cp;
ac3ceb42 125 fd_set dsmask;
616a94ba
RC
126 struct timeval timeout;
127 HEADER *hp = (HEADER *) buf;
128 HEADER *anhp = (HEADER *) answer;
679f3274 129 struct iovec iov[2];
1ea504e8 130 int terrno = ETIMEDOUT;
2344735f 131 char junk[512];
616a94ba 132
1c15e888
C
133#if SR
134 struct sockaddr_in sin;
135
136 if (_res.options & RES_DEBUG2) {
137 printf("------------\nSendRequest(), len %d\n", buflen);
138 Print_query(buf, buf+buflen, 1);
139 }
140 sin.sin_family = AF_INET;
141 sin.sin_port = htons(nsport);
142 sin.sin_addr = *nsAddrPtr;
143#else
ae94a224 144#ifdef DEBUG
616a94ba 145 if (_res.options & RES_DEBUG) {
31f0ead0 146 printf("res_send()\n");
616a94ba
RC
147 p_query(buf);
148 }
0b8992ca 149#endif DEBUG
31f0ead0 150 if (!(_res.options & RES_INIT))
ae94a224
JB
151 if (res_init() == -1) {
152 return(-1);
153 }
1c15e888 154#endif /* SR */
616a94ba
RC
155 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ;
156 id = hp->id;
157 /*
158 * Send request, RETRY times, or until successful
159 */
e9e1a1f3 160 for (try = 0; try < _res.retry; try++) {
1c15e888 161#if !SR
0b8992ca
KD
162 for (ns = 0; ns < _res.nscount; ns++) {
163#ifdef DEBUG
164 if (_res.options & RES_DEBUG)
165 printf("Querying server (# %d) address = %s\n", ns+1,
2344735f 166 inet_ntoa(_res.nsaddr_list[ns].sin_addr));
0b8992ca 167#endif DEBUG
1c15e888 168#endif /* !SR */
e9e1a1f3 169 usevc:
616a94ba 170 if (v_circuit) {
2344735f
MK
171 int truncated = 0;
172
616a94ba 173 /*
e9e1a1f3
MK
174 * Use virtual circuit;
175 * at most one attempt per server.
616a94ba 176 */
e9e1a1f3 177 try = _res.retry;
a5d4a4c0 178 if (s < 0) {
616a94ba 179 s = socket(AF_INET, SOCK_STREAM, 0);
92a82fe4 180 if (s < 0) {
1ea504e8 181 terrno = errno;
92a82fe4
MK
182#ifdef DEBUG
183 if (_res.options & RES_DEBUG)
f7d00d5e 184 perror("socket (vc) failed");
92a82fe4
MK
185#endif DEBUG
186 continue;
187 }
1c15e888 188#if SR
af359dea 189 if (connect(s, (struct sockaddr *)&sin,
1c15e888 190#else
af359dea
C
191 if (connect(s,
192 (struct sockaddr *)&(_res.nsaddr_list[ns]),
1c15e888 193#endif
a5d4a4c0 194 sizeof(struct sockaddr)) < 0) {
1ea504e8 195 terrno = errno;
ae94a224 196#ifdef DEBUG
a5d4a4c0 197 if (_res.options & RES_DEBUG)
747d796e 198 perror("connect failed");
0b8992ca 199#endif DEBUG
a5d4a4c0
JB
200 (void) close(s);
201 s = -1;
202 continue;
203 }
616a94ba
RC
204 }
205 /*
206 * Send length & message
207 */
3126f4c0 208 len = htons((u_short)buflen);
679f3274
JB
209 iov[0].iov_base = (caddr_t)&len;
210 iov[0].iov_len = sizeof(len);
211 iov[1].iov_base = buf;
212 iov[1].iov_len = buflen;
213 if (writev(s, iov, 2) != sizeof(len) + buflen) {
1ea504e8 214 terrno = errno;
ae94a224 215#ifdef DEBUG
616a94ba 216 if (_res.options & RES_DEBUG)
747d796e 217 perror("write failed");
0b8992ca 218#endif DEBUG
616a94ba
RC
219 (void) close(s);
220 s = -1;
221 continue;
222 }
223 /*
224 * Receive length & response
225 */
226 cp = answer;
227 len = sizeof(short);
679f3274 228 while (len != 0 &&
747d796e 229 (n = read(s, (char *)cp, (int)len)) > 0) {
616a94ba
RC
230 cp += n;
231 len -= n;
232 }
233 if (n <= 0) {
1ea504e8 234 terrno = errno;
ae94a224 235#ifdef DEBUG
616a94ba 236 if (_res.options & RES_DEBUG)
747d796e 237 perror("read failed");
0b8992ca 238#endif DEBUG
616a94ba
RC
239 (void) close(s);
240 s = -1;
17b5e053
JB
241 /*
242 * A long running process might get its TCP
243 * connection reset if the remote server was
244 * restarted. Requery the server instead of
245 * trying a new one. When there is only one
246 * server, this means that a query might work
247 * instead of failing. We only allow one reset
248 * per query to prevent looping.
249 */
250 if (terrno == ECONNRESET && !connreset) {
251 connreset = 1;
252 ns--;
253 }
616a94ba
RC
254 continue;
255 }
256 cp = answer;
2344735f
MK
257 if ((resplen = ntohs(*(u_short *)cp)) > anslen) {
258#ifdef DEBUG
259 if (_res.options & RES_DEBUG)
260 fprintf(stderr, "response truncated\n");
261#endif DEBUG
262 len = anslen;
263 truncated = 1;
264 } else
265 len = resplen;
679f3274 266 while (len != 0 &&
747d796e 267 (n = read(s, (char *)cp, (int)len)) > 0) {
616a94ba
RC
268 cp += n;
269 len -= n;
270 }
271 if (n <= 0) {
1ea504e8 272 terrno = errno;
ae94a224 273#ifdef DEBUG
616a94ba 274 if (_res.options & RES_DEBUG)
747d796e 275 perror("read failed");
0b8992ca 276#endif DEBUG
616a94ba
RC
277 (void) close(s);
278 s = -1;
279 continue;
280 }
2344735f
MK
281 if (truncated) {
282 /*
283 * Flush rest of answer
284 * so connection stays in synch.
285 */
286 anhp->tc = 1;
287 len = resplen - anslen;
288 while (len != 0) {
289 n = (len > sizeof(junk) ?
290 sizeof(junk) : len);
291 if ((n = read(s, junk, n)) > 0)
292 len -= n;
293 else
294 break;
295 }
296 }
616a94ba
RC
297 } else {
298 /*
299 * Use datagrams.
300 */
f7d00d5e 301 if (s < 0) {
616a94ba 302 s = socket(AF_INET, SOCK_DGRAM, 0);
f7d00d5e
JB
303 if (s < 0) {
304 terrno = errno;
305#ifdef DEBUG
306 if (_res.options & RES_DEBUG)
307 perror("socket (dg) failed");
308#endif DEBUG
309 continue;
310 }
311 }
1c15e888
C
312#if SR
313 /*
314 * Special case the send code below
315 * since we have just 1 server.
316 */
317#if BSD >= 43
318 if (connected == 0) {
af359dea 319 if (connect(s, (struct sockaddr *)&sin,
1c15e888
C
320 sizeof(struct sockaddr)) < 0) {
321 if (_res.options & RES_DEBUG)
322 perror("connect");
323 continue;
324 }
325 connected = 1;
326 }
327 if (send(s, buf, buflen, 0) != buflen) {
328 if (_res.options & RES_DEBUG)
329 perror("send");
330 continue;
331 }
332#else /* BSD */
333 if (sendto(s, buf, buflen, 0, &sin,
334 sizeof(struct sockaddr)) != buflen) {
335 if (_res.options & RES_DEBUG)
336 perror("sendto");
337 continue;
338 }
339#endif
340#else /* SR */
92a82fe4 341#if BSD >= 43
e9e1a1f3
MK
342 /*
343 * I'm tired of answering this question, so:
344 * On a 4.3BSD+ machine (client and server,
345 * actually), sending to a nameserver datagram
346 * port with no nameserver will cause an
347 * ICMP port unreachable message to be returned.
348 * If our datagram socket is "connected" to the
349 * server, we get an ECONNREFUSED error on the next
350 * socket operation, and select returns if the
351 * error message is received. We can thus detect
352 * the absence of a nameserver without timing out.
353 * If we have sent queries to at least two servers,
354 * however, we don't want to remain connected,
355 * as we wish to receive answers from the first
356 * server to respond.
357 */
358 if (_res.nscount == 1 || (try == 0 && ns == 0)) {
7a8f7802 359 /*
9bb3997d
MK
360 * Don't use connect if we might
361 * still receive a response
362 * from another server.
7a8f7802 363 */
2344735f
MK
364 if (connected == 0) {
365 if (connect(s, &_res.nsaddr_list[ns],
366 sizeof(struct sockaddr)) < 0) {
367#ifdef DEBUG
368 if (_res.options & RES_DEBUG)
369 perror("connect");
370#endif DEBUG
371 continue;
372 }
373 connected = 1;
374 }
375 if (send(s, buf, buflen, 0) != buflen) {
ae94a224 376#ifdef DEBUG
7a8f7802 377 if (_res.options & RES_DEBUG)
2344735f 378 perror("send");
0b8992ca 379#endif DEBUG
7a8f7802
KD
380 continue;
381 }
fee59cfd
MK
382 } else {
383 /*
384 * Disconnect if we want to listen
385 * for responses from more than one server.
386 */
387 if (connected) {
388 (void) connect(s, &no_addr,
389 sizeof(no_addr));
390 connected = 0;
391 }
7a8f7802 392#endif BSD
fee59cfd
MK
393 if (sendto(s, buf, buflen, 0,
394 &_res.nsaddr_list[ns],
395 sizeof(struct sockaddr)) != buflen) {
92a82fe4 396#ifdef DEBUG
fee59cfd
MK
397 if (_res.options & RES_DEBUG)
398 perror("sendto");
92a82fe4 399#endif DEBUG
fee59cfd
MK
400 continue;
401 }
402#if BSD >= 43
616a94ba 403 }
fee59cfd 404#endif
1c15e888 405#endif /* SR */
7a8f7802 406
616a94ba 407 /*
747d796e 408 * Wait for reply
616a94ba 409 */
e9e1a1f3 410 timeout.tv_sec = (_res.retrans << try);
1c15e888 411#if !SR
e9e1a1f3
MK
412 if (try > 0)
413 timeout.tv_sec /= _res.nscount;
1c15e888 414#endif /* SR */
747d796e
KD
415 if (timeout.tv_sec <= 0)
416 timeout.tv_sec = 1;
616a94ba 417 timeout.tv_usec = 0;
87b12937 418wait:
ac3ceb42
KD
419 FD_ZERO(&dsmask);
420 FD_SET(s, &dsmask);
679f3274
JB
421 n = select(s+1, &dsmask, (fd_set *)NULL,
422 (fd_set *)NULL, &timeout);
616a94ba 423 if (n < 0) {
ae94a224 424#ifdef DEBUG
616a94ba 425 if (_res.options & RES_DEBUG)
747d796e 426 perror("select");
0b8992ca 427#endif DEBUG
616a94ba
RC
428 continue;
429 }
430 if (n == 0) {
431 /*
432 * timeout
433 */
ae94a224 434#ifdef DEBUG
616a94ba 435 if (_res.options & RES_DEBUG)
1c15e888
C
436 printf("timeout (%d secs)\n",
437 timeout.tv_sec);
0b8992ca 438#endif DEBUG
e9e1a1f3 439#if BSD >= 43
92a82fe4 440 gotsomewhere = 1;
e9e1a1f3 441#endif
616a94ba
RC
442 continue;
443 }
dd7a6a73 444 if ((resplen = recv(s, answer, anslen, 0)) <= 0) {
ae94a224 445#ifdef DEBUG
616a94ba 446 if (_res.options & RES_DEBUG)
747d796e 447 perror("recvfrom");
0b8992ca 448#endif DEBUG
616a94ba
RC
449 continue;
450 }
92a82fe4 451 gotsomewhere = 1;
616a94ba
RC
452 if (id != anhp->id) {
453 /*
454 * response from old query, ignore it
455 */
1c15e888
C
456#if SR
457 if (_res.options & RES_DEBUG2) {
458 printf("------------\nOld answer:\n");
459 Print_query(answer, answer+resplen, 1);
460 }
461#else
ae94a224 462#ifdef DEBUG
616a94ba 463 if (_res.options & RES_DEBUG) {
616a94ba 464 printf("old answer:\n");
616a94ba
RC
465 p_query(answer);
466 }
0b8992ca 467#endif DEBUG
1c15e888 468#endif
87b12937 469 goto wait;
616a94ba
RC
470 }
471 if (!(_res.options & RES_IGNTC) && anhp->tc) {
472 /*
e9e1a1f3
MK
473 * get rest of answer;
474 * use TCP with same server.
616a94ba 475 */
ae94a224 476#ifdef DEBUG
616a94ba
RC
477 if (_res.options & RES_DEBUG)
478 printf("truncated answer\n");
0b8992ca 479#endif DEBUG
616a94ba
RC
480 (void) close(s);
481 s = -1;
616a94ba 482 v_circuit = 1;
e9e1a1f3 483 goto usevc;
616a94ba
RC
484 }
485 }
1c15e888
C
486#if SR
487 if (_res.options & RES_DEBUG) {
488 if (_res.options & RES_DEBUG2)
489 printf("------------\nGot answer (%d bytes):\n",
490 resplen);
491 else
492 printf("------------\nGot answer:\n");
493 Print_query(answer, answer+resplen, 1);
494 }
495 (void) close(s);
496 s = -1;
497 *trueLenPtr = resplen;
498 return (SUCCESS);
499#else
ae94a224 500#ifdef DEBUG
616a94ba
RC
501 if (_res.options & RES_DEBUG) {
502 printf("got answer:\n");
503 p_query(answer);
504 }
0b8992ca 505#endif DEBUG
a5d4a4c0 506 /*
e9e1a1f3
MK
507 * If using virtual circuits, we assume that the first server
508 * is preferred * over the rest (i.e. it is on the local
509 * machine) and only keep that one open.
510 * If we have temporarily opened a virtual circuit,
511 * or if we haven't been asked to keep a socket open,
512 * close the socket.
a5d4a4c0 513 */
e9e1a1f3
MK
514 if ((v_circuit &&
515 ((_res.options & RES_USEVC) == 0 || ns != 0)) ||
516 (_res.options & RES_STAYOPEN) == 0) {
a5d4a4c0
JB
517 (void) close(s);
518 s = -1;
a5d4a4c0 519 }
fee59cfd 520 return (resplen);
0b8992ca 521 }
1c15e888 522#endif /* SR */
616a94ba 523 }
1ea504e8
JB
524 if (s >= 0) {
525 (void) close(s);
526 s = -1;
527 }
1c15e888
C
528#if SR
529 if (v_circuit == 0)
530 if (gotsomewhere == 0)
531 return NO_RESPONSE; /* no nameservers found */
532 else
533 return TIME_OUT; /* no answer obtained */
534 else
535 if (errno == ECONNREFUSED)
536 return NO_RESPONSE;
537 else
538 return ERROR;
539#else
1ea504e8
JB
540 if (v_circuit == 0)
541 if (gotsomewhere == 0)
e9e1a1f3 542 errno = ECONNREFUSED; /* no nameservers found */
1ea504e8 543 else
e9e1a1f3 544 errno = ETIMEDOUT; /* no answer obtained */
92a82fe4 545 else
1ea504e8 546 errno = terrno;
616a94ba 547 return (-1);
1c15e888 548#endif
616a94ba 549}
3126f4c0
JB
550
551/*
552 * This routine is for closing the socket if a virtual circuit is used and
1c15e888 553 * the program wants to close it.
3126f4c0 554 *
1c15e888 555 * Called from the interrupt handler.
3126f4c0 556 */
1c15e888 557SendRequest_close()
3126f4c0
JB
558{
559 if (s != -1) {
560 (void) close(s);
561 s = -1;
562 }
563}