]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/dnssd.c
mDNSResponder-1310.80.1.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / dnssd.c
1 /*
2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "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
259 dnssd_retain(const dnssd_any_t any)
260 {
261 os_retain(any.object);
262 }
263
264 //======================================================================================================================
265
266 void
267 dnssd_release(const dnssd_any_t any)
268 {
269 os_release(any.object);
270 }
271
272 //======================================================================================================================
273
274 char *
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
699 dnssd_getaddrinfo_result_get_type(dnssd_getaddrinfo_result_t me)
700 {
701 return me->type;
702 }
703
704 //======================================================================================================================
705
706 const char *
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 *
715 dnssd_getaddrinfo_result_get_address(dnssd_getaddrinfo_result_t me)
716 {
717 return &me->addr.sa;
718 }
719
720 //======================================================================================================================
721
722 const char *
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 *
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
739 dnssd_getaddrinfo_result_get_service_port(dnssd_getaddrinfo_result_t me)
740 {
741 return me->port;
742 }
743
744 //======================================================================================================================
745
746 uint16_t
747 dnssd_getaddrinfo_result_get_service_priority(dnssd_getaddrinfo_result_t me)
748 {
749 return me->priority;
750 }
751
752 //======================================================================================================================
753
754 const char *
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
763 dnssd_getaddrinfo_result_service_is_valid(dnssd_getaddrinfo_result_t me)
764 {
765 return me->valid_svcb;
766 }
767
768 //======================================================================================================================
769
770 void
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
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 *
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
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 *
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
849 dnssd_getaddrinfo_result_get_protocol(dnssd_getaddrinfo_result_t me)
850 {
851 return me->protocol;
852 }
853
854 //======================================================================================================================
855
856 const char *
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
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
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 *
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
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
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
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
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 *
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
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 }