1/* 2 * Copyright (c) 2004-2006, 2009, 2011-2013 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__ 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.generation = mach_absolute_time(); 67// config->n_attribute = 0; 68// config->n_padding = 0; 69 return (dns_create_config_t)config; 70} 71 72 73static void 74config_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 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 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__ 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 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__ 293void 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__ 330void 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__ 342void 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__ 354void 355_dns_resolver_set_domain(dns_create_resolver_t *_resolver, const char *domain) 356{ 357 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_DOMAIN, (uint32_t)strlen(domain) + 1, (void *)domain); 358 return; 359} 360 361 362__private_extern__ 363void 364_dns_resolver_set_flags(dns_create_resolver_t *_resolver, uint32_t flags) 365{ 366 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver; 367 368 resolver->resolver.flags = htonl(flags); 369 return; 370} 371 372 373__private_extern__ 374void 375_dns_resolver_set_if_index(dns_create_resolver_t *_resolver, uint32_t if_index) 376{ 377 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver; 378 379 resolver->resolver.if_index = htonl(if_index); 380 return; 381} 382 383 384__private_extern__ 385void 386_dns_resolver_set_options(dns_create_resolver_t *_resolver, const char *options) 387{ 388 _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_OPTIONS, (uint32_t)strlen(options) + 1, (void *)options); 389 return; 390} 391 392 393__private_extern__ 394void 395_dns_resolver_set_order(dns_create_resolver_t *_resolver, uint32_t order) 396{ 397 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver; 398 399 resolver->resolver.search_order = htonl(order); 400 return; 401} 402 403 404__private_extern__ 405void 406_dns_resolver_set_port(dns_create_resolver_t *_resolver, uint16_t port) 407{ 408 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver; 409 410 resolver->resolver.port = htons(port); 411 return; 412} 413 414 415/* 416 * rankReachability() 417 * Not reachable == 0 418 * Connection Required == 1 419 * Reachable == 2 420 */ 421static int 422rankReachability(SCNetworkReachabilityFlags flags) 423{ 424 int rank = 0; 425 426 if (flags & kSCNetworkReachabilityFlagsReachable) rank = 2; 427 if (flags & kSCNetworkReachabilityFlagsConnectionRequired) rank = 1; 428 return rank; 429} 430 431 432static void 433_dns_resolver_set_reach_flags(dns_create_resolver_t _resolver) 434{ 435 _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)_resolver; 436 437 if (resolver->resolver.n_nameserver != 0) { 438 dns_attribute_t *attribute; 439 SCNetworkReachabilityFlags flags = kSCNetworkReachabilityFlagsReachable; 440 uint32_t n_attribute; 441 uint32_t n_nameserver = 0; 442 CFMutableDictionaryRef targetOptions; 443 444 targetOptions = CFDictionaryCreateMutable(NULL, 445 0, 446 &kCFTypeDictionaryKeyCallBacks, 447 &kCFTypeDictionaryValueCallBacks); 448 CFDictionarySetValue(targetOptions, 449 kSCNetworkReachabilityOptionServerBypass, 450 kCFBooleanTrue); 451 if (resolver->resolver.if_index != 0) { 452 char if_name[IFNAMSIZ]; 453 454 if (if_indextoname(ntohl(resolver->resolver.if_index), if_name) != NULL) { 455 CFStringRef targetInterface; 456 457 targetInterface = CFStringCreateWithCString(NULL, 458 if_name, 459 kCFStringEncodingASCII); 460 CFDictionarySetValue(targetOptions, 461 kSCNetworkReachabilityOptionInterface, 462 targetInterface); 463 CFRelease(targetInterface); 464 } 465 } 466 467 attribute = (dns_attribute_t *)(void *)&resolver->attribute[0]; 468 n_attribute = ntohl(resolver->n_attribute); 469 470 while (n_attribute >= sizeof(dns_attribute_t)) { 471 uint32_t attribute_length = ntohl(attribute->length); 472 uint32_t attribute_type = ntohl(attribute->type); 473 474 if (attribute_type == RESOLVER_ATTRIBUTE_ADDRESS) { 475 struct sockaddr *addr; 476 CFDataRef addrData; 477 SCNetworkReachabilityFlags ns_flags; 478 Boolean ok; 479 SCNetworkReachabilityRef target; 480 481 addr = (struct sockaddr *)&attribute->attribute[0]; 482 addrData = CFDataCreate(NULL, (const UInt8 *)addr, addr->sa_len); 483 CFDictionarySetValue(targetOptions, 484 kSCNetworkReachabilityOptionRemoteAddress, 485 addrData); 486 CFRelease(addrData); 487 488 target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions); 489 if (target == NULL) { 490 CFDictionaryRemoveValue(targetOptions, kSCNetworkReachabilityOptionInterface); 491 target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions); 492 if (target != NULL) { 493 // if interface name not (no longer) valid 494 CFRelease(target); 495 flags = 0; 496 break; 497 } 498 499 // address not valid? 500 my_log(LOG_ERR, 501 "_dns_resolver_set_reach_flags SCNetworkReachabilityCreateWithOptions() failed:\n options = %@", 502 targetOptions); 503 break; 504 } 505 506 ok = SCNetworkReachabilityGetFlags(target, &ns_flags); 507 CFRelease(target); 508 if (!ok) { 509 break; 510 } 511 512 if ((n_nameserver++ == 0) || 513 (rankReachability(ns_flags) < rankReachability(flags))) { 514 /* return the first (and later, worst case) result */ 515 flags = ns_flags; 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} 563