1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2003 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 28 /* All Rights Reserved */ 29 30 /* 31 * University Copyright- Copyright (c) 1982, 1986, 1988 32 * The Regents of the University of California 33 * All Rights Reserved 34 * 35 * University Acknowledgment- Portions of this document are derived from 36 * software developed by the University of California, Berkeley, and its 37 * contributors. 38 */ 39 40 #pragma ident "%Z%%M% %I% %E% SMI" 41 42 /* 43 * Send query to name server and wait for reply. 44 */ 45 46 #include "synonyms.h" 47 48 #include <sys/param.h> 49 #include <sys/time.h> 50 #include <sys/socket.h> 51 #include <sys/uio.h> 52 #include <sys/stat.h> 53 #include <netinet/in.h> 54 #include <stdio.h> 55 #include <errno.h> 56 #include <arpa/nameser.h> 57 #include <resolv.h> 58 59 60 static int s = -1; /* socket used for communications */ 61 static struct sockaddr no_addr; 62 63 64 #ifndef FD_SET 65 #define NFDBITS 32 66 #define FD_SETSIZE 32 67 #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS))) 68 #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS))) 69 #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS))) 70 #ifdef SYSV 71 #define FD_ZERO(p) memset((void *)(p), 0, sizeof (*(p))) 72 #else 73 #define FD_ZERO(p) bzero((char *)(p), sizeof (*(p))) 74 #endif 75 #endif 76 77 /* 78 * 1247019: Kludge to time out quickly if there is no /etc/resolv.conf 79 * and a TCP connection to the local DNS server fails. 80 */ 81 82 static int _confcheck() 83 { 84 int ns; 85 struct stat rc_stat; 86 struct sockaddr_in ns_sin; 87 88 89 /* First, we check to see if /etc/resolv.conf exists. 90 * If it doesn't, then localhost is mostlikely to be 91 * the nameserver. 92 */ 93 if (stat(_PATH_RESCONF, &rc_stat) == -1 && errno == ENOENT) { 94 95 /* Next, we check to see if _res.nsaddr is set to loopback. 96 * If it isn't, it has been altered by the application 97 * explicitly and we then want to bail with success. 98 */ 99 if (_res.nsaddr.sin_addr.S_un.S_addr == htonl(INADDR_LOOPBACK)) { 100 101 /* Lastly, we try to connect to the TCP port of the 102 * nameserver. If this fails, then we know that 103 * DNS is misconfigured and we can quickly exit. 104 */ 105 ns = socket(AF_INET, SOCK_STREAM, 0); 106 IN_SET_LOOPBACK_ADDR(&ns_sin); 107 ns_sin.sin_port = htons(NAMESERVER_PORT); 108 if (connect(ns, (struct sockaddr *) &ns_sin, 109 sizeof ns_sin) == -1) { 110 close(ns); 111 return(-1); 112 } 113 else { 114 close(ns); 115 return(0); 116 } 117 } 118 119 return(0); 120 } 121 122 return (0); 123 } 124 125 res_send(buf, buflen, answer, anslen) 126 char *buf; 127 int buflen; 128 char *answer; 129 int anslen; 130 { 131 register int n; 132 int try, v_circuit, resplen, ns; 133 int gotsomewhere = 0, connected = 0; 134 int connreset = 0; 135 u_short id, len; 136 char *cp; 137 fd_set dsmask; 138 struct timeval timeout; 139 HEADER *hp = (HEADER *) buf; 140 HEADER *anhp = (HEADER *) answer; 141 struct iovec iov[2]; 142 int terrno = ETIMEDOUT; 143 char junk[512]; 144 145 #ifdef DEBUG 146 if (_res.options & RES_DEBUG) { 147 printf("res_send()\n"); 148 p_query(buf); 149 } 150 #endif DEBUG 151 if (!(_res.options & RES_INIT)) 152 if (res_init() == -1) { 153 return (-1); 154 } 155 156 /* 1247019: Check to see if we can bailout quickly. */ 157 if (_confcheck() == -1) 158 return(-1); 159 160 v_circuit = (_res.options & RES_USEVC) || buflen > PACKETSZ; 161 id = hp->id; 162 /* 163 * Send request, RETRY times, or until successful 164 */ 165 for (try = 0; try < _res.retry; try++) { 166 for (ns = 0; ns < _res.nscount; ns++) { 167 #ifdef DEBUG 168 if (_res.options & RES_DEBUG) 169 printf("Querying server (# %d) address = %s\n", 170 ns+1, inet_ntoa(_res.nsaddr_list[ns].sin_addr)); 171 #endif DEBUG 172 usevc: 173 if (v_circuit) { 174 int truncated = 0; 175 176 /* 177 * Use virtual circuit; 178 * at most one attempt per server. 179 */ 180 try = _res.retry; 181 if (s < 0) { 182 s = _socket(AF_INET, SOCK_STREAM, 0); 183 if (s < 0) { 184 terrno = errno; 185 #ifdef DEBUG 186 if (_res.options & RES_DEBUG) { 187 perror("socket (vc) failed"); 188 } 189 #endif DEBUG 190 continue; 191 } 192 if (connect(s, (struct sockaddr *) &_res.nsaddr_list[ns], 193 sizeof (struct sockaddr)) < 0) { 194 terrno = errno; 195 #ifdef DEBUG 196 if (_res.options & RES_DEBUG) { 197 perror("connect failed"); 198 } 199 #endif DEBUG 200 (void) close(s); 201 s = -1; 202 continue; 203 } 204 } 205 /* 206 * Send length & message 207 */ 208 len = htons((u_short)buflen); 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) + 214 buflen) { 215 terrno = errno; 216 #ifdef DEBUG 217 if (_res.options & RES_DEBUG) 218 perror("write failed"); 219 #endif DEBUG 220 (void) close(s); 221 s = -1; 222 continue; 223 } 224 /* 225 * Receive length & response 226 */ 227 cp = answer; 228 len = sizeof (short); 229 while (len != 0 && (n = read 230 (s, (char *)cp, (int)len)) > 0) { 231 cp += n; 232 len -= n; 233 } 234 if (n <= 0) { 235 terrno = errno; 236 #ifdef DEBUG 237 if (_res.options & RES_DEBUG) 238 perror("read failed"); 239 #endif DEBUG 240 (void) close(s); 241 s = -1; 242 /* 243 * A long running process might get its TCP 244 * connection reset if the remote server was 245 * restarted. Requery the server instead of 246 * trying a new one. When there is only one 247 * server, this means that a query might work 248 * instead of failing. We only allow one reset 249 * per query to prevent looping. 250 */ 251 if (terrno == ECONNRESET && 252 !connreset) { 253 connreset = 1; 254 ns--; 255 } 256 continue; 257 } 258 cp = answer; 259 if ((resplen = ntohs(*(u_short *)cp)) > 260 anslen) { 261 #ifdef DEBUG 262 if (_res.options & RES_DEBUG) 263 fprintf(stderr, 264 "response truncated\n"); 265 #endif DEBUG 266 len = anslen; 267 truncated = 1; 268 } else 269 len = resplen; 270 while (len != 0 && 271 (n = read(s, (char *)cp, 272 (int)len)) > 0) { 273 cp += n; 274 len -= n; 275 } 276 if (n <= 0) { 277 terrno = errno; 278 #ifdef DEBUG 279 if (_res.options & RES_DEBUG) 280 perror("read failed"); 281 #endif DEBUG 282 (void) close(s); 283 s = -1; 284 continue; 285 } 286 if (truncated) { 287 /* 288 * Flush rest of answer 289 * so connection stays in synch. 290 */ 291 anhp->tc = 1; 292 len = resplen - anslen; 293 /* 294 * set the value of resplen to anslen, 295 * this is done because the caller 296 * assumes resplen contains the size of 297 * message read into the "answer" buffer 298 * passed in. 299 */ 300 resplen = anslen; 301 302 while (len != 0) { 303 n = (len > sizeof (junk) ? 304 sizeof (junk) : len); 305 if ((n = read(s, junk, n)) > 0) 306 len -= n; 307 else 308 break; 309 } 310 } 311 } else { 312 /* 313 * Use datagrams. 314 */ 315 if (s < 0) { 316 s = _socket(AF_INET, SOCK_DGRAM, 0); 317 if (s < 0) { 318 terrno = errno; 319 #ifdef DEBUG 320 if (_res.options & RES_DEBUG) { 321 perror("socket (dg) failed"); 322 } 323 #endif DEBUG 324 continue; 325 } 326 } 327 #if BSD >= 43 328 /* 329 * I'm tired of answering this question, so: 330 * On a 4.3BSD+ machine (client and server, 331 * actually), sending to a nameserver datagram 332 * port with no nameserver will cause an 333 * ICMP port unreachable message to be returned. 334 * If our datagram socket is "connected" to the 335 * server, we get an ECONNREFUSED error on the next 336 * socket operation, and select returns if the 337 * error message is received. We can thus detect 338 * the absence of a nameserver without timing out. 339 * If we have sent queries to at least two servers, 340 * however, we don't want to remain connected, 341 * as we wish to receive answers from the first 342 * server to respond. 343 */ 344 if (_res.nscount == 1 || 345 (try == 0 && ns == 0)) { 346 /* 347 * Don't use connect if we might 348 * still receive a response 349 * from another server. 350 */ 351 if (connected == 0) { 352 if (connect(s, 353 (struct sockaddr *) &_res.nsaddr_list[ns], 354 sizeof (struct sockaddr)) < 0) { 355 #ifdef DEBUG 356 if (_res.options & 357 RES_DEBUG) { 358 perror("connect"); 359 } 360 #endif DEBUG 361 continue; 362 } 363 connected = 1; 364 } 365 if (send(s, buf, buflen, 0) != buflen) { 366 #ifdef DEBUG 367 if (_res.options & RES_DEBUG) 368 perror("send"); 369 #endif DEBUG 370 continue; 371 } 372 } else { 373 /* 374 * Disconnect if we want to listen for 375 * responses from more than one server. 376 */ 377 if (connected) { 378 (void) connect(s, &no_addr, 379 sizeof (no_addr)); 380 connected = 0; 381 } 382 #endif BSD 383 if (sendto(s, buf, buflen, 0, 384 (struct sockaddr *) &_res.nsaddr_list[ns], 385 sizeof (struct sockaddr)) != buflen) { 386 #ifdef DEBUG 387 if (_res.options & RES_DEBUG) 388 perror("sendto"); 389 #endif DEBUG 390 continue; 391 } 392 #if BSD >= 43 393 } 394 #endif 395 396 /* 397 * Wait for reply 398 */ 399 timeout.tv_sec = (_res.retrans << try); 400 if (try > 0) 401 timeout.tv_sec /= _res.nscount; 402 if (timeout.tv_sec <= 0) 403 timeout.tv_sec = 1; 404 timeout.tv_usec = 0; 405 wait: 406 FD_ZERO(&dsmask); 407 FD_SET(s, &dsmask); 408 n = select(s+1, &dsmask, (fd_set *)NULL, 409 (fd_set *)NULL, &timeout); 410 if (n < 0) { 411 #ifdef DEBUG 412 if (_res.options & RES_DEBUG) 413 perror("select"); 414 #endif DEBUG 415 continue; 416 } 417 if (n == 0) { 418 /* 419 * timeout 420 */ 421 #ifdef DEBUG 422 if (_res.options & RES_DEBUG) 423 printf("timeout\n"); 424 #endif DEBUG 425 #if BSD >= 43 426 gotsomewhere = 1; 427 #endif 428 continue; 429 } 430 if ((resplen = recv(s, answer, anslen, 0)) 431 <= 0) { 432 #ifdef DEBUG 433 if (_res.options & RES_DEBUG) 434 perror("recvfrom"); 435 #endif DEBUG 436 continue; 437 } 438 gotsomewhere = 1; 439 if (id != anhp->id) { 440 /* 441 * response from old query, ignore it 442 */ 443 #ifdef DEBUG 444 if (_res.options & RES_DEBUG) { 445 printf("old answer:\n"); 446 p_query(answer); 447 } 448 #endif DEBUG 449 goto wait; 450 } 451 if (!(_res.options & RES_IGNTC) && anhp->tc) { 452 /* 453 * get rest of answer; 454 * use TCP with same server. 455 */ 456 #ifdef DEBUG 457 if (_res.options & RES_DEBUG) 458 printf("truncated answer\n"); 459 #endif DEBUG 460 (void) close(s); 461 s = -1; 462 v_circuit = 1; 463 goto usevc; 464 } 465 } 466 #ifdef DEBUG 467 if (_res.options & RES_DEBUG) { 468 printf("got answer:\n"); 469 p_query(answer); 470 } 471 #endif DEBUG 472 /* 473 * If using virtual circuits, we assume that the first server 474 * is preferred * over the rest (i.e. it is on the local 475 * machine) and only keep that one open. 476 * If we have temporarily opened a virtual circuit, 477 * or if we haven't been asked to keep a socket open, 478 * close the socket. 479 */ 480 if ((v_circuit && 481 ((_res.options & RES_USEVC) == 0 || ns != 0)) || 482 (_res.options & RES_STAYOPEN) == 0) { 483 (void) close(s); 484 s = -1; 485 } 486 return (resplen); 487 } 488 } 489 if (s >= 0) { 490 (void) close(s); 491 s = -1; 492 } 493 if (v_circuit == 0) 494 if (gotsomewhere == 0) 495 errno = ECONNREFUSED; /* no nameservers found */ 496 else 497 errno = ETIMEDOUT; /* no answer obtained */ 498 else 499 errno = terrno; 500 return (-1); 501 } 502 503 /* 504 * This routine is for closing the socket if a virtual circuit is used and 505 * the program wants to close it. This provides support for endhostent() 506 * which expects to close the socket. 507 * 508 * This routine is not expected to be user visible. 509 */ 510 _res_close() 511 { 512 if (s != -1) { 513 (void) close(s); 514 s = -1; 515 } 516 } 517