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