1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2012 Apple Inc. All rights reserved.
8 * XPC as an IPC mechanism to communicate with Clients. Open only to Apple OSX/iOS clients
11 #include "xpc_services.h"
14 #ifndef UNICAST_DISABLED
16 #include "dnsproxy.h" // DNSProxyInit/ProxyUDPCallback/ProxyTCPCallback
17 #include "mDNSMacOSX.h" // KQueueLock/KQueueUnlock
19 #include <xpc/private.h> // xpc_connection_copy_entitlement_value
21 // ***************************************************************************
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 // ***************************************************************************
28 // prints current XPC Server State
29 mDNSexport
void xpcserver_info(mDNS
*const m
)
32 LogMsg("----- Active XPC Clients -----");
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
);
39 mDNSlocal
void ActivateDNSProxy(mDNSu32 IpIfArr
[MaxIp
], mDNSu32 OpIf
, mDNSBool proxy_off
)
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
);
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");
52 mDNSlocal
void handle_dps_terminate()
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
59 KQueueLock(&mDNSStorage
);
60 mDNSPlatformCloseDNSProxySkts(&mDNSStorage
);
61 // TBD: Close TCP Sockets
62 DNSProxyTerminate(&mDNSStorage
);
63 KQueueUnlock(&mDNSStorage
, "DNSProxy Deactivated");
66 mDNSlocal
void handle_dps_request(xpc_object_t req
)
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
);
73 LogInfo("handle_dps_request: Handler for DNS Proxy Requests");
75 if (dps_client_pid
<= 0)
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
;
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
)
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);
93 xpc_dictionary_set_uint64(reply
, kDNSDaemonReply
, kDNSDaemonEngaged
);
94 xpc_connection_send_message(remote_conn
, reply
);
99 LogMsg("handle_dps_request: Reply Dictionary could not be created");
102 // We do not really need to terminate the connection with the client
103 // as it may try again later which is fine
108 // Return Success Status to the client
109 xpc_object_t response
= xpc_dictionary_create(NULL
, NULL
, 0);
112 xpc_dictionary_set_uint64(response
, kDNSDaemonReply
, kDNSMsgReceived
);
113 xpc_connection_send_message(remote_conn
, response
);
114 xpc_release(response
);
118 LogMsg("handle_dps_request: Response Dictionary could not be created");
122 // Proceed to get DNS Proxy Settings from the Client
123 if (xpc_dictionary_get_uint64(req
, kDNSProxyParameters
))
125 mDNSu32 inIf
[MaxIp
], outIf
;
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
);
134 ActivateDNSProxy(inIf
, outIf
, proxy_off
);
139 // Verify Client's Entitlement
140 mDNSlocal mDNSBool
IsEntitled(xpc_connection_t conn
, const char *password
)
142 mDNSBool entitled
= mDNSfalse
;
143 xpc_object_t ent
= xpc_connection_copy_entitlement_value(conn
, password
);
147 if (xpc_get_type(ent
) == XPC_TYPE_BOOL
&& xpc_bool_get_value(ent
))
155 LogMsg("IsEntitled: Client Entitlement is NULL");
161 mDNSlocal
void accept_dps_client(xpc_connection_t conn
)
164 euid
= xpc_connection_get_euid(conn
);
166 if (euid
!= 0 || !IsEntitled(conn
, kDNSProxyService
))
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
);
174 xpc_connection_set_target_queue(conn
, dps_queue
);
175 xpc_connection_set_event_handler(conn
, ^(xpc_object_t req_msg
)
177 xpc_type_t type
= xpc_get_type(req_msg
);
179 if (type
== XPC_TYPE_DICTIONARY
)
181 handle_dps_request(req_msg
);
183 // We hit the case below only if Client Terminated DPS Connection OR Crashed
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();
193 xpc_connection_resume(conn
);
197 mDNSlocal
void init_dnsproxy_service(void)
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
)
203 LogMsg("init_dnsproxy_service: Error Creating XPC Listener for DNSProxyService !!");
207 dps_queue
= dispatch_queue_create("com.apple.mDNSResponder.dnsproxyservice_queue", NULL
);
209 xpc_connection_set_event_handler(dps_listener
, ^(xpc_object_t eventmsg
)
211 xpc_type_t type
= xpc_get_type(eventmsg
);
213 if (type
== XPC_TYPE_CONNECTION
)
215 LogInfo("init_dnsproxy_service: New DNSProxyService Client %p", eventmsg
);
216 accept_dps_client(eventmsg
);
218 // Ideally, we would never hit the cases below
219 else if (type
== XPC_TYPE_ERROR
)
221 LogMsg("init_dnsproxy_service: XPCError: %s", xpc_dictionary_get_string(eventmsg
, XPC_ERROR_KEY_DESCRIPTION
));
226 LogMsg("init_dnsproxy_service: Unknown EventMsg type");
230 xpc_connection_resume(dps_listener
);
234 mDNSexport
void xpc_server_init()
236 // Add XPC Services here
237 init_dnsproxy_service();
240 #else // !UNICAST_DISABLED
242 mDNSexport
void xpc_server_init()
247 mDNSexport
void xpcserver_info(mDNS
*const m
)
254 #endif // !UNICAST_DISABLED