configd-395.11.tar.gz
[apple/configd.git] / dnsinfo / dnsinfo_copy.c
CommitLineData
dbf6a266 1/*
6bb65964 2 * Copyright (c) 2004, 2006, 2008-2010 Apple Inc. All rights reserved.
dbf6a266
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
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
11 * file.
12 *
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.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 * Modification History
26 *
27 * March 9, 2004 Allan Nathanson <ajn@apple.com>
28 * - initial revision
29 */
30
a40a14f8 31#include <stdio.h>
dbf6a266 32#include <stdlib.h>
a40a14f8 33#include <pthread.h>
dbf6a266
A
34#include <mach/mach.h>
35#include <mach/mach_error.h>
36
37#include "dnsinfo.h"
38#include "dnsinfo_private.h"
39#include "shared_dns_info.h"
40
41
a40a14f8
A
42static pthread_once_t _dns_initialized = PTHREAD_ONCE_INIT;
43static pthread_mutex_t _dns_lock = PTHREAD_MUTEX_INITIALIZER;
44static mach_port_t _dns_server = MACH_PORT_NULL;
45
46
47static void
48__dns_fork_handler()
49{
50 // the process has forked (and we are the child process)
51 _dns_server = MACH_PORT_NULL;
52 return;
53}
54
55
56static void
57__dns_initialize(void)
58{
59 // add handler to cleanup after fork()
60 (void) pthread_atfork(NULL, NULL, __dns_fork_handler);
61
62 return;
63}
64
65
dbf6a266
A
66static boolean_t
67add_list(void **padding, uint32_t *n_padding, int32_t count, int32_t size, void **list)
68{
69 int32_t need;
70
71 need = count * size;
72 if (need > *n_padding) {
73 return FALSE;
74 }
75
76 *list = (need == 0) ? NULL : *padding;
77 *padding += need;
78 *n_padding -= need;
79 return TRUE;
80}
81
82
6bb65964
A
83#define DNS_CONFIG_BUF_MAX 1024*1024
84
85
dbf6a266
A
86static _dns_config_buf_t *
87copy_dns_info()
88{
89 uint8_t *buf = NULL;
90 dnsDataOut_t dataRef = NULL;
91 mach_msg_type_number_t dataLen = 0;
92 mach_port_t server;
93 kern_return_t status;
94
a40a14f8
A
95 // initialize runtime
96 pthread_once(&_dns_initialized, __dns_initialize);
dbf6a266 97
a40a14f8
A
98 // open a new session with the DNS configuration server
99 server = _dns_server;
100 while (TRUE) {
101 if (server != MACH_PORT_NULL) {
102 status = shared_dns_infoGet(server, &dataRef, &dataLen);
103 if (status == KERN_SUCCESS) {
104 break;
105 }
106
107 // our [cached] server port is not valid
6bb65964 108 if ((status != MACH_SEND_INVALID_DEST) && (status != MIG_SERVER_DIED)) {
a40a14f8
A
109 // if we got an unexpected error, don't retry
110 fprintf(stderr,
111 "dns_configuration_copy shared_dns_infoGet(): %s\n",
112 mach_error_string(status));
113 break;
114 }
115 }
116
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();
123 } else {
124 // another thread has refreshed the DNS server port
125 }
126 } else {
127 _dns_server = _dns_configuration_server_port();
128 }
129 server = _dns_server;
130 pthread_mutex_unlock(&_dns_lock);
131
132 if (server == MACH_PORT_NULL) {
133 // if server not available
134 break;
135 }
dbf6a266
A
136 }
137
138 if (dataRef != NULL) {
6bb65964 139 if ((dataLen >= sizeof(_dns_config_buf_t)) && (dataLen <= DNS_CONFIG_BUF_MAX)) {
dbf6a266 140 _dns_config_buf_t *config = (_dns_config_buf_t *)dataRef;
dbf6a266
A
141 uint32_t n_padding = ntohl(config->n_padding);
142
6bb65964
A
143 if (n_padding <= (DNS_CONFIG_BUF_MAX - dataLen)) {
144 uint32_t len;
145
146 len = dataLen + n_padding;
147 buf = malloc(len);
148 bcopy((void *)dataRef, buf, dataLen);
149 bzero(&buf[dataLen], n_padding);
150 }
dbf6a266
A
151 }
152
153 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
154 if (status != KERN_SUCCESS) {
155 mach_error("vm_deallocate():", status);
156 free(buf);
157 return NULL;
158 }
159 }
160
161 return (_dns_config_buf_t *)buf;
162}
163
164
165static dns_resolver_t *
166expand_resolver(_dns_resolver_buf_t *buf, uint32_t n_buf, void **padding, uint32_t *n_padding)
167{
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;
174
175 if (n_buf < sizeof(_dns_resolver_buf_t)) {
176 goto error;
177 }
178
179 // initialize domain
180
181 resolver->domain = NULL;
182
183 // initialize nameserver list
184
185 resolver->n_nameserver = ntohl(resolver->n_nameserver);
186 if (!add_list(padding,
187 n_padding,
188 resolver->n_nameserver,
edebe297 189 sizeof(DNS_PTR(struct sockaddr *, x)),
dbf6a266
A
190 (void **)&resolver->nameserver)) {
191 goto error;
192 }
193
194 // initialize port
195
196 resolver->port = ntohs(resolver->port);
197
198 // initialize search list
199
200 resolver->n_search = ntohl(resolver->n_search);
201 if (!add_list(padding,
202 n_padding,
203 resolver->n_search,
edebe297 204 sizeof(DNS_PTR(char *, x)),
dbf6a266
A
205 (void **)&resolver->search)) {
206 goto error;
207 }
208
209 // initialize sortaddr list
210
211 resolver->n_sortaddr = ntohl(resolver->n_sortaddr);
212 if (!add_list(padding,
213 n_padding,
214 resolver->n_sortaddr,
edebe297 215 sizeof(DNS_PTR(dns_sortaddr_t *, x)),
dbf6a266
A
216 (void **)&resolver->sortaddr)) {
217 goto error;
218 }
219
220 // initialize options
221
222 resolver->options = NULL;
223
224 // initialize timeout
225
226 resolver->timeout = ntohl(resolver->timeout);
227
228 // initialize search_order
229
230 resolver->search_order = ntohl(resolver->search_order);
231
6bb65964
A
232 // initialize if_index
233
234 resolver->if_index = ntohl(resolver->if_index);
235
236 // initialize flags
237
238 resolver->flags = ntohl(resolver->flags);
239
dbf6a266
A
240 // process resolver buffer "attribute" data
241
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)) {
245 goto error;
246 }
247
248 while (n_attribute >= sizeof(dns_attribute_t)) {
249 int32_t attribute_length = ntohl(attribute->length);
250
251 switch (ntohl(attribute->type)) {
252 case RESOLVER_ATTRIBUTE_DOMAIN :
253 resolver->domain = (char *)&attribute->attribute[0];
254 break;
255
256 case RESOLVER_ATTRIBUTE_ADDRESS :
257 resolver->nameserver[n_nameserver++] = (struct sockaddr *)&attribute->attribute[0];
258 break;
259
260 case RESOLVER_ATTRIBUTE_SEARCH :
261 resolver->search[n_search++] = (char *)&attribute->attribute[0];
262 break;
263
264 case RESOLVER_ATTRIBUTE_SORTADDR :
265 resolver->sortaddr[n_sortaddr++] = (dns_sortaddr_t *)&attribute->attribute[0];
266 break;
267
268 case RESOLVER_ATTRIBUTE_OPTIONS :
269 resolver->options = (char *)&attribute->attribute[0];
270 break;
271
272 default :
273 break;
274 }
275
276 attribute = (dns_attribute_t *)((void *)attribute + attribute_length);
277 n_attribute -= attribute_length;
278 }
279
280 if ((n_nameserver != resolver->n_nameserver) ||
281 (n_search != resolver->n_search ) ||
282 (n_sortaddr != resolver->n_sortaddr )) {
283 goto error;
284 }
285
286 return resolver;
287
288 error :
289
290 return NULL;
291}
292
293
294static dns_config_t *
295expand_config(_dns_config_buf_t *buf)
296{
297 dns_attribute_t *attribute;
6bb65964 298 dns_config_t *config = (dns_config_t *)buf;
dbf6a266
A
299 uint32_t n_attribute;
300 uint32_t n_padding;
6bb65964
A
301 int32_t n_resolver = 0;
302 int32_t n_scoped_resolver = 0;
dbf6a266
A
303 void *padding;
304
305 // establish padding
306
307 padding = &buf->attribute[ntohl(buf->n_attribute)];
308 n_padding = ntohl(buf->n_padding);
309
6bb65964 310 // initialize resolver lists
dbf6a266
A
311
312 config->n_resolver = ntohl(config->n_resolver);
313 if (!add_list(&padding,
314 &n_padding,
315 config->n_resolver,
edebe297 316 sizeof(DNS_PTR(dns_resolver_t *, x)),
dbf6a266
A
317 (void **)&config->resolver)) {
318 goto error;
319 }
320
6bb65964
A
321 config->n_scoped_resolver = ntohl(config->n_scoped_resolver);
322 if (!add_list(&padding,
323 &n_padding,
324 config->n_scoped_resolver,
325 sizeof(DNS_PTR(dns_resolver_t *, x)),
326 (void **)&config->scoped_resolver)) {
327 goto error;
328 }
329
dbf6a266
A
330 // process configuration buffer "attribute" data
331
332 n_attribute = ntohl(buf->n_attribute);
333 attribute = (dns_attribute_t *)&buf->attribute[0];
334
335 while (n_attribute >= sizeof(dns_attribute_t)) {
6bb65964
A
336 uint32_t attribute_length = ntohl(attribute->length);
337 uint32_t attribute_type = ntohl(attribute->type);
dbf6a266 338
6bb65964
A
339 switch (attribute_type) {
340 case CONFIG_ATTRIBUTE_RESOLVER :
341 case CONFIG_ATTRIBUTE_SCOPED_RESOLVER : {
dbf6a266
A
342 dns_resolver_t *resolver;
343
344 // expand resolver buffer
345
346 resolver = expand_resolver((_dns_resolver_buf_t *)&attribute->attribute[0],
347 attribute_length - sizeof(dns_attribute_t),
348 &padding,
349 &n_padding);
350 if (resolver == NULL) {
351 goto error;
352 }
353
354 // add resolver to config list
355
6bb65964
A
356 if (attribute_type == CONFIG_ATTRIBUTE_RESOLVER) {
357 config->resolver[n_resolver++] = resolver;
358 } else {
359 config->scoped_resolver[n_scoped_resolver++] = resolver;
360 }
dbf6a266
A
361
362 break;
363 }
364
365 default :
366 break;
367 }
368
369 attribute = (dns_attribute_t *)((void *)attribute + attribute_length);
370 n_attribute -= attribute_length;
371 }
372
373 if (n_resolver != config->n_resolver) {
374 goto error;
375 }
376
6bb65964
A
377 if (n_scoped_resolver != config->n_scoped_resolver) {
378 goto error;
379 }
380
dbf6a266
A
381 return config;
382
383 error :
384
385 return NULL;
386}
387
388
dbf6a266
A
389const char *
390dns_configuration_notify_key()
391{
6bb65964
A
392 const char *key;
393
394 // initialize runtime
395 pthread_once(&_dns_initialized, __dns_initialize);
396
397 key = _dns_configuration_notify_key();
398 return key;
dbf6a266
A
399}
400
401
dbf6a266
A
402dns_config_t *
403dns_configuration_copy()
404{
405 _dns_config_buf_t *buf;
406 dns_config_t *config;
407
408 buf = copy_dns_info();
409 if (buf == NULL) {
410 return NULL;
411 }
412
413 config = expand_config(buf);
414 if (config == NULL) {
415 free(buf);
416 return NULL;
417 }
418
419 return config;
420}
421
422
dbf6a266
A
423void
424dns_configuration_free(dns_config_t *config)
425{
426 if (config == NULL) {
427 return;
428 }
429
430 free((void *)config);
431 return;
432}
6bb65964
A
433
434#ifdef MAIN
435
436int
437main(int argc, char **argv)
438{
439 dns_config_t *config;
440
441 config = dns_configuration_copy();
442 if (config != NULL) {
443 dns_configuration_free(&config);
444 }
445
446 exit(0);
447}
448
449#endif