]>
Commit | Line | Data |
---|---|---|
51601d48 A |
1 | /* -*- Mode: C; tab-width: 4 -*- |
2 | * | |
3 | * Copyright (c) 2012 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, kDNSDaemonEngaged); | |
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 | // Return Success Status to the client | |
109 | xpc_object_t response = xpc_dictionary_create(NULL, NULL, 0); | |
110 | if (response) | |
111 | { | |
112 | xpc_dictionary_set_uint64(response, kDNSDaemonReply, kDNSMsgReceived); | |
113 | xpc_connection_send_message(remote_conn, response); | |
114 | xpc_release(response); | |
115 | } | |
116 | else | |
117 | { | |
118 | LogMsg("handle_dps_request: Response Dictionary could not be created"); | |
119 | return; | |
120 | } | |
121 | ||
122 | // Proceed to get DNS Proxy Settings from the Client | |
123 | if (xpc_dictionary_get_uint64(req, kDNSProxyParameters)) | |
124 | { | |
125 | mDNSu32 inIf[MaxIp], outIf; | |
126 | ||
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); | |
133 | ||
134 | ActivateDNSProxy(inIf, outIf, proxy_off); | |
135 | } | |
136 | ||
137 | } | |
138 | ||
139 | // Verify Client's Entitlement | |
140 | mDNSlocal mDNSBool IsEntitled(xpc_connection_t conn, const char *password) | |
141 | { | |
142 | mDNSBool entitled = mDNSfalse; | |
143 | xpc_object_t ent = xpc_connection_copy_entitlement_value(conn, password); | |
144 | ||
145 | if (ent) | |
146 | { | |
147 | if (xpc_get_type(ent) == XPC_TYPE_BOOL && xpc_bool_get_value(ent)) | |
148 | { | |
149 | entitled = mDNStrue; | |
150 | } | |
151 | xpc_release(ent); | |
152 | } | |
153 | else | |
154 | { | |
155 | LogMsg("IsEntitled: Client Entitlement is NULL"); | |
156 | } | |
157 | ||
158 | return entitled; | |
159 | } | |
160 | ||
161 | mDNSlocal void accept_dps_client(xpc_connection_t conn) | |
162 | { | |
163 | uid_t euid; | |
164 | euid = xpc_connection_get_euid(conn); | |
165 | ||
166 | if (euid != 0 || !IsEntitled(conn, kDNSProxyService)) | |
167 | { | |
168 | LogMsg("accept_dps_client: DNSProxyService Client Pid[%d] is missing Entitlement or is not root!", (int) xpc_connection_get_pid(conn)); | |
169 | xpc_connection_cancel(conn); | |
170 | return; | |
171 | } | |
172 | ||
173 | xpc_retain(conn); | |
174 | xpc_connection_set_target_queue(conn, dps_queue); | |
175 | xpc_connection_set_event_handler(conn, ^(xpc_object_t req_msg) | |
176 | { | |
177 | xpc_type_t type = xpc_get_type(req_msg); | |
178 | ||
179 | if (type == XPC_TYPE_DICTIONARY) | |
180 | { | |
181 | handle_dps_request(req_msg); | |
182 | } | |
183 | // We hit the case below only if Client Terminated DPS Connection OR Crashed | |
184 | else | |
185 | { | |
186 | LogInfo("accept_dps_client: DPS Client %p teared down the connection or Crashed", (void *) conn); | |
187 | // Only the Client that has activated DPS should be able to terminate it | |
188 | if (((int)xpc_connection_get_pid(conn)) == dps_client_pid) | |
189 | handle_dps_terminate(); | |
190 | xpc_release(conn); | |
191 | } | |
192 | }); | |
193 | xpc_connection_resume(conn); | |
194 | ||
195 | } | |
196 | ||
197 | mDNSlocal void init_dnsproxy_service(void) | |
198 | { | |
199 | ||
200 | xpc_connection_t dps_listener = xpc_connection_create_mach_service(kDNSProxyService, NULL, XPC_CONNECTION_MACH_SERVICE_LISTENER); | |
201 | if (!dps_listener || xpc_get_type(dps_listener) != XPC_TYPE_CONNECTION) | |
202 | { | |
203 | LogMsg("init_dnsproxy_service: Error Creating XPC Listener for DNSProxyService !!"); | |
204 | return; | |
205 | } | |
206 | ||
207 | dps_queue = dispatch_queue_create("com.apple.mDNSResponder.dnsproxyservice_queue", NULL); | |
208 | ||
209 | xpc_connection_set_event_handler(dps_listener, ^(xpc_object_t eventmsg) | |
210 | { | |
211 | xpc_type_t type = xpc_get_type(eventmsg); | |
212 | ||
213 | if (type == XPC_TYPE_CONNECTION) | |
214 | { | |
215 | LogInfo("init_dnsproxy_service: New DNSProxyService Client %p", eventmsg); | |
216 | accept_dps_client(eventmsg); | |
217 | } | |
218 | // Ideally, we would never hit the cases below | |
219 | else if (type == XPC_TYPE_ERROR) | |
220 | { | |
221 | LogMsg("init_dnsproxy_service: XPCError: %s", xpc_dictionary_get_string(eventmsg, XPC_ERROR_KEY_DESCRIPTION)); | |
222 | return; | |
223 | } | |
224 | else | |
225 | { | |
226 | LogMsg("init_dnsproxy_service: Unknown EventMsg type"); | |
227 | return; | |
228 | } | |
229 | }); | |
230 | xpc_connection_resume(dps_listener); | |
231 | ||
232 | } | |
233 | ||
234 | mDNSexport void xpc_server_init() | |
235 | { | |
236 | // Add XPC Services here | |
237 | init_dnsproxy_service(); | |
238 | } | |
239 | ||
240 | #else // !UNICAST_DISABLED | |
241 | ||
242 | mDNSexport void xpc_server_init() | |
243 | { | |
244 | return; | |
245 | } | |
246 | ||
247 | mDNSexport void xpcserver_info(mDNS *const m) | |
248 | { | |
249 | (void) m; | |
250 | ||
251 | return; | |
252 | } | |
253 | ||
254 | #endif // !UNICAST_DISABLED | |
255 |