]> git.saurik.com Git - apple/configd.git/blob - dnsinfo/dnsinfo_create.c
configd-963.tar.gz
[apple/configd.git] / dnsinfo / dnsinfo_create.c
1 /*
2 * Copyright (c) 2004-2006, 2009, 2011-2013, 2015-2017 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_time.h>
28 #include <CommonCrypto/CommonDigest.h>
29 #include <CoreFoundation/CoreFoundation.h>
30 #include <SystemConfiguration/SystemConfiguration.h>
31 #include <SystemConfiguration/SCPrivate.h>
32 #include "SCNetworkReachabilityInternal.h"
33
34 #include "dnsinfo_create.h"
35 #include "dnsinfo_private.h"
36 #include "network_state_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.version = DNSINFO_VERSION;
67 config->config.generation = mach_absolute_time();
68 // config->n_attribute = 0;
69 // config->n_padding = 0;
70 return (dns_create_config_t)config;
71 }
72
73
74 static void
75 config_add_attribute(dns_create_config_t *_config,
76 uint32_t attribute_type,
77 uint32_t attribute_length,
78 void *attribute,
79 uint32_t extra_padding)
80 {
81 _dns_config_buf_t *config = (_dns_config_buf_t *)*_config;
82 dns_attribute_t *header;
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 (uint32_t 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 uint32_t newLen;
256 uint32_t newSize;
257 uint32_t oldLen;
258 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
259 uint32_t rounded_length;
260
261 // add space
262
263 oldLen = ntohl(resolver->n_attribute);
264 rounded_length = ROUNDUP(attribute_length, sizeof(uint32_t));
265 newLen = sizeof(dns_attribute_t) + rounded_length;
266 newSize = sizeof(_dns_resolver_buf_t) + oldLen + newLen;
267 if (newSize > INITIAL_RESOLVER_BUF_SIZE) {
268 resolver = realloc(resolver, newSize);
269 }
270 resolver->n_attribute = htonl(ntohl(resolver->n_attribute) + newLen);
271
272 // add attribute [header]
273
274 /* ALIGN: _dns_resolver_buf_t is int aligned */
275 header = (dns_attribute_t *)(void *)&resolver->attribute[oldLen];
276 header->type = htonl(attribute_type);
277 header->length = htonl(newLen);
278
279 // add attribute [data]
280
281 bcopy(attribute, &header->attribute[0], attribute_length);
282 for (uint32_t i = attribute_length; i < rounded_length; i++) {
283 header->attribute[i] = 0;
284 }
285
286 *_resolver = (dns_create_resolver_t)resolver;
287 return;
288 }
289
290
291 __private_extern__
292 void
293 _dns_resolver_add_nameserver(dns_create_resolver_t *_resolver, struct sockaddr *nameserver)
294 {
295 uint32_t new_flags = 0;
296 uint32_t old_flags;
297 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
298
299 old_flags = ntohl(resolver->resolver.flags);
300
301 switch (nameserver->sa_family) {
302 case AF_INET:
303 if (ntohl(((struct sockaddr_in*)(void *)nameserver)->sin_addr.s_addr) == INADDR_LOOPBACK) {
304 new_flags = DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS;
305 }
306 break;
307 case AF_INET6:
308 if (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6 *)(void *)nameserver)->sin6_addr)){
309 new_flags = DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS;
310 }
311 break;
312 default:
313 break;
314 }
315
316 resolver->resolver.n_nameserver = htonl(ntohl(resolver->resolver.n_nameserver) + 1);
317 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_ADDRESS, nameserver->sa_len, (void *)nameserver);
318
319 if (new_flags != 0) {
320 // if DNS request flags not explicitly set and we are
321 // adding a LOOPBACK resolver address
322 _dns_resolver_set_flags(_resolver, old_flags | new_flags);
323 }
324 return;
325 }
326
327
328 __private_extern__
329 void
330 _dns_resolver_add_search(dns_create_resolver_t *_resolver, const char *search)
331 {
332 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
333
334 resolver->resolver.n_search = htonl(ntohl(resolver->resolver.n_search) + 1);
335 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_SEARCH, (uint32_t)strlen(search) + 1, (void *)search);
336 return;
337 }
338
339
340 __private_extern__
341 void
342 _dns_resolver_add_sortaddr(dns_create_resolver_t *_resolver, dns_sortaddr_t *sortaddr)
343 {
344 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
345
346 resolver->resolver.n_sortaddr = htonl(ntohl(resolver->resolver.n_sortaddr) + 1);
347 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_SORTADDR, (uint32_t)sizeof(dns_sortaddr_t), (void *)sortaddr);
348 return;
349 }
350
351
352 __private_extern__
353 void
354 _dns_resolver_set_configuration_identifier(dns_create_resolver_t *_resolver, const char *cid)
355 {
356 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_CONFIGURATION_ID, (uint32_t)strlen(cid) + 1, (void *)cid);
357 return;
358 }
359
360
361 __private_extern__
362 void
363 _dns_resolver_set_domain(dns_create_resolver_t *_resolver, const char *domain)
364 {
365 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_DOMAIN, (uint32_t)strlen(domain) + 1, (void *)domain);
366 return;
367 }
368
369
370 __private_extern__
371 void
372 _dns_resolver_set_flags(dns_create_resolver_t *_resolver, uint32_t flags)
373 {
374 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
375
376 resolver->resolver.flags = htonl(flags);
377 return;
378 }
379
380
381 __private_extern__
382 void
383 _dns_resolver_set_if_index(dns_create_resolver_t *_resolver,
384 uint32_t if_index,
385 const char *if_name)
386 {
387 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
388
389 resolver->resolver.if_index = htonl(if_index);
390 if (if_name != NULL) {
391 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_INTERFACE_NAME, (uint32_t)strlen(if_name), (void *)if_name);
392 }
393 return;
394 }
395
396
397 __private_extern__
398 void
399 _dns_resolver_set_options(dns_create_resolver_t *_resolver, const char *options)
400 {
401 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_OPTIONS, (uint32_t)strlen(options) + 1, (void *)options);
402 return;
403 }
404
405
406 __private_extern__
407 void
408 _dns_resolver_set_order(dns_create_resolver_t *_resolver, uint32_t order)
409 {
410 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
411
412 resolver->resolver.search_order = htonl(order);
413 return;
414 }
415
416
417 __private_extern__
418 void
419 _dns_resolver_set_port(dns_create_resolver_t *_resolver, uint16_t port)
420 {
421 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
422
423 resolver->resolver.port = htons(port);
424 return;
425 }
426
427
428 static void
429 _dns_resolver_set_reach_flags(dns_create_resolver_t _resolver)
430 {
431 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)_resolver;
432
433 if (resolver->resolver.n_nameserver != 0) {
434 dns_attribute_t *attribute;
435 SCNetworkReachabilityFlags flags = kSCNetworkReachabilityFlagsReachable;
436 uint32_t n_attribute;
437 uint32_t n_nameserver = 0;
438 CFMutableDictionaryRef targetOptions;
439
440 targetOptions = CFDictionaryCreateMutable(NULL,
441 0,
442 &kCFTypeDictionaryKeyCallBacks,
443 &kCFTypeDictionaryValueCallBacks);
444 CFDictionarySetValue(targetOptions,
445 kSCNetworkReachabilityOptionServerBypass,
446 kCFBooleanTrue);
447 if (resolver->resolver.if_index != 0) {
448 char if_name[IFNAMSIZ];
449
450 if (if_indextoname(ntohl(resolver->resolver.if_index), if_name) != NULL) {
451 CFStringRef targetInterface;
452
453 targetInterface = CFStringCreateWithCString(NULL,
454 if_name,
455 kCFStringEncodingASCII);
456 CFDictionarySetValue(targetOptions,
457 kSCNetworkReachabilityOptionInterface,
458 targetInterface);
459 CFRelease(targetInterface);
460 }
461 }
462
463 attribute = (dns_attribute_t *)(void *)&resolver->attribute[0];
464 n_attribute = ntohl(resolver->n_attribute);
465
466 while (n_attribute >= sizeof(dns_attribute_t)) {
467 uint32_t attribute_length = ntohl(attribute->length);
468 uint32_t attribute_type = ntohl(attribute->type);
469
470 if (attribute_type == RESOLVER_ATTRIBUTE_ADDRESS) {
471 struct sockaddr *addr;
472 CFDataRef addrData;
473 SCNetworkReachabilityFlags ns_flags;
474 Boolean ok;
475 SCNetworkReachabilityRef target;
476
477 addr = (struct sockaddr *)&attribute->attribute[0];
478 addrData = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len);
479 CFDictionarySetValue(targetOptions,
480 kSCNetworkReachabilityOptionRemoteAddress,
481 addrData);
482 CFRelease(addrData);
483
484 target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions);
485 if (target == NULL) {
486 CFDictionaryRemoveValue(targetOptions, kSCNetworkReachabilityOptionInterface);
487 target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions);
488 if (target != NULL) {
489 // if interface name not (no longer) valid
490 CFRelease(target);
491 flags = 0;
492 break;
493 }
494
495 // address not valid?
496 my_log(LOG_ERR,
497 "_dns_resolver_set_reach_flags SCNetworkReachabilityCreateWithOptions() failed:\n options = %@",
498 targetOptions);
499 break;
500 }
501
502 ok = SCNetworkReachabilityGetFlags(target, &ns_flags);
503 CFRelease(target);
504 if (!ok) {
505 break;
506 }
507
508 if ((n_nameserver++ == 0) ||
509 (__SCNetworkReachabilityRank(ns_flags) > __SCNetworkReachabilityRank(flags))) {
510 /* return the first (and later, best case) result */
511 flags = ns_flags;
512 if (__SCNetworkReachabilityRank(flags) == ReachabilityRankReachable) {
513 // Can't get any better than REACHABLE
514 break;
515 }
516 }
517 }
518
519 attribute = (dns_attribute_t *)((void *)attribute + attribute_length);
520 n_attribute -= attribute_length;
521 }
522
523 CFRelease(targetOptions);
524
525 resolver->resolver.reach_flags = htonl(flags);
526 }
527
528 return;
529 }
530
531
532 __private_extern__
533 void
534 _dns_resolver_set_timeout(dns_create_resolver_t *_resolver, uint32_t timeout)
535 {
536 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
537
538 resolver->resolver.timeout = htonl(timeout);
539 return;
540 }
541
542
543 __private_extern__
544 void
545 _dns_resolver_set_service_identifier(dns_create_resolver_t *_resolver, uint32_t service_identifier)
546 {
547 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
548
549 resolver->resolver.service_identifier = htonl(service_identifier);
550 }
551
552
553 __private_extern__
554 void
555 _dns_resolver_free(dns_create_resolver_t *_resolver)
556 {
557 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver;
558
559 free(resolver);
560 *_resolver = NULL;
561 return;
562 }