]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/Private/xpc_services.c
mDNSResponder-522.1.11.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / Private / xpc_services.c
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