1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
8 * XPC as an IPC mechanism to communicate with Clients. Open only to Apple OSX/iOS clients
11 #include "xpc_services.h"
14 #ifndef UNICAST_DISABLED
16 #include "dnsproxy.h" // DNSProxyInit/ProxyUDPCallback/ProxyTCPCallback
17 #include "mDNSMacOSX.h" // KQueueLock/KQueueUnlock
18 #include <xpc/private.h> // xpc_connection_copy_entitlement_value
20 // ***************************************************************************
22 extern mDNS mDNSStorage;
23 static int dps_client_pid; // To track current active client using DNS Proxy Service
24 static dispatch_queue_t dps_queue = NULL;
25 // ***************************************************************************
27 // prints current XPC Server State
28 mDNSexport void xpcserver_info(mDNS *const m)
31 LogMsg("----- Active XPC Clients -----");
33 LogMsg("DNSProxy->Client[%d]: InputIntfs[%d, %d, %d, %d, %d] Output[%d]", dps_client_pid, m->dp_ipintf[0],
34 m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4], m->dp_opintf);
38 mDNSlocal void ActivateDNSProxy(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf, mDNSBool proxy_off)
41 LogInfo("ActivateDNSProxy: InterfaceIndex List by Client: Input[%d, %d, %d, %d, %d] Output[%d] ", IpIfArr[0], IpIfArr[1],
42 IpIfArr[2], IpIfArr[3], IpIfArr[4], OpIf);
45 DNSProxyInit(IpIfArr, OpIf);
46 if (proxy_off) // Open skts only if proxy was OFF else we may end up opening extra skts
47 mDNSPlatformInitDNSProxySkts(ProxyUDPCallback, ProxyTCPCallback);
48 KQueueUnlock("DNSProxy Activated");
51 mDNSlocal void handle_dps_terminate()
54 LogInfo("handle_dps_terminate: Client PID[%d] terminated connection or crashed. Proceed to terminate DNSProxy", dps_client_pid);
55 // Clear the Client's PID, so that we can now accept new DPS requests
59 mDNSPlatformCloseDNSProxySkts(&mDNSStorage);
60 // TBD: Close TCP Sockets
62 KQueueUnlock("DNSProxy Deactivated");
65 mDNSlocal void handle_dps_request(xpc_object_t req)
68 mDNSBool proxy_off = mDNSfalse;
69 xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req);
70 dps_tmp_client = (int) xpc_connection_get_pid(remote_conn);
72 LogInfo("handle_dps_request: Handler for DNS Proxy Requests");
74 if (dps_client_pid <= 0)
76 LogInfo("handle_dps_request: DNSProxy is not engaged (New Client)");
77 // No Active Client, save new Client's PID (also indicates DNS Proxy was OFF)
78 dps_client_pid = dps_tmp_client;
83 // We already have an active DNS Proxy Client and until that client does not terminate the connection
84 // or crashes, a new client cannot change/override the current DNS Proxy settings.
85 if (dps_client_pid != dps_tmp_client)
87 LogMsg("handle_dps_request: A Client is already using DNS Proxy and your request cannot be handled at this time");
88 // Return Engaged Status to the client
89 xpc_object_t reply = xpc_dictionary_create_reply(req);
92 xpc_dictionary_set_uint64(reply, kDNSDaemonReply, kDNSMsg_Busy);
93 xpc_connection_send_message(remote_conn, reply);
98 LogMsg("handle_dps_request: Reply Dictionary could not be created");
101 // We do not really need to terminate the connection with the client
102 // as it may try again later which is fine
108 xpc_object_t response = xpc_dictionary_create_reply(req);
109 // Return Success Status to the client
112 xpc_dictionary_set_uint64(response, kDNSDaemonReply, kDNSMsg_NoError);
113 xpc_connection_send_message(remote_conn, response);
114 xpc_release(response);
118 LogMsg("handle_dps_request: Response Dictionary could not be created");
122 // Proceed to get DNS Proxy Settings from the Client
123 if (xpc_dictionary_get_uint64(req, kDNSProxyParameters))
125 mDNSu32 inIf[MaxIp], outIf;
127 inIf[0] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex0);
128 inIf[1] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex1);
129 inIf[2] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex2);
130 inIf[3] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex3);
131 inIf[4] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex4);
132 outIf = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSOutIfindex);
134 ActivateDNSProxy(inIf, outIf, proxy_off);
139 // Verify Client's Entitlement
140 mDNSexport mDNSBool IsEntitled(xpc_connection_t conn, const char *password)
142 mDNSBool entitled = mDNSfalse;
143 xpc_object_t ent = xpc_connection_copy_entitlement_value(conn, password);
147 if (xpc_get_type(ent) == XPC_TYPE_BOOL && xpc_bool_get_value(ent))
155 LogMsg("IsEntitled: Client Entitlement is NULL");
159 LogMsg("IsEntitled: Client is missing Entitlement!");
164 mDNSlocal void accept_dps_client(xpc_connection_t conn)
168 c_euid = xpc_connection_get_euid(conn);
169 c_pid = xpc_connection_get_pid(conn);
171 if (c_euid != 0 || !IsEntitled(conn, kDNSProxyService))
173 LogMsg("accept_dps_client: DNSProxyService Client PID[%d] is missing Entitlement or is not running as root!", c_pid);
174 xpc_connection_cancel(conn);
179 xpc_connection_set_target_queue(conn, dps_queue);
180 xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg)
182 xpc_type_t type = xpc_get_type(req_msg);
184 if (type == XPC_TYPE_DICTIONARY)
186 handle_dps_request(req_msg);
188 else // We hit this case ONLY if Client Terminated DPS Connection OR Crashed
190 LogInfo("accept_dps_client: DPS Client %p teared down the connection or Crashed", (void *) conn);
191 // Only the Client that has activated DPS should be able to terminate it
192 if (c_pid == dps_client_pid)
193 handle_dps_terminate();
198 xpc_connection_resume(conn);
202 mDNSlocal void init_dnsproxy_service(void)
205 xpc_connection_t dps_listener = xpc_connection_create_mach_service(kDNSProxyService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER);
206 if (!dps_listener || xpc_get_type(dps_listener) != XPC_TYPE_CONNECTION)
208 LogMsg("init_dnsproxy_service: Error Creating XPC Listener for DNSProxyService !!");
212 dps_queue = dispatch_queue_create("com.apple.mDNSResponder.dnsproxyservice_queue", NULL);
214 xpc_connection_set_event_handler(dps_listener, ^(xpc_object_t eventmsg)
216 xpc_type_t type = xpc_get_type(eventmsg);
218 if (type == XPC_TYPE_CONNECTION)
220 LogInfo("init_dnsproxy_service: New DNSProxyService Client %p", eventmsg);
221 accept_dps_client(eventmsg);
223 else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases
225 LogMsg("init_dnsproxy_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION));
230 LogMsg("init_dnsproxy_service: Unknown EventMsg type");
235 xpc_connection_resume(dps_listener);
239 mDNSexport void xpc_server_init()
241 // Add XPC Services here
242 init_dnsproxy_service();
243 init_dnsctl_service();
247 #else // !UNICAST_DISABLED
249 mDNSexport void xpc_server_init()
254 mDNSexport void xpcserver_info(mDNS *const m)
261 #endif // !UNICAST_DISABLED