1/* 2 * Copyright (c) 1999-2007 Apple Inc. All rights reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24#include "dns.h" 25#include <stdio.h> 26#include <stdlib.h> 27#include <string.h> 28#include <unistd.h> 29#include <time.h> 30#include <netdb.h> 31#include <stdarg.h> 32#include <sys/stat.h> 33#include <sys/dir.h> 34#include <errno.h> 35#include <ifaddrs.h> 36#include <net/if.h> 37#include <pthread.h> 38#include <netinet/in.h> 39#include <arpa/nameser.h> 40#include <resolv.h> 41#include <fcntl.h> 42#include <notify.h> 43#include <dnsinfo.h> 44#include "dns_private.h" 45#include "res_private.h" 46 47#define INET_NTOP_AF_INET_OFFSET 4 48#define INET_NTOP_AF_INET6_OFFSET 8 49 50#define SEARCH_COUNT_INIT -1 51 52#define DNS_RESOLVER_DIR "/etc/resolver" 53 54#define NOTIFY_DNS_CONTROL_NAME "com.apple.system.dns" 55#define DNS_CONTROL_FLAG_DEBUG 0x0000000000000001LL 56#define DNS_CONTROL_FLAG_NO_MDNS 0x0000000000000002LL 57 58#define NOTIFY_DIR_NAME "com.apple.system.dns.resolver.dir" 59#define DNS_DELAY_NAME "com.apple.system.dns.delay" 60 61#define DNS_DELAY_INTERVAL 4 62 63#define DNS_PRIVATE_HANDLE_TYPE_SUPER 0 64#define DNS_PRIVATE_HANDLE_TYPE_PLAIN 1 65 66#define MDNS_MIN_TTL 2 67 68static int dns_control_token = -1; 69static int dns_control_mdns = 1; 70static int dns_control_debug = 0; 71static pthread_mutex_t dns_control_lock = PTHREAD_MUTEX_INITIALIZER; 72 73extern uint32_t notify_monitor_file(int token, const char *name, int flags); 74 75extern void res_client_close(res_state res); 76extern res_state res_state_new(); 77extern int res_nquery_soa_min(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, int *fromlen, int *min); 78extern int res_nsearch_2(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, uint32_t *fromlen); 79extern int __res_nsearch_list_2(res_state statp, const char *name, int class, int type, u_char *answer, int anslen, struct sockaddr *from, uint32_t *fromlen, int nsearch, char **search); 80 81extern char *res_next_word(char **p); 82extern res_state res_build_start(res_state res); 83extern int res_build(res_state res, uint16_t port, uint32_t *nsrch, char *key, char *val); 84extern int res_build_sortlist(res_state res, struct in_addr addr, struct in_addr mask); 85 86static void 87_pdns_set_name(pdns_handle_t *pdns, const char *name) 88{ 89 int n; 90 91 if (pdns == NULL) return; 92 if (name == NULL) return; 93 94 /* only set the name once */ 95 if (pdns->name != NULL) return; 96 97 /* strip trailing dots */ 98 n = strlen(name) - 1; 99 while ((n >= 0) && (name[n] == '.')) n--; 100 101 if (n < 0) return; 102 103 n++; 104 pdns->name = calloc(n + 1, sizeof(char)); 105 if (pdns->name == NULL) return; 106 memcpy(pdns->name, name, n); 107} 108 109static pdns_handle_t * 110_pdns_build_start(char *name) 111{ 112 pdns_handle_t *pdns; 113 114 pdns = (pdns_handle_t *)calloc(1, sizeof(pdns_handle_t)); 115 if (pdns == NULL) return NULL; 116 117 pdns->res = res_build_start(NULL); 118 if (pdns->res == NULL) 119 { 120 free(pdns); 121 return NULL; 122 } 123 124 _pdns_set_name(pdns, name); 125 pdns->port = NS_DEFAULTPORT; 126 127 return pdns; 128} 129 130static int 131_pdns_build_finish(pdns_handle_t *pdns) 132{ 133 uint32_t n; 134 135 if (pdns == NULL) return -1; 136 137 n = pdns->res->nscount; 138 if (n == 0) n = 1; 139 140 if (pdns->total_timeout == 0) 141 { 142 if (pdns->send_timeout == 0) pdns->total_timeout = RES_MAXRETRANS; 143 else pdns->total_timeout = pdns->send_timeout * pdns->res->retry * n; 144 } 145 146 if (pdns->total_timeout == 0) pdns->res->retrans = RES_MAXRETRANS; 147 else pdns->res->retrans = pdns->total_timeout; 148 149 pdns->res->options |= RES_INIT; 150 151 return 0; 152} 153 154static int 155_pdns_build_sortlist(pdns_handle_t *pdns, struct in_addr addr, struct in_addr mask) 156{ 157 if (pdns == NULL) return -1; 158 return res_build_sortlist(pdns->res, addr, mask); 159} 160 161static void 162_pdns_free(pdns_handle_t *pdns) 163{ 164 int i; 165 166 if (pdns == NULL) return; 167 168 if ((pdns->search_count != SEARCH_COUNT_INIT) && (pdns->search_count > 0) && (pdns->search_list != NULL)) 169 { 170 for (i = 0; i < pdns->search_count; i++) free(pdns->search_list[i]); 171 free(pdns->search_list); 172 } 173 174 if (pdns->name != NULL) free(pdns->name); 175 if (pdns->res != NULL) res_client_close(pdns->res); 176 177 free(pdns); 178} 179 180static int 181_pdns_build(pdns_handle_t *pdns, char *key, char *val) 182{ 183 struct in6_addr addr6; 184 int32_t status; 185 char *dupval; 186 187 if (pdns == NULL) return -1; 188 189 /* 190 * Detect IPv6 server addresses. 191 */ 192 if (((pdns->flags & DNS_FLAG_HAVE_IPV6_SERVER) == 0) && (!strcmp(key, "nameserver"))) 193 { 194 memset(&addr6, 0, sizeof(struct in6_addr)); 195 status = inet_pton(AF_INET6, val, &addr6); 196 if (status == 1) pdns->flags |= DNS_FLAG_HAVE_IPV6_SERVER; 197 } 198 199 /* 200 * We handle some keys here. 201 * Other keys get passed on to res_build. 202 */ 203 if (!strcmp(key, "default")) 204 { 205 pdns->flags |= DNS_FLAG_DEFAULT_RESOLVER; 206 return 0; 207 } 208 209 if (!strcmp(key, "port")) 210 { 211 pdns->port = atoi(val); 212 return 0; 213 } 214 215 if (!strcmp(key, "search")) 216 { 217 dupval = strdup(val); 218 if (dupval == NULL) return -1; 219 220 if (pdns->search_count == SEARCH_COUNT_INIT) pdns->search_count = 0; 221 if (pdns->search_count == 0) 222 { 223 pdns->search_list = (char **)calloc(1, sizeof(char *)); 224 } 225 else 226 { 227 pdns->search_list = (char **)reallocf(pdns->search_list, (pdns->search_count + 1) * sizeof(char *)); 228 } 229 230 if (pdns->search_list == NULL) 231 { 232 free(dupval); 233 _pdns_free(pdns); 234 return -1; 235 } 236 237 pdns->search_list[pdns->search_count] = dupval; 238 pdns->search_count++; 239 return 0; 240 } 241 242 if (!strcmp(key, "total_timeout")) 243 { 244 pdns->total_timeout = atoi(val); 245 return 0; 246 } 247 248 if (!strcmp(key, "timeout")) 249 { 250 pdns->send_timeout = atoi(val); 251 return 0; 252 } 253 254 if (!strcmp(key, "search_order")) 255 { 256 pdns->search_order = atoi(val); 257 return 0; 258 } 259 260 if (!strcmp(key, "pdns")) 261 { 262 pdns->flags |= DNS_FLAG_FORWARD_TO_MDNSRESPONDER; 263 return 0; 264 } 265 266 if (!strcmp(key, "mdns")) 267 { 268 pdns->flags |= DNS_FLAG_FORWARD_TO_MDNSRESPONDER; 269 return 0; 270 } 271 272 /* pass on to res_build */ 273 return res_build(pdns->res, pdns->port, &(pdns->search_count), key, val); 274} 275 276static pdns_handle_t * 277_pdns_convert_sc(dns_resolver_t *r) 278{ 279 pdns_handle_t *pdns; 280 char *val, *p, *x; 281 int i; 282 283 pdns = _pdns_build_start(r->domain); 284 if (r->domain == NULL) _pdns_build(pdns, "default", NULL); 285 286 p = getenv("RES_RETRY_TIMEOUT"); 287 if (p != NULL) pdns->send_timeout = atoi(p); 288 289 p = getenv("RES_RETRY"); 290 if (p != NULL) pdns->res->retry= atoi(p); 291 292 if (r->port != 0) 293 { 294 val = NULL; 295 asprintf(&val, "%hu", r->port); 296 if (val == NULL) 297 { 298 _pdns_free(pdns); 299 return NULL; 300 } 301 302 _pdns_build(pdns, "port", val); 303 free(val); 304 } 305 306 if (r->n_nameserver > MAXNS) r->n_nameserver = MAXNS; 307 for (i = 0; i < r->n_nameserver; i++) 308 { 309 if (r->nameserver[i]->sa_family == AF_INET) 310 { 311 val = calloc(1, 256); 312 if (val == NULL) 313 { 314 _pdns_free(pdns); 315 return NULL; 316 } 317 318 inet_ntop(AF_INET, (char *)(r->nameserver[i]) + INET_NTOP_AF_INET_OFFSET, val, 256); 319 _pdns_build(pdns, "nameserver", val); 320 free(val); 321 } 322 else if (r->nameserver[i]->sa_family == AF_INET6) 323 { 324 pdns->flags |= DNS_FLAG_HAVE_IPV6_SERVER; 325 val = calloc(1, 256); 326 if (val == NULL) 327 { 328 _pdns_free(pdns); 329 return NULL; 330 } 331 332 inet_ntop(AF_INET6, (char *)(r->nameserver[i]) + INET_NTOP_AF_INET6_OFFSET, val, 256); 333 _pdns_build(pdns, "nameserver", val); 334 free(val); 335 } 336 } 337 338 if (r->n_search > MAXDNSRCH) r->n_search = MAXDNSRCH; 339 for (i = 0; i < r->n_search; i++) 340 { 341 val = NULL; 342 asprintf(&val, "%s", r->search[i]); 343 if (val == NULL) 344 { 345 _pdns_free(pdns); 346 return NULL; 347 } 348 349 _pdns_build(pdns, "search", val); 350 free(val); 351 } 352 353 if (r->timeout > 0) 354 { 355 val = NULL; 356 asprintf(&val, "%d", r->timeout); 357 if (val == NULL) 358 { 359 _pdns_free(pdns); 360 return NULL; 361 } 362 363 _pdns_build(pdns, "total_timeout", val); 364 free(val); 365 } 366 367 val = NULL; 368 asprintf(&val, "%d", r->search_order); 369 if (val == NULL) 370 { 371 _pdns_free(pdns); 372 return NULL; 373 } 374 375 _pdns_build(pdns, "search_order", val); 376 free(val); 377 378 if (r->n_sortaddr > MAXRESOLVSORT) r->n_sortaddr = MAXRESOLVSORT; 379 for (i = 0; i < r->n_sortaddr; i++) 380 { 381 _pdns_build_sortlist(pdns, r->sortaddr[i]->address, r->sortaddr[i]->mask); 382 } 383 384 p = r->options; 385 while (NULL != (x = res_next_word(&p))) 386 { 387 /* search for and process individual options */ 388 if (!strncmp(x, "ndots:", 6)) 389 { 390 _pdns_build(pdns, "ndots", x+6); 391 } 392 393 else if (!strncmp(x, "nibble:", 7)) 394 { 395 _pdns_build(pdns, "nibble", x+7); 396 } 397 398 else if (!strncmp(x, "nibble2:", 8)) 399 { 400 _pdns_build(pdns, "nibble2", x+8); 401 } 402 403 else if (!strncmp(x, "timeout:", 8)) 404 { 405 _pdns_build(pdns, "timeout", x+8); 406 } 407 408 else if (!strncmp(x, "attempts:", 9)) 409 { 410 _pdns_build(pdns, "attempts", x+9); 411 } 412 413 else if (!strncmp(x, "bitstring:", 10)) 414 { 415 _pdns_build(pdns, "bitstring", x+10); 416 } 417 418 else if (!strncmp(x, "v6revmode:", 10)) 419 { 420 _pdns_build(pdns, "v6revmode", x+10); 421 } 422 423 else if (!strcmp(x, "debug")) 424 { 425 _pdns_build(pdns, "debug", NULL); 426 } 427 428 else if (!strcmp(x, "no_tld_query")) 429 { 430 _pdns_build(pdns, "no_tld_query", NULL); 431 } 432 433 else if (!strcmp(x, "inet6")) 434 { 435 _pdns_build(pdns, "inet6", NULL); 436 } 437 438 else if (!strcmp(x, "rotate")) 439 { 440 _pdns_build(pdns, "rotate", NULL); 441 } 442 443 else if (!strcmp(x, "no-check-names")) 444 { 445 _pdns_build(pdns, "no-check-names", NULL); 446 } 447 448#ifdef RES_USE_EDNS0 449 else if (!strcmp(x, "edns0")) 450 { 451 _pdns_build(pdns, "edns0", NULL); 452 } 453#endif 454 else if (!strcmp(x, "a6")) 455 { 456 _pdns_build(pdns, "a6", NULL); 457 } 458 459 else if (!strcmp(x, "dname")) 460 { 461 _pdns_build(pdns, "dname", NULL); 462 } 463 464 else if (!strcmp(x, "default")) 465 { 466 _pdns_build(pdns, "default", NULL); 467 } 468 469 else if (!strcmp(x, "pdns")) 470 { 471 _pdns_build(pdns, "pdns", NULL); 472 } 473 474 else if (!strcmp(x, "mdns")) 475 { 476 _pdns_build(pdns, "mdns", NULL); 477 } 478 } 479 480 _pdns_build_finish(pdns); 481 return pdns; 482} 483 484static pdns_handle_t * 485_mdns_primary(dns_resolver_t *r) 486{ 487 pdns_handle_t *pdns; 488 char *val, *p; 489 int i; 490 491 pdns = _pdns_build_start(r->domain); 492 if (r->domain == NULL) _pdns_build(pdns, "default", NULL); 493 494 p = getenv("RES_RETRY_TIMEOUT"); 495 if (p != NULL) pdns->send_timeout = atoi(p); 496 497 p = getenv("RES_RETRY"); 498 if (p != NULL) pdns->res->retry= atoi(p); 499 500 if (r->n_search > MAXDNSRCH) r->n_search = MAXDNSRCH; 501 for (i = 0; i < r->n_search; i++) 502 { 503 val = NULL; 504 asprintf(&val, "%s", r->search[i]); 505 if (val == NULL) 506 { 507 _pdns_free(pdns); 508 return NULL; 509 } 510 511 _pdns_build(pdns, "search", val); 512 free(val); 513 } 514 515 _pdns_build(pdns, "mdns", NULL); 516 517 _pdns_build_finish(pdns); 518 return pdns; 519} 520 521/* 522 * Open a named resolver client from the system config data. 523 */ 524static pdns_handle_t * 525_pdns_sc_open(const char *name) 526{ 527 pdns_handle_t *pdns; 528 int i; 529 dns_config_t *sc_dns; 530 dns_resolver_t *sc_res; 531 532 sc_dns = dns_configuration_copy(); 533 if (sc_dns == NULL) return NULL; 534 535 sc_res = NULL; 536 537 if (name == NULL) 538 { 539 if (sc_dns->n_resolver != 0) sc_res = sc_dns->resolver[0]; 540 } 541 else 542 { 543 for (i = 0; (sc_res == NULL) && (i < sc_dns->n_resolver); i++) 544 { 545 if (sc_dns->resolver[i] == NULL) continue; 546 if (sc_dns->resolver[i]->domain == NULL) continue; 547 if (!strcasecmp(name, sc_dns->resolver[i]->domain)) sc_res = sc_dns->resolver[i]; 548 } 549 } 550 551 if (sc_res == NULL) 552 { 553 dns_configuration_free(sc_dns); 554 return NULL; 555 } 556 557 pdns = (pdns_handle_t *)calloc(1, sizeof(pdns_handle_t)); 558 if (pdns == NULL) 559 { 560 dns_configuration_free(sc_dns); 561 return NULL; 562 } 563 564 pdns = _pdns_convert_sc(sc_res); 565 566 dns_configuration_free(sc_dns); 567 568 if (pdns == NULL) return NULL; 569 570 if (pdns->res == NULL) 571 { 572 free(pdns); 573 return NULL; 574 } 575 576 pdns->name = NULL; 577 if (pdns->res->defdname[0] != '\0') _pdns_set_name(pdns, pdns->res->defdname); 578 else if (name != NULL) _pdns_set_name(pdns, name); 579 580 if (name != NULL) pdns->search_count = SEARCH_COUNT_INIT; 581 582 return pdns; 583} 584 585/* 586 * Open a named resolver client from file. 587 */ 588static pdns_handle_t * 589_pdns_file_open(const char *name) 590{ 591 pdns_handle_t *pdns; 592 char *path, buf[1024]; 593 char *p, *x, *y; 594 FILE *fp; 595 596 path = NULL; 597 if (name == NULL) 598 { 599 asprintf(&path, "%s", _PATH_RESCONF); 600 } 601 else if ((name[0] == '.') || (name[0] == '/')) 602 { 603 asprintf(&path, "%s", name); 604 } 605 else 606 { 607 asprintf(&path, "%s/%s", DNS_RESOLVER_DIR, name); 608 } 609 610 if (path == NULL) return NULL; 611 612 fp = fopen(path, "r"); 613 free(path); 614 if (fp == NULL) return NULL; 615 616 pdns = _pdns_build_start(NULL); 617 if (pdns == NULL) 618 { 619 fclose(fp); 620 return NULL; 621 } 622 623 p = getenv("RES_RETRY_TIMEOUT"); 624 if (p != NULL) pdns->send_timeout = atoi(p); 625 626 p = getenv("RES_RETRY"); 627 if (p != NULL) pdns->res->retry= atoi(p); 628 629 while (fgets(buf, sizeof(buf), fp) != NULL) 630 { 631 /* skip comments */ 632 if ((buf[0] == ';') || (buf[0] == '#')) continue; 633 p = buf; 634 x = res_next_word(&p); 635 if (x == NULL) continue; 636 if (!strcmp(x, "sortlist")) 637 { 638 while (NULL != (x = res_next_word(&p))) 639 { 640 _pdns_build(pdns, "sortlist", x); 641 } 642 } 643 else if (!strcmp(x, "timeout")) 644 { 645 x = res_next_word(&p); 646 if (x != NULL) _pdns_build(pdns, "total_timeout", x); 647 } 648 else if (!strcmp(x, "options")) 649 { 650 while (NULL != (x = res_next_word(&p))) 651 { 652 y = strchr(x, ':'); 653 if (y != NULL) 654 { 655 *y = '\0'; 656 y++; 657 } 658 _pdns_build(pdns, x, y); 659 } 660 } 661 else 662 { 663 y = res_next_word(&p); 664 _pdns_build(pdns, x, y); 665 666 if ((!strcmp(x, "domain")) && (pdns->name == NULL)) _pdns_set_name(pdns, y); 667 } 668 } 669 670 fclose(fp); 671 672 if (pdns->name == NULL) _pdns_set_name(pdns, name); 673 674 _pdns_build_finish(pdns); 675 676 return pdns; 677} 678 679/* 680 * If there was no search list, use domain name and parent domain components. 681 * 682 * N.B. This code deals with multiple trailing dots, but does not deal with 683 * multiple internal dots, e.g. "foo.....com". 684 */ 685static void 686_pdns_check_search_list(pdns_handle_t *pdns) 687{ 688 int n; 689 char *p; 690 691 if (pdns == NULL) return; 692 if (pdns->name == NULL) return; 693 if (pdns->search_count > 0) return; 694 695 /* Count dots */ 696 n = 0; 697 for (p = pdns->name; *p != '\0'; p++) 698 { 699 if (*p == '.') n++; 700 } 701 702 /* Back up over any trailing dots and cut them out of the name */ 703 for (p--; (p >= pdns->name) && (*p == '.'); p--) 704 { 705 *p = '\0'; 706 n--; 707 } 708 709 /* This will be true if name was all dots */ 710 if (p < pdns->name) return; 711 712 /* dots are separators, so number of components is one larger */ 713 n++; 714 715 _pdns_build(pdns, "search", pdns->name); 716 717 /* Include parent domains with at least LOCALDOMAINPARTS components */ 718 p = pdns->name; 719 while (n > LOCALDOMAINPARTS) 720 { 721 /* Find next component */ 722 while ((*p != '.') && (*p != '\0')) p++; 723 if (*p == '\0') break; 724 p++; 725 726 n--; 727 _pdns_build(pdns, "search", p); 728 } 729} 730 731__private_extern__ void 732_check_cache(sdns_handle_t *sdns) 733{ 734 int i, n, status, refresh, sc_dns_count; 735 DIR *dp; 736 struct direct *d; 737 pdns_handle_t *c; 738 dns_config_t *sc_dns; 739 740 if (sdns == NULL) return; 741 742 refresh = 0; 743 744 if (sdns->stattime == 0) refresh = 1; 745 746 if (refresh == 0) 747 { 748 if (sdns->notify_sys_config_token == -1) refresh = 1; 749 else 750 { 751 n = 1; 752 status = notify_check(sdns->notify_sys_config_token, &n); 753 if ((status != NOTIFY_STATUS_OK) || (n == 1)) refresh = 1; 754 } 755 } 756 757 if (refresh == 0) 758 { 759 if (sdns->notify_dir_token == -1) refresh = 1; 760 else 761 { 762 n = 1; 763 status = notify_check(sdns->notify_dir_token, &n); 764 if ((status != NOTIFY_STATUS_OK) || (n == 1)) refresh = 1; 765 } 766 } 767 768 if (refresh == 0) return; 769 770 /* Free old clients */ 771 sdns->pdns_primary = NULL; 772 773 for (i = 0; i < sdns->client_count; i++) 774 { 775 _pdns_free(sdns->client[i]); 776 } 777 778 sdns->client_count = 0; 779 if (sdns->client != NULL) free(sdns->client); 780 sdns->client = NULL; 781 782 /* Fetch clients from System Configuration */ 783 sc_dns = dns_configuration_copy(); 784 785 /* Set up Primary resolver. It's the one we consult for a search list */ 786 sc_dns_count = 0; 787 if ((sc_dns != NULL) && (sc_dns->n_resolver > 0)) 788 { 789 if (sdns->flags & DNS_FLAG_FORWARD_TO_MDNSRESPONDER) 790 { 791 sc_dns_count = 1; 792 sdns->pdns_primary = _mdns_primary(sc_dns->resolver[0]); 793 } 794 else 795 { 796 sc_dns_count = sc_dns->n_resolver; 797 sdns->pdns_primary = _pdns_convert_sc(sc_dns->resolver[0]); 798 } 799 800 _pdns_check_search_list(sdns->pdns_primary); 801 } 802 else 803 { 804 sdns->pdns_primary = _pdns_file_open(_PATH_RESCONF); 805 } 806 807 if (sdns->pdns_primary != NULL) 808 { 809 if ((sdns->flags & DNS_FLAG_DEBUG) && (sdns->pdns_primary->res != NULL)) sdns->pdns_primary->res->options |= RES_DEBUG; 810 if (sdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA) sdns->pdns_primary->flags |= DNS_FLAG_OK_TO_SKIP_AAAA; 811 sdns->pdns_primary->flags |= DNS_FLAG_DEFAULT_RESOLVER; 812 813 sdns->client = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *)); 814 if (sdns->client == NULL) 815 { 816 if (sc_dns != NULL) dns_configuration_free(sc_dns); 817 return; 818 } 819 820 sdns->client[sdns->client_count] = sdns->pdns_primary; 821 sdns->client_count++; 822 } 823 824 /* Convert System Configuration resolvers */ 825 for (i = 1; i < sc_dns_count; i++) 826 { 827 c = _pdns_convert_sc(sc_dns->resolver[i]); 828 if (c == NULL) continue; 829 830 if (sdns->flags & DNS_FLAG_DEBUG) c->res->options |= RES_DEBUG; 831 if (sdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA) c->flags |= DNS_FLAG_OK_TO_SKIP_AAAA; 832 833 if (sdns->client_count == 0) 834 { 835 sdns->client = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *)); 836 } 837 else 838 { 839 sdns->client = (pdns_handle_t **)reallocf(sdns->client, (sdns->client_count + 1) * sizeof(pdns_handle_t *)); 840 } 841 842 if (sdns->client == NULL) 843 { 844 sdns->client_count = 0; 845 dns_configuration_free(sc_dns); 846 return; 847 } 848 849 sdns->client[sdns->client_count] = c; 850 sdns->client_count++; 851 } 852 853 if (sc_dns != NULL) dns_configuration_free(sc_dns); 854 855 if (sdns->flags & DNS_FLAG_CHECK_RESOLVER_DIR) 856 { 857 /* Read /etc/resolvers clients */ 858 dp = opendir(DNS_RESOLVER_DIR); 859 if (dp == NULL) 860 { 861 sdns->flags &= ~DNS_FLAG_CHECK_RESOLVER_DIR; 862 } 863 else 864 { 865 while (NULL != (d = readdir(dp))) 866 { 867 if (d->d_name[0] == '.') continue; 868 869 c = _pdns_file_open(d->d_name); 870 if (c == NULL) continue; 871 if (sdns->flags & DNS_FLAG_DEBUG) c->res->options |= RES_DEBUG; 872 if (sdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA) c->flags |= DNS_FLAG_OK_TO_SKIP_AAAA; 873 874 if (sdns->client_count == 0) 875 { 876 sdns->client = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *)); 877 } 878 else 879 { 880 sdns->client = (pdns_handle_t **)reallocf(sdns->client, (sdns->client_count + 1) * sizeof(pdns_handle_t *)); 881 } 882 883 if (sdns->client == NULL) 884 { 885 sdns->client_count = 0; 886 return; 887 } 888 889 sdns->client[sdns->client_count] = c; 890 sdns->client_count++; 891 } 892 closedir(dp); 893 } 894 } 895 896 sdns->stattime = 1; 897} 898 899static uint32_t 900_pdns_get_default_handles(sdns_handle_t *sdns, pdns_handle_t ***pdns) 901{ 902 int i, j, k, count; 903 904 if (sdns == NULL) return 0; 905 if (pdns == NULL) return 0; 906 907 count = 0; 908 909 for (i = 0; i < sdns->client_count; i++) 910 { 911 if (sdns->client[i]->flags & DNS_FLAG_DEFAULT_RESOLVER) 912 { 913 if (count == 0) 914 { 915 *pdns = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *)); 916 } 917 else 918 { 919 *pdns = (pdns_handle_t **)reallocf((*pdns), (count + 1) * sizeof(pdns_handle_t *)); 920 } 921 922 if (*pdns == NULL) return 0; 923 924 /* Insert sorted by search_order */ 925 for (j = 0; j < count; j++) 926 { 927 if (sdns->client[i]->search_order < (*pdns)[j]->search_order) break; 928 } 929 930 for (k = count; k > j; k--) (*pdns)[k] = (*pdns)[k-1]; 931 (*pdns)[j] = sdns->client[i]; 932 count++; 933 } 934 } 935 936 return count; 937} 938 939static uint32_t 940_pdns_get_handles_for_name(sdns_handle_t *sdns, const char *name, pdns_handle_t ***pdns) 941{ 942 char *p, *vname; 943 int i, j, k, count; 944 945 if (sdns == NULL) return 0; 946 if (pdns == NULL) return 0; 947 948 if (name == NULL) return _pdns_get_default_handles(sdns, pdns); 949 else if (name[0] == '\0') return _pdns_get_default_handles(sdns, pdns); 950 951 count = 0; 952 953 vname = strdup(name); 954 i = strlen(vname) - 1; 955 if ((i >= 0) && (vname[i] == '.')) vname[i] = '\0'; 956 957 p = vname; 958 while (p != NULL) 959 { 960 for (i = 0; i < sdns->client_count; i++) 961 { 962 if (sdns->client[i]->name == NULL) continue; 963 964 if (!strcasecmp(sdns->client[i]->name, p)) 965 { 966 if (count == 0) 967 { 968 *pdns = (pdns_handle_t **)calloc(1, sizeof(pdns_handle_t *)); 969 } 970 else 971 { 972 *pdns = (pdns_handle_t **)reallocf((*pdns), (count + 1) * sizeof(pdns_handle_t *)); 973 } 974 975 if (*pdns == NULL) return 0; 976 977 /* Insert sorted by search_order */ 978 for (j = 0; j < count; j++) 979 { 980 if (sdns->client[i]->search_order < (*pdns)[j]->search_order) break; 981 } 982 983 for (k = count; k > j; k--) (*pdns)[k] = (*pdns)[k-1]; 984 (*pdns)[j] = sdns->client[i]; 985 count++; 986 } 987 } 988 989 p = strchr(p, '.'); 990 if (p != NULL) p++; 991 } 992 993 free(vname); 994 995 if (count != 0) return count; 996 997 return _pdns_get_default_handles(sdns, pdns); 998} 999 1000static void 1001_pdns_process_res_search_list(pdns_handle_t *pdns) 1002{ 1003 if (pdns->search_count != SEARCH_COUNT_INIT) return; 1004 for (pdns->search_count = 0; (pdns->res->dnsrch[pdns->search_count] != NULL) && (pdns->res->dnsrch[pdns->search_count][0] != '\0'); pdns->search_count++); 1005} 1006 1007static char * 1008_pdns_search_list_domain(pdns_handle_t *pdns, uint32_t i) 1009{ 1010 char *s; 1011 1012 if (pdns == NULL) return NULL; 1013 if (pdns->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(pdns); 1014 if (i >= pdns->search_count) return NULL; 1015 1016 s = pdns->search_list[i]; 1017 if (s == NULL) return NULL; 1018 return strdup(s); 1019} 1020 1021static void 1022_dns_open_notify(sdns_handle_t *sdns) 1023{ 1024 int status, n; 1025 1026 if (sdns == NULL) return; 1027 1028 if (sdns->notify_delay_token == -1) 1029 { 1030 status = notify_register_check(DNS_DELAY_NAME, &(sdns->notify_delay_token)); 1031 if (status != NOTIFY_STATUS_OK) sdns->notify_delay_token = -1; 1032 else status = notify_check(sdns->notify_delay_token, &n); 1033 } 1034 1035 if (sdns->notify_sys_config_token == -1) 1036 { 1037 status = notify_register_check(dns_configuration_notify_key(), &(sdns->notify_sys_config_token)); 1038 if (status != NOTIFY_STATUS_OK) sdns->notify_sys_config_token = -1; 1039 } 1040 1041 if (sdns->notify_dir_token == -1) 1042 { 1043 status = notify_register_check(NOTIFY_DIR_NAME, &(sdns->notify_dir_token)); 1044 if (status == NOTIFY_STATUS_OK) 1045 { 1046 status = notify_monitor_file(sdns->notify_dir_token, "/private/etc/resolver", 0); 1047 if (status != NOTIFY_STATUS_OK) 1048 { 1049 notify_cancel(sdns->notify_dir_token); 1050 sdns->notify_dir_token = -1; 1051 } 1052 } 1053 else 1054 { 1055 sdns->notify_dir_token = -1; 1056 } 1057 } 1058} 1059 1060static void 1061_dns_close_notify(sdns_handle_t *sdns) 1062{ 1063 if (sdns == NULL) return; 1064 1065 if (sdns->notify_delay_token != -1) notify_cancel(sdns->notify_delay_token); 1066 sdns->notify_delay_token = -1; 1067 1068 if (sdns->notify_sys_config_token != -1) notify_cancel(sdns->notify_sys_config_token); 1069 sdns->notify_sys_config_token = -1; 1070 1071 if (sdns->notify_dir_token != -1) notify_cancel(sdns->notify_dir_token); 1072 sdns->notify_dir_token = -1; 1073} 1074 1075dns_handle_t 1076dns_open(const char *name) 1077{ 1078 dns_private_handle_t *dns; 1079 struct stat sb; 1080 int check, status, local_control; 1081 uint64_t control; 1082 1083 dns = (dns_private_handle_t *)calloc(1, sizeof(dns_private_handle_t)); 1084 if (dns == NULL) return NULL; 1085 1086 /* set up control notification if necessary */ 1087 if (dns_control_token == -1) 1088 { 1089 pthread_mutex_lock(&dns_control_lock); 1090 if (dns_control_token == -1) status = notify_register_check(NOTIFY_DNS_CONTROL_NAME, &dns_control_token); 1091 pthread_mutex_unlock(&dns_control_lock); 1092 } 1093 1094 /* check for dns flags */ 1095 if (dns_control_token != -1) 1096 { 1097 pthread_mutex_lock(&dns_control_lock); 1098 status = notify_check(dns_control_token, &check); 1099 if ((status == 0) && (check == 1)) 1100 { 1101 /* notification was triggered */ 1102 status = notify_get_state(dns_control_token, &control); 1103 if (status == 0) 1104 { 1105 if (control & DNS_CONTROL_FLAG_NO_MDNS) dns_control_mdns = 0; 1106 if (control & DNS_CONTROL_FLAG_DEBUG) dns_control_debug = 1; 1107 } 1108 } 1109 1110 pthread_mutex_unlock(&dns_control_lock); 1111 } 1112 1113 if (name == NULL) local_control = dns_control_mdns; 1114 else if (!strcmp(name, MDNS_HANDLE_NAME)) local_control = 2; 1115 else local_control = 0; 1116 1117 if ((name == NULL) && (local_control == 0)) 1118 { 1119 dns->handle_type = DNS_PRIVATE_HANDLE_TYPE_SUPER; 1120 dns->sdns = (sdns_handle_t *)calloc(1, sizeof(sdns_handle_t)); 1121 if (dns->sdns == NULL) 1122 { 1123 free(dns); 1124 return NULL; 1125 } 1126 1127 dns->sdns->flags |= DNS_FLAG_CHECK_RESOLVER_DIR; 1128 dns->sdns->notify_sys_config_token = -1; 1129 dns->sdns->notify_dir_token = -1; 1130 dns->sdns->notify_delay_token = -1; 1131 _dns_open_notify(dns->sdns); 1132 1133 memset(&sb, 0, sizeof(struct stat)); 1134 dns_set_debug((dns_handle_t)dns, dns_control_debug); 1135 1136 return (dns_handle_t)dns; 1137 } 1138 1139 if (local_control != 0) 1140 { 1141 dns->handle_type = DNS_PRIVATE_HANDLE_TYPE_SUPER; 1142 dns->sdns = (sdns_handle_t *)calloc(1, sizeof(sdns_handle_t)); 1143 if (dns->sdns == NULL) 1144 { 1145 free(dns); 1146 return NULL; 1147 } 1148 1149 dns->sdns->flags = DNS_FLAG_FORWARD_TO_MDNSRESPONDER; 1150 dns->sdns->notify_sys_config_token = -1; 1151 dns->sdns->notify_dir_token = -1; 1152 dns->sdns->notify_delay_token = -1; 1153 if (local_control == 1) _dns_open_notify(dns->sdns); 1154 1155 memset(&sb, 0, sizeof(struct stat)); 1156 dns_set_debug((dns_handle_t)dns, dns_control_debug); 1157 1158 return (dns_handle_t)dns; 1159 } 1160 1161 dns->handle_type = DNS_PRIVATE_HANDLE_TYPE_PLAIN; 1162 1163 /* Look for name in System Configuration first */ 1164 dns->pdns = _pdns_sc_open(name); 1165 if (dns->pdns == NULL) dns->pdns = _pdns_file_open(name); 1166 1167 if (dns->pdns == NULL) 1168 { 1169 free(dns); 1170 return NULL; 1171 } 1172 1173 dns_set_debug((dns_handle_t)dns, dns_control_debug); 1174 return (dns_handle_t)dns; 1175} 1176 1177/* 1178 * Release a DNS client handle 1179 */ 1180void 1181dns_free(dns_handle_t d) 1182{ 1183 dns_private_handle_t *dns; 1184 int i; 1185 1186 if (d == NULL) return; 1187 1188 dns = (dns_private_handle_t *)d; 1189 1190 if (dns->recvbuf != NULL) free(dns->recvbuf); 1191 1192 if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER) 1193 { 1194 if (dns->sdns == NULL) return; 1195 1196 _dns_close_notify(dns->sdns); 1197 1198 for (i = 0; i < dns->sdns->client_count; i++) 1199 { 1200 _pdns_free(dns->sdns->client[i]); 1201 } 1202 1203 dns->sdns->client_count = 0; 1204 if (dns->sdns->client != NULL) free(dns->sdns->client); 1205 1206 free(dns->sdns); 1207 } 1208 else 1209 { 1210 _pdns_free(dns->pdns); 1211 } 1212 1213 free(dns); 1214} 1215 1216static void 1217_pdns_debug(pdns_handle_t *pdns, uint32_t flag) 1218{ 1219 if (pdns == NULL) return; 1220 1221 if (flag == 0) 1222 { 1223 pdns->res->options &= ~RES_DEBUG; 1224 } 1225 else 1226 { 1227 pdns->res->options |= RES_DEBUG; 1228 } 1229} 1230 1231static void 1232_sdns_debug(sdns_handle_t *sdns, uint32_t flag) 1233{ 1234 int i; 1235 1236 if (sdns == NULL) return; 1237 1238 if (flag == 0) 1239 { 1240 sdns->flags &= ~ DNS_FLAG_DEBUG; 1241 1242 for (i = 0; i < sdns->client_count; i++) 1243 { 1244 sdns->client[i]->res->options &= ~RES_DEBUG; 1245 } 1246 } 1247 else 1248 { 1249 sdns->flags |= DNS_FLAG_DEBUG; 1250 1251 for (i = 0; i < sdns->client_count; i++) 1252 { 1253 sdns->client[i]->res->options |= RES_DEBUG; 1254 } 1255 } 1256} 1257 1258/* 1259 * Enable / Disable debugging 1260 */ 1261void 1262dns_set_debug(dns_handle_t d, uint32_t flag) 1263{ 1264 dns_private_handle_t *dns; 1265 1266 if (d == NULL) return; 1267 1268 dns = (dns_private_handle_t *)d; 1269 1270 if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER) 1271 { 1272 _sdns_debug(dns->sdns, flag); 1273 } 1274 else 1275 { 1276 _pdns_debug(dns->pdns, flag); 1277 } 1278} 1279 1280/* 1281 * Returns the number of names in the search list 1282 */ 1283uint32_t 1284dns_search_list_count(dns_handle_t d) 1285{ 1286 dns_private_handle_t *dns; 1287 pdns_handle_t *pdns; 1288 1289 if (d == NULL) return 0; 1290 1291 dns = (dns_private_handle_t *)d; 1292 1293 if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER) 1294 { 1295 _check_cache(dns->sdns); 1296 pdns = dns->sdns->pdns_primary; 1297 } 1298 else 1299 { 1300 pdns = dns->pdns; 1301 } 1302 1303 if (pdns->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(pdns); 1304 return pdns->search_count; 1305} 1306 1307/* 1308 * Returns the domain name at index i in the search list. 1309 * Returns NULL if there are no names in the search list. 1310 * Caller must free the returned name. 1311 */ 1312char * 1313dns_search_list_domain(dns_handle_t d, uint32_t i) 1314{ 1315 dns_private_handle_t *dns; 1316 pdns_handle_t *pdns; 1317 1318 if (d == NULL) return NULL; 1319 1320 dns = (dns_private_handle_t *)d; 1321 1322 if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER) 1323 { 1324 _check_cache(dns->sdns); 1325 pdns = dns->sdns->pdns_primary; 1326 } 1327 else 1328 { 1329 pdns = dns->pdns; 1330 } 1331 1332 return _pdns_search_list_domain(pdns, i); 1333} 1334 1335static int 1336_pdns_delay(sdns_handle_t *sdns) 1337{ 1338 int status, n, snooze; 1339 time_t tick; 1340 1341 if (sdns == NULL) return 0; 1342 1343 snooze = 0; 1344 n = 0; 1345 1346 /* No delay if we are not receiving notifications */ 1347 if (sdns->notify_delay_token == -1) return 0; 1348 1349 if (sdns->dns_delay == 0) 1350 { 1351 status = notify_check(sdns->notify_delay_token, &n); 1352 if ((status == NOTIFY_STATUS_OK) && (n == 1)) 1353 { 1354 /* 1355 * First thread to hit this condition sleeps for DNS_DELAY_INTERVAL seconds 1356 */ 1357 sdns->dns_delay = time(NULL) + DNS_DELAY_INTERVAL; 1358 snooze = DNS_DELAY_INTERVAL; 1359 } 1360 } 1361 else 1362 { 1363 tick = time(NULL); 1364 /* 1365 * Subsequent threads sleep for the remaining duration. 1366 * We add one to round up the interval since our granularity is coarse. 1367 */ 1368 snooze = 1 + (sdns->dns_delay - tick); 1369 if (snooze < 0) snooze = 0; 1370 } 1371 1372 if (snooze == 0) return 0; 1373 1374 sleep(snooze); 1375 1376 /* When exiting, first thread in resets the delay condition */ 1377 if (n == 1) sdns->dns_delay = 0; 1378 1379 return 0; 1380} 1381 1382static int 1383_pdns_query(sdns_handle_t *sdns, pdns_handle_t *pdns, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen, int *min) 1384{ 1385 int n; 1386 1387 if (name == NULL) return -1; 1388 if (pdns == NULL) return -1; 1389 1390 if (pdns->flags & DNS_FLAG_FORWARD_TO_MDNSRESPONDER) 1391 { 1392 n = res_query_mDNSResponder(pdns->res, name, class, type, (u_char *)buf, len, from, fromlen); 1393 if ((n < 0) && (min != NULL)) *min = MDNS_MIN_TTL; 1394 return n; 1395 } 1396 1397 if (pdns->res == NULL) return -1; 1398 if (pdns->res->nscount == 0) return -1; 1399 1400 if ((type == ns_t_aaaa) && ((pdns->flags & DNS_FLAG_HAVE_IPV6_SERVER) == 0) && (pdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA)) return -1; 1401 1402 _pdns_delay(sdns); 1403 1404 /* BIND_9 API */ 1405 return res_nquery_soa_min(pdns->res, name, class, type, (u_char *)buf, len, from, (int32_t *)fromlen, min); 1406} 1407 1408__private_extern__ int 1409_pdns_search(sdns_handle_t *sdns, pdns_handle_t *pdns, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen) 1410{ 1411 char *dot, *qname; 1412 int append, status; 1413 1414 if (name == NULL) return -1; 1415 if (pdns == NULL) return -1; 1416 if (pdns->res == NULL) return -1; 1417 if (pdns->res->nscount == 0) return -1; 1418 1419 if ((type == ns_t_aaaa) && ((pdns->flags & DNS_FLAG_HAVE_IPV6_SERVER) == 0) && (pdns->flags & DNS_FLAG_OK_TO_SKIP_AAAA)) return -1; 1420 1421 qname = NULL; 1422 append = 1; 1423 1424 /* 1425 * don't append my name if: 1426 * - my name is NULL 1427 * - input name is qualified (i.e. not single component) 1428 * - there is a search list 1429 * - there is a domain name 1430 */ 1431 1432 if (pdns->name == NULL) append = 0; 1433 1434 if (append == 1) 1435 { 1436 dot = strrchr(name, '.'); 1437 if (dot != NULL) append = 0; 1438 } 1439 1440 if (append == 1) 1441 { 1442 if (pdns->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(pdns); 1443 if (pdns->search_count > 0) append = 0; 1444 } 1445 1446 if ((append == 1) && (pdns->res->defdname != NULL) && (pdns->res->defdname[0] != '\0')) append = 0; 1447 1448 status = -1; 1449 if (append == 0) 1450 { 1451 /* BIND_9 API */ 1452 _pdns_delay(sdns); 1453 1454 status = __res_nsearch_list_2(pdns->res, name, class, type, (u_char *)buf, len, from, fromlen, pdns->search_count, pdns->search_list); 1455 } 1456 else 1457 { 1458 _pdns_delay(sdns); 1459 1460 qname = NULL; 1461 asprintf(&qname, "%s.%s.", name, pdns->name); 1462 if (qname == NULL) return -1; 1463 1464 /* BIND_9 API */ 1465 status = res_nsearch_2(pdns->res, qname, class, type, (u_char *)buf, len, from, fromlen); 1466 free(qname); 1467 } 1468 1469 return status; 1470} 1471 1472static int 1473_sdns_send(sdns_handle_t *sdns, const char *name, uint32_t class, uint32_t type, uint32_t fqdn, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen, int *min) 1474{ 1475 char *qname; 1476 pdns_handle_t **pdns; 1477 uint32_t pdns_count; 1478 int i, n; 1479 int m, tmin, minstate; 1480 1481 pdns = NULL; 1482 pdns_count = 0; 1483 n = -1; 1484 minstate = 0; 1485 *min = -1; 1486 m = -1; 1487 1488 pdns_count = _pdns_get_handles_for_name(sdns, name, &pdns); 1489 1490 if (pdns_count == 0) return -1; 1491 1492 qname = NULL; 1493 asprintf(&qname, "%s%s", name, (fqdn == 0) ? "." : ""); 1494 if (qname == NULL) return -1; 1495 1496 for (i = 0; i < pdns_count; i++) 1497 { 1498 tmin = -1; 1499 n = _pdns_query(sdns, pdns[i], qname, class, type, buf, len, from, fromlen, &tmin); 1500 if (n <= 0) 1501 { 1502 if (tmin < 0) 1503 { 1504 minstate = -1; 1505 } 1506 else if (minstate == 0) 1507 { 1508 if (m == -1) m = tmin; 1509 else if (tmin < m) m = tmin; 1510 } 1511 } 1512 1513 if (n > 0) break; 1514 } 1515 1516 if (minstate == 0) *min = m; 1517 1518 free(pdns); 1519 free(qname); 1520 return n; 1521} 1522 1523__private_extern__ int 1524_sdns_search(sdns_handle_t *sdns, const char *name, uint32_t class, uint32_t type, uint32_t fqdn, uint32_t recurse, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen, int *min) 1525{ 1526 pdns_handle_t *primary, **pdns; 1527 int i, n, ndots, status; 1528 int m, tmin, minstate; 1529 char *dot, *qname; 1530 uint32_t pdns_count; 1531 1532 if (sdns == NULL) return -1; 1533 if (name == NULL) return -1; 1534 1535 /* 1536 * A minimum TTL derived from the minimim of all SOA records 1537 * that are received with NXDOMAIN or no data is returned to 1538 * the caller if every call returns an NXDOMAIN or no data 1539 * and a SOA min ttl. If any call times out or returns some 1540 * other error, we return "-1" in the "min" out parameter. 1541 * The minstate variable is set to -1 if we must return -1. 1542 */ 1543 minstate = 0; 1544 *min = -1; 1545 1546 /* m is the lowest of all minima. -1 is unset */ 1547 m = -1; 1548 1549 /* ndots is the threshold for trying a qualified name "as is" */ 1550 ndots = 1; 1551 primary = sdns->pdns_primary; 1552 if ((primary != NULL) && (primary->res != NULL)) ndots = primary->res->ndots; 1553 1554 /* count dots in input name, and keep track of the location of the last dot */ 1555 n = 0; 1556 dot = NULL; 1557 1558 for (i = 0; name[i] != '\0'; i++) 1559 { 1560 if (name[i] == '.') 1561 { 1562 n++; 1563 dot = (char *)(name + i); 1564 } 1565 } 1566 1567 /* the last dot is the last character, name is fully qualified */ 1568 if ((fqdn == 0) && (dot != NULL) && (*(dot + 1) == '\0')) fqdn = 1; 1569 1570 /* 1571 * If n >= ndots, or it's a FQDN, or if it's a PTR query, 1572 * we try a query with the name "as is". 1573 */ 1574 if ((n >= ndots) || (fqdn == 1) || (type == ns_t_ptr)) 1575 { 1576 tmin = -1; 1577 status = _sdns_send(sdns, name, class, type, fqdn, buf, len, from, fromlen, &tmin); 1578 if (status > 0) return status; 1579 1580 if (tmin < 0) minstate = -1; 1581 else m = tmin; 1582 } 1583 1584 /* end of the line for FQDNs or PTR queries */ 1585 if ((fqdn == 1) || (type == ns_t_ptr) || (recurse == 0) || (primary == NULL)) 1586 { 1587 if (minstate == 0) *min = m; 1588 return -1; 1589 } 1590 1591 /* Try appending names from the search list */ 1592 if (primary->search_count == SEARCH_COUNT_INIT) _pdns_process_res_search_list(primary); 1593 n = primary->search_count; 1594 if (n > 0) 1595 { 1596 /* Try qualifying with each name in the search list */ 1597 for (i = 0; i < n ; i++) 1598 { 1599 qname = NULL; 1600 asprintf(&qname, "%s.%s", name, primary->search_list[i]); 1601 if (qname == NULL) return -1; 1602 1603 tmin = -1; 1604 status = _sdns_search(sdns, qname, class, type, fqdn, 0, buf, len, from, fromlen, &tmin); 1605 if (status <= 0) 1606 { 1607 if (tmin < 0) 1608 { 1609 minstate = -1; 1610 } 1611 else if (minstate == 0) 1612 { 1613 if (m == -1) m = tmin; 1614 else if (tmin < m) m = tmin; 1615 } 1616 } 1617 1618 free(qname); 1619 if (status > 0) return status; 1620 } 1621 1622 if (minstate == 0) *min = m; 1623 return -1; 1624 } 1625 1626 /* 1627 * We get here if the name is not fully qualified (no trailing dot), and there is no search list. 1628 * Try each default client, qualifying with that client's name. 1629 */ 1630 pdns = NULL; 1631 pdns_count = _pdns_get_default_handles(sdns, &pdns); 1632 status = -1; 1633 1634 if (pdns_count == 0) 1635 { 1636 if (minstate == 0) *min = m; 1637 return -1; 1638 } 1639 1640 for (i = 0; i < pdns_count; i++) 1641 { 1642 qname = NULL; 1643 if (pdns[i]->name == NULL) asprintf(&qname, "%s", name); 1644 else asprintf(&qname, "%s.%s", name, pdns[i]->name); 1645 1646 /* leave *min at -1 in case of a malloc failure */ 1647 if (qname == NULL) return -1; 1648 1649 tmin = -1; 1650 status = _pdns_query(sdns, pdns[i], qname, class, type, buf, len, from, fromlen, &tmin); 1651 if (status <= 0) 1652 { 1653 if (tmin < 0) 1654 { 1655 minstate = -1; 1656 } 1657 else if (minstate == 0) 1658 { 1659 if (m == -1) m = tmin; 1660 else if (tmin < m) m = tmin; 1661 } 1662 } 1663 1664 free(qname); 1665 if (status > 0) break; 1666 } 1667 1668 free(pdns); 1669 1670 if (minstate == 0) *min = m; 1671 return status; 1672} 1673 1674int 1675dns_query(dns_handle_t d, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen) 1676{ 1677 dns_private_handle_t *dns; 1678 int status, unused; 1679 1680 if (d == NULL) return -1; 1681 if (name == NULL) return -1; 1682 dns = (dns_private_handle_t *)d; 1683 1684 status = -1; 1685 unused = 0; 1686 1687 if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER) 1688 { 1689 _check_cache(dns->sdns); 1690 status = _sdns_search(dns->sdns, name, class, type, 1, 1, buf, len, from, fromlen, &unused); 1691 } 1692 else 1693 { 1694 status = _pdns_query(dns->sdns, dns->pdns, name, class, type, buf, len, from, fromlen, &unused); 1695 } 1696 1697 return status; 1698} 1699 1700 1701int 1702dns_search(dns_handle_t d, const char *name, uint32_t class, uint32_t type, char *buf, uint32_t len, struct sockaddr *from, uint32_t *fromlen) 1703{ 1704 dns_private_handle_t *dns; 1705 int status, unused; 1706 1707 if (d == NULL) return -1; 1708 if (name == NULL) return -1; 1709 dns = (dns_private_handle_t *)d; 1710 1711 status = -1; 1712 unused = 0; 1713 1714 if (dns->handle_type == DNS_PRIVATE_HANDLE_TYPE_SUPER) 1715 { 1716 _check_cache(dns->sdns); 1717 status = _sdns_search(dns->sdns, name, class, type, 0, 1, buf, len, from, fromlen, &unused); 1718 } 1719 else 1720 { 1721 status = _pdns_search(dns->sdns, dns->pdns, name, class, type, buf, len, from, fromlen); 1722 } 1723 1724 return status; 1725} 1726 1727/* 1728 * PRIVATE 1729 */ 1730 1731uint32_t 1732dns_server_list_count(dns_handle_t d) 1733{ 1734 dns_private_handle_t *dns; 1735 res_state r; 1736 1737 if (d == NULL) return 0; 1738 dns = (dns_private_handle_t *)d; 1739 1740 if (dns->handle_type != DNS_PRIVATE_HANDLE_TYPE_PLAIN) return 0; 1741 1742 if (dns->pdns == NULL) return 0; 1743 1744 r = dns->pdns->res; 1745 if (r == NULL) return 0; 1746 1747 return r->nscount; 1748} 1749 1750struct sockaddr * 1751dns_server_list_address(dns_handle_t d, uint32_t i) 1752{ 1753 dns_private_handle_t *dns; 1754 res_state r; 1755 struct sockaddr_storage *s; 1756 struct sockaddr *sa; 1757 1758 if (d == NULL) return NULL; 1759 dns = (dns_private_handle_t *)d; 1760 1761 if (dns->handle_type != DNS_PRIVATE_HANDLE_TYPE_PLAIN) return NULL; 1762 1763 if (dns->pdns == NULL) return NULL; 1764 1765 r = dns->pdns->res; 1766 if (r == NULL) return NULL; 1767 1768 if (i >= r->nscount) return NULL; 1769 sa = get_nsaddr(r, i); 1770 if (sa == NULL) return NULL; 1771 1772 s = (struct sockaddr_storage *)calloc(1, sizeof(struct sockaddr_storage)); 1773 if (s == NULL) return NULL; 1774 1775 memcpy(s, sa, sizeof(struct sockaddr_storage)); 1776 return (struct sockaddr *)s; 1777} 1778