2 * Copyright (c) 2004-2008, 2011, 2012 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 <mach/mach_error.h>
39 #include <bsm/libbsm.h>
40 #include <dispatch/dispatch.h>
43 #include <CoreFoundation/CoreFoundation.h>
44 #include <SystemConfiguration/SCPrivate.h>
46 #include "libSystemConfiguration_client.h"
47 #include "libSystemConfiguration_server.h"
49 #include "dnsinfo_create.h"
50 #include "dnsinfo_server.h"
51 #include "dnsinfo_private.h"
60 * Note: all accesses should be made while running on the _dns_server_queue()
62 static libSC_info_server_t S_dns_info
;
67 * A boolean that enables additional logging.
69 static Boolean
*S_debug
= NULL
;
70 static SCLoggerRef S_logger
= NULL
;
75 * ACK (in-sync or not-in-sync) updates should be posted using
78 * Note: all accesses should be made while running on the _dns_server_queue()
80 static _dns_sync_handler_t S_sync_handler
= NULL
;
84 #pragma mark Support functions
89 log_xpc_object(const char *msg
, xpc_object_t obj
)
93 desc
= xpc_copy_description(obj
);
95 SCLoggerLog(S_logger
, LOG_INFO
, CFSTR("%s = %s"), msg
, desc
);
103 #pragma mark DNS configuration server
106 static dispatch_queue_t
107 _dnsinfo_server_queue()
109 static dispatch_once_t once
;
110 static dispatch_queue_t q
;
112 dispatch_once(&once
, ^{
113 q
= dispatch_queue_create(DNSINFO_SERVICE_NAME
".server", NULL
);
123 * Called when a client wants a copy of the current
126 * - caller must be running on the _dns_server_queue()
129 _dnsinfo_copy(xpc_connection_t connection
, xpc_object_t request
)
133 xpc_connection_t remote
;
136 remote
= xpc_dictionary_get_remote_connection(request
);
137 reply
= xpc_dictionary_create_reply(request
);
139 SCLoggerLog(S_logger
, LOG_ERR
,
140 CFSTR("<%p> _dnsinfo_copy: xpc_dictionary_create_reply: failed"),
145 // extract data and generation #
146 data
= _libSC_info_server_get_data(&S_dns_info
,
151 const char *proc_name
;
153 // extract process name
154 proc_name
= xpc_dictionary_get_string(request
, DNSINFO_PROC_NAME
);
155 if (proc_name
== NULL
) {
159 SCLoggerLog(S_logger
, LOG_INFO
, CFSTR("<%p:%s[%d]> DNS configuration copy: %llu"),
162 xpc_connection_get_pid(connection
),
166 // return the DNS configuration (if available)
168 xpc_dictionary_set_data(reply
,
169 DNSINFO_CONFIGURATION
,
170 CFDataGetBytePtr(data
),
171 CFDataGetLength(data
));
175 xpc_connection_send_message(remote
, reply
);
183 * _dnsinfo_acknowledge
185 * Called when a client wants to acknowledge processing
186 * of the DNS configuration
188 * - caller must be running on the _dns_server_queue()
191 _dnsinfo_acknowledge(xpc_connection_t connection
, xpc_object_t request
)
196 generation
= xpc_dictionary_get_uint64(request
, DNSINFO_GENERATION
);
199 SCLoggerLog(S_logger
, LOG_INFO
, CFSTR("<%p:%d> DNS configuration ack: %llu"),
201 xpc_connection_get_pid(connection
),
205 (void) _libSC_info_server_acknowledged(&S_dns_info
, connection
, generation
);
207 // Note: all of the mDNSResponder ack's should result
208 // in a [new] network change being posted
210 inSync
= _libSC_info_server_in_sync(&S_dns_info
);
211 S_sync_handler(inSync
);
218 process_request(xpc_connection_t connection
, xpc_object_t request
)
222 op
= xpc_dictionary_get_int64(request
, DNSINFO_REQUEST
);
224 case DNSINFO_REQUEST_COPY
:
226 * Return the DNS configuration
228 _dnsinfo_copy(connection
, request
);
231 case DNSINFO_REQUEST_ACKNOWLEDGE
:
233 * Acknowlege a [processed] DNS configuration
235 _dnsinfo_acknowledge(connection
, request
);
239 SCLoggerLog(S_logger
, LOG_ERR
,
240 CFSTR("<%p> unknown request : %d"),
252 process_new_connection(xpc_connection_t c
)
255 SCLoggerLog(S_logger
, LOG_INFO
, CFSTR("<%p:%d> DNS configuration session: open"),
257 xpc_connection_get_pid(c
));
260 _libSC_info_server_open(&S_dns_info
, c
);
262 xpc_connection_set_target_queue(c
, _dnsinfo_server_queue());
264 xpc_connection_set_event_handler(c
, ^(xpc_object_t xobj
) {
267 type
= xpc_get_type(xobj
);
268 if (type
== XPC_TYPE_DICTIONARY
) {
269 // process the request
270 process_request(c
, xobj
);
272 } else if (type
== XPC_TYPE_ERROR
) {
275 desc
= xpc_dictionary_get_string(xobj
, XPC_ERROR_KEY_DESCRIPTION
);
276 if (xobj
== XPC_ERROR_CONNECTION_INVALID
) {
280 SCLoggerLog(S_logger
, LOG_INFO
, CFSTR("<%p:%d> DNS configuration session: close"),
282 xpc_connection_get_pid(c
));
285 changed
= _libSC_info_server_close(&S_dns_info
, c
);
290 inSync
= _libSC_info_server_in_sync(&S_dns_info
);
291 S_sync_handler(inSync
);
294 } else if (xobj
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
295 SCLoggerLog(S_logger
, LOG_ERR
,
298 xpc_connection_get_pid(c
),
302 SCLoggerLog(S_logger
, LOG_ERR
,
303 CFSTR("<%p:%d> Connection error: %d : %s"),
305 xpc_connection_get_pid(c
),
311 SCLoggerLog(S_logger
, LOG_ERR
,
312 CFSTR("<%p:%d> unknown event type : %x"),
314 xpc_connection_get_pid(c
),
319 xpc_connection_resume(c
);
326 #pragma mark DNS configuration server SPIs
331 load_DNSConfiguration(CFBundleRef bundle
,
333 Boolean
*bundleVerbose
,
334 _dns_sync_handler_t syncHandler
)
339 S_debug
= bundleVerbose
;
343 * keep track of DNS configuration acknowledgements
345 _libSC_info_server_init(&S_dns_info
);
348 * save the in-sync/not-in-sync handler
350 S_sync_handler
= Block_copy(syncHandler
);
352 // create XPC listener
353 name
= getenv(DNSINFO_SERVICE_NAME
);
355 name
= DNSINFO_SERVICE_NAME
;
358 c
= xpc_connection_create_mach_service(name
,
359 _dnsinfo_server_queue(),
360 XPC_CONNECTION_MACH_SERVICE_LISTENER
);
362 xpc_connection_set_event_handler(c
, ^(xpc_object_t event
) {
365 type
= xpc_get_type(event
);
366 if (type
== XPC_TYPE_CONNECTION
) {
367 process_new_connection(event
);
369 } else if (type
== XPC_TYPE_ERROR
) {
372 desc
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
373 if (event
== XPC_ERROR_CONNECTION_INVALID
) {
374 SCLoggerLog(S_logger
, LOG_ERR
, CFSTR("DNS configuration server: %s"), desc
);
376 } else if (event
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
377 SCLoggerLog(S_logger
, LOG_ERR
, CFSTR("DNS configuration server: %s"), desc
);
379 SCLoggerLog(S_logger
, LOG_ERR
,
380 CFSTR("DNS configuration server: Connection error: %d : %s"),
386 SCLoggerLog(S_logger
, LOG_ERR
,
387 CFSTR("DNS configuration server: unknown event type : %x"),
393 xpc_connection_resume(c
);
395 SCLoggerLog(S_logger
, LOG_DEBUG
, CFSTR("XPC server \"%s\" started"), name
);
403 _dns_configuration_store(dns_create_config_t
*_config
)
405 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)*_config
;
407 uint64_t new_generation
= 0;
408 CFDataRef new_dns_info
= NULL
;
409 const char *notify_key
;
411 if (config
!= NULL
) {
415 new_generation
= config
->config
.generation
;
418 SCLoggerLog(S_logger
, LOG_INFO
, CFSTR("DNS configuration updated: %llu"),
422 bytes
= (const UInt8
*)config
;
423 len
= sizeof(_dns_config_buf_t
) + ntohl(config
->n_attribute
);
425 new_dns_info
= CFDataCreate(NULL
, bytes
, len
);
428 dispatch_sync(_dnsinfo_server_queue(), ^{
429 _libSC_info_server_set_data(&S_dns_info
, new_dns_info
, new_generation
);
432 if (new_dns_info
!= NULL
) {
433 CFRelease(new_dns_info
);
436 // if anyone is keeping us in sync, they now need to catch up
437 in_sync
= _libSC_info_server_in_sync(&S_dns_info
);
438 S_sync_handler(in_sync
);
440 // and let everyone else know that the configuration has been updated
441 notify_key
= dns_configuration_notify_key();
442 if (notify_key
!= NULL
) {
445 status
= notify_post(notify_key
);
446 if (status
!= NOTIFY_STATUS_OK
) {
447 SCLoggerLog(S_logger
, LOG_ERR
, CFSTR("notify_post() failed: %d"), status
);
448 // notification posting failures are non-fatal
463 main(int argc
, char **argv
)
465 static Boolean verbose
= (argc
> 1) ? TRUE
: FALSE
;
467 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
470 load_DNSConfiguration(CFBundleGetMainBundle(), // bundle
472 &verbose
, // bundleVerbose
473 ^(Boolean inSync
) { // sync handler
474 SCLoggerLog(NULL
, LOG_INFO
,
475 CFSTR("in sync: %s"),
476 inSync
? "Yes" : "No")