]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/helper-stubs.c
mDNSResponder-1310.80.1.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / helper-stubs.c
1 /*
2 * Copyright (c) 2007-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 <mach/mach.h>
18 #include <mach/mach_error.h>
19 #include <mach/vm_map.h>
20 #include <servers/bootstrap.h>
21 #include <IOKit/IOReturn.h>
22 #include <CoreFoundation/CoreFoundation.h>
23 #include "helper.h"
24 #include <dispatch/dispatch.h>
25 #include <arpa/inet.h>
26 #include <xpc/private.h>
27 #include <Block.h>
28
29 //
30 // Implementation Notes about the HelperQueue:
31 //
32 // To prevent blocking the main queue, all communications with mDNSResponderHelper should happen on
33 // HelperQueue. There are a few calls which are still synchronous and needs to be handled separately
34 // case by case.
35 //
36 // When spawning off the work to the HelperQueue, any arguments that are pointers need to be copied
37 // explicitly as they may cease to exist after the call returns. From within the block that is scheduled,
38 // arrays defined on the stack can't be referenced and hence it is enclosed them in a struct. If the array is
39 // an argument to the function, the blocks can reference them as they are passed in as pointers. But care should
40 // be taken to copy them locally as they may cease to exist when the function returns.
41 //
42
43
44 //*************************************************************************************************************
45 // Globals
46 static dispatch_queue_t HelperQueue;
47
48 static int64_t maxwait_secs = 5LL;
49
50 #define mDNSHELPER_DEBUG LogOperation
51
52 //*************************************************************************************************************
53 // Utility Functions
54
55 static void HelperLog(const char *prefix, xpc_object_t o)
56 {
57 char *desc = xpc_copy_description(o);
58 mDNSHELPER_DEBUG("HelperLog %s: %s", prefix, desc);
59 free(desc);
60 }
61
62 //*************************************************************************************************************
63 // XPC Funcs:
64 //*************************************************************************************************************
65
66
67 mDNSlocal xpc_connection_t Create_Connection(void)
68 {
69 xpc_connection_t connection = xpc_connection_create_mach_service(kHelperService, HelperQueue,
70 XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
71 if (connection)
72 {
73 xpc_connection_set_event_handler(connection, ^(xpc_object_t event)
74 {
75 mDNSHELPER_DEBUG("Create_Connection xpc: [%s] \n", xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
76 });
77 xpc_connection_activate(connection);
78 }
79 return connection;
80 }
81
82 mDNSlocal int SendDict_ToServer(xpc_object_t msg, xpc_object_t *out_reply)
83 {
84 xpc_connection_t connection;
85 dispatch_semaphore_t sem = NULL;
86 __block xpc_object_t reply = NULL;
87 __block int errorcode = kHelperErr_NoResponse;
88
89 HelperLog("SendDict_ToServer Sending msg to Daemon", msg);
90
91 connection = Create_Connection();
92 if (!connection)
93 {
94 goto exit;
95 }
96
97 sem = dispatch_semaphore_create(0);
98 if (!sem)
99 {
100 goto exit;
101 }
102
103 dispatch_retain(sem); // for the block below
104 xpc_connection_send_message_with_reply(connection, msg, HelperQueue, ^(xpc_object_t recv_msg)
105 {
106 const xpc_type_t type = xpc_get_type(recv_msg);
107
108 if (type == XPC_TYPE_DICTIONARY)
109 {
110 HelperLog("SendDict_ToServer Received reply msg from Daemon", recv_msg);
111 uint64_t reply_status = xpc_dictionary_get_uint64(recv_msg, kHelperReplyStatus);
112 errorcode = (int)xpc_dictionary_get_int64(recv_msg, kHelperErrCode);
113
114 switch (reply_status)
115 {
116 case kHelperReply_ACK:
117 mDNSHELPER_DEBUG("NoError: successful reply");
118 break;
119 default:
120 LogMsg("default: Unexpected reply from Helper");
121 break;
122 }
123 reply = recv_msg;
124 xpc_retain(reply);
125 }
126 else
127 {
128 LogMsg("SendDict_ToServer Received unexpected reply from daemon [%s]",
129 xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION));
130 HelperLog("SendDict_ToServer Unexpected Reply contents", recv_msg);
131 }
132
133 dispatch_semaphore_signal(sem);
134 dispatch_release(sem);
135 });
136
137 if (dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, (maxwait_secs * NSEC_PER_SEC))) != 0)
138 {
139 LogMsg("SendDict_ToServer: UNEXPECTED WAIT_TIME in dispatch_semaphore_wait");
140
141 // If we insist on using a semaphore timeout, then cancel the connection if the timeout is reached.
142 // This forces the reply block to be called if a reply wasn't received to keep things serialized.
143 xpc_connection_cancel(connection);
144 dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER);
145 }
146 if (out_reply)
147 {
148 *out_reply = reply;
149 reply = NULL;
150 }
151
152 mDNSHELPER_DEBUG("SendDict_ToServer returning with errorcode[%d]", errorcode);
153
154 exit:
155 if (connection)
156 {
157 xpc_connection_cancel(connection);
158 xpc_release(connection);
159 }
160 if (sem)
161 {
162 dispatch_release(sem);
163 }
164 if (reply)
165 {
166 xpc_release(reply);
167 }
168 return errorcode;
169 }
170
171 //**************************************************************************************************************
172
173 mDNSexport mStatus mDNSHelperInit()
174 {
175 HelperQueue = dispatch_queue_create("com.apple.mDNSResponder.HelperQueue", NULL);
176 if (HelperQueue == NULL)
177 {
178 LogMsg("dispatch_queue_create: Helper queue NULL");
179 return mStatus_NoMemoryErr;
180 }
181 return mStatus_NoError;
182 }
183
184 void mDNSPreferencesSetName(int key, domainlabel *old, domainlabel *new)
185 {
186 struct
187 {
188 char oldname[MAX_DOMAIN_LABEL+1];
189 char newname[MAX_DOMAIN_LABEL+1];
190 } names;
191
192 mDNSPlatformMemZero(names.oldname, MAX_DOMAIN_LABEL + 1);
193 mDNSPlatformMemZero(names.newname, MAX_DOMAIN_LABEL + 1);
194
195 ConvertDomainLabelToCString_unescaped(old, names.oldname);
196
197 if (new)
198 ConvertDomainLabelToCString_unescaped(new, names.newname);
199
200
201 mDNSHELPER_DEBUG("mDNSPreferencesSetName: XPC IPC Test oldname %s newname %s", names.oldname, names.newname);
202
203 // Create Dictionary To Send
204 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
205 xpc_dictionary_set_uint64(dict, kHelperMode, set_name);
206
207 xpc_dictionary_set_uint64(dict, kPrefsNameKey, key);
208 xpc_dictionary_set_string(dict, kPrefsOldName, names.oldname);
209 xpc_dictionary_set_string(dict, kPrefsNewName, names.newname);
210
211 SendDict_ToServer(dict, NULL);
212 xpc_release(dict);
213 dict = NULL;
214
215 }
216
217 void mDNSRequestBPF()
218 {
219 mDNSHELPER_DEBUG("mDNSRequestBPF: Using XPC IPC");
220
221 // Create Dictionary To Send
222 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
223 xpc_dictionary_set_uint64(dict, kHelperMode, bpf_request);
224 SendDict_ToServer(dict, NULL);
225 xpc_release(dict);
226 dict = NULL;
227
228 }
229
230 int mDNSPowerRequest(int key, int interval)
231 {
232 int err_code = kHelperErr_NotConnected;
233
234 mDNSHELPER_DEBUG("mDNSPowerRequest: Using XPC IPC calling out to Helper key is [%d] interval is [%d]", key, interval);
235
236 // Create Dictionary To Send
237 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
238 xpc_dictionary_set_uint64(dict, kHelperMode, power_req);
239 xpc_dictionary_set_uint64(dict, "powerreq_key", key);
240 xpc_dictionary_set_uint64(dict, "powerreq_interval", interval);
241
242 err_code = SendDict_ToServer(dict, NULL);
243 xpc_release(dict);
244 dict = NULL;
245
246 mDNSHELPER_DEBUG("mDNSPowerRequest: Using XPC IPC returning error_code %d", err_code);
247 return err_code;
248 }
249
250 int mDNSSetLocalAddressCacheEntry(int ifindex, int family, const v6addr_t ip, const ethaddr_t eth)
251 {
252 int err_code = kHelperErr_NotConnected;
253
254 mDNSHELPER_DEBUG("mDNSSetLocalAddressCacheEntry: Using XPC IPC calling out to Helper: ifindex is [%d] family is [%d]", ifindex, family);
255
256 // Create Dictionary To Send
257 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
258 xpc_dictionary_set_uint64(dict, kHelperMode, set_localaddr_cacheentry);
259
260 xpc_dictionary_set_uint64(dict, "slace_ifindex", ifindex);
261 xpc_dictionary_set_uint64(dict, "slace_family", family);
262
263 xpc_dictionary_set_data(dict, "slace_ip", (uint8_t*)ip, sizeof(v6addr_t));
264 xpc_dictionary_set_data(dict, "slace_eth", (uint8_t*)eth, sizeof(ethaddr_t));
265
266 err_code = SendDict_ToServer(dict, NULL);
267 xpc_release(dict);
268 dict = NULL;
269
270 mDNSHELPER_DEBUG("mDNSSetLocalAddressCacheEntry: Using XPC IPC returning error_code %d", err_code);
271 return err_code;
272 }
273
274
275 void mDNSNotify(const char *title, const char *msg) // Both strings are UTF-8 text
276 {
277 mDNSHELPER_DEBUG("mDNSNotify() calling out to Helper XPC IPC title[%s] msg[%s]", title, msg);
278
279 // Create Dictionary To Send
280 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
281 xpc_dictionary_set_uint64(dict, kHelperMode, user_notify);
282
283 xpc_dictionary_set_string(dict, "notify_title", title);
284 xpc_dictionary_set_string(dict, "notify_msg", msg);
285
286 SendDict_ToServer(dict, NULL);
287 xpc_release(dict);
288 dict = NULL;
289
290 }
291
292
293 int mDNSKeychainGetSecrets(CFArrayRef *result)
294 {
295
296 CFPropertyListRef plist = NULL;
297 CFDataRef bytes = NULL;
298 uint64_t numsecrets = 0;
299 size_t secretsCnt = 0;
300 int error_code = kHelperErr_NotConnected;
301 xpc_object_t reply_dict = NULL;
302 const void *sec = NULL;
303
304 mDNSHELPER_DEBUG("mDNSKeychainGetSecrets: Using XPC IPC calling out to Helper");
305
306 // Create Dictionary To Send
307 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
308 xpc_dictionary_set_uint64(dict, kHelperMode, keychain_getsecrets);
309
310 SendDict_ToServer(dict, &reply_dict);
311
312 if (reply_dict != NULL)
313 {
314 numsecrets = xpc_dictionary_get_uint64(reply_dict, "keychain_num_secrets");
315 sec = xpc_dictionary_get_data(reply_dict, "keychain_secrets", &secretsCnt);
316 error_code = (int)xpc_dictionary_get_int64(reply_dict, kHelperErrCode);
317 }
318
319 mDNSHELPER_DEBUG("mDNSKeychainGetSecrets: Using XPC IPC calling out to Helper: numsecrets is %u, secretsCnt is %u error_code is %d",
320 (unsigned int)numsecrets, (unsigned int)secretsCnt, error_code);
321
322 if (NULL == (bytes = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, (void*)sec, secretsCnt, kCFAllocatorNull)))
323 {
324 error_code = kHelperErr_ApiErr;
325 LogMsg("mDNSKeychainGetSecrets: CFDataCreateWithBytesNoCopy failed");
326 goto fin;
327 }
328
329 if (NULL == (plist = CFPropertyListCreateWithData(kCFAllocatorDefault, bytes, kCFPropertyListImmutable, NULL, NULL)))
330 {
331 error_code = kHelperErr_ApiErr;
332 LogMsg("mDNSKeychainGetSecrets: CFPropertyListCreateFromXMLData failed");
333 goto fin;
334 }
335
336 if (CFArrayGetTypeID() != CFGetTypeID(plist))
337 {
338 error_code = kHelperErr_ApiErr;
339 LogMsg("mDNSKeychainGetSecrets: Unexpected result type");
340 CFRelease(plist);
341 plist = NULL;
342 goto fin;
343 }
344
345 *result = (CFArrayRef)plist;
346
347
348 fin:
349 if (bytes)
350 CFRelease(bytes);
351 if (dict)
352 xpc_release(dict);
353 if (reply_dict)
354 xpc_release(reply_dict);
355
356 dict = NULL;
357 reply_dict = NULL;
358
359 return error_code;
360 }
361
362 void mDNSSendWakeupPacket(unsigned int ifid, char *eth_addr, char *ip_addr, int iteration)
363 {
364 // (void) ip_addr; // unused
365 // (void) iteration; // unused
366
367 mDNSHELPER_DEBUG("mDNSSendWakeupPacket: Entered ethernet address[%s],ip_address[%s], interface_id[%d], iteration[%d]",
368 eth_addr, ip_addr, ifid, iteration);
369
370 // Create Dictionary To Send
371 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
372 xpc_dictionary_set_uint64(dict, kHelperMode, send_wakepkt);
373
374 xpc_dictionary_set_uint64(dict, "interface_index", ifid);
375 xpc_dictionary_set_string(dict, "ethernet_address", eth_addr);
376 xpc_dictionary_set_string(dict, "ip_address", ip_addr);
377 xpc_dictionary_set_uint64(dict, "swp_iteration", iteration);
378
379 SendDict_ToServer(dict, NULL);
380 xpc_release(dict);
381 dict = NULL;
382
383 }
384
385 void mDNSPacketFilterControl(uint32_t command, char * ifname, uint32_t count, pfArray_t portArray, pfArray_t protocolArray)
386 {
387 struct
388 {
389 pfArray_t portArray;
390 pfArray_t protocolArray;
391 } pfa;
392
393 mDNSPlatformMemCopy(pfa.portArray, portArray, sizeof(pfArray_t));
394 mDNSPlatformMemCopy(pfa.protocolArray, protocolArray, sizeof(pfArray_t));
395
396 mDNSHELPER_DEBUG("mDNSPacketFilterControl: XPC IPC, ifname %s", ifname);
397
398 // Create Dictionary To Send
399 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
400 xpc_dictionary_set_uint64(dict, kHelperMode, p2p_packetfilter);
401
402 xpc_dictionary_set_uint64(dict, "pf_opcode", command);
403 if (ifname)
404 xpc_dictionary_set_string(dict, "pf_ifname", ifname);
405
406 xpc_object_t xpc_obj_portArray = xpc_array_create(NULL, 0);
407 xpc_object_t xpc_obj_protocolArray = xpc_array_create(NULL, 0);
408
409 for (size_t i = 0; i < count && i < PFPortArraySize; i++) {
410 xpc_array_set_uint64(xpc_obj_portArray, XPC_ARRAY_APPEND, pfa.portArray[i]);
411 xpc_array_set_uint64(xpc_obj_protocolArray, XPC_ARRAY_APPEND, pfa.protocolArray[i]);
412 }
413 xpc_dictionary_set_value(dict, "xpc_obj_array_port", xpc_obj_portArray);
414 xpc_dictionary_set_value(dict, "xpc_obj_array_protocol", xpc_obj_protocolArray);
415 xpc_release(xpc_obj_portArray);
416 xpc_release(xpc_obj_protocolArray);
417
418 SendDict_ToServer(dict, NULL);
419 xpc_release(dict);
420 dict = NULL;
421
422 mDNSHELPER_DEBUG("mDNSPacketFilterControl: portArray0[%d] portArray1[%d] portArray2[%d] portArray3[%d] protocolArray0[%d] protocolArray1[%d] protocolArray2[%d] protocolArray3[%d]",
423 pfa.portArray[0], pfa.portArray[1], pfa.portArray[2], pfa.portArray[3], pfa.protocolArray[0], pfa.protocolArray[1], pfa.protocolArray[2], pfa.protocolArray[3]);
424
425 }
426
427 void mDNSSendKeepalive(const v6addr_t sadd, const v6addr_t dadd, uint16_t lport, uint16_t rport, uint32_t seq, uint32_t ack, uint16_t win)
428 {
429
430 mDNSHELPER_DEBUG("mDNSSendKeepalive: Using XPC IPC calling out to Helper: lport is[%d] rport is[%d] seq is[%d] ack is[%d] win is[%d]",
431 lport, rport, seq, ack, win);
432
433 char buf1[INET6_ADDRSTRLEN];
434 char buf2[INET6_ADDRSTRLEN];
435
436 buf1[0] = 0;
437 buf2[0] = 0;
438
439 inet_ntop(AF_INET6, sadd, buf1, sizeof(buf1));
440 inet_ntop(AF_INET6, dadd, buf2, sizeof(buf2));
441 mDNSHELPER_DEBUG("mDNSSendKeepalive: Using XPC IPC calling out to Helper: sadd is %s, dadd is %s", buf1, buf2);
442
443 // Create Dictionary To Send
444 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
445 xpc_dictionary_set_uint64(dict, kHelperMode, send_keepalive);
446
447 xpc_dictionary_set_data(dict, "send_keepalive_sadd", (uint8_t*)sadd, sizeof(v6addr_t));
448 xpc_dictionary_set_data(dict, "send_keepalive_dadd", (uint8_t*)dadd, sizeof(v6addr_t));
449
450 xpc_dictionary_set_uint64(dict, "send_keepalive_lport", lport);
451 xpc_dictionary_set_uint64(dict, "send_keepalive_rport", rport);
452 xpc_dictionary_set_uint64(dict, "send_keepalive_seq", seq);
453 xpc_dictionary_set_uint64(dict, "send_keepalive_ack", ack);
454 xpc_dictionary_set_uint64(dict, "send_keepalive_win", win);
455
456 SendDict_ToServer(dict, NULL);
457 xpc_release(dict);
458 dict = NULL;
459
460 }
461
462 int mDNSRetrieveTCPInfo(int family, v6addr_t laddr, uint16_t lport, v6addr_t raddr, uint16_t rport, uint32_t *seq, uint32_t *ack, uint16_t *win, int32_t *intfid)
463 {
464 int error_code = kHelperErr_NotConnected;
465 xpc_object_t reply_dict = NULL;
466
467 mDNSHELPER_DEBUG("mDNSRetrieveTCPInfo: Using XPC IPC calling out to Helper: lport is[%d] rport is[%d] family is[%d]",
468 lport, rport, family);
469
470 char buf1[INET6_ADDRSTRLEN];
471 char buf2[INET6_ADDRSTRLEN];
472 buf1[0] = 0;
473 buf2[0] = 0;
474
475 inet_ntop(AF_INET6, laddr, buf1, sizeof(buf1));
476 inet_ntop(AF_INET6, raddr, buf2, sizeof(buf2));
477 mDNSHELPER_DEBUG("mDNSRetrieveTCPInfo:: Using XPC IPC calling out to Helper: laddr is %s, raddr is %s", buf1, buf2);
478
479 // Create Dictionary To Send
480 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
481 xpc_dictionary_set_uint64(dict, kHelperMode, retreive_tcpinfo);
482
483 xpc_dictionary_set_data(dict, "retreive_tcpinfo_laddr", (uint8_t*)laddr, sizeof(v6addr_t));
484 xpc_dictionary_set_data(dict, "retreive_tcpinfo_raddr", (uint8_t*)raddr, sizeof(v6addr_t));
485
486 xpc_dictionary_set_uint64(dict, "retreive_tcpinfo_family", family);
487 xpc_dictionary_set_uint64(dict, "retreive_tcpinfo_lport", lport);
488 xpc_dictionary_set_uint64(dict, "retreive_tcpinfo_rport", rport);
489
490 SendDict_ToServer(dict, &reply_dict);
491
492 if (reply_dict != NULL)
493 {
494 *seq = (uint32_t)xpc_dictionary_get_uint64(reply_dict, "retreive_tcpinfo_seq");
495 *ack = (uint32_t)xpc_dictionary_get_uint64(reply_dict, "retreive_tcpinfo_ack");
496 *win = (uint16_t)xpc_dictionary_get_uint64(reply_dict, "retreive_tcpinfo_win");
497 *intfid = (int32_t)xpc_dictionary_get_uint64(reply_dict, "retreive_tcpinfo_ifid");
498 error_code = (int)xpc_dictionary_get_int64(reply_dict, kHelperErrCode);
499 }
500
501 mDNSHELPER_DEBUG("mDNSRetrieveTCPInfo: Using XPC IPC calling out to Helper: seq is %d, ack is %d, win is %d, intfid is %d, error is %d",
502 *seq, *ack, *win, *intfid, error_code);
503
504 if (dict)
505 xpc_release(dict);
506 if (reply_dict)
507 xpc_release(reply_dict);
508 dict = NULL;
509 reply_dict = NULL;
510
511 return error_code;
512 }