]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/dnssd.c
mDNSResponder-1096.60.2.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / dnssd.c
1 /*
2 * Copyright (c) 2019 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 * http://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
22 #include <CoreUtils/CoreUtils.h>
23 #include <os/object_private.h>
24 #include <xpc/private.h>
25
26 #if 0
27 //======================================================================================================================
28 #pragma mark - Kind Declarations
29 #endif
30
31 #define DNSSD_STRUCT(NAME) struct dnssd_ ## NAME ## _s
32 #define DNSSD_TYPE(NAME) dnssd_ ## NAME ## _t
33
34 #define DNSSD_KIND_DECLARE(NAME) \
35 static DNSSD_TYPE(NAME) \
36 _dnssd_ ## NAME ## _alloc(void); \
37 \
38 static char * \
39 _dnssd_ ## NAME ## _copy_description(DNSSD_TYPE(NAME) object, bool debug, bool privacy); \
40 \
41 static void \
42 _dnssd_ ## NAME ## _finalize(DNSSD_TYPE(NAME) object)
43
44 // Note: The last check checks if the base's type is equal to that of the superkind. If it's not, then the pointer
45 // comparison used as the argument to sizeof will cause a "comparison of distinct pointer types" warning, so long as
46 // the warning hasn't been disabled.
47
48 #define DNSSD_BASE_CHECK(NAME, SUPER) \
49 check_compile_time(offsetof(DNSSD_STRUCT(NAME), base) == 0); \
50 check_compile_time(sizeof_field(DNSSD_STRUCT(NAME), base) == sizeof(DNSSD_STRUCT(SUPER))); \
51 extern int _dnssd_base_type_check[sizeof(&(((DNSSD_TYPE(NAME))0)->base) == ((DNSSD_TYPE(SUPER))0))]
52
53 #define DNSSD_KIND_DEFINE(NAME, SUPER) \
54 static const struct dnssd_kind_s _dnssd_ ## NAME ## _kind = { \
55 &_dnssd_ ## SUPER ## _kind, \
56 # NAME, \
57 _dnssd_ ## NAME ## _copy_description, \
58 _dnssd_ ## NAME ## _finalize, \
59 }; \
60 \
61 static DNSSD_TYPE(NAME) \
62 _dnssd_ ## NAME ## _alloc(void) \
63 { \
64 DNSSD_TYPE(NAME) obj = dnssd_object_ ## NAME ## _alloc(sizeof(*obj)); \
65 require_quiet(obj, exit); \
66 \
67 const dnssd_object_t base = (dnssd_object_t)obj; \
68 base->kind = &_dnssd_ ## NAME ## _kind; \
69 \
70 exit: \
71 return obj; \
72 } \
73 DNSSD_BASE_CHECK(NAME, SUPER)
74
75 DNSSD_KIND_DECLARE(getaddrinfo);
76 DNSSD_KIND_DECLARE(getaddrinfo_result);
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 #if 0
90 //======================================================================================================================
91 #pragma mark - dnssd_object Kind Definition
92 #endif
93
94 struct dnssd_object_s {
95 _OS_OBJECT_HEADER(const void *_os_obj_isa, _os_obj_refcnt, _os_obj_xref_cnt);
96 dnssd_kind_t kind; // Pointer to an object's kind.
97 };
98
99 static const struct dnssd_kind_s _dnssd_object_kind = {
100 NULL, // No superkind.
101 "object",
102 NULL, // No copy_description method.
103 NULL, // No finalize method.
104 };
105
106 #if 0
107 //======================================================================================================================
108 #pragma mark - dnssd_getaddrinfo Kind Definition
109 #endif
110
111 typedef enum {
112 dnssd_getaddrinfo_state_nascent = 0,
113 dnssd_getaddrinfo_state_starting = 1,
114 dnssd_getaddrinfo_state_started = 2,
115 dnssd_getaddrinfo_state_failed = 3,
116 dnssd_getaddrinfo_state_invalidated = 4,
117 } dnssd_getaddrinfo_state_t;
118
119 struct dnssd_getaddrinfo_s {
120 struct dnssd_object_s base; // Object base.
121 dnssd_getaddrinfo_t next; // Next getaddrinfo object in list.
122 uint64_t command_id; // Command ID.
123 dispatch_queue_t user_queue; // User's dispatch queue for invoking result and event handlers.
124 dispatch_queue_t mutex_queue; // Mutex for accessing result_list from different queues.
125 xpc_object_t params; // Parameters dictionary for getaddrinfo command.
126 xpc_object_t hostname; // Reference to hostname from parameters dictionary.
127 dispatch_source_t event_source; // Data source for triggering result and event handlers.
128 dnssd_getaddrinfo_result_t result_list; // List of getaddrinfo results.
129 dnssd_getaddrinfo_result_handler_t result_handler; // User's result handler.
130 dnssd_event_handler_t event_handler; // User's event handler.
131 dnssd_getaddrinfo_state_t state; // Internal state.
132 OSStatus error; // Pending error.
133 bool user_activated; // True if the object has been activated by user.
134 };
135
136 DNSSD_KIND_DEFINE(getaddrinfo, object);
137
138 #if 0
139 //======================================================================================================================
140 #pragma mark - dnssd_getaddrinfo_result Kind Definition
141 #endif
142
143 struct dnssd_getaddrinfo_result_s {
144 struct dnssd_object_s base; // Object base.
145 sockaddr_ip addr; // IPv4 or IPv6 address of hostname.
146 xpc_object_t hostname; // Requested hostname to resolve.
147 xpc_object_t actual_hostname; // The actual/canonical hostname of the requested hostname.
148 xpc_object_t auth_tag; // Authentication tag.
149 uint32_t interface_index; // Interface index to which the result pertains.
150 dnssd_getaddrinfo_result_type_t type; // Type of getaddrinfo result.
151 dnssd_getaddrinfo_result_t next; // Next getaddrinfo result in list.
152 };
153
154 DNSSD_KIND_DEFINE(getaddrinfo_result, object);
155
156 #if 0
157 //======================================================================================================================
158 #pragma mark - Constants
159 #endif
160
161 #define DNSSD_EVENT_HAVE_RESULTS (1U << 0) // Results are available.
162 #define DNSSD_EVENT_REMOVE_ALL (1U << 1) // Previously delivered results are no longer valid.
163 #define DNSSD_EVENT_ERROR (1U << 2) // An error was encountered.
164
165 // Strings for redacted description items.
166
167 #define DNSSD_REDACTED_HOSTNAME_STR "<redacted hostname>"
168 #define DNSSD_REDACTED_ACTUAL_HOSTNAME_STR "<redacted actual hostname>"
169 #define DNSSD_REDACTED_IPv4_ADDRESS_STR "<redacted IPv4 address>"
170 #define DNSSD_REDACTED_IPv6_ADDRESS_STR "<redacted IPv6 address>"
171
172 #if 0
173 //======================================================================================================================
174 #pragma mark - Local Prototypes
175 #endif
176
177 static dispatch_queue_t
178 _dnssd_client_queue(void);
179
180 static xpc_connection_t
181 _dnssd_client_connection(void);
182
183 static uint64_t
184 _dnssd_client_get_new_id(void);
185
186 static void
187 _dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai);
188
189 static void
190 _dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai);
191
192 static void
193 _dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai);
194
195 static OSStatus
196 _dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai);
197
198 static void
199 _dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai, OSStatus error);
200
201 static void
202 _dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t gai, dnssd_getaddrinfo_result_t result_list);
203
204 static void
205 _dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t gai);
206
207 static dnssd_getaddrinfo_result_t
208 _dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t gai);
209
210 static void
211 _dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t gai, OSStatus error);
212
213 static dnssd_getaddrinfo_result_t
214 _dnssd_getaddrinfo_result_create_from_dictionary(xpc_object_t hostname, xpc_object_t result_dict, OSStatus *out_error);
215
216 static DNSServiceErrorType
217 _dnssd_osstatus_to_dns_service_error(OSStatus status);
218
219 #if !defined(dnssd_release_null_safe)
220 #define dnssd_release_null_safe(X) \
221 do { \
222 if (X) { \
223 dnssd_release(X); \
224 } \
225 } while(0)
226 #endif
227
228 #if !defined(dnssd_forget)
229 #define dnssd_forget(X) ForgetCustom(X, dnssd_release)
230 #endif
231
232 #if 0
233 //======================================================================================================================
234 #pragma mark - dnssd_object Public Methods
235 #endif
236
237 void
238 dnssd_retain(dnssd_any_t object)
239 {
240 os_retain(object.base);
241 }
242
243 //======================================================================================================================
244
245 void
246 dnssd_release(dnssd_any_t object)
247 {
248 os_release(object.base);
249 }
250
251 //======================================================================================================================
252
253 char *
254 dnssd_copy_description(dnssd_any_t object)
255 {
256 return dnssd_object_copy_description(object, false, false);
257 }
258
259 #if 0
260 //======================================================================================================================
261 #pragma mark - dnssd_object Private Methods
262 #endif
263
264 char *
265 dnssd_object_copy_description(dnssd_any_t object, bool debug, bool privacy)
266 {
267 for (dnssd_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
268 if (kind->copy_description) {
269 char *desc = kind->copy_description(object, debug, privacy);
270 return desc;
271 }
272 }
273 return NULL;
274 }
275
276 //======================================================================================================================
277
278 void
279 dnssd_object_finalize(dnssd_any_t object)
280 {
281 for (dnssd_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
282 if (kind->finalize) {
283 kind->finalize(object);
284 }
285 }
286 }
287
288 #if 0
289 //======================================================================================================================
290 #pragma mark - dnssd_getaddrinfo Public Methods
291 #endif
292
293 dnssd_getaddrinfo_t
294 dnssd_getaddrinfo_create(void)
295 {
296 dnssd_getaddrinfo_t gai = NULL;
297 dnssd_getaddrinfo_t obj = _dnssd_getaddrinfo_alloc();
298 require_quiet(obj, exit);
299
300 obj->params = xpc_dictionary_create(NULL, NULL, 0);
301 require_quiet(obj->params, exit);
302
303 obj->mutex_queue = dispatch_queue_create("com.apple.dnssd.getaddrinfo.mutex", DISPATCH_QUEUE_SERIAL);
304 require_quiet(obj->mutex_queue, exit);
305
306 gai = obj;
307 obj = NULL;
308
309 exit:
310 dnssd_release_null_safe(obj);
311 return gai;
312 }
313
314 //======================================================================================================================
315
316 void
317 dnssd_getaddrinfo_set_queue(dnssd_getaddrinfo_t me, dispatch_queue_t queue)
318 {
319 if (!me->user_activated) {
320 dispatch_retain(queue);
321 dispatch_release_null_safe(me->user_queue);
322 me->user_queue = queue;
323 } else if (!me->user_queue) {
324 me->user_queue = queue;
325 dispatch_retain(me->user_queue);
326 _dnssd_client_activate_getaddrinfo_async(me);
327 }
328 }
329
330 //======================================================================================================================
331
332 void
333 dnssd_getaddrinfo_set_flags(dnssd_getaddrinfo_t me, DNSServiceFlags flags)
334 {
335 if (!me->user_activated) {
336 dnssd_xpc_parameters_set_flags(me->params, flags);
337 }
338 }
339
340 //======================================================================================================================
341
342 void
343 dnssd_getaddrinfo_set_hostname(dnssd_getaddrinfo_t me, const char *hostname)
344 {
345 if (!me->user_activated) {
346 dnssd_xpc_parameters_set_hostname(me->params, hostname);
347 }
348 }
349
350 //======================================================================================================================
351
352 void
353 dnssd_getaddrinfo_set_interface_index(dnssd_getaddrinfo_t me, uint32_t interface_index)
354 {
355 if (!me->user_activated) {
356 dnssd_xpc_parameters_set_interface_index(me->params, interface_index);
357 }
358 }
359
360 //======================================================================================================================
361
362 void
363 dnssd_getaddrinfo_set_protocols(dnssd_getaddrinfo_t me, DNSServiceProtocol protocols)
364 {
365 if (!me->user_activated) {
366 dnssd_xpc_parameters_set_protocols(me->params, protocols);
367 }
368 }
369
370 //======================================================================================================================
371
372 void
373 dnssd_getaddrinfo_set_delegate_pid(dnssd_getaddrinfo_t me, pid_t pid)
374 {
375 if (!me->user_activated) {
376 dnssd_xpc_parameters_set_delegate_pid(me->params, pid);
377 }
378 }
379
380 //======================================================================================================================
381
382 void
383 dnssd_getaddrinfo_set_delegate_uuid(dnssd_getaddrinfo_t me, uuid_t uuid)
384 {
385 if (!me->user_activated) {
386 dnssd_xpc_parameters_set_delegate_uuid(me->params, uuid);
387 }
388 }
389
390 //======================================================================================================================
391
392 void
393 dnssd_getaddrinfo_set_result_handler(dnssd_getaddrinfo_t me, dnssd_getaddrinfo_result_handler_t handler)
394 {
395 dnssd_getaddrinfo_result_handler_t const new_handler = handler ? Block_copy(handler) : NULL;
396 if (me->result_handler) {
397 Block_release(me->result_handler);
398 }
399 me->result_handler = new_handler;
400 }
401
402 //======================================================================================================================
403
404 void
405 dnssd_getaddrinfo_set_event_handler(dnssd_getaddrinfo_t me, dnssd_event_handler_t handler)
406 {
407 dnssd_event_handler_t const new_handler = handler ? Block_copy(handler) : NULL;
408 if (me->event_handler) {
409 Block_release(me->event_handler);
410 }
411 me->event_handler = new_handler;
412 }
413
414 //======================================================================================================================
415
416 void
417 dnssd_getaddrinfo_set_need_authenticated_results(dnssd_getaddrinfo_t me, bool need)
418 {
419 if (!me->user_activated) {
420 dnssd_xpc_parameters_set_need_authentication_tags(me->params, need);
421 }
422 }
423
424 //======================================================================================================================
425
426 void
427 dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me)
428 {
429 if (!me->user_activated) {
430 if (me->user_queue) {
431 _dnssd_client_activate_getaddrinfo_async(me);
432 }
433 me->user_activated = true;
434 }
435 }
436
437 //======================================================================================================================
438
439 static void
440 _dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai);
441
442 static void
443 _dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me);
444
445 void
446 dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me)
447 {
448 dnssd_retain(me);
449 dispatch_async(_dnssd_client_queue(),
450 ^{
451 _dnssd_client_invalidate_getaddrinfo(me);
452 dnssd_release(me);
453 });
454 }
455
456 static void
457 _dnssd_client_invalidate_getaddrinfo(dnssd_getaddrinfo_t gai)
458 {
459 require_quiet(gai->state != dnssd_getaddrinfo_state_invalidated, exit);
460
461 _dnssd_client_deregister_getaddrinfo(gai);
462 if ((gai->state == dnssd_getaddrinfo_state_starting) || (gai->state == dnssd_getaddrinfo_state_started)) {
463 xpc_object_t const msg = xpc_dictionary_create(NULL, NULL, 0);
464 if (msg) {
465 dnssd_xpc_message_set_id(msg, gai->command_id);
466 dnssd_xpc_message_set_command(msg, DNSSD_COMMAND_STOP);
467 xpc_connection_send_message_with_reply(_dnssd_client_connection(), msg, _dnssd_client_queue(),
468 ^(xpc_object_t reply)
469 {
470 (void)reply;
471 });
472 xpc_release(msg);
473 }
474 }
475 _dnssd_getaddrinfo_invalidate(gai);
476 gai->state = dnssd_getaddrinfo_state_invalidated;
477
478 exit:
479 return;
480 }
481
482 static void
483 _dnssd_getaddrinfo_invalidate(dnssd_getaddrinfo_t me)
484 {
485 dispatch_source_forget(&me->event_source);
486 _dnssd_getaddrinfo_remove_all_results(me);
487
488 if (me->user_queue) {
489 dnssd_retain(me);
490 dispatch_async(me->user_queue,
491 ^{
492 if (me->event_handler) {
493 me->event_handler(dnssd_event_invalidated, kDNSServiceErr_NoError);
494 }
495 dnssd_release(me);
496 });
497 }
498 }
499
500 #if 0
501 //======================================================================================================================
502 #pragma mark - dnssd_getaddrinfo Private Methods
503 #endif
504
505 static char *
506 _dnssd_getaddrinfo_copy_description(dnssd_getaddrinfo_t me, const bool debug, const bool privacy)
507 {
508 const char *hostname;
509 if (me->hostname) {
510 hostname = xpc_string_get_string_ptr(me->hostname);
511 if (privacy && hostname) {
512 hostname = DNSSD_REDACTED_HOSTNAME_STR;
513 }
514 } else {
515 hostname = NULL;
516 }
517
518 char * desc = NULL;
519 char * buf_ptr = NULL;
520 size_t buf_len = 0;
521 for (;;)
522 {
523 size_t need = 0;
524 char * dst = buf_ptr;
525 char * const end = &buf_ptr[buf_len];
526 int n;
527
528 if (debug) {
529 const size_t len = (size_t)(end - dst);
530 n = snprintf(dst, len, "dnssd_%s (%p): ", me->base.kind->name, (void *)me);
531 require_quiet(n >= 0, exit);
532
533 if (buf_ptr) {
534 dst = (((size_t)n) < len) ? &dst[n] : end;
535 } else {
536 need += (size_t)n;
537 }
538 }
539 n = snprintf(dst, (size_t)(end - dst), "hostname = %s", hostname ? hostname : "<NO HOSTNAME>");
540 require_quiet(n >= 0, exit);
541
542 if (!buf_ptr) {
543 need += (size_t)n;
544 buf_len = need + 1;
545 buf_ptr = malloc(buf_len);
546 require_quiet(buf_ptr, exit);
547 } else {
548 break;
549 }
550 }
551 desc = buf_ptr;
552 buf_ptr = NULL;
553
554 exit:
555 FreeNullSafe(buf_ptr);
556 return desc;
557 }
558
559 //======================================================================================================================
560
561 static void
562 _dnssd_getaddrinfo_finalize(dnssd_getaddrinfo_t me)
563 {
564 dispatch_forget(&me->user_queue);
565 dispatch_forget(&me->mutex_queue);
566 xpc_forget(&me->params);
567 xpc_forget(&me->hostname);
568 BlockForget(&me->result_handler);
569 BlockForget(&me->event_handler);
570 }
571
572 //======================================================================================================================
573
574 static void
575 _dnssd_getaddrinfo_append_results(dnssd_getaddrinfo_t me, dnssd_getaddrinfo_result_t result_list)
576 {
577 dispatch_sync(me->mutex_queue,
578 ^{
579 dnssd_getaddrinfo_result_t *ptr = &me->result_list;
580 while (*ptr) {
581 ptr = &(*ptr)->next;
582 }
583 *ptr = result_list;
584 });
585 dispatch_source_merge_data(me->event_source, DNSSD_EVENT_HAVE_RESULTS);
586 }
587
588 //======================================================================================================================
589
590 static void
591 _dnssd_getaddrinfo_remove_all_results(dnssd_getaddrinfo_t me)
592 {
593 dnssd_getaddrinfo_result_t result_list = _dnssd_getaddrinfo_take_results(me);
594 if (me->event_source) {
595 dispatch_source_merge_data(me->event_source, DNSSD_EVENT_REMOVE_ALL);
596 }
597
598 dnssd_getaddrinfo_result_t result;
599 while ((result = result_list) != NULL) {
600 result_list = result->next;
601 dnssd_release(result);
602 }
603 }
604
605 //======================================================================================================================
606
607 static dnssd_getaddrinfo_result_t
608 _dnssd_getaddrinfo_take_results(dnssd_getaddrinfo_t me)
609 {
610 __block dnssd_getaddrinfo_result_t list;
611 dispatch_sync(me->mutex_queue,
612 ^{
613 list = me->result_list;
614 me->result_list = NULL;
615 });
616 return list;
617 }
618
619 //======================================================================================================================
620
621 static void
622 _dnssd_getaddrinfo_post_error_event(dnssd_getaddrinfo_t me, OSStatus error)
623 {
624 dispatch_sync(me->mutex_queue,
625 ^{
626 me->error = error;
627 });
628 dispatch_source_merge_data(me->event_source, DNSSD_EVENT_ERROR);
629 }
630
631 #if 0
632 //======================================================================================================================
633 #pragma mark - dnssd_getaddrinfo_result Public Methods
634 #endif
635
636 dnssd_getaddrinfo_result_type_t
637 dnssd_getaddrinfo_result_get_type(dnssd_getaddrinfo_result_t me)
638 {
639 return me->type;
640 }
641
642 //======================================================================================================================
643
644 const char *
645 dnssd_getaddrinfo_result_get_actual_hostname(dnssd_getaddrinfo_result_t me)
646 {
647 return xpc_string_get_string_ptr(me->actual_hostname);
648 }
649
650 //======================================================================================================================
651
652 const struct sockaddr *
653 dnssd_getaddrinfo_result_get_address(dnssd_getaddrinfo_result_t me)
654 {
655 return &me->addr.sa;
656 }
657
658 //======================================================================================================================
659
660 const char *
661 dnssd_getaddrinfo_result_get_hostname(dnssd_getaddrinfo_result_t me)
662 {
663 return xpc_string_get_string_ptr(me->hostname);
664 }
665
666 //======================================================================================================================
667
668 uint32_t
669 dnssd_getaddrinfo_result_get_interface_index(dnssd_getaddrinfo_result_t me)
670 {
671 return me->interface_index;
672 }
673
674 //======================================================================================================================
675
676 const void *
677 dnssd_getaddrinfo_result_get_authentication_tag(dnssd_getaddrinfo_result_t me, size_t *out_length)
678 {
679 const void * auth_tag_ptr;
680 size_t auth_tag_len;
681
682 if (me->auth_tag) {
683 auth_tag_ptr = xpc_data_get_bytes_ptr(me->auth_tag);
684 auth_tag_len = xpc_data_get_length(me->auth_tag);
685 } else {
686 auth_tag_ptr = NULL;
687 auth_tag_len = 0;
688 }
689 if (out_length) {
690 *out_length = auth_tag_len;
691 }
692 return auth_tag_ptr;
693 }
694
695 #if 0
696 //======================================================================================================================
697 #pragma mark - dnssd_getaddrinfo_result Private Methods
698 #endif
699
700 static char *
701 _dnssd_getaddrinfo_result_copy_description(dnssd_getaddrinfo_result_t me, const bool debug, const bool privacy)
702 {
703 const char *hostname;
704 if (me->hostname) {
705 hostname = xpc_string_get_string_ptr(me->hostname);
706 if (privacy && hostname) {
707 hostname = DNSSD_REDACTED_HOSTNAME_STR;
708 }
709 } else {
710 hostname = NULL;
711 }
712
713 const char *actual_hostname;
714 if (me->actual_hostname) {
715 actual_hostname = xpc_string_get_string_ptr(me->actual_hostname);
716 if (privacy && actual_hostname) {
717 actual_hostname = DNSSD_REDACTED_ACTUAL_HOSTNAME_STR;
718 }
719 } else {
720 actual_hostname = NULL;
721 }
722 char addr_buf[INET6_ADDRSTRLEN];
723 check_compile_time_code(sizeof(addr_buf) >= INET_ADDRSTRLEN);
724 check_compile_time_code(sizeof(addr_buf) >= INET6_ADDRSTRLEN);
725
726 const char *addr;
727 if (me->addr.sa.sa_family == AF_INET) {
728 if (privacy) {
729 addr = DNSSD_REDACTED_IPv4_ADDRESS_STR;
730 } else {
731 addr = inet_ntop(AF_INET, &me->addr.v4.sin_addr.s_addr, addr_buf, (socklen_t)sizeof(addr_buf));
732 }
733 } else if (me->addr.sa.sa_family == AF_INET6) {
734 if (privacy) {
735 addr = DNSSD_REDACTED_IPv6_ADDRESS_STR;
736 } else {
737 addr = inet_ntop(AF_INET6, me->addr.v6.sin6_addr.s6_addr, addr_buf, (socklen_t)sizeof(addr_buf));
738 }
739 } else {
740 addr = NULL;
741 }
742
743 char * desc = NULL;
744 char * buf_ptr = NULL;
745 size_t buf_len = 0;
746 for (;;)
747 {
748 char * dst = buf_ptr;
749 char * const end = &buf_ptr[buf_len];
750 size_t need = 0;
751 int n;
752
753 if (debug) {
754 const size_t len = (size_t)(end - dst);
755 n = snprintf(dst, len, "dnssd_%s (%p): ", me->base.kind->name, (void *)me);
756 require_quiet(n >= 0, exit);
757
758 if (buf_ptr) {
759 dst = (((size_t)n) < len) ? &dst[n] : end;
760 } else {
761 need += (size_t)n;
762 }
763 }
764 n = snprintf(dst, (size_t)(end - dst), "[%s] %s (%s) -> %s (interface index %lu)",
765 dnssd_getaddrinfo_result_type_to_string(me->type), hostname ? hostname : "<NO HOSTNAME>",
766 actual_hostname ? actual_hostname : "<NO ACTUAL HOSTNAME>", addr ? addr : "<NO IP ADDRESS>",
767 (unsigned long)me->interface_index);
768 require_quiet(n >= 0, exit);
769
770 if (!buf_ptr) {
771 need += (size_t)n;
772 buf_len = need + 1;
773 buf_ptr = malloc(buf_len);
774 require_quiet(buf_ptr, exit);
775 } else {
776 break;
777 }
778 }
779 desc = buf_ptr;
780 buf_ptr = NULL;
781
782 exit:
783 FreeNullSafe(buf_ptr);
784 return desc;
785 }
786
787 //======================================================================================================================
788
789 void
790 _dnssd_getaddrinfo_result_finalize(dnssd_getaddrinfo_result_t me)
791 {
792 xpc_forget(&me->hostname);
793 xpc_forget(&me->actual_hostname);
794 xpc_forget(&me->auth_tag);
795 }
796
797 #if 0
798 //======================================================================================================================
799 #pragma mark - dnssd Client
800 #endif
801
802 static dnssd_getaddrinfo_t g_gai_list = NULL;
803
804 static dispatch_queue_t
805 _dnssd_client_queue(void)
806 {
807 static dispatch_once_t once = 0;
808 static dispatch_queue_t queue = NULL;
809
810 dispatch_once(&once,
811 ^{
812 dispatch_queue_attr_t const attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL,
813 QOS_CLASS_UTILITY, 0);
814 queue = dispatch_queue_create("com.apple.dnssd.client", attr);
815 });
816 return queue;
817 }
818
819 //======================================================================================================================
820
821 static void
822 _dnssd_client_handle_message(xpc_object_t msg);
823 static void
824 _dnssd_client_handle_interruption(void);
825
826 static xpc_connection_t
827 _dnssd_client_connection(void)
828 {
829 static dispatch_once_t once = 0;
830 static xpc_connection_t connection = NULL;
831
832 dispatch_once(&once,
833 ^{
834 connection = xpc_connection_create_mach_service(DNSSD_MACH_SERVICE_NAME, _dnssd_client_queue(),
835 XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
836 xpc_connection_set_event_handler(connection,
837 ^(xpc_object_t event)
838 {
839 if (xpc_get_type(event) == XPC_TYPE_DICTIONARY) {
840 _dnssd_client_handle_message(event);
841 } else if (event == XPC_ERROR_CONNECTION_INTERRUPTED) {
842 _dnssd_client_handle_interruption();
843 }
844 });
845 xpc_connection_activate(connection);
846 });
847 return connection;
848 }
849
850 static void
851 _dnssd_client_handle_message(xpc_object_t msg)
852 {
853 const uint64_t command_id = dnssd_xpc_message_get_id(msg, NULL);
854 dnssd_getaddrinfo_t gai;
855 for (gai = g_gai_list; gai; gai = gai->next) {
856 if (gai->command_id == command_id) {
857 break;
858 }
859 }
860 require_quiet(gai, exit);
861
862 const OSStatus error = dnssd_xpc_message_get_error(msg, NULL);
863 if (!error) {
864 xpc_object_t const result_array = dnssd_xpc_message_get_results(msg);
865 require_quiet(result_array, exit);
866
867 dnssd_getaddrinfo_result_t result_list = NULL;
868 __block dnssd_getaddrinfo_result_t * result_ptr = &result_list;
869 xpc_array_apply(result_array,
870 ^bool(__unused size_t index, xpc_object_t result_dict)
871 {
872 dnssd_getaddrinfo_result_t result = _dnssd_getaddrinfo_result_create_from_dictionary(gai->hostname,
873 result_dict, NULL);
874 if (result) {
875 *result_ptr = result;
876 result_ptr = &result->next;
877 }
878 return true;
879 });
880 require_quiet(result_list, exit);
881
882 _dnssd_getaddrinfo_append_results(gai, result_list);
883 result_list = NULL;
884 } else {
885 _dnssd_client_fail_getaddrinfo(gai, error);
886 }
887
888 exit:
889 return;
890 }
891
892 static void
893 _dnssd_client_handle_interruption(void)
894 {
895 dnssd_getaddrinfo_t next_gai;
896 for (dnssd_getaddrinfo_t gai = g_gai_list; gai; gai = next_gai) {
897 next_gai = gai->next;
898 gai->state = dnssd_getaddrinfo_state_starting;
899 const OSStatus err = _dnssd_client_send_getaddrinfo_command(gai);
900 if (!err) {
901 _dnssd_getaddrinfo_remove_all_results(gai);
902 } else {
903 _dnssd_client_fail_getaddrinfo(gai, err);
904 }
905 }
906 }
907
908 //======================================================================================================================
909
910 static uint64_t
911 _dnssd_client_get_new_id(void)
912 {
913 static uint64_t last_id = 0;
914 return ++last_id;
915 }
916
917 //======================================================================================================================
918
919 static void
920 _dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai);
921
922 static OSStatus
923 _dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t gai);
924
925 static void
926 _dnssd_client_activate_getaddrinfo_async(dnssd_getaddrinfo_t gai)
927 {
928 dnssd_retain(gai);
929 dispatch_async(_dnssd_client_queue(),
930 ^{
931 _dnssd_client_activate_getaddrinfo(gai);
932 dnssd_release(gai);
933 });
934 }
935
936 static void
937 _dnssd_client_activate_getaddrinfo(dnssd_getaddrinfo_t gai)
938 {
939 OSStatus err;
940 require_action_quiet(gai->state == dnssd_getaddrinfo_state_nascent, exit, err = kNoErr);
941
942 err = _dnssd_getaddrinfo_activate(gai);
943 if (err) {
944 gai->state = dnssd_getaddrinfo_state_failed;
945 goto exit;
946 }
947
948 gai->command_id = _dnssd_client_get_new_id();
949 gai->state = dnssd_getaddrinfo_state_starting;
950
951 _dnssd_client_register_getaddrinfo(gai);
952
953 err = _dnssd_client_send_getaddrinfo_command(gai);
954 if (err) {
955 _dnssd_client_fail_getaddrinfo(gai, err);
956 }
957
958 exit:
959 return;
960 }
961
962 static void
963 _dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t gai, unsigned long events);
964
965 static OSStatus
966 _dnssd_getaddrinfo_activate(dnssd_getaddrinfo_t me)
967 {
968 OSStatus err;
969 xpc_object_t const hostname = dnssd_xpc_parameters_get_hostname_object(me->params);
970 require_action_quiet(hostname, exit, err = kParamErr);
971
972 me->hostname = xpc_copy(hostname);
973 require_action_quiet(me->hostname, exit, err = kNoResourcesErr);
974
975 me->event_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_DATA_OR, 0, 0, me->user_queue);
976 require_action_quiet(me->event_source, exit, err = kNoResourcesErr);
977
978 dnssd_retain(me);
979 dispatch_source_t const event_source = me->event_source;
980 dispatch_source_set_event_handler(me->event_source,
981 ^{
982 _dnssd_getaddrinfo_process_events(me, dispatch_source_get_data(event_source));
983 });
984 dispatch_source_set_cancel_handler(me->event_source,
985 ^{
986 dnssd_release(me);
987 });
988 dispatch_activate(me->event_source);
989 err = kNoErr;
990
991 exit:
992 if (err) {
993 dnssd_retain(me);
994 dispatch_async(me->user_queue,
995 ^{
996 if (me->event_handler) {
997 me->event_handler(dnssd_event_error, _dnssd_osstatus_to_dns_service_error(err));
998 }
999 dnssd_release(me);
1000 });
1001 }
1002 return err;
1003 }
1004
1005 static void
1006 _dnssd_getaddrinfo_process_events(dnssd_getaddrinfo_t me, unsigned long events)
1007 {
1008 if (events & DNSSD_EVENT_REMOVE_ALL) {
1009 if (me->event_handler) {
1010 me->event_handler(dnssd_event_remove_all, kDNSServiceErr_NoError);
1011 }
1012 }
1013
1014 if (events & DNSSD_EVENT_HAVE_RESULTS) {
1015 dnssd_getaddrinfo_result_t result;
1016 dnssd_getaddrinfo_result_t result_array[32];
1017 dnssd_getaddrinfo_result_t result_list = _dnssd_getaddrinfo_take_results(me);
1018
1019 size_t result_count = 0;
1020 while ((result = result_list) != NULL) {
1021 result_list = result->next;
1022 result->next = NULL;
1023 result_array[result_count++] = result;
1024
1025 if ((result_count == countof(result_array)) || !result_list) {
1026 if (me->result_handler) {
1027 me->result_handler(result_array, result_count);
1028 }
1029 for (size_t i = 0; i < result_count; ++i) {
1030 dnssd_release(result_array[i]);
1031 }
1032 result_count = 0;
1033 }
1034 }
1035 }
1036
1037 if (events & DNSSD_EVENT_ERROR) {
1038 __block OSStatus error;
1039 dispatch_sync(me->mutex_queue,
1040 ^{
1041 error = me->error;
1042 me->error = kNoErr;
1043 });
1044 if (me->event_handler && error) {
1045 me->event_handler(dnssd_event_error, _dnssd_osstatus_to_dns_service_error(error));
1046 }
1047 }
1048 }
1049
1050 //======================================================================================================================
1051
1052 static void
1053 _dnssd_client_register_getaddrinfo(dnssd_getaddrinfo_t gai)
1054 {
1055 gai->next = g_gai_list;
1056 g_gai_list = gai;
1057 dnssd_retain(gai);
1058 }
1059
1060 //======================================================================================================================
1061
1062 static void
1063 _dnssd_client_deregister_getaddrinfo(dnssd_getaddrinfo_t gai)
1064 {
1065 dnssd_getaddrinfo_t *ptr;
1066 for (ptr = &g_gai_list; *ptr; ptr = &(*ptr)->next)
1067 {
1068 if (*ptr == gai) {
1069 break;
1070 }
1071 }
1072 if (*ptr) {
1073 *ptr = gai->next;
1074 gai->next = NULL;
1075 dnssd_release(gai);
1076 }
1077 }
1078
1079 //======================================================================================================================
1080
1081 static void
1082 _dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai, xpc_object_t reply);
1083
1084 static OSStatus
1085 _dnssd_client_send_getaddrinfo_command(dnssd_getaddrinfo_t gai)
1086 {
1087 OSStatus err;
1088 xpc_object_t const msg = xpc_dictionary_create(NULL, NULL, 0);
1089 require_action_quiet(msg, exit, err = kNoResourcesErr);
1090
1091 dnssd_xpc_message_set_id(msg, gai->command_id);
1092 dnssd_xpc_message_set_command(msg, DNSSD_COMMAND_GETADDRINFO);
1093 dnssd_xpc_message_set_parameters(msg, gai->params);
1094
1095 dnssd_retain(gai);
1096 xpc_connection_send_message_with_reply(_dnssd_client_connection(), msg, _dnssd_client_queue(),
1097 ^(xpc_object_t reply)
1098 {
1099 _dnssd_client_handle_getaddrinfo_reply(gai, reply);
1100 dnssd_release(gai);
1101 });
1102 xpc_release(msg);
1103 err = kNoErr;
1104
1105 exit:
1106 return err;
1107 }
1108
1109 static void
1110 _dnssd_client_handle_getaddrinfo_reply(dnssd_getaddrinfo_t gai, xpc_object_t reply)
1111 {
1112 require_quiet(gai->state == dnssd_getaddrinfo_state_starting, exit);
1113
1114 if (xpc_get_type(reply) == XPC_TYPE_DICTIONARY) {
1115 const OSStatus error = dnssd_xpc_message_get_error(reply, NULL);
1116 if (error) {
1117 _dnssd_client_fail_getaddrinfo(gai, error);
1118 } else {
1119 gai->state = dnssd_getaddrinfo_state_started;
1120 }
1121 } else if (reply != XPC_ERROR_CONNECTION_INTERRUPTED) {
1122 OSStatus error;
1123 if (reply == XPC_ERROR_CONNECTION_INVALID) {
1124 error = kDNSServiceErr_ServiceNotRunning;
1125 } else {
1126 error = kDNSServiceErr_Unknown;
1127 }
1128 _dnssd_client_fail_getaddrinfo(gai, error);
1129 }
1130
1131 exit:
1132 return;
1133 }
1134
1135 //======================================================================================================================
1136
1137 static void
1138 _dnssd_client_fail_getaddrinfo(dnssd_getaddrinfo_t gai, OSStatus error)
1139 {
1140 _dnssd_client_deregister_getaddrinfo(gai);
1141 gai->state = dnssd_getaddrinfo_state_failed;
1142 _dnssd_getaddrinfo_post_error_event(gai, error);
1143 }
1144
1145 //======================================================================================================================
1146 // _dnssd_getaddrinfo_result_create_from_dictionary
1147 //======================================================================================================================
1148
1149 static bool
1150 _dnssd_extract_result_dict_values(xpc_object_t result, xpc_object_t *out_hostname, DNSServiceErrorType *out_error,
1151 DNSServiceFlags *out_flags, uint32_t *out_interface_index, uint16_t *out_type, uint16_t *out_class,
1152 xpc_object_t *out_rdata, xpc_object_t *out_auth_tag);
1153
1154 static dnssd_getaddrinfo_result_t
1155 _dnssd_getaddrinfo_result_create(dnssd_getaddrinfo_result_type_t type, xpc_object_t hostname,
1156 xpc_object_t actual_hostname, int addr_family, const void *addr_data, uint32_t interface_index,
1157 xpc_object_t auth_tag, OSStatus *out_error);
1158
1159 static dnssd_getaddrinfo_result_t
1160 _dnssd_getaddrinfo_result_create_from_dictionary(xpc_object_t hostname, xpc_object_t result_dict, OSStatus *out_error)
1161 {
1162 OSStatus err;
1163 xpc_object_t actual_hostname, rdata, auth_tag;
1164 DNSServiceErrorType error;
1165 DNSServiceFlags flags;
1166 uint32_t interface_index;
1167 uint16_t rtype;
1168 dnssd_getaddrinfo_result_t result = NULL;
1169
1170 const bool success = _dnssd_extract_result_dict_values(result_dict, &actual_hostname, &error, &flags,
1171 &interface_index, &rtype, NULL, &rdata, &auth_tag);
1172 require_action_quiet(success, exit, err = kMalformedErr);
1173
1174 if ((error != kDNSServiceErr_NoError) &&
1175 (error != kDNSServiceErr_NoSuchRecord)) {
1176 err = kUnexpectedErr;
1177 goto exit;
1178 }
1179 require_action_quiet((rtype == kDNSServiceType_A) || (rtype == kDNSServiceType_AAAA), exit, err = kTypeErr);
1180
1181 dnssd_getaddrinfo_result_type_t result_type;
1182 if (error == kDNSServiceErr_NoSuchRecord) {
1183 result_type = dnssd_getaddrinfo_result_type_no_address;
1184 } else {
1185 if (flags & kDNSServiceFlagsAdd) {
1186 if (flags & kDNSServiceFlagsExpiredAnswer) {
1187 result_type = dnssd_getaddrinfo_result_type_expired;
1188 } else {
1189 result_type = dnssd_getaddrinfo_result_type_add;
1190 }
1191 } else {
1192 result_type = dnssd_getaddrinfo_result_type_remove;
1193 }
1194 if (rtype == kDNSServiceType_A) {
1195 require_action_quiet(xpc_data_get_length(rdata) == 4, exit, err = kMalformedErr);
1196 } else {
1197 require_action_quiet(xpc_data_get_length(rdata) == 16, exit, err = kMalformedErr);
1198 }
1199 }
1200 const int addr_family = (rtype == kDNSServiceType_A) ? AF_INET : AF_INET6;
1201 result = _dnssd_getaddrinfo_result_create(result_type, hostname, actual_hostname, addr_family,
1202 xpc_data_get_bytes_ptr(rdata), interface_index, auth_tag, &err);
1203 require_noerr_quiet(err, exit);
1204
1205 exit:
1206 if (err) {
1207 dnssd_forget(&result);
1208 }
1209 if (out_error) {
1210 *out_error = err;
1211 }
1212 return result;
1213 }
1214
1215 static bool
1216 _dnssd_extract_result_dict_values(xpc_object_t result, xpc_object_t *out_hostname, DNSServiceErrorType *out_error,
1217 DNSServiceFlags *out_flags, uint32_t *out_interface_index, uint16_t *out_type, uint16_t *out_class,
1218 xpc_object_t *out_rdata, xpc_object_t *out_auth_tag)
1219 {
1220 bool result_is_valid = false;
1221 xpc_object_t const hostname = dnssd_xpc_result_get_record_name_object(result);
1222 require_quiet(hostname, exit);
1223
1224 xpc_object_t const rdata = dnssd_xpc_result_get_record_data_object(result);
1225 require_quiet(rdata, exit);
1226
1227 if (out_hostname) {
1228 *out_hostname = hostname;
1229 }
1230 if (out_error) {
1231 *out_error = dnssd_xpc_result_get_error(result, NULL);
1232 }
1233 if (out_flags) {
1234 *out_flags = dnssd_xpc_result_get_flags(result, NULL);
1235 }
1236 if (out_interface_index) {
1237 *out_interface_index = dnssd_xpc_result_get_interface_index(result, NULL);
1238 }
1239 if (out_type) {
1240 *out_type = dnssd_xpc_result_get_record_type(result, NULL);
1241 }
1242 if (out_class) {
1243 *out_class = dnssd_xpc_result_get_record_class(result, NULL);
1244 }
1245 if (out_rdata) {
1246 *out_rdata = rdata;
1247 }
1248 if (out_auth_tag) {
1249 *out_auth_tag = dnssd_xpc_result_get_authentication_tag_object(result);
1250 }
1251 result_is_valid = true;
1252
1253 exit:
1254 return result_is_valid;
1255 }
1256
1257 static dnssd_getaddrinfo_result_t
1258 _dnssd_getaddrinfo_result_create(dnssd_getaddrinfo_result_type_t type, xpc_object_t hostname,
1259 xpc_object_t actual_hostname, int addr_family, const void *addr_data, uint32_t interface_index,
1260 xpc_object_t auth_tag, OSStatus *out_error)
1261 {
1262 OSStatus err;
1263 dnssd_getaddrinfo_result_t result = NULL;
1264 dnssd_getaddrinfo_result_t obj = _dnssd_getaddrinfo_result_alloc();
1265 require_action_quiet(obj, exit, err = kNoMemoryErr);
1266
1267 switch (type) {
1268 case dnssd_getaddrinfo_result_type_add:
1269 case dnssd_getaddrinfo_result_type_remove:
1270 case dnssd_getaddrinfo_result_type_no_address:
1271 case dnssd_getaddrinfo_result_type_expired:
1272 break;
1273
1274 default:
1275 err = kTypeErr;
1276 goto exit;
1277 }
1278 obj->type = type;
1279 obj->interface_index = interface_index;
1280
1281 require_action_quiet(xpc_get_type(hostname) == XPC_TYPE_STRING, exit, err = kTypeErr);
1282
1283 obj->hostname = xpc_copy(hostname);
1284 require_action_quiet(obj->hostname, exit, err = kNoResourcesErr);
1285
1286 require_action_quiet(xpc_get_type(actual_hostname) == XPC_TYPE_STRING, exit, err = kTypeErr);
1287
1288 obj->actual_hostname = xpc_copy(actual_hostname);
1289 require_action_quiet(obj->actual_hostname, exit, err = kNoResourcesErr);
1290
1291 require_action_quiet((addr_family == AF_INET) || (addr_family == AF_INET6), exit, err = kTypeErr);
1292
1293 if (addr_family == AF_INET) {
1294 obj->addr.sa.sa_family = AF_INET;
1295 obj->addr.v4.sin_len = sizeof(struct sockaddr_in);
1296 if (obj->type != dnssd_getaddrinfo_result_type_no_address) {
1297 memcpy(&obj->addr.v4.sin_addr.s_addr, addr_data, 4);
1298 }
1299 } else {
1300 obj->addr.sa.sa_family = AF_INET6;
1301 obj->addr.v6.sin6_len = sizeof(struct sockaddr_in6);
1302 if (obj->type != dnssd_getaddrinfo_result_type_no_address) {
1303 memcpy(&obj->addr.v6.sin6_addr.s6_addr, addr_data, 16);
1304 }
1305 }
1306
1307 if (auth_tag) {
1308 require_action_quiet(xpc_get_type(auth_tag) == XPC_TYPE_DATA, exit, err = kTypeErr);
1309
1310 obj->auth_tag = xpc_copy(auth_tag);
1311 require_action_quiet(obj->auth_tag, exit, err = kNoResourcesErr);
1312 }
1313 result = obj;
1314 obj = NULL;
1315 err = kNoErr;
1316
1317 exit:
1318 if (out_error) {
1319 *out_error = err;
1320 }
1321 dnssd_release_null_safe(obj);
1322 return result;
1323 }
1324
1325 #if 0
1326 //======================================================================================================================
1327 #pragma mark - Misc. Helpers
1328 #endif
1329
1330 static DNSServiceErrorType
1331 _dnssd_osstatus_to_dns_service_error(OSStatus error)
1332 {
1333 switch (error) {
1334 case kNoMemoryErr:
1335 case kNoResourcesErr:
1336 error = kDNSServiceErr_NoMemory;
1337 break;
1338
1339 case kParamErr:
1340 error = kDNSServiceErr_BadParam;
1341 break;
1342
1343 default:
1344 if ((error >= kGenericErrorBase) && (error <= kGenericErrorEnd)) {
1345 error = kDNSServiceErr_Unknown;
1346 }
1347 break;
1348 }
1349 return error;
1350 }