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