2 * Copyright (c) 2004, 2006, 2008-2013, 2015, 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>
34 #include <dispatch/dispatch.h>
35 #include <mach/mach.h>
36 #include <os/activity.h>
39 #include "libSystemConfiguration_client.h"
41 #include "dnsinfo_private.h"
42 #include "dnsinfo_internal.h"
46 dns_configuration_notify_key()
50 key
= "com.apple.system.SystemConfiguration.dns_configuration";
56 #pragma mark DNS configuration [dnsinfo] client support
59 // Note: protected by __dns_configuration_queue()
60 static int dnsinfo_active
= 0;
61 static libSC_info_client_t
*dnsinfo_client
= NULL
;
65 __dns_configuration_activity()
67 static os_activity_t activity
;
68 static dispatch_once_t once
;
70 dispatch_once(&once
, ^{
71 activity
= os_activity_create("accessing DNS configuration",
73 OS_ACTIVITY_FLAG_DEFAULT
);
80 static dispatch_queue_t
81 __dns_configuration_queue()
83 static dispatch_once_t once
;
84 static dispatch_queue_t q
;
86 dispatch_once(&once
, ^{
87 q
= dispatch_queue_create(DNSINFO_SERVICE_NAME
, NULL
);
95 dns_configuration_copy()
99 dns_config_t
*config
= NULL
;
100 static const char *proc_name
= NULL
;
101 xpc_object_t reqdict
;
104 if (!libSC_info_available()) {
105 os_log(OS_LOG_DEFAULT
, "*** DNS configuration requested between fork() and exec()");
109 dispatch_sync(__dns_configuration_queue(), ^{
110 if ((dnsinfo_active
++ == 0) || (dnsinfo_client
== NULL
)) {
111 static dispatch_once_t once
;
112 static const char *service_name
= DNSINFO_SERVICE_NAME
;
114 dispatch_once(&once
, ^{
118 // get [XPC] service name
119 name
= getenv(service_name
);
121 service_name
= strdup(name
);
126 proc_name
= getprogname();
130 libSC_info_client_create(__dns_configuration_queue(), // dispatch queue
131 service_name
, // XPC service name
132 "DNS configuration"); // service description
133 if (dnsinfo_client
== NULL
) {
139 if ((dnsinfo_client
== NULL
) || !dnsinfo_client
->active
) {
140 // if DNS configuration server not available
144 // scope DNS configuration activity
145 os_activity_scope(__dns_configuration_activity());
148 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
151 if (proc_name
!= NULL
) {
152 xpc_dictionary_set_string(reqdict
, DNSINFO_PROC_NAME
, proc_name
);
156 xpc_dictionary_set_int64(reqdict
, DNSINFO_REQUEST
, DNSINFO_REQUEST_COPY
);
158 // send request to the DNS configuration server
159 reply
= libSC_send_message_with_reply_sync(dnsinfo_client
, reqdict
);
160 xpc_release(reqdict
);
166 dataRef
= xpc_dictionary_get_data(reply
, DNSINFO_CONFIGURATION
, &dataLen
);
167 if ((dataRef
!= NULL
) &&
168 ((dataLen
>= sizeof(_dns_config_buf_t
)) && (dataLen
<= DNS_CONFIG_BUF_MAX
))) {
169 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)(void *)dataRef
;
171 uint32_t n_attribute
= ntohl(config
->n_attribute
);
172 uint32_t n_padding
= ntohl(config
->n_padding
);
175 * Check that the size of the configuration header plus the size of the
176 * attribute data matches the size of the configuration buffer.
178 * If the sizes are different, something that should NEVER happen, CRASH!
180 configLen
= sizeof(_dns_config_buf_t
) + n_attribute
;
181 assert(configLen
== dataLen
);
184 * Check that the size of the requested padding would not result in our
185 * allocating a configuration + padding buffer larger than our maximum size.
187 * If the requested padding size is too large, something that should NEVER
190 assert(n_padding
<= (DNS_CONFIG_BUF_MAX
- dataLen
));
193 * Check that the actual size of the configuration data and any requested
194 * padding will be less than the maximum possible size of the in-memory
195 * configuration buffer.
197 * If the length needed is too large, something that should NEVER happen, CRASH!
199 bufLen
= dataLen
+ n_padding
;
200 assert(bufLen
<= DNS_CONFIG_BUF_MAX
);
202 // allocate a buffer large enough to hold both the configuration
203 // data and the padding.
204 buf
= malloc(bufLen
);
205 bcopy((void *)dataRef
, buf
, dataLen
);
206 bzero(&buf
[dataLen
], n_padding
);
213 /* ALIGN: cast okay since _dns_config_buf_t is int aligned */
214 config
= _dns_configuration_expand_config((_dns_config_buf_t
*)(void *)buf
);
215 if (config
== NULL
) {
225 dns_configuration_free(dns_config_t
*config
)
227 if (config
== NULL
) {
231 dispatch_sync(__dns_configuration_queue(), ^{
232 if (--dnsinfo_active
== 0) {
233 // if last reference, drop connection
234 libSC_info_client_release(dnsinfo_client
);
235 dnsinfo_client
= NULL
;
239 free((void *)config
);
245 _dns_configuration_ack(dns_config_t
*config
, const char *bundle_id
)
247 xpc_object_t reqdict
;
249 if (config
== NULL
) {
253 if ((dnsinfo_client
== NULL
) || !dnsinfo_client
->active
) {
254 // if DNS configuration server not available
258 dispatch_sync(__dns_configuration_queue(), ^{
259 dnsinfo_active
++; // keep connection active (for the life of the process)
263 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
266 xpc_dictionary_set_int64(reqdict
, DNSINFO_REQUEST
, DNSINFO_REQUEST_ACKNOWLEDGE
);
269 xpc_dictionary_set_uint64(reqdict
, DNSINFO_GENERATION
, config
->generation
);
271 // send acknowledgement to the DNS configuration server
272 xpc_connection_send_message(dnsinfo_client
->connection
, reqdict
);
274 xpc_release(reqdict
);
281 main(int argc
, char **argv
)
283 dns_config_t
*config
;
285 config
= dns_configuration_copy();
286 if (config
!= NULL
) {
287 dns_configuration_free(config
);