/*
- * Copyright (c) 2004-2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2020 Apple Inc. All rights reserved.
*
* @APPLE_LICENSE_HEADER_START@
- *
+ *
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apple Public Source License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://www.opensource.apple.com/apsl/ and read it before using this
* file.
- *
+ *
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
- *
+ *
* @APPLE_LICENSE_HEADER_END@
*/
#include <arpa/inet.h>
#include <arpa/nameser.h>
#include <resolv.h>
-#if !TARGET_OS_IPHONE
-#include <notify.h>
-extern uint32_t notify_monitor_file(int token, const char *name, int flags);
-#endif // !TARGET_OS_IPHONE
+#include <CommonCrypto/CommonDigest.h>
#include <CoreFoundation/CoreFoundation.h>
#include <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h>
#include <SystemConfiguration/SCValidation.h>
+#include "ip_plugin.h"
+
+#include "dns-configuration.h"
#include <dnsinfo.h>
-#include <dnsinfo_create.h>
+#include "dnsinfo_create.h"
+#include "dnsinfo_internal.h"
+#include "dnsinfo_logging.h"
+#include "dnsinfo_private.h"
+#include "dnsinfo_server.h"
-#ifdef MAIN
-#undef MAIN
-#include "dnsinfo_copy.c"
-#define MAIN
-#endif // MAIN
+#include <network_information.h>
#include <dns_sd.h>
-#ifndef kDNSServiceCompMulticastDNS
-#define kDNSServiceCompMulticastDNS "MulticastDNS"
-#endif
-#ifndef kDNSServiceCompPrivateDNS
-#define kDNSServiceCompPrivateDNS "PrivateDNS"
-#endif
+#include <dns_sd_private.h>
+
+#if !TARGET_OS_IPHONE
+#include <CoreServices/CoreServices.h>
+#else // TARGET_OS_IPHONE
+#include <FSEvents/FSEvents.h>
+#endif // TARGET_OS_IPHONE
+
+#define DNS_CONFIGURATION_FLAGS_KEY CFSTR("__FLAGS__")
+#define DNS_CONFIGURATION_IF_INDEX_KEY CFSTR("__IF_INDEX__")
+#define DNS_CONFIGURATION_ORDER_KEY CFSTR("__ORDER__")
/* multicast DNS resolver configurations */
static CFNumberRef S_mdns_timeout = NULL;
static CFNumberRef S_pdns_timeout = NULL;
+#pragma mark -
+#pragma mark DNS resolver flags
+
+
+static __inline__ boolean_t
+dns_resolver_flags_all_queries(uint32_t query_flags)
+{
+ return ((query_flags & DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS) == DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS);
+}
+
+
+
+
+static uint32_t
+dns_resolver_flags_service(CFDictionaryRef service, uint32_t resolver_flags)
+{
+
+ // check if the service has v4 configured
+ if (((resolver_flags & DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS) == 0) &&
+ service_is_routable(service, AF_INET)) {
+ resolver_flags |= DNS_RESOLVER_FLAGS_REQUEST_A_RECORDS;
+ }
+
+ // check if the service has v6 configured
+ if (((resolver_flags & DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS) == 0) &&
+ service_is_routable(service, AF_INET6)) {
+ resolver_flags |= DNS_RESOLVER_FLAGS_REQUEST_AAAA_RECORDS;
+ }
+
+ return resolver_flags;
+}
+
+
+static void
+add_dns_resolver_flags(const void *key, const void *value, void *context)
+{
+#pragma unused(key)
+ CFDictionaryRef service = (CFDictionaryRef)value;
+// CFStringRef serviceID = (CFStringRef)key;
+ uint32_t *resolver_flags = (uint32_t *)context;
+
+ if (service_is_scoped_only(service)) {
+ return;
+ }
+
+ // update resovler flags based on configured (and available) protocols
+ *resolver_flags = dns_resolver_flags_service(service, *resolver_flags);
+ return;
+}
+
+
+#pragma mark -
+#pragma mark DNS resolver configuration
+
+
static void
add_resolver(CFMutableArrayRef resolvers, CFMutableDictionaryRef resolver)
{
CFIndex i;
+ CFStringRef interface;
CFIndex n_resolvers;
CFNumberRef order;
uint32_t order_val = 0;
order = CFDictionaryGetValue(resolver, kSCPropNetDNSSearchOrder);
if (!isA_CFNumber(order) ||
- !CFNumberGetValue(order, kCFNumberIntType, &order_val)) {
+ !CFNumberGetValue(order, kCFNumberSInt32Type, &order_val)) {
order = NULL;
order_val = 0;
}
// if only the search order's are different
match_order = CFDictionaryGetValue(match_resolver, kSCPropNetDNSSearchOrder);
if (!isA_CFNumber(match_order) ||
- !CFNumberGetValue(match_order, kCFNumberIntType, &match_order_val)) {
+ !CFNumberGetValue(match_order, kCFNumberSInt32Type, &match_order_val)) {
match_order_val = 0;
}
}
}
- order = CFNumberCreate(NULL, kCFNumberIntType, &n_resolvers);
- CFDictionarySetValue(resolver, CFSTR("*ORDER*"), order);
+ order = CFNumberCreate(NULL, kCFNumberCFIndexType, &n_resolvers);
+ CFDictionarySetValue(resolver, DNS_CONFIGURATION_ORDER_KEY, order);
CFRelease(order);
+ interface = CFDictionaryGetValue(resolver, kSCPropInterfaceName);
+ if ((interface != NULL) && !CFEqual(interface, CFSTR("*"))) {
+ uint32_t flags;
+ unsigned int if_index = 0;
+ char if_name[IF_NAMESIZE];
+ CFNumberRef num;
+ CFBooleanRef val;
+
+ if (_SC_cfstring_to_cstring(interface,
+ if_name,
+ sizeof(if_name),
+ kCFStringEncodingASCII) != NULL) {
+ if_index = my_if_nametoindex(if_name);
+ }
+
+ if ((if_index != 0) &&
+ (
+ // check if this is a "scoped" configuration
+ (CFDictionaryGetValueIfPresent(resolver, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) &&
+ isA_CFNumber(num) &&
+ CFNumberGetValue(num, kCFNumberSInt32Type, &flags) &&
+ (flags & DNS_RESOLVER_FLAGS_SCOPED) != 0)
+ ||
+ // check if we should scope all queries with this configuration
+ (CFDictionaryGetValueIfPresent(resolver, DNS_CONFIGURATION_SCOPED_QUERY_KEY, (const void **)&val) &&
+ isA_CFBoolean(val) &&
+ CFBooleanGetValue(val))
+ )
+ ) {
+ // if interface index available and it should be used
+ num = CFNumberCreate(NULL, kCFNumberIntType, &if_index);
+ CFDictionarySetValue(resolver, DNS_CONFIGURATION_IF_INDEX_KEY, num);
+ CFRelease(num);
+ }
+ }
+
CFArrayAppendValue(resolvers, resolver);
return;
}
+#define DNS_CONFIGURATION_CONFIGURATION_ID CFSTR("__CONFIGURATION_ID__")
+
+
+static void
+add_resolver_signature(CFMutableDictionaryRef resolver, const char *rType, CFStringRef cID, CFIndex rIndex)
+{
+ CFStringRef str;
+
+ str = CFStringCreateWithFormat(NULL, NULL,
+ CFSTR("%s:%s%@ %ld"),
+ rType,
+ (cID != NULL) ? " " : "",
+ (cID != NULL) ? cID : CFSTR(""),
+ rIndex);
+ CFDictionarySetValue(resolver, DNS_CONFIGURATION_CONFIGURATION_ID, str);
+ CFRelease(str);
+
+ return;
+}
+
+
static void
-add_supplemental(CFMutableArrayRef resolvers, CFDictionaryRef dns, uint32_t defaultOrder)
+add_supplemental(CFMutableArrayRef resolvers,
+ CFStringRef serviceID,
+ CFDictionaryRef dns,
+ uint32_t defaultOrder,
+ Boolean scoped)
{
CFArrayRef domains;
CFIndex i;
CFIndex n_domains;
CFArrayRef orders;
+ CFArrayRef servers;
domains = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchDomains);
n_domains = isA_CFArray(domains) ? CFArrayGetCount(domains) : 0;
if (n_domains == 0) {
+ // if no supplemental match domains
return;
}
orders = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchOrders);
if (orders != NULL) {
if (!isA_CFArray(orders) || (n_domains != CFArrayGetCount(orders))) {
+ // if supplemental match orders... but too many/not enough
return;
}
}
+ servers = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses);
+ if (!isA_CFArray(servers) || (CFArrayGetCount(servers) == 0)) {
+ // if no DNS server addresses
+ return;
+ }
+
/*
* yes, this is a "supplemental" resolver configuration, expand
* the match domains and add each to the resolvers list.
CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSearchDomains);
CFDictionaryRemoveValue(match_resolver, kSCPropNetDNSSortList);
+ add_resolver_signature(match_resolver,
+ scoped ? "Supplemental/Scoped" : "Supplemental",
+ serviceID,
+ i);
add_resolver(resolvers, match_resolver);
CFRelease(match_resolver);
}
static void
-add_supplemental_resolvers(CFMutableArrayRef resolvers, CFDictionaryRef services, CFArrayRef service_order)
+merge_configuration_flags(CFMutableDictionaryRef newDNS, uint32_t mergeFlags)
+{
+ uint32_t flags;
+ CFNumberRef num;
+
+ if (!CFDictionaryGetValueIfPresent(newDNS, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) ||
+ !isA_CFNumber(num) ||
+ !CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
+ flags = 0;
+ }
+
+ flags |= mergeFlags;
+
+ num = CFNumberCreate(NULL, kCFNumberSInt32Type, &flags);
+ CFDictionarySetValue(newDNS, DNS_CONFIGURATION_FLAGS_KEY, num);
+ CFRelease(num);
+
+ return;
+}
+
+
+static void
+add_supplemental_resolvers(CFMutableArrayRef resolvers,
+ CFDictionaryRef services,
+ CFArrayRef service_order,
+ CFStringRef scoped_interface,
+ CFDictionaryRef scoped_service)
{
const void * keys_q[N_QUICK];
const void ** keys = keys_q;
CFDictionaryGetKeysAndValues(services, keys, vals);
for (i = 0; i < n_services; i++) {
- uint32_t defaultOrder;
- CFDictionaryRef dns;
- CFDictionaryRef service = (CFDictionaryRef)vals[i];
+ uint32_t defaultOrder;
+ CFDictionaryRef dns;
+ uint32_t dns_resolver_flags;
+ CFStringRef interface;
+ CFMutableDictionaryRef newDNS = NULL;
+ uint32_t newFlags;
+ CFDictionaryRef service = (CFDictionaryRef)vals[i];
+ CFStringRef serviceID = (CFStringRef)keys[i];
+ Boolean trusted = FALSE; // trusted config w/interface
if (!isA_CFDictionary(service)) {
continue;
}
dns = CFDictionaryGetValue(service, kSCEntNetDNS);
- if (!isA_CFDictionary(dns)) {
+ dns = isA_CFDictionary(dns);
+ if (dns == NULL) {
continue;
}
+ interface = CFDictionaryGetValue(dns, kSCPropInterfaceName);
+
+ if (scoped_interface != NULL) {
+ //
+ // we only want to add split/supplemental configurations
+ // for queries scoped to an interface if they are NOT
+ // associated with a "real" service
+ //
+ if (CFDictionaryContainsKey(service, kSCEntNetIPv4) ||
+ CFDictionaryContainsKey(service, kSCEntNetIPv6)) {
+ continue;
+ }
+
+ //
+ // in addition, we don't want to add split/supplemental
+ // configurations for queries scoped to an interface if
+ // the configuration does not apply to all interfaces and
+ // the configuration is explicitly NOT for this interface
+ //
+ if (!_SC_CFEqual(interface, CFSTR("*")) &&
+ !_SC_CFEqual(interface, scoped_interface)) {
+ continue;
+ }
+
+ //
+ // lastly, check if A/AAAA queries should be issued (based
+ // on the IP[v6] addresses). If we would not be issuing a
+ // query then don't bother adding the configuration.
+ //
+ dns_resolver_flags = dns_resolver_flags_service(scoped_service, 0);
+ if (dns_resolver_flags == 0) {
+ continue;
+ }
+ }
+
defaultOrder = DEFAULT_SEARCH_ORDER
- (DEFAULT_SEARCH_ORDER / 2)
- + ((DEFAULT_SEARCH_ORDER / 1000) * i);
+ + ((DEFAULT_SEARCH_ORDER / 1000) * (uint32_t)i);
if ((n_order > 0) &&
!CFArrayContainsValue(service_order, CFRangeMake(0, n_order), keys[i])) {
// push out services not specified in service order
defaultOrder += (DEFAULT_SEARCH_ORDER / 1000) * n_services;
}
- add_supplemental(resolvers, dns, defaultOrder);
+ /*
+ * Ensure that we have the correct InterfaceName in the DNS configuration
+ *
+ * scoped_interface [supplemental] interface Trusted config DNS interface
+ * ================ ======================== ============== =================
+ * NULL NULL No NULL (No change)
+ * NULL en0 No NULL
+ * NULL * No NULL
+ * NULL NULL Yes NULL (No change)
+ * NULL en0 Yes en0 (trusted config w/interface)
+ * NULL * Yes NULL
+ * en0 NULL N/A en0 (scoped interface)
+ * en0 en0 N/A en0 (scoped interface)
+ * en0 * N/A en0 (scoped interface)
+ */
+ if ((scoped_interface == NULL) && (interface == NULL)) {
+ newDNS = (CFMutableDictionaryRef)CFRetain(dns);
+ } else {
+ CFBooleanRef val;
+
+ newDNS = CFDictionaryCreateMutableCopy(NULL, 0, dns);
+ if (scoped_interface != NULL) {
+ CFDictionarySetValue(newDNS, kSCPropInterfaceName, scoped_interface);
+ } else if ((interface != NULL) &&
+ CFDictionaryGetValueIfPresent(dns, DNS_CONFIGURATION_SCOPED_QUERY_KEY, (const void **)&val) &&
+ isA_CFBoolean(val) &&
+ CFBooleanGetValue(val)) {
+ // leave the [trusted configuration] InterfaceName in place
+ trusted = TRUE;
+ } else {
+ CFDictionaryRemoveValue(newDNS, kSCPropInterfaceName);
+ }
+ }
+
+ // set "supplemental" flag
+ newFlags = DNS_RESOLVER_FLAGS_SUPPLEMENTAL;
+
+ if (scoped_interface != NULL) {
+ // set "scoped" configuration flag
+ newFlags |= DNS_RESOLVER_FLAGS_SCOPED;
+
+ // add "Request A/AAAA query" flag(s)
+ newFlags |= dns_resolver_flags;
+ } else if (trusted) {
+ // use the DNS query flags from the supplemental match service
+ newFlags |= dns_resolver_flags_service(service, 0);
+ }
+
+ merge_configuration_flags(newDNS, newFlags);
+
+ // add [scoped] resolver entry
+ add_supplemental(resolvers, serviceID, newDNS, defaultOrder, (scoped_interface != NULL));
+ CFRelease(newDNS);
}
if (keys != keys_q) {
defaultOrder = DEFAULT_SEARCH_ORDER
+ (DEFAULT_SEARCH_ORDER / 2)
- + ((DEFAULT_SEARCH_ORDER / 1000) * i);
+ + ((DEFAULT_SEARCH_ORDER / 1000) * (uint32_t)i);
resolver = CFDictionaryCreateMutable(NULL,
0,
if (S_mdns_timeout != NULL) {
CFDictionarySetValue(resolver, kSCPropNetDNSServerTimeout, S_mdns_timeout);
}
+ add_resolver_signature(resolver, "Multicast DNS", NULL, i);
add_resolver(resolvers, resolver);
CFRelease(resolver);
CFRelease(domain);
defaultOrder = DEFAULT_SEARCH_ORDER
- (DEFAULT_SEARCH_ORDER / 4)
- + ((DEFAULT_SEARCH_ORDER / 1000) * i);
+ + ((DEFAULT_SEARCH_ORDER / 1000) * (uint32_t)i);
resolver = CFDictionaryCreateMutable(NULL,
0,
if (S_pdns_timeout != NULL) {
CFDictionarySetValue(resolver, kSCPropNetDNSServerTimeout, S_pdns_timeout);
}
+ add_resolver_signature(resolver, "Private DNS", NULL, i);
add_resolver(resolvers, resolver);
CFRelease(resolver);
CFRelease(domain);
static CFComparisonResult
compareBySearchOrder(const void *val1, const void *val2, void *context)
{
+#pragma unused(context)
CFDictionaryRef dns1 = (CFDictionaryRef)val1;
CFDictionaryRef dns2 = (CFDictionaryRef)val2;
CFNumberRef num1;
num1 = CFDictionaryGetValue(dns1, kSCPropNetDNSSearchOrder);
if (!isA_CFNumber(num1) ||
- !CFNumberGetValue(num1, kCFNumberIntType, &order1)) {
+ !CFNumberGetValue(num1, kCFNumberSInt32Type, &order1)) {
order1 = DEFAULT_SEARCH_ORDER;
}
num2 = CFDictionaryGetValue(dns2, kSCPropNetDNSSearchOrder);
if (!isA_CFNumber(num2) ||
- !CFNumberGetValue(num2, kCFNumberIntType, &order2)) {
+ !CFNumberGetValue(num2, kCFNumberSInt32Type, &order2)) {
order2 = DEFAULT_SEARCH_ORDER;
}
if (order1 == order2) {
// if same "SearchOrder", retain original orderring for configurations
- if (CFDictionaryGetValueIfPresent(dns1, CFSTR("*ORDER*"), (const void **)&num1) &&
- CFDictionaryGetValueIfPresent(dns2, CFSTR("*ORDER*"), (const void **)&num2) &&
+ if (CFDictionaryGetValueIfPresent(dns1, DNS_CONFIGURATION_ORDER_KEY, (const void **)&num1) &&
+ CFDictionaryGetValueIfPresent(dns2, DNS_CONFIGURATION_ORDER_KEY, (const void **)&num2) &&
isA_CFNumber(num1) &&
isA_CFNumber(num2) &&
- CFNumberGetValue(num1, kCFNumberIntType, &order1) &&
- CFNumberGetValue(num2, kCFNumberIntType, &order2)) {
+ CFNumberGetValue(num1, kCFNumberSInt32Type, &order1) &&
+ CFNumberGetValue(num2, kCFNumberSInt32Type, &order2)) {
if (order1 == order2) {
return kCFCompareEqualTo;
} else {
}
-static CFArrayRef
+static CF_RETURNS_RETAINED CFArrayRef
extract_search_domains(CFMutableDictionaryRef defaultDomain, CFArrayRef supplemental)
{
CFStringRef defaultDomainName = NULL;
uint32_t defaultOrder = DEFAULT_SEARCH_ORDER;
CFArrayRef defaultSearchDomains = NULL;
CFIndex defaultSearchIndex = 0;
- CFIndex i;
CFMutableArrayRef mySearchDomains;
CFMutableArrayRef mySupplemental = NULL;
CFIndex n_supplemental;
+ CFStringRef trimmedDomainName;
mySearchDomains = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
num = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSSearchOrder);
if (!isA_CFNumber(num) ||
- !CFNumberGetValue(num, kCFNumberIntType, &defaultOrder)) {
+ !CFNumberGetValue(num, kCFNumberSInt32Type, &defaultOrder)) {
defaultOrder = DEFAULT_SEARCH_ORDER;
}
CFIndex n_search;
n_search = CFArrayGetCount(defaultSearchDomains);
- for (i = 0; i < n_search; i++) {
+ for (int i = 0; i < n_search; i++) {
CFStringRef search;
search = CFArrayGetValueAtIndex(defaultSearchDomains, i);
}
}
} else {
- defaultDomainName = _SC_trimDomain(defaultDomainName);
- if (defaultDomainName != NULL) {
- CFStringRef defaultOptions;
+ trimmedDomainName = _SC_trimDomain(defaultDomainName);
+#ifdef PERFORM_DOMAIN_EXPANSION
+ /*
+ * With BIND 4.8.3 (and earlier) resolvers, the default search list included
+ * the default domain and each of its parent domains with two or more labels.
+ */
+ if ((trimmedDomainName != NULL) &&
+ CFStringHasSuffix(defaultDomainName, CFSTR("."))) {
+ // if "domain" name is fully qualified
+ CFArrayAppendValue(mySearchDomains, trimmedDomainName);
+ CFRelease(trimmedDomainName);
+ } else if (trimmedDomainName != NULL) {
char *domain;
int domain_parts = 1;
char *dp;
- int ndots = 1;
-
-#define NDOTS_OPT "ndots="
-#define NDOTS_OPT_LEN (sizeof("ndots=") - 1)
-
- defaultOptions = CFDictionaryGetValue(defaultDomain, kSCPropNetDNSOptions);
- if (defaultOptions != NULL) {
- char *cp;
- char *options;
-
- options = _SC_cfstring_to_cstring(defaultOptions,
- NULL,
- 0,
- kCFStringEncodingUTF8);
- cp = strstr(options, NDOTS_OPT);
- if ((cp != NULL) &&
- ((cp == options) || isspace(cp[-1])) &&
- ((cp[NDOTS_OPT_LEN] != '\0') && isdigit(cp[NDOTS_OPT_LEN]))) {
- char *end;
- long val;
-
- cp += NDOTS_OPT_LEN;
- errno = 0;
- val = strtol(cp, &end, 10);
- if ((*cp != '\0') && (cp != end) && (errno == 0) &&
- ((*end == '\0') || isspace(*end)) && (val > 0)) {
- ndots = val;
- }
- }
- CFAllocatorDeallocate(NULL, options);
- }
+ const int ndots = 1;
- domain = _SC_cfstring_to_cstring(defaultDomainName,
+ domain = _SC_cfstring_to_cstring(trimmedDomainName,
NULL,
0,
kCFStringEncodingUTF8);
- CFRelease(defaultDomainName);
+ CFRelease(trimmedDomainName);
// count domain parts
for (dp = domain; *dp != '\0'; dp++) {
}
// move "domain" to "search" list (and expand as needed)
- i = LOCALDOMAINPARTS;
dp = domain;
do {
CFStringRef search;
}
dp = strchr(dp, '.') + 1;
- } while (++i <= (domain_parts - ndots));
+ } while (domain_parts-- > 2);
CFAllocatorDeallocate(NULL, domain);
}
+#else // PERFORM_DOMAIN_EXPANSION
+ /*
+ * With BIND 4.9.3 (and later) resolvers, the default search list included
+ * just the default domain.
+ */
+ if (trimmedDomainName != NULL) {
+ CFArrayAppendValue(mySearchDomains, trimmedDomainName);
+ CFRelease(trimmedDomainName);
+ }
+#endif // PERFORM_DOMAIN_EXPANSION
}
// add any supplemental "domain" names to the search list
NULL);
supplemental = mySupplemental;
}
- for (i = 0; i < n_supplemental; i++) {
+ for (int i = 0; i < n_supplemental; i++) {
CFDictionaryRef dns;
CFIndex domainIndex;
+ int noSearch;
CFNumberRef num;
CFStringRef options;
CFStringRef supplementalDomain;
continue;
}
+ num = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchDomainsNoSearch);
+ if (isA_CFNumber(num) &&
+ CFNumberGetValue(num, kCFNumberIntType, &noSearch) &&
+ (noSearch != 0)) {
+ CFRelease(supplementalDomain);
+ continue;
+ }
+
if (CFStringHasSuffix(supplementalDomain, CFSTR(".in-addr.arpa")) ||
CFStringHasSuffix(supplementalDomain, CFSTR(".ip6.arpa" ))) {
CFRelease(supplementalDomain);
num = CFDictionaryGetValue(dns, kSCPropNetDNSSearchOrder);
if (!isA_CFNumber(num) ||
- !CFNumberGetValue(num, kCFNumberIntType, &supplementalOrder)) {
+ !CFNumberGetValue(num, kCFNumberSInt32Type, &supplementalOrder)) {
supplementalOrder = DEFAULT_SEARCH_ORDER;
}
static void
-add_scoped_resolvers(CFMutableArrayRef scoped, CFDictionaryRef services, CFArrayRef service_order)
+add_scoped_resolvers(CFMutableArrayRef scoped,
+ CFDictionaryRef services,
+ CFArrayRef service_order)
{
const void * keys_q[N_QUICK];
const void ** keys = keys_q;
n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0;
if (n_order > 0) {
order = CFArrayCreateMutableCopy(NULL, 0, service_order);
- } else{
+ } else {
order = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
seen = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
for (i = 0; i < n_order; i++) {
CFDictionaryRef dns;
- uint32_t flags;
- unsigned int if_index;
+ uint32_t dns_resolver_flags;
char if_name[IF_NAMESIZE];
CFStringRef interface;
CFMutableDictionaryRef newDNS;
- CFNumberRef num;
+ uint32_t newFlags;
CFArrayRef searchDomains;
CFDictionaryRef service;
CFStringRef serviceID;
+ CFArrayRef servers;
serviceID = CFArrayGetValueAtIndex(order, i);
service = CFDictionaryGetValue(services, serviceID);
continue;
}
+ servers = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses);
+ if (!isA_CFArray(servers) || (CFArrayGetCount(servers) == 0)) {
+ // if no DNS server addresses
+ continue;
+ }
+
interface = CFDictionaryGetValue(dns, kSCPropInterfaceName);
- if (interface == NULL) {
- // if no [scoped] interface
+ if ((interface == NULL) || CFEqual(interface, CFSTR("*"))) {
+ // if no [scoped] interface or supplemental configuration w/match-all
continue;
}
+
+ if (CFDictionaryContainsKey(dns, kSCPropNetDNSServiceIdentifier)) {
+ // if this is a service-specific resolver
+ continue;
+ }
+
if (CFSetContainsValue(seen, interface)) {
// if we've already processed this [scoped] interface
continue;
if_name,
sizeof(if_name),
kCFStringEncodingASCII) == NULL) ||
- ((if_index = if_nametoindex(if_name)) == 0)) {
+ (my_if_nametoindex(if_name) == 0)) {
// if interface index not available
continue;
}
CFRelease(searchDomains);
}
- // set if_index
- num = CFNumberCreate(NULL, kCFNumberIntType, &if_index);
- CFDictionarySetValue(newDNS, CFSTR("*IF_INDEX*"), num);
- CFRelease(num);
+ // get "Request A/AAAA query" flag(s)
+ dns_resolver_flags = dns_resolver_flags_service(service, 0);
+ if (dns_resolver_flags == 0) {
+ goto skip;
+ }
- // set "scoped" flag
- flags = DNS_RESOLVER_FLAGS_SCOPED;
- num = CFNumberCreate(NULL, kCFNumberSInt32Type, &flags);
- CFDictionarySetValue(newDNS, CFSTR("*FLAGS*"), num);
- CFRelease(num);
+ // set "scoped" configuration flag
+ newFlags = DNS_RESOLVER_FLAGS_SCOPED;
+
+ // add "Request A/AAAA query" flag(s)
+ newFlags |= dns_resolver_flags;
+
+ merge_configuration_flags(newDNS, newFlags);
// remove keys we don't want in a [scoped] resolver
CFDictionaryRemoveValue(newDNS, kSCPropNetDNSSupplementalMatchDomains);
CFDictionaryRemoveValue(newDNS, kSCPropNetDNSSupplementalMatchOrders);
+ // add the [scoped] resolver
+ add_resolver_signature(newDNS, "Scoped", serviceID, 0);
add_resolver(scoped, newDNS);
+
+ // add any supplemental resolver configurations for this interface
+ add_supplemental_resolvers(scoped, services, service_order, interface, service);
+
+ skip:
CFRelease(newDNS);
}
}
+static void
+add_service_specific_resolvers(CFMutableArrayRef resolvers, CFDictionaryRef services)
+{
+ CFIndex i;
+ CFStringRef keys_q[N_QUICK];
+ CFStringRef *keys = keys_q;
+ CFIndex n_services;
+ CFMutableSetRef seen;
+ CFDictionaryRef vals_q[N_QUICK];
+ CFDictionaryRef *vals = vals_q;
+
+ n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
+ if (n_services == 0) {
+ return; // if no services
+ }
+
+ if (n_services > (CFIndex)(sizeof(keys_q) / sizeof(keys_q[0]))) {
+ keys = CFAllocatorAllocate(kCFAllocatorDefault, n_services * sizeof(keys[0]), 0);
+ vals = CFAllocatorAllocate(kCFAllocatorDefault, n_services * sizeof(vals[0]), 0);
+ }
+ CFDictionaryGetKeysAndValues(services, (const void **)keys, (const void **)vals);
+
+ seen = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks);
+ for (i = 0; i < n_services; i++) {
+ CFDictionaryRef dns;
+ CFNumberRef dns_service_identifier;
+ CFMutableDictionaryRef newDNS;
+ uint32_t newFlags = 0;
+ CFDictionaryRef service = vals[i];
+ CFStringRef serviceID = keys[i];
+ CFArrayRef searchDomains;
+
+ dns = CFDictionaryGetValue(service, kSCEntNetDNS);
+ if (!isA_CFDictionary(dns)) {
+ // if no DNS
+ continue;
+ }
+
+ dns_service_identifier = CFDictionaryGetValue(dns, kSCPropNetDNSServiceIdentifier);
+ if (!isA_CFNumber(dns_service_identifier)) {
+ // if no DNS [vpn] Service Identifier
+ continue;
+ }
+
+ if (CFSetContainsValue(seen, dns_service_identifier)) {
+ my_log(LOG_ERR, "add_service_specific_resolvers: got a resolver with a duplicate service identifier, skipping");
+ continue;
+ }
+ CFSetSetValue(seen, dns_service_identifier);
+
+ newDNS = CFDictionaryCreateMutableCopy(NULL, 0, dns);
+
+ // add "Request A/AAAA query" flag(s)
+ newFlags |= DNS_RESOLVER_FLAGS_REQUEST_ALL_RECORDS;
+
+ // set search list
+ searchDomains = extract_search_domains(newDNS, NULL);
+ if (searchDomains != NULL) {
+ CFDictionarySetValue(newDNS, kSCPropNetDNSSearchDomains, searchDomains);
+ CFRelease(searchDomains);
+ searchDomains = NULL;
+ }
+
+ CFDictionaryRemoveValue(newDNS, kSCPropNetDNSSupplementalMatchDomains);
+ CFDictionaryRemoveValue(newDNS, kSCPropNetDNSSupplementalMatchOrders);
+
+ if (CFDictionaryContainsKey(newDNS, kSCPropInterfaceName)) {
+ CFMutableDictionaryRef interfaceScopedDNS;
+ uint32_t interfaceScopedFlags;
+
+ // The dictionary has an interface, so add a interface-scoped resolver
+
+ CFDictionarySetValue(newDNS, DNS_CONFIGURATION_SCOPED_QUERY_KEY, kCFBooleanTrue);
+
+ interfaceScopedDNS = CFDictionaryCreateMutableCopy(NULL, 0, newDNS);
+ interfaceScopedFlags = newFlags;
+
+ // set "scoped" configuration flag
+ interfaceScopedFlags |= DNS_RESOLVER_FLAGS_SCOPED;
+ merge_configuration_flags(interfaceScopedDNS, interfaceScopedFlags);
+
+ CFDictionaryRemoveValue(interfaceScopedDNS, kSCPropNetDNSServiceIdentifier);
+
+ add_resolver_signature(interfaceScopedDNS, "Service", serviceID, 0);
+ add_resolver(resolvers, interfaceScopedDNS);
+ CFRelease(interfaceScopedDNS);
+ }
+
+ // set "service specific" configuration flag
+ newFlags |= DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC;
+ merge_configuration_flags(newDNS, newFlags);
+
+ add_resolver_signature(newDNS, "Service", serviceID, 0);
+ add_resolver(resolvers, newDNS);
+ CFRelease(newDNS);
+ }
+ CFRelease(seen);
+
+ if (keys != keys_q) {
+ CFAllocatorDeallocate(kCFAllocatorDefault, keys);
+ CFAllocatorDeallocate(kCFAllocatorDefault, vals);
+ }
+
+ return;
+}
+
+
static void
add_default_resolver(CFMutableArrayRef resolvers,
CFDictionaryRef defaultResolver,
} else {
myDefault = CFDictionaryCreateMutableCopy(NULL, 0, defaultResolver);
}
+ assert(myDefault != NULL);
// ensure that the default resolver has a search order
order = CFDictionaryGetValue(myDefault, kSCPropNetDNSSearchOrder);
if (!isA_CFNumber(order) ||
- !CFNumberGetValue(order, kCFNumberIntType, &myOrder)) {
+ !CFNumberGetValue(order, kCFNumberSInt32Type, &myOrder)) {
myOrder = DEFAULT_SEARCH_ORDER;
order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder);
CFDictionarySetValue(myDefault, kSCPropNetDNSSearchOrder, order);
// add the default resolver
+ add_resolver_signature(myDefault, "Default", NULL, 0);
add_resolver(resolvers, myDefault);
CFRelease(myDefault);
return;
CFNumberRef num;
dns_create_resolver_t _resolver;
CFStringRef str;
+ CFStringRef targetInterface = NULL;
+ unsigned int targetInterfaceIndex = 0;
_resolver = _dns_resolver_create();
}
}
+ // process interface index
+ num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_IF_INDEX_KEY);
+ if (isA_CFNumber(num)) {
+ int if_index;
+
+ if (CFNumberGetValue(num, kCFNumberIntType, &if_index)) {
+ char buf[IFNAMSIZ];
+ const char *if_name = NULL;
+
+ if (if_index != 0) {
+ if_name = my_if_indextoname(if_index, buf);
+ if (if_name != NULL) {
+ targetInterface = CFStringCreateWithCString(NULL,
+ if_name,
+ kCFStringEncodingASCII);
+ targetInterfaceIndex = if_index;
+ }
+ }
+
+ _dns_resolver_set_if_index(&_resolver, if_index, if_name);
+ }
+ }
+
+ // process flags
+ num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_FLAGS_KEY);
+ if (isA_CFNumber(num)) {
+ uint32_t flags;
+
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
+ _dns_resolver_set_flags(&_resolver, flags);
+ }
+ }
+
// process nameserver addresses
+ // Note: the flags may be overwritten if the resolver has LOOPBACK addresses
list = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses);
if (isA_CFArray(list)) {
CFIndex i;
- CFIndex n = CFArrayGetCount(list);
+ CFIndex n = CFArrayGetCount(list);
for (i = 0; i < n; i++) {
union {
- struct sockaddr sa;
- struct sockaddr_in sin;
- struct sockaddr_in6 sin6;
+ struct sockaddr sa;
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
} addr;
- char buf[128];
+ char buf[64];
str = CFArrayGetValueAtIndex(list, i);
if (!isA_CFString(str)) {
continue;
}
- bzero(&addr, sizeof(addr));
- if (inet_aton(buf, &addr.sin.sin_addr) == 1) {
- /* if IPv4 address */
- addr.sin.sin_len = sizeof(addr.sin);
- addr.sin.sin_family = AF_INET;
- _dns_resolver_add_nameserver(&_resolver, &addr.sa);
- } else if (inet_pton(AF_INET6, buf, &addr.sin6.sin6_addr) == 1) {
- /* if IPv6 address */
- char *p;
-
- p = strchr(buf, '%');
- if (p != NULL) {
- addr.sin6.sin6_scope_id = if_nametoindex(p + 1);
- }
-
- addr.sin6.sin6_len = sizeof(addr.sin6);
- addr.sin6.sin6_family = AF_INET6;
- _dns_resolver_add_nameserver(&_resolver, &addr.sa);
- } else {
+ if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) {
continue;
}
+
+ if ((addr.sa.sa_family == AF_INET6) &&
+ IN6_IS_ADDR_LINKLOCAL(&addr.sin6.sin6_addr) &&
+ (addr.sin6.sin6_scope_id == 0) &&
+ (targetInterfaceIndex != 0)) {
+ // for link local [IPv6] addresses, if the scope id is not
+ // set then we should use the interface associated with the
+ // resolver configuration
+ addr.sin6.sin6_scope_id = targetInterfaceIndex;
+ }
+
+ _dns_resolver_add_nameserver(&_resolver, &addr.sa);
}
}
if (isA_CFNumber(num)) {
uint32_t order;
- if (CFNumberGetValue(num, kCFNumberIntType, &order)) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &order)) {
_dns_resolver_set_order(&_resolver, order);
}
}
*slash = '\0';
}
- bzero(&sortaddr, sizeof(sortaddr));
+ memset(&sortaddr, 0, sizeof(sortaddr));
if (inet_aton(buf, &sortaddr.address) != 1) {
/* if address not valid */
continue;
}
}
- // process interface index
- num = CFDictionaryGetValue(dns, CFSTR("*IF_INDEX*"));
+ num = CFDictionaryGetValue(dns, kSCPropNetDNSServiceIdentifier);
if (isA_CFNumber(num)) {
- int if_index;
+ int dns_service_identifier;
- if (CFNumberGetValue(num, kCFNumberIntType, &if_index)) {
- _dns_resolver_set_if_index(&_resolver, if_index);
+ if (CFNumberGetValue(num, kCFNumberIntType, &dns_service_identifier)) {
+ _dns_resolver_set_service_identifier(&_resolver, (uint32_t)dns_service_identifier);
}
}
- // process flags
- num = CFDictionaryGetValue(dns, CFSTR("*FLAGS*"));
- if (isA_CFNumber(num)) {
- uint32_t flags;
+ // process configuration ID
+ str = CFDictionaryGetValue(dns, DNS_CONFIGURATION_CONFIGURATION_ID);
+ if (isA_CFString(str) && (CFStringGetLength(str) > 0)) {
+ char *cID;
- if (CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
- _dns_resolver_set_flags(&_resolver, flags);
+ cID = _SC_cfstring_to_cstring(str, NULL, 0, kCFStringEncodingUTF8);
+ if (cID != NULL) {
+ _dns_resolver_set_configuration_identifier(&_resolver, cID);
+ CFAllocatorDeallocate(NULL, cID);
}
}
+ if (targetInterface != NULL) {
+ CFRelease(targetInterface);
+ }
+
return _resolver;
}
static __inline__ Boolean
-isScopedDNS(CFDictionaryRef dns)
+isScopedConfiguration(CFDictionaryRef dns)
{
uint32_t flags;
CFNumberRef num;
if ((dns != NULL) &&
- CFDictionaryGetValueIfPresent(dns, CFSTR("*FLAGS*"), (const void **)&num) &&
+ CFDictionaryGetValueIfPresent(dns, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) &&
(num != NULL) &&
CFNumberGetValue(num, kCFNumberSInt32Type, &flags) &&
((flags & DNS_RESOLVER_FLAGS_SCOPED) != 0)) {
+ // if scoped
return TRUE;
}
}
// sort non-scoped before scoped
- scoped1 = isScopedDNS(dns1);
- scoped2 = isScopedDNS(dns2);
+ scoped1 = isScopedConfiguration(dns1);
+ scoped2 = isScopedConfiguration(dns2);
if (scoped1 != scoped2) {
if (!scoped1) {
return kCFCompareLessThan;
}
}
- // must have domain names for any further comparisons
- if ((domain1 == NULL) || (domain2 == NULL)) {
- return kCFCompareEqualTo;
- }
-
// forward (A, AAAA) domains sort before reverse (PTR) domains
rev1 = CFStringHasSuffix(domain1, CFSTR(".arpa"));
rev2 = CFStringHasSuffix(domain2, CFSTR(".arpa"));
}
+static __inline__ Boolean
+needsMergeWithDefaultConfiguration(CFDictionaryRef dns)
+{
+ uint32_t flags;
+ CFNumberRef num;
+
+ if ((dns != NULL) &&
+ CFDictionaryGetValueIfPresent(dns, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) &&
+ (num != NULL) &&
+ CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) {
+
+ // check if merge needed (at all)
+ if (dns_resolver_flags_all_queries(flags)) {
+ // if we are already querying for both A/AAAA
+ return FALSE;
+ }
+
+ // check if scoped or service-specific
+ if (((flags & DNS_RESOLVER_FLAGS_SCOPED ) != 0) ||
+ ((flags & DNS_RESOLVER_FLAGS_SERVICE_SPECIFIC) != 0)) {
+ // yes, skip merge
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+
__private_extern__
-void
+Boolean
dns_configuration_set(CFDictionaryRef defaultResolver,
CFDictionaryRef services,
CFArrayRef serviceOrder,
CFArrayRef multicastResolvers,
- CFArrayRef privateResolvers)
+ CFArrayRef privateResolvers,
+ CFDictionaryRef *globalResolver)
{
+ dns_create_config_t dns_create_config;
+ Boolean changed = FALSE;
CFIndex i;
CFMutableDictionaryRef myDefault;
- Boolean myOrderAdded = FALSE;
- CFArrayRef mySearchDomains = NULL;
+ Boolean myOrderAdded = FALSE;
+ CFArrayRef mySearchDomains = NULL;
CFIndex n_resolvers;
CFMutableArrayRef resolvers;
+ unsigned char signature[CC_SHA256_DIGEST_LENGTH];
+ static unsigned char signature_last[CC_SHA256_DIGEST_LENGTH];
// establish list of resolvers
resolvers = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ assert(resolvers != NULL);
// collect (and add) any "supplemental" resolver configurations
- add_supplemental_resolvers(resolvers, services, serviceOrder);
+ add_supplemental_resolvers(resolvers, services, serviceOrder, NULL, NULL);
// collect (and add) any "private" resolver configurations
// add the "default" resolver
+ if (defaultResolver != NULL) {
+ CFArrayRef servers;
+
+ servers = CFDictionaryGetValue(defaultResolver, kSCPropNetDNSServerAddresses);
+ if (!isA_CFArray(servers) || (CFArrayGetCount(servers) == 0)) {
+ // if no DNS server addresses
+ defaultResolver = NULL;
+ }
+ }
+
add_default_resolver(resolvers, defaultResolver, &myOrderAdded, &mySearchDomains);
// collect (and add) any "multicast" resolver configurations
add_scoped_resolvers(resolvers, services, serviceOrder);
+ // collect (and add) any "service-specific" resolver configurations
+
+ add_service_specific_resolvers(resolvers, services);
+
// sort resolvers
n_resolvers = CFArrayGetCount(resolvers);
resolver = CFArrayGetValueAtIndex(resolvers, 1);
if (CFDictionaryContainsKey(resolver, kSCPropNetDNSDomainName) ||
- isScopedDNS(resolver)) {
+ isScopedConfiguration(resolver)) {
// if not a supplemental "default" resolver (a domain name is
- // present) or a if it's a scoped resolver
+ // present) or if it's a scoped configuration
CFDictionaryRemoveValue(myDefault, kSCPropNetDNSSearchOrder);
}
}
/*
* if no default and no supplemental/scoped resolvers
*/
- if (!_dns_configuration_store(NULL)) {
- SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration"));
- }
+ dns_create_config = NULL;
} else {
- dns_create_config_t _config;
+ uint32_t default_resolver_flags = 0;
+ Boolean have_default_flags = FALSE;
/*
* if default and/or supplemental/scoped resolvers are defined
*/
- _config = _dns_configuration_create();
-
- // add resolvers
+ dns_create_config = _dns_configuration_create();
for (i = 0; i < n_resolvers; i++) {
+ Boolean merge_default_flags;
CFDictionaryRef resolver;
dns_create_resolver_t _resolver;
resolver = CFArrayGetValueAtIndex(resolvers, i);
+
+ merge_default_flags = needsMergeWithDefaultConfiguration(resolver);
+ if (merge_default_flags) {
+ CFMutableDictionaryRef new_resolver;
+
+ if (!have_default_flags) {
+ CFDictionaryApplyFunction(services,
+ add_dns_resolver_flags,
+ &default_resolver_flags);
+ have_default_flags = TRUE;
+ }
+
+ new_resolver = CFDictionaryCreateMutableCopy(NULL, 0, resolver);
+ merge_configuration_flags(new_resolver, default_resolver_flags);
+ resolver = new_resolver;
+ }
+
+ if (i == 0) {
+ *globalResolver = CFRetain(resolver);
+ }
+
_resolver = create_resolver(resolver);
- _dns_configuration_add_resolver(&_config, _resolver);
+ _dns_configuration_add_resolver(&dns_create_config, _resolver);
_dns_resolver_free(&_resolver);
+
+ if (merge_default_flags) {
+ CFRelease(resolver);
+ }
}
-#if !TARGET_OS_IPHONE
// add flatfile resolvers
- _dnsinfo_flatfile_add_resolvers(&_config);
-#endif // !TARGET_OS_IPHONE
+ _dnsinfo_flatfile_set_flags(default_resolver_flags);
+ _dnsinfo_flatfile_add_resolvers(&dns_create_config);
+ }
- // save configuration
+ // check if the configuration changed
+ _dns_configuration_signature(&dns_create_config, signature, sizeof(signature));
+ if (bcmp(signature, signature_last, sizeof(signature)) != 0) {
+ // save [new] signature
+ memcpy(signature_last, signature, sizeof(signature));
+
+ my_log(LOG_INFO, "Updating DNS configuration");
+ if (dns_create_config != NULL) {
+ dns_config_t *dns_config = NULL;
+ _dns_config_buf_t *dns_config_buf;
+ size_t n;
+
+ n = sizeof(_dns_config_buf_t);
+ n += ntohl(((_dns_config_buf_t *)dns_create_config)->n_attribute);
+ dns_config_buf = _dns_configuration_buffer_create((void *)dns_create_config, n);
+ if (dns_config_buf != NULL) {
+ dns_config = _dns_configuration_buffer_expand(dns_config_buf);
+ if (dns_config == NULL) {
+ // if we were unable to expand the configuration
+ _dns_configuration_buffer_free(&dns_config_buf);
+ }
+ }
- if (!_dns_configuration_store(&_config)) {
- SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration"));
+ if (dns_config != NULL) {
+ _dns_configuration_log(dns_config, TRUE, NULL);
+ free(dns_config);
+ }
+ } else {
+ my_log(LOG_INFO, "*** No DNS configuration");
}
+#ifndef MAIN
+ // save [new] configuration
+ if (!_dns_configuration_store(&dns_create_config)) {
+ my_log(LOG_ERR, "could not store configuration");
+ }
+#endif // MAIN
- _dns_configuration_free(&_config);
+ changed = TRUE;
+ }
+
+ if (dns_create_config != NULL) {
+ _dns_configuration_free(&dns_create_config);
}
CFRelease(resolvers);
- return;
+ return changed;
}
-#if !TARGET_OS_IPHONE
static SCDynamicStoreRef dns_configuration_store;
static SCDynamicStoreCallBack dns_configuration_callout;
static void
-dns_configuration_changed(CFMachPortRef port, void *msg, CFIndex size, void *info)
+dns_configuration_changed(ConstFSEventStreamRef streamRef,
+ void *clientCallBackInfo,
+ size_t numEvents,
+ void *eventPaths,
+ const FSEventStreamEventFlags *eventFlags,
+ const FSEventStreamEventId *eventIds)
{
- CFStringRef key = CFSTR(_PATH_RESOLVER_DIR);
- CFArrayRef keys;
- Boolean resolvers_now;
- static Boolean resolvers_save = FALSE;
- struct stat statbuf;
+#pragma unused(streamRef)
+#pragma unused(clientCallBackInfo)
+#pragma unused(numEvents)
+#pragma unused(eventPaths)
+#pragma unused(eventFlags)
+#pragma unused(eventIds)
+ static const CFStringRef key = CFSTR(_PATH_RESOLVER_DIR);
+ CFArrayRef keys;
+ Boolean resolvers_now;
+ static Boolean resolvers_save = FALSE;
+ struct stat statbuf;
resolvers_now = (stat(_PATH_RESOLVER_DIR, &statbuf) == 0);
if (!resolvers_save && (resolvers_save == resolvers_now)) {
}
resolvers_save = resolvers_now;
- SCLog(TRUE, LOG_DEBUG, CFSTR(_PATH_RESOLVER_DIR " changed"));
+ my_log(LOG_INFO, _PATH_RESOLVER_DIR " changed");
// fake a "DNS" change
keys = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks);
(*dns_configuration_callout)(dns_configuration_store, keys, NULL);
CFRelease(keys);
+
return;
}
+static Boolean
+normalize_path(const char *file_name, char resolved_name[PATH_MAX])
+{
+ char *ch;
+ char path[PATH_MAX];
+
+ strlcpy(path, file_name, sizeof(path));
+ if (realpath(path, resolved_name) != NULL) {
+ // if the path exists
+ return TRUE;
+ }
+
+ ch = strrchr(path, '/');
+ if (ch != NULL) {
+ *ch = '\0';
+ if (realpath(path, resolved_name) != NULL) {
+ // if a parent path exists
+ strlcat(resolved_name, "/", PATH_MAX);
+ strlcat(resolved_name, ch+1, PATH_MAX);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+
__private_extern__
void
dns_configuration_monitor(SCDynamicStoreRef store, SCDynamicStoreCallBack callout)
{
- CFMachPortRef mp;
- mach_port_t notify_port;
- int notify_token;
- CFRunLoopSourceRef rls;
- uint32_t status;
+ FSEventStreamContext context = { 0, // version
+ NULL, // info
+ NULL, // retain
+ NULL, // release
+ NULL }; // copyDescription
+ FSEventStreamCreateFlags flags = kFSEventStreamCreateFlagUseCFTypes
+ | kFSEventStreamCreateFlagFileEvents
+ | kFSEventStreamCreateFlagWatchRoot;
+ FSEventStreamRef monitor;
+ CFStringRef path;
+ CFMutableArrayRef paths;
+ char resolver_directory_path[PATH_MAX];
+
+ if (!normalize_path(_PATH_RESOLVER_DIR, resolver_directory_path)) {
+ my_log(LOG_ERR, "Not monitoring \"%s\", could not resolve directory path", _PATH_RESOLVER_DIR);
+ return;
+ }
dns_configuration_store = store;
dns_configuration_callout = callout;
- status = notify_register_mach_port(_PATH_RESOLVER_DIR, ¬ify_port, 0, ¬ify_token);
- if (status != NOTIFY_STATUS_OK) {
- SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed"));
- return;
- }
+ paths = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
+ path = CFStringCreateWithCString(NULL, resolver_directory_path, kCFStringEncodingUTF8);
+ CFArrayAppendValue(paths, path);
+ CFRelease(path);
- status = notify_monitor_file(notify_token, "/private" _PATH_RESOLVER_DIR, 0);
- if (status != NOTIFY_STATUS_OK) {
- SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_monitor_file() failed"));
- (void)notify_cancel(notify_token);
- return;
- }
+ monitor = FSEventStreamCreate(NULL, // allocator
+ dns_configuration_changed, // callback
+ &context, // context
+ paths, // pathsToWatch (CFArray)
+ kFSEventStreamEventIdSinceNow, // sinceWhen
+ 0.0, // latency
+ flags); // flags
- mp = _SC_CFMachPortCreateWithPort("IPMonitor/dns_configuration",
- notify_port,
- dns_configuration_changed,
- NULL);
+ CFRelease(paths);
- rls = CFMachPortCreateRunLoopSource(NULL, mp, -1);
- if (rls == NULL) {
- SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("SCDynamicStoreCreateRunLoopSource() failed"));
- CFRelease(mp);
- (void)notify_cancel(notify_token);
- return;
- }
- CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode);
- CFRelease(rls);
+ FSEventStreamScheduleWithRunLoop(monitor, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
+ FSEventStreamStart(monitor);
- CFRelease(mp);
return;
}
-#endif // !TARGET_OS_IPHONE
__private_extern__
}
+#pragma mark -
+#pragma mark Standalone test code
+
+
#ifdef MAIN
static void
if (CFEqual(entity_id, kSCEntNetIPv4) ||
CFEqual(entity_id, kSCEntNetIPv6)) {
- CFStringRef interface;
+ CFDictionaryRef dict;
+ CFStringRef interface;
+
+ if (CFEqual(entity_id, kSCEntNetIPv4)) {
+ dict = ipv4_dict_create(value);
+ }
+ else {
+ dict = ipv6_dict_create(value);
+ }
+ if (dict != NULL) {
+ CFDictionarySetValue(state_dict, entity_id, dict);
+ }
interface = CFDictionaryGetValue((CFDictionaryRef)value, kSCPropInterfaceName);
if (interface != NULL) {
new_dns = CFDictionaryCreateMutableCopy(NULL, 0, dns);
} else {
new_dns = CFDictionaryCreateMutable(NULL,
- 0,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
}
CFDictionarySetValue(new_dns, kSCPropInterfaceName, interface);
CFDictionarySetValue(state_dict, kSCEntNetDNS, new_dns);
main(int argc, char **argv)
{
CFDictionaryRef entities;
+ CFDictionaryRef globalResolver = NULL;
CFStringRef key;
CFArrayRef multicast_resolvers;
CFStringRef pattern;
CFDictionaryRef state_global_ipv4;
SCDynamicStoreRef store;
- _sc_log = FALSE;
+ _sc_debug = TRUE;
+ _sc_log = kSCLogDestinationFile;
_sc_verbose = (argc > 1) ? TRUE : FALSE;
store = SCDynamicStoreCreate(NULL, CFSTR("TEST"), NULL, NULL);
// update DNS configuration
dns_configuration_init(CFBundleGetMainBundle());
- dns_configuration_set(primaryDNS,
- service_state_dict,
- service_order,
- multicast_resolvers,
- private_resolvers);
+ (void)dns_configuration_set(primaryDNS,
+ service_state_dict,
+ service_order,
+ multicast_resolvers,
+ private_resolvers,
+ &globalResolver);
// cleanup
if (setup_global_ipv4 != NULL) CFRelease(setup_global_ipv4);
if (state_global_ipv4 != NULL) CFRelease(state_global_ipv4);
if (multicast_resolvers != NULL) CFRelease(multicast_resolvers);
if (private_resolvers != NULL) CFRelease(private_resolvers);
+ if (globalResolver != NULL) CFRelease(globalResolver);
CFRelease(service_state_dict);
CFRelease(store);