2 * Copyright (c) 2012-2019 Apple Inc. All rights reserved.
4 * PRIVATE DNSX CLIENT LIBRARY --FOR Apple Platforms ONLY OSX/iOS--
5 * Resides in /usr/lib/libdns_services.dylib
8 #include "dns_services.h"
12 #include "xpc_clients.h"
14 //*************************************************************************************************************
17 #define connection_t xpc_connection_t
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
27 //*************************************************************************************************************
30 static bool LogDebugEnabled()
35 static void LogDebug(const char *prefix
, xpc_object_t o
)
37 if (!LogDebugEnabled())
40 char *desc
= xpc_copy_description(o
);
41 os_log_info(OS_LOG_DEFAULT
, "%s: %s", prefix
, desc
);
45 //**************************************************************************************************************
47 void DNSXRefDeAlloc(DNSXConnRef connRef
)
51 os_log(OS_LOG_DEFAULT
, "dns_services: DNSXRefDeAlloc called with NULL DNSXConnRef");
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");
65 dispatch_async((connRef
)->client_q
, ^{
66 dispatch_release(connRef
->client_q
);
67 connRef
->client_q
= NULL
;
69 os_log_info(OS_LOG_DEFAULT
, "dns_services: DNSXRefDeAlloc successfully DeAllocated client_q & freed connRef");
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");
78 // Sends the Msg(Dictionary) to the Server Daemon
79 static DNSXErrorType
SendMsgToServer(DNSXConnRef connRef
, xpc_object_t msg
)
81 DNSXErrorType errx
= kDNSX_NoError
;
83 LogDebug("dns_services: SendMsgToServer Sending msg to Daemon", msg
);
85 xpc_connection_send_message_with_reply((connRef
)->conn_ref
, msg
, (connRef
)->lib_q
, ^(xpc_object_t recv_msg
)
87 xpc_type_t type
= xpc_get_type(recv_msg
);
89 if (type
== XPC_TYPE_DICTIONARY
)
91 LogDebug("dns_services: SendMsgToServer Received reply msg from Daemon", recv_msg
);
92 uint64_t daemon_status
= xpc_dictionary_get_uint64(recv_msg
, kDNSDaemonReply
);
94 if (connRef
== NULL
|| connRef
->client_q
== NULL
|| connRef
->AppCallBack
== NULL
)
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
);
101 switch (daemon_status
)
103 case kDNSMsg_NoError
:
104 dispatch_async((connRef
)->client_q
, ^{
105 if (connRef
->AppCallBack
!= NULL
)
106 connRef
->AppCallBack(connRef
, kDNSX_NoError
);
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
);
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
);
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
);
139 // Creates a new DNSX Connection Reference(DNSXConnRef)
140 static DNSXErrorType
InitConnection(DNSXConnRef
*connRefOut
, const char *servname
, dispatch_queue_t clientq
, DNSXEnableProxyReply AppCallBack
)
142 if (connRefOut
== NULL
)
144 os_log(OS_LOG_DEFAULT
, "dns_services: InitConnection() connRef cannot be NULL");
145 return kDNSX_BadParam
;
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
));
152 os_log(OS_LOG_DEFAULT
, "dns_services: InitConnection() No memory to allocate!");
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
);
163 if (connRef
->conn_ref
== NULL
|| connRef
->lib_q
== NULL
)
165 os_log(OS_LOG_DEFAULT
, "dns_services: InitConnection() conn_ref/lib_q is NULL");
171 xpc_connection_set_event_handler(connRef
->conn_ref
, ^(xpc_object_t event
)
173 if (connRef
== NULL
|| connRef
->client_q
== NULL
|| connRef
->AppCallBack
== NULL
)
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
));
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
);
190 xpc_connection_resume(connRef
->conn_ref
);
192 *connRefOut
= connRef
;
194 return kDNSX_NoError
;
197 DNSXErrorType
DNSXEnableProxy(DNSXConnRef
*connRef
, DNSProxyParameters proxyparam
, IfIndex inIfindexArr
[MaxInputIf
],
198 IfIndex outIfindex
, dispatch_queue_t clientq
, DNSXEnableProxyReply callBack
)
201 DNSXErrorType errx
= kDNSX_NoError
;
204 if (connRef
== NULL
|| callBack
== NULL
|| clientq
== NULL
)
206 os_log(OS_LOG_DEFAULT
, "dns_services: DNSXEnableProxy called with NULL DNSXConnRef OR Callback OR ClientQ parameter");
207 return kDNSX_BadParam
;
210 // Get connRef from InitConnection()
211 if (*connRef
== NULL
)
213 errx
= InitConnection(connRef
, kDNSProxyService
, clientq
, callBack
);
214 if (errx
) // On error InitConnection() leaves *connRef set to NULL
216 os_log(OS_LOG_DEFAULT
, "dns_services: Since InitConnection() returned %d error returning w/o sending msg", errx
);
220 else // Client already has a connRef and this is not valid use for this SPI
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
;
226 // Create Dictionary To Send
227 xpc_object_t dict
= xpc_dictionary_create(NULL
, NULL
, 0);
230 os_log(OS_LOG_DEFAULT
, "dns_services: DNSXEnableProxy could not create the Msg Dict To Send!");
231 DNSXRefDeAlloc(*connRef
);
235 xpc_dictionary_set_uint64(dict
, kDNSProxyParameters
, proxyparam
);
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]);
243 xpc_dictionary_set_uint64(dict
, kDNSOutIfindex
, outIfindex
);
245 errx
= SendMsgToServer(*connRef
, dict
);