1 /* 2 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 /* 7 * Copyright (c) 1985, 1989, 1993 8 * The Regents of the University of California. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 * 4. Neither the name of the University nor the names of its contributors 23 * may be used to endorse or promote products derived from this software 24 * without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 * SUCH DAMAGE. 37 */ 38 39 /* 40 * Portions Copyright (c) 1993 by Digital Equipment Corporation. 41 * 42 * Permission to use, copy, modify, and distribute this software for any 43 * purpose with or without fee is hereby granted, provided that the above 44 * copyright notice and this permission notice appear in all copies, and that 45 * the name of Digital Equipment Corporation not be used in advertising or 46 * publicity pertaining to distribution of the document or software without 47 * specific, written prior permission. 48 * 49 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 50 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 51 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 52 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 53 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 54 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 55 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 56 * SOFTWARE. 57 */ 58 59 /* 60 * Portions Copyright (c) 1996-1999 by Internet Software Consortium. 61 * 62 * Permission to use, copy, modify, and distribute this software for any 63 * purpose with or without fee is hereby granted, provided that the above 64 * copyright notice and this permission notice appear in all copies. 65 * 66 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 67 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 68 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 69 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 70 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 71 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 72 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 73 * SOFTWARE. 74 */ 75 76 #pragma ident "%Z%%M% %I% %E% SMI" 77 78 #if defined(LIBC_SCCS) && !defined(lint) 79 static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; 80 static const char rcsid[] = "$Id: res_init.c,v 8.32 2003/04/03 06:31:10 marka Exp $"; 81 #endif /* LIBC_SCCS and not lint */ 82 83 #include "port_before.h" 84 85 #include <sys/types.h> 86 #include <sys/param.h> 87 #include <sys/socket.h> 88 #include <sys/time.h> 89 90 #include <netinet/in.h> 91 #include <arpa/inet.h> 92 #include <arpa/nameser.h> 93 94 #include <ctype.h> 95 #include <stdio.h> 96 #include <stdlib.h> 97 #include <string.h> 98 #include <unistd.h> 99 #include <netdb.h> 100 101 #include "port_after.h" 102 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 103 #include "../../../libnsl/include/nsl_stdio_prv.h" 104 #endif 105 106 /* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */ 107 #include <resolv.h> 108 109 #include "res_private.h" 110 111 /* Options. Should all be left alone. */ 112 #define RESOLVSORT 113 #define DEBUG 114 115 #ifdef SUNW_INITCHKIF 116 #include <net/if.h> 117 #include <netinet/if_ether.h> 118 #include <sys/sockio.h> 119 #define MAXIFS 8192 120 #endif /* SUNW_INITCHKIF */ 121 122 #ifdef SUNW_DOMAINFROMNIS 123 #include <sys/systeminfo.h> 124 #include <string.h> 125 #endif /* SUNW_DOMAINFROMNIS */ 126 127 #ifdef ORIGINAL_ISC_CODE 128 #else 129 #pragma weak __res_randomid = res_randomid 130 #endif /* ORIGINAL_ISC_CODE */ 131 132 static void res_setoptions __P((res_state, const char *, const char *)); 133 134 #ifdef RESOLVSORT 135 static const char sort_mask[] = "/&"; 136 #define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL) 137 static u_int32_t net_mask __P((struct in_addr)); 138 #endif 139 140 #if !defined(isascii) /* XXX - could be a function */ 141 # define isascii(c) (!(c & 0200)) 142 #endif 143 144 /* 145 * Resolver state default settings. 146 */ 147 148 /* 149 * Set up default settings. If the configuration file exist, the values 150 * there will have precedence. Otherwise, the server address is set to 151 * INADDR_ANY and the default domain name comes from the gethostname(). 152 * 153 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1 154 * rather than INADDR_ANY ("0.0.0.0") as the default name server address 155 * since it was noted that INADDR_ANY actually meant ``the first interface 156 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface, 157 * it had to be "up" in order for you to reach your own name server. It 158 * was later decided that since the recommended practice is to always 159 * install local static routes through 127.0.0.1 for all your network 160 * interfaces, that we could solve this problem without a code change. 161 * 162 * The configuration file should always be used, since it is the only way 163 * to specify a default domain. If you are running a server on your local 164 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1" 165 * in the configuration file. 166 * 167 * Return 0 if completes successfully, -1 on error 168 */ 169 int 170 res_ninit(res_state statp) { 171 extern int __res_vinit(res_state, int); 172 173 return (__res_vinit(statp, 0)); 174 } 175 176 /* This function has to be reachable by res_data.c but not publically. */ 177 int 178 __res_vinit(res_state statp, int preinit) { 179 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 180 register __NSL_FILE *fp; 181 #else 182 register FILE *fp; 183 #endif 184 register char *cp, **pp; 185 register int n; 186 char buf[BUFSIZ]; 187 int nserv = 0; /* number of nameserver records read from file */ 188 int haveenv = 0; 189 int havesearch = 0; 190 #ifdef RESOLVSORT 191 int nsort = 0; 192 char *net; 193 #endif 194 int dots; 195 union res_sockaddr_union u[2]; 196 197 if (!preinit) { 198 statp->retrans = RES_TIMEOUT; 199 statp->retry = RES_DFLRETRY; 200 statp->options = RES_DEFAULT; 201 statp->id = res_randomid(); 202 } 203 204 if ((statp->options & RES_INIT) != 0) 205 res_ndestroy(statp); 206 207 memset(u, 0, sizeof(u)); 208 #ifdef USELOOPBACK 209 u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); 210 #else 211 u[nserv].sin.sin_addr.s_addr = INADDR_ANY; 212 #endif 213 u[nserv].sin.sin_family = AF_INET; 214 u[nserv].sin.sin_port = htons(NAMESERVER_PORT); 215 #ifdef HAVE_SA_LEN 216 u[nserv].sin.sin_len = sizeof(struct sockaddr_in); 217 #endif 218 nserv++; 219 #ifdef HAS_INET6_STRUCTS 220 #ifdef USELOOPBACK 221 u[nserv].sin6.sin6_addr = in6addr_loopback; 222 #else 223 u[nserv].sin6.sin6_addr = in6addr_any; 224 #endif 225 u[nserv].sin6.sin6_family = AF_INET6; 226 u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT); 227 #ifdef HAVE_SA_LEN 228 u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6); 229 #endif 230 nserv++; 231 #endif 232 statp->nscount = 0; 233 statp->ndots = 1; 234 statp->pfcode = 0; 235 statp->_vcsock = -1; 236 statp->_flags = 0; 237 statp->qhook = NULL; 238 statp->rhook = NULL; 239 statp->_u._ext.nscount = 0; 240 statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext)); 241 if (statp->_u._ext.ext != NULL) { 242 memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext)); 243 statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr; 244 strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa"); 245 strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int"); 246 } 247 #ifdef RESOLVSORT 248 statp->nsort = 0; 249 #endif 250 res_setservers(statp, u, nserv); 251 252 #ifdef SUNW_INITCHKIF 253 /* 254 * Short circuit res_init() if no non-loopback interfaces are up. This is 255 * done to avoid boot delays if "dns" comes before "files" in nsswitch.conf. 256 * An additional fix has been added to this code, to count all external 257 * interfaces, which includes the IPv6 interfaces. If no external interfaces 258 * are found, an additional check is carried out to determine if any deprecated 259 * interfaces are up. 260 */ 261 { 262 int s; 263 struct lifnum lifn; 264 265 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 266 perror("res_init: socket"); 267 return (-1); 268 } 269 lifn.lifn_family = AF_UNSPEC; 270 lifn.lifn_flags = LIFC_EXTERNAL_SOURCE; 271 if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) { 272 close(s); 273 return (-1); 274 } 275 if (lifn.lifn_count == 0) { 276 /* 277 * Check if there are any deprecated interfaces up 278 */ 279 struct lifconf lifc; 280 uchar_t *buf; 281 int buflen, i, int_up = 0; 282 283 lifn.lifn_flags = 0; 284 if ((ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) || 285 (lifn.lifn_count < 1)) { 286 close(s); 287 return (-1); 288 } 289 290 buflen = lifn.lifn_count * sizeof (struct lifreq); 291 buf = (uchar_t *)malloc(buflen); 292 if (buf == NULL) { 293 close(s); 294 return (-1); 295 } 296 297 lifc.lifc_family = AF_UNSPEC; 298 lifc.lifc_flags = 0; 299 lifc.lifc_len = buflen; 300 lifc.lifc_lifcu.lifcu_buf = (caddr_t)buf; 301 if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) { 302 close(s); 303 free(buf); 304 return (-1); 305 } 306 307 for (i = 0; i < lifn.lifn_count; ++i) { 308 struct lifreq *lreqp, lreq; 309 310 lreqp = (struct lifreq *)&lifc.lifc_req[i]; 311 strlcpy(lreq.lifr_name, lreqp->lifr_name, 312 sizeof (lreq.lifr_name)); 313 if (ioctl(s, SIOCGLIFFLAGS, &lreq) < 0) { 314 close(s); 315 free(buf); 316 return (-1); 317 } 318 if ((lreq.lifr_flags & IFF_UP) && 319 !(lreq.lifr_flags & IFF_NOLOCAL) && 320 !(lreq.lifr_flags & IFF_NOXMIT) && 321 !(lreq.lifr_flags & IFF_LOOPBACK)) { 322 int_up = 1; 323 break; 324 } 325 } 326 free(buf); 327 328 if (!int_up) { 329 close(s); 330 return (-1); 331 } 332 } 333 close(s); 334 } 335 #endif /* SUNW_INITCHKIF */ 336 337 #ifdef SUNW_DOMAINFROMNIS 338 /* 339 * The old (4.8.3) libresolv derived the default domainname from NIS/NIS+. 340 */ 341 { 342 char buf[sizeof(statp->defdname)], *cp; 343 int ret; 344 if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 && 345 ret <= sizeof(buf)) { 346 if (buf[0] == '+') 347 buf[0] = '.'; 348 cp = strchr(buf, '.'); 349 if (cp == 0) 350 strcpy(statp->defdname, buf); 351 else 352 strcpy(statp->defdname, cp+1); 353 } 354 } 355 #endif /* SUNW_DOMAINFROMNIS */ 356 357 /* Allow user to override the local domain definition */ 358 if ((cp = getenv("LOCALDOMAIN")) != NULL) { 359 (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); 360 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 361 haveenv++; 362 363 /* 364 * Set search list to be blank-separated strings 365 * from rest of env value. Permits users of LOCALDOMAIN 366 * to still have a search list, and anyone to set the 367 * one that they want to use as an individual (even more 368 * important now that the rfc1535 stuff restricts searches) 369 */ 370 cp = statp->defdname; 371 pp = statp->dnsrch; 372 *pp++ = cp; 373 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { 374 if (*cp == '\n') /* silly backwards compat */ 375 break; 376 else if (*cp == ' ' || *cp == '\t') { 377 *cp = 0; 378 n = 1; 379 } else if (n) { 380 *pp++ = cp; 381 n = 0; 382 havesearch = 1; 383 } 384 } 385 /* null terminate last domain if there are excess */ 386 while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') 387 cp++; 388 *cp = '\0'; 389 *pp++ = 0; 390 } 391 392 #define MATCH(line, name) \ 393 (!strncmp(line, name, sizeof(name) - 1) && \ 394 (line[sizeof(name) - 1] == ' ' || \ 395 line[sizeof(name) - 1] == '\t')) 396 397 nserv = 0; 398 399 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 400 if ((fp = __nsl_fopen(_PATH_RESCONF, "r")) != NULL) { 401 /* read the config file */ 402 while (__nsl_fgets(buf, sizeof(buf), fp) != NULL) { 403 #else 404 if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 405 /* read the config file */ 406 while (fgets(buf, sizeof(buf), fp) != NULL) { 407 #endif 408 /* skip comments */ 409 if (*buf == ';' || *buf == '#') 410 continue; 411 /* read default domain name */ 412 if (MATCH(buf, "domain")) { 413 if (haveenv) /* skip if have from environ */ 414 continue; 415 cp = buf + sizeof("domain") - 1; 416 while (*cp == ' ' || *cp == '\t') 417 cp++; 418 if ((*cp == '\0') || (*cp == '\n')) 419 continue; 420 strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); 421 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 422 if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) 423 *cp = '\0'; 424 havesearch = 0; 425 continue; 426 } 427 /* set search list */ 428 if (MATCH(buf, "search")) { 429 if (haveenv) /* skip if have from environ */ 430 continue; 431 cp = buf + sizeof("search") - 1; 432 while (*cp == ' ' || *cp == '\t') 433 cp++; 434 if ((*cp == '\0') || (*cp == '\n')) 435 continue; 436 strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); 437 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 438 if ((cp = strchr(statp->defdname, '\n')) != NULL) 439 *cp = '\0'; 440 /* 441 * Set search list to be blank-separated strings 442 * on rest of line. 443 */ 444 cp = statp->defdname; 445 pp = statp->dnsrch; 446 *pp++ = cp; 447 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { 448 if (*cp == ' ' || *cp == '\t') { 449 *cp = 0; 450 n = 1; 451 } else if (n) { 452 *pp++ = cp; 453 n = 0; 454 } 455 } 456 /* null terminate last domain if there are excess */ 457 while (*cp != '\0' && *cp != ' ' && *cp != '\t') 458 cp++; 459 *cp = '\0'; 460 *pp++ = 0; 461 havesearch = 1; 462 continue; 463 } 464 /* read nameservers to query */ 465 if (MATCH(buf, "nameserver") && nserv < MAXNS) { 466 struct addrinfo hints, *ai; 467 char sbuf[NI_MAXSERV]; 468 const size_t minsiz = 469 sizeof(statp->_u._ext.ext->nsaddrs[0]); 470 471 cp = buf + sizeof("nameserver") - 1; 472 while (*cp == ' ' || *cp == '\t') 473 cp++; 474 cp[strcspn(cp, ";# \t\n")] = '\0'; 475 if ((*cp != '\0') && (*cp != '\n')) { 476 memset(&hints, 0, sizeof(hints)); 477 hints.ai_family = PF_UNSPEC; 478 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 479 hints.ai_flags = AI_NUMERICHOST; 480 sprintf(sbuf, "%u", NAMESERVER_PORT); 481 if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && 482 ai->ai_addrlen <= minsiz) { 483 if (statp->_u._ext.ext != NULL) { 484 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], 485 ai->ai_addr, ai->ai_addrlen); 486 } 487 if (ai->ai_addrlen <= 488 sizeof(statp->nsaddr_list[nserv])) { 489 memcpy(&statp->nsaddr_list[nserv], 490 ai->ai_addr, ai->ai_addrlen); 491 } else 492 statp->nsaddr_list[nserv].sin_family = 0; 493 freeaddrinfo(ai); 494 nserv++; 495 } 496 } 497 continue; 498 } 499 #ifdef RESOLVSORT 500 if (MATCH(buf, "sortlist")) { 501 struct in_addr a; 502 503 cp = buf + sizeof("sortlist") - 1; 504 while (nsort < MAXRESOLVSORT) { 505 while (*cp == ' ' || *cp == '\t') 506 cp++; 507 if (*cp == '\0' || *cp == '\n' || *cp == ';') 508 break; 509 net = cp; 510 while (*cp && !ISSORTMASK(*cp) && *cp != ';' && 511 isascii(*cp) && !isspace((unsigned char)*cp)) 512 cp++; 513 n = *cp; 514 *cp = 0; 515 if (inet_aton(net, &a)) { 516 statp->sort_list[nsort].addr = a; 517 if (ISSORTMASK(n)) { 518 *cp++ = n; 519 net = cp; 520 while (*cp && *cp != ';' && 521 isascii(*cp) && 522 !isspace((unsigned char)*cp)) 523 cp++; 524 n = *cp; 525 *cp = 0; 526 if (inet_aton(net, &a)) { 527 statp->sort_list[nsort].mask = a.s_addr; 528 } else { 529 statp->sort_list[nsort].mask = 530 net_mask(statp->sort_list[nsort].addr); 531 } 532 } else { 533 statp->sort_list[nsort].mask = 534 net_mask(statp->sort_list[nsort].addr); 535 } 536 nsort++; 537 } 538 *cp = n; 539 } 540 continue; 541 } 542 #endif 543 if (MATCH(buf, "options")) { 544 res_setoptions(statp, buf + sizeof("options") - 1, "conf"); 545 continue; 546 } 547 } 548 if (nserv > 0) 549 statp->nscount = nserv; 550 #ifdef RESOLVSORT 551 statp->nsort = nsort; 552 #endif 553 554 #ifdef SUNW_AVOIDSTDIO_FDLIMIT 555 (void) __nsl_fclose(fp); 556 #else 557 (void) fclose(fp); 558 #endif 559 } 560 /* 561 * Last chance to get a nameserver. This should not normally 562 * be necessary 563 */ 564 #ifdef NO_RESOLV_CONF 565 if(nserv == 0) 566 nserv = get_nameservers(statp); 567 #endif 568 569 if (statp->defdname[0] == 0 && 570 gethostname(buf, sizeof(statp->defdname) - 1) == 0 && 571 (cp = strchr(buf, '.')) != NULL) 572 strcpy(statp->defdname, cp + 1); 573 574 /* find components of local domain that might be searched */ 575 if (havesearch == 0) { 576 pp = statp->dnsrch; 577 *pp++ = statp->defdname; 578 *pp = NULL; 579 580 dots = 0; 581 for (cp = statp->defdname; *cp; cp++) 582 dots += (*cp == '.'); 583 584 cp = statp->defdname; 585 while (pp < statp->dnsrch + MAXDFLSRCH) { 586 if (dots < LOCALDOMAINPARTS) 587 break; 588 cp = strchr(cp, '.') + 1; /* we know there is one */ 589 *pp++ = cp; 590 dots--; 591 } 592 *pp = NULL; 593 #ifdef DEBUG 594 if (statp->options & RES_DEBUG) { 595 printf(";; res_init()... default dnsrch list:\n"); 596 for (pp = statp->dnsrch; *pp; pp++) 597 printf(";;\t%s\n", *pp); 598 printf(";;\t..END..\n"); 599 } 600 #endif 601 } 602 603 if ((cp = getenv("RES_OPTIONS")) != NULL) 604 res_setoptions(statp, cp, "env"); 605 statp->options |= RES_INIT; 606 return (0); 607 } 608 609 static void 610 res_setoptions(res_state statp, const char *options, const char *source) 611 { 612 const char *cp = options; 613 int i; 614 struct __res_state_ext *ext = statp->_u._ext.ext; 615 616 #ifdef DEBUG 617 if (statp->options & RES_DEBUG) 618 printf(";; res_setoptions(\"%s\", \"%s\")...\n", 619 options, source); 620 #endif 621 while (*cp) { 622 /* skip leading and inner runs of spaces */ 623 while (*cp == ' ' || *cp == '\t') 624 cp++; 625 /* search for and process individual options */ 626 if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { 627 i = atoi(cp + sizeof("ndots:") - 1); 628 if (i <= RES_MAXNDOTS) 629 statp->ndots = i; 630 else 631 statp->ndots = RES_MAXNDOTS; 632 #ifdef DEBUG 633 if (statp->options & RES_DEBUG) 634 printf(";;\tndots=%d\n", statp->ndots); 635 #endif 636 } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) { 637 i = atoi(cp + sizeof("timeout:") - 1); 638 if (i <= RES_MAXRETRANS) 639 statp->retrans = i; 640 else 641 statp->retrans = RES_MAXRETRANS; 642 } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){ 643 i = atoi(cp + sizeof("attempts:") - 1); 644 if (i <= RES_MAXRETRY) 645 statp->retry = i; 646 else 647 statp->retry = RES_MAXRETRY; 648 #ifdef ORIGINAL_ISC_CODE 649 #else 650 } else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) { 651 /* 652 * For backward compatibility, 'retrans' is 653 * supported as an alias for 'timeout', though 654 * without an imposed maximum. 655 */ 656 statp->retrans = atoi(cp + sizeof("retrans:") - 1); 657 } else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){ 658 /* 659 * For backward compatibility, 'retry' is 660 * supported as an alias for 'attempts', though 661 * without an imposed maximum. 662 */ 663 statp->retry = atoi(cp + sizeof("retry:") - 1); 664 #endif /* ORIGINAL_ISC_CODE */ 665 } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { 666 #ifdef DEBUG 667 if (!(statp->options & RES_DEBUG)) { 668 printf(";; res_setoptions(\"%s\", \"%s\")..\n", 669 options, source); 670 statp->options |= RES_DEBUG; 671 } 672 printf(";;\tdebug\n"); 673 #endif 674 } else if (!strncmp(cp, "no_tld_query", 675 sizeof("no_tld_query") - 1) || 676 !strncmp(cp, "no-tld-query", 677 sizeof("no-tld-query") - 1)) { 678 statp->options |= RES_NOTLDQUERY; 679 } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { 680 statp->options |= RES_USE_INET6; 681 } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) { 682 statp->options |= RES_ROTATE; 683 } else if (!strncmp(cp, "no-check-names", 684 sizeof("no-check-names") - 1)) { 685 statp->options |= RES_NOCHECKNAME; 686 } 687 #ifdef RES_USE_EDNS0 688 else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) { 689 statp->options |= RES_USE_EDNS0; 690 } 691 #endif 692 else if (!strncmp(cp, "dname", sizeof("dname") - 1)) { 693 statp->options |= RES_USE_DNAME; 694 } 695 else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) { 696 if (ext == NULL) 697 goto skip; 698 cp += sizeof("nibble:") - 1; 699 i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1); 700 strncpy(ext->nsuffix, cp, i); 701 ext->nsuffix[i] = '\0'; 702 } 703 else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) { 704 if (ext == NULL) 705 goto skip; 706 cp += sizeof("nibble2:") - 1; 707 i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1); 708 strncpy(ext->nsuffix2, cp, i); 709 ext->nsuffix2[i] = '\0'; 710 } 711 else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) { 712 cp += sizeof("v6revmode:") - 1; 713 /* "nibble" and "bitstring" used to be valid */ 714 if (!strncmp(cp, "single", sizeof("single") - 1)) { 715 statp->options |= RES_NO_NIBBLE2; 716 } else if (!strncmp(cp, "both", sizeof("both") - 1)) { 717 statp->options &= 718 ~RES_NO_NIBBLE2; 719 } 720 } 721 else { 722 /* XXX - print a warning here? */ 723 } 724 skip: 725 /* skip to next run of spaces */ 726 while (*cp && *cp != ' ' && *cp != '\t') 727 cp++; 728 } 729 } 730 731 #ifdef RESOLVSORT 732 /* XXX - should really support CIDR which means explicit masks always. */ 733 static u_int32_t 734 net_mask(in) /* XXX - should really use system's version of this */ 735 struct in_addr in; 736 { 737 register u_int32_t i = ntohl(in.s_addr); 738 739 if (IN_CLASSA(i)) 740 return (htonl(IN_CLASSA_NET)); 741 else if (IN_CLASSB(i)) 742 return (htonl(IN_CLASSB_NET)); 743 return (htonl(IN_CLASSC_NET)); 744 } 745 #endif 746 747 u_int 748 res_randomid(void) { 749 struct timeval now; 750 751 gettimeofday(&now, NULL); 752 return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); 753 } 754 755 /* 756 * This routine is for closing the socket if a virtual circuit is used and 757 * the program wants to close it. This provides support for endhostent() 758 * which expects to close the socket. 759 * 760 * This routine is not expected to be user visible. 761 */ 762 void 763 res_nclose(res_state statp) { 764 int ns; 765 766 if (statp->_vcsock >= 0) { 767 (void) close(statp->_vcsock); 768 statp->_vcsock = -1; 769 statp->_flags &= ~(RES_F_VC | RES_F_CONN); 770 } 771 for (ns = 0; ns < statp->_u._ext.nscount; ns++) { 772 if (statp->_u._ext.nssocks[ns] != -1) { 773 (void) close(statp->_u._ext.nssocks[ns]); 774 statp->_u._ext.nssocks[ns] = -1; 775 } 776 } 777 } 778 779 void 780 res_ndestroy(res_state statp) { 781 res_nclose(statp); 782 if (statp->_u._ext.ext != NULL) 783 free(statp->_u._ext.ext); 784 statp->options &= ~RES_INIT; 785 statp->_u._ext.ext = NULL; 786 } 787 788 const char * 789 res_get_nibblesuffix(res_state statp) { 790 if (statp->_u._ext.ext) 791 return (statp->_u._ext.ext->nsuffix); 792 return ("ip6.arpa"); 793 } 794 795 const char * 796 res_get_nibblesuffix2(res_state statp) { 797 if (statp->_u._ext.ext) 798 return (statp->_u._ext.ext->nsuffix2); 799 return ("ip6.int"); 800 } 801 802 void 803 res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) { 804 int i, nserv; 805 size_t size; 806 807 /* close open servers */ 808 res_nclose(statp); 809 810 /* cause rtt times to be forgotten */ 811 statp->_u._ext.nscount = 0; 812 813 nserv = 0; 814 for (i = 0; i < cnt && nserv < MAXNS; i++) { 815 switch (set->sin.sin_family) { 816 case AF_INET: 817 size = sizeof(set->sin); 818 if (statp->_u._ext.ext) 819 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], 820 &set->sin, size); 821 if (size <= sizeof(statp->nsaddr_list[nserv])) 822 memcpy(&statp->nsaddr_list[nserv], 823 &set->sin, size); 824 else 825 statp->nsaddr_list[nserv].sin_family = 0; 826 nserv++; 827 break; 828 829 #ifdef HAS_INET6_STRUCTS 830 case AF_INET6: 831 size = sizeof(set->sin6); 832 if (statp->_u._ext.ext) 833 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], 834 &set->sin6, size); 835 if (size <= sizeof(statp->nsaddr_list[nserv])) 836 memcpy(&statp->nsaddr_list[nserv], 837 &set->sin6, size); 838 else 839 statp->nsaddr_list[nserv].sin_family = 0; 840 nserv++; 841 break; 842 #endif 843 844 default: 845 break; 846 } 847 set++; 848 } 849 statp->nscount = nserv; 850 851 } 852 853 int 854 res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) { 855 int i; 856 size_t size; 857 u_int16_t family; 858 859 for (i = 0; i < statp->nscount && i < cnt; i++) { 860 if (statp->_u._ext.ext) 861 family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family; 862 else 863 family = statp->nsaddr_list[i].sin_family; 864 865 switch (family) { 866 case AF_INET: 867 size = sizeof(set->sin); 868 if (statp->_u._ext.ext) 869 memcpy(&set->sin, 870 &statp->_u._ext.ext->nsaddrs[i], 871 size); 872 else 873 memcpy(&set->sin, &statp->nsaddr_list[i], 874 size); 875 break; 876 877 #ifdef HAS_INET6_STRUCTS 878 case AF_INET6: 879 size = sizeof(set->sin6); 880 if (statp->_u._ext.ext) 881 memcpy(&set->sin6, 882 &statp->_u._ext.ext->nsaddrs[i], 883 size); 884 else 885 memcpy(&set->sin6, &statp->nsaddr_list[i], 886 size); 887 break; 888 #endif 889 890 default: 891 set->sin.sin_family = 0; 892 break; 893 } 894 set++; 895 } 896 return (statp->nscount); 897 } 898