]> git.saurik.com Git - apple/configd.git/blob - dnsinfo/dnsinfo_create.c
configd-801.1.1.tar.gz
[apple/configd.git] / dnsinfo / dnsinfo_create.c
1 /*
2 * Copyright (c) 2004-2006, 2009, 2011-2013, 2015 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 #include <stdlib.h>
25 #include <strings.h>
26 #include <mach/mach.h>
27 #include <mach/mach_error.h>
28 #include <mach/mach_time.h>
29 #include <CommonCrypto/CommonDigest.h>
30 #include <CoreFoundation/CoreFoundation.h>
31 #include <SystemConfiguration/SystemConfiguration.h>
32 #include <SystemConfiguration/SCPrivate.h>
33
34 #include "dnsinfo_create.h"
35 #include "dnsinfo_private.h"
36 #include "network_information_priv.h"
37
38 #include "ip_plugin.h"
39
40
41 #define ROUNDUP(a, size) \
42 (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
43
44
45 /*
46 * to avoid extra calls to realloc() we want to pre-allocate the initial
47 * resolver and configuration buffers of a sufficient size that they would
48 * not normally need to be expanded.
49 */
50 #define INITIAL_CONFIGURATION_BUF_SIZE 8192
51 #define INITIAL_RESOLVER_BUF_SIZE 1024
52
53
54 /*
55 * DNS [configuration] buffer functions
56 */
57
58
59 __private_extern__
60 dns_create_config_t
61 _dns_configuration_create()
62 {
63 _dns_config_buf_t *config;
64
65 config = calloc(1, INITIAL_CONFIGURATION_BUF_SIZE);
66 config->config.generation = mach_absolute_time();
67 // config->n_attribute = 0;
68 // config->n_padding = 0;
69 return (dns_create_config_t)config;
70 }
71
72
73 static void
74 config_add_attribute(dns_create_config_t *_config,
75 uint32_t attribute_type,
76 uint32_t attribute_length,
77 void *attribute,
78 uint32_t extra_padding)
79 {
80 _dns_config_buf_t *config = (_dns_config_buf_t *)*_config;
81 dns_attribute_t *header;
82 int i;
83 uint32_t newLen;
84 uint32_t newSize;
85 uint32_t oldLen;
86 uint32_t rounded_length;
87
88 // add space
89
90 oldLen = ntohl(config->n_attribute);
91 rounded_length = ROUNDUP(attribute_length, sizeof(uint32_t));
92 newLen = sizeof(dns_attribute_t) + rounded_length;
93 newSize = sizeof(_dns_config_buf_t) + oldLen + newLen;
94 if (newSize > INITIAL_CONFIGURATION_BUF_SIZE) {
95 config = realloc(config, newSize);
96 }
97 config->n_attribute = htonl(ntohl(config->n_attribute) + newLen);
98
99 // increment additional padding that will be needed (later)
100 config->n_padding = htonl(ntohl(config->n_padding) + extra_padding);
101
102 // add attribute [header]
103
104 /* ALIGN: _dns_config_buf_t is int aligned */
105 header = (dns_attribute_t *)(void *)&config->attribute[oldLen];
106 header->type = htonl(attribute_type);
107 header->length = htonl(newLen);
108
109 // add attribute [data]
110
111 bcopy(attribute, &header->attribute[0], attribute_length);
112 for (i = attribute_length; i < rounded_length; i++) {
113 header->attribute[i] = 0;
114 }
115
116 *_config = (dns_create_config_t)config;
117 return;
118 }
119
120
121 static void
122 _dns_resolver_set_reach_flags(dns_create_resolver_t _resolver);
123
124
125 __private_extern__
126 void
127 _dns_configuration_add_resolver(dns_create_config_t *_config,
128 dns_create_resolver_t _resolver)
129 {
130 _dns_config_buf_t *config = (_dns_config_buf_t *)*_config;
131 uint32_t padding = 0;
132 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)_resolver;
133
134 /*
135 * add reachability flags for this resovler configuration
136 */
137 _dns_resolver_set_reach_flags(_resolver);
138
139 /*
140 * compute the amount of space that will be needed for
141 * pointers to the resolver, the nameservers, the search
142 * list, and the sortaddr list.
143 */
144 padding += sizeof(DNS_PTR(dns_resolver_t *, x));
145 if (resolver->resolver.n_nameserver != 0) {
146 padding += ntohl(resolver->resolver.n_nameserver) * sizeof(DNS_PTR(struct sockaddr *, x));
147 }
148 if (resolver->resolver.n_search != 0) {
149 padding += ntohl(resolver->resolver.n_search) * sizeof(DNS_PTR(char *, x));
150 }
151 if (resolver->resolver.n_sortaddr != 0) {
152 padding += ntohl(resolver->resolver.n_sortaddr) * sizeof(DNS_PTR(dns_sortaddr_t *, x));
153 }
154
155 if ((ntohl(resolver->resolver.flags) & DNS_RESOLVER_FLAGS_SCOPED)) {
156 config->config.n_scoped_resolver = htonl(ntohl(config->config.n_scoped_resolver) + 1);
157 config_add_attribute(_config,
158 CONFIG_ATTRIBUTE_SCOPED_RESOLVER,
159 sizeof(_dns_resolver_buf_t) + ntohl(resolver->n_attribute),
160 (void *)resolver,
161 padding);
162 } else if ((ntohl(resolver->resolver.flags) & DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC)) {
163 config->config.n_service_specific_resolver = htonl(ntohl(config->config.n_service_specific_resolver) + 1);
164 config_add_attribute(_config,
165 CONFIG_ATTRIBUTE_SERVICE_SPECIFIC_RESOLVER,
166 sizeof(_dns_resolver_buf_t) + ntohl(resolver->n_attribute),
167 (void *)resolver,
168 padding);
169 } else {
170 config->config.n_resolver = htonl(ntohl(config->config.n_resolver) + 1);
171 config_add_attribute(_config,
172 CONFIG_ATTRIBUTE_RESOLVER,
173 sizeof(_dns_resolver_buf_t) + ntohl(resolver->n_attribute),
174 (void *)resolver,
175 padding);
176 }
177
178 return;
179 }
180
181
182 __private_extern__
183 void
184 _dns_configuration_signature(dns_create_config_t *_config,
185 unsigned char *signature,
186 size_t signature_len)
187 {
188 bzero(signature, signature_len);
189
190 if (_config != NULL) {
191 _dns_config_buf_t *config = (_dns_config_buf_t *)*_config;
192
193 if (config != NULL) {
194 CC_SHA1_CTX ctx;
195 uint64_t generation_save;
196 unsigned char *sha1;
197 unsigned char sha1_buf[CC_SHA1_DIGEST_LENGTH];
198
199 generation_save = config->config.generation;
200 config->config.generation = 0;
201
202 sha1 = (signature_len >= CC_SHA1_DIGEST_LENGTH) ? signature : sha1_buf;
203 CC_SHA1_Init(&ctx);
204 CC_SHA1_Update(&ctx,
205 config,
206 sizeof(_dns_config_buf_t) + ntohl(config->n_attribute));
207 CC_SHA1_Final(sha1, &ctx);
208 if (sha1 != signature) {
209 bcopy(sha1, signature, signature_len);
210 }
211
212 config->config.generation = generation_save;
213 }
214 }
215
216 return;
217 }
218
219
220 __private_extern__
221 void
222 _dns_configuration_free(dns_create_config_t *_config)
223 {
224 _dns_config_buf_t *config = (_dns_config_buf_t *)*_config;
225
226 free(config);
227 *_config = NULL;
228 return;
229 }
230
231
232 /*
233 * DNS resolver configuration functions
234 */
235
236 __private_extern__
237 dns_create_resolver_t
238 _dns_resolver_create()
239 {
240 _dns_resolver_buf_t *buf;
241
242 buf = calloc(1, INITIAL_RESOLVER_BUF_SIZE);
243 // buf->n_attribute = 0;
244 return (dns_create_resolver_t)buf;
245 }
246
247
248 static void
249 _dns_resolver_add_attribute(dns_create_resolver_t *_resolver,
250 uint32_t attribute_type,
251 uint32_t attribute_length,
252 void *attribute)
253 {
254 dns_attribute_t *header;
255 int i;
256 uint32_t newLen;
257 uint32_t newSize;
258 uint32_t oldLen;
259 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
260 uint32_t rounded_length;
261
262 // add space
263
264 oldLen = ntohl(resolver->n_attribute);
265 rounded_length = ROUNDUP(attribute_length, sizeof(uint32_t));
266 newLen = sizeof(dns_attribute_t) + rounded_length;
267 newSize = sizeof(_dns_resolver_buf_t) + oldLen + newLen;
268 if (newSize > INITIAL_RESOLVER_BUF_SIZE) {
269 resolver = realloc(resolver, newSize);
270 }
271 resolver->n_attribute = htonl(ntohl(resolver->n_attribute) + newLen);
272
273 // add attribute [header]
274
275 /* ALIGN: _dns_resolver_buf_t is int aligned */
276 header = (dns_attribute_t *)(void *)&resolver->attribute[oldLen];
277 header->type = htonl(attribute_type);
278 header->length = htonl(newLen);
279
280 // add attribute [data]
281
282 bcopy(attribute, &header->attribute[0], attribute_length);
283 for (i = attribute_length; i < rounded_length; i++) {
284 header->attribute[i] = 0;
285 }
286
287 *_resolver = (dns_create_resolver_t)resolver;
288 return;
289 }
290
291
292 __private_extern__
293 void
294 _dns_resolver_add_nameserver(dns_create_resolver_t *_resolver, struct sockaddr *nameserver)
295 {
296 uint32_t new_flags = 0;
297 uint32_t old_flags;
298 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
299
300 old_flags = ntohl(resolver->resolver.flags);
301
302 switch (nameserver->sa_family) {
303 case AF_INET:
304 if (ntohl(((struct sockaddr_in*)(void *)nameserver)->sin_addr.s_addr) == INADDR_LOOPBACK) {
305 new_flags = DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS;
306 }
307 break;
308 case AF_INET6:
309 if (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)(void *)nameserver)->sin6_addr)){
310 new_flags = DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS;
311 }
312 break;
313 default:
314 break;
315 }
316
317 resolver->resolver.n_nameserver = htonl(ntohl(resolver->resolver.n_nameserver) + 1);
318 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_ADDRESS, nameserver->sa_len, (void *)nameserver);
319
320 if (new_flags != 0) {
321 // if DNS request flags not explicitly set and we are
322 // adding a LOOPBACK resolver address
323 _dns_resolver_set_flags(_resolver, old_flags | new_flags);
324 }
325 return;
326 }
327
328
329 __private_extern__
330 void
331 _dns_resolver_add_search(dns_create_resolver_t *_resolver, const char *search)
332 {
333 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
334
335 resolver->resolver.n_search = htonl(ntohl(resolver->resolver.n_search) + 1);
336 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_SEARCH, (uint32_t)strlen(search) + 1, (void *)search);
337 return;
338 }
339
340
341 __private_extern__
342 void
343 _dns_resolver_add_sortaddr(dns_create_resolver_t *_resolver, dns_sortaddr_t *sortaddr)
344 {
345 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
346
347 resolver->resolver.n_sortaddr = htonl(ntohl(resolver->resolver.n_sortaddr) + 1);
348 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_SORTADDR, (uint32_t)sizeof(dns_sortaddr_t), (void *)sortaddr);
349 return;
350 }
351
352
353 __private_extern__
354 void
355 _dns_resolver_set_configuration_identifier(dns_create_resolver_t *_resolver, const char *cid)
356 {
357 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_CONFIGURATION_ID, (uint32_t)strlen(cid) + 1, (void *)cid);
358 return;
359 }
360
361
362 __private_extern__
363 void
364 _dns_resolver_set_domain(dns_create_resolver_t *_resolver, const char *domain)
365 {
366 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_DOMAIN, (uint32_t)strlen(domain) + 1, (void *)domain);
367 return;
368 }
369
370
371 __private_extern__
372 void
373 _dns_resolver_set_flags(dns_create_resolver_t *_resolver, uint32_t flags)
374 {
375 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
376
377 resolver->resolver.flags = htonl(flags);
378 return;
379 }
380
381
382 __private_extern__
383 void
384 _dns_resolver_set_if_index(dns_create_resolver_t *_resolver, uint32_t if_index)
385 {
386 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
387
388 resolver->resolver.if_index = htonl(if_index);
389 return;
390 }
391
392
393 __private_extern__
394 void
395 _dns_resolver_set_options(dns_create_resolver_t *_resolver, const char *options)
396 {
397 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_OPTIONS, (uint32_t)strlen(options) + 1, (void *)options);
398 return;
399 }
400
401
402 __private_extern__
403 void
404 _dns_resolver_set_order(dns_create_resolver_t *_resolver, uint32_t order)
405 {
406 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
407
408 resolver->resolver.search_order = htonl(order);
409 return;
410 }
411
412
413 __private_extern__
414 void
415 _dns_resolver_set_port(dns_create_resolver_t *_resolver, uint16_t port)
416 {
417 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
418
419 resolver->resolver.port = htons(port);
420 return;
421 }
422
423
424 /*
425 * rankReachability()
426 * Not reachable == 0
427 * Connection Required == 1
428 * Reachable == 2
429 */
430 static int
431 rankReachability(SCNetworkReachabilityFlags flags)
432 {
433 int rank = 0;
434
435 if (flags & kSCNetworkReachabilityFlagsReachable) rank = 2;
436 if (flags & kSCNetworkReachabilityFlagsConnectionRequired) rank = 1;
437 return rank;
438 }
439
440
441 static void
442 _dns_resolver_set_reach_flags(dns_create_resolver_t _resolver)
443 {
444 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)_resolver;
445
446 if (resolver->resolver.n_nameserver != 0) {
447 dns_attribute_t *attribute;
448 SCNetworkReachabilityFlags flags = kSCNetworkReachabilityFlagsReachable;
449 uint32_t n_attribute;
450 uint32_t n_nameserver = 0;
451 CFMutableDictionaryRef targetOptions;
452
453 targetOptions = CFDictionaryCreateMutable(NULL,
454 0,
455 &kCFTypeDictionaryKeyCallBacks,
456 &kCFTypeDictionaryValueCallBacks);
457 CFDictionarySetValue(targetOptions,
458 kSCNetworkReachabilityOptionServerBypass,
459 kCFBooleanTrue);
460 if (resolver->resolver.if_index != 0) {
461 char if_name[IFNAMSIZ];
462
463 if (if_indextoname(ntohl(resolver->resolver.if_index), if_name) != NULL) {
464 CFStringRef targetInterface;
465
466 targetInterface = CFStringCreateWithCString(NULL,
467 if_name,
468 kCFStringEncodingASCII);
469 CFDictionarySetValue(targetOptions,
470 kSCNetworkReachabilityOptionInterface,
471 targetInterface);
472 CFRelease(targetInterface);
473 }
474 }
475
476 attribute = (dns_attribute_t *)(void *)&resolver->attribute[0];
477 n_attribute = ntohl(resolver->n_attribute);
478
479 while (n_attribute >= sizeof(dns_attribute_t)) {
480 uint32_t attribute_length = ntohl(attribute->length);
481 uint32_t attribute_type = ntohl(attribute->type);
482
483 if (attribute_type == RESOLVER_ATTRIBUTE_ADDRESS) {
484 struct sockaddr *addr;
485 CFDataRef addrData;
486 SCNetworkReachabilityFlags ns_flags;
487 Boolean ok;
488 SCNetworkReachabilityRef target;
489
490 addr = (struct sockaddr *)&attribute->attribute[0];
491 addrData = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
492 CFDictionarySetValue(targetOptions,
493 kSCNetworkReachabilityOptionRemoteAddress,
494 addrData);
495 CFRelease(addrData);
496
497 target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions);
498 if (target == NULL) {
499 CFDictionaryRemoveValue(targetOptions, kSCNetworkReachabilityOptionInterface);
500 target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions);
501 if (target != NULL) {
502 // if interface name not (no longer) valid
503 CFRelease(target);
504 flags = 0;
505 break;
506 }
507
508 // address not valid?
509 my_log(LOG_ERR,
510 "_dns_resolver_set_reach_flags SCNetworkReachabilityCreateWithOptions() failed:\n options = %@",
511 targetOptions);
512 break;
513 }
514
515 ok = SCNetworkReachabilityGetFlags(target, &ns_flags);
516 CFRelease(target);
517 if (!ok) {
518 break;
519 }
520
521 if ((n_nameserver++ == 0) ||
522 (rankReachability(ns_flags) < rankReachability(flags))) {
523 /* return the first (and later, worst case) result */
524 flags = ns_flags;
525 }
526 }
527
528 attribute = (dns_attribute_t *)((void *)attribute + attribute_length);
529 n_attribute -= attribute_length;
530 }
531
532 CFRelease(targetOptions);
533
534 resolver->resolver.reach_flags = htonl(flags);
535 }
536
537 return;
538 }
539
540
541 __private_extern__
542 void
543 _dns_resolver_set_timeout(dns_create_resolver_t *_resolver, uint32_t timeout)
544 {
545 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
546
547 resolver->resolver.timeout = htonl(timeout);
548 return;
549 }
550
551
552 __private_extern__
553 void
554 _dns_resolver_set_service_identifier(dns_create_resolver_t *_resolver, uint32_t service_identifier)
555 {
556 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
557
558 resolver->resolver.service_identifier = htonl(service_identifier);
559 }
560
561
562 __private_extern__
563 void
564 _dns_resolver_free(dns_create_resolver_t *_resolver)
565 {
566 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
567
568 free(resolver);
569 *_resolver = NULL;
570 return;
571 }