2 * Copyright (c) 2004-2008, 2011-2016 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
21 * @APPLE_LICENSE_HEADER_END@
25 * Modification History
27 * March 9, 2004 Allan Nathanson <ajn@apple.com>
35 #include <sys/types.h>
36 #include <servers/bootstrap.h>
37 #include <mach/mach.h>
38 #include <bsm/libbsm.h>
39 #include <dispatch/dispatch.h>
41 #include <CoreFoundation/CoreFoundation.h>
42 #include <SystemConfiguration/SCPrivate.h>
44 #include "libSystemConfiguration_client.h"
45 #include "libSystemConfiguration_server.h"
47 #include "dnsinfo_create.h"
48 #include "dnsinfo_server.h"
49 #include "dnsinfo_private.h"
53 os_log_t SC_LOG_HANDLE
;
54 #endif //SC_LOG_HANDLE
64 * Note: all accesses should be made while running on the _dns_server_queue()
66 static libSC_info_server_t S_dns_info
;
71 * ACK (in-sync or not-in-sync) updates should be posted using
74 * Note: all accesses should be made while running on the _dns_server_queue()
76 static _dns_sync_handler_t S_sync_handler
= NULL
;
80 #pragma mark Support functions
84 #pragma mark DNS configuration server
87 static dispatch_queue_t
88 _dnsinfo_server_queue()
90 static dispatch_once_t once
;
91 static dispatch_queue_t q
;
93 dispatch_once(&once
, ^{
94 q
= dispatch_queue_create(DNSINFO_SERVICE_NAME
".server", NULL
);
104 * Called when a client wants a copy of the current
107 * - caller must be running on the _dns_server_queue()
110 _dnsinfo_copy(xpc_connection_t connection
, xpc_object_t request
)
114 const char *proc_name
;
115 xpc_connection_t remote
;
118 remote
= xpc_dictionary_get_remote_connection(request
);
119 reply
= xpc_dictionary_create_reply(request
);
121 SC_log(LOG_ERR
, "<%p> _dnsinfo_copy: xpc_dictionary_create_reply: failed",
126 // extract data and generation #
127 data
= _libSC_info_server_get_data(&S_dns_info
,
131 // extract process name
132 proc_name
= xpc_dictionary_get_string(request
, DNSINFO_PROC_NAME
);
133 if (proc_name
== NULL
) {
137 SC_log(LOG_DEBUG
, "<%p:%s[%d]> DNS configuration copy: %llu",
140 xpc_connection_get_pid(connection
),
143 // return the DNS configuration (if available)
145 xpc_dictionary_set_data(reply
,
146 DNSINFO_CONFIGURATION
,
147 CFDataGetBytePtr(data
),
148 CFDataGetLength(data
));
152 xpc_connection_send_message(remote
, reply
);
160 * _dnsinfo_acknowledge
162 * Called when a client wants to acknowledge processing
163 * of the DNS configuration
165 * - caller must be running on the _dns_server_queue()
168 _dnsinfo_acknowledge(xpc_connection_t connection
, xpc_object_t request
)
173 generation
= xpc_dictionary_get_uint64(request
, DNSINFO_GENERATION
);
175 SC_log(LOG_DEBUG
, "<%p:%d> DNS configuration ack: %llu",
177 xpc_connection_get_pid(connection
),
180 (void) _libSC_info_server_acknowledged(&S_dns_info
, connection
, generation
);
182 // Note: all of the DNS service ack's should result
183 // in a [new] network change being posted
185 inSync
= _libSC_info_server_in_sync(&S_dns_info
);
186 if (S_sync_handler
!= NULL
) {
187 S_sync_handler(inSync
);
194 process_request(xpc_connection_t connection
, xpc_object_t request
)
198 op
= xpc_dictionary_get_int64(request
, DNSINFO_REQUEST
);
200 case DNSINFO_REQUEST_COPY
:
202 * Return the DNS configuration
204 _dnsinfo_copy(connection
, request
);
207 case DNSINFO_REQUEST_ACKNOWLEDGE
:
209 * Acknowlege a [processed] DNS configuration
211 _dnsinfo_acknowledge(connection
, request
);
215 SC_log(LOG_ERR
, "<%p> unknown request : %lld",
227 process_new_connection(xpc_connection_t c
)
229 SC_log(LOG_DEBUG
, "<%p:%d> DNS configuration session: open",
231 xpc_connection_get_pid(c
));
233 _libSC_info_server_open(&S_dns_info
, c
);
235 xpc_connection_set_target_queue(c
, _dnsinfo_server_queue());
237 xpc_connection_set_event_handler(c
, ^(xpc_object_t xobj
) {
240 type
= xpc_get_type(xobj
);
241 if (type
== XPC_TYPE_DICTIONARY
) {
242 // process the request
243 process_request(c
, xobj
);
245 } else if (type
== XPC_TYPE_ERROR
) {
248 desc
= xpc_dictionary_get_string(xobj
, XPC_ERROR_KEY_DESCRIPTION
);
249 if (xobj
== XPC_ERROR_CONNECTION_INVALID
) {
252 SC_log(LOG_DEBUG
, "<%p:%d> DNS configuration session: close",
254 xpc_connection_get_pid(c
));
256 changed
= _libSC_info_server_close(&S_dns_info
, c
);
261 inSync
= _libSC_info_server_in_sync(&S_dns_info
);
262 if (S_sync_handler
!= NULL
) {
263 S_sync_handler(inSync
);
267 } else if (xobj
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
268 SC_log(LOG_ERR
, "<%p:%d> %s",
270 xpc_connection_get_pid(c
),
274 SC_log(LOG_ERR
, "<%p:%d> Connection error: %p : %s",
276 xpc_connection_get_pid(c
),
282 SC_log(LOG_ERR
, "<%p:%d> unknown event type : %p",
284 xpc_connection_get_pid(c
),
289 xpc_connection_resume(c
);
296 #pragma mark DNS configuration server SPIs
301 load_DNSConfiguration(CFBundleRef bundle
,
302 _dns_sync_handler_t syncHandler
)
308 * keep track of DNS configuration acknowledgements
310 _libSC_info_server_init(&S_dns_info
);
313 * save the in-sync/not-in-sync handler
315 S_sync_handler
= Block_copy(syncHandler
);
317 // create XPC listener
318 name
= getenv(DNSINFO_SERVICE_NAME
);
320 name
= DNSINFO_SERVICE_NAME
;
323 c
= xpc_connection_create_mach_service(name
,
324 _dnsinfo_server_queue(),
325 XPC_CONNECTION_MACH_SERVICE_LISTENER
);
327 xpc_connection_set_event_handler(c
, ^(xpc_object_t event
) {
330 type
= xpc_get_type(event
);
331 if (type
== XPC_TYPE_CONNECTION
) {
332 process_new_connection(event
);
334 } else if (type
== XPC_TYPE_ERROR
) {
337 desc
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
338 if (event
== XPC_ERROR_CONNECTION_INVALID
) {
339 SC_log(LOG_ERR
, "DNS configuration server: %s", desc
);
341 } else if (event
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
342 SC_log(LOG_ERR
, "DNS configuration server: %s", desc
);
344 SC_log(LOG_ERR
, "DNS configuration server: Connection error: %p : %s",
350 SC_log(LOG_ERR
, "DNS configuration server: unknown event type : %p", type
);
355 xpc_connection_resume(c
);
357 SC_log(LOG_DEBUG
, "XPC server \"%s\" started", name
);
365 _dns_configuration_store(dns_create_config_t
*_config
)
367 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)*_config
;
369 uint64_t new_generation
= 0;
370 CFDataRef new_dns_info
= NULL
;
371 const char *notify_key
;
373 if (config
!= NULL
) {
377 new_generation
= config
->config
.generation
;
379 SC_log(LOG_INFO
, "DNS configuration updated: %llu",
382 bytes
= (const UInt8
*)config
;
383 len
= sizeof(_dns_config_buf_t
) + ntohl(config
->n_attribute
);
385 new_dns_info
= CFDataCreate(NULL
, bytes
, len
);
388 dispatch_sync(_dnsinfo_server_queue(), ^{
389 _libSC_info_server_set_data(&S_dns_info
, new_dns_info
, new_generation
);
392 if (new_dns_info
!= NULL
) {
393 CFRelease(new_dns_info
);
396 // if anyone is keeping us in sync, they now need to catch up
397 in_sync
= _libSC_info_server_in_sync(&S_dns_info
);
398 if (S_sync_handler
!= NULL
) {
399 S_sync_handler(in_sync
);
402 // and let everyone else know that the configuration has been updated
403 notify_key
= dns_configuration_notify_key();
404 if (notify_key
!= NULL
) {
407 status
= notify_post(notify_key
);
408 if (status
!= NOTIFY_STATUS_OK
) {
409 SC_log(LOG_ERR
, "notify_post() failed: %d", status
);
410 // notification posting failures are non-fatal
425 main(int argc
, char **argv
)
427 static Boolean verbose
= (argc
> 1) ? TRUE
: FALSE
;
429 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
432 load_DNSConfiguration(CFBundleGetMainBundle(), // bundle
433 ^(Boolean inSync
) { // sync handler
436 inSync
? "Yes" : "No")