]> git.saurik.com Git - apple/configd.git/blob - dnsinfo/dnsinfo_copy.c
configd-596.12.tar.gz
[apple/configd.git] / dnsinfo / dnsinfo_copy.c
1 /*
2 * Copyright (c) 2004, 2006, 2008-2013 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 #include <dispatch/dispatch.h>
37 #include <xpc/xpc.h>
38
39 #include "libSystemConfiguration_client.h"
40 #include "dnsinfo.h"
41 #include "dnsinfo_private.h"
42
43 typedef uint32_t getflags;
44
45 static boolean_t
46 add_list(void **padding, uint32_t *n_padding, int32_t count, int32_t size, void **list)
47 {
48 int32_t need;
49
50 need = count * size;
51 if (need > *n_padding) {
52 return FALSE;
53 }
54
55 *list = (need == 0) ? NULL : *padding;
56 *padding += need;
57 *n_padding -= need;
58 return TRUE;
59 }
60
61
62 #define DNS_CONFIG_BUF_MAX 1024*1024
63
64
65 static dns_resolver_t *
66 expand_resolver(_dns_resolver_buf_t *buf, uint32_t n_buf, void **padding, uint32_t *n_padding)
67 {
68 dns_attribute_t *attribute;
69 uint32_t n_attribute;
70 int32_t n_nameserver = 0;
71 int32_t n_search = 0;
72 int32_t n_sortaddr = 0;
73 dns_resolver_t *resolver = (dns_resolver_t *)&buf->resolver;
74
75 if (n_buf < sizeof(_dns_resolver_buf_t)) {
76 goto error;
77 }
78
79 // initialize domain
80
81 resolver->domain = NULL;
82
83 // initialize nameserver list
84
85 resolver->n_nameserver = ntohl(resolver->n_nameserver);
86 if (!add_list(padding,
87 n_padding,
88 resolver->n_nameserver,
89 sizeof(DNS_PTR(struct sockaddr *, x)),
90 (void **)&resolver->nameserver)) {
91 goto error;
92 }
93
94 // initialize port
95
96 resolver->port = ntohs(resolver->port);
97
98 // initialize search list
99
100 resolver->n_search = ntohl(resolver->n_search);
101 if (!add_list(padding,
102 n_padding,
103 resolver->n_search,
104 sizeof(DNS_PTR(char *, x)),
105 (void **)&resolver->search)) {
106 goto error;
107 }
108
109 // initialize sortaddr list
110
111 resolver->n_sortaddr = ntohl(resolver->n_sortaddr);
112 if (!add_list(padding,
113 n_padding,
114 resolver->n_sortaddr,
115 sizeof(DNS_PTR(dns_sortaddr_t *, x)),
116 (void **)&resolver->sortaddr)) {
117 goto error;
118 }
119
120 // initialize options
121
122 resolver->options = NULL;
123
124 // initialize timeout
125
126 resolver->timeout = ntohl(resolver->timeout);
127
128 // initialize search_order
129
130 resolver->search_order = ntohl(resolver->search_order);
131
132 // initialize if_index
133
134 resolver->if_index = ntohl(resolver->if_index);
135
136 // initialize service_identifier
137
138 resolver->service_identifier = ntohl(resolver->service_identifier);
139
140 // initialize flags
141
142 resolver->flags = ntohl(resolver->flags);
143
144 // initialize SCNetworkReachability flags
145
146 resolver->reach_flags = ntohl(resolver->reach_flags);
147
148 // process resolver buffer "attribute" data
149
150 n_attribute = n_buf - sizeof(_dns_resolver_buf_t);
151 /* ALIGN: alignment not assumed, using accessors */
152 attribute = (dns_attribute_t *)(void *)&buf->attribute[0];
153 if (n_attribute != ntohl(buf->n_attribute)) {
154 goto error;
155 }
156
157 while (n_attribute >= sizeof(dns_attribute_t)) {
158 uint32_t attribute_length = ntohl(attribute->length);
159
160 switch (ntohl(attribute->type)) {
161 case RESOLVER_ATTRIBUTE_DOMAIN :
162 resolver->domain = (char *)&attribute->attribute[0];
163 break;
164
165 case RESOLVER_ATTRIBUTE_ADDRESS :
166 resolver->nameserver[n_nameserver++] = (struct sockaddr *)&attribute->attribute[0];
167 break;
168
169 case RESOLVER_ATTRIBUTE_SEARCH :
170 resolver->search[n_search++] = (char *)&attribute->attribute[0];
171 break;
172
173 case RESOLVER_ATTRIBUTE_SORTADDR :
174 resolver->sortaddr[n_sortaddr++] = (dns_sortaddr_t *)(void *)&attribute->attribute[0];
175 break;
176
177 case RESOLVER_ATTRIBUTE_OPTIONS :
178 resolver->options = (char *)&attribute->attribute[0];
179 break;
180
181 default :
182 break;
183 }
184
185 attribute = (dns_attribute_t *)((void *)attribute + attribute_length);
186 n_attribute -= attribute_length;
187 }
188
189 if ((n_nameserver != resolver->n_nameserver) ||
190 (n_search != resolver->n_search ) ||
191 (n_sortaddr != resolver->n_sortaddr )) {
192 goto error;
193 }
194
195 return resolver;
196
197 error :
198
199 return NULL;
200 }
201
202
203 static dns_config_t *
204 expand_config(_dns_config_buf_t *buf)
205 {
206 dns_attribute_t *attribute;
207 dns_config_t *config = (dns_config_t *)buf;
208 uint32_t n_attribute;
209 uint32_t n_padding;
210 int32_t n_resolver = 0;
211 int32_t n_scoped_resolver = 0;
212 int32_t n_service_specific_resolver = 0;
213 void *padding;
214
215 // establish padding
216
217 padding = &buf->attribute[ntohl(buf->n_attribute)];
218 n_padding = ntohl(buf->n_padding);
219
220 // initialize resolver lists
221
222 config->n_resolver = ntohl(config->n_resolver);
223 if (!add_list(&padding,
224 &n_padding,
225 config->n_resolver,
226 sizeof(DNS_PTR(dns_resolver_t *, x)),
227 (void **)&config->resolver)) {
228 goto error;
229 }
230
231 config->n_scoped_resolver = ntohl(config->n_scoped_resolver);
232 if (!add_list(&padding,
233 &n_padding,
234 config->n_scoped_resolver,
235 sizeof(DNS_PTR(dns_resolver_t *, x)),
236 (void **)&config->scoped_resolver)) {
237 goto error;
238 }
239
240 config->n_service_specific_resolver = ntohl(config->n_service_specific_resolver);
241 if (!add_list(&padding,
242 &n_padding,
243 config->n_service_specific_resolver,
244 sizeof(DNS_PTR(dns_resolver_t *, x)),
245 (void **)&config->service_specific_resolver)) {
246 goto error;
247 }
248
249 // process configuration buffer "attribute" data
250
251 n_attribute = ntohl(buf->n_attribute);
252 attribute = (dns_attribute_t *)(void *)&buf->attribute[0];
253
254 while (n_attribute >= sizeof(dns_attribute_t)) {
255 uint32_t attribute_length = ntohl(attribute->length);
256 uint32_t attribute_type = ntohl(attribute->type);
257
258 switch (attribute_type) {
259 case CONFIG_ATTRIBUTE_RESOLVER :
260 case CONFIG_ATTRIBUTE_SCOPED_RESOLVER :
261 case CONFIG_ATTRIBUTE_SERVICE_SPECIFIC_RESOLVER : {
262 dns_resolver_t *resolver;
263
264 // expand resolver buffer
265
266 resolver = expand_resolver((_dns_resolver_buf_t *)(void *)&attribute->attribute[0],
267 attribute_length - sizeof(dns_attribute_t),
268 &padding,
269 &n_padding);
270 if (resolver == NULL) {
271 goto error;
272 }
273
274 // add resolver to config list
275
276 if (attribute_type == CONFIG_ATTRIBUTE_RESOLVER) {
277 config->resolver[n_resolver++] = resolver;
278 } else if (attribute_type == CONFIG_ATTRIBUTE_SCOPED_RESOLVER) {
279 config->scoped_resolver[n_scoped_resolver++] = resolver;
280 } else if (attribute_type == CONFIG_ATTRIBUTE_SERVICE_SPECIFIC_RESOLVER) {
281 config->service_specific_resolver[n_service_specific_resolver++] = resolver;
282 }
283
284 break;
285 }
286
287 default :
288 break;
289 }
290
291 attribute = (dns_attribute_t *)((void *)attribute + attribute_length);
292 n_attribute -= attribute_length;
293 }
294
295 if (n_resolver != config->n_resolver) {
296 goto error;
297 }
298
299 if (n_scoped_resolver != config->n_scoped_resolver) {
300 goto error;
301 }
302
303 if (n_service_specific_resolver != config->n_service_specific_resolver) {
304 goto error;
305 }
306
307 return config;
308
309 error :
310
311 return NULL;
312 }
313
314
315 const char *
316 dns_configuration_notify_key()
317 {
318 const char *key;
319
320 #if !TARGET_IPHONE_SIMULATOR
321 key = "com.apple.system.SystemConfiguration.dns_configuration";
322 #else // !TARGET_IPHONE_SIMULATOR
323 key = "com.apple.iOS_Simulator.SystemConfiguration.dns_configuration";
324 #endif // !TARGET_IPHONE_SIMULATOR
325 return key;
326 }
327
328
329 #pragma mark -
330 #pragma mark DNS configuration [dnsinfo] client support
331
332
333 // Note: protected by __dns_configuration_queue()
334 static int dnsinfo_active = 0;
335 static libSC_info_client_t *dnsinfo_client = NULL;
336
337
338 static dispatch_queue_t
339 __dns_configuration_queue()
340 {
341 static dispatch_once_t once;
342 static dispatch_queue_t q;
343
344 dispatch_once(&once, ^{
345 q = dispatch_queue_create(DNSINFO_SERVICE_NAME, NULL);
346 });
347
348 return q;
349 }
350
351
352 dns_config_t *
353 dns_configuration_copy()
354 {
355 uint8_t *buf = NULL;
356 dns_config_t *config = NULL;
357 static const char *proc_name = NULL;
358 xpc_object_t reqdict;
359 xpc_object_t reply;
360
361 dispatch_sync(__dns_configuration_queue(), ^{
362 if ((dnsinfo_active++ == 0) || (dnsinfo_client == NULL)) {
363 static dispatch_once_t once;
364 static const char *service_name = DNSINFO_SERVICE_NAME;
365
366 dispatch_once(&once, ^{
367 const char *name;
368
369 // get [XPC] service name
370 name = getenv(service_name);
371 if ((name != NULL) && (issetugid() == 0)) {
372 service_name = strdup(name);
373 }
374
375 // get process name
376 proc_name = getprogname();
377 });
378
379 dnsinfo_client =
380 libSC_info_client_create(__dns_configuration_queue(), // dispatch queue
381 service_name, // XPC service name
382 "DNS configuration"); // service description
383 if (dnsinfo_client == NULL) {
384 --dnsinfo_active;
385 }
386 }
387 });
388
389 if ((dnsinfo_client == NULL) || !dnsinfo_client->active) {
390 // if DNS configuration server not available
391 return NULL;
392 }
393
394 // create message
395 reqdict = xpc_dictionary_create(NULL, NULL, 0);
396
397 // set process name
398 if (proc_name != NULL) {
399 xpc_dictionary_set_string(reqdict, DNSINFO_PROC_NAME, proc_name);
400 }
401
402 // set request
403 xpc_dictionary_set_int64(reqdict, DNSINFO_REQUEST, DNSINFO_REQUEST_COPY);
404
405 // send request to the DNS configuration server
406 reply = libSC_send_message_with_reply_sync(dnsinfo_client, reqdict);
407 xpc_release(reqdict);
408
409 if (reply != NULL) {
410 const void *dataRef;
411 size_t dataLen = 0;
412
413 dataRef = xpc_dictionary_get_data(reply, DNSINFO_CONFIGURATION, &dataLen);
414 if ((dataRef != NULL) &&
415 ((dataLen >= sizeof(_dns_config_buf_t)) && (dataLen <= DNS_CONFIG_BUF_MAX))) {
416 _dns_config_buf_t *config = (_dns_config_buf_t *)(void *)dataRef;
417 uint32_t n_padding = ntohl(config->n_padding);
418
419 if (n_padding <= (DNS_CONFIG_BUF_MAX - dataLen)) {
420 uint32_t len;
421
422 len = dataLen + n_padding;
423 buf = malloc(len);
424 bcopy((void *)dataRef, buf, dataLen);
425 bzero(&buf[dataLen], n_padding);
426 }
427 }
428
429 xpc_release(reply);
430 }
431
432 if (buf != NULL) {
433 /* ALIGN: cast okay since _dns_config_buf_t is int aligned */
434 config = expand_config((_dns_config_buf_t *)(void *)buf);
435 if (config == NULL) {
436 free(buf);
437 }
438 }
439
440 return config;
441 }
442
443
444 void
445 dns_configuration_free(dns_config_t *config)
446 {
447 if (config == NULL) {
448 return; // ASSERT
449 }
450
451 dispatch_sync(__dns_configuration_queue(), ^{
452 if (--dnsinfo_active == 0) {
453 // if last reference, drop connection
454 libSC_info_client_release(dnsinfo_client);
455 dnsinfo_client = NULL;
456 }
457 });
458
459 free((void *)config);
460 return;
461 }
462
463
464 void
465 _dns_configuration_ack(dns_config_t *config, const char *bundle_id)
466 {
467 xpc_object_t reqdict;
468
469 if (config == NULL) {
470 return; // ASSERT
471 }
472
473 if ((dnsinfo_client == NULL) || !dnsinfo_client->active) {
474 // if DNS configuration server not available
475 return;
476 }
477
478 dispatch_sync(__dns_configuration_queue(), ^{
479 dnsinfo_active++; // keep connection active (for the life of the process)
480 });
481
482 // create message
483 reqdict = xpc_dictionary_create(NULL, NULL, 0);
484
485 // set request
486 xpc_dictionary_set_int64(reqdict, DNSINFO_REQUEST, DNSINFO_REQUEST_ACKNOWLEDGE);
487
488 // set generation
489 xpc_dictionary_set_uint64(reqdict, DNSINFO_GENERATION, config->generation);
490
491 // send acknowledgement to the DNS configuration server
492 xpc_connection_send_message(dnsinfo_client->connection, reqdict);
493
494 xpc_release(reqdict);
495 return;
496 }
497
498 #ifdef MAIN
499
500 int
501 main(int argc, char **argv)
502 {
503 dns_config_t *config;
504
505 config = dns_configuration_copy();
506 if (config != NULL) {
507 dns_configuration_free(config);
508 }
509
510 exit(0);
511 }
512
513 #endif