2 * Copyright (c) 2007-2019 Apple Inc. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #include <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>
24 #include <dispatch/dispatch.h>
25 #include <arpa/inet.h>
26 #include <xpc/private.h>
30 // Implementation Notes about the HelperQueue:
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
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.
44 //*************************************************************************************************************
46 static dispatch_queue_t HelperQueue
;
48 static int64_t maxwait_secs
= 5LL;
50 #define mDNSHELPER_DEBUG LogOperation
52 //*************************************************************************************************************
55 static void HelperLog(const char *prefix
, xpc_object_t o
)
57 char *desc
= xpc_copy_description(o
);
58 mDNSHELPER_DEBUG("HelperLog %s: %s", prefix
, desc
);
62 //*************************************************************************************************************
64 //*************************************************************************************************************
67 mDNSlocal xpc_connection_t
Create_Connection(void)
69 xpc_connection_t connection
= xpc_connection_create_mach_service(kHelperService
, HelperQueue
,
70 XPC_CONNECTION_MACH_SERVICE_PRIVILEGED
);
73 xpc_connection_set_event_handler(connection
, ^(xpc_object_t event
)
75 mDNSHELPER_DEBUG("Create_Connection xpc: [%s] \n", xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
));
77 xpc_connection_activate(connection
);
82 mDNSlocal
int SendDict_ToServer(xpc_object_t msg
, xpc_object_t
*out_reply
)
84 xpc_connection_t connection
;
85 dispatch_semaphore_t sem
= NULL
;
86 __block xpc_object_t reply
= NULL
;
87 __block
int errorcode
= kHelperErr_NoResponse
;
89 HelperLog("SendDict_ToServer Sending msg to Daemon", msg
);
91 connection
= Create_Connection();
97 sem
= dispatch_semaphore_create(0);
103 dispatch_retain(sem
); // for the block below
104 xpc_connection_send_message_with_reply(connection
, msg
, HelperQueue
, ^(xpc_object_t recv_msg
)
106 const xpc_type_t type
= xpc_get_type(recv_msg
);
108 if (type
== XPC_TYPE_DICTIONARY
)
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
);
114 switch (reply_status
)
116 case kHelperReply_ACK
:
117 mDNSHELPER_DEBUG("NoError: successful reply");
120 LogMsg("default: Unexpected reply from Helper");
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
);
133 dispatch_semaphore_signal(sem
);
134 dispatch_release(sem
);
137 if (dispatch_semaphore_wait(sem
, dispatch_time(DISPATCH_TIME_NOW
, (maxwait_secs
* NSEC_PER_SEC
))) != 0)
139 LogMsg("SendDict_ToServer: UNEXPECTED WAIT_TIME in dispatch_semaphore_wait");
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
);
152 mDNSHELPER_DEBUG("SendDict_ToServer returning with errorcode[%d]", errorcode
);
157 xpc_connection_cancel(connection
);
158 xpc_release(connection
);
162 dispatch_release(sem
);
171 //**************************************************************************************************************
173 mDNSexport mStatus
mDNSHelperInit()
175 HelperQueue
= dispatch_queue_create("com.apple.mDNSResponder.HelperQueue", NULL
);
176 if (HelperQueue
== NULL
)
178 LogMsg("dispatch_queue_create: Helper queue NULL");
179 return mStatus_NoMemoryErr
;
181 return mStatus_NoError
;
184 void mDNSPreferencesSetName(int key
, domainlabel
*old
, domainlabel
*new)
188 char oldname
[MAX_DOMAIN_LABEL
+1];
189 char newname
[MAX_DOMAIN_LABEL
+1];
192 mDNSPlatformMemZero(names
.oldname
, MAX_DOMAIN_LABEL
+ 1);
193 mDNSPlatformMemZero(names
.newname
, MAX_DOMAIN_LABEL
+ 1);
195 ConvertDomainLabelToCString_unescaped(old
, names
.oldname
);
198 ConvertDomainLabelToCString_unescaped(new, names
.newname
);
201 mDNSHELPER_DEBUG("mDNSPreferencesSetName: XPC IPC Test oldname %s newname %s", names
.oldname
, names
.newname
);
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
);
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
);
211 SendDict_ToServer(dict
, NULL
);
217 void mDNSRequestBPF()
219 mDNSHELPER_DEBUG("mDNSRequestBPF: Using XPC IPC");
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
);
230 int mDNSPowerRequest(int key
, int interval
)
232 int err_code
= kHelperErr_NotConnected
;
234 mDNSHELPER_DEBUG("mDNSPowerRequest: Using XPC IPC calling out to Helper key is [%d] interval is [%d]", key
, interval
);
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
);
242 err_code
= SendDict_ToServer(dict
, NULL
);
246 mDNSHELPER_DEBUG("mDNSPowerRequest: Using XPC IPC returning error_code %d", err_code
);
250 int mDNSSetLocalAddressCacheEntry(int ifindex
, int family
, const v6addr_t ip
, const ethaddr_t eth
)
252 int err_code
= kHelperErr_NotConnected
;
254 mDNSHELPER_DEBUG("mDNSSetLocalAddressCacheEntry: Using XPC IPC calling out to Helper: ifindex is [%d] family is [%d]", ifindex
, family
);
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
);
260 xpc_dictionary_set_uint64(dict
, "slace_ifindex", ifindex
);
261 xpc_dictionary_set_uint64(dict
, "slace_family", family
);
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
));
266 err_code
= SendDict_ToServer(dict
, NULL
);
270 mDNSHELPER_DEBUG("mDNSSetLocalAddressCacheEntry: Using XPC IPC returning error_code %d", err_code
);
275 void mDNSNotify(const char *title
, const char *msg
) // Both strings are UTF-8 text
277 mDNSHELPER_DEBUG("mDNSNotify() calling out to Helper XPC IPC title[%s] msg[%s]", title
, msg
);
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
);
283 xpc_dictionary_set_string(dict
, "notify_title", title
);
284 xpc_dictionary_set_string(dict
, "notify_msg", msg
);
286 SendDict_ToServer(dict
, NULL
);
293 int mDNSKeychainGetSecrets(CFArrayRef
*result
)
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
;
304 mDNSHELPER_DEBUG("mDNSKeychainGetSecrets: Using XPC IPC calling out to Helper");
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
);
310 SendDict_ToServer(dict
, &reply_dict
);
312 if (reply_dict
!= NULL
)
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
);
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
);
322 if (NULL
== (bytes
= CFDataCreateWithBytesNoCopy(kCFAllocatorDefault
, (void*)sec
, secretsCnt
, kCFAllocatorNull
)))
324 error_code
= kHelperErr_ApiErr
;
325 LogMsg("mDNSKeychainGetSecrets: CFDataCreateWithBytesNoCopy failed");
329 if (NULL
== (plist
= CFPropertyListCreateWithData(kCFAllocatorDefault
, bytes
, kCFPropertyListImmutable
, NULL
, NULL
)))
331 error_code
= kHelperErr_ApiErr
;
332 LogMsg("mDNSKeychainGetSecrets: CFPropertyListCreateFromXMLData failed");
336 if (CFArrayGetTypeID() != CFGetTypeID(plist
))
338 error_code
= kHelperErr_ApiErr
;
339 LogMsg("mDNSKeychainGetSecrets: Unexpected result type");
345 *result
= (CFArrayRef
)plist
;
354 xpc_release(reply_dict
);
362 void mDNSSendWakeupPacket(unsigned int ifid
, char *eth_addr
, char *ip_addr
, int iteration
)
364 // (void) ip_addr; // unused
365 // (void) iteration; // unused
367 mDNSHELPER_DEBUG("mDNSSendWakeupPacket: Entered ethernet address[%s],ip_address[%s], interface_id[%d], iteration[%d]",
368 eth_addr
, ip_addr
, ifid
, iteration
);
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
);
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
);
379 SendDict_ToServer(dict
, NULL
);
385 void mDNSPacketFilterControl(uint32_t command
, char * ifname
, uint32_t count
, pfArray_t portArray
, pfArray_t protocolArray
)
390 pfArray_t protocolArray
;
393 mDNSPlatformMemCopy(pfa
.portArray
, portArray
, sizeof(pfArray_t
));
394 mDNSPlatformMemCopy(pfa
.protocolArray
, protocolArray
, sizeof(pfArray_t
));
396 mDNSHELPER_DEBUG("mDNSPacketFilterControl: XPC IPC, ifname %s", ifname
);
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
);
402 xpc_dictionary_set_uint64(dict
, "pf_opcode", command
);
404 xpc_dictionary_set_string(dict
, "pf_ifname", ifname
);
406 xpc_object_t xpc_obj_portArray
= xpc_array_create(NULL
, 0);
407 xpc_object_t xpc_obj_protocolArray
= xpc_array_create(NULL
, 0);
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
]);
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
);
418 SendDict_ToServer(dict
, NULL
);
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]);
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
)
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
);
433 char buf1
[INET6_ADDRSTRLEN
];
434 char buf2
[INET6_ADDRSTRLEN
];
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
);
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
);
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
));
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
);
456 SendDict_ToServer(dict
, NULL
);
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
)
464 int error_code
= kHelperErr_NotConnected
;
465 xpc_object_t reply_dict
= NULL
;
467 mDNSHELPER_DEBUG("mDNSRetrieveTCPInfo: Using XPC IPC calling out to Helper: lport is[%d] rport is[%d] family is[%d]",
468 lport
, rport
, family
);
470 char buf1
[INET6_ADDRSTRLEN
];
471 char buf2
[INET6_ADDRSTRLEN
];
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
);
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
);
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
));
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
);
490 SendDict_ToServer(dict
, &reply_dict
);
492 if (reply_dict
!= NULL
)
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
);
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
);
507 xpc_release(reply_dict
);