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