2 * Copyright (c) 2004-2006, 2009, 2011-2013, 2015, 2016 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
.generation
= mach_absolute_time();
67 // config->n_attribute = 0;
68 // config->n_padding = 0;
69 return (dns_create_config_t
)config
;
74 config_add_attribute(dns_create_config_t
*_config
,
75 uint32_t attribute_type
,
76 uint32_t attribute_length
,
78 uint32_t extra_padding
)
80 _dns_config_buf_t
*config
= (_dns_config_buf_t
*)*_config
;
81 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 bcopy(attribute
, &header
->attribute
[0], attribute_length
);
112 for (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 bzero(signature
, 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
;
197 unsigned char sha1_buf
[CC_SHA1_DIGEST_LENGTH
];
199 generation_save
= config
->config
.generation
;
200 config
->config
.generation
= 0;
202 sha1
= (signature_len
>= CC_SHA1_DIGEST_LENGTH
) ? signature
: sha1_buf
;
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
);
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
;
259 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
260 uint32_t rounded_length
;
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
);
271 resolver
->n_attribute
= htonl(ntohl(resolver
->n_attribute
) + newLen
);
273 // add attribute [header]
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
);
280 // add attribute [data]
282 bcopy(attribute
, &header
->attribute
[0], attribute_length
);
283 for (i
= attribute_length
; i
< rounded_length
; i
++) {
284 header
->attribute
[i
] = 0;
287 *_resolver
= (dns_create_resolver_t
)resolver
;
294 _dns_resolver_add_nameserver(dns_create_resolver_t
*_resolver
, struct sockaddr
*nameserver
)
296 uint32_t new_flags
= 0;
298 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
300 old_flags
= ntohl(resolver
->resolver
.flags
);
302 switch (nameserver
->sa_family
) {
304 if (ntohl(((struct sockaddr_in
*)(void *)nameserver
)->sin_addr
.s_addr
) == INADDR_LOOPBACK
) {
305 new_flags
= DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
;
309 if (IN6_IS_ADDR_LOOPBACK(&((struct sockaddr_in6
*)(void *)nameserver
)->sin6_addr
)){
310 new_flags
= DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS
;
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
);
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
);
331 _dns_resolver_add_search(dns_create_resolver_t
*_resolver
, const char *search
)
333 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
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
);
343 _dns_resolver_add_sortaddr(dns_create_resolver_t
*_resolver
, dns_sortaddr_t
*sortaddr
)
345 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
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
);
355 _dns_resolver_set_configuration_identifier(dns_create_resolver_t
*_resolver
, const char *cid
)
357 _dns_resolver_add_attribute(_resolver
, RESOLVER_ATTRIBUTE_CONFIGURATION_ID
, (uint32_t)strlen(cid
) + 1, (void *)cid
);
364 _dns_resolver_set_domain(dns_create_resolver_t
*_resolver
, const char *domain
)
366 _dns_resolver_add_attribute(_resolver
, RESOLVER_ATTRIBUTE_DOMAIN
, (uint32_t)strlen(domain
) + 1, (void *)domain
);
373 _dns_resolver_set_flags(dns_create_resolver_t
*_resolver
, uint32_t flags
)
375 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
377 resolver
->resolver
.flags
= htonl(flags
);
384 _dns_resolver_set_if_index(dns_create_resolver_t
*_resolver
, uint32_t if_index
)
386 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
388 resolver
->resolver
.if_index
= htonl(if_index
);
395 _dns_resolver_set_options(dns_create_resolver_t
*_resolver
, const char *options
)
397 _dns_resolver_add_attribute(_resolver
, RESOLVER_ATTRIBUTE_OPTIONS
, (uint32_t)strlen(options
) + 1, (void *)options
);
404 _dns_resolver_set_order(dns_create_resolver_t
*_resolver
, uint32_t order
)
406 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
408 resolver
->resolver
.search_order
= htonl(order
);
415 _dns_resolver_set_port(dns_create_resolver_t
*_resolver
, uint16_t port
)
417 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
419 resolver
->resolver
.port
= htons(port
);
425 _dns_resolver_set_reach_flags(dns_create_resolver_t _resolver
)
427 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)_resolver
;
429 if (resolver
->resolver
.n_nameserver
!= 0) {
430 dns_attribute_t
*attribute
;
431 SCNetworkReachabilityFlags flags
= kSCNetworkReachabilityFlagsReachable
;
432 uint32_t n_attribute
;
433 uint32_t n_nameserver
= 0;
434 CFMutableDictionaryRef targetOptions
;
436 targetOptions
= CFDictionaryCreateMutable(NULL
,
438 &kCFTypeDictionaryKeyCallBacks
,
439 &kCFTypeDictionaryValueCallBacks
);
440 CFDictionarySetValue(targetOptions
,
441 kSCNetworkReachabilityOptionServerBypass
,
443 if (resolver
->resolver
.if_index
!= 0) {
444 char if_name
[IFNAMSIZ
];
446 if (if_indextoname(ntohl(resolver
->resolver
.if_index
), if_name
) != NULL
) {
447 CFStringRef targetInterface
;
449 targetInterface
= CFStringCreateWithCString(NULL
,
451 kCFStringEncodingASCII
);
452 CFDictionarySetValue(targetOptions
,
453 kSCNetworkReachabilityOptionInterface
,
455 CFRelease(targetInterface
);
459 attribute
= (dns_attribute_t
*)(void *)&resolver
->attribute
[0];
460 n_attribute
= ntohl(resolver
->n_attribute
);
462 while (n_attribute
>= sizeof(dns_attribute_t
)) {
463 uint32_t attribute_length
= ntohl(attribute
->length
);
464 uint32_t attribute_type
= ntohl(attribute
->type
);
466 if (attribute_type
== RESOLVER_ATTRIBUTE_ADDRESS
) {
467 struct sockaddr
*addr
;
469 SCNetworkReachabilityFlags ns_flags
;
471 SCNetworkReachabilityRef target
;
473 addr
= (struct sockaddr
*)&attribute
->attribute
[0];
474 addrData
= CFDataCreate(NULL
, (const UInt8
*)addr
, addr
->sa_len
);
475 CFDictionarySetValue(targetOptions
,
476 kSCNetworkReachabilityOptionRemoteAddress
,
480 target
= SCNetworkReachabilityCreateWithOptions(NULL
, targetOptions
);
481 if (target
== NULL
) {
482 CFDictionaryRemoveValue(targetOptions
, kSCNetworkReachabilityOptionInterface
);
483 target
= SCNetworkReachabilityCreateWithOptions(NULL
, targetOptions
);
484 if (target
!= NULL
) {
485 // if interface name not (no longer) valid
491 // address not valid?
493 "_dns_resolver_set_reach_flags SCNetworkReachabilityCreateWithOptions() failed:\n options = %@",
498 ok
= SCNetworkReachabilityGetFlags(target
, &ns_flags
);
504 if ((n_nameserver
++ == 0) ||
505 (__SCNetworkReachabilityRank(ns_flags
) > __SCNetworkReachabilityRank(flags
))) {
506 /* return the first (and later, best case) result */
508 if (__SCNetworkReachabilityRank(flags
) == ReachabilityRankReachable
) {
509 // Can't get any better than REACHABLE
515 attribute
= (dns_attribute_t
*)((void *)attribute
+ attribute_length
);
516 n_attribute
-= attribute_length
;
519 CFRelease(targetOptions
);
521 resolver
->resolver
.reach_flags
= htonl(flags
);
530 _dns_resolver_set_timeout(dns_create_resolver_t
*_resolver
, uint32_t timeout
)
532 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
534 resolver
->resolver
.timeout
= htonl(timeout
);
541 _dns_resolver_set_service_identifier(dns_create_resolver_t
*_resolver
, uint32_t service_identifier
)
543 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;
545 resolver
->resolver
.service_identifier
= htonl(service_identifier
);
551 _dns_resolver_free(dns_create_resolver_t
*_resolver
)
553 _dns_resolver_buf_t
*resolver
= (_dns_resolver_buf_t
*)*_resolver
;