]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/dnssd_server.c
mDNSResponder-1096.60.2.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / dnssd_server.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_server.h"
18
19 #include "ClientRequests.h"
20 #include "dnssd_xpc.h"
21 #include "mDNSMacOSX.h"
22
23 #include <CoreUtils/CommonServices.h>
24 #include <CoreUtils/DebugServices.h>
25 #include <libproc.h>
26 #include <net/necp.h>
27 #include <sys/proc_info.h>
28 #include <xpc/private.h>
29
30 #if 0
31 //======================================================================================================================
32 #pragma mark - Kind Declarations
33 #endif
34
35 #define DX_STRUCT(NAME) struct dx_ ## NAME ## _s
36 #define DX_TYPE(NAME) dx_ ## NAME ## _t
37 #define DX_KIND_DECLARE(NAME) typedef DX_STRUCT(NAME) * DX_TYPE(NAME)
38
39 #define DX_KIND_DECLARE_FULL(NAME) \
40 DX_KIND_DECLARE(NAME); \
41 \
42 static void \
43 _dx_ ## NAME ## _invalidate(DX_TYPE(NAME) object); \
44 \
45 static void \
46 _dx_ ## NAME ## _finalize(DX_TYPE(NAME) object); \
47 \
48 static DX_TYPE(NAME) \
49 _dx_ ## NAME ## _alloc(void)
50
51 // Note: The last check checks if the base's type is equal to that of the superkind. If it's not, then the pointer
52 // comparison used as the argument to sizeof will cause a "comparison of distinct pointer types" warning, so long as
53 // the warning hasn't been disabled.
54
55 #define DX_BASE_CHECK(NAME, SUPER) \
56 check_compile_time(offsetof(DX_STRUCT(NAME), base) == 0); \
57 check_compile_time(sizeof_field(DX_STRUCT(NAME), base) == sizeof(DX_STRUCT(SUPER))); \
58 extern int _dx_base_type_check[sizeof(&(((DX_TYPE(NAME))0)->base) == ((DX_TYPE(SUPER))0))]
59
60 #define DX_KIND_DEFINE(NAME, SUPER) \
61 static const struct dx_kind_s _dx_ ## NAME ## _kind = { \
62 &_dx_ ## SUPER ##_kind, \
63 _dx_ ## NAME ## _invalidate, \
64 _dx_ ## NAME ## _finalize, \
65 }; \
66 \
67 static DX_TYPE(NAME) \
68 _dx_ ## NAME ## _alloc(void) \
69 { \
70 const DX_TYPE(NAME) obj = (DX_TYPE(NAME))calloc(1, sizeof(*obj)); \
71 require_quiet(obj, exit); \
72 \
73 const dx_base_t base = (dx_base_t)obj; \
74 base->ref_count = 1; \
75 base->kind = &_dx_ ## NAME ## _kind; \
76 \
77 exit: \
78 return obj; \
79 } \
80 DX_BASE_CHECK(NAME, SUPER)
81
82 DX_KIND_DECLARE(base);
83 DX_KIND_DECLARE(request);
84 DX_KIND_DECLARE_FULL(session);
85 DX_KIND_DECLARE_FULL(getaddrinfo_request);
86
87 typedef union {
88 dx_base_t base;
89 dx_session_t session;
90 dx_request_t request;
91 dx_getaddrinfo_request_t getaddrinfo_request;
92 } dx_any_t __attribute__((__transparent_union__));
93
94 typedef void (*dx_invalidate_f)(dx_any_t object);
95 typedef void (*dx_finalize_f)(dx_any_t object);
96
97 typedef const struct dx_kind_s * dx_kind_t;
98 struct dx_kind_s {
99 dx_kind_t superkind; // This kind's superkind. All kinds have a superkind, except the base kind.
100 dx_invalidate_f invalidate; // Stops an object's outstanding operations, if any.
101 dx_finalize_f finalize; // Releases object's resources right before the object is freed.
102 };
103
104 #if 0
105 //======================================================================================================================
106 #pragma mark - Base Kind Definition
107 #endif
108
109 struct dx_base_s {
110 dx_kind_t kind; // The object's kind.
111 int32_t ref_count; // Reference count.
112 };
113
114 static const struct dx_kind_s _dx_base_kind = {
115 NULL, // No superkind.
116 NULL, // No invalidate method.
117 NULL, // No finalize method.
118 };
119
120 #if 0
121 //======================================================================================================================
122 #pragma mark - Request Kind Definition
123 #endif
124
125 struct dx_request_s {
126 struct dx_base_s base; // Object base.
127 dx_request_t next; // Next request in list.
128 xpc_object_t result_array; // Array of pending results.
129 uint64_t command_id; // ID to distinquish multiple commands during a session.
130 uint32_t request_id; // Request ID, used for logging purposes.
131 DNSServiceErrorType error; // Pending error.
132 bool sent_error; // True if the pending error has been sent to client.
133 };
134
135 static void
136 _dx_request_finalize(dx_any_t request);
137
138 static const struct dx_kind_s _dx_request_kind = {
139 &_dx_base_kind,
140 NULL, // No invalidate method.
141 _dx_request_finalize,
142 };
143 DX_BASE_CHECK(request, base);
144
145 #if 0
146 //======================================================================================================================
147 #pragma mark - Session Kind Definition
148 #endif
149
150 struct dx_session_s {
151 struct dx_base_s base; // Object base;
152 dx_session_t next; // Next session in list.
153 dx_request_t request_list; // List of outstanding requests.
154 xpc_connection_t connection; // Underlying XPC connection.
155 bool has_delegate_entitlement; // True if the client is entitled to be a delegate.
156 };
157
158 DX_KIND_DEFINE(session, base);
159
160 #if 0
161 //======================================================================================================================
162 #pragma mark - GetAddrInfo Request Kind Definition
163 #endif
164
165 struct dx_getaddrinfo_request_s {
166 struct dx_request_s base; // Request object base.
167 GetAddrInfoClientRequest gai; // Underlying GetAddrInfoClientRequest.
168 xpc_object_t hostname; // Hostname to be resolved for getaddrinfo requests.
169 uuid_t client_uuid; // Client's UUID for authenticating results.
170 bool need_auth; // True if results need to be authenticated.
171 bool active; // True if the GetAddrInfoClientRequest is currently active.
172 };
173
174 DX_KIND_DEFINE(getaddrinfo_request, request);
175
176 #if 0
177 //======================================================================================================================
178 #pragma mark - Local Prototypes
179 #endif
180
181 static dispatch_queue_t
182 _dx_server_queue(void);
183
184 static void
185 _dx_server_register_session(dx_session_t session);
186
187 static void
188 _dx_server_deregister_session(dx_session_t session);
189
190 static void
191 _dx_retain(dx_any_t object);
192
193 static void
194 _dx_release(dx_any_t object);
195 #define _dx_release_null_safe(X) do { if (X) { _dx_release(X); } } while (0)
196
197 static void
198 _dx_invalidate(dx_any_t object);
199
200 static dx_session_t
201 _dx_session_create(xpc_connection_t connection);
202
203 static void
204 _dx_session_activate(dx_session_t me);
205
206 static DNSServiceErrorType
207 _dx_session_handle_getaddrinfo_command(dx_session_t session, xpc_object_t msg);
208
209 static DNSServiceErrorType
210 _dx_session_handle_stop_command(dx_session_t session, xpc_object_t msg);
211
212 static void
213 _dx_session_send_results(dx_session_t session);
214
215 static dx_getaddrinfo_request_t
216 _dx_getaddrinfo_request_create(uint64_t command_id, uint32_t request_id);
217
218 static DNSServiceErrorType
219 _dx_getaddrinfo_request_set_hostname(dx_getaddrinfo_request_t request, xpc_object_t hostname);
220
221 static void
222 _dx_getaddrinfo_request_set_need_authenticaed_results(dx_getaddrinfo_request_t request, bool need,
223 const uuid_t client_uuid);
224
225 static DNSServiceErrorType
226 _dx_getaddrinfo_request_activate(dx_getaddrinfo_request_t request, uint32_t interface_index, DNSServiceFlags flags,
227 DNSServiceProtocol protocols, pid_t pid, const uuid_t uuid, uid_t uid);
228
229 static void
230 _dx_getaddrinfo_request_result_handler(mDNS *m, DNSQuestion *question, const ResourceRecord *answer,
231 QC_result qc_result, DNSServiceErrorType error, void *context);
232
233 #if 0
234 //======================================================================================================================
235 #pragma mark - Server Functions
236 #endif
237
238 static void
239 _dx_server_handle_new_connection(xpc_connection_t connection);
240
241 mDNSexport void
242 dnssd_server_init(void)
243 {
244 static xpc_connection_t listener = NULL;
245
246 listener = xpc_connection_create_mach_service(DNSSD_MACH_SERVICE_NAME, _dx_server_queue(),
247 XPC_CONNECTION_MACH_SERVICE_LISTENER);
248 xpc_connection_set_event_handler(listener,
249 ^(xpc_object_t event)
250 {
251 if (xpc_get_type(event) == XPC_TYPE_CONNECTION) {
252 _dx_server_handle_new_connection((xpc_connection_t)event);
253 }
254 });
255 xpc_connection_activate(listener);
256 }
257
258 static void
259 _dx_server_handle_new_connection(xpc_connection_t connection)
260 {
261 const dx_session_t session = _dx_session_create(connection);
262 if (session) {
263 _dx_session_activate(session);
264 _dx_server_register_session(session);
265 _dx_release(session);
266 } else {
267 xpc_connection_cancel(connection);
268 }
269 }
270
271
272 //======================================================================================================================
273
274 static dx_session_t g_session_list = NULL;
275
276 mDNSexport void
277 dnssd_server_idle(void)
278 {
279 for (dx_session_t session = g_session_list; session; session = session->next) {
280 _dx_session_send_results(session);
281 }
282 }
283
284 //======================================================================================================================
285
286 static dispatch_queue_t
287 _dx_server_queue(void)
288 {
289 static dispatch_once_t once = 0;
290 static dispatch_queue_t queue = NULL;
291
292 dispatch_once(&once,
293 ^{
294 const dispatch_queue_attr_t attr = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL,
295 QOS_CLASS_UTILITY, 0);
296 queue = dispatch_queue_create("com.apple.dnssd.server", attr);
297 });
298 return queue;
299 }
300
301 //======================================================================================================================
302
303 static void
304 _dx_server_register_session(dx_session_t session)
305 {
306 session->next = g_session_list;
307 g_session_list = session;
308 _dx_retain(session);
309 }
310
311 //======================================================================================================================
312
313 static void
314 _dx_server_deregister_session(dx_session_t session)
315 {
316 dx_session_t *ptr;
317 for (ptr = &g_session_list; *ptr; ptr = &(*ptr)->next) {
318 if (*ptr == session) {
319 break;
320 }
321 }
322 if (*ptr) {
323 *ptr = session->next;
324 session->next = NULL;
325 _dx_release(session);
326 }
327 }
328
329 #if 0
330 //======================================================================================================================
331 #pragma mark - Base Methods
332 #endif
333
334 static void
335 _dx_retain(dx_any_t object)
336 {
337 ++object.base->ref_count;
338 }
339
340 //======================================================================================================================
341
342 static void
343 _dx_release(dx_any_t object)
344 {
345 if (--object.base->ref_count == 0) {
346 for (dx_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
347 if (kind->finalize) {
348 kind->finalize(object);
349 }
350 }
351 free(object.base);
352 }
353 }
354
355 //======================================================================================================================
356
357 static void
358 _dx_invalidate(dx_any_t object)
359 {
360 for (dx_kind_t kind = object.base->kind; kind; kind = kind->superkind) {
361 if (kind->invalidate) {
362 kind->invalidate(object);
363 return;
364 }
365 }
366 }
367
368 #if 0
369 //======================================================================================================================
370 #pragma mark - Session Methods
371 #endif
372
373 static dx_session_t
374 _dx_session_create(xpc_connection_t connection)
375 {
376 const dx_session_t obj = _dx_session_alloc();
377 require_quiet(obj, exit);
378
379 obj->connection = connection;
380 xpc_retain(obj->connection);
381
382 exit:
383 return obj;
384 }
385
386 //======================================================================================================================
387
388 static void
389 _dx_session_handle_message(dx_session_t session, xpc_object_t msg);
390
391 #define DNSSD_DELEGATE_ENTITLEMENT "com.apple.private.network.socket-delegate"
392
393 static void
394 _dx_session_activate(dx_session_t me)
395 {
396 const xpc_object_t value = xpc_connection_copy_entitlement_value(me->connection, DNSSD_DELEGATE_ENTITLEMENT);
397 if (value) {
398 if (value == XPC_BOOL_TRUE) {
399 me->has_delegate_entitlement = true;
400 }
401 xpc_release(value);
402 }
403 _dx_retain(me);
404 xpc_connection_set_target_queue(me->connection, _dx_server_queue());
405 xpc_connection_set_event_handler(me->connection,
406 ^(xpc_object_t event) {
407 const xpc_type_t type = xpc_get_type(event);
408 if (type == XPC_TYPE_DICTIONARY) {
409 KQueueLock();
410 _dx_session_handle_message(me, event);
411 KQueueUnlock("_dx_session_handle_message");
412 } else if (event == XPC_ERROR_CONNECTION_INVALID) {
413 KQueueLock();
414 _dx_server_deregister_session(me);
415 KQueueUnlock("_dx_server_deregister_session");
416 _dx_session_invalidate(me);
417 _dx_release(me);
418 } else {
419 xpc_connection_cancel(me->connection);
420 }
421 });
422 xpc_connection_activate(me->connection);
423 }
424
425 static void
426 _dx_session_handle_message(dx_session_t me, xpc_object_t msg)
427 {
428 DNSServiceErrorType error;
429 const char * const command = dnssd_xpc_message_get_command(msg);
430 require_action_quiet(command, exit, error = kDNSServiceErr_BadParam);
431
432 if (strcmp(command, DNSSD_COMMAND_GETADDRINFO) == 0) {
433 error = _dx_session_handle_getaddrinfo_command(me, msg);
434 } else if (strcmp(command, DNSSD_COMMAND_STOP) == 0) {
435 error = _dx_session_handle_stop_command(me, msg);
436 } else {
437 error = kDNSServiceErr_BadParam;
438 }
439
440 exit:
441 {
442 const xpc_object_t reply = xpc_dictionary_create_reply(msg);
443 if (likely(reply)) {
444 dnssd_xpc_message_set_error(reply, error);
445 xpc_connection_send_message(me->connection, reply);
446 xpc_release(reply);
447 } else {
448 xpc_connection_cancel(me->connection);
449 }
450 }
451 }
452
453 //======================================================================================================================
454
455 static void
456 _dx_session_invalidate(dx_session_t me)
457 {
458 xpc_connection_forget(&me->connection);
459 dx_request_t req;
460 while ((req = me->request_list) != NULL)
461 {
462 me->request_list = req->next;
463 _dx_invalidate(req);
464 _dx_release(req);
465 }
466 }
467
468 //======================================================================================================================
469
470 static void
471 _dx_session_finalize(dx_session_t me)
472 {
473 (void)me;
474 }
475
476 //======================================================================================================================
477
478 static bool
479 _dx_get_getaddrinfo_params(xpc_object_t msg, uint64_t *out_command_id, xpc_object_t *out_hostname,
480 uint32_t *out_interface_index, DNSServiceFlags *out_flags, DNSServiceProtocol *out_protocols,
481 pid_t *out_delegate_pid, const uint8_t **out_delegate_uuid, bool *out_need_auth_tags);
482
483 extern mDNS mDNSStorage;
484 #define g_mdns mDNSStorage
485
486 static DNSServiceErrorType
487 _dx_session_handle_getaddrinfo_command(dx_session_t me, xpc_object_t msg)
488 {
489 dx_getaddrinfo_request_t req = NULL;
490 DNSServiceErrorType error;
491 uint64_t command_id;
492 xpc_object_t hostname;
493 uint32_t interface_index;
494 DNSServiceFlags flags;
495 DNSServiceProtocol protocols;
496 pid_t pid;
497 const uint8_t * uuid;
498 bool need_auth;
499
500 const bool valid = _dx_get_getaddrinfo_params(msg, &command_id, &hostname, &interface_index, &flags, &protocols,
501 &pid, &uuid, &need_auth);
502 require_action_quiet(valid, exit, error = kDNSServiceErr_BadParam);
503
504 if (uuid || (pid != 0)) {
505 require_action_quiet(me->has_delegate_entitlement, exit, error = kDNSServiceErr_NoAuth);
506 } else {
507 pid = xpc_connection_get_pid(me->connection);
508 }
509
510 req = _dx_getaddrinfo_request_create(command_id, g_mdns.next_request_id++);
511 require_action_quiet(req, exit, error = kDNSServiceErr_NoMemory);
512
513 error = _dx_getaddrinfo_request_set_hostname(req, hostname);
514 require_noerr_quiet(error, exit);
515
516 if (need_auth) {
517 struct proc_uniqidentifierinfo info;
518 const int n = proc_pidinfo(pid, PROC_PIDUNIQIDENTIFIERINFO, 1, &info, sizeof(info));
519 if (n == (int)sizeof(info)) {
520 _dx_getaddrinfo_request_set_need_authenticaed_results(req, true, info.p_uuid);
521 }
522 }
523
524 const uid_t euid = xpc_connection_get_euid(me->connection);
525 error = _dx_getaddrinfo_request_activate(req, interface_index, flags, protocols, pid, uuid, euid);
526 require_noerr_quiet(error, exit);
527
528 req->base.next = me->request_list;
529 me->request_list = (dx_request_t)req;
530 req = NULL;
531
532 exit:
533 _dx_release_null_safe(req);
534 static_analyzer_malloc_freed(req);
535 return error;
536 }
537
538 static bool
539 _dx_get_getaddrinfo_params(xpc_object_t msg, uint64_t *out_command_id, xpc_object_t *out_hostname,
540 uint32_t *out_interface_index, DNSServiceFlags *out_flags, DNSServiceProtocol *out_protocols,
541 pid_t *out_delegate_pid, const uint8_t **out_delegate_uuid, bool *out_need_auth_tags)
542 {
543 bool params_are_valid = false;
544 bool valid;
545 const uint64_t command_id = dnssd_xpc_message_get_id(msg, &valid);
546 require_quiet(valid, exit);
547
548 const xpc_object_t params = dnssd_xpc_message_get_parameters(msg);
549 require_quiet(params, exit);
550
551 xpc_object_t hostname = dnssd_xpc_parameters_get_hostname_object(params);
552 require_quiet(hostname, exit);
553
554 const uint32_t interface_index = dnssd_xpc_parameters_get_interface_index(params, &valid);
555 require_quiet(valid, exit);
556
557 const DNSServiceFlags flags = dnssd_xpc_parameters_get_flags(params, &valid);
558 require_quiet(valid, exit);
559
560 const uint32_t protocols = dnssd_xpc_parameters_get_protocols(params, &valid);
561 require_quiet(valid, exit);
562
563 pid_t pid;
564 const uint8_t * const uuid = dnssd_xpc_parameters_get_delegate_uuid(params);
565 if (uuid) {
566 pid = 0;
567 } else {
568 pid = dnssd_xpc_parameters_get_delegate_pid(params, NULL);
569 }
570
571 *out_command_id = command_id;
572 *out_hostname = hostname;
573 *out_interface_index = interface_index;
574 *out_flags = flags;
575 *out_protocols = protocols;
576 *out_delegate_pid = pid;
577 *out_delegate_uuid = uuid;
578 *out_need_auth_tags = dnssd_xpc_parameters_get_need_authentication_tags(params);
579 params_are_valid = true;
580
581 exit:
582 return params_are_valid;
583 }
584
585 //======================================================================================================================
586
587 static DNSServiceErrorType
588 _dx_session_handle_stop_command(dx_session_t me, xpc_object_t msg)
589 {
590 bool valid;
591 DNSServiceErrorType error;
592 const uint64_t command_id = dnssd_xpc_message_get_id(msg, &valid);
593 require_action_quiet(valid, exit, error = kDNSServiceErr_BadParam);
594
595 dx_request_t * ptr;
596 dx_request_t req;
597 for (ptr = &me->request_list; (req = *ptr) != NULL; ptr = &req->next) {
598 if (req->command_id == command_id) {
599 break;
600 }
601 }
602 require_action_quiet(req, exit, error = kDNSServiceErr_BadReference);
603
604 *ptr = req->next;
605 req->next = NULL;
606
607 _dx_invalidate(req);
608 _dx_release(req);
609 error = kDNSServiceErr_NoError;
610
611 exit:
612 return error;
613 }
614
615 //======================================================================================================================
616
617 static void
618 _dx_session_send_results(dx_session_t me)
619 {
620 bool success = false;
621 for (dx_request_t req = me->request_list; req; req = req->next) {
622 if (req->result_array && (xpc_array_get_count(req->result_array) > 0)) {
623 const xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
624 require_quiet(msg, exit);
625
626 dnssd_xpc_message_set_id(msg, req->command_id);
627 dnssd_xpc_message_set_error(msg, kDNSServiceErr_NoError);
628 dnssd_xpc_message_set_results(msg, req->result_array);
629 xpc_connection_send_message(me->connection, msg);
630 xpc_release(msg);
631
632 xpc_release(req->result_array);
633 req->result_array = xpc_array_create(NULL, 0);
634 require_quiet(req->result_array, exit);
635 }
636 if (req->error && !req->sent_error) {
637 const xpc_object_t msg = xpc_dictionary_create(NULL, NULL, 0);
638 require_quiet(msg, exit);
639
640 dnssd_xpc_message_set_id(msg, req->command_id);
641 dnssd_xpc_message_set_error(msg, req->error);
642 xpc_connection_send_message(me->connection, msg);
643 xpc_release(msg);
644 req->sent_error = true;
645 }
646 }
647 success = true;
648
649 exit:
650 if (unlikely(!success)) {
651 xpc_connection_cancel(me->connection);
652 }
653 }
654
655 #if 0
656 //======================================================================================================================
657 #pragma mark - Request Methods
658 #endif
659
660 static void
661 _dx_request_finalize(dx_request_t me)
662 {
663 xpc_forget(&me->result_array);
664 }
665
666 #if 0
667 //======================================================================================================================
668 #pragma mark - GetAddrInfo Request Methods
669 #endif
670
671 static dx_getaddrinfo_request_t
672 _dx_getaddrinfo_request_create(uint64_t command_id, uint32_t request_id)
673 {
674 dx_getaddrinfo_request_t req = NULL;
675 dx_getaddrinfo_request_t obj = _dx_getaddrinfo_request_alloc();
676 require_quiet(obj, exit);
677
678 obj->base.command_id = command_id;
679 obj->base.request_id = request_id;
680 obj->base.result_array = xpc_array_create(NULL, 0);
681 require_quiet(obj->base.result_array, exit);
682
683 req = obj;
684 obj = NULL;
685
686 exit:
687 _dx_release_null_safe(obj);
688 return req;
689 }
690
691 //======================================================================================================================
692
693 static DNSServiceErrorType
694 _dx_getaddrinfo_request_set_hostname(dx_getaddrinfo_request_t me, xpc_object_t hostname)
695 {
696 DNSServiceErrorType err;
697 require_action_quiet(xpc_string_get_length(hostname) <= MAX_ESCAPED_DOMAIN_NAME, exit,
698 err = kDNSServiceErr_BadParam);
699
700 xpc_release_null_safe(me->hostname);
701 me->hostname = xpc_copy(hostname);
702 require_action_quiet(me->hostname, exit, err = kDNSServiceErr_NoMemory);
703
704 err = kDNSServiceErr_NoError;
705
706 exit:
707 return err;
708 }
709
710 //======================================================================================================================
711
712 static void
713 _dx_getaddrinfo_request_set_need_authenticaed_results(dx_getaddrinfo_request_t me, bool need, const uuid_t client_uuid)
714 {
715 if (need) {
716 uuid_copy(me->client_uuid, client_uuid);
717 me->need_auth = true;
718 } else {
719 uuid_clear(me->client_uuid);
720 me->need_auth = false;
721 }
722 }
723
724 //======================================================================================================================
725
726 static DNSServiceErrorType
727 _dx_getaddrinfo_request_activate(dx_getaddrinfo_request_t me, uint32_t interface_index, DNSServiceFlags flags,
728 DNSServiceProtocol protocols, pid_t pid, const uuid_t uuid, uid_t uid)
729 {
730 DNSServiceErrorType err;
731 const char * const hostname_str = xpc_string_get_string_ptr(me->hostname);
732 require_action_quiet(hostname_str, exit, err = kDNSServiceErr_Unknown);
733
734 err = GetAddrInfoClientRequestStart(&me->gai, me->base.request_id, hostname_str, interface_index, flags,
735 protocols, pid, uuid, uid, _dx_getaddrinfo_request_result_handler, me);
736 require_noerr_quiet(err, exit);
737
738 _dx_retain(me);
739 me->active = true;
740
741 exit:
742 return err;
743 }
744
745 //======================================================================================================================
746
747 static void
748 _dx_getaddrinfo_request_invalidate(dx_getaddrinfo_request_t me)
749 {
750 if (me->active) {
751 GetAddrInfoClientRequestStop(&me->gai);
752 me->active = false;
753 _dx_release(me);
754 }
755 }
756
757 //======================================================================================================================
758
759 static void
760 _dx_getaddrinfo_request_finalize(dx_getaddrinfo_request_t me)
761 {
762 xpc_forget(&me->hostname);
763 }
764
765 //======================================================================================================================
766
767 #if defined(NECP_CLIENT_ACTION_SIGN)
768 #define DNSSD_AUTHENTICATION_TAG_SIZE 32 // XXX: Defined as a workaround until NECP header defines this length.
769
770 static bool
771 _dx_authenticate_answer(uuid_t client_id, xpc_object_t hostname, int record_type, const void *record_data,
772 uint8_t out_auth_tag[STATIC_PARAM DNSSD_AUTHENTICATION_TAG_SIZE]);
773 #endif
774
775 static void
776 _dx_getaddrinfo_request_result_handler(mDNS *m, DNSQuestion *question, const ResourceRecord *answer,
777 QC_result qc_result, DNSServiceErrorType error, void *context)
778 {
779 (void)question;
780
781 const dx_getaddrinfo_request_t me = (dx_getaddrinfo_request_t)context;
782 if (error && (error != kDNSServiceErr_NoSuchRecord)) {
783 if (!me->base.error) {
784 me->base.error = error;
785 }
786 goto exit;
787 }
788 require_quiet((answer->rrtype == kDNSServiceType_A) || (answer->rrtype == kDNSServiceType_AAAA), exit);
789
790 const void * rdata_ptr;
791 size_t rdata_len;
792 if (!error) {
793 if (answer->rrtype == kDNSServiceType_A) {
794 rdata_ptr = answer->rdata->u.ipv4.b;
795 rdata_len = 4;
796 } else {
797 rdata_ptr = answer->rdata->u.ipv6.b;
798 rdata_len = 16;
799 }
800 } else {
801 rdata_ptr = NULL;
802 rdata_len = 0;
803 }
804
805 DNSServiceFlags flags = 0;
806 if (qc_result != QC_rmv) {
807 flags |= kDNSServiceFlagsAdd;
808 }
809 if (answer->mortality == Mortality_Ghost) {
810 flags |= kDNSServiceFlagsExpiredAnswer;
811 }
812 if (!question->InitialCacheMiss) {
813 flags |= kDNSServiceFlagAnsweredFromCache;
814 }
815
816 const uint32_t interface_index = mDNSPlatformInterfaceIndexfromInterfaceID(m, answer->InterfaceID, mDNStrue);
817 const xpc_object_t result = xpc_dictionary_create(NULL, NULL, 0);
818 if (likely(result)) {
819 char name_str[MAX_ESCAPED_DOMAIN_NAME];
820 ConvertDomainNameToCString(answer->name, name_str);
821
822 dnssd_xpc_result_set_error(result, error);
823 dnssd_xpc_result_set_flags(result, flags);
824 dnssd_xpc_result_set_interface_index(result, interface_index);
825 dnssd_xpc_result_set_record_name(result, name_str);
826 dnssd_xpc_result_set_record_type(result, answer->rrtype);
827 dnssd_xpc_result_set_record_class(result, answer->rrclass);
828 dnssd_xpc_result_set_record_data(result, rdata_ptr, rdata_len);
829
830 #if defined(NECP_CLIENT_ACTION_SIGN)
831 if (me->need_auth && !error && (flags & kDNSServiceFlagsAdd)) {
832 uint8_t auth_tag[DNSSD_AUTHENTICATION_TAG_SIZE];
833 const bool success = _dx_authenticate_answer(me->client_uuid, me->hostname, answer->rrtype, rdata_ptr,
834 auth_tag);
835 if (success) {
836 dnssd_xpc_result_set_authentication_tag(result, auth_tag, sizeof(auth_tag));
837 }
838 }
839 #endif
840 xpc_array_append_value(me->base.result_array, result);
841 xpc_release(result);
842 } else {
843 me->base.error = kDNSServiceErr_NoMemory;
844 }
845
846 exit:
847 return;
848 }
849
850 #if defined(NECP_CLIENT_ACTION_SIGN)
851 typedef struct {
852 struct necp_client_resolver_answer hdr;
853 uint8_t hostname[MAX_ESCAPED_DOMAIN_NAME];
854 } dx_necp_answer_t;
855
856 check_compile_time(offsetof(dx_necp_answer_t, hdr) == 0);
857 check_compile_time(endof_field(struct necp_client_resolver_answer, hostname_length) == offsetof(dx_necp_answer_t, hostname));
858
859 static bool
860 _dx_authenticate_answer(uuid_t client_id, xpc_object_t hostname, int record_type, const void *record_data,
861 uint8_t out_auth_tag[STATIC_PARAM DNSSD_AUTHENTICATION_TAG_SIZE])
862 {
863 static int necp_fd = -1;
864
865 bool success = false;
866 if (necp_fd < 0) {
867 necp_fd = necp_open(0);
868 }
869 require_quiet(necp_fd >= 0, exit);
870
871 dx_necp_answer_t answer;
872 memset(&answer, 0, sizeof(answer));
873
874 struct necp_client_resolver_answer * const hdr = &answer.hdr;
875 uuid_copy(hdr->client_id, client_id);
876
877 hdr->sign_type = NECP_CLIENT_SIGN_TYPE_RESOLVER_ANSWER;
878
879 switch (record_type) {
880 case kDNSServiceType_A:
881 hdr->address_answer.sa.sa_family = AF_INET;
882 hdr->address_answer.sa.sa_len = sizeof(struct sockaddr_in);
883 memcpy(&hdr->address_answer.sin.sin_addr.s_addr, record_data, 4);
884 break;
885
886 case kDNSServiceType_AAAA:
887 hdr->address_answer.sa.sa_family = AF_INET6;
888 hdr->address_answer.sa.sa_len = sizeof(struct sockaddr_in6);
889 memcpy(hdr->address_answer.sin6.sin6_addr.s6_addr, record_data, 16);
890 break;
891
892 default:
893 goto exit;
894 }
895 const size_t hostname_len = xpc_string_get_length(hostname);
896 require_quiet(hostname_len <= sizeof(answer.hostname), exit);
897
898 hdr->hostname_length = (uint32_t)hostname_len;
899 memcpy(answer.hostname, xpc_string_get_string_ptr(hostname), hdr->hostname_length);
900
901 const int necp_err = necp_client_action(necp_fd, NECP_CLIENT_ACTION_SIGN, (void *)&answer,
902 sizeof(answer.hdr) + hdr->hostname_length, out_auth_tag, DNSSD_AUTHENTICATION_TAG_SIZE);
903 require_noerr_quiet(necp_err, exit);
904
905 success = true;
906
907 exit:
908 return success;
909 }
910 #endif // defined(NECP_CLIENT_ACTION_SIGN)