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