1 /* 2 * Copyright (c) 2020-2024 Apple Inc. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * https://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 * This file contains code to let mDNSResponder set up the resolver for 17 * the automatic browsing domain learned from "lb._dns-sd._udp.local PTR" 18 * query. To setup the resolver, it will get the NS record for the domain 19 * and the A/AAAA record for the resolver name in the NS record rdata. 20 * Once it knows about resolver's address, it will set the resolver with 21 * configuration change to let mDNSResponder add it as a regular DNS resolver. 22 */ 23 24 #include "mDNSFeatures.h" // for MDNSRESPONDER_SUPPORTS(COMMON, LOCAL_DNS_RESOLVER_DISCOVERY) 25 26 #if MDNSRESPONDER_SUPPORTS(COMMON, LOCAL_DNS_RESOLVER_DISCOVERY) 27 28 //====================================================================================================================== 29 // MARK: - Headers 30 31 #include <stdio.h> 32 #include <mdns/private.h> 33 #include "mDNSEmbeddedAPI.h" 34 #include "uds_daemon.h" 35 #include "bsd_queue.h" // For SLIST. 36 #include "discover_resolver.h" 37 #include "tls-keychain.h" // For init_tls_cert(). 38 #include "uDNS.h" // For mDNS_StartQuery_internal() and mDNS_StopQuery_internal(). 39 40 41 #include "DNSCommon.h" // For mDNS_Lock() and mDNS_Unlock(). 42 43 // for require_* 44 #if defined(__APPLE__) 45 #include <AssertMacros.h> 46 #elif defined(POSIX_BUILD) 47 #include "DebugServices.h" 48 #else 49 #ifndef require 50 #define require(assertion, exception_label) \ 51 do { \ 52 if (!(assertion)) { \ 53 goto exception_label; \ 54 } \ 55 } while (false) 56 #endif // #ifndef require 57 58 #ifndef require_action 59 #define require_action(assertion, exception_label, action) \ 60 do { \ 61 if (!(assertion)) { \ 62 { \ 63 action; \ 64 } \ 65 goto exception_label; \ 66 } \ 67 } while (false) 68 #endif // #ifndef require_action 69 #endif 70 71 #include "mdns_strict.h" 72 73 //====================================================================================================================== 74 // MARK: - Macros 75 76 // Release macros that are used to do reference counting for the discover_resolver_t object. 77 #define discover_resolver_release(OBJ) \ 78 do { \ 79 (OBJ)->ref_count--; \ 80 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "discover_resolver_t released " \ 81 "- ref count after releasing: %u.", (OBJ)->ref_count); \ 82 if ((OBJ)->ref_count == 0) { \ 83 _MDNS_STRICT_DISPOSE_TEMPLATE((OBJ), (OBJ)->finalizer); \ 84 } \ 85 } while (false) 86 87 #define discover_resolver_forget(PTR) \ 88 do { \ 89 if (*(PTR)) { \ 90 discover_resolver_release(*(PTR)); \ 91 *(PTR) = mDNSNULL; \ 92 } \ 93 } while (mDNSfalse) 94 95 //====================================================================================================================== 96 // MARK: - Structures 97 98 // the addresse of the discovered resolver get by resolving the resolver's name 99 typedef struct resolver_address resolver_address_t; 100 struct resolver_address { 101 mDNSAddr addr; 102 resolver_address_t * NULLABLE next; 103 }; 104 105 // the name of the discovered resolver for the given domain. 106 typedef struct discover_resolver_name discover_resolver_name_t; 107 struct discover_resolver_name { 108 domainname resolver_name; // the discovered resolver name for the given domain 109 mDNSInterfaceID NULLABLE interface_id; // the interface id where the response was received 110 DNSQuestion ipv4_question; // used to query for IPv4 address of the resolver name 111 DNSQuestion ipv6_question; // used to query for IPv6 address of the resolver name 112 113 resolver_address_t * NULLABLE addresses; // linked list of all addresses for the resolver name 114 mDNSs32 next_update_time; // If non-zero, it indicates the next time when we should update the DNS 115 // service that has been previously registered 116 discover_resolver_name_t * NULLABLE next; 117 }; 118 119 // the context of resolver discovery. 120 typedef struct discover_resolver_context discover_resolver_context_t; 121 struct discover_resolver_context { 122 DNSQuestion ns_question; // used to query for the resolver name for the given domain 123 discover_resolver_name_t * NULLABLE resolver_names; // linked list of all resolver names for the given domain 124 }; 125 126 // This object is used by the caller to start or stop the resolver discovery. 127 typedef struct discover_resolver discover_resolver_t; 128 typedef void (* discover_resolver_finalizer_t)(discover_resolver_t * NULLABLE discover_resolver); 129 struct discover_resolver { 130 domainname domain; // The domain that is used to discover the local DNS resolver. 131 mDNSs32 next_stop_time; // If non-zero, indicate when the object should be released. 132 mDNSu32 ref_count; // The reference count. If it is zero, the object will be finalized. 133 mDNSu32 use_count; // The use count that indicates how many clients need this resolver 134 // discovery. 135 136 discover_resolver_context_t * context; // The context. 137 discover_resolver_finalizer_t finalizer; // The finalizer that will be called to invalidate any ongoing 138 // activity and free the memory associated with this object, when 139 // the reference count becomes 0. 140 }; 141 142 // The single-linked node type that contains discover_resolver_t. 143 typedef struct discover_resolver_node discover_resolver_node_t; 144 struct discover_resolver_node { 145 SLIST_ENTRY(discover_resolver_node) __entries; 146 discover_resolver_t * NULLABLE discover_resolver; 147 }; 148 149 // The single-linked list that contains multiple discover_resolver_t objects. 150 typedef struct discover_resolver_slist discover_resolver_slist_t; 151 SLIST_HEAD(discover_resolver_slist, discover_resolver_node); 152 153 //====================================================================================================================== 154 // MARK: - Globals 155 156 extern mDNS mDNSStorage; 157 static discover_resolver_slist_t * g_discover_resolvers = NULL; 158 159 //====================================================================================================================== 160 // MARK: - Forward Declarations 161 162 discover_resolver_t * 163 discover_resolver_create(const domainname * NONNULL domain); 164 165 static void 166 discover_resolver_finalize(discover_resolver_t * NULLABLE discover_resolver); 167 #define MDNS_DISPOSE_DISCOVER_RESOLVER(obj) _MDNS_STRICT_DISPOSE_TEMPLATE(obj, discover_resolver_finalize) 168 169 static discover_resolver_context_t * 170 discover_resolver_context_create(void); 171 172 static void 173 discover_resolver_context_dispose(discover_resolver_context_t * NULLABLE context); 174 #define MDNS_DISPOSE_DISCOVER_RESOLVER_CONTEXT(obj) _MDNS_STRICT_DISPOSE_TEMPLATE(obj, discover_resolver_context_dispose) 175 176 static bool 177 discover_resolver_start(discover_resolver_context_t * NULLABLE context, const domainname * NONNULL domain); 178 179 void 180 discover_resolver_stop(discover_resolver_context_t * NULLABLE context); 181 182 static mDNSs32 183 _discover_resolver_get_next_dns_service_update_time(void); 184 185 static void 186 _discover_resolver_update_dns_service(void); 187 188 static mDNSs32 189 _discover_resolver_get_next_unused_resolver_discovery_stop_time(void); 190 191 static void 192 _discover_resolver_stop_unused_resolver_discovery(void); 193 194 //====================================================================================================================== 195 // MARK: - Functions 196 197 // discover_resolver_slist_t 198 199 static discover_resolver_slist_t * NULLABLE 200 discover_resolver_slist_create(void) 201 { 202 discover_resolver_slist_t * const me = mdns_calloc(1, sizeof(*me)); 203 require(me != NULL, exit); 204 205 SLIST_INIT(me); 206 207 exit: 208 return me; 209 } 210 211 //====================================================================================================================== 212 213 static discover_resolver_node_t * 214 discover_resolver_slist_add_front(discover_resolver_slist_t * const NONNULL me, 215 discover_resolver_t * const NONNULL discover_resolver) 216 { 217 discover_resolver_node_t * const n = mdns_calloc(1, sizeof(*n)); 218 require(n != NULL, exit); 219 220 n->discover_resolver = discover_resolver; 221 SLIST_INSERT_HEAD(me, n, __entries); 222 223 exit: 224 return n; 225 } 226 227 //====================================================================================================================== 228 229 static bool 230 discover_resolver_slist_empty(const discover_resolver_slist_t * const NONNULL me) 231 { 232 return SLIST_EMPTY(me); 233 } 234 235 //====================================================================================================================== 236 237 static void 238 discover_resolver_slist_dispose(discover_resolver_slist_t * const NONNULL me) 239 { 240 discover_resolver_node_t * n; 241 242 while (!SLIST_EMPTY(me)) { 243 n = SLIST_FIRST(me); 244 SLIST_REMOVE_HEAD(me, __entries); 245 mdns_free(n); 246 } 247 248 discover_resolver_slist_t * temp_me = me; 249 mdns_free(temp_me); 250 } 251 #define MDNS_DISPOSE_DISCOVER_RESOLVER_SLIST(obj) _MDNS_STRICT_DISPOSE_TEMPLATE(obj, discover_resolver_slist_dispose) 252 253 //====================================================================================================================== 254 255 // resolver_address_t 256 257 static resolver_address_t * 258 resolver_address_create(const void * const NONNULL addr_data, mDNSAddr_Type addr_type) 259 { 260 resolver_address_t * resolver_address = NULL; 261 262 require(addr_type == mDNSAddrType_IPv4|| addr_type == mDNSAddrType_IPv6, exit); 263 264 resolver_address = mdns_calloc(1, sizeof(*resolver_address)); 265 require(resolver_address != NULL, exit); 266 267 if (addr_type == mDNSAddrType_IPv4) { 268 memcpy(&resolver_address->addr.ip.v4, addr_data, sizeof(resolver_address->addr.ip.v4)); 269 } else { // sa_family == mDNSAddrType_IPv6 270 memcpy(&resolver_address->addr.ip.v6, addr_data, sizeof(resolver_address->addr.ip.v6)); 271 } 272 273 resolver_address->addr.type = addr_type; 274 275 exit: 276 return resolver_address; 277 } 278 279 //====================================================================================================================== 280 281 static void 282 resolver_address_delete(resolver_address_t * NONNULL to_be_deleted) 283 { 284 resolver_address_t * temp = to_be_deleted; 285 mdns_free(temp); 286 } 287 288 //====================================================================================================================== 289 290 static resolver_address_t * 291 resolver_addresses_add(const void * const NONNULL addr_data, const mDNSAddr_Type addr_type, 292 resolver_address_t * NULLABLE * const NONNULL out_addresses) 293 { 294 resolver_address_t * resolver_address = resolver_address_create(addr_data, addr_type); 295 require(resolver_address != NULL, exit); 296 297 if (*out_addresses != NULL) { 298 resolver_address->next = *out_addresses; 299 } 300 *out_addresses = resolver_address; 301 302 exit: 303 return resolver_address; 304 } 305 306 //====================================================================================================================== 307 308 static bool 309 resolver_addresses_remove(const void * const NONNULL addr_data, mDNSAddr_Type addr_type, 310 resolver_address_t * NULLABLE * const NONNULL out_addresses) 311 { 312 bool succeeded; 313 314 require_action(addr_type == mDNSAddrType_IPv4 || addr_type == mDNSAddrType_IPv6, exit, succeeded = false); 315 316 resolver_address_t * prev = NULL; 317 resolver_address_t * current = NULL; 318 resolver_address_t * next; 319 320 for (current = *out_addresses; current != NULL; current = next) { 321 bool found = false; 322 next = current->next; 323 if (current->addr.type != addr_type) { 324 continue; 325 } 326 if (addr_type == mDNSAddrType_IPv4) { 327 found = (memcmp(¤t->addr.ip.v4, addr_data, sizeof(current->addr.ip.v4)) == 0); 328 } else { // sa_family == AF_INET6 329 found = (memcmp(¤t->addr.ip.v6, addr_data, sizeof(current->addr.ip.v6)) == 0); 330 } 331 if (found) { 332 break; 333 } 334 prev = current; 335 } 336 337 require_action(current != NULL, exit, succeeded = false); 338 339 if (prev != NULL) { 340 prev->next = current->next; 341 } else { 342 *out_addresses = current->next; 343 } 344 345 resolver_address_delete(current); 346 347 succeeded = true; 348 exit: 349 return succeeded; 350 } 351 352 //====================================================================================================================== 353 354 static void 355 resolver_addresses_remove_all(resolver_address_t * const NONNULL addresses) 356 { 357 resolver_address_t * current, * next; 358 for (current = addresses; current != NULL; current = next) { 359 next = current->next; 360 resolver_address_delete(current); 361 } 362 } 363 364 //====================================================================================================================== 365 366 static resolver_address_t * 367 resolver_addresses_find(const void * const NONNULL addr_data, const mDNSAddr_Type addr_type, 368 resolver_address_t * const addresses) 369 { 370 resolver_address_t * current = NULL; 371 372 require(addr_type == mDNSAddrType_IPv4 || addr_type == mDNSAddrType_IPv6, exit); 373 374 for (current = addresses; current != NULL; current = current->next) { 375 bool found = false; 376 if (current->addr.type != mDNSAddrType_IPv6) { 377 continue; 378 } 379 if (addr_type == mDNSAddrType_IPv4) { 380 found = (memcmp(¤t->addr.ip.v4, addr_data, sizeof(current->addr.ip.v4)) == 0); 381 } else { // sa_family == AF_INET6 382 found = (memcmp(¤t->addr.ip.v6, addr_data, sizeof(current->addr.ip.v6)) == 0); 383 } 384 if (found) { 385 break; 386 } 387 } 388 389 exit: 390 return current; 391 } 392 393 //====================================================================================================================== 394 // discover_resolver_name_t 395 396 static discover_resolver_name_t * 397 discover_resolver_name_create(const domainname * const NONNULL resolver_name, const mDNSInterfaceID interface_id) 398 { 399 bool succeeded; 400 discover_resolver_name_t * resolver = NULL; 401 402 resolver = mdns_calloc(1, sizeof(*resolver)); 403 require_action(resolver != NULL, exit, succeeded = false); 404 405 AssignDomainName(&resolver->resolver_name, resolver_name); 406 resolver->interface_id = interface_id; 407 408 succeeded = true; 409 exit: 410 if (!succeeded) { 411 mdns_free(resolver); 412 } 413 return resolver; 414 } 415 416 //====================================================================================================================== 417 418 static void 419 discover_resolver_name_delete(discover_resolver_name_t * NONNULL to_be_deleted) 420 { 421 if (to_be_deleted->addresses != NULL) { 422 resolver_addresses_remove_all(to_be_deleted->addresses); 423 } 424 discover_resolver_name_t * NULLABLE temp_to_be_deleted = to_be_deleted; 425 mdns_free(temp_to_be_deleted); 426 } 427 428 //====================================================================================================================== 429 430 static discover_resolver_name_t * 431 discover_resolver_name_add(const domainname * const name, const mDNSInterfaceID interface_id, 432 discover_resolver_name_t * NULLABLE * const NONNULL out_resolver_names) 433 { 434 bool succeeded; 435 discover_resolver_name_t * new_resolver_name = NULL; 436 437 new_resolver_name = discover_resolver_name_create(name, interface_id); 438 require_action(new_resolver_name != NULL, exit, succeeded = false); 439 440 memset(&new_resolver_name->ipv4_question, 0, sizeof(new_resolver_name->ipv4_question)); 441 memset(&new_resolver_name->ipv6_question, 0, sizeof(new_resolver_name->ipv6_question)); 442 443 if (*out_resolver_names != NULL) { 444 new_resolver_name->next = *out_resolver_names; 445 } 446 *out_resolver_names = new_resolver_name; 447 448 succeeded = true; 449 exit: 450 if (!succeeded) { 451 if (new_resolver_name != NULL) { 452 discover_resolver_name_delete(new_resolver_name); 453 } 454 } 455 return new_resolver_name; 456 } 457 458 //====================================================================================================================== 459 460 static bool 461 discover_resolver_name_remove(const domainname * const resolver_name, const mDNSInterfaceID interface_id, 462 discover_resolver_name_t * NULLABLE * const NONNULL out_resolver_names) 463 { 464 bool succeeded; 465 discover_resolver_name_t * prev = NULL; 466 discover_resolver_name_t * current, * next; 467 468 for (current = *out_resolver_names; current != NULL; current = next) { 469 next = current->next; 470 if (SameDomainName(¤t->resolver_name, resolver_name) && current->interface_id == interface_id) { 471 break; 472 } 473 prev = current; 474 } 475 476 require_action(current != NULL, exit, succeeded = false); 477 478 if (prev != NULL) { 479 prev->next = current->next; 480 } else { 481 *out_resolver_names = current->next; 482 } 483 discover_resolver_name_delete(current); 484 485 succeeded = true; 486 exit: 487 return succeeded; 488 } 489 490 //====================================================================================================================== 491 492 static discover_resolver_name_t * 493 discover_resolver_name_find(const domainname * const name, mDNSInterfaceID interface_id, 494 discover_resolver_name_t * const NULLABLE resolver_names) 495 { 496 discover_resolver_name_t * resolver_name = NULL; 497 498 for (resolver_name = resolver_names; resolver_name != NULL; resolver_name = resolver_name->next) { 499 if (SameDomainName(&resolver_name->resolver_name, name) && resolver_name->interface_id == interface_id) { 500 break; 501 } 502 } 503 504 return resolver_name; 505 } 506 507 //====================================================================================================================== 508 509 bool 510 resolver_discovery_add(const domainname * const NONNULL domain_to_discover, const bool grab_mdns_lock) 511 { 512 bool succeeded; 513 discover_resolver_node_t * np; 514 discover_resolver_t * discover_resolver_to_retain = NULL; 515 516 // The list has not been initialized. 517 if (g_discover_resolvers == NULL) { 518 g_discover_resolvers = discover_resolver_slist_create(); 519 require_action(g_discover_resolvers != NULL, exit, succeeded = false); 520 } 521 522 // Looking for the existing resolver discovery. 523 SLIST_FOREACH(np, g_discover_resolvers, __entries) { 524 if (!SameDomainName(&np->discover_resolver->domain, domain_to_discover)) { 525 continue; 526 } 527 discover_resolver_to_retain = np->discover_resolver; 528 break; 529 } 530 531 // Increase the use count if it exists. 532 if (discover_resolver_to_retain != NULL) { 533 discover_resolver_to_retain->use_count++; 534 535 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "Use the ongoing resolver discovery -- " 536 "domain: " PRI_DM_NAME ", use count: %u", DM_NAME_PARAM(&discover_resolver_to_retain->domain), 537 discover_resolver_to_retain->use_count); 538 539 // Clears the stop time in case we are waiting for stopping it. 540 discover_resolver_to_retain->next_stop_time = 0; 541 discover_resolver_to_retain = NULL; 542 succeeded = true; 543 goto exit; 544 } 545 546 // Or create and start a new resolver discovery for the given domain. 547 discover_resolver_to_retain = discover_resolver_create(domain_to_discover); 548 require_action(discover_resolver_to_retain != NULL, exit, succeeded = false); 549 550 if (grab_mdns_lock) { 551 mDNS_Lock(&mDNSStorage); 552 } 553 succeeded = discover_resolver_start(discover_resolver_to_retain->context, domain_to_discover); 554 if (grab_mdns_lock) { 555 mDNS_Unlock(&mDNSStorage); 556 } 557 require(succeeded, exit); 558 559 // Add the new one to the list. 560 np = discover_resolver_slist_add_front(g_discover_resolvers, discover_resolver_to_retain); 561 require_action(np != NULL, exit, succeeded = false); 562 563 discover_resolver_to_retain->use_count = 1; 564 565 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Start new resolver discovery -- " 566 "domain: " PRI_DM_NAME ", use count: %u", DM_NAME_PARAM(&discover_resolver_to_retain->domain), 567 discover_resolver_to_retain->use_count); 568 569 discover_resolver_to_retain = NULL; 570 571 exit: 572 discover_resolver_forget(&discover_resolver_to_retain); 573 574 return succeeded; 575 } 576 577 //====================================================================================================================== 578 579 bool 580 resolver_discovery_remove(const domainname * const NONNULL domain_to_discover, const bool grab_mdns_lock) 581 { 582 bool succeeded = false; 583 discover_resolver_node_t *np, *np_temp; 584 mDNS *const m = &mDNSStorage; 585 586 require_action(g_discover_resolvers != NULL, exit, LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_FAULT, 587 "Trying to stop a domain resolver discovery that does not exist - domain: " PRI_DM_NAME ".", 588 DM_NAME_PARAM(domain_to_discover))); 589 590 SLIST_FOREACH_SAFE(np, g_discover_resolvers, __entries, np_temp) { 591 592 discover_resolver_t *const discover_resolver = np->discover_resolver; 593 if (!SameDomainName(&discover_resolver->domain, domain_to_discover)) { 594 continue; 595 } 596 597 discover_resolver->use_count--; 598 599 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "One less resolver discovery use count -- " 600 "domain: " PRI_DM_NAME ", use count: %u", DM_NAME_PARAM(&discover_resolver->domain), 601 discover_resolver->use_count); 602 603 if (discover_resolver->use_count == 0) { 604 const mDNSs32 gracePeriodInSeconds = 5; 605 const mDNSs32 gracePeriodPlatformTime = gracePeriodInSeconds * mDNSPlatformOneSecond; 606 607 if (grab_mdns_lock) { 608 mDNS_Lock(&mDNSStorage); 609 } 610 611 discover_resolver->next_stop_time = NonZeroTime(m->timenow + gracePeriodPlatformTime); 612 613 if (grab_mdns_lock) { 614 mDNS_Unlock(&mDNSStorage); 615 } 616 617 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEBUG, "Planning to stop the resolver discovery -- " 618 "domain: " PRI_DM_NAME ", grace period: %ds", DM_NAME_PARAM(&discover_resolver->domain), 619 gracePeriodInSeconds); 620 } 621 622 succeeded = true; 623 break; 624 } 625 626 // If the entire list is now empty, delete the list. 627 if (discover_resolver_slist_empty(g_discover_resolvers)) { 628 MDNS_DISPOSE_DISCOVER_RESOLVER_SLIST(g_discover_resolvers); 629 } 630 631 exit: 632 return succeeded; 633 } 634 635 //====================================================================================================================== 636 637 mDNSs32 638 resolver_discovery_get_next_scheduled_event(void) 639 { 640 mDNSs32 next_event = 0; 641 642 // See if we need to update the registered native DNS service. 643 const mDNSs32 next_update_time = _discover_resolver_get_next_dns_service_update_time(); 644 if ((next_update_time != 0) && ((next_event == 0) || (next_update_time - next_event < 0))) { 645 next_event = next_update_time; 646 } 647 648 // See if we need to deregister the native DNS service that has not been used for a while. 649 const mDNSs32 next_stop_time = _discover_resolver_get_next_unused_resolver_discovery_stop_time(); 650 if ((next_stop_time != 0) && ((next_event == 0) || (next_stop_time - next_event < 0))) { 651 next_event = next_stop_time; 652 } 653 654 return next_event; 655 } 656 657 //====================================================================================================================== 658 659 void 660 resolver_discovery_perform_periodic_tasks(void) 661 { 662 _discover_resolver_update_dns_service(); 663 _discover_resolver_stop_unused_resolver_discovery(); 664 } 665 666 //====================================================================================================================== 667 668 bool 669 dns_question_requires_resolver_discovery(const DNSQuestion * NONNULL q, const domainname ** const out_domain) 670 { 671 if (!q->ForceMCast && !IsRootDomain(Do53_UNICAST_DISCOVERY_DOMAIN) 672 && IsSubdomain(&q->qname, Do53_UNICAST_DISCOVERY_DOMAIN)) { 673 *out_domain = Do53_UNICAST_DISCOVERY_DOMAIN; 674 return true; 675 } else { 676 *out_domain = NULL; 677 return false; 678 } 679 } 680 681 //====================================================================================================================== 682 683 discover_resolver_t * NULLABLE 684 discover_resolver_create(const domainname * const NONNULL domain) 685 { 686 discover_resolver_t * returned_discover_resolver = NULL; 687 discover_resolver_context_t * discover_resolver_context = NULL; 688 689 discover_resolver_t * discover_resolver = mdns_calloc(1, sizeof(*discover_resolver)); 690 require(discover_resolver != NULL, exit); 691 692 AssignDomainName(&discover_resolver->domain, domain); 693 694 discover_resolver_context = discover_resolver_context_create(); 695 require(discover_resolver_context != NULL, exit); 696 697 discover_resolver->context = discover_resolver_context; 698 discover_resolver_context = NULL; 699 700 discover_resolver->finalizer = discover_resolver_finalize; 701 discover_resolver->ref_count = 1; 702 703 returned_discover_resolver = discover_resolver; 704 discover_resolver = NULL; 705 exit: 706 MDNS_DISPOSE_DISCOVER_RESOLVER_CONTEXT(discover_resolver_context); 707 MDNS_DISPOSE_DISCOVER_RESOLVER(discover_resolver); 708 return returned_discover_resolver; 709 } 710 711 //====================================================================================================================== 712 713 static void 714 discover_resolver_finalize(discover_resolver_t * const NULLABLE discover_resolver) 715 { 716 if (discover_resolver == NULL) { 717 return; 718 } 719 720 if (discover_resolver->context != NULL) { 721 discover_resolver_stop(discover_resolver->context); 722 MDNS_DISPOSE_DISCOVER_RESOLVER_CONTEXT(discover_resolver->context); 723 } 724 725 discover_resolver_t * temp_discover_resolver = discover_resolver; 726 mdns_free(temp_discover_resolver); 727 } 728 729 //====================================================================================================================== 730 // discover_resolver_context_t 731 732 static discover_resolver_context_t * 733 discover_resolver_context_create(void) 734 { 735 discover_resolver_context_t * const context = mdns_calloc(1, sizeof(*context)); 736 737 memset(&context->ns_question, 0, sizeof(context->ns_question)); 738 context->resolver_names = NULL; 739 740 return context; 741 } 742 743 //====================================================================================================================== 744 745 static void 746 discover_resolver_context_dispose(discover_resolver_context_t * const NULLABLE context) 747 { 748 if (context == NULL) { 749 return; 750 } 751 752 if (context->resolver_names != NULL) { 753 discover_resolver_name_t * current, * next; 754 for (current = context->resolver_names; current != NULL; current = next) { 755 next = current->next; 756 discover_resolver_name_delete(current); 757 } 758 context->resolver_names = NULL; 759 } 760 discover_resolver_context_t * temp_context = context; 761 mdns_free(temp_context); 762 } 763 764 //====================================================================================================================== 765 766 static void 767 discover_resolver_setup_question(DNSQuestion * const NONNULL q, mDNSInterfaceID interface_id, 768 const domainname * const NONNULL q_name, uint16_t q_type, bool force_multicast, 769 mDNSQuestionCallback * const NULLABLE callback, void * const NONNULL context) 770 { 771 q->InterfaceID = interface_id; 772 q->flags = force_multicast ? kDNSServiceFlagsForceMulticast : 0; 773 AssignDomainName(&q->qname, q_name); 774 q->qtype = q_type; 775 q->qclass = kDNSClass_IN; 776 q->LongLived = false; 777 q->ExpectUnique = false; 778 q->ForceMCast = force_multicast; 779 q->ReturnIntermed = false; 780 q->SuppressUnusable = false; 781 q->AppendSearchDomains = false; 782 q->TimeoutQuestion = 0; 783 q->WakeOnResolve = 0; 784 q->UseBackgroundTraffic = false; 785 q->pid = mDNSPlatformGetPID(); 786 q->euid = 0; 787 q->QuestionCallback = callback; 788 q->QuestionContext = context; 789 } 790 791 792 //====================================================================================================================== 793 794 static void 795 _schedule_dns_service_update(discover_resolver_name_t * const resolver_name) 796 { 797 mDNS * const m = &mDNSStorage; 798 mDNS_Lock(m); 799 const mDNSs32 time_now = m->timenow; 800 mDNS_Unlock(m); 801 802 // Wait for 0.005s before updating the DNS service. 803 const mDNSs32 update_pending_time = mDNSPlatformOneSecond / 200; 804 resolver_name->next_update_time = NonZeroTime(time_now + update_pending_time); 805 } 806 807 //====================================================================================================================== 808 809 MDNS_CLOSED_ENUM(_resolver_dns_service_update_result_t, int8_t, 810 _resolver_dns_service_update_result_error = -1, 811 _resolver_dns_service_update_result_no_change = 0, 812 _resolver_dns_service_update_result_newly_registered = 1, 813 _resolver_dns_service_update_result_updated = 2, 814 _resolver_dns_service_update_result_deregistered = 3 815 ); 816 817 static _resolver_dns_service_update_result_t 818 _native_dns_service_update(const domainname * const domain, discover_resolver_name_t * const resolver_name) 819 { 820 (void)domain; 821 (void)resolver_name; 822 return _resolver_dns_service_update_result_no_change; 823 } 824 825 //====================================================================================================================== 826 827 static bool 828 native_dns_service_deregister(discover_resolver_name_t * const NONNULL resolver_name) 829 { 830 (void) resolver_name; 831 return false; 832 } 833 834 //====================================================================================================================== 835 836 static void 837 discover_resolver_addr_query_callback(mDNS * const NONNULL m, DNSQuestion * const NONNULL q, 838 const ResourceRecord * const NONNULL answer, const QC_result change_event) 839 { 840 discover_resolver_context_t * context = q->QuestionContext; 841 discover_resolver_name_t * resolver_name = NULL; 842 const void * const addr_data = answer->rdata->u.data; 843 const mDNSAddr_Type addr_type = answer->rrtype == kDNSType_A ? mDNSAddrType_IPv4 : mDNSAddrType_IPv6; 844 845 mDNS_Lock(m); 846 char if_name[64]; // The same size as the ((NetworkInterfaceInfo *)0)->ifname). 847 mdns_compile_time_check_local(sizeof(if_name) == sizeof(((NetworkInterfaceInfo *)0)->ifname)); 848 849 const char * const if_name_ptr = InterfaceNameForID(m, answer->InterfaceID); 850 if (if_name_ptr) { 851 mDNSPlatformStrLCopy(if_name, if_name_ptr, sizeof(if_name)); 852 } else { 853 mDNS_snprintf(if_name, sizeof(if_name), "<ID: %u>", IIDPrintable(answer->InterfaceID)); 854 } 855 mDNS_Unlock(m); 856 857 bool address_add; 858 mDNSAddr addr_changed; 859 860 mdns_require_quiet(change_event == QC_add ||change_event == QC_rmv, exit); 861 mdns_require_quiet(answer->rrtype == kDNSType_A || answer->rrtype == kDNSType_AAAA, exit); 862 mdns_require_quiet(q->InterfaceID == answer->InterfaceID, exit); 863 864 // Find the corresponding discover_resolver_name_t that starts this address query. 865 resolver_name = discover_resolver_name_find(&q->qname, q->InterfaceID, context->resolver_names); 866 mdns_require_quiet(resolver_name, exit); 867 868 // Try to find if there is existing address in the list. 869 resolver_address_t * resolver_addr = resolver_addresses_find(addr_data, addr_type, resolver_name->addresses); 870 871 if (change_event == QC_add) { 872 // Should have no duplicate addresses for the QC_add event. 873 mdns_require_quiet(resolver_addr == NULL, exit); 874 875 // Add the address into list. 876 resolver_addr = resolver_addresses_add(addr_data, addr_type, &resolver_name->addresses); 877 mdns_require_quiet(resolver_addr != NULL, exit); 878 memcpy(&addr_changed, &resolver_addr->addr, sizeof(addr_changed)); 879 880 address_add = true; 881 } else { 882 // Should be the added address in the list and should not be removed twice. 883 mdns_require_quiet(resolver_addr != NULL, exit); 884 // Should already have configured resolver. 885 886 memcpy(&addr_changed, &resolver_addr->addr, sizeof(addr_changed)); 887 888 // Remove the address from the list. 889 resolver_addresses_remove(addr_data, addr_type, &resolver_name->addresses); 890 891 address_add = false; 892 } 893 894 // Schedule new DNS configuration update. 895 _schedule_dns_service_update(resolver_name); 896 897 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "[Q%u] Resolver " PUB_ADD_RMV " - " 898 "browsing domain: " PRI_DM_NAME ", resolver name: " PRI_DM_NAME ", address: " PRI_IP_ADDR 899 ", interface: " PUB_S ".", mDNSVal16(q->TargetQID), ADD_RMV_PARAM(address_add), 900 DM_NAME_PARAM(&context->ns_question.qname), DM_NAME_PARAM(&q->qname), &addr_changed, if_name); 901 902 exit: 903 return; 904 } 905 906 //====================================================================================================================== 907 908 static bool 909 discover_resolver_start_addr_query(discover_resolver_context_t * const NONNULL context, 910 discover_resolver_name_t * const NONNULL resolver_name, const domainname * const name) 911 { 912 bool succeeded; 913 914 DNSQuestion * const ipv4 = &resolver_name->ipv4_question; 915 DNSQuestion * const ipv6 = &resolver_name->ipv6_question; 916 917 // Send address queries as normal 918 discover_resolver_setup_question(ipv4, resolver_name->interface_id, name, kDNSType_A, false, 919 discover_resolver_addr_query_callback, context); 920 discover_resolver_setup_question(ipv6, resolver_name->interface_id, name, kDNSType_AAAA, false, 921 discover_resolver_addr_query_callback, context); 922 923 // discover_resolver_start_addr_query() is called as a callback, therefore, mDNSCore lock is not held. 924 // mDNS_StartQuery() must be used here instead of mDNS_StartQuery_internal(). 925 mStatus mdns_err = mDNS_StartQuery(&mDNSStorage, ipv4); 926 require_action(mdns_err == mStatus_NoError, exit, succeeded = false); 927 928 mdns_err = mDNS_StartQuery(&mDNSStorage, ipv6); 929 require_action(mdns_err == mStatus_NoError, exit, succeeded = false); 930 931 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Starting A/AAAA queries for resolver - name: " PRI_DM_NAME, 932 DM_NAME_PARAM(name)); 933 934 succeeded = true; 935 exit: 936 return succeeded; 937 } 938 939 static bool 940 discover_resolver_stop_addr_query(discover_resolver_name_t * const NONNULL resolver_name) 941 { 942 bool succeeded = true; 943 944 // Remove the DNS config added by the resolved addresses. 945 succeeded = native_dns_service_deregister(resolver_name); 946 947 // Stop the address queries. 948 // discover_resolver_stop_addr_query() is called with lock held, and the two mDNS_StopQuery_internal() below are 949 // used to stop the two queries started by mDNS_StartQuery() in discover_resolver_start_addr_query(). 950 mStatus ipv4_err = mDNS_StopQuery_internal(&mDNSStorage, &resolver_name->ipv4_question); 951 mStatus ipv6_err = mDNS_StopQuery_internal(&mDNSStorage, &resolver_name->ipv6_question); 952 if (ipv4_err != mStatus_NoError || ipv6_err != mStatus_NoError) { 953 succeeded = false; 954 } 955 956 return succeeded; 957 } 958 959 //====================================================================================================================== 960 961 static void 962 discover_resolver_ns_query_callback(mDNS * const NONNULL UNUSED m, DNSQuestion * const NONNULL q, 963 const ResourceRecord * const NONNULL answer, const QC_result change_event) 964 { 965 bool succeeded; 966 bool new_resolver_name_created = false; 967 discover_resolver_context_t * context = q->QuestionContext; 968 const mDNSInterfaceID if_id = answer->InterfaceID; 969 const char * const if_name = InterfaceNameForID(&mDNSStorage, if_id); 970 971 require_action(change_event == QC_add || change_event == QC_rmv, exit, succeeded = false); 972 973 if (if_id == mDNSInterface_LocalOnly) { 974 succeeded = true; 975 goto exit; 976 } 977 978 // Find out the corresponding discover_resolver_name_t for resolver name, if exists. 979 const domainname * const name = &answer->rdata->u.name; 980 discover_resolver_name_t * resolver_name = discover_resolver_name_find(name, if_id, context->resolver_names); 981 982 if (change_event == QC_add) { 983 // If there is existing discover_resolver_name_t, do not start duplicate query. 984 if (resolver_name != NULL) { 985 succeeded = true; 986 goto exit; 987 } 988 989 // Add current name into list. 990 resolver_name = discover_resolver_name_add(name, if_id, &context->resolver_names); 991 require_action(resolver_name != NULL, exit, succeeded = false); 992 new_resolver_name_created = true; 993 994 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Name server found for the browsing domain - " 995 PRI_DM_NAME " -NS-> " PRI_DM_NAME ", interface: " PUB_S, DM_NAME_PARAM(&q->qname), DM_NAME_PARAM(name), 996 if_name ? if_name : "any"); 997 998 // Start to resolve the resolver name. 999 succeeded = discover_resolver_start_addr_query(context, resolver_name, name); 1000 require_action(succeeded, exit, false); 1001 } else { // change_event == QC_rmv 1002 // Should have the added discover_resolver_name_t 1003 require_action(resolver_name != NULL, exit, succeeded = false); 1004 1005 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Name server disappeared for the browsing domain - " 1006 PRI_DM_NAME " -NS-> " PRI_DM_NAME ", interface: " PUB_S, DM_NAME_PARAM(&q->qname), DM_NAME_PARAM(name), 1007 if_name ? if_name : "any"); 1008 1009 // Stop all the address queries started by this resolver name. 1010 // Since discover_resolver_ns_query_callback() is always called as a callback function without mDNS_Lock held, 1011 // we need to grab the lock explicitly. 1012 mDNS_Lock(&mDNSStorage); 1013 discover_resolver_stop_addr_query(resolver_name); 1014 mDNS_Unlock(&mDNSStorage); 1015 1016 // Remove the name from the list 1017 discover_resolver_name_remove(name, if_id, &context->resolver_names); 1018 } 1019 1020 succeeded = true; 1021 exit: 1022 if (!succeeded) { 1023 if (new_resolver_name_created) { 1024 discover_resolver_name_remove(name, if_id, &context->resolver_names); 1025 } 1026 } 1027 return; 1028 } 1029 1030 //====================================================================================================================== 1031 1032 static bool 1033 discover_resolver_start_ns_query(discover_resolver_context_t * const NONNULL context, 1034 const domainname * const NONNULL domain) 1035 { 1036 bool succeeded; 1037 1038 // Start NS query with kDNSServiceFlagsForceMulticast. 1039 DNSQuestion * const q = &context->ns_question; 1040 1041 discover_resolver_setup_question(q, mDNSInterface_Any, domain, kDNSType_NS, true, 1042 discover_resolver_ns_query_callback, context); 1043 1044 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Sending NS query to discover name server - " 1045 "browsing domain: " PRI_DM_NAME, DM_NAME_PARAM(domain)); 1046 1047 // discover_resolver_start_ns_query() is called with lock held, therefore, mDNS_StartQuery_internal() must be used 1048 // here instead of mDNS_StartQuery(). 1049 mStatus err = mDNS_StartQuery_internal(&mDNSStorage, q); 1050 require_action(err == mStatus_NoError, exit, succeeded = false); 1051 1052 succeeded = true; 1053 exit: 1054 return succeeded; 1055 } 1056 1057 //====================================================================================================================== 1058 1059 static void 1060 discover_resolver_stop_ns_query(discover_resolver_context_t * const NONNULL context) 1061 { 1062 // Stop all address subqueries. 1063 for (discover_resolver_name_t * current = context->resolver_names; current != NULL; current = current->next) { 1064 discover_resolver_stop_addr_query(current); 1065 } 1066 1067 // Stop the original NS query. 1068 mDNS_StopQuery_internal(&mDNSStorage, &context->ns_question); 1069 } 1070 1071 //====================================================================================================================== 1072 1073 static bool 1074 discover_resolver_start(discover_resolver_context_t * const NULLABLE context, 1075 const domainname * const NONNULL domain) 1076 { 1077 bool succeeded; 1078 require_action(context != NULL, exit, succeeded = false); 1079 1080 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Starting the resolver discovery for domain - " 1081 "domain: " PRI_DM_NAME, DM_NAME_PARAM(domain)); 1082 // Start NS query with kDNSServiceFlagsForceMulticast to learn about the browsing domain with mDNS. 1083 succeeded = discover_resolver_start_ns_query(context, domain); 1084 1085 exit: 1086 return succeeded; 1087 } 1088 1089 //====================================================================================================================== 1090 1091 void 1092 discover_resolver_stop(discover_resolver_context_t * const NULLABLE context) 1093 { 1094 if (context == NULL) { 1095 return; 1096 } 1097 discover_resolver_stop_ns_query(context); 1098 } 1099 1100 //====================================================================================================================== 1101 1102 static mDNSs32 1103 _discover_resolver_get_next_dns_service_update_time(void) 1104 { 1105 mDNSs32 next_time = 0; 1106 mdns_require_quiet(g_discover_resolvers, exit); 1107 1108 discover_resolver_node_t *np, *np_temp; 1109 SLIST_FOREACH_SAFE(np, g_discover_resolvers, __entries, np_temp) { 1110 const discover_resolver_t *const discover_resolver = np->discover_resolver; 1111 1112 if (discover_resolver == mDNSNULL || discover_resolver->context == mDNSNULL || 1113 discover_resolver->context->resolver_names == mDNSNULL) { 1114 continue; 1115 } 1116 1117 const discover_resolver_name_t * const resolver_name = discover_resolver->context->resolver_names; 1118 const mDNSs32 next_update_time = resolver_name->next_update_time; 1119 if (next_update_time == 0) { 1120 continue; 1121 } 1122 1123 if ((next_time == 0) || ((next_update_time - next_time) < 0)) { 1124 next_time = next_update_time; 1125 } 1126 } 1127 1128 exit: 1129 return next_time; 1130 } 1131 1132 //====================================================================================================================== 1133 1134 static void 1135 _discover_resolver_update_dns_service(void) 1136 { 1137 const mDNSs32 time_now = mDNSStorage.timenow; 1138 mdns_require_return(g_discover_resolvers); 1139 1140 discover_resolver_node_t *np, *np_temp; 1141 SLIST_FOREACH_SAFE(np, g_discover_resolvers, __entries, np_temp) { 1142 discover_resolver_t *const discover_resolver = np->discover_resolver; 1143 1144 if (discover_resolver == mDNSNULL || discover_resolver->context == mDNSNULL || 1145 discover_resolver->context->resolver_names == mDNSNULL) { 1146 continue; 1147 } 1148 1149 discover_resolver_name_t * const resolver_name = discover_resolver->context->resolver_names; 1150 const mDNSs32 next_update_time = resolver_name->next_update_time; 1151 if ((next_update_time == 0) || ((next_update_time - time_now) > 0)) { 1152 continue; 1153 } 1154 1155 const _resolver_dns_service_update_result_t err = _native_dns_service_update(&discover_resolver->domain, 1156 resolver_name); 1157 1158 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Discovered local resolver configuration updated" 1159 " - name: " PRI_DM_NAME ", result: %d", DM_NAME_PARAM(&discover_resolver->domain), err); 1160 1161 resolver_name->next_update_time = 0; 1162 } 1163 } 1164 1165 //====================================================================================================================== 1166 1167 static mDNSs32 1168 _discover_resolver_get_next_unused_resolver_discovery_stop_time(void) 1169 { 1170 mDNSs32 next_time = 0; 1171 mdns_require_quiet(g_discover_resolvers, exit); 1172 1173 // Find the next stop time that is closest to us. 1174 discover_resolver_node_t *np, *np_temp; 1175 SLIST_FOREACH_SAFE(np, g_discover_resolvers, __entries, np_temp) { 1176 const discover_resolver_t *const discover_resolver = np->discover_resolver; 1177 if (discover_resolver->use_count != 0) { 1178 continue; 1179 } 1180 1181 const mDNSs32 next_stop_time = discover_resolver->next_stop_time; 1182 if (next_stop_time == 0) { 1183 continue; 1184 } 1185 1186 if ((next_time == 0) || (next_time - next_stop_time > 0)) { 1187 next_time = next_stop_time; 1188 } 1189 } 1190 1191 exit: 1192 return next_time; 1193 } 1194 1195 //====================================================================================================================== 1196 1197 static void 1198 _discover_resolver_stop_unused_resolver_discovery(void) 1199 { 1200 const mDNSs32 time_now = mDNSStorage.timenow; 1201 mdns_require_return(g_discover_resolvers); 1202 1203 discover_resolver_node_t *np, *np_temp; 1204 SLIST_FOREACH_SAFE(np, g_discover_resolvers, __entries, np_temp) { 1205 if (np->discover_resolver->use_count != 0) { 1206 continue; 1207 } 1208 1209 const mDNSs32 next_stop_time = np->discover_resolver->next_stop_time; 1210 if ((next_stop_time == 0) || (time_now - next_stop_time < 0)) { 1211 continue; 1212 } 1213 1214 // Now (next_stop_time <= time_now) indicates that we have passed the next_stop_time. 1215 // Therefore, it is time to cancel the resolver discovery. 1216 LogRedact(MDNS_LOG_CATEGORY_DEFAULT, MDNS_LOG_DEFAULT, "Stopping the resolver discovery -- " 1217 "domain: " PRI_DM_NAME, DM_NAME_PARAM(&np->discover_resolver->domain)); 1218 1219 discover_resolver_forget(&np->discover_resolver); 1220 SLIST_REMOVE(g_discover_resolvers, np, discover_resolver_node, __entries); 1221 mdns_free(np); 1222 } 1223 } 1224 1225 #else // MDNSRESPONDER_SUPPORTS(COMMON, LOCAL_DNS_RESOLVER_DISCOVERY) 1226 1227 // iso C requires a translation unit to contain at least one declaration 1228 typedef int __make_iso_c_happy_about_no_declaration; 1229 1230 #endif // MDNSRESPONDER_SUPPORTS(COMMON, LOCAL_DNS_RESOLVER_DISCOVERY) 1231