]> git.saurik.com Git - apple/mdnsresponder.git/blob - mDNSMacOSX/Private/dns_services.c
mDNSResponder-1310.40.42.tar.gz
[apple/mdnsresponder.git] / mDNSMacOSX / Private / dns_services.c
1 /*
2 * Copyright (c) 2012-2020 Apple Inc. All rights reserved.
3 *
4 * PRIVATE DNSX CLIENT LIBRARY --FOR Apple Platforms ONLY OSX/iOS--
5 * Resides in /usr/lib/libdns_services.dylib
6 */
7
8 #include "dns_services.h"
9 #include <xpc/xpc.h>
10 #include <Block.h>
11 #include <os/log.h>
12 #include <stdatomic.h>
13 #include "xpc_clients.h"
14
15 //*************************************************************************************************************
16 // Globals
17
18 #define connection_t xpc_connection_t
19
20 struct _DNSXConnRef_t
21 {
22 connection_t conn_ref; // xpc_connection between client and daemon
23 dispatch_queue_t lib_q; // internal queue created in library itself
24 DNSXEnableProxyReply AppCallBack; // Callback function ptr for Client
25 dispatch_queue_t client_q; // Queue specified by client for scheduling its Callback
26 _Atomic(int32_t) refCount; // Reference count for this object.
27 };
28
29 //*************************************************************************************************************
30 // Utility Functions
31
32 static bool LogDebugEnabled()
33 {
34 return true;
35 }
36
37 static void LogDebug(const char *prefix, xpc_object_t o)
38 {
39 if (!LogDebugEnabled())
40 return;
41
42 char *desc = xpc_copy_description(o);
43 os_log_info(OS_LOG_DEFAULT, "%s: %s", prefix, desc);
44 free(desc);
45 }
46
47 static void _DNSXConnRefRetain(DNSXConnRef connRef)
48 {
49 atomic_fetch_add(&connRef->refCount, 1);
50 }
51
52 static void _DNSXConnRefRelease(DNSXConnRef connRef)
53 {
54 if (atomic_fetch_add(&connRef->refCount, -1) == 1)
55 {
56 free(connRef);
57 }
58 }
59
60 //**************************************************************************************************************
61
62 void DNSXRefDeAlloc(DNSXConnRef connRef)
63 {
64 if (connRef == NULL)
65 {
66 os_log(OS_LOG_DEFAULT, "dns_services: DNSXRefDeAlloc called with NULL DNSXConnRef");
67 return;
68 }
69
70 // Schedule this work on the internal library queue
71 dispatch_sync(connRef->lib_q, ^{
72 xpc_connection_set_event_handler((connRef)->conn_ref, ^(__unused xpc_object_t event){}); // ignore any more events
73 xpc_release(connRef->conn_ref);
74 connRef->conn_ref = NULL;
75 dispatch_release(connRef->lib_q);
76 connRef->lib_q = NULL;
77 connRef->AppCallBack = NULL;
78 os_log_info(OS_LOG_DEFAULT, "dns_services: DNSXRefDeAlloc successfully DeAllocated conn_ref & lib_q");
79
80 dispatch_async((connRef)->client_q, ^{
81 dispatch_release(connRef->client_q);
82 connRef->client_q = NULL;
83 _DNSXConnRefRelease(connRef);
84 os_log_info(OS_LOG_DEFAULT, "dns_services: DNSXRefDeAlloc successfully DeAllocated client_q & released connRef");
85 });
86 });
87
88 // DO NOT reference connRef after this comment, as it may have been freed
89 os_log_info(OS_LOG_DEFAULT, "dns_services: DNSXRefDeAlloc successfully DeAllocated connRef");
90
91 }
92
93 // Sends the Msg(Dictionary) to the Server Daemon
94 static DNSXErrorType SendMsgToServer(DNSXConnRef connRef, xpc_object_t msg)
95 {
96 DNSXErrorType errx = kDNSX_NoError;
97
98 LogDebug("dns_services: SendMsgToServer Sending msg to Daemon", msg);
99
100 _DNSXConnRefRetain(connRef);
101 xpc_connection_send_message_with_reply((connRef)->conn_ref, msg, (connRef)->lib_q, ^(xpc_object_t recv_msg)
102 {
103 xpc_type_t type = xpc_get_type(recv_msg);
104
105 if (type == XPC_TYPE_DICTIONARY)
106 {
107 LogDebug("dns_services: SendMsgToServer Received reply msg from Daemon", recv_msg);
108 uint64_t daemon_status = xpc_dictionary_get_uint64(recv_msg, kDNSDaemonReply);
109
110 if (connRef == NULL || connRef->client_q == NULL || connRef->AppCallBack == NULL)
111 {
112 // If connRef is bad, do not schedule any callbacks to the client
113 os_log(OS_LOG_DEFAULT, "dns_services: SendMsgToServer: connRef is BAD Daemon status code [%llu]", daemon_status);
114 }
115 else
116 {
117 switch (daemon_status)
118 {
119 case kDNSMsg_NoError:
120 dispatch_async((connRef)->client_q, ^{
121 if (connRef->AppCallBack != NULL)
122 connRef->AppCallBack(connRef, kDNSX_NoError);
123 });
124 break;
125
126 case kDNSMsg_Busy:
127 os_log(OS_LOG_DEFAULT, "dns_services: SendMsgToServer: DNS Proxy already in use");
128 dispatch_async((connRef)->client_q, ^{
129 if (connRef->AppCallBack != NULL)
130 connRef->AppCallBack(connRef, kDNSX_Busy);
131 });
132 break;
133
134 default:
135 os_log(OS_LOG_DEFAULT, "dns_services: SendMsgToServer: Unknown error");
136 dispatch_async((connRef)->client_q, ^{
137 if (connRef->AppCallBack != NULL)
138 connRef->AppCallBack(connRef, kDNSX_UnknownErr);
139 });
140 break;
141 }
142 }
143 }
144 else
145 {
146 os_log(OS_LOG_DEFAULT, "dns_services: SendMsgToServer Received unexpected reply from daemon [%s]",
147 xpc_dictionary_get_string(recv_msg, XPC_ERROR_KEY_DESCRIPTION));
148 LogDebug("dns_services: SendMsgToServer Unexpected Reply contents", recv_msg);
149 }
150 _DNSXConnRefRelease(connRef);
151 });
152
153 return errx;
154 }
155
156 // Creates a new DNSX Connection Reference(DNSXConnRef)
157 static DNSXErrorType InitConnection(DNSXConnRef *connRefOut, const char *servname, dispatch_queue_t clientq, DNSXEnableProxyReply AppCallBack)
158 {
159 if (connRefOut == NULL)
160 {
161 os_log(OS_LOG_DEFAULT, "dns_services: InitConnection() connRef cannot be NULL");
162 return kDNSX_BadParam;
163 }
164
165 // Use a DNSXConnRef on the stack to be captured in the blocks below, rather than capturing the DNSXConnRef* owned by the client
166 DNSXConnRef connRef = (DNSXConnRef)calloc(1, sizeof(*connRef));
167 if (connRef == NULL)
168 {
169 os_log(OS_LOG_DEFAULT, "dns_services: InitConnection() No memory to allocate!");
170 return kDNSX_NoMem;
171 }
172
173 // Initialize the DNSXConnRef
174 atomic_init(&connRef->refCount, 1);
175 dispatch_retain(clientq);
176 connRef->client_q = clientq;
177 connRef->AppCallBack = AppCallBack;
178 connRef->lib_q = dispatch_queue_create("com.apple.mDNSResponder.libdns_services.q", DISPATCH_QUEUE_SERIAL);
179 connRef->conn_ref = xpc_connection_create_mach_service(servname, connRef->lib_q, XPC_CONNECTION_MACH_SERVICE_PRIVILEGED);
180
181 if (connRef->conn_ref == NULL || connRef->lib_q == NULL)
182 {
183 os_log(OS_LOG_DEFAULT, "dns_services: InitConnection() conn_ref/lib_q is NULL");
184 if (connRef != NULL)
185 {
186 _DNSXConnRefRelease(connRef);
187 }
188 return kDNSX_NoMem;
189 }
190
191 xpc_connection_set_event_handler(connRef->conn_ref, ^(xpc_object_t event)
192 {
193 if (connRef == NULL || connRef->client_q == NULL || connRef->AppCallBack == NULL)
194 {
195 // If connRef is bad, do not schedule any callbacks to the client
196 os_log(OS_LOG_DEFAULT, "dns_services: InitConnection: connRef is BAD Unexpected Connection Error [%s]",
197 xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
198 }
199 else
200 {
201 os_log(OS_LOG_DEFAULT, "dns_services: InitConnection: Unexpected Connection Error [%s] Ping the client",
202 xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION));
203 dispatch_async(connRef->client_q, ^{
204 if (connRef->AppCallBack != NULL)
205 connRef->AppCallBack(connRef, kDNSX_DaemonNotRunning);
206 });
207 }
208
209 });
210 xpc_connection_resume(connRef->conn_ref);
211
212 *connRefOut = connRef;
213
214 return kDNSX_NoError;
215 }
216
217 #define kDNSXProxyRecognizedFlags (kDNSXProxyFlagForceAAAASynthesis)
218
219 static DNSXErrorType _DNSXEnableProxy(DNSXConnRef *connRef, DNSProxyParameters proxyparam, IfIndex inIfindexArr[MaxInputIf],
220 IfIndex outIfindex, uint8_t ipv6Prefix[16], int ipv6PrefixBitLen,
221 DNSXProxyFlags flags, dispatch_queue_t clientq, DNSXEnableProxyReply callBack)
222 {
223 DNSXErrorType errx = kDNSX_NoError;
224
225 // Sanity Checks
226 if (connRef == NULL || callBack == NULL || clientq == NULL)
227 {
228 os_log(OS_LOG_DEFAULT, "dns_services: _DNSXEnableProxy called with NULL DNSXConnRef OR Callback OR ClientQ parameter");
229 return kDNSX_BadParam;
230 }
231
232 // Get connRef from InitConnection()
233 if (*connRef == NULL)
234 {
235 errx = InitConnection(connRef, kDNSProxyService, clientq, callBack);
236 if (errx) // On error InitConnection() leaves *connRef set to NULL
237 {
238 os_log(OS_LOG_DEFAULT, "dns_services: Since InitConnection() returned %d error returning w/o sending msg", errx);
239 return errx;
240 }
241 }
242 else // Client already has a connRef and this is not valid use for this SPI
243 {
244 os_log(OS_LOG_DEFAULT, "dns_services: Client already has a valid connRef! This is incorrect usage from the client");
245 return kDNSX_BadParam;
246 }
247
248 if (flags & ~kDNSXProxyRecognizedFlags)
249 {
250 os_log_error(OS_LOG_DEFAULT, "dns_services: Use of unrecognized flags 0x%08X", flags & ~kDNSXProxyRecognizedFlags);
251 return kDNSX_BadParam;
252 }
253
254 // Create Dictionary To Send
255 xpc_object_t dict = xpc_dictionary_create(NULL, NULL, 0);
256 if (dict == NULL)
257 {
258 os_log(OS_LOG_DEFAULT, "dns_services: _DNSXEnableProxy could not create the Msg Dict To Send!");
259 DNSXRefDeAlloc(*connRef);
260 return kDNSX_NoMem;
261 }
262
263 xpc_dictionary_set_uint64(dict, kDNSProxyParameters, proxyparam);
264
265 xpc_dictionary_set_uint64(dict, kDNSInIfindex0, inIfindexArr[0]);
266 xpc_dictionary_set_uint64(dict, kDNSInIfindex1, inIfindexArr[1]);
267 xpc_dictionary_set_uint64(dict, kDNSInIfindex2, inIfindexArr[2]);
268 xpc_dictionary_set_uint64(dict, kDNSInIfindex3, inIfindexArr[3]);
269 xpc_dictionary_set_uint64(dict, kDNSInIfindex4, inIfindexArr[4]);
270
271 xpc_dictionary_set_uint64(dict, kDNSOutIfindex, outIfindex);
272
273 if (ipv6Prefix)
274 {
275 xpc_dictionary_set_data(dict, kDNSProxyDNS64IPv6Prefix, ipv6Prefix, 16);
276 xpc_dictionary_set_int64(dict, kDNSProxyDNS64IPv6PrefixBitLen, ipv6PrefixBitLen);
277 const bool forceAAAASynthesis = (flags & kDNSXProxyFlagForceAAAASynthesis) ? true : false;
278 xpc_dictionary_set_bool(dict, kDNSProxyDNS64ForceAAAASynthesis, forceAAAASynthesis);
279 }
280 errx = SendMsgToServer(*connRef, dict);
281 xpc_release(dict);
282 dict = NULL;
283
284 return errx;
285 }
286
287 DNSXErrorType DNSXEnableProxy(DNSXConnRef *connRef, DNSProxyParameters proxyparam, IfIndex inIfindexArr[MaxInputIf],
288 IfIndex outIfindex, dispatch_queue_t clientq, DNSXEnableProxyReply callBack)
289 {
290 return _DNSXEnableProxy(connRef, proxyparam, inIfindexArr, outIfindex, NULL, 0, kDNSXProxyFlagNull, clientq, callBack);
291 }
292
293 DNSXErrorType DNSXEnableProxy64(DNSXConnRef *connRef, DNSProxyParameters proxyparam, IfIndex inIfindexArr[MaxInputIf],
294 IfIndex outIfindex, uint8_t ipv6Prefix[16], int ipv6PrefixBitLen, DNSXProxyFlags flags,
295 dispatch_queue_t clientq, DNSXEnableProxyReply callBack)
296 {
297 return _DNSXEnableProxy(connRef, proxyparam, inIfindexArr, outIfindex, ipv6Prefix, ipv6PrefixBitLen, flags, clientq,
298 callBack);
299 }