1 /* 2 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 3 * Use is subject to license terms. 4 */ 5 6 7 /* 8 * Copyright (c) 1985, 1989, 1993 9 * The Regents of the University of California. All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 */ 39 40 /* 41 * Portions Copyright (c) 1993 by Digital Equipment Corporation. 42 * 43 * Permission to use, copy, modify, and distribute this software for any 44 * purpose with or without fee is hereby granted, provided that the above 45 * copyright notice and this permission notice appear in all copies, and that 46 * the name of Digital Equipment Corporation not be used in advertising or 47 * publicity pertaining to distribution of the document or software without 48 * specific, written prior permission. 49 * 50 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 51 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 52 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 53 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 54 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 55 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 56 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 57 * SOFTWARE. 58 */ 59 60 /* 61 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 62 * Portions Copyright (c) 1996-1999 by Internet Software Consortium. 63 * 64 * Permission to use, copy, modify, and distribute this software for any 65 * purpose with or without fee is hereby granted, provided that the above 66 * copyright notice and this permission notice appear in all copies. 67 * 68 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 69 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 70 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 71 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 72 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 73 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 74 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 75 */ 76 77 #if defined(LIBC_SCCS) && !defined(lint) 78 static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; 79 static const char rcsid[] = "$Id: res_init.c,v 1.26 2008/12/11 09:59:00 marka Exp $"; 80 #endif /* LIBC_SCCS and not lint */ 81 82 #include "port_before.h" 83 84 #include <sys/types.h> 85 #include <sys/param.h> 86 #include <sys/socket.h> 87 #include <sys/time.h> 88 89 #include <netinet/in.h> 90 #include <arpa/inet.h> 91 #include <arpa/nameser.h> 92 93 #include <ctype.h> 94 #include <stdio.h> 95 #include <stdlib.h> 96 #include <string.h> 97 #include <unistd.h> 98 #include <netdb.h> 99 100 #ifndef HAVE_MD5 101 # include "../dst/md5.h" 102 #else 103 # ifdef SOLARIS2 104 # include <sys/md5.h> 105 # endif 106 #endif 107 #ifndef _MD5_H_ 108 # define _MD5_H_ 1 /*%< make sure we do not include rsaref md5.h file */ 109 #endif 110 111 112 #include "port_after.h" 113 114 /* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */ 115 #include <resolv.h> 116 117 /* ISC purposely put port_after.h before <resolv.h> to force in6 stuff 118 * (above) so we explicitly include port_resolv.h here */ 119 #include "port_resolv.h" 120 121 #include "res_private.h" 122 123 /*% Options. Should all be left alone. */ 124 #define RESOLVSORT 125 #define DEBUG 126 127 #ifdef SUNW_INITCHKIF 128 #include <net/if.h> 129 #include <netinet/if_ether.h> 130 #include <sys/sockio.h> 131 #define MAXIFS 8192 132 #endif /* SUNW_INITCHKIF */ 133 134 #ifdef SOLARIS2 135 #include <sys/systeminfo.h> 136 #endif 137 138 static void res_setoptions __P((res_state, const char *, const char *)); 139 140 #ifdef RESOLVSORT 141 static const char sort_mask[] = "/&"; 142 #define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL) 143 static u_int32_t net_mask __P((struct in_addr)); 144 #endif 145 146 #if !defined(isascii) /*%< XXX - could be a function */ 147 # define isascii(c) (!(c & 0200)) 148 #endif 149 150 /* 151 * Resolver state default settings. 152 */ 153 154 /*% 155 * Set up default settings. If the configuration file exist, the values 156 * there will have precedence. Otherwise, the server address is set to 157 * INADDR_ANY and the default domain name comes from the gethostname(). 158 * 159 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1 160 * rather than INADDR_ANY ("0.0.0.0") as the default name server address 161 * since it was noted that INADDR_ANY actually meant ``the first interface 162 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface, 163 * it had to be "up" in order for you to reach your own name server. It 164 * was later decided that since the recommended practice is to always 165 * install local static routes through 127.0.0.1 for all your network 166 * interfaces, that we could solve this problem without a code change. 167 * 168 * The configuration file should always be used, since it is the only way 169 * to specify a default domain. If you are running a server on your local 170 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1" 171 * in the configuration file. 172 * 173 * Return 0 if completes successfully, -1 on error 174 */ 175 int 176 res_ninit(res_state statp) { 177 extern int __res_vinit(res_state, int); 178 return (__res_vinit(statp, 0)); 179 } 180 181 /*% This function has to be reachable by res_data.c but not publically. */ 182 int 183 __res_vinit(res_state statp, int preinit) { 184 register FILE *fp; 185 register char *cp, **pp; 186 register int n; 187 char buf[BUFSIZ]; 188 int nserv = 0; /*%< number of nameserver records read from file */ 189 int haveenv = 0; 190 int havesearch = 0; 191 #ifdef RESOLVSORT 192 int nsort = 0; 193 char *net; 194 #endif 195 int dots; 196 union res_sockaddr_union u[2]; 197 int maxns = MAXNS; 198 199 RES_SET_H_ERRNO(statp, 0); 200 if (statp->_u._ext.ext != NULL) 201 res_ndestroy(statp); 202 203 if (!preinit) { 204 statp->retrans = RES_TIMEOUT; 205 statp->retry = RES_DFLRETRY; 206 statp->options = RES_DEFAULT; 207 res_rndinit(statp); 208 statp->id = res_nrandomid(statp); 209 } 210 211 memset(u, 0, sizeof(u)); 212 #ifdef USELOOPBACK 213 u[nserv].sin.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); 214 #else 215 u[nserv].sin.sin_addr.s_addr = INADDR_ANY; 216 #endif 217 u[nserv].sin.sin_family = AF_INET; 218 u[nserv].sin.sin_port = htons(NAMESERVER_PORT); 219 #ifdef HAVE_SA_LEN 220 u[nserv].sin.sin_len = sizeof(struct sockaddr_in); 221 #endif 222 nserv++; 223 #ifdef HAS_INET6_STRUCTS 224 #ifdef USELOOPBACK 225 u[nserv].sin6.sin6_addr = in6addr_loopback; 226 #else 227 u[nserv].sin6.sin6_addr = in6addr_any; 228 #endif 229 u[nserv].sin6.sin6_family = AF_INET6; 230 u[nserv].sin6.sin6_port = htons(NAMESERVER_PORT); 231 #ifdef HAVE_SA_LEN 232 u[nserv].sin6.sin6_len = sizeof(struct sockaddr_in6); 233 #endif 234 nserv++; 235 #endif 236 statp->nscount = 0; 237 statp->ndots = 1; 238 statp->pfcode = 0; 239 statp->_vcsock = -1; 240 statp->_flags = 0; 241 statp->qhook = NULL; 242 statp->rhook = NULL; 243 statp->_u._ext.nscount = 0; 244 statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext)); 245 if (statp->_u._ext.ext != NULL) { 246 memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext)); 247 statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr; 248 strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa"); 249 strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int"); 250 } else { 251 /* 252 * Historically res_init() rarely, if at all, failed. 253 * Examples and applications exist which do not check 254 * our return code. Furthermore several applications 255 * simply call us to get the systems domainname. So 256 * rather then immediately fail here we store the 257 * failure, which is returned later, in h_errno. And 258 * prevent the collection of 'nameserver' information 259 * by setting maxns to 0. Thus applications that fail 260 * to check our return code wont be able to make 261 * queries anyhow. 262 */ 263 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 264 maxns = 0; 265 } 266 #ifdef RESOLVSORT 267 statp->nsort = 0; 268 #endif 269 res_setservers(statp, u, nserv); 270 271 #ifdef SUNW_INITCHKIF 272 /* 273 * Short circuit res_init() if no non-loopback interfaces are up. This is 274 * done to avoid boot delays if "dns" comes before "files" in nsswitch.conf. 275 * An additional fix has been added to this code, to count all external 276 * interfaces, which includes the IPv6 interfaces. If no external interfaces 277 * are found, an additional check is carried out to determine if any deprecated 278 * interfaces are up. 279 */ 280 { 281 int s; 282 struct lifnum lifn; 283 284 if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 285 perror("res_init: socket"); 286 goto freedata; 287 } 288 lifn.lifn_family = AF_UNSPEC; 289 lifn.lifn_flags = LIFC_EXTERNAL_SOURCE; 290 if (ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) { 291 close(s); 292 goto freedata; 293 } 294 if (lifn.lifn_count == 0) { 295 /* 296 * Check if there are any deprecated interfaces up 297 */ 298 struct lifconf lifc; 299 uchar_t *buf; 300 int buflen, i, int_up = 0; 301 302 lifn.lifn_flags = 0; 303 if ((ioctl(s, SIOCGLIFNUM, (char *)&lifn) < 0) || 304 (lifn.lifn_count < 1)) { 305 close(s); 306 goto freedata; 307 } 308 309 buflen = lifn.lifn_count * sizeof (struct lifreq); 310 buf = (uchar_t *)malloc(buflen); 311 if (buf == NULL) { 312 close(s); 313 goto freedata; 314 } 315 316 lifc.lifc_family = AF_UNSPEC; 317 lifc.lifc_flags = 0; 318 lifc.lifc_len = buflen; 319 lifc.lifc_lifcu.lifcu_buf = (caddr_t)buf; 320 if (ioctl(s, SIOCGLIFCONF, (char *)&lifc) < 0) { 321 close(s); 322 free(buf); 323 goto freedata; 324 } 325 326 for (i = 0; i < lifn.lifn_count; ++i) { 327 struct lifreq *lreqp, lreq; 328 329 lreqp = (struct lifreq *)&lifc.lifc_req[i]; 330 strlcpy(lreq.lifr_name, lreqp->lifr_name, 331 sizeof (lreq.lifr_name)); 332 if (ioctl(s, SIOCGLIFFLAGS, &lreq) < 0) { 333 close(s); 334 free(buf); 335 goto freedata; 336 } 337 if ((lreq.lifr_flags & IFF_UP) && 338 !(lreq.lifr_flags & IFF_NOLOCAL) && 339 !(lreq.lifr_flags & IFF_NOXMIT) && 340 !(lreq.lifr_flags & IFF_LOOPBACK)) { 341 int_up = 1; 342 break; 343 } 344 } 345 free(buf); 346 347 if (!int_up) { 348 close(s); 349 goto freedata; 350 } 351 } 352 close(s); 353 } 354 #endif /* SUNW_INITCHKIF */ 355 356 #ifdef SOLARIS2 357 /* 358 * The old libresolv derived the defaultdomain from NIS/NIS+. 359 * We want to keep this behaviour 360 */ 361 { 362 char buf[sizeof(statp->defdname)], *cp; 363 int ret; 364 365 if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 && 366 (unsigned int)ret <= sizeof(buf)) { 367 if (buf[0] == '+') 368 buf[0] = '.'; 369 cp = strchr(buf, '.'); 370 cp = (cp == NULL) ? buf : (cp + 1); 371 strncpy(statp->defdname, cp, 372 sizeof(statp->defdname) - 1); 373 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 374 } 375 } 376 #endif /* SOLARIS2 */ 377 378 /* Allow user to override the local domain definition */ 379 if ((cp = getenv("LOCALDOMAIN")) != NULL) { 380 (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); 381 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 382 haveenv++; 383 384 /* 385 * Set search list to be blank-separated strings 386 * from rest of env value. Permits users of LOCALDOMAIN 387 * to still have a search list, and anyone to set the 388 * one that they want to use as an individual (even more 389 * important now that the rfc1535 stuff restricts searches) 390 */ 391 cp = statp->defdname; 392 pp = statp->dnsrch; 393 *pp++ = cp; 394 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { 395 if (*cp == '\n') /*%< silly backwards compat */ 396 break; 397 else if (*cp == ' ' || *cp == '\t') { 398 *cp = 0; 399 n = 1; 400 } else if (n) { 401 *pp++ = cp; 402 n = 0; 403 havesearch = 1; 404 } 405 } 406 /* null terminate last domain if there are excess */ 407 while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') 408 cp++; 409 *cp = '\0'; 410 *pp++ = 0; 411 } 412 413 #define MATCH(line, name) \ 414 (!strncmp(line, name, sizeof(name) - 1) && \ 415 (line[sizeof(name) - 1] == ' ' || \ 416 line[sizeof(name) - 1] == '\t')) 417 418 nserv = 0; 419 if ((fp = fopen(_PATH_RESCONF, "r")) != NULL) { 420 /* read the config file */ 421 while (fgets(buf, sizeof(buf), fp) != NULL) { 422 /* skip comments */ 423 if (*buf == ';' || *buf == '#') 424 continue; 425 /* read default domain name */ 426 if (MATCH(buf, "domain")) { 427 if (haveenv) /*%< skip if have from environ */ 428 continue; 429 cp = buf + sizeof("domain") - 1; 430 while (*cp == ' ' || *cp == '\t') 431 cp++; 432 if ((*cp == '\0') || (*cp == '\n')) 433 continue; 434 strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); 435 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 436 if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) 437 *cp = '\0'; 438 havesearch = 0; 439 continue; 440 } 441 /* set search list */ 442 if (MATCH(buf, "search")) { 443 if (haveenv) /*%< skip if have from environ */ 444 continue; 445 cp = buf + sizeof("search") - 1; 446 while (*cp == ' ' || *cp == '\t') 447 cp++; 448 if ((*cp == '\0') || (*cp == '\n')) 449 continue; 450 strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); 451 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 452 if ((cp = strchr(statp->defdname, '\n')) != NULL) 453 *cp = '\0'; 454 /* 455 * Set search list to be blank-separated strings 456 * on rest of line. 457 */ 458 cp = statp->defdname; 459 pp = statp->dnsrch; 460 *pp++ = cp; 461 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { 462 if (*cp == ' ' || *cp == '\t') { 463 *cp = 0; 464 n = 1; 465 } else if (n) { 466 *pp++ = cp; 467 n = 0; 468 } 469 } 470 /* null terminate last domain if there are excess */ 471 while (*cp != '\0' && *cp != ' ' && *cp != '\t') 472 cp++; 473 *cp = '\0'; 474 *pp++ = 0; 475 havesearch = 1; 476 continue; 477 } 478 /* read nameservers to query */ 479 if (MATCH(buf, "nameserver") && nserv < maxns) { 480 struct addrinfo hints, *ai; 481 char sbuf[NI_MAXSERV]; 482 const size_t minsiz = 483 sizeof(statp->_u._ext.ext->nsaddrs[0]); 484 485 cp = buf + sizeof("nameserver") - 1; 486 while (*cp == ' ' || *cp == '\t') 487 cp++; 488 cp[strcspn(cp, ";# \t\n")] = '\0'; 489 if ((*cp != '\0') && (*cp != '\n')) { 490 memset(&hints, 0, sizeof(hints)); 491 hints.ai_family = PF_UNSPEC; 492 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 493 hints.ai_flags = AI_NUMERICHOST; 494 sprintf(sbuf, "%u", NAMESERVER_PORT); 495 if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && 496 ai->ai_addrlen <= minsiz) { 497 if (statp->_u._ext.ext != NULL) { 498 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], 499 ai->ai_addr, ai->ai_addrlen); 500 } 501 if (ai->ai_addrlen <= 502 sizeof(statp->nsaddr_list[nserv])) { 503 memcpy(&statp->nsaddr_list[nserv], 504 ai->ai_addr, ai->ai_addrlen); 505 } else 506 statp->nsaddr_list[nserv].sin_family = 0; 507 freeaddrinfo(ai); 508 nserv++; 509 } 510 } 511 continue; 512 } 513 #ifdef RESOLVSORT 514 if (MATCH(buf, "sortlist")) { 515 struct in_addr a; 516 517 cp = buf + sizeof("sortlist") - 1; 518 while (nsort < MAXRESOLVSORT) { 519 while (*cp == ' ' || *cp == '\t') 520 cp++; 521 if (*cp == '\0' || *cp == '\n' || *cp == ';') 522 break; 523 net = cp; 524 while (*cp && !ISSORTMASK(*cp) && *cp != ';' && 525 isascii(*cp) && !isspace((unsigned char)*cp)) 526 cp++; 527 n = *cp; 528 *cp = 0; 529 if (inet_aton(net, &a)) { 530 statp->sort_list[nsort].addr = a; 531 if (ISSORTMASK(n)) { 532 *cp++ = n; 533 net = cp; 534 while (*cp && *cp != ';' && 535 isascii(*cp) && 536 !isspace((unsigned char)*cp)) 537 cp++; 538 n = *cp; 539 *cp = 0; 540 if (inet_aton(net, &a)) { 541 statp->sort_list[nsort].mask = a.s_addr; 542 } else { 543 statp->sort_list[nsort].mask = 544 net_mask(statp->sort_list[nsort].addr); 545 } 546 } else { 547 statp->sort_list[nsort].mask = 548 net_mask(statp->sort_list[nsort].addr); 549 } 550 nsort++; 551 } 552 *cp = n; 553 } 554 continue; 555 } 556 #endif 557 if (MATCH(buf, "options")) { 558 res_setoptions(statp, buf + sizeof("options") - 1, "conf"); 559 continue; 560 } 561 } 562 if (nserv > 0) 563 statp->nscount = nserv; 564 #ifdef RESOLVSORT 565 statp->nsort = nsort; 566 #endif 567 (void) fclose(fp); 568 } 569 /* 570 * Last chance to get a nameserver. This should not normally 571 * be necessary 572 */ 573 #ifdef NO_RESOLV_CONF 574 if(nserv == 0) 575 nserv = get_nameservers(statp); 576 #endif 577 578 if (statp->defdname[0] == 0 && 579 gethostname(buf, sizeof(statp->defdname) - 1) == 0 && 580 (cp = strchr(buf, '.')) != NULL) 581 strcpy(statp->defdname, cp + 1); 582 583 /* find components of local domain that might be searched */ 584 if (havesearch == 0) { 585 pp = statp->dnsrch; 586 *pp++ = statp->defdname; 587 *pp = NULL; 588 589 dots = 0; 590 for (cp = statp->defdname; *cp; cp++) 591 dots += (*cp == '.'); 592 593 cp = statp->defdname; 594 while (pp < statp->dnsrch + MAXDFLSRCH) { 595 if (dots < LOCALDOMAINPARTS) 596 break; 597 cp = strchr(cp, '.') + 1; /*%< we know there is one */ 598 *pp++ = cp; 599 dots--; 600 } 601 *pp = NULL; 602 #ifdef DEBUG 603 if (statp->options & RES_DEBUG) { 604 printf(";; res_init()... default dnsrch list:\n"); 605 for (pp = statp->dnsrch; *pp; pp++) 606 printf(";;\t%s\n", *pp); 607 printf(";;\t..END..\n"); 608 } 609 #endif 610 } 611 612 if ((cp = getenv("RES_OPTIONS")) != NULL) 613 res_setoptions(statp, cp, "env"); 614 statp->options |= RES_INIT; 615 return (statp->res_h_errno); 616 #ifdef SUNW_INITCHKIF 617 freedata: 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