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 6 * provided that the above copyright notice and this paragraph are 7 * duplicated in all such forms and that any documentation, 8 * advertising materials, and other materials related to such 9 * distribution and use acknowledge that the software was developed 10 * by the University of California, Berkeley. The name of the 11 * University may not be used to endorse or promote products derived 12 * from this software without specific prior written permission. 13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 16 */ 17 18 #if defined(LIBC_SCCS) && !defined(lint) 19 static char sccsid[] = "@(#)res_send.c 6.24 (Berkeley) 12/27/89"; 20 #endif /* LIBC_SCCS and not lint */ 21 22 /* 23 * Send query to name server and wait for reply. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/time.h> 28 #include <sys/socket.h> 29 #include <sys/uio.h> 30 #include <netinet/in.h> 31 #include <stdio.h> 32 #include <errno.h> 33 #include <arpa/nameser.h> 34 #include <resolv.h> 35 36 extern int errno; 37 38 static int s = -1; /* socket used for communications */ 39 static struct sockaddr no_addr; 40 41 42 #ifndef FD_SET 43 #define NFDBITS 32 44 #define FD_SETSIZE 32 45 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 46 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 47 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 48 #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p))) 49 #endif 50 51 res_send(buf, buflen, answer, anslen) 52 char *buf; 53 int buflen; 54 char *answer; 55 int anslen; 56 { 57 register int n; 58 int try, v_circuit, resplen, ns; 59 int gotsomewhere = 0, connected = 0; 60 int connreset = 0; 61 u_short id, len; 62 char *cp; 63 fd_set dsmask; 64 struct timeval timeout; 65 HEADER *hp = (HEADER *) buf; 66 HEADER *anhp = (HEADER *) answer; 67 struct iovec iov[2]; 68 int terrno = ETIMEDOUT; 69 char junk[512]; 70 71 #ifdef DEBUG 72 if (_res.options & RES_DEBUG) { 73 printf("res_send()\n"); 74 p_query(buf); 75 } 76 #endif DEBUG 77 if (!(_res.options & RES_INIT)) 78 if (res_init() == -1) { 79 return(-1); 80 } 81 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 82 id = hp->id; 83 /* 84 * Send request, RETRY times, or until successful 85 */ 86 for (try = 0; try < _res.retry; try++) { 87 for (ns = 0; ns < _res.nscount; ns++) { 88 #ifdef DEBUG 89 if (_res.options & RES_DEBUG) 90 printf("Querying server (# %d) address = %s\n", ns+1, 91 inet_ntoa(_res.nsaddr_list[ns].sin_addr)); 92 #endif DEBUG 93 usevc: 94 if (v_circuit) { 95 int truncated = 0; 96 97 /* 98 * Use virtual circuit; 99 * at most one attempt per server. 100 */ 101 try = _res.retry; 102 if (s < 0) { 103 s = socket(AF_INET, SOCK_STREAM, 0); 104 if (s < 0) { 105 terrno = errno; 106 #ifdef DEBUG 107 if (_res.options & RES_DEBUG) 108 perror("socket (vc) failed"); 109 #endif DEBUG 110 continue; 111 } 112 if (connect(s, &(_res.nsaddr_list[ns]), 113 sizeof(struct sockaddr)) < 0) { 114 terrno = errno; 115 #ifdef DEBUG 116 if (_res.options & RES_DEBUG) 117 perror("connect failed"); 118 #endif DEBUG 119 (void) close(s); 120 s = -1; 121 continue; 122 } 123 } 124 /* 125 * Send length & message 126 */ 127 len = htons((u_short)buflen); 128 iov[0].iov_base = (caddr_t)&len; 129 iov[0].iov_len = sizeof(len); 130 iov[1].iov_base = buf; 131 iov[1].iov_len = buflen; 132 if (writev(s, iov, 2) != sizeof(len) + buflen) { 133 terrno = errno; 134 #ifdef DEBUG 135 if (_res.options & RES_DEBUG) 136 perror("write failed"); 137 #endif DEBUG 138 (void) close(s); 139 s = -1; 140 continue; 141 } 142 /* 143 * Receive length & response 144 */ 145 cp = answer; 146 len = sizeof(short); 147 while (len != 0 && 148 (n = read(s, (char *)cp, (int)len)) > 0) { 149 cp += n; 150 len -= n; 151 } 152 if (n <= 0) { 153 terrno = errno; 154 #ifdef DEBUG 155 if (_res.options & RES_DEBUG) 156 perror("read failed"); 157 #endif DEBUG 158 (void) close(s); 159 s = -1; 160 /* 161 * A long running process might get its TCP 162 * connection reset if the remote server was 163 * restarted. Requery the server instead of 164 * trying a new one. When there is only one 165 * server, this means that a query might work 166 * instead of failing. We only allow one reset 167 * per query to prevent looping. 168 */ 169 if (terrno == ECONNRESET && !connreset) { 170 connreset = 1; 171 ns--; 172 } 173 continue; 174 } 175 cp = answer; 176 if ((resplen = ntohs(*(u_short *)cp)) > anslen) { 177 #ifdef DEBUG 178 if (_res.options & RES_DEBUG) 179 fprintf(stderr, "response truncated\n"); 180 #endif DEBUG 181 len = anslen; 182 truncated = 1; 183 } else 184 len = resplen; 185 while (len != 0 && 186 (n = read(s, (char *)cp, (int)len)) > 0) { 187 cp += n; 188 len -= n; 189 } 190 if (n <= 0) { 191 terrno = errno; 192 #ifdef DEBUG 193 if (_res.options & RES_DEBUG) 194 perror("read failed"); 195 #endif DEBUG 196 (void) close(s); 197 s = -1; 198 continue; 199 } 200 if (truncated) { 201 /* 202 * Flush rest of answer 203 * so connection stays in synch. 204 */ 205 anhp->tc = 1; 206 len = resplen - anslen; 207 while (len != 0) { 208 n = (len > sizeof(junk) ? 209 sizeof(junk) : len); 210 if ((n = read(s, junk, n)) > 0) 211 len -= n; 212 else 213 break; 214 } 215 } 216 } else { 217 /* 218 * Use datagrams. 219 */ 220 if (s < 0) { 221 s = socket(AF_INET, SOCK_DGRAM, 0); 222 if (s < 0) { 223 terrno = errno; 224 #ifdef DEBUG 225 if (_res.options & RES_DEBUG) 226 perror("socket (dg) failed"); 227 #endif DEBUG 228 continue; 229 } 230 } 231 #if BSD >= 43 232 /* 233 * I'm tired of answering this question, so: 234 * On a 4.3BSD+ machine (client and server, 235 * actually), sending to a nameserver datagram 236 * port with no nameserver will cause an 237 * ICMP port unreachable message to be returned. 238 * If our datagram socket is "connected" to the 239 * server, we get an ECONNREFUSED error on the next 240 * socket operation, and select returns if the 241 * error message is received. We can thus detect 242 * the absence of a nameserver without timing out. 243 * If we have sent queries to at least two servers, 244 * however, we don't want to remain connected, 245 * as we wish to receive answers from the first 246 * server to respond. 247 */ 248 if (_res.nscount == 1 || (try == 0 && ns == 0)) { 249 /* 250 * Don't use connect if we might 251 * still receive a response 252 * from another server. 253 */ 254 if (connected == 0) { 255 if (connect(s, &_res.nsaddr_list[ns], 256 sizeof(struct sockaddr)) < 0) { 257 #ifdef DEBUG 258 if (_res.options & RES_DEBUG) 259 perror("connect"); 260 #endif DEBUG 261 continue; 262 } 263 connected = 1; 264 } 265 if (send(s, buf, buflen, 0) != buflen) { 266 #ifdef DEBUG 267 if (_res.options & RES_DEBUG) 268 perror("send"); 269 #endif DEBUG 270 continue; 271 } 272 } else { 273 /* 274 * Disconnect if we want to listen 275 * for responses from more than one server. 276 */ 277 if (connected) { 278 (void) connect(s, &no_addr, 279 sizeof(no_addr)); 280 connected = 0; 281 } 282 #endif BSD 283 if (sendto(s, buf, buflen, 0, 284 &_res.nsaddr_list[ns], 285 sizeof(struct sockaddr)) != buflen) { 286 #ifdef DEBUG 287 if (_res.options & RES_DEBUG) 288 perror("sendto"); 289 #endif DEBUG 290 continue; 291 } 292 #if BSD >= 43 293 } 294 #endif 295 296 /* 297 * Wait for reply 298 */ 299 timeout.tv_sec = (_res.retrans << try); 300 if (try > 0) 301 timeout.tv_sec /= _res.nscount; 302 if (timeout.tv_sec <= 0) 303 timeout.tv_sec = 1; 304 timeout.tv_usec = 0; 305 wait: 306 FD_ZERO(&dsmask); 307 FD_SET(s, &dsmask); 308 n = select(s+1, &dsmask, (fd_set *)NULL, 309 (fd_set *)NULL, &timeout); 310 if (n < 0) { 311 #ifdef DEBUG 312 if (_res.options & RES_DEBUG) 313 perror("select"); 314 #endif DEBUG 315 continue; 316 } 317 if (n == 0) { 318 /* 319 * timeout 320 */ 321 #ifdef DEBUG 322 if (_res.options & RES_DEBUG) 323 printf("timeout\n"); 324 #endif DEBUG 325 #if BSD >= 43 326 gotsomewhere = 1; 327 #endif 328 continue; 329 } 330 if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 331 #ifdef DEBUG 332 if (_res.options & RES_DEBUG) 333 perror("recvfrom"); 334 #endif DEBUG 335 continue; 336 } 337 gotsomewhere = 1; 338 if (id != anhp->id) { 339 /* 340 * response from old query, ignore it 341 */ 342 #ifdef DEBUG 343 if (_res.options & RES_DEBUG) { 344 printf("old answer:\n"); 345 p_query(answer); 346 } 347 #endif DEBUG 348 goto wait; 349 } 350 if (!(_res.options & RES_IGNTC) && anhp->tc) { 351 /* 352 * get rest of answer; 353 * use TCP with same server. 354 */ 355 #ifdef DEBUG 356 if (_res.options & RES_DEBUG) 357 printf("truncated answer\n"); 358 #endif DEBUG 359 (void) close(s); 360 s = -1; 361 v_circuit = 1; 362 goto usevc; 363 } 364 } 365 #ifdef DEBUG 366 if (_res.options & RES_DEBUG) { 367 printf("got answer:\n"); 368 p_query(answer); 369 } 370 #endif DEBUG 371 /* 372 * If using virtual circuits, we assume that the first server 373 * is preferred * over the rest (i.e. it is on the local 374 * machine) and only keep that one open. 375 * If we have temporarily opened a virtual circuit, 376 * or if we haven't been asked to keep a socket open, 377 * close the socket. 378 */ 379 if ((v_circuit && 380 ((_res.options & RES_USEVC) == 0 || ns != 0)) || 381 (_res.options & RES_STAYOPEN) == 0) { 382 (void) close(s); 383 s = -1; 384 } 385 return (resplen); 386 } 387 } 388 if (s >= 0) { 389 (void) close(s); 390 s = -1; 391 } 392 if (v_circuit == 0) 393 if (gotsomewhere == 0) 394 errno = ECONNREFUSED; /* no nameservers found */ 395 else 396 errno = ETIMEDOUT; /* no answer obtained */ 397 else 398 errno = terrno; 399 return (-1); 400 } 401 402 /* 403 * This routine is for closing the socket if a virtual circuit is used and 404 * the program wants to close it. This provides support for endhostent() 405 * which expects to close the socket. 406 * 407 * This routine is not expected to be user visible. 408 */ 409 _res_close() 410 { 411 if (s != -1) { 412 (void) close(s); 413 s = -1; 414 } 415 } 416