2 * Copyright (c) 2004, 2006, 2008-2011 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>
38 #include "dnsinfo_private.h"
39 #include "shared_dns_info.h"
40 #include "network_information_priv.h"
43 static pthread_once_t _dns_initialized
= PTHREAD_ONCE_INIT
;
44 static pthread_mutex_t _dns_lock
= PTHREAD_MUTEX_INITIALIZER
;
45 static mach_port_t _dns_server
= MACH_PORT_NULL
;
52 typedef uint32_t getflags
;
57 // the process has forked (and we are the child process)
58 _dns_server
= MACH_PORT_NULL
;
64 __dns_initialize(void)
66 // add handler to cleanup after fork()
67 (void) pthread_atfork(NULL
, NULL
, __dns_fork_handler
);
74 add_list(void **padding
, uint32_t *n_padding
, int32_t count
, int32_t size
, void **list
)
79 if (need
> *n_padding
) {
83 *list
= (need
== 0) ? NULL
: *padding
;
90 #define DNS_CONFIG_BUF_MAX 1024*1024
94 _dns_server_copy(void* dataRef
, mach_msg_type_number_t
* dataLen
, getflags flags
){
96 kern_return_t status
= KERN_FAILURE
;
99 pthread_once(&_dns_initialized
, __dns_initialize
);
101 // open a new session with the DNS configuration server
102 server
= _dns_server
;
104 if (server
!= MACH_PORT_NULL
) {
105 if (flags
== get_dns_info
) {
106 status
= shared_dns_infoGet(server
, dataRef
, dataLen
);
108 status
= shared_nwi_stateGet(server
, dataRef
, dataLen
);
110 if (status
== KERN_SUCCESS
) {
114 // our [cached] server port is not valid
115 if ((status
!= MACH_SEND_INVALID_DEST
) && (status
!= MIG_SERVER_DIED
)) {
116 // if we got an unexpected error, don't retry
118 "dns_configuration_copy shared_dns_infoGet(): %s\n",
119 mach_error_string(status
));
124 pthread_mutex_lock(&_dns_lock
);
125 if (_dns_server
!= MACH_PORT_NULL
) {
126 if (server
== _dns_server
) {
127 // if the server we tried returned the error
128 (void)mach_port_deallocate(mach_task_self(), server
);
129 _dns_server
= _dns_configuration_server_port();
131 // another thread has refreshed the DNS server port
134 _dns_server
= _dns_configuration_server_port();
136 server
= _dns_server
;
137 pthread_mutex_unlock(&_dns_lock
);
139 if (server
== MACH_PORT_NULL
) {
140 // if server not available
152 dnsDataOut_t dataRef
= NULL
;
153 mach_msg_type_number_t dataLen
= 0;
154 kern_return_t status
;
155 nwi_state
* state
= NULL
;
157 status
= _dns_server_copy(&dataRef
, &dataLen
, get_nwi_state
);
158 if (status
!= KERN_SUCCESS
) {
162 if (dataRef
!= NULL
) {
163 state
= malloc(dataLen
);
165 vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
,
169 memcpy((void*) state
, (void*) dataRef
, dataLen
);
171 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
172 if (status
!= KERN_SUCCESS
) {
173 mach_error("vm_deallocate():", status
);
183 static _dns_config_buf_t
*
187 dnsDataOut_t dataRef
= NULL
;
188 mach_msg_type_number_t dataLen
= 0;
189 kern_return_t status
;
191 status
= _dns_server_copy(&dataRef
, &dataLen
, get_dns_info
);
192 if (status
!= KERN_SUCCESS
) {
196 if (dataRef
!= NULL
) {
197 if ((dataLen
>= sizeof(_dns_config_buf_t
)) && (dataLen
<= DNS_CONFIG_BUF_MAX
)) {
198 /* ALIGN: cast okay since _dns_config_buf_t is int aligned */
199 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)(void *)dataRef
;
200 uint32_t n_padding
= ntohl(config
->n_padding
);
202 if (n_padding
<= (DNS_CONFIG_BUF_MAX
- dataLen
)) {
205 len
= dataLen
+ n_padding
;
207 bcopy((void *)dataRef
, buf
, dataLen
);
208 bzero(&buf
[dataLen
], n_padding
);
212 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
213 if (status
!= KERN_SUCCESS
) {
214 mach_error("vm_deallocate():", status
);
220 /* ALIGN: buf malloc'ed, should be aligned >8 bytes */
221 return (_dns_config_buf_t
*)(void *)buf
;
225 static dns_resolver_t
*
226 expand_resolver(_dns_resolver_buf_t
*buf
, uint32_t n_buf
, void **padding
, uint32_t *n_padding
)
228 dns_attribute_t
*attribute
;
229 uint32_t n_attribute
;
230 int32_t n_nameserver
= 0;
231 int32_t n_search
= 0;
232 int32_t n_sortaddr
= 0;
233 dns_resolver_t
*resolver
= (dns_resolver_t
*)&buf
->resolver
;
235 if (n_buf
< sizeof(_dns_resolver_buf_t
)) {
241 resolver
->domain
= NULL
;
243 // initialize nameserver list
245 resolver
->n_nameserver
= ntohl(resolver
->n_nameserver
);
246 if (!add_list(padding
,
248 resolver
->n_nameserver
,
249 sizeof(DNS_PTR(struct sockaddr
*, x
)),
250 (void **)&resolver
->nameserver
)) {
256 resolver
->port
= ntohs(resolver
->port
);
258 // initialize search list
260 resolver
->n_search
= ntohl(resolver
->n_search
);
261 if (!add_list(padding
,
264 sizeof(DNS_PTR(char *, x
)),
265 (void **)&resolver
->search
)) {
269 // initialize sortaddr list
271 resolver
->n_sortaddr
= ntohl(resolver
->n_sortaddr
);
272 if (!add_list(padding
,
274 resolver
->n_sortaddr
,
275 sizeof(DNS_PTR(dns_sortaddr_t
*, x
)),
276 (void **)&resolver
->sortaddr
)) {
280 // initialize options
282 resolver
->options
= NULL
;
284 // initialize timeout
286 resolver
->timeout
= ntohl(resolver
->timeout
);
288 // initialize search_order
290 resolver
->search_order
= ntohl(resolver
->search_order
);
292 // initialize if_index
294 resolver
->if_index
= ntohl(resolver
->if_index
);
298 resolver
->flags
= ntohl(resolver
->flags
);
300 // initialize SCNetworkReachability flags
302 resolver
->reach_flags
= ntohl(resolver
->reach_flags
);
304 // process resolver buffer "attribute" data
306 n_attribute
= n_buf
- sizeof(_dns_resolver_buf_t
);
307 /* ALIGN: alignment not assumed, using accessors */
308 attribute
= (dns_attribute_t
*)(void *)&buf
->attribute
[0];
309 if (n_attribute
!= ntohl(buf
->n_attribute
)) {
313 while (n_attribute
>= sizeof(dns_attribute_t
)) {
314 int32_t attribute_length
= ntohl(attribute
->length
);
316 switch (ntohl(attribute
->type
)) {
317 case RESOLVER_ATTRIBUTE_DOMAIN
:
318 resolver
->domain
= (char *)&attribute
->attribute
[0];
321 case RESOLVER_ATTRIBUTE_ADDRESS
:
322 resolver
->nameserver
[n_nameserver
++] = (struct sockaddr
*)&attribute
->attribute
[0];
325 case RESOLVER_ATTRIBUTE_SEARCH
:
326 resolver
->search
[n_search
++] = (char *)&attribute
->attribute
[0];
329 case RESOLVER_ATTRIBUTE_SORTADDR
:
330 resolver
->sortaddr
[n_sortaddr
++] = (dns_sortaddr_t
*)(void *)&attribute
->attribute
[0];
333 case RESOLVER_ATTRIBUTE_OPTIONS
:
334 resolver
->options
= (char *)&attribute
->attribute
[0];
341 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
342 n_attribute
-= attribute_length
;
345 if ((n_nameserver
!= resolver
->n_nameserver
) ||
346 (n_search
!= resolver
->n_search
) ||
347 (n_sortaddr
!= resolver
->n_sortaddr
)) {
359 static dns_config_t
*
360 expand_config(_dns_config_buf_t
*buf
)
362 dns_attribute_t
*attribute
;
363 dns_config_t
*config
= (dns_config_t
*)buf
;
364 uint32_t n_attribute
;
366 int32_t n_resolver
= 0;
367 int32_t n_scoped_resolver
= 0;
372 padding
= &buf
->attribute
[ntohl(buf
->n_attribute
)];
373 n_padding
= ntohl(buf
->n_padding
);
375 // initialize resolver lists
377 config
->n_resolver
= ntohl(config
->n_resolver
);
378 if (!add_list(&padding
,
381 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
382 (void **)&config
->resolver
)) {
386 config
->n_scoped_resolver
= ntohl(config
->n_scoped_resolver
);
387 if (!add_list(&padding
,
389 config
->n_scoped_resolver
,
390 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
391 (void **)&config
->scoped_resolver
)) {
395 // process configuration buffer "attribute" data
397 n_attribute
= ntohl(buf
->n_attribute
);
398 attribute
= (dns_attribute_t
*)(void *)&buf
->attribute
[0];
400 while (n_attribute
>= sizeof(dns_attribute_t
)) {
401 uint32_t attribute_length
= ntohl(attribute
->length
);
402 uint32_t attribute_type
= ntohl(attribute
->type
);
404 switch (attribute_type
) {
405 case CONFIG_ATTRIBUTE_RESOLVER
:
406 case CONFIG_ATTRIBUTE_SCOPED_RESOLVER
: {
407 dns_resolver_t
*resolver
;
409 // expand resolver buffer
411 resolver
= expand_resolver((_dns_resolver_buf_t
*)(void *)&attribute
->attribute
[0],
412 attribute_length
- sizeof(dns_attribute_t
),
415 if (resolver
== NULL
) {
419 // add resolver to config list
421 if (attribute_type
== CONFIG_ATTRIBUTE_RESOLVER
) {
422 config
->resolver
[n_resolver
++] = resolver
;
424 config
->scoped_resolver
[n_scoped_resolver
++] = resolver
;
434 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
435 n_attribute
-= attribute_length
;
438 if (n_resolver
!= config
->n_resolver
) {
442 if (n_scoped_resolver
!= config
->n_scoped_resolver
) {
455 dns_configuration_notify_key()
459 // initialize runtime
460 pthread_once(&_dns_initialized
, __dns_initialize
);
462 key
= _dns_configuration_notify_key();
468 dns_configuration_copy()
470 _dns_config_buf_t
*buf
;
471 dns_config_t
*config
;
473 buf
= copy_dns_info();
478 config
= expand_config(buf
);
479 if (config
== NULL
) {
489 dns_configuration_free(dns_config_t
*config
)
491 if (config
== NULL
) {
495 free((void *)config
);
501 _dns_configuration_ack(dns_config_t
*config
, const char *bundle_id
)
509 main(int argc
, char **argv
)
511 dns_config_t
*config
;
513 config
= dns_configuration_copy();
514 if (config
!= NULL
) {
515 dns_configuration_free(&config
);