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 "dnssd_private.h"
18 
19 #include "dnssd_object.h"
20 #include "dnssd_xpc.h"
21 #include "dnssd_svcb.h"
22 
23 #include <CoreUtils/CoreUtils.h>
24 #include <os/object_private.h>
25 #include <xpc/private.h>
26 
27 //======================================================================================================================
28 // MARK: - Kind Declarations
29 
30 #define DNSSD_STRUCT(NAME)	struct dnssd_ ## NAME ## _s
31 #define DNSSD_TYPE(NAME)	dnssd_ ## NAME ## _t
32 
33 #define DNSSD_KIND_DECLARE(NAME)																\
34 	static DNSSD_TYPE(NAME)																		\
35 	_dnssd_ ## NAME ## _alloc(void);															\
36 																								\
37 	static char *																				\
38 	_dnssd_ ## NAME ## _copy_description(DNSSD_TYPE(NAME) object, bool debug, bool privacy);	\
39 																								\
40 	static void																					\
41 	_dnssd_ ## NAME ## _finalize(DNSSD_TYPE(NAME) object)
42 
43 // Note: The last check checks if the base's type is equal to that of the superkind. If it's not, then the pointer
44 // comparison used as the argument to sizeof will cause a "comparison of distinct pointer types" warning, so long as
45 // the warning hasn't been disabled.
46 
47 #define DNSSD_BASE_CHECK(NAME, SUPER)																	\
48 	check_compile_time(offsetof(DNSSD_STRUCT(NAME), base) == 0);										\
49 	check_compile_time(sizeof_field(DNSSD_STRUCT(NAME), base) == sizeof(DNSSD_STRUCT(SUPER)));			\
50 	extern int _dnssd_base_type_check[sizeof(&(((DNSSD_TYPE(NAME))0)->base) == ((DNSSD_TYPE(SUPER))0))]
51 
52 #define DNSSD_KIND_DEFINE(NAME, SUPER) 											\
53 	static const struct dnssd_kind_s _dnssd_ ## NAME ## _kind = {				\
54 		&_dnssd_ ## SUPER ## _kind,												\
55 		# NAME,																	\
56 		_dnssd_ ## NAME ## _copy_description,									\
57 		_dnssd_ ## NAME ## _finalize,											\
58 	};																			\
59 																				\
60 	static DNSSD_TYPE(NAME)														\
61 	_dnssd_ ## NAME ## _alloc(void)												\
62 	{																			\
63 		DNSSD_TYPE(NAME) obj = dnssd_object_ ## NAME ## _alloc(sizeof(*obj));	\
64 		require_quiet(obj, exit);												\
65 																				\
66 		const dnssd_object_t base = (dnssd_object_t)obj;						\
67 		base->kind = &_dnssd_ ## NAME ## _kind;									\
68 																				\
69 	exit:																		\
70 		return obj;																\
71 	}																			\
72 	DNSSD_BASE_CHECK(NAME, SUPER)
73 
74 DNSSD_KIND_DECLARE(getaddrinfo);
75 DNSSD_KIND_DECLARE(getaddrinfo_result);
76 DNSSD_KIND_DECLARE(cname_array);
77 
78 typedef char *	(*dnssd_copy_description_f)(dnssd_any_t object, bool debug, bool privacy);
79 typedef void	(*dnssd_finalize_f)(dnssd_any_t object);
80 
81 typedef const struct dnssd_kind_s *	dnssd_kind_t;
82 struct dnssd_kind_s {
83 	dnssd_kind_t				superkind;			// This kind's superkind.
84 	const char *				name;				// Name of this kind.
85 	dnssd_copy_description_f	copy_description;	// Creates a textual description of object.
86 	dnssd_finalize_f			finalize;			// Releases object's resources right before the object is freed.
87 };
88 
89 //======================================================================================================================
90 // MARK: - Object Kind Definition
91 
92 struct dnssd_object_s {
93 	_OS_OBJECT_HEADER(const void * __ptrauth_objc_isa_pointer _os_obj_isa, _os_obj_refcnt, _os_obj_xref_cnt);
94 	dnssd_kind_t	kind;	// Pointer to an object's kind.
95 };
96 
97 static const struct dnssd_kind_s _dnssd_object_kind = {
98 	NULL,		// No superkind.
99 	"object",
100 	NULL,		// No copy_description method.
101 	NULL,		// No finalize method.
102 };
103 
104 //======================================================================================================================
105 // MARK: - GetAddrInfo Kind Definition
106 
107 typedef enum {
108 	dnssd_getaddrinfo_state_nascent		= 0,
109 	dnssd_getaddrinfo_state_starting	= 1,
110 	dnssd_getaddrinfo_state_started		= 2,
111 	dnssd_getaddrinfo_state_failed		= 3,
112 	dnssd_getaddrinfo_state_invalidated	= 4,
113 } dnssd_getaddrinfo_state_t;
114 
115 struct dnssd_getaddrinfo_s {
116 	struct dnssd_object_s				base;			// Object base.
117 	dnssd_getaddrinfo_t					next;			// Next getaddrinfo object in list.
118 	uint64_t							command_id;		// Command ID.
119 	dispatch_queue_t					user_queue;		// User's dispatch queue for invoking result and event handlers.
120 	dispatch_queue_t					mutex_queue;	// Mutex for accessing result_list from different queues.
121 	xpc_object_t						params;			// Parameters dictionary for getaddrinfo command.
122 	xpc_object_t						hostname;		// Reference to hostname from parameters dictionary.
123 	dnssd_cname_array_t					cnames_a;		// Array of hostname's canonical names for A results.
124 	dnssd_cname_array_t					cnames_aaaa;	// Array of hostname's canonical names for AAAA results.
125 	dispatch_source_t					event_source;	// Data source for triggering result and event handlers.
126 	dnssd_getaddrinfo_result_t			result_list;	// List of getaddrinfo results.
127 	dnssd_getaddrinfo_result_handler_t	result_handler;	// User's result handler.
128 	dnssd_event_handler_t				event_handler;	// User's event handler.
129 	dnssd_getaddrinfo_state_t			state;			// Internal state.
130 	OSStatus							error;			// Pending error.
131 	bool								user_activated;	// True if the object has been activated by user.
132 };
133 
134 DNSSD_KIND_DEFINE(getaddrinfo, object);
135 
136 //======================================================================================================================
137 // MARK: - GetAddrInfo Result Kind Definition
138 
139 struct dnssd_getaddrinfo_result_s {
140 	struct dnssd_object_s				base;				// Object base.
141 	dnssd_getaddrinfo_result_t			next;				// Next getaddrinfo result in list.
142 	sockaddr_ip							addr;				// IPv4 or IPv6 address of hostname.
143 	xpc_object_t						hostname;			// Requested hostname to resolve.
144 	xpc_object_t						actual_hostname;	// The actual/canonical hostname of the requested hostname.
145 	dnssd_cname_array_t					cnames;				// Array of hostname's canonical names.
146 	xpc_object_t						auth_tag;			// Authentication tag.
147 	xpc_object_t						provider_name;		// Provider name.
148 	xpc_object_t						ech_config;			// SVCB ECH config.
149 	xpc_object_t						address_hints;		// SVCB address hints.
150 	xpc_object_t						doh_uri;			// SVCB DoH URI.
151 	xpc_object_t						alpn_values;		// SVCB ALPN values.
152 	xpc_object_t						service_name;		// SVCB name.
153 	uint16_t							port;				// SVCB port.
154 	uint16_t							priority;			// SVCB priority.
155 	uint32_t							if_index;			// Interface index to which the result pertains.
156 	dnssd_getaddrinfo_result_type_t		type;				// Type of getaddrinfo result.
157 	dnssd_getaddrinfo_result_protocol_t	protocol;			// Protocol used for getaddrinfo result.
158 	bool								is_from_cache;		// True if the result was an answer from the cache.
159 	bool								valid_svcb;			// True if SVCB info is valid.
160 };
161 
162 DNSSD_KIND_DEFINE(getaddrinfo_result, object);
163 
164 //======================================================================================================================
165 // MARK: - CName Array Kind Definition
166 
167 struct dnssd_cname_array_s {
168 	struct dnssd_object_s	base;		// Object base.
169 	xpc_object_t			xpc_array;	// Underlying array of cnames as strings. Important: Must not be modified.
170 };
171 
172 DNSSD_KIND_DEFINE(cname_array, object);
173 
174 //======================================================================================================================
175 // MARK: - Constants
176 
177 #define DNSSD_EVENT_HAVE_RESULTS	(1U << 0)	// Results are available.
178 #define DNSSD_EVENT_REMOVE_ALL		(1U << 1)	// Previously delivered results are no longer valid.
179 #define DNSSD_EVENT_ERROR			(1U << 2)	// An error was encountered.
180 
181 // Strings for redacted description items.
182 
183 #define DNSSD_REDACTED_HOSTNAME_STR		"<redacted hostname>"
184 #define DNSSD_REDACTED_IPv4_ADDRESS_STR	"<redacted IPv4 address>"
185 #define DNSSD_REDACTED_IPv6_ADDRESS_STR	"<redacted IPv6 address>"
186 
187 //======================================================================================================================
188 // MARK: - Local Prototypes
189 
190 static dispatch_queue_t
191 _dnssd_client_queue(void);
192 
193 static xpc_connection_t
194 _dnssd_client_connection(void);
195 
196 static uint64_t
197 _dnssd_client_get_new_id(void);
198 
199 static void
200 _dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai);
201 
202 static void
203 _dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai);
204 
205 static void
206 _dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai);
207 
208 static OSStatus
209 _dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai);
210 
211 static void
212 _dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai, OSStatus error);
213 
214 static void
215 _dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t gai, dnssd_getaddrinfo_result_t result_list);
216 
217 static void
218 _dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t gai);
219 
220 static dnssd_getaddrinfo_result_t
221 _dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t gai);
222 
223 static void
224 _dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t gai, OSStatus error);
225 
226 static dnssd_getaddrinfo_result_t
227 _dnssd_getaddrinfo_create_result_from_dictionary(dnssd_getaddrinfo_t gai, xpc_object_t result_dict,
228 	OSStatus *out_error);
229 
230 static dnssd_cname_array_t
231 _dnssd_cname_array_create(xpc_object_t xpc_array, OSStatus *out_error);
232 
233 static dnssd_cname_array_t
234 _dnssd_get_empty_cname_array(void);
235 
236 static DNSServiceErrorType
237 _dnssd_osstatus_to_dns_service_error(OSStatus status);
238 
239 static int
240 _dnssd_snprintf(char **dst, const char *end, const char *format, ...);
241 
242 #if !defined(dnssd_release_null_safe)
243 	#define dnssd_release_null_safe(X)	\
244 		do {							\
245 			if (X) {					\
246 				dnssd_release(X);		\
247 			}							\
248 		} while(0)
249 #endif
250 
251 #if !defined(dnssd_forget)
252 	#define dnssd_forget(X)	ForgetCustom(X, dnssd_release)
253 #endif
254 
255 //======================================================================================================================
256 // MARK: - Object Public Methods
257 
258 void
dnssd_retain(const dnssd_any_t any)259 dnssd_retain(const dnssd_any_t any)
260 {
261 	os_retain(any.object);
262 }
263 
264 //======================================================================================================================
265 
266 void
dnssd_release(const dnssd_any_t any)267 dnssd_release(const dnssd_any_t any)
268 {
269 	os_release(any.object);
270 }
271 
272 //======================================================================================================================
273 
274 char *
dnssd_copy_description(dnssd_any_t object)275 dnssd_copy_description(dnssd_any_t object)
276 {
277 	return dnssd_object_copy_description(object, false, false);
278 }
279 
280 //======================================================================================================================
281 // MARK: - Object Private Methods
282 
283 char *
dnssd_object_copy_description(const dnssd_any_t any,const bool debug,const bool privacy)284 dnssd_object_copy_description(const dnssd_any_t any, const bool debug, const bool privacy)
285 {
286 	const dnssd_object_t me = any.object;
287 	for (dnssd_kind_t kind = me->kind; kind; kind = kind->superkind) {
288 		if (kind->copy_description) {
289 			char *desc = kind->copy_description(me, debug, privacy);
290 			return desc;
291 		}
292 	}
293 	return NULL;
294 }
295 
296 //======================================================================================================================
297 
298 void
dnssd_object_finalize(const dnssd_any_t any)299 dnssd_object_finalize(const dnssd_any_t any)
300 {
301 	const dnssd_object_t me = any.object;
302 	for (dnssd_kind_t kind = me->kind; kind; kind = kind->superkind) {
303 		if (kind->finalize) {
304 			kind->finalize(me);
305 		}
306 	}
307 }
308 
309 //======================================================================================================================
310 // MARK: - GetAddrInfo Public Methods
311 
312 dnssd_getaddrinfo_t
dnssd_getaddrinfo_create(void)313 dnssd_getaddrinfo_create(void)
314 {
315 	dnssd_getaddrinfo_t	gai = NULL;
316 	dnssd_getaddrinfo_t	obj = _dnssd_getaddrinfo_alloc();
317 	require_quiet(obj, exit);
318 
319 	obj->params = xpc_dictionary_create(NULL, NULL, 0);
320 	require_quiet(obj->params, exit);
321 
322 	obj->mutex_queue = dispatch_queue_create("com.apple.dnssd.getaddrinfo.mutex", DISPATCH_QUEUE_SERIAL);
323 	require_quiet(obj->mutex_queue, exit);
324 
325 	gai = obj;
326 	obj = NULL;
327 
328 exit:
329 	dnssd_release_null_safe(obj);
330 	return gai;
331 }
332 
333 //======================================================================================================================
334 
335 void
dnssd_getaddrinfo_set_queue(dnssd_getaddrinfo_t me,dispatch_queue_t queue)336 dnssd_getaddrinfo_set_queue(dnssd_getaddrinfo_t me, dispatch_queue_t queue)
337 {
338 	if (!me->user_activated) {
339 		dispatch_retain(queue);
340 		dispatch_release_null_safe(me->user_queue);
341 		me->user_queue = queue;
342 	} else if (!me->user_queue) {
343 		me->user_queue = queue;
344 		dispatch_retain(me->user_queue);
345 		_dnssd_client_activate_getaddrinfo_async(me);
346 	}
347 }
348 
349 //======================================================================================================================
350 
351 void
dnssd_getaddrinfo_set_flags(dnssd_getaddrinfo_t me,DNSServiceFlags flags)352 dnssd_getaddrinfo_set_flags(dnssd_getaddrinfo_t me, DNSServiceFlags flags)
353 {
354 	if (!me->user_activated) {
355 		dnssd_xpc_parameters_set_flags(me->params, flags);
356 	}
357 }
358 
359 //======================================================================================================================
360 
361 void
dnssd_getaddrinfo_set_account_id(dnssd_getaddrinfo_t me,const char * account_id)362 dnssd_getaddrinfo_set_account_id(dnssd_getaddrinfo_t me, const char * account_id)
363 {
364 	if (!me->user_activated) {
365 		dnssd_xpc_parameters_set_account_id(me->params, account_id);
366 	}
367 }
368 
369 //======================================================================================================================
370 
371 void
dnssd_getaddrinfo_set_hostname(dnssd_getaddrinfo_t me,const char * hostname)372 dnssd_getaddrinfo_set_hostname(dnssd_getaddrinfo_t me, const char *hostname)
373 {
374 	if (!me->user_activated) {
375 		dnssd_xpc_parameters_set_hostname(me->params, hostname);
376 	}
377 }
378 
379 //======================================================================================================================
380 
381 void
dnssd_getaddrinfo_set_interface_index(dnssd_getaddrinfo_t me,uint32_t interface_index)382 dnssd_getaddrinfo_set_interface_index(dnssd_getaddrinfo_t me, uint32_t interface_index)
383 {
384 	if (!me->user_activated) {
385 		dnssd_xpc_parameters_set_interface_index(me->params, interface_index);
386 	}
387 }
388 
389 //======================================================================================================================
390 
391 void
dnssd_getaddrinfo_set_protocols(dnssd_getaddrinfo_t me,DNSServiceProtocol protocols)392 dnssd_getaddrinfo_set_protocols(dnssd_getaddrinfo_t me, DNSServiceProtocol protocols)
393 {
394 	if (!me->user_activated) {
395 		dnssd_xpc_parameters_set_protocols(me->params, protocols);
396 	}
397 }
398 
399 //======================================================================================================================
400 
401 void
dnssd_getaddrinfo_set_service_scheme(dnssd_getaddrinfo_t me,const char * service_scheme)402 dnssd_getaddrinfo_set_service_scheme(dnssd_getaddrinfo_t me, const char *service_scheme)
403 {
404 	if (!me->user_activated) {
405 		dnssd_xpc_parameters_set_service_scheme(me->params, service_scheme);
406 	}
407 }
408 
409 //======================================================================================================================
410 
411 void
dnssd_getaddrinfo_set_delegate_pid(dnssd_getaddrinfo_t me,pid_t pid)412 dnssd_getaddrinfo_set_delegate_pid(dnssd_getaddrinfo_t me, pid_t pid)
413 {
414 	if (!me->user_activated) {
415 		dnssd_xpc_parameters_set_delegate_pid(me->params, pid);
416 	}
417 }
418 
419 //======================================================================================================================
420 
421 void
dnssd_getaddrinfo_set_delegate_uuid(dnssd_getaddrinfo_t me,uuid_t uuid)422 dnssd_getaddrinfo_set_delegate_uuid(dnssd_getaddrinfo_t me, uuid_t uuid)
423 {
424 	if (!me->user_activated) {
425 		dnssd_xpc_parameters_set_delegate_uuid(me->params, uuid);
426 	}
427 }
428 
429 //======================================================================================================================
430 
431 void
dnssd_getaddrinfo_set_delegate_audit_token(dnssd_getaddrinfo_t me,audit_token_t audit_token)432 dnssd_getaddrinfo_set_delegate_audit_token(dnssd_getaddrinfo_t me, audit_token_t audit_token)
433 {
434 	if (!me->user_activated) {
435 		dnssd_xpc_parameters_set_delegate_audit_token(me->params, &audit_token);
436 	}
437 }
438 
439 //======================================================================================================================
440 
441 void
dnssd_getaddrinfo_set_result_handler(dnssd_getaddrinfo_t me,dnssd_getaddrinfo_result_handler_t handler)442 dnssd_getaddrinfo_set_result_handler(dnssd_getaddrinfo_t me, dnssd_getaddrinfo_result_handler_t handler)
443 {
444 	dnssd_getaddrinfo_result_handler_t const new_handler = handler ? Block_copy(handler) : NULL;
445 	if (me->result_handler) {
446 		Block_release(me->result_handler);
447 	}
448 	me->result_handler = new_handler;
449 }
450 
451 //======================================================================================================================
452 
453 void
dnssd_getaddrinfo_set_event_handler(dnssd_getaddrinfo_t me,dnssd_event_handler_t handler)454 dnssd_getaddrinfo_set_event_handler(dnssd_getaddrinfo_t me, dnssd_event_handler_t handler)
455 {
456 	dnssd_event_handler_t const new_handler = handler ? Block_copy(handler) : NULL;
457 	if (me->event_handler) {
458 		Block_release(me->event_handler);
459 	}
460 	me->event_handler = new_handler;
461 }
462 
463 //======================================================================================================================
464 
465 void
dnssd_getaddrinfo_set_need_authenticated_results(dnssd_getaddrinfo_t me,bool need)466 dnssd_getaddrinfo_set_need_authenticated_results(dnssd_getaddrinfo_t me, bool need)
467 {
468 	if (!me->user_activated) {
469 		dnssd_xpc_parameters_set_need_authentication_tags(me->params, need);
470 	}
471 }
472 
473 //======================================================================================================================
474 
475 void
dnssd_getaddrinfo_set_need_encrypted_query(dnssd_getaddrinfo_t me,bool need,_Nullable xpc_object_t fallback_config)476 dnssd_getaddrinfo_set_need_encrypted_query(dnssd_getaddrinfo_t me, bool need, _Nullable xpc_object_t fallback_config)
477 {
478 	if (!me->user_activated) {
479 		dnssd_xpc_parameters_set_need_encrypted_query(me->params, need, fallback_config);
480 	}
481 }
482 
483 //======================================================================================================================
484 
485 void
dnssd_getaddrinfo_add_resolver_uuid(dnssd_getaddrinfo_t me,uuid_t _Nonnull uuid)486 dnssd_getaddrinfo_add_resolver_uuid(dnssd_getaddrinfo_t me, uuid_t _Nonnull uuid)
487 {
488 	if (!me->user_activated) {
489 		dnssd_xpc_parameters_add_resolver_uuid(me->params, uuid);
490 	}
491 }
492 
493 //======================================================================================================================
494 
495 void
dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me)496 dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me)
497 {
498 	if (!me->user_activated) {
499 		if (me->user_queue) {
500 			_dnssd_client_activate_getaddrinfo_async(me);
501 		}
502 		me->user_activated = true;
503 	}
504 }
505 
506 //======================================================================================================================
507 
508 static void
509 _dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai);
510 
511 static void
512 _dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me);
513 
514 void
dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me)515 dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me)
516 {
517 	dnssd_retain(me);
518 	dispatch_async(_dnssd_client_queue(),
519 	^{
520 		_dnssd_client_invalidate_getaddrinfo(me);
521 		dnssd_release(me);
522 	});
523 }
524 
525 static void
_dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai)526 _dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai)
527 {
528 	require_quiet(gai->state != dnssd_getaddrinfo_state_invalidated, exit);
529 
530 	_dnssd_client_deregister_getaddrinfo(gai);
531 	if ((gai->state == dnssd_getaddrinfo_state_starting) || (gai->state == dnssd_getaddrinfo_state_started)) {
532 		xpc_object_t const msg = xpc_dictionary_create(NULL, NULL, 0);
533 		if (msg) {
534 			dnssd_xpc_message_set_id(msg, gai->command_id);
535 			dnssd_xpc_message_set_command(msg, DNSSD_COMMAND_STOP);
536 			xpc_connection_send_message_with_reply(_dnssd_client_connection(), msg, _dnssd_client_queue(),
537 			^(xpc_object_t reply)
538 			{
539 				(void)reply;
540 			});
541 			xpc_release(msg);
542 		}
543 	}
544 	_dnssd_getaddrinfo_invalidate(gai);
545 	gai->state = dnssd_getaddrinfo_state_invalidated;
546 
547 exit:
548 	return;
549 }
550 
551 static void
_dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me)552 _dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me)
553 {
554 	dispatch_source_forget(&me->event_source);
555 	_dnssd_getaddrinfo_remove_all_results(me);
556 
557 	if (me->user_queue) {
558 		dnssd_retain(me);
559 		dispatch_async(me->user_queue,
560 		^{
561 			if (me->event_handler) {
562 				me->event_handler(dnssd_event_invalidated, kDNSServiceErr_NoError);
563 			}
564 			dnssd_release(me);
565 		});
566 	}
567 }
568 
569 //======================================================================================================================
570 // MARK: - GetAddrInfo Private Methods
571 
572 static char *
_dnssd_getaddrinfo_copy_description(dnssd_getaddrinfo_t me,const bool debug,const bool privacy)573 _dnssd_getaddrinfo_copy_description(dnssd_getaddrinfo_t me, const bool debug, const bool privacy)
574 {
575 	const char *hostname_str;
576 	if (me->hostname) {
577 		hostname_str = xpc_string_get_string_ptr(me->hostname);
578 		if (privacy && hostname_str) {
579 			hostname_str = DNSSD_REDACTED_HOSTNAME_STR;
580 		}
581 	} else {
582 		hostname_str = NULL;
583 	}
584 	char *desc = NULL;
585 	char *buf_ptr = NULL;
586 	size_t buf_len = 0;
587 	for (;;)
588 	{
589 		int n;
590 		char * dst = buf_ptr;
591 		char * const end = &buf_ptr[buf_len];
592 		size_t desc_len = 0;
593 		if (debug) {
594 			n = _dnssd_snprintf(&dst, end, "dnssd_%s (%p): ", me->base.kind->name, (void *)me);
595 			require_quiet(n >= 0, exit);
596 			desc_len += (size_t)n;
597 		}
598 		n = _dnssd_snprintf(&dst, end, "hostname: %s", hostname_str ? hostname_str : "<NO HOSTNAME>");
599 		require_quiet(n >= 0, exit);
600 		desc_len += (size_t)n;
601 
602 		if (!buf_ptr) {
603 			buf_len = desc_len + 1;
604 			buf_ptr = malloc(buf_len);
605 			require_quiet(buf_ptr, exit);
606 			buf_ptr[0] = '\0';
607 		} else {
608 			break;
609 		}
610 	}
611 	desc = buf_ptr;
612 	buf_ptr = NULL;
613 
614 exit:
615 	FreeNullSafe(buf_ptr);
616 	return desc;
617 }
618 
619 //======================================================================================================================
620 
621 static void
_dnssd_getaddrinfo_finalize(dnssd_getaddrinfo_t me)622 _dnssd_getaddrinfo_finalize(dnssd_getaddrinfo_t me)
623 {
624 	dispatch_forget(&me->user_queue);
625 	dispatch_forget(&me->mutex_queue);
626 	xpc_forget(&me->params);
627 	xpc_forget(&me->hostname);
628 	dnssd_forget(&me->cnames_a);
629 	dnssd_forget(&me->cnames_aaaa);
630 	BlockForget(&me->result_handler);
631 	BlockForget(&me->event_handler);
632 }
633 
634 //======================================================================================================================
635 
636 static void
_dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t me,dnssd_getaddrinfo_result_t result_list)637 _dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t me, dnssd_getaddrinfo_result_t result_list)
638 {
639 	dispatch_sync(me->mutex_queue,
640 	^{
641 		dnssd_getaddrinfo_result_t *ptr = &me->result_list;
642 		while (*ptr) {
643 			ptr = &(*ptr)->next;
644 		}
645 		*ptr = result_list;
646 	});
647 	dispatch_source_merge_data(me->event_source, DNSSD_EVENT_HAVE_RESULTS);
648 }
649 
650 //======================================================================================================================
651 
652 static void
_dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t me)653 _dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t me)
654 {
655 	dnssd_forget(&me->cnames_a);
656 	dnssd_forget(&me->cnames_aaaa);
657 	dnssd_getaddrinfo_result_t result_list = _dnssd_getaddrinfo_take_results(me);
658 	if (me->event_source) {
659 		dispatch_source_merge_data(me->event_source, DNSSD_EVENT_REMOVE_ALL);
660 	}
661 
662 	dnssd_getaddrinfo_result_t result;
663 	while ((result = result_list) != NULL) {
664 		result_list = result->next;
665 		dnssd_release(result);
666 	}
667 }
668 
669 //======================================================================================================================
670 
671 static dnssd_getaddrinfo_result_t
_dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t me)672 _dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t me)
673 {
674 	__block dnssd_getaddrinfo_result_t list;
675 	dispatch_sync(me->mutex_queue,
676 	^{
677 		list = me->result_list;
678 		me->result_list = NULL;
679 	});
680 	return list;
681 }
682 
683 //======================================================================================================================
684 
685 static void
_dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t me,OSStatus error)686 _dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t me, OSStatus error)
687 {
688 	dispatch_sync(me->mutex_queue,
689 	^{
690 		me->error = error;
691 	});
692 	dispatch_source_merge_data(me->event_source, DNSSD_EVENT_ERROR);
693 }
694 
695 //======================================================================================================================
696 // MARK: - GetAddrInfo Result Public Methods
697 
698 dnssd_getaddrinfo_result_type_t
dnssd_getaddrinfo_result_get_type(dnssd_getaddrinfo_result_t me)699 dnssd_getaddrinfo_result_get_type(dnssd_getaddrinfo_result_t me)
700 {
701 	return me->type;
702 }
703 
704 //======================================================================================================================
705 
706 const char *
dnssd_getaddrinfo_result_get_actual_hostname(dnssd_getaddrinfo_result_t me)707 dnssd_getaddrinfo_result_get_actual_hostname(dnssd_getaddrinfo_result_t me)
708 {
709 	return xpc_string_get_string_ptr(me->actual_hostname);
710 }
711 
712 //======================================================================================================================
713 
714 const struct sockaddr *
dnssd_getaddrinfo_result_get_address(dnssd_getaddrinfo_result_t me)715 dnssd_getaddrinfo_result_get_address(dnssd_getaddrinfo_result_t me)
716 {
717 	return &me->addr.sa;
718 }
719 
720 //======================================================================================================================
721 
722 const char *
dnssd_getaddrinfo_result_get_hostname(dnssd_getaddrinfo_result_t me)723 dnssd_getaddrinfo_result_get_hostname(dnssd_getaddrinfo_result_t me)
724 {
725 	return xpc_string_get_string_ptr(me->hostname);
726 }
727 
728 //======================================================================================================================
729 
730 const char *
dnssd_getaddrinfo_result_get_doh_uri(dnssd_getaddrinfo_result_t me)731 dnssd_getaddrinfo_result_get_doh_uri(dnssd_getaddrinfo_result_t me)
732 {
733 	return xpc_string_get_string_ptr(me->doh_uri);
734 }
735 
736 //======================================================================================================================
737 
738 uint16_t
dnssd_getaddrinfo_result_get_service_port(dnssd_getaddrinfo_result_t me)739 dnssd_getaddrinfo_result_get_service_port(dnssd_getaddrinfo_result_t me)
740 {
741 	return me->port;
742 }
743 
744 //======================================================================================================================
745 
746 uint16_t
dnssd_getaddrinfo_result_get_service_priority(dnssd_getaddrinfo_result_t me)747 dnssd_getaddrinfo_result_get_service_priority(dnssd_getaddrinfo_result_t me)
748 {
749 	return me->priority;
750 }
751 
752 //======================================================================================================================
753 
754 const char *
dnssd_getaddrinfo_result_get_service_name(dnssd_getaddrinfo_result_t me)755 dnssd_getaddrinfo_result_get_service_name(dnssd_getaddrinfo_result_t me)
756 {
757 	return xpc_string_get_string_ptr(me->service_name);
758 }
759 
760 //======================================================================================================================
761 
762 bool
dnssd_getaddrinfo_result_service_is_valid(dnssd_getaddrinfo_result_t me)763 dnssd_getaddrinfo_result_service_is_valid(dnssd_getaddrinfo_result_t me)
764 {
765 	return me->valid_svcb;
766 }
767 
768 //======================================================================================================================
769 
770 void
dnssd_getaddrinfo_result_enumerate_alpn_values(dnssd_getaddrinfo_result_t me,DNSSD_NOESCAPE dnssd_getaddrinfo_enumerate_alpn_values_block_t enumerator)771 dnssd_getaddrinfo_result_enumerate_alpn_values(dnssd_getaddrinfo_result_t me,
772 											   DNSSD_NOESCAPE dnssd_getaddrinfo_enumerate_alpn_values_block_t enumerator)
773 {
774 	if (me->alpn_values != NULL) {
775 		xpc_array_apply(me->alpn_values, ^bool(__unused size_t index, xpc_object_t _Nonnull value) {
776 			const char *string = xpc_string_get_string_ptr(value);
777 			return enumerator(string);
778 		});
779 	}
780 }
781 
782 //======================================================================================================================
783 
784 void
dnssd_getaddrinfo_result_enumerate_service_address_hints(dnssd_getaddrinfo_result_t me,DNSSD_NOESCAPE dnssd_getaddrinfo_enumerate_addresses_block_t enumerator)785 dnssd_getaddrinfo_result_enumerate_service_address_hints(dnssd_getaddrinfo_result_t me,
786 														 DNSSD_NOESCAPE dnssd_getaddrinfo_enumerate_addresses_block_t enumerator)
787 {
788 	if (me->address_hints != NULL) {
789 		xpc_array_apply(me->address_hints, ^bool(__unused size_t index, xpc_object_t _Nonnull value) {
790 			const void *bytes = xpc_data_get_bytes_ptr(value);
791 			return enumerator((const struct sockaddr *)bytes);
792 		});
793 	}
794 }
795 
796 //======================================================================================================================
797 
798 const void *
dnssd_getaddrinfo_result_get_ech_config(dnssd_getaddrinfo_result_t me,size_t * out_length)799 dnssd_getaddrinfo_result_get_ech_config(dnssd_getaddrinfo_result_t me, size_t *out_length)
800 {
801 	const void *	ech_ptr;
802 	size_t			ech_len;
803 
804 	if (me->ech_config) {
805 		ech_ptr = xpc_data_get_bytes_ptr(me->ech_config);
806 		ech_len = xpc_data_get_length(me->ech_config);
807 	} else {
808 		ech_ptr = NULL;
809 		ech_len = 0;
810 	}
811 	if (out_length) {
812 		*out_length = ech_len;
813 	}
814 	return ech_ptr;
815 }
816 
817 //======================================================================================================================
818 
819 uint32_t
dnssd_getaddrinfo_result_get_interface_index(dnssd_getaddrinfo_result_t me)820 dnssd_getaddrinfo_result_get_interface_index(dnssd_getaddrinfo_result_t me)
821 {
822 	return me->if_index;
823 }
824 
825 //======================================================================================================================
826 
827 const void *
dnssd_getaddrinfo_result_get_authentication_tag(dnssd_getaddrinfo_result_t me,size_t * out_length)828 dnssd_getaddrinfo_result_get_authentication_tag(dnssd_getaddrinfo_result_t me, size_t *out_length)
829 {
830 	const void *	auth_tag_ptr;
831 	size_t			auth_tag_len;
832 
833 	if (me->auth_tag) {
834 		auth_tag_ptr = xpc_data_get_bytes_ptr(me->auth_tag);
835 		auth_tag_len = xpc_data_get_length(me->auth_tag);
836 	} else {
837 		auth_tag_ptr = NULL;
838 		auth_tag_len = 0;
839 	}
840 	if (out_length) {
841 		*out_length = auth_tag_len;
842 	}
843 	return auth_tag_ptr;
844 }
845 
846 //======================================================================================================================
847 
848 dnssd_getaddrinfo_result_protocol_t
dnssd_getaddrinfo_result_get_protocol(dnssd_getaddrinfo_result_t me)849 dnssd_getaddrinfo_result_get_protocol(dnssd_getaddrinfo_result_t me)
850 {
851 	return me->protocol;
852 }
853 
854 //======================================================================================================================
855 
856 const char *
dnssd_getaddrinfo_result_get_provider_name(dnssd_getaddrinfo_result_t me)857 dnssd_getaddrinfo_result_get_provider_name(dnssd_getaddrinfo_result_t me)
858 {
859 	return xpc_string_get_string_ptr(me->provider_name);
860 }
861 
862 //======================================================================================================================
863 
864 dnssd_cname_array_t
dnssd_getaddrinfo_result_get_cnames(const dnssd_getaddrinfo_result_t me)865 dnssd_getaddrinfo_result_get_cnames(const dnssd_getaddrinfo_result_t me)
866 {
867 	return (me->cnames ? me->cnames : _dnssd_get_empty_cname_array());
868 }
869 
870 //======================================================================================================================
871 
872 bool
dnssd_getaddrinfo_result_is_from_cache(const dnssd_getaddrinfo_result_t me)873 dnssd_getaddrinfo_result_is_from_cache(const dnssd_getaddrinfo_result_t me)
874 {
875 	return me->is_from_cache;
876 }
877 
878 //======================================================================================================================
879 // MARK: - GetAddrInfo Result Private Methods
880 
881 static char *
_dnssd_getaddrinfo_result_copy_description(dnssd_getaddrinfo_result_t me,const bool debug,const bool privacy)882 _dnssd_getaddrinfo_result_copy_description(dnssd_getaddrinfo_result_t me, const bool debug, const bool privacy)
883 {
884 	const char *hostname;
885 	if (me->hostname) {
886 		hostname = xpc_string_get_string_ptr(me->hostname);
887 		if (privacy && hostname) {
888 			hostname = DNSSD_REDACTED_HOSTNAME_STR;
889 		}
890 	} else {
891 		hostname = NULL;
892 	}
893 	char addr_buf[INET6_ADDRSTRLEN + 1 + Max(IF_NAMESIZE, 10) + 1];
894 	const char *addr_str;
895 	if (me->addr.sa.sa_family == AF_INET) {
896 		if (privacy) {
897 			addr_str = DNSSD_REDACTED_IPv4_ADDRESS_STR;
898 		} else {
899 			check_compile_time_code(sizeof(addr_buf) >= INET_ADDRSTRLEN);
900 			addr_str = inet_ntop(AF_INET, &me->addr.v4.sin_addr.s_addr, addr_buf, (socklen_t)sizeof(addr_buf));
901 		}
902 	} else if (me->addr.sa.sa_family == AF_INET6) {
903 		if (privacy) {
904 			addr_str = DNSSD_REDACTED_IPv6_ADDRESS_STR;
905 		} else {
906 			const struct sockaddr_in6 * const sin6 = &me->addr.v6;
907 			check_compile_time_code(sizeof(addr_buf) >= INET6_ADDRSTRLEN);
908 			addr_str = inet_ntop(AF_INET6, sin6->sin6_addr.s6_addr, addr_buf, (socklen_t)sizeof(addr_buf));
909 			if (addr_str && (sin6->sin6_scope_id > 0)) {
910 				char * const		dst = &addr_buf[strlen(addr_buf)];
911 				const char * const	end = &addr_buf[countof(addr_buf)];
912 				char ifname[IF_NAMESIZE + 1];
913 				if (if_indextoname(sin6->sin6_scope_id, ifname)) {
914 					snprintf(dst, (size_t)(end - dst), "%%%s", ifname);
915 				} else {
916 					snprintf(dst, (size_t)(end - dst), "%%%u", sin6->sin6_scope_id);
917 				}
918 			}
919 		}
920 	} else {
921 		addr_str = NULL;
922 	}
923 	char *desc = NULL;
924 	char *buf_ptr = NULL;
925 	size_t buf_len = 0;
926 	for (;;)
927 	{
928 		char *dst = buf_ptr;
929 		char * const end = &buf_ptr[buf_len];
930 		size_t desc_len = 0;
931 		int n;
932 		if (debug) {
933 			n = _dnssd_snprintf(&dst, end, "dnssd_%s (%p): ", me->base.kind->name, (void *)me);
934 			require_quiet(n >= 0, exit);
935 			desc_len += (size_t)n;
936 		}
937 		n = _dnssd_snprintf(&dst, end, "hostname: %s, address: %s, type: %s, ifindex: %lu",
938 			hostname ? hostname : "<NO HOSTNAME>", addr_str ? addr_str : "<NO ADDR>",
939 			dnssd_getaddrinfo_result_type_to_string(me->type), (unsigned long)me->if_index);
940 		require_quiet(n >= 0, exit);
941 		desc_len += (size_t)n;
942 
943 		if (!buf_ptr) {
944 			buf_len = desc_len + 1;
945 			buf_ptr = malloc(buf_len);
946 			require_quiet(buf_ptr, exit);
947 			buf_ptr[0] = '\0';
948 		} else {
949 			break;
950 		}
951 	}
952 	desc = buf_ptr;
953 	buf_ptr	= NULL;
954 
955 exit:
956 	FreeNullSafe(buf_ptr);
957 	return desc;
958 }
959 
960 //======================================================================================================================
961 
962 void
_dnssd_getaddrinfo_result_finalize(dnssd_getaddrinfo_result_t me)963 _dnssd_getaddrinfo_result_finalize(dnssd_getaddrinfo_result_t me)
964 {
965 	xpc_forget(&me->hostname);
966 	xpc_forget(&me->actual_hostname);
967 	dnssd_forget(&me->cnames);
968 	xpc_forget(&me->auth_tag);
969 	xpc_forget(&me->provider_name);
970 	xpc_forget(&me->doh_uri);
971 	xpc_forget(&me->alpn_values);
972 	xpc_forget(&me->service_name);
973 	xpc_forget(&me->ech_config);
974 	xpc_forget(&me->address_hints);
975 }
976 
977 //======================================================================================================================
978 
979 static OSStatus
_dnssd_getaddrinfo_set_cnames(const dnssd_getaddrinfo_t me,const int record_type,const xpc_object_t xpc_cname_array)980 _dnssd_getaddrinfo_set_cnames(const dnssd_getaddrinfo_t me, const int record_type, const xpc_object_t xpc_cname_array)
981 {
982 	dnssd_cname_array_t *cnames_ptr;
983 	switch (record_type) {
984 		case kDNSServiceType_A:
985 			cnames_ptr = &me->cnames_a;
986 			break;
987 
988 		case kDNSServiceType_AAAA:
989 			cnames_ptr = &me->cnames_aaaa;
990 			break;
991 
992 		default:
993 			cnames_ptr = NULL;
994 			break;
995 	}
996 	OSStatus err;
997 	if (cnames_ptr) {
998 		dnssd_forget(cnames_ptr);
999 		*cnames_ptr = _dnssd_cname_array_create(xpc_cname_array, &err);
1000 		require_noerr_quiet(err, exit);
1001 	}
1002 	err = kNoErr;
1003 
1004 exit:
1005 	return err;
1006 }
1007 
1008 //======================================================================================================================
1009 
1010 static xpc_object_t
_dnssd_getaddrinfo_get_cname_array(const dnssd_getaddrinfo_t me,const int type)1011 _dnssd_getaddrinfo_get_cname_array(const dnssd_getaddrinfo_t me, const int type)
1012 {
1013 	switch (type) {
1014 		case kDNSServiceType_A:
1015 			return me->cnames_a;
1016 
1017 		case kDNSServiceType_AAAA:
1018 			return me->cnames_aaaa;
1019 
1020 		default:
1021 			return NULL;
1022 	}
1023 }
1024 
1025 //======================================================================================================================
1026 // MARK: - dnssd_cname_array Public Methods
1027 
1028 size_t
dnssd_cname_array_get_count(const dnssd_cname_array_t me)1029 dnssd_cname_array_get_count(const dnssd_cname_array_t me)
1030 {
1031 	return (me->xpc_array ? xpc_array_get_count(me->xpc_array) : 0);
1032 }
1033 
1034 //======================================================================================================================
1035 
1036 const char *
dnssd_cname_array_get_cname(const dnssd_cname_array_t me,const size_t index)1037 dnssd_cname_array_get_cname(const dnssd_cname_array_t me, const size_t index)
1038 {
1039 	return (me->xpc_array ? xpc_array_get_string(me->xpc_array, index) : NULL);
1040 }
1041 
1042 //======================================================================================================================
1043 // MARK: - dnssd_cname_array Private Methods
1044 
1045 static dnssd_cname_array_t
_dnssd_cname_array_create(const xpc_object_t xpc_array,OSStatus * const out_error)1046 _dnssd_cname_array_create(const xpc_object_t xpc_array, OSStatus * const out_error)
1047 {
1048 	OSStatus err;
1049 	dnssd_cname_array_t array = NULL;
1050 	dnssd_cname_array_t obj = _dnssd_cname_array_alloc();
1051 	require_action_quiet(obj, exit, err = kNoMemoryErr);
1052 
1053 	if (xpc_array) {
1054 		obj->xpc_array = xpc_copy(xpc_array);
1055 		require_action_quiet(obj->xpc_array, exit, err = kNoResourcesErr);
1056 	}
1057 	array = obj;
1058 	obj = NULL;
1059 	err = kNoErr;
1060 
1061 exit:
1062 	if (out_error) {
1063 		*out_error = err;
1064 	}
1065 	dnssd_release_null_safe(obj);
1066 	return array;
1067 }
1068 
1069 //======================================================================================================================
1070 
1071 static char *
_dnssd_cname_array_copy_description(const dnssd_cname_array_t me,const bool debug,const bool privacy)1072 _dnssd_cname_array_copy_description(const dnssd_cname_array_t me, const bool debug, const bool privacy)
1073 {
1074 	char *desc = NULL;
1075 	char *buf_ptr = NULL;
1076 	size_t buf_len = 0;
1077 	for (;;)
1078 	{
1079 		__block int n;
1080 		__block char *dst = buf_ptr;
1081 		const char * const end = &buf_ptr[buf_len];
1082 		__block size_t desc_len = 0;
1083 		if (debug) {
1084 			n = _dnssd_snprintf(&dst, end, "dnssd_%s (%p): ", me->base.kind->name, (void *)me);
1085 			require_quiet(n >= 0, exit);
1086 			desc_len += (size_t)n;
1087 		}
1088 		n = _dnssd_snprintf(&dst, end, "[");
1089 		require_quiet(n >= 0, exit);
1090 		desc_len += (size_t)n;
1091 
1092 		if (privacy) {
1093 			n = _dnssd_snprintf(&dst, end, "<%zu redacted cnames>",
1094 				me->xpc_array ? xpc_array_get_count(me->xpc_array) : 0);
1095 			require_quiet(n >= 0, exit);
1096 			desc_len += (size_t)n;
1097 		} else if (me->xpc_array) {
1098 			const bool ok = xpc_array_apply(me->xpc_array,
1099 			^ bool (const size_t index, const xpc_object_t _Nonnull cname)
1100 			{
1101 				const char *cname_str = xpc_string_get_string_ptr(cname);
1102 				if (!cname_str) {
1103 					cname_str = "";
1104 				}
1105 				n = _dnssd_snprintf(&dst, end, "%s%s", (index == 0) ? "" : ", ", cname_str);
1106 				if (likely(n >= 0)) {
1107 					desc_len += (size_t)n;
1108 					return true;
1109 				} else {
1110 					return false;
1111 				}
1112 			});
1113 			require_quiet(ok, exit);
1114 		}
1115 		n = _dnssd_snprintf(&dst, end, "]");
1116 		require_quiet(n >= 0, exit);
1117 		desc_len += (size_t)n;
1118 
1119 		if (!buf_ptr) {
1120 			buf_len = desc_len + 1;
1121 			buf_ptr = malloc(buf_len);
1122 			require_quiet(buf_ptr, exit);
1123 			buf_ptr[0] = '\0';
1124 		} else {
1125 			break;
1126 		}
1127 	}
1128 	desc = buf_ptr;
1129 	buf_ptr = NULL;
1130 
1131 exit:
1132 	FreeNullSafe(buf_ptr);
1133 	return desc;
1134 }
1135 
1136 //======================================================================================================================
1137 
1138 void
_dnssd_cname_array_finalize(dnssd_cname_array_t me)1139 _dnssd_cname_array_finalize(dnssd_cname_array_t me)
1140 {
1141 	xpc_forget(&me->xpc_array);
1142 }
1143 
1144 //======================================================================================================================
1145 // MARK: - dnssd Client
1146 
1147 static dnssd_getaddrinfo_t g_gai_list = NULL;
1148 
1149 static dispatch_queue_t
_dnssd_client_queue(void)1150 _dnssd_client_queue(void)
1151 {
1152 	static dispatch_once_t	once	= 0;
1153 	static dispatch_queue_t	queue	= NULL;
1154 
1155 	dispatch_once(&once,
1156 	^{
1157 		queue = dispatch_queue_create("com.apple.dnssd.client", DISPATCH_QUEUE_SERIAL);
1158 	});
1159 	return queue;
1160 }
1161 
1162 //======================================================================================================================
1163 
1164 static void
1165 _dnssd_client_handle_message(xpc_object_t msg);
1166 static void
1167 _dnssd_client_handle_interruption(void);
1168 
1169 static xpc_connection_t
_dnssd_client_connection(void)1170 _dnssd_client_connection(void)
1171 {
1172 	static dispatch_once_t	once		= 0;
1173 	static xpc_connection_t	connection	= NULL;
1174 
1175 	dispatch_once(&once,
1176 	^{
1177 		connection = xpc_connection_create_mach_service(DNSSD_MACH_SERVICE_NAME, _dnssd_client_queue(),
1178 			XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
1179 		xpc_connection_set_event_handler(connection,
1180 		^(xpc_object_t event)
1181 		{
1182 			if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
1183 				_dnssd_client_handle_message(event);
1184 			} else if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
1185 				_dnssd_client_handle_interruption();
1186 			}
1187 		});
1188 		xpc_connection_activate(connection);
1189 	});
1190 	return connection;
1191 }
1192 
1193 static void
_dnssd_client_handle_message(xpc_object_t msg)1194 _dnssd_client_handle_message(xpc_object_t msg)
1195 {
1196 	const uint64_t command_id = dnssd_xpc_message_get_id(msg, NULL);
1197 	dnssd_getaddrinfo_t gai;
1198 	for (gai = g_gai_list; gai; gai = gai->next) {
1199 		if (gai->command_id == command_id) {
1200 			break;
1201 		}
1202 	}
1203 	require_quiet(gai, exit);
1204 
1205 	const OSStatus error = dnssd_xpc_message_get_error(msg, NULL);
1206 	if (!error) {
1207 		xpc_object_t const result_array = dnssd_xpc_message_get_results(msg);
1208 		require_quiet(result_array, exit);
1209 
1210 		dnssd_getaddrinfo_result_t				result_list	= NULL;
1211 		__block dnssd_getaddrinfo_result_t *	result_ptr	= &result_list;
1212 		xpc_array_apply(result_array,
1213 		^ bool (__unused size_t index, xpc_object_t _Nonnull result_dict)
1214 		{
1215 			const dnssd_getaddrinfo_result_t result = _dnssd_getaddrinfo_create_result_from_dictionary(gai, result_dict,
1216 				NULL);
1217 			if (result) {
1218 				*result_ptr	= result;
1219 				result_ptr	= &result->next;
1220 			}
1221 			return true;
1222 		});
1223 		require_quiet(result_list, exit);
1224 
1225 		_dnssd_getaddrinfo_append_results(gai, result_list);
1226 		result_list = NULL;
1227 	} else {
1228 		_dnssd_client_fail_getaddrinfo(gai, error);
1229 	}
1230 
1231 exit:
1232 	return;
1233 }
1234 
1235 static void
_dnssd_client_handle_interruption(void)1236 _dnssd_client_handle_interruption(void)
1237 {
1238 	dnssd_getaddrinfo_t next_gai;
1239 	for (dnssd_getaddrinfo_t gai = g_gai_list; gai; gai = next_gai) {
1240 		next_gai = gai->next;
1241 		gai->state = dnssd_getaddrinfo_state_starting;
1242 		const OSStatus err = _dnssd_client_send_getaddrinfo_command(gai);
1243 		if (!err) {
1244 			_dnssd_getaddrinfo_remove_all_results(gai);
1245 		} else {
1246 			_dnssd_client_fail_getaddrinfo(gai, err);
1247 		}
1248 	}
1249 }
1250 
1251 //======================================================================================================================
1252 
1253 static uint64_t
_dnssd_client_get_new_id(void)1254 _dnssd_client_get_new_id(void)
1255 {
1256 	static uint64_t last_id = 0;
1257 	return ++last_id;
1258 }
1259 
1260 //======================================================================================================================
1261 
1262 static void
1263 _dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai);
1264 
1265 static OSStatus
1266 _dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t gai);
1267 
1268 static void
_dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai)1269 _dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai)
1270 {
1271 	dnssd_retain(gai);
1272 	dispatch_async(_dnssd_client_queue(),
1273 	^{
1274 		_dnssd_client_activate_getaddrinfo(gai);
1275 		dnssd_release(gai);
1276 	});
1277 }
1278 
1279 static void
_dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai)1280 _dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai)
1281 {
1282 	OSStatus err;
1283 	require_action_quiet(gai->state == dnssd_getaddrinfo_state_nascent, exit, err = kNoErr);
1284 
1285 	err = _dnssd_getaddrinfo_activate(gai);
1286 	if (err) {
1287 		gai->state = dnssd_getaddrinfo_state_failed;
1288 		goto exit;
1289 	}
1290 
1291 	gai->command_id = _dnssd_client_get_new_id();
1292 	gai->state = dnssd_getaddrinfo_state_starting;
1293 
1294 	_dnssd_client_register_getaddrinfo(gai);
1295 
1296 	err = _dnssd_client_send_getaddrinfo_command(gai);
1297 	if (err) {
1298 		_dnssd_client_fail_getaddrinfo(gai, err);
1299 	}
1300 
1301 exit:
1302 	return;
1303 }
1304 
1305 static void
1306 _dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t gai, unsigned long events);
1307 
1308 static OSStatus
_dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me)1309 _dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me)
1310 {
1311 	OSStatus err;
1312 	xpc_object_t const hostname = dnssd_xpc_parameters_get_hostname_object(me->params);
1313 	require_action_quiet(hostname, exit, err = kParamErr);
1314 
1315 	me->hostname = xpc_copy(hostname);
1316 	require_action_quiet(me->hostname, exit, err = kNoResourcesErr);
1317 
1318 	me->event_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_OR, 0, 0, me->user_queue);
1319 	require_action_quiet(me->event_source, exit, err = kNoResourcesErr);
1320 
1321 	dnssd_retain(me);
1322 	dispatch_source_t const event_source = me->event_source;
1323 	dispatch_source_set_event_handler(me->event_source,
1324 	^{
1325 		_dnssd_getaddrinfo_process_events(me, dispatch_source_get_data(event_source));
1326 	});
1327 	dispatch_source_set_cancel_handler(me->event_source,
1328 	^{
1329 		dnssd_release(me);
1330 	});
1331 	dispatch_activate(me->event_source);
1332 	err = kNoErr;
1333 
1334 exit:
1335 	if (err) {
1336 		dnssd_retain(me);
1337 		dispatch_async(me->user_queue,
1338 		^{
1339 			if (me->event_handler) {
1340 				me->event_handler(dnssd_event_error, _dnssd_osstatus_to_dns_service_error(err));
1341 			}
1342 			dnssd_release(me);
1343 		});
1344 	}
1345 	return err;
1346 }
1347 
1348 static void
_dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t me,unsigned long events)1349 _dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t me, unsigned long events)
1350 {
1351 	if (events & DNSSD_EVENT_REMOVE_ALL) {
1352 		if (me->event_handler) {
1353 			me->event_handler(dnssd_event_remove_all, kDNSServiceErr_NoError);
1354 		}
1355 	}
1356 
1357 	if (events & DNSSD_EVENT_HAVE_RESULTS) {
1358 		dnssd_getaddrinfo_result_t result;
1359 		dnssd_getaddrinfo_result_t result_array[32];
1360 		dnssd_getaddrinfo_result_t result_list = _dnssd_getaddrinfo_take_results(me);
1361 
1362 		size_t result_count = 0;
1363 		while ((result = result_list) != NULL) {
1364 			result_list		= result->next;
1365 			result->next	= NULL;
1366 			result_array[result_count++] = result;
1367 
1368 			if ((result_count == countof(result_array)) || !result_list) {
1369 				if (me->result_handler) {
1370 					me->result_handler(result_array, result_count);
1371 				}
1372 				for (size_t i = 0; i < result_count; ++i) {
1373 					dnssd_release(result_array[i]);
1374 				}
1375 				result_count = 0;
1376 			}
1377 		}
1378 	}
1379 
1380 	if (events & DNSSD_EVENT_ERROR) {
1381 		__block OSStatus error;
1382 		dispatch_sync(me->mutex_queue,
1383 		^{
1384 			error = me->error;
1385 			me->error = kNoErr;
1386 		});
1387 		if (me->event_handler && error) {
1388 			me->event_handler(dnssd_event_error, _dnssd_osstatus_to_dns_service_error(error));
1389 		}
1390 	}
1391 }
1392 
1393 //======================================================================================================================
1394 
1395 static void
_dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai)1396 _dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai)
1397 {
1398 	gai->next	= g_gai_list;
1399 	g_gai_list	= gai;
1400 	dnssd_retain(gai);
1401 }
1402 
1403 //======================================================================================================================
1404 
1405 static void
_dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai)1406 _dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai)
1407 {
1408 	dnssd_getaddrinfo_t *ptr;
1409 	for (ptr = &g_gai_list; *ptr; ptr = &(*ptr)->next)
1410 	{
1411 		if (*ptr == gai) {
1412 			break;
1413 		}
1414 	}
1415 	if (*ptr) {
1416 		*ptr = gai->next;
1417 		gai->next = NULL;
1418 		dnssd_release(gai);
1419 	}
1420 }
1421 
1422 //======================================================================================================================
1423 
1424 static void
1425 _dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai, xpc_object_t reply);
1426 
1427 static OSStatus
_dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai)1428 _dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai)
1429 {
1430 	OSStatus err;
1431 	xpc_object_t const msg = xpc_dictionary_create(NULL, NULL, 0);
1432 	require_action_quiet(msg, exit, err = kNoResourcesErr);
1433 
1434 	dnssd_xpc_message_set_id(msg, gai->command_id);
1435 	dnssd_xpc_message_set_command(msg, DNSSD_COMMAND_GETADDRINFO);
1436 	dnssd_xpc_message_set_parameters(msg, gai->params);
1437 
1438 	dnssd_retain(gai);
1439 	xpc_connection_send_message_with_reply(_dnssd_client_connection(), msg, _dnssd_client_queue(),
1440 	^(xpc_object_t reply)
1441 	{
1442 		_dnssd_client_handle_getaddrinfo_reply(gai, reply);
1443 		dnssd_release(gai);
1444 	});
1445 	xpc_release(msg);
1446 	err = kNoErr;
1447 
1448 exit:
1449 	return err;
1450 }
1451 
1452 static void
_dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai,xpc_object_t reply)1453 _dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai, xpc_object_t reply)
1454 {
1455 	require_quiet(gai->state == dnssd_getaddrinfo_state_starting, exit);
1456 
1457 	if (xpc_get_type(reply) == XPC_TYPE_DICTIONARY) {
1458 		const OSStatus error = dnssd_xpc_message_get_error(reply, NULL);
1459 		if (error) {
1460 			_dnssd_client_fail_getaddrinfo(gai, error);
1461 		} else {
1462 			gai->state = dnssd_getaddrinfo_state_started;
1463 		}
1464 	} else if (reply != XPC_ERROR_CONNECTION_INTERRUPTED) {
1465 		OSStatus error;
1466 		if (reply == XPC_ERROR_CONNECTION_INVALID) {
1467 			error = kDNSServiceErr_ServiceNotRunning;
1468 		} else {
1469 			error = kDNSServiceErr_Unknown;
1470 		}
1471 		_dnssd_client_fail_getaddrinfo(gai, error);
1472 	}
1473 
1474 exit:
1475 	return;
1476 }
1477 
1478 //======================================================================================================================
1479 
1480 static void
_dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai,OSStatus error)1481 _dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai, OSStatus error)
1482 {
1483 	_dnssd_client_deregister_getaddrinfo(gai);
1484 	gai->state = dnssd_getaddrinfo_state_failed;
1485 	_dnssd_getaddrinfo_post_error_event(gai, error);
1486 }
1487 
1488 //======================================================================================================================
1489 
1490 static bool
1491 _dnssd_extract_result_dict_values(xpc_object_t result, xpc_object_t *out_hostname, DNSServiceErrorType *out_error,
1492 	DNSServiceFlags *out_flags, uint32_t *out_interface_index, uint16_t *out_type, uint16_t *out_class,
1493 	xpc_object_t *out_rdata, xpc_object_t *out_auth_tag, dnssd_getaddrinfo_result_protocol_t *out_protocol,
1494 	xpc_object_t *out_provider_name);
1495 
1496 static dnssd_getaddrinfo_result_t
1497 _dnssd_getaddrinfo_result_create(dnssd_getaddrinfo_result_type_t type, xpc_object_t hostname,
1498 	xpc_object_t actual_hostname, dnssd_cname_array_t cname_array, int addr_family, const void *addr_data,
1499 	uint32_t interface_index, xpc_object_t auth_tag, dnssd_getaddrinfo_result_protocol_t protocol,
1500 	xpc_object_t provider_name, OSStatus *out_error);
1501 
1502 static dnssd_getaddrinfo_result_t
1503 _dnssd_getaddrinfo_result_create_svcb(xpc_object_t hostname, xpc_object_t actual_hostname, const void *svcb_data,
1504 	size_t svcb_length, uint32_t interface_index, xpc_object_t auth_tag, dnssd_getaddrinfo_result_protocol_t protocol,
1505 	xpc_object_t provider_name, OSStatus *out_error);
1506 
1507 static dnssd_getaddrinfo_result_t
_dnssd_getaddrinfo_create_result_from_dictionary(dnssd_getaddrinfo_t me,xpc_object_t result_dict,OSStatus * out_error)1508 _dnssd_getaddrinfo_create_result_from_dictionary(dnssd_getaddrinfo_t me, xpc_object_t result_dict, OSStatus *out_error)
1509 {
1510 	OSStatus					err;
1511 	xpc_object_t				actual_hostname, rdata, auth_tag, provider_name;
1512 	DNSServiceErrorType			error;
1513 	DNSServiceFlags				flags;
1514 	uint32_t					if_index;
1515 	uint16_t					rtype;
1516 	dnssd_getaddrinfo_result_protocol_t protocol;
1517 
1518 	dnssd_getaddrinfo_result_t result = NULL;
1519 	const bool ok = _dnssd_extract_result_dict_values(result_dict, &actual_hostname, &error, &flags, &if_index,
1520 		&rtype, NULL, &rdata, &auth_tag, &protocol, &provider_name);
1521 	require_action_quiet(ok, exit, err = kMalformedErr);
1522 	require_action_quiet((error == kDNSServiceErr_NoError) || (error == kDNSServiceErr_NoSuchRecord), exit,
1523 		err = kUnexpectedErr);
1524 
1525 	switch(rtype) {
1526 		case kDNSServiceType_A:
1527 		case kDNSServiceType_AAAA: {
1528 			const xpc_object_t cname_update = dnssd_xpc_result_get_cname_update(result_dict);
1529 			if (cname_update) {
1530 				_dnssd_getaddrinfo_set_cnames(me, rtype, cname_update);
1531 			}
1532 			dnssd_getaddrinfo_result_type_t result_type;
1533 			if (error == kDNSServiceErr_NoSuchRecord) {
1534 				result_type = dnssd_getaddrinfo_result_type_no_address;
1535 			} else {
1536 				if (flags & kDNSServiceFlagsAdd) {
1537 					if (flags & kDNSServiceFlagsExpiredAnswer) {
1538 						result_type = dnssd_getaddrinfo_result_type_expired;
1539 					} else {
1540 						result_type = dnssd_getaddrinfo_result_type_add;
1541 					}
1542 				} else {
1543 					result_type = dnssd_getaddrinfo_result_type_remove;
1544 				}
1545 				if (rtype == kDNSServiceType_A) {
1546 					require_action_quiet(xpc_data_get_length(rdata) == 4, exit, err = kMalformedErr);
1547 				} else {
1548 					require_action_quiet(xpc_data_get_length(rdata) == 16, exit, err = kMalformedErr);
1549 				}
1550 			}
1551 			const int addr_family = (rtype == kDNSServiceType_A) ? AF_INET : AF_INET6;
1552 			result = _dnssd_getaddrinfo_result_create(result_type, me->hostname, actual_hostname,
1553 				_dnssd_getaddrinfo_get_cname_array(me, rtype), addr_family, xpc_data_get_bytes_ptr(rdata), if_index,
1554 				auth_tag, protocol, provider_name, &err);
1555 			require_noerr_quiet(err, exit);
1556 			break;
1557 		}
1558 		case kDNSServiceType_SVCB:
1559 		case kDNSServiceType_HTTPS: {
1560 			if (error != kDNSServiceErr_NoSuchRecord) {
1561 				require_action_quiet(xpc_data_get_length(rdata) > 0, exit, err = kMalformedErr);
1562 			}
1563 
1564 			// SVCB type answer
1565 			result = _dnssd_getaddrinfo_result_create_svcb(me->hostname, actual_hostname,
1566 				xpc_data_get_bytes_ptr(rdata), xpc_data_get_length(rdata), if_index, auth_tag, protocol,
1567 				provider_name, &err);
1568 			require_noerr_quiet(err, exit);
1569 			break;
1570 		}
1571 		default:
1572 			err = kTypeErr;
1573 			goto exit;
1574 	}
1575 	if ((flags & kDNSServiceFlagsAdd) && (flags & kDNSServiceFlagAnsweredFromCache)) {
1576 		result->is_from_cache = true;
1577 	}
1578 
1579 exit:
1580 	if (err) {
1581 		dnssd_forget(&result);
1582 	}
1583 	if (out_error) {
1584 		*out_error = err;
1585 	}
1586 	return result;
1587 }
1588 
1589 static bool
_dnssd_extract_result_dict_values(xpc_object_t result,xpc_object_t * out_hostname,DNSServiceErrorType * out_error,DNSServiceFlags * out_flags,uint32_t * out_interface_index,uint16_t * out_type,uint16_t * out_class,xpc_object_t * out_rdata,xpc_object_t * out_auth_tag,dnssd_getaddrinfo_result_protocol_t * out_protocol,xpc_object_t * out_provider_name)1590 _dnssd_extract_result_dict_values(xpc_object_t result, xpc_object_t *out_hostname, DNSServiceErrorType *out_error,
1591 	DNSServiceFlags *out_flags, uint32_t *out_interface_index, uint16_t *out_type, uint16_t *out_class,
1592 	xpc_object_t *out_rdata, xpc_object_t *out_auth_tag, dnssd_getaddrinfo_result_protocol_t *out_protocol,
1593 	xpc_object_t *out_provider_name)
1594 {
1595 	bool result_is_valid = false;
1596 	xpc_object_t const hostname = dnssd_xpc_result_get_record_name_object(result);
1597 	require_quiet(hostname, exit);
1598 
1599 	xpc_object_t const rdata = dnssd_xpc_result_get_record_data_object(result);
1600 	require_quiet(rdata, exit);
1601 
1602 	if (out_hostname) {
1603 		*out_hostname = hostname;
1604 	}
1605 	if (out_error) {
1606 		*out_error = dnssd_xpc_result_get_error(result, NULL);
1607 	}
1608 	if (out_flags) {
1609 		*out_flags = dnssd_xpc_result_get_flags(result, NULL);
1610 	}
1611 	if (out_interface_index) {
1612 		*out_interface_index = dnssd_xpc_result_get_interface_index(result, NULL);
1613 	}
1614 	if (out_type) {
1615 		*out_type = dnssd_xpc_result_get_record_type(result, NULL);
1616 	}
1617 	if (out_class) {
1618 		*out_class = dnssd_xpc_result_get_record_class(result, NULL);
1619 	}
1620 	if (out_rdata) {
1621 		*out_rdata = rdata;
1622 	}
1623 	if (out_auth_tag) {
1624 		*out_auth_tag = dnssd_xpc_result_get_authentication_tag_object(result);
1625 	}
1626 	if (out_protocol) {
1627 		*out_protocol = dnssd_xpc_result_get_record_protocol(result, NULL);
1628 	}
1629 	if (out_provider_name) {
1630 		*out_provider_name = dnssd_xpc_result_get_provider_name_object(result);
1631 	}
1632 	result_is_valid = true;
1633 
1634 exit:
1635 	return result_is_valid;
1636 }
1637 
1638 static dnssd_getaddrinfo_result_t
_dnssd_getaddrinfo_result_create(const dnssd_getaddrinfo_result_type_t type,const xpc_object_t hostname,const xpc_object_t actual_hostname,const dnssd_cname_array_t cnames,const int addr_family,const void * const addr_data,const uint32_t if_index,const xpc_object_t auth_tag,const dnssd_getaddrinfo_result_protocol_t protocol,const xpc_object_t provider_name,OSStatus * const out_error)1639 _dnssd_getaddrinfo_result_create(const dnssd_getaddrinfo_result_type_t type, const xpc_object_t hostname,
1640 	const xpc_object_t actual_hostname, const dnssd_cname_array_t cnames, const int addr_family,
1641 	const void * const addr_data, const uint32_t if_index, const xpc_object_t auth_tag,
1642 	const dnssd_getaddrinfo_result_protocol_t protocol, const xpc_object_t provider_name, OSStatus * const out_error)
1643 {
1644 	OSStatus err;
1645 	dnssd_getaddrinfo_result_t result = NULL;
1646 	dnssd_getaddrinfo_result_t obj = _dnssd_getaddrinfo_result_alloc();
1647 	require_action_quiet(obj, exit, err = kNoMemoryErr);
1648 
1649 	switch (type) {
1650 		case dnssd_getaddrinfo_result_type_add:
1651 		case dnssd_getaddrinfo_result_type_remove:
1652 		case dnssd_getaddrinfo_result_type_no_address:
1653 		case dnssd_getaddrinfo_result_type_expired:
1654 			break;
1655 
1656 		default:
1657 			err = kTypeErr;
1658 			goto exit;
1659 	}
1660 	obj->type		= type;
1661 	obj->if_index	= if_index;
1662 	obj->protocol	= protocol;
1663 
1664 	require_action_quiet(xpc_get_type(hostname) == XPC_TYPE_STRING, exit, err = kTypeErr);
1665 
1666 	obj->hostname = xpc_copy(hostname);
1667 	require_action_quiet(obj->hostname, exit, err = kNoResourcesErr);
1668 
1669 	require_action_quiet(xpc_get_type(actual_hostname) == XPC_TYPE_STRING, exit, err = kTypeErr);
1670 
1671 	obj->actual_hostname = xpc_copy(actual_hostname);
1672 	require_action_quiet(obj->actual_hostname, exit, err = kNoResourcesErr);
1673 
1674 	obj->cnames = cnames ? cnames : _dnssd_get_empty_cname_array();
1675 	dnssd_retain(obj->cnames);
1676 	require_action_quiet((addr_family == AF_INET) || (addr_family == AF_INET6), exit, err = kTypeErr);
1677 
1678 	if (addr_family == AF_INET) {
1679 		obj->addr.sa.sa_family	= AF_INET;
1680 		obj->addr.v4.sin_len	= sizeof(struct sockaddr_in);
1681 		if (obj->type != dnssd_getaddrinfo_result_type_no_address) {
1682 			memcpy(&obj->addr.v4.sin_addr.s_addr, addr_data, 4);
1683 		}
1684 	} else if (addr_family == AF_INET6) {
1685 		struct sockaddr_in6 * const sin6 = &obj->addr.v6;
1686 		sin6->sin6_family	= AF_INET6;
1687 		sin6->sin6_len		= sizeof(struct sockaddr_in6);
1688 		if (obj->type != dnssd_getaddrinfo_result_type_no_address) {
1689 			memcpy(&sin6->sin6_addr.s6_addr, addr_data, 16);
1690 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
1691 				sin6->sin6_scope_id = obj->if_index;
1692 			}
1693 		}
1694 	}
1695 	if (auth_tag) {
1696 		require_action_quiet(xpc_get_type(auth_tag) == XPC_TYPE_DATA, exit, err = kTypeErr);
1697 
1698 		obj->auth_tag = xpc_copy(auth_tag);
1699 		require_action_quiet(obj->auth_tag, exit, err = kNoResourcesErr);
1700 	}
1701 	if (provider_name) {
1702 		require_action_quiet(xpc_get_type(provider_name) == XPC_TYPE_STRING, exit, err = kTypeErr);
1703 
1704 		obj->provider_name = xpc_copy(provider_name);
1705 		require_action_quiet(obj->provider_name, exit, err = kNoResourcesErr);
1706 	}
1707 	result	= obj;
1708 	obj		= NULL;
1709 	err = kNoErr;
1710 
1711 exit:
1712 	if (out_error) {
1713 		*out_error = err;
1714 	}
1715 	dnssd_release_null_safe(obj);
1716 	return result;
1717 }
1718 
1719 static dnssd_getaddrinfo_result_t
_dnssd_getaddrinfo_result_create_svcb(xpc_object_t hostname,xpc_object_t actual_hostname,const void * svcb_data,size_t svcb_length,uint32_t interface_index,xpc_object_t auth_tag,dnssd_getaddrinfo_result_protocol_t protocol,xpc_object_t provider_name,OSStatus * out_error)1720 _dnssd_getaddrinfo_result_create_svcb(xpc_object_t hostname, xpc_object_t actual_hostname, const void *svcb_data,
1721 	size_t svcb_length, uint32_t interface_index, xpc_object_t auth_tag, dnssd_getaddrinfo_result_protocol_t protocol,
1722 	xpc_object_t provider_name, OSStatus *out_error)
1723 {
1724 	OSStatus err;
1725 	dnssd_getaddrinfo_result_t result = NULL;
1726 	dnssd_getaddrinfo_result_t obj = _dnssd_getaddrinfo_result_alloc();
1727 	require_action_quiet(obj, exit, err = kNoMemoryErr);
1728 
1729 	obj->type		= dnssd_getaddrinfo_result_type_service_binding;
1730 	obj->if_index	= interface_index;
1731 	obj->protocol	= protocol;
1732 
1733 	require_action_quiet(xpc_get_type(hostname) == XPC_TYPE_STRING, exit, err = kTypeErr);
1734 	obj->hostname = xpc_copy(hostname);
1735 
1736 	require_action_quiet(xpc_get_type(actual_hostname) == XPC_TYPE_STRING, exit, err = kTypeErr);
1737 
1738 	obj->actual_hostname = xpc_copy(actual_hostname);
1739 	require_action_quiet(obj->actual_hostname, exit, err = kNoResourcesErr);
1740 
1741 	if (svcb_data != NULL && svcb_length > 0) {
1742 		obj->valid_svcb = dnssd_svcb_is_valid(svcb_data, svcb_length);
1743 		obj->priority = dnssd_svcb_get_priority(svcb_data, svcb_length);
1744 		obj->port = dnssd_svcb_get_port(svcb_data, svcb_length);
1745 
1746 		char *service_name = dnssd_svcb_copy_domain(svcb_data, svcb_length);
1747 		if (service_name != NULL) {
1748 			if (strcmp(service_name, ".") == 0) {
1749 				// The empty name is an placeholder for the name for the record
1750 				obj->service_name = xpc_copy(obj->hostname);
1751 			} else {
1752 				obj->service_name = xpc_string_create(service_name);
1753 			}
1754 			free(service_name);
1755 			require_action_quiet(obj->service_name, exit, err = kNoResourcesErr);
1756 		}
1757 
1758 		char *doh_uri = dnssd_svcb_copy_doh_uri(svcb_data, svcb_length);
1759 		if (doh_uri != NULL) {
1760 			obj->doh_uri = xpc_string_create(doh_uri);
1761 			free(doh_uri);
1762 			require_action_quiet(obj->doh_uri, exit, err = kNoResourcesErr);
1763 		}
1764 
1765 		size_t ech_config_length = 0;
1766 		uint8_t *ech_config = dnssd_svcb_copy_ech_config(svcb_data, svcb_length, &ech_config_length);
1767 		if (ech_config != NULL) {
1768 			obj->ech_config = xpc_data_create(ech_config, ech_config_length);
1769 			free(ech_config);
1770 			require_action_quiet(obj->ech_config, exit, err = kNoResourcesErr);
1771 		}
1772 
1773 		dnssd_svcb_access_alpn_values(svcb_data, svcb_length, ^bool(const char *alpn) {
1774 			xpc_object_t alpn_string = xpc_string_create(alpn);
1775 			if (obj->alpn_values == NULL) {
1776 				obj->alpn_values = xpc_array_create(NULL, 0);
1777 			}
1778 			xpc_array_append_value(obj->alpn_values, alpn_string);
1779 			xpc_release(alpn_string);
1780 			return true;
1781 		});
1782 
1783 		dnssd_svcb_access_address_hints(svcb_data, svcb_length, ^bool(const struct sockaddr *address) {
1784 			xpc_object_t address_hint = xpc_data_create(address, address->sa_len);
1785 			if (obj->address_hints == NULL) {
1786 				obj->address_hints = xpc_array_create(NULL, 0);
1787 			}
1788 			xpc_array_append_value(obj->address_hints, address_hint);
1789 			xpc_release(address_hint);
1790 			return true;
1791 		});
1792 	} else {
1793 		obj->valid_svcb = false;
1794 	}
1795 
1796 	if (auth_tag) {
1797 		require_action_quiet(xpc_get_type(auth_tag) == XPC_TYPE_DATA, exit, err = kTypeErr);
1798 
1799 		obj->auth_tag = xpc_copy(auth_tag);
1800 		require_action_quiet(obj->auth_tag, exit, err = kNoResourcesErr);
1801 	}
1802 
1803 	if (provider_name) {
1804 		require_action_quiet(xpc_get_type(provider_name) == XPC_TYPE_STRING, exit, err = kTypeErr);
1805 
1806 		obj->provider_name = xpc_copy(provider_name);
1807 		require_action_quiet(obj->provider_name, exit, err = kNoResourcesErr);
1808 	}
1809 
1810 	result	= obj;
1811 	obj		= NULL;
1812 	err = kNoErr;
1813 
1814 exit:
1815 	if (out_error) {
1816 		*out_error = err;
1817 	}
1818 	dnssd_release_null_safe(obj);
1819 	return result;
1820 }
1821 
1822 //======================================================================================================================
1823 // MARK: - Misc. Helpers
1824 
1825 static dnssd_cname_array_t
_dnssd_get_empty_cname_array(void)1826 _dnssd_get_empty_cname_array(void)
1827 {
1828 	static dispatch_once_t		s_once = 0;
1829 	static dnssd_cname_array_t	s_empty_cname_array = NULL;
1830 	dispatch_once(&s_once,
1831 	^{
1832 		s_empty_cname_array = _dnssd_cname_array_create(NULL, NULL);
1833 		s_empty_cname_array->base._os_obj_refcnt	= _OS_OBJECT_GLOBAL_REFCNT;
1834 		s_empty_cname_array->base._os_obj_xref_cnt	= _OS_OBJECT_GLOBAL_REFCNT;
1835 	});
1836 	return s_empty_cname_array;
1837 }
1838 
1839 //======================================================================================================================
1840 
1841 static DNSServiceErrorType
_dnssd_osstatus_to_dns_service_error(OSStatus error)1842 _dnssd_osstatus_to_dns_service_error(OSStatus error)
1843 {
1844 	switch (error) {
1845 		case kNoMemoryErr:
1846 		case kNoResourcesErr:
1847 			error = kDNSServiceErr_NoMemory;
1848 			break;
1849 
1850 		case kParamErr:
1851 			error = kDNSServiceErr_BadParam;
1852 			break;
1853 
1854 		default:
1855 			if ((error >= kGenericErrorBase) && (error <= kGenericErrorEnd)) {
1856 				error = kDNSServiceErr_Unknown;
1857 			}
1858 			break;
1859 	}
1860 	return error;
1861 }
1862 
1863 //======================================================================================================================
1864 
1865 static int
_dnssd_snprintf(char ** const dst,const char * const end,const char * const format,...)1866 _dnssd_snprintf(char ** const dst, const char * const end, const char * const format, ...)
1867 {
1868 	char * const ptr = *dst;
1869 	const size_t len = (size_t)(end - ptr);
1870 	va_list args;
1871 	va_start(args, format);
1872 	const int n = vsnprintf(ptr, len, format, args);
1873 	va_end(args);
1874 	if (n >= 0) {
1875 		*dst = ptr + Min((size_t)n, len);
1876 	}
1877 	return n;
1878 }
1879