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 (statp->_u._ext.ext != NULL) 198 res_ndestroy(statp); 199 200 if (!preinit) { 201 statp->retrans = RES_TIMEOUT; 202 statp->retry = RES_DFLRETRY; 203 statp->options = RES_DEFAULT; 204 statp->id = res_randomid(); 205 } 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 goto freedata; 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 goto freedata; 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 goto freedata; 288 } 289 290 buflen = lifn.lifn_count * sizeof (struct lifreq); 291 buf = (uchar_t *)malloc(buflen); 292 if (buf == NULL) { 293 close(s); 294 goto freedata; 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 goto freedata; 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 goto freedata; 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 goto freedata; 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 freedata: 608 if (statp->_u._ext.ext != NULL) { 609 free(statp->_u._ext.ext); 610 statp->_u._ext.ext = NULL; 611 } 612 return (-1); 613 } 614 615 static void 616 res_setoptions(res_state statp, const char *options, const char *source) 617 { 618 const char *cp = options; 619 int i; 620 struct __res_state_ext *ext = statp->_u._ext.ext; 621 622 #ifdef DEBUG 623 if (statp->options & RES_DEBUG) 624 printf(";; res_setoptions(\"%s\", \"%s\")...\n", 625 options, source); 626 #endif 627 while (*cp) { 628 /* skip leading and inner runs of spaces */ 629 while (*cp == ' ' || *cp == '\t') 630 cp++; 631 /* search for and process individual options */ 632 if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { 633 i = atoi(cp + sizeof("ndots:") - 1); 634 if (i <= RES_MAXNDOTS) 635 statp->ndots = i; 636 else 637 statp->ndots = RES_MAXNDOTS; 638 #ifdef DEBUG 639 if (statp->options & RES_DEBUG) 640 printf(";;\tndots=%d\n", statp->ndots); 641 #endif 642 } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) { 643 i = atoi(cp + sizeof("timeout:") - 1); 644 if (i <= RES_MAXRETRANS) 645 statp->retrans = i; 646 else 647 statp->retrans = RES_MAXRETRANS; 648 } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){ 649 i = atoi(cp + sizeof("attempts:") - 1); 650 if (i <= RES_MAXRETRY) 651 statp->retry = i; 652 else 653 statp->retry = RES_MAXRETRY; 654 #ifdef ORIGINAL_ISC_CODE 655 #else 656 } else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) { 657 /* 658 * For backward compatibility, 'retrans' is 659 * supported as an alias for 'timeout', though 660 * without an imposed maximum. 661 */ 662 statp->retrans = atoi(cp + sizeof("retrans:") - 1); 663 } else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){ 664 /* 665 * For backward compatibility, 'retry' is 666 * supported as an alias for 'attempts', though 667 * without an imposed maximum. 668 */ 669 statp->retry = atoi(cp + sizeof("retry:") - 1); 670 #endif /* ORIGINAL_ISC_CODE */ 671 } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { 672 #ifdef DEBUG 673 if (!(statp->options & RES_DEBUG)) { 674 printf(";; res_setoptions(\"%s\", \"%s\")..\n", 675 options, source); 676 statp->options |= RES_DEBUG; 677 } 678 printf(";;\tdebug\n"); 679 #endif 680 } else if (!strncmp(cp, "no_tld_query", 681 sizeof("no_tld_query") - 1) || 682 !strncmp(cp, "no-tld-query", 683 sizeof("no-tld-query") - 1)) { 684 statp->options |= RES_NOTLDQUERY; 685 } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { 686 statp->options |= RES_USE_INET6; 687 } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) { 688 statp->options |= RES_ROTATE; 689 } else if (!strncmp(cp, "no-check-names", 690 sizeof("no-check-names") - 1)) { 691 statp->options |= RES_NOCHECKNAME; 692 } 693 #ifdef RES_USE_EDNS0 694 else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) { 695 statp->options |= RES_USE_EDNS0; 696 } 697 #endif 698 else if (!strncmp(cp, "dname", sizeof("dname") - 1)) { 699 statp->options |= RES_USE_DNAME; 700 } 701 else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) { 702 if (ext == NULL) 703 goto skip; 704 cp += sizeof("nibble:") - 1; 705 i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1); 706 strncpy(ext->nsuffix, cp, i); 707 ext->nsuffix[i] = '\0'; 708 } 709 else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) { 710 if (ext == NULL) 711 goto skip; 712 cp += sizeof("nibble2:") - 1; 713 i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1); 714 strncpy(ext->nsuffix2, cp, i); 715 ext->nsuffix2[i] = '\0'; 716 } 717 else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) { 718 cp += sizeof("v6revmode:") - 1; 719 /* "nibble" and "bitstring" used to be valid */ 720 if (!strncmp(cp, "single", sizeof("single") - 1)) { 721 statp->options |= RES_NO_NIBBLE2; 722 } else if (!strncmp(cp, "both", sizeof("both") - 1)) { 723 statp->options &= 724 ~RES_NO_NIBBLE2; 725 } 726 } 727 else { 728 /* XXX - print a warning here? */ 729 } 730 skip: 731 /* skip to next run of spaces */ 732 while (*cp && *cp != ' ' && *cp != '\t') 733 cp++; 734 } 735 } 736 737 #ifdef RESOLVSORT 738 /* XXX - should really support CIDR which means explicit masks always. */ 739 static u_int32_t 740 net_mask(in) /* XXX - should really use system's version of this */ 741 struct in_addr in; 742 { 743 register u_int32_t i = ntohl(in.s_addr); 744 745 if (IN_CLASSA(i)) 746 return (htonl(IN_CLASSA_NET)); 747 else if (IN_CLASSB(i)) 748 return (htonl(IN_CLASSB_NET)); 749 return (htonl(IN_CLASSC_NET)); 750 } 751 #endif 752 753 u_int 754 res_randomid(void) { 755 struct timeval now; 756 757 gettimeofday(&now, NULL); 758 return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); 759 } 760 761 /* 762 * This routine is for closing the socket if a virtual circuit is used and 763 * the program wants to close it. This provides support for endhostent() 764 * which expects to close the socket. 765 * 766 * This routine is not expected to be user visible. 767 */ 768 void 769 res_nclose(res_state statp) { 770 int ns; 771 772 if (statp->_vcsock >= 0) { 773 (void) close(statp->_vcsock); 774 statp->_vcsock = -1; 775 statp->_flags &= ~(RES_F_VC | RES_F_CONN); 776 } 777 for (ns = 0; ns < statp->_u._ext.nscount; ns++) { 778 if (statp->_u._ext.nssocks[ns] != -1) { 779 (void) close(statp->_u._ext.nssocks[ns]); 780 statp->_u._ext.nssocks[ns] = -1; 781 } 782 } 783 } 784 785 void 786 res_ndestroy(res_state statp) { 787 res_nclose(statp); 788 if (statp->_u._ext.ext != NULL) 789 free(statp->_u._ext.ext); 790 statp->options &= ~RES_INIT; 791 statp->_u._ext.ext = NULL; 792 } 793 794 const char * 795 res_get_nibblesuffix(res_state statp) { 796 if (statp->_u._ext.ext) 797 return (statp->_u._ext.ext->nsuffix); 798 return ("ip6.arpa"); 799 } 800 801 const char * 802 res_get_nibblesuffix2(res_state statp) { 803 if (statp->_u._ext.ext) 804 return (statp->_u._ext.ext->nsuffix2); 805 return ("ip6.int"); 806 } 807 808 void 809 res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) { 810 int i, nserv; 811 size_t size; 812 813 /* close open servers */ 814 res_nclose(statp); 815 816 /* cause rtt times to be forgotten */ 817 statp->_u._ext.nscount = 0; 818 819 nserv = 0; 820 for (i = 0; i < cnt && nserv < MAXNS; i++) { 821 switch (set->sin.sin_family) { 822 case AF_INET: 823 size = sizeof(set->sin); 824 if (statp->_u._ext.ext) 825 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], 826 &set->sin, size); 827 if (size <= sizeof(statp->nsaddr_list[nserv])) 828 memcpy(&statp->nsaddr_list[nserv], 829 &set->sin, size); 830 else 831 statp->nsaddr_list[nserv].sin_family = 0; 832 nserv++; 833 break; 834 835 #ifdef HAS_INET6_STRUCTS 836 case AF_INET6: 837 size = sizeof(set->sin6); 838 if (statp->_u._ext.ext) 839 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], 840 &set->sin6, size); 841 if (size <= sizeof(statp->nsaddr_list[nserv])) 842 memcpy(&statp->nsaddr_list[nserv], 843 &set->sin6, size); 844 else 845 statp->nsaddr_list[nserv].sin_family = 0; 846 nserv++; 847 break; 848 #endif 849 850 default: 851 break; 852 } 853 set++; 854 } 855 statp->nscount = nserv; 856 857 } 858 859 int 860 res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) { 861 int i; 862 size_t size; 863 u_int16_t family; 864 865 for (i = 0; i < statp->nscount && i < cnt; i++) { 866 if (statp->_u._ext.ext) 867 family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family; 868 else 869 family = statp->nsaddr_list[i].sin_family; 870 871 switch (family) { 872 case AF_INET: 873 size = sizeof(set->sin); 874 if (statp->_u._ext.ext) 875 memcpy(&set->sin, 876 &statp->_u._ext.ext->nsaddrs[i], 877 size); 878 else 879 memcpy(&set->sin, &statp->nsaddr_list[i], 880 size); 881 break; 882 883 #ifdef HAS_INET6_STRUCTS 884 case AF_INET6: 885 size = sizeof(set->sin6); 886 if (statp->_u._ext.ext) 887 memcpy(&set->sin6, 888 &statp->_u._ext.ext->nsaddrs[i], 889 size); 890 else 891 memcpy(&set->sin6, &statp->nsaddr_list[i], 892 size); 893 break; 894 #endif 895 896 default: 897 set->sin.sin_family = 0; 898 break; 899 } 900 set++; 901 } 902 return (statp->nscount); 903 } 904