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