2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
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
8 * https://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "dnssd_private.h"
19 #include "dnssd_object.h"
20 #include "dnssd_xpc.h"
21 #include "dnssd_svcb.h"
23 #include <CoreUtils/CoreUtils.h>
24 #include <os/object_private.h>
25 #include <xpc/private.h>
27 //======================================================================================================================
28 // MARK: - Kind Declarations
30 #define DNSSD_STRUCT(NAME) struct dnssd_ ## NAME ## _s
31 #define DNSSD_TYPE(NAME) dnssd_ ## NAME ## _t
33 #define DNSSD_KIND_DECLARE(NAME) \
34 static DNSSD_TYPE(NAME) \
35 _dnssd_ ## NAME ## _alloc(void); \
38 _dnssd_ ## NAME ## _copy_description(DNSSD_TYPE(NAME) object, bool debug, bool privacy); \
41 _dnssd_ ## NAME ## _finalize(DNSSD_TYPE(NAME) object)
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.
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))]
52 #define DNSSD_KIND_DEFINE(NAME, SUPER) \
53 static const struct dnssd_kind_s _dnssd_ ## NAME ## _kind = { \
54 &_dnssd_ ## SUPER ## _kind, \
56 _dnssd_ ## NAME ## _copy_description, \
57 _dnssd_ ## NAME ## _finalize, \
60 static DNSSD_TYPE(NAME) \
61 _dnssd_ ## NAME ## _alloc(void) \
63 DNSSD_TYPE(NAME) obj = dnssd_object_ ## NAME ## _alloc(sizeof(*obj)); \
64 require_quiet(obj, exit); \
66 const dnssd_object_t base = (dnssd_object_t)obj; \
67 base->kind = &_dnssd_ ## NAME ## _kind; \
72 DNSSD_BASE_CHECK(NAME, SUPER)
74 DNSSD_KIND_DECLARE(getaddrinfo
);
75 DNSSD_KIND_DECLARE(getaddrinfo_result
);
76 DNSSD_KIND_DECLARE(cname_array
);
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
);
81 typedef const struct dnssd_kind_s
* dnssd_kind_t
;
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.
89 //======================================================================================================================
90 // MARK: - Object Kind Definition
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.
97 static const struct dnssd_kind_s _dnssd_object_kind
= {
98 NULL
, // No superkind.
100 NULL
, // No copy_description method.
101 NULL
, // No finalize method.
104 //======================================================================================================================
105 // MARK: - GetAddrInfo Kind Definition
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
;
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.
134 DNSSD_KIND_DEFINE(getaddrinfo
, object
);
136 //======================================================================================================================
137 // MARK: - GetAddrInfo Result Kind Definition
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.
162 DNSSD_KIND_DEFINE(getaddrinfo_result
, object
);
164 //======================================================================================================================
165 // MARK: - CName Array Kind Definition
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.
172 DNSSD_KIND_DEFINE(cname_array
, object
);
174 //======================================================================================================================
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.
181 // Strings for redacted description items.
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>"
187 //======================================================================================================================
188 // MARK: - Local Prototypes
190 static dispatch_queue_t
191 _dnssd_client_queue(void);
193 static xpc_connection_t
194 _dnssd_client_connection(void);
197 _dnssd_client_get_new_id(void);
200 _dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai
);
203 _dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai
);
206 _dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai
);
209 _dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai
);
212 _dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai
, OSStatus error
);
215 _dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t gai
, dnssd_getaddrinfo_result_t result_list
);
218 _dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t gai
);
220 static dnssd_getaddrinfo_result_t
221 _dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t gai
);
224 _dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t gai
, OSStatus error
);
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
);
230 static dnssd_cname_array_t
231 _dnssd_cname_array_create(xpc_object_t xpc_array
, OSStatus
*out_error
);
233 static dnssd_cname_array_t
234 _dnssd_get_empty_cname_array(void);
236 static DNSServiceErrorType
237 _dnssd_osstatus_to_dns_service_error(OSStatus status
);
240 _dnssd_snprintf(char **dst
, const char *end
, const char *format
, ...);
242 #if !defined(dnssd_release_null_safe)
243 #define dnssd_release_null_safe(X) \
251 #if !defined(dnssd_forget)
252 #define dnssd_forget(X) ForgetCustom(X, dnssd_release)
255 //======================================================================================================================
256 // MARK: - Object Public Methods
259 dnssd_retain(const dnssd_any_t any
)
261 os_retain(any
.object
);
264 //======================================================================================================================
267 dnssd_release(const dnssd_any_t any
)
269 os_release(any
.object
);
272 //======================================================================================================================
275 dnssd_copy_description(dnssd_any_t object
)
277 return dnssd_object_copy_description(object
, false, false);
280 //======================================================================================================================
281 // MARK: - Object Private Methods
284 dnssd_object_copy_description(const dnssd_any_t any
, const bool debug
, const bool privacy
)
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
);
296 //======================================================================================================================
299 dnssd_object_finalize(const dnssd_any_t any
)
301 const dnssd_object_t me
= any
.object
;
302 for (dnssd_kind_t kind
= me
->kind
; kind
; kind
= kind
->superkind
) {
303 if (kind
->finalize
) {
309 //======================================================================================================================
310 // MARK: - GetAddrInfo Public Methods
313 dnssd_getaddrinfo_create(void)
315 dnssd_getaddrinfo_t gai
= NULL
;
316 dnssd_getaddrinfo_t obj
= _dnssd_getaddrinfo_alloc();
317 require_quiet(obj
, exit
);
319 obj
->params
= xpc_dictionary_create(NULL
, NULL
, 0);
320 require_quiet(obj
->params
, exit
);
322 obj
->mutex_queue
= dispatch_queue_create("com.apple.dnssd.getaddrinfo.mutex", DISPATCH_QUEUE_SERIAL
);
323 require_quiet(obj
->mutex_queue
, exit
);
329 dnssd_release_null_safe(obj
);
333 //======================================================================================================================
336 dnssd_getaddrinfo_set_queue(dnssd_getaddrinfo_t me
, dispatch_queue_t queue
)
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
);
349 //======================================================================================================================
352 dnssd_getaddrinfo_set_flags(dnssd_getaddrinfo_t me
, DNSServiceFlags flags
)
354 if (!me
->user_activated
) {
355 dnssd_xpc_parameters_set_flags(me
->params
, flags
);
359 //======================================================================================================================
362 dnssd_getaddrinfo_set_account_id(dnssd_getaddrinfo_t me
, const char * account_id
)
364 if (!me
->user_activated
) {
365 dnssd_xpc_parameters_set_account_id(me
->params
, account_id
);
369 //======================================================================================================================
372 dnssd_getaddrinfo_set_hostname(dnssd_getaddrinfo_t me
, const char *hostname
)
374 if (!me
->user_activated
) {
375 dnssd_xpc_parameters_set_hostname(me
->params
, hostname
);
379 //======================================================================================================================
382 dnssd_getaddrinfo_set_interface_index(dnssd_getaddrinfo_t me
, uint32_t interface_index
)
384 if (!me
->user_activated
) {
385 dnssd_xpc_parameters_set_interface_index(me
->params
, interface_index
);
389 //======================================================================================================================
392 dnssd_getaddrinfo_set_protocols(dnssd_getaddrinfo_t me
, DNSServiceProtocol protocols
)
394 if (!me
->user_activated
) {
395 dnssd_xpc_parameters_set_protocols(me
->params
, protocols
);
399 //======================================================================================================================
402 dnssd_getaddrinfo_set_service_scheme(dnssd_getaddrinfo_t me
, const char *service_scheme
)
404 if (!me
->user_activated
) {
405 dnssd_xpc_parameters_set_service_scheme(me
->params
, service_scheme
);
409 //======================================================================================================================
412 dnssd_getaddrinfo_set_delegate_pid(dnssd_getaddrinfo_t me
, pid_t pid
)
414 if (!me
->user_activated
) {
415 dnssd_xpc_parameters_set_delegate_pid(me
->params
, pid
);
419 //======================================================================================================================
422 dnssd_getaddrinfo_set_delegate_uuid(dnssd_getaddrinfo_t me
, uuid_t uuid
)
424 if (!me
->user_activated
) {
425 dnssd_xpc_parameters_set_delegate_uuid(me
->params
, uuid
);
429 //======================================================================================================================
432 dnssd_getaddrinfo_set_delegate_audit_token(dnssd_getaddrinfo_t me
, audit_token_t audit_token
)
434 if (!me
->user_activated
) {
435 dnssd_xpc_parameters_set_delegate_audit_token(me
->params
, &audit_token
);
439 //======================================================================================================================
442 dnssd_getaddrinfo_set_result_handler(dnssd_getaddrinfo_t me
, dnssd_getaddrinfo_result_handler_t handler
)
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
);
448 me
->result_handler
= new_handler
;
451 //======================================================================================================================
454 dnssd_getaddrinfo_set_event_handler(dnssd_getaddrinfo_t me
, dnssd_event_handler_t handler
)
456 dnssd_event_handler_t
const new_handler
= handler
? Block_copy(handler
) : NULL
;
457 if (me
->event_handler
) {
458 Block_release(me
->event_handler
);
460 me
->event_handler
= new_handler
;
463 //======================================================================================================================
466 dnssd_getaddrinfo_set_need_authenticated_results(dnssd_getaddrinfo_t me
, bool need
)
468 if (!me
->user_activated
) {
469 dnssd_xpc_parameters_set_need_authentication_tags(me
->params
, need
);
473 //======================================================================================================================
476 dnssd_getaddrinfo_set_need_encrypted_query(dnssd_getaddrinfo_t me
, bool need
, _Nullable xpc_object_t fallback_config
)
478 if (!me
->user_activated
) {
479 dnssd_xpc_parameters_set_need_encrypted_query(me
->params
, need
, fallback_config
);
483 //======================================================================================================================
486 dnssd_getaddrinfo_add_resolver_uuid(dnssd_getaddrinfo_t me
, uuid_t _Nonnull uuid
)
488 if (!me
->user_activated
) {
489 dnssd_xpc_parameters_add_resolver_uuid(me
->params
, uuid
);
493 //======================================================================================================================
496 dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me
)
498 if (!me
->user_activated
) {
499 if (me
->user_queue
) {
500 _dnssd_client_activate_getaddrinfo_async(me
);
502 me
->user_activated
= true;
506 //======================================================================================================================
509 _dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai
);
512 _dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me
);
515 dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me
)
518 dispatch_async(_dnssd_client_queue(),
520 _dnssd_client_invalidate_getaddrinfo(me
);
526 _dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai
)
528 require_quiet(gai
->state
!= dnssd_getaddrinfo_state_invalidated
, exit
);
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);
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
)
544 _dnssd_getaddrinfo_invalidate(gai
);
545 gai
->state
= dnssd_getaddrinfo_state_invalidated
;
552 _dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me
)
554 dispatch_source_forget(&me
->event_source
);
555 _dnssd_getaddrinfo_remove_all_results(me
);
557 if (me
->user_queue
) {
559 dispatch_async(me
->user_queue
,
561 if (me
->event_handler
) {
562 me
->event_handler(dnssd_event_invalidated
, kDNSServiceErr_NoError
);
569 //======================================================================================================================
570 // MARK: - GetAddrInfo Private Methods
573 _dnssd_getaddrinfo_copy_description(dnssd_getaddrinfo_t me
, const bool debug
, const bool privacy
)
575 const char *hostname_str
;
577 hostname_str
= xpc_string_get_string_ptr(me
->hostname
);
578 if (privacy
&& hostname_str
) {
579 hostname_str
= DNSSD_REDACTED_HOSTNAME_STR
;
585 char *buf_ptr
= NULL
;
590 char * dst
= buf_ptr
;
591 char * const end
= &buf_ptr
[buf_len
];
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
;
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
;
603 buf_len
= desc_len
+ 1;
604 buf_ptr
= malloc(buf_len
);
605 require_quiet(buf_ptr
, exit
);
615 FreeNullSafe(buf_ptr
);
619 //======================================================================================================================
622 _dnssd_getaddrinfo_finalize(dnssd_getaddrinfo_t me
)
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
);
634 //======================================================================================================================
637 _dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t me
, dnssd_getaddrinfo_result_t result_list
)
639 dispatch_sync(me
->mutex_queue
,
641 dnssd_getaddrinfo_result_t
*ptr
= &me
->result_list
;
647 dispatch_source_merge_data(me
->event_source
, DNSSD_EVENT_HAVE_RESULTS
);
650 //======================================================================================================================
653 _dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t me
)
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
);
662 dnssd_getaddrinfo_result_t result
;
663 while ((result
= result_list
) != NULL
) {
664 result_list
= result
->next
;
665 dnssd_release(result
);
669 //======================================================================================================================
671 static dnssd_getaddrinfo_result_t
672 _dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t me
)
674 __block dnssd_getaddrinfo_result_t list
;
675 dispatch_sync(me
->mutex_queue
,
677 list
= me
->result_list
;
678 me
->result_list
= NULL
;
683 //======================================================================================================================
686 _dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t me
, OSStatus error
)
688 dispatch_sync(me
->mutex_queue
,
692 dispatch_source_merge_data(me
->event_source
, DNSSD_EVENT_ERROR
);
695 //======================================================================================================================
696 // MARK: - GetAddrInfo Result Public Methods
698 dnssd_getaddrinfo_result_type_t
699 dnssd_getaddrinfo_result_get_type(dnssd_getaddrinfo_result_t me
)
704 //======================================================================================================================
707 dnssd_getaddrinfo_result_get_actual_hostname(dnssd_getaddrinfo_result_t me
)
709 return xpc_string_get_string_ptr(me
->actual_hostname
);
712 //======================================================================================================================
714 const struct sockaddr
*
715 dnssd_getaddrinfo_result_get_address(dnssd_getaddrinfo_result_t me
)
720 //======================================================================================================================
723 dnssd_getaddrinfo_result_get_hostname(dnssd_getaddrinfo_result_t me
)
725 return xpc_string_get_string_ptr(me
->hostname
);
728 //======================================================================================================================
731 dnssd_getaddrinfo_result_get_doh_uri(dnssd_getaddrinfo_result_t me
)
733 return xpc_string_get_string_ptr(me
->doh_uri
);
736 //======================================================================================================================
739 dnssd_getaddrinfo_result_get_service_port(dnssd_getaddrinfo_result_t me
)
744 //======================================================================================================================
747 dnssd_getaddrinfo_result_get_service_priority(dnssd_getaddrinfo_result_t me
)
752 //======================================================================================================================
755 dnssd_getaddrinfo_result_get_service_name(dnssd_getaddrinfo_result_t me
)
757 return xpc_string_get_string_ptr(me
->service_name
);
760 //======================================================================================================================
763 dnssd_getaddrinfo_result_service_is_valid(dnssd_getaddrinfo_result_t me
)
765 return me
->valid_svcb
;
768 //======================================================================================================================
771 dnssd_getaddrinfo_result_enumerate_alpn_values(dnssd_getaddrinfo_result_t me
,
772 DNSSD_NOESCAPE dnssd_getaddrinfo_enumerate_alpn_values_block_t enumerator
)
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
);
782 //======================================================================================================================
785 dnssd_getaddrinfo_result_enumerate_service_address_hints(dnssd_getaddrinfo_result_t me
,
786 DNSSD_NOESCAPE dnssd_getaddrinfo_enumerate_addresses_block_t enumerator
)
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
);
796 //======================================================================================================================
799 dnssd_getaddrinfo_result_get_ech_config(dnssd_getaddrinfo_result_t me
, size_t *out_length
)
801 const void * ech_ptr
;
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
);
812 *out_length
= ech_len
;
817 //======================================================================================================================
820 dnssd_getaddrinfo_result_get_interface_index(dnssd_getaddrinfo_result_t me
)
825 //======================================================================================================================
828 dnssd_getaddrinfo_result_get_authentication_tag(dnssd_getaddrinfo_result_t me
, size_t *out_length
)
830 const void * auth_tag_ptr
;
834 auth_tag_ptr
= xpc_data_get_bytes_ptr(me
->auth_tag
);
835 auth_tag_len
= xpc_data_get_length(me
->auth_tag
);
841 *out_length
= auth_tag_len
;
846 //======================================================================================================================
848 dnssd_getaddrinfo_result_protocol_t
849 dnssd_getaddrinfo_result_get_protocol(dnssd_getaddrinfo_result_t me
)
854 //======================================================================================================================
857 dnssd_getaddrinfo_result_get_provider_name(dnssd_getaddrinfo_result_t me
)
859 return xpc_string_get_string_ptr(me
->provider_name
);
862 //======================================================================================================================
865 dnssd_getaddrinfo_result_get_cnames(const dnssd_getaddrinfo_result_t me
)
867 return (me
->cnames
? me
->cnames
: _dnssd_get_empty_cname_array());
870 //======================================================================================================================
873 dnssd_getaddrinfo_result_is_from_cache(const dnssd_getaddrinfo_result_t me
)
875 return me
->is_from_cache
;
878 //======================================================================================================================
879 // MARK: - GetAddrInfo Result Private Methods
882 _dnssd_getaddrinfo_result_copy_description(dnssd_getaddrinfo_result_t me
, const bool debug
, const bool privacy
)
884 const char *hostname
;
886 hostname
= xpc_string_get_string_ptr(me
->hostname
);
887 if (privacy
&& hostname
) {
888 hostname
= DNSSD_REDACTED_HOSTNAME_STR
;
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
) {
897 addr_str
= DNSSD_REDACTED_IPv4_ADDRESS_STR
;
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
));
902 } else if (me
->addr
.sa
.sa_family
== AF_INET6
) {
904 addr_str
= DNSSD_REDACTED_IPv6_ADDRESS_STR
;
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
);
916 snprintf(dst
, (size_t)(end
- dst
), "%%%u", sin6
->sin6_scope_id
);
924 char *buf_ptr
= NULL
;
929 char * const end
= &buf_ptr
[buf_len
];
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
;
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
;
944 buf_len
= desc_len
+ 1;
945 buf_ptr
= malloc(buf_len
);
946 require_quiet(buf_ptr
, exit
);
956 FreeNullSafe(buf_ptr
);
960 //======================================================================================================================
963 _dnssd_getaddrinfo_result_finalize(dnssd_getaddrinfo_result_t me
)
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
);
977 //======================================================================================================================
980 _dnssd_getaddrinfo_set_cnames(const dnssd_getaddrinfo_t me
, const int record_type
, const xpc_object_t xpc_cname_array
)
982 dnssd_cname_array_t
*cnames_ptr
;
983 switch (record_type
) {
984 case kDNSServiceType_A
:
985 cnames_ptr
= &me
->cnames_a
;
988 case kDNSServiceType_AAAA
:
989 cnames_ptr
= &me
->cnames_aaaa
;
998 dnssd_forget(cnames_ptr
);
999 *cnames_ptr
= _dnssd_cname_array_create(xpc_cname_array
, &err
);
1000 require_noerr_quiet(err
, exit
);
1008 //======================================================================================================================
1011 _dnssd_getaddrinfo_get_cname_array(const dnssd_getaddrinfo_t me
, const int type
)
1014 case kDNSServiceType_A
:
1015 return me
->cnames_a
;
1017 case kDNSServiceType_AAAA
:
1018 return me
->cnames_aaaa
;
1025 //======================================================================================================================
1026 // MARK: - dnssd_cname_array Public Methods
1029 dnssd_cname_array_get_count(const dnssd_cname_array_t me
)
1031 return (me
->xpc_array
? xpc_array_get_count(me
->xpc_array
) : 0);
1034 //======================================================================================================================
1037 dnssd_cname_array_get_cname(const dnssd_cname_array_t me
, const size_t index
)
1039 return (me
->xpc_array
? xpc_array_get_string(me
->xpc_array
, index
) : NULL
);
1042 //======================================================================================================================
1043 // MARK: - dnssd_cname_array Private Methods
1045 static dnssd_cname_array_t
1046 _dnssd_cname_array_create(const xpc_object_t xpc_array
, OSStatus
* const out_error
)
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
);
1054 obj
->xpc_array
= xpc_copy(xpc_array
);
1055 require_action_quiet(obj
->xpc_array
, exit
, err
= kNoResourcesErr
);
1065 dnssd_release_null_safe(obj
);
1069 //======================================================================================================================
1072 _dnssd_cname_array_copy_description(const dnssd_cname_array_t me
, const bool debug
, const bool privacy
)
1075 char *buf_ptr
= NULL
;
1080 __block
char *dst
= buf_ptr
;
1081 const char * const end
= &buf_ptr
[buf_len
];
1082 __block
size_t desc_len
= 0;
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
;
1088 n
= _dnssd_snprintf(&dst
, end
, "[");
1089 require_quiet(n
>= 0, exit
);
1090 desc_len
+= (size_t)n
;
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
)
1101 const char *cname_str
= xpc_string_get_string_ptr(cname
);
1105 n
= _dnssd_snprintf(&dst
, end
, "%s%s", (index
== 0) ? "" : ", ", cname_str
);
1106 if (likely(n
>= 0)) {
1107 desc_len
+= (size_t)n
;
1113 require_quiet(ok
, exit
);
1115 n
= _dnssd_snprintf(&dst
, end
, "]");
1116 require_quiet(n
>= 0, exit
);
1117 desc_len
+= (size_t)n
;
1120 buf_len
= desc_len
+ 1;
1121 buf_ptr
= malloc(buf_len
);
1122 require_quiet(buf_ptr
, exit
);
1132 FreeNullSafe(buf_ptr
);
1136 //======================================================================================================================
1139 _dnssd_cname_array_finalize(dnssd_cname_array_t me
)
1141 xpc_forget(&me
->xpc_array
);
1144 //======================================================================================================================
1145 // MARK: - dnssd Client
1147 static dnssd_getaddrinfo_t g_gai_list
= NULL
;
1149 static dispatch_queue_t
1150 _dnssd_client_queue(void)
1152 static dispatch_once_t once
= 0;
1153 static dispatch_queue_t queue
= NULL
;
1155 dispatch_once(&once
,
1157 queue
= dispatch_queue_create("com.apple.dnssd.client", DISPATCH_QUEUE_SERIAL
);
1162 //======================================================================================================================
1165 _dnssd_client_handle_message(xpc_object_t msg
);
1167 _dnssd_client_handle_interruption(void);
1169 static xpc_connection_t
1170 _dnssd_client_connection(void)
1172 static dispatch_once_t once
= 0;
1173 static xpc_connection_t connection
= NULL
;
1175 dispatch_once(&once
,
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
)
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();
1188 xpc_connection_activate(connection
);
1194 _dnssd_client_handle_message(xpc_object_t msg
)
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
) {
1203 require_quiet(gai
, exit
);
1205 const OSStatus error
= dnssd_xpc_message_get_error(msg
, NULL
);
1207 xpc_object_t
const result_array
= dnssd_xpc_message_get_results(msg
);
1208 require_quiet(result_array
, exit
);
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
)
1215 const dnssd_getaddrinfo_result_t result
= _dnssd_getaddrinfo_create_result_from_dictionary(gai
, result_dict
,
1218 *result_ptr
= result
;
1219 result_ptr
= &result
->next
;
1223 require_quiet(result_list
, exit
);
1225 _dnssd_getaddrinfo_append_results(gai
, result_list
);
1228 _dnssd_client_fail_getaddrinfo(gai
, error
);
1236 _dnssd_client_handle_interruption(void)
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
);
1244 _dnssd_getaddrinfo_remove_all_results(gai
);
1246 _dnssd_client_fail_getaddrinfo(gai
, err
);
1251 //======================================================================================================================
1254 _dnssd_client_get_new_id(void)
1256 static uint64_t last_id
= 0;
1260 //======================================================================================================================
1263 _dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai
);
1266 _dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t gai
);
1269 _dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai
)
1272 dispatch_async(_dnssd_client_queue(),
1274 _dnssd_client_activate_getaddrinfo(gai
);
1280 _dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai
)
1283 require_action_quiet(gai
->state
== dnssd_getaddrinfo_state_nascent
, exit
, err
= kNoErr
);
1285 err
= _dnssd_getaddrinfo_activate(gai
);
1287 gai
->state
= dnssd_getaddrinfo_state_failed
;
1291 gai
->command_id
= _dnssd_client_get_new_id();
1292 gai
->state
= dnssd_getaddrinfo_state_starting
;
1294 _dnssd_client_register_getaddrinfo(gai
);
1296 err
= _dnssd_client_send_getaddrinfo_command(gai
);
1298 _dnssd_client_fail_getaddrinfo(gai
, err
);
1306 _dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t gai
, unsigned long events
);
1309 _dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me
)
1312 xpc_object_t
const hostname
= dnssd_xpc_parameters_get_hostname_object(me
->params
);
1313 require_action_quiet(hostname
, exit
, err
= kParamErr
);
1315 me
->hostname
= xpc_copy(hostname
);
1316 require_action_quiet(me
->hostname
, exit
, err
= kNoResourcesErr
);
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
);
1322 dispatch_source_t
const event_source
= me
->event_source
;
1323 dispatch_source_set_event_handler(me
->event_source
,
1325 _dnssd_getaddrinfo_process_events(me
, dispatch_source_get_data(event_source
));
1327 dispatch_source_set_cancel_handler(me
->event_source
,
1331 dispatch_activate(me
->event_source
);
1337 dispatch_async(me
->user_queue
,
1339 if (me
->event_handler
) {
1340 me
->event_handler(dnssd_event_error
, _dnssd_osstatus_to_dns_service_error(err
));
1349 _dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t me
, unsigned long events
)
1351 if (events
& DNSSD_EVENT_REMOVE_ALL
) {
1352 if (me
->event_handler
) {
1353 me
->event_handler(dnssd_event_remove_all
, kDNSServiceErr_NoError
);
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
);
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
;
1368 if ((result_count
== countof(result_array
)) || !result_list
) {
1369 if (me
->result_handler
) {
1370 me
->result_handler(result_array
, result_count
);
1372 for (size_t i
= 0; i
< result_count
; ++i
) {
1373 dnssd_release(result_array
[i
]);
1380 if (events
& DNSSD_EVENT_ERROR
) {
1381 __block OSStatus error
;
1382 dispatch_sync(me
->mutex_queue
,
1387 if (me
->event_handler
&& error
) {
1388 me
->event_handler(dnssd_event_error
, _dnssd_osstatus_to_dns_service_error(error
));
1393 //======================================================================================================================
1396 _dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai
)
1398 gai
->next
= g_gai_list
;
1403 //======================================================================================================================
1406 _dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai
)
1408 dnssd_getaddrinfo_t
*ptr
;
1409 for (ptr
= &g_gai_list
; *ptr
; ptr
= &(*ptr
)->next
)
1422 //======================================================================================================================
1425 _dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai
, xpc_object_t reply
);
1428 _dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai
)
1431 xpc_object_t
const msg
= xpc_dictionary_create(NULL
, NULL
, 0);
1432 require_action_quiet(msg
, exit
, err
= kNoResourcesErr
);
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
);
1439 xpc_connection_send_message_with_reply(_dnssd_client_connection(), msg
, _dnssd_client_queue(),
1440 ^(xpc_object_t reply
)
1442 _dnssd_client_handle_getaddrinfo_reply(gai
, reply
);
1453 _dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai
, xpc_object_t reply
)
1455 require_quiet(gai
->state
== dnssd_getaddrinfo_state_starting
, exit
);
1457 if (xpc_get_type(reply
) == XPC_TYPE_DICTIONARY
) {
1458 const OSStatus error
= dnssd_xpc_message_get_error(reply
, NULL
);
1460 _dnssd_client_fail_getaddrinfo(gai
, error
);
1462 gai
->state
= dnssd_getaddrinfo_state_started
;
1464 } else if (reply
!= XPC_ERROR_CONNECTION_INTERRUPTED
) {
1466 if (reply
== XPC_ERROR_CONNECTION_INVALID
) {
1467 error
= kDNSServiceErr_ServiceNotRunning
;
1469 error
= kDNSServiceErr_Unknown
;
1471 _dnssd_client_fail_getaddrinfo(gai
, error
);
1478 //======================================================================================================================
1481 _dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai
, OSStatus error
)
1483 _dnssd_client_deregister_getaddrinfo(gai
);
1484 gai
->state
= dnssd_getaddrinfo_state_failed
;
1485 _dnssd_getaddrinfo_post_error_event(gai
, error
);
1488 //======================================================================================================================
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
);
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
);
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
);
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
)
1511 xpc_object_t actual_hostname
, rdata
, auth_tag
, provider_name
;
1512 DNSServiceErrorType error
;
1513 DNSServiceFlags flags
;
1516 dnssd_getaddrinfo_result_protocol_t protocol
;
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
);
1526 case kDNSServiceType_A
:
1527 case kDNSServiceType_AAAA
: {
1528 const xpc_object_t cname_update
= dnssd_xpc_result_get_cname_update(result_dict
);
1530 _dnssd_getaddrinfo_set_cnames(me
, rtype
, cname_update
);
1532 dnssd_getaddrinfo_result_type_t result_type
;
1533 if (error
== kDNSServiceErr_NoSuchRecord
) {
1534 result_type
= dnssd_getaddrinfo_result_type_no_address
;
1536 if (flags
& kDNSServiceFlagsAdd
) {
1537 if (flags
& kDNSServiceFlagsExpiredAnswer
) {
1538 result_type
= dnssd_getaddrinfo_result_type_expired
;
1540 result_type
= dnssd_getaddrinfo_result_type_add
;
1543 result_type
= dnssd_getaddrinfo_result_type_remove
;
1545 if (rtype
== kDNSServiceType_A
) {
1546 require_action_quiet(xpc_data_get_length(rdata
) == 4, exit
, err
= kMalformedErr
);
1548 require_action_quiet(xpc_data_get_length(rdata
) == 16, exit
, err
= kMalformedErr
);
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
);
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
);
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
);
1575 if ((flags
& kDNSServiceFlagsAdd
) && (flags
& kDNSServiceFlagAnsweredFromCache
)) {
1576 result
->is_from_cache
= true;
1581 dnssd_forget(&result
);
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
)
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
);
1599 xpc_object_t
const rdata
= dnssd_xpc_result_get_record_data_object(result
);
1600 require_quiet(rdata
, exit
);
1603 *out_hostname
= hostname
;
1606 *out_error
= dnssd_xpc_result_get_error(result
, NULL
);
1609 *out_flags
= dnssd_xpc_result_get_flags(result
, NULL
);
1611 if (out_interface_index
) {
1612 *out_interface_index
= dnssd_xpc_result_get_interface_index(result
, NULL
);
1615 *out_type
= dnssd_xpc_result_get_record_type(result
, NULL
);
1618 *out_class
= dnssd_xpc_result_get_record_class(result
, NULL
);
1624 *out_auth_tag
= dnssd_xpc_result_get_authentication_tag_object(result
);
1627 *out_protocol
= dnssd_xpc_result_get_record_protocol(result
, NULL
);
1629 if (out_provider_name
) {
1630 *out_provider_name
= dnssd_xpc_result_get_provider_name_object(result
);
1632 result_is_valid
= true;
1635 return result_is_valid
;
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
)
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
);
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
:
1661 obj
->if_index
= if_index
;
1662 obj
->protocol
= protocol
;
1664 require_action_quiet(xpc_get_type(hostname
) == XPC_TYPE_STRING
, exit
, err
= kTypeErr
);
1666 obj
->hostname
= xpc_copy(hostname
);
1667 require_action_quiet(obj
->hostname
, exit
, err
= kNoResourcesErr
);
1669 require_action_quiet(xpc_get_type(actual_hostname
) == XPC_TYPE_STRING
, exit
, err
= kTypeErr
);
1671 obj
->actual_hostname
= xpc_copy(actual_hostname
);
1672 require_action_quiet(obj
->actual_hostname
, exit
, err
= kNoResourcesErr
);
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
);
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);
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
;
1696 require_action_quiet(xpc_get_type(auth_tag
) == XPC_TYPE_DATA
, exit
, err
= kTypeErr
);
1698 obj
->auth_tag
= xpc_copy(auth_tag
);
1699 require_action_quiet(obj
->auth_tag
, exit
, err
= kNoResourcesErr
);
1701 if (provider_name
) {
1702 require_action_quiet(xpc_get_type(provider_name
) == XPC_TYPE_STRING
, exit
, err
= kTypeErr
);
1704 obj
->provider_name
= xpc_copy(provider_name
);
1705 require_action_quiet(obj
->provider_name
, exit
, err
= kNoResourcesErr
);
1715 dnssd_release_null_safe(obj
);
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
)
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
);
1729 obj
->type
= dnssd_getaddrinfo_result_type_service_binding
;
1730 obj
->if_index
= interface_index
;
1731 obj
->protocol
= protocol
;
1733 require_action_quiet(xpc_get_type(hostname
) == XPC_TYPE_STRING
, exit
, err
= kTypeErr
);
1734 obj
->hostname
= xpc_copy(hostname
);
1736 require_action_quiet(xpc_get_type(actual_hostname
) == XPC_TYPE_STRING
, exit
, err
= kTypeErr
);
1738 obj
->actual_hostname
= xpc_copy(actual_hostname
);
1739 require_action_quiet(obj
->actual_hostname
, exit
, err
= kNoResourcesErr
);
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
);
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
);
1752 obj
->service_name
= xpc_string_create(service_name
);
1755 require_action_quiet(obj
->service_name
, exit
, err
= kNoResourcesErr
);
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
);
1762 require_action_quiet(obj
->doh_uri
, exit
, err
= kNoResourcesErr
);
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
);
1770 require_action_quiet(obj
->ech_config
, exit
, err
= kNoResourcesErr
);
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);
1778 xpc_array_append_value(obj
->alpn_values
, alpn_string
);
1779 xpc_release(alpn_string
);
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);
1788 xpc_array_append_value(obj
->address_hints
, address_hint
);
1789 xpc_release(address_hint
);
1793 obj
->valid_svcb
= false;
1797 require_action_quiet(xpc_get_type(auth_tag
) == XPC_TYPE_DATA
, exit
, err
= kTypeErr
);
1799 obj
->auth_tag
= xpc_copy(auth_tag
);
1800 require_action_quiet(obj
->auth_tag
, exit
, err
= kNoResourcesErr
);
1803 if (provider_name
) {
1804 require_action_quiet(xpc_get_type(provider_name
) == XPC_TYPE_STRING
, exit
, err
= kTypeErr
);
1806 obj
->provider_name
= xpc_copy(provider_name
);
1807 require_action_quiet(obj
->provider_name
, exit
, err
= kNoResourcesErr
);
1818 dnssd_release_null_safe(obj
);
1822 //======================================================================================================================
1823 // MARK: - Misc. Helpers
1825 static dnssd_cname_array_t
1826 _dnssd_get_empty_cname_array(void)
1828 static dispatch_once_t s_once
= 0;
1829 static dnssd_cname_array_t s_empty_cname_array
= NULL
;
1830 dispatch_once(&s_once
,
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
;
1836 return s_empty_cname_array
;
1839 //======================================================================================================================
1841 static DNSServiceErrorType
1842 _dnssd_osstatus_to_dns_service_error(OSStatus error
)
1846 case kNoResourcesErr
:
1847 error
= kDNSServiceErr_NoMemory
;
1851 error
= kDNSServiceErr_BadParam
;
1855 if ((error
>= kGenericErrorBase
) && (error
<= kGenericErrorEnd
)) {
1856 error
= kDNSServiceErr_Unknown
;
1863 //======================================================================================================================
1866 _dnssd_snprintf(char ** const dst
, const char * const end
, const char * const format
, ...)
1868 char * const ptr
= *dst
;
1869 const size_t len
= (size_t)(end
- ptr
);
1871 va_start(args
, format
);
1872 const int n
= vsnprintf(ptr
, len
, format
, args
);
1875 *dst
= ptr
+ Min((size_t)n
, len
);