2 * Copyright (c) 2004, 2006, 2008, 2009 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 static _dns_config_buf_t
*
87 dnsDataOut_t dataRef
= NULL
;
88 mach_msg_type_number_t dataLen
= 0;
93 pthread_once(&_dns_initialized
, __dns_initialize
);
95 // open a new session with the DNS configuration server
98 if (server
!= MACH_PORT_NULL
) {
99 status
= shared_dns_infoGet(server
, &dataRef
, &dataLen
);
100 if (status
== KERN_SUCCESS
) {
104 // our [cached] server port is not valid
105 if (status
!= MACH_SEND_INVALID_DEST
) {
106 // if we got an unexpected error, don't retry
108 "dns_configuration_copy shared_dns_infoGet(): %s\n",
109 mach_error_string(status
));
114 pthread_mutex_lock(&_dns_lock
);
115 if (_dns_server
!= MACH_PORT_NULL
) {
116 if (server
== _dns_server
) {
117 // if the server we tried returned the error
118 (void)mach_port_deallocate(mach_task_self(), server
);
119 _dns_server
= _dns_configuration_server_port();
121 // another thread has refreshed the DNS server port
124 _dns_server
= _dns_configuration_server_port();
126 server
= _dns_server
;
127 pthread_mutex_unlock(&_dns_lock
);
129 if (server
== MACH_PORT_NULL
) {
130 // if server not available
135 if (dataRef
!= NULL
) {
136 if (dataLen
>= sizeof(_dns_config_buf_t
)) {
137 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)dataRef
;
139 uint32_t n_padding
= ntohl(config
->n_padding
);
141 len
= dataLen
+ n_padding
;
143 bcopy((void *)dataRef
, buf
, dataLen
);
144 bzero(&buf
[dataLen
], n_padding
);
147 status
= vm_deallocate(mach_task_self(), (vm_address_t
)dataRef
, dataLen
);
148 if (status
!= KERN_SUCCESS
) {
149 mach_error("vm_deallocate():", status
);
155 return (_dns_config_buf_t
*)buf
;
159 static dns_resolver_t
*
160 expand_resolver(_dns_resolver_buf_t
*buf
, uint32_t n_buf
, void **padding
, uint32_t *n_padding
)
162 dns_attribute_t
*attribute
;
163 uint32_t n_attribute
;
164 int32_t n_nameserver
= 0;
165 int32_t n_search
= 0;
166 int32_t n_sortaddr
= 0;
167 dns_resolver_t
*resolver
= (dns_resolver_t
*)&buf
->resolver
;
169 if (n_buf
< sizeof(_dns_resolver_buf_t
)) {
175 resolver
->domain
= NULL
;
177 // initialize nameserver list
179 resolver
->n_nameserver
= ntohl(resolver
->n_nameserver
);
180 if (!add_list(padding
,
182 resolver
->n_nameserver
,
183 sizeof(DNS_PTR(struct sockaddr
*, x
)),
184 (void **)&resolver
->nameserver
)) {
190 resolver
->port
= ntohs(resolver
->port
);
192 // initialize search list
194 resolver
->n_search
= ntohl(resolver
->n_search
);
195 if (!add_list(padding
,
198 sizeof(DNS_PTR(char *, x
)),
199 (void **)&resolver
->search
)) {
203 // initialize sortaddr list
205 resolver
->n_sortaddr
= ntohl(resolver
->n_sortaddr
);
206 if (!add_list(padding
,
208 resolver
->n_sortaddr
,
209 sizeof(DNS_PTR(dns_sortaddr_t
*, x
)),
210 (void **)&resolver
->sortaddr
)) {
214 // initialize options
216 resolver
->options
= NULL
;
218 // initialize timeout
220 resolver
->timeout
= ntohl(resolver
->timeout
);
222 // initialize search_order
224 resolver
->search_order
= ntohl(resolver
->search_order
);
226 // process resolver buffer "attribute" data
228 n_attribute
= n_buf
- sizeof(_dns_resolver_buf_t
);
229 attribute
= (dns_attribute_t
*)&buf
->attribute
[0];
230 if (n_attribute
!= ntohl(buf
->n_attribute
)) {
234 while (n_attribute
>= sizeof(dns_attribute_t
)) {
235 int32_t attribute_length
= ntohl(attribute
->length
);
237 switch (ntohl(attribute
->type
)) {
238 case RESOLVER_ATTRIBUTE_DOMAIN
:
239 resolver
->domain
= (char *)&attribute
->attribute
[0];
242 case RESOLVER_ATTRIBUTE_ADDRESS
:
243 resolver
->nameserver
[n_nameserver
++] = (struct sockaddr
*)&attribute
->attribute
[0];
246 case RESOLVER_ATTRIBUTE_SEARCH
:
247 resolver
->search
[n_search
++] = (char *)&attribute
->attribute
[0];
250 case RESOLVER_ATTRIBUTE_SORTADDR
:
251 resolver
->sortaddr
[n_sortaddr
++] = (dns_sortaddr_t
*)&attribute
->attribute
[0];
254 case RESOLVER_ATTRIBUTE_OPTIONS
:
255 resolver
->options
= (char *)&attribute
->attribute
[0];
262 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
263 n_attribute
-= attribute_length
;
266 if ((n_nameserver
!= resolver
->n_nameserver
) ||
267 (n_search
!= resolver
->n_search
) ||
268 (n_sortaddr
!= resolver
->n_sortaddr
)) {
280 static dns_config_t
*
281 expand_config(_dns_config_buf_t
*buf
)
283 dns_attribute_t
*attribute
;
284 dns_config_t
*config
= (dns_config_t
*)buf
;
285 uint32_t n_attribute
;
287 int32_t n_resolver
= 0;
292 padding
= &buf
->attribute
[ntohl(buf
->n_attribute
)];
293 n_padding
= ntohl(buf
->n_padding
);
295 // initialize resolver list
297 config
->n_resolver
= ntohl(config
->n_resolver
);
298 if (!add_list(&padding
,
301 sizeof(DNS_PTR(dns_resolver_t
*, x
)),
302 (void **)&config
->resolver
)) {
306 // process configuration buffer "attribute" data
308 n_attribute
= ntohl(buf
->n_attribute
);
309 attribute
= (dns_attribute_t
*)&buf
->attribute
[0];
311 while (n_attribute
>= sizeof(dns_attribute_t
)) {
312 int32_t attribute_length
= ntohl(attribute
->length
);
314 switch (ntohl(attribute
->type
)) {
315 case CONFIG_ATTRIBUTE_RESOLVER
: {
316 dns_resolver_t
*resolver
;
318 // expand resolver buffer
320 resolver
= expand_resolver((_dns_resolver_buf_t
*)&attribute
->attribute
[0],
321 attribute_length
- sizeof(dns_attribute_t
),
324 if (resolver
== NULL
) {
328 // add resolver to config list
330 config
->resolver
[n_resolver
++] = resolver
;
339 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
340 n_attribute
-= attribute_length
;
343 if (n_resolver
!= config
->n_resolver
) {
356 dns_configuration_notify_key()
358 return _dns_configuration_notify_key();
363 dns_configuration_copy()
365 _dns_config_buf_t
*buf
;
366 dns_config_t
*config
;
368 buf
= copy_dns_info();
373 config
= expand_config(buf
);
374 if (config
== NULL
) {
384 dns_configuration_free(dns_config_t
*config
)
386 if (config
== NULL
) {
390 free((void *)config
);