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