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 * the loopback address the default domain name comes from gethostname(). 122 * 123 * The configuration file should always be used, since it is the only way 124 * to specify options and a default domain. If you are running a server 125 * on your local machine, you should say "nameserver 127.0.0.1" or 126 * "nameserver ::1" in the configuration file. 127 * 128 * Return 0 if completes successfully, -1 on error 129 */ 130 int 131 res_ninit(res_state statp) { 132 extern int __res_vinit(res_state, int); 133 134 return (__res_vinit(statp, 0)); 135 } 136 137 /*% This function has to be reachable by res_data.c but not publicly. */ 138 int 139 __res_vinit(res_state statp, int preinit) { 140 union res_sockaddr_union u[] = { 141 { .sin = { 142 .sin_family = AF_INET, 143 #ifdef HAVE_SA_LEN 144 .sin_len = sizeof(struct sockaddr_in), 145 #endif 146 .sin_port = htons(NAMESERVER_PORT), 147 .sin_addr = { htonl(INADDR_LOOPBACK) }, 148 } }, 149 #ifdef HAS_INET6_STRUCTS 150 { .sin6 = { 151 .sin6_family = AF_INET6, 152 #ifdef HAVE_SA_LEN 153 .sin6_len = sizeof(struct sockaddr_in6), 154 #endif 155 .sin6_port = htons(NAMESERVER_PORT), 156 .sin6_addr = IN6ADDR_LOOPBACK_INIT, 157 } }, 158 #endif 159 }; 160 FILE *fp; 161 char *cp, **pp; 162 int n; 163 char buf[BUFSIZ]; 164 int nserv = 0; /*%< number of nameserver records read from file */ 165 int haveenv = 0; 166 int havesearch = 0; 167 #ifdef RESOLVSORT 168 int nsort = 0; 169 char *net; 170 #endif 171 int dots; 172 int maxns = MAXNS; 173 174 RES_SET_H_ERRNO(statp, 0); 175 if (statp->_u._ext.ext != NULL) 176 res_ndestroy(statp); 177 178 if (!preinit) { 179 statp->retrans = RES_TIMEOUT; 180 statp->retry = RES_DFLRETRY; 181 statp->options = RES_DEFAULT; 182 } 183 184 statp->id = res_nrandomid(statp); 185 186 statp->nscount = 0; 187 statp->ndots = 1; 188 statp->pfcode = 0; 189 statp->_vcsock = -1; 190 statp->_flags = 0; 191 statp->qhook = NULL; 192 statp->rhook = NULL; 193 statp->_u._ext.nscount = 0; 194 statp->_u._ext.ext = malloc(sizeof(*statp->_u._ext.ext)); 195 if (statp->_u._ext.ext != NULL) { 196 memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext)); 197 statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr; 198 strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa"); 199 strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int"); 200 statp->_u._ext.ext->reload_period = 2; 201 } else { 202 /* 203 * Historically res_init() rarely, if at all, failed. 204 * Examples and applications exist which do not check 205 * our return code. Furthermore several applications 206 * simply call us to get the systems domainname. So 207 * rather then immediately fail here we store the 208 * failure, which is returned later, in h_errno. And 209 * prevent the collection of 'nameserver' information 210 * by setting maxns to 0. Thus applications that fail 211 * to check our return code wont be able to make 212 * queries anyhow. 213 */ 214 RES_SET_H_ERRNO(statp, NETDB_INTERNAL); 215 maxns = 0; 216 } 217 #ifdef RESOLVSORT 218 statp->nsort = 0; 219 #endif 220 res_setservers(statp, u, nitems(u)); 221 222 #ifdef SOLARIS2 223 /* 224 * The old libresolv derived the defaultdomain from NIS/NIS+. 225 * We want to keep this behaviour 226 */ 227 { 228 char buf[sizeof(statp->defdname)], *cp; 229 int ret; 230 231 if ((ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf))) > 0 && 232 (unsigned int)ret <= sizeof(buf)) { 233 if (buf[0] == '+') 234 buf[0] = '.'; 235 cp = strchr(buf, '.'); 236 cp = (cp == NULL) ? buf : (cp + 1); 237 strncpy(statp->defdname, cp, 238 sizeof(statp->defdname) - 1); 239 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 240 } 241 } 242 #endif /* SOLARIS2 */ 243 244 /* Allow user to override the local domain definition */ 245 if ((cp = secure_getenv("LOCALDOMAIN")) != NULL) { 246 (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); 247 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 248 haveenv++; 249 250 /* 251 * Set search list to be blank-separated strings 252 * from rest of env value. Permits users of LOCALDOMAIN 253 * to still have a search list, and anyone to set the 254 * one that they want to use as an individual (even more 255 * important now that the rfc1535 stuff restricts searches) 256 */ 257 cp = statp->defdname; 258 pp = statp->dnsrch; 259 *pp++ = cp; 260 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { 261 if (*cp == '\n') /*%< silly backwards compat */ 262 break; 263 else if (*cp == ' ' || *cp == '\t') { 264 *cp = 0; 265 n = 1; 266 } else if (n) { 267 *pp++ = cp; 268 n = 0; 269 havesearch = 1; 270 } 271 } 272 /* null terminate last domain if there are excess */ 273 while (*cp != '\0' && *cp != ' ' && *cp != '\t' && *cp != '\n') 274 cp++; 275 *cp = '\0'; 276 *pp++ = NULL; 277 } 278 279 #define MATCH(line, name) \ 280 (!strncmp(line, name, sizeof(name) - 1) && \ 281 (line[sizeof(name) - 1] == ' ' || \ 282 line[sizeof(name) - 1] == '\t')) 283 284 if ((fp = fopen(_PATH_RESCONF, "re")) != NULL) { 285 struct stat sb; 286 struct timespec now; 287 288 if (statp->_u._ext.ext != NULL) { 289 if (_fstat(fileno(fp), &sb) == 0) { 290 statp->_u._ext.ext->conf_mtim = sb.st_mtim; 291 if (clock_gettime(CLOCK_MONOTONIC_FAST, &now) == 0) { 292 statp->_u._ext.ext->conf_stat = now.tv_sec; 293 } 294 } 295 } 296 297 /* read the config file */ 298 while (fgets(buf, sizeof(buf), fp) != NULL) { 299 /* skip comments */ 300 if (*buf == ';' || *buf == '#') 301 continue; 302 /* read default domain name */ 303 if (MATCH(buf, "domain")) { 304 if (haveenv) /*%< skip if have from environ */ 305 continue; 306 cp = buf + sizeof("domain") - 1; 307 while (*cp == ' ' || *cp == '\t') 308 cp++; 309 if ((*cp == '\0') || (*cp == '\n')) 310 continue; 311 strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); 312 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 313 if ((cp = strpbrk(statp->defdname, " \t\n")) != NULL) 314 *cp = '\0'; 315 havesearch = 0; 316 continue; 317 } 318 /* set search list */ 319 if (MATCH(buf, "search")) { 320 if (haveenv) /*%< skip if have from environ */ 321 continue; 322 cp = buf + sizeof("search") - 1; 323 while (*cp == ' ' || *cp == '\t') 324 cp++; 325 if ((*cp == '\0') || (*cp == '\n')) 326 continue; 327 strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); 328 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 329 if ((cp = strchr(statp->defdname, '\n')) != NULL) 330 *cp = '\0'; 331 /* 332 * Set search list to be blank-separated strings 333 * on rest of line. 334 */ 335 cp = statp->defdname; 336 pp = statp->dnsrch; 337 *pp++ = cp; 338 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) { 339 if (*cp == ' ' || *cp == '\t') { 340 *cp = 0; 341 n = 1; 342 } else if (n) { 343 *pp++ = cp; 344 n = 0; 345 } 346 } 347 /* null terminate last domain if there are excess */ 348 while (*cp != '\0' && *cp != ' ' && *cp != '\t') 349 cp++; 350 *cp = '\0'; 351 *pp++ = NULL; 352 havesearch = 1; 353 continue; 354 } 355 /* read nameservers to query */ 356 if (MATCH(buf, "nameserver") && nserv < maxns) { 357 struct addrinfo hints, *ai; 358 char sbuf[NI_MAXSERV]; 359 const size_t minsiz = 360 sizeof(statp->_u._ext.ext->nsaddrs[0]); 361 362 cp = buf + sizeof("nameserver") - 1; 363 while (*cp == ' ' || *cp == '\t') 364 cp++; 365 cp[strcspn(cp, ";# \t\n")] = '\0'; 366 if ((*cp != '\0') && (*cp != '\n')) { 367 memset(&hints, 0, sizeof(hints)); 368 hints.ai_family = PF_UNSPEC; 369 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 370 hints.ai_flags = AI_NUMERICHOST; 371 sprintf(sbuf, "%u", NAMESERVER_PORT); 372 if (getaddrinfo(cp, sbuf, &hints, &ai) == 0) { 373 if (ai->ai_addrlen <= minsiz) { 374 if (statp->_u._ext.ext != NULL) { 375 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], 376 ai->ai_addr, ai->ai_addrlen); 377 } 378 if (ai->ai_addrlen <= 379 sizeof(statp->nsaddr_list[nserv])) { 380 memcpy(&statp->nsaddr_list[nserv], 381 ai->ai_addr, ai->ai_addrlen); 382 } else 383 statp->nsaddr_list[nserv].sin_family = 0; 384 nserv++; 385 } 386 freeaddrinfo(ai); 387 } 388 } 389 continue; 390 } 391 #ifdef RESOLVSORT 392 if (MATCH(buf, "sortlist")) { 393 struct in_addr a; 394 struct in6_addr a6; 395 int m, i; 396 u_char *u; 397 struct __res_state_ext *ext = statp->_u._ext.ext; 398 399 cp = buf + sizeof("sortlist") - 1; 400 while (nsort < MAXRESOLVSORT) { 401 while (*cp == ' ' || *cp == '\t') 402 cp++; 403 if (*cp == '\0' || *cp == '\n' || *cp == ';') 404 break; 405 net = cp; 406 while (*cp && !ISSORTMASK(*cp) && *cp != ';' && 407 isascii(*cp) && !isspace((unsigned char)*cp)) 408 cp++; 409 n = *cp; 410 *cp = 0; 411 if (inet_aton(net, &a)) { 412 statp->sort_list[nsort].addr = a; 413 if (ISSORTMASK(n)) { 414 *cp++ = n; 415 net = cp; 416 while (*cp && *cp != ';' && 417 isascii(*cp) && 418 !isspace((unsigned char)*cp)) 419 cp++; 420 n = *cp; 421 *cp = 0; 422 if (inet_aton(net, &a)) { 423 statp->sort_list[nsort].mask = a.s_addr; 424 } else { 425 statp->sort_list[nsort].mask = 426 net_mask(statp->sort_list[nsort].addr); 427 } 428 } else { 429 statp->sort_list[nsort].mask = 430 net_mask(statp->sort_list[nsort].addr); 431 } 432 ext->sort_list[nsort].af = AF_INET; 433 ext->sort_list[nsort].addr.ina = 434 statp->sort_list[nsort].addr; 435 ext->sort_list[nsort].mask.ina.s_addr = 436 statp->sort_list[nsort].mask; 437 nsort++; 438 } 439 else if (inet_pton(AF_INET6, net, &a6) == 1) { 440 441 ext->sort_list[nsort].af = AF_INET6; 442 ext->sort_list[nsort].addr.in6a = a6; 443 u = (u_char *)&ext->sort_list[nsort].mask.in6a; 444 *cp++ = n; 445 net = cp; 446 while (*cp && *cp != ';' && 447 isascii(*cp) && !isspace(*cp)) 448 cp++; 449 m = n; 450 n = *cp; 451 *cp = 0; 452 switch (m) { 453 case '/': 454 m = atoi(net); 455 break; 456 case '&': 457 if (inet_pton(AF_INET6, net, u) == 1) { 458 m = -1; 459 break; 460 } 461 /*FALLTHROUGH*/ 462 default: 463 m = sizeof(struct in6_addr) * CHAR_BIT; 464 break; 465 } 466 if (m >= 0) { 467 for (i = 0; i < sizeof(struct in6_addr); i++) { 468 if (m <= 0) { 469 *u = 0; 470 } else { 471 m -= CHAR_BIT; 472 *u = (u_char)~0; 473 if (m < 0) 474 *u <<= -m; 475 } 476 u++; 477 } 478 } 479 statp->sort_list[nsort].addr.s_addr = 480 (u_int32_t)0xffffffff; 481 statp->sort_list[nsort].mask = 482 (u_int32_t)0xffffffff; 483 nsort++; 484 } 485 *cp = n; 486 } 487 continue; 488 } 489 #endif 490 if (MATCH(buf, "options")) { 491 res_setoptions(statp, buf + sizeof("options") - 1, "conf"); 492 continue; 493 } 494 } 495 if (nserv > 0) 496 statp->nscount = nserv; 497 #ifdef RESOLVSORT 498 statp->nsort = nsort; 499 #endif 500 (void) fclose(fp); 501 } 502 503 /* guess default domain if not set */ 504 if (statp->defdname[0] == 0 && 505 gethostname(buf, sizeof(statp->defdname) - 1) == 0 && 506 (cp = strchr(buf, '.')) != NULL) 507 strcpy(statp->defdname, cp + 1); 508 509 /* find components of local domain that might be searched */ 510 if (havesearch == 0) { 511 pp = statp->dnsrch; 512 *pp++ = statp->defdname; 513 *pp = NULL; 514 515 dots = 0; 516 for (cp = statp->defdname; *cp; cp++) 517 dots += (*cp == '.'); 518 519 cp = statp->defdname; 520 while (pp < statp->dnsrch + MAXDFLSRCH) { 521 if (dots < LOCALDOMAINPARTS) 522 break; 523 cp = strchr(cp, '.') + 1; /*%< we know there is one */ 524 *pp++ = cp; 525 dots--; 526 } 527 *pp = NULL; 528 #ifdef DEBUG 529 if (statp->options & RES_DEBUG) { 530 printf(";; res_init()... default dnsrch list:\n"); 531 for (pp = statp->dnsrch; *pp; pp++) 532 printf(";;\t%s\n", *pp); 533 printf(";;\t..END..\n"); 534 } 535 #endif 536 } 537 538 if (issetugid()) 539 statp->options |= RES_NOALIASES; 540 else if ((cp = getenv("RES_OPTIONS")) != NULL) 541 res_setoptions(statp, cp, "env"); 542 statp->options |= RES_INIT; 543 return (statp->res_h_errno); 544 } 545 546 static void 547 res_setoptions(res_state statp, const char *options, const char *source) 548 { 549 const char *cp = options; 550 int i; 551 struct __res_state_ext *ext = statp->_u._ext.ext; 552 553 #ifdef DEBUG 554 if (statp->options & RES_DEBUG) 555 printf(";; res_setoptions(\"%s\", \"%s\")...\n", 556 options, source); 557 #endif 558 while (*cp) { 559 /* skip leading and inner runs of spaces */ 560 while (*cp == ' ' || *cp == '\t') 561 cp++; 562 /* search for and process individual options */ 563 if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { 564 i = atoi(cp + sizeof("ndots:") - 1); 565 if (i <= RES_MAXNDOTS) 566 statp->ndots = i; 567 else 568 statp->ndots = RES_MAXNDOTS; 569 #ifdef DEBUG 570 if (statp->options & RES_DEBUG) 571 printf(";;\tndots=%d\n", statp->ndots); 572 #endif 573 } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) { 574 i = atoi(cp + sizeof("timeout:") - 1); 575 if (i <= RES_MAXRETRANS) 576 statp->retrans = i; 577 else 578 statp->retrans = RES_MAXRETRANS; 579 #ifdef DEBUG 580 if (statp->options & RES_DEBUG) 581 printf(";;\ttimeout=%d\n", statp->retrans); 582 #endif 583 #ifdef SOLARIS2 584 } else if (!strncmp(cp, "retrans:", sizeof("retrans:") - 1)) { 585 /* 586 * For backward compatibility, 'retrans' is 587 * supported as an alias for 'timeout', though 588 * without an imposed maximum. 589 */ 590 statp->retrans = atoi(cp + sizeof("retrans:") - 1); 591 } else if (!strncmp(cp, "retry:", sizeof("retry:") - 1)){ 592 /* 593 * For backward compatibility, 'retry' is 594 * supported as an alias for 'attempts', though 595 * without an imposed maximum. 596 */ 597 statp->retry = atoi(cp + sizeof("retry:") - 1); 598 #endif /* SOLARIS2 */ 599 } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){ 600 i = atoi(cp + sizeof("attempts:") - 1); 601 if (i <= RES_MAXRETRY) 602 statp->retry = i; 603 else 604 statp->retry = RES_MAXRETRY; 605 #ifdef DEBUG 606 if (statp->options & RES_DEBUG) 607 printf(";;\tattempts=%d\n", statp->retry); 608 #endif 609 } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { 610 #ifdef DEBUG 611 if (!(statp->options & RES_DEBUG)) { 612 printf(";; res_setoptions(\"%s\", \"%s\")..\n", 613 options, source); 614 statp->options |= RES_DEBUG; 615 } 616 printf(";;\tdebug\n"); 617 #endif 618 } else if (!strncmp(cp, "no_tld_query", 619 sizeof("no_tld_query") - 1) || 620 !strncmp(cp, "no-tld-query", 621 sizeof("no-tld-query") - 1)) { 622 statp->options |= RES_NOTLDQUERY; 623 } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { 624 statp->options |= RES_USE_INET6; 625 } else if (!strncmp(cp, "insecure1", sizeof("insecure1") - 1)) { 626 statp->options |= RES_INSECURE1; 627 } else if (!strncmp(cp, "insecure2", sizeof("insecure2") - 1)) { 628 statp->options |= RES_INSECURE2; 629 } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) { 630 statp->options |= RES_ROTATE; 631 } else if (!strncmp(cp, "usevc", sizeof("usevc") - 1)) { 632 statp->options |= RES_USEVC; 633 } else if (!strncmp(cp, "no-check-names", 634 sizeof("no-check-names") - 1)) { 635 statp->options |= RES_NOCHECKNAME; 636 } else if (!strncmp(cp, "reload-period:", 637 sizeof("reload-period:") - 1)) { 638 if (ext != NULL) { 639 ext->reload_period = (u_short) 640 atoi(cp + sizeof("reload-period:") - 1); 641 } 642 } 643 #ifdef RES_USE_EDNS0 644 else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) { 645 statp->options |= RES_USE_EDNS0; 646 } 647 #endif 648 #ifndef _LIBC 649 else if (!strncmp(cp, "dname", sizeof("dname") - 1)) { 650 statp->options |= RES_USE_DNAME; 651 } 652 else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) { 653 if (ext == NULL) 654 goto skip; 655 cp += sizeof("nibble:") - 1; 656 i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1); 657 strncpy(ext->nsuffix, cp, i); 658 ext->nsuffix[i] = '\0'; 659 } 660 else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) { 661 if (ext == NULL) 662 goto skip; 663 cp += sizeof("nibble2:") - 1; 664 i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1); 665 strncpy(ext->nsuffix2, cp, i); 666 ext->nsuffix2[i] = '\0'; 667 } 668 else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) { 669 cp += sizeof("v6revmode:") - 1; 670 /* "nibble" and "bitstring" used to be valid */ 671 if (!strncmp(cp, "single", sizeof("single") - 1)) { 672 statp->options |= RES_NO_NIBBLE2; 673 } else if (!strncmp(cp, "both", sizeof("both") - 1)) { 674 statp->options &= 675 ~RES_NO_NIBBLE2; 676 } 677 } 678 #endif 679 else { 680 /* XXX - print a warning here? */ 681 } 682 #ifndef _LIBC 683 skip: 684 #endif 685 /* skip to next run of spaces */ 686 while (*cp && *cp != ' ' && *cp != '\t') 687 cp++; 688 } 689 } 690 691 #ifdef RESOLVSORT 692 /* XXX - should really support CIDR which means explicit masks always. */ 693 static u_int32_t 694 net_mask(struct in_addr in) /*!< XXX - should really use system's version of this */ 695 { 696 u_int32_t i = ntohl(in.s_addr); 697 698 if (IN_CLASSA(i)) 699 return (htonl(IN_CLASSA_NET)); 700 else if (IN_CLASSB(i)) 701 return (htonl(IN_CLASSB_NET)); 702 return (htonl(IN_CLASSC_NET)); 703 } 704 #endif 705 706 void 707 freebsd15_res_rndinit(res_state statp) 708 { 709 (void)statp; 710 } 711 __sym_compat(__res_rndinit, freebsd15_res_rndinit, FBSD_1.4); 712 713 u_int 714 res_nrandomid(res_state statp) { 715 (void) statp; 716 717 return ((u_int)(arc4random() & 0xffff)); 718 } 719 720 /*% 721 * This routine is for closing the socket if a virtual circuit is used and 722 * the program wants to close it. This provides support for endhostent() 723 * which expects to close the socket. 724 * 725 * This routine is not expected to be user visible. 726 */ 727 void 728 res_nclose(res_state statp) { 729 int ns; 730 731 if (statp->_vcsock >= 0) { 732 (void) _close(statp->_vcsock); 733 statp->_vcsock = -1; 734 statp->_flags &= ~(RES_F_VC | RES_F_CONN); 735 } 736 for (ns = 0; ns < statp->_u._ext.nscount; ns++) { 737 if (statp->_u._ext.nssocks[ns] != -1) { 738 (void) _close(statp->_u._ext.nssocks[ns]); 739 statp->_u._ext.nssocks[ns] = -1; 740 } 741 } 742 } 743 744 void 745 res_ndestroy(res_state statp) { 746 res_nclose(statp); 747 if (statp->_u._ext.ext != NULL) { 748 free(statp->_u._ext.ext); 749 statp->_u._ext.ext = NULL; 750 } 751 statp->options &= ~RES_INIT; 752 } 753 754 #ifndef _LIBC 755 const char * 756 res_get_nibblesuffix(res_state statp) { 757 if (statp->_u._ext.ext) 758 return (statp->_u._ext.ext->nsuffix); 759 return ("ip6.arpa"); 760 } 761 762 const char * 763 res_get_nibblesuffix2(res_state statp) { 764 if (statp->_u._ext.ext) 765 return (statp->_u._ext.ext->nsuffix2); 766 return ("ip6.int"); 767 } 768 #endif 769 770 void 771 res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) { 772 int i, nserv; 773 size_t size; 774 775 /* close open servers */ 776 res_nclose(statp); 777 778 /* cause rtt times to be forgotten */ 779 statp->_u._ext.nscount = 0; 780 781 nserv = 0; 782 for (i = 0; i < cnt && nserv < MAXNS; i++) { 783 switch (set->sin.sin_family) { 784 case AF_INET: 785 size = sizeof(set->sin); 786 if (statp->_u._ext.ext) 787 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], 788 &set->sin, size); 789 if (size <= sizeof(statp->nsaddr_list[nserv])) 790 memcpy(&statp->nsaddr_list[nserv], 791 &set->sin, size); 792 else 793 statp->nsaddr_list[nserv].sin_family = 0; 794 nserv++; 795 break; 796 797 #ifdef HAS_INET6_STRUCTS 798 case AF_INET6: 799 size = sizeof(set->sin6); 800 if (statp->_u._ext.ext) 801 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], 802 &set->sin6, size); 803 if (size <= sizeof(statp->nsaddr_list[nserv])) 804 memcpy(&statp->nsaddr_list[nserv], 805 &set->sin6, size); 806 else 807 statp->nsaddr_list[nserv].sin_family = 0; 808 nserv++; 809 break; 810 #endif 811 812 default: 813 break; 814 } 815 set++; 816 } 817 statp->nscount = nserv; 818 819 } 820 821 int 822 res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) { 823 int i; 824 size_t size; 825 u_int16_t family; 826 827 for (i = 0; i < statp->nscount && i < cnt; i++) { 828 if (statp->_u._ext.ext) 829 family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family; 830 else 831 family = statp->nsaddr_list[i].sin_family; 832 833 switch (family) { 834 case AF_INET: 835 size = sizeof(set->sin); 836 if (statp->_u._ext.ext) 837 memcpy(&set->sin, 838 &statp->_u._ext.ext->nsaddrs[i], 839 size); 840 else 841 memcpy(&set->sin, &statp->nsaddr_list[i], 842 size); 843 break; 844 845 #ifdef HAS_INET6_STRUCTS 846 case AF_INET6: 847 size = sizeof(set->sin6); 848 if (statp->_u._ext.ext) 849 memcpy(&set->sin6, 850 &statp->_u._ext.ext->nsaddrs[i], 851 size); 852 else 853 memcpy(&set->sin6, &statp->nsaddr_list[i], 854 size); 855 break; 856 #endif 857 858 default: 859 set->sin.sin_family = 0; 860 break; 861 } 862 set++; 863 } 864 return (statp->nscount); 865 } 866 867 /*! \file */ 868