1 | /* -*- Mode: C; tab-width: 4 -*- |
---|
2 | * |
---|
3 | * Copyright (c) 2012-2015 Apple Inc. All rights reserved. |
---|
4 | * |
---|
5 | * xpc_services.c |
---|
6 | * mDNSResponder |
---|
7 | * |
---|
8 | * XPC as an IPC mechanism to communicate with Clients. Open only to Apple OSX/iOS clients |
---|
9 | */ |
---|
10 | |
---|
11 | #include "xpc_services.h" |
---|
12 | #include "dns_xpc.h" |
---|
13 | |
---|
14 | #ifndef UNICAST_DISABLED |
---|
15 | |
---|
16 | #include "dnsproxy.h" // DNSProxyInit/ProxyUDPCallback/ProxyTCPCallback |
---|
17 | #include "mDNSMacOSX.h" // KQueueLock/KQueueUnlock |
---|
18 | #include <xpc/xpc.h> |
---|
19 | #include <xpc/private.h> // xpc_connection_copy_entitlement_value |
---|
20 | |
---|
21 | // *************************************************************************** |
---|
22 | // Globals |
---|
23 | extern mDNS mDNSStorage; |
---|
24 | static int dps_client_pid; // To track current active client using DNS Proxy Service |
---|
25 | static dispatch_queue_t dps_queue = NULL; |
---|
26 | // *************************************************************************** |
---|
27 | |
---|
28 | // prints current XPC Server State |
---|
29 | mDNSexport void xpcserver_info(mDNS *const m) |
---|
30 | { |
---|
31 | |
---|
32 | LogMsg("----- Active XPC Clients -----"); |
---|
33 | if (dps_client_pid) |
---|
34 | LogMsg("DNSProxy->Client[%d]: InputIntfs[%d, %d, %d, %d, %d] Output[%d]", dps_client_pid, m->dp_ipintf[0], |
---|
35 | m->dp_ipintf[1], m->dp_ipintf[2], m->dp_ipintf[3], m->dp_ipintf[4], m->dp_opintf); |
---|
36 | } |
---|
37 | |
---|
38 | |
---|
39 | mDNSlocal void ActivateDNSProxy(mDNSu32 IpIfArr[MaxIp], mDNSu32 OpIf, mDNSBool proxy_off) |
---|
40 | { |
---|
41 | |
---|
42 | LogInfo("ActivateDNSProxy: InterfaceIndex List by Client: Input[%d, %d, %d, %d, %d] Output[%d] ", IpIfArr[0], IpIfArr[1], |
---|
43 | IpIfArr[2], IpIfArr[3], IpIfArr[4], OpIf); |
---|
44 | |
---|
45 | KQueueLock(&mDNSStorage); |
---|
46 | DNSProxyInit(&mDNSStorage, IpIfArr, OpIf); |
---|
47 | if (proxy_off) // Open skts only if proxy was OFF else we may end up opening extra skts |
---|
48 | mDNSPlatformInitDNSProxySkts(&mDNSStorage, ProxyUDPCallback, ProxyTCPCallback); |
---|
49 | KQueueUnlock(&mDNSStorage, "DNSProxy Activated"); |
---|
50 | } |
---|
51 | |
---|
52 | mDNSlocal void handle_dps_terminate() |
---|
53 | { |
---|
54 | |
---|
55 | LogInfo("handle_dps_terminate: Client PID[%d] terminated connection or crashed. Proceed to terminate DNSProxy", dps_client_pid); |
---|
56 | // Clear the Client's PID, so that we can now accept new DPS requests |
---|
57 | dps_client_pid = 0; |
---|
58 | |
---|
59 | KQueueLock(&mDNSStorage); |
---|
60 | mDNSPlatformCloseDNSProxySkts(&mDNSStorage); |
---|
61 | // TBD: Close TCP Sockets |
---|
62 | DNSProxyTerminate(&mDNSStorage); |
---|
63 | KQueueUnlock(&mDNSStorage, "DNSProxy Deactivated"); |
---|
64 | } |
---|
65 | |
---|
66 | mDNSlocal void handle_dps_request(xpc_object_t req) |
---|
67 | { |
---|
68 | int dps_tmp_client; |
---|
69 | mDNSBool proxy_off = mDNSfalse; |
---|
70 | xpc_connection_t remote_conn = xpc_dictionary_get_remote_connection(req); |
---|
71 | dps_tmp_client = (int) xpc_connection_get_pid(remote_conn); |
---|
72 | |
---|
73 | LogInfo("handle_dps_request: Handler for DNS Proxy Requests"); |
---|
74 | |
---|
75 | if (dps_client_pid <= 0) |
---|
76 | { |
---|
77 | LogInfo("handle_dps_request: DNSProxy is not engaged (New Client)"); |
---|
78 | // No Active Client, save new Client's PID (also indicates DNS Proxy was OFF) |
---|
79 | dps_client_pid = dps_tmp_client; |
---|
80 | proxy_off = mDNStrue; |
---|
81 | } |
---|
82 | else |
---|
83 | { |
---|
84 | // We already have an active DNS Proxy Client and until that client does not terminate the connection |
---|
85 | // or crashes, a new client cannot change/override the current DNS Proxy settings. |
---|
86 | if (dps_client_pid != dps_tmp_client) |
---|
87 | { |
---|
88 | LogMsg("handle_dps_request: A Client is already using DNS Proxy and your request cannot be handled at this time"); |
---|
89 | // Return Engaged Status to the client |
---|
90 | xpc_object_t reply = xpc_dictionary_create(NULL, NULL, 0); |
---|
91 | if (reply) |
---|
92 | { |
---|
93 | xpc_dictionary_set_uint64(reply, kDNSDaemonReply, kDNSMsg_BadArg); |
---|
94 | xpc_connection_send_message(remote_conn, reply); |
---|
95 | xpc_release(reply); |
---|
96 | } |
---|
97 | else |
---|
98 | { |
---|
99 | LogMsg("handle_dps_request: Reply Dictionary could not be created"); |
---|
100 | return; |
---|
101 | } |
---|
102 | // We do not really need to terminate the connection with the client |
---|
103 | // as it may try again later which is fine |
---|
104 | return; |
---|
105 | } |
---|
106 | } |
---|
107 | |
---|
108 | |
---|
109 | xpc_object_t response = xpc_dictionary_create_reply(req); |
---|
110 | // Return Success Status to the client |
---|
111 | if (response) |
---|
112 | { |
---|
113 | xpc_dictionary_set_uint64(response, kDNSDaemonReply, kDNSMsg_NoError); |
---|
114 | xpc_connection_send_message(remote_conn, response); |
---|
115 | xpc_release(response); |
---|
116 | } |
---|
117 | else |
---|
118 | { |
---|
119 | LogMsg("handle_dps_request: Response Dictionary could not be created"); |
---|
120 | return; |
---|
121 | } |
---|
122 | |
---|
123 | // Proceed to get DNS Proxy Settings from the Client |
---|
124 | if (xpc_dictionary_get_uint64(req, kDNSProxyParameters)) |
---|
125 | { |
---|
126 | mDNSu32 inIf[MaxIp], outIf; |
---|
127 | |
---|
128 | inIf[0] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex0); |
---|
129 | inIf[1] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex1); |
---|
130 | inIf[2] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex2); |
---|
131 | inIf[3] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex3); |
---|
132 | inIf[4] = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSInIfindex4); |
---|
133 | outIf = (mDNSu32)xpc_dictionary_get_uint64(req, kDNSOutIfindex); |
---|
134 | |
---|
135 | ActivateDNSProxy(inIf, outIf, proxy_off); |
---|
136 | } |
---|
137 | |
---|
138 | } |
---|
139 | |
---|
140 | // Verify Client's Entitlement |
---|
141 | mDNSlocal mDNSBool IsEntitled(xpc_connection_t conn, const char *password) |
---|
142 | { |
---|
143 | mDNSBool entitled = mDNSfalse; |
---|
144 | xpc_object_t ent = xpc_connection_copy_entitlement_value(conn, password); |
---|
145 | |
---|
146 | if (ent) |
---|
147 | { |
---|
148 | if (xpc_get_type(ent) == XPC_TYPE_BOOL && xpc_bool_get_value(ent)) |
---|
149 | { |
---|
150 | entitled = mDNStrue; |
---|
151 | } |
---|
152 | xpc_release(ent); |
---|
153 | } |
---|
154 | else |
---|
155 | { |
---|
156 | LogMsg("IsEntitled: Client Entitlement is NULL"); |
---|
157 | } |
---|
158 | |
---|
159 | if (!entitled) |
---|
160 | LogMsg("IsEntitled: DNSProxyService Client is missing Entitlement!"); |
---|
161 | |
---|
162 | return entitled; |
---|
163 | } |
---|
164 | |
---|
165 | mDNSlocal void accept_dps_client(xpc_connection_t conn) |
---|
166 | { |
---|
167 | uid_t c_euid; |
---|
168 | int c_pid; |
---|
169 | c_euid = xpc_connection_get_euid(conn); |
---|
170 | c_pid = xpc_connection_get_pid(conn); |
---|
171 | |
---|
172 | if (c_euid != 0 || !IsEntitled(conn, kDNSProxyService)) |
---|
173 | { |
---|
174 | LogMsg("accept_dps_client: DNSProxyService Client PID[%d] is missing Entitlement or is not running as root!", c_pid); |
---|
175 | xpc_connection_cancel(conn); |
---|
176 | return; |
---|
177 | } |
---|
178 | |
---|
179 | xpc_retain(conn); |
---|
180 | xpc_connection_set_target_queue(conn, dps_queue); |
---|
181 | xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg) |
---|
182 | { |
---|
183 | xpc_type_t type = xpc_get_type(req_msg); |
---|
184 | |
---|
185 | if (type == XPC_TYPE_DICTIONARY) |
---|
186 | { |
---|
187 | handle_dps_request(req_msg); |
---|
188 | } |
---|
189 | else // We hit this case ONLY if Client Terminated DPS Connection OR Crashed |
---|
190 | { |
---|
191 | LogInfo("accept_dps_client: DPS Client %p teared down the connection or Crashed", (void *) conn); |
---|
192 | // Only the Client that has activated DPS should be able to terminate it |
---|
193 | if (c_pid == dps_client_pid) |
---|
194 | handle_dps_terminate(); |
---|
195 | xpc_release(conn); |
---|
196 | } |
---|
197 | }); |
---|
198 | |
---|
199 | xpc_connection_resume(conn); |
---|
200 | |
---|
201 | } |
---|
202 | |
---|
203 | mDNSlocal void init_dnsproxy_service(void) |
---|
204 | { |
---|
205 | |
---|
206 | xpc_connection_t dps_listener = xpc_connection_create_mach_service(kDNSProxyService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); |
---|
207 | if (!dps_listener || xpc_get_type(dps_listener) != XPC_TYPE_CONNECTION) |
---|
208 | { |
---|
209 | LogMsg("init_dnsproxy_service: Error Creating XPC Listener for DNSProxyService !!"); |
---|
210 | return; |
---|
211 | } |
---|
212 | |
---|
213 | dps_queue = dispatch_queue_create("com.apple.mDNSResponder.dnsproxyservice_queue", NULL); |
---|
214 | |
---|
215 | xpc_connection_set_event_handler(dps_listener, ^(xpc_object_t eventmsg) |
---|
216 | { |
---|
217 | xpc_type_t type = xpc_get_type(eventmsg); |
---|
218 | |
---|
219 | if (type == XPC_TYPE_CONNECTION) |
---|
220 | { |
---|
221 | LogInfo("init_dnsproxy_service: New DNSProxyService Client %p", eventmsg); |
---|
222 | accept_dps_client(eventmsg); |
---|
223 | } |
---|
224 | else if (type == XPC_TYPE_ERROR) // Ideally, we would never hit these cases |
---|
225 | { |
---|
226 | LogMsg("init_dnsproxy_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION)); |
---|
227 | return; |
---|
228 | } |
---|
229 | else |
---|
230 | { |
---|
231 | LogMsg("init_dnsproxy_service: Unknown EventMsg type"); |
---|
232 | return; |
---|
233 | } |
---|
234 | }); |
---|
235 | |
---|
236 | xpc_connection_resume(dps_listener); |
---|
237 | |
---|
238 | } |
---|
239 | |
---|
240 | mDNSexport void xpc_server_init() |
---|
241 | { |
---|
242 | // Add XPC Services here |
---|
243 | init_dnsproxy_service(); |
---|
244 | } |
---|
245 | |
---|
246 | #else // !UNICAST_DISABLED |
---|
247 | |
---|
248 | mDNSexport void xpc_server_init() |
---|
249 | { |
---|
250 | return; |
---|
251 | } |
---|
252 | |
---|
253 | mDNSexport void xpcserver_info(mDNS *const m) |
---|
254 | { |
---|
255 | (void) m; |
---|
256 | |
---|
257 | return; |
---|
258 | } |
---|
259 | |
---|
260 | #endif // !UNICAST_DISABLED |
---|
261 | |
---|