2 * Copyright (c) 2004-2008, 2011-2017 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 <os/state_private.h>
42 #include <CoreFoundation/CoreFoundation.h>
43 #include <SystemConfiguration/SCPrivate.h>
45 #include "libSystemConfiguration_client.h"
46 #include "libSystemConfiguration_server.h"
48 #include "dnsinfo_create.h"
49 #include "dnsinfo_server.h"
50 #include "dnsinfo_private.h"
54 os_log_t
SC_LOG_HANDLE(void);
55 #endif //SC_LOG_HANDLE
65 * Note: all accesses should be made while running on the _dns_server_queue()
67 static libSC_info_server_t S_dns_info
;
72 * ACK (in-sync or not-in-sync) updates should be posted using
75 * Note: all accesses should be made while running on the _dns_server_queue()
77 static _dns_sync_handler_t S_sync_handler
= NULL
;
81 #pragma mark Support functions
85 #pragma mark DNS configuration server
88 static dispatch_queue_t
89 _dnsinfo_server_queue()
91 static dispatch_once_t once
;
92 static dispatch_queue_t q
;
94 dispatch_once(&once
, ^{
95 q
= dispatch_queue_create(DNSINFO_SERVICE_NAME
".server", NULL
);
105 * Called when a client wants a copy of the current
108 * - caller must be running on the _dns_server_queue()
111 _dnsinfo_copy(xpc_connection_t connection
, xpc_object_t request
)
115 const char *proc_name
;
116 xpc_connection_t remote
;
119 remote
= xpc_dictionary_get_remote_connection(request
);
120 reply
= xpc_dictionary_create_reply(request
);
122 SC_log(LOG_ERR
, "<%p> _dnsinfo_copy: xpc_dictionary_create_reply: failed",
127 // extract data and generation #
128 data
= _libSC_info_server_get_data(&S_dns_info
,
132 // extract process name
133 proc_name
= xpc_dictionary_get_string(request
, DNSINFO_PROC_NAME
);
134 if (proc_name
== NULL
) {
138 SC_log(LOG_DEBUG
, "<%p:%s[%d]> DNS configuration copy: %llu",
141 xpc_connection_get_pid(connection
),
144 // return the DNS configuration (if available)
146 xpc_dictionary_set_data(reply
,
147 DNSINFO_CONFIGURATION
,
148 CFDataGetBytePtr(data
),
149 CFDataGetLength(data
));
153 xpc_connection_send_message(remote
, reply
);
161 * _dnsinfo_acknowledge
163 * Called when a client wants to acknowledge processing
164 * of the DNS configuration
166 * - caller must be running on the _dns_server_queue()
169 _dnsinfo_acknowledge(xpc_connection_t connection
, xpc_object_t request
)
174 generation
= xpc_dictionary_get_uint64(request
, DNSINFO_GENERATION
);
176 SC_log(LOG_DEBUG
, "<%p:%d> DNS configuration ack: %llu",
178 xpc_connection_get_pid(connection
),
181 (void) _libSC_info_server_acknowledged(&S_dns_info
, connection
, generation
);
183 // Note: all of the DNS service ack's should result
184 // in a [new] network change being posted
186 inSync
= _libSC_info_server_in_sync(&S_dns_info
);
187 if (S_sync_handler
!= NULL
) {
188 S_sync_handler(inSync
);
195 process_request(xpc_connection_t connection
, xpc_object_t request
)
199 op
= xpc_dictionary_get_int64(request
, DNSINFO_REQUEST
);
201 case DNSINFO_REQUEST_COPY
:
203 * Return the DNS configuration
205 _dnsinfo_copy(connection
, request
);
208 case DNSINFO_REQUEST_ACKNOWLEDGE
:
210 * Acknowlege a [processed] DNS configuration
212 _dnsinfo_acknowledge(connection
, request
);
216 SC_log(LOG_ERR
, "<%p> unknown request : %lld",
228 process_new_connection(xpc_connection_t c
)
230 SC_log(LOG_DEBUG
, "<%p:%d> DNS configuration session: open",
232 xpc_connection_get_pid(c
));
234 _libSC_info_server_open(&S_dns_info
, c
);
236 xpc_connection_set_target_queue(c
, _dnsinfo_server_queue());
238 xpc_connection_set_event_handler(c
, ^(xpc_object_t xobj
) {
241 type
= xpc_get_type(xobj
);
242 if (type
== XPC_TYPE_DICTIONARY
) {
243 // process the request
244 process_request(c
, xobj
);
246 } else if (type
== XPC_TYPE_ERROR
) {
249 desc
= xpc_dictionary_get_string(xobj
, XPC_ERROR_KEY_DESCRIPTION
);
250 if (xobj
== XPC_ERROR_CONNECTION_INVALID
) {
253 SC_log(LOG_DEBUG
, "<%p:%d> DNS configuration session: close",
255 xpc_connection_get_pid(c
));
257 changed
= _libSC_info_server_close(&S_dns_info
, c
);
262 inSync
= _libSC_info_server_in_sync(&S_dns_info
);
263 if (S_sync_handler
!= NULL
) {
264 S_sync_handler(inSync
);
268 } else if (xobj
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
269 SC_log(LOG_ERR
, "<%p:%d> %s",
271 xpc_connection_get_pid(c
),
275 SC_log(LOG_ERR
, "<%p:%d> Connection error: %p : %s",
277 xpc_connection_get_pid(c
),
283 SC_log(LOG_ERR
, "<%p:%d> unknown event type : %p",
285 xpc_connection_get_pid(c
),
290 xpc_connection_resume(c
);
297 #pragma mark DNS configuration state
303 #if !TARGET_OS_SIMULATOR
304 os_state_block_t state_block
;
305 os_state_handle_t state_handle
;
307 state_block
= ^os_state_data_t(os_state_hints_t hints
) {
308 #pragma unused(hints)
310 os_state_data_t state_data
;
311 size_t state_data_size
;
313 dnsinfo_len
= (S_dns_info
.data
!= NULL
) ? CFDataGetLength(S_dns_info
.data
) : 0;
314 state_data_size
= OS_STATE_DATA_SIZE_NEEDED(dnsinfo_len
);
315 if (state_data_size
> MAX_STATEDUMP_SIZE
) {
316 SC_log(LOG_ERR
, "DNS configuration: state data too large (%zd > %zd)",
318 (size_t)MAX_STATEDUMP_SIZE
);
322 state_data
= calloc(1, state_data_size
);
323 if (state_data
== NULL
) {
324 SC_log(LOG_ERR
, "DNS configuration: could not allocate state data");
328 state_data
->osd_type
= OS_STATE_DATA_CUSTOM
;
329 state_data
->osd_data_size
= (uint32_t)dnsinfo_len
;
330 strlcpy(state_data
->osd_decoder
.osdd_library
,
331 "SystemConfiguration",
332 sizeof(state_data
->osd_decoder
.osdd_library
));
333 strlcpy(state_data
->osd_decoder
.osdd_type
,
335 sizeof(state_data
->osd_decoder
.osdd_type
));
336 strlcpy(state_data
->osd_title
, "DNS Configuration", sizeof(state_data
->osd_title
));
337 if (dnsinfo_len
> 0) {
338 memcpy(state_data
->osd_data
, CFDataGetBytePtr(S_dns_info
.data
), dnsinfo_len
);
344 state_handle
= os_state_add_handler(_dnsinfo_server_queue(), state_block
);
345 if (state_handle
== 0) {
346 SC_log(LOG_ERR
, "DNS configuration: os_state_add_handler() failed");
348 #endif // !TARGET_OS_SIMULATOR
356 #pragma mark DNS configuration server SPIs
361 load_DNSConfiguration(CFBundleRef bundle
,
362 _dns_sync_handler_t syncHandler
)
364 #pragma unused(bundle)
369 * keep track of DNS configuration acknowledgements
371 _libSC_info_server_init(&S_dns_info
);
374 * add a state dump handler
379 * save the in-sync/not-in-sync handler
381 S_sync_handler
= Block_copy(syncHandler
);
383 // create XPC listener
384 name
= getenv(DNSINFO_SERVICE_NAME
);
386 name
= DNSINFO_SERVICE_NAME
;
389 c
= xpc_connection_create_mach_service(name
,
390 _dnsinfo_server_queue(),
391 XPC_CONNECTION_MACH_SERVICE_LISTENER
);
393 xpc_connection_set_event_handler(c
, ^(xpc_object_t event
) {
396 type
= xpc_get_type(event
);
397 if (type
== XPC_TYPE_CONNECTION
) {
398 process_new_connection(event
);
400 } else if (type
== XPC_TYPE_ERROR
) {
403 desc
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
404 if (event
== XPC_ERROR_CONNECTION_INVALID
) {
405 SC_log(LOG_ERR
, "DNS configuration server: %s", desc
);
407 } else if (event
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
408 SC_log(LOG_ERR
, "DNS configuration server: %s", desc
);
410 SC_log(LOG_ERR
, "DNS configuration server: Connection error: %p : %s",
416 SC_log(LOG_ERR
, "DNS configuration server: unknown event type : %p", type
);
420 xpc_connection_resume(c
);
422 SC_log(LOG_DEBUG
, "XPC server \"%s\" started", name
);
430 _dns_configuration_store(dns_create_config_t
*_config
)
432 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)*_config
;
434 uint64_t new_generation
= 0;
435 CFDataRef new_dns_info
= NULL
;
436 const char *notify_key
;
438 if (config
!= NULL
) {
442 new_generation
= config
->config
.generation
;
444 SC_log(LOG_INFO
, "DNS configuration updated: %llu",
447 bytes
= (const UInt8
*)config
;
448 len
= sizeof(_dns_config_buf_t
) + ntohl(config
->n_attribute
);
450 new_dns_info
= CFDataCreate(NULL
, bytes
, len
);
453 dispatch_sync(_dnsinfo_server_queue(), ^{
454 _libSC_info_server_set_data(&S_dns_info
, new_dns_info
, new_generation
);
457 if (new_dns_info
!= NULL
) {
458 CFRelease(new_dns_info
);
461 // if anyone is keeping us in sync, they now need to catch up
462 in_sync
= _libSC_info_server_in_sync(&S_dns_info
);
463 if (S_sync_handler
!= NULL
) {
464 S_sync_handler(in_sync
);
467 // and let everyone else know that the configuration has been updated
468 notify_key
= dns_configuration_notify_key();
469 if (notify_key
!= NULL
) {
472 status
= notify_post(notify_key
);
473 if (status
!= NOTIFY_STATUS_OK
) {
474 SC_log(LOG_ERR
, "notify_post() failed: %d", status
);
475 // notification posting failures are non-fatal
490 main(int argc
, char **argv
)
492 static Boolean verbose
= (argc
> 1) ? TRUE
: FALSE
;
494 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
497 load_DNSConfiguration(CFBundleGetMainBundle(), // bundle
498 ^(Boolean inSync
) { // sync handler
501 inSync
? "Yes" : "No")