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