2 * Copyright (c) 2004-2006, 2009, 2011-2013, 2015-2018 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
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"
34 #include "dnsinfo_create.h"
35 #include "dnsinfo_private.h"
36 #include "network_state_information_priv.h"
38 #include "ip_plugin.h"
41 #define ROUNDUP(a, size) \
42 (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a))
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.
50 #define INITIAL_CONFIGURATION_BUF_SIZE 8192
51 #define INITIAL_RESOLVER_BUF_SIZE 1024
55 * DNS [configuration] buffer functions
61 _dns_configuration_create()
63 _dns_config_buf_t
*config
;
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
;
75 config_add_attribute(dns_create_config_t
*_config
,
76 uint32_t attribute_type
,
77 uint32_t attribute_length
,
79 uint32_t extra_padding
)
81 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)*_config
;
82 dns_attribute_t
*header
;
86 uint32_t rounded_length
;
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
);
97 config
->n_attribute
= htonl(ntohl(config
->n_attribute
) + newLen
);
99 // increment additional padding that will be needed (later)
100 config
->n_padding
= htonl(ntohl(config
->n_padding
) + extra_padding
);
102 // add attribute [header]
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
);
109 // add attribute [data]
111 memcpy(&header
->attribute
[0], attribute
, attribute_length
);
112 for (uint32_t i
= attribute_length
; i
< rounded_length
; i
++) {
113 header
->attribute
[i
] = 0;
116 *_config
= (dns_create_config_t
)config
;
122 _dns_resolver_set_reach_flags(dns_create_resolver_t _resolver
);
127 _dns_configuration_add_resolver(dns_create_config_t
*_config
,
128 dns_create_resolver_t _resolver
)
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
;
135 * add reachability flags for this resovler configuration
137 _dns_resolver_set_reach_flags(_resolver
);
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.
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
));
148 if (resolver
->resolver
.n_search
!= 0) {
149 padding
+= ntohl(resolver
->resolver
.n_search
) * sizeof(DNS_PTR(char *, x
));
151 if (resolver
->resolver
.n_sortaddr
!= 0) {
152 padding
+= ntohl(resolver
->resolver
.n_sortaddr
) * sizeof(DNS_PTR(dns_sortaddr_t
*, x
));
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
),
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
),
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
),
184 _dns_configuration_signature(dns_create_config_t
*_config
,
185 unsigned char *signature
,
186 size_t signature_len
)
188 memset(signature
, 0, signature_len
);
190 if (_config
!= NULL
) {
191 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)*_config
;
193 if (config
!= NULL
) {
195 uint64_t generation_save
;
196 unsigned char *sha256
;
197 unsigned char sha256_buf
[CC_SHA256_DIGEST_LENGTH
];
199 generation_save
= config
->config
.generation
;
200 config
->config
.generation
= 0;
202 sha256
= (signature_len
>= CC_SHA256_DIGEST_LENGTH
) ? signature
: sha256_buf
;
203 CC_SHA256_Init(&ctx
);
204 CC_SHA256_Update(&ctx
,
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
);
212 config
->config
.generation
= generation_save
;
222 _dns_configuration_free(dns_create_config_t
*_config
)
224 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)*_config
;
233 * DNS resolver configuration functions
237 dns_create_resolver_t
238 _dns_resolver_create()
240 _dns_resolver_buf_t
*buf
;
242 buf
= calloc(1, INITIAL_RESOLVER_BUF_SIZE
);
243 // buf->n_attribute = 0;
244 return (dns_create_resolver_t
)buf
;
249 _dns_resolver_add_attribute(dns_create_resolver_t
*_resolver
,
250 uint32_t attribute_type
,
251 uint32_t attribute_length
,
254 dns_attribute_t
*header
;
258 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
259 uint32_t rounded_length
;
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
);
270 resolver
->n_attribute
= htonl(ntohl(resolver
->n_attribute
) + newLen
);
272 // add attribute [header]
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
);
279 // add attribute [data]
281 memcpy(&header
->attribute
[0], attribute
, attribute_length
);
282 for (uint32_t i
= attribute_length
; i
< rounded_length
; i
++) {
283 header
->attribute
[i
] = 0;
286 *_resolver
= (dns_create_resolver_t
)resolver
;
293 _dns_resolver_add_nameserver(dns_create_resolver_t
*_resolver
, struct sockaddr
*nameserver
)
295 uint32_t new_flags
= 0;
297 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
299 old_flags
= ntohl(resolver
->resolver
.flags
);
301 switch (nameserver
->sa_family
) {
303 if (ntohl(((struct sockaddr_in
*)(void *)nameserver
)->sin_addr
.s_addr
) == INADDR_LOOPBACK
) {
304 new_flags
= DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
;
308 if (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6
*)(void *)nameserver
)->sin6_addr
)){
309 new_flags
= DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
;
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
);
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
);
330 _dns_resolver_add_search(dns_create_resolver_t
*_resolver
, const char *search
)
332 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
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
);
342 _dns_resolver_add_sortaddr(dns_create_resolver_t
*_resolver
, dns_sortaddr_t
*sortaddr
)
344 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
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
);
354 _dns_resolver_set_configuration_identifier(dns_create_resolver_t
*_resolver
, const char *cid
)
356 _dns_resolver_add_attribute(_resolver
, RESOLVER_ATTRIBUTE_CONFIGURATION_ID
, (uint32_t)strlen(cid
) + 1, (void *)cid
);
363 _dns_resolver_set_domain(dns_create_resolver_t
*_resolver
, const char *domain
)
365 _dns_resolver_add_attribute(_resolver
, RESOLVER_ATTRIBUTE_DOMAIN
, (uint32_t)strlen(domain
) + 1, (void *)domain
);
372 _dns_resolver_set_flags(dns_create_resolver_t
*_resolver
, uint32_t flags
)
374 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
376 resolver
->resolver
.flags
= htonl(flags
);
383 _dns_resolver_set_if_index(dns_create_resolver_t
*_resolver
,
387 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
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
);
399 _dns_resolver_set_options(dns_create_resolver_t
*_resolver
, const char *options
)
401 _dns_resolver_add_attribute(_resolver
, RESOLVER_ATTRIBUTE_OPTIONS
, (uint32_t)strlen(options
) + 1, (void *)options
);
408 _dns_resolver_set_order(dns_create_resolver_t
*_resolver
, uint32_t order
)
410 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
412 resolver
->resolver
.search_order
= htonl(order
);
419 _dns_resolver_set_port(dns_create_resolver_t
*_resolver
, uint16_t port
)
421 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
423 resolver
->resolver
.port
= htons(port
);
429 _dns_resolver_set_reach_flags(dns_create_resolver_t _resolver
)
431 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)_resolver
;
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
;
440 targetOptions
= CFDictionaryCreateMutable(NULL
,
442 &kCFTypeDictionaryKeyCallBacks
,
443 &kCFTypeDictionaryValueCallBacks
);
444 CFDictionarySetValue(targetOptions
,
445 kSCNetworkReachabilityOptionServerBypass
,
447 if (resolver
->resolver
.if_index
!= 0) {
448 char if_name
[IFNAMSIZ
];
450 if (if_indextoname(ntohl(resolver
->resolver
.if_index
), if_name
) != NULL
) {
451 CFStringRef targetInterface
;
453 targetInterface
= CFStringCreateWithCString(NULL
,
455 kCFStringEncodingASCII
);
456 CFDictionarySetValue(targetOptions
,
457 kSCNetworkReachabilityOptionInterface
,
459 CFRelease(targetInterface
);
463 attribute
= (dns_attribute_t
*)(void *)&resolver
->attribute
[0];
464 n_attribute
= ntohl(resolver
->n_attribute
);
466 while (n_attribute
>= sizeof(dns_attribute_t
)) {
467 uint32_t attribute_length
= ntohl(attribute
->length
);
468 uint32_t attribute_type
= ntohl(attribute
->type
);
470 if (attribute_type
== RESOLVER_ATTRIBUTE_ADDRESS
) {
471 struct sockaddr
*addr
;
473 SCNetworkReachabilityFlags ns_flags
;
475 SCNetworkReachabilityRef target
;
477 addr
= (struct sockaddr
*)&attribute
->attribute
[0];
478 addrData
= CFDataCreate(NULL
, (const UInt8
*)addr
, addr
->sa_len
);
479 CFDictionarySetValue(targetOptions
,
480 kSCNetworkReachabilityOptionRemoteAddress
,
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
495 // address not valid?
497 "_dns_resolver_set_reach_flags SCNetworkReachabilityCreateWithOptions() failed:\n options = %@",
502 ok
= SCNetworkReachabilityGetFlags(target
, &ns_flags
);
508 if ((n_nameserver
++ == 0) ||
509 (__SCNetworkReachabilityRank(ns_flags
) > __SCNetworkReachabilityRank(flags
))) {
510 /* return the first (and later, best case) result */
512 if (__SCNetworkReachabilityRank(flags
) == ReachabilityRankReachable
) {
513 // Can't get any better than REACHABLE
519 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
520 n_attribute
-= attribute_length
;
523 CFRelease(targetOptions
);
525 resolver
->resolver
.reach_flags
= htonl(flags
);
534 _dns_resolver_set_timeout(dns_create_resolver_t
*_resolver
, uint32_t timeout
)
536 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
538 resolver
->resolver
.timeout
= htonl(timeout
);
545 _dns_resolver_set_service_identifier(dns_create_resolver_t
*_resolver
, uint32_t service_identifier
)
547 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
549 resolver
->resolver
.service_identifier
= htonl(service_identifier
);
555 _dns_resolver_free(dns_create_resolver_t
*_resolver
)
557 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;