1 /* -*- Mode: C; tab-width: 4 -*-
3 * Copyright (c) 2012-2015 Apple Inc. All rights reserved.
5 * PRIVATE DNSX CLIENT LIBRARY --FOR Apple Platforms ONLY OSX/iOS--
6 * Resides in /usr/lib/libdns_services.dylib
9 #include "dns_services.h"
15 //*************************************************************************************************************
18 #define connection_t xpc_connection_t
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
28 //*************************************************************************************************************
31 static bool LogDebugEnabled()
36 static void LogDebug(const char *prefix
, xpc_object_t o
)
38 if (!LogDebugEnabled())
41 char *desc
= xpc_copy_description(o
);
42 os_log_info(OS_LOG_DEFAULT
, "%s: %s", prefix
, desc
);
46 //**************************************************************************************************************
48 void DNSXRefDeAlloc(DNSXConnRef connRef
)
52 os_log(OS_LOG_DEFAULT
, "dns_services: DNSXRefDeAlloc called with NULL DNSXConnRef");
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");
66 dispatch_async((connRef
)->client_q
, ^{
67 dispatch_release(connRef
->client_q
);
68 connRef
->client_q
= NULL
;
70 os_log_info(OS_LOG_DEFAULT
, "dns_services: DNSXRefDeAlloc successfully DeAllocated client_q & freed connRef");
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");
79 // Sends the Msg(Dictionary) to the Server Daemon
80 static DNSXErrorType
SendMsgToServer(DNSXConnRef connRef
, xpc_object_t msg
)
82 DNSXErrorType errx
= kDNSX_NoError
;
84 LogDebug("dns_services: SendMsgToServer Sending msg to Daemon", msg
);
86 xpc_connection_send_message_with_reply((connRef
)->conn_ref
, msg
, (connRef
)->lib_q
, ^(xpc_object_t recv_msg
)
88 xpc_type_t type
= xpc_get_type(recv_msg
);
90 if (type
== XPC_TYPE_DICTIONARY
)
92 LogDebug("dns_services: SendMsgToServer Received reply msg from Daemon", recv_msg
);
93 uint64_t daemon_status
= xpc_dictionary_get_uint64(recv_msg
, kDNSDaemonReply
);
95 if (connRef
== NULL
|| connRef
->client_q
== NULL
|| connRef
->AppCallBack
== NULL
)
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
);
102 switch (daemon_status
)
104 case kDNSMsg_NoError
:
105 dispatch_async((connRef
)->client_q
, ^{
106 if (connRef
->AppCallBack
!= NULL
)
107 ((DNSXEnableProxyReply
)connRef
->AppCallBack
)(connRef
, kDNSX_NoError
);
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
);
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
);
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
);
140 // Creates a new DNSX Connection Reference(DNSXConnRef)
141 static DNSXErrorType
InitConnection(DNSXConnRef
*connRefOut
, const char *servname
, dispatch_queue_t clientq
, void *AppCallBack
)
143 if (connRefOut
== NULL
)
145 os_log(OS_LOG_DEFAULT
, "dns_services: InitConnection() connRef cannot be NULL");
146 return kDNSX_BadParam
;
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
));
153 os_log(OS_LOG_DEFAULT
, "dns_services: InitConnection() No memory to allocate!");
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
);
164 if (connRef
->conn_ref
== NULL
|| connRef
->lib_q
== NULL
)
166 os_log(OS_LOG_DEFAULT
, "dns_services: InitConnection() conn_ref/lib_q is NULL");
172 xpc_connection_set_event_handler(connRef
->conn_ref
, ^(xpc_object_t event
)
174 if (connRef
== NULL
|| connRef
->client_q
== NULL
|| connRef
->AppCallBack
== NULL
)
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
));
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
);
191 xpc_connection_resume(connRef
->conn_ref
);
193 *connRefOut
= connRef
;
195 return kDNSX_NoError
;
198 DNSXErrorType
DNSXEnableProxy(DNSXConnRef
*connRef
, DNSProxyParameters proxyparam
, IfIndex inIfindexArr
[MaxInputIf
],
199 IfIndex outIfindex
, dispatch_queue_t clientq
, DNSXEnableProxyReply callBack
)
202 DNSXErrorType errx
= kDNSX_NoError
;
205 if (connRef
== NULL
|| callBack
== NULL
|| clientq
== NULL
)
207 os_log(OS_LOG_DEFAULT
, "dns_services: DNSXEnableProxy called with NULL DNSXConnRef OR Callback OR ClientQ parameter");
208 return kDNSX_BadParam
;
211 // Get connRef from InitConnection()
212 if (*connRef
== NULL
)
214 errx
= InitConnection(connRef
, kDNSProxyService
, clientq
, callBack
);
215 if (errx
) // On error InitConnection() leaves *connRef set to NULL
217 os_log(OS_LOG_DEFAULT
, "dns_services: Since InitConnection() returned %d error returning w/o sending msg", errx
);
221 else // Client already has a connRef and this is not valid use for this SPI
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
;
227 // Create Dictionary To Send
228 xpc_object_t dict
= xpc_dictionary_create(NULL
, NULL
, 0);
231 os_log(OS_LOG_DEFAULT
, "dns_services: DNSXEnableProxy could not create the Msg Dict To Send!");
232 DNSXRefDeAlloc(*connRef
);
236 xpc_dictionary_set_uint64(dict
, kDNSProxyParameters
, proxyparam
);
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]);
244 xpc_dictionary_set_uint64(dict
, kDNSOutIfindex
, outIfindex
);
246 errx
= SendMsgToServer(*connRef
, dict
);