2 * Copyright (c) 2004-2008, 2011-2015 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
;
69 static SCLoggerRef S_logger
= NULL
;
74 * ACK (in-sync or not-in-sync) updates should be posted using
77 * Note: all accesses should be made while running on the _dns_server_queue()
79 static _dns_sync_handler_t S_sync_handler
= NULL
;
83 #pragma mark Support functions
87 #pragma mark DNS configuration server
90 static dispatch_queue_t
91 _dnsinfo_server_queue()
93 static dispatch_once_t once
;
94 static dispatch_queue_t q
;
96 dispatch_once(&once
, ^{
97 q
= dispatch_queue_create(DNSINFO_SERVICE_NAME
".server", NULL
);
107 * Called when a client wants a copy of the current
110 * - caller must be running on the _dns_server_queue()
113 _dnsinfo_copy(xpc_connection_t connection
, xpc_object_t request
)
117 const char *proc_name
;
118 xpc_connection_t remote
;
121 remote
= xpc_dictionary_get_remote_connection(request
);
122 reply
= xpc_dictionary_create_reply(request
);
124 SCLoggerLog(S_logger
, LOG_ERR
,
125 CFSTR("<%p> _dnsinfo_copy: xpc_dictionary_create_reply: failed"),
130 // extract data and generation #
131 data
= _libSC_info_server_get_data(&S_dns_info
,
135 // extract process name
136 proc_name
= xpc_dictionary_get_string(request
, DNSINFO_PROC_NAME
);
137 if (proc_name
== NULL
) {
141 SCLoggerLog(S_logger
, LOG_DEBUG
, CFSTR("<%p:%s[%d]> DNS configuration copy: %llu"),
144 xpc_connection_get_pid(connection
),
147 // return the DNS configuration (if available)
149 xpc_dictionary_set_data(reply
,
150 DNSINFO_CONFIGURATION
,
151 CFDataGetBytePtr(data
),
152 CFDataGetLength(data
));
156 xpc_connection_send_message(remote
, reply
);
164 * _dnsinfo_acknowledge
166 * Called when a client wants to acknowledge processing
167 * of the DNS configuration
169 * - caller must be running on the _dns_server_queue()
172 _dnsinfo_acknowledge(xpc_connection_t connection
, xpc_object_t request
)
177 generation
= xpc_dictionary_get_uint64(request
, DNSINFO_GENERATION
);
179 SCLoggerLog(S_logger
, LOG_DEBUG
, CFSTR("<%p:%d> DNS configuration ack: %llu"),
181 xpc_connection_get_pid(connection
),
184 (void) _libSC_info_server_acknowledged(&S_dns_info
, connection
, generation
);
186 // Note: all of the DNS service ack's should result
187 // in a [new] network change being posted
189 inSync
= _libSC_info_server_in_sync(&S_dns_info
);
190 if (S_sync_handler
) {
191 S_sync_handler(inSync
);
198 process_request(xpc_connection_t connection
, xpc_object_t request
)
202 op
= xpc_dictionary_get_int64(request
, DNSINFO_REQUEST
);
204 case DNSINFO_REQUEST_COPY
:
206 * Return the DNS configuration
208 _dnsinfo_copy(connection
, request
);
211 case DNSINFO_REQUEST_ACKNOWLEDGE
:
213 * Acknowlege a [processed] DNS configuration
215 _dnsinfo_acknowledge(connection
, request
);
219 SCLoggerLog(S_logger
, LOG_ERR
,
220 CFSTR("<%p> unknown request : %lld"),
232 process_new_connection(xpc_connection_t c
)
234 SCLoggerLog(S_logger
, LOG_DEBUG
, CFSTR("<%p:%d> DNS configuration session: open"),
236 xpc_connection_get_pid(c
));
238 _libSC_info_server_open(&S_dns_info
, c
);
240 xpc_connection_set_target_queue(c
, _dnsinfo_server_queue());
242 xpc_connection_set_event_handler(c
, ^(xpc_object_t xobj
) {
243 os_activity_t activity_id
;
246 activity_id
= os_activity_start("processing dnsinfo request",
247 OS_ACTIVITY_FLAG_DEFAULT
);
249 type
= xpc_get_type(xobj
);
250 if (type
== XPC_TYPE_DICTIONARY
) {
251 // process the request
252 process_request(c
, xobj
);
254 } else if (type
== XPC_TYPE_ERROR
) {
257 desc
= xpc_dictionary_get_string(xobj
, XPC_ERROR_KEY_DESCRIPTION
);
258 if (xobj
== XPC_ERROR_CONNECTION_INVALID
) {
261 SCLoggerLog(S_logger
, LOG_DEBUG
, CFSTR("<%p:%d> DNS configuration session: close"),
263 xpc_connection_get_pid(c
));
265 changed
= _libSC_info_server_close(&S_dns_info
, c
);
270 inSync
= _libSC_info_server_in_sync(&S_dns_info
);
271 S_sync_handler(inSync
);
274 } else if (xobj
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
275 SCLoggerLog(S_logger
, LOG_ERR
,
278 xpc_connection_get_pid(c
),
282 SCLoggerLog(S_logger
, LOG_ERR
,
283 CFSTR("<%p:%d> Connection error: %p : %s"),
285 xpc_connection_get_pid(c
),
291 SCLoggerLog(S_logger
, LOG_ERR
,
292 CFSTR("<%p:%d> unknown event type : %p"),
294 xpc_connection_get_pid(c
),
298 os_activity_end(activity_id
);
301 xpc_connection_resume(c
);
308 #pragma mark DNS configuration server SPIs
313 load_DNSConfiguration(CFBundleRef bundle
,
315 _dns_sync_handler_t syncHandler
)
323 * keep track of DNS configuration acknowledgements
325 _libSC_info_server_init(&S_dns_info
);
328 * save the in-sync/not-in-sync handler
330 S_sync_handler
= Block_copy(syncHandler
);
332 // create XPC listener
333 name
= getenv(DNSINFO_SERVICE_NAME
);
335 name
= DNSINFO_SERVICE_NAME
;
338 c
= xpc_connection_create_mach_service(name
,
339 _dnsinfo_server_queue(),
340 XPC_CONNECTION_MACH_SERVICE_LISTENER
);
342 xpc_connection_set_event_handler(c
, ^(xpc_object_t event
) {
343 os_activity_t activity_id
;
346 activity_id
= os_activity_start("processing dnsinfo connection",
347 OS_ACTIVITY_FLAG_DEFAULT
);
349 type
= xpc_get_type(event
);
350 if (type
== XPC_TYPE_CONNECTION
) {
351 process_new_connection(event
);
353 } else if (type
== XPC_TYPE_ERROR
) {
356 desc
= xpc_dictionary_get_string(event
, XPC_ERROR_KEY_DESCRIPTION
);
357 if (event
== XPC_ERROR_CONNECTION_INVALID
) {
358 SCLoggerLog(S_logger
, LOG_ERR
, CFSTR("DNS configuration server: %s"), desc
);
360 } else if (event
== XPC_ERROR_CONNECTION_INTERRUPTED
) {
361 SCLoggerLog(S_logger
, LOG_ERR
, CFSTR("DNS configuration server: %s"), desc
);
363 SCLoggerLog(S_logger
, LOG_ERR
,
364 CFSTR("DNS configuration server: Connection error: %p : %s"),
370 SCLoggerLog(S_logger
, LOG_ERR
,
371 CFSTR("DNS configuration server: unknown event type : %p"),
376 os_activity_end(activity_id
);
379 xpc_connection_resume(c
);
381 SCLoggerLog(S_logger
, LOG_DEBUG
, CFSTR("XPC server \"%s\" started"), name
);
389 _dns_configuration_store(dns_create_config_t
*_config
)
391 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)*_config
;
393 uint64_t new_generation
= 0;
394 CFDataRef new_dns_info
= NULL
;
395 const char *notify_key
;
397 if (config
!= NULL
) {
401 new_generation
= config
->config
.generation
;
403 SCLoggerLog(S_logger
, LOG_INFO
,
404 CFSTR("DNS configuration updated: %llu"),
407 bytes
= (const UInt8
*)config
;
408 len
= sizeof(_dns_config_buf_t
) + ntohl(config
->n_attribute
);
410 new_dns_info
= CFDataCreate(NULL
, bytes
, len
);
413 dispatch_sync(_dnsinfo_server_queue(), ^{
414 _libSC_info_server_set_data(&S_dns_info
, new_dns_info
, new_generation
);
417 if (new_dns_info
!= NULL
) {
418 CFRelease(new_dns_info
);
421 // if anyone is keeping us in sync, they now need to catch up
422 in_sync
= _libSC_info_server_in_sync(&S_dns_info
);
423 if (S_sync_handler
) {
424 S_sync_handler(in_sync
);
427 // and let everyone else know that the configuration has been updated
428 notify_key
= dns_configuration_notify_key();
429 if (notify_key
!= NULL
) {
432 status
= notify_post(notify_key
);
433 if (status
!= NOTIFY_STATUS_OK
) {
434 SCLoggerLog(S_logger
, LOG_ERR
, CFSTR("notify_post() failed: %d"), status
);
435 // notification posting failures are non-fatal
450 main(int argc
, char **argv
)
452 static Boolean verbose
= (argc
> 1) ? TRUE
: FALSE
;
454 _sc_verbose
= (argc
> 1) ? TRUE
: FALSE
;
457 load_DNSConfiguration(CFBundleGetMainBundle(), // bundle
459 ^(Boolean inSync
) { // sync handler
460 SCLoggerLog(NULL
, LOG_INFO
,
461 CFSTR("in sync: %s"),
462 inSync
? "Yes" : "No")