2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
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
8 * https://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "mdns_internal.h"
18 #include "mdns_dns_service.h"
19 #include "mdns_helpers.h"
20 #include "mdns_interface_monitor.h"
21 #include "mdns_objects.h"
22 #include "mdns_resolver.h"
24 #include "HTTPUtilities.h"
25 #include "DNSMessage.h"
26 #include <CoreUtils/CoreUtils.h>
27 #include <stdatomic.h>
29 //======================================================================================================================
30 // MARK: - DNS Service Manager Kind Definition
32 struct mdns_dns_service_manager_s
{
33 struct mdns_object_s base
; // Object base.
34 CFMutableArrayRef default_services
; // DNS services from configd.
35 CFMutableArrayRef path_services
; // DNS services from path clients.
36 CFMutableArrayRef discovered_services
;// DNS services discovered from DNS records.
37 CFMutableArrayRef custom_services
; // DNS services created for custom use.
38 CFMutableArrayRef monitors
; // Interface monitors.
39 dispatch_queue_t queue
; // Serial queue for interface monitor events.
40 dispatch_queue_t user_queue
; // User's queue for invoking user's event handler.
41 dispatch_source_t update_source
; // Data source for triggering update events.
42 mdns_event_handler_t event_handler
; // User's event handler.
43 bool report_symptoms
; // True if resolvers should report DNS symptoms.
44 bool invalidated
; // True if the manager has been invalidated.
45 bool terminated
; // True if the manager has been terminated.
46 bool user_activated
; // True if user called mdns_dns_service_manager_activate().
47 #if MDNS_RESOLVER_PROBLEMATIC_QTYPE_WORKAROUND
48 int pqw_threshold
; // Threshold value for problematic QTYPE workaround.
52 MDNS_OBJECT_SUBKIND_DEFINE(dns_service_manager
);
54 #define MDNS_DNS_SERVICE_MANAGER_ARRAYS(MANAGER) \
55 (MANAGER)->default_services, \
56 (MANAGER)->path_services, \
57 (MANAGER)->discovered_services, \
58 (MANAGER)->custom_services
60 //======================================================================================================================
61 // MARK: - DNS Service Kind Definition
63 OS_CLOSED_ENUM(mdns_dns_service_source
, int,
64 mdns_dns_service_source_sc
= 1, // For DNS services defined by SystemConfiguration.
65 mdns_dns_service_source_nw
= 2, // For DNS services defined system-wide by libnetwork.
66 mdns_dns_service_source_dns
= 3, // For DNS services defined by SVCB/HTTPS DNS records.
67 mdns_dns_service_source_custom
= 4 // For DNS services defined by on a client using an XPC dictionary.
70 OS_CLOSED_OPTIONS(mdns_dns_service_flags
, uint32_t,
71 mdns_dns_service_flag_null
= 0, // Null flag.
72 mdns_dns_service_flag_defunct
= (1U << 0), // DNS service is defunct.
73 mdns_dns_service_flag_a_queries_advised
= (1U << 1), // Querying for A records is advised.
74 mdns_dns_service_flag_aaaa_queries_advised
= (1U << 2), // Querying for AAAA records is advised.
75 mdns_dns_service_flag_cellular
= (1U << 3), // DNS service's interface is cellular.
76 mdns_dns_service_flag_ipv4_connectivity
= (1U << 4), // DNS service's interface has IPv4 connectivity.
77 mdns_dns_service_flag_ipv6_connectivity
= (1U << 5), // DNS service's interface has IPv6 connectivity.
78 mdns_dns_service_flag_expensive
= (1U << 6), // DNS service's interface is expensive.
79 mdns_dns_service_flag_constrained
= (1U << 7), // DNS service's interface is constrained.
80 mdns_dns_service_flag_clat46
= (1U << 8), // DNS service's interface is CLAT46.
81 mdns_dns_service_flag_vpn
= (1U << 9), // DNS service's interface is VPN.
82 mdns_dns_service_flag_connection_problems
= (1U << 10) // DNS service is currently having connection problems.
85 #define MDNS_DNS_SERVICE_FLAGS_FROM_DNS_CONFIG \
86 (mdns_dns_service_flag_a_queries_advised | \
87 mdns_dns_service_flag_aaaa_queries_advised | \
88 mdns_dns_service_flag_cellular) \
90 #define MDNS_DNS_SERVICE_FLAGS_FROM_INTERFACE_MONITOR ( \
91 mdns_dns_service_flag_ipv4_connectivity | \
92 mdns_dns_service_flag_ipv6_connectivity | \
93 mdns_dns_service_flag_expensive | \
94 mdns_dns_service_flag_constrained | \
95 mdns_dns_service_flag_clat46 | \
96 mdns_dns_service_flag_vpn \
99 // Make sure that the two sets of flags are mutually exclusive.
100 check_compile_time((MDNS_DNS_SERVICE_FLAGS_FROM_DNS_CONFIG
& MDNS_DNS_SERVICE_FLAGS_FROM_INTERFACE_MONITOR
) == 0);
102 struct _discovered_detail_s
{
103 nw_endpoint_t url_endpoint
; // URL endpoint for discovered DNS services.
104 uint64_t use_time
; // Recent use time for discovered DNS service.
105 uint64_t expire_time
; // Expire time for discovered DNS service.
106 bool squash_cnames
; // Should squash CNAMEs.
109 typedef struct _domain_item_s
* _domain_item_t
;
111 struct mdns_dns_service_s
{
112 struct mdns_object_s base
; // Object base.
113 mdns_resolver_t resolver
; // The DNS service's resolver.
114 CFMutableArrayRef addresses
; // Addresses of servers that implement the DNS service.
115 _domain_item_t domain_list
; // List of domains that this DNS service should be used for.
116 nw_resolver_config_t config
; // Resolver config from nw_path.
117 char * if_name
; // Name of DNS service's network interface (for logging).
118 mdns_dns_service_id_t ident
; // The DNS service's process-wide unique identifier.
119 void * context
; // User-defined context.
120 mdns_context_finalizer_t context_finalizer
; // Finalizer for user-defined context.
121 uint32_t if_index
; // Index of DNS service's network interface.
122 uint32_t service_id
; // Service ID for service-scoped DNS services.
123 int32_t reg_count
; // Count of outstanding registrations for a custom DNS service.
124 struct _discovered_detail_s discovered
; // Details for discovered DNS services.
125 mdns_dns_service_source_t source
; // Service's source.
126 mdns_dns_service_scope_t scope
; // The DNS service's scope type.
127 mdns_dns_service_flags_t flags
; // Flags that represent the service's properties.
128 mdns_resolver_type_t resolver_type
; // The resolver's type.
129 bool defuncting
; // True if the service becoming defunct is imminent.
130 bool cannot_connect
; // True if we cannot connect to the DNS service.
131 bool config_needs_cancel
;// True if the new_resolver_config updates need to be cancelled.
132 bool replace_resolver
; // True if resolver needs to be replaced on wake.
135 MDNS_OBJECT_SUBKIND_DEFINE_FULL(dns_service
);
137 struct _domain_item_s
{
138 _domain_item_t next
; // Next item in list.
139 uint8_t * name
; // Domain name in label format.
140 char * name_str
; // Domain name as a C string.
141 int label_count
; // Domain name's label count for longest parent domain matching.
142 uint32_t order
; // Order value from associated dns_resolver_t object, if any.
145 //======================================================================================================================
146 // MARK: - Local Prototypes
149 _mdns_dns_service_manager_terminate(mdns_dns_service_manager_t manager
, OSStatus error
);
152 _mdns_dns_service_manager_add_service(mdns_dns_service_manager_t manager
, CFMutableArrayRef services
,
153 mdns_dns_service_t service
);
155 static mdns_dns_service_t
156 _mdns_dns_service_manager_get_service(mdns_dns_service_manager_t manager
, const uint8_t *name
,
157 mdns_dns_service_scope_t scope
, uint32_t scoping_id
);
159 static mdns_dns_service_t
160 _mdns_dns_service_manager_get_uuid_scoped_service(mdns_dns_service_manager_t manager
, const uuid_t uuid
);
162 static mdns_dns_service_t
163 _mdns_dns_service_manager_get_discovered_service(mdns_dns_service_manager_t manager
, nw_endpoint_t url_endpoint
);
166 _mdns_dns_service_manager_update_interface_properties(mdns_dns_service_manager_t manager
);
169 _mdns_dns_service_manager_remove_unneeded_interface_monitors(mdns_dns_service_manager_t manager
);
172 _mdns_dns_service_manager_update_interface_properties_for_services(mdns_dns_service_manager_t manager
,
173 CFArrayRef services
);
176 _mdns_dns_service_manager_update_interface_properties_for_service(mdns_dns_service_manager_t manager
,
177 mdns_dns_service_t service
);
179 static mdns_dns_service_t
180 _mdns_dns_service_create(mdns_dns_service_source_t source
, mdns_dns_service_scope_t scope
,
181 mdns_resolver_type_t resolver_type
, OSStatus
*out_error
);
184 _mdns_dns_service_manager_prepare_resolver(mdns_dns_service_manager_t manager
, mdns_dns_service_t service
);
187 _mdns_dns_service_manager_start_defuncting(mdns_dns_service_manager_t manager
, mdns_dns_service_t service
);
189 static mdns_dns_service_t
190 _mdns_dns_service_manager_prepare_service(mdns_dns_service_manager_t manager
, mdns_dns_service_t service
);
193 _mdns_dns_service_manager_trigger_update(mdns_dns_service_manager_t manager
);
195 typedef bool (^mdns_dns_service_array_applier_t
)(CFMutableArrayRef service_array
);
198 _mdns_dns_service_manager_iterate_over_all_service_arrays(mdns_dns_service_manager_t manager
,
199 mdns_dns_service_array_applier_t applier
);
202 _mdns_dns_service_make_defunct(mdns_dns_service_t service
);
205 _mdns_dns_service_equal_ex(mdns_dns_service_t service
, mdns_dns_service_t other
, bool ignore_domains
);
208 _mdns_dns_service_add_domain(mdns_dns_service_t service
, const char *name
, uint32_t order
);
211 _mdns_dns_service_handles_domain_name(mdns_dns_service_t service
, const uint8_t *name
, uint32_t *out_order
);
213 static mdns_resolver_type_t
214 _mdns_dns_service_get_resolver_type_safe(mdns_dns_service_t service
);
216 static CFMutableArrayRef
217 _mdns_create_dns_service_array_from_config(const dns_config_t
*config
, OSStatus
*out_error
);
219 static mdns_dns_service_t
220 _mdns_dns_service_create_from_resolver_config(nw_resolver_config_t config
, mdns_dns_service_source_t source
,
221 OSStatus
*out_error
);
223 static mdns_dns_service_id_t
224 _mdns_dns_service_get_id_safe(mdns_dns_service_t service
);
226 static const uint8_t *
227 _mdns_domain_name_get_parent(const uint8_t *name
, int depth
);
230 _domain_item_free(_domain_item_t item
);
233 _domain_item_compare(const struct _domain_item_s
*d1
, const struct _domain_item_s
*d2
, bool ignore_order
);
235 //======================================================================================================================
238 MDNS_LOG_CATEGORY_DEFINE(dns_service
, "dns_service");
240 //======================================================================================================================
241 // MARK: - DNS Service Manager Public Methods
243 mdns_dns_service_manager_t
244 mdns_dns_service_manager_create(const dispatch_queue_t user_queue
, OSStatus
* const out_error
)
247 mdns_dns_service_manager_t manager
= NULL
;
248 mdns_dns_service_manager_t obj
= _mdns_dns_service_manager_alloc();
249 require_action_quiet(obj
, exit
, err
= kNoMemoryErr
);
251 obj
->default_services
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &mdns_cfarray_callbacks
);
252 require_action_quiet(obj
->default_services
, exit
, err
= kNoResourcesErr
);
254 obj
->path_services
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &mdns_cfarray_callbacks
);
255 require_action_quiet(obj
->path_services
, exit
, err
= kNoResourcesErr
);
257 obj
->discovered_services
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &mdns_cfarray_callbacks
);
258 require_action_quiet(obj
->discovered_services
, exit
, err
= kNoResourcesErr
);
260 obj
->custom_services
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &mdns_cfarray_callbacks
);
261 require_action_quiet(obj
->custom_services
, exit
, err
= kNoResourcesErr
);
263 obj
->monitors
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &mdns_cfarray_callbacks
);
264 require_action_quiet(obj
->monitors
, exit
, err
= kNoResourcesErr
);
266 obj
->queue
= dispatch_queue_create("com.apple.mdns.dns-service-manager", DISPATCH_QUEUE_SERIAL
);
267 require_action_quiet(obj
->queue
, exit
, err
= kNoResourcesErr
);
269 obj
->user_queue
= user_queue
;
270 dispatch_retain(obj
->user_queue
);
280 mdns_release_null_safe(obj
);
284 //======================================================================================================================
287 mdns_dns_service_manager_set_report_symptoms(const mdns_dns_service_manager_t me
, const bool report_symptoms
)
289 if (!me
->user_activated
) {
290 me
->report_symptoms
= report_symptoms
;
294 //======================================================================================================================
296 #if MDNS_RESOLVER_PROBLEMATIC_QTYPE_WORKAROUND
298 mdns_dns_service_manager_enable_problematic_qtype_workaround(const mdns_dns_service_manager_t me
, const int threshold
)
300 require_return(!me
->user_activated
);
301 me
->pqw_threshold
= threshold
;
305 //======================================================================================================================
308 mdns_dns_service_manager_set_event_handler(const mdns_dns_service_manager_t me
, const mdns_event_handler_t handler
)
310 if (!me
->user_activated
) {
311 const mdns_event_handler_t new_handler
= handler
? Block_copy(handler
) : NULL
;
312 if (me
->event_handler
) {
313 Block_release(me
->event_handler
);
315 me
->event_handler
= new_handler
;
319 //======================================================================================================================
322 _mdns_dns_service_manager_activate_internal(mdns_dns_service_manager_t manager
);
325 mdns_dns_service_manager_activate(const mdns_dns_service_manager_t me
)
327 require_return(!me
->user_activated
);
329 me
->user_activated
= true;
330 dispatch_sync(me
->queue
,
332 require_return(!me
->terminated
);
333 _mdns_dns_service_manager_activate_internal(me
);
338 _mdns_dns_service_manager_activate_internal(const mdns_dns_service_manager_t me
)
340 require_return(!me
->update_source
);
341 me
->update_source
= dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_OR
, 0, 0, me
->user_queue
);
342 if (me
->update_source
) {
344 dispatch_source_set_event_handler(me
->update_source
,
346 if (me
->event_handler
) {
347 me
->event_handler(mdns_event_update
, kNoErr
);
350 dispatch_source_set_cancel_handler(me
->update_source
,
354 dispatch_activate(me
->update_source
);
356 _mdns_dns_service_manager_terminate(me
, kNoResourcesErr
);
360 //======================================================================================================================
363 _mdns_dns_service_manager_apply_dns_config_internal(mdns_dns_service_manager_t manager
, const dns_config_t
*config
);
366 mdns_dns_service_manager_apply_dns_config(const mdns_dns_service_manager_t me
, const dns_config_t
* const config
)
368 dispatch_sync(me
->queue
,
370 require_return(!me
->terminated
);
371 _mdns_dns_service_manager_apply_dns_config_internal(me
, config
);
375 #define MDNS_TARGET_DISCOVERED_SERVICE_COUNT 4
377 static CFComparisonResult
378 _mdns_dns_service_compare_time(const void *val1
, const void *val2
, __unused
void *context
)
380 const mdns_dns_service_t service1
= (const mdns_dns_service_t
)val1
;
381 const mdns_dns_service_t service2
= (const mdns_dns_service_t
)val2
;
383 if (service1
->discovered
.use_time
> service2
->discovered
.use_time
) {
384 return kCFCompareLessThan
;
385 } else if (service1
->discovered
.use_time
< service2
->discovered
.use_time
) {
386 return kCFCompareGreaterThan
;
388 return kCFCompareEqualTo
;
393 _mdns_dns_service_manager_purge_discovered_services(const mdns_dns_service_manager_t me
)
395 const CFIndex n
= CFArrayGetCount(me
->discovered_services
);
396 if (n
< MDNS_TARGET_DISCOVERED_SERVICE_COUNT
) {
400 // Sort by recent use
401 CFMutableArrayRef recent_services
= CFArrayCreateMutableCopy(kCFAllocatorDefault
, 0, me
->discovered_services
);
402 CFArraySortValues(recent_services
, CFRangeMake(0, n
), _mdns_dns_service_compare_time
, NULL
);
404 // Reduce number of services down to target by defuncting them
405 for (CFIndex i
= 0; i
< n
; ++i
) {
406 if (i
>= MDNS_TARGET_DISCOVERED_SERVICE_COUNT
) {
407 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(recent_services
, i
);
408 _mdns_dns_service_make_defunct(service
);
411 CFRelease(recent_services
);
415 _mdns_dns_service_manager_apply_dns_config_internal(const mdns_dns_service_manager_t me
,
416 const dns_config_t
* const config
)
418 _mdns_dns_service_manager_purge_discovered_services(me
);
421 CFMutableArrayRef new_services
= _mdns_create_dns_service_array_from_config(config
, &err
);
422 require_noerr_quiet(err
, exit
);
424 // Keep DNS services that still exist, and mark those that no longer exist as defunct.
425 const CFRange full_range
= CFRangeMake(0, CFArrayGetCount(new_services
));
426 for (CFIndex i
= CFArrayGetCount(me
->default_services
) - 1; i
>= 0; --i
) {
427 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(me
->default_services
, i
);
428 const CFIndex j
= CFArrayGetFirstIndexOfValue(new_services
, full_range
, service
);
430 // The service still exists, but its flags may have changed.
431 const mdns_dns_service_t new_service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(new_services
, j
);
432 service
->flags
&= ~MDNS_DNS_SERVICE_FLAGS_FROM_DNS_CONFIG
;
433 service
->flags
|= (new_service
->flags
& MDNS_DNS_SERVICE_FLAGS_FROM_DNS_CONFIG
);
435 // Replace the new service object with the established one.
436 CFArraySetValueAtIndex(new_services
, j
, service
);
438 // The service no longer exists.
439 _mdns_dns_service_make_defunct(service
);
442 CFRelease(me
->default_services
);
443 me
->default_services
= new_services
;
446 _mdns_dns_service_manager_remove_unneeded_interface_monitors(me
);
447 _mdns_dns_service_manager_update_interface_properties_for_services(me
, me
->default_services
);
451 _mdns_dns_service_manager_terminate(me
, err
);
455 //======================================================================================================================
458 _mdns_dns_service_manager_register_path_resolver_internal(mdns_dns_service_manager_t manager
,
459 const uuid_t resolver_config_uuid
);
462 _mdns_dns_service_manager_handle_resolver_config_removal(mdns_dns_service_manager_t manager
,
463 nw_resolver_config_t config
);
466 _mdns_dns_service_manager_cancel_resolver_config_updates(mdns_dns_service_manager_t manager
,
467 nw_resolver_config_t config
);
470 mdns_dns_service_manager_register_path_resolver(const mdns_dns_service_manager_t me
, const uuid_t resolver_config_uuid
)
472 dispatch_sync(me
->queue
,
474 require_return(!me
->terminated
);
475 _mdns_dns_service_manager_register_path_resolver_internal(me
, resolver_config_uuid
);
480 _mdns_dns_service_manager_register_path_resolver_internal(const mdns_dns_service_manager_t me
,
481 const uuid_t config_uuid
)
483 mdns_dns_service_t service
= _mdns_dns_service_manager_get_uuid_scoped_service(me
, config_uuid
);
484 require_return_action(!service
, os_log_debug(_mdns_dns_service_log(),
485 "Already registered service -- service id: %llu, uuid: %{uuid_t}.16P", service
->ident
, config_uuid
));
487 // Need a new service in the path array.
488 nw_resolver_config_t _Nonnull config
= nw_resolver_config_create();
489 nw_resolver_config_set_identifier(config
, config_uuid
);
491 // Calling nw_resolver_config_watch_updates will fill out the contents of the resolver.
494 nw_resolver_config_watch_updates(config
, me
->queue
,
495 ^(const bool removed
)
498 _mdns_dns_service_manager_handle_resolver_config_removal(me
, config
);
502 service
= _mdns_dns_service_create_from_resolver_config(config
, mdns_dns_service_source_nw
, &err
);
504 service
->config_needs_cancel
= true;
505 _mdns_dns_service_manager_add_service(me
, me
->path_services
, service
);
506 os_log(_mdns_dns_service_log(), "Registered service -- %@", service
);
507 mdns_forget(&service
);
509 _mdns_dns_service_manager_cancel_resolver_config_updates(me
, config
);
510 os_log_error(_mdns_dns_service_log(),
511 "Failed to register service -- uuid: %{uuid_t}.16P, config: %@, error: %{mdns:err}ld",
512 config_uuid
, config
, (long)err
);
518 _mdns_dns_service_manager_handle_resolver_config_removal(const mdns_dns_service_manager_t me
,
519 const nw_resolver_config_t config
)
521 const CFIndex n
= CFArrayGetCount(me
->path_services
);
522 for (CFIndex i
= 0; i
< n
; ++i
) {
523 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(me
->path_services
, i
);
524 if (service
->config
== config
) {
525 os_log(_mdns_dns_service_log(), "Removing service -- %@", service
);
526 // Cancel the config's updates now and mark the service as defuncting.
527 // The service will ultimately be made defunct when the user accepts the next set of pending updates.
528 if (service
->config_needs_cancel
) {
529 service
->config_needs_cancel
= false;
530 _mdns_dns_service_manager_cancel_resolver_config_updates(me
, service
->config
);
532 _mdns_dns_service_manager_start_defuncting(me
, service
);
539 _mdns_dns_service_manager_cancel_resolver_config_updates(const mdns_dns_service_manager_t me
,
540 const nw_resolver_config_t config
)
542 nw_resolver_config_cancel_updates(config
, me
->queue
,
549 //======================================================================================================================
551 static mdns_dns_service_id_t
552 _mdns_dns_service_manager_register_custom_service_internal(mdns_dns_service_manager_t manager
,
553 xpc_object_t resolver_config_dict
);
555 static mdns_dns_service_t
556 _mdns_dns_service_manager_get_custom_service_by_uuid(mdns_dns_service_manager_t manager
, const uuid_t config_uuid
);
558 mdns_dns_service_id_t
559 mdns_dns_service_manager_register_custom_service(const mdns_dns_service_manager_t me
,
560 const xpc_object_t resolver_config_dict
)
562 __block mdns_dns_service_id_t ident
;
563 dispatch_sync(me
->queue
,
565 require_return_action(!me
->terminated
, ident
= 0);
566 ident
= _mdns_dns_service_manager_register_custom_service_internal(me
, resolver_config_dict
);
571 static mdns_dns_service_id_t
572 _mdns_dns_service_manager_register_custom_service_internal(const mdns_dns_service_manager_t me
,
573 const xpc_object_t resolver_config_dict
)
575 nw_resolver_config_t config
= NULL
;
576 mdns_dns_service_t service
= NULL
;
578 // Parse the dictionary
579 config
= nw_resolver_config_create_with_dictionary(resolver_config_dict
);
580 if (unlikely(!config
)) {
581 char *dict_desc
= xpc_copy_description(resolver_config_dict
);
582 os_log_error(_mdns_dns_service_log(),
583 "Failed to create nw_resolver_config for dictionary: %s", dict_desc
? dict_desc
: "<NO DESC.>");
584 ForgetMem(&dict_desc
);
587 uuid_t config_uuid
= {0};
588 nw_resolver_config_get_identifier(config
, config_uuid
);
589 service
= _mdns_dns_service_manager_get_custom_service_by_uuid(me
, config_uuid
);
592 service
= _mdns_dns_service_create_from_resolver_config(config
, mdns_dns_service_source_custom
, &err
);
594 _mdns_dns_service_manager_add_service(me
, me
->custom_services
, service
);
595 os_log(_mdns_dns_service_log(), "Registered custom service -- %@", service
);
596 mdns_release(service
);
598 os_log_error(_mdns_dns_service_log(),
599 "Failed to register custom service -- uuid: %{uuid_t}.16P, config: %@, error: %{mdns:err}ld",
600 config_uuid
, config
, (long)err
);
604 if (service
->reg_count
++ != 0) {
605 os_log_info(_mdns_dns_service_log(),
606 "Registered custom service -- service id: %llu, registration count: %d",
607 service
->ident
, service
->reg_count
);
613 return _mdns_dns_service_get_id_safe(service
);
616 static mdns_dns_service_t
617 _mdns_dns_service_manager_get_custom_service_by_uuid(const mdns_dns_service_manager_t me
, const uuid_t config_uuid
)
619 const CFIndex n
= CFArrayGetCount(me
->custom_services
);
620 for (CFIndex i
= 0; i
< n
; ++i
) {
621 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(me
->custom_services
, i
);
622 if (service
->config
) {
623 uuid_t match_uuid
= {0};
624 nw_resolver_config_get_identifier(service
->config
, match_uuid
);
625 if (uuid_compare(match_uuid
, config_uuid
) == 0) {
633 //======================================================================================================================
636 _mdns_dns_service_manager_deregister_custom_service_internal(mdns_dns_service_manager_t manager
,
637 mdns_dns_service_id_t ident
);
640 mdns_dns_service_manager_deregister_custom_service(const mdns_dns_service_manager_t me
,
641 const mdns_dns_service_id_t ident
)
643 require_return(ident
!= 0);
644 dispatch_sync(me
->queue
,
646 require_return(!me
->terminated
);
647 _mdns_dns_service_manager_deregister_custom_service_internal(me
, ident
);
652 _mdns_dns_service_manager_deregister_custom_service_internal(const mdns_dns_service_manager_t me
,
653 const mdns_dns_service_id_t ident
)
655 const CFIndex n
= CFArrayGetCount(me
->custom_services
);
656 for (CFIndex i
= 0; i
< n
; ++i
) {
657 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(me
->custom_services
, i
);
658 if (service
->ident
== ident
) {
659 --service
->reg_count
;
660 os_log_with_type(_mdns_dns_service_log(),
661 (service
->reg_count
== 0) ? OS_LOG_TYPE_DEFAULT
: OS_LOG_TYPE_INFO
,
662 "Deregistered custom service -- service id: %llu, registration count: %d",
663 service
->ident
, service
->reg_count
);
664 if (service
->reg_count
== 0) {
665 _mdns_dns_service_manager_start_defuncting(me
, service
);
672 //======================================================================================================================
675 _mdns_dns_service_manager_register_doh_uri_internal(mdns_dns_service_manager_t manager
,
676 const char *doh_uri
, const char *domain
);
678 static mdns_dns_service_t
679 _mdns_dns_service_create_from_doh_uri(nw_endpoint_t url_endpoint
, OSStatus
*out_error
);
682 mdns_dns_service_manager_register_doh_uri(const mdns_dns_service_manager_t me
,
683 const char *doh_uri
, const char *domain
)
685 dispatch_sync(me
->queue
,
687 require_return(!me
->terminated
);
688 _mdns_dns_service_manager_register_doh_uri_internal(me
, doh_uri
, domain
);
693 _mdns_dns_service_manager_fetch_trusted_name_pvd(const mdns_dns_service_manager_t me
,
694 mdns_dns_service_t service
, nw_endpoint_t doh_endpoint
,
695 xpc_object_t dns_zone_array
, const char *trusted_name
)
697 if (doh_endpoint
== NULL
|| trusted_name
== NULL
||
698 dns_zone_array
== NULL
|| xpc_get_type(dns_zone_array
) != XPC_TYPE_ARRAY
) {
702 char *trusted_name_suffix
= NULL
;
703 asprintf(&trusted_name_suffix
, ".%s", trusted_name
);
705 xpc_object_t candidate_dns_zones
= xpc_array_create(NULL
, 0);
706 xpc_array_apply(dns_zone_array
, ^bool(__unused
size_t index
, xpc_object_t _Nonnull array_value
) {
707 if (xpc_get_type(array_value
) == XPC_TYPE_STRING
) {
708 const char *dns_zone
= xpc_string_get_string_ptr(array_value
);
710 if (strcmp(trusted_name
, dns_zone
) == 0) {
712 xpc_array_append_value(candidate_dns_zones
, array_value
);
714 size_t trusted_name_suffix_length
= strlen(trusted_name_suffix
);
715 size_t dns_zone_length
= strlen(dns_zone
);
716 if (trusted_name_suffix_length
<= dns_zone_length
) {
717 if (strcmp(trusted_name_suffix
, dns_zone
+ (dns_zone_length
- trusted_name_suffix_length
)) == 0) {
719 xpc_array_append_value(candidate_dns_zones
, array_value
);
727 free(trusted_name_suffix
);
729 if (xpc_array_get_count(candidate_dns_zones
) == 0) {
730 xpc_forget(&candidate_dns_zones
);
734 __block
void *trusted_name_task
= NULL
;
735 nw_retain(doh_endpoint
);
736 mdns_retain(service
);
737 // candidate_dns_zones is already retained
738 nw_endpoint_t trusted_name_endpoint
= nw_endpoint_create_host(trusted_name
, "443");
739 trusted_name_task
= http_task_create_pvd_query(me
->queue
,
740 trusted_name
, "", ^(xpc_object_t trusted_name_json
) {
742 if (trusted_name_json
!= NULL
) {
743 const char *trusted_doh_template
= xpc_dictionary_get_string(trusted_name_json
, "dohTemplate");
744 if (trusted_doh_template
== NULL
) {
745 os_log_error(_mdns_dns_service_log(), "Trusted name %@ missing DoH template", trusted_name_endpoint
);
749 const char *inner_doh_string
= nw_endpoint_get_url(doh_endpoint
);
750 if (inner_doh_string
== NULL
|| strcasecmp(trusted_doh_template
, inner_doh_string
) != 0) {
751 os_log_error(_mdns_dns_service_log(), "DoH resolver for %@ does not match trusted DoH template %s for %@",
752 doh_endpoint
, trusted_doh_template
, trusted_name_endpoint
);
756 os_log(_mdns_dns_service_log(), "DoH resolver at %@ is trusted for %@",
757 doh_endpoint
, trusted_name_endpoint
);
759 xpc_array_apply(candidate_dns_zones
, ^bool(__unused
size_t index
, xpc_object_t _Nonnull array_value
) {
760 const char *dns_zone
= xpc_string_get_string_ptr(array_value
);
762 os_log(_mdns_dns_service_log(), "Adding domain %s to discovered DoH resolver for %@",
763 dns_zone
, doh_endpoint
);
764 _mdns_dns_service_add_domain(service
, dns_zone
, 0);
768 os_log_error(_mdns_dns_service_log(), "No PvD file found at %@ for DoH server %@",
769 trusted_name_endpoint
, doh_endpoint
);
772 http_task_cancel(trusted_name_task
);
773 nw_release(trusted_name_endpoint
);
774 nw_release(doh_endpoint
);
775 xpc_release(candidate_dns_zones
);
776 mdns_release(service
);
778 http_task_start(trusted_name_task
);
782 _mdns_get_future_continuous_time(uint64_t seconds
)
784 static dispatch_once_t onceToken
;
785 static mach_timebase_info_data_t time_base
= {0, 0};
786 dispatch_once(&onceToken
, ^{
787 mach_timebase_info(&time_base
);
789 uint64_t delta
= seconds
* NSEC_PER_SEC
;
790 delta
*= time_base
.denom
;
791 delta
/= time_base
.numer
;
792 return mach_continuous_time() + delta
;
796 _mdns_dns_service_manager_fetch_doh_pvd(const mdns_dns_service_manager_t me
,
797 mdns_dns_service_t service
)
799 __block
void *task
= NULL
;
800 mdns_retain(service
);
802 nw_endpoint_t doh_endpoint
= service
->discovered
.url_endpoint
;
803 nw_retain(doh_endpoint
);
804 task
= http_task_create_pvd_query(me
->queue
,
805 nw_endpoint_get_hostname(doh_endpoint
),
806 nw_endpoint_get_url_path(doh_endpoint
), ^(xpc_object_t json_object
) {
808 if (json_object
!= NULL
) {
809 const char *doh_template
= xpc_dictionary_get_string(json_object
, "dohTemplate");
810 if (doh_template
== NULL
) {
811 os_log_error(_mdns_dns_service_log(), "DoH resolver for %@ missing DoH template", doh_endpoint
);
815 // If the string is suffixed by a string like "{?dns}", trim off that variable template
816 size_t template_length
= strlen(doh_template
);
817 const char *template_portion
= strchr(doh_template
, '{');
818 if (template_portion
!= NULL
) {
819 template_length
= (size_t)(template_portion
- doh_template
);
822 const char *doh_string
= nw_endpoint_get_url(doh_endpoint
);
823 if (doh_string
== NULL
||
824 strlen(doh_string
) != template_length
||
825 strncasecmp(doh_template
, doh_string
, template_length
) != 0) {
826 os_log_error(_mdns_dns_service_log(), "DoH resolver for %@ does not match DoH template %s",
827 doh_endpoint
, doh_template
);
831 uint64_t seconds_remaining
= xpc_dictionary_get_uint64(json_object
, "secondsRemaining");
832 if (seconds_remaining
== 0) {
833 seconds_remaining
= xpc_dictionary_get_uint64(json_object
, "seconds-remaining");
835 if (seconds_remaining
!= 0) {
836 os_log_info(_mdns_dns_service_log(), "DoH resolver for %@ will expire in %llu seconds",
837 doh_endpoint
, seconds_remaining
);
838 service
->discovered
.expire_time
= _mdns_get_future_continuous_time(seconds_remaining
);
840 os_log_info(_mdns_dns_service_log(), "DoH resolver for %@ does not specify an expiration",
842 service
->discovered
.expire_time
= 0;
845 xpc_object_t dns_zone_array
= xpc_dictionary_get_value(json_object
, "dnsZones");
847 xpc_object_t trusted_names_array
= xpc_dictionary_get_value(json_object
, "trustedNames");
848 if (trusted_names_array
&& xpc_get_type(trusted_names_array
) == XPC_TYPE_ARRAY
) {
849 xpc_array_apply(trusted_names_array
, ^bool(__unused
size_t index
, xpc_object_t _Nonnull array_value
) {
850 if (xpc_get_type(array_value
) == XPC_TYPE_STRING
) {
851 const char *trusted_name
= xpc_string_get_string_ptr(array_value
);
852 os_log(_mdns_dns_service_log(), "Query trusted name %s for DoH resolver for %@",
853 trusted_name
, doh_endpoint
);
854 _mdns_dns_service_manager_fetch_trusted_name_pvd(me
, service
, doh_endpoint
, dns_zone_array
, trusted_name
);
861 http_task_cancel(task
);
862 mdns_release(service
);
863 nw_release(doh_endpoint
);
865 http_task_start(task
);
869 _mdns_dns_service_manager_check_service_expiration(const mdns_dns_service_manager_t me
,
870 mdns_dns_service_t service
)
872 // Check if a service is expired
873 if (service
->discovered
.expire_time
!= 0 &&
874 service
->discovered
.expire_time
< mach_continuous_time()) {
876 os_log_info(_mdns_dns_service_log(), "DoH resolver for %@ has passed expiration",
877 service
->discovered
.url_endpoint
);
879 service
->discovered
.expire_time
= 0;
881 // Clear out domain list, in case they have changed
883 while ((item
= service
->domain_list
) != NULL
) {
884 service
->domain_list
= item
->next
;
885 _domain_item_free(item
);
888 // Refresh PvD to rebuild the list
889 _mdns_dns_service_manager_fetch_doh_pvd(me
, service
);
894 _mdns_dns_service_manager_register_doh_uri_internal(const mdns_dns_service_manager_t me
,
895 const char *doh_uri
, const char *domain
)
897 mdns_dns_service_t service
= NULL
;
898 nw_endpoint_t doh_endpoint
= NULL
;
902 // Make a copy of the string in case it needs to be sanitized
903 uri_string
= strdup(doh_uri
);
904 require_quiet(uri_string
, exit
);
906 // If the string is suffixed by a string like "{?dns}", trim off that variable template
907 char *template_portion
= strchr(uri_string
, '{');
908 if (template_portion
!= NULL
) {
909 template_portion
[0] = '\0';
912 doh_endpoint
= nw_endpoint_create_url(uri_string
);
913 require_action_quiet(doh_endpoint
, exit
, err
= kNoResourcesErr
);
915 const char *scheme
= nw_endpoint_get_url_scheme(doh_endpoint
);
916 require_action_quiet((scheme
!= NULL
&& strcasecmp("https", scheme
) == 0), exit
, err
= kMalformedErr
);
918 service
= _mdns_dns_service_manager_get_discovered_service(me
, doh_endpoint
);
919 if (service
== NULL
) {
920 os_log(_mdns_dns_service_log(), "Registering discovered DoH resolver at %s", uri_string
);
922 service
= _mdns_dns_service_create_from_doh_uri(doh_endpoint
, NULL
);
924 _mdns_dns_service_manager_add_service(me
, me
->discovered_services
, service
);
925 mdns_release(service
);
926 _mdns_dns_service_manager_fetch_doh_pvd(me
, service
);
930 if (service
&& domain
) {
931 os_log(_mdns_dns_service_log(), "Adding domain %s to DoH resolver at %s", domain
, uri_string
);
932 _mdns_dns_service_add_domain(service
, domain
, 0);
937 nw_forget(&doh_endpoint
);
941 static mdns_dns_service_t
942 _mdns_dns_service_create_from_doh_uri(nw_endpoint_t url_endpoint
, OSStatus
* const out_error
)
944 nw_resolver_config_t config
= nw_resolver_config_create();
945 nw_resolver_config_set_class(config
, nw_resolver_class_designated
);
946 nw_resolver_config_set_protocol(config
, nw_resolver_protocol_doh
);
947 nw_resolver_config_set_provider_name(config
, nw_endpoint_get_hostname(url_endpoint
));
948 nw_resolver_config_set_provider_path(config
, nw_endpoint_get_url_path(url_endpoint
));
950 uuid_t new_identifier
;
951 uuid_generate(new_identifier
);
952 nw_resolver_config_set_identifier(config
, new_identifier
);
955 const mdns_dns_service_t service
= _mdns_dns_service_create(mdns_dns_service_source_dns
,
956 mdns_dns_service_scope_uuid
, mdns_resolver_type_null
, &err
);
957 require_noerr_quiet(err
, exit
);
959 service
->discovered
.url_endpoint
= nw_retain(url_endpoint
);
960 service
->discovered
.squash_cnames
= true;
961 service
->config
= config
;
963 service
->flags
= (mdns_dns_service_flag_a_queries_advised
| mdns_dns_service_flag_aaaa_queries_advised
);
973 //======================================================================================================================
976 mdns_dns_service_manager_invalidate(const mdns_dns_service_manager_t me
)
978 dispatch_sync(me
->queue
,
980 require_return(!me
->invalidated
);
981 _mdns_dns_service_manager_terminate(me
, kNoErr
);
982 me
->invalidated
= true;
986 //======================================================================================================================
989 mdns_dns_service_manager_get_unscoped_service(const mdns_dns_service_manager_t me
, const uint8_t * const name
)
991 __block mdns_dns_service_t result
;
992 dispatch_sync(me
->queue
,
994 require_return_action(!me
->terminated
, result
= NULL
);
995 const mdns_dns_service_scope_t scope
= mdns_dns_service_scope_none
;
996 const mdns_dns_service_t service
= _mdns_dns_service_manager_get_service(me
, name
, scope
, 0);
997 result
= _mdns_dns_service_manager_prepare_service(me
, service
);
1002 //======================================================================================================================
1005 mdns_dns_service_manager_get_interface_scoped_service(const mdns_dns_service_manager_t me
, const uint8_t * const name
,
1006 const uint32_t if_index
)
1008 __block mdns_dns_service_t result
;
1009 dispatch_sync(me
->queue
,
1011 require_return_action(!me
->terminated
, result
= NULL
);
1012 const mdns_dns_service_scope_t scope
= mdns_dns_service_scope_interface
;
1013 const mdns_dns_service_t service
= _mdns_dns_service_manager_get_service(me
, name
, scope
, if_index
);
1014 result
= _mdns_dns_service_manager_prepare_service(me
, service
);
1019 //======================================================================================================================
1022 mdns_dns_service_manager_get_service_scoped_service(const mdns_dns_service_manager_t me
, const uint8_t * const name
,
1023 const uint32_t service_id
)
1025 __block mdns_dns_service_t result
;
1026 dispatch_sync(me
->queue
,
1028 require_return_action(!me
->terminated
, result
= NULL
);
1029 const mdns_dns_service_scope_t scope
= mdns_dns_service_scope_service
;
1030 const mdns_dns_service_t service
= _mdns_dns_service_manager_get_service(me
, name
, scope
, service_id
);
1031 result
= _mdns_dns_service_manager_prepare_service(me
, service
);
1036 //======================================================================================================================
1038 static mdns_dns_service_t
1039 _mdns_dns_service_manager_get_custom_service(mdns_dns_service_manager_t manager
, mdns_dns_service_id_t ident
);
1042 mdns_dns_service_manager_get_custom_service(const mdns_dns_service_manager_t me
, const mdns_dns_service_id_t ident
)
1044 __block mdns_dns_service_t result
;
1045 dispatch_sync(me
->queue
,
1047 require_return_action(!me
->terminated
, result
= NULL
);
1048 const mdns_dns_service_t service
= _mdns_dns_service_manager_get_custom_service(me
, ident
);
1049 result
= _mdns_dns_service_manager_prepare_service(me
, service
);
1054 static mdns_dns_service_t
1055 _mdns_dns_service_manager_get_custom_service(const mdns_dns_service_manager_t me
, const mdns_dns_service_id_t ident
)
1057 const CFIndex n
= CFArrayGetCount(me
->custom_services
);
1058 for (CFIndex i
= 0; i
< n
; ++i
) {
1059 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(me
->custom_services
, i
);
1060 if (service
->ident
== ident
) {
1067 //======================================================================================================================
1070 mdns_dns_service_manager_get_uuid_scoped_service(const mdns_dns_service_manager_t me
, const uuid_t uuid
)
1072 __block mdns_dns_service_t result
;
1073 dispatch_sync(me
->queue
,
1075 require_return_action(!me
->terminated
, result
= NULL
);
1076 const mdns_dns_service_t service
= _mdns_dns_service_manager_get_uuid_scoped_service(me
, uuid
);
1077 result
= _mdns_dns_service_manager_prepare_service(me
, service
);
1082 //======================================================================================================================
1085 _mdns_dns_service_manager_fillout_discovered_service_for_name(mdns_dns_service_manager_t manager
,
1086 const uint8_t *name
, uuid_t out_uuid
);
1089 mdns_dns_service_manager_fillout_discovered_service_for_name(const mdns_dns_service_manager_t me
,
1090 const uint8_t * const name
, uuid_t out_uuid
)
1092 __block
bool success
= false;
1093 dispatch_sync(me
->queue
,
1095 require_return(!me
->terminated
);
1096 success
= _mdns_dns_service_manager_fillout_discovered_service_for_name(me
, name
, out_uuid
);
1102 _mdns_dns_service_manager_fillout_discovered_service_for_name(const mdns_dns_service_manager_t me
,
1103 const uint8_t * const name
, uuid_t out_uuid
)
1105 mdns_dns_service_t service
= NULL
;
1106 int best_label_count
= -1;
1107 const CFIndex n
= CFArrayGetCount(me
->discovered_services
);
1108 for (CFIndex i
= 0; i
< n
; ++i
) {
1109 mdns_dns_service_t candidate
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(me
->discovered_services
, i
);
1110 const int label_count
= _mdns_dns_service_handles_domain_name(candidate
, name
, NULL
);
1111 if (candidate
->config
&& (label_count
> best_label_count
)) {
1112 service
= candidate
;
1113 best_label_count
= label_count
;
1116 // Check if service details have expired while iterating the list
1117 _mdns_dns_service_manager_check_service_expiration(me
, candidate
);
1121 // Update the most recent use (approximate) time for this service
1122 service
->discovered
.use_time
= mach_continuous_approximate_time();
1123 nw_resolver_config_get_identifier(service
->config
, out_uuid
);
1129 //======================================================================================================================
1132 _mdns_dns_service_manager_apply_pending_updates_internal(mdns_dns_service_manager_t manager
);
1135 _mdns_dns_service_manager_finish_defuncting_services(CFMutableArrayRef services
);
1138 _mdns_dns_service_manager_update_service_usability(CFMutableArrayRef services
);
1141 mdns_dns_service_manager_apply_pending_updates(const mdns_dns_service_manager_t me
)
1143 dispatch_sync(me
->queue
,
1145 require_return(!me
->terminated
);
1146 _mdns_dns_service_manager_apply_pending_updates_internal(me
);
1151 _mdns_dns_service_manager_apply_pending_updates_internal(const mdns_dns_service_manager_t me
)
1153 _mdns_dns_service_manager_finish_defuncting_services(me
->path_services
);
1154 _mdns_dns_service_manager_finish_defuncting_services(me
->custom_services
);
1155 _mdns_dns_service_manager_update_service_usability(me
->path_services
);
1156 _mdns_dns_service_manager_update_service_usability(me
->discovered_services
);
1157 _mdns_dns_service_manager_update_service_usability(me
->custom_services
);
1158 _mdns_dns_service_manager_remove_unneeded_interface_monitors(me
);
1159 _mdns_dns_service_manager_update_interface_properties(me
);
1163 _mdns_dns_service_manager_finish_defuncting_services(const CFMutableArrayRef services
)
1165 for (CFIndex i
= CFArrayGetCount(services
) - 1; i
>= 0; --i
) {
1166 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(services
, i
);
1167 if (service
->defuncting
) {
1168 _mdns_dns_service_make_defunct(service
);
1169 CFArrayRemoveValueAtIndex(services
, i
);
1175 _mdns_dns_service_manager_update_service_usability(const CFMutableArrayRef services
)
1177 const CFIndex n
= CFArrayGetCount(services
);
1178 for (CFIndex i
= 0; i
< n
; ++i
) {
1179 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(services
, i
);
1180 if (service
->cannot_connect
) {
1181 if (!(service
->flags
& mdns_dns_service_flag_connection_problems
)) {
1182 service
->flags
|= mdns_dns_service_flag_connection_problems
;
1185 if (service
->flags
& mdns_dns_service_flag_connection_problems
) {
1186 service
->flags
&= ~mdns_dns_service_flag_connection_problems
;
1192 //======================================================================================================================
1195 mdns_dns_service_manager_iterate(const mdns_dns_service_manager_t me
, const mdns_dns_service_applier_t applier
)
1197 dispatch_sync(me
->queue
,
1199 require_return(!me
->terminated
);
1200 _mdns_dns_service_manager_iterate_over_all_service_arrays(me
,
1201 ^ bool (const CFMutableArrayRef service_array
)
1204 const CFIndex n
= CFArrayGetCount(service_array
);
1205 for (CFIndex i
= 0; i
< n
; ++i
) {
1206 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(service_array
, i
);
1207 stop
= applier(service
);
1217 //======================================================================================================================
1220 mdns_dns_service_manager_get_count(const mdns_dns_service_manager_t me
)
1222 __block
size_t count
= 0;
1223 dispatch_sync(me
->queue
,
1225 require_return(!me
->terminated
);
1226 _mdns_dns_service_manager_iterate_over_all_service_arrays(me
,
1227 ^ bool (const CFMutableArrayRef service_array
)
1229 count
+= (size_t)CFArrayGetCount(service_array
);
1236 //======================================================================================================================
1239 mdns_dns_service_manager_handle_sleep(const mdns_dns_service_manager_t me
)
1241 mdns_dns_service_manager_iterate(me
,
1242 ^ bool (const mdns_dns_service_t service
)
1244 const mdns_resolver_type_t type
= _mdns_dns_service_get_resolver_type_safe(service
);
1245 if ((type
== mdns_resolver_type_tls
) || (type
== mdns_resolver_type_https
)) {
1246 if (service
->resolver
) {
1247 mdns_resolver_forget(&service
->resolver
);
1248 service
->replace_resolver
= true;
1255 //======================================================================================================================
1258 mdns_dns_service_manager_handle_wake(const mdns_dns_service_manager_t me
)
1260 mdns_dns_service_manager_iterate(me
,
1261 ^ bool (const mdns_dns_service_t service
)
1263 if (service
->replace_resolver
) {
1264 _mdns_dns_service_manager_prepare_service(me
, service
);
1265 service
->replace_resolver
= false;
1271 //======================================================================================================================
1272 // MARK: - DNS Service Manager Private Methods
1275 _mdns_dns_service_manager_finalize(mdns_dns_service_manager_t me
)
1277 ForgetCF(&me
->default_services
);
1278 ForgetCF(&me
->path_services
);
1279 ForgetCF(&me
->discovered_services
);
1280 ForgetCF(&me
->custom_services
);
1281 ForgetCF(&me
->monitors
);
1282 dispatch_forget(&me
->queue
);
1283 dispatch_forget(&me
->user_queue
);
1284 BlockForget(&me
->event_handler
);
1287 //======================================================================================================================
1290 _mdns_dns_service_manager_print_description(const mdns_dns_service_manager_t me
, const bool debug
, const bool privacy
,
1291 char * const buf_ptr
, const size_t buf_len
, size_t *out_len
, size_t *out_true_len
);
1294 _mdns_dns_service_manager_copy_description(const mdns_dns_service_manager_t me
, const bool debug
, const bool privacy
)
1296 char *description
= NULL
;
1300 OSStatus err
= _mdns_dns_service_manager_print_description(me
, debug
, privacy
, buf
, sizeof(buf
), NULL
, &true_len
);
1301 require_noerr_quiet(err
, exit
);
1303 if (true_len
< sizeof(buf
)) {
1304 description
= strdup(buf
);
1306 const size_t buf_len
= true_len
+ 1;
1307 char *buf_ptr
= malloc(buf_len
);
1308 require_quiet(buf_ptr
, exit
);
1310 err
= _mdns_dns_service_manager_print_description(me
, debug
, privacy
, buf_ptr
, buf_len
, NULL
, NULL
);
1312 description
= buf_ptr
;
1323 _mdns_dns_service_print_description(const mdns_dns_service_t service
, const bool debug
, const bool privacy
,
1324 char * const buf_ptr
, const size_t buf_len
, size_t *out_len
, size_t *out_true_len
);
1327 _mdns_dns_service_manager_print_description(const mdns_dns_service_manager_t me
, const bool debug
, const bool privacy
,
1328 char * const buf_ptr
, const size_t buf_len
, size_t *out_len
, size_t *out_true_len
)
1331 char * dst
= buf_ptr
;
1332 const char * const lim
= &buf_ptr
[buf_len
];
1333 size_t true_len
= 0;
1336 #define _do_appendf(...) \
1338 n = mdns_snprintf_add(&dst, lim, __VA_ARGS__); \
1339 require_action_quiet(n >= 0, exit, err = kUnknownErr); \
1340 true_len += (size_t)n; \
1344 _do_appendf("<%s: %p>: ", me
->base
.kind
->name
, me
);
1346 const CFArrayRef service_arrays
[] = {
1347 MDNS_DNS_SERVICE_MANAGER_ARRAYS(me
)
1350 const char *sep
= "";
1351 for (size_t i
= 0; i
< countof(service_arrays
); ++i
) {
1352 const CFArrayRef services
= service_arrays
[i
];
1353 const CFIndex service_count
= CFArrayGetCount(services
);
1354 for (CFIndex j
= 0; j
< service_count
; ++j
) {
1355 _do_appendf("%s\n\t", sep
);
1356 size_t len
, true_len2
;
1357 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(services
, j
);
1358 err
= _mdns_dns_service_print_description(service
, false, privacy
, dst
, (size_t)(lim
- dst
), &len
,
1360 require_noerr_quiet(err
, exit
);
1363 true_len
+= true_len2
;
1371 *out_len
= (size_t)(dst
- buf_ptr
);
1374 *out_true_len
= true_len
;
1382 //======================================================================================================================
1385 _mdns_dns_service_manager_terminate_services(mdns_dns_service_manager_t manager
, CFMutableArrayRef services
);
1388 _mdns_dns_service_manager_terminate(const mdns_dns_service_manager_t me
, const OSStatus error
)
1390 require_return(!me
->invalidated
);
1392 me
->terminated
= true;
1393 dispatch_source_forget(&me
->update_source
);
1394 CFIndex n
= CFArrayGetCount(me
->monitors
);
1395 for (CFIndex i
= 0; i
< n
; ++i
) {
1396 mdns_interface_monitor_invalidate((mdns_interface_monitor_t
)CFArrayGetValueAtIndex(me
->monitors
, i
));
1398 CFArrayRemoveAllValues(me
->monitors
);
1400 _mdns_dns_service_manager_terminate_services(me
, me
->default_services
);
1401 _mdns_dns_service_manager_terminate_services(me
, me
->path_services
);
1402 _mdns_dns_service_manager_terminate_services(me
, me
->discovered_services
);
1403 _mdns_dns_service_manager_terminate_services(me
, me
->custom_services
);
1406 dispatch_async(me
->user_queue
,
1408 if (me
->event_handler
) {
1409 me
->event_handler(error
? mdns_event_error
: mdns_event_invalidated
, error
);
1416 _mdns_dns_service_manager_terminate_services(const mdns_dns_service_manager_t me
, const CFMutableArrayRef services
)
1418 const CFIndex n
= CFArrayGetCount(services
);
1419 for (CFIndex i
= 0; i
< n
; ++i
) {
1420 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(services
, i
);
1421 if (service
->config
&& service
->config_needs_cancel
) {
1422 _mdns_dns_service_manager_cancel_resolver_config_updates(me
, service
->config
);
1423 service
->config_needs_cancel
= false;
1425 _mdns_dns_service_make_defunct((mdns_dns_service_t
)CFArrayGetValueAtIndex(services
, i
));
1427 CFArrayRemoveAllValues(services
);
1430 //======================================================================================================================
1433 _mdns_dns_service_manager_add_service(const mdns_dns_service_manager_t me
, const CFMutableArrayRef services
,
1434 const mdns_dns_service_t service
)
1436 CFArrayAppendValue(services
, service
);
1437 _mdns_dns_service_manager_update_interface_properties_for_service(me
, service
);
1440 //======================================================================================================================
1442 static mdns_dns_service_t
1443 _mdns_dns_service_manager_get_service(const mdns_dns_service_manager_t me
, const uint8_t * const name
,
1444 const mdns_dns_service_scope_t scope
, const uint32_t scoping_id
)
1446 mdns_dns_service_t best_service
= NULL
;
1447 int best_label_count
= -1;
1448 uint32_t best_order
= 0;
1449 // Find the best service.
1450 const CFIndex n
= CFArrayGetCount(me
->default_services
);
1451 for (CFIndex i
= 0; i
< n
; ++i
) {
1452 mdns_dns_service_t candidate
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(me
->default_services
, i
);
1453 if (candidate
->scope
!= scope
) {
1457 case mdns_dns_service_scope_interface
:
1458 if (candidate
->if_index
!= scoping_id
) {
1463 case mdns_dns_service_scope_service
:
1464 if (candidate
->service_id
!= scoping_id
) {
1470 case mdns_dns_service_scope_none
:
1474 const int label_count
= _mdns_dns_service_handles_domain_name(candidate
, name
, &order
);
1475 if (label_count
< 0) {
1478 // The longer a service's parent domain match (in terms of label count), the better the service.
1479 // If a service has a parent domain match with a label count equal to that of the best service so far,
1480 // and its parent domain's order value is less than the current best service's parent domain's order
1481 // value (i.e., it has a higher priority), then it's a better service.
1482 if ((label_count
> best_label_count
) || ((label_count
== best_label_count
) && (order
< best_order
))) {
1483 best_service
= candidate
;
1484 best_label_count
= label_count
;
1488 return best_service
;
1491 //======================================================================================================================
1493 static mdns_dns_service_t
1494 _mdns_dns_service_manager_get_service_by_config_uuid(CFArrayRef services
, const uuid_t uuid
);
1496 static mdns_dns_service_t
1497 _mdns_dns_service_manager_get_uuid_scoped_service(const mdns_dns_service_manager_t me
, const uuid_t uuid
)
1499 // First check in discovered services
1500 mdns_dns_service_t service
= _mdns_dns_service_manager_get_service_by_config_uuid(me
->discovered_services
, uuid
);
1502 service
= _mdns_dns_service_manager_get_service_by_config_uuid(me
->path_services
, uuid
);
1507 static mdns_dns_service_t
1508 _mdns_dns_service_manager_get_service_by_config_uuid(const CFArrayRef services
, const uuid_t uuid
)
1510 const CFIndex n
= CFArrayGetCount(services
);
1511 for (CFIndex i
= 0; i
< n
; ++i
) {
1512 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(services
, i
);
1513 if (service
->config
) {
1514 uuid_t config_uuid
= {0};
1515 nw_resolver_config_get_identifier(service
->config
, config_uuid
);
1516 if (uuid_compare(uuid
, config_uuid
) == 0) {
1524 //======================================================================================================================
1526 static mdns_dns_service_t
1527 _mdns_dns_service_manager_get_discovered_service(const mdns_dns_service_manager_t me
, nw_endpoint_t url_endpoint
)
1529 const char *hostname
= nw_endpoint_get_hostname(url_endpoint
);
1530 const char *path
= nw_endpoint_get_url_path(url_endpoint
);
1531 if (hostname
== NULL
|| path
== NULL
) {
1535 const CFIndex n
= CFArrayGetCount(me
->discovered_services
);
1536 for (CFIndex i
= 0; i
< n
; ++i
) {
1537 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(me
->discovered_services
, i
);
1538 if (service
->config
&&
1539 nw_resolver_config_get_protocol(service
->config
) == nw_resolver_protocol_doh
) {
1541 const char *config_hostname
= nw_resolver_config_get_provider_name(service
->config
);
1542 const char *config_path
= nw_resolver_config_get_provider_path(service
->config
);
1543 if (strcmp(hostname
, config_hostname
) == 0 ||
1544 strcmp(path
, config_path
) == 0) {
1552 //======================================================================================================================
1555 _mdns_dns_service_manager_update_interface_properties(const mdns_dns_service_manager_t me
)
1557 _mdns_dns_service_manager_update_interface_properties_for_services(me
, me
->default_services
);
1558 _mdns_dns_service_manager_update_interface_properties_for_services(me
, me
->path_services
);
1559 _mdns_dns_service_manager_update_interface_properties_for_services(me
, me
->discovered_services
);
1560 _mdns_dns_service_manager_update_interface_properties_for_services(me
, me
->custom_services
);
1563 //======================================================================================================================
1566 _mdns_dns_service_manager_uses_interface(mdns_dns_service_manager_t manager
, uint32_t if_index
);
1569 _mdns_dns_services_use_interface(CFArrayRef services
, uint32_t if_index
);
1572 _mdns_dns_service_manager_remove_unneeded_interface_monitors(const mdns_dns_service_manager_t me
)
1574 for (CFIndex i
= CFArrayGetCount(me
->monitors
) - 1; i
>= 0; --i
) {
1575 const mdns_interface_monitor_t monitor
= (mdns_interface_monitor_t
)CFArrayGetValueAtIndex(me
->monitors
, i
);
1576 const uint32_t if_index
= mdns_interface_monitor_get_interface_index(monitor
);
1577 const bool needed
= _mdns_dns_service_manager_uses_interface(me
, if_index
);
1579 mdns_interface_monitor_invalidate(monitor
);
1580 CFArrayRemoveValueAtIndex(me
->monitors
, i
);
1586 _mdns_dns_service_manager_uses_interface(const mdns_dns_service_manager_t me
, const uint32_t if_index
)
1588 if (_mdns_dns_services_use_interface(me
->default_services
, if_index
) ||
1589 _mdns_dns_services_use_interface(me
->path_services
, if_index
) ||
1590 _mdns_dns_services_use_interface(me
->discovered_services
, if_index
) ||
1591 _mdns_dns_services_use_interface(me
->custom_services
, if_index
)) {
1599 _mdns_dns_services_use_interface(const CFArrayRef services
, const uint32_t if_index
)
1601 const CFIndex n
= CFArrayGetCount(services
);
1602 for (CFIndex i
= 0; i
< n
; ++i
) {
1603 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(services
, i
);
1604 if (service
->if_index
== if_index
) {
1611 //======================================================================================================================
1614 _mdns_dns_service_manager_update_interface_properties_for_services(const mdns_dns_service_manager_t me
,
1615 const CFArrayRef services
)
1617 const CFIndex n
= CFArrayGetCount(services
);
1618 for (CFIndex i
= 0; i
< n
; ++i
) {
1619 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(services
, i
);
1620 _mdns_dns_service_manager_update_interface_properties_for_service(me
, service
);
1624 //======================================================================================================================
1626 static mdns_interface_monitor_t
1627 _mdns_dns_service_manager_get_interface_monitor(mdns_dns_service_manager_t manager
, uint32_t if_index
);
1630 _mdns_dns_service_manager_update_interface_properties_for_service(const mdns_dns_service_manager_t me
,
1631 const mdns_dns_service_t service
)
1633 require_quiet(service
->if_index
!= 0, exit
);
1635 const mdns_interface_monitor_t monitor
= _mdns_dns_service_manager_get_interface_monitor(me
, service
->if_index
);
1636 require_action_quiet(monitor
, exit
,
1637 os_log_error(_mdns_dns_service_log(), "Failed to get interface monitor for interface %{public}s/%u",
1638 service
->if_name
? service
->if_name
: "", service
->if_index
));
1640 service
->flags
&= ~MDNS_DNS_SERVICE_FLAGS_FROM_INTERFACE_MONITOR
;
1641 if (mdns_interface_monitor_has_ipv4_connectivity(monitor
)) {
1642 service
->flags
|= mdns_dns_service_flag_ipv4_connectivity
;
1644 if (mdns_interface_monitor_has_ipv6_connectivity(monitor
)) {
1645 service
->flags
|= mdns_dns_service_flag_ipv6_connectivity
;
1647 if (mdns_interface_monitor_is_expensive(monitor
)) {
1648 service
->flags
|= mdns_dns_service_flag_expensive
;
1650 if (mdns_interface_monitor_is_constrained(monitor
)) {
1651 service
->flags
|= mdns_dns_service_flag_constrained
;
1653 if (mdns_interface_monitor_is_clat46(monitor
)) {
1654 service
->flags
|= mdns_dns_service_flag_clat46
;
1656 if (mdns_interface_monitor_is_vpn(monitor
)) {
1657 service
->flags
|= mdns_dns_service_flag_vpn
;
1664 static mdns_interface_monitor_t
1665 _mdns_dns_service_manager_get_interface_monitor(const mdns_dns_service_manager_t me
, const uint32_t if_index
)
1667 mdns_interface_monitor_t monitor
= NULL
;
1668 const CFIndex n
= CFArrayGetCount(me
->monitors
);
1669 for (CFIndex i
= 0; i
< n
; ++i
) {
1670 mdns_interface_monitor_t candidate
= (mdns_interface_monitor_t
)CFArrayGetValueAtIndex(me
->monitors
, i
);
1671 if (mdns_interface_monitor_get_interface_index(candidate
) == if_index
) {
1672 monitor
= candidate
;
1679 monitor
= mdns_interface_monitor_create(if_index
);
1680 require_quiet(monitor
, exit
);
1682 mdns_interface_monitor_set_queue(monitor
, me
->queue
);
1684 mdns_interface_monitor_set_update_handler(monitor
,
1685 ^(mdns_interface_flags_t change_flags
)
1687 const mdns_interface_flags_t relevant_flags
=
1688 mdns_interface_flag_ipv4_connectivity
|
1689 mdns_interface_flag_ipv6_connectivity
|
1690 mdns_interface_flag_expensive
|
1691 mdns_interface_flag_constrained
|
1692 mdns_interface_flag_clat46
|
1693 mdns_interface_flag_vpn
;
1694 if ((change_flags
& relevant_flags
) != 0) {
1695 const CFRange full_range
= CFRangeMake(0, CFArrayGetCount(me
->monitors
));
1696 if (CFArrayContainsValue(me
->monitors
, full_range
, monitor
)) {
1697 _mdns_dns_service_manager_trigger_update(me
);
1701 mdns_interface_monitor_set_event_handler(monitor
,
1702 ^(mdns_event_t event
, __unused OSStatus error
)
1705 case mdns_event_invalidated
:
1706 mdns_release(monitor
);
1710 case mdns_event_error
: {
1711 const CFRange full_range
= CFRangeMake(0, CFArrayGetCount(me
->monitors
));
1712 const CFIndex i
= CFArrayGetFirstIndexOfValue(me
->monitors
, full_range
, monitor
);
1714 CFArrayRemoveValueAtIndex(me
->monitors
, i
);
1716 mdns_interface_monitor_invalidate(monitor
);
1723 mdns_interface_monitor_activate(monitor
);
1724 CFArrayAppendValue(me
->monitors
, monitor
);
1730 //======================================================================================================================
1731 // MARK: - DNS Service Public Methods
1734 mdns_dns_service_set_context(const mdns_dns_service_t me
, void * const context
)
1736 me
->context
= context
;
1739 //======================================================================================================================
1742 mdns_dns_service_get_context(const mdns_dns_service_t me
)
1747 //======================================================================================================================
1750 mdns_dns_service_set_context_finalizer(const mdns_dns_service_t me
, const mdns_context_finalizer_t finalizer
)
1752 me
->context_finalizer
= finalizer
;
1755 //======================================================================================================================
1758 mdns_dns_service_create_querier(const mdns_dns_service_t me
, OSStatus
* const out_error
)
1761 return mdns_resolver_create_querier(me
->resolver
, out_error
);
1764 *out_error
= kNotInUseErr
;
1770 //======================================================================================================================
1772 mdns_dns_service_scope_t
1773 mdns_dns_service_get_scope(const mdns_dns_service_t me
)
1778 //======================================================================================================================
1781 mdns_dns_service_get_interface_index(const mdns_dns_service_t me
)
1783 return me
->if_index
;
1786 //======================================================================================================================
1788 mdns_dns_service_id_t
1789 mdns_dns_service_get_id(const mdns_dns_service_t me
)
1791 return _mdns_dns_service_get_id_safe(me
);
1794 //======================================================================================================================
1797 mdns_dns_service_is_defunct(const mdns_dns_service_t me
)
1799 return ((me
->flags
& mdns_dns_service_flag_defunct
) ? true : false);
1802 //======================================================================================================================
1805 mdns_dns_service_is_encrypted(mdns_dns_service_t me
)
1807 return mdns_resolver_type_uses_encryption(_mdns_dns_service_get_resolver_type_safe(me
));
1810 //======================================================================================================================
1813 mdns_dns_service_a_queries_advised(const mdns_dns_service_t me
)
1815 return ((me
->flags
& mdns_dns_service_flag_a_queries_advised
) ? true : false);
1818 //======================================================================================================================
1821 mdns_dns_service_aaaa_queries_advised(const mdns_dns_service_t me
)
1823 return ((me
->flags
& mdns_dns_service_flag_aaaa_queries_advised
) ? true : false);
1826 //======================================================================================================================
1829 mdns_dns_service_has_connection_problems(const mdns_dns_service_t me
)
1831 return ((me
->flags
& mdns_dns_service_flag_connection_problems
) ? true : false);
1834 //======================================================================================================================
1837 mdns_dns_service_interface_has_ipv4_connectivity(const mdns_dns_service_t me
)
1839 return ((me
->flags
& mdns_dns_service_flag_ipv4_connectivity
) ? true : false);
1842 //======================================================================================================================
1845 mdns_dns_service_interface_has_ipv6_connectivity(const mdns_dns_service_t me
)
1847 return ((me
->flags
& mdns_dns_service_flag_ipv6_connectivity
) ? true : false);
1850 //======================================================================================================================
1853 mdns_dns_service_interface_is_cellular(const mdns_dns_service_t me
)
1855 return ((me
->flags
& mdns_dns_service_flag_cellular
) ? true : false);
1858 //======================================================================================================================
1861 mdns_dns_service_interface_is_expensive(const mdns_dns_service_t me
)
1863 return ((me
->flags
& mdns_dns_service_flag_expensive
) ? true : false);
1866 //======================================================================================================================
1869 mdns_dns_service_interface_is_constrained(const mdns_dns_service_t me
)
1871 return ((me
->flags
& mdns_dns_service_flag_constrained
) ? true : false);
1874 //======================================================================================================================
1877 mdns_dns_service_interface_is_clat46(const mdns_dns_service_t me
)
1879 return ((me
->flags
& mdns_dns_service_flag_clat46
) ? true : false);
1882 //======================================================================================================================
1885 mdns_dns_service_interface_is_vpn(const mdns_dns_service_t me
)
1887 return ((me
->flags
& mdns_dns_service_flag_vpn
) ? true : false);
1890 //======================================================================================================================
1893 mdns_dns_service_get_provider_name(const mdns_dns_service_t me
)
1896 const char *provider_name
= nw_resolver_config_get_provider_name(me
->config
);
1897 if (provider_name
) {
1898 return provider_name
;
1904 //======================================================================================================================
1906 mdns_resolver_type_t
1907 mdns_dns_service_get_resolver_type(const mdns_dns_service_t me
)
1909 return me
->resolver_type
;
1912 //======================================================================================================================
1913 // MARK: - DNS Service Private Methods
1916 _mdns_dns_service_finalize(const mdns_dns_service_t me
)
1919 if (me
->context_finalizer
) {
1920 me
->context_finalizer(me
->context
);
1924 ForgetCF(&me
->addresses
);
1925 _domain_item_t item
;
1926 while ((item
= me
->domain_list
) != NULL
) {
1927 me
->domain_list
= item
->next
;
1928 _domain_item_free(item
);
1930 nw_forget(&me
->discovered
.url_endpoint
);
1931 nw_forget(&me
->config
);
1932 ForgetMem(&me
->if_name
);
1935 //======================================================================================================================
1938 _mdns_dns_service_copy_description(const mdns_dns_service_t me
, const bool debug
, const bool privacy
)
1940 char *description
= NULL
;
1944 OSStatus err
= _mdns_dns_service_print_description(me
, debug
, privacy
, buf
, sizeof(buf
), NULL
, &true_len
);
1945 require_noerr_quiet(err
, exit
);
1947 if (true_len
< sizeof(buf
)) {
1948 description
= strdup(buf
);
1950 const size_t buf_len
= true_len
+ 1;
1951 char *buf_ptr
= malloc(buf_len
);
1952 require_quiet(buf_ptr
, exit
);
1954 err
= _mdns_dns_service_print_description(me
, debug
, privacy
, buf_ptr
, buf_len
, NULL
, NULL
);
1956 description
= buf_ptr
;
1967 mdns_dns_service_flags_t flag
;
1969 } mdns_dns_service_flag_description_t
;
1971 #define MDNS_DNS_SERVICE_REDACTED_STR "<REDACTED>"
1974 _mdns_dns_service_print_description(const mdns_dns_service_t me
, const bool debug
, const bool privacy
,
1975 char * const buf_ptr
, const size_t buf_len
, size_t *out_len
, size_t *out_true_len
)
1978 char * dst
= buf_ptr
;
1979 const char * const lim
= &buf_ptr
[buf_len
];
1980 size_t true_len
= 0;
1981 char * address_desc
= NULL
;
1983 #define _do_appendf(...) \
1985 const int n = mdns_snprintf_add(&dst, lim, __VA_ARGS__); \
1986 require_action_quiet(n >= 0, exit, err = kUnknownErr); \
1987 true_len += (size_t)n; \
1991 _do_appendf("<%s: %p>: ", me
->base
.kind
->name
, me
);
1995 _do_appendf("id: %llu", me
->ident
);
1998 _do_appendf(", type: ");
1999 const mdns_resolver_type_t type
= _mdns_dns_service_get_resolver_type_safe(me
);
2001 case mdns_resolver_type_normal
:
2002 _do_appendf("Do53");
2005 case mdns_resolver_type_tls
:
2009 case mdns_resolver_type_https
:
2014 _do_appendf("<unknown type %d>", (int)type
);
2019 _do_appendf(", source: ");
2020 switch (me
->source
) {
2021 case mdns_dns_service_source_sc
:
2025 case mdns_dns_service_source_nw
:
2029 case mdns_dns_service_source_dns
:
2033 case mdns_dns_service_source_custom
: {
2034 _do_appendf("custom");
2038 _do_appendf("<unknown source %d>", (int)me
->source
);
2043 _do_appendf(", scope: ");
2044 switch (me
->scope
) {
2045 case mdns_dns_service_scope_none
:
2046 _do_appendf("none");
2049 case mdns_dns_service_scope_interface
:
2050 _do_appendf("interface");
2053 case mdns_dns_service_scope_service
:
2054 _do_appendf("service (%u)", me
->service_id
);
2057 case mdns_dns_service_scope_uuid
: {
2058 _do_appendf("uuid");
2061 nw_resolver_config_get_identifier(me
->config
, uuid
);
2062 uuid_string_t uuid_str
;
2063 uuid_unparse(uuid
, uuid_str
);
2064 _do_appendf(" (%s)", uuid_str
);
2069 _do_appendf("<ERROR: unknown scope %d>", (int)me
->scope
);
2073 // Print interface index.
2074 _do_appendf(", interface: %s/%u", me
->if_name
? me
->if_name
: "", me
->if_index
);
2076 // Print server addresses.
2077 _do_appendf(", servers: {");
2079 const char *sep
= "";
2080 const CFIndex address_count
= CFArrayGetCount(me
->addresses
);
2081 for (CFIndex i
= 0; i
< address_count
; ++i
) {
2082 const mdns_address_t address
= (mdns_address_t
)CFArrayGetValueAtIndex(me
->addresses
, i
);
2086 const struct sockaddr
* const sa
= mdns_address_get_sockaddr(address
);
2087 const int family
= sa
->sa_family
;
2088 if ((family
== AF_INET
) || (family
== AF_INET6
)) {
2089 const int n
= mdns_print_obfuscated_ip_address(strbuf
, sizeof(strbuf
), sa
);
2093 str
= (family
== AF_INET
) ? "<IPv4>" : "<IPv6>";
2098 _do_appendf("%s%s", sep
, str
);
2099 const int port
= mdns_address_get_port(address
);
2101 _do_appendf(":%d", port
);
2104 address_desc
= mdns_object_copy_description(address
, false, privacy
);
2105 _do_appendf("%s%s", sep
, address_desc
? address_desc
: "<NO DESC.>");
2106 ForgetMem(&address_desc
);
2113 _do_appendf(", domains: {");
2116 for (const struct _domain_item_s
*item
= me
->domain_list
; item
; item
= item
->next
) {
2120 const int n
= DNSMessagePrintObfuscatedString(strbuf
, sizeof(strbuf
), item
->name_str
);
2121 str
= (n
>= 0) ? strbuf
: MDNS_DNS_SERVICE_REDACTED_STR
;
2123 str
= item
->name_str
;
2125 _do_appendf("%s%s", sep
, str
);
2126 if (item
->order
!= 0) {
2127 _do_appendf(" (%u)", item
->order
);
2133 // Print attributes.
2134 _do_appendf(", attributes: {");
2136 const mdns_dns_service_flag_description_t mdns_dns_service_flag_service_descs
[] = {
2137 {mdns_dns_service_flag_defunct
, "defunct"},
2138 {mdns_dns_service_flag_a_queries_advised
, "a-ok"},
2139 {mdns_dns_service_flag_aaaa_queries_advised
, "aaaa-ok"},
2140 {mdns_dns_service_flag_connection_problems
, "connection-problems"},
2143 for (size_t i
= 0; i
< countof(mdns_dns_service_flag_service_descs
); ++i
) {
2144 const mdns_dns_service_flag_description_t
* const flag_desc
= &mdns_dns_service_flag_service_descs
[i
];
2145 if (me
->flags
& flag_desc
->flag
) {
2146 _do_appendf("%s%s", sep
, flag_desc
->desc
);
2152 // Print interface properties.
2153 _do_appendf(", interface properties: {");
2155 const mdns_dns_service_flag_description_t mdns_dns_service_flag_interface_descs
[] = {
2156 {mdns_dns_service_flag_cellular
, "cellular"},
2157 {mdns_dns_service_flag_ipv4_connectivity
, "ipv4"},
2158 {mdns_dns_service_flag_ipv6_connectivity
, "ipv6"},
2159 {mdns_dns_service_flag_expensive
, "expensive"},
2160 {mdns_dns_service_flag_constrained
, "constrained"},
2161 {mdns_dns_service_flag_clat46
, "clat46"},
2162 {mdns_dns_service_flag_vpn
, "vpn"}
2165 for (size_t i
= 0; i
< countof(mdns_dns_service_flag_interface_descs
); ++i
) {
2166 const mdns_dns_service_flag_description_t
* const flag_desc
= &mdns_dns_service_flag_interface_descs
[i
];
2167 if (me
->flags
& flag_desc
->flag
) {
2168 _do_appendf("%s%s", sep
, flag_desc
->desc
);
2174 // Print additional information from resolver config object that isn't already printed.
2176 _do_appendf(", resolver config: {");
2177 const char *provider_name
= nw_resolver_config_get_provider_name(me
->config
);
2178 _do_appendf("provider name: ");
2179 if (provider_name
) {
2183 const int n
= DNSMessagePrintObfuscatedString(strbuf
, sizeof(strbuf
), provider_name
);
2184 str
= (n
>= 0) ? strbuf
: MDNS_DNS_SERVICE_REDACTED_STR
;
2186 str
= provider_name
;
2188 _do_appendf("%s", str
);
2190 const char *provider_path
= nw_resolver_config_get_provider_path(me
->config
);
2191 _do_appendf(", provider path: ");
2192 if (provider_path
) {
2196 const int n
= DNSMessagePrintObfuscatedString(strbuf
, sizeof(strbuf
), provider_path
);
2197 str
= (n
>= 0) ? strbuf
: MDNS_DNS_SERVICE_REDACTED_STR
;
2199 str
= provider_path
;
2201 _do_appendf("%s", str
);
2208 *out_len
= (size_t)(dst
- buf_ptr
);
2211 *out_true_len
= true_len
;
2216 ForgetMem(&address_desc
);
2219 //======================================================================================================================
2222 _mdns_dns_service_equal(const mdns_dns_service_t me
, const mdns_dns_service_t other
)
2224 return _mdns_dns_service_equal_ex(me
, other
, false);
2227 //======================================================================================================================
2229 static mdns_dns_service_id_t
2230 _mdns_get_next_dns_service_id(void);
2232 static mdns_dns_service_t
2233 _mdns_dns_service_create(const mdns_dns_service_source_t source
, const mdns_dns_service_scope_t scope
,
2234 const mdns_resolver_type_t resolver_type
, OSStatus
* const out_error
)
2237 mdns_dns_service_t service
= NULL
;
2238 mdns_dns_service_t obj
= _mdns_dns_service_alloc();
2239 require_action_quiet(obj
, exit
, err
= kNoMemoryErr
);
2241 obj
->ident
= _mdns_get_next_dns_service_id();
2242 obj
->source
= source
;
2244 obj
->resolver_type
= resolver_type
;
2246 obj
->addresses
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &mdns_cfarray_callbacks
);
2247 require_action_quiet(obj
->addresses
, exit
, err
= kNoResourcesErr
);
2257 mdns_release_null_safe(obj
);
2261 static mdns_dns_service_id_t
2262 _mdns_get_next_dns_service_id(void)
2264 static _Atomic(mdns_dns_service_id_t
) s_next_id
= ATOMIC_VAR_INIT(1);
2265 return atomic_fetch_add_explicit(&s_next_id
, 1, memory_order_relaxed
);
2268 //======================================================================================================================
2270 #define MDNS_INITIAL_DGRAM_RTX_INTERVAL_NONCELLULAR_SECS 1
2271 #define MDNS_INITIAL_DGRAM_RTX_INTERVAL_CELLULAR_SECS 2
2274 _mdns_dns_service_manager_handle_resolver_event(mdns_dns_service_manager_t me
, mdns_dns_service_t service
,
2275 mdns_resolver_t resolver
, mdns_resolver_event_t event
, xpc_object_t info
);
2278 _mdns_dns_service_manager_prepare_resolver(const mdns_dns_service_manager_t me
, const mdns_dns_service_t service
)
2280 require_return(!service
->resolver
);
2282 // Determine the appropriate resolver type.
2283 const mdns_resolver_type_t type
= _mdns_dns_service_get_resolver_type_safe(service
);
2284 require_return(type
!= mdns_resolver_type_null
);
2286 // Create the resolver.
2288 mdns_resolver_t resolver
= mdns_resolver_create(type
, service
->if_index
, &err
);
2289 require_action_quiet(resolver
, exit
, os_log_error(_mdns_dns_service_log(),
2290 "Failed to create resolver for service -- service id: %llu", service
->ident
));
2292 // Set up the resolver.
2293 if (service
->config
) {
2294 mdns_resolver_set_provider_name(resolver
, nw_resolver_config_get_provider_name(service
->config
));
2295 mdns_resolver_set_url_path(resolver
, nw_resolver_config_get_provider_path(service
->config
));
2297 // Squash CNAMES if this discovered config requires it.
2298 if (service
->discovered
.squash_cnames
) {
2299 mdns_resolver_set_squash_cnames(resolver
, true);
2301 const uint32_t interval_secs
= mdns_dns_service_interface_is_cellular(service
) ?
2302 MDNS_INITIAL_DGRAM_RTX_INTERVAL_CELLULAR_SECS
: MDNS_INITIAL_DGRAM_RTX_INTERVAL_NONCELLULAR_SECS
;
2303 mdns_resolver_set_initial_datagram_retransmission_interval(resolver
, interval_secs
);
2304 mdns_resolver_enable_symptom_reporting(resolver
, me
->report_symptoms
);
2305 if (type
== mdns_resolver_type_normal
) {
2306 mdns_resolver_disable_connection_reuse(resolver
, true);
2307 #if MDNS_RESOLVER_PROBLEMATIC_QTYPE_WORKAROUND
2308 mdns_resolver_enable_problematic_qtype_workaround(resolver
, me
->pqw_threshold
);
2311 const CFIndex n
= CFArrayGetCount(service
->addresses
);
2312 CFIndex add_count
= 0;
2313 for (CFIndex i
= 0; i
< n
; ++i
) {
2314 const mdns_address_t address
= (mdns_address_t
)CFArrayGetValueAtIndex(service
->addresses
, i
);
2315 const OSStatus add_err
= mdns_resolver_add_server_address(resolver
, address
);
2316 if (likely(!add_err
)) {
2319 os_log_error(_mdns_dns_service_log(),
2320 "Failed to add address to resolver -- service id: %llu, address: %@, error: %{mdns:err}ld",
2321 service
->ident
, address
, (long)add_err
);
2324 require_quiet((n
== 0) || (add_count
> 0), exit
);
2326 mdns_resolver_set_queue(resolver
, me
->queue
);
2328 mdns_retain(resolver
);
2329 mdns_retain(service
);
2330 mdns_resolver_set_event_handler(resolver
,
2331 ^(const mdns_resolver_event_t event
, const xpc_object_t info
)
2333 _mdns_dns_service_manager_handle_resolver_event(me
, service
, resolver
, event
, info
);
2335 service
->resolver
= resolver
;
2338 // Reset the "cannot connect" state if the service used to have a resolver that couldn't connect.
2339 if (service
->cannot_connect
) {
2340 service
->cannot_connect
= false;
2341 _mdns_dns_service_manager_trigger_update(me
);
2343 mdns_resolver_activate(service
->resolver
);
2346 mdns_release_null_safe(resolver
);
2350 _mdns_dns_service_manager_handle_resolver_event(const mdns_dns_service_manager_t me
,
2351 const mdns_dns_service_t service
, const mdns_resolver_t resolver
, const mdns_resolver_event_t event
,
2352 const xpc_object_t info
)
2355 case mdns_resolver_event_connection
: {
2356 require_quiet(info
, exit
);
2357 require_quiet(service
->resolver
== resolver
, exit
);
2359 bool cannot_connect
= xpc_dictionary_get_bool(info
, MDNS_RESOLVER_EVENT_CONNECTION_INFO_KEY_CANNOT_CONNECT
);
2360 os_log(_mdns_dns_service_log(),
2361 "Resolver can%{public}s connect -- service id: %llu, resolver: %@",
2362 cannot_connect
? "not" : "", service
->ident
, resolver
);
2363 if (cannot_connect
) {
2364 if (!service
->cannot_connect
) {
2365 service
->cannot_connect
= true;
2366 _mdns_dns_service_manager_trigger_update(me
);
2369 if (service
->cannot_connect
) {
2370 service
->cannot_connect
= false;
2371 _mdns_dns_service_manager_trigger_update(me
);
2376 case mdns_resolver_event_invalidated
: {
2377 os_log_info(_mdns_dns_service_log(),
2378 "Resolver has been invalidated -- service id: %llu, resolver: %@", service
->ident
, resolver
);
2379 mdns_release(resolver
);
2380 mdns_release(service
);
2385 if (os_log_debug_enabled(_mdns_dns_service_log())) {
2386 char *info_desc
= info
? xpc_copy_description(info
) : NULL
;
2387 os_log_debug(_mdns_dns_service_log(),
2388 "DNS service (%@) got unhandled event: %s info: %{public}s",
2389 service
, mdns_resolver_event_to_string(event
), info_desc
);
2390 ForgetMem(&info_desc
);
2400 //======================================================================================================================
2403 _mdns_dns_service_manager_start_defuncting(const mdns_dns_service_manager_t me
, const mdns_dns_service_t service
)
2405 if (!service
->defuncting
) {
2406 service
->defuncting
= true;
2407 _mdns_dns_service_manager_trigger_update(me
);
2411 //======================================================================================================================
2413 static mdns_dns_service_t
2414 _mdns_dns_service_manager_prepare_service(const mdns_dns_service_manager_t me
, const mdns_dns_service_t service
)
2416 require_return_value(service
, NULL
);
2417 _mdns_dns_service_manager_prepare_resolver(me
, service
);
2418 require_return_value_action(service
->resolver
, NULL
,
2419 os_log_error(_mdns_dns_service_log(), "Failed to prepare resolver -- service id: %llu", service
->ident
));
2423 //======================================================================================================================
2426 _mdns_dns_service_manager_trigger_update(const mdns_dns_service_manager_t me
)
2428 if (me
->update_source
) {
2429 dispatch_source_merge_data(me
->update_source
, 1);
2433 //======================================================================================================================
2436 _mdns_dns_service_manager_iterate_over_all_service_arrays(const mdns_dns_service_manager_t me
,
2437 const mdns_dns_service_array_applier_t applier
)
2439 const CFMutableArrayRef all_arrays
[] = {
2440 MDNS_DNS_SERVICE_MANAGER_ARRAYS(me
)
2442 for (size_t i
= 0; i
< countof(all_arrays
); ++i
) {
2443 const bool stop
= applier(all_arrays
[i
]);
2450 //======================================================================================================================
2453 _mdns_dns_service_make_defunct(const mdns_dns_service_t me
)
2455 me
->flags
|= mdns_dns_service_flag_defunct
;
2456 mdns_resolver_forget(&me
->resolver
);
2459 //======================================================================================================================
2462 _mdns_dns_service_equal_ex(const mdns_dns_service_t me
, const mdns_dns_service_t other
, const bool ignore_domains
)
2467 if (me
->scope
!= other
->scope
) {
2470 if (me
->if_index
!= other
->if_index
) {
2473 if ((me
->scope
== mdns_dns_service_scope_service
) && (me
->service_id
!= other
->service_id
)) {
2476 if (!CFEqual(me
->addresses
, other
->addresses
)) {
2479 if (!ignore_domains
) {
2480 const struct _domain_item_s
*d1
= me
->domain_list
;
2481 const struct _domain_item_s
*d2
= other
->domain_list
;
2483 if (_domain_item_compare(d1
, d2
, false) != 0) {
2496 //======================================================================================================================
2499 _mdns_dns_service_add_domain(const mdns_dns_service_t me
, const char * const name_str
, const uint32_t order
)
2502 _domain_item_t new_item
= (_domain_item_t
)calloc(1, sizeof(*new_item
));
2503 require_action_quiet(new_item
, exit
, err
= kNoMemoryErr
);
2505 uint8_t name
[kDomainNameLengthMax
];
2506 err
= DomainNameFromString(name
, name_str
, NULL
);
2507 require_noerr_quiet(err
, exit
);
2509 char normalized_name_str
[kDNSServiceMaxDomainName
];
2510 err
= DomainNameToString(name
, NULL
, normalized_name_str
, NULL
);
2511 require_noerr_quiet(err
, exit
);
2513 new_item
->name_str
= strdup(normalized_name_str
);
2514 require_action_quiet(new_item
->name_str
, exit
, err
= kNoMemoryErr
);
2516 err
= DomainNameDup(name
, &new_item
->name
, NULL
);
2517 require_noerr_quiet(err
, exit
);
2519 new_item
->label_count
= DomainNameLabelCount(new_item
->name
);
2520 require_action_quiet(new_item
->label_count
>= 0, exit
, err
= kMalformedErr
);
2522 new_item
->order
= order
;
2523 _domain_item_t
*ptr
;
2524 _domain_item_t item
;
2525 for (ptr
= &me
->domain_list
; (item
= *ptr
) != NULL
; ptr
= &item
->next
) {
2526 // Compare domain items, but ignore their order values.
2527 const int cmp
= _domain_item_compare(new_item
, item
, true);
2532 // The domain items are equal, but may have different order values. Keep the smaller order
2533 // (higher priority) value. The domain item with the larger order (lower priority) value is redundant.
2534 if (new_item
->order
< item
->order
) {
2535 item
->order
= new_item
->order
;
2540 new_item
->next
= item
;
2546 _domain_item_free(new_item
);
2551 //======================================================================================================================
2554 _mdns_dns_service_handles_domain_name(const mdns_dns_service_t me
, const uint8_t * const name
,
2555 uint32_t * const out_order
)
2558 const int label_count
= DomainNameLabelCount(name
);
2559 require_action_quiet(label_count
>= 0, exit
, result
= -1);
2561 const struct _domain_item_s
*item
;
2562 for (item
= me
->domain_list
; item
; item
= item
->next
) {
2563 if (label_count
< item
->label_count
) {
2566 const uint8_t * const ptr
= _mdns_domain_name_get_parent(name
, label_count
- item
->label_count
);
2567 if (DomainNameEqual(ptr
, item
->name
)) {
2571 require_action_quiet(item
, exit
, result
= -1);
2573 result
= item
->label_count
;
2575 *out_order
= item
->order
;
2582 //======================================================================================================================
2584 static mdns_resolver_type_t
2585 _mdns_dns_service_get_resolver_type_safe(const mdns_dns_service_t me
)
2587 if (me
->config
&& (me
->resolver_type
== mdns_resolver_type_null
)) {
2588 const nw_resolver_protocol_t proto
= nw_resolver_config_get_protocol(me
->config
);
2590 case nw_resolver_protocol_dns53
:
2591 return mdns_resolver_type_normal
;
2593 case nw_resolver_protocol_dot
:
2594 return mdns_resolver_type_tls
;
2596 case nw_resolver_protocol_doh
:
2597 return mdns_resolver_type_https
;
2600 return mdns_resolver_type_null
;
2603 return me
->resolver_type
;
2607 //======================================================================================================================
2608 // MARK: - Local Helpers
2611 _mdns_append_dns_service_from_config_by_scope(CFMutableArrayRef services
, const dns_config_t
*config
,
2612 mdns_dns_service_scope_t scope
);
2614 static CFMutableArrayRef
2615 _mdns_create_dns_service_array_from_config(const dns_config_t
* const config
, OSStatus
* const out_error
)
2618 CFMutableArrayRef result
= NULL
;
2620 CFMutableArrayRef services
= CFArrayCreateMutable(kCFAllocatorDefault
, 0, &mdns_cfarray_callbacks
);
2621 require_action_quiet(services
, exit
, err
= kNoResourcesErr
);
2623 err
= _mdns_append_dns_service_from_config_by_scope(services
, config
, mdns_dns_service_scope_none
);
2624 require_noerr_quiet(err
, exit
);
2626 err
= _mdns_append_dns_service_from_config_by_scope(services
, config
, mdns_dns_service_scope_interface
);
2627 require_noerr_quiet(err
, exit
);
2629 err
= _mdns_append_dns_service_from_config_by_scope(services
, config
, mdns_dns_service_scope_service
);
2630 require_noerr_quiet(err
, exit
);
2639 CFReleaseNullSafe(services
);
2643 #define MDNS_DNS_SERVICE_DNS_PORT 53
2644 #define MDNS_DNS_SERVICE_MDNS_PORT 5353
2647 _mdns_append_dns_service_from_config_by_scope(const CFMutableArrayRef services
, const dns_config_t
* const config
,
2648 const mdns_dns_service_scope_t scope
)
2651 mdns_dns_service_t new_service
= NULL
;
2652 dns_resolver_t
* const * resolver_array
;
2653 int32_t resolver_count
;
2655 case mdns_dns_service_scope_none
:
2656 resolver_array
= config
->resolver
;
2657 resolver_count
= config
->n_resolver
;
2660 case mdns_dns_service_scope_interface
:
2661 resolver_array
= config
->scoped_resolver
;
2662 resolver_count
= config
->n_scoped_resolver
;
2665 case mdns_dns_service_scope_service
:
2666 resolver_array
= config
->service_specific_resolver
;
2667 resolver_count
= config
->n_service_specific_resolver
;
2674 for (int32_t i
= 0; i
< resolver_count
; ++i
) {
2675 const dns_resolver_t
* const resolver
= resolver_array
[i
];
2676 if ((resolver
->port
== MDNS_DNS_SERVICE_MDNS_PORT
) || (resolver
->n_nameserver
== 0)) {
2679 // Don't let a malformed domain name prevent parsing the remaining config.
2680 if (resolver
->domain
) {
2681 uint8_t domain
[kDomainNameLengthMax
];
2682 if (DomainNameFromString(domain
, resolver
->domain
, NULL
) != kNoErr
) {
2683 os_log_error(_mdns_dns_service_log(),
2684 "Encountered invalid dns_config_t resolver domain name: %s", resolver
->domain
);
2688 new_service
= _mdns_dns_service_create(mdns_dns_service_source_sc
, scope
, mdns_resolver_type_normal
, &err
);
2689 require_noerr_quiet(err
, exit
);
2691 const uint16_t port
= (resolver
->port
== 0) ? MDNS_DNS_SERVICE_DNS_PORT
: resolver
->port
;
2692 for (int32_t j
= 0; j
< resolver
->n_nameserver
; ++j
) {
2693 const struct sockaddr
* const sa
= resolver
->nameserver
[j
];
2694 mdns_address_t address
;
2695 if (sa
->sa_family
== AF_INET
) {
2696 const struct sockaddr_in
* const sin
= (const struct sockaddr_in
*)sa
;
2697 address
= mdns_address_create_ipv4(ntohl(sin
->sin_addr
.s_addr
), port
);
2698 require_action_quiet(address
, exit
, err
= kNoMemoryErr
);
2699 } else if (sa
->sa_family
== AF_INET6
) {
2700 struct sockaddr_in6 sin6_fixed
;
2701 const struct sockaddr_in6
*sin6
= (const struct sockaddr_in6
*)sa
;
2702 if (IN6_IS_ADDR_LINKLOCAL(&sin6
->sin6_addr
) && (resolver
->if_index
!= 0) &&
2703 (sin6
->sin6_scope_id
!= resolver
->if_index
)) {
2705 sin6_fixed
.sin6_scope_id
= resolver
->if_index
;
2706 os_log(_mdns_dns_service_log(),
2707 "Corrected scope ID of link-local server address %{network:sockaddr}.*P from %u to %u",
2708 (int)sizeof(*sin6
), sin6
, sin6
->sin6_scope_id
, sin6_fixed
.sin6_scope_id
);
2711 address
= mdns_address_create_ipv6(sin6
->sin6_addr
.s6_addr
, port
, sin6
->sin6_scope_id
);
2712 require_action_quiet(address
, exit
, err
= kNoMemoryErr
);
2716 CFArrayAppendValue(new_service
->addresses
, address
);
2717 mdns_forget(&address
);
2719 new_service
->if_index
= resolver
->if_index
;
2720 new_service
->service_id
= (scope
== mdns_dns_service_scope_service
) ? resolver
->service_identifier
: 0;
2721 new_service
->flags
= mdns_dns_service_flag_null
;
2723 // Check if a service object that's identical in every way except domains and flags already exists.
2724 const char * const domain_str
= resolver
->domain
? resolver
->domain
: ".";
2725 const CFIndex n
= CFArrayGetCount(services
);
2726 for (CFIndex j
= 0; j
< n
; ++j
) {
2727 const mdns_dns_service_t service
= (mdns_dns_service_t
)CFArrayGetValueAtIndex(services
, j
);
2728 if (_mdns_dns_service_equal_ex(service
, new_service
, true)) {
2729 // Simply add the domain to the existing service.
2730 err
= _mdns_dns_service_add_domain(service
, domain_str
, resolver
->search_order
);
2731 require_noerr_quiet(err
, exit
);
2732 mdns_forget(&new_service
);
2737 // If no existing service was found, add this one.
2739 if (resolver
->flags
& DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS
) {
2740 new_service
->flags
|= mdns_dns_service_flag_a_queries_advised
;
2742 if (resolver
->flags
& DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS
) {
2743 new_service
->flags
|= mdns_dns_service_flag_aaaa_queries_advised
;
2745 #if !(TARGET_OS_OSX)
2746 if (resolver
->reach_flags
& kSCNetworkReachabilityFlagsIsWWAN
) {
2747 new_service
->flags
|= mdns_dns_service_flag_cellular
;
2750 if (new_service
->if_index
!= 0) {
2751 const char *name_ptr
;
2752 char name_buf
[IF_NAMESIZE
+ 1];
2753 name_ptr
= if_indextoname(new_service
->if_index
, name_buf
);
2754 const int name_err
= map_global_value_errno(name_ptr
, name_ptr
);
2756 new_service
->if_name
= strdup(name_ptr
);
2758 os_log_error(_mdns_dns_service_log(),
2759 "if_indextoname() for %u failed: %{darwin.errno}d", new_service
->if_index
, name_err
);
2762 err
= _mdns_dns_service_add_domain(new_service
, domain_str
, resolver
->search_order
);
2763 require_noerr_quiet(err
, exit
);
2764 CFArrayAppendValue(services
, new_service
);
2765 mdns_forget(&new_service
);
2771 mdns_release_null_safe(new_service
);
2775 //======================================================================================================================
2777 static mdns_dns_service_t
2778 _mdns_dns_service_create_from_resolver_config(const nw_resolver_config_t config
, const mdns_dns_service_source_t source
,
2779 OSStatus
* const out_error
)
2782 const mdns_dns_service_t service
= _mdns_dns_service_create(source
, mdns_dns_service_scope_uuid
,
2783 mdns_resolver_type_null
, &err
);
2784 require_noerr_quiet(err
, exit
);
2786 nw_resolver_config_enumerate_name_servers(config
,
2787 ^ bool (const char * _Nonnull name_server
)
2789 mdns_address_t address
= mdns_address_create_from_ip_address_string(name_server
);
2791 CFArrayAppendValue(service
->addresses
, address
);
2792 mdns_forget(&address
);
2796 nw_resolver_config_enumerate_match_domains(config
,
2797 ^ bool (const char * _Nonnull match_domain
)
2799 _mdns_dns_service_add_domain(service
, match_domain
, 0);
2802 service
->config
= config
;
2803 nw_retain(service
->config
);
2804 const char * const interface_name
= nw_resolver_config_get_interface_name(config
);
2805 if (interface_name
) {
2806 service
->if_name
= strdup(interface_name
);
2807 service
->if_index
= if_nametoindex(interface_name
);
2809 service
->flags
= (mdns_dns_service_flag_a_queries_advised
| mdns_dns_service_flag_aaaa_queries_advised
);
2819 //======================================================================================================================
2821 static mdns_dns_service_id_t
2822 _mdns_dns_service_get_id_safe(const mdns_dns_service_t me
)
2824 require_return_value(me
, 0);
2828 //======================================================================================================================
2830 static const uint8_t *
2831 _mdns_domain_name_get_parent(const uint8_t * const name
, const int depth
)
2833 int current_depth
= 0;
2834 const uint8_t *ptr
= name
;
2835 while ((*ptr
!= 0) && (current_depth
< depth
)) {
2842 //======================================================================================================================
2845 _domain_item_free(const _domain_item_t item
)
2847 ForgetMem(&item
->name
);
2848 ForgetMem(&item
->name_str
);
2852 //======================================================================================================================
2855 _domain_item_compare(const struct _domain_item_s
* const d1
, const struct _domain_item_s
* const d2
,
2856 const bool ignore_order
)
2858 // The domain name with the greater label count precedes the other.
2859 int diff
= d1
->label_count
- d2
->label_count
;
2866 // The domain name with the lexicographically lesser rightmost label precedes the other.
2867 // Compare each pair of non-root labels from right to left.
2868 for (int depth
= d1
->label_count
; depth
-- > 0; ) {
2869 const uint8_t * const label1
= _mdns_domain_name_get_parent(d1
->name
, depth
);
2870 const uint8_t * const label2
= _mdns_domain_name_get_parent(d2
->name
, depth
);
2871 const int length1
= label1
[0];
2872 const int length2
= label2
[0];
2873 const int n
= Min(length1
, length2
);
2874 for (int i
= 1; i
<= n
; ++i
) {
2875 diff
= tolower_safe(label1
[i
]) - tolower_safe(label2
[i
]);
2883 diff
= length1
- length2
;
2891 if (!ignore_order
) {
2892 // The domain name with the smaller order (higher priority) precedes the other.
2893 if (d1
->order
< d2
->order
) {
2896 if (d1
->order
> d2
->order
) {