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