]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/mdns_objects/mdns_dns_service.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / mdns_objects / mdns_dns_service.c
1 /*
2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
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"
23
24 #include "HTTPUtilities.h"
25 #include "DNSMessage.h"
26 #include <CoreUtils/CoreUtils.h>
27 #include <stdatomic.h>
28
29 //======================================================================================================================
30 // MARK: - DNS Service Manager Kind Definition
31
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.
49 #endif
50 };
51
52 MDNS_OBJECT_SUBKIND_DEFINE(dns_service_manager);
53
54 #define MDNS_DNS_SERVICE_MANAGER_ARRAYS(MANAGER) \
55 (MANAGER)->default_services, \
56 (MANAGER)->path_services, \
57 (MANAGER)->discovered_services, \
58 (MANAGER)->custom_services
59
60 //======================================================================================================================
61 // MARK: - DNS Service Kind Definition
62
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.
68 );
69
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.
83 );
84
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) \
89
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 \
97 )
98
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);
101
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.
107 };
108
109 typedef struct _domain_item_s * _domain_item_t;
110
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.
133 };
134
135 MDNS_OBJECT_SUBKIND_DEFINE_FULL(dns_service);
136
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.
143 };
144
145 //======================================================================================================================
146 // MARK: - Local Prototypes
147
148 static void
149 _mdns_dns_service_manager_terminate(mdns_dns_service_manager_t manager, OSStatus error);
150
151 static void
152 _mdns_dns_service_manager_add_service(mdns_dns_service_manager_t manager, CFMutableArrayRef services,
153 mdns_dns_service_t service);
154
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);
158
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);
161
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);
164
165 static void
166 _mdns_dns_service_manager_update_interface_properties(mdns_dns_service_manager_t manager);
167
168 static void
169 _mdns_dns_service_manager_remove_unneeded_interface_monitors(mdns_dns_service_manager_t manager);
170
171 static void
172 _mdns_dns_service_manager_update_interface_properties_for_services(mdns_dns_service_manager_t manager,
173 CFArrayRef services);
174
175 static void
176 _mdns_dns_service_manager_update_interface_properties_for_service(mdns_dns_service_manager_t manager,
177 mdns_dns_service_t service);
178
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);
182
183 static void
184 _mdns_dns_service_manager_prepare_resolver(mdns_dns_service_manager_t manager, mdns_dns_service_t service);
185
186 static void
187 _mdns_dns_service_manager_start_defuncting(mdns_dns_service_manager_t manager, mdns_dns_service_t service);
188
189 static mdns_dns_service_t
190 _mdns_dns_service_manager_prepare_service(mdns_dns_service_manager_t manager, mdns_dns_service_t service);
191
192 static void
193 _mdns_dns_service_manager_trigger_update(mdns_dns_service_manager_t manager);
194
195 typedef bool (^mdns_dns_service_array_applier_t)(CFMutableArrayRef service_array);
196
197 static void
198 _mdns_dns_service_manager_iterate_over_all_service_arrays(mdns_dns_service_manager_t manager,
199 mdns_dns_service_array_applier_t applier);
200
201 static void
202 _mdns_dns_service_make_defunct(mdns_dns_service_t service);
203
204 static bool
205 _mdns_dns_service_equal_ex(mdns_dns_service_t service, mdns_dns_service_t other, bool ignore_domains);
206
207 static OSStatus
208 _mdns_dns_service_add_domain(mdns_dns_service_t service, const char *name, uint32_t order);
209
210 static int
211 _mdns_dns_service_handles_domain_name(mdns_dns_service_t service, const uint8_t *name, uint32_t *out_order);
212
213 static mdns_resolver_type_t
214 _mdns_dns_service_get_resolver_type_safe(mdns_dns_service_t service);
215
216 static CFMutableArrayRef
217 _mdns_create_dns_service_array_from_config(const dns_config_t *config, OSStatus *out_error);
218
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);
222
223 static mdns_dns_service_id_t
224 _mdns_dns_service_get_id_safe(mdns_dns_service_t service);
225
226 static const uint8_t *
227 _mdns_domain_name_get_parent(const uint8_t *name, int depth);
228
229 static void
230 _domain_item_free(_domain_item_t item);
231
232 static int
233 _domain_item_compare(const struct _domain_item_s *d1, const struct _domain_item_s *d2, bool ignore_order);
234
235 //======================================================================================================================
236 // MARK: - Internals
237
238 MDNS_LOG_CATEGORY_DEFINE(dns_service, "dns_service");
239
240 //======================================================================================================================
241 // MARK: - DNS Service Manager Public Methods
242
243 mdns_dns_service_manager_t
244 mdns_dns_service_manager_create(const dispatch_queue_t user_queue, OSStatus * const out_error)
245 {
246 OSStatus err;
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);
250
251 obj->default_services = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
252 require_action_quiet(obj->default_services, exit, err = kNoResourcesErr);
253
254 obj->path_services = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
255 require_action_quiet(obj->path_services, exit, err = kNoResourcesErr);
256
257 obj->discovered_services = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
258 require_action_quiet(obj->discovered_services, exit, err = kNoResourcesErr);
259
260 obj->custom_services = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
261 require_action_quiet(obj->custom_services, exit, err = kNoResourcesErr);
262
263 obj->monitors = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
264 require_action_quiet(obj->monitors, exit, err = kNoResourcesErr);
265
266 obj->queue = dispatch_queue_create("com.apple.mdns.dns-service-manager", DISPATCH_QUEUE_SERIAL);
267 require_action_quiet(obj->queue, exit, err = kNoResourcesErr);
268
269 obj->user_queue = user_queue;
270 dispatch_retain(obj->user_queue);
271
272 manager = obj;
273 obj = NULL;
274 err = kNoErr;
275
276 exit:
277 if (out_error) {
278 *out_error = err;
279 }
280 mdns_release_null_safe(obj);
281 return manager;
282 }
283
284 //======================================================================================================================
285
286 void
287 mdns_dns_service_manager_set_report_symptoms(const mdns_dns_service_manager_t me, const bool report_symptoms)
288 {
289 if (!me->user_activated) {
290 me->report_symptoms = report_symptoms;
291 }
292 }
293
294 //======================================================================================================================
295
296 #if MDNS_RESOLVER_PROBLEMATIC_QTYPE_WORKAROUND
297 void
298 mdns_dns_service_manager_enable_problematic_qtype_workaround(const mdns_dns_service_manager_t me, const int threshold)
299 {
300 require_return(!me->user_activated);
301 me->pqw_threshold = threshold;
302 }
303 #endif
304
305 //======================================================================================================================
306
307 void
308 mdns_dns_service_manager_set_event_handler(const mdns_dns_service_manager_t me, const mdns_event_handler_t handler)
309 {
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);
314 }
315 me->event_handler = new_handler;
316 }
317 }
318
319 //======================================================================================================================
320
321 void
322 _mdns_dns_service_manager_activate_internal(mdns_dns_service_manager_t manager);
323
324 void
325 mdns_dns_service_manager_activate(const mdns_dns_service_manager_t me)
326 {
327 require_return(!me->user_activated);
328
329 me->user_activated = true;
330 dispatch_sync(me->queue,
331 ^{
332 require_return(!me->terminated);
333 _mdns_dns_service_manager_activate_internal(me);
334 });
335 }
336
337 void
338 _mdns_dns_service_manager_activate_internal(const mdns_dns_service_manager_t me)
339 {
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) {
343 mdns_retain(me);
344 dispatch_source_set_event_handler(me->update_source,
345 ^{
346 if (me->event_handler) {
347 me->event_handler(mdns_event_update, kNoErr);
348 }
349 });
350 dispatch_source_set_cancel_handler(me->update_source,
351 ^{
352 mdns_release(me);
353 });
354 dispatch_activate(me->update_source);
355 } else {
356 _mdns_dns_service_manager_terminate(me, kNoResourcesErr);
357 }
358 }
359
360 //======================================================================================================================
361
362 static void
363 _mdns_dns_service_manager_apply_dns_config_internal(mdns_dns_service_manager_t manager, const dns_config_t *config);
364
365 void
366 mdns_dns_service_manager_apply_dns_config(const mdns_dns_service_manager_t me, const dns_config_t * const config)
367 {
368 dispatch_sync(me->queue,
369 ^{
370 require_return(!me->terminated);
371 _mdns_dns_service_manager_apply_dns_config_internal(me, config);
372 });
373 }
374
375 #define MDNS_TARGET_DISCOVERED_SERVICE_COUNT 4
376
377 static CFComparisonResult
378 _mdns_dns_service_compare_time(const void *val1, const void *val2, __unused void *context)
379 {
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;
382
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;
387 } else {
388 return kCFCompareEqualTo;
389 }
390 }
391
392 static void
393 _mdns_dns_service_manager_purge_discovered_services(const mdns_dns_service_manager_t me)
394 {
395 const CFIndex n = CFArrayGetCount(me->discovered_services);
396 if (n < MDNS_TARGET_DISCOVERED_SERVICE_COUNT) {
397 return;
398 }
399
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);
403
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);
409 }
410 }
411 CFRelease(recent_services);
412 }
413
414 static void
415 _mdns_dns_service_manager_apply_dns_config_internal(const mdns_dns_service_manager_t me,
416 const dns_config_t * const config)
417 {
418 _mdns_dns_service_manager_purge_discovered_services(me);
419
420 OSStatus err;
421 CFMutableArrayRef new_services = _mdns_create_dns_service_array_from_config(config, &err);
422 require_noerr_quiet(err, exit);
423
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);
429 if (j >= 0) {
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);
434
435 // Replace the new service object with the established one.
436 CFArraySetValueAtIndex(new_services, j, service);
437 } else {
438 // The service no longer exists.
439 _mdns_dns_service_make_defunct(service);
440 }
441 }
442 CFRelease(me->default_services);
443 me->default_services = new_services;
444 new_services = NULL;
445
446 _mdns_dns_service_manager_remove_unneeded_interface_monitors(me);
447 _mdns_dns_service_manager_update_interface_properties_for_services(me, me->default_services);
448
449 exit:
450 if (err) {
451 _mdns_dns_service_manager_terminate(me, err);
452 }
453 }
454
455 //======================================================================================================================
456
457 static void
458 _mdns_dns_service_manager_register_path_resolver_internal(mdns_dns_service_manager_t manager,
459 const uuid_t resolver_config_uuid);
460
461 static void
462 _mdns_dns_service_manager_handle_resolver_config_removal(mdns_dns_service_manager_t manager,
463 nw_resolver_config_t config);
464
465 static void
466 _mdns_dns_service_manager_cancel_resolver_config_updates(mdns_dns_service_manager_t manager,
467 nw_resolver_config_t config);
468
469 void
470 mdns_dns_service_manager_register_path_resolver(const mdns_dns_service_manager_t me, const uuid_t resolver_config_uuid)
471 {
472 dispatch_sync(me->queue,
473 ^{
474 require_return(!me->terminated);
475 _mdns_dns_service_manager_register_path_resolver_internal(me, resolver_config_uuid);
476 });
477 }
478
479 static void
480 _mdns_dns_service_manager_register_path_resolver_internal(const mdns_dns_service_manager_t me,
481 const uuid_t config_uuid)
482 {
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));
486
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);
490
491 // Calling nw_resolver_config_watch_updates will fill out the contents of the resolver.
492 mdns_retain(me);
493 nw_retain(config);
494 nw_resolver_config_watch_updates(config, me->queue,
495 ^(const bool removed)
496 {
497 if (removed) {
498 _mdns_dns_service_manager_handle_resolver_config_removal(me, config);
499 }
500 });
501 OSStatus err;
502 service = _mdns_dns_service_create_from_resolver_config(config, mdns_dns_service_source_nw, &err);
503 if (service) {
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);
508 } else {
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);
513 }
514 nw_release(config);
515 }
516
517 static void
518 _mdns_dns_service_manager_handle_resolver_config_removal(const mdns_dns_service_manager_t me,
519 const nw_resolver_config_t config)
520 {
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);
531 }
532 _mdns_dns_service_manager_start_defuncting(me, service);
533 break;
534 }
535 }
536 }
537
538 static void
539 _mdns_dns_service_manager_cancel_resolver_config_updates(const mdns_dns_service_manager_t me,
540 const nw_resolver_config_t config)
541 {
542 nw_resolver_config_cancel_updates(config, me->queue,
543 ^{
544 mdns_release(me);
545 nw_release(config);
546 });
547 }
548
549 //======================================================================================================================
550
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);
554
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);
557
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)
561 {
562 __block mdns_dns_service_id_t ident;
563 dispatch_sync(me->queue,
564 ^{
565 require_return_action(!me->terminated, ident = 0);
566 ident = _mdns_dns_service_manager_register_custom_service_internal(me, resolver_config_dict);
567 });
568 return ident;
569 }
570
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)
574 {
575 nw_resolver_config_t config = NULL;
576 mdns_dns_service_t service = NULL;
577
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);
585 goto exit;
586 }
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);
590 if (!service) {
591 OSStatus err;
592 service = _mdns_dns_service_create_from_resolver_config(config, mdns_dns_service_source_custom, &err);
593 if (service) {
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);
597 } else {
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);
601 }
602 }
603 if (service) {
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);
608 }
609 }
610
611 exit:
612 nw_forget(&config);
613 return _mdns_dns_service_get_id_safe(service);
614 }
615
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)
618 {
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) {
626 return service;
627 }
628 }
629 }
630 return NULL;
631 }
632
633 //======================================================================================================================
634
635 static void
636 _mdns_dns_service_manager_deregister_custom_service_internal(mdns_dns_service_manager_t manager,
637 mdns_dns_service_id_t ident);
638
639 void
640 mdns_dns_service_manager_deregister_custom_service(const mdns_dns_service_manager_t me,
641 const mdns_dns_service_id_t ident)
642 {
643 require_return(ident != 0);
644 dispatch_sync(me->queue,
645 ^{
646 require_return(!me->terminated);
647 _mdns_dns_service_manager_deregister_custom_service_internal(me, ident);
648 });
649 }
650
651 static void
652 _mdns_dns_service_manager_deregister_custom_service_internal(const mdns_dns_service_manager_t me,
653 const mdns_dns_service_id_t ident)
654 {
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);
666 }
667 break;
668 }
669 }
670 }
671
672 //======================================================================================================================
673
674 static void
675 _mdns_dns_service_manager_register_doh_uri_internal(mdns_dns_service_manager_t manager,
676 const char *doh_uri, const char *domain);
677
678 static mdns_dns_service_t
679 _mdns_dns_service_create_from_doh_uri(nw_endpoint_t url_endpoint, OSStatus *out_error);
680
681 void
682 mdns_dns_service_manager_register_doh_uri(const mdns_dns_service_manager_t me,
683 const char *doh_uri, const char *domain)
684 {
685 dispatch_sync(me->queue,
686 ^{
687 require_return(!me->terminated);
688 _mdns_dns_service_manager_register_doh_uri_internal(me, doh_uri, domain);
689 });
690 }
691
692 static void
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)
696 {
697 if (doh_endpoint == NULL || trusted_name == NULL ||
698 dns_zone_array == NULL || xpc_get_type(dns_zone_array) != XPC_TYPE_ARRAY) {
699 return;
700 }
701
702 char *trusted_name_suffix = NULL;
703 asprintf(&trusted_name_suffix, ".%s", trusted_name);
704
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);
709
710 if (strcmp(trusted_name, dns_zone) == 0) {
711 // Exact match
712 xpc_array_append_value(candidate_dns_zones, array_value);
713 } else {
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) {
718 // Suffix match
719 xpc_array_append_value(candidate_dns_zones, array_value);
720 }
721 }
722 }
723 }
724 return true;
725 });
726
727 free(trusted_name_suffix);
728
729 if (xpc_array_get_count(candidate_dns_zones) == 0) {
730 xpc_forget(&candidate_dns_zones);
731 return;
732 }
733
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) {
741 do {
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);
746 break;
747 }
748
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);
753 break;
754 }
755
756 os_log(_mdns_dns_service_log(), "DoH resolver at %@ is trusted for %@",
757 doh_endpoint, trusted_name_endpoint);
758
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);
761
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);
765 return true;
766 });
767 } else {
768 os_log_error(_mdns_dns_service_log(), "No PvD file found at %@ for DoH server %@",
769 trusted_name_endpoint, doh_endpoint);
770 }
771 } while (0);
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);
777 });
778 http_task_start(trusted_name_task);
779 }
780
781 static uint64_t
782 _mdns_get_future_continuous_time(uint64_t seconds)
783 {
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);
788 });
789 uint64_t delta = seconds * NSEC_PER_SEC;
790 delta *= time_base.denom;
791 delta /= time_base.numer;
792 return mach_continuous_time() + delta;
793 }
794
795 static void
796 _mdns_dns_service_manager_fetch_doh_pvd(const mdns_dns_service_manager_t me,
797 mdns_dns_service_t service)
798 {
799 __block void *task = NULL;
800 mdns_retain(service);
801
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) {
807 do {
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);
812 break;
813 }
814
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);
820 }
821
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);
828 break;
829 }
830
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");
834 }
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);
839 } else {
840 os_log_info(_mdns_dns_service_log(), "DoH resolver for %@ does not specify an expiration",
841 doh_endpoint);
842 service->discovered.expire_time = 0;
843 }
844
845 xpc_object_t dns_zone_array = xpc_dictionary_get_value(json_object, "dnsZones");
846
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);
855 }
856 return true;
857 });
858 }
859 }
860 } while (0);
861 http_task_cancel(task);
862 mdns_release(service);
863 nw_release(doh_endpoint);
864 });
865 http_task_start(task);
866 }
867
868 static void
869 _mdns_dns_service_manager_check_service_expiration(const mdns_dns_service_manager_t me,
870 mdns_dns_service_t service)
871 {
872 // Check if a service is expired
873 if (service->discovered.expire_time != 0 &&
874 service->discovered.expire_time < mach_continuous_time()) {
875
876 os_log_info(_mdns_dns_service_log(), "DoH resolver for %@ has passed expiration",
877 service->discovered.url_endpoint);
878
879 service->discovered.expire_time = 0;
880
881 // Clear out domain list, in case they have changed
882 _domain_item_t item;
883 while ((item = service->domain_list) != NULL) {
884 service->domain_list = item->next;
885 _domain_item_free(item);
886 }
887
888 // Refresh PvD to rebuild the list
889 _mdns_dns_service_manager_fetch_doh_pvd(me, service);
890 }
891 }
892
893 static void
894 _mdns_dns_service_manager_register_doh_uri_internal(const mdns_dns_service_manager_t me,
895 const char *doh_uri, const char *domain)
896 {
897 mdns_dns_service_t service = NULL;
898 nw_endpoint_t doh_endpoint = NULL;
899 char *uri_string;
900 OSStatus err;
901
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);
905
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';
910 }
911
912 doh_endpoint = nw_endpoint_create_url(uri_string);
913 require_action_quiet(doh_endpoint, exit, err = kNoResourcesErr);
914
915 const char *scheme = nw_endpoint_get_url_scheme(doh_endpoint);
916 require_action_quiet((scheme != NULL && strcasecmp("https", scheme) == 0), exit, err = kMalformedErr);
917
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);
921
922 service = _mdns_dns_service_create_from_doh_uri(doh_endpoint, NULL);
923 if (service) {
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);
927 }
928 }
929
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);
933 }
934
935 exit:
936 free(uri_string);
937 nw_forget(&doh_endpoint);
938 return;
939 }
940
941 static mdns_dns_service_t
942 _mdns_dns_service_create_from_doh_uri(nw_endpoint_t url_endpoint, OSStatus * const out_error)
943 {
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));
949
950 uuid_t new_identifier;
951 uuid_generate(new_identifier);
952 nw_resolver_config_set_identifier(config, new_identifier);
953
954 OSStatus err;
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);
958
959 service->discovered.url_endpoint = nw_retain(url_endpoint);
960 service->discovered.squash_cnames = true;
961 service->config = config;
962 config = NULL;
963 service->flags = (mdns_dns_service_flag_a_queries_advised | mdns_dns_service_flag_aaaa_queries_advised);
964
965 exit:
966 if (out_error) {
967 *out_error = err;
968 }
969 nw_forget(&config);
970 return service;
971 }
972
973 //======================================================================================================================
974
975 void
976 mdns_dns_service_manager_invalidate(const mdns_dns_service_manager_t me)
977 {
978 dispatch_sync(me->queue,
979 ^{
980 require_return(!me->invalidated);
981 _mdns_dns_service_manager_terminate(me, kNoErr);
982 me->invalidated = true;
983 });
984 }
985
986 //======================================================================================================================
987
988 mdns_dns_service_t
989 mdns_dns_service_manager_get_unscoped_service(const mdns_dns_service_manager_t me, const uint8_t * const name)
990 {
991 __block mdns_dns_service_t result;
992 dispatch_sync(me->queue,
993 ^{
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);
998 });
999 return result;
1000 }
1001
1002 //======================================================================================================================
1003
1004 mdns_dns_service_t
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)
1007 {
1008 __block mdns_dns_service_t result;
1009 dispatch_sync(me->queue,
1010 ^{
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);
1015 });
1016 return result;
1017 }
1018
1019 //======================================================================================================================
1020
1021 mdns_dns_service_t
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)
1024 {
1025 __block mdns_dns_service_t result;
1026 dispatch_sync(me->queue,
1027 ^{
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);
1032 });
1033 return result;
1034 }
1035
1036 //======================================================================================================================
1037
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);
1040
1041 mdns_dns_service_t
1042 mdns_dns_service_manager_get_custom_service(const mdns_dns_service_manager_t me, const mdns_dns_service_id_t ident)
1043 {
1044 __block mdns_dns_service_t result;
1045 dispatch_sync(me->queue,
1046 ^{
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);
1050 });
1051 return result;
1052 }
1053
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)
1056 {
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) {
1061 return service;
1062 }
1063 }
1064 return NULL;
1065 }
1066
1067 //======================================================================================================================
1068
1069 mdns_dns_service_t
1070 mdns_dns_service_manager_get_uuid_scoped_service(const mdns_dns_service_manager_t me, const uuid_t uuid)
1071 {
1072 __block mdns_dns_service_t result;
1073 dispatch_sync(me->queue,
1074 ^{
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);
1078 });
1079 return result;
1080 }
1081
1082 //======================================================================================================================
1083
1084 bool
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);
1087
1088 bool
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)
1091 {
1092 __block bool success = false;
1093 dispatch_sync(me->queue,
1094 ^{
1095 require_return(!me->terminated);
1096 success = _mdns_dns_service_manager_fillout_discovered_service_for_name(me, name, out_uuid);
1097 });
1098 return success;
1099 }
1100
1101 bool
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)
1104 {
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;
1114 }
1115
1116 // Check if service details have expired while iterating the list
1117 _mdns_dns_service_manager_check_service_expiration(me, candidate);
1118 }
1119
1120 if (service) {
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);
1124 return true;
1125 }
1126 return false;
1127 }
1128
1129 //======================================================================================================================
1130
1131 static void
1132 _mdns_dns_service_manager_apply_pending_updates_internal(mdns_dns_service_manager_t manager);
1133
1134 static void
1135 _mdns_dns_service_manager_finish_defuncting_services(CFMutableArrayRef services);
1136
1137 static void
1138 _mdns_dns_service_manager_update_service_usability(CFMutableArrayRef services);
1139
1140 void
1141 mdns_dns_service_manager_apply_pending_updates(const mdns_dns_service_manager_t me)
1142 {
1143 dispatch_sync(me->queue,
1144 ^{
1145 require_return(!me->terminated);
1146 _mdns_dns_service_manager_apply_pending_updates_internal(me);
1147 });
1148 }
1149
1150 static void
1151 _mdns_dns_service_manager_apply_pending_updates_internal(const mdns_dns_service_manager_t me)
1152 {
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);
1160 }
1161
1162 static void
1163 _mdns_dns_service_manager_finish_defuncting_services(const CFMutableArrayRef services)
1164 {
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);
1170 }
1171 }
1172 }
1173
1174 static void
1175 _mdns_dns_service_manager_update_service_usability(const CFMutableArrayRef services)
1176 {
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;
1183 }
1184 } else {
1185 if (service->flags & mdns_dns_service_flag_connection_problems) {
1186 service->flags &= ~mdns_dns_service_flag_connection_problems;
1187 }
1188 }
1189 }
1190 }
1191
1192 //======================================================================================================================
1193
1194 void
1195 mdns_dns_service_manager_iterate(const mdns_dns_service_manager_t me, const mdns_dns_service_applier_t applier)
1196 {
1197 dispatch_sync(me->queue,
1198 ^{
1199 require_return(!me->terminated);
1200 _mdns_dns_service_manager_iterate_over_all_service_arrays(me,
1201 ^ bool (const CFMutableArrayRef service_array)
1202 {
1203 bool stop = false;
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);
1208 if (stop) {
1209 break;
1210 }
1211 }
1212 return stop;
1213 });
1214 });
1215 }
1216
1217 //======================================================================================================================
1218
1219 size_t
1220 mdns_dns_service_manager_get_count(const mdns_dns_service_manager_t me)
1221 {
1222 __block size_t count = 0;
1223 dispatch_sync(me->queue,
1224 ^{
1225 require_return(!me->terminated);
1226 _mdns_dns_service_manager_iterate_over_all_service_arrays(me,
1227 ^ bool (const CFMutableArrayRef service_array)
1228 {
1229 count += (size_t)CFArrayGetCount(service_array);
1230 return false;
1231 });
1232 });
1233 return count;
1234 }
1235
1236 //======================================================================================================================
1237
1238 void
1239 mdns_dns_service_manager_handle_sleep(const mdns_dns_service_manager_t me)
1240 {
1241 mdns_dns_service_manager_iterate(me,
1242 ^ bool (const mdns_dns_service_t service)
1243 {
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;
1249 }
1250 }
1251 return false;
1252 });
1253 }
1254
1255 //======================================================================================================================
1256
1257 void
1258 mdns_dns_service_manager_handle_wake(const mdns_dns_service_manager_t me)
1259 {
1260 mdns_dns_service_manager_iterate(me,
1261 ^ bool (const mdns_dns_service_t service)
1262 {
1263 if (service->replace_resolver) {
1264 _mdns_dns_service_manager_prepare_service(me, service);
1265 service->replace_resolver = false;
1266 }
1267 return false;
1268 });
1269 }
1270
1271 //======================================================================================================================
1272 // MARK: - DNS Service Manager Private Methods
1273
1274 static void
1275 _mdns_dns_service_manager_finalize(mdns_dns_service_manager_t me)
1276 {
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);
1285 }
1286
1287 //======================================================================================================================
1288
1289 static OSStatus
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);
1292
1293 static char *
1294 _mdns_dns_service_manager_copy_description(const mdns_dns_service_manager_t me, const bool debug, const bool privacy)
1295 {
1296 char *description = NULL;
1297
1298 size_t true_len;
1299 char buf[1024];
1300 OSStatus err = _mdns_dns_service_manager_print_description(me, debug, privacy, buf, sizeof(buf), NULL, &true_len);
1301 require_noerr_quiet(err, exit);
1302
1303 if (true_len < sizeof(buf)) {
1304 description = strdup(buf);
1305 } else {
1306 const size_t buf_len = true_len + 1;
1307 char *buf_ptr = malloc(buf_len);
1308 require_quiet(buf_ptr, exit);
1309
1310 err = _mdns_dns_service_manager_print_description(me, debug, privacy, buf_ptr, buf_len, NULL, NULL);
1311 if (!err) {
1312 description = buf_ptr;
1313 } else {
1314 free(buf_ptr);
1315 }
1316 }
1317
1318 exit:
1319 return description;
1320 }
1321
1322 static OSStatus
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);
1325
1326 static OSStatus
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)
1329 {
1330 OSStatus err;
1331 char * dst = buf_ptr;
1332 const char * const lim = &buf_ptr[buf_len];
1333 size_t true_len = 0;
1334 int n;
1335
1336 #define _do_appendf(...) \
1337 do { \
1338 n = mdns_snprintf_add(&dst, lim, __VA_ARGS__); \
1339 require_action_quiet(n >= 0, exit, err = kUnknownErr); \
1340 true_len += (size_t)n; \
1341 } while(0)
1342
1343 if (debug) {
1344 _do_appendf("<%s: %p>: ", me->base.kind->name, me);
1345 }
1346 const CFArrayRef service_arrays[] = {
1347 MDNS_DNS_SERVICE_MANAGER_ARRAYS(me)
1348 };
1349 _do_appendf("{");
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,
1359 &true_len2);
1360 require_noerr_quiet(err, exit);
1361
1362 dst += len;
1363 true_len += true_len2;
1364 sep = ",";
1365 }
1366 }
1367 _do_appendf("\n}");
1368 #undef _do_appendf
1369
1370 if (out_len) {
1371 *out_len = (size_t)(dst - buf_ptr);
1372 }
1373 if (out_true_len) {
1374 *out_true_len = true_len;
1375 }
1376 err = kNoErr;
1377
1378 exit:
1379 return err;
1380 }
1381
1382 //======================================================================================================================
1383
1384 static void
1385 _mdns_dns_service_manager_terminate_services(mdns_dns_service_manager_t manager, CFMutableArrayRef services);
1386
1387 static void
1388 _mdns_dns_service_manager_terminate(const mdns_dns_service_manager_t me, const OSStatus error)
1389 {
1390 require_return(!me->invalidated);
1391
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));
1397 }
1398 CFArrayRemoveAllValues(me->monitors);
1399
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);
1404
1405 mdns_retain(me);
1406 dispatch_async(me->user_queue,
1407 ^{
1408 if (me->event_handler) {
1409 me->event_handler(error ? mdns_event_error : mdns_event_invalidated, error);
1410 }
1411 mdns_release(me);
1412 });
1413 }
1414
1415 static void
1416 _mdns_dns_service_manager_terminate_services(const mdns_dns_service_manager_t me, const CFMutableArrayRef services)
1417 {
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;
1424 }
1425 _mdns_dns_service_make_defunct((mdns_dns_service_t)CFArrayGetValueAtIndex(services, i));
1426 }
1427 CFArrayRemoveAllValues(services);
1428 }
1429
1430 //======================================================================================================================
1431
1432 static void
1433 _mdns_dns_service_manager_add_service(const mdns_dns_service_manager_t me, const CFMutableArrayRef services,
1434 const mdns_dns_service_t service)
1435 {
1436 CFArrayAppendValue(services, service);
1437 _mdns_dns_service_manager_update_interface_properties_for_service(me, service);
1438 }
1439
1440 //======================================================================================================================
1441
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)
1445 {
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) {
1454 continue;
1455 }
1456 switch (scope) {
1457 case mdns_dns_service_scope_interface:
1458 if (candidate->if_index != scoping_id) {
1459 continue;
1460 }
1461 break;
1462
1463 case mdns_dns_service_scope_service:
1464 if (candidate->service_id != scoping_id) {
1465 continue;
1466 }
1467 break;
1468
1469 default:
1470 case mdns_dns_service_scope_none:
1471 break;
1472 }
1473 uint32_t order = 0;
1474 const int label_count = _mdns_dns_service_handles_domain_name(candidate, name, &order);
1475 if (label_count < 0) {
1476 continue;
1477 }
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;
1485 best_order = order;
1486 }
1487 }
1488 return best_service;
1489 }
1490
1491 //======================================================================================================================
1492
1493 static mdns_dns_service_t
1494 _mdns_dns_service_manager_get_service_by_config_uuid(CFArrayRef services, const uuid_t uuid);
1495
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)
1498 {
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);
1501 if (!service) {
1502 service = _mdns_dns_service_manager_get_service_by_config_uuid(me->path_services, uuid);
1503 }
1504 return service;
1505 }
1506
1507 static mdns_dns_service_t
1508 _mdns_dns_service_manager_get_service_by_config_uuid(const CFArrayRef services, const uuid_t uuid)
1509 {
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) {
1517 return service;
1518 }
1519 }
1520 }
1521 return NULL;
1522 }
1523
1524 //======================================================================================================================
1525
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)
1528 {
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) {
1532 return NULL;
1533 }
1534
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) {
1540
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) {
1545 return service;
1546 }
1547 }
1548 }
1549 return NULL;
1550 }
1551
1552 //======================================================================================================================
1553
1554 static void
1555 _mdns_dns_service_manager_update_interface_properties(const mdns_dns_service_manager_t me)
1556 {
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);
1561 }
1562
1563 //======================================================================================================================
1564
1565 static bool
1566 _mdns_dns_service_manager_uses_interface(mdns_dns_service_manager_t manager, uint32_t if_index);
1567
1568 static bool
1569 _mdns_dns_services_use_interface(CFArrayRef services, uint32_t if_index);
1570
1571 static void
1572 _mdns_dns_service_manager_remove_unneeded_interface_monitors(const mdns_dns_service_manager_t me)
1573 {
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);
1578 if (!needed) {
1579 mdns_interface_monitor_invalidate(monitor);
1580 CFArrayRemoveValueAtIndex(me->monitors, i);
1581 }
1582 }
1583 }
1584
1585 static bool
1586 _mdns_dns_service_manager_uses_interface(const mdns_dns_service_manager_t me, const uint32_t if_index)
1587 {
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)) {
1592 return true;
1593 } else {
1594 return false;
1595 }
1596 }
1597
1598 static bool
1599 _mdns_dns_services_use_interface(const CFArrayRef services, const uint32_t if_index)
1600 {
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) {
1605 return true;
1606 }
1607 }
1608 return false;
1609 }
1610
1611 //======================================================================================================================
1612
1613 static void
1614 _mdns_dns_service_manager_update_interface_properties_for_services(const mdns_dns_service_manager_t me,
1615 const CFArrayRef services)
1616 {
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);
1621 }
1622 }
1623
1624 //======================================================================================================================
1625
1626 static mdns_interface_monitor_t
1627 _mdns_dns_service_manager_get_interface_monitor(mdns_dns_service_manager_t manager, uint32_t if_index);
1628
1629 static void
1630 _mdns_dns_service_manager_update_interface_properties_for_service(const mdns_dns_service_manager_t me,
1631 const mdns_dns_service_t service)
1632 {
1633 require_quiet(service->if_index != 0, exit);
1634
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));
1639
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;
1643 }
1644 if (mdns_interface_monitor_has_ipv6_connectivity(monitor)) {
1645 service->flags |= mdns_dns_service_flag_ipv6_connectivity;
1646 }
1647 if (mdns_interface_monitor_is_expensive(monitor)) {
1648 service->flags |= mdns_dns_service_flag_expensive;
1649 }
1650 if (mdns_interface_monitor_is_constrained(monitor)) {
1651 service->flags |= mdns_dns_service_flag_constrained;
1652 }
1653 if (mdns_interface_monitor_is_clat46(monitor)) {
1654 service->flags |= mdns_dns_service_flag_clat46;
1655 }
1656 if (mdns_interface_monitor_is_vpn(monitor)) {
1657 service->flags |= mdns_dns_service_flag_vpn;
1658 }
1659
1660 exit:
1661 return;
1662 }
1663
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)
1666 {
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;
1673 break;
1674 }
1675 }
1676 if (monitor) {
1677 goto exit;
1678 }
1679 monitor = mdns_interface_monitor_create(if_index);
1680 require_quiet(monitor, exit);
1681
1682 mdns_interface_monitor_set_queue(monitor, me->queue);
1683 mdns_retain(me);
1684 mdns_interface_monitor_set_update_handler(monitor,
1685 ^(mdns_interface_flags_t change_flags)
1686 {
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);
1698 }
1699 }
1700 });
1701 mdns_interface_monitor_set_event_handler(monitor,
1702 ^(mdns_event_t event, __unused OSStatus error)
1703 {
1704 switch (event) {
1705 case mdns_event_invalidated:
1706 mdns_release(monitor);
1707 mdns_release(me);
1708 break;
1709
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);
1713 if (i >= 0) {
1714 CFArrayRemoveValueAtIndex(me->monitors, i);
1715 }
1716 mdns_interface_monitor_invalidate(monitor);
1717 break;
1718 }
1719 default:
1720 break;
1721 }
1722 });
1723 mdns_interface_monitor_activate(monitor);
1724 CFArrayAppendValue(me->monitors, monitor);
1725
1726 exit:
1727 return monitor;
1728 }
1729
1730 //======================================================================================================================
1731 // MARK: - DNS Service Public Methods
1732
1733 void
1734 mdns_dns_service_set_context(const mdns_dns_service_t me, void * const context)
1735 {
1736 me->context = context;
1737 }
1738
1739 //======================================================================================================================
1740
1741 void *
1742 mdns_dns_service_get_context(const mdns_dns_service_t me)
1743 {
1744 return me->context;
1745 }
1746
1747 //======================================================================================================================
1748
1749 void
1750 mdns_dns_service_set_context_finalizer(const mdns_dns_service_t me, const mdns_context_finalizer_t finalizer)
1751 {
1752 me->context_finalizer = finalizer;
1753 }
1754
1755 //======================================================================================================================
1756
1757 mdns_querier_t
1758 mdns_dns_service_create_querier(const mdns_dns_service_t me, OSStatus * const out_error)
1759 {
1760 if (me->resolver) {
1761 return mdns_resolver_create_querier(me->resolver, out_error);
1762 } else {
1763 if (out_error) {
1764 *out_error = kNotInUseErr;
1765 }
1766 return NULL;
1767 }
1768 }
1769
1770 //======================================================================================================================
1771
1772 mdns_dns_service_scope_t
1773 mdns_dns_service_get_scope(const mdns_dns_service_t me)
1774 {
1775 return me->scope;
1776 }
1777
1778 //======================================================================================================================
1779
1780 uint32_t
1781 mdns_dns_service_get_interface_index(const mdns_dns_service_t me)
1782 {
1783 return me->if_index;
1784 }
1785
1786 //======================================================================================================================
1787
1788 mdns_dns_service_id_t
1789 mdns_dns_service_get_id(const mdns_dns_service_t me)
1790 {
1791 return _mdns_dns_service_get_id_safe(me);
1792 }
1793
1794 //======================================================================================================================
1795
1796 bool
1797 mdns_dns_service_is_defunct(const mdns_dns_service_t me)
1798 {
1799 return ((me->flags & mdns_dns_service_flag_defunct) ? true : false);
1800 }
1801
1802 //======================================================================================================================
1803
1804 bool
1805 mdns_dns_service_is_encrypted(mdns_dns_service_t me)
1806 {
1807 return mdns_resolver_type_uses_encryption(_mdns_dns_service_get_resolver_type_safe(me));
1808 }
1809
1810 //======================================================================================================================
1811
1812 bool
1813 mdns_dns_service_a_queries_advised(const mdns_dns_service_t me)
1814 {
1815 return ((me->flags & mdns_dns_service_flag_a_queries_advised) ? true : false);
1816 }
1817
1818 //======================================================================================================================
1819
1820 bool
1821 mdns_dns_service_aaaa_queries_advised(const mdns_dns_service_t me)
1822 {
1823 return ((me->flags & mdns_dns_service_flag_aaaa_queries_advised) ? true : false);
1824 }
1825
1826 //======================================================================================================================
1827
1828 bool
1829 mdns_dns_service_has_connection_problems(const mdns_dns_service_t me)
1830 {
1831 return ((me->flags & mdns_dns_service_flag_connection_problems) ? true : false);
1832 }
1833
1834 //======================================================================================================================
1835
1836 bool
1837 mdns_dns_service_interface_has_ipv4_connectivity(const mdns_dns_service_t me)
1838 {
1839 return ((me->flags & mdns_dns_service_flag_ipv4_connectivity) ? true : false);
1840 }
1841
1842 //======================================================================================================================
1843
1844 bool
1845 mdns_dns_service_interface_has_ipv6_connectivity(const mdns_dns_service_t me)
1846 {
1847 return ((me->flags & mdns_dns_service_flag_ipv6_connectivity) ? true : false);
1848 }
1849
1850 //======================================================================================================================
1851
1852 bool
1853 mdns_dns_service_interface_is_cellular(const mdns_dns_service_t me)
1854 {
1855 return ((me->flags & mdns_dns_service_flag_cellular) ? true : false);
1856 }
1857
1858 //======================================================================================================================
1859
1860 bool
1861 mdns_dns_service_interface_is_expensive(const mdns_dns_service_t me)
1862 {
1863 return ((me->flags & mdns_dns_service_flag_expensive) ? true : false);
1864 }
1865
1866 //======================================================================================================================
1867
1868 bool
1869 mdns_dns_service_interface_is_constrained(const mdns_dns_service_t me)
1870 {
1871 return ((me->flags & mdns_dns_service_flag_constrained) ? true : false);
1872 }
1873
1874 //======================================================================================================================
1875
1876 bool
1877 mdns_dns_service_interface_is_clat46(const mdns_dns_service_t me)
1878 {
1879 return ((me->flags & mdns_dns_service_flag_clat46) ? true : false);
1880 }
1881
1882 //======================================================================================================================
1883
1884 bool
1885 mdns_dns_service_interface_is_vpn(const mdns_dns_service_t me)
1886 {
1887 return ((me->flags & mdns_dns_service_flag_vpn) ? true : false);
1888 }
1889
1890 //======================================================================================================================
1891
1892 const char *
1893 mdns_dns_service_get_provider_name(const mdns_dns_service_t me)
1894 {
1895 if (me->config) {
1896 const char *provider_name = nw_resolver_config_get_provider_name(me->config);
1897 if (provider_name) {
1898 return provider_name;
1899 }
1900 }
1901 return NULL;
1902 }
1903
1904 //======================================================================================================================
1905
1906 mdns_resolver_type_t
1907 mdns_dns_service_get_resolver_type(const mdns_dns_service_t me)
1908 {
1909 return me->resolver_type;
1910 }
1911
1912 //======================================================================================================================
1913 // MARK: - DNS Service Private Methods
1914
1915 static void
1916 _mdns_dns_service_finalize(const mdns_dns_service_t me)
1917 {
1918 if (me->context) {
1919 if (me->context_finalizer) {
1920 me->context_finalizer(me->context);
1921 }
1922 me->context = NULL;
1923 }
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);
1929 }
1930 nw_forget(&me->discovered.url_endpoint);
1931 nw_forget(&me->config);
1932 ForgetMem(&me->if_name);
1933 }
1934
1935 //======================================================================================================================
1936
1937 static char *
1938 _mdns_dns_service_copy_description(const mdns_dns_service_t me, const bool debug, const bool privacy)
1939 {
1940 char *description = NULL;
1941
1942 size_t true_len;
1943 char buf[512];
1944 OSStatus err = _mdns_dns_service_print_description(me, debug, privacy, buf, sizeof(buf), NULL, &true_len);
1945 require_noerr_quiet(err, exit);
1946
1947 if (true_len < sizeof(buf)) {
1948 description = strdup(buf);
1949 } else {
1950 const size_t buf_len = true_len + 1;
1951 char *buf_ptr = malloc(buf_len);
1952 require_quiet(buf_ptr, exit);
1953
1954 err = _mdns_dns_service_print_description(me, debug, privacy, buf_ptr, buf_len, NULL, NULL);
1955 if (!err) {
1956 description = buf_ptr;
1957 } else {
1958 free(buf_ptr);
1959 }
1960 }
1961
1962 exit:
1963 return description;
1964 }
1965
1966 typedef struct {
1967 mdns_dns_service_flags_t flag;
1968 const char * desc;
1969 } mdns_dns_service_flag_description_t;
1970
1971 #define MDNS_DNS_SERVICE_REDACTED_STR "<REDACTED>"
1972
1973 static OSStatus
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)
1976 {
1977 OSStatus err;
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;
1982
1983 #define _do_appendf(...) \
1984 do { \
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; \
1988 } while(0)
1989
1990 if (debug) {
1991 _do_appendf("<%s: %p>: ", me->base.kind->name, me);
1992 }
1993
1994 // Print ID.
1995 _do_appendf("id: %llu", me->ident);
1996
1997 // Print DNS type.
1998 _do_appendf(", type: ");
1999 const mdns_resolver_type_t type = _mdns_dns_service_get_resolver_type_safe(me);
2000 switch (type) {
2001 case mdns_resolver_type_normal:
2002 _do_appendf("Do53");
2003 break;
2004
2005 case mdns_resolver_type_tls:
2006 _do_appendf("DoT");
2007 break;
2008
2009 case mdns_resolver_type_https:
2010 _do_appendf("DoH");
2011 break;
2012
2013 default:
2014 _do_appendf("<unknown type %d>", (int)type);
2015 break;
2016 }
2017
2018 // Print source.
2019 _do_appendf(", source: ");
2020 switch (me->source) {
2021 case mdns_dns_service_source_sc:
2022 _do_appendf("sc");
2023 break;
2024
2025 case mdns_dns_service_source_nw:
2026 _do_appendf("nw");
2027 break;
2028
2029 case mdns_dns_service_source_dns:
2030 _do_appendf("dns");
2031 break;
2032
2033 case mdns_dns_service_source_custom: {
2034 _do_appendf("custom");
2035 break;
2036 }
2037 default:
2038 _do_appendf("<unknown source %d>", (int)me->source);
2039 break;
2040 }
2041
2042 // Print scope.
2043 _do_appendf(", scope: ");
2044 switch (me->scope) {
2045 case mdns_dns_service_scope_none:
2046 _do_appendf("none");
2047 break;
2048
2049 case mdns_dns_service_scope_interface:
2050 _do_appendf("interface");
2051 break;
2052
2053 case mdns_dns_service_scope_service:
2054 _do_appendf("service (%u)", me->service_id);
2055 break;
2056
2057 case mdns_dns_service_scope_uuid: {
2058 _do_appendf("uuid");
2059 if (!privacy) {
2060 uuid_t uuid = {0};
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);
2065 }
2066 break;
2067 }
2068 default:
2069 _do_appendf("<ERROR: unknown scope %d>", (int)me->scope);
2070 break;
2071 }
2072
2073 // Print interface index.
2074 _do_appendf(", interface: %s/%u", me->if_name ? me->if_name : "", me->if_index);
2075
2076 // Print server addresses.
2077 _do_appendf(", servers: {");
2078
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);
2083 if (privacy) {
2084 const char *str;
2085 char strbuf[64];
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);
2090 if (n >= 0) {
2091 str = strbuf;
2092 } else {
2093 str = (family == AF_INET) ? "<IPv4>" : "<IPv6>";
2094 }
2095 } else {
2096 str = "<IPv?>";
2097 }
2098 _do_appendf("%s%s", sep, str);
2099 const int port = mdns_address_get_port(address);
2100 if (port != 0) {
2101 _do_appendf(":%d", port);
2102 }
2103 } else {
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);
2107 }
2108 sep = ", ";
2109 }
2110 _do_appendf("}");
2111
2112 // Print domains.
2113 _do_appendf(", domains: {");
2114
2115 sep = "";
2116 for (const struct _domain_item_s *item = me->domain_list; item; item = item->next) {
2117 const char *str;
2118 char strbuf[64];
2119 if (privacy) {
2120 const int n = DNSMessagePrintObfuscatedString(strbuf, sizeof(strbuf), item->name_str);
2121 str = (n >= 0) ? strbuf : MDNS_DNS_SERVICE_REDACTED_STR;
2122 } else {
2123 str = item->name_str;
2124 }
2125 _do_appendf("%s%s", sep, str);
2126 if (item->order != 0) {
2127 _do_appendf(" (%u)", item->order);
2128 }
2129 sep = ", ";
2130 }
2131 _do_appendf("}");
2132
2133 // Print attributes.
2134 _do_appendf(", attributes: {");
2135
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"},
2141 };
2142 sep = "";
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);
2147 sep = ", ";
2148 }
2149 }
2150 _do_appendf("}");
2151
2152 // Print interface properties.
2153 _do_appendf(", interface properties: {");
2154
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"}
2163 };
2164 sep = "";
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);
2169 sep = ", ";
2170 }
2171 }
2172 _do_appendf("}");
2173
2174 // Print additional information from resolver config object that isn't already printed.
2175 if (me->config) {
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) {
2180 const char *str;
2181 char strbuf[64];
2182 if (privacy) {
2183 const int n = DNSMessagePrintObfuscatedString(strbuf, sizeof(strbuf), provider_name);
2184 str = (n >= 0) ? strbuf : MDNS_DNS_SERVICE_REDACTED_STR;
2185 } else {
2186 str = provider_name;
2187 }
2188 _do_appendf("%s", str);
2189 }
2190 const char *provider_path = nw_resolver_config_get_provider_path(me->config);
2191 _do_appendf(", provider path: ");
2192 if (provider_path) {
2193 const char *str;
2194 char strbuf[64];
2195 if (privacy) {
2196 const int n = DNSMessagePrintObfuscatedString(strbuf, sizeof(strbuf), provider_path);
2197 str = (n >= 0) ? strbuf : MDNS_DNS_SERVICE_REDACTED_STR;
2198 } else {
2199 str = provider_path;
2200 }
2201 _do_appendf("%s", str);
2202 }
2203 _do_appendf("}");
2204 }
2205 #undef _do_appendf
2206
2207 if (out_len) {
2208 *out_len = (size_t)(dst - buf_ptr);
2209 }
2210 if (out_true_len) {
2211 *out_true_len = true_len;
2212 }
2213 err = kNoErr;
2214
2215 exit:
2216 ForgetMem(&address_desc);
2217 return err;
2218 }
2219 //======================================================================================================================
2220
2221 static bool
2222 _mdns_dns_service_equal(const mdns_dns_service_t me, const mdns_dns_service_t other)
2223 {
2224 return _mdns_dns_service_equal_ex(me, other, false);
2225 }
2226
2227 //======================================================================================================================
2228
2229 static mdns_dns_service_id_t
2230 _mdns_get_next_dns_service_id(void);
2231
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)
2235 {
2236 OSStatus err;
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);
2240
2241 obj->ident = _mdns_get_next_dns_service_id();
2242 obj->source = source;
2243 obj->scope = scope;
2244 obj->resolver_type = resolver_type;
2245
2246 obj->addresses = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
2247 require_action_quiet(obj->addresses, exit, err = kNoResourcesErr);
2248
2249 service = obj;
2250 obj = NULL;
2251 err = kNoErr;
2252
2253 exit:
2254 if (out_error) {
2255 *out_error = err;
2256 }
2257 mdns_release_null_safe(obj);
2258 return service;
2259 }
2260
2261 static mdns_dns_service_id_t
2262 _mdns_get_next_dns_service_id(void)
2263 {
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);
2266 }
2267
2268 //======================================================================================================================
2269
2270 #define MDNS_INITIAL_DGRAM_RTX_INTERVAL_NONCELLULAR_SECS 1
2271 #define MDNS_INITIAL_DGRAM_RTX_INTERVAL_CELLULAR_SECS 2
2272
2273 static void
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);
2276
2277 static void
2278 _mdns_dns_service_manager_prepare_resolver(const mdns_dns_service_manager_t me, const mdns_dns_service_t service)
2279 {
2280 require_return(!service->resolver);
2281
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);
2285
2286 // Create the resolver.
2287 OSStatus err;
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));
2291
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));
2296 }
2297 // Squash CNAMES if this discovered config requires it.
2298 if (service->discovered.squash_cnames) {
2299 mdns_resolver_set_squash_cnames(resolver, true);
2300 }
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);
2309 #endif
2310 }
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)) {
2317 ++add_count;
2318 } else {
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);
2322 }
2323 }
2324 require_quiet((n == 0) || (add_count > 0), exit);
2325
2326 mdns_resolver_set_queue(resolver, me->queue);
2327 mdns_retain(me);
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)
2332 {
2333 _mdns_dns_service_manager_handle_resolver_event(me, service, resolver, event, info);
2334 });
2335 service->resolver = resolver;
2336 resolver = NULL;
2337
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);
2342 }
2343 mdns_resolver_activate(service->resolver);
2344
2345 exit:
2346 mdns_release_null_safe(resolver);
2347 }
2348
2349 static void
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)
2353 {
2354 switch (event) {
2355 case mdns_resolver_event_connection: {
2356 require_quiet(info, exit);
2357 require_quiet(service->resolver == resolver, exit);
2358
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);
2367 }
2368 } else {
2369 if (service->cannot_connect) {
2370 service->cannot_connect = false;
2371 _mdns_dns_service_manager_trigger_update(me);
2372 }
2373 }
2374 break;
2375 }
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);
2381 mdns_release(me);
2382 break;
2383 }
2384 default: {
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);
2391 }
2392 break;
2393 }
2394 }
2395
2396 exit:
2397 return;
2398 }
2399
2400 //======================================================================================================================
2401
2402 static void
2403 _mdns_dns_service_manager_start_defuncting(const mdns_dns_service_manager_t me, const mdns_dns_service_t service)
2404 {
2405 if (!service->defuncting) {
2406 service->defuncting = true;
2407 _mdns_dns_service_manager_trigger_update(me);
2408 }
2409 }
2410
2411 //======================================================================================================================
2412
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)
2415 {
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));
2420 return service;
2421 }
2422
2423 //======================================================================================================================
2424
2425 static void
2426 _mdns_dns_service_manager_trigger_update(const mdns_dns_service_manager_t me)
2427 {
2428 if (me->update_source) {
2429 dispatch_source_merge_data(me->update_source, 1);
2430 }
2431 }
2432
2433 //======================================================================================================================
2434
2435 static void
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)
2438 {
2439 const CFMutableArrayRef all_arrays[] = {
2440 MDNS_DNS_SERVICE_MANAGER_ARRAYS(me)
2441 };
2442 for (size_t i = 0; i < countof(all_arrays); ++i) {
2443 const bool stop = applier(all_arrays[i]);
2444 if (stop) {
2445 break;
2446 }
2447 }
2448 }
2449
2450 //======================================================================================================================
2451
2452 static void
2453 _mdns_dns_service_make_defunct(const mdns_dns_service_t me)
2454 {
2455 me->flags |= mdns_dns_service_flag_defunct;
2456 mdns_resolver_forget(&me->resolver);
2457 }
2458
2459 //======================================================================================================================
2460
2461 static bool
2462 _mdns_dns_service_equal_ex(const mdns_dns_service_t me, const mdns_dns_service_t other, const bool ignore_domains)
2463 {
2464 if (me == other) {
2465 return true;
2466 }
2467 if (me->scope != other->scope) {
2468 return false;
2469 }
2470 if (me->if_index != other->if_index) {
2471 return false;
2472 }
2473 if ((me->scope == mdns_dns_service_scope_service) && (me->service_id != other->service_id)) {
2474 return false;
2475 }
2476 if (!CFEqual(me->addresses, other->addresses)) {
2477 return false;
2478 }
2479 if (!ignore_domains) {
2480 const struct _domain_item_s *d1 = me->domain_list;
2481 const struct _domain_item_s *d2 = other->domain_list;
2482 while (d1 && d2) {
2483 if (_domain_item_compare(d1, d2, false) != 0) {
2484 return false;
2485 }
2486 d1 = d1->next;
2487 d2 = d2->next;
2488 }
2489 if (d1 || d2) {
2490 return false;
2491 }
2492 }
2493 return true;
2494 }
2495
2496 //======================================================================================================================
2497
2498 static OSStatus
2499 _mdns_dns_service_add_domain(const mdns_dns_service_t me, const char * const name_str, const uint32_t order)
2500 {
2501 OSStatus err;
2502 _domain_item_t new_item = (_domain_item_t)calloc(1, sizeof(*new_item));
2503 require_action_quiet(new_item, exit, err = kNoMemoryErr);
2504
2505 uint8_t name[kDomainNameLengthMax];
2506 err = DomainNameFromString(name, name_str, NULL);
2507 require_noerr_quiet(err, exit);
2508
2509 char normalized_name_str[kDNSServiceMaxDomainName];
2510 err = DomainNameToString(name, NULL, normalized_name_str, NULL);
2511 require_noerr_quiet(err, exit);
2512
2513 new_item->name_str = strdup(normalized_name_str);
2514 require_action_quiet(new_item->name_str, exit, err = kNoMemoryErr);
2515
2516 err = DomainNameDup(name, &new_item->name, NULL);
2517 require_noerr_quiet(err, exit);
2518
2519 new_item->label_count = DomainNameLabelCount(new_item->name);
2520 require_action_quiet(new_item->label_count >= 0, exit, err = kMalformedErr);
2521
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);
2528 if (cmp < 0) {
2529 break;
2530 }
2531 if (cmp == 0) {
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;
2536 }
2537 goto exit;
2538 }
2539 }
2540 new_item->next = item;
2541 *ptr = new_item;
2542 new_item = NULL;
2543
2544 exit:
2545 if (new_item) {
2546 _domain_item_free(new_item);
2547 }
2548 return err;
2549 }
2550
2551 //======================================================================================================================
2552
2553 static int
2554 _mdns_dns_service_handles_domain_name(const mdns_dns_service_t me, const uint8_t * const name,
2555 uint32_t * const out_order)
2556 {
2557 int result;
2558 const int label_count = DomainNameLabelCount(name);
2559 require_action_quiet(label_count >= 0, exit, result = -1);
2560
2561 const struct _domain_item_s *item;
2562 for (item = me->domain_list; item; item = item->next) {
2563 if (label_count < item->label_count) {
2564 continue;
2565 }
2566 const uint8_t * const ptr = _mdns_domain_name_get_parent(name, label_count - item->label_count);
2567 if (DomainNameEqual(ptr, item->name)) {
2568 break;
2569 }
2570 }
2571 require_action_quiet(item, exit, result = -1);
2572
2573 result = item->label_count;
2574 if (out_order) {
2575 *out_order = item->order;
2576 }
2577
2578 exit:
2579 return result;
2580 }
2581
2582 //======================================================================================================================
2583
2584 static mdns_resolver_type_t
2585 _mdns_dns_service_get_resolver_type_safe(const mdns_dns_service_t me)
2586 {
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);
2589 switch (proto) {
2590 case nw_resolver_protocol_dns53:
2591 return mdns_resolver_type_normal;
2592
2593 case nw_resolver_protocol_dot:
2594 return mdns_resolver_type_tls;
2595
2596 case nw_resolver_protocol_doh:
2597 return mdns_resolver_type_https;
2598
2599 default:
2600 return mdns_resolver_type_null;
2601 }
2602 } else {
2603 return me->resolver_type;
2604 }
2605 }
2606
2607 //======================================================================================================================
2608 // MARK: - Local Helpers
2609
2610 static OSStatus
2611 _mdns_append_dns_service_from_config_by_scope(CFMutableArrayRef services, const dns_config_t *config,
2612 mdns_dns_service_scope_t scope);
2613
2614 static CFMutableArrayRef
2615 _mdns_create_dns_service_array_from_config(const dns_config_t * const config, OSStatus * const out_error)
2616 {
2617 OSStatus err;
2618 CFMutableArrayRef result = NULL;
2619
2620 CFMutableArrayRef services = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
2621 require_action_quiet(services, exit, err = kNoResourcesErr);
2622
2623 err = _mdns_append_dns_service_from_config_by_scope(services, config, mdns_dns_service_scope_none);
2624 require_noerr_quiet(err, exit);
2625
2626 err = _mdns_append_dns_service_from_config_by_scope(services, config, mdns_dns_service_scope_interface);
2627 require_noerr_quiet(err, exit);
2628
2629 err = _mdns_append_dns_service_from_config_by_scope(services, config, mdns_dns_service_scope_service);
2630 require_noerr_quiet(err, exit);
2631
2632 result = services;
2633 services = NULL;
2634
2635 exit:
2636 if (out_error) {
2637 *out_error = err;
2638 }
2639 CFReleaseNullSafe(services);
2640 return result;
2641 }
2642
2643 #define MDNS_DNS_SERVICE_DNS_PORT 53
2644 #define MDNS_DNS_SERVICE_MDNS_PORT 5353
2645
2646 static OSStatus
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)
2649 {
2650 OSStatus err;
2651 mdns_dns_service_t new_service = NULL;
2652 dns_resolver_t * const * resolver_array;
2653 int32_t resolver_count;
2654 switch (scope) {
2655 case mdns_dns_service_scope_none:
2656 resolver_array = config->resolver;
2657 resolver_count = config->n_resolver;
2658 break;
2659
2660 case mdns_dns_service_scope_interface:
2661 resolver_array = config->scoped_resolver;
2662 resolver_count = config->n_scoped_resolver;
2663 break;
2664
2665 case mdns_dns_service_scope_service:
2666 resolver_array = config->service_specific_resolver;
2667 resolver_count = config->n_service_specific_resolver;
2668 break;
2669
2670 default:
2671 err = kNoErr;
2672 goto exit;
2673 }
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)) {
2677 continue;
2678 }
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);
2685 continue;
2686 }
2687 }
2688 new_service = _mdns_dns_service_create(mdns_dns_service_source_sc, scope, mdns_resolver_type_normal, &err);
2689 require_noerr_quiet(err, exit);
2690
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)) {
2704 sin6_fixed = *sin6;
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);
2709 sin6 = &sin6_fixed;
2710 }
2711 address = mdns_address_create_ipv6(sin6->sin6_addr.s6_addr, port, sin6->sin6_scope_id);
2712 require_action_quiet(address, exit, err = kNoMemoryErr);
2713 } else {
2714 continue;
2715 }
2716 CFArrayAppendValue(new_service->addresses, address);
2717 mdns_forget(&address);
2718 }
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;
2722
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);
2733 break;
2734 }
2735 }
2736
2737 // If no existing service was found, add this one.
2738 if (new_service) {
2739 if (resolver->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS) {
2740 new_service->flags |= mdns_dns_service_flag_a_queries_advised;
2741 }
2742 if (resolver->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS) {
2743 new_service->flags |= mdns_dns_service_flag_aaaa_queries_advised;
2744 }
2745 #if !(TARGET_OS_OSX)
2746 if (resolver->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) {
2747 new_service->flags |= mdns_dns_service_flag_cellular;
2748 }
2749 #endif
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);
2755 if (!name_err) {
2756 new_service->if_name = strdup(name_ptr);
2757 } else {
2758 os_log_error(_mdns_dns_service_log(),
2759 "if_indextoname() for %u failed: %{darwin.errno}d", new_service->if_index, name_err);
2760 }
2761 }
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);
2766 }
2767 }
2768 err = kNoErr;
2769
2770 exit:
2771 mdns_release_null_safe(new_service);
2772 return err;
2773 }
2774
2775 //======================================================================================================================
2776
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)
2780 {
2781 OSStatus err;
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);
2785
2786 nw_resolver_config_enumerate_name_servers(config,
2787 ^ bool (const char * _Nonnull name_server)
2788 {
2789 mdns_address_t address = mdns_address_create_from_ip_address_string(name_server);
2790 if (address) {
2791 CFArrayAppendValue(service->addresses, address);
2792 mdns_forget(&address);
2793 }
2794 return true;
2795 });
2796 nw_resolver_config_enumerate_match_domains(config,
2797 ^ bool (const char * _Nonnull match_domain)
2798 {
2799 _mdns_dns_service_add_domain(service, match_domain, 0);
2800 return true;
2801 });
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);
2808 }
2809 service->flags = (mdns_dns_service_flag_a_queries_advised | mdns_dns_service_flag_aaaa_queries_advised);
2810 err = kNoErr;
2811
2812 exit:
2813 if (out_error) {
2814 *out_error = err;
2815 }
2816 return service;
2817 }
2818
2819 //======================================================================================================================
2820
2821 static mdns_dns_service_id_t
2822 _mdns_dns_service_get_id_safe(const mdns_dns_service_t me)
2823 {
2824 require_return_value(me, 0);
2825 return me->ident;
2826 }
2827
2828 //======================================================================================================================
2829
2830 static const uint8_t *
2831 _mdns_domain_name_get_parent(const uint8_t * const name, const int depth)
2832 {
2833 int current_depth = 0;
2834 const uint8_t *ptr = name;
2835 while ((*ptr != 0) && (current_depth < depth)) {
2836 ptr += (1 + *ptr);
2837 ++current_depth;
2838 }
2839 return ptr;
2840 }
2841
2842 //======================================================================================================================
2843
2844 static void
2845 _domain_item_free(const _domain_item_t item)
2846 {
2847 ForgetMem(&item->name);
2848 ForgetMem(&item->name_str);
2849 free(item);
2850 }
2851
2852 //======================================================================================================================
2853
2854 static int
2855 _domain_item_compare(const struct _domain_item_s * const d1, const struct _domain_item_s * const d2,
2856 const bool ignore_order)
2857 {
2858 // The domain name with the greater label count precedes the other.
2859 int diff = d1->label_count - d2->label_count;
2860 if (diff > 0) {
2861 return -1;
2862 }
2863 if (diff < 0) {
2864 return 1;
2865 }
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]);
2876 if (diff < 0) {
2877 return -1;
2878 }
2879 if (diff > 0) {
2880 return 1;
2881 }
2882 }
2883 diff = length1 - length2;
2884 if (diff < 0) {
2885 return -1;
2886 }
2887 if (diff > 0) {
2888 return 1;
2889 }
2890 }
2891 if (!ignore_order) {
2892 // The domain name with the smaller order (higher priority) precedes the other.
2893 if (d1->order < d2->order) {
2894 return -1;
2895 }
2896 if (d1->order > d2->order) {
2897 return 1;
2898 }
2899 }
2900 return 0;
2901 }