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