2 * Copyright (c) 2004, 2006, 2008-2010 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"
42 static pthread_once_t _dns_initialized
= PTHREAD_ONCE_INIT
;
43 static pthread_mutex_t _dns_lock
= PTHREAD_MUTEX_INITIALIZER
;
44 static mach_port_t _dns_server
= MACH_PORT_NULL
;
50 // the process has forked (and we are the child process)
51 _dns_server
= MACH_PORT_NULL
;
57 __dns_initialize(void)
59 // add handler to cleanup after fork()
60 (void) pthread_atfork(NULL
, NULL
, __dns_fork_handler
);
67 add_list(void **padding
, uint32_t *n_padding
, int32_t count
, int32_t size
, void **list
)
72 if (need
> *n_padding
) {
76 *list
= (need
== 0) ? NULL
: *padding
;
83 #define DNS_CONFIG_BUF_MAX 1024*1024
86 static _dns_config_buf_t
*
90 dnsDataOut_t dataRef
= NULL
;
91 mach_msg_type_number_t dataLen
= 0;
96 pthread_once(&_dns_initialized
, __dns_initialize
);
98 // open a new session with the DNS configuration server
101 if (server
!= MACH_PORT_NULL
) {
102 status
= shared_dns_infoGet(server
, &dataRef
, &dataLen
);
103 if (status
== KERN_SUCCESS
) {
107 // our [cached] server port is not valid
108 if ((status
!= MACH_SEND_INVALID_DEST
) && (status
!= MIG_SERVER_DIED
)) {
109 // if we got an unexpected error, don't retry
111 "dns_configuration_copy shared_dns_infoGet(): %s\n",
112 mach_error_string(status
));
117 pthread_mutex_lock(&_dns_lock
);
118 if (_dns_server
!= MACH_PORT_NULL
) {
119 if (server
== _dns_server
) {
120 // if the server we tried returned the error
121 (void)mach_port_deallocate(mach_task_self(), server
);
122 _dns_server
= _dns_configuration_server_port();
124 // another thread has refreshed the DNS server port
127 _dns_server
= _dns_configuration_server_port();
129 server
= _dns_server
;
130 pthread_mutex_unlock(&_dns_lock
);
132 if (server
== MACH_PORT_NULL
) {
133 // if server not available
138 if (dataRef
!= NULL
) {
139 if ((dataLen
>= sizeof(_dns_config_buf_t
)) && (dataLen
<= DNS_CONFIG_BUF_MAX
)) {
140 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)dataRef
;
141 uint32_t n_padding
= ntohl(config
->n_padding
);
143 if (n_padding
<= (DNS_CONFIG_BUF_MAX
- dataLen
)) {
146 len
= dataLen
+ n_padding
;
148 bcopy((void *)dataRef
, buf
, dataLen
);
149 bzero(&buf
[dataLen
], n_padding
);
153 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
154 if (status
!= KERN_SUCCESS
) {
155 mach_error("vm_deallocate():", status
);
161 return (_dns_config_buf_t
*)buf
;
165 static dns_resolver_t
*
166 expand_resolver(_dns_resolver_buf_t
*buf
, uint32_t n_buf
, void **padding
, uint32_t *n_padding
)
168 dns_attribute_t
*attribute
;
169 uint32_t n_attribute
;
170 int32_t n_nameserver
= 0;
171 int32_t n_search
= 0;
172 int32_t n_sortaddr
= 0;
173 dns_resolver_t
*resolver
= (dns_resolver_t
*)&buf
->resolver
;
175 if (n_buf
< sizeof(_dns_resolver_buf_t
)) {
181 resolver
->domain
= NULL
;
183 // initialize nameserver list
185 resolver
->n_nameserver
= ntohl(resolver
->n_nameserver
);
186 if (!add_list(padding
,
188 resolver
->n_nameserver
,
189 sizeof(DNS_PTR(struct sockaddr
*, x
)),
190 (void **)&resolver
->nameserver
)) {
196 resolver
->port
= ntohs(resolver
->port
);
198 // initialize search list
200 resolver
->n_search
= ntohl(resolver
->n_search
);
201 if (!add_list(padding
,
204 sizeof(DNS_PTR(char *, x
)),
205 (void **)&resolver
->search
)) {
209 // initialize sortaddr list
211 resolver
->n_sortaddr
= ntohl(resolver
->n_sortaddr
);
212 if (!add_list(padding
,
214 resolver
->n_sortaddr
,
215 sizeof(DNS_PTR(dns_sortaddr_t
*, x
)),
216 (void **)&resolver
->sortaddr
)) {
220 // initialize options
222 resolver
->options
= NULL
;
224 // initialize timeout
226 resolver
->timeout
= ntohl(resolver
->timeout
);
228 // initialize search_order
230 resolver
->search_order
= ntohl(resolver
->search_order
);
232 // initialize if_index
234 resolver
->if_index
= ntohl(resolver
->if_index
);
238 resolver
->flags
= ntohl(resolver
->flags
);
240 // process resolver buffer "attribute" data
242 n_attribute
= n_buf
- sizeof(_dns_resolver_buf_t
);
243 attribute
= (dns_attribute_t
*)&buf
->attribute
[0];
244 if (n_attribute
!= ntohl(buf
->n_attribute
)) {
248 while (n_attribute
>= sizeof(dns_attribute_t
)) {
249 int32_t attribute_length
= ntohl(attribute
->length
);
251 switch (ntohl(attribute
->type
)) {
252 case RESOLVER_ATTRIBUTE_DOMAIN
:
253 resolver
->domain
= (char *)&attribute
->attribute
[0];
256 case RESOLVER_ATTRIBUTE_ADDRESS
:
257 resolver
->nameserver
[n_nameserver
++] = (struct sockaddr
*)&attribute
->attribute
[0];
260 case RESOLVER_ATTRIBUTE_SEARCH
:
261 resolver
->search
[n_search
++] = (char *)&attribute
->attribute
[0];
264 case RESOLVER_ATTRIBUTE_SORTADDR
:
265 resolver
->sortaddr
[n_sortaddr
++] = (dns_sortaddr_t
*)&attribute
->attribute
[0];
268 case RESOLVER_ATTRIBUTE_OPTIONS
:
269 resolver
->options
= (char *)&attribute
->attribute
[0];
276 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
277 n_attribute
-= attribute_length
;
280 if ((n_nameserver
!= resolver
->n_nameserver
) ||
281 (n_search
!= resolver
->n_search
) ||
282 (n_sortaddr
!= resolver
->n_sortaddr
)) {
294 static dns_config_t
*
295 expand_config(_dns_config_buf_t
*buf
)
297 dns_attribute_t
*attribute
;
298 dns_config_t
*config
= (dns_config_t
*)buf
;
299 uint32_t n_attribute
;
301 int32_t n_resolver
= 0;
302 int32_t n_scoped_resolver
= 0;
307 padding
= &buf
->attribute
[ntohl(buf
->n_attribute
)];
308 n_padding
= ntohl(buf
->n_padding
);
310 // initialize resolver lists
312 config
->n_resolver
= ntohl(config
->n_resolver
);
313 if (!add_list(&padding
,
316 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
317 (void **)&config
->resolver
)) {
321 config
->n_scoped_resolver
= ntohl(config
->n_scoped_resolver
);
322 if (!add_list(&padding
,
324 config
->n_scoped_resolver
,
325 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
326 (void **)&config
->scoped_resolver
)) {
330 // process configuration buffer "attribute" data
332 n_attribute
= ntohl(buf
->n_attribute
);
333 attribute
= (dns_attribute_t
*)&buf
->attribute
[0];
335 while (n_attribute
>= sizeof(dns_attribute_t
)) {
336 uint32_t attribute_length
= ntohl(attribute
->length
);
337 uint32_t attribute_type
= ntohl(attribute
->type
);
339 switch (attribute_type
) {
340 case CONFIG_ATTRIBUTE_RESOLVER
:
341 case CONFIG_ATTRIBUTE_SCOPED_RESOLVER
: {
342 dns_resolver_t
*resolver
;
344 // expand resolver buffer
346 resolver
= expand_resolver((_dns_resolver_buf_t
*)&attribute
->attribute
[0],
347 attribute_length
- sizeof(dns_attribute_t
),
350 if (resolver
== NULL
) {
354 // add resolver to config list
356 if (attribute_type
== CONFIG_ATTRIBUTE_RESOLVER
) {
357 config
->resolver
[n_resolver
++] = resolver
;
359 config
->scoped_resolver
[n_scoped_resolver
++] = resolver
;
369 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
370 n_attribute
-= attribute_length
;
373 if (n_resolver
!= config
->n_resolver
) {
377 if (n_scoped_resolver
!= config
->n_scoped_resolver
) {
390 dns_configuration_notify_key()
394 // initialize runtime
395 pthread_once(&_dns_initialized
, __dns_initialize
);
397 key
= _dns_configuration_notify_key();
403 dns_configuration_copy()
405 _dns_config_buf_t
*buf
;
406 dns_config_t
*config
;
408 buf
= copy_dns_info();
413 config
= expand_config(buf
);
414 if (config
== NULL
) {
424 dns_configuration_free(dns_config_t
*config
)
426 if (config
== NULL
) {
430 free((void *)config
);
437 main(int argc
, char **argv
)
439 dns_config_t
*config
;
441 config
= dns_configuration_copy();
442 if (config
!= NULL
) {
443 dns_configuration_free(&config
);