this repo has no description
1/*
2 * Copyright (c) 2004-2006, 2009, 2011-2013, 2015-2018 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__
60dns_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
74static void
75config_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 memcpy(&header->attribute[0], attribute, 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
121static void
122_dns_resolver_set_reach_flags(dns_create_resolver_t _resolver);
123
124
125__private_extern__
126void
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__
183void
184_dns_configuration_signature(dns_create_config_t *_config,
185 unsigned char *signature,
186 size_t signature_len)
187{
188 memset(signature, 0, 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_SHA256_CTX ctx;
195 uint64_t generation_save;
196 unsigned char *sha256;
197 unsigned char sha256_buf[CC_SHA256_DIGEST_LENGTH];
198
199 generation_save = config->config.generation;
200 config->config.generation = 0;
201
202 sha256 = (signature_len >= CC_SHA256_DIGEST_LENGTH) ? signature : sha256_buf;
203 CC_SHA256_Init(&ctx);
204 CC_SHA256_Update(&ctx,
205 config,
206 sizeof(_dns_config_buf_t) + ntohl(config->n_attribute));
207 CC_SHA256_Final(sha256, &ctx);
208 if (sha256 != signature) {
209 memcpy(signature, sha256, signature_len);
210 }
211
212 config->config.generation = generation_save;
213 }
214 }
215
216 return;
217}
218
219
220__private_extern__
221void
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__
237dns_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
248static 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 memcpy(&header->attribute[0], attribute, 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__
292void
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__
329void
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__
341void
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__
353void
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__
362void
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__
371void
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__
382void
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__
398void
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__
407void
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__
418void
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
428static 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__
533void
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__
544void
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__
554void
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}