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.23 (Berkeley) 12/12/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 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 BSD >= 43 223 /* 224 * I'm tired of answering this question, so: 225 * On a 4.3BSD+ machine (client and server, 226 * actually), sending to a nameserver datagram 227 * port with no nameserver will cause an 228 * ICMP port unreachable message to be returned. 229 * If our datagram socket is "connected" to the 230 * server, we get an ECONNREFUSED error on the next 231 * socket operation, and select returns if the 232 * error message is received. We can thus detect 233 * the absence of a nameserver without timing out. 234 * If we have sent queries to at least two servers, 235 * however, we don't want to remain connected, 236 * as we wish to receive answers from the first 237 * server to respond. 238 */ 239 if (_res.nscount == 1 || (try == 0 && ns == 0)) { 240 /* 241 * Don't use connect if we might 242 * still receive a response 243 * from another server. 244 */ 245 if (connected == 0) { 246 if (connect(s, &_res.nsaddr_list[ns], 247 sizeof(struct sockaddr)) < 0) { 248 #ifdef DEBUG 249 if (_res.options & RES_DEBUG) 250 perror("connect"); 251 #endif DEBUG 252 continue; 253 } 254 connected = 1; 255 } 256 if (send(s, buf, buflen, 0) != buflen) { 257 #ifdef DEBUG 258 if (_res.options & RES_DEBUG) 259 perror("send"); 260 #endif DEBUG 261 continue; 262 } 263 } else { 264 /* 265 * Disconnect if we want to listen 266 * for responses from more than one server. 267 */ 268 if (connected) { 269 (void) connect(s, &no_addr, 270 sizeof(no_addr)); 271 connected = 0; 272 } 273 #endif BSD 274 if (sendto(s, buf, buflen, 0, 275 &_res.nsaddr_list[ns], 276 sizeof(struct sockaddr)) != buflen) { 277 #ifdef DEBUG 278 if (_res.options & RES_DEBUG) 279 perror("sendto"); 280 #endif DEBUG 281 continue; 282 } 283 #if BSD >= 43 284 } 285 #endif 286 287 /* 288 * Wait for reply 289 */ 290 timeout.tv_sec = (_res.retrans << try); 291 if (try > 0) 292 timeout.tv_sec /= _res.nscount; 293 if (timeout.tv_sec <= 0) 294 timeout.tv_sec = 1; 295 timeout.tv_usec = 0; 296 wait: 297 FD_ZERO(&dsmask); 298 FD_SET(s, &dsmask); 299 n = select(s+1, &dsmask, (fd_set *)NULL, 300 (fd_set *)NULL, &timeout); 301 if (n < 0) { 302 #ifdef DEBUG 303 if (_res.options & RES_DEBUG) 304 perror("select"); 305 #endif DEBUG 306 continue; 307 } 308 if (n == 0) { 309 /* 310 * timeout 311 */ 312 #ifdef DEBUG 313 if (_res.options & RES_DEBUG) 314 printf("timeout\n"); 315 #endif DEBUG 316 #if BSD >= 43 317 gotsomewhere = 1; 318 #endif 319 continue; 320 } 321 if ((resplen = recv(s, answer, anslen, 0)) <= 0) { 322 #ifdef DEBUG 323 if (_res.options & RES_DEBUG) 324 perror("recvfrom"); 325 #endif DEBUG 326 continue; 327 } 328 gotsomewhere = 1; 329 if (id != anhp->id) { 330 /* 331 * response from old query, ignore it 332 */ 333 #ifdef DEBUG 334 if (_res.options & RES_DEBUG) { 335 printf("old answer:\n"); 336 p_query(answer); 337 } 338 #endif DEBUG 339 goto wait; 340 } 341 if (!(_res.options & RES_IGNTC) && anhp->tc) { 342 /* 343 * get rest of answer; 344 * use TCP with same server. 345 */ 346 #ifdef DEBUG 347 if (_res.options & RES_DEBUG) 348 printf("truncated answer\n"); 349 #endif DEBUG 350 (void) close(s); 351 s = -1; 352 v_circuit = 1; 353 goto usevc; 354 } 355 } 356 #ifdef DEBUG 357 if (_res.options & RES_DEBUG) { 358 printf("got answer:\n"); 359 p_query(answer); 360 } 361 #endif DEBUG 362 /* 363 * If using virtual circuits, we assume that the first server 364 * is preferred * over the rest (i.e. it is on the local 365 * machine) and only keep that one open. 366 * If we have temporarily opened a virtual circuit, 367 * or if we haven't been asked to keep a socket open, 368 * close the socket. 369 */ 370 if ((v_circuit && 371 ((_res.options & RES_USEVC) == 0 || ns != 0)) || 372 (_res.options & RES_STAYOPEN) == 0) { 373 (void) close(s); 374 s = -1; 375 } 376 return (resplen); 377 } 378 } 379 if (s >= 0) { 380 (void) close(s); 381 s = -1; 382 } 383 if (v_circuit == 0) 384 if (gotsomewhere == 0) 385 errno = ECONNREFUSED; /* no nameservers found */ 386 else 387 errno = ETIMEDOUT; /* no answer obtained */ 388 else 389 errno = terrno; 390 return (-1); 391 } 392 393 /* 394 * This routine is for closing the socket if a virtual circuit is used and 395 * the program wants to close it. This provides support for endhostent() 396 * which expects to close the socket. 397 * 398 * This routine is not expected to be user visible. 399 */ 400 _res_close() 401 { 402 if (s != -1) { 403 (void) close(s); 404 s = -1; 405 } 406 } 407