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
mdns_dns_service_manager_create(const dispatch_queue_t user_queue,OSStatus * const out_error)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
mdns_dns_service_manager_set_report_symptoms(const mdns_dns_service_manager_t me,const bool report_symptoms)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
mdns_dns_service_manager_enable_problematic_qtype_workaround(const mdns_dns_service_manager_t me,const int threshold)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
mdns_dns_service_manager_set_event_handler(const mdns_dns_service_manager_t me,const mdns_event_handler_t handler)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
mdns_dns_service_manager_activate(const mdns_dns_service_manager_t me)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
_mdns_dns_service_manager_activate_internal(const mdns_dns_service_manager_t me)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
mdns_dns_service_manager_apply_dns_config(const mdns_dns_service_manager_t me,const dns_config_t * const config)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
_mdns_dns_service_compare_time(const void * val1,const void * val2,__unused void * context)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
_mdns_dns_service_manager_purge_discovered_services(const mdns_dns_service_manager_t me)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 os_log(_mdns_dns_service_log(), "Purging %u discovered services down to 4", (uint32_t)n);
401
402 // Create a new array to hold the remaining services
403 CFMutableArrayRef remaining_services = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
404
405 // Sort by recent use
406 CFMutableArrayRef recent_services = CFArrayCreateMutableCopy(kCFAllocatorDefault, 0, me->discovered_services);
407 CFArraySortValues(recent_services, CFRangeMake(0, n), _mdns_dns_service_compare_time, NULL);
408
409 // Reduce number of services down to target by defuncting them
410 for (CFIndex i = 0; i < n; ++i) {
411 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(recent_services, i);
412 if (i >= MDNS_TARGET_DISCOVERED_SERVICE_COUNT) {
413 _mdns_dns_service_make_defunct(service);
414 } else {
415 CFArrayAppendValue(remaining_services, service);
416 }
417 }
418 ForgetCF(&recent_services);
419
420 ForgetCF(&me->discovered_services);
421 me->discovered_services = remaining_services;
422 remaining_services = NULL;
423 }
424
425 static void
_mdns_dns_service_manager_apply_dns_config_internal(const mdns_dns_service_manager_t me,const dns_config_t * const config)426 _mdns_dns_service_manager_apply_dns_config_internal(const mdns_dns_service_manager_t me,
427 const dns_config_t * const config)
428 {
429 _mdns_dns_service_manager_purge_discovered_services(me);
430
431 OSStatus err;
432 CFMutableArrayRef new_services = _mdns_create_dns_service_array_from_config(config, &err);
433 require_noerr_quiet(err, exit);
434
435 // Keep DNS services that still exist, and mark those that no longer exist as defunct.
436 const CFRange full_range = CFRangeMake(0, CFArrayGetCount(new_services));
437 for (CFIndex i = CFArrayGetCount(me->default_services) - 1; i >= 0; --i) {
438 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(me->default_services, i);
439 const CFIndex j = CFArrayGetFirstIndexOfValue(new_services, full_range, service);
440 if (j >= 0) {
441 // The service still exists, but its flags may have changed.
442 const mdns_dns_service_t new_service = (mdns_dns_service_t)CFArrayGetValueAtIndex(new_services, j);
443 service->flags &= ~MDNS_DNS_SERVICE_FLAGS_FROM_DNS_CONFIG;
444 service->flags |= (new_service->flags & MDNS_DNS_SERVICE_FLAGS_FROM_DNS_CONFIG);
445
446 // Replace the new service object with the established one.
447 CFArraySetValueAtIndex(new_services, j, service);
448 } else {
449 // The service no longer exists.
450 _mdns_dns_service_make_defunct(service);
451 }
452 }
453 CFRelease(me->default_services);
454 me->default_services = new_services;
455 new_services = NULL;
456
457 _mdns_dns_service_manager_remove_unneeded_interface_monitors(me);
458 _mdns_dns_service_manager_update_interface_properties_for_services(me, me->default_services);
459
460 exit:
461 if (err) {
462 _mdns_dns_service_manager_terminate(me, err);
463 }
464 }
465
466 //======================================================================================================================
467
468 static void
469 _mdns_dns_service_manager_register_path_resolver_internal(mdns_dns_service_manager_t manager,
470 const uuid_t resolver_config_uuid);
471
472 static void
473 _mdns_dns_service_manager_handle_resolver_config_removal(mdns_dns_service_manager_t manager,
474 nw_resolver_config_t config);
475
476 static void
477 _mdns_dns_service_manager_cancel_resolver_config_updates(mdns_dns_service_manager_t manager,
478 nw_resolver_config_t config);
479
480 void
mdns_dns_service_manager_register_path_resolver(const mdns_dns_service_manager_t me,const uuid_t resolver_config_uuid)481 mdns_dns_service_manager_register_path_resolver(const mdns_dns_service_manager_t me, const uuid_t resolver_config_uuid)
482 {
483 dispatch_sync(me->queue,
484 ^{
485 require_return(!me->terminated);
486 _mdns_dns_service_manager_register_path_resolver_internal(me, resolver_config_uuid);
487 });
488 }
489
490 static void
_mdns_dns_service_manager_register_path_resolver_internal(const mdns_dns_service_manager_t me,const uuid_t config_uuid)491 _mdns_dns_service_manager_register_path_resolver_internal(const mdns_dns_service_manager_t me,
492 const uuid_t config_uuid)
493 {
494 mdns_dns_service_t service = _mdns_dns_service_manager_get_uuid_scoped_service(me, config_uuid);
495 require_return_action(!service, os_log_debug(_mdns_dns_service_log(),
496 "Already registered service -- service id: %llu, uuid: %{uuid_t}.16P", service->ident, config_uuid));
497
498 // Need a new service in the path array.
499 nw_resolver_config_t _Nonnull config = nw_resolver_config_create();
500 nw_resolver_config_set_identifier(config, config_uuid);
501
502 // Calling nw_resolver_config_watch_updates will fill out the contents of the resolver.
503 mdns_retain(me);
504 nw_retain(config);
505 nw_resolver_config_watch_updates(config, me->queue,
506 ^(const bool removed)
507 {
508 if (removed) {
509 _mdns_dns_service_manager_handle_resolver_config_removal(me, config);
510 }
511 });
512 OSStatus err;
513 service = _mdns_dns_service_create_from_resolver_config(config, mdns_dns_service_source_nw, &err);
514 if (service) {
515 service->config_needs_cancel = true;
516 _mdns_dns_service_manager_add_service(me, me->path_services, service);
517 os_log(_mdns_dns_service_log(), "Registered service -- %@", service);
518 mdns_forget(&service);
519 } else {
520 _mdns_dns_service_manager_cancel_resolver_config_updates(me, config);
521 os_log_error(_mdns_dns_service_log(),
522 "Failed to register service -- uuid: %{uuid_t}.16P, config: %@, error: %{mdns:err}ld",
523 config_uuid, config, (long)err);
524 }
525 nw_release(config);
526 }
527
528 static void
_mdns_dns_service_manager_handle_resolver_config_removal(const mdns_dns_service_manager_t me,const nw_resolver_config_t config)529 _mdns_dns_service_manager_handle_resolver_config_removal(const mdns_dns_service_manager_t me,
530 const nw_resolver_config_t config)
531 {
532 const CFIndex n = CFArrayGetCount(me->path_services);
533 for (CFIndex i = 0; i < n; ++i) {
534 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(me->path_services, i);
535 if (service->config == config) {
536 os_log(_mdns_dns_service_log(), "Removing service -- %@", service);
537 // Cancel the config's updates now and mark the service as defuncting.
538 // The service will ultimately be made defunct when the user accepts the next set of pending updates.
539 if (service->config_needs_cancel) {
540 service->config_needs_cancel = false;
541 _mdns_dns_service_manager_cancel_resolver_config_updates(me, service->config);
542 }
543 _mdns_dns_service_manager_start_defuncting(me, service);
544 break;
545 }
546 }
547 }
548
549 static void
_mdns_dns_service_manager_cancel_resolver_config_updates(const mdns_dns_service_manager_t me,const nw_resolver_config_t config)550 _mdns_dns_service_manager_cancel_resolver_config_updates(const mdns_dns_service_manager_t me,
551 const nw_resolver_config_t config)
552 {
553 nw_resolver_config_cancel_updates(config, me->queue,
554 ^{
555 mdns_release(me);
556 nw_release(config);
557 });
558 }
559
560 //======================================================================================================================
561
562 static mdns_dns_service_id_t
563 _mdns_dns_service_manager_register_custom_service_internal(mdns_dns_service_manager_t manager,
564 xpc_object_t resolver_config_dict);
565
566 static mdns_dns_service_t
567 _mdns_dns_service_manager_get_custom_service_by_uuid(mdns_dns_service_manager_t manager, const uuid_t config_uuid);
568
569 mdns_dns_service_id_t
mdns_dns_service_manager_register_custom_service(const mdns_dns_service_manager_t me,const xpc_object_t resolver_config_dict)570 mdns_dns_service_manager_register_custom_service(const mdns_dns_service_manager_t me,
571 const xpc_object_t resolver_config_dict)
572 {
573 __block mdns_dns_service_id_t ident;
574 dispatch_sync(me->queue,
575 ^{
576 require_return_action(!me->terminated, ident = 0);
577 ident = _mdns_dns_service_manager_register_custom_service_internal(me, resolver_config_dict);
578 });
579 return ident;
580 }
581
582 static mdns_dns_service_id_t
_mdns_dns_service_manager_register_custom_service_internal(const mdns_dns_service_manager_t me,const xpc_object_t resolver_config_dict)583 _mdns_dns_service_manager_register_custom_service_internal(const mdns_dns_service_manager_t me,
584 const xpc_object_t resolver_config_dict)
585 {
586 nw_resolver_config_t config = NULL;
587 mdns_dns_service_t service = NULL;
588
589 // Parse the dictionary
590 config = nw_resolver_config_create_with_dictionary(resolver_config_dict);
591 if (unlikely(!config)) {
592 char *dict_desc = xpc_copy_description(resolver_config_dict);
593 os_log_error(_mdns_dns_service_log(),
594 "Failed to create nw_resolver_config for dictionary: %s", dict_desc ? dict_desc : "<NO DESC.>");
595 ForgetMem(&dict_desc);
596 goto exit;
597 }
598 uuid_t config_uuid = {0};
599 nw_resolver_config_get_identifier(config, config_uuid);
600 service = _mdns_dns_service_manager_get_custom_service_by_uuid(me, config_uuid);
601 if (!service) {
602 OSStatus err;
603 service = _mdns_dns_service_create_from_resolver_config(config, mdns_dns_service_source_custom, &err);
604 if (service) {
605 _mdns_dns_service_manager_add_service(me, me->custom_services, service);
606 os_log(_mdns_dns_service_log(), "Registered custom service -- %@", service);
607 mdns_release(service);
608 } else {
609 os_log_error(_mdns_dns_service_log(),
610 "Failed to register custom service -- uuid: %{uuid_t}.16P, config: %@, error: %{mdns:err}ld",
611 config_uuid, config, (long)err);
612 }
613 }
614 if (service) {
615 if (service->reg_count++ != 0) {
616 os_log_info(_mdns_dns_service_log(),
617 "Registered custom service -- service id: %llu, registration count: %d",
618 service->ident, service->reg_count);
619 }
620 }
621
622 exit:
623 nw_forget(&config);
624 return _mdns_dns_service_get_id_safe(service);
625 }
626
627 static mdns_dns_service_t
_mdns_dns_service_manager_get_custom_service_by_uuid(const mdns_dns_service_manager_t me,const uuid_t config_uuid)628 _mdns_dns_service_manager_get_custom_service_by_uuid(const mdns_dns_service_manager_t me, const uuid_t config_uuid)
629 {
630 const CFIndex n = CFArrayGetCount(me->custom_services);
631 for (CFIndex i = 0; i < n; ++i) {
632 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(me->custom_services, i);
633 if (service->config) {
634 uuid_t match_uuid = {0};
635 nw_resolver_config_get_identifier(service->config, match_uuid);
636 if (uuid_compare(match_uuid, config_uuid) == 0) {
637 return service;
638 }
639 }
640 }
641 return NULL;
642 }
643
644 //======================================================================================================================
645
646 static void
647 _mdns_dns_service_manager_deregister_custom_service_internal(mdns_dns_service_manager_t manager,
648 mdns_dns_service_id_t ident);
649
650 void
mdns_dns_service_manager_deregister_custom_service(const mdns_dns_service_manager_t me,const mdns_dns_service_id_t ident)651 mdns_dns_service_manager_deregister_custom_service(const mdns_dns_service_manager_t me,
652 const mdns_dns_service_id_t ident)
653 {
654 require_return(ident != 0);
655 dispatch_sync(me->queue,
656 ^{
657 require_return(!me->terminated);
658 _mdns_dns_service_manager_deregister_custom_service_internal(me, ident);
659 });
660 }
661
662 static void
_mdns_dns_service_manager_deregister_custom_service_internal(const mdns_dns_service_manager_t me,const mdns_dns_service_id_t ident)663 _mdns_dns_service_manager_deregister_custom_service_internal(const mdns_dns_service_manager_t me,
664 const mdns_dns_service_id_t ident)
665 {
666 const CFIndex n = CFArrayGetCount(me->custom_services);
667 for (CFIndex i = 0; i < n; ++i) {
668 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(me->custom_services, i);
669 if (service->ident == ident) {
670 --service->reg_count;
671 os_log_with_type(_mdns_dns_service_log(),
672 (service->reg_count == 0) ? OS_LOG_TYPE_DEFAULT : OS_LOG_TYPE_INFO,
673 "Deregistered custom service -- service id: %llu, registration count: %d",
674 service->ident, service->reg_count);
675 if (service->reg_count == 0) {
676 _mdns_dns_service_manager_start_defuncting(me, service);
677 }
678 break;
679 }
680 }
681 }
682
683 //======================================================================================================================
684
685 static void
686 _mdns_dns_service_manager_register_doh_uri_internal(mdns_dns_service_manager_t manager,
687 const char *doh_uri, const char *domain);
688
689 static mdns_dns_service_t
690 _mdns_dns_service_create_from_doh_uri(nw_endpoint_t url_endpoint, OSStatus *out_error);
691
692 void
mdns_dns_service_manager_register_doh_uri(const mdns_dns_service_manager_t me,const char * doh_uri,const char * domain)693 mdns_dns_service_manager_register_doh_uri(const mdns_dns_service_manager_t me,
694 const char *doh_uri, const char *domain)
695 {
696 dispatch_sync(me->queue,
697 ^{
698 require_return(!me->terminated);
699 _mdns_dns_service_manager_register_doh_uri_internal(me, doh_uri, domain);
700 });
701 }
702
703 static void
_mdns_dns_service_manager_fetch_trusted_name_pvd(const mdns_dns_service_manager_t me,mdns_dns_service_t service,nw_endpoint_t doh_endpoint,xpc_object_t dns_zone_array,const char * trusted_name)704 _mdns_dns_service_manager_fetch_trusted_name_pvd(const mdns_dns_service_manager_t me,
705 mdns_dns_service_t service, nw_endpoint_t doh_endpoint,
706 xpc_object_t dns_zone_array, const char *trusted_name)
707 {
708 if (doh_endpoint == NULL || trusted_name == NULL ||
709 dns_zone_array == NULL || xpc_get_type(dns_zone_array) != XPC_TYPE_ARRAY) {
710 return;
711 }
712
713 char *trusted_name_suffix = NULL;
714 asprintf(&trusted_name_suffix, ".%s", trusted_name);
715
716 xpc_object_t candidate_dns_zones = xpc_array_create(NULL, 0);
717 xpc_array_apply(dns_zone_array, ^bool(__unused size_t index, xpc_object_t _Nonnull array_value) {
718 if (xpc_get_type(array_value) == XPC_TYPE_STRING) {
719 const char *dns_zone = xpc_string_get_string_ptr(array_value);
720
721 if (strcasecmp(trusted_name, dns_zone) == 0) {
722 // Exact match
723 xpc_array_append_value(candidate_dns_zones, array_value);
724 } else {
725 size_t trusted_name_suffix_length = strlen(trusted_name_suffix);
726 size_t dns_zone_length = strlen(dns_zone);
727 if (trusted_name_suffix_length <= dns_zone_length) {
728 if (strcasecmp(trusted_name_suffix, dns_zone + (dns_zone_length - trusted_name_suffix_length)) == 0) {
729 // Suffix match
730 xpc_array_append_value(candidate_dns_zones, array_value);
731 }
732 }
733 }
734 }
735 return true;
736 });
737
738 free(trusted_name_suffix);
739
740 if (xpc_array_get_count(candidate_dns_zones) == 0) {
741 xpc_forget(&candidate_dns_zones);
742 return;
743 }
744
745 __block void *trusted_name_task = NULL;
746 nw_retain(doh_endpoint);
747 mdns_retain(service);
748 // candidate_dns_zones is already retained
749 nw_endpoint_t trusted_name_endpoint = nw_endpoint_create_host(trusted_name, "443");
750 trusted_name_task = http_task_create_pvd_query(me->queue,
751 trusted_name, "", ^(xpc_object_t trusted_name_json) {
752 do {
753 if (trusted_name_json != NULL) {
754 const char *trusted_doh_template = xpc_dictionary_get_string(trusted_name_json, "dohTemplate");
755 if (trusted_doh_template == NULL) {
756 os_log_error(_mdns_dns_service_log(), "Trusted name %@ missing DoH template", trusted_name_endpoint);
757 break;
758 }
759
760 const char *inner_doh_string = nw_endpoint_get_url(doh_endpoint);
761 if (inner_doh_string == NULL || strcasecmp(trusted_doh_template, inner_doh_string) != 0) {
762 os_log_error(_mdns_dns_service_log(), "DoH resolver for %@ does not match trusted DoH template %s for %@",
763 doh_endpoint, trusted_doh_template, trusted_name_endpoint);
764 break;
765 }
766
767 os_log(_mdns_dns_service_log(), "DoH resolver at %@ is trusted for %@",
768 doh_endpoint, trusted_name_endpoint);
769
770 xpc_array_apply(candidate_dns_zones, ^bool(__unused size_t index, xpc_object_t _Nonnull array_value) {
771 const char *dns_zone = xpc_string_get_string_ptr(array_value);
772
773 os_log(_mdns_dns_service_log(), "Adding domain %s to discovered DoH resolver for %@",
774 dns_zone, doh_endpoint);
775 _mdns_dns_service_add_domain(service, dns_zone, 0);
776 return true;
777 });
778 } else {
779 os_log_error(_mdns_dns_service_log(), "No PvD file found at %@ for DoH server %@",
780 trusted_name_endpoint, doh_endpoint);
781 }
782 } while (0);
783 http_task_cancel(trusted_name_task);
784 nw_release(trusted_name_endpoint);
785 nw_release(doh_endpoint);
786 xpc_release(candidate_dns_zones);
787 mdns_release(service);
788 });
789 http_task_start(trusted_name_task);
790 }
791
792 static uint64_t
_mdns_get_future_continuous_time(uint64_t seconds)793 _mdns_get_future_continuous_time(uint64_t seconds)
794 {
795 static dispatch_once_t onceToken;
796 static mach_timebase_info_data_t time_base = {0, 0};
797 dispatch_once(&onceToken, ^{
798 mach_timebase_info(&time_base);
799 });
800 uint64_t delta = seconds * NSEC_PER_SEC;
801 delta *= time_base.denom;
802 delta /= time_base.numer;
803 return mach_continuous_time() + delta;
804 }
805
806 static void
_mdns_dns_service_manager_fetch_doh_pvd(const mdns_dns_service_manager_t me,mdns_dns_service_t service)807 _mdns_dns_service_manager_fetch_doh_pvd(const mdns_dns_service_manager_t me,
808 mdns_dns_service_t service)
809 {
810 __block void *task = NULL;
811 mdns_retain(service);
812
813 nw_endpoint_t doh_endpoint = service->discovered.url_endpoint;
814 nw_retain(doh_endpoint);
815 task = http_task_create_pvd_query(me->queue,
816 nw_endpoint_get_hostname(doh_endpoint),
817 nw_endpoint_get_url_path(doh_endpoint), ^(xpc_object_t json_object) {
818 do {
819 if (json_object != NULL) {
820 const char *doh_template = xpc_dictionary_get_string(json_object, "dohTemplate");
821 if (doh_template == NULL) {
822 os_log_error(_mdns_dns_service_log(), "DoH resolver for %@ missing DoH template", doh_endpoint);
823 break;
824 }
825
826 // If the string is suffixed by a string like "{?dns}", trim off that variable template
827 size_t template_length = strlen(doh_template);
828 const char *template_portion = strchr(doh_template, '{');
829 if (template_portion != NULL) {
830 template_length = (size_t)(template_portion - doh_template);
831 }
832
833 const char *doh_string = nw_endpoint_get_url(doh_endpoint);
834 if (doh_string == NULL ||
835 strlen(doh_string) != template_length ||
836 strncasecmp(doh_template, doh_string, template_length) != 0) {
837 os_log_error(_mdns_dns_service_log(), "DoH resolver for %@ does not match DoH template %s",
838 doh_endpoint, doh_template);
839 break;
840 }
841
842 uint64_t seconds_remaining = xpc_dictionary_get_uint64(json_object, "secondsRemaining");
843 if (seconds_remaining == 0) {
844 seconds_remaining = xpc_dictionary_get_uint64(json_object, "seconds-remaining");
845 }
846 if (seconds_remaining != 0) {
847 os_log_info(_mdns_dns_service_log(), "DoH resolver for %@ will expire in %llu seconds",
848 doh_endpoint, seconds_remaining);
849 service->discovered.expire_time = _mdns_get_future_continuous_time(seconds_remaining);
850 } else {
851 os_log_info(_mdns_dns_service_log(), "DoH resolver for %@ does not specify an expiration",
852 doh_endpoint);
853 service->discovered.expire_time = 0;
854 }
855
856 xpc_object_t dns_zone_array = xpc_dictionary_get_value(json_object, "dnsZones");
857
858 xpc_object_t trusted_names_array = xpc_dictionary_get_value(json_object, "trustedNames");
859 if (trusted_names_array && xpc_get_type(trusted_names_array) == XPC_TYPE_ARRAY) {
860 xpc_array_apply(trusted_names_array, ^bool(__unused size_t index, xpc_object_t _Nonnull array_value) {
861 if (xpc_get_type(array_value) == XPC_TYPE_STRING) {
862 const char *trusted_name = xpc_string_get_string_ptr(array_value);
863 os_log(_mdns_dns_service_log(), "Query trusted name %s for DoH resolver for %@",
864 trusted_name, doh_endpoint);
865 _mdns_dns_service_manager_fetch_trusted_name_pvd(me, service, doh_endpoint, dns_zone_array, trusted_name);
866 }
867 return true;
868 });
869 }
870 }
871 } while (0);
872 http_task_cancel(task);
873 mdns_release(service);
874 nw_release(doh_endpoint);
875 });
876 http_task_start(task);
877 }
878
879 static void
_mdns_dns_service_manager_check_service_expiration(const mdns_dns_service_manager_t me,mdns_dns_service_t service)880 _mdns_dns_service_manager_check_service_expiration(const mdns_dns_service_manager_t me,
881 mdns_dns_service_t service)
882 {
883 // Check if a service is expired
884 if (service->discovered.expire_time != 0 &&
885 service->discovered.expire_time < mach_continuous_time()) {
886
887 os_log_info(_mdns_dns_service_log(), "DoH resolver for %@ has passed expiration",
888 service->discovered.url_endpoint);
889
890 service->discovered.expire_time = 0;
891
892 // Clear out domain list, in case they have changed
893 _domain_item_t item;
894 while ((item = service->domain_list) != NULL) {
895 service->domain_list = item->next;
896 _domain_item_free(item);
897 }
898
899 // Refresh PvD to rebuild the list
900 _mdns_dns_service_manager_fetch_doh_pvd(me, service);
901 }
902 }
903
904 static void
_mdns_dns_service_manager_register_doh_uri_internal(const mdns_dns_service_manager_t me,const char * doh_uri,const char * domain)905 _mdns_dns_service_manager_register_doh_uri_internal(const mdns_dns_service_manager_t me,
906 const char *doh_uri, const char *domain)
907 {
908 mdns_dns_service_t service = NULL;
909 nw_endpoint_t doh_endpoint = NULL;
910 char *uri_string;
911 OSStatus err;
912
913 // Make a copy of the string in case it needs to be sanitized
914 uri_string = strdup(doh_uri);
915 require_quiet(uri_string, exit);
916
917 // If the string is suffixed by a string like "{?dns}", trim off that variable template
918 char *template_portion = strchr(uri_string, '{');
919 if (template_portion != NULL) {
920 template_portion[0] = '\0';
921 }
922
923 doh_endpoint = nw_endpoint_create_url(uri_string);
924 require_action_quiet(doh_endpoint, exit, err = kNoResourcesErr);
925
926 const char *scheme = nw_endpoint_get_url_scheme(doh_endpoint);
927 require_action_quiet((scheme != NULL && strcasecmp("https", scheme) == 0), exit, err = kMalformedErr);
928
929 service = _mdns_dns_service_manager_get_discovered_service(me, doh_endpoint);
930 if (service == NULL) {
931 os_log(_mdns_dns_service_log(), "Registering discovered DoH resolver at %s", uri_string);
932
933 service = _mdns_dns_service_create_from_doh_uri(doh_endpoint, NULL);
934 if (service) {
935 _mdns_dns_service_manager_add_service(me, me->discovered_services, service);
936 mdns_release(service);
937 _mdns_dns_service_manager_fetch_doh_pvd(me, service);
938 }
939 }
940
941 if (service && domain) {
942 os_log(_mdns_dns_service_log(), "Adding domain %s to DoH resolver at %s", domain, uri_string);
943 _mdns_dns_service_add_domain(service, domain, 0);
944 }
945
946 exit:
947 free(uri_string);
948 nw_forget(&doh_endpoint);
949 return;
950 }
951
952 static mdns_dns_service_t
_mdns_dns_service_create_from_doh_uri(nw_endpoint_t url_endpoint,OSStatus * const out_error)953 _mdns_dns_service_create_from_doh_uri(nw_endpoint_t url_endpoint, OSStatus * const out_error)
954 {
955 nw_resolver_config_t config = nw_resolver_config_create();
956 nw_resolver_config_set_class(config, nw_resolver_class_designated);
957 nw_resolver_config_set_protocol(config, nw_resolver_protocol_doh);
958 nw_resolver_config_set_provider_name(config, nw_endpoint_get_hostname(url_endpoint));
959 nw_resolver_config_set_provider_path(config, nw_endpoint_get_url_path(url_endpoint));
960
961 uuid_t new_identifier;
962 uuid_generate(new_identifier);
963 nw_resolver_config_set_identifier(config, new_identifier);
964
965 OSStatus err;
966 const mdns_dns_service_t service = _mdns_dns_service_create(mdns_dns_service_source_dns,
967 mdns_dns_service_scope_uuid, mdns_resolver_type_null, &err);
968 require_noerr_quiet(err, exit);
969
970 service->discovered.url_endpoint = nw_retain(url_endpoint);
971 service->discovered.squash_cnames = true;
972 service->config = config;
973 config = NULL;
974 service->flags = (mdns_dns_service_flag_a_queries_advised | mdns_dns_service_flag_aaaa_queries_advised);
975
976 exit:
977 if (out_error) {
978 *out_error = err;
979 }
980 nw_forget(&config);
981 return service;
982 }
983
984 //======================================================================================================================
985
986 void
mdns_dns_service_manager_invalidate(const mdns_dns_service_manager_t me)987 mdns_dns_service_manager_invalidate(const mdns_dns_service_manager_t me)
988 {
989 dispatch_sync(me->queue,
990 ^{
991 require_return(!me->invalidated);
992 _mdns_dns_service_manager_terminate(me, kNoErr);
993 me->invalidated = true;
994 });
995 }
996
997 //======================================================================================================================
998
999 mdns_dns_service_t
mdns_dns_service_manager_get_unscoped_service(const mdns_dns_service_manager_t me,const uint8_t * const name)1000 mdns_dns_service_manager_get_unscoped_service(const mdns_dns_service_manager_t me, const uint8_t * const name)
1001 {
1002 __block mdns_dns_service_t result;
1003 dispatch_sync(me->queue,
1004 ^{
1005 require_return_action(!me->terminated, result = NULL);
1006 const mdns_dns_service_scope_t scope = mdns_dns_service_scope_none;
1007 const mdns_dns_service_t service = _mdns_dns_service_manager_get_service(me, name, scope, 0);
1008 result = _mdns_dns_service_manager_prepare_service(me, service);
1009 });
1010 return result;
1011 }
1012
1013 //======================================================================================================================
1014
1015 mdns_dns_service_t
mdns_dns_service_manager_get_interface_scoped_service(const mdns_dns_service_manager_t me,const uint8_t * const name,const uint32_t if_index)1016 mdns_dns_service_manager_get_interface_scoped_service(const mdns_dns_service_manager_t me, const uint8_t * const name,
1017 const uint32_t if_index)
1018 {
1019 __block mdns_dns_service_t result;
1020 dispatch_sync(me->queue,
1021 ^{
1022 require_return_action(!me->terminated, result = NULL);
1023 const mdns_dns_service_scope_t scope = mdns_dns_service_scope_interface;
1024 const mdns_dns_service_t service = _mdns_dns_service_manager_get_service(me, name, scope, if_index);
1025 result = _mdns_dns_service_manager_prepare_service(me, service);
1026 });
1027 return result;
1028 }
1029
1030 //======================================================================================================================
1031
1032 mdns_dns_service_t
mdns_dns_service_manager_get_service_scoped_service(const mdns_dns_service_manager_t me,const uint8_t * const name,const uint32_t service_id)1033 mdns_dns_service_manager_get_service_scoped_service(const mdns_dns_service_manager_t me, const uint8_t * const name,
1034 const uint32_t service_id)
1035 {
1036 __block mdns_dns_service_t result;
1037 dispatch_sync(me->queue,
1038 ^{
1039 require_return_action(!me->terminated, result = NULL);
1040 const mdns_dns_service_scope_t scope = mdns_dns_service_scope_service;
1041 const mdns_dns_service_t service = _mdns_dns_service_manager_get_service(me, name, scope, service_id);
1042 result = _mdns_dns_service_manager_prepare_service(me, service);
1043 });
1044 return result;
1045 }
1046
1047 //======================================================================================================================
1048
1049 static mdns_dns_service_t
1050 _mdns_dns_service_manager_get_custom_service(mdns_dns_service_manager_t manager, mdns_dns_service_id_t ident);
1051
1052 mdns_dns_service_t
mdns_dns_service_manager_get_custom_service(const mdns_dns_service_manager_t me,const mdns_dns_service_id_t ident)1053 mdns_dns_service_manager_get_custom_service(const mdns_dns_service_manager_t me, const mdns_dns_service_id_t ident)
1054 {
1055 __block mdns_dns_service_t result;
1056 dispatch_sync(me->queue,
1057 ^{
1058 require_return_action(!me->terminated, result = NULL);
1059 const mdns_dns_service_t service = _mdns_dns_service_manager_get_custom_service(me, ident);
1060 result = _mdns_dns_service_manager_prepare_service(me, service);
1061 });
1062 return result;
1063 }
1064
1065 static mdns_dns_service_t
_mdns_dns_service_manager_get_custom_service(const mdns_dns_service_manager_t me,const mdns_dns_service_id_t ident)1066 _mdns_dns_service_manager_get_custom_service(const mdns_dns_service_manager_t me, const mdns_dns_service_id_t ident)
1067 {
1068 const CFIndex n = CFArrayGetCount(me->custom_services);
1069 for (CFIndex i = 0; i < n; ++i) {
1070 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(me->custom_services, i);
1071 if (service->ident == ident) {
1072 return service;
1073 }
1074 }
1075 return NULL;
1076 }
1077
1078 //======================================================================================================================
1079
1080 mdns_dns_service_t
mdns_dns_service_manager_get_uuid_scoped_service(const mdns_dns_service_manager_t me,const uuid_t uuid)1081 mdns_dns_service_manager_get_uuid_scoped_service(const mdns_dns_service_manager_t me, const uuid_t uuid)
1082 {
1083 __block mdns_dns_service_t result;
1084 dispatch_sync(me->queue,
1085 ^{
1086 require_return_action(!me->terminated, result = NULL);
1087 const mdns_dns_service_t service = _mdns_dns_service_manager_get_uuid_scoped_service(me, uuid);
1088 result = _mdns_dns_service_manager_prepare_service(me, service);
1089 });
1090 return result;
1091 }
1092
1093 //======================================================================================================================
1094
1095 bool
1096 _mdns_dns_service_manager_fillout_discovered_service_for_name(mdns_dns_service_manager_t manager,
1097 const uint8_t *name, uuid_t out_uuid);
1098
1099 bool
mdns_dns_service_manager_fillout_discovered_service_for_name(const mdns_dns_service_manager_t me,const uint8_t * const name,uuid_t out_uuid)1100 mdns_dns_service_manager_fillout_discovered_service_for_name(const mdns_dns_service_manager_t me,
1101 const uint8_t * const name, uuid_t out_uuid)
1102 {
1103 __block bool success = false;
1104 dispatch_sync(me->queue,
1105 ^{
1106 require_return(!me->terminated);
1107 success = _mdns_dns_service_manager_fillout_discovered_service_for_name(me, name, out_uuid);
1108 });
1109 return success;
1110 }
1111
1112 bool
_mdns_dns_service_manager_fillout_discovered_service_for_name(const mdns_dns_service_manager_t me,const uint8_t * const name,uuid_t out_uuid)1113 _mdns_dns_service_manager_fillout_discovered_service_for_name(const mdns_dns_service_manager_t me,
1114 const uint8_t * const name, uuid_t out_uuid)
1115 {
1116 mdns_dns_service_t service = NULL;
1117 int best_label_count = -1;
1118 const CFIndex n = CFArrayGetCount(me->discovered_services);
1119 for (CFIndex i = 0; i < n; ++i) {
1120 mdns_dns_service_t candidate = (mdns_dns_service_t)CFArrayGetValueAtIndex(me->discovered_services, i);
1121 const int label_count = _mdns_dns_service_handles_domain_name(candidate, name, NULL);
1122 if (candidate->config && (label_count > best_label_count)) {
1123 service = candidate;
1124 best_label_count = label_count;
1125 }
1126
1127 // Check if service details have expired while iterating the list
1128 _mdns_dns_service_manager_check_service_expiration(me, candidate);
1129 }
1130
1131 if (service) {
1132 // Update the most recent use (approximate) time for this service
1133 service->discovered.use_time = mach_continuous_approximate_time();
1134 nw_resolver_config_get_identifier(service->config, out_uuid);
1135 return true;
1136 }
1137 return false;
1138 }
1139
1140 //======================================================================================================================
1141
1142 static void
1143 _mdns_dns_service_manager_apply_pending_updates_internal(mdns_dns_service_manager_t manager);
1144
1145 static void
1146 _mdns_dns_service_manager_finish_defuncting_services(CFMutableArrayRef services);
1147
1148 static void
1149 _mdns_dns_service_manager_update_service_usability(CFMutableArrayRef services);
1150
1151 void
mdns_dns_service_manager_apply_pending_updates(const mdns_dns_service_manager_t me)1152 mdns_dns_service_manager_apply_pending_updates(const mdns_dns_service_manager_t me)
1153 {
1154 dispatch_sync(me->queue,
1155 ^{
1156 require_return(!me->terminated);
1157 _mdns_dns_service_manager_apply_pending_updates_internal(me);
1158 });
1159 }
1160
1161 static void
_mdns_dns_service_manager_apply_pending_updates_internal(const mdns_dns_service_manager_t me)1162 _mdns_dns_service_manager_apply_pending_updates_internal(const mdns_dns_service_manager_t me)
1163 {
1164 _mdns_dns_service_manager_finish_defuncting_services(me->path_services);
1165 _mdns_dns_service_manager_finish_defuncting_services(me->custom_services);
1166 _mdns_dns_service_manager_update_service_usability(me->path_services);
1167 _mdns_dns_service_manager_update_service_usability(me->discovered_services);
1168 _mdns_dns_service_manager_update_service_usability(me->custom_services);
1169 _mdns_dns_service_manager_remove_unneeded_interface_monitors(me);
1170 _mdns_dns_service_manager_update_interface_properties(me);
1171 }
1172
1173 static void
_mdns_dns_service_manager_finish_defuncting_services(const CFMutableArrayRef services)1174 _mdns_dns_service_manager_finish_defuncting_services(const CFMutableArrayRef services)
1175 {
1176 for (CFIndex i = CFArrayGetCount(services) - 1; i >= 0; --i) {
1177 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(services, i);
1178 if (service->defuncting) {
1179 _mdns_dns_service_make_defunct(service);
1180 CFArrayRemoveValueAtIndex(services, i);
1181 }
1182 }
1183 }
1184
1185 static void
_mdns_dns_service_manager_update_service_usability(const CFMutableArrayRef services)1186 _mdns_dns_service_manager_update_service_usability(const CFMutableArrayRef services)
1187 {
1188 const CFIndex n = CFArrayGetCount(services);
1189 for (CFIndex i = 0; i < n; ++i) {
1190 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(services, i);
1191 if (service->cannot_connect) {
1192 if (!(service->flags & mdns_dns_service_flag_connection_problems)) {
1193 service->flags |= mdns_dns_service_flag_connection_problems;
1194 }
1195 } else {
1196 if (service->flags & mdns_dns_service_flag_connection_problems) {
1197 service->flags &= ~mdns_dns_service_flag_connection_problems;
1198 }
1199 }
1200 }
1201 }
1202
1203 //======================================================================================================================
1204
1205 void
mdns_dns_service_manager_iterate(const mdns_dns_service_manager_t me,const mdns_dns_service_applier_t applier)1206 mdns_dns_service_manager_iterate(const mdns_dns_service_manager_t me, const mdns_dns_service_applier_t applier)
1207 {
1208 dispatch_sync(me->queue,
1209 ^{
1210 require_return(!me->terminated);
1211 _mdns_dns_service_manager_iterate_over_all_service_arrays(me,
1212 ^ bool (const CFMutableArrayRef service_array)
1213 {
1214 bool stop = false;
1215 const CFIndex n = CFArrayGetCount(service_array);
1216 for (CFIndex i = 0; i < n; ++i) {
1217 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(service_array, i);
1218 stop = applier(service);
1219 if (stop) {
1220 break;
1221 }
1222 }
1223 return stop;
1224 });
1225 });
1226 }
1227
1228 //======================================================================================================================
1229
1230 size_t
mdns_dns_service_manager_get_count(const mdns_dns_service_manager_t me)1231 mdns_dns_service_manager_get_count(const mdns_dns_service_manager_t me)
1232 {
1233 __block size_t count = 0;
1234 dispatch_sync(me->queue,
1235 ^{
1236 require_return(!me->terminated);
1237 _mdns_dns_service_manager_iterate_over_all_service_arrays(me,
1238 ^ bool (const CFMutableArrayRef service_array)
1239 {
1240 count += (size_t)CFArrayGetCount(service_array);
1241 return false;
1242 });
1243 });
1244 return count;
1245 }
1246
1247 //======================================================================================================================
1248
1249 void
mdns_dns_service_manager_handle_sleep(const mdns_dns_service_manager_t me)1250 mdns_dns_service_manager_handle_sleep(const mdns_dns_service_manager_t me)
1251 {
1252 mdns_dns_service_manager_iterate(me,
1253 ^ bool (const mdns_dns_service_t service)
1254 {
1255 const mdns_resolver_type_t type = _mdns_dns_service_get_resolver_type_safe(service);
1256 if ((type == mdns_resolver_type_tls) || (type == mdns_resolver_type_https)) {
1257 if (service->resolver) {
1258 mdns_resolver_forget(&service->resolver);
1259 service->replace_resolver = true;
1260 }
1261 }
1262 return false;
1263 });
1264 }
1265
1266 //======================================================================================================================
1267
1268 void
mdns_dns_service_manager_handle_wake(const mdns_dns_service_manager_t me)1269 mdns_dns_service_manager_handle_wake(const mdns_dns_service_manager_t me)
1270 {
1271 mdns_dns_service_manager_iterate(me,
1272 ^ bool (const mdns_dns_service_t service)
1273 {
1274 if (service->replace_resolver) {
1275 _mdns_dns_service_manager_prepare_service(me, service);
1276 service->replace_resolver = false;
1277 }
1278 return false;
1279 });
1280 }
1281
1282 //======================================================================================================================
1283 // MARK: - DNS Service Manager Private Methods
1284
1285 static void
_mdns_dns_service_manager_finalize(mdns_dns_service_manager_t me)1286 _mdns_dns_service_manager_finalize(mdns_dns_service_manager_t me)
1287 {
1288 ForgetCF(&me->default_services);
1289 ForgetCF(&me->path_services);
1290 ForgetCF(&me->discovered_services);
1291 ForgetCF(&me->custom_services);
1292 ForgetCF(&me->monitors);
1293 dispatch_forget(&me->queue);
1294 dispatch_forget(&me->user_queue);
1295 BlockForget(&me->event_handler);
1296 }
1297
1298 //======================================================================================================================
1299
1300 static OSStatus
1301 _mdns_dns_service_manager_print_description(const mdns_dns_service_manager_t me, const bool debug, const bool privacy,
1302 char * const buf_ptr, const size_t buf_len, size_t *out_len, size_t *out_true_len);
1303
1304 static char *
_mdns_dns_service_manager_copy_description(const mdns_dns_service_manager_t me,const bool debug,const bool privacy)1305 _mdns_dns_service_manager_copy_description(const mdns_dns_service_manager_t me, const bool debug, const bool privacy)
1306 {
1307 char *description = NULL;
1308
1309 size_t true_len;
1310 char buf[1024];
1311 OSStatus err = _mdns_dns_service_manager_print_description(me, debug, privacy, buf, sizeof(buf), NULL, &true_len);
1312 require_noerr_quiet(err, exit);
1313
1314 if (true_len < sizeof(buf)) {
1315 description = strdup(buf);
1316 } else {
1317 const size_t buf_len = true_len + 1;
1318 char *buf_ptr = malloc(buf_len);
1319 require_quiet(buf_ptr, exit);
1320
1321 err = _mdns_dns_service_manager_print_description(me, debug, privacy, buf_ptr, buf_len, NULL, NULL);
1322 if (!err) {
1323 description = buf_ptr;
1324 } else {
1325 free(buf_ptr);
1326 }
1327 }
1328
1329 exit:
1330 return description;
1331 }
1332
1333 static OSStatus
1334 _mdns_dns_service_print_description(const mdns_dns_service_t service, const bool debug, const bool privacy,
1335 char * const buf_ptr, const size_t buf_len, size_t *out_len, size_t *out_true_len);
1336
1337 static OSStatus
_mdns_dns_service_manager_print_description(const mdns_dns_service_manager_t me,const bool debug,const bool privacy,char * const buf_ptr,const size_t buf_len,size_t * out_len,size_t * out_true_len)1338 _mdns_dns_service_manager_print_description(const mdns_dns_service_manager_t me, const bool debug, const bool privacy,
1339 char * const buf_ptr, const size_t buf_len, size_t *out_len, size_t *out_true_len)
1340 {
1341 OSStatus err;
1342 char * dst = buf_ptr;
1343 const char * const lim = &buf_ptr[buf_len];
1344 size_t true_len = 0;
1345 int n;
1346
1347 #define _do_appendf(...) \
1348 do { \
1349 n = mdns_snprintf_add(&dst, lim, __VA_ARGS__); \
1350 require_action_quiet(n >= 0, exit, err = kUnknownErr); \
1351 true_len += (size_t)n; \
1352 } while(0)
1353
1354 if (debug) {
1355 _do_appendf("<%s: %p>: ", me->base.kind->name, me);
1356 }
1357 const CFArrayRef service_arrays[] = {
1358 MDNS_DNS_SERVICE_MANAGER_ARRAYS(me)
1359 };
1360 _do_appendf("{");
1361 const char *sep = "";
1362 for (size_t i = 0; i < countof(service_arrays); ++i) {
1363 const CFArrayRef services = service_arrays[i];
1364 const CFIndex service_count = CFArrayGetCount(services);
1365 for (CFIndex j = 0; j < service_count; ++j) {
1366 _do_appendf("%s\n\t", sep);
1367 size_t len, true_len2;
1368 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(services, j);
1369 err = _mdns_dns_service_print_description(service, false, privacy, dst, (size_t)(lim - dst), &len,
1370 &true_len2);
1371 require_noerr_quiet(err, exit);
1372
1373 dst += len;
1374 true_len += true_len2;
1375 sep = ",";
1376 }
1377 }
1378 _do_appendf("\n}");
1379 #undef _do_appendf
1380
1381 if (out_len) {
1382 *out_len = (size_t)(dst - buf_ptr);
1383 }
1384 if (out_true_len) {
1385 *out_true_len = true_len;
1386 }
1387 err = kNoErr;
1388
1389 exit:
1390 return err;
1391 }
1392
1393 //======================================================================================================================
1394
1395 static void
1396 _mdns_dns_service_manager_terminate_services(mdns_dns_service_manager_t manager, CFMutableArrayRef services);
1397
1398 static void
_mdns_dns_service_manager_terminate(const mdns_dns_service_manager_t me,const OSStatus error)1399 _mdns_dns_service_manager_terminate(const mdns_dns_service_manager_t me, const OSStatus error)
1400 {
1401 require_return(!me->invalidated);
1402
1403 me->terminated = true;
1404 dispatch_source_forget(&me->update_source);
1405 CFIndex n = CFArrayGetCount(me->monitors);
1406 for (CFIndex i = 0; i < n; ++i) {
1407 mdns_interface_monitor_invalidate((mdns_interface_monitor_t)CFArrayGetValueAtIndex(me->monitors, i));
1408 }
1409 CFArrayRemoveAllValues(me->monitors);
1410
1411 _mdns_dns_service_manager_terminate_services(me, me->default_services);
1412 _mdns_dns_service_manager_terminate_services(me, me->path_services);
1413 _mdns_dns_service_manager_terminate_services(me, me->discovered_services);
1414 _mdns_dns_service_manager_terminate_services(me, me->custom_services);
1415
1416 mdns_retain(me);
1417 dispatch_async(me->user_queue,
1418 ^{
1419 if (me->event_handler) {
1420 me->event_handler(error ? mdns_event_error : mdns_event_invalidated, error);
1421 }
1422 mdns_release(me);
1423 });
1424 }
1425
1426 static void
_mdns_dns_service_manager_terminate_services(const mdns_dns_service_manager_t me,const CFMutableArrayRef services)1427 _mdns_dns_service_manager_terminate_services(const mdns_dns_service_manager_t me, const CFMutableArrayRef services)
1428 {
1429 const CFIndex n = CFArrayGetCount(services);
1430 for (CFIndex i = 0; i < n; ++i) {
1431 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(services, i);
1432 if (service->config && service->config_needs_cancel) {
1433 _mdns_dns_service_manager_cancel_resolver_config_updates(me, service->config);
1434 service->config_needs_cancel = false;
1435 }
1436 _mdns_dns_service_make_defunct((mdns_dns_service_t)CFArrayGetValueAtIndex(services, i));
1437 }
1438 CFArrayRemoveAllValues(services);
1439 }
1440
1441 //======================================================================================================================
1442
1443 static void
_mdns_dns_service_manager_add_service(const mdns_dns_service_manager_t me,const CFMutableArrayRef services,const mdns_dns_service_t service)1444 _mdns_dns_service_manager_add_service(const mdns_dns_service_manager_t me, const CFMutableArrayRef services,
1445 const mdns_dns_service_t service)
1446 {
1447 CFArrayAppendValue(services, service);
1448 _mdns_dns_service_manager_update_interface_properties_for_service(me, service);
1449 }
1450
1451 //======================================================================================================================
1452
1453 static mdns_dns_service_t
_mdns_dns_service_manager_get_service(const mdns_dns_service_manager_t me,const uint8_t * const name,const mdns_dns_service_scope_t scope,const uint32_t scoping_id)1454 _mdns_dns_service_manager_get_service(const mdns_dns_service_manager_t me, const uint8_t * const name,
1455 const mdns_dns_service_scope_t scope, const uint32_t scoping_id)
1456 {
1457 mdns_dns_service_t best_service = NULL;
1458 int best_label_count = -1;
1459 uint32_t best_order = 0;
1460 // Find the best service.
1461 const CFIndex n = CFArrayGetCount(me->default_services);
1462 for (CFIndex i = 0; i < n; ++i) {
1463 mdns_dns_service_t candidate = (mdns_dns_service_t)CFArrayGetValueAtIndex(me->default_services, i);
1464 if (candidate->scope != scope) {
1465 continue;
1466 }
1467 switch (scope) {
1468 case mdns_dns_service_scope_interface:
1469 if (candidate->if_index != scoping_id) {
1470 continue;
1471 }
1472 break;
1473
1474 case mdns_dns_service_scope_service:
1475 if (candidate->service_id != scoping_id) {
1476 continue;
1477 }
1478 break;
1479
1480 default:
1481 case mdns_dns_service_scope_none:
1482 break;
1483 }
1484 uint32_t order = 0;
1485 const int label_count = _mdns_dns_service_handles_domain_name(candidate, name, &order);
1486 if (label_count < 0) {
1487 continue;
1488 }
1489 // The longer a service's parent domain match (in terms of label count), the better the service.
1490 // If a service has a parent domain match with a label count equal to that of the best service so far,
1491 // and its parent domain's order value is less than the current best service's parent domain's order
1492 // value (i.e., it has a higher priority), then it's a better service.
1493 if ((label_count > best_label_count) || ((label_count == best_label_count) && (order < best_order))) {
1494 best_service = candidate;
1495 best_label_count = label_count;
1496 best_order = order;
1497 }
1498 }
1499 return best_service;
1500 }
1501
1502 //======================================================================================================================
1503
1504 static mdns_dns_service_t
1505 _mdns_dns_service_manager_get_service_by_config_uuid(CFArrayRef services, const uuid_t uuid);
1506
1507 static mdns_dns_service_t
_mdns_dns_service_manager_get_uuid_scoped_service(const mdns_dns_service_manager_t me,const uuid_t uuid)1508 _mdns_dns_service_manager_get_uuid_scoped_service(const mdns_dns_service_manager_t me, const uuid_t uuid)
1509 {
1510 // First check in discovered services
1511 mdns_dns_service_t service = _mdns_dns_service_manager_get_service_by_config_uuid(me->discovered_services, uuid);
1512 if (!service) {
1513 service = _mdns_dns_service_manager_get_service_by_config_uuid(me->path_services, uuid);
1514 }
1515 return service;
1516 }
1517
1518 static mdns_dns_service_t
_mdns_dns_service_manager_get_service_by_config_uuid(const CFArrayRef services,const uuid_t uuid)1519 _mdns_dns_service_manager_get_service_by_config_uuid(const CFArrayRef services, const uuid_t uuid)
1520 {
1521 const CFIndex n = CFArrayGetCount(services);
1522 for (CFIndex i = 0; i < n; ++i) {
1523 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(services, i);
1524 if (service->config) {
1525 uuid_t config_uuid = {0};
1526 nw_resolver_config_get_identifier(service->config, config_uuid);
1527 if (uuid_compare(uuid, config_uuid) == 0) {
1528 return service;
1529 }
1530 }
1531 }
1532 return NULL;
1533 }
1534
1535 //======================================================================================================================
1536
1537 static mdns_dns_service_t
_mdns_dns_service_manager_get_discovered_service(const mdns_dns_service_manager_t me,nw_endpoint_t url_endpoint)1538 _mdns_dns_service_manager_get_discovered_service(const mdns_dns_service_manager_t me, nw_endpoint_t url_endpoint)
1539 {
1540 const char *hostname = nw_endpoint_get_hostname(url_endpoint);
1541 const char *path = nw_endpoint_get_url_path(url_endpoint);
1542 if (hostname == NULL || path == NULL) {
1543 return NULL;
1544 }
1545
1546 const CFIndex n = CFArrayGetCount(me->discovered_services);
1547 for (CFIndex i = 0; i < n; ++i) {
1548 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(me->discovered_services, i);
1549 if (service->config &&
1550 nw_resolver_config_get_protocol(service->config) == nw_resolver_protocol_doh) {
1551
1552 const char *config_hostname = nw_resolver_config_get_provider_name(service->config);
1553 const char *config_path = nw_resolver_config_get_provider_path(service->config);
1554 if (strcasecmp(hostname, config_hostname) == 0 &&
1555 strcasecmp(path, config_path) == 0) {
1556 return service;
1557 }
1558 }
1559 }
1560 return NULL;
1561 }
1562
1563 //======================================================================================================================
1564
1565 static void
_mdns_dns_service_manager_update_interface_properties(const mdns_dns_service_manager_t me)1566 _mdns_dns_service_manager_update_interface_properties(const mdns_dns_service_manager_t me)
1567 {
1568 _mdns_dns_service_manager_update_interface_properties_for_services(me, me->default_services);
1569 _mdns_dns_service_manager_update_interface_properties_for_services(me, me->path_services);
1570 _mdns_dns_service_manager_update_interface_properties_for_services(me, me->discovered_services);
1571 _mdns_dns_service_manager_update_interface_properties_for_services(me, me->custom_services);
1572 }
1573
1574 //======================================================================================================================
1575
1576 static bool
1577 _mdns_dns_service_manager_uses_interface(mdns_dns_service_manager_t manager, uint32_t if_index);
1578
1579 static bool
1580 _mdns_dns_services_use_interface(CFArrayRef services, uint32_t if_index);
1581
1582 static void
_mdns_dns_service_manager_remove_unneeded_interface_monitors(const mdns_dns_service_manager_t me)1583 _mdns_dns_service_manager_remove_unneeded_interface_monitors(const mdns_dns_service_manager_t me)
1584 {
1585 for (CFIndex i = CFArrayGetCount(me->monitors) - 1; i >= 0; --i) {
1586 const mdns_interface_monitor_t monitor = (mdns_interface_monitor_t)CFArrayGetValueAtIndex(me->monitors, i);
1587 const uint32_t if_index = mdns_interface_monitor_get_interface_index(monitor);
1588 const bool needed = _mdns_dns_service_manager_uses_interface(me, if_index);
1589 if (!needed) {
1590 mdns_interface_monitor_invalidate(monitor);
1591 CFArrayRemoveValueAtIndex(me->monitors, i);
1592 }
1593 }
1594 }
1595
1596 static bool
_mdns_dns_service_manager_uses_interface(const mdns_dns_service_manager_t me,const uint32_t if_index)1597 _mdns_dns_service_manager_uses_interface(const mdns_dns_service_manager_t me, const uint32_t if_index)
1598 {
1599 if (_mdns_dns_services_use_interface(me->default_services, if_index) ||
1600 _mdns_dns_services_use_interface(me->path_services, if_index) ||
1601 _mdns_dns_services_use_interface(me->discovered_services, if_index) ||
1602 _mdns_dns_services_use_interface(me->custom_services, if_index)) {
1603 return true;
1604 } else {
1605 return false;
1606 }
1607 }
1608
1609 static bool
_mdns_dns_services_use_interface(const CFArrayRef services,const uint32_t if_index)1610 _mdns_dns_services_use_interface(const CFArrayRef services, const uint32_t if_index)
1611 {
1612 const CFIndex n = CFArrayGetCount(services);
1613 for (CFIndex i = 0; i < n; ++i) {
1614 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(services, i);
1615 if (service->if_index == if_index) {
1616 return true;
1617 }
1618 }
1619 return false;
1620 }
1621
1622 //======================================================================================================================
1623
1624 static void
_mdns_dns_service_manager_update_interface_properties_for_services(const mdns_dns_service_manager_t me,const CFArrayRef services)1625 _mdns_dns_service_manager_update_interface_properties_for_services(const mdns_dns_service_manager_t me,
1626 const CFArrayRef services)
1627 {
1628 const CFIndex n = CFArrayGetCount(services);
1629 for (CFIndex i = 0; i < n; ++i) {
1630 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(services, i);
1631 _mdns_dns_service_manager_update_interface_properties_for_service(me, service);
1632 }
1633 }
1634
1635 //======================================================================================================================
1636
1637 static mdns_interface_monitor_t
1638 _mdns_dns_service_manager_get_interface_monitor(mdns_dns_service_manager_t manager, uint32_t if_index);
1639
1640 static void
_mdns_dns_service_manager_update_interface_properties_for_service(const mdns_dns_service_manager_t me,const mdns_dns_service_t service)1641 _mdns_dns_service_manager_update_interface_properties_for_service(const mdns_dns_service_manager_t me,
1642 const mdns_dns_service_t service)
1643 {
1644 require_quiet(service->if_index != 0, exit);
1645
1646 const mdns_interface_monitor_t monitor = _mdns_dns_service_manager_get_interface_monitor(me, service->if_index);
1647 require_action_quiet(monitor, exit,
1648 os_log_error(_mdns_dns_service_log(), "Failed to get interface monitor for interface %{public}s/%u",
1649 service->if_name ? service->if_name : "", service->if_index));
1650
1651 service->flags &= ~MDNS_DNS_SERVICE_FLAGS_FROM_INTERFACE_MONITOR;
1652 if (mdns_interface_monitor_has_ipv4_connectivity(monitor)) {
1653 service->flags |= mdns_dns_service_flag_ipv4_connectivity;
1654 }
1655 if (mdns_interface_monitor_has_ipv6_connectivity(monitor)) {
1656 service->flags |= mdns_dns_service_flag_ipv6_connectivity;
1657 }
1658 if (mdns_interface_monitor_is_expensive(monitor)) {
1659 service->flags |= mdns_dns_service_flag_expensive;
1660 }
1661 if (mdns_interface_monitor_is_constrained(monitor)) {
1662 service->flags |= mdns_dns_service_flag_constrained;
1663 }
1664 if (mdns_interface_monitor_is_clat46(monitor)) {
1665 service->flags |= mdns_dns_service_flag_clat46;
1666 }
1667 if (mdns_interface_monitor_is_vpn(monitor)) {
1668 service->flags |= mdns_dns_service_flag_vpn;
1669 }
1670
1671 exit:
1672 return;
1673 }
1674
1675 static mdns_interface_monitor_t
_mdns_dns_service_manager_get_interface_monitor(const mdns_dns_service_manager_t me,const uint32_t if_index)1676 _mdns_dns_service_manager_get_interface_monitor(const mdns_dns_service_manager_t me, const uint32_t if_index)
1677 {
1678 mdns_interface_monitor_t monitor = NULL;
1679 const CFIndex n = CFArrayGetCount(me->monitors);
1680 for (CFIndex i = 0; i < n; ++i) {
1681 mdns_interface_monitor_t candidate = (mdns_interface_monitor_t)CFArrayGetValueAtIndex(me->monitors, i);
1682 if (mdns_interface_monitor_get_interface_index(candidate) == if_index) {
1683 monitor = candidate;
1684 break;
1685 }
1686 }
1687 if (monitor) {
1688 goto exit;
1689 }
1690 monitor = mdns_interface_monitor_create(if_index);
1691 require_quiet(monitor, exit);
1692
1693 mdns_interface_monitor_set_queue(monitor, me->queue);
1694 mdns_retain(me);
1695 mdns_interface_monitor_set_update_handler(monitor,
1696 ^(mdns_interface_flags_t change_flags)
1697 {
1698 const mdns_interface_flags_t relevant_flags =
1699 mdns_interface_flag_ipv4_connectivity |
1700 mdns_interface_flag_ipv6_connectivity |
1701 mdns_interface_flag_expensive |
1702 mdns_interface_flag_constrained |
1703 mdns_interface_flag_clat46 |
1704 mdns_interface_flag_vpn;
1705 if ((change_flags & relevant_flags) != 0) {
1706 const CFRange full_range = CFRangeMake(0, CFArrayGetCount(me->monitors));
1707 if (CFArrayContainsValue(me->monitors, full_range, monitor)) {
1708 _mdns_dns_service_manager_trigger_update(me);
1709 }
1710 }
1711 });
1712 mdns_interface_monitor_set_event_handler(monitor,
1713 ^(mdns_event_t event, __unused OSStatus error)
1714 {
1715 switch (event) {
1716 case mdns_event_invalidated:
1717 mdns_release(monitor);
1718 mdns_release(me);
1719 break;
1720
1721 case mdns_event_error: {
1722 const CFRange full_range = CFRangeMake(0, CFArrayGetCount(me->monitors));
1723 const CFIndex i = CFArrayGetFirstIndexOfValue(me->monitors, full_range, monitor);
1724 if (i >= 0) {
1725 CFArrayRemoveValueAtIndex(me->monitors, i);
1726 }
1727 mdns_interface_monitor_invalidate(monitor);
1728 break;
1729 }
1730 default:
1731 break;
1732 }
1733 });
1734 mdns_interface_monitor_activate(monitor);
1735 CFArrayAppendValue(me->monitors, monitor);
1736
1737 exit:
1738 return monitor;
1739 }
1740
1741 //======================================================================================================================
1742 // MARK: - DNS Service Public Methods
1743
1744 void
mdns_dns_service_set_context(const mdns_dns_service_t me,void * const context)1745 mdns_dns_service_set_context(const mdns_dns_service_t me, void * const context)
1746 {
1747 me->context = context;
1748 }
1749
1750 //======================================================================================================================
1751
1752 void *
mdns_dns_service_get_context(const mdns_dns_service_t me)1753 mdns_dns_service_get_context(const mdns_dns_service_t me)
1754 {
1755 return me->context;
1756 }
1757
1758 //======================================================================================================================
1759
1760 void
mdns_dns_service_set_context_finalizer(const mdns_dns_service_t me,const mdns_context_finalizer_t finalizer)1761 mdns_dns_service_set_context_finalizer(const mdns_dns_service_t me, const mdns_context_finalizer_t finalizer)
1762 {
1763 me->context_finalizer = finalizer;
1764 }
1765
1766 //======================================================================================================================
1767
1768 mdns_querier_t
mdns_dns_service_create_querier(const mdns_dns_service_t me,OSStatus * const out_error)1769 mdns_dns_service_create_querier(const mdns_dns_service_t me, OSStatus * const out_error)
1770 {
1771 if (me->resolver) {
1772 return mdns_resolver_create_querier(me->resolver, out_error);
1773 } else {
1774 if (out_error) {
1775 *out_error = kNotInUseErr;
1776 }
1777 return NULL;
1778 }
1779 }
1780
1781 //======================================================================================================================
1782
1783 mdns_dns_service_scope_t
mdns_dns_service_get_scope(const mdns_dns_service_t me)1784 mdns_dns_service_get_scope(const mdns_dns_service_t me)
1785 {
1786 return me->scope;
1787 }
1788
1789 //======================================================================================================================
1790
1791 uint32_t
mdns_dns_service_get_interface_index(const mdns_dns_service_t me)1792 mdns_dns_service_get_interface_index(const mdns_dns_service_t me)
1793 {
1794 return me->if_index;
1795 }
1796
1797 //======================================================================================================================
1798
1799 mdns_dns_service_id_t
mdns_dns_service_get_id(const mdns_dns_service_t me)1800 mdns_dns_service_get_id(const mdns_dns_service_t me)
1801 {
1802 return _mdns_dns_service_get_id_safe(me);
1803 }
1804
1805 //======================================================================================================================
1806
1807 bool
mdns_dns_service_is_defunct(const mdns_dns_service_t me)1808 mdns_dns_service_is_defunct(const mdns_dns_service_t me)
1809 {
1810 return ((me->flags & mdns_dns_service_flag_defunct) ? true : false);
1811 }
1812
1813 //======================================================================================================================
1814
1815 bool
mdns_dns_service_is_encrypted(mdns_dns_service_t me)1816 mdns_dns_service_is_encrypted(mdns_dns_service_t me)
1817 {
1818 return mdns_resolver_type_uses_encryption(_mdns_dns_service_get_resolver_type_safe(me));
1819 }
1820
1821 //======================================================================================================================
1822
1823 bool
mdns_dns_service_a_queries_advised(const mdns_dns_service_t me)1824 mdns_dns_service_a_queries_advised(const mdns_dns_service_t me)
1825 {
1826 return ((me->flags & mdns_dns_service_flag_a_queries_advised) ? true : false);
1827 }
1828
1829 //======================================================================================================================
1830
1831 bool
mdns_dns_service_aaaa_queries_advised(const mdns_dns_service_t me)1832 mdns_dns_service_aaaa_queries_advised(const mdns_dns_service_t me)
1833 {
1834 return ((me->flags & mdns_dns_service_flag_aaaa_queries_advised) ? true : false);
1835 }
1836
1837 //======================================================================================================================
1838
1839 bool
mdns_dns_service_has_connection_problems(const mdns_dns_service_t me)1840 mdns_dns_service_has_connection_problems(const mdns_dns_service_t me)
1841 {
1842 return ((me->flags & mdns_dns_service_flag_connection_problems) ? true : false);
1843 }
1844
1845 //======================================================================================================================
1846
1847 bool
mdns_dns_service_interface_has_ipv4_connectivity(const mdns_dns_service_t me)1848 mdns_dns_service_interface_has_ipv4_connectivity(const mdns_dns_service_t me)
1849 {
1850 return ((me->flags & mdns_dns_service_flag_ipv4_connectivity) ? true : false);
1851 }
1852
1853 //======================================================================================================================
1854
1855 bool
mdns_dns_service_interface_has_ipv6_connectivity(const mdns_dns_service_t me)1856 mdns_dns_service_interface_has_ipv6_connectivity(const mdns_dns_service_t me)
1857 {
1858 return ((me->flags & mdns_dns_service_flag_ipv6_connectivity) ? true : false);
1859 }
1860
1861 //======================================================================================================================
1862
1863 bool
mdns_dns_service_interface_is_cellular(const mdns_dns_service_t me)1864 mdns_dns_service_interface_is_cellular(const mdns_dns_service_t me)
1865 {
1866 return ((me->flags & mdns_dns_service_flag_cellular) ? true : false);
1867 }
1868
1869 //======================================================================================================================
1870
1871 bool
mdns_dns_service_interface_is_expensive(const mdns_dns_service_t me)1872 mdns_dns_service_interface_is_expensive(const mdns_dns_service_t me)
1873 {
1874 return ((me->flags & mdns_dns_service_flag_expensive) ? true : false);
1875 }
1876
1877 //======================================================================================================================
1878
1879 bool
mdns_dns_service_interface_is_constrained(const mdns_dns_service_t me)1880 mdns_dns_service_interface_is_constrained(const mdns_dns_service_t me)
1881 {
1882 return ((me->flags & mdns_dns_service_flag_constrained) ? true : false);
1883 }
1884
1885 //======================================================================================================================
1886
1887 bool
mdns_dns_service_interface_is_clat46(const mdns_dns_service_t me)1888 mdns_dns_service_interface_is_clat46(const mdns_dns_service_t me)
1889 {
1890 return ((me->flags & mdns_dns_service_flag_clat46) ? true : false);
1891 }
1892
1893 //======================================================================================================================
1894
1895 bool
mdns_dns_service_interface_is_vpn(const mdns_dns_service_t me)1896 mdns_dns_service_interface_is_vpn(const mdns_dns_service_t me)
1897 {
1898 return ((me->flags & mdns_dns_service_flag_vpn) ? true : false);
1899 }
1900
1901 //======================================================================================================================
1902
1903 const char *
mdns_dns_service_get_provider_name(const mdns_dns_service_t me)1904 mdns_dns_service_get_provider_name(const mdns_dns_service_t me)
1905 {
1906 if (me->config) {
1907 const char *provider_name = nw_resolver_config_get_provider_name(me->config);
1908 if (provider_name) {
1909 return provider_name;
1910 }
1911 }
1912 return NULL;
1913 }
1914
1915 //======================================================================================================================
1916
1917 mdns_resolver_type_t
mdns_dns_service_get_resolver_type(const mdns_dns_service_t me)1918 mdns_dns_service_get_resolver_type(const mdns_dns_service_t me)
1919 {
1920 return me->resolver_type;
1921 }
1922
1923 //======================================================================================================================
1924 // MARK: - DNS Service Private Methods
1925
1926 static void
_mdns_dns_service_finalize(const mdns_dns_service_t me)1927 _mdns_dns_service_finalize(const mdns_dns_service_t me)
1928 {
1929 if (me->context) {
1930 if (me->context_finalizer) {
1931 me->context_finalizer(me->context);
1932 }
1933 me->context = NULL;
1934 }
1935 ForgetCF(&me->addresses);
1936 _domain_item_t item;
1937 while ((item = me->domain_list) != NULL) {
1938 me->domain_list = item->next;
1939 _domain_item_free(item);
1940 }
1941 nw_forget(&me->discovered.url_endpoint);
1942 nw_forget(&me->config);
1943 ForgetMem(&me->if_name);
1944 }
1945
1946 //======================================================================================================================
1947
1948 static char *
_mdns_dns_service_copy_description(const mdns_dns_service_t me,const bool debug,const bool privacy)1949 _mdns_dns_service_copy_description(const mdns_dns_service_t me, const bool debug, const bool privacy)
1950 {
1951 char *description = NULL;
1952
1953 size_t true_len;
1954 char buf[512];
1955 OSStatus err = _mdns_dns_service_print_description(me, debug, privacy, buf, sizeof(buf), NULL, &true_len);
1956 require_noerr_quiet(err, exit);
1957
1958 if (true_len < sizeof(buf)) {
1959 description = strdup(buf);
1960 } else {
1961 const size_t buf_len = true_len + 1;
1962 char *buf_ptr = malloc(buf_len);
1963 require_quiet(buf_ptr, exit);
1964
1965 err = _mdns_dns_service_print_description(me, debug, privacy, buf_ptr, buf_len, NULL, NULL);
1966 if (!err) {
1967 description = buf_ptr;
1968 } else {
1969 free(buf_ptr);
1970 }
1971 }
1972
1973 exit:
1974 return description;
1975 }
1976
1977 typedef struct {
1978 mdns_dns_service_flags_t flag;
1979 const char * desc;
1980 } mdns_dns_service_flag_description_t;
1981
1982 #define MDNS_DNS_SERVICE_REDACTED_STR "<REDACTED>"
1983
1984 static OSStatus
_mdns_dns_service_print_description(const mdns_dns_service_t me,const bool debug,const bool privacy,char * const buf_ptr,const size_t buf_len,size_t * out_len,size_t * out_true_len)1985 _mdns_dns_service_print_description(const mdns_dns_service_t me, const bool debug, const bool privacy,
1986 char * const buf_ptr, const size_t buf_len, size_t *out_len, size_t *out_true_len)
1987 {
1988 OSStatus err;
1989 char * dst = buf_ptr;
1990 const char * const lim = &buf_ptr[buf_len];
1991 size_t true_len = 0;
1992 char * address_desc = NULL;
1993
1994 #define _do_appendf(...) \
1995 do { \
1996 const int n = mdns_snprintf_add(&dst, lim, __VA_ARGS__); \
1997 require_action_quiet(n >= 0, exit, err = kUnknownErr); \
1998 true_len += (size_t)n; \
1999 } while(0)
2000
2001 if (debug) {
2002 _do_appendf("<%s: %p>: ", me->base.kind->name, me);
2003 }
2004
2005 // Print ID.
2006 _do_appendf("id: %llu", me->ident);
2007
2008 // Print DNS type.
2009 _do_appendf(", type: ");
2010 const mdns_resolver_type_t type = _mdns_dns_service_get_resolver_type_safe(me);
2011 switch (type) {
2012 case mdns_resolver_type_normal:
2013 _do_appendf("Do53");
2014 break;
2015
2016 case mdns_resolver_type_tls:
2017 _do_appendf("DoT");
2018 break;
2019
2020 case mdns_resolver_type_https:
2021 _do_appendf("DoH");
2022 break;
2023
2024 default:
2025 _do_appendf("<unknown type %d>", (int)type);
2026 break;
2027 }
2028
2029 // Print source.
2030 _do_appendf(", source: ");
2031 switch (me->source) {
2032 case mdns_dns_service_source_sc:
2033 _do_appendf("sc");
2034 break;
2035
2036 case mdns_dns_service_source_nw:
2037 _do_appendf("nw");
2038 break;
2039
2040 case mdns_dns_service_source_dns:
2041 _do_appendf("dns");
2042 break;
2043
2044 case mdns_dns_service_source_custom: {
2045 _do_appendf("custom");
2046 break;
2047 }
2048 default:
2049 _do_appendf("<unknown source %d>", (int)me->source);
2050 break;
2051 }
2052
2053 // Print scope.
2054 _do_appendf(", scope: ");
2055 switch (me->scope) {
2056 case mdns_dns_service_scope_none:
2057 _do_appendf("none");
2058 break;
2059
2060 case mdns_dns_service_scope_interface:
2061 _do_appendf("interface");
2062 break;
2063
2064 case mdns_dns_service_scope_service:
2065 _do_appendf("service (%u)", me->service_id);
2066 break;
2067
2068 case mdns_dns_service_scope_uuid: {
2069 _do_appendf("uuid");
2070 if (!privacy) {
2071 uuid_t uuid = {0};
2072 nw_resolver_config_get_identifier(me->config, uuid);
2073 uuid_string_t uuid_str;
2074 uuid_unparse(uuid, uuid_str);
2075 _do_appendf(" (%s)", uuid_str);
2076 }
2077 break;
2078 }
2079 default:
2080 _do_appendf("<ERROR: unknown scope %d>", (int)me->scope);
2081 break;
2082 }
2083
2084 // Print interface index.
2085 _do_appendf(", interface: %s/%u", me->if_name ? me->if_name : "", me->if_index);
2086
2087 // Print server addresses.
2088 _do_appendf(", servers: {");
2089
2090 const char *sep = "";
2091 const CFIndex address_count = CFArrayGetCount(me->addresses);
2092 for (CFIndex i = 0; i < address_count; ++i) {
2093 const mdns_address_t address = (mdns_address_t)CFArrayGetValueAtIndex(me->addresses, i);
2094 if (privacy) {
2095 const char *str;
2096 char strbuf[64];
2097 const struct sockaddr * const sa = mdns_address_get_sockaddr(address);
2098 const int family = sa->sa_family;
2099 if ((family == AF_INET) || (family == AF_INET6)) {
2100 const int n = mdns_print_obfuscated_ip_address(strbuf, sizeof(strbuf), sa);
2101 if (n >= 0) {
2102 str = strbuf;
2103 } else {
2104 str = (family == AF_INET) ? "<IPv4>" : "<IPv6>";
2105 }
2106 } else {
2107 str = "<IPv?>";
2108 }
2109 _do_appendf("%s%s", sep, str);
2110 const int port = mdns_address_get_port(address);
2111 if (port != 0) {
2112 _do_appendf(":%d", port);
2113 }
2114 } else {
2115 address_desc = mdns_object_copy_description(address, false, privacy);
2116 _do_appendf("%s%s", sep, address_desc ? address_desc : "<NO DESC.>");
2117 ForgetMem(&address_desc);
2118 }
2119 sep = ", ";
2120 }
2121 _do_appendf("}");
2122
2123 // Print domains.
2124 _do_appendf(", domains: {");
2125
2126 sep = "";
2127 for (const struct _domain_item_s *item = me->domain_list; item; item = item->next) {
2128 const char *str;
2129 char strbuf[64];
2130 if (privacy) {
2131 const int n = DNSMessagePrintObfuscatedString(strbuf, sizeof(strbuf), item->name_str);
2132 str = (n >= 0) ? strbuf : MDNS_DNS_SERVICE_REDACTED_STR;
2133 } else {
2134 str = item->name_str;
2135 }
2136 _do_appendf("%s%s", sep, str);
2137 if (item->order != 0) {
2138 _do_appendf(" (%u)", item->order);
2139 }
2140 sep = ", ";
2141 }
2142 _do_appendf("}");
2143
2144 // Print attributes.
2145 _do_appendf(", attributes: {");
2146
2147 const mdns_dns_service_flag_description_t mdns_dns_service_flag_service_descs[] = {
2148 {mdns_dns_service_flag_defunct, "defunct"},
2149 {mdns_dns_service_flag_a_queries_advised, "a-ok"},
2150 {mdns_dns_service_flag_aaaa_queries_advised, "aaaa-ok"},
2151 {mdns_dns_service_flag_connection_problems, "connection-problems"},
2152 };
2153 sep = "";
2154 for (size_t i = 0; i < countof(mdns_dns_service_flag_service_descs); ++i) {
2155 const mdns_dns_service_flag_description_t * const flag_desc = &mdns_dns_service_flag_service_descs[i];
2156 if (me->flags & flag_desc->flag) {
2157 _do_appendf("%s%s", sep, flag_desc->desc);
2158 sep = ", ";
2159 }
2160 }
2161 _do_appendf("}");
2162
2163 // Print interface properties.
2164 _do_appendf(", interface properties: {");
2165
2166 const mdns_dns_service_flag_description_t mdns_dns_service_flag_interface_descs[] = {
2167 {mdns_dns_service_flag_cellular, "cellular"},
2168 {mdns_dns_service_flag_ipv4_connectivity, "ipv4"},
2169 {mdns_dns_service_flag_ipv6_connectivity, "ipv6"},
2170 {mdns_dns_service_flag_expensive, "expensive"},
2171 {mdns_dns_service_flag_constrained, "constrained"},
2172 {mdns_dns_service_flag_clat46, "clat46"},
2173 {mdns_dns_service_flag_vpn, "vpn"}
2174 };
2175 sep = "";
2176 for (size_t i = 0; i < countof(mdns_dns_service_flag_interface_descs); ++i) {
2177 const mdns_dns_service_flag_description_t * const flag_desc = &mdns_dns_service_flag_interface_descs[i];
2178 if (me->flags & flag_desc->flag) {
2179 _do_appendf("%s%s", sep, flag_desc->desc);
2180 sep = ", ";
2181 }
2182 }
2183 _do_appendf("}");
2184
2185 // Print additional information from resolver config object that isn't already printed.
2186 if (me->config) {
2187 _do_appendf(", resolver config: {");
2188 const char *provider_name = nw_resolver_config_get_provider_name(me->config);
2189 _do_appendf("provider name: ");
2190 if (provider_name) {
2191 const char *str;
2192 char strbuf[64];
2193 if (privacy) {
2194 const int n = DNSMessagePrintObfuscatedString(strbuf, sizeof(strbuf), provider_name);
2195 str = (n >= 0) ? strbuf : MDNS_DNS_SERVICE_REDACTED_STR;
2196 } else {
2197 str = provider_name;
2198 }
2199 _do_appendf("%s", str);
2200 }
2201 const char *provider_path = nw_resolver_config_get_provider_path(me->config);
2202 _do_appendf(", provider path: ");
2203 if (provider_path) {
2204 const char *str;
2205 char strbuf[64];
2206 if (privacy) {
2207 const int n = DNSMessagePrintObfuscatedString(strbuf, sizeof(strbuf), provider_path);
2208 str = (n >= 0) ? strbuf : MDNS_DNS_SERVICE_REDACTED_STR;
2209 } else {
2210 str = provider_path;
2211 }
2212 _do_appendf("%s", str);
2213 }
2214 _do_appendf("}");
2215 }
2216 #undef _do_appendf
2217
2218 if (out_len) {
2219 *out_len = (size_t)(dst - buf_ptr);
2220 }
2221 if (out_true_len) {
2222 *out_true_len = true_len;
2223 }
2224 err = kNoErr;
2225
2226 exit:
2227 ForgetMem(&address_desc);
2228 return err;
2229 }
2230 //======================================================================================================================
2231
2232 static bool
_mdns_dns_service_equal(const mdns_dns_service_t me,const mdns_dns_service_t other)2233 _mdns_dns_service_equal(const mdns_dns_service_t me, const mdns_dns_service_t other)
2234 {
2235 return _mdns_dns_service_equal_ex(me, other, false);
2236 }
2237
2238 //======================================================================================================================
2239
2240 static mdns_dns_service_id_t
2241 _mdns_get_next_dns_service_id(void);
2242
2243 static mdns_dns_service_t
_mdns_dns_service_create(const mdns_dns_service_source_t source,const mdns_dns_service_scope_t scope,const mdns_resolver_type_t resolver_type,OSStatus * const out_error)2244 _mdns_dns_service_create(const mdns_dns_service_source_t source, const mdns_dns_service_scope_t scope,
2245 const mdns_resolver_type_t resolver_type, OSStatus * const out_error)
2246 {
2247 OSStatus err;
2248 mdns_dns_service_t service = NULL;
2249 mdns_dns_service_t obj = _mdns_dns_service_alloc();
2250 require_action_quiet(obj, exit, err = kNoMemoryErr);
2251
2252 obj->ident = _mdns_get_next_dns_service_id();
2253 obj->source = source;
2254 obj->scope = scope;
2255 obj->resolver_type = resolver_type;
2256
2257 obj->addresses = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
2258 require_action_quiet(obj->addresses, exit, err = kNoResourcesErr);
2259
2260 service = obj;
2261 obj = NULL;
2262 err = kNoErr;
2263
2264 exit:
2265 if (out_error) {
2266 *out_error = err;
2267 }
2268 mdns_release_null_safe(obj);
2269 return service;
2270 }
2271
2272 static mdns_dns_service_id_t
_mdns_get_next_dns_service_id(void)2273 _mdns_get_next_dns_service_id(void)
2274 {
2275 static _Atomic(mdns_dns_service_id_t) s_next_id = ATOMIC_VAR_INIT(1);
2276 return atomic_fetch_add_explicit(&s_next_id, 1, memory_order_relaxed);
2277 }
2278
2279 //======================================================================================================================
2280
2281 #define MDNS_INITIAL_DGRAM_RTX_INTERVAL_NONCELLULAR_SECS 1
2282 #define MDNS_INITIAL_DGRAM_RTX_INTERVAL_CELLULAR_SECS 2
2283
2284 static void
2285 _mdns_dns_service_manager_handle_resolver_event(mdns_dns_service_manager_t me, mdns_dns_service_t service,
2286 mdns_resolver_t resolver, mdns_resolver_event_t event, xpc_object_t info);
2287
2288 static void
_mdns_dns_service_manager_prepare_resolver(const mdns_dns_service_manager_t me,const mdns_dns_service_t service)2289 _mdns_dns_service_manager_prepare_resolver(const mdns_dns_service_manager_t me, const mdns_dns_service_t service)
2290 {
2291 require_return(!service->resolver);
2292
2293 // Determine the appropriate resolver type.
2294 const mdns_resolver_type_t type = _mdns_dns_service_get_resolver_type_safe(service);
2295 require_return(type != mdns_resolver_type_null);
2296
2297 // Create the resolver.
2298 OSStatus err;
2299 mdns_resolver_t resolver = mdns_resolver_create(type, service->if_index, &err);
2300 require_action_quiet(resolver, exit, os_log_error(_mdns_dns_service_log(),
2301 "Failed to create resolver for service -- service id: %llu", service->ident));
2302
2303 // Set up the resolver.
2304 if (service->config) {
2305 mdns_resolver_set_provider_name(resolver, nw_resolver_config_get_provider_name(service->config));
2306 mdns_resolver_set_url_path(resolver, nw_resolver_config_get_provider_path(service->config));
2307 }
2308 // Squash CNAMES if this discovered config requires it.
2309 if (service->discovered.squash_cnames) {
2310 mdns_resolver_set_squash_cnames(resolver, true);
2311 }
2312 const uint32_t interval_secs = mdns_dns_service_interface_is_cellular(service) ?
2313 MDNS_INITIAL_DGRAM_RTX_INTERVAL_CELLULAR_SECS : MDNS_INITIAL_DGRAM_RTX_INTERVAL_NONCELLULAR_SECS;
2314 mdns_resolver_set_initial_datagram_retransmission_interval(resolver, interval_secs);
2315 mdns_resolver_enable_symptom_reporting(resolver, me->report_symptoms);
2316 if (type == mdns_resolver_type_normal) {
2317 mdns_resolver_disable_connection_reuse(resolver, true);
2318 #if MDNS_RESOLVER_PROBLEMATIC_QTYPE_WORKAROUND
2319 mdns_resolver_enable_problematic_qtype_workaround(resolver, me->pqw_threshold);
2320 #endif
2321 }
2322 const CFIndex n = CFArrayGetCount(service->addresses);
2323 CFIndex add_count = 0;
2324 for (CFIndex i = 0; i < n; ++i) {
2325 const mdns_address_t address = (mdns_address_t)CFArrayGetValueAtIndex(service->addresses, i);
2326 const OSStatus add_err = mdns_resolver_add_server_address(resolver, address);
2327 if (likely(!add_err)) {
2328 ++add_count;
2329 } else {
2330 os_log_error(_mdns_dns_service_log(),
2331 "Failed to add address to resolver -- service id: %llu, address: %@, error: %{mdns:err}ld",
2332 service->ident, address, (long)add_err);
2333 }
2334 }
2335 require_quiet((n == 0) || (add_count > 0), exit);
2336
2337 mdns_resolver_set_queue(resolver, me->queue);
2338 mdns_retain(me);
2339 mdns_retain(resolver);
2340 mdns_retain(service);
2341 mdns_resolver_set_event_handler(resolver,
2342 ^(const mdns_resolver_event_t event, const xpc_object_t info)
2343 {
2344 _mdns_dns_service_manager_handle_resolver_event(me, service, resolver, event, info);
2345 });
2346 service->resolver = resolver;
2347 resolver = NULL;
2348
2349 // Reset the "cannot connect" state if the service used to have a resolver that couldn't connect.
2350 if (service->cannot_connect) {
2351 service->cannot_connect = false;
2352 _mdns_dns_service_manager_trigger_update(me);
2353 }
2354 mdns_resolver_activate(service->resolver);
2355
2356 exit:
2357 mdns_release_null_safe(resolver);
2358 }
2359
2360 static void
_mdns_dns_service_manager_handle_resolver_event(const mdns_dns_service_manager_t me,const mdns_dns_service_t service,const mdns_resolver_t resolver,const mdns_resolver_event_t event,const xpc_object_t info)2361 _mdns_dns_service_manager_handle_resolver_event(const mdns_dns_service_manager_t me,
2362 const mdns_dns_service_t service, const mdns_resolver_t resolver, const mdns_resolver_event_t event,
2363 const xpc_object_t info)
2364 {
2365 switch (event) {
2366 case mdns_resolver_event_connection: {
2367 require_quiet(info, exit);
2368 require_quiet(service->resolver == resolver, exit);
2369
2370 bool cannot_connect = xpc_dictionary_get_bool(info, MDNS_RESOLVER_EVENT_CONNECTION_INFO_KEY_CANNOT_CONNECT);
2371 os_log(_mdns_dns_service_log(),
2372 "Resolver can%{public}s connect -- service id: %llu, resolver: %@",
2373 cannot_connect ? "not" : "", service->ident, resolver);
2374 if (cannot_connect) {
2375 if (!service->cannot_connect) {
2376 service->cannot_connect = true;
2377 _mdns_dns_service_manager_trigger_update(me);
2378 }
2379 } else {
2380 if (service->cannot_connect) {
2381 service->cannot_connect = false;
2382 _mdns_dns_service_manager_trigger_update(me);
2383 }
2384 }
2385 break;
2386 }
2387 case mdns_resolver_event_invalidated: {
2388 os_log_info(_mdns_dns_service_log(),
2389 "Resolver has been invalidated -- service id: %llu, resolver: %@", service->ident, resolver);
2390 mdns_release(resolver);
2391 mdns_release(service);
2392 mdns_release(me);
2393 break;
2394 }
2395 default: {
2396 if (os_log_debug_enabled(_mdns_dns_service_log())) {
2397 char *info_desc = info ? xpc_copy_description(info) : NULL;
2398 os_log_debug(_mdns_dns_service_log(),
2399 "DNS service (%@) got unhandled event: %s info: %{public}s",
2400 service, mdns_resolver_event_to_string(event), info_desc);
2401 ForgetMem(&info_desc);
2402 }
2403 break;
2404 }
2405 }
2406
2407 exit:
2408 return;
2409 }
2410
2411 //======================================================================================================================
2412
2413 static void
_mdns_dns_service_manager_start_defuncting(const mdns_dns_service_manager_t me,const mdns_dns_service_t service)2414 _mdns_dns_service_manager_start_defuncting(const mdns_dns_service_manager_t me, const mdns_dns_service_t service)
2415 {
2416 if (!service->defuncting) {
2417 service->defuncting = true;
2418 _mdns_dns_service_manager_trigger_update(me);
2419 }
2420 }
2421
2422 //======================================================================================================================
2423
2424 static mdns_dns_service_t
_mdns_dns_service_manager_prepare_service(const mdns_dns_service_manager_t me,const mdns_dns_service_t service)2425 _mdns_dns_service_manager_prepare_service(const mdns_dns_service_manager_t me, const mdns_dns_service_t service)
2426 {
2427 require_return_value(service, NULL);
2428 _mdns_dns_service_manager_prepare_resolver(me, service);
2429 require_return_value_action(service->resolver, NULL,
2430 os_log_error(_mdns_dns_service_log(), "Failed to prepare resolver -- service id: %llu", service->ident));
2431 return service;
2432 }
2433
2434 //======================================================================================================================
2435
2436 static void
_mdns_dns_service_manager_trigger_update(const mdns_dns_service_manager_t me)2437 _mdns_dns_service_manager_trigger_update(const mdns_dns_service_manager_t me)
2438 {
2439 if (me->update_source) {
2440 dispatch_source_merge_data(me->update_source, 1);
2441 }
2442 }
2443
2444 //======================================================================================================================
2445
2446 static void
_mdns_dns_service_manager_iterate_over_all_service_arrays(const mdns_dns_service_manager_t me,const mdns_dns_service_array_applier_t applier)2447 _mdns_dns_service_manager_iterate_over_all_service_arrays(const mdns_dns_service_manager_t me,
2448 const mdns_dns_service_array_applier_t applier)
2449 {
2450 const CFMutableArrayRef all_arrays[] = {
2451 MDNS_DNS_SERVICE_MANAGER_ARRAYS(me)
2452 };
2453 for (size_t i = 0; i < countof(all_arrays); ++i) {
2454 const bool stop = applier(all_arrays[i]);
2455 if (stop) {
2456 break;
2457 }
2458 }
2459 }
2460
2461 //======================================================================================================================
2462
2463 static void
_mdns_dns_service_make_defunct(const mdns_dns_service_t me)2464 _mdns_dns_service_make_defunct(const mdns_dns_service_t me)
2465 {
2466 me->flags |= mdns_dns_service_flag_defunct;
2467 mdns_resolver_forget(&me->resolver);
2468 }
2469
2470 //======================================================================================================================
2471
2472 static bool
_mdns_dns_service_equal_ex(const mdns_dns_service_t me,const mdns_dns_service_t other,const bool ignore_domains)2473 _mdns_dns_service_equal_ex(const mdns_dns_service_t me, const mdns_dns_service_t other, const bool ignore_domains)
2474 {
2475 if (me == other) {
2476 return true;
2477 }
2478 if (me->scope != other->scope) {
2479 return false;
2480 }
2481 if (me->if_index != other->if_index) {
2482 return false;
2483 }
2484 if ((me->scope == mdns_dns_service_scope_service) && (me->service_id != other->service_id)) {
2485 return false;
2486 }
2487 if (!CFEqual(me->addresses, other->addresses)) {
2488 return false;
2489 }
2490 if (!ignore_domains) {
2491 const struct _domain_item_s *d1 = me->domain_list;
2492 const struct _domain_item_s *d2 = other->domain_list;
2493 while (d1 && d2) {
2494 if (_domain_item_compare(d1, d2, false) != 0) {
2495 return false;
2496 }
2497 d1 = d1->next;
2498 d2 = d2->next;
2499 }
2500 if (d1 || d2) {
2501 return false;
2502 }
2503 }
2504 return true;
2505 }
2506
2507 //======================================================================================================================
2508
2509 static OSStatus
_mdns_dns_service_add_domain(const mdns_dns_service_t me,const char * const name_str,const uint32_t order)2510 _mdns_dns_service_add_domain(const mdns_dns_service_t me, const char * const name_str, const uint32_t order)
2511 {
2512 OSStatus err;
2513 _domain_item_t new_item = (_domain_item_t)calloc(1, sizeof(*new_item));
2514 require_action_quiet(new_item, exit, err = kNoMemoryErr);
2515
2516 uint8_t name[kDomainNameLengthMax];
2517 err = DomainNameFromString(name, name_str, NULL);
2518 require_noerr_quiet(err, exit);
2519
2520 char normalized_name_str[kDNSServiceMaxDomainName];
2521 err = DomainNameToString(name, NULL, normalized_name_str, NULL);
2522 require_noerr_quiet(err, exit);
2523
2524 new_item->name_str = strdup(normalized_name_str);
2525 require_action_quiet(new_item->name_str, exit, err = kNoMemoryErr);
2526
2527 err = DomainNameDup(name, &new_item->name, NULL);
2528 require_noerr_quiet(err, exit);
2529
2530 new_item->label_count = DomainNameLabelCount(new_item->name);
2531 require_action_quiet(new_item->label_count >= 0, exit, err = kMalformedErr);
2532
2533 new_item->order = order;
2534 _domain_item_t *ptr;
2535 _domain_item_t item;
2536 for (ptr = &me->domain_list; (item = *ptr) != NULL; ptr = &item->next) {
2537 // Compare domain items, but ignore their order values.
2538 const int cmp = _domain_item_compare(new_item, item, true);
2539 if (cmp < 0) {
2540 break;
2541 }
2542 if (cmp == 0) {
2543 // The domain items are equal, but may have different order values. Keep the smaller order
2544 // (higher priority) value. The domain item with the larger order (lower priority) value is redundant.
2545 if (new_item->order < item->order) {
2546 item->order = new_item->order;
2547 }
2548 goto exit;
2549 }
2550 }
2551 new_item->next = item;
2552 *ptr = new_item;
2553 new_item = NULL;
2554
2555 exit:
2556 if (new_item) {
2557 _domain_item_free(new_item);
2558 }
2559 return err;
2560 }
2561
2562 //======================================================================================================================
2563
2564 static int
_mdns_dns_service_handles_domain_name(const mdns_dns_service_t me,const uint8_t * const name,uint32_t * const out_order)2565 _mdns_dns_service_handles_domain_name(const mdns_dns_service_t me, const uint8_t * const name,
2566 uint32_t * const out_order)
2567 {
2568 int result;
2569 const int label_count = DomainNameLabelCount(name);
2570 require_action_quiet(label_count >= 0, exit, result = -1);
2571
2572 const struct _domain_item_s *item;
2573 for (item = me->domain_list; item; item = item->next) {
2574 if (label_count < item->label_count) {
2575 continue;
2576 }
2577 const uint8_t * const ptr = _mdns_domain_name_get_parent(name, label_count - item->label_count);
2578 if (DomainNameEqual(ptr, item->name)) {
2579 break;
2580 }
2581 }
2582 require_action_quiet(item, exit, result = -1);
2583
2584 result = item->label_count;
2585 if (out_order) {
2586 *out_order = item->order;
2587 }
2588
2589 exit:
2590 return result;
2591 }
2592
2593 //======================================================================================================================
2594
2595 static mdns_resolver_type_t
_mdns_dns_service_get_resolver_type_safe(const mdns_dns_service_t me)2596 _mdns_dns_service_get_resolver_type_safe(const mdns_dns_service_t me)
2597 {
2598 if (me->config && (me->resolver_type == mdns_resolver_type_null)) {
2599 const nw_resolver_protocol_t proto = nw_resolver_config_get_protocol(me->config);
2600 switch (proto) {
2601 case nw_resolver_protocol_dns53:
2602 return mdns_resolver_type_normal;
2603
2604 case nw_resolver_protocol_dot:
2605 return mdns_resolver_type_tls;
2606
2607 case nw_resolver_protocol_doh:
2608 return mdns_resolver_type_https;
2609
2610 default:
2611 return mdns_resolver_type_null;
2612 }
2613 } else {
2614 return me->resolver_type;
2615 }
2616 }
2617
2618 //======================================================================================================================
2619 // MARK: - Local Helpers
2620
2621 static OSStatus
2622 _mdns_append_dns_service_from_config_by_scope(CFMutableArrayRef services, const dns_config_t *config,
2623 mdns_dns_service_scope_t scope);
2624
2625 static CFMutableArrayRef
_mdns_create_dns_service_array_from_config(const dns_config_t * const config,OSStatus * const out_error)2626 _mdns_create_dns_service_array_from_config(const dns_config_t * const config, OSStatus * const out_error)
2627 {
2628 OSStatus err;
2629 CFMutableArrayRef result = NULL;
2630
2631 CFMutableArrayRef services = CFArrayCreateMutable(kCFAllocatorDefault, 0, &mdns_cfarray_callbacks);
2632 require_action_quiet(services, exit, err = kNoResourcesErr);
2633
2634 err = _mdns_append_dns_service_from_config_by_scope(services, config, mdns_dns_service_scope_none);
2635 require_noerr_quiet(err, exit);
2636
2637 err = _mdns_append_dns_service_from_config_by_scope(services, config, mdns_dns_service_scope_interface);
2638 require_noerr_quiet(err, exit);
2639
2640 err = _mdns_append_dns_service_from_config_by_scope(services, config, mdns_dns_service_scope_service);
2641 require_noerr_quiet(err, exit);
2642
2643 result = services;
2644 services = NULL;
2645
2646 exit:
2647 if (out_error) {
2648 *out_error = err;
2649 }
2650 CFReleaseNullSafe(services);
2651 return result;
2652 }
2653
2654 #define MDNS_DNS_SERVICE_DNS_PORT 53
2655 #define MDNS_DNS_SERVICE_MDNS_PORT 5353
2656
2657 static OSStatus
_mdns_append_dns_service_from_config_by_scope(const CFMutableArrayRef services,const dns_config_t * const config,const mdns_dns_service_scope_t scope)2658 _mdns_append_dns_service_from_config_by_scope(const CFMutableArrayRef services, const dns_config_t * const config,
2659 const mdns_dns_service_scope_t scope)
2660 {
2661 OSStatus err;
2662 mdns_dns_service_t new_service = NULL;
2663 dns_resolver_t * const * resolver_array;
2664 int32_t resolver_count;
2665 switch (scope) {
2666 case mdns_dns_service_scope_none:
2667 resolver_array = config->resolver;
2668 resolver_count = config->n_resolver;
2669 break;
2670
2671 case mdns_dns_service_scope_interface:
2672 resolver_array = config->scoped_resolver;
2673 resolver_count = config->n_scoped_resolver;
2674 break;
2675
2676 case mdns_dns_service_scope_service:
2677 resolver_array = config->service_specific_resolver;
2678 resolver_count = config->n_service_specific_resolver;
2679 break;
2680
2681 default:
2682 err = kNoErr;
2683 goto exit;
2684 }
2685 for (int32_t i = 0; i < resolver_count; ++i) {
2686 const dns_resolver_t * const resolver = resolver_array[i];
2687 if ((resolver->port == MDNS_DNS_SERVICE_MDNS_PORT) || (resolver->n_nameserver == 0)) {
2688 continue;
2689 }
2690 // Don't let a malformed domain name prevent parsing the remaining config.
2691 if (resolver->domain) {
2692 uint8_t domain[kDomainNameLengthMax];
2693 if (DomainNameFromString(domain, resolver->domain, NULL) != kNoErr) {
2694 os_log_error(_mdns_dns_service_log(),
2695 "Encountered invalid dns_config_t resolver domain name: %s", resolver->domain);
2696 continue;
2697 }
2698 }
2699 new_service = _mdns_dns_service_create(mdns_dns_service_source_sc, scope, mdns_resolver_type_normal, &err);
2700 require_noerr_quiet(err, exit);
2701
2702 const uint16_t port = (resolver->port == 0) ? MDNS_DNS_SERVICE_DNS_PORT : resolver->port;
2703 for (int32_t j = 0; j < resolver->n_nameserver; ++j) {
2704 const struct sockaddr * const sa = resolver->nameserver[j];
2705 mdns_address_t address;
2706 if (sa->sa_family == AF_INET) {
2707 const struct sockaddr_in * const sin = (const struct sockaddr_in *)sa;
2708 address = mdns_address_create_ipv4(ntohl(sin->sin_addr.s_addr), port);
2709 require_action_quiet(address, exit, err = kNoMemoryErr);
2710 } else if (sa->sa_family == AF_INET6) {
2711 struct sockaddr_in6 sin6_fixed;
2712 const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sa;
2713 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && (resolver->if_index != 0) &&
2714 (sin6->sin6_scope_id != resolver->if_index)) {
2715 sin6_fixed = *sin6;
2716 sin6_fixed.sin6_scope_id = resolver->if_index;
2717 os_log(_mdns_dns_service_log(),
2718 "Corrected scope ID of link-local server address %{network:sockaddr}.*P from %u to %u",
2719 (int)sizeof(*sin6), sin6, sin6->sin6_scope_id, sin6_fixed.sin6_scope_id);
2720 sin6 = &sin6_fixed;
2721 }
2722 address = mdns_address_create_ipv6(sin6->sin6_addr.s6_addr, port, sin6->sin6_scope_id);
2723 require_action_quiet(address, exit, err = kNoMemoryErr);
2724 } else {
2725 continue;
2726 }
2727 CFArrayAppendValue(new_service->addresses, address);
2728 mdns_forget(&address);
2729 }
2730 new_service->if_index = resolver->if_index;
2731 new_service->service_id = (scope == mdns_dns_service_scope_service) ? resolver->service_identifier : 0;
2732 new_service->flags = mdns_dns_service_flag_null;
2733
2734 // Check if a service object that's identical in every way except domains and flags already exists.
2735 const char * const domain_str = resolver->domain ? resolver->domain : ".";
2736 const CFIndex n = CFArrayGetCount(services);
2737 for (CFIndex j = 0; j < n; ++j) {
2738 const mdns_dns_service_t service = (mdns_dns_service_t)CFArrayGetValueAtIndex(services, j);
2739 if (_mdns_dns_service_equal_ex(service, new_service, true)) {
2740 // Simply add the domain to the existing service.
2741 err = _mdns_dns_service_add_domain(service, domain_str, resolver->search_order);
2742 require_noerr_quiet(err, exit);
2743 mdns_forget(&new_service);
2744 break;
2745 }
2746 }
2747
2748 // If no existing service was found, add this one.
2749 if (new_service) {
2750 if (resolver->flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS) {
2751 new_service->flags |= mdns_dns_service_flag_a_queries_advised;
2752 }
2753 if (resolver->flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS) {
2754 new_service->flags |= mdns_dns_service_flag_aaaa_queries_advised;
2755 }
2756 #if !(TARGET_OS_OSX)
2757 if (resolver->reach_flags & kSCNetworkReachabilityFlagsIsWWAN) {
2758 new_service->flags |= mdns_dns_service_flag_cellular;
2759 }
2760 #endif
2761 if (new_service->if_index != 0) {
2762 const char *name_ptr;
2763 char name_buf[IF_NAMESIZE + 1];
2764 name_ptr = if_indextoname(new_service->if_index, name_buf);
2765 const int name_err = map_global_value_errno(name_ptr, name_ptr);
2766 if (!name_err) {
2767 new_service->if_name = strdup(name_ptr);
2768 } else {
2769 os_log_error(_mdns_dns_service_log(),
2770 "if_indextoname() for %u failed: %{darwin.errno}d", new_service->if_index, name_err);
2771 }
2772 }
2773 err = _mdns_dns_service_add_domain(new_service, domain_str, resolver->search_order);
2774 require_noerr_quiet(err, exit);
2775 CFArrayAppendValue(services, new_service);
2776 mdns_forget(&new_service);
2777 }
2778 }
2779 err = kNoErr;
2780
2781 exit:
2782 mdns_release_null_safe(new_service);
2783 return err;
2784 }
2785
2786 //======================================================================================================================
2787
2788 static mdns_dns_service_t
_mdns_dns_service_create_from_resolver_config(const nw_resolver_config_t config,const mdns_dns_service_source_t source,OSStatus * const out_error)2789 _mdns_dns_service_create_from_resolver_config(const nw_resolver_config_t config, const mdns_dns_service_source_t source,
2790 OSStatus * const out_error)
2791 {
2792 OSStatus err;
2793 const mdns_dns_service_t service = _mdns_dns_service_create(source, mdns_dns_service_scope_uuid,
2794 mdns_resolver_type_null, &err);
2795 require_noerr_quiet(err, exit);
2796
2797 nw_resolver_config_enumerate_name_servers(config,
2798 ^ bool (const char * _Nonnull name_server)
2799 {
2800 mdns_address_t address = mdns_address_create_from_ip_address_string(name_server);
2801 if (address) {
2802 CFArrayAppendValue(service->addresses, address);
2803 mdns_forget(&address);
2804 }
2805 return true;
2806 });
2807 nw_resolver_config_enumerate_match_domains(config,
2808 ^ bool (const char * _Nonnull match_domain)
2809 {
2810 _mdns_dns_service_add_domain(service, match_domain, 0);
2811 return true;
2812 });
2813 service->config = config;
2814 nw_retain(service->config);
2815 const char * const interface_name = nw_resolver_config_get_interface_name(config);
2816 if (interface_name) {
2817 service->if_name = strdup(interface_name);
2818 service->if_index = if_nametoindex(interface_name);
2819 }
2820 service->flags = (mdns_dns_service_flag_a_queries_advised | mdns_dns_service_flag_aaaa_queries_advised);
2821 err = kNoErr;
2822
2823 exit:
2824 if (out_error) {
2825 *out_error = err;
2826 }
2827 return service;
2828 }
2829
2830 //======================================================================================================================
2831
2832 static mdns_dns_service_id_t
_mdns_dns_service_get_id_safe(const mdns_dns_service_t me)2833 _mdns_dns_service_get_id_safe(const mdns_dns_service_t me)
2834 {
2835 require_return_value(me, 0);
2836 return me->ident;
2837 }
2838
2839 //======================================================================================================================
2840
2841 static const uint8_t *
_mdns_domain_name_get_parent(const uint8_t * const name,const int depth)2842 _mdns_domain_name_get_parent(const uint8_t * const name, const int depth)
2843 {
2844 int current_depth = 0;
2845 const uint8_t *ptr = name;
2846 while ((*ptr != 0) && (current_depth < depth)) {
2847 ptr += (1 + *ptr);
2848 ++current_depth;
2849 }
2850 return ptr;
2851 }
2852
2853 //======================================================================================================================
2854
2855 static void
_domain_item_free(const _domain_item_t item)2856 _domain_item_free(const _domain_item_t item)
2857 {
2858 ForgetMem(&item->name);
2859 ForgetMem(&item->name_str);
2860 free(item);
2861 }
2862
2863 //======================================================================================================================
2864
2865 static int
_domain_item_compare(const struct _domain_item_s * const d1,const struct _domain_item_s * const d2,const bool ignore_order)2866 _domain_item_compare(const struct _domain_item_s * const d1, const struct _domain_item_s * const d2,
2867 const bool ignore_order)
2868 {
2869 // The domain name with the greater label count precedes the other.
2870 int diff = d1->label_count - d2->label_count;
2871 if (diff > 0) {
2872 return -1;
2873 }
2874 if (diff < 0) {
2875 return 1;
2876 }
2877 // The domain name with the lexicographically lesser rightmost label precedes the other.
2878 // Compare each pair of non-root labels from right to left.
2879 for (int depth = d1->label_count; depth-- > 0; ) {
2880 const uint8_t * const label1 = _mdns_domain_name_get_parent(d1->name, depth);
2881 const uint8_t * const label2 = _mdns_domain_name_get_parent(d2->name, depth);
2882 const int length1 = label1[0];
2883 const int length2 = label2[0];
2884 const int n = Min(length1, length2);
2885 for (int i = 1; i <= n; ++i) {
2886 diff = tolower_safe(label1[i]) - tolower_safe(label2[i]);
2887 if (diff < 0) {
2888 return -1;
2889 }
2890 if (diff > 0) {
2891 return 1;
2892 }
2893 }
2894 diff = length1 - length2;
2895 if (diff < 0) {
2896 return -1;
2897 }
2898 if (diff > 0) {
2899 return 1;
2900 }
2901 }
2902 if (!ignore_order) {
2903 // The domain name with the smaller order (higher priority) precedes the other.
2904 if (d1->order < d2->order) {
2905 return -1;
2906 }
2907 if (d1->order > d2->order) {
2908 return 1;
2909 }
2910 }
2911 return 0;
2912 }
2913