1/* 2 * Copyright (c) 1985, 1989, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34/* 35 * Portions Copyright (c) 1993 by Digital Equipment Corporation. 36 * 37 * Permission to use, copy, modify, and distribute this software for any 38 * purpose with or without fee is hereby granted, provided that the above 39 * copyright notice and this permission notice appear in all copies, and that 40 * the name of Digital Equipment Corporation not be used in advertising or 41 * publicity pertaining to distribution of the document or software without 42 * specific, written prior permission. 43 * 44 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL 45 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES 46 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT 47 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 48 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 49 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 50 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 51 * SOFTWARE. 52 */ 53 54/* 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 INTERNET SOFTWARE CONSORTIUM DISCLAIMS 62 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 63 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 64 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 65 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 66 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 67 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 68 * SOFTWARE. 69 */ 70 71#if defined(LIBC_SCCS) && !defined(lint) 72static const char sccsid[] = "@(#)res_init.c 8.1 (Berkeley) 6/7/93"; 73static const char rcsid[] = "$Id: res_init.c,v 1.1 2006/03/01 19:01:38 majka Exp $"; 74#endif /* LIBC_SCCS and not lint */ 75 76#ifndef __APPLE__ 77#include "port_before.h" 78#endif 79 80#include <sys/types.h> 81#include <sys/param.h> 82#include <sys/socket.h> 83#include <sys/time.h> 84 85#include <netinet/in.h> 86#include <arpa/inet.h> 87#include <arpa/nameser.h> 88 89#include <ctype.h> 90#include <stdio.h> 91#include <stdlib.h> 92#include <string.h> 93#include <unistd.h> 94#include <netdb.h> 95#ifdef __APPLE__ 96#include <fcntl.h> 97#include <dnsinfo.h> 98#endif 99 100#ifndef __APPLE__ 101#include "port_after.h" 102#endif 103 104/* ensure that sockaddr_in6 and IN6ADDR_ANY_INIT are declared / defined */ 105#include <resolv.h> 106 107#include "res_private.h" 108 109/* Options. Should all be left alone. */ 110#define RESOLVSORT 111#define DEBUG 112 113static void res_setoptions __P((res_state, const char *, const char *)); 114extern res_state res_state_new(); 115 116#ifdef RESOLVSORT 117static const char sort_mask[] = "/&"; 118#define ISSORTMASK(ch) (strchr(sort_mask, ch) != NULL) 119static u_int32_t net_mask __P((struct in_addr)); 120#endif 121 122#if !defined(isascii) /* XXX - could be a function */ 123# define isascii(c) (!(c & 0200)) 124#endif 125 126#define INET_NTOP_AF_INET_OFFSET 4 127#define INET_NTOP_AF_INET6_OFFSET 8 128 129/* 130 * Resolver state default settings. 131 */ 132 133res_state 134res_build_start(res_state x) 135{ 136 res_state res; 137 138 res = NULL; 139 140 if (x == NULL) 141 { 142 res = res_state_new(); 143 } 144 else 145 { 146 if ((x->options & RES_INIT) != 0) res_ndestroy(x); 147 res = x; 148 } 149 150 if (res == NULL) return NULL; 151 152 /* res_ndestroy frees _u._ext.ext so we create a new one if necessary */ 153 if (res->_u._ext.ext == NULL) res->_u._ext.ext = (struct __res_state_ext *)calloc(1, sizeof(struct __res_state_ext)); 154 155 /* make sure version is set */ 156 res->_pad = 9; 157 158 res->retry = RES_DFLRETRY; 159 res->options = RES_DEFAULT; 160 res->id = res_randomid(); 161 162 res->ndots = 1; 163 res->_vcsock = -1; 164 165 if (res->_u._ext.ext != NULL) 166 { 167 strcpy(res->_u._ext.ext->nsuffix, "ip6.arpa"); 168 strcpy(res->_u._ext.ext->nsuffix2, "ip6.int"); 169 strcpy(res->_u._ext.ext->bsuffix, "ip6.arpa"); 170 } 171 172 return res; 173} 174 175int 176res_build_finish(res_state res, uint32_t timeout, uint16_t port) 177{ 178 if (res == NULL) return -1; 179 180 if (res->nscount == 0) 181 { 182#ifdef USELOOPBACK 183 res->nsaddr_list[0].sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); 184#else 185 res->nsaddr_list[0].sin_addr.s_addr = INADDR_ANY; 186#endif 187 188 res->nsaddr_list[0].sin_family = AF_INET; 189 res->nsaddr_list[0].sin_port = htons(port); 190#ifdef HAVE_SA_LEN 191 res->nsaddr_list[0].sin_len = sizeof(struct sockaddr_in); 192#endif 193 194 res->nscount = 1; 195 196 /* 197 * Force loopback queries to use TCP 198 * so we don't take a timeout if named isn't running. 199 */ 200 res->options |= RES_USEVC; 201 } 202 203 if (timeout == 0) res->retrans = RES_MAXRETRANS; 204 else res->retrans = timeout; 205 206 res->options |= RES_INIT; 207 return 0; 208} 209 210int 211res_build_sortlist(res_state res, struct in_addr addr, struct in_addr mask) 212{ 213 uint32_t n; 214 215 if (res == NULL) return -1; 216 217 n = res->nsort; 218 if (n >= MAXRESOLVSORT) return -1; 219 220 res->sort_list[n].addr = addr; 221 res->sort_list[n].mask = mask.s_addr; 222 n++; 223 res->nsort = n; 224 225 return 0; 226} 227 228char * 229res_next_word(char **p) 230{ 231 char *s, *x; 232 233 if (p == NULL) return NULL; 234 if (*p == NULL) return NULL; 235 236 s = *p; 237 238 /* Skip leading white space */ 239 while ((*s == ' ') || (*s == '\t') || (*s == '\n')) s++; 240 *p = s; 241 242 if (*s == '\0') return NULL; 243 244 /* Find end of word */ 245 x = s; 246 while ((*x != ' ') && (*x != '\t') && (*x != '\n') && (*x != '\0')) x++; 247 if (*x != '\0') 248 { 249 *x = '\0'; 250 x++; 251 } 252 253 *p = x; 254 255 if (s == x) return NULL; 256 return s; 257} 258 259int 260res_build(res_state res, uint16_t port, uint32_t *nsrch, char *key, char *val) 261{ 262 int32_t dotcount, semicount, status; 263 int32_t ival, len; 264 char *p, *lastdot; 265 uint16_t aport; 266 struct in_addr addr4, mask; 267 struct sockaddr_in sin4; 268 struct in6_addr addr6; 269 struct sockaddr_in6 sin6; 270 271 if (res == NULL) return -1; 272 273 if (!strcmp(key, "domain")) 274 { 275 strncpy(res->defdname, val, sizeof(res->defdname) - 1); 276 res->defdname[sizeof(res->defdname) - 1] = '\0'; 277 return 0; 278 } 279 280 else if (!strcmp(key, "search")) 281 { 282 len = strlen(val) + 1; 283 ival = sizeof(res->defdname); 284 p = res->defdname; 285 286 if ((*nsrch) == 0) 287 { 288 memset(res->defdname, 0, sizeof(res->defdname)); 289 } 290 else 291 { 292 p = res->dnsrch[*nsrch - 1]; 293 for (; (ival > 0) && (*p != '\0'); ival--) p++; 294 if (*p == '\0') p++; 295 } 296 297 if (len > ival) return -1; 298 299 memcpy(p, val, len); 300 res->dnsrch[*nsrch] = p; 301 *nsrch = *nsrch + 1; 302 return 0; 303 } 304 305 else if (!strcmp(key, "nameserver")) 306 { 307 dotcount = 0; 308 semicount = 0; 309 lastdot = NULL; 310 aport = port; 311 312 for (p = val; *p != '\0'; p++) 313 { 314 if (*p == ':') semicount++; 315 else if (*p == '.') 316 { 317 dotcount++; 318 lastdot = p; 319 } 320 } 321 322 if ((dotcount == 4) || ((semicount > 0) && (lastdot != NULL))) 323 { 324 aport = atoi(lastdot + 1); 325 if (aport == 0) aport = port; 326 *lastdot = '\0'; 327 } 328 329 memset(&addr4, 0, sizeof(struct in_addr)); 330 memset(&sin4, 0, sizeof(struct sockaddr_in)); 331 332 memset(&addr6, 0, sizeof(struct in6_addr)); 333 memset(&sin6, 0, sizeof(struct sockaddr_in6)); 334 335 status = inet_pton(AF_INET6, val, &addr6); 336 if (status == 1) 337 { 338 sin6.sin6_addr = addr6; 339 sin6.sin6_family = AF_INET6; 340 sin6.sin6_port = htons(aport); 341 sin6.sin6_len = sizeof(struct sockaddr_in6); 342 if (res->_u._ext.ext != NULL) 343 { 344 memcpy(&(res->_u._ext.ext->nsaddrs[res->nscount]), &sin6, sizeof(struct sockaddr_in6)); 345 } 346 res->nsaddr_list[res->nscount].sin_family = 0; 347 res->nscount++; 348 } 349 else 350 { 351 status = inet_pton(AF_INET, val, &addr4); 352 if (status == 1) 353 { 354 sin4.sin_addr = addr4; 355 sin4.sin_family = AF_INET; 356 sin4.sin_port = htons(aport); 357 sin4.sin_len = sizeof(struct sockaddr_in); 358 if (res->_u._ext.ext != NULL) 359 { 360 memcpy(&(res->_u._ext.ext->nsaddrs[res->nscount]), &sin4, sizeof(struct sockaddr_in)); 361 } 362 memcpy(&(res->nsaddr_list[res->nscount]), &sin4, sizeof(struct sockaddr_in)); 363 res->nscount++; 364 } 365 } 366 367 return 0; 368 } 369 370 else if (!strcmp(key, "sortlist")) 371 { 372 p = strchr(val, '/'); 373 374 if (p != NULL) 375 { 376 *p = '\0'; 377 p++; 378 } 379 380 /* we use inet_aton rather than inet_pton to be compatible with res_init() */ 381 status = inet_aton(val, &addr4); 382 if (status == 0) return -1; 383 384 status = 0; 385 if (p != NULL) status = inet_aton(p, &mask); 386 if (status == 0) 387 { 388 ival = ntohl(addr4.s_addr); 389 390 if (IN_CLASSA(ival)) mask.s_addr = htonl(IN_CLASSA_NET); 391 else if (IN_CLASSB(ival)) mask.s_addr = htonl(IN_CLASSB_NET); 392 else mask.s_addr = htonl(IN_CLASSC_NET); 393 } 394 395 return res_build_sortlist(res, addr4, mask); 396 } 397 398 else if (!strcmp(key, "ndots")) 399 { 400 ival = atoi(val); 401 if (ival < 0) ival = 0; 402 if (ival > RES_MAXNDOTS) ival = RES_MAXNDOTS; 403 res->ndots = ival; 404 return 0; 405 } 406 407 else if (!strcmp(key, "nibble")) 408 { 409 if ((strlen(val) + 1) > RES_EXT_SUFFIX_LEN) return -1; 410 if (res->_u._ext.ext == NULL) return -1; 411 strcpy(res->_u._ext.ext->nsuffix, val); 412 return 0; 413 } 414 415 else if (!strcmp(key, "nibble2")) 416 { 417 if ((strlen(val) + 1) > RES_EXT_SUFFIX_LEN) return -1; 418 if (res->_u._ext.ext == NULL) return -1; 419 strcpy(res->_u._ext.ext->nsuffix2, val); 420 return 0; 421 } 422 423 else if (!strcmp(key, "bitstring")) 424 { 425 if ((strlen(val) + 1) > RES_EXT_SUFFIX_LEN) return -1; 426 if (res->_u._ext.ext == NULL) return -1; 427 strcpy(res->_u._ext.ext->bsuffix, val); 428 return 0; 429 } 430 431 else if (!strcmp(key, "attempts")) 432 { 433 ival = atoi(val); 434 if (ival < 0) ival = 0; 435 if (ival > RES_MAXRETRY) ival = RES_MAXRETRY; 436 res->retry = ival; 437 return 0; 438 } 439 440 else if (!strcmp(key, "v6revmode")) 441 { 442 if (!strcmp(val, "single")) res->options |= RES_NO_NIBBLE2; 443 else if (!strcmp(val, "both")) res->options &= ~RES_NO_NIBBLE2; 444 return 0; 445 } 446 447 else if (!strcmp(key, "debug")) 448 { 449 res->options |= RES_DEBUG; 450 return 0; 451 } 452 453 else if (!strcmp(key, "no_tld_query")) 454 { 455 res->options |= RES_NOTLDQUERY; 456 return 0; 457 } 458 459 else if (!strcmp(key, "inet6")) 460 { 461 res->options |= RES_USE_INET6; 462 return 0; 463 } 464 465 else if (!strcmp(key, "rotate")) 466 { 467 res->options |= RES_ROTATE; 468 return 0; 469 } 470 471 else if (!strcmp(key, "no-check-names")) 472 { 473 res->options |= RES_NOCHECKNAME; 474 return 0; 475 } 476 477#ifdef RES_USE_EDNS0 478 else if (!strcmp(key, "edns0")) 479 { 480 res->options |= RES_USE_EDNS0; 481 return 0; 482 } 483#endif 484 485 else if (!strcmp(key, "a6")) 486 { 487 res->options |= RES_USE_A6; 488 return 0; 489 } 490 491 else if (!strcmp(key, "dname")) 492 { 493 res->options |= RES_USE_DNAME; 494 return 0; 495 } 496 497 return -1; 498} 499 500/* 501 * Set up default settings. If the configuration file exist, the values 502 * there will have precedence. Otherwise, the server address is set to 503 * INADDR_ANY and the default domain name comes from the gethostname(). 504 * 505 * An interrim version of this code (BIND 4.9, pre-4.4BSD) used 127.0.0.1 506 * rather than INADDR_ANY ("0.0.0.0") as the default name server address 507 * since it was noted that INADDR_ANY actually meant ``the first interface 508 * you "ifconfig"'d at boot time'' and if this was a SLIP or PPP interface, 509 * it had to be "up" in order for you to reach your own name server. It 510 * was later decided that since the recommended practice is to always 511 * install local static routes through 127.0.0.1 for all your network 512 * interfaces, that we could solve this problem without a code change. 513 * 514 * The configuration file should always be used, since it is the only way 515 * to specify a default domain. If you are running a server on your local 516 * machine, you should say "nameserver 0.0.0.0" or "nameserver 127.0.0.1" 517 * in the configuration file. 518 * 519 * Return 0 if completes successfully, -1 on error 520 */ 521 522int 523res_vinit_from_file(res_state statp, int preinit, char *resconf_file) 524{ 525 register FILE *fp; 526 register char *cp, **pp; 527 register int n; 528 char buf[BUFSIZ]; 529 int nserv = 0; /* number of nameserver records read from file */ 530 int haveenv = 0; 531 int havesearch = 0; 532 int isresdefault = 0; 533 unsigned short port; /* HOST BYTE ORDER */ 534 unsigned int i, total_timeout; 535#ifdef RESOLVSORT 536 int nsort = 0; 537 char *net; 538#endif 539 int dots; 540 541 port = NS_DEFAULTPORT; 542 total_timeout = 0; 543 544 if (!preinit) 545 { 546 statp->retrans = RES_TIMEOUT; 547 statp->retry = RES_DFLRETRY; 548 statp->options = RES_DEFAULT; 549 statp->id = res_randomid(); 550 } 551 552 if ((statp->options & RES_INIT) != 0) res_ndestroy(statp); 553 554 /* N.B. we allocate a new statp->_u._ext.ext below */ 555 556 /* make sure version is set */ 557 statp->_pad = 9; 558 559 statp->nscount = 0; 560 561 if ((resconf_file == NULL) || (!strcmp(resconf_file, _PATH_RESCONF))) 562 { 563 isresdefault = 1; 564 565#ifdef USELOOPBACK 566 statp->nsaddr.sin_addr = inet_makeaddr(IN_LOOPBACKNET, 1); 567#else 568 statp->nsaddr.sin_addr.s_addr = INADDR_ANY; 569#endif 570 statp->nsaddr.sin_family = AF_INET; 571 statp->nsaddr.sin_port = htons(NS_DEFAULTPORT); 572#ifdef HAVE_SA_LEN 573 statp->nsaddr.sin_len = sizeof(struct sockaddr_in); 574#endif 575 statp->nscount = 1; 576 577 /* 578 * Force loopback queries to use TCP 579 * so we don't take a timeout if named isn't running. 580 */ 581 statp->options |= RES_USEVC; 582 } 583 584 statp->ndots = 1; 585 statp->pfcode = 0; 586 statp->_vcsock = -1; 587 statp->_flags = 0; 588 statp->qhook = NULL; 589 statp->rhook = NULL; 590 591 statp->_u._ext.nscount = 0; 592 statp->_u._ext.ext = (struct __res_state_ext *)calloc(1, sizeof(struct __res_state_ext)); 593 594 if (statp->_u._ext.ext != NULL) 595 { 596 memset(statp->_u._ext.ext, 0, sizeof(*statp->_u._ext.ext)); 597 statp->_u._ext.ext->nsaddrs[0].sin = statp->nsaddr; 598 strcpy(statp->_u._ext.ext->nsuffix, "ip6.arpa"); 599 strcpy(statp->_u._ext.ext->nsuffix2, "ip6.int"); 600 strcpy(statp->_u._ext.ext->bsuffix, "ip6.arpa"); 601 } 602 603#ifdef RESOLVSORT 604 statp->nsort = 0; 605#endif 606 607 /* Allow user to override the local domain definition */ 608 cp = getenv("LOCALDOMAIN"); 609 if ((cp != NULL) && (isresdefault != 0)) 610 { 611 (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); 612 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 613 haveenv++; 614 615 /* 616 * Set search list to be blank-separated strings 617 * from rest of env value. Permits users of LOCALDOMAIN 618 * to still have a search list, and anyone to set the 619 * one that they want to use as an individual (even more 620 * important now that the rfc1535 stuff restricts searches) 621 */ 622 cp = statp->defdname; 623 pp = statp->dnsrch; 624 *pp++ = cp; 625 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) 626 { 627 if (*cp == '\n') break; 628 else if (*cp == ' ' || *cp == '\t') 629 { 630 *cp = 0; 631 n = 1; 632 } 633 else if (n != 0) 634 { 635 *pp++ = cp; 636 n = 0; 637 havesearch = 1; 638 } 639 } 640 641 /* null terminate last domain if there are excess */ 642 while ((*cp != '\0') && (*cp != ' ') && (*cp != '\t') && (*cp != '\n')) cp++; 643 *cp = '\0'; 644 *pp++ = 0; 645 } 646 647#define MATCH(line, name) \ 648 (!strncmp(line, name, sizeof(name) - 1) && \ 649 (line[sizeof(name) - 1] == ' ' || \ 650 line[sizeof(name) - 1] == '\t')) 651 652 if (resconf_file == NULL) resconf_file = _PATH_RESCONF; 653 654 if ((fp = fopen(resconf_file, "r")) != NULL) 655 { 656 /* look for port number */ 657 while (fgets(buf, sizeof(buf), fp) != NULL) 658 { 659 /* skip comments */ 660 if (*buf == ';' || *buf == '#') continue; 661 662 /* read default domain name */ 663 if (MATCH(buf, "port")) 664 { 665 cp = buf + sizeof("port") - 1; 666 while (*cp == ' ' || *cp == '\t') cp++; 667 if ((*cp == '\0') || (*cp == '\n')) continue; 668 port = atoi(cp); 669 break; 670 } 671 } 672 fclose(fp); 673 } 674 675 if ((fp = fopen(resconf_file, "r")) != NULL) 676 { 677 /* read the config file */ 678 while (fgets(buf, sizeof(buf), fp) != NULL) 679 { 680 /* skip comments */ 681 if ((*buf == ';') || (*buf == '#')) continue; 682 683 /* read default domain name */ 684 if (MATCH(buf, "domain")) 685 { 686 /* skip if have from environ */ 687 if (haveenv) continue; 688 689 cp = buf + sizeof("domain") - 1; 690 while ((*cp == ' ') || (*cp == '\t')) cp++; 691 if ((*cp == '\0') || (*cp == '\n')) continue; 692 693 strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); 694 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 695 cp = strpbrk(statp->defdname, " \t\n"); 696 if (cp != NULL) *cp = '\0'; 697 havesearch = 0; 698 continue; 699 } 700 701 /* set search list */ 702 if (MATCH(buf, "search")) 703 { 704 /* skip if have from environ */ 705 if (haveenv) continue; 706 707 cp = buf + sizeof("search") - 1; 708 while ((*cp == ' ') || (*cp == '\t')) cp++; 709 if ((*cp == '\0') || (*cp == '\n')) continue; 710 711 strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); 712 statp->defdname[sizeof(statp->defdname) - 1] = '\0'; 713 cp = strchr(statp->defdname, '\n'); 714 if (cp != NULL) *cp = '\0'; 715 716 /* 717 * Set search list to be blank-separated strings 718 * on rest of line. 719 */ 720 cp = statp->defdname; 721 pp = statp->dnsrch; 722 *pp++ = cp; 723 for (n = 0; *cp && pp < statp->dnsrch + MAXDNSRCH; cp++) 724 { 725 if ((*cp == ' ') || (*cp == '\t')) 726 { 727 *cp = 0; 728 n = 1; 729 } 730 else if (n != 0) 731 { 732 *pp++ = cp; 733 n = 0; 734 } 735 } 736 737 /* null terminate last domain if there are excess */ 738 while ((*cp != '\0') && (*cp != ' ') && (*cp != '\t')) cp++; 739 *cp = '\0'; 740 *pp++ = 0; 741 havesearch = 1; 742 continue; 743 } 744 745 /* read nameservers to query */ 746 if (MATCH(buf, "nameserver") && (nserv < MAXNS)) 747 { 748#ifndef __APPLE__ 749 struct addrinfo hints, *ai; 750#endif 751 int dotcount, semicount, status; 752 struct in_addr addr4; 753 struct sockaddr_in sin4; 754 struct in6_addr addr6; 755 struct sockaddr_in6 sin6; 756 unsigned short aport; /* HOST BYTE ORDER */ 757 char *lastdot, *checkp; 758 char sbuf[NI_MAXSERV]; 759#ifndef __APPLE__ 760 const size_t minsiz = sizeof(statp->_u._ext.ext->nsaddrs[0]); 761#endif 762 763 cp = buf + sizeof("nameserver") - 1; 764 while ((*cp == ' ') || (*cp == '\t')) cp++; 765 cp[strcspn(cp, ";# \t\n")] = '\0'; 766 if ((*cp != '\0') && (*cp != '\n')) 767 { 768#ifndef __APPLE__ 769 memset(&hints, 0, sizeof(hints)); 770 hints.ai_family = PF_UNSPEC; 771 hints.ai_socktype = SOCK_DGRAM; /*dummy*/ 772 hints.ai_flags = AI_NUMERICHOST; 773#endif 774 dotcount = 0; 775 semicount = 0; 776 lastdot = NULL; 777 aport = port; 778 779 for (checkp = cp; *checkp != '\0'; checkp++) 780 { 781 if (*checkp == ':') semicount++; 782 else if (*checkp == '.') 783 { 784 dotcount++; 785 lastdot = checkp; 786 } 787 } 788 789 if ((dotcount == 4) || ((semicount > 0) && (lastdot != NULL))) 790 { 791 aport = atoi(lastdot + 1); 792 if (aport == 0) aport = port; 793 *lastdot = '\0'; 794 } 795 796 sprintf(sbuf, "%u", aport); 797 798#ifdef __APPLE__ 799 memset(&addr4, 0, sizeof(struct in_addr)); 800 memset(&sin4, 0, sizeof(struct sockaddr_in)); 801 802 memset(&addr6, 0, sizeof(struct in6_addr)); 803 memset(&sin6, 0, sizeof(struct sockaddr_in6)); 804 805 status = inet_pton(AF_INET6, cp, &addr6); 806 if (status == 1) 807 { 808 sin6.sin6_addr = addr6; 809 sin6.sin6_family = AF_INET6; 810 sin6.sin6_port = htons(aport); 811 sin6.sin6_len = sizeof(struct sockaddr_in6); 812 if (statp->_u._ext.ext != NULL) 813 { 814 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &sin6, sizeof(struct sockaddr_in6)); 815 } 816 statp->nsaddr_list[nserv].sin_family = 0; 817 nserv++; 818 } 819 else 820 { 821 status = inet_pton(AF_INET, cp, &addr4); 822 if (status == 1) 823 { 824 sin4.sin_addr = addr4; 825 sin4.sin_family = AF_INET; 826 sin4.sin_port = htons(port); 827 sin4.sin_len = sizeof(struct sockaddr_in); 828 if (statp->_u._ext.ext != NULL) 829 { 830 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], &sin4, sizeof(struct sockaddr_in)); 831 } 832 memcpy(&statp->nsaddr_list[nserv], &sin4, sizeof(struct sockaddr_in)); 833 nserv++; 834 } 835 } 836 837 838#else 839 if (getaddrinfo(cp, sbuf, &hints, &ai) == 0 && ai->ai_addrlen <= minsiz) 840 { 841 if (statp->_u._ext.ext != NULL) 842 { 843 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], ai->ai_addr, ai->ai_addrlen); 844 } 845 846 if (ai->ai_addrlen <= sizeof(statp->nsaddr_list[nserv])) 847 { 848 memcpy(&statp->nsaddr_list[nserv], ai->ai_addr, ai->ai_addrlen); 849 } 850 else 851 { 852 statp->nsaddr_list[nserv].sin_family = 0; 853 } 854 855 freeaddrinfo(ai); 856 nserv++; 857 } 858#endif 859 } 860 861 continue; 862 } 863 864#ifdef RESOLVSORT 865 if (MATCH(buf, "sortlist")) 866 { 867 struct in_addr a; 868 869 cp = buf + sizeof("sortlist") - 1; 870 while (nsort < MAXRESOLVSORT) 871 { 872 while ((*cp == ' ') || (*cp == '\t')) cp++; 873 if ((*cp == '\0') || (*cp == '\n') || (*cp == ';')) break; 874 875 net = cp; 876 while (*cp && !ISSORTMASK(*cp) && (*cp != ';') && isascii(*cp) && !isspace((unsigned char)*cp)) cp++; 877 n = *cp; 878 *cp = 0; 879 if (inet_aton(net, &a)) 880 { 881 statp->sort_list[nsort].addr = a; 882 if (ISSORTMASK(n)) 883 { 884 *cp++ = n; 885 net = cp; 886 while (*cp && (*cp != ';') && isascii(*cp) && !isspace((unsigned char)*cp)) cp++; 887 n = *cp; 888 *cp = 0; 889 if (inet_aton(net, &a)) 890 { 891 statp->sort_list[nsort].mask = a.s_addr; 892 } 893 else 894 { 895 statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); 896 } 897 } 898 else 899 { 900 statp->sort_list[nsort].mask = net_mask(statp->sort_list[nsort].addr); 901 } 902 nsort++; 903 } 904 905 *cp = n; 906 } 907 908 continue; 909 } 910#endif 911 912 if (MATCH(buf, "options")) 913 { 914 res_setoptions(statp, buf + sizeof("options") - 1, "conf"); 915 continue; 916 } 917 918 if (MATCH(buf, "timeout")) 919 { 920 cp = buf + sizeof("timeout") - 1; 921 while (*cp == ' ' || *cp == '\t') cp++; 922 if ((*cp == '\0') || (*cp == '\n')) continue; 923 i = atoi(cp); 924 if (i > RES_MAXRETRANS) i = RES_MAXRETRANS; 925 total_timeout = i; 926 continue; 927 } 928 } 929 930 if (nserv > 1) statp->nscount = nserv; 931#ifdef RESOLVSORT 932 statp->nsort = nsort; 933#endif 934 fclose(fp); 935 } 936 937 /* 938 * Last chance to get a nameserver. This should not normally 939 * be necessary 940 */ 941#ifdef NO_RESOLV_CONF 942 if(nserv == 0) nserv = get_nameservers(statp); 943#endif 944 945 if (isresdefault != 0) 946 { 947 if ((statp->defdname[0] == 0) && (gethostname(buf, sizeof(statp->defdname) - 1) == 0) && ((cp = strchr(buf, '.')) != NULL)) 948 { 949 strcpy(statp->defdname, cp + 1); 950 } 951 } 952 953 /* find components of local domain that might be searched */ 954 if (havesearch == 0) 955 { 956 pp = statp->dnsrch; 957 *pp++ = statp->defdname; 958 *pp = NULL; 959 960 dots = 0; 961 for (cp = statp->defdname; *cp; cp++) 962 { 963 if (*cp == '.') dots++; 964 } 965 966 /* Back up over any trailing dots and cut them out of the name */ 967 for (cp--; (cp >= statp->defdname) && (*cp == '.'); cp--) 968 { 969 *cp = '\0'; 970 dots--; 971 } 972 973 cp = statp->defdname; 974 while (pp < statp->dnsrch + MAXDFLSRCH) 975 { 976 if (dots < LOCALDOMAINPARTS) break; 977 978 /* we know there is a dot */ 979 cp = strchr(cp, '.') + 1; 980 *pp++ = cp; 981 dots--; 982 } 983 984 *pp = NULL; 985#ifdef DEBUG 986 if (statp->options & RES_DEBUG) 987 { 988 printf(";; res_init()... default dnsrch list:\n"); 989 for (pp = statp->dnsrch; *pp; pp++) printf(";;\t%s\n", *pp); 990 printf(";;\t..END..\n"); 991 } 992#endif 993 } 994 995 cp = getenv("RES_OPTIONS"); 996 if ((cp != NULL) && (isresdefault != 0)) 997 { 998 res_setoptions(statp, cp, "env"); 999 } 1000 1001#ifdef __APPLE__ 1002 /* 1003 * Post processing to set the timeout value. 1004 */ 1005 if (total_timeout != 0) 1006 { 1007 /* Timeout was set with a "timeout" line in the file */ 1008 statp->retrans = total_timeout; 1009 } 1010 else 1011 { 1012 /* 1013 * Timeout is default, or was set with "options timeout:" 1014 * This is a per-select timeout value. Calculate total timeout 1015 * and set statp->restrans which we (Apple) use to indicate 1016 * total time allowed for a query to be resolved. 1017 */ 1018 total_timeout = statp->retrans * (statp->retry + 1) * statp->nscount; 1019 statp->retrans = total_timeout; 1020 } 1021#endif 1022 1023 statp->options |= RES_INIT; 1024 return (0); 1025} 1026 1027static void 1028res_setoptions(res_state statp, const char *options, const char *source) 1029{ 1030 const char *cp = options; 1031 int i; 1032 struct __res_state_ext *ext = statp->_u._ext.ext; 1033 1034#ifdef DEBUG 1035 if (statp->options & RES_DEBUG) 1036 printf(";; res_setoptions(\"%s\", \"%s\")...\n", 1037 options, source); 1038#endif 1039 while (*cp) { 1040 /* skip leading and inner runs of spaces */ 1041 while (*cp == ' ' || *cp == '\t') 1042 cp++; 1043 /* search for and process individual options */ 1044 if (!strncmp(cp, "ndots:", sizeof("ndots:") - 1)) { 1045 i = atoi(cp + sizeof("ndots:") - 1); 1046 if (i <= RES_MAXNDOTS) 1047 statp->ndots = i; 1048 else 1049 statp->ndots = RES_MAXNDOTS; 1050#ifdef DEBUG 1051 if (statp->options & RES_DEBUG) 1052 printf(";;\tndots=%d\n", statp->ndots); 1053#endif 1054 } else if (!strncmp(cp, "timeout:", sizeof("timeout:") - 1)) { 1055 i = atoi(cp + sizeof("timeout:") - 1); 1056 if (i <= RES_MAXRETRANS) 1057 statp->retrans = i; 1058 else 1059 statp->retrans = RES_MAXRETRANS; 1060 } else if (!strncmp(cp, "attempts:", sizeof("attempts:") - 1)){ 1061 i = atoi(cp + sizeof("attempts:") - 1); 1062 if (i <= RES_MAXRETRY) 1063 statp->retry = i; 1064 else 1065 statp->retry = RES_MAXRETRY; 1066 } else if (!strncmp(cp, "debug", sizeof("debug") - 1)) { 1067#ifdef DEBUG 1068 if (!(statp->options & RES_DEBUG)) { 1069 printf(";; res_setoptions(\"%s\", \"%s\")..\n", 1070 options, source); 1071 statp->options |= RES_DEBUG; 1072 } 1073 printf(";;\tdebug\n"); 1074#endif 1075 } else if (!strncmp(cp, "no_tld_query", 1076 sizeof("no_tld_query") - 1) || 1077 !strncmp(cp, "no-tld-query", 1078 sizeof("no-tld-query") - 1)) { 1079 statp->options |= RES_NOTLDQUERY; 1080 } else if (!strncmp(cp, "inet6", sizeof("inet6") - 1)) { 1081 statp->options |= RES_USE_INET6; 1082 } else if (!strncmp(cp, "rotate", sizeof("rotate") - 1)) { 1083 statp->options |= RES_ROTATE; 1084 } else if (!strncmp(cp, "no-check-names", 1085 sizeof("no-check-names") - 1)) { 1086 statp->options |= RES_NOCHECKNAME; 1087 } 1088#ifdef RES_USE_EDNS0 1089 else if (!strncmp(cp, "edns0", sizeof("edns0") - 1)) { 1090 statp->options |= RES_USE_EDNS0; 1091 } 1092#endif 1093 else if (!strncmp(cp, "a6", sizeof("a6") - 1)) { 1094 statp->options |= RES_USE_A6; 1095 } 1096 else if (!strncmp(cp, "dname", sizeof("dname") - 1)) { 1097 statp->options |= RES_USE_DNAME; 1098 } 1099 else if (!strncmp(cp, "nibble:", sizeof("nibble:") - 1)) { 1100 if (ext == NULL) 1101 goto skip; 1102 cp += sizeof("nibble:") - 1; 1103 i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix) - 1); 1104 strncpy(ext->nsuffix, cp, i); 1105 ext->nsuffix[i] = '\0'; 1106 } 1107 else if (!strncmp(cp, "nibble2:", sizeof("nibble2:") - 1)) { 1108 if (ext == NULL) 1109 goto skip; 1110 cp += sizeof("nibble2:") - 1; 1111 i = MIN(strcspn(cp, " \t"), sizeof(ext->nsuffix2) - 1); 1112 strncpy(ext->nsuffix2, cp, i); 1113 ext->nsuffix2[i] = '\0'; 1114 } 1115 else if (!strncmp(cp, "bitstring:", sizeof("bitstring:") - 1)) { 1116 if (ext == NULL) 1117 goto skip; 1118 cp += sizeof("bitstring:") - 1; 1119 i = MIN(strcspn(cp, " \t"), sizeof(ext->bsuffix) - 1); 1120 strncpy(ext->bsuffix, cp, i); 1121 ext->bsuffix[i] = '\0'; 1122 } 1123 else if (!strncmp(cp, "v6revmode:", sizeof("v6revmode:") - 1)) { 1124 cp += sizeof("v6revmode:") - 1; 1125 /* "nibble" and "bitstring" used to be valid */ 1126 if (!strncmp(cp, "single", sizeof("single") - 1)) { 1127 statp->options |= RES_NO_NIBBLE2; 1128 } else if (!strncmp(cp, "both", sizeof("both") - 1)) { 1129 statp->options &= 1130 ~RES_NO_NIBBLE2; 1131 } 1132 } 1133 else { 1134 /* XXX - print a warning here? */ 1135 } 1136 skip: 1137 /* skip to next run of spaces */ 1138 while (*cp && *cp != ' ' && *cp != '\t') 1139 cp++; 1140 } 1141} 1142 1143/* This function has to be reachable by res_data.c but not publically. */ 1144int 1145__res_vinit(res_state statp, int preinit) 1146{ 1147 dns_config_t *sc_dns; 1148 dns_resolver_t *sc_res; 1149 char val[256], *p, *x; 1150 int i, n; 1151 uint32_t nsearch, total_timeout, send_timeout; 1152 uint16_t port; 1153 1154 nsearch = 0; 1155 send_timeout = 0; 1156 1157 sc_dns = dns_configuration_copy(); 1158 if (sc_dns == NULL) return res_vinit_from_file(statp, preinit, _PATH_RESCONF); 1159 1160 sc_res = sc_dns->resolver[0]; 1161 port = sc_res->port; 1162 if (port == 0) port = NS_DEFAULTPORT; 1163 1164 if ((statp->options & RES_INIT) != 0) res_ndestroy(statp); 1165 1166 /* N.B. res_build_start will allocate statp->_u._ext.ext for us */ 1167 statp = res_build_start(statp); 1168 1169 p = getenv("RES_RETRY_TIMEOUT"); 1170 if (p != NULL) send_timeout = atoi(p); 1171 1172 p = getenv("RES_RETRY"); 1173 if (p != NULL) statp->retry= atoi(p); 1174 1175 if (sc_res->n_nameserver > MAXNS) sc_res->n_nameserver = MAXNS; 1176 for (i = 0; i < sc_res->n_nameserver; i++) 1177 { 1178 if (sc_res->nameserver[i]->sa_family == AF_INET) 1179 { 1180 memset(val, 0, sizeof(val)); 1181 inet_ntop(AF_INET, (char *)(sc_res->nameserver[i]) + INET_NTOP_AF_INET_OFFSET, val, sizeof(val)); 1182 res_build(statp, port, &nsearch, "nameserver", val); 1183 } 1184 else if (sc_res->nameserver[i]->sa_family == AF_INET6) 1185 { 1186 memset(val, 0, sizeof(val)); 1187 inet_ntop(AF_INET6, (char *)(sc_res->nameserver[i]) + INET_NTOP_AF_INET6_OFFSET, val, sizeof(val)); 1188 res_build(statp, port, &nsearch, "nameserver", val); 1189 } 1190 } 1191 1192 if (sc_res->n_search > MAXDNSRCH) sc_res->n_search = MAXDNSRCH; 1193 for (i = 0; i < sc_res->n_search; i++) 1194 { 1195 res_build(statp, port, &nsearch, "search", sc_res->search[i]); 1196 } 1197 1198 /* If there was no search list, use "domain" */ 1199 if ((sc_res->n_search == 0) && (sc_res->domain != NULL)) 1200 { 1201 /* Count dots */ 1202 n = 0; 1203 for (p = sc_res->domain; *p != '\0'; p++) 1204 { 1205 if (*p == '.') n++; 1206 } 1207 1208 /* Back up over any trailing dots and cut them out of the name */ 1209 for (p--; (p >= sc_res->domain) && (*p == '.'); p--) 1210 { 1211 *p = '\0'; 1212 n--; 1213 } 1214 1215 if (p >= sc_res->domain) res_build(statp, port, &nsearch, "search", sc_res->domain); 1216 1217 /* dots are separators, so number of components is one larger */ 1218 n++; 1219 1220 /* Include parent domains with at least LOCALDOMAINPARTS components */ 1221 p = sc_res->domain; 1222 while ((n > LOCALDOMAINPARTS) && (nsearch < MAXDFLSRCH)) 1223 { 1224 /* Find next component */ 1225 while (*p != '.') p++; 1226 if (*p == '\0') break; 1227 p++; 1228 1229 n--; 1230 res_build(statp, port, &nsearch, "search", p); 1231 } 1232 } 1233 1234 total_timeout = sc_res->timeout; 1235 1236 snprintf(val, sizeof(val), "%d", sc_res->search_order); 1237 res_build(statp, port, &nsearch, "search_order", val); 1238 1239 if (sc_res->n_sortaddr > MAXRESOLVSORT) sc_res->n_sortaddr = MAXRESOLVSORT; 1240 for (i = 0; i < sc_res->n_sortaddr; i++) 1241 { 1242 res_build_sortlist(statp, sc_res->sortaddr[i]->address, sc_res->sortaddr[i]->mask); 1243 } 1244 1245 p = sc_res->options; 1246 while (NULL != (x = res_next_word(&p))) 1247 { 1248 if (!strncmp(x, "ndots:", 6)) 1249 { 1250 res_build(statp, port, &nsearch, "ndots", x+6); 1251 } 1252 1253 else if (!strncmp(x, "nibble:", 7)) 1254 { 1255 res_build(statp, port, &nsearch, "nibble", x+7); 1256 } 1257 1258 else if (!strncmp(x, "nibble2:", 8)) 1259 { 1260 res_build(statp, port, &nsearch, "nibble2", x+8); 1261 } 1262 1263 else if (!strncmp(x, "timeout:", 8)) 1264 { 1265 send_timeout = atoi(x+8); 1266 } 1267 1268 else if (!strncmp(x, "attempts:", 9)) 1269 { 1270 res_build(statp, port, &nsearch, "attempts", x+9); 1271 } 1272 1273 else if (!strncmp(x, "bitstring:", 10)) 1274 { 1275 res_build(statp, port, &nsearch, "bitstring", x+10); 1276 } 1277 1278 else if (!strncmp(x, "v6revmode:", 10)) 1279 { 1280 res_build(statp, port, &nsearch, "v6revmode", x+10); 1281 } 1282 1283 else if (!strcmp(x, "debug")) 1284 { 1285 res_build(statp, port, &nsearch, "debug", NULL); 1286 } 1287 1288 else if (!strcmp(x, "no_tld_query")) 1289 { 1290 res_build(statp, port, &nsearch, "no_tld_query", NULL); 1291 } 1292 1293 else if (!strcmp(x, "inet6")) 1294 { 1295 res_build(statp, port, &nsearch, "inet6", NULL); 1296 } 1297 1298 else if (!strcmp(x, "rotate")) 1299 { 1300 res_build(statp, port, &nsearch, "rotate", NULL); 1301 } 1302 1303 else if (!strcmp(x, "no-check-names")) 1304 { 1305 res_build(statp, port, &nsearch, "no-check-names", NULL); 1306 } 1307 1308#ifdef RES_USE_EDNS0 1309 else if (!strcmp(x, "edns0")) 1310 { 1311 res_build(statp, port, &nsearch, "edns0", NULL); 1312 } 1313#endif 1314 else if (!strcmp(x, "a6")) 1315 { 1316 res_build(statp, port, &nsearch, "a6", NULL); 1317 } 1318 1319 else if (!strcmp(x, "dname")) 1320 { 1321 res_build(statp, port, &nsearch, "dname", NULL); 1322 } 1323 } 1324 1325 n = statp->nscount; 1326 if (n == 0) n = 1; 1327 1328 if (total_timeout == 0) 1329 { 1330 if (send_timeout == 0) total_timeout = RES_MAXRETRANS; 1331 else total_timeout = send_timeout * statp->retry * n; 1332 } 1333 1334 dns_configuration_free(sc_dns); 1335 1336 res_build_finish(statp, total_timeout, port); 1337 1338 return 0; 1339} 1340 1341int 1342res_ninit(res_state statp) 1343{ 1344 if (statp == NULL) return -1; 1345 memset(statp, 0, sizeof(struct __res_state)); 1346 return __res_vinit(statp, 0); 1347} 1348 1349#ifdef RESOLVSORT 1350/* XXX - should really support CIDR which means explicit masks always. */ 1351static u_int32_t 1352net_mask(in) /* XXX - should really use system's version of this */ 1353 struct in_addr in; 1354{ 1355 register u_int32_t i = ntohl(in.s_addr); 1356 1357 if (IN_CLASSA(i)) 1358 return (htonl(IN_CLASSA_NET)); 1359 else if (IN_CLASSB(i)) 1360 return (htonl(IN_CLASSB_NET)); 1361 return (htonl(IN_CLASSC_NET)); 1362} 1363#endif 1364 1365u_int 1366res_randomid(void) 1367{ 1368#ifdef __APPLE__ 1369 return arc4random(); 1370#else 1371 struct timeval now; 1372 gettimeofday(&now, NULL); 1373 return (0xffff & (now.tv_sec ^ now.tv_usec ^ getpid())); 1374#endif 1375} 1376 1377/* 1378 * This routine is for closing the socket if a virtual circuit is used and 1379 * the program wants to close it. This provides support for endhostent() 1380 * which expects to close the socket. 1381 * 1382 * This routine is not expected to be user visible. 1383 */ 1384void 1385res_nclose(res_state statp) 1386{ 1387 int ns; 1388 1389 if (statp->_vcsock >= 0) 1390 { 1391 close(statp->_vcsock); 1392 statp->_vcsock = -1; 1393 statp->_flags &= ~(RES_F_VC | RES_F_CONN); 1394 } 1395 1396 if (statp->_pad >= 9) 1397 { 1398 for (ns = 0; ns < statp->_u._ext.nscount; ns++) 1399 { 1400 if (statp->_u._ext.nssocks[ns] != -1) 1401 { 1402 close(statp->_u._ext.nssocks[ns]); 1403 statp->_u._ext.nssocks[ns] = -1; 1404 } 1405 } 1406 } 1407} 1408 1409void 1410res_ndestroy(res_state statp) 1411{ 1412 res_nclose(statp); 1413 statp->options &= ~RES_INIT; 1414 1415 /* 1416 * _pad (normally unused) is a version number. 1417 * We use it to prevent BIND_9 from trashing memory 1418 * if statp was created by BIND-8. 1419 */ 1420 if (statp->_pad >= 9) 1421 { 1422 if (statp->_u._ext.ext != NULL) free(statp->_u._ext.ext); 1423 statp->_u._ext.ext = NULL; 1424 statp->_pad = 9; 1425 } 1426} 1427 1428const char * 1429res_get_nibblesuffix(res_state statp) { 1430 if (statp->_u._ext.ext) 1431 return (statp->_u._ext.ext->nsuffix); 1432 return ("ip6.arpa"); 1433} 1434 1435const char * 1436res_get_nibblesuffix2(res_state statp) { 1437 if (statp->_u._ext.ext) 1438 return (statp->_u._ext.ext->nsuffix2); 1439 return ("ip6.int"); 1440} 1441 1442const char * 1443res_get_bitstringsuffix(res_state statp) { 1444 if (statp->_u._ext.ext) 1445 return (statp->_u._ext.ext->bsuffix); 1446 return ("ip6.arpa"); 1447} 1448 1449void 1450res_setservers(res_state statp, const union res_sockaddr_union *set, int cnt) { 1451 int i, nserv; 1452 size_t size; 1453 1454 /* close open servers */ 1455 res_nclose(statp); 1456 1457 /* cause rtt times to be forgotten */ 1458 statp->_u._ext.nscount = 0; 1459 1460 nserv = 0; 1461 for (i = 0; i < cnt && nserv < MAXNS; i++) { 1462 switch (set->sin.sin_family) { 1463 case AF_INET: 1464 size = sizeof(set->sin); 1465 if (statp->_u._ext.ext) 1466 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], 1467 &set->sin, size); 1468 if (size <= sizeof(statp->nsaddr_list[nserv])) 1469 memcpy(&statp->nsaddr_list[nserv], 1470 &set->sin, size); 1471 else 1472 statp->nsaddr_list[nserv].sin_family = 0; 1473 nserv++; 1474 break; 1475 1476 case AF_INET6: 1477 size = sizeof(set->sin6); 1478 if (statp->_u._ext.ext) 1479 memcpy(&statp->_u._ext.ext->nsaddrs[nserv], 1480 &set->sin6, size); 1481 if (size <= sizeof(statp->nsaddr_list[nserv])) 1482 memcpy(&statp->nsaddr_list[nserv], 1483 &set->sin6, size); 1484 else 1485 statp->nsaddr_list[nserv].sin_family = 0; 1486 nserv++; 1487 break; 1488 1489 default: 1490 break; 1491 } 1492 set++; 1493 } 1494 1495 statp->nscount = nserv; 1496} 1497 1498int 1499res_getservers(res_state statp, union res_sockaddr_union *set, int cnt) { 1500 int i; 1501 size_t size; 1502 u_int16_t family; 1503 1504 for (i = 0; i < statp->nscount && i < cnt; i++) { 1505 if (statp->_u._ext.ext) 1506 family = statp->_u._ext.ext->nsaddrs[i].sin.sin_family; 1507 else 1508 family = statp->nsaddr_list[i].sin_family; 1509 1510 switch (family) { 1511 case AF_INET: 1512 size = sizeof(set->sin); 1513 if (statp->_u._ext.ext) 1514 memcpy(&set->sin, 1515 &statp->_u._ext.ext->nsaddrs[i], 1516 size); 1517 else 1518 memcpy(&set->sin, &statp->nsaddr_list[i], 1519 size); 1520 break; 1521 1522 case AF_INET6: 1523 size = sizeof(set->sin6); 1524 if (statp->_u._ext.ext) 1525 memcpy(&set->sin6, 1526 &statp->_u._ext.ext->nsaddrs[i], 1527 size); 1528 else 1529 memcpy(&set->sin6, &statp->nsaddr_list[i], 1530 size); 1531 break; 1532 1533 default: 1534 set->sin.sin_family = 0; 1535 break; 1536 } 1537 set++; 1538 } 1539 return (statp->nscount); 1540} 1541