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