2 * Copyright (c) 2019-2020 Apple Inc. All rights reserved.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include <xpc/private.h>
18 #include "xpc_service_dns_proxy.h"
19 #include "xpc_clients.h"
22 #include "mDNSMacOSX.h"
23 #include "xpc_services.h"
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
;
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
);
36 mDNSlocal
void ActivateDNSProxy(mDNSu32 IpIfArr
[MaxIp
], mDNSu32 OpIf
, mDNSBool proxy_off
);
39 mDNSexport
void log_dnsproxy_info(mDNS
*const m
)
41 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "----- Active XPC Clients -----");
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],
47 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "<None>");
51 mDNSexport
void log_dnsproxy_info_to_fd(int fd
, mDNS
*const m
)
53 LogToFD(fd
, "----- Active XPC Clients -----");
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],
59 LogToFD(fd
, "<None>");
63 mDNSexport
void init_dnsproxy_service(void)
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
)
68 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
,
69 "init_dnsproxy_service: Error Creating XPC Listener for DNSProxyService !!");
73 dps_queue
= dispatch_queue_create("com.apple.mDNSResponder.dnsproxyservice_queue", NULL
);
75 xpc_connection_set_event_handler(dps_listener
, ^(xpc_object_t eventmsg
)
77 xpc_type_t type
= xpc_get_type(eventmsg
);
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
);
84 else if (type
== XPC_TYPE_ERROR
) // Ideally, we would never hit these cases
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
));
92 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "init_dnsproxy_service: Unknown EventMsg type");
97 xpc_connection_resume(dps_listener
);
100 mDNSlocal
void accept_dps_client(xpc_connection_t conn
)
104 c_euid
= xpc_connection_get_euid(conn
);
105 c_pid
= xpc_connection_get_pid(conn
);
107 if (c_euid
!= 0 || !IsEntitled(conn
, kDNSProxyService
))
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!",
112 xpc_connection_cancel(conn
);
117 xpc_connection_set_target_queue(conn
, dps_queue
);
118 xpc_connection_set_event_handler(conn
, ^(xpc_object_t req_msg
)
120 xpc_type_t type
= xpc_get_type(req_msg
);
122 if (type
== XPC_TYPE_DICTIONARY
)
124 handle_dps_request(req_msg
);
126 else // We hit this case ONLY if Client Terminated DPS Connection OR Crashed
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();
137 xpc_connection_resume(conn
);
140 mDNSlocal
void handle_dps_request(xpc_object_t req
)
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
);
147 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "handle_dps_request: Handler for DNS Proxy Requests");
149 if (dps_client_pid
<= 0)
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
;
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
)
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
);
168 xpc_dictionary_set_uint64(reply
, kDNSDaemonReply
, kDNSMsg_Busy
);
169 xpc_connection_send_message(remote_conn
, reply
);
174 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
,
175 "handle_dps_request: Reply Dictionary could not be created");
178 // We do not really need to terminate the connection with the client
179 // as it may try again later which is fine
185 xpc_object_t response
= xpc_dictionary_create_reply(req
);
186 // Return Success Status to the client
189 xpc_dictionary_set_uint64(response
, kDNSDaemonReply
, kDNSMsg_NoError
);
190 xpc_connection_send_message(remote_conn
, response
);
191 xpc_release(response
);
195 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
,
196 "handle_dps_request: Response Dictionary could not be created");
200 // Proceed to get DNS Proxy Settings from the Client
201 if (xpc_dictionary_get_uint64(req
, kDNSProxyParameters
))
203 mDNSu32 inIf
[MaxIp
], outIf
;
204 #if MDNSRESPONDER_SUPPORTS(APPLE, DNS_PROXY_DNS64)
205 const mDNSu8
*ipv6Prefix
;
208 mDNSBool forceAAAASynthesis
;
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
);
218 #if MDNSRESPONDER_SUPPORTS(APPLE, DNS_PROXY_DNS64)
219 ipv6Prefix
= xpc_dictionary_get_data(req
, kDNSProxyDNS64IPv6Prefix
, &dataLen
);
220 if (ipv6Prefix
&& (dataLen
== 16))
222 int64_t prefixLen
= xpc_dictionary_get_int64(req
, kDNSProxyDNS64IPv6PrefixBitLen
);
223 if (prefixLen
< INT_MIN
)
227 else if (prefixLen
> INT_MAX
)
231 ipv6PrefixLen
= (int)prefixLen
;
232 forceAAAASynthesis
= xpc_dictionary_get_bool(req
, kDNSProxyDNS64ForceAAAASynthesis
);
238 forceAAAASynthesis
= mDNSfalse
;
240 ActivateDNSProxy(inIf
, outIf
, ipv6Prefix
, ipv6PrefixLen
, forceAAAASynthesis
, proxy_off
);
242 ActivateDNSProxy(inIf
, outIf
, proxy_off
);
247 mDNSlocal
void handle_dps_terminate(void)
250 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
,
251 "handle_dps_terminate: Client PID[%d] terminated connection or crashed. Proceed to terminate DNSProxy",
253 // Clear the Client's PID, so that we can now accept new DPS requests
257 mDNSPlatformCloseDNSProxySkts(&mDNSStorage
);
258 // TBD: Close TCP Sockets
260 KQueueUnlock("DNSProxy Deactivated");
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
)
267 mDNSlocal
void ActivateDNSProxy(mDNSu32 IpIfArr
[MaxIp
], mDNSu32 OpIf
, mDNSBool proxy_off
)
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
);
275 #if MDNSRESPONDER_SUPPORTS(APPLE, DNS_PROXY_DNS64)
276 DNSProxyInit(IpIfArr
, OpIf
, IPv6Prefix
, IPv6PrefixBitLen
, forceAAAASynthesis
);
278 DNSProxyInit(IpIfArr
, OpIf
);
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");