2 * Copyright (c) 2004, 2006, 2008-2013 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 <mach/mach.h>
35 #include <mach/mach_error.h>
36 #include <dispatch/dispatch.h>
39 #include "libSystemConfiguration_client.h"
41 #include "dnsinfo_private.h"
43 typedef uint32_t getflags
;
46 add_list(void **padding
, uint32_t *n_padding
, int32_t count
, int32_t size
, void **list
)
51 if (need
> *n_padding
) {
55 *list
= (need
== 0) ? NULL
: *padding
;
62 #define DNS_CONFIG_BUF_MAX 1024*1024
65 static dns_resolver_t
*
66 expand_resolver(_dns_resolver_buf_t
*buf
, uint32_t n_buf
, void **padding
, uint32_t *n_padding
)
68 dns_attribute_t
*attribute
;
70 int32_t n_nameserver
= 0;
72 int32_t n_sortaddr
= 0;
73 dns_resolver_t
*resolver
= (dns_resolver_t
*)&buf
->resolver
;
75 if (n_buf
< sizeof(_dns_resolver_buf_t
)) {
81 resolver
->domain
= NULL
;
83 // initialize nameserver list
85 resolver
->n_nameserver
= ntohl(resolver
->n_nameserver
);
86 if (!add_list(padding
,
88 resolver
->n_nameserver
,
89 sizeof(DNS_PTR(struct sockaddr
*, x
)),
90 (void **)&resolver
->nameserver
)) {
96 resolver
->port
= ntohs(resolver
->port
);
98 // initialize search list
100 resolver
->n_search
= ntohl(resolver
->n_search
);
101 if (!add_list(padding
,
104 sizeof(DNS_PTR(char *, x
)),
105 (void **)&resolver
->search
)) {
109 // initialize sortaddr list
111 resolver
->n_sortaddr
= ntohl(resolver
->n_sortaddr
);
112 if (!add_list(padding
,
114 resolver
->n_sortaddr
,
115 sizeof(DNS_PTR(dns_sortaddr_t
*, x
)),
116 (void **)&resolver
->sortaddr
)) {
120 // initialize options
122 resolver
->options
= NULL
;
124 // initialize timeout
126 resolver
->timeout
= ntohl(resolver
->timeout
);
128 // initialize search_order
130 resolver
->search_order
= ntohl(resolver
->search_order
);
132 // initialize if_index
134 resolver
->if_index
= ntohl(resolver
->if_index
);
136 // initialize service_identifier
138 resolver
->service_identifier
= ntohl(resolver
->service_identifier
);
142 resolver
->flags
= ntohl(resolver
->flags
);
144 // initialize SCNetworkReachability flags
146 resolver
->reach_flags
= ntohl(resolver
->reach_flags
);
148 // process resolver buffer "attribute" data
150 n_attribute
= n_buf
- sizeof(_dns_resolver_buf_t
);
151 /* ALIGN: alignment not assumed, using accessors */
152 attribute
= (dns_attribute_t
*)(void *)&buf
->attribute
[0];
153 if (n_attribute
!= ntohl(buf
->n_attribute
)) {
157 while (n_attribute
>= sizeof(dns_attribute_t
)) {
158 uint32_t attribute_length
= ntohl(attribute
->length
);
160 switch (ntohl(attribute
->type
)) {
161 case RESOLVER_ATTRIBUTE_DOMAIN
:
162 resolver
->domain
= (char *)&attribute
->attribute
[0];
165 case RESOLVER_ATTRIBUTE_ADDRESS
:
166 resolver
->nameserver
[n_nameserver
++] = (struct sockaddr
*)&attribute
->attribute
[0];
169 case RESOLVER_ATTRIBUTE_SEARCH
:
170 resolver
->search
[n_search
++] = (char *)&attribute
->attribute
[0];
173 case RESOLVER_ATTRIBUTE_SORTADDR
:
174 resolver
->sortaddr
[n_sortaddr
++] = (dns_sortaddr_t
*)(void *)&attribute
->attribute
[0];
177 case RESOLVER_ATTRIBUTE_OPTIONS
:
178 resolver
->options
= (char *)&attribute
->attribute
[0];
185 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
186 n_attribute
-= attribute_length
;
189 if ((n_nameserver
!= resolver
->n_nameserver
) ||
190 (n_search
!= resolver
->n_search
) ||
191 (n_sortaddr
!= resolver
->n_sortaddr
)) {
203 static dns_config_t
*
204 expand_config(_dns_config_buf_t
*buf
)
206 dns_attribute_t
*attribute
;
207 dns_config_t
*config
= (dns_config_t
*)buf
;
208 uint32_t n_attribute
;
210 int32_t n_resolver
= 0;
211 int32_t n_scoped_resolver
= 0;
212 int32_t n_service_specific_resolver
= 0;
217 padding
= &buf
->attribute
[ntohl(buf
->n_attribute
)];
218 n_padding
= ntohl(buf
->n_padding
);
220 // initialize resolver lists
222 config
->n_resolver
= ntohl(config
->n_resolver
);
223 if (!add_list(&padding
,
226 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
227 (void **)&config
->resolver
)) {
231 config
->n_scoped_resolver
= ntohl(config
->n_scoped_resolver
);
232 if (!add_list(&padding
,
234 config
->n_scoped_resolver
,
235 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
236 (void **)&config
->scoped_resolver
)) {
240 config
->n_service_specific_resolver
= ntohl(config
->n_service_specific_resolver
);
241 if (!add_list(&padding
,
243 config
->n_service_specific_resolver
,
244 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
245 (void **)&config
->service_specific_resolver
)) {
249 // process configuration buffer "attribute" data
251 n_attribute
= ntohl(buf
->n_attribute
);
252 attribute
= (dns_attribute_t
*)(void *)&buf
->attribute
[0];
254 while (n_attribute
>= sizeof(dns_attribute_t
)) {
255 uint32_t attribute_length
= ntohl(attribute
->length
);
256 uint32_t attribute_type
= ntohl(attribute
->type
);
258 switch (attribute_type
) {
259 case CONFIG_ATTRIBUTE_RESOLVER
:
260 case CONFIG_ATTRIBUTE_SCOPED_RESOLVER
:
261 case CONFIG_ATTRIBUTE_SERVICE_SPECIFIC_RESOLVER
: {
262 dns_resolver_t
*resolver
;
264 // expand resolver buffer
266 resolver
= expand_resolver((_dns_resolver_buf_t
*)(void *)&attribute
->attribute
[0],
267 attribute_length
- sizeof(dns_attribute_t
),
270 if (resolver
== NULL
) {
274 // add resolver to config list
276 if (attribute_type
== CONFIG_ATTRIBUTE_RESOLVER
) {
277 config
->resolver
[n_resolver
++] = resolver
;
278 } else if (attribute_type
== CONFIG_ATTRIBUTE_SCOPED_RESOLVER
) {
279 config
->scoped_resolver
[n_scoped_resolver
++] = resolver
;
280 } else if (attribute_type
== CONFIG_ATTRIBUTE_SERVICE_SPECIFIC_RESOLVER
) {
281 config
->service_specific_resolver
[n_service_specific_resolver
++] = resolver
;
291 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
292 n_attribute
-= attribute_length
;
295 if (n_resolver
!= config
->n_resolver
) {
299 if (n_scoped_resolver
!= config
->n_scoped_resolver
) {
303 if (n_service_specific_resolver
!= config
->n_service_specific_resolver
) {
316 dns_configuration_notify_key()
320 #if !TARGET_IPHONE_SIMULATOR
321 key
= "com.apple.system.SystemConfiguration.dns_configuration";
322 #else // !TARGET_IPHONE_SIMULATOR
323 key
= "com.apple.iOS_Simulator.SystemConfiguration.dns_configuration";
324 #endif // !TARGET_IPHONE_SIMULATOR
330 #pragma mark DNS configuration [dnsinfo] client support
333 // Note: protected by __dns_configuration_queue()
334 static int dnsinfo_active
= 0;
335 static libSC_info_client_t
*dnsinfo_client
= NULL
;
338 static dispatch_queue_t
339 __dns_configuration_queue()
341 static dispatch_once_t once
;
342 static dispatch_queue_t q
;
344 dispatch_once(&once
, ^{
345 q
= dispatch_queue_create(DNSINFO_SERVICE_NAME
, NULL
);
353 dns_configuration_copy()
356 dns_config_t
*config
= NULL
;
357 static const char *proc_name
= NULL
;
358 xpc_object_t reqdict
;
361 dispatch_sync(__dns_configuration_queue(), ^{
362 if ((dnsinfo_active
++ == 0) || (dnsinfo_client
== NULL
)) {
363 static dispatch_once_t once
;
364 static const char *service_name
= DNSINFO_SERVICE_NAME
;
366 dispatch_once(&once
, ^{
369 // get [XPC] service name
370 name
= getenv(service_name
);
371 if ((name
!= NULL
) && (issetugid() == 0)) {
372 service_name
= strdup(name
);
376 proc_name
= getprogname();
380 libSC_info_client_create(__dns_configuration_queue(), // dispatch queue
381 service_name
, // XPC service name
382 "DNS configuration"); // service description
383 if (dnsinfo_client
== NULL
) {
389 if ((dnsinfo_client
== NULL
) || !dnsinfo_client
->active
) {
390 // if DNS configuration server not available
395 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
398 if (proc_name
!= NULL
) {
399 xpc_dictionary_set_string(reqdict
, DNSINFO_PROC_NAME
, proc_name
);
403 xpc_dictionary_set_int64(reqdict
, DNSINFO_REQUEST
, DNSINFO_REQUEST_COPY
);
405 // send request to the DNS configuration server
406 reply
= libSC_send_message_with_reply_sync(dnsinfo_client
, reqdict
);
407 xpc_release(reqdict
);
413 dataRef
= xpc_dictionary_get_data(reply
, DNSINFO_CONFIGURATION
, &dataLen
);
414 if ((dataRef
!= NULL
) &&
415 ((dataLen
>= sizeof(_dns_config_buf_t
)) && (dataLen
<= DNS_CONFIG_BUF_MAX
))) {
416 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)(void *)dataRef
;
417 uint32_t n_padding
= ntohl(config
->n_padding
);
419 if (n_padding
<= (DNS_CONFIG_BUF_MAX
- dataLen
)) {
422 len
= dataLen
+ n_padding
;
424 bcopy((void *)dataRef
, buf
, dataLen
);
425 bzero(&buf
[dataLen
], n_padding
);
433 /* ALIGN: cast okay since _dns_config_buf_t is int aligned */
434 config
= expand_config((_dns_config_buf_t
*)(void *)buf
);
435 if (config
== NULL
) {
445 dns_configuration_free(dns_config_t
*config
)
447 if (config
== NULL
) {
451 dispatch_sync(__dns_configuration_queue(), ^{
452 if (--dnsinfo_active
== 0) {
453 // if last reference, drop connection
454 libSC_info_client_release(dnsinfo_client
);
455 dnsinfo_client
= NULL
;
459 free((void *)config
);
465 _dns_configuration_ack(dns_config_t
*config
, const char *bundle_id
)
467 xpc_object_t reqdict
;
469 if (config
== NULL
) {
473 if ((dnsinfo_client
== NULL
) || !dnsinfo_client
->active
) {
474 // if DNS configuration server not available
478 dispatch_sync(__dns_configuration_queue(), ^{
479 dnsinfo_active
++; // keep connection active (for the life of the process)
483 reqdict
= xpc_dictionary_create(NULL
, NULL
, 0);
486 xpc_dictionary_set_int64(reqdict
, DNSINFO_REQUEST
, DNSINFO_REQUEST_ACKNOWLEDGE
);
489 xpc_dictionary_set_uint64(reqdict
, DNSINFO_GENERATION
, config
->generation
);
491 // send acknowledgement to the DNS configuration server
492 xpc_connection_send_message(dnsinfo_client
->connection
, reqdict
);
494 xpc_release(reqdict
);
501 main(int argc
, char **argv
)
503 dns_config_t
*config
;
505 config
= dns_configuration_copy();
506 if (config
!= NULL
) {
507 dns_configuration_free(config
);