]> git.saurik.com Git - apple/configd.git/blob - dnsinfo/dnsinfo_copy.c
ab536e786f38783177282e1148a9c54d4e20161c
[apple/configd.git] / dnsinfo / dnsinfo_copy.c
1 /*
2 * Copyright (c) 2004, 2006, 2008, 2009 Apple Inc. All rights reserved.
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
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <pthread.h>
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
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;
45
46
47 static 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
56 static 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
66 static boolean_t
67 add_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
83 static _dns_config_buf_t *
84 copy_dns_info()
85 {
86 uint8_t *buf = NULL;
87 dnsDataOut_t dataRef = NULL;
88 mach_msg_type_number_t dataLen = 0;
89 mach_port_t server;
90 kern_return_t status;
91
92 // initialize runtime
93 pthread_once(&_dns_initialized, __dns_initialize);
94
95 // open a new session with the DNS configuration server
96 server = _dns_server;
97 while (TRUE) {
98 if (server != MACH_PORT_NULL) {
99 status = shared_dns_infoGet(server, &dataRef, &dataLen);
100 if (status == KERN_SUCCESS) {
101 break;
102 }
103
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
107 fprintf(stderr,
108 "dns_configuration_copy shared_dns_infoGet(): %s\n",
109 mach_error_string(status));
110 break;
111 }
112 }
113
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();
120 } else {
121 // another thread has refreshed the DNS server port
122 }
123 } else {
124 _dns_server = _dns_configuration_server_port();
125 }
126 server = _dns_server;
127 pthread_mutex_unlock(&_dns_lock);
128
129 if (server == MACH_PORT_NULL) {
130 // if server not available
131 break;
132 }
133 }
134
135 if (dataRef != NULL) {
136 if (dataLen >= sizeof(_dns_config_buf_t)) {
137 _dns_config_buf_t *config = (_dns_config_buf_t *)dataRef;
138 uint32_t len;
139 uint32_t n_padding = ntohl(config->n_padding);
140
141 len = dataLen + n_padding;
142 buf = malloc(len);
143 bcopy((void *)dataRef, buf, dataLen);
144 bzero(&buf[dataLen], n_padding);
145 }
146
147 status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen);
148 if (status != KERN_SUCCESS) {
149 mach_error("vm_deallocate():", status);
150 free(buf);
151 return NULL;
152 }
153 }
154
155 return (_dns_config_buf_t *)buf;
156 }
157
158
159 static dns_resolver_t *
160 expand_resolver(_dns_resolver_buf_t *buf, uint32_t n_buf, void **padding, uint32_t *n_padding)
161 {
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;
168
169 if (n_buf < sizeof(_dns_resolver_buf_t)) {
170 goto error;
171 }
172
173 // initialize domain
174
175 resolver->domain = NULL;
176
177 // initialize nameserver list
178
179 resolver->n_nameserver = ntohl(resolver->n_nameserver);
180 if (!add_list(padding,
181 n_padding,
182 resolver->n_nameserver,
183 sizeof(DNS_PTR(struct sockaddr *, x)),
184 (void **)&resolver->nameserver)) {
185 goto error;
186 }
187
188 // initialize port
189
190 resolver->port = ntohs(resolver->port);
191
192 // initialize search list
193
194 resolver->n_search = ntohl(resolver->n_search);
195 if (!add_list(padding,
196 n_padding,
197 resolver->n_search,
198 sizeof(DNS_PTR(char *, x)),
199 (void **)&resolver->search)) {
200 goto error;
201 }
202
203 // initialize sortaddr list
204
205 resolver->n_sortaddr = ntohl(resolver->n_sortaddr);
206 if (!add_list(padding,
207 n_padding,
208 resolver->n_sortaddr,
209 sizeof(DNS_PTR(dns_sortaddr_t *, x)),
210 (void **)&resolver->sortaddr)) {
211 goto error;
212 }
213
214 // initialize options
215
216 resolver->options = NULL;
217
218 // initialize timeout
219
220 resolver->timeout = ntohl(resolver->timeout);
221
222 // initialize search_order
223
224 resolver->search_order = ntohl(resolver->search_order);
225
226 // process resolver buffer "attribute" data
227
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)) {
231 goto error;
232 }
233
234 while (n_attribute >= sizeof(dns_attribute_t)) {
235 int32_t attribute_length = ntohl(attribute->length);
236
237 switch (ntohl(attribute->type)) {
238 case RESOLVER_ATTRIBUTE_DOMAIN :
239 resolver->domain = (char *)&attribute->attribute[0];
240 break;
241
242 case RESOLVER_ATTRIBUTE_ADDRESS :
243 resolver->nameserver[n_nameserver++] = (struct sockaddr *)&attribute->attribute[0];
244 break;
245
246 case RESOLVER_ATTRIBUTE_SEARCH :
247 resolver->search[n_search++] = (char *)&attribute->attribute[0];
248 break;
249
250 case RESOLVER_ATTRIBUTE_SORTADDR :
251 resolver->sortaddr[n_sortaddr++] = (dns_sortaddr_t *)&attribute->attribute[0];
252 break;
253
254 case RESOLVER_ATTRIBUTE_OPTIONS :
255 resolver->options = (char *)&attribute->attribute[0];
256 break;
257
258 default :
259 break;
260 }
261
262 attribute = (dns_attribute_t *)((void *)attribute + attribute_length);
263 n_attribute -= attribute_length;
264 }
265
266 if ((n_nameserver != resolver->n_nameserver) ||
267 (n_search != resolver->n_search ) ||
268 (n_sortaddr != resolver->n_sortaddr )) {
269 goto error;
270 }
271
272 return resolver;
273
274 error :
275
276 return NULL;
277 }
278
279
280 static dns_config_t *
281 expand_config(_dns_config_buf_t *buf)
282 {
283 dns_attribute_t *attribute;
284 dns_config_t *config = (dns_config_t *)buf;
285 uint32_t n_attribute;
286 uint32_t n_padding;
287 int32_t n_resolver = 0;
288 void *padding;
289
290 // establish padding
291
292 padding = &buf->attribute[ntohl(buf->n_attribute)];
293 n_padding = ntohl(buf->n_padding);
294
295 // initialize resolver list
296
297 config->n_resolver = ntohl(config->n_resolver);
298 if (!add_list(&padding,
299 &n_padding,
300 config->n_resolver,
301 sizeof(DNS_PTR(dns_resolver_t *, x)),
302 (void **)&config->resolver)) {
303 goto error;
304 }
305
306 // process configuration buffer "attribute" data
307
308 n_attribute = ntohl(buf->n_attribute);
309 attribute = (dns_attribute_t *)&buf->attribute[0];
310
311 while (n_attribute >= sizeof(dns_attribute_t)) {
312 int32_t attribute_length = ntohl(attribute->length);
313
314 switch (ntohl(attribute->type)) {
315 case CONFIG_ATTRIBUTE_RESOLVER : {
316 dns_resolver_t *resolver;
317
318 // expand resolver buffer
319
320 resolver = expand_resolver((_dns_resolver_buf_t *)&attribute->attribute[0],
321 attribute_length - sizeof(dns_attribute_t),
322 &padding,
323 &n_padding);
324 if (resolver == NULL) {
325 goto error;
326 }
327
328 // add resolver to config list
329
330 config->resolver[n_resolver++] = resolver;
331
332 break;
333 }
334
335 default :
336 break;
337 }
338
339 attribute = (dns_attribute_t *)((void *)attribute + attribute_length);
340 n_attribute -= attribute_length;
341 }
342
343 if (n_resolver != config->n_resolver) {
344 goto error;
345 }
346
347 return config;
348
349 error :
350
351 return NULL;
352 }
353
354
355 const char *
356 dns_configuration_notify_key()
357 {
358 return _dns_configuration_notify_key();
359 }
360
361
362 dns_config_t *
363 dns_configuration_copy()
364 {
365 _dns_config_buf_t *buf;
366 dns_config_t *config;
367
368 buf = copy_dns_info();
369 if (buf == NULL) {
370 return NULL;
371 }
372
373 config = expand_config(buf);
374 if (config == NULL) {
375 free(buf);
376 return NULL;
377 }
378
379 return config;
380 }
381
382
383 void
384 dns_configuration_free(dns_config_t *config)
385 {
386 if (config == NULL) {
387 return;
388 }
389
390 free((void *)config);
391 return;
392 }