2 * Copyright (c) 2019 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();
32 mDNSlocal
void ActivateDNSProxy(mDNSu32 IpIfArr
[MaxIp
], mDNSu32 OpIf
, mDNSBool proxy_off
);
34 mDNSexport
void log_dnsproxy_info(mDNS
*const m
)
36 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "----- Active XPC Clients -----");
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],
42 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "<None>");
46 mDNSexport
void log_dnsproxy_info_to_fd(int fd
, mDNS
*const m
)
48 LogToFD(fd
, "----- Active XPC Clients -----");
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],
54 LogToFD(fd
, "<None>");
58 mDNSexport
void init_dnsproxy_service(void)
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
)
63 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
,
64 "init_dnsproxy_service: Error Creating XPC Listener for DNSProxyService !!");
68 dps_queue
= dispatch_queue_create("com.apple.mDNSResponder.dnsproxyservice_queue", NULL
);
70 xpc_connection_set_event_handler(dps_listener
, ^(xpc_object_t eventmsg
)
72 xpc_type_t type
= xpc_get_type(eventmsg
);
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
);
79 else if (type
== XPC_TYPE_ERROR
) // Ideally, we would never hit these cases
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
));
87 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "init_dnsproxy_service: Unknown EventMsg type");
92 xpc_connection_resume(dps_listener
);
95 mDNSlocal
void accept_dps_client(xpc_connection_t conn
)
99 c_euid
= xpc_connection_get_euid(conn
);
100 c_pid
= xpc_connection_get_pid(conn
);
102 if (c_euid
!= 0 || !IsEntitled(conn
, kDNSProxyService
))
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!",
107 xpc_connection_cancel(conn
);
112 xpc_connection_set_target_queue(conn
, dps_queue
);
113 xpc_connection_set_event_handler(conn
, ^(xpc_object_t req_msg
)
115 xpc_type_t type
= xpc_get_type(req_msg
);
117 if (type
== XPC_TYPE_DICTIONARY
)
119 handle_dps_request(req_msg
);
121 else // We hit this case ONLY if Client Terminated DPS Connection OR Crashed
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();
132 xpc_connection_resume(conn
);
135 mDNSlocal
void handle_dps_request(xpc_object_t req
)
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
);
142 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
, "handle_dps_request: Handler for DNS Proxy Requests");
144 if (dps_client_pid
<= 0)
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
;
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
)
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
);
163 xpc_dictionary_set_uint64(reply
, kDNSDaemonReply
, kDNSMsg_Busy
);
164 xpc_connection_send_message(remote_conn
, reply
);
169 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
,
170 "handle_dps_request: Reply Dictionary could not be created");
173 // We do not really need to terminate the connection with the client
174 // as it may try again later which is fine
180 xpc_object_t response
= xpc_dictionary_create_reply(req
);
181 // Return Success Status to the client
184 xpc_dictionary_set_uint64(response
, kDNSDaemonReply
, kDNSMsg_NoError
);
185 xpc_connection_send_message(remote_conn
, response
);
186 xpc_release(response
);
190 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_DEFAULT
,
191 "handle_dps_request: Response Dictionary could not be created");
195 // Proceed to get DNS Proxy Settings from the Client
196 if (xpc_dictionary_get_uint64(req
, kDNSProxyParameters
))
198 mDNSu32 inIf
[MaxIp
], outIf
;
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
);
207 ActivateDNSProxy(inIf
, outIf
, proxy_off
);
211 mDNSlocal
void handle_dps_terminate()
214 LogRedact(MDNS_LOG_CATEGORY_DEFAULT
, MDNS_LOG_INFO
,
215 "handle_dps_terminate: Client PID[%d] terminated connection or crashed. Proceed to terminate DNSProxy",
217 // Clear the Client's PID, so that we can now accept new DPS requests
221 mDNSPlatformCloseDNSProxySkts(&mDNSStorage
);
222 // TBD: Close TCP Sockets
224 KQueueUnlock("DNSProxy Deactivated");
227 mDNSlocal
void ActivateDNSProxy(mDNSu32 IpIfArr
[MaxIp
], mDNSu32 OpIf
, mDNSBool proxy_off
)
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
);
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");