From: Apple Date: Tue, 24 Jul 2012 15:52:23 +0000 (+0000) Subject: configd-453.16.tar.gz X-Git-Tag: mac-os-x-108^0 X-Git-Url: https://git.saurik.com/apple/configd.git/commitdiff_plain/17d3ee29fb04fcc79d3be0b9d5c7bcb377cfc610 configd-453.16.tar.gz --- diff --git a/Makefile b/Makefile index b3d4dc2..af81588 100644 --- a/Makefile +++ b/Makefile @@ -12,33 +12,25 @@ all : -noinstallsrc -noinstallhdrs -noverify -nosum \ -arch i386 -arch x86_64 -arch ppc \ -target All \ - -project configd \ + -project ${PROJECT}-${VERSION} \ -configuration Debug \ -release $(shell cat /usr/share/buildit/.releaseName) \ #---------------------------------------------------------------------- # -# Build for SnowLeopard, SUSnowXXX, ... -# -# Note: assumes that the "pppcontroller_sendmsg" routine has been defined -# in pppcontroller.defs. +# Darwin build # #---------------------------------------------------------------------- -SNOW_CFLAGS += -D__MAC_10_7=1060 -SNOW_CFLAGS += -D__AVAILABILITY_INTERNAL__MAC_10_7=__AVAILABILITY_INTERNAL__MAC_10_6 -SNOW_CFLAGS += -D__AVAILABILITY_INTERNAL__MAC_10_5_DEP__MAC_10_7=__AVAILABILITY_INTERNAL__MAC_10_5 -#SNOW_CFLAGS += -DHAVE_PPPCONTROLLER_SENDMSG=YES - -snow : +darwin : /usr/local/bin/buildit . \ -noinstallsrc -noinstallhdrs -noverify -nosum \ - -arch i386 -arch x86_64 -arch ppc \ + -arch i386 -arch x86_64 -arch ppc \ -target All \ - -project ${PROJECT} \ + -project ${PROJECT}_darwin-${VERSION} \ -configuration Debug \ -release $(shell cat /usr/share/buildit/.releaseName) \ - -othercflags "\"$(SNOW_CFLAGS)\"" \ + -othercflags "\"-D_OPEN_SOURCE_\"" \ #---------------------------------------------------------------------- # @@ -47,6 +39,9 @@ snow : #---------------------------------------------------------------------- LION_CFLAGS= +LION_CFLAGS+=-D__MAC_10_8=1070 +LION_CFLAGS+=-D__AVAILABILITY_INTERNAL__MAC_10_8=__attribute__((visibility(\\\"default\\\"))) +LION_CFLAGS+=-DHAVE_REACHABILITY_SERVER=YES lion : /usr/local/bin/buildit . \ diff --git a/Plugins/IPMonitor/Info.plist b/Plugins/IPMonitor/Info.plist index eadcad1..667418a 100644 --- a/Plugins/IPMonitor/Info.plist +++ b/Plugins/IPMonitor/Info.plist @@ -15,15 +15,16 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.11.3 + 1.12 CFBundleSignature ???? CFBundleVersion - 1.11 + 1.12 Requires com.apple.SystemConfiguration.IPConfiguration com.apple.SystemConfiguration.PreferencesMonitor + com.apple.SystemConfiguration.SCNetworkReachability Builtin diff --git a/Plugins/IPMonitor/Makefile b/Plugins/IPMonitor/Makefile index f3106a4..5b0750c 100644 --- a/Plugins/IPMonitor/Makefile +++ b/Plugins/IPMonitor/Makefile @@ -11,16 +11,19 @@ shared_dns_infoUser.o: shared_dns_info.h shared_dns_infoUser.c cc -I../../dnsinfo -Wall -O0 -g -c shared_dns_infoUser.c dnsinfo_create.o: shared_dns_info.h ../../dnsinfo/dnsinfo_create.h ../../dnsinfo/dnsinfo_create.c - cc -I. -I../../dnsinfo -Wall -O0 -g -c ../../dnsinfo/dnsinfo_create.c + cc -I. -I../../dnsinfo -I../../nwi -Wall -O0 -g -c ../../dnsinfo/dnsinfo_create.c dnsinfo_flatfile.o: ../../dnsinfo/dnsinfo_copy.c ../../dnsinfo/dnsinfo_flatfile.c shared_dns_info.h - cc -I../../dnsinfo -D_PATH_RESOLVER_DIR='"/var/tmp/resolver"' -Wall -O0 -g -c ../../dnsinfo/dnsinfo_flatfile.c + cc -I../../dnsinfo -I../../nwi -D_PATH_RESOLVER_DIR='"/var/tmp/resolver"' -Wall -O0 -g -c ../../dnsinfo/dnsinfo_flatfile.c dnsinfo_private.o: ../../dnsinfo/dnsinfo_private.h ../../dnsinfo/dnsinfo_private.c cc -I../../dnsinfo -Wall -O0 -g -c ../../dnsinfo/dnsinfo_private.c dns-configuration.o: dns-configuration.h dns-configuration.c dnsinfo_create.o - cc -I. -I../../dnsinfo -DMAIN -Wall -O0 -g -c dns-configuration.c + cc -I. -I../../dnsinfo -I../../nwi -DMAIN -Wall -O0 -g -c dns-configuration.c + +network_information_priv.o: ../../nwi/network_information_priv.h ../../nwi/network_information_priv.c + cc -I. -I../../dnsinfo -I../../nwi -DMAIN -Wall -O0 -g -c ../../nwi/network_information_priv.c proxy-configuration.o: proxy-configuration.h proxy-configuration.c cc -I. -Wall -O0 -g -c proxy-configuration.c @@ -46,10 +49,10 @@ test_smb: Makefile smb-configuration.h smb-configuration.c # ---------- test_ipv4_routelist.o: ip_plugin.c - cc -I. -I../../dnsinfo -DTEST_IPV4_ROUTELIST -Wall -O0 -g -c -o test_ipv4_routelist.o ip_plugin.c + cc -I. -I../../dnsinfo -I../../nwi -DTEST_IPV4_ROUTELIST -Wall -O0 -g -c -o test_ipv4_routelist.o ip_plugin.c -test_ipv4_routelist: test_ipv4_routelist.o dnsinfo_create.o dnsinfo_flatfile.o dnsinfo_private.o shared_dns_infoUser.o smb-configuration.o - cc -Wall -O0 -g -o test_ipv4_routelist test_ipv4_routelist.o dnsinfo_create.o dnsinfo_flatfile.o dnsinfo_private.o shared_dns_infoUser.o smb-configuration.o -framework SystemConfiguration -framework CoreFoundation +test_ipv4_routelist: test_ipv4_routelist.o dnsinfo_create.o dnsinfo_flatfile.o dnsinfo_private.o shared_dns_infoUser.o network_information_priv.o smb-configuration.o proxy-configuration.o + cc -Wall -O0 -g -o test_ipv4_routelist test_ipv4_routelist.o dnsinfo_create.o dnsinfo_flatfile.o dnsinfo_private.o network_information_priv.o shared_dns_infoUser.o smb-configuration.o proxy-configuration.o -framework SystemConfiguration -framework CoreFoundation test_ipv4_routelist_reference.txt: test_ipv4_routelist sh test_reference.sh create test_ipv4_routelist test_ipv4_routelist_reference.txt test_ipv4_routelist_filter.sh @@ -60,7 +63,7 @@ test_ipv4_routelist_test: test_ipv4_routelist # ---------- IPMonitor.o: ip_plugin.c - cc -I. -I../../dnsinfo -DTEST_IPMONITOR -Wall -O0 -g -c -o IPMonitor.o ip_plugin.c + cc -I. -I../../dnsinfo -I../../nwi -DTEST_IPMONITOR -Wall -O0 -g -c -o IPMonitor.o ip_plugin.c IPMonitor: IPMonitor.o dnsinfo_create.o dnsinfo_flatfile.o dnsinfo_private.o shared_dns_infoUser.o smb-configuration.o cc -Wall -O0 -g -o IPMonitor IPMonitor.o dnsinfo_create.o dnsinfo_flatfile.o dnsinfo_private.o shared_dns_infoUser.o smb-configuration.o -framework SystemConfiguration -framework CoreFoundation diff --git a/Plugins/IPMonitor/dns-configuration.c b/Plugins/IPMonitor/dns-configuration.c index f60b512..ca9e7ba 100644 --- a/Plugins/IPMonitor/dns-configuration.c +++ b/Plugins/IPMonitor/dns-configuration.c @@ -45,12 +45,15 @@ #include extern uint32_t notify_monitor_file(int token, const char *name, int flags); #endif // !TARGET_OS_IPHONE +#include #include #include #include #include +#include "dns-configuration.h" + #include #include @@ -68,6 +71,10 @@ extern uint32_t notify_monitor_file(int token, const char *name, int flags); #define kDNSServiceCompPrivateDNS "PrivateDNS" #endif +#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; @@ -79,6 +86,7 @@ static void add_resolver(CFMutableArrayRef resolvers, CFMutableDictionaryRef resolver) { CFIndex i; + CFStringRef interface; CFIndex n_resolvers; CFNumberRef order; uint32_t order_val = 0; @@ -129,10 +137,46 @@ add_resolver(CFMutableArrayRef resolvers, CFMutableDictionaryRef resolver) } } - 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) { + 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 = 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; } @@ -384,8 +428,8 @@ compareBySearchOrder(const void *val1, const void *val2, void *context) 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) && @@ -404,7 +448,7 @@ compareBySearchOrder(const void *val1, const void *val2, void *context) } -static CFArrayRef +static CF_RETURNS_RETAINED CFArrayRef extract_search_domains(CFMutableDictionaryRef defaultDomain, CFArrayRef supplemental) { CFStringRef defaultDomainName = NULL; @@ -663,7 +707,6 @@ add_scoped_resolvers(CFMutableArrayRef scoped, CFDictionaryRef services, CFArray for (i = 0; i < n_order; i++) { CFDictionaryRef dns; uint32_t flags; - unsigned int if_index; char if_name[IF_NAMESIZE]; CFStringRef interface; CFMutableDictionaryRef newDNS; @@ -700,7 +743,7 @@ add_scoped_resolvers(CFMutableArrayRef scoped, CFDictionaryRef services, CFArray if_name, sizeof(if_name), kCFStringEncodingASCII) == NULL) || - ((if_index = if_nametoindex(if_name)) == 0)) { + (if_nametoindex(if_name) == 0)) { // if interface index not available continue; } @@ -715,15 +758,15 @@ add_scoped_resolvers(CFMutableArrayRef scoped, CFDictionaryRef services, CFArray CFRelease(searchDomains); } - // set if_index - num = CFNumberCreate(NULL, kCFNumberIntType, &if_index); - CFDictionarySetValue(newDNS, CFSTR("*IF_INDEX*"), num); - CFRelease(num); - - // set "scoped" flag - flags = DNS_RESOLVER_FLAGS_SCOPED; + // set "scoped" configuration flag(s) + if (!CFDictionaryGetValueIfPresent(newDNS, DNS_CONFIGURATION_FLAGS_KEY, (const void **)&num) || + !isA_CFNumber(num) || + !CFNumberGetValue(num, kCFNumberSInt32Type, &flags)) { + flags = 0; + } + flags |= DNS_RESOLVER_FLAGS_SCOPED; num = CFNumberCreate(NULL, kCFNumberSInt32Type, &flags); - CFDictionarySetValue(newDNS, CFSTR("*FLAGS*"), num); + CFDictionarySetValue(newDNS, DNS_CONFIGURATION_FLAGS_KEY, num); CFRelease(num); // remove keys we don't want in a [scoped] resolver @@ -784,6 +827,23 @@ add_default_resolver(CFMutableArrayRef resolvers, } +/* + * rankReachability() + * Not reachable == 0 + * Connection Required == 1 + * Reachable == 2 + */ +static int +rankReachability(SCNetworkReachabilityFlags flags) +{ + int rank = 0; + + if (flags & kSCNetworkReachabilityFlagsReachable) rank = 2; + if (flags & kSCNetworkReachabilityFlagsConnectionRequired) rank = 1; + return rank; +} + + static dns_create_resolver_t create_resolver(CFDictionaryRef dns) { @@ -791,6 +851,9 @@ create_resolver(CFDictionaryRef dns) CFNumberRef num; dns_create_resolver_t _resolver; CFStringRef str; + CFMutableArrayRef serverAddresses = NULL; + CFStringRef targetInterface = NULL; + unsigned int targetInterfaceIndex = 0; _resolver = _dns_resolver_create(); @@ -823,19 +886,42 @@ create_resolver(CFDictionaryRef dns) } } + // 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 if_name[IFNAMSIZ]; + + _dns_resolver_set_if_index(&_resolver, if_index); + + if ((if_index != 0) && + (if_indextoname(if_index, if_name) != NULL)) { + targetInterface = CFStringCreateWithCString(NULL, + if_name, + kCFStringEncodingASCII); + targetInterfaceIndex = if_index; + } + } + } + // process nameserver addresses list = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses); if (isA_CFArray(list)) { CFIndex i; - CFIndex n = CFArrayGetCount(list); + CFIndex n = CFArrayGetCount(list); + + serverAddresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); 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]; + CFDataRef serverAddress; str = CFArrayGetValueAtIndex(list, i); if (!isA_CFString(str)) { @@ -846,27 +932,26 @@ create_resolver(CFDictionaryRef dns) 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) || + IN6_IS_ADDR_MC_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); + + serverAddress = CFDataCreate(NULL, (const void *)&addr.sa, addr.sa.sa_len); + CFArrayAppendValue(serverAddresses, serverAddress); + CFRelease(serverAddress); } } @@ -970,18 +1055,8 @@ create_resolver(CFDictionaryRef dns) } } - // process interface index - num = CFDictionaryGetValue(dns, CFSTR("*IF_INDEX*")); - if (isA_CFNumber(num)) { - int if_index; - - if (CFNumberGetValue(num, kCFNumberIntType, &if_index)) { - _dns_resolver_set_if_index(&_resolver, if_index); - } - } - // process flags - num = CFDictionaryGetValue(dns, CFSTR("*FLAGS*")); + num = CFDictionaryGetValue(dns, DNS_CONFIGURATION_FLAGS_KEY); if (isA_CFNumber(num)) { uint32_t flags; @@ -990,18 +1065,85 @@ create_resolver(CFDictionaryRef dns) } } + if (serverAddresses != NULL) { + SCNetworkReachabilityFlags flags = kSCNetworkReachabilityFlagsReachable; + CFIndex i; + CFIndex n = CFArrayGetCount(serverAddresses); + CFMutableDictionaryRef targetOptions; + + targetOptions = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (targetInterface != NULL) { + CFDictionarySetValue(targetOptions, + kSCNetworkReachabilityOptionInterface, + targetInterface); + } + + for (i = 0; i < n; i++) { + SCNetworkReachabilityFlags ns_flags; + Boolean ok; + CFDataRef serverAddress; + SCNetworkReachabilityRef target; + + serverAddress = CFArrayGetValueAtIndex(serverAddresses, i); + CFDictionarySetValue(targetOptions, + kSCNetworkReachabilityOptionRemoteAddress, + serverAddress); + target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions); + if (target == NULL) { + CFDictionaryRemoveValue(targetOptions, kSCNetworkReachabilityOptionInterface); + target = SCNetworkReachabilityCreateWithOptions(NULL, targetOptions); + if (target != NULL) { + // if interface name not (no longer) valid + CFRelease(target); + flags = 0; + break; + } + + // address not valid? + SCLog(TRUE, LOG_ERR, + CFSTR("create_resolver SCNetworkReachabilityCreateWithOptions() failed:\n options = %@"), + targetOptions); + break; + } + + ok = SCNetworkReachabilityGetFlags(target, &ns_flags); + CFRelease(target); + if (!ok) { + break; + } + + if ((i == 0) || + (rankReachability(ns_flags) < rankReachability(flags))) { + /* return the worst case result */ + flags = ns_flags; + } + } + + _dns_resolver_set_reach_flags(&_resolver, flags); + + CFRelease(targetOptions); + CFRelease(serverAddresses); + } + + 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)) { @@ -1039,8 +1181,8 @@ compareDomain(const void *val1, const void *val2, void *context) } // sort non-scoped before scoped - scoped1 = isScopedDNS(dns1); - scoped2 = isScopedDNS(dns2); + scoped1 = isScopedConfiguration(dns1); + scoped2 = isScopedConfiguration(dns2); if (scoped1 != scoped2) { if (!scoped1) { return kCFCompareLessThan; @@ -1103,19 +1245,23 @@ compareDomain(const void *val1, const void *val2, void *context) __private_extern__ -void +Boolean dns_configuration_set(CFDictionaryRef defaultResolver, CFDictionaryRef services, CFArrayRef serviceOrder, CFArrayRef multicastResolvers, CFArrayRef privateResolvers) { + dns_create_config_t _config; + Boolean changed = FALSE; CFIndex i; CFMutableDictionaryRef myDefault; Boolean myOrderAdded = FALSE; CFArrayRef mySearchDomains = NULL; CFIndex n_resolvers; CFMutableArrayRef resolvers; + unsigned char signature[CC_SHA1_DIGEST_LENGTH]; + static unsigned char signature_last[CC_SHA1_DIGEST_LENGTH]; // establish list of resolvers @@ -1178,9 +1324,9 @@ dns_configuration_set(CFDictionaryRef defaultResolver, 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); } } @@ -1193,12 +1339,8 @@ dns_configuration_set(CFDictionaryRef defaultResolver, /* * 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")); - } + _config = NULL; } else { - dns_create_config_t _config; - /* * if default and/or supplemental/scoped resolvers are defined */ @@ -1221,18 +1363,23 @@ dns_configuration_set(CFDictionaryRef defaultResolver, _dnsinfo_flatfile_add_resolvers(&_config); #endif // !TARGET_OS_IPHONE + } - // save configuration - - if (!_dns_configuration_store(&_config)) { - SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration")); - } + // check if the configuration changed + _dns_configuration_signature(&_config, signature, sizeof(signature)); + if (bcmp(signature, signature_last, sizeof(signature)) != 0) { + changed = TRUE; + } + bcopy(signature, signature_last, sizeof(signature)); - _dns_configuration_free(&_config); + // save configuration + if (!_dns_configuration_store(&_config)) { + SCLog(TRUE, LOG_ERR, CFSTR("dns_configuration_set: could not store configuration")); } + if (_config != NULL) _dns_configuration_free(&_config); CFRelease(resolvers); - return; + return changed; } @@ -1334,6 +1481,10 @@ dns_configuration_init(CFBundleRef bundle) } +#pragma mark - +#pragma mark Standalone test code + + #ifdef MAIN static void @@ -1510,11 +1661,11 @@ main(int argc, char **argv) // 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); // cleanup if (setup_global_ipv4 != NULL) CFRelease(setup_global_ipv4); diff --git a/Plugins/IPMonitor/dns-configuration.h b/Plugins/IPMonitor/dns-configuration.h index 51062b0..08dc9e1 100644 --- a/Plugins/IPMonitor/dns-configuration.h +++ b/Plugins/IPMonitor/dns-configuration.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (c) 2006, 2008, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,17 +28,24 @@ #include #include + +#define DNS_CONFIGURATION_SCOPED_QUERY_KEY CFSTR("__SCOPED_QUERY__") + + __BEGIN_DECLS +__private_extern__ void dns_configuration_init (CFBundleRef bundle); #if !TARGET_OS_IPHONE +__private_extern__ void dns_configuration_monitor (SCDynamicStoreRef store, SCDynamicStoreCallBack callout); #endif // !TARGET_OS_IPHONE -void dns_configuration_set (CFDictionaryRef defaultResolver, +__private_extern__ +Boolean dns_configuration_set (CFDictionaryRef defaultResolver, CFDictionaryRef services, CFArrayRef serviceOrder, CFArrayRef multicastResolvers, diff --git a/Plugins/IPMonitor/ip_plugin.c b/Plugins/IPMonitor/ip_plugin.c index 82cd44b..cb683f4 100644 --- a/Plugins/IPMonitor/ip_plugin.c +++ b/Plugins/IPMonitor/ip_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Apple Inc. All Rights Reserved. + * Copyright (c) 2000-2012 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -87,6 +87,7 @@ #include #include #include +#include #include #include @@ -104,6 +105,8 @@ #ifndef kDNSServiceCompPrivateDNS #define kDNSServiceCompPrivateDNS "PrivateDNS" #endif +#include +#include "network_information_priv.h" enum { kProtocolFlagsNone = 0x0, @@ -117,7 +120,7 @@ enum { kDebugFlag2 = 0x00000002, kDebugFlag4 = 0x00000004, kDebugFlag8 = 0x00000008, - kDebugFlagDefault = kDebugFlag1, + kDebugFlagDefault = kDebugFlag1, kDebugFlagAll = 0xffffffff }; @@ -140,13 +143,6 @@ enum { #define IP_CH(ip) ((u_char *)(ip)) #define IP_LIST(ip) IP_CH(ip)[0],IP_CH(ip)[1],IP_CH(ip)[2],IP_CH(ip)[3] -typedef uint32_t Rank; - -enum { - kRankFirst = 0, - kRankLast = UINT_MAX -}; - /* * IPv4 Route management */ @@ -154,13 +150,9 @@ enum { typedef uint32_t RouteFlags; enum { - kRouteIsDirectToInterfaceFlag = 0x00000001, - kRouteIsNotSubnetLocalFlag = 0x00000002, - kRouteChooseFirstFlag = 0x00000004, - kRouteChooseLastFlag = 0x00000008, - kRouteChooseNeverFlag = 0x00000010, - kRouteIsScopedFlag = 0x00000020, - kRouteWantScopedFlag = (kRouteChooseNeverFlag|kRouteIsScopedFlag), + kRouteIsDirectToInterfaceFlag = 0x00000001, + kRouteIsNotSubnetLocalFlag = 0x00000002, + kRouteIsScopedFlag = 0x00000004, }; typedef struct { @@ -185,6 +177,59 @@ enum { kIPv4RouteListRemoveRouteCommand }; +typedef struct { + char ifname[IFNAMSIZ]; + uint32_t flags; + Rank rank; + struct in6_addr iaddr6; +} IPv6RankedE, *IPv6RankedERef; + +typedef struct { + int count; + int size; + IPv6RankedE elem[1]; +} IPv6RankedList, *IPv6RankedListRef; + +/* + * Type: Rank + * Purpose: + * A 32-bit value to encode the relative rank of a service. + * + * The top 8 bits are used to hold the rank assertion (first, last, never, default), + * the bottom 24 bits are used to store the service index i.e. the position within + * the service order array. + */ +#define RANK_ASSERTION_MAKE(r) ((Rank)(r) << 24) +#define kRankAssertionFirst RANK_ASSERTION_MAKE(0) +#define kRankAssertionDefault RANK_ASSERTION_MAKE(1) +#define kRankAssertionLast RANK_ASSERTION_MAKE(2) +#define kRankAssertionNever RANK_ASSERTION_MAKE(3) +#define kRankAssertionMask RANK_ASSERTION_MAKE(0xff) +#define RANK_ASSERTION_MASK(r) ((Rank)(r) & kRankAssertionMask) + +#define RANK_INDEX_MAKE(r) ((Rank)(r)) +#define kRankIndexMask RANK_INDEX_MAKE(0xffffff) +#define RANK_INDEX_MASK(r) ((Rank)(r) & kRankIndexMask) + +static __inline__ Rank +RankMake(uint32_t service_index, Rank primary_rank) +{ + return (RANK_INDEX_MASK(service_index) | RANK_ASSERTION_MASK(primary_rank)); +} + +static __inline__ Rank +PrimaryRankGetRankAssertion(CFStringRef primaryRank) +{ + if (CFEqual(primaryRank, kSCValNetServicePrimaryRankNever)) { + return kRankAssertionNever; + } else if (CFEqual(primaryRank, kSCValNetServicePrimaryRankFirst)) { + return kRankAssertionFirst; + } else if (CFEqual(primaryRank, kSCValNetServicePrimaryRankLast)) { + return kRankAssertionLast; + } + return kRankAssertionDefault; +} + typedef uint32_t IPv4RouteListApplyCommand; typedef void IPv4RouteListApplyCallBackFunc(IPv4RouteListApplyCommand cmd, @@ -211,6 +256,9 @@ static CFMutableDictionaryRef S_service_state_dict = NULL; static CFMutableDictionaryRef S_ipv4_service_rank_dict = NULL; static CFMutableDictionaryRef S_ipv6_service_rank_dict = NULL; +/* dictionary to hold per-interface rank information */ +static CFMutableDictionaryRef S_if_rank_dict = NULL; + /* if set, a PPP interface overrides the primary */ static boolean_t S_ppp_override_primary = FALSE; @@ -238,6 +286,8 @@ static const struct in6_addr S_ip6_zeros = IN6ADDR_ANY_INIT; static boolean_t S_append_state = FALSE; +static nwi_state_t S_nwi_state = NULL; + #if !TARGET_OS_IPHONE static CFStringRef S_primary_smb = NULL; static CFStringRef S_state_global_smb = NULL; @@ -249,7 +299,7 @@ static CFStringRef S_state_global_smb = NULL; #ifndef KERN_NETBOOT #define KERN_NETBOOT 40 /* int: are we netbooted? 1=yes,0=no */ -#endif KERN_NETBOOT +#endif //KERN_NETBOOT /** ** entityType*, GetEntityChanges* @@ -278,6 +328,51 @@ static const CFStringRef *entityTypeNames[ENTITY_TYPES_COUNT] = { #endif /* !TARGET_OS_IPHONE */ }; +#ifndef kSCEntNetIPv4RouteList +#define kSCEntNetIPv4RouteList CFSTR("IPv4RouteList") +#endif + +#ifndef kSCEntNetIPv4ServiceDict +#define kSCEntNetIPv4ServiceDict CFSTR("IPv4ServiceDict") +#endif + +static IPv4RouteListRef +ipv4_dict_get_routelist(CFDictionaryRef ipv4_dict) +{ + CFDataRef routes; + IPv4RouteListRef routes_list = NULL; + + if (isA_CFDictionary(ipv4_dict) == NULL) { + return (NULL); + } + + routes = CFDictionaryGetValue(ipv4_dict, kSCEntNetIPv4RouteList); + + if (routes != NULL) { + routes_list = (IPv4RouteListRef)(void*)CFDataGetBytePtr(routes); + } + return (routes_list); +} + +static CFStringRef +ipv4_dict_get_ifname(CFDictionaryRef ipv4_dict) +{ + CFDictionaryRef ipv4_service_dict = NULL; + + if (isA_CFDictionary(ipv4_dict) == NULL) { + return (NULL); + } + + ipv4_service_dict = CFDictionaryGetValue(ipv4_dict, + kSCEntNetIPv4ServiceDict); + + if (isA_CFDictionary(ipv4_service_dict) == NULL) { + return NULL; + } + + return CFDictionaryGetValue(ipv4_service_dict, kSCPropInterfaceName); +} + typedef boolean_t GetEntityChangesFunc(CFStringRef serviceID, CFDictionaryRef state_dict, CFDictionaryRef setup_dict, @@ -322,6 +417,27 @@ typedef struct { CFMutableDictionaryRef set; } keyChangeList, * keyChangeListRef; +static CFStringRef +my_CFStringCopyComponent(CFStringRef path, CFStringRef separator, + CFIndex component_index) +{ + CFArrayRef arr; + CFStringRef component = NULL; + + arr = CFStringCreateArrayBySeparatingStrings(NULL, path, separator); + if (arr == NULL) { + goto done; + } + if (CFArrayGetCount(arr) <= component_index) { + goto done; + } + component = CFRetain(CFArrayGetValueAtIndex(arr, component_index)); + + done: + my_CFRelease(&arr); + return (component); +} + static void keyChangeListInit(keyChangeListRef keys) { @@ -366,7 +482,8 @@ keyChangeListSetValue(keyChangeListRef keys, CFStringRef key, CFTypeRef value) } static void -keyChangeListApplyToStore(keyChangeListRef keys, SCDynamicStoreRef session) +keyChangeListApplyToStore(keyChangeListRef keys, SCDynamicStoreRef session, + CFStringRef network_change_msg) { CFArrayRef notify = keys->notify; CFArrayRef remove = keys->remove; @@ -403,7 +520,11 @@ keyChangeListApplyToStore(keyChangeListRef keys, SCDynamicStoreRef session) status = notify_post("com.apple.system.config.network_change"); if (status == NOTIFY_STATUS_OK) { - SCLog(TRUE, LOG_NOTICE, CFSTR("network configuration changed.")); + if (CFStringGetLength(network_change_msg) != 0) { + SCLog(TRUE, LOG_NOTICE, CFSTR("network changed:%@"), network_change_msg); + } else { + SCLog(TRUE, LOG_NOTICE, CFSTR("network changed.")); + } } else { SCLog(TRUE, LOG_NOTICE, CFSTR("IPMonitor: notify_post() failed: error=%ld"), status); @@ -597,7 +718,7 @@ cfstring_to_ip6(CFStringRef str, struct in6_addr * ip6_p) return (cfstring_to_ipvx(AF_INET6, str, ip6_p, sizeof(*ip6_p))); } -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef setup_service_key(CFStringRef serviceID, CFStringRef entity) { return (SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, @@ -606,7 +727,7 @@ setup_service_key(CFStringRef serviceID, CFStringRef entity) entity)); } -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef state_service_key(CFStringRef serviceID, CFStringRef entity) { return (SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, @@ -616,27 +737,27 @@ state_service_key(CFStringRef serviceID, CFStringRef entity) } static CFDictionaryRef -get_service_setup_entity(CFDictionaryRef service_info, CFStringRef serviceID, +get_service_setup_entity(CFDictionaryRef services_info, CFStringRef serviceID, CFStringRef entity) { CFStringRef setup_key; CFDictionaryRef setup_dict; setup_key = setup_service_key(serviceID, entity); - setup_dict = my_CFDictionaryGetDictionary(service_info, setup_key); + setup_dict = my_CFDictionaryGetDictionary(services_info, setup_key); my_CFRelease(&setup_key); return (setup_dict); } static CFDictionaryRef -get_service_state_entity(CFDictionaryRef service_info, CFStringRef serviceID, +get_service_state_entity(CFDictionaryRef services_info, CFStringRef serviceID, CFStringRef entity) { CFStringRef state_key; CFDictionaryRef state_dict; state_key = state_service_key(serviceID, entity); - state_dict = my_CFDictionaryGetDictionary(service_info, state_key); + state_dict = my_CFDictionaryGetDictionary(services_info, state_key); my_CFRelease(&state_key); return (state_dict); } @@ -690,35 +811,12 @@ subnet_addr(struct in_addr addr, struct in_addr mask) return (net); } -static __inline__ int -uint32_cmp(uint32_t a, uint32_t b) -{ - int ret; - - if (a == b) { - ret = 0; - } - else if (a < b) { - ret = -1; - } - else { - ret = 1; - } - return (ret); -} - static __inline__ int in_addr_cmp(struct in_addr a, struct in_addr b) { return (uint32_cmp(ntohl(a.s_addr), ntohl(b.s_addr))); } -static __inline__ int -RankCompare(Rank a, Rank b) -{ - return (uint32_cmp(a, b)); -} - static __inline__ int RouteFlagsCompare(RouteFlags a, RouteFlags b) { @@ -728,6 +826,8 @@ RouteFlagsCompare(RouteFlags a, RouteFlags b) static void IPv4RouteCopyDescriptionWithString(IPv4RouteRef r, CFMutableStringRef str) { + Rank rank_assertion = RANK_ASSERTION_MASK(r->rank); + CFStringAppendFormat(str, NULL, CFSTR("Dest " IP_FORMAT " Mask " IP_FORMAT @@ -744,21 +844,24 @@ IPv4RouteCopyDescriptionWithString(IPv4RouteRef r, CFMutableStringRef str) else if ((r->flags & kRouteIsDirectToInterfaceFlag) != 0) { CFStringAppend(str, CFSTR(" [direct]")); } - if ((r->flags & kRouteChooseFirstFlag) != 0) { - CFStringAppend(str, CFSTR(" [first]")); - } - if ((r->flags & kRouteChooseLastFlag) != 0) { - CFStringAppend(str, CFSTR(" [last]")); - } - if ((r->flags & kRouteChooseNeverFlag) != 0) { - CFStringAppend(str, CFSTR(" [never]")); + + switch(rank_assertion) { + case kRankAssertionFirst: + CFStringAppend(str, CFSTR(" [first]")); + break; + case kRankAssertionLast: + CFStringAppend(str, CFSTR(" [last]")); + break; + case kRankAssertionNever: + CFStringAppend(str, CFSTR(" [never]")); + break; + default: + break; } + if ((r->flags & kRouteIsScopedFlag) != 0) { CFStringAppend(str, CFSTR(" [SCOPED]")); } - else if ((r->flags & kRouteWantScopedFlag) != 0) { - CFStringAppend(str, CFSTR(" [SCOPED*]")); - } return; } @@ -777,7 +880,7 @@ IPv4RoutePrint(IPv4RouteRef route) { CFStringRef str = IPv4RouteCopyDescription(route); - SCPrint(TRUE, stdout, CFSTR("%@"), str); + SCPrint(TRUE, stdout, CFSTR("%@\n"), str); CFRelease(str); return; } @@ -809,49 +912,10 @@ IPv4RouteCompare(IPv4RouteRef a, Rank a_rank, cmp = 0; } else { - boolean_t a_never = (a->flags & kRouteChooseNeverFlag) != 0; - boolean_t b_never = (b->flags & kRouteChooseNeverFlag) != 0; *same_dest = TRUE; - - if (a_never != b_never) { - if (a_never) { - cmp = 1; - } - else { - cmp = -1; - } - } - else { - boolean_t a_last = (a->flags & kRouteChooseLastFlag) != 0; - boolean_t b_last = (b->flags & kRouteChooseLastFlag) != 0; - - if (a_last != b_last) { - if (a_last) { - cmp = 1; - } - else { - cmp = -1; - } - } - else { - boolean_t a_first = (a->flags & kRouteChooseFirstFlag) != 0; - boolean_t b_first = (b->flags & kRouteChooseFirstFlag) != 0; - - if (a_first != b_first) { - if (a_first) { - cmp = -1; - } - else { - cmp = 1; - } - } - else { - cmp = RankCompare(a_rank, b_rank); - if (cmp == 0) { - cmp = name_cmp; - } - } - } + cmp = RankCompare(a_rank, b_rank); + if (cmp == 0) { + cmp = name_cmp; } } } @@ -880,7 +944,7 @@ IPv4RouteCompare(IPv4RouteRef a, Rank a_rank, return (cmp); } -static CFStringRef +static CFMutableStringRef IPv4RouteListCopyDescription(IPv4RouteListRef routes) { int i; @@ -894,7 +958,7 @@ IPv4RouteListCopyDescription(IPv4RouteListRef routes) CFStringAppendFormat(str, NULL, CFSTR("\n%2d. "), i); IPv4RouteCopyDescriptionWithString(r, str); } - CFStringAppend(str, CFSTR("\n}\n")); + CFStringAppend(str, CFSTR("\n}")); return (str); } @@ -903,7 +967,7 @@ IPv4RouteListPrint(IPv4RouteListRef routes) { CFStringRef str = IPv4RouteListCopyDescription(routes); - SCPrint(TRUE, stdout, CFSTR("%@"), str); + SCPrint(TRUE, stdout, CFSTR("%@\n"), str); CFRelease(str); return; } @@ -936,26 +1000,10 @@ IPv4RouteListFindRoute(IPv4RouteListRef routes, IPv4RouteRef route) && (scan->mask.s_addr == route->mask.s_addr) && (strcmp(scan->ifname, route->ifname) == 0) && (scan->ifa.s_addr == route->ifa.s_addr) - && (scan->gateway.s_addr == route->gateway.s_addr)) { - /* - * So far, the routes look the same. If the flags - * are also equiv than we've found a match. - */ - RouteFlags r_flags; - RouteFlags s_flags; - - s_flags = scan->flags; - if ((s_flags & kRouteWantScopedFlag) != 0) { - s_flags |= kRouteWantScopedFlag; - } - r_flags = route->flags; - if ((r_flags & kRouteWantScopedFlag) != 0) { - r_flags |= kRouteWantScopedFlag; - } - if (s_flags == r_flags) { + && (scan->gateway.s_addr == route->gateway.s_addr) + && (scan->flags == route->flags)) { scan_result = scan; break; - } } } return (scan_result); @@ -1025,7 +1073,7 @@ IPv4RouteListApply(IPv4RouteListRef old_routes, IPv4RouteListRef new_routes, enum { kScopeNone = 0, kScopeThis = 1, - kScopeNext = 2 + kScopeNext = 2 }; static IPv4RouteListRef @@ -1033,6 +1081,7 @@ IPv4RouteListAddRoute(IPv4RouteListRef routes, int init_size, IPv4RouteRef this_route, Rank this_rank) { int i; + IPv4RouteRef first_scan = NULL; int scope_which = kScopeNone; IPv4RouteRef scan; int where = -1; @@ -1048,9 +1097,15 @@ IPv4RouteListAddRoute(IPv4RouteListRef routes, int init_size, boolean_t same_dest; cmp = IPv4RouteCompare(this_route, this_rank, scan, scan->rank, &same_dest); + + if (same_dest == TRUE && first_scan == NULL) { + first_scan = scan; + } + if (cmp < 0) { if (where == -1) { - if (same_dest == TRUE) { + if (same_dest == TRUE + && (first_scan->flags & kRouteIsScopedFlag) == 0) { if ((scan->flags & kRouteIsScopedFlag) != 0) { ROUTELIST_DEBUG(("Hit 1: set scope on self\n"), kDebugFlag8); @@ -1184,7 +1239,7 @@ static IPv4RouteListRef IPv4RouteListAddRouteList(IPv4RouteListRef routes, int init_size, IPv4RouteListRef service_routes, Rank rank) { - int i; + int i; IPv4RouteRef scan; for (i = 0, scan = service_routes->list; @@ -1239,6 +1294,7 @@ IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes, IPv4RouteRef r; struct in_addr subnet = { 0 }; struct in_addr router = { 0 }; + Rank rank = kRankAssertionDefault; if (dict == NULL) { return (NULL); @@ -1275,7 +1331,8 @@ IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes, return (NULL); } if (router.s_addr == 0) { - flags |= kRouteIsDirectToInterfaceFlag | kRouteChooseLastFlag; + flags |= kRouteIsDirectToInterfaceFlag; + rank = kRankAssertionLast; } else { /* @@ -1287,17 +1344,16 @@ IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes, flags |= kRouteIsDirectToInterfaceFlag; } if (primaryRank != NULL) { - if (CFEqual(primaryRank, kSCValNetServicePrimaryRankNever)) { - flags |= kRouteChooseNeverFlag; - } else if (CFEqual(primaryRank, kSCValNetServicePrimaryRankFirst)) { - flags |= kRouteChooseFirstFlag; - } else if (CFEqual(primaryRank, kSCValNetServicePrimaryRankLast)) { - flags |= kRouteChooseLastFlag; - } + rank = PrimaryRankGetRankAssertion(primaryRank); } else if (get_override_primary(dict)) { - flags |= kRouteChooseFirstFlag; + rank = kRankAssertionFirst; } } + + if (rank == kRankAssertionNever) { + flags |= kRouteIsScopedFlag; + } + if (add_subnet && (flags & kRouteIsDirectToInterfaceFlag) == 0 && subnet.s_addr != subnet_addr(router, mask).s_addr) { flags |= kRouteIsNotSubnetLocalFlag; @@ -1330,6 +1386,10 @@ IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes, else { r->gateway = addr; } + r->rank = rank; + if (r->rank == kRankAssertionNever) { + r->flags |= kRouteIsScopedFlag; + } r++; } @@ -1341,7 +1401,10 @@ IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes, r->mask = mask; strlcpy(r->ifname, ifn, sizeof(r->ifname)); r->ifa = addr; - r->flags = flags & (kRouteChooseFirstFlag|kRouteChooseLastFlag|kRouteChooseNeverFlag); + r->rank = rank; + if (r->rank == kRankAssertionNever) { + r->flags |= kRouteIsScopedFlag; + } } return (routes); @@ -1360,7 +1423,7 @@ IPv4RouteListCreateWithDictionary(IPv4RouteListRef routes, * 2. key = "a/b/c" prefix = "a/b/" * returns "c" */ -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef parse_component(CFStringRef key, CFStringRef prefix) { CFMutableStringRef comp; @@ -1407,14 +1470,29 @@ static void dump_service_entity(CFStringRef serviceID, CFStringRef entity, CFStringRef operation, CFTypeRef val) { - CFStringRef this_val = NULL; - if (isA_CFData(val) && CFEqual(entity, kSCEntNetIPv4)) { - this_val = IPv4RouteListCopyDescription((IPv4RouteListRef) - CFDataGetBytePtr(val)); - if (this_val != NULL) { - val = this_val; + CFDataRef route_list; + CFMutableStringRef this_val = NULL; + + if (CFEqual(entity, kSCEntNetIPv4) && isA_CFDictionary(val) != NULL) { + CFDictionaryRef service_dict = NULL; + + route_list = CFDictionaryGetValue(val, kSCEntNetIPv4RouteList); + if (route_list != NULL) { + /* ALIGN: CF should align to at least 8-byte boundaries */ + this_val = IPv4RouteListCopyDescription((IPv4RouteListRef) + (void *)CFDataGetBytePtr(route_list)); + } + + service_dict = CFDictionaryGetValue(val, kSCEntNetIPv4ServiceDict); + + if (service_dict != NULL && isA_CFDictionary(service_dict) != NULL) { + if (this_val == NULL) { + this_val = CFStringCreateMutable(NULL, 0); + } + CFStringAppendFormat(this_val, NULL, CFSTR("\n : %@"), service_dict); } + val = this_val; } if (val == NULL) { val = CFSTR(""); @@ -1479,6 +1557,42 @@ service_dict_get(CFStringRef serviceID, CFStringRef entity) return (CFDictionaryGetValue(service_dict, entity)); } +#ifndef kSCPropNetHostname +#define kSCPropNetHostname CFSTR("Hostname") +#endif + +__private_extern__ +CFStringRef +copy_dhcp_hostname(CFStringRef serviceID) +{ + CFDictionaryRef dict = NULL; + CFStringRef hostname = NULL; + CFDictionaryRef service_dict = NULL; + + dict = service_dict_get(serviceID, kSCEntNetIPv4); + + if (dict == NULL || isA_CFDictionary(dict) == NULL) { + return (NULL); + } + + service_dict = + CFDictionaryGetValue(dict, kSCEntNetIPv4ServiceDict); + + if (service_dict == NULL + || isA_CFDictionary(service_dict) == NULL) { + return (NULL); + } + + hostname = + CFDictionaryGetValue(service_dict, kSCPropNetHostname); + + if (hostname != NULL) { + CFRetain(hostname); + } + + return (hostname); +} + static boolean_t ipv6_service_dict_set(CFStringRef serviceID, CFDictionaryRef new_val) { @@ -1486,7 +1600,7 @@ ipv6_service_dict_set(CFStringRef serviceID, CFDictionaryRef new_val) int if_index; char ifn[IFNAMSIZ]; CFStringRef new_router = NULL; - char ntopbuf[INET6_ADDRSTRLEN]; + char ntopbuf[INET6_ADDRSTRLEN]; CFDictionaryRef old_val = NULL; CFStringRef old_router = NULL; struct in6_addr router_ip; @@ -1524,7 +1638,8 @@ ipv6_service_dict_set(CFStringRef serviceID, CFDictionaryRef new_val) && (new_router == NULL || CFEqual(old_router, new_router) == FALSE)) { /* remove the old Router */ if (cfstring_to_ip6(old_router, &router_ip)) { - if (IN6_IS_ADDR_LINKLOCAL(&router_ip)) { + if (IN6_IS_ADDR_LINKLOCAL(&router_ip) || + IN6_IS_ADDR_MC_LINKLOCAL(&router_ip)) { /* scope it */ router_ip.__u6_addr.__u6_addr16[1] = htons(if_index); } @@ -1549,7 +1664,8 @@ ipv6_service_dict_set(CFStringRef serviceID, CFDictionaryRef new_val) } /* add the new Router */ if (cfstring_to_ip6(new_router, &router_ip)) { - if (IN6_IS_ADDR_LINKLOCAL(&router_ip)) { + if (IN6_IS_ADDR_LINKLOCAL(&router_ip) || + IN6_IS_ADDR_MC_LINKLOCAL(&router_ip)) { /* scope it */ router_ip.__u6_addr.__u6_addr16[1] = htons(if_index); } @@ -1580,7 +1696,7 @@ ipv6_service_dict_set(CFStringRef serviceID, CFDictionaryRef new_val) #define ALLOW_EMPTY_STRING 0x1 -static CFTypeRef +static CF_RETURNS_RETAINED CFTypeRef sanitize_prop(CFTypeRef val, uint32_t flags) { if (val != NULL) { @@ -1701,13 +1817,15 @@ static boolean_t get_ipv4_changes(CFStringRef serviceID, CFDictionaryRef state_dict, CFDictionaryRef setup_dict, CFDictionaryRef info) { + CFDictionaryRef aggregated_dict = NULL; boolean_t changed = FALSE; CFMutableDictionaryRef dict = NULL; CFStringRef primaryRank = NULL; IPv4RouteListRef r; #define R_STATIC 3 IPv4RouteListRef routes; - char routes_buf[IPv4RouteListComputeSize(R_STATIC)]; + /* ALIGN: force align */ + uint32_t routes_buf[roundup(IPv4RouteListComputeSize(R_STATIC), sizeof(uint32_t))]; CFDataRef routes_data = NULL; CFDictionaryRef service_options; @@ -1732,7 +1850,7 @@ get_ipv4_changes(CFStringRef serviceID, CFDictionaryRef state_dict, router); } } - routes = (IPv4RouteListRef)routes_buf; + routes = (IPv4RouteListRef)(void *)routes_buf; routes->size = R_STATIC; routes->count = 0; r = IPv4RouteListCreateWithDictionary(routes, dict, primaryRank); @@ -1751,12 +1869,30 @@ get_ipv4_changes(CFStringRef serviceID, CFDictionaryRef state_dict, dict); } done: - changed = service_dict_set(serviceID, kSCEntNetIPv4, routes_data); + if (routes_data != NULL) { + CFStringRef keys[2]; + CFTypeRef values[2]; + + keys[0] = kSCEntNetIPv4ServiceDict; + values[0] = dict; + keys[1] = kSCEntNetIPv4RouteList; + values[1] = routes_data; + + aggregated_dict = CFDictionaryCreate(NULL, + (const void**)keys, + values, + sizeof(keys)/sizeof(keys[0]), + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + } + changed = service_dict_set(serviceID, kSCEntNetIPv4, aggregated_dict); if (routes_data == NULL) { /* clean up the rank too */ CFDictionaryRemoveValue(S_ipv4_service_rank_dict, serviceID); } my_CFRelease(&dict); + my_CFRelease(&aggregated_dict); my_CFRelease(&routes_data); return (changed); } @@ -1822,7 +1958,7 @@ get_ipv6_changes(CFStringRef serviceID, CFDictionaryRef state_dict, static void accumulate_dns_servers(CFArrayRef in_servers, ProtocolFlags active_protos, - CFMutableArrayRef out_servers) + CFMutableArrayRef out_servers, CFStringRef interface) { int count; int i; @@ -1845,13 +1981,15 @@ accumulate_dns_servers(CFArrayRef in_servers, ProtocolFlags active_protos, } continue; } + + CFRetain(addr); } else if (cfstring_to_ip6(addr, &ipv6_addr)) { /* IPv6 address */ if ((active_protos & kProtocolFlagsIPv6) == 0 && !IN6_IS_ADDR_LOOPBACK(&ipv6_addr)) { if ((S_IPMonitor_debug & kDebugFlag1) != 0) { - char ntopbuf[INET6_ADDRSTRLEN]; + char ntopbuf[INET6_ADDRSTRLEN]; syslog(LOG_NOTICE, "IPMonitor: no IPv6 connectivity, " @@ -1861,6 +1999,19 @@ accumulate_dns_servers(CFArrayRef in_servers, ProtocolFlags active_protos, } continue; } + + if ((IN6_IS_ADDR_LINKLOCAL(&ipv6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&ipv6_addr)) + && (interface != NULL) + && (CFStringFind(addr, CFSTR("%"), 0).location == kCFNotFound)) { + // append interface name to IPv6 link local address + addr = CFStringCreateWithFormat(NULL, NULL, + CFSTR("%@%%%@"), + addr, + interface); + } else { + CFRetain(addr); + } } else { /* bad IP address */ @@ -1869,8 +2020,10 @@ accumulate_dns_servers(CFArrayRef in_servers, ProtocolFlags active_protos, addr); continue; } + /* DNS server is valid and one we want */ CFArrayAppendValue(out_servers, addr); + CFRelease(addr); } return; } @@ -1879,9 +2032,12 @@ static void merge_dns_servers(CFMutableDictionaryRef new_dict, CFArrayRef state_servers, CFArrayRef setup_servers, - ProtocolFlags active_protos) + Boolean have_setup, + ProtocolFlags active_protos, + CFStringRef interface) { CFMutableArrayRef dns_servers; + Boolean have_dns_setup = FALSE; if (state_servers == NULL && setup_servers == NULL) { /* no DNS servers */ @@ -1891,17 +2047,52 @@ merge_dns_servers(CFMutableDictionaryRef new_dict, &kCFTypeArrayCallBacks); if (setup_servers != NULL) { accumulate_dns_servers(setup_servers, active_protos, - dns_servers); + dns_servers, interface); + if (CFArrayGetCount(dns_servers) > 0) { + have_dns_setup = TRUE; + } } if ((CFArrayGetCount(dns_servers) == 0 || S_append_state) && state_servers != NULL) { accumulate_dns_servers(state_servers, active_protos, - dns_servers); + dns_servers, NULL); } + + /* + * Here, we determine whether or not we want all queries for this DNS + * configuration to be bound to the associated network interface. + * + * For dynamically derived network configurations (i.e. from State:) + * this would be the preferred option using the argument "Hey, the + * server told us to use these servers on this network so let's not + * argue". + * + * But, when a DNS configuration has been provided by the user/admin + * via the Network pref pane (i.e. from Setup:) we opt to not force + * binding of the outbound queries. The simplest example why we take + * this stance is with a multi-homing configuration. Consider a system + * with one network service associated with "en0" and a second service + * associated with "en1". The "en0" service has been set higher in + * the network service order so it would be primary but the user/admin + * wants the DNS queries to go to a server only accessible via "en1". + * Without this exception we would take the DNS server addresses from + * the Network pref pane (for "en0") and have the queries bound to + * "en0" where they'd never reach their intended destination (via + * "en1"). So, our exception to the rule is that we will not bind + * user/admin configurations to any specific network interface. + * + * We also add an exception to the "follow the dynamically derived + * network configuration" path for on-the-fly (no Setup: content) + * network services. + */ if (CFArrayGetCount(dns_servers) != 0) { CFDictionarySetValue(new_dict, kSCPropNetDNSServerAddresses, dns_servers); + if (have_setup && !have_dns_setup) { + CFDictionarySetValue(new_dict, DNS_CONFIGURATION_SCOPED_QUERY_KEY, kCFBooleanTrue); + } } + my_CFRelease(&dns_servers); return; } @@ -1914,11 +2105,12 @@ get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict, ProtocolFlags active_protos = kProtocolFlagsNone; boolean_t changed = FALSE; CFStringRef domain; + Boolean have_setup = FALSE; CFStringRef interface = NULL; - CFDataRef ipv4; + CFDictionaryRef ipv4; CFDictionaryRef ipv6; int i; - struct { + const struct { CFStringRef key; uint32_t flags; Boolean append; @@ -1929,45 +2121,49 @@ get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict, { kSCPropNetDNSSupplementalMatchOrders, 0, TRUE }, }; CFMutableDictionaryRef new_dict = NULL; - CFStringRef pick_list[] = { + const CFStringRef pick_list[] = { kSCPropNetDNSDomainName, kSCPropNetDNSOptions, kSCPropNetDNSSearchOrder, kSCPropNetDNSServerPort, kSCPropNetDNSServerTimeout, }; + IPv4RouteListRef routes = NULL; if ((state_dict == NULL) && (setup_dict == NULL)) { /* there is no DNS content */ goto done; } - ipv4 = (CFDataRef)service_dict_get(serviceID, kSCEntNetIPv4); - if (ipv4 != NULL) { - IPv4RouteListRef routes; + ipv4 = service_dict_get(serviceID, kSCEntNetIPv4); + routes = ipv4_dict_get_routelist(ipv4); + + if (routes != NULL) { + if (get_service_setup_entity(info, serviceID, kSCEntNetIPv4) != NULL) { + have_setup = TRUE; + } active_protos |= kProtocolFlagsIPv4; - routes = (IPv4RouteListRef)CFDataGetBytePtr(ipv4); - if (routes->count > 0) { - interface = CFStringCreateWithCString(NULL, - routes->list[0].ifname, - kCFStringEncodingASCII); - } + interface = ipv4_dict_get_ifname(ipv4); } ipv6 = service_dict_get(serviceID, kSCEntNetIPv6); if (ipv6 != NULL) { + if (!have_setup && + get_service_setup_entity(info, serviceID, kSCEntNetIPv6) != NULL) { + have_setup = TRUE; + } + active_protos |= kProtocolFlagsIPv6; - if ((interface == NULL) && - CFDictionaryGetValueIfPresent(ipv6, - kSCPropInterfaceName, - (const void **)&interface)) { - CFRetain(interface); + if (interface == NULL) { + interface = CFDictionaryGetValue(ipv6, + kSCPropInterfaceName); } } + if (active_protos == kProtocolFlagsNone) { /* there is no IPv4 nor IPv6 */ if (state_dict == NULL) { @@ -1987,7 +2183,9 @@ get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict, my_CFDictionaryGetArray(state_dict, kSCPropNetDNSServerAddresses), NULL, - kProtocolFlagsIPv4 | kProtocolFlagsIPv6); + FALSE, + kProtocolFlagsIPv4 | kProtocolFlagsIPv6, + NULL); } else { merge_dns_servers(new_dict, @@ -1995,7 +2193,9 @@ get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict, kSCPropNetDNSServerAddresses), my_CFDictionaryGetArray(setup_dict, kSCPropNetDNSServerAddresses), - active_protos); + have_setup, + active_protos, + interface); } for (i = 0; i < sizeof(merge_list)/sizeof(merge_list[0]); i++) { @@ -2063,7 +2263,6 @@ get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict, done: changed = service_dict_set(serviceID, kSCEntNetDNS, new_dict); my_CFRelease(&new_dict); - my_CFRelease(&interface); return (changed); } @@ -2078,7 +2277,7 @@ merge_dict(const void *key, const void *value, void *context) #define PROXY_AUTO_DISCOVERY_URL 252 -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef wpadURL_dhcp(CFDictionaryRef dhcp_options) { CFStringRef urlString = NULL; @@ -2117,7 +2316,7 @@ wpadURL_dhcp(CFDictionaryRef dhcp_options) return urlString; } -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef wpadURL_dns(void) { CFURLRef url; @@ -2142,10 +2341,10 @@ get_proxies_changes(CFStringRef serviceID, CFDictionaryRef state_dict, ProtocolFlags active_protos = kProtocolFlagsNone; boolean_t changed = FALSE; CFStringRef interface = NULL; - CFDataRef ipv4; + CFDictionaryRef ipv4; CFDictionaryRef ipv6; CFMutableDictionaryRef new_dict = NULL; - struct { + const struct { CFStringRef key; uint32_t flags; Boolean append; @@ -2153,7 +2352,7 @@ get_proxies_changes(CFStringRef serviceID, CFDictionaryRef state_dict, { kSCPropNetProxiesSupplementalMatchDomains, ALLOW_EMPTY_STRING, TRUE }, { kSCPropNetProxiesSupplementalMatchOrders, 0, TRUE }, }; - struct { + const struct { CFStringRef key1; /* an "enable" key */ CFStringRef key2; CFStringRef key3; @@ -2171,36 +2370,30 @@ get_proxies_changes(CFStringRef serviceID, CFDictionaryRef state_dict, NULL, NULL, } }; + IPv4RouteListRef routes = NULL; if ((state_dict == NULL) && (setup_dict == NULL)) { /* there is no proxy content */ goto done; } - ipv4 = (CFDataRef)service_dict_get(serviceID, kSCEntNetIPv4); - if (ipv4 != NULL) { - IPv4RouteListRef routes; + ipv4 = service_dict_get(serviceID, kSCEntNetIPv4); + routes = ipv4_dict_get_routelist(ipv4); + if (routes != NULL) { active_protos |= kProtocolFlagsIPv4; - routes = (IPv4RouteListRef)CFDataGetBytePtr(ipv4); - if (routes->count > 0) { - interface = CFStringCreateWithCString(NULL, - routes->list[0].ifname, - kCFStringEncodingASCII); - } + interface = ipv4_dict_get_ifname(ipv4); } ipv6 = service_dict_get(serviceID, kSCEntNetIPv6); if (ipv6 != NULL) { active_protos |= kProtocolFlagsIPv6; - if ((interface == NULL) && - CFDictionaryGetValueIfPresent(ipv6, - kSCPropInterfaceName, - (const void **)&interface)) { - CFRetain(interface); - } + if (interface == NULL) { + interface = CFDictionaryGetValue(ipv6, + kSCPropInterfaceName); + } } if (active_protos == kProtocolFlagsNone) { @@ -2385,7 +2578,6 @@ get_proxies_changes(CFStringRef serviceID, CFDictionaryRef state_dict, done: changed = service_dict_set(serviceID, kSCEntNetProxies, new_dict); my_CFRelease(&new_dict); - my_CFRelease(&interface); return (changed); } @@ -2397,7 +2589,7 @@ get_smb_changes(CFStringRef serviceID, CFDictionaryRef state_dict, boolean_t changed = FALSE; int i; CFMutableDictionaryRef new_dict = NULL; - CFStringRef pick_list[] = { + const CFStringRef pick_list[] = { kSCPropNetSMBNetBIOSName, kSCPropNetSMBNetBIOSNodeType, #ifdef ADD_NETBIOS_SCOPE @@ -2447,9 +2639,33 @@ get_smb_changes(CFStringRef serviceID, CFDictionaryRef state_dict, } #endif /* !TARGET_OS_IPHONE */ +static CFStringRef +services_info_get_interface(CFDictionaryRef services_info, + CFStringRef serviceID) +{ + CFStringRef interface = NULL; + CFDictionaryRef ipv4_dict; + + ipv4_dict = get_service_state_entity(services_info, serviceID, + kSCEntNetIPv4); + if (isA_CFDictionary(ipv4_dict) != NULL) { + interface = CFDictionaryGetValue(ipv4_dict, kSCPropInterfaceName); + } + else { + CFDictionaryRef ipv6_dict; + + ipv6_dict = get_service_state_entity(services_info, serviceID, + kSCEntNetIPv6); + if (isA_CFDictionary(ipv6_dict) != NULL) { + interface = CFDictionaryGetValue(ipv6_dict, kSCPropInterfaceName); + } + } + return (interface); +} + static boolean_t get_rank_changes(CFStringRef serviceID, CFDictionaryRef state_options, - CFDictionaryRef setup_options, CFDictionaryRef info) + CFDictionaryRef setup_options, CFDictionaryRef services_info) { boolean_t changed = FALSE; CFMutableDictionaryRef new_dict = NULL; @@ -2461,7 +2677,11 @@ get_rank_changes(CFStringRef serviceID, CFDictionaryRef state_options, /* * Check "PrimaryRank" setting * - * Note: Rank Never > Rank Last > Rank First > Rank None + * Note 1: Rank setting in setup/state option overwrites the + * Rank setting in interface + * Within each rank setting, the following precedence is defined: + * + * Note 2: Rank Never > Rank Last > Rank First > Rank None */ if (isA_CFDictionary(setup_options)) { setup_rank = CFDictionaryGetValue(setup_options, kSCPropNetServicePrimaryRank); @@ -2485,6 +2705,25 @@ get_rank_changes(CFStringRef serviceID, CFDictionaryRef state_options, new_rank = kSCValNetServicePrimaryRankFirst; } + /* This corresponds to Note 1 */ + if (setup_rank == NULL && state_rank == NULL) { + /* Fetch the interface associated with the service */ + CFStringRef interface; + + interface = services_info_get_interface(services_info, serviceID); + + /* Get the rank on that interface */ + if (interface != NULL) { + new_rank = CFDictionaryGetValue(S_if_rank_dict, interface); + if (S_IPMonitor_debug & kDebugFlag1) { + SCLog(TRUE, LOG_NOTICE, + CFSTR("serviceID %@ interface %@ rank = %@"), + serviceID, interface, + (new_rank != NULL) ? new_rank : CFSTR("")); + } + } + } + if (new_rank != NULL) { new_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, @@ -2497,6 +2736,83 @@ get_rank_changes(CFStringRef serviceID, CFDictionaryRef state_options, return (changed); } +static CFStringRef +if_rank_key_copy(CFStringRef ifname) +{ + return (SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, + kSCDynamicStoreDomainState, + ifname, + kSCEntNetService)); +} + +static void +if_rank_set(CFStringRef ifname, CFDictionaryRef rank_dict) +{ + CFStringRef rank = NULL; + + if (isA_CFDictionary(rank_dict) != NULL) { + rank = CFDictionaryGetValue(rank_dict, kSCPropNetServicePrimaryRank); + rank = isA_CFString(rank); + } + + /* specific rank is asserted */ + if (rank != NULL) { + if (S_IPMonitor_debug & kDebugFlag1) { + SCLog(TRUE, LOG_NOTICE, CFSTR("Interface %@ asserted rank %@"), + ifname, rank); + } + CFDictionarySetValue(S_if_rank_dict, ifname, rank); + } else { + if (S_IPMonitor_debug & kDebugFlag1) { + SCLog(TRUE, LOG_NOTICE, CFSTR("Interface %@ removed rank."), + ifname); + } + CFDictionaryRemoveValue(S_if_rank_dict, ifname); + } + return; +} + +static void +if_rank_apply(const void * key, const void * value, void * context) +{ + CFStringRef ifname; + CFDictionaryRef rank_dict = (CFDictionaryRef)value; + + /* State:/Network/Interface//Service, is at index 3 */ + ifname = my_CFStringCopyComponent(key, CFSTR("/"), 3); + if (ifname != NULL) { + if_rank_set(ifname, rank_dict); + CFRelease(ifname); + } + return; +} + +static void +if_rank_dict_init(void) +{ + CFDictionaryRef info; + CFStringRef pattern; + CFArrayRef patterns; + + S_if_rank_dict + = CFDictionaryCreateMutable(NULL, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + pattern = if_rank_key_copy(kSCCompAnyRegex); + patterns = CFArrayCreate(NULL, + (const void **)&pattern, 1, + &kCFTypeArrayCallBacks); + CFRelease(pattern); + info = SCDynamicStoreCopyMultiple(S_session, NULL, patterns); + CFRelease(patterns); + if (info != NULL) { + CFDictionaryApplyFunction(info, if_rank_apply, NULL); + CFRelease(info); + } + return; + +} + static void add_service_keys(CFStringRef serviceID, CFMutableArrayRef keys, CFMutableArrayRef patterns) { @@ -2532,11 +2848,13 @@ add_service_keys(CFStringRef serviceID, CFMutableArrayRef keys, CFMutableArrayRe } static CFDictionaryRef -services_info_copy(SCDynamicStoreRef session, CFArrayRef service_list) +services_info_copy(SCDynamicStoreRef session, CFArrayRef service_list, + CFArrayRef if_rank_list) { int count; CFMutableArrayRef get_keys; CFMutableArrayRef get_patterns; + int if_count; CFDictionaryRef info; int s; @@ -2554,6 +2872,17 @@ services_info_copy(SCDynamicStoreRef session, CFArrayRef service_list) add_service_keys(serviceID, get_keys, get_patterns); } + if_count = (if_rank_list != NULL) + ? CFArrayGetCount(if_rank_list) : 0; + for (s = 0; s < if_count; s++) { + CFStringRef ifname = CFArrayGetValueAtIndex(if_rank_list, s); + CFStringRef key; + + key = if_rank_key_copy(ifname); + CFArrayAppendValue(get_keys, key); + CFRelease(key); + } + info = SCDynamicStoreCopyMultiple(session, get_keys, get_patterns); my_CFRelease(&get_keys); my_CFRelease(&get_patterns); @@ -2630,7 +2959,7 @@ ipv4_route(int sockfd, else { rtmsg.hdr.rtm_flags = RTF_UP | RTF_CLONING | RTF_STATIC; } - if ((flags & kRouteWantScopedFlag) != 0) { + if ((flags & kRouteIsScopedFlag) != 0) { #ifdef RTF_IFSCOPE if (!S_scopedroute) { return (0); @@ -2720,7 +3049,9 @@ ipv6_route(int cmd, struct in6_addr gateway, struct in6_addr netaddr, default_route = (bcmp(&zeroes, &netaddr, sizeof(netaddr)) == 0); - if (IN6_IS_ADDR_LINKLOCAL(&gateway) && ifname != NULL) { + if ((IN6_IS_ADDR_LINKLOCAL(&gateway) || + IN6_IS_ADDR_MC_LINKLOCAL(&gateway)) && + (ifname != NULL)) { unsigned int index = if_nametoindex(ifname); /* add the scope id to the link local address */ @@ -2806,7 +3137,7 @@ ipv6_default_route_add(struct in6_addr router, char * ifname, boolean_t is_direct) { if ((S_IPMonitor_debug & kDebugFlag1) != 0) { - char ntopbuf[INET6_ADDRSTRLEN]; + char ntopbuf[INET6_ADDRSTRLEN]; SCLog(TRUE, LOG_NOTICE, CFSTR("IPMonitor: IPv6 route add default" @@ -2987,13 +3318,12 @@ router_is_our_ipv6_address(CFStringRef router, CFArrayRef addr_list) static IPv4RouteListRef service_dict_get_ipv4_routelist(CFDictionaryRef service_dict) { - CFDataRef data; + CFDictionaryRef dict; IPv4RouteListRef routes = NULL; - data = (CFDataRef)CFDictionaryGetValue(service_dict, kSCEntNetIPv4); - if (data != NULL) { - routes = (IPv4RouteListRef)CFDataGetBytePtr(data); - } + dict = CFDictionaryGetValue(service_dict, kSCEntNetIPv4); + + routes = ipv4_dict_get_routelist(dict); return (routes); } @@ -3013,8 +3343,7 @@ ipv4_route_gateway(int sockfd, int cmd, char * ifn_p, mask.s_addr = htonl(INADDR_BROADCAST); return (ipv4_route(sockfd, cmd, def_route->ifa, def_route->gateway, mask, ifn_p, def_route->ifindex, - def_route->ifa, - (def_route->flags & kRouteWantScopedFlag))); + def_route->ifa, def_route->flags)); } /* @@ -3225,7 +3554,7 @@ update_ipv4(CFStringRef primary, } static void -update_ipv6(CFDictionaryRef service_info, +update_ipv6(CFDictionaryRef services_info, CFStringRef primary, keyChangeListRef keys) { @@ -3306,7 +3635,7 @@ update_ipv6(CFDictionaryRef service_info, } static void -update_dns(CFDictionaryRef service_info, +update_dns(CFDictionaryRef services_info, CFStringRef primary, keyChangeListRef keys) { @@ -3339,6 +3668,7 @@ update_dns(CFDictionaryRef service_info, CFDictionaryRemoveValue(new_dict, kSCPropInterfaceName); CFDictionaryRemoveValue(new_dict, kSCPropNetDNSSupplementalMatchDomains); CFDictionaryRemoveValue(new_dict, kSCPropNetDNSSupplementalMatchOrders); + CFDictionaryRemoveValue(new_dict, DNS_CONFIGURATION_SCOPED_QUERY_KEY); keyChangeListSetValue(keys, S_state_global_dns, new_dict); CFRelease(new_dict); } @@ -3346,17 +3676,18 @@ update_dns(CFDictionaryRef service_info, } static void -update_dnsinfo(CFDictionaryRef service_info, +update_dnsinfo(CFDictionaryRef services_info, CFStringRef primary, keyChangeListRef keys, CFArrayRef service_order) { + Boolean changed; CFDictionaryRef dict = NULL; CFArrayRef multicastResolvers; CFArrayRef privateResolvers; - multicastResolvers = CFDictionaryGetValue(service_info, S_multicast_resolvers); - privateResolvers = CFDictionaryGetValue(service_info, S_private_resolvers); + multicastResolvers = CFDictionaryGetValue(services_info, S_multicast_resolvers); + privateResolvers = CFDictionaryGetValue(services_info, S_private_resolvers); if (primary != NULL) { CFDictionaryRef service_dict; @@ -3367,17 +3698,19 @@ update_dnsinfo(CFDictionaryRef service_info, } } - dns_configuration_set(dict, - S_service_state_dict, - service_order, - multicastResolvers, - privateResolvers); - keyChangeListNotifyKey(keys, S_state_global_dns); + changed = dns_configuration_set(dict, + S_service_state_dict, + service_order, + multicastResolvers, + privateResolvers); + if (changed) { + keyChangeListNotifyKey(keys, S_state_global_dns); + } return; } static void -update_proxies(CFDictionaryRef service_info, +update_proxies(CFDictionaryRef services_info, CFStringRef primary, keyChangeListRef keys, CFArrayRef service_order) @@ -3409,7 +3742,7 @@ update_proxies(CFDictionaryRef service_info, #if !TARGET_OS_IPHONE static void -update_smb(CFDictionaryRef service_info, +update_smb(CFDictionaryRef services_info, CFStringRef primary, keyChangeListRef keys) { @@ -3438,7 +3771,7 @@ static Rank get_service_rank(CFArrayRef order, int n_order, CFStringRef serviceID) { CFIndex i; - Rank rank = kRankLast; + Rank rank = kRankIndexMask; if (serviceID != NULL && order != NULL && n_order > 0) { for (i = 0; i < n_order; i++) { @@ -3468,7 +3801,7 @@ static Rank rank_dict_get_service_rank(CFDictionaryRef rank_dict, CFStringRef serviceID) { CFNumberRef rank; - Rank rank_val = kRankLast; + Rank rank_val = RankMake(kRankIndexMask, kRankAssertionDefault); rank = CFDictionaryGetValue(rank_dict, serviceID); if (rank != NULL) { @@ -3503,8 +3836,7 @@ typedef struct election_info { int n_order; CFStringRef serviceID; CFDictionaryRef service_dict; - Rank service_rank; - boolean_t choose_last; + Rank rank; } election_info_t; typedef boolean_t election_func_t(void * context, election_info_t * info); @@ -3519,37 +3851,39 @@ typedef boolean_t election_func_t(void * context, election_info_t * info); static boolean_t elect_ipv4(void * context, election_info_t * info) { + Rank primary_rank; IPv4RouteListRef * routes_p = (IPv4RouteListRef *)context; IPv4RouteListRef service_routes; service_routes = service_dict_get_ipv4_routelist(info->service_dict); + + info->rank = get_service_rank(info->order, info->n_order, + info->serviceID); + if (service_routes == NULL) { return (FALSE); } - if ((service_routes->list->flags & kRouteChooseFirstFlag) != 0) { - info->service_rank = kRankFirst; - } - else if (S_ppp_override_primary + + primary_rank = RANK_ASSERTION_MASK(service_routes->list->rank); + + if (S_ppp_override_primary && (strncmp(PPP_PREFIX, service_routes->list->ifname, sizeof(PPP_PREFIX) - 1) == 0)) { /* PPP override: make ppp* look the best */ /* Hack: should use interface type, not interface name */ - info->service_rank = kRankFirst; - } - else { - info->service_rank = get_service_rank(info->order, info->n_order, - info->serviceID); - if ((service_routes->list->flags & kRouteChooseLastFlag) != 0) { - info->choose_last = TRUE; - } + primary_rank = kRankAssertionFirst; } + + info->rank = RankMake(info->rank, primary_rank); + if (routes_p != NULL) { *routes_p = IPv4RouteListAddRouteList(*routes_p, info->n_services * 3, service_routes, - info->service_rank); + info->rank); } - if ((service_routes->list->flags & kRouteChooseNeverFlag) != 0) { + + if (primary_rank == kRankAssertionNever) { /* never elect as primary */ return (FALSE); } @@ -3560,66 +3894,243 @@ elect_ipv4(void * context, election_info_t * info) } rank_dict_set_service_rank(S_ipv4_service_rank_dict, - info->serviceID, info->service_rank); + info->serviceID, info->rank); return (TRUE); } -static boolean_t -elect_ipv6(void * context, election_info_t * info) +static void +IPv6RankedListInsertE(IPv6RankedListRef list, IPv6RankedERef e) { - CFStringRef if_name; - CFStringRef primaryRank = NULL; - CFDictionaryRef proto_dict; - CFStringRef router; - CFDictionaryRef service_options; + int idx = 0; + int elems_to_be_moved = 0; + + if (list == NULL) return; + + for (idx = 0; idx < list->count; idx++) { + if ((e->rank < list->elem[idx].rank)) { + break; + } + } + + if ((S_IPMonitor_debug & kDebugFlag2) != 0) { + SCLog(TRUE, LOG_NOTICE, + CFSTR("IPv6RankedListInsertE: %s flags 0x%x at index %d with rank %u."), + e->ifname, e->flags, idx, e->rank); + } + + elems_to_be_moved = list->count - idx; + if (elems_to_be_moved > 0) { + bcopy((void*) &list->elem[idx], (void*) &list->elem[idx+1], + elems_to_be_moved * sizeof(*e)); + } + + bcopy((void*) e, (void*) &list->elem[idx], sizeof(*e)); + list->count++; + return; +} + +static boolean_t +elect_ipv6(void * context, election_info_t * info) +{ + CFStringRef if_name; + CFStringRef primaryRankStr = NULL; + CFDictionaryRef proto_dict; + CFStringRef router; + CFDictionaryRef service_options; + IPv6RankedListRef list = (IPv6RankedListRef) context; + IPv6RankedE elem; + CFDictionaryRef dns_dict = NULL; + Rank primary_rank = kRankAssertionDefault; + + memset((void *)&elem, 0, sizeof(elem)); + + info->rank = get_service_rank(info->order, info->n_order, info->serviceID); proto_dict = CFDictionaryGetValue(info->service_dict, kSCEntNetIPv6); if (proto_dict == NULL) { return (FALSE); } - service_options = service_dict_get(info->serviceID, kSCEntNetService); - if (service_options != NULL) { - primaryRank = CFDictionaryGetValue(service_options, kSCPropNetServicePrimaryRank); - if ((primaryRank != NULL) - && CFEqual(primaryRank, kSCValNetServicePrimaryRankNever)) { - return (FALSE); - } - } if_name = CFDictionaryGetValue(proto_dict, kSCPropInterfaceName); - if (if_name != NULL && CFEqual(if_name, CFSTR("lo0"))) { - /* never elect as primary */ + if (if_name == NULL) { + /* we need an interface name */ + return (FALSE); + } + if (CFEqual(if_name, CFSTR("lo0"))) { + /* don't ever elect loopback */ return (FALSE); } + CFStringGetCString(if_name, elem.ifname, + sizeof(elem.ifname), + kCFStringEncodingASCII); router = CFDictionaryGetValue(proto_dict, kSCPropNetIPv6Router); if (router == NULL) { - info->choose_last = TRUE; - info->service_rank = kRankLast; + /* can't become primary without a router */ + return (FALSE); } - else if ((primaryRank != NULL) - && CFEqual(primaryRank, kSCValNetServicePrimaryRankFirst)) { - info->service_rank = kRankFirst; + + dns_dict = service_dict_get(info->serviceID, kSCEntNetDNS); + if (dns_dict != NULL) { + elem.flags |= NWI_IFSTATE_FLAGS_HAS_DNS; } - else if (get_override_primary(proto_dict)) { - info->service_rank = kRankFirst; + + service_options = service_dict_get(info->serviceID, kSCEntNetService); + if (service_options != NULL) { + primaryRankStr = CFDictionaryGetValue(service_options, kSCPropNetServicePrimaryRank); + if (primaryRankStr != NULL) { + primary_rank = PrimaryRankGetRankAssertion(primaryRankStr); + } + if (primary_rank == kRankAssertionNever) { + elem.flags |= NWI_IFSTATE_FLAGS_NOT_IN_LIST; + elem.rank = RankMake(info->rank, primary_rank); + IPv6RankedListInsertE(list, &elem); + return (FALSE); + } + } + + if (get_override_primary(proto_dict)) { + primary_rank = kRankAssertionFirst; } else if (S_ppp_override_primary - && if_name != NULL && CFStringHasPrefix(if_name, CFSTR(PPP_PREFIX))) { /* PPP override: make ppp* look the best */ /* Hack: should use interface type, not interface name */ - info->service_rank = kRankFirst; - } - else { - info->service_rank = get_service_rank(info->order, info->n_order, - info->serviceID); + primary_rank = kRankAssertionFirst; } + elem.rank = RankMake(info->rank, primary_rank); + info->rank = RankMake(info->rank, primary_rank); + + (void)cfstring_to_ip6(router, &elem.iaddr6); + + IPv6RankedListInsertE(list, &elem); rank_dict_set_service_rank(S_ipv6_service_rank_dict, - info->serviceID, info->service_rank); + info->serviceID, info->rank); return (TRUE); } +static void +update_nwi_state_ipv6(nwi_state_t state, IPv6RankedListRef list) +{ + int idx; + + if (state == NULL) { + return; + } + + /* A null list indicates to clear the ifstates */ + nwi_state_clear(state, AF_INET6); + + if (list == NULL) { + return; + } + + for (idx = 0 ; idx < list->count; idx++) { + if ((S_IPMonitor_debug & kDebugFlag2) != 0) { + char ntopbuf[INET6_ADDRSTRLEN]; + + inet_ntop(AF_INET6, &list->elem[idx].iaddr6, ntopbuf, + sizeof(ntopbuf)); + + SCLog(TRUE, LOG_NOTICE, + CFSTR("Inserting v6 [%s] into list with flags 0x%x" + " with rank %lu ipv6 addr %s"), + list->elem[idx].ifname, list->elem[idx].flags, + list->elem[idx].rank, ntopbuf); + } + + nwi_insert_ifstate(state, list->elem[idx].ifname, + AF_INET6, list->elem[idx].flags, + list->elem[idx].rank, + (void *)&list->elem[idx].iaddr6); + } + nwi_state_set_last(state, AF_INET6); +} + +static boolean_t +interface_has_dns(const void * * values, int values_count, + const char * ifname) +{ + boolean_t has_dns = FALSE; + int i; + CFStringRef ifname_cf; + + ifname_cf = CFStringCreateWithCString(NULL, ifname, kCFStringEncodingASCII); + for (i = 0; i < values_count; i++) { + CFDictionaryRef dns_dict; + + dns_dict = CFDictionaryGetValue(values[i], kSCEntNetDNS); + if (dns_dict != NULL) { + CFStringRef this_ifname; + + this_ifname = CFDictionaryGetValue(dns_dict, kSCPropInterfaceName); + if (this_ifname != NULL + && CFEqual(this_ifname, ifname_cf)) { + has_dns = TRUE; + break; + } + } + } + CFRelease(ifname_cf); + return (has_dns); +} + +static void +update_nwi_state_ipv4(nwi_state_t state, IPv4RouteListRef route) +{ + int idx; + IPv4RouteRef r; + const void * * values; + const void * values_buf[10]; + int values_count; + + if (state == NULL) { + return; + } + nwi_state_clear(state, AF_INET); + if (route == NULL) { + return; + } + values_count = CFDictionaryGetCount(S_service_state_dict); + if (values_count == 0) { + return; + } + if (values_count <= (sizeof(values_buf) / sizeof(values_buf[0]))) { + values = values_buf; + } + else { + values = (const void * *)malloc(sizeof(*values) * values_count); + } + CFDictionaryGetKeysAndValues(S_service_state_dict, + NULL, (const void * *)values); + for (idx = 0, r = route->list; idx < route->count; idx++, r++) { + uint64_t flags = 0ULL; + + if (r->dest.s_addr != 0) { + /* we're done, no more default routes */ + break; + } + if (RANK_ASSERTION_MASK(r->rank) == kRankAssertionNever) { + flags |= NWI_IFSTATE_FLAGS_NOT_IN_LIST; + } + + if (interface_has_dns(values, values_count, r->ifname)) { + flags |= NWI_IFSTATE_FLAGS_HAS_DNS; + } + if ((S_IPMonitor_debug & kDebugFlag2) != 0) { + SCLog(TRUE, LOG_NOTICE, CFSTR("Inserting v4 [%s] with flags 0x%x primary_rank %u"), + r->ifname, flags, r->rank); + } + nwi_insert_ifstate(state, r->ifname, AF_INET, flags, r->rank, + (void *)&r->ifa); + } + if (values != values_buf) { + free(values); + } + nwi_state_set_last(state, AF_INET); + return; +} + /* * Function: elect_new_primary * Purpose: @@ -3638,8 +4149,7 @@ elect_new_primary(election_func_t * elect_func, void * context, #define N_KEYS_VALUES_STATIC 10 void * keys_values_buf[N_KEYS_VALUES_STATIC * 2]; CFStringRef new_primary = NULL; - Rank new_primary_rank = kRankLast; - boolean_t new_primary_choose_last = FALSE; + Rank new_rank = 0; void * * values; count = CFDictionaryGetCount(S_service_state_dict); @@ -3657,30 +4167,25 @@ elect_new_primary(election_func_t * elect_func, void * context, info.n_services = count; info.order = order; info.n_order = n_order; + new_rank = 0; for (i = 0; i < count; i++) { boolean_t found_new_primary = FALSE; info.serviceID = (CFStringRef)keys[i]; info.service_dict = (CFDictionaryRef)values[i]; - info.service_rank = kRankLast; - info.choose_last = FALSE; + info.rank = kRankAssertionMask; if ((*elect_func)(context, &info) == FALSE) { continue; } - if (new_primary == NULL) { - found_new_primary = TRUE; - } - else if (info.choose_last == new_primary_choose_last) { - found_new_primary = (info.service_rank < new_primary_rank); - } - else if (new_primary_choose_last) { + if (new_primary == NULL + || (info.rank < new_rank)) { found_new_primary = TRUE; } + if (found_new_primary) { new_primary = info.serviceID; - new_primary_rank = info.service_rank; - new_primary_choose_last = info.choose_last; + new_rank = info.rank; } } if (new_primary != NULL) { @@ -3795,27 +4300,285 @@ rank_service_entity(CFDictionaryRef rank_dict, CFStringRef serviceID, CFStringRef entity) { if (service_dict_get(serviceID, entity) == NULL) { - return (kRankLast); + return (RankMake(kRankIndexMask, kRankAssertionDefault)); } return (rank_dict_get_service_rank(rank_dict, serviceID)); } +static __inline__ unsigned int +IPv6RankedListComputeSize(int n) +{ + return (offsetof(IPv6RankedList, elem[n])); + +} + +static void +update_interface_rank(CFDictionaryRef services_info, CFStringRef ifname) +{ + CFStringRef if_rank_key; + CFDictionaryRef rank_dict; + + if_rank_key = if_rank_key_copy(ifname); + rank_dict = CFDictionaryGetValue(services_info, if_rank_key); + CFRelease(if_rank_key); + if_rank_set(ifname, rank_dict); + return; +} + +static void +append_serviceIDs_for_interface(CFMutableArrayRef services_changed, + CFStringRef ifname) +{ + int count; + int i; + void * * keys; +#define N_KEYS_VALUES_STATIC 10 + void * keys_values_buf[N_KEYS_VALUES_STATIC * 2]; + void * * values; + + count = CFDictionaryGetCount(S_service_state_dict); + if (count <= N_KEYS_VALUES_STATIC) { + keys = keys_values_buf; + } else { + keys = (void * *)malloc(sizeof(*keys) * count * 2); + } + values = keys + count; + CFDictionaryGetKeysAndValues(S_service_state_dict, + (const void * *)keys, + (const void * *)values); + + for (i = 0; i < count; i++) { + CFDictionaryRef ipv4 = NULL; + CFStringRef interface = NULL; + CFStringRef serviceID; + CFDictionaryRef service_dict; + + serviceID = (CFStringRef)keys[i]; + service_dict = (CFDictionaryRef)values[i]; + + /* check if this is a ipv4 dictionary */ + ipv4 = CFDictionaryGetValue(service_dict, kSCEntNetIPv4); + if (ipv4 != NULL) { + interface = ipv4_dict_get_ifname(ipv4); + if (interface != NULL && CFEqual(interface, ifname)) { + if (S_IPMonitor_debug & kDebugFlag1) { + SCLog(TRUE, LOG_NOTICE, CFSTR("Found ipv4 service %@ on interface %@."), + serviceID, ifname); + } + + my_CFArrayAppendUniqueValue(services_changed, serviceID); + } + } else { + CFDictionaryRef proto_dict; + + /* check if this is a ipv6 dictionary */ + proto_dict = CFDictionaryGetValue(service_dict, kSCEntNetIPv6); + if (proto_dict == NULL) { + continue; + } + interface = CFDictionaryGetValue(proto_dict, kSCPropInterfaceName); + if (interface != NULL && CFEqual(interface, ifname)) { + if (S_IPMonitor_debug & kDebugFlag1) { + SCLog(TRUE, LOG_NOTICE, CFSTR("Found ipv6 service %@ on interface %@."), + serviceID, ifname); + } + + my_CFArrayAppendUniqueValue(services_changed, serviceID); + } + } + } + + if (keys != keys_values_buf) { + free(keys); + } +} + +static const CFStringRef *statusEntityNames[] = { + &kSCEntNetIPSec, + &kSCEntNetPPP, + &kSCEntNetVPN, +}; + +static void +add_status_keys(CFMutableArrayRef patterns) +{ + int i; + + for (i = 0; i < sizeof(statusEntityNames)/sizeof(statusEntityNames[0]); i++) { + CFStringRef pattern; + + pattern = state_service_key(kSCCompAnyRegex, *statusEntityNames[i]); + CFArrayAppendValue(patterns, pattern); + CFRelease(pattern); + } + + return; +} + +static +inline +const char * +get_changed_str(CFStringRef serviceID, CFStringRef entity, CFDictionaryRef old_dict) +{ + CFDictionaryRef new_dict = NULL; + + if (serviceID != NULL) { + new_dict = service_dict_get(serviceID, entity); + } + + if (old_dict == NULL) { + if (new_dict != NULL) { + return "+"; + } + } else { + if (new_dict == NULL) { + return "-"; + } else if (!CFEqual(old_dict, new_dict)) { + return "!"; + } + } + return ""; +} + +static CF_RETURNS_RETAINED CFStringRef +generate_log_changes(nwi_state_t changes_state, + boolean_t dns_changed, + boolean_t dnsinfo_changed, + CFDictionaryRef old_primary_dns, + boolean_t proxy_changed, + CFDictionaryRef old_primary_proxy, + boolean_t smb_changed, + CFDictionaryRef old_primary_smb + ) +{ + int idx; + CFMutableStringRef log_output; + nwi_ifstate_t scan; + + log_output = CFStringCreateMutable(NULL, 0); + + if (changes_state != NULL) { + for (idx = 0; idx < sizeof(nwi_af_list)/sizeof(nwi_af_list[0]); idx++) { + CFMutableStringRef changes = NULL; + CFMutableStringRef primary_str = NULL; + + scan = nwi_state_get_first_ifstate(changes_state, nwi_af_list[idx]); + + while (scan != NULL) { + const char * changed_str; + + changed_str = nwi_ifstate_get_diff_str(scan); + if (changed_str != NULL) { + void * address; + const char * addr_str; + char ntopbuf[INET6_ADDRSTRLEN]; + + address = (void *)nwi_ifstate_get_address(scan); + addr_str = inet_ntop(scan->af, address, + ntopbuf, sizeof(ntopbuf)); + + if (primary_str == NULL) { + primary_str = CFStringCreateMutable(NULL, 0); + CFStringAppendFormat(primary_str, NULL, CFSTR("%s%s:%s"), + nwi_ifstate_get_ifname(scan), + changed_str, addr_str); + } else { + if (changes == NULL) { + changes = CFStringCreateMutable(NULL, 0); + } + CFStringAppendFormat(changes, NULL, CFSTR(", %s"), + nwi_ifstate_get_ifname(scan)); + if (strcmp(changed_str, "") != 0) { + CFStringAppendFormat(changes, NULL, CFSTR("%s:%s"), + changed_str, addr_str); + } + } + } + scan = nwi_ifstate_get_next(scan, scan->af); + } + + if (primary_str != NULL) { + CFStringAppendFormat(log_output, NULL, CFSTR(" %s(%@"), + nwi_af_list[idx] == AF_INET ? "v4" : "v6", + primary_str); + + if (changes != NULL && CFStringGetLength(changes) != 0) { + CFStringAppendFormat(log_output, NULL, CFSTR("%@"), + changes); + } + CFStringAppendFormat(log_output, NULL, CFSTR(")")); + + my_CFRelease(&primary_str); + my_CFRelease(&changes); + } + } + } + + if (dns_changed || dnsinfo_changed) { + const char *str; + + str = get_changed_str(S_primary_dns, kSCEntNetDNS, old_primary_dns); + if ((strcmp(str, "") == 0) && dnsinfo_changed) { + str = "*"; // dnsinfo change w/no change to primary + } + CFStringAppendFormat(log_output, NULL, CFSTR(" DNS%s"), str); + } else if (S_primary_dns != NULL){ + CFStringAppendFormat(log_output, NULL, CFSTR(" DNS")); + } + + if (proxy_changed) { + const char *str; + + str = get_changed_str(S_primary_proxies, kSCEntNetProxies, old_primary_proxy); + CFStringAppendFormat(log_output, NULL, CFSTR(" Proxy%s"), str); + } else if (S_primary_proxies != NULL) { + CFStringAppendFormat(log_output, NULL, CFSTR(" Proxy")); + } + +#if !TARGET_OS_IPHONE + if (smb_changed) { + const char *str; + + str = get_changed_str(S_primary_smb, kSCEntNetSMB, old_primary_smb); + CFStringAppendFormat(log_output, NULL, CFSTR(" SMB%s"), str); + } else if (S_primary_smb != NULL) { + CFStringAppendFormat(log_output, NULL, CFSTR(" SMB")); + } +#endif // !TARGET_OS_IPHONE + + return log_output; +} + static void IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys, void * not_used) { CFIndex count; - boolean_t dnsinfo_changed = FALSE; - boolean_t global_ipv4_changed = FALSE; - boolean_t global_ipv6_changed = FALSE; + nwi_state_t changes_state = NULL; + boolean_t dns_changed = FALSE; + boolean_t dnsinfo_changed = FALSE; + boolean_t global_ipv4_changed = FALSE; + boolean_t global_ipv6_changed = FALSE; int i; + CFMutableArrayRef if_rank_changes = NULL; keyChangeList keys; CFIndex n; - int n_service_order = 0; - boolean_t proxies_changed = FALSE; + CFStringRef network_change_msg; + int n_services; + int n_service_order = 0; + nwi_state_t old_nwi_state = NULL; + CFDictionaryRef old_primary_dns = NULL; + CFDictionaryRef old_primary_proxy = NULL; +#if !TARGET_OS_IPHONE + CFDictionaryRef old_primary_smb = NULL; +#endif // !TARGET_OS_IPHONE + boolean_t proxies_changed = FALSE; CFArrayRef service_order; - CFMutableArrayRef service_changes = NULL; - CFDictionaryRef services_info = NULL; + CFMutableArrayRef service_changes = NULL; + CFDictionaryRef services_info = NULL; +#if !TARGET_OS_IPHONE + boolean_t smb_changed = FALSE; +#endif // !TARGET_OS_IPHONE count = CFArrayGetCount(changed_keys); if (count == 0) { @@ -3827,9 +4590,33 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys, CFSTR("IPMonitor: changes %@ (%d)"), changed_keys, count); } + if (S_primary_dns != NULL) { + old_primary_dns = service_dict_get(S_primary_dns, kSCEntNetDNS); + if (old_primary_dns != NULL) { + old_primary_dns = CFDictionaryCreateCopy(NULL, old_primary_dns); + } + } + + if (S_primary_proxies != NULL) { + old_primary_proxy = service_dict_get(S_primary_proxies, kSCEntNetProxies); + if (old_primary_proxy != NULL) { + old_primary_proxy = CFDictionaryCreateCopy(NULL, old_primary_proxy); + } + } + +#if !TARGET_OS_IPHONE + if (S_primary_smb != NULL) { + old_primary_smb = service_dict_get(S_primary_smb, kSCEntNetSMB); + if (old_primary_smb != NULL) { + old_primary_smb = CFDictionaryCreateCopy(NULL, old_primary_smb); + } + } +#endif // !TARGET_OS_IPHONE + keyChangeListInit(&keys); service_changes = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + for (i = 0; i < count; i++) { CFStringRef change = CFArrayGetValueAtIndex(changed_keys, i); if (CFEqual(change, S_setup_global_ipv4)) { @@ -3848,11 +4635,24 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys, } #endif /* !TARGET_OS_IPHONE */ else if (CFStringHasPrefix(change, S_state_service_prefix)) { - CFStringRef serviceID = parse_component(change, - S_state_service_prefix); - if (serviceID) { - my_CFArrayAppendUniqueValue(service_changes, serviceID); - CFRelease(serviceID); + int i; + boolean_t status_changed = FALSE; + + for (i = 0; i < sizeof(statusEntityNames)/sizeof(statusEntityNames[0]); i++) { + if (CFStringHasSuffix(change, *statusEntityNames[i])) { + status_changed = TRUE; + dnsinfo_changed = TRUE; + break; + } + } + + if (!status_changed) { + CFStringRef serviceID = parse_component(change, + S_state_service_prefix); + if (serviceID) { + my_CFArrayAppendUniqueValue(service_changes, serviceID); + CFRelease(serviceID); + } } } else if (CFStringHasPrefix(change, S_setup_service_prefix)) { @@ -3863,10 +4663,37 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys, CFRelease(serviceID); } } + else if (CFStringHasSuffix(change, kSCEntNetService)) { + CFStringRef ifname = my_CFStringCopyComponent(change, CFSTR("/"), 3); + + if (ifname != NULL) { + if (if_rank_changes == NULL) { + if_rank_changes = CFArrayCreateMutable(NULL, 0, + &kCFTypeArrayCallBacks); + } + my_CFArrayAppendUniqueValue(if_rank_changes, ifname); + CFRelease(ifname); + } + } + } + + /* determine which serviceIDs are impacted by the interface rank changes */ + if (if_rank_changes != NULL) { + n = CFArrayGetCount(if_rank_changes); + for (i = 0; i < n; i++) { + CFStringRef ifname = CFArrayGetValueAtIndex(if_rank_changes, i); + + if (S_IPMonitor_debug & kDebugFlag1) { + SCLog(TRUE, LOG_NOTICE, CFSTR("Interface rank changed %@"), + ifname); + } + append_serviceIDs_for_interface(service_changes, ifname); + } } /* grab a snapshot of everything we need */ - services_info = services_info_copy(session, service_changes); + services_info = services_info_copy(session, service_changes, + if_rank_changes); service_order = service_order_get(services_info); if (service_order != NULL) { n_service_order = CFArrayGetCount(service_order); @@ -3875,6 +4702,14 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys, CFSTR("IPMonitor: service_order %@ "), service_order); } } + + if (if_rank_changes != NULL) { + for (i = 0; i < n; i++) { + CFStringRef ifname = CFArrayGetValueAtIndex(if_rank_changes, i); + update_interface_rank(services_info, ifname); + } + } + n = CFArrayGetCount(service_changes); for (i = 0; i < n; i++) { uint32_t changes; @@ -3917,9 +4752,14 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys, #endif /* !TARGET_OS_IPHONE */ } - if (global_ipv4_changed) { + /* ensure S_nwi_state can hold as many services as we have currently */ + n_services = CFDictionaryGetCount(S_service_state_dict); + old_nwi_state = nwi_state_copy_priv(S_nwi_state); + S_nwi_state = nwi_state_new(S_nwi_state, n_services); + + if (global_ipv4_changed || dnsinfo_changed) { IPv4RouteListRef new_routelist = NULL; - CFStringRef new_primary; + CFStringRef new_primary; if ((S_IPMonitor_debug & kDebugFlag1) != 0) { SCLog(TRUE, LOG_NOTICE, @@ -3927,21 +4767,51 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys, } new_primary = elect_new_primary(&elect_ipv4, &new_routelist, service_order, n_service_order); - (void)set_new_primary(&S_primary_ipv4, new_primary, "IPv4"); - update_ipv4(S_primary_ipv4, new_routelist, &keys); + update_nwi_state_ipv4(S_nwi_state, new_routelist); + + if (global_ipv4_changed) { + (void)set_new_primary(&S_primary_ipv4, new_primary, "IPv4"); + update_ipv4(S_primary_ipv4, new_routelist, &keys); + } + else if (new_routelist != NULL) { + free(new_routelist); + new_routelist = NULL; + } my_CFRelease(&new_primary); } - if (global_ipv6_changed) { - CFStringRef new_primary; + if (global_ipv6_changed || dnsinfo_changed) { + IPv6RankedListRef list = NULL; + CFStringRef new_primary; + int size; + + size = (n_services != 0) + ? (sizeof(IPv6RankedList) + + IPv6RankedListComputeSize(n_services)) : 0; + + if (size != 0) { + list = malloc(size); + } + if (list != NULL) { + list->count = 0; + list->size = size; + } if ((S_IPMonitor_debug & kDebugFlag1) != 0) { SCLog(TRUE, LOG_NOTICE, CFSTR("IPMonitor: IPv6 service election")); } - new_primary = elect_new_primary(&elect_ipv6, NULL, + new_primary = elect_new_primary(&elect_ipv6, list, service_order, n_service_order); - (void)set_new_primary(&S_primary_ipv6, new_primary, "IPv6"); - update_ipv6(services_info, S_primary_ipv6, &keys); + update_nwi_state_ipv6(S_nwi_state, list); + + if (global_ipv6_changed) { + (void)set_new_primary(&S_primary_ipv6, new_primary, "IPv6"); + update_ipv6(services_info, S_primary_ipv6, &keys); + } + + if (list != NULL) { + free(list); + } my_CFRelease(&new_primary); } if (global_ipv4_changed || global_ipv6_changed) { @@ -4001,6 +4871,7 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys, if (set_new_primary(&S_primary_dns, new_primary_dns, "DNS")) { update_dns(services_info, S_primary_dns, &keys); + dns_changed = TRUE; dnsinfo_changed = TRUE; } if (set_new_primary(&S_primary_proxies, new_primary_proxies, "Proxies")) { @@ -4009,18 +4880,69 @@ IPMonitorNotify(SCDynamicStoreRef session, CFArrayRef changed_keys, #if !TARGET_OS_IPHONE if (set_new_primary(&S_primary_smb, new_primary_smb, "SMB")) { update_smb(services_info, S_primary_smb, &keys); + smb_changed = TRUE; } #endif /* !TARGET_OS_IPHONE */ } + if (dnsinfo_changed || global_ipv4_changed || global_ipv6_changed) { + if (S_nwi_state != NULL) { + S_nwi_state->generation_count = mach_absolute_time(); + if ((S_IPMonitor_debug & kDebugFlag1) != 0) { + syslog(LOG_NOTICE, "Updating network information"); + _nwi_state_dump(LOG_NOTICE, S_nwi_state); + } + if (_nwi_state_store(S_nwi_state) == FALSE) { + SCLog(TRUE, LOG_ERR, CFSTR("Notifying nwi_state_store failed")); + } + } + } if (dnsinfo_changed) { update_dnsinfo(services_info, S_primary_dns, &keys, service_order); } - if (proxies_changed || dnsinfo_changed) { // note: supplemental Proxies may follow supplemental DNS + if (proxies_changed || + (dnsinfo_changed && (G_supplemental_proxies_follow_dns != NULL) && CFBooleanGetValue(G_supplemental_proxies_follow_dns)) + ) { + // if proxy change OR supplemental Proxies follow supplemental DNS update_proxies(services_info, S_primary_proxies, &keys, service_order); + proxies_changed = TRUE; } my_CFRelease(&service_changes); my_CFRelease(&services_info); - keyChangeListApplyToStore(&keys, session); + my_CFRelease(&if_rank_changes); + changes_state = nwi_state_diff(old_nwi_state, S_nwi_state); + if ((S_IPMonitor_debug & kDebugFlag2) != 0) { + syslog(LOG_NOTICE, "network information diffs: "); + _nwi_state_dump(LOG_NOTICE, changes_state); + } + network_change_msg = + generate_log_changes(changes_state, + dns_changed, + dnsinfo_changed, + old_primary_dns, + proxies_changed, + old_primary_proxy, +#if !TARGET_OS_IPHONE + smb_changed, + old_primary_smb +#else // !TARGET_OS_IPHONE + FALSE, + NULL +#endif // !TARGET_OS_IPHONE + ); + keyChangeListApplyToStore(&keys, session, network_change_msg); + my_CFRelease(&old_primary_dns); + my_CFRelease(&old_primary_proxy); +#if !TARGET_OS_IPHONE + my_CFRelease(&old_primary_smb); +#endif // !TARGET_OS_IPHONE + my_CFRelease(&network_change_msg); + + if (changes_state != NULL) { + nwi_state_release(changes_state); + } + if (old_nwi_state != NULL) { + nwi_state_release(old_nwi_state); + } keyChangeListFree(&keys); return; } @@ -4029,6 +4951,7 @@ static void ip_plugin_init() { CFMutableArrayRef keys = NULL; + CFStringRef pattern; CFMutableArrayRef patterns = NULL; CFRunLoopSourceRef rls = NULL; @@ -4081,15 +5004,15 @@ ip_plugin_init() kSCDynamicStoreDomainSetup, kSCEntNetIPv4); S_state_service_prefix - = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@/"), - kSCDynamicStoreDomainState, - kSCCompNetwork, - kSCCompService); + = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainState, + CFSTR(""), + NULL); S_setup_service_prefix - = SCDynamicStoreKeyCreate(NULL, CFSTR("%@/%@/%@/"), - kSCDynamicStoreDomainSetup, - kSCCompNetwork, - kSCCompService); + = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainSetup, + CFSTR(""), + NULL); S_service_state_dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, @@ -4111,6 +5034,14 @@ ip_plugin_init() /* register for State: and Setup: per-service notifications */ add_service_keys(kSCCompAnyRegex, keys, patterns); + /* register for State: per-service PPP/VPN/IPSec status notifications */ + add_status_keys(patterns); + + /* register for interface rank notifications */ + pattern = if_rank_key_copy(kSCCompAnyRegex); + CFArrayAppendValue(patterns, pattern); + CFRelease(pattern); + /* add notifier for ServiceOrder/PPPOverridePrimary changes for IPv4 */ CFArrayAppendValue(keys, S_setup_global_ipv4); @@ -4149,7 +5080,7 @@ ip_plugin_init() CFRelease(rls); /* initialize dns configuration */ - dns_configuration_set(NULL, NULL, NULL, NULL, NULL); + (void)dns_configuration_set(NULL, NULL, NULL, NULL, NULL); #if !TARGET_OS_IPHONE empty_dns(); #endif /* !TARGET_OS_IPHONE */ @@ -4160,6 +5091,8 @@ ip_plugin_init() (void)SCDynamicStoreRemoveValue(S_session, S_state_global_smb); #endif /* !TARGET_OS_IPHONE */ + if_rank_dict_init(); + done: my_CFRelease(&keys); my_CFRelease(&patterns); @@ -4179,7 +5112,7 @@ static boolean_t S_get_plist_boolean(CFDictionaryRef plist, CFStringRef key, boolean_t def) { - CFBooleanRef b; + CFBooleanRef b; boolean_t ret = def; b = isA_CFBoolean(CFDictionaryGetValue(plist, key)); @@ -4193,7 +5126,7 @@ __private_extern__ void load_IPMonitor(CFBundleRef bundle, Boolean bundleVerbose) { - CFDictionaryRef info_dict; + CFDictionaryRef info_dict; info_dict = CFBundleGetInfoDictionary(bundle); if (info_dict != NULL) { @@ -4225,6 +5158,10 @@ load_IPMonitor(CFBundleRef bundle, Boolean bundleVerbose) } +#pragma mark - +#pragma mark Standalone test code + + #ifdef TEST_IPMONITOR #include "dns-configuration.c" #include "set-hostname.c" @@ -4263,58 +5200,58 @@ struct ipv4_service_contents { }; /* - * addr mask dest router ifname pri primaryRank + * addr mask dest router ifname pri primaryRank */ struct ipv4_service_contents en0_10 = { - "10.0.0.10", "255.255.255.0", NULL, "10.0.0.1", "en0", 10, NULL + "10.0.0.10", "255.255.255.0", NULL, "10.0.0.1", "en0", 10, NULL }; struct ipv4_service_contents en0_15 = { - "10.0.0.19", "255.255.255.0", NULL, "10.0.0.1", "en0", 15, NULL + "10.0.0.19", "255.255.255.0", NULL, "10.0.0.1", "en0", 15, NULL }; struct ipv4_service_contents en0_30 = { - "10.0.0.11", "255.255.255.0", NULL, "10.0.0.1", "en0", 30, NULL + "10.0.0.11", "255.255.255.0", NULL, "10.0.0.1", "en0", 30, NULL }; struct ipv4_service_contents en0_40 = { - "10.0.0.12", "255.255.255.0", NULL, "10.0.0.1", "en0", 40, NULL + "10.0.0.12", "255.255.255.0", NULL, "10.0.0.1", "en0", 40, NULL }; struct ipv4_service_contents en0_50 = { - "10.0.0.13", "255.255.255.0", NULL, "10.0.0.1", "en0", 50, NULL + "10.0.0.13", "255.255.255.0", NULL, "10.0.0.1", "en0", 50, NULL }; struct ipv4_service_contents en0_110 = { - "192.168.2.10", "255.255.255.0", NULL, "192.168.2.1", "en0", 110, NULL + "192.168.2.10", "255.255.255.0", NULL, "192.168.2.1", "en0", 110, NULL }; struct ipv4_service_contents en0_1 = { - "17.202.40.191", "255.255.252.0", NULL, "17.202.20.1", "en0", 1, NULL + "17.202.40.191", "255.255.252.0", NULL, "17.202.20.1", "en0", 1, NULL }; struct ipv4_service_contents en1_20 = { - "10.0.0.20", "255.255.255.0", NULL, "10.0.0.1", "en1", 20, NULL + "10.0.0.20", "255.255.255.0", NULL, "10.0.0.1", "en1", 20, NULL }; struct ipv4_service_contents en1_2 = { - "17.202.42.24", "255.255.252.0", NULL, "17.202.20.1", "en1", 2, NULL + "17.202.42.24", "255.255.252.0", NULL, "17.202.20.1", "en1", 2, NULL }; struct ipv4_service_contents en1_125 = { - "192.168.2.20", "255.255.255.0", NULL, "192.168.2.1", "en1", 125, NULL + "192.168.2.20", "255.255.255.0", NULL, "192.168.2.1", "en1", 125, NULL }; struct ipv4_service_contents fw0_25 = { - "192.168.2.30", "255.255.255.0", NULL, "192.168.2.1", "fw0", 25, NULL + "192.168.2.30", "255.255.255.0", NULL, "192.168.2.1", "fw0", 25, NULL }; struct ipv4_service_contents fw0_21 = { - "192.168.3.30", "255.255.255.0", NULL, "192.168.3.1", "fw0", 21, NULL + "192.168.3.30", "255.255.255.0", NULL, "192.168.3.1", "fw0", 21, NULL }; struct ipv4_service_contents ppp0_0_1 = { - "17.219.156.22", NULL, "17.219.156.1", "17.219.156.1", "ppp0", 0, NULL + "17.219.156.22", NULL, "17.219.156.1", "17.219.156.1", "ppp0", 0, NULL }; struct ipv4_service_contents en0_test6 = { @@ -4337,23 +5274,23 @@ struct ipv4_service_contents en2_test7 = { "17.255.98.164", "255.255.240.0", NULL, "17.255.96.1", "en2", 1, NULL }; struct ipv4_service_contents fw0_test6_and_7 = { - "169.254.11.33", "255.255.0.0", NULL, NULL, "fw0", UINT_MAX, NULL + "169.254.11.33", "255.255.0.0", NULL, NULL, "fw0", 0x0ffffff, NULL }; struct ipv4_service_contents en0_10_last = { - "10.0.0.10", "255.255.255.0", NULL, "10.0.0.1", "en0", 10, &kSCValNetServicePrimaryRankLast + "10.0.0.10", "255.255.255.0", NULL, "10.0.0.1", "en0", 10, &kSCValNetServicePrimaryRankLast }; struct ipv4_service_contents en0_10_never = { - "10.0.0.10", "255.255.255.0", NULL, "10.0.0.1", "en0", 10, &kSCValNetServicePrimaryRankNever + "10.0.0.10", "255.255.255.0", NULL, "10.0.0.1", "en0", 10, &kSCValNetServicePrimaryRankNever }; struct ipv4_service_contents en1_20_first = { - "10.0.0.20", "255.255.255.0", NULL, "10.0.0.1", "en1", 20, &kSCValNetServicePrimaryRankFirst + "10.0.0.20", "255.255.255.0", NULL, "10.0.0.1", "en1", 20, &kSCValNetServicePrimaryRankFirst }; struct ipv4_service_contents en1_20_never = { - "10.0.0.20", "255.255.255.0", NULL, "10.0.0.1", "en1", 20, &kSCValNetServicePrimaryRankNever + "10.0.0.20", "255.255.255.0", NULL, "10.0.0.1", "en1", 20, &kSCValNetServicePrimaryRankNever }; struct ipv4_service_contents * test1[] = { @@ -4551,6 +5488,19 @@ make_IPv4RouteList(struct ipv4_service_contents * * this_test) fprintf(stderr, "IPv4RouteListCreateWithDictionary failed\n"); exit(1); } + + (*scan_test)->rank = RankMake((*scan_test)->rank, kRankAssertionDefault); + + if ((*scan_test)->primaryRank != NULL) { + (*scan_test)->rank = RankMake((*scan_test)->rank, + PrimaryRankGetRankAssertion(*(*scan_test)->primaryRank)); + } + + if ((*scan_test)->router == NULL) { + (*scan_test)->rank = RankMake((*scan_test)->rank, + PrimaryRankGetRankAssertion(kSCValNetServicePrimaryRankLast)); + } + ret = IPv4RouteListAddRouteList(ret, 1, r, (*scan_test)->rank); if (r != routes) { free(r); @@ -4602,6 +5552,13 @@ run_test(const char * name, struct ipv4_service_contents * * this_test) CFRelease(descr); } + (*scan_test)->rank = RankMake((*scan_test)->rank, kRankAssertionDefault); + + if ((*scan_test)->primaryRank != NULL) { + (*scan_test)->rank = RankMake((*scan_test)->rank, + PrimaryRankGetRankAssertion(*(*scan_test)->primaryRank)); + } + routes1 = IPv4RouteListAddRouteList(routes1, 1, r, (*scan_test)->rank); if (r != routes) { free(r); @@ -4637,6 +5594,11 @@ run_test(const char * name, struct ipv4_service_contents * * this_test) SCLog(TRUE, LOG_NOTICE, CFSTR("test: Adding %@"), descr); CFRelease(descr); } + if ((*scan_test)->primaryRank != NULL) { + (*scan_test)->rank = RankMake((*scan_test)->rank, + PrimaryRankGetRankAssertion(*(*scan_test)->primaryRank)); + } + routes2 = IPv4RouteListAddRouteList(routes2, 1, r, (*scan_test)->rank); if (r != routes) { free(r); @@ -4694,12 +5656,10 @@ compare_callback(IPv4RouteListApplyCommand cmd, IPv4RouteRef route, void * arg) case kIPv4RouteListAddRouteCommand: printf("Add new[%ld] = ", route - context->new->list); IPv4RoutePrint(route); - printf("\n"); break; case kIPv4RouteListRemoveRouteCommand: printf("Remove old[%ld] = ", route - context->old->list); IPv4RoutePrint(route); - printf("\n"); break; default: break; @@ -4713,7 +5673,7 @@ compare_tests(struct ipv4_service_contents * * old_test, { IPv4RouteListRef new_routes; IPv4RouteListRef old_routes; - compare_context_t context; + compare_context_t context; old_routes = make_IPv4RouteList(old_test); new_routes = make_IPv4RouteList(new_test); diff --git a/Plugins/IPMonitor/proxy-configuration.c b/Plugins/IPMonitor/proxy-configuration.c index 827b99f..76d60fa 100644 --- a/Plugins/IPMonitor/proxy-configuration.c +++ b/Plugins/IPMonitor/proxy-configuration.c @@ -46,7 +46,7 @@ #define ORDER_KEY CFSTR("__ORDER__") -static CFBooleanRef S_proxies_follow_dns = NULL; +CFBooleanRef G_supplemental_proxies_follow_dns = NULL; static void @@ -67,7 +67,7 @@ add_proxy(CFMutableArrayRef proxies, CFMutableDictionaryRef proxy) } } - order = CFNumberCreate(NULL, kCFNumberIntType, &n_proxies); + order = CFNumberCreate(NULL, kCFNumberCFIndexType, &n_proxies); CFDictionarySetValue(proxy, ORDER_KEY, order); CFRelease(order); @@ -191,7 +191,7 @@ add_supplemental_proxies(CFMutableArrayRef proxies, CFDictionaryRef services, CF continue; } - if ((S_proxies_follow_dns != NULL) && CFBooleanGetValue(S_proxies_follow_dns)) { + if ((G_supplemental_proxies_follow_dns != NULL) && CFBooleanGetValue(G_supplemental_proxies_follow_dns)) { CFDictionaryRef dns; CFArrayRef matchDomains; CFArrayRef matchOrders; @@ -545,7 +545,7 @@ compareDomain(const void *val1, const void *val2, void *context) __private_extern__ -CFDictionaryRef +CF_RETURNS_RETAINED CFDictionaryRef proxy_configuration_update(CFDictionaryRef defaultProxy, CFDictionaryRef services, CFArrayRef serviceOrder) @@ -558,10 +558,6 @@ proxy_configuration_update(CFDictionaryRef defaultProxy, CFDictionaryRef proxy; CFMutableArrayRef proxies; - SCLog(TRUE, LOG_DEBUG, CFSTR("defaultProxy : %@"), defaultProxy ? defaultProxy : (CFTypeRef)CFSTR("NULL")); - SCLog(TRUE, LOG_DEBUG, CFSTR("services : %@"), services ? services : (CFTypeRef)CFSTR("NULL")); - SCLog(TRUE, LOG_DEBUG, CFSTR("serviceOrder : %@"), serviceOrder ? serviceOrder : (CFTypeRef)CFSTR("NULL")); - // establish full list of proxies proxies = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); @@ -672,14 +668,18 @@ proxy_configuration_init(CFBundleRef bundle) dict = CFBundleGetInfoDictionary(bundle); if (isA_CFDictionary(dict)) { - S_proxies_follow_dns = CFDictionaryGetValue(dict, CFSTR("SupplementalProxiesFollowSupplementalDNS")); - S_proxies_follow_dns = isA_CFBoolean(S_proxies_follow_dns); + G_supplemental_proxies_follow_dns = CFDictionaryGetValue(dict, CFSTR("SupplementalProxiesFollowSupplementalDNS")); + G_supplemental_proxies_follow_dns = isA_CFBoolean(G_supplemental_proxies_follow_dns); } return; } +#pragma mark - +#pragma mark Standalone test code + + #ifdef MAIN static void diff --git a/Plugins/IPMonitor/proxy-configuration.h b/Plugins/IPMonitor/proxy-configuration.h index c03d9e4..fbb233c 100644 --- a/Plugins/IPMonitor/proxy-configuration.h +++ b/Plugins/IPMonitor/proxy-configuration.h @@ -28,14 +28,22 @@ #include #include + +CFBooleanRef G_supplemental_proxies_follow_dns; + + __BEGIN_DECLS -void proxy_configuration_init (CFBundleRef bundle); +__private_extern__ +void +proxy_configuration_init (CFBundleRef bundle); -CFDictionaryRef proxy_configuration_update (CFDictionaryRef defaultProxy, - CFDictionaryRef services, - CFArrayRef serviceOrder); +__private_extern__ +CF_RETURNS_RETAINED CFDictionaryRef +proxy_configuration_update (CFDictionaryRef defaultProxy, + CFDictionaryRef services, + CFArrayRef serviceOrder); __END_DECLS diff --git a/Plugins/IPMonitor/set-hostname.c b/Plugins/IPMonitor/set-hostname.c index 8d80870..6ebcafd 100644 --- a/Plugins/IPMonitor/set-hostname.c +++ b/Plugins/IPMonitor/set-hostname.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2010 Apple Inc. All rights reserved. + * Copyright (c) 2004-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -53,6 +53,7 @@ static Boolean _verbose = FALSE; #define HOSTNAME_NOTIFY_KEY "com.apple.system.hostname" +CFStringRef copy_dhcp_hostname(CFStringRef serviceID); static void set_hostname(CFStringRef hostname) @@ -308,31 +309,6 @@ copy_primary_ip(SCDynamicStoreRef store, CFStringRef serviceID) return address; } - -#define DHCP_OPTION_HOSTNAME 12 - -static CFStringRef -copy_dhcp_name(SCDynamicStoreRef store, CFStringRef serviceID) -{ - CFDictionaryRef info; - CFStringRef name = NULL; - - info = SCDynamicStoreCopyDHCPInfo(store, serviceID); - if (info != NULL) { - CFDataRef data; - - data = DHCPInfoGetOptionData(info, DHCP_OPTION_HOSTNAME); - if (data != NULL) { - name = CFStringCreateFromExternalRepresentation(NULL, data, kCFStringEncodingUTF8); - } - - CFRelease(info); - } - - return name; -} - - static void reverseDNSComplete(int32_t status, char *host, char *serv, void *context) { @@ -472,50 +448,28 @@ getnameinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, voi static void start_dns_query(SCDynamicStoreRef store, CFStringRef address) { - char addr[64]; + union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } addr; + char buf[64]; SCNetworkReachabilityFlags flags; Boolean haveDNS; Boolean ok; - struct sockaddr *sa; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - if (_SC_cfstring_to_cstring(address, addr, sizeof(addr), kCFStringEncodingASCII) == NULL) { + if (_SC_cfstring_to_cstring(address, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) { SCLog(TRUE, LOG_ERR, CFSTR("could not convert [primary] address")); return; } - bzero(&sin, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - - bzero(&sin6, sizeof(sin6)); - sin6.sin6_len = sizeof(sin6); - sin6.sin6_family = AF_INET6; - - if (inet_aton(addr, &sin.sin_addr) == 1) { - /* - * if IPv4 address - */ - sa = (struct sockaddr *)&sin; - } else if (inet_pton(AF_INET6, addr, &sin6.sin6_addr) == 1) { - /* - * if IPv6 address - */ - char *p; - - p = strchr(addr, '%'); - if (p != NULL) { - sin6.sin6_scope_id = if_nametoindex(p + 1); - } - - sa = (struct sockaddr *)&sin6; - } else { - goto done; + if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) { + /* if not an IP[v6] address */ + SCLog(TRUE, LOG_ERR, CFSTR("could not parse [primary] address")); + return; } - - ok = _SC_checkResolverReachabilityByAddress(&store, &flags, &haveDNS, sa); + ok = _SC_checkResolverReachabilityByAddress(&store, &flags, &haveDNS, &addr.sa); if (ok) { if (!(flags & kSCNetworkReachabilityFlagsReachable) || (flags & kSCNetworkReachabilityFlagsConnectionRequired)) { @@ -538,8 +492,8 @@ start_dns_query(SCDynamicStoreRef store, CFStringRef address) (void) gettimeofday(&dnsQueryStart, NULL); error = getnameinfo_async_start(&mp, - sa, - sa->sa_len, + &addr.sa, + addr.sa.sa_len, NI_NAMEREQD, // flags reverseDNSComplete, NULL); @@ -612,7 +566,7 @@ update_hostname(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) // get DHCP provided name, if available - hostname = copy_dhcp_name(store, serviceID); + hostname = copy_dhcp_hostname(serviceID); if (hostname != NULL) { SCLog(TRUE, LOG_INFO, CFSTR("hostname (DHCP) = %@"), hostname); set_hostname(hostname); diff --git a/Plugins/IPMonitor/set-hostname.h b/Plugins/IPMonitor/set-hostname.h index 109779d..3315cce 100644 --- a/Plugins/IPMonitor/set-hostname.h +++ b/Plugins/IPMonitor/set-hostname.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2006, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -29,6 +29,7 @@ __BEGIN_DECLS +__private_extern__ void load_hostname (Boolean verbose); __END_DECLS diff --git a/Plugins/IPMonitor/smb-configuration.c b/Plugins/IPMonitor/smb-configuration.c index 3325efc..8c06cd6 100644 --- a/Plugins/IPMonitor/smb-configuration.c +++ b/Plugins/IPMonitor/smb-configuration.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2010 Apple Inc. All rights reserved. + * Copyright (c) 2006-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -645,49 +645,28 @@ getnameinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, voi static Boolean start_dns_query(SCDynamicStoreRef store, CFStringRef address) { - char addr[64]; + union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } addr; + char buf[64]; SCNetworkReachabilityFlags flags; Boolean haveDNS; Boolean ok = FALSE; - struct sockaddr *sa; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; - if (_SC_cfstring_to_cstring(address, addr, sizeof(addr), kCFStringEncodingASCII) == NULL) { + if (_SC_cfstring_to_cstring(address, buf, sizeof(buf), kCFStringEncodingASCII) == NULL) { SCLog(TRUE, LOG_ERR, CFSTR("could not convert [primary] address")); return FALSE; } - bzero(&sin, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - - bzero(&sin6, sizeof(sin6)); - sin6.sin6_len = sizeof(sin6); - sin6.sin6_family = AF_INET6; - - if (inet_aton(addr, &sin.sin_addr) == 1) { - /* - * if IPv4 address - */ - sa = (struct sockaddr *)&sin; - } else if (inet_pton(AF_INET6, addr, &sin6.sin6_addr) == 1) { - /* - * if IPv6 address - */ - char *p; - - p = strchr(addr, '%'); - if (p != NULL) { - sin6.sin6_scope_id = if_nametoindex(p + 1); - } - - sa = (struct sockaddr *)&sin6; - } else { - goto done; + if (_SC_string_to_sockaddr(buf, AF_UNSPEC, (void *)&addr, sizeof(addr)) == NULL) { + /* if not an IP[v6] address */ + SCLog(TRUE, LOG_ERR, CFSTR("could not parse [primary] address")); + return FALSE; } - ok = _SC_checkResolverReachabilityByAddress(&store, &flags, &haveDNS, sa); + ok = _SC_checkResolverReachabilityByAddress(&store, &flags, &haveDNS, &addr.sa); if (ok) { if (!(flags & kSCNetworkReachabilityFlagsReachable) || (flags & kSCNetworkReachabilityFlagsConnectionRequired)) { @@ -710,8 +689,8 @@ start_dns_query(SCDynamicStoreRef store, CFStringRef address) (void) gettimeofday(&dnsQueryStart, NULL); error = getnameinfo_async_start(&mp, - sa, - sa->sa_len, + &addr.sa, + addr.sa.sa_len, NI_NAMEREQD, // flags reverseDNSComplete, (void *)store); diff --git a/Plugins/IPMonitor/smb-configuration.h b/Plugins/IPMonitor/smb-configuration.h index 46ece86..d1fdf3a 100644 --- a/Plugins/IPMonitor/smb-configuration.h +++ b/Plugins/IPMonitor/smb-configuration.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2006, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,6 +28,7 @@ __BEGIN_DECLS +__private_extern__ void load_smb_configuration (Boolean verbose); __END_DECLS diff --git a/Plugins/IPMonitor/test_ipv4_routelist_reference.txt b/Plugins/IPMonitor/test_ipv4_routelist_reference.txt index 6698c5b..410103d 100644 --- a/Plugins/IPMonitor/test_ipv4_routelist_reference.txt +++ b/Plugins/IPMonitor/test_ipv4_routelist_reference.txt @@ -758,8 +758,8 @@ Old Routes = = { 3. Dest 10.0.0.0 Mask 255.255.255.0 Gate 10.0.0.20 Ifp en1 Ifa 10.0.0.20 [never] [SCOPED] } New Routes = = { - 0. Dest 0.0.0.0 Mask 0.0.0.0 Gate 10.0.0.1 Ifp en1 Ifa 10.0.0.20 [never] [SCOPED*] - 1. Dest 10.0.0.0 Mask 255.255.255.0 Gate 10.0.0.20 Ifp en1 Ifa 10.0.0.20 [never] [SCOPED*] + 0. Dest 0.0.0.0 Mask 0.0.0.0 Gate 10.0.0.1 Ifp en1 Ifa 10.0.0.20 [never] [SCOPED] + 1. Dest 10.0.0.0 Mask 255.255.255.0 Gate 10.0.0.20 Ifp en1 Ifa 10.0.0.20 [never] [SCOPED] } Remove old[0] = Dest 0.0.0.0 Mask 0.0.0.0 Gate 10.0.0.1 Ifp en0 Ifa 10.0.0.10 Remove old[2] = Dest 10.0.0.0 Mask 255.255.255.0 Gate 10.0.0.10 Ifp en0 Ifa 10.0.0.10 diff --git a/Plugins/InterfaceNamer/Info.plist b/Plugins/InterfaceNamer/Info.plist index d2650f6..5efd372 100644 --- a/Plugins/InterfaceNamer/Info.plist +++ b/Plugins/InterfaceNamer/Info.plist @@ -17,10 +17,10 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.11.3 + 1.12 CFBundleSignature ???? CFBundleVersion - 1.11 + 1.12 diff --git a/Plugins/InterfaceNamer/ifnamer.c b/Plugins/InterfaceNamer/ifnamer.c index ae4d87a..639f9ae 100644 --- a/Plugins/InterfaceNamer/ifnamer.c +++ b/Plugins/InterfaceNamer/ifnamer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2011 Apple Inc. All rights reserved. + * Copyright (c) 2001-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -72,6 +72,10 @@ #include #include #include +#include +#include + +#include #include @@ -149,12 +153,6 @@ static CFMutableArrayRef S_iflist = NULL; */ static io_iterator_t S_iter = MACH_PORT_NULL; -/* - * S_model - * Hardware model for this network configuration. - */ -static CFStringRef S_model = NULL; - /* * S_notify * notification object for receiving IOKit notifications of @@ -207,6 +205,14 @@ static CFRunLoopTimerRef S_timer = NULL; static double S_stack_timeout = WAIT_STACK_TIMEOUT_DEFAULT; static double S_quiet_timeout = WAIT_QUIET_TIMEOUT_DEFAULT; +#if !TARGET_OS_EMBEDDED +/* + * S_vproc_transaction + * The vproc transaction used to keep launchd from sending us + * a SIGKILL before we've had a chance to set the platform UUID + */ +vproc_transaction_t S_vproc_transaction = NULL; +#endif // !TARGET_OS_EMBEDDED /* * Virtual network interface configuration @@ -234,34 +240,8 @@ addTimestamp(CFMutableDictionaryRef dict, CFStringRef key) } #define INTERFACES CFSTR("Interfaces") -#define MODEL CFSTR("Model") #define NETWORK_INTERFACES_PREFS CFSTR("NetworkInterfaces.plist") -static CFStringRef -hw_model() -{ - if (S_model == NULL) { - char hwModel[64]; - int mib[] = { CTL_HW, HW_MODEL }; - size_t n = sizeof(hwModel); - int ret; - - // get HW model name - bzero(&hwModel, sizeof(hwModel)); - ret = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &hwModel, &n, NULL, 0); - if (ret != 0) { - SCLog(TRUE, LOG_ERR, CFSTR("sysctl() CTL_HW/HW_MODEL failed: %s"), strerror(errno)); - return NULL; - } - hwModel[sizeof(hwModel) - 1] = '\0'; - - S_model = CFStringCreateWithCString(NULL, hwModel, kCFStringEncodingASCII); - } - - return S_model; - -} - static CFComparisonResult if_unit_compare(const void *val1, const void *val2, void *context) { @@ -327,7 +307,7 @@ writeInterfaceList(CFArrayRef if_list) } old_model = SCPreferencesGetValue(prefs, MODEL); - new_model = hw_model(); + new_model = _SC_hw_model(); if ((new_model != NULL) && !_SC_CFEqual(old_model, new_model)) { // if new hardware if ((old_model != NULL) && (cur_list != NULL)) { @@ -385,7 +365,7 @@ done: return; } -static CFMutableArrayRef +static CF_RETURNS_RETAINED CFMutableArrayRef readInterfaceList() { CFArrayRef if_list; @@ -408,7 +388,7 @@ readInterfaceList() if (old_model != NULL) { CFStringRef new_model; - new_model = hw_model(); + new_model = _SC_hw_model(); if (!_SC_CFEqual(old_model, new_model)) { // if interface list was created on other hardware if_list = NULL; @@ -439,7 +419,7 @@ readInterfaceList() return (plist); } -static CFMutableArrayRef +static CF_RETURNS_RETAINED CFMutableArrayRef previouslyActiveInterfaces() { CFMutableArrayRef active; @@ -475,22 +455,16 @@ static void updateStore(void) { CFStringRef key; - SCDynamicStoreRef store; - - store = SCDynamicStoreCreate(NULL, CFSTR(MY_PLUGIN_NAME), NULL, NULL); - if (store == NULL) { - return; - } key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@" MY_PLUGIN_NAME), kSCDynamicStoreDomainPlugin); - (void)SCDynamicStoreSetValue(store, key, S_state); + (void)SCDynamicStoreSetValue(NULL, key, S_state); CFRelease(key); - CFRelease(store); return; } +#if !TARGET_OS_IPHONE static void updateBondInterfaceConfiguration(SCPreferencesRef prefs) { @@ -519,6 +493,7 @@ updateBondInterfaceConfiguration(SCPreferencesRef prefs) return; } +#endif // !TARGET_OS_IPHONE static void updateBridgeInterfaceConfiguration(SCPreferencesRef prefs) @@ -604,7 +579,9 @@ updateVirtualNetworkInterfaceConfiguration(SCPreferencesRef prefs, } } +#if !TARGET_OS_IPHONE updateBondInterfaceConfiguration (prefs); +#endif // !TARGET_OS_IPHONE updateBridgeInterfaceConfiguration(prefs); updateVLANInterfaceConfiguration (prefs); @@ -752,7 +729,7 @@ typedef struct { CFMutableArrayRef matches; } matchContext, *matchContextRef; -static CFDictionaryRef +static CF_RETURNS_RETAINED CFDictionaryRef thinInterfaceInfo(CFDictionaryRef info) { CFNumberRef num; @@ -1108,6 +1085,23 @@ getHighestUnitForType(CFNumberRef if_type) return (ret_unit); } +/* + * Function: ensureInterfaceHasUnit + * Purpose: + * Ensure that the SCNetworkInterfaceRef has a unit number. If it doesn't, + * release the interface and return NULL. + */ +static SCNetworkInterfaceRef +ensureInterfaceHasUnit(SCNetworkInterfaceRef net_if) +{ + if (net_if != NULL + && _SCNetworkInterfaceGetIOInterfaceUnit(net_if) == NULL) { + CFRelease(net_if); + net_if = NULL; + } + return (net_if); +} + #ifdef USE_REGISTRY_ENTRY_ID static kern_return_t registerInterfaceWithIORegistryEntryID(io_connect_t connect, @@ -1136,7 +1130,7 @@ registerInterfaceWithIORegistryEntryID(io_connect_t connect, } static SCNetworkInterfaceRef -lookupIORegistryEntryID(uint64_t entryID) +copyInterfaceForIORegistryEntryID(uint64_t entryID) { io_registry_entry_t entry = MACH_PORT_NULL; SCNetworkInterfaceRef interface = NULL; @@ -1187,6 +1181,16 @@ lookupIORegistryEntryID(uint64_t entryID) return (interface); } + +static SCNetworkInterfaceRef +copyNamedInterfaceForIORegistryEntryID(uint64_t entryID) +{ + SCNetworkInterfaceRef net_if; + + net_if = copyInterfaceForIORegistryEntryID(entryID); + return (ensureInterfaceHasUnit(net_if)); +} + #else // USE_REGISTRY_ENTRY_ID /* * Function: registerInterface @@ -1218,7 +1222,7 @@ registerInterfaceWithIOServicePath(io_connect_t connect, } static SCNetworkInterfaceRef -lookupIOKitPath(CFStringRef if_path) +copyInterfaceForIOKitPath(CFStringRef if_path) { io_registry_entry_t entry = MACH_PORT_NULL; SCNetworkInterfaceRef interface = NULL; @@ -1254,6 +1258,16 @@ lookupIOKitPath(CFStringRef if_path) return (interface); } + +static SCNetworkInterfaceRef +copyNamedInterfaceForIOKitPath(CFStringRef if_path) +{ + SCNetworkInterfaceRef net_if; + + net_if = copyInterfaceForIOKitPath(if_path); + return (ensureInterfaceHasUnit(net_if)); +} + #endif // USE_REGISTRY_ENTRY_ID static void @@ -1318,7 +1332,7 @@ nameInterfaces(CFMutableArrayRef if_list) for (i = 0; i < n; i++) { uint64_t entryID; SCNetworkInterfaceRef interface; - Boolean ok = TRUE; + SCNetworkInterfaceRef new_interface; CFStringRef path; CFStringRef str; CFNumberRef type; @@ -1348,6 +1362,8 @@ nameInterfaces(CFMutableArrayRef if_list) && lookupInterfaceByAddress(S_prev_active_list, interface, &where) != NULL) { CFArrayRemoveValueAtIndex(S_prev_active_list, where); } + + replaceInterface(interface); } else { CFDictionaryRef dbdict; boolean_t is_builtin; @@ -1434,14 +1450,16 @@ nameInterfaces(CFMutableArrayRef if_list) unit, (dbdict == NULL) ? kIONetworkStackRegisterInterfaceWithLowestUnit : kIONetworkStackRegisterInterfaceWithUnit); + new_interface = copyNamedInterfaceForIORegistryEntryID(entryID); #else // USE_REGISTRY_ENTRY_ID kr = registerInterfaceWithIOServicePath(S_connect, path, unit, (dbdict == NULL) ? kRegisterInterface : kRegisterInterfaceWithFixedUnit); + new_interface = copyNamedInterfaceForIOKitPath(path); #endif // USE_REGISTRY_ENTRY_ID - if (kr != KERN_SUCCESS) { + if (new_interface == NULL) { const char *signature; signature = (dbdict == NULL) ? "failed to name new interface" @@ -1475,10 +1493,9 @@ nameInterfaces(CFMutableArrayRef if_list) usleep(50 * 1000); // sleep 50ms between attempts goto retry; } - - ok = FALSE; // ... and don't update the database - } else { - SCNetworkInterfaceRef new_interface; + } + else { + CFNumberRef new_unit; if (retries > 0) { SCLog(TRUE, LOG_ERR, @@ -1511,51 +1528,37 @@ nameInterfaces(CFMutableArrayRef if_list) #endif // SHOW_NAMING_FAILURE } -#ifdef USE_REGISTRY_ENTRY_ID - new_interface = lookupIORegistryEntryID(entryID); -#else // USE_REGISTRY_ENTRY_ID - new_interface = lookupIOKitPath(path); -#endif // USE_REGISTRY_ENTRY_ID - if (new_interface != NULL) { - CFNumberRef new_unit; - - new_unit = _SCNetworkInterfaceGetIOInterfaceUnit(new_interface); - if (CFEqual(unit, new_unit) == FALSE) { - SCLog(S_debug, LOG_INFO, - CFSTR(MY_PLUGIN_NAME - ": interface type %@ assigned " - "unit %@ instead of %@"), - type, new_unit, unit); - } - if (S_debug) { - displayInterface(new_interface); - } + new_unit = _SCNetworkInterfaceGetIOInterfaceUnit(new_interface); + if (CFEqual(unit, new_unit) == FALSE) { + SCLog(S_debug, LOG_INFO, + CFSTR(MY_PLUGIN_NAME + ": interface type %@ assigned " + "unit %@ instead of %@"), + type, new_unit, unit); + } + if (S_debug) { + displayInterface(new_interface); + } - // update if_list (with the interface name & unit) - CFArraySetValueAtIndex(if_list, i, new_interface); - CFRelease(new_interface); - interface = new_interface; // if_list holds the reference + // update if_list (with the interface name & unit) + CFArraySetValueAtIndex(if_list, i, new_interface); + CFRelease(new_interface); + interface = new_interface; // if_list holds the reference - if (is_builtin && (S_prev_active_list != NULL)) { - CFIndex where; + if (is_builtin && (S_prev_active_list != NULL)) { + CFIndex where; - // update the list of [built-in] interfaces that were previously named - if (lookupInterfaceByUnit(S_prev_active_list, interface, &where) != NULL) { - SCLog(S_debug, LOG_INFO, - CFSTR(MY_PLUGIN_NAME ": and updated database (new address)")); - CFArrayRemoveValueAtIndex(S_prev_active_list, where); - } + // update the list of [built-in] interfaces that were previously named + if (lookupInterfaceByUnit(S_prev_active_list, interface, &where) != NULL) { + SCLog(S_debug, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": and updated database (new address)")); + CFArrayRemoveValueAtIndex(S_prev_active_list, where); } } + replaceInterface(interface); } - CFRelease(unit); } - - // update db - if (ok) { - replaceInterface(interface); - } } return; } @@ -1647,6 +1650,7 @@ updateInterfaces() return; } +#if !TARGET_OS_EMBEDDED static CFComparisonResult compareMacAddress(const void *val1, const void *val2, void *context) { @@ -1669,29 +1673,14 @@ compareMacAddress(const void *val1, const void *val2, void *context) return res; } -#ifndef kIOPlatformUUIDKey -#define kIOPlatformUUIDKey "IOPlatformUUID" -#endif -static void -updatePlatformUUID() +static CFStringRef +copyEthernetUUID() { CFDataRef addr; CFMutableArrayRef addrs = NULL; - CFStringRef guid; + CFStringRef guid = NULL; CFIndex i; CFIndex n; - io_registry_entry_t platform; - - platform = IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreePlane ":/"); - if (platform == MACH_PORT_NULL) { - return; - } - - guid = IORegistryEntryCreateCFProperty(platform, CFSTR(kIOPlatformUUIDKey), NULL, 0); - if (guid != NULL) { - // if GUID already defined - goto done; - } addrs = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); n = (S_dblist != NULL) ? CFArrayGetCount(S_dblist) : 0; @@ -1738,8 +1727,7 @@ updatePlatformUUID() n = CFArrayGetCount(addrs); switch (n) { case 0 : - SCLog(TRUE, LOG_ERR, - CFSTR(MY_PLUGIN_NAME ": no network interfaces, could not update platform UUID")); + // if no network interfaces break; default : // sort by MAC address @@ -1749,7 +1737,6 @@ updatePlatformUUID() case 1 : { CFUUIDBytes bytes = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - kern_return_t kr; CFUUIDRef uuid; // set GUID @@ -1762,28 +1749,74 @@ updatePlatformUUID() CFRelease(uuid); SCLog(TRUE, LOG_INFO, - CFSTR(MY_PLUGIN_NAME ": setting platform UUID = %@"), + CFSTR(MY_PLUGIN_NAME ": setting platform UUID [MAC] = %@"), guid); - kr = IORegistryEntrySetCFProperty(platform, CFSTR(kIOPlatformUUIDKey), guid); - if (kr != KERN_SUCCESS) { - SCLog(TRUE, LOG_ERR, - CFSTR(MY_PLUGIN_NAME ": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"), - kr); - } - - addTimestamp(S_state, CFSTR("*PLATFORM-UUID*")); - updateStore(); break; } } + if (addrs != NULL) CFRelease(addrs); + return guid; +} + +#ifndef kIOPlatformUUIDKey +#define kIOPlatformUUIDKey "IOPlatformUUID" +#endif +static void +updatePlatformUUID() +{ + CFStringRef guid = NULL; + kern_return_t kr; + io_registry_entry_t platform; + + platform = IORegistryEntryFromPath(kIOMasterPortDefault, kIODeviceTreePlane ":/"); + if (platform == MACH_PORT_NULL) { + goto done; + } + + guid = IORegistryEntryCreateCFProperty(platform, CFSTR(kIOPlatformUUIDKey), NULL, 0); + if (guid != NULL) { + // if GUID already defined + goto done; + } + + guid = copyEthernetUUID(); + if (guid == NULL) { + CFUUIDRef uuid; + + uuid = CFUUIDCreate(NULL); + guid = CFUUIDCreateString(NULL, uuid); + CFRelease(uuid); + + SCLog(TRUE, LOG_INFO, + CFSTR(MY_PLUGIN_NAME ": setting platform UUID [random] = %@"), + guid); + } + +if (getenv("DO_NOT_SET_PLATFORM_UUID") == NULL) { + kr = IORegistryEntrySetCFProperty(platform, CFSTR(kIOPlatformUUIDKey), guid); + if (kr != KERN_SUCCESS) { + SCLog(TRUE, LOG_ERR, + CFSTR(MY_PLUGIN_NAME ": IORegistryEntrySetCFProperty(platform UUID) failed, kr=0x%x"), + kr); + } +} + + addTimestamp(S_state, CFSTR("*PLATFORM-UUID*")); + updateStore(); + done : - if (addrs != NULL) CFRelease(addrs); + if (S_vproc_transaction != NULL) { + vproc_transaction_end(NULL, S_vproc_transaction); + S_vproc_transaction = NULL; + } + if (platform != MACH_PORT_NULL) IOObjectRelease(platform); if (guid != NULL) CFRelease(guid); return; } +#endif // !TARGET_OS_EMBEDDED static void interfaceArrivalCallback(void *refcon, io_iterator_t iter) @@ -1900,7 +1933,9 @@ quietCallback(void *refcon, // grab (and name) any additional interfaces. interfaceArrivalCallback((void *)S_notify, S_iter); +#if !TARGET_OS_EMBEDDED updatePlatformUUID(); +#endif // !TARGET_OS_EMBEDDED return; } @@ -1984,6 +2019,7 @@ iterateRegistryBusy(io_iterator_t iterator, CFArrayRef nodes, CFMutableStringRef (state & kIOServiceRegisteredState) ? "" : "!registered, ", (state & kIOServiceMatchedState) ? "" : "!matched, ", (state & kIOServiceInactiveState) ? "inactive, " : "", + busy_state, accumulated_busy_time / kMillisecondScale); CFRelease(path); } @@ -2014,7 +2050,7 @@ iterateRegistryBusy(io_iterator_t iterator, CFArrayRef nodes, CFMutableStringRef return; } -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef captureBusy() { int count = 0; @@ -2275,9 +2311,7 @@ exec_InterfaceNamer(void *arg) CFBundleRef bundle = (CFBundleRef)arg; CFDictionaryRef dict; -#if !TARGET_OS_EMBEDDED pthread_setname_np(MY_PLUGIN_NAME " thread"); -#endif // !TARGET_OS_EMBEDDED dict = CFBundleGetInfoDictionary(bundle); if (isA_CFDictionary(dict)) { @@ -2316,6 +2350,12 @@ exec_InterfaceNamer(void *arg) goto error; } +#if !TARGET_OS_EMBEDDED + // keep launchd from SIGKILL'ing us until after the platform-uuid has + // been updated + S_vproc_transaction = vproc_transaction_begin(NULL); +#endif // !TARGET_OS_EMBEDDED + goto done; error : @@ -2353,10 +2393,8 @@ exec_InterfaceNamer(void *arg) } done : -#if !TARGET_OS_EMBEDDED CFRelease(bundle); CFRunLoopRun(); -#endif // !TARGET_OS_EMBEDDED return NULL; } @@ -2365,27 +2403,21 @@ __private_extern__ void load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose) { + pthread_attr_t tattr; + pthread_t tid; + if (bundleVerbose) { S_debug = TRUE; } -#if !TARGET_OS_EMBEDDED - { - pthread_attr_t tattr; - pthread_t tid; + CFRetain(bundle); // released in exec_InterfaceNamer - CFRetain(bundle); // released in exec_InterfaceNamer - - pthread_attr_init(&tattr); - pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM); - pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); -// pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack - pthread_create(&tid, &tattr, exec_InterfaceNamer, bundle); - pthread_attr_destroy(&tattr); - } -#else // !TARGET_OS_EMBEDDED - (void)exec_InterfaceNamer(bundle); -#endif // !TARGET_OS_EMBEDDED + pthread_attr_init(&tattr); + pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM); + pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); +// pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack + pthread_create(&tid, &tattr, exec_InterfaceNamer, bundle); + pthread_attr_destroy(&tattr); return; } @@ -2396,11 +2428,18 @@ load_InterfaceNamer(CFBundleRef bundle, Boolean bundleVerbose) int main(int argc, char ** argv) { + CFBundleRef bundle; + _sc_log = FALSE; _sc_verbose = (argc > 1) ? TRUE : FALSE; - load_InterfaceNamer(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE); - CFRunLoopRun(); + S_debug = _sc_verbose; + + bundle = CFBundleGetMainBundle(); + CFRetain(bundle); // released in exec_InterfaceNamer + + (void)exec_InterfaceNamer(); + /* not reached */ exit(0); return 0; @@ -2411,6 +2450,7 @@ main(int argc, char ** argv) int main(int argc, char ** argv) { + CFStringRef guid; CFArrayRef interfaces; _sc_log = FALSE; @@ -2434,6 +2474,11 @@ main(int argc, char ** argv) } CFRelease(interfaces); } + + guid = copyEthernetUUID(); + SCPrint(TRUE, stdout, CFSTR("copyEthernetUUID() = %@\n"), (guid != NULL) ? guid : CFSTR("NULL")); + if (guid != NULL) CFRelease(guid); + updatePlatformUUID(); CFRelease(S_dblist); exit(0); diff --git a/Plugins/KernelEventMonitor/Info.plist b/Plugins/KernelEventMonitor/Info.plist index 2b26025..5473f52 100644 --- a/Plugins/KernelEventMonitor/Info.plist +++ b/Plugins/KernelEventMonitor/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.11.3 + 1.12 CFBundleSignature ???? CFBundleVersion - 1.11 + 1.12 Requires com.apple.SystemConfiguration.InterfaceNamer diff --git a/Plugins/KernelEventMonitor/ev_dlil.c b/Plugins/KernelEventMonitor/ev_dlil.c index 82487f3..0830019 100644 --- a/Plugins/KernelEventMonitor/ev_dlil.c +++ b/Plugins/KernelEventMonitor/ev_dlil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2006, 2009 Apple Inc. All rights reserved. + * Copyright (c) 2002-2006, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -32,6 +32,10 @@ #include "cache.h" #include "ev_dlil.h" +#ifndef kSCEntNetIdleRoute +#define kSCEntNetIdleRoute CFSTR("IdleRoute") +#endif /* kSCEntNetIdleRoute */ + static CFStringRef create_interface_key(const char * if_name) { @@ -103,6 +107,88 @@ interface_update_status(const char *if_name, CFBooleanRef active, return; } + +#ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED +static CFStringRef +create_linkquality_key(const char * if_name) +{ + CFStringRef interface; + CFStringRef key; + + interface = CFStringCreateWithCString(NULL, if_name, kCFStringEncodingMacRoman); + key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, + kSCDynamicStoreDomainState, + interface, + kSCEntNetLinkQuality); + CFRelease(interface); + return (key); +} + + +__private_extern__ +void +interface_update_quality_metric(const char *if_name, + int quality) +{ + CFStringRef key = NULL; + CFMutableDictionaryRef newDict = NULL; + CFNumberRef linkquality = NULL; + + key = create_linkquality_key(if_name); + newDict = copy_entity(key); + + if (quality != IFNET_LQM_THRESH_UNKNOWN) { + linkquality = CFNumberCreate(NULL, kCFNumberIntType, &quality); + CFDictionarySetValue(newDict, kSCPropNetLinkQuality, linkquality); + CFRelease(linkquality); + } else { + CFDictionaryRemoveValue(newDict, kSCPropNetLinkQuality); + } + + /* update status */ + if (CFDictionaryGetCount(newDict) > 0) { + cache_SCDynamicStoreSetValue(store, key, newDict); + } else { + cache_SCDynamicStoreRemoveValue(store, key); + } + + CFRelease(key); + CFRelease(newDict); + return; +} + + +static +void +link_update_quality_metric(const char *if_name) +{ + struct ifreq ifr; + int quality = IFNET_LQM_THRESH_UNKNOWN; + int sock; + + sock = dgram_socket(AF_INET); + if (sock == -1) { + SCLog(TRUE, LOG_NOTICE, CFSTR("socket_get_link_quality: socket open failed, %s"), strerror(errno)); + goto done; + } + + bzero((char *)&ifr, sizeof(ifr)); + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name); + + if (ioctl(sock, SIOCGIFLINKQUALITYMETRIC, (caddr_t)&ifr) != -1) { + quality = ifr.ifr_link_quality_metric; + } + +done: + interface_update_quality_metric(if_name, quality); + if (sock != -1) + close(sock); + return; + +} +#endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */ + + __private_extern__ void interface_detaching(const char *if_name) @@ -128,6 +214,13 @@ interface_remove(const char *if_name) key = create_interface_key(if_name); cache_SCDynamicStoreRemoveValue(store, key); CFRelease(key); + +#ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED + key = create_linkquality_key(if_name); + cache_SCDynamicStoreRemoveValue(store, key); + CFRelease(key); +#endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */ + return; } @@ -223,6 +316,9 @@ link_add(const char *if_name) } cache_SCDynamicStoreSetValue(store, cacheKey, newDict); link_update_status(if_name, TRUE); +#ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED + link_update_quality_metric(if_name); +#endif /* KEV_DL_LINK_QUALITY_METRIC_CHANGED */ CFRelease(cacheKey); CFRelease(interface); if (newDict) CFRelease(newDict); @@ -284,3 +380,61 @@ link_remove(const char *if_name) return; } + + +#ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT +#define INVALID_SOCKET_REF -1 +static +int +socket_reference_count(const char* if_name) { + struct ifreq ifr; + int ref = INVALID_SOCKET_REF; + int s; + + s = dgram_socket(AF_INET); + if (s == -1) { + return (ref); + } + + bzero((char *)&ifr, sizeof(ifr)); + snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%s", if_name); + + if (ioctl(s, SIOCGIFGETRTREFCNT, (caddr_t)&ifr) != -1) { + ref = ifr.ifr_route_refcnt; + } else { + ref = INVALID_SOCKET_REF; + } + close(s); + return (ref); +} + + +__private_extern__ +void +interface_update_idle_state(const char *if_name) +{ + CFStringRef if_name_cf; + CFStringRef key; + int ref; + + /* We will only update the SCDynamicStore if the idle ref count + * is still 0 */ + ref = socket_reference_count(if_name); + if (ref != 0) { + return; + } + + if_name_cf = CFStringCreateWithCString(NULL, if_name, + kCFStringEncodingASCII); + + key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, + kSCDynamicStoreDomainState, + if_name_cf, + kSCEntNetIdleRoute); + + cache_SCDynamicStoreNotifyValue(store, key); + CFRelease(key); + CFRelease(if_name_cf); + return; +} +#endif // KEV_DL_IF_IDLE_ROUTE_REFCNT diff --git a/Plugins/KernelEventMonitor/ev_dlil.h b/Plugins/KernelEventMonitor/ev_dlil.h index 7e21623..f78ce84 100644 --- a/Plugins/KernelEventMonitor/ev_dlil.h +++ b/Plugins/KernelEventMonitor/ev_dlil.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2004, 2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002, 2004, 2005, 2011 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -34,10 +34,23 @@ __BEGIN_DECLS -void interface_detaching (const char *if_name); -void link_add (const char *if_name); -void link_remove (const char *if_name); -void link_update_status (const char *if_name, boolean_t attach); +__private_extern__ +void interface_detaching (const char *if_name); + +__private_extern__ +void interface_update_idle_state (const char *if_name); + +__private_extern__ +void interface_update_quality_metric (const char *if_name, int quality); + +__private_extern__ +void link_add (const char *if_name); + +__private_extern__ +void link_remove (const char *if_name); + +__private_extern__ +void link_update_status (const char *if_name, boolean_t attach); __END_DECLS diff --git a/Plugins/KernelEventMonitor/ev_ipv4.c b/Plugins/KernelEventMonitor/ev_ipv4.c index 4f1c15f..14e2979 100644 --- a/Plugins/KernelEventMonitor/ev_ipv4.c +++ b/Plugins/KernelEventMonitor/ev_ipv4.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2005, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (c) 2002-2005, 2007, 2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -72,7 +72,7 @@ appendAddress(CFMutableDictionaryRef dict, CFStringRef key, struct in_addr *addr static CFMutableDictionaryRef -getIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs) +copyIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs) { CFDictionaryRef dict = NULL; CFMutableDictionaryRef newDict = NULL; @@ -180,23 +180,28 @@ interface_update_ipv4(struct ifaddrs *ifap, const char *if_name) kSCEntNetIPv4); CFRelease(interface); - newDict = getIF(key, oldIFs, newIFs); + newDict = copyIF(key, oldIFs, newIFs); - sin = (struct sockaddr_in *)ifa->ifa_addr; + /* ALIGN: cast ok, this should be aligned (getifaddrs). */ + sin = (struct sockaddr_in *)(void *)ifa->ifa_addr; appendAddress(newDict, kSCPropNetIPv4Addresses, &sin->sin_addr); if (ifa->ifa_flags & IFF_POINTOPOINT) { struct sockaddr_in *dst; - dst = (struct sockaddr_in *)ifa->ifa_dstaddr; + /* ALIGN: cast ok, this should be aligned (getifaddrs). */ + dst = (struct sockaddr_in *)(void *)ifa->ifa_dstaddr; appendAddress(newDict, kSCPropNetIPv4DestAddresses, &dst->sin_addr); } else { struct sockaddr_in *brd; struct sockaddr_in *msk; - brd = (struct sockaddr_in *)ifa->ifa_broadaddr; - appendAddress(newDict, kSCPropNetIPv4BroadcastAddresses, &brd->sin_addr); - msk = (struct sockaddr_in *)ifa->ifa_netmask; + /* ALIGN: cast ok, this should be aligned (getifaddrs). */ + brd = (struct sockaddr_in *)(void *)ifa->ifa_broadaddr; + appendAddress(newDict, kSCPropNetIPv4BroadcastAddresses,&brd->sin_addr); + + /* ALIGN: cast ok, this should be aligned (getifaddrs). */ + msk = (struct sockaddr_in *)(void *)ifa->ifa_netmask; appendAddress(newDict, kSCPropNetIPv4SubnetMasks, &msk->sin_addr); } @@ -214,7 +219,7 @@ interface_update_ipv4(struct ifaddrs *ifap, const char *if_name) kSCEntNetIPv4); CFRelease(interface); - newDict = getIF(key, oldIFs, newIFs); + newDict = copyIF(key, oldIFs, newIFs); CFDictionarySetValue(newIFs, key, newDict); CFRelease(newDict); diff --git a/Plugins/KernelEventMonitor/ev_ipv4.h b/Plugins/KernelEventMonitor/ev_ipv4.h index 786cf09..0e75b21 100644 --- a/Plugins/KernelEventMonitor/ev_ipv4.h +++ b/Plugins/KernelEventMonitor/ev_ipv4.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2005, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (c) 2002-2005, 2007, 2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -37,12 +37,17 @@ __BEGIN_DECLS +__private_extern__ void interface_update_ipv4 (struct ifaddrs *ifap, const char *if_name); + +__private_extern__ void interface_collision_ipv4(const char *if_name, struct in_addr ip_addr, int hw_len, const void * hw_addr); + #if !TARGET_OS_IPHONE -void port_in_use_ipv4(uint16_t port, pid_t req_pid); +__private_extern__ +void port_in_use_ipv4 (uint16_t port, pid_t req_pid); #endif /* !TARGET_OS_IPHONE */ __END_DECLS diff --git a/Plugins/KernelEventMonitor/ev_ipv6.c b/Plugins/KernelEventMonitor/ev_ipv6.c index 880713a..abe37ff 100644 --- a/Plugins/KernelEventMonitor/ev_ipv6.c +++ b/Plugins/KernelEventMonitor/ev_ipv6.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002-2007 Apple Inc. All rights reserved. + * Copyright (c) 2002-2007, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -185,7 +185,7 @@ appendScopeID(CFMutableDictionaryRef dict, struct sockaddr_in6 *sin6) static CFMutableDictionaryRef -getIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs) +copyIF(CFStringRef key, CFMutableDictionaryRef oldIFs, CFMutableDictionaryRef newIFs) { CFDictionaryRef dict = NULL; CFMutableDictionaryRef newDict = NULL; @@ -308,12 +308,13 @@ interface_update_ipv6(struct ifaddrs *ifap, const char *if_name) kSCEntNetIPv6); CFRelease(interface); - newDict = getIF(key, oldIFs, newIFs); + newDict = copyIF(key, oldIFs, newIFs); - sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; + /* ALIGN: ifa->ifa_addr aligned (getifaddrs), cast ok. */ + sin6 = (struct sockaddr_in6 *)(void *)ifa->ifa_addr; /* XXX: embedded link local addr check */ - if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { + if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) { u_int16_t index; index = sin6->sin6_addr.s6_addr16[1]; @@ -337,17 +338,20 @@ interface_update_ipv6(struct ifaddrs *ifap, const char *if_name) #ifdef NOTYET appendScopeID (newDict, sin6); #endif /* NOTYET */ - appendPrefixLen(newDict, (struct sockaddr_in6 *)ifa->ifa_netmask); + /* ALIGN: ifa should be aligned (from getifaddrs), cast ok. + * appendPrefixLen expect byte alignment */ + appendPrefixLen(newDict, (struct sockaddr_in6 *)(void *)ifa->ifa_netmask); appendFlags (newDict, flags6); if (ifa->ifa_flags & IFF_POINTOPOINT) { struct sockaddr_in6 *dst6; - dst6 = (struct sockaddr_in6 *)ifa->ifa_dstaddr; + /* ALIGN: ifa should be aligned (from getifaddrs), cast ok. */ + dst6 = (struct sockaddr_in6 *)(void *)ifa->ifa_dstaddr; /* XXX: embedded link local addr check */ - if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr)) { + if (IN6_IS_ADDR_LINKLOCAL(&dst6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&dst6->sin6_addr)) { u_int16_t index; index = dst6->sin6_addr.s6_addr16[1]; @@ -376,7 +380,7 @@ interface_update_ipv6(struct ifaddrs *ifap, const char *if_name) kSCEntNetIPv6); CFRelease(interface); - newDict = getIF(key, oldIFs, newIFs); + newDict = copyIF(key, oldIFs, newIFs); CFDictionarySetValue(newIFs, key, newDict); CFRelease(newDict); diff --git a/Plugins/KernelEventMonitor/ev_ipv6.h b/Plugins/KernelEventMonitor/ev_ipv6.h index 23f1ced..4cdd378 100644 --- a/Plugins/KernelEventMonitor/ev_ipv6.h +++ b/Plugins/KernelEventMonitor/ev_ipv6.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2002, 2004, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -36,6 +36,7 @@ __BEGIN_DECLS +__private_extern__ void interface_update_ipv6 (struct ifaddrs *ifap, const char *if_name); __END_DECLS diff --git a/Plugins/KernelEventMonitor/eventmon.c b/Plugins/KernelEventMonitor/eventmon.c index 10792c0..c2cad27 100644 --- a/Plugins/KernelEventMonitor/eventmon.c +++ b/Plugins/KernelEventMonitor/eventmon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2008, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2008, 2010, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -96,7 +96,13 @@ static const char *dlEventName[] = { "KEV_DL_WAKEFLAGS_CHANGED", #ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT "KEV_DL_IF_IDLE_ROUTE_REFCNT", -#endif // KEV_DL_IF_IDLE_ROUTE_REFCNT +#endif +#ifdef KEV_DL_IFCAP_CHANGED + "KEV_DL_IFCAP_CHANGED", +#endif +#ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED + "KEV_DL_LINK_QUALITY_METRIC_CHANGED", +#endif }; static const char *inet6EventName[] = { @@ -109,6 +115,13 @@ static const char *inet6EventName[] = { "KEV_INET6_DEFROUTER" }; +#ifdef KEV_ND6_SUBCLASS +static const char *nd6EventNameString[] = { + "", + "KEV_ND6_RA" +}; +#endif // KEV_ND6_SUBCLASS + __private_extern__ Boolean network_changed = FALSE; __private_extern__ SCDynamicStoreRef store = NULL; __private_extern__ Boolean _verbose = FALSE; @@ -398,6 +411,21 @@ processEvent_Apple_Network(struct kern_event_msg *ev_msg) break; } +#ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT + case KEV_DL_IF_IDLE_ROUTE_REFCNT: { + /* + * interface route refcnt idle + */ + if (dataLen < sizeof(*ev)) { + handled = FALSE; + break; + } + copy_if_name(ev, ifr_name, sizeof(ifr_name)); + interface_update_idle_state(ifr_name); + break; + } +#endif // KEV_DL_IF_IDLE_ROUTE_REFCNT + case KEV_DL_LINK_OFF : case KEV_DL_LINK_ON : /* @@ -411,6 +439,22 @@ processEvent_Apple_Network(struct kern_event_msg *ev_msg) link_update_status(ifr_name, FALSE); break; +#ifdef KEV_DL_LINK_QUALITY_METRIC_CHANGED + case KEV_DL_LINK_QUALITY_METRIC_CHANGED: { + struct kev_dl_link_quality_metric_data * lqm_data; + lqm_data = (struct kev_dl_link_quality_metric_data *) event_data; + + if (dataLen < sizeof(*ev)) { + handled = FALSE; + break; + } + copy_if_name(ev, ifr_name, sizeof(ifr_name)); + interface_update_quality_metric(ifr_name, + lqm_data->link_quality_metric); + break; + } +#endif // KEV_DL_LINK_QUALITY_METRIC_CHANGED + case KEV_DL_SIFFLAGS : case KEV_DL_SIFMETRICS : case KEV_DL_SIFMTU : @@ -421,9 +465,22 @@ processEvent_Apple_Network(struct kern_event_msg *ev_msg) case KEV_DL_DELMULTI : case KEV_DL_LINK_ADDRESS_CHANGED : case KEV_DL_WAKEFLAGS_CHANGED : -#ifdef KEV_DL_IF_IDLE_ROUTE_REFCNT - case KEV_DL_IF_IDLE_ROUTE_REFCNT : -#endif // KEV_DL_IF_IDLE_ROUTE_REFCNT +#ifdef KEV_DL_IFCAP_CHANGED + case KEV_DL_IFCAP_CHANGED : +#endif // KEV_DL_IFCAP_CHANGED + break; + + default : + handled = FALSE; + break; + } + break; + } +#ifdef KEV_ND6_SUBCLASS + case KEV_ND6_SUBCLASS : { + eventName = nd6EventNameString(ev_msg->event_code); + switch (ev_msg->event_code) { + case KEV_KEV_ND6_RA : break; default : @@ -432,6 +489,7 @@ processEvent_Apple_Network(struct kern_event_msg *ev_msg) } break; } +#endif // KEV_ND6_SUBCLASS case KEV_LOG_SUBCLASS : { break; } @@ -457,8 +515,11 @@ eventCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const { int so = CFSocketGetNative(s); int status; - char buf[1024]; - struct kern_event_msg *ev_msg = (struct kern_event_msg *)&buf[0]; + union { + char bytes[1024]; + struct kern_event_msg ev_msg1; // first kernel event + } buf; + struct kern_event_msg *ev_msg = &buf.ev_msg1; int offset = 0; status = recv(so, &buf, sizeof(buf), 0); @@ -499,7 +560,7 @@ eventCallback(CFSocketRef s, CFSocketCallBackType type, CFDataRef address, const break; } offset += ev_msg->total_size; - ev_msg = (struct kern_event_msg *)&buf[offset]; + ev_msg = (struct kern_event_msg *)(void *)&buf.bytes[offset]; } cache_write(store); diff --git a/Plugins/KernelEventMonitor/eventmon.h b/Plugins/KernelEventMonitor/eventmon.h index c9a81c0..af70ff1 100644 --- a/Plugins/KernelEventMonitor/eventmon.h +++ b/Plugins/KernelEventMonitor/eventmon.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2004, 2005, 2007 Apple Inc. All rights reserved. + * Copyright (c) 2002, 2004, 2005, 2007, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -63,6 +63,7 @@ extern Boolean _verbose; __BEGIN_DECLS +__private_extern__ int dgram_socket (int domain); __END_DECLS diff --git a/Plugins/LinkConfiguration/Info.plist b/Plugins/LinkConfiguration/Info.plist index 30e9f1d..f3cbe7b 100644 --- a/Plugins/LinkConfiguration/Info.plist +++ b/Plugins/LinkConfiguration/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.11.3 + 1.12 CFBundleSignature ???? CFBundleVersion - 1.11 + 1.12 Requires com.apple.SystemConfiguration.InterfaceNamer diff --git a/Plugins/LinkConfiguration/linkconfig.c b/Plugins/LinkConfiguration/linkconfig.c index 3f73f2e..619bac4 100644 --- a/Plugins/LinkConfiguration/linkconfig.c +++ b/Plugins/LinkConfiguration/linkconfig.c @@ -442,7 +442,7 @@ _SCNetworkInterfaceSetMTU(SCNetworkInterfaceRef interface, * 2. key = "a/b/c" prefix = "a/b/" * returns "c" */ -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef parse_component(CFStringRef key, CFStringRef prefix) { CFMutableStringRef comp; diff --git a/Plugins/Logger/Info-Embedded.plist b/Plugins/Logger/Info-Embedded.plist index be01e39..295de0b 100644 --- a/Plugins/Logger/Info-Embedded.plist +++ b/Plugins/Logger/Info-Embedded.plist @@ -15,11 +15,11 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.11.3 + 1.12 CFBundleSignature ???? CFBundleVersion - 1.11 + 1.12 Enabled Verbose @@ -30,6 +30,8 @@ LOG_NETWORK_KERNEL_EVENTS + LOG_NETWORK_INFORMATION + LOG_NOTIFY_DNS_CONFIGURATION LOG_NOTIFY_NETWORK_CHANGE @@ -44,5 +46,9 @@ mail.me.com + Requires + + com.apple.SystemConfiguration.SCNetworkReachability + diff --git a/Plugins/Logger/Info.plist b/Plugins/Logger/Info.plist index 5247be2..440c296 100644 --- a/Plugins/Logger/Info.plist +++ b/Plugins/Logger/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.11.3 + 1.12 CFBundleSignature ???? CFBundleVersion - 1.11 + 1.12 Enabled Verbose @@ -32,6 +32,8 @@ LOG_NETWORK_KERNEL_EVENTS + LOG_NETWORK_INFORMATION + LOG_NOTIFY_DNS_CONFIGURATION LOG_NOTIFY_NETWORK_CHANGE @@ -56,5 +58,9 @@ mail.me.com + Requires + + com.apple.SystemConfiguration.SCNetworkReachability + diff --git a/Plugins/Logger/logger.c b/Plugins/Logger/logger.c index 489734c..81b7c6e 100644 --- a/Plugins/Logger/logger.c +++ b/Plugins/Logger/logger.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2010 Apple Inc. All rights reserved. + * Copyright (c) 2005-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,7 @@ #include #include +#include #include #if (__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) && !TARGET_OS_EMBEDDED #include @@ -211,8 +213,11 @@ KernelEvent_notification(CFSocketRef s, CFSocketCallBackType type, CFDataRef add { int so = CFSocketGetNative(s); int status; - char buf[1024]; - struct kern_event_msg *ev_msg = (struct kern_event_msg *)&buf[0]; + union { + char bytes[1024]; + struct kern_event_msg ev_msg1; // first kernel event + } buf; + struct kern_event_msg *ev_msg = &buf.ev_msg1; int offset = 0; status = recv(so, &buf, sizeof(buf), 0); @@ -435,7 +440,7 @@ KernelEvent_notification(CFSocketRef s, CFSocketCallBackType type, CFDataRef add break; } offset += ev_msg->total_size; - ev_msg = (struct kern_event_msg *)&buf[offset]; + ev_msg = (struct kern_event_msg *)(void *)&buf.bytes[offset]; } return; @@ -689,68 +694,171 @@ static void NetworkChange_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void *context) { CFIndex i; - CFIndex n; - CFMutableStringRef str = CFStringCreateMutable(NULL, 0); + CFIndex nk; + CFMutableStringRef str; + str = CFStringCreateMutable(NULL, 0); CFStringAppendFormat(str, NULL, CFSTR("%s SCDynamicStore \"network\" notification"), elapsed()); - n = CFArrayGetCount(changedKeys); - for (i = 0; i < n; i++) { + nk = CFArrayGetCount(changedKeys); + for (i = 0; i < nk; i++) { + CFArrayRef components; CFStringRef key; + CFIndex nc; key = CFArrayGetValueAtIndex(changedKeys, i); - if (CFStringHasSuffix(key, kSCEntNetLink)) { - CFDictionaryRef dict; - const char *val = "?"; - dict = SCDynamicStoreCopyValue(store, key); - if (dict != NULL) { - CFBooleanRef link; + components = CFStringCreateArrayBySeparatingStrings(NULL, key, CFSTR("/")); + if (components == NULL) { + CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key); + continue; + } - link = CFDictionaryGetValue(dict, kSCPropNetLinkActive); - if (link != NULL) { - val = CFBooleanGetValue(link) ? "up" : "down"; - } + nc = CFArrayGetCount(components); + switch (nc) { + case 5 : { + CFStringRef entity_id; - CFRelease(dict); + entity_id = CFArrayGetValueAtIndex(components, 4); + if (CFEqual(entity_id, kSCEntNetLink)) { + CFDictionaryRef dict; + const char *val = "?"; + + dict = SCDynamicStoreCopyValue(store, key); + if (dict != NULL) { + CFBooleanRef link; + + link = CFDictionaryGetValue(dict, kSCPropNetLinkActive); + if (link != NULL) { + val = CFBooleanGetValue(link) ? "up" : "down"; + } + + CFRelease(dict); + } + CFStringAppendFormat(str, NULL, CFSTR("\n%@ (%s)"), key, val); + } else if (CFEqual(entity_id, kSCEntNetIPv4) || + CFEqual(entity_id, kSCEntNetIPv6) || + CFEqual(entity_id, kSCEntNetDNS)) { + CFDictionaryRef dict; + + dict = SCDynamicStoreCopyValue(store, key); + if (dict != NULL) { + CFStringRef val; + + val = _SCCopyDescription(dict, NULL); + CFStringAppendFormat(str, NULL, CFSTR("\n%@ : %@"), key, val); + CFRelease(val); + CFRelease(dict); + } else { + CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key); + } + } else if (CFEqual(entity_id, kSCEntNetAirPort)) { + CFDictionaryRef dict; + + dict = SCDynamicStoreCopyValue(store, key); + if (dict != NULL) { + CFStringRef ssid_str; + + ssid_str = CFDictionaryGetValue(dict, CFSTR("SSID_STR")); + if (ssid_str != NULL) { + CFDataRef bssid; + + bssid = CFDictionaryGetValue(dict, CFSTR("BSSID")); + CFStringAppendFormat(str, NULL, CFSTR("\n%@ : SSID: %@ BSSID: %s"), + key, + ssid_str, + (bssid != NULL) ? ether_ntoa((struct ether_addr *)CFDataGetBytePtr(bssid)) : ""); + } else { + CFStringAppendFormat(str, NULL, CFSTR("\n%@ : no SSID"), key); + } + CFRelease(dict); + } else { + CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key); + } + } else if (CFEqual(entity_id, kSCEntNetService)) { + CFDictionaryRef dict; + CFStringRef rank = kSCNetworkServicePrimaryRankDefault; + + dict = SCDynamicStoreCopyValue(store, key); + if ((dict == NULL) || + !CFDictionaryGetValueIfPresent(dict, + kSCPropNetServicePrimaryRank, + (const void **)&rank)) { + rank = kSCNetworkServicePrimaryRankDefault; + } + CFStringAppendFormat(str, NULL, CFSTR("\n%@ : Rank = %@"), key, rank); + if (dict != NULL) CFRelease(dict); + } else { + CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key); + } + break; } - CFStringAppendFormat(str, NULL, CFSTR("\n%@ (%s)"), key, val); - } else if (CFStringHasSuffix(key, kSCEntNetIPv4) || - CFStringHasSuffix(key, kSCEntNetIPv6) || - CFStringHasSuffix(key, kSCEntNetDNS)) { - CFDictionaryRef dict; - - dict = SCDynamicStoreCopyValue(store, key); - if (dict != NULL) { - CFStringRef val; - - val = _SCCopyDescription(dict, NULL); - CFStringAppendFormat(str, NULL, CFSTR("\n%@ : %@"), key, val); - CFRelease(val); - CFRelease(dict); - } else { - CFStringAppendFormat(str, NULL, CFSTR("\n%@ : removed"), key); + + case 4 : { + static CFStringRef rank_setup_prefix = NULL; + static CFStringRef rank_state_prefix = NULL; + + if (rank_setup_prefix == NULL) { + rank_setup_prefix = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainSetup, + CFSTR(""), + NULL); + rank_state_prefix = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainState, + CFSTR(""), + NULL); + } + + if (CFStringHasPrefix(key, rank_setup_prefix) || + CFStringHasPrefix(key, rank_state_prefix)) { + CFDictionaryRef dict; + CFStringRef rank = kSCNetworkServicePrimaryRankDefault; + + dict = SCDynamicStoreCopyValue(store, key); + if ((dict == NULL) || + !CFDictionaryGetValueIfPresent(dict, + kSCPropNetServicePrimaryRank, + (const void **)&rank)) { + rank = kSCNetworkServicePrimaryRankDefault; + } + CFStringAppendFormat(str, NULL, CFSTR("\n%@ : Rank = %@"), key, rank); + if (dict != NULL) CFRelease(dict); + } else { + CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key); + } + break; } - } else if (CFStringHasSuffix(key, CFSTR(kIOPMSystemPowerCapabilitiesKeySuffix))) { - CFNumberRef num; - num = SCDynamicStoreCopyValue(store, key); - if (num != NULL) { - IOPMSystemPowerStateCapabilities capabilities; + case 2 : + if (CFEqual(CFArrayGetValueAtIndex(components, 1), + CFSTR(kIOPMSystemPowerCapabilitiesKeySuffix))) { + CFNumberRef num; - if (isA_CFNumber(num) && - CFNumberGetValue(num, kCFNumberSInt32Type, &capabilities)) { - CFStringAppendFormat(str, NULL, CFSTR("\n%@ (0x%x)"), key, capabilities); + num = SCDynamicStoreCopyValue(store, key); + if (num != NULL) { + IOPMSystemPowerStateCapabilities capabilities; + + if (isA_CFNumber(num) && + CFNumberGetValue(num, kCFNumberSInt32Type, &capabilities)) { + CFStringAppendFormat(str, NULL, CFSTR("\n%@ (0x%x)"), key, capabilities); + } + + CFRelease(num); + } + } else { + CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key); } + break; - CFRelease(num); - } - } else { - CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key); + default : + CFStringAppendFormat(str, NULL, CFSTR("\n%@"), key); + break; } + + CFRelease(components); } SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, CFSTR("%@"), str); @@ -759,6 +867,47 @@ NetworkChange_notification(SCDynamicStoreRef store, CFArrayRef changedKeys, void } +static void +add_NetworkChange_keys(CFMutableArrayRef keys, + CFMutableArrayRef patterns, + CFStringRef entity, + Boolean doGlobal, + Boolean doService, + Boolean doInterface) +{ + CFStringRef key; + CFStringRef pattern; + + if (doGlobal) { + key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainSetup, entity); + CFArrayAppendValue(keys, key); + CFRelease(key); + + key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, entity); + CFArrayAppendValue(keys, key); + CFRelease(key); + } + + if (doService) { + pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, entity); + CFArrayAppendValue(patterns, pattern); + CFRelease(pattern); + + pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, entity); + CFArrayAppendValue(patterns, pattern); + CFRelease(pattern); + } + + if (doInterface) { + pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, entity); + CFArrayAppendValue(patterns, pattern); + CFRelease(pattern); + } + + return; +} + + static void add_NetworkChange_notification() { @@ -766,7 +915,6 @@ add_NetworkChange_notification() CFStringRef key; CFMutableArrayRef keys; Boolean ok; - CFStringRef pattern; CFMutableArrayRef patterns; SCDynamicStoreRef store; CFRunLoopSourceRef rls; @@ -788,67 +936,31 @@ add_NetworkChange_notification() // IPv4 - key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv4); - CFArrayAppendValue(keys, key); - CFRelease(key); - - pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4); - CFArrayAppendValue(patterns, pattern); - CFRelease(pattern); - - pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv4); - CFArrayAppendValue(patterns, pattern); - CFRelease(pattern); + add_NetworkChange_keys(keys, patterns, kSCEntNetIPv4, TRUE, TRUE, TRUE); // IPv6 - key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetIPv6); - CFArrayAppendValue(keys, key); - CFRelease(key); - - pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6); - CFArrayAppendValue(patterns, pattern); - CFRelease(pattern); - - pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetIPv6); - CFArrayAppendValue(patterns, pattern); - CFRelease(pattern); + add_NetworkChange_keys(keys, patterns, kSCEntNetIPv6, TRUE, TRUE, TRUE); // PPP, VPN - pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetPPP); - CFArrayAppendValue(patterns, pattern); - CFRelease(pattern); - - pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetPPP); - CFArrayAppendValue(patterns, pattern); - CFRelease(pattern); - - pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetVPN); - CFArrayAppendValue(patterns, pattern); - CFRelease(pattern); - - pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetVPN); - CFArrayAppendValue(patterns, pattern); - CFRelease(pattern); + add_NetworkChange_keys(keys, patterns, kSCEntNetPPP, FALSE, TRUE, TRUE); + add_NetworkChange_keys(keys, patterns, kSCEntNetVPN, FALSE, TRUE, TRUE); + add_NetworkChange_keys(keys, patterns, kSCEntNetL2TP, FALSE, TRUE, TRUE); + add_NetworkChange_keys(keys, patterns, kSCEntNetPPTP, FALSE, TRUE, TRUE); + add_NetworkChange_keys(keys, patterns, kSCEntNetIPSec, FALSE, TRUE, TRUE); // Link - pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetLink); - CFArrayAppendValue(patterns, pattern); - CFRelease(pattern); + add_NetworkChange_keys(keys, patterns, kSCEntNetLink, FALSE, FALSE, TRUE); // AirPort (e.g. BSSID) - pattern = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, kSCCompAnyRegex, kSCEntNetAirPort); - CFArrayAppendValue(patterns, pattern); - CFRelease(pattern); + add_NetworkChange_keys(keys, patterns, kSCEntNetAirPort, FALSE, FALSE, TRUE); // DNS - key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetDNS); - CFArrayAppendValue(keys, key); - CFRelease(key); + add_NetworkChange_keys(keys, patterns, kSCEntNetDNS, TRUE, TRUE, TRUE); dns_key = CFStringCreateWithCString(NULL, dns_configuration_notify_key(), @@ -864,6 +976,11 @@ add_NetworkChange_notification() CFArrayAppendValue(keys, key); CFRelease(key); + // Rank + + add_NetworkChange_keys(keys, patterns, NULL, FALSE, TRUE, FALSE); // per-service + add_NetworkChange_keys(keys, patterns, kSCEntNetService, FALSE, FALSE, TRUE); // per-interface + // ComputerName, LocalHostName key = SCDynamicStoreKeyCreateComputerName(NULL); @@ -874,12 +991,17 @@ add_NetworkChange_notification() CFArrayAppendValue(keys, key); CFRelease(key); + // Power Management + key = SCDynamicStoreKeyCreate(NULL, CFSTR("%@%@"), kSCDynamicStoreDomainState, CFSTR(kIOPMSystemPowerCapabilitiesKeySuffix)); CFArrayAppendValue(keys, key); CFRelease(key); + + // Setup monitoring + ok = SCDynamicStoreSetNotificationKeys(store, keys, patterns); CFRelease(keys); CFRelease(patterns); @@ -1332,6 +1454,60 @@ add_dnsinfo_notification() } +#pragma mark - +#pragma mark Network Information Events + + +static void +nwi_notification(CFMachPortRef port, void *msg, CFIndex size, void *info) +{ + SCLOG(NULL, log_msg, ~ASL_LEVEL_INFO, + CFSTR("%s network_information notification"), + elapsed()); + + return; +} + + +static void +add_nwi_notification() +{ + const char *key; + CFMachPortRef mp; + mach_port_t notify_port; + int notify_token; + CFRunLoopSourceRef rls; + uint32_t status; + + key = nwi_state_get_notify_key(); + status = notify_register_mach_port(key, ¬ify_port, 0, ¬ify_token); + if (status != NOTIFY_STATUS_OK) { + SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("notify_register_mach_port() failed")); + return; + } + + mp = _SC_CFMachPortCreateWithPort("Logger/nwi", notify_port, nwi_notification, NULL); + if (mp == NULL) { + SCLOG(NULL, NULL, ASL_LEVEL_ERR, CFSTR("CFMachPortCreateWithPort() failed")); + (void)notify_cancel(notify_token); + return; + } + + 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); + + CFRelease(mp); + return; +} + + #pragma mark - #pragma mark Network Configuration Change Events @@ -1792,6 +1968,10 @@ load(CFBundleRef bundle, Boolean bundleVerbose) add_KernelEvent_notification(); } + if (log_all || bValFromDictionary(config, CFSTR("LOG_NETWORK_INFORMATION"))) { + add_nwi_notification(); + } + if (log_all || bValFromDictionary(config, CFSTR("LOG_NOTIFY_DNS_CONFIGURATION"))) { add_dnsinfo_notification(); } diff --git a/Plugins/NetworkIdentification/Info.plist b/Plugins/NetworkIdentification/Info.plist deleted file mode 100644 index e8e42f5..0000000 --- a/Plugins/NetworkIdentification/Info.plist +++ /dev/null @@ -1,26 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleExecutable - NetworkIdentification - CFBundleIdentifier - com.apple.SystemConfiguration.NetworkIdentification - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - com.apple.SystemConfiguration.NetworkIdentification - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.11.3 - CFBundleSignature - ???? - CFBundleVersion - 1.11 - Builtin - - - diff --git a/Plugins/NetworkIdentification/Makefile b/Plugins/NetworkIdentification/Makefile deleted file mode 100644 index 1220f47..0000000 --- a/Plugins/NetworkIdentification/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -netsig: NetworkIdentification.c - cc -Wall -g -DTEST_NETWORKIDENTIFICATION -o netsig NetworkIdentification.c -framework CoreFoundation -framework SystemConfiguration - -clean: - rm -f netsig - diff --git a/Plugins/NetworkIdentification/NetworkIdentification.c b/Plugins/NetworkIdentification/NetworkIdentification.c deleted file mode 100644 index 3f5ad51..0000000 --- a/Plugins/NetworkIdentification/NetworkIdentification.c +++ /dev/null @@ -1,1235 +0,0 @@ -/* - * Copyright (c) 2005-2007, 2009 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, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * 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@ - */ - -/* - * NetworkIdentification.c - * - maintains a history of networks that the system has connected to by - * watching the Network Services that post data to the SCDynamicStore - */ - -/* - * Modification History - * - * November 9, 2006 Dieter Siegmund (dieter@apple.com) - * - created - */ - -#include -#include -#include -#include -#include -#include -#include - -/* debug output on/off */ -static Boolean S_NetworkIdentification_debug; - -/* should we bother keeping track of networks? */ -static Boolean S_NetworkIdentification_disabled; - -typedef struct ServiceWatcher_s ServiceWatcher, * ServiceWatcherRef; - -/* returns an array of currently available information */ -static CFArrayRef -ServiceWatcherCopyCurrent(ServiceWatcherRef watcher); - -static ServiceWatcherRef -ServiceWatcherCreate(); - -static void -ServiceWatcherFree(ServiceWatcherRef * watcher_p); - -/* XXX these should be made tunable */ -#define SIGNATURE_HISTORY_MAX 150 -#define SERVICE_HISTORY_MAX 5 - -/* don't re-write the prefs file unless this time interval has elapsed */ -#define SIGNATURE_UPDATE_INTERVAL_SECS (24 * 3600) /* 24 hours */ - -struct ServiceWatcher_s { - CFRunLoopSourceRef rls; - SCDynamicStoreRef store; - CFMutableArrayRef signatures; - CFArrayRef active_signatures; - CFStringRef primary_ipv4; - CFStringRef setup_ipv4_key; - CFStringRef state_ipv4_key; -}; - -#define kIdentifier CFSTR("Identifier") -#define kService CFSTR("Service") -#define kServices CFSTR("Services") -#define kSignature CFSTR("Signature") -#define kSignatures CFSTR("Signatures") -#define kTimestamp CFSTR("Timestamp") -#define kServiceID CFSTR("ServiceID") -#define kNetworkSignature CFSTR("NetworkSignature") -#define kServiceIdentifiers kStoreKeyServiceIdentifiers - -static CFArrayRef -make_service_entity_pattern_array(CFStringRef * keys, int n_keys) -{ - int i; - CFArrayRef list; - - for (i = 0; i < n_keys; i++) { - /* re-use the array that was passed in to get the pattern */ - keys[i] = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, - kSCDynamicStoreDomainState, - kSCCompAnyRegex, - keys[i]); - } - list = CFArrayCreate(NULL, (const void * *)keys, n_keys, - &kCFTypeArrayCallBacks); - for (i = 0; i < n_keys; i++) { - /* then release the allocated patterns */ - CFRelease(keys[i]); - } - return (list); -} - -static CFArrayRef -ServiceWatcherNotificationPatterns(void) -{ - CFStringRef keys[1] = { kSCEntNetIPv4 }; - - return (make_service_entity_pattern_array(keys, - sizeof(keys) / sizeof(keys[0]))); -} - -static CFArrayRef -ServiceWatcherPatterns(void) -{ - CFStringRef keys[2] = { kSCEntNetIPv4, kSCEntNetDNS }; - - return (make_service_entity_pattern_array(keys, - sizeof(keys) / sizeof(keys[0]))); -} - -static CFTypeRef -myCFDictionaryArrayGetValue(CFArrayRef array, CFStringRef key, CFTypeRef value, - int * ret_index) -{ - int count = 0; - int i; - - if (array != NULL) { - count = CFArrayGetCount(array); - } - if (count == 0) { - goto done; - } - for (i = 0; i < count; i++) { - CFDictionaryRef dict; - CFTypeRef this_val; - - dict = CFArrayGetValueAtIndex(array, i); - if (isA_CFDictionary(dict) == NULL) { - continue; - } - this_val = CFDictionaryGetValue(dict, key); - if (CFEqual(this_val, value)) { - if (ret_index != NULL) { - *ret_index = i; - } - return (dict); - } - } - done: - if (ret_index != NULL) { - *ret_index = -1; - } - return (NULL); -} - -static CFDictionaryRef -copy_airport_dict(SCDynamicStoreRef store, CFStringRef if_name) -{ - CFDictionaryRef dict; - CFStringRef key; - - key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, - kSCDynamicStoreDomainState, - if_name, - kSCEntNetAirPort); - dict = SCDynamicStoreCopyValue(store, key); - CFRelease(key); - return (dict); -} - -static void -add_airport_info(SCDynamicStoreRef store, CFMutableDictionaryRef dict) -{ - CFDictionaryRef airport_dict = NULL; - CFStringRef key; - CFStringRef if_name; - CFDictionaryRef simple_dict; - CFStringRef value; - - if_name = CFDictionaryGetValue(dict, kSCPropInterfaceName); - if (isA_CFString(if_name) == NULL) { - goto done; - } - airport_dict = copy_airport_dict(store, if_name); - if (airport_dict == NULL) { - goto done; - } - key = CFSTR("SSID"); - value = CFDictionaryGetValue(airport_dict, key); - if (value == NULL) { - goto done; - } - simple_dict = - CFDictionaryCreate(NULL, - (const void * *)&key, (const void * *)&value, 1, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFDictionarySetValue(dict, kSCEntNetAirPort, simple_dict); - CFRelease(simple_dict); - - done: - if (airport_dict != NULL) { - CFRelease(airport_dict); - } - return; -} - -static CFDictionaryRef -get_current_dict(CFDictionaryRef current, CFStringRef entity, - CFArrayRef components) -{ - CFDictionaryRef dict; - CFStringRef key; - - if (CFArrayGetCount(components) < 5) { - /* this can't happen, we already checked */ - return (NULL); - } - key = CFStringCreateWithFormat(NULL, NULL, - CFSTR("%@/%@/%@/%@/%@"), - CFArrayGetValueAtIndex(components, 0), - CFArrayGetValueAtIndex(components, 1), - CFArrayGetValueAtIndex(components, 2), - CFArrayGetValueAtIndex(components, 3), - entity); - dict = CFDictionaryGetValue(current, key); - CFRelease(key); - return (isA_CFDictionary(dict)); -} - -static CFArrayRef -process_dict(SCDynamicStoreRef store, CFDictionaryRef current) -{ - CFMutableArrayRef array = NULL; - int count = 0; - int i; - const void * * keys = NULL; - const void * * values = NULL; - - count = CFDictionaryGetCount(current); - if (count == 0) { - goto done; - } - array = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - keys = (const void * *)malloc(sizeof(keys) * count); - values = (const void * *)malloc(sizeof(values) * count); - CFDictionaryGetKeysAndValues(current, keys, values); - for (i = 0; i < count; i++) { - CFArrayRef components = NULL; - CFDictionaryRef dns_dict; - CFStringRef entity; - CFMutableDictionaryRef entity_dict = NULL; - CFMutableDictionaryRef new_dict = NULL; - CFStringRef sig_str = NULL; - CFMutableDictionaryRef service_dict = NULL; - CFStringRef serviceID; - - if (isA_CFDictionary(values[i]) == NULL) { - goto loop_done; - } - components = CFStringCreateArrayBySeparatingStrings(NULL, keys[i], - CFSTR("/")); - if (components == NULL) { - goto loop_done; - } - if (CFArrayGetCount(components) < 5) { - /* too few components */ - goto loop_done; - } - entity = CFArrayGetValueAtIndex(components, 4); - if (!CFEqual(entity, kSCEntNetIPv4)) { - goto loop_done; - } - serviceID = CFArrayGetValueAtIndex(components, 3); - sig_str = CFDictionaryGetValue(values[i], kNetworkSignature); - if (isA_CFString(sig_str) == NULL - || CFStringGetLength(sig_str) == 0) { - goto loop_done; - } - /* create a new entry */ - new_dict = CFDictionaryCreateMutable(NULL, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFDictionarySetValue(new_dict, kSignature, sig_str); - service_dict = CFDictionaryCreateMutable(NULL, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFDictionarySetValue(service_dict, kServiceID, serviceID); - add_airport_info(store, service_dict); - entity_dict = CFDictionaryCreateMutableCopy(NULL, 0, values[i]); - CFDictionaryRemoveValue(entity_dict, kNetworkSignature); - CFDictionarySetValue(service_dict, kSCEntNetIPv4, entity_dict); - dns_dict = get_current_dict(current, kSCEntNetDNS, components); - if (dns_dict != NULL) { - CFDictionarySetValue(service_dict, kSCEntNetDNS, dns_dict); - } - CFDictionarySetValue(new_dict, kService, service_dict); - CFArrayAppendValue(array, new_dict); - - loop_done: - if (entity_dict != NULL) { - CFRelease(entity_dict); - } - if (service_dict != NULL) { - CFRelease(service_dict); - } - if (components != NULL) { - CFRelease(components); - } - if (new_dict != NULL) { - CFRelease(new_dict); - } - } - count = CFArrayGetCount(array); - if (count == 0) { - CFRelease(array); - array = NULL; - goto done; - } - - done: - if (keys != NULL) { - free(keys); - } - if (values != NULL) { - free(values); - } - return (array); - -} - -static CFArrayRef -ServiceWatcherCopyCurrent(ServiceWatcherRef watcher) -{ - CFDictionaryRef current; - CFArrayRef list; - CFArrayRef ret = NULL; - - list = ServiceWatcherPatterns(); - current = SCDynamicStoreCopyMultiple(watcher->store, NULL, list); - CFRelease(list); - if (current == NULL) { - goto done; - } - ret = process_dict(watcher->store, current); - done: - if (current != NULL) { - CFRelease(current); - } - return (ret); -} - -static Boolean -ServiceWatcherSetActiveSignatures(ServiceWatcherRef watcher, CFArrayRef active) -{ - Boolean changed = FALSE; - CFArrayRef prev_active; - - prev_active = watcher->active_signatures; - if (prev_active == NULL && active == NULL) { - /* nothing to do */ - goto done; - } - if (prev_active != NULL && active != NULL) { - changed = !CFEqual(prev_active, active); - } - else { - changed = TRUE; - } - if (active != NULL) { - CFRetain(active); - } - if (prev_active != NULL) { - CFRelease(prev_active); - } - watcher->active_signatures = active; - if (changed) { - if (active != NULL) { - SCLog(S_NetworkIdentification_debug, - LOG_NOTICE, CFSTR("Active Signatures %@"), active); - } - else { - SCLog(S_NetworkIdentification_debug, - LOG_NOTICE, CFSTR("No Active Signatures")); - } - } - done: - return (changed); -} - -static Boolean -ServiceWatcherSetPrimaryIPv4(ServiceWatcherRef watcher, - CFStringRef primary_ipv4) -{ - Boolean changed = FALSE; - CFStringRef prev_ipv4_primary; - - prev_ipv4_primary = watcher->primary_ipv4; - if (prev_ipv4_primary == NULL && primary_ipv4 == NULL) { - /* nothing to do */ - goto done; - } - if (prev_ipv4_primary != NULL && primary_ipv4 != NULL) { - changed = !CFEqual(prev_ipv4_primary, primary_ipv4); - } - else { - changed = TRUE; - } - if (primary_ipv4 != NULL) { - CFRetain(primary_ipv4); - } - if (prev_ipv4_primary != NULL) { - CFRelease(prev_ipv4_primary); - } - watcher->primary_ipv4 = primary_ipv4; - if (changed) { - if (primary_ipv4 != NULL) { - SCLog(S_NetworkIdentification_debug, - LOG_NOTICE, CFSTR("Primary IPv4 %@"), primary_ipv4); - } - else { - SCLog(S_NetworkIdentification_debug, LOG_NOTICE, - CFSTR("No Primary IPv4")); - } - } - done: - return (changed); -} - - -static CFDictionaryRef -signature_add_service(CFDictionaryRef sig_dict, CFDictionaryRef service, - CFArrayRef active_services) -{ - CFArrayRef list; - CFMutableDictionaryRef new_dict = NULL; - CFDateRef now; - - list = CFDictionaryGetValue(sig_dict, kServices); - now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()); - if (list == NULL) { - list = CFArrayCreate(NULL, (const void * *)&service, 1, - &kCFTypeArrayCallBacks); - } - else { - int list_count = CFArrayGetCount(list); - CFMutableArrayRef new_list = NULL; - CFRange range = CFRangeMake(0, list_count); - int where; - - where = CFArrayGetFirstIndexOfValue(list, range, service); - if (where != kCFNotFound) { - CFDateRef date; - - date = CFDictionaryGetValue(sig_dict, kTimestamp); - if (date != NULL) { - CFTimeInterval time_interval; - - time_interval = CFDateGetTimeIntervalSinceDate(now, date); - /* don't bother updating timestamp until interval has passed */ - if (time_interval < (SIGNATURE_UPDATE_INTERVAL_SECS)) { - goto done; - } - } - if (where == 0) { - /* it's already in the right place */ - list = NULL; - } - } - - if (list != NULL) { - new_list = CFArrayCreateMutableCopy(NULL, 0, list); - if (where != kCFNotFound) { - CFArrayRemoveValueAtIndex(new_list, where); - } - else { - list_count++; - } - CFArrayInsertValueAtIndex(new_list, 0, service); - /* try to remove stale entries */ - if (list_count > SERVICE_HISTORY_MAX) { - int i; - int remove_count = list_count - SERVICE_HISTORY_MAX; - - SCLog(S_NetworkIdentification_debug, - LOG_NOTICE, CFSTR("Attempting to remove %d services"), - remove_count); - for (i = list_count - 1; i >= 0 && remove_count > 0; i--) { - CFDictionaryRef dict; - - dict = CFArrayGetValueAtIndex(new_list, i); - if (myCFDictionaryArrayGetValue(active_services, - kService, dict, NULL) - != NULL) { - /* skip anything that's currently active */ - SCLog(S_NetworkIdentification_debug, - LOG_NOTICE, CFSTR("Skipping Service %@"), - dict); - } - else { - SCLog(S_NetworkIdentification_debug, LOG_NOTICE, - CFSTR("Removing Service %@"), dict); - CFArrayRemoveValueAtIndex(new_list, i); - remove_count--; - } - } - } - list = (CFArrayRef)new_list; - - } - } - - new_dict = CFDictionaryCreateMutableCopy(NULL, 0, sig_dict); - if (list != NULL) { - CFDictionarySetValue(new_dict, kServices, list); - CFRelease(list); - } - CFDictionarySetValue(new_dict, kTimestamp, now); - - done: - CFRelease(now); - return (new_dict); -} - -#define ARBITRARILY_LARGE_NUMBER (1024 * 1024) -static CFStringRef -get_best_serviceID(CFArrayRef serviceID_list, CFArrayRef order) -{ - int best_rank; - CFStringRef best_serviceID; - int count; - int i; - CFRange range; - - count = CFArrayGetCount(serviceID_list); - if (count == 1 || order == NULL) { - return (CFArrayGetValueAtIndex(serviceID_list, 0)); - } - best_serviceID = NULL; - best_rank = ARBITRARILY_LARGE_NUMBER; - range = CFRangeMake(0, CFArrayGetCount(order)); - for (i = 0; i < count; i++) { - CFStringRef serviceID = CFArrayGetValueAtIndex(serviceID_list, i); - int this_rank; - - this_rank = CFArrayGetFirstIndexOfValue(order, range, serviceID); - if (this_rank == kCFNotFound) { - this_rank = ARBITRARILY_LARGE_NUMBER; - } - if (best_serviceID == NULL || this_rank < best_rank) { - best_serviceID = serviceID; - best_rank = this_rank; - } - } - return (best_serviceID); -} - -static CFArrayRef -copy_service_order(SCDynamicStoreRef session, CFStringRef ipv4_key) -{ - CFArrayRef order = NULL; - CFDictionaryRef ipv4_dict = NULL; - - if (session == NULL) { - return (NULL); - } - ipv4_dict = SCDynamicStoreCopyValue(session, ipv4_key); - if (isA_CFDictionary(ipv4_dict) != NULL) { - order = CFDictionaryGetValue(ipv4_dict, kSCPropNetServiceOrder); - order = isA_CFArray(order); - if (order) { - CFRetain(order); - } - } - if (ipv4_dict != NULL) { - CFRelease(ipv4_dict); - } - return (order); -} - -typedef struct service_order_with_range { - CFArrayRef service_order; - CFRange range; -} service_order_with_range_t; - -static void -add_netID_and_serviceID(service_order_with_range_t * order, int count, - CFMutableArrayRef netID_list, CFStringRef netID, - CFMutableArrayRef serviceID_list, CFStringRef serviceID) - -{ - int i; - int serviceID_index; - - if (count == 0 || order->service_order == NULL) { - goto add_to_end; - } - serviceID_index = CFArrayGetFirstIndexOfValue(order->service_order, - order->range, - serviceID); - if (serviceID_index == kCFNotFound) { - goto add_to_end; - } - for (i = 0; i < count; i++) { - CFStringRef scan = CFArrayGetValueAtIndex(serviceID_list, i); - int scan_index; - - scan_index = CFArrayGetFirstIndexOfValue(order->service_order, - order->range, - scan); - if (scan_index == kCFNotFound - || serviceID_index < scan_index) { - /* found our insertion point */ - CFArrayInsertValueAtIndex(netID_list, i, netID); - CFArrayInsertValueAtIndex(serviceID_list, i, serviceID); - return; - } - } - - add_to_end: - CFArrayAppendValue(netID_list, netID); - CFArrayAppendValue(serviceID_list, serviceID); - return; -} - -static Boolean -ServiceWatcherPublishActiveIdentifiers(ServiceWatcherRef watcher) -{ - Boolean updated = FALSE; - - if (watcher->active_signatures == NULL) { - CFDictionaryRef dict; - - dict = SCDynamicStoreCopyValue(watcher->store, - kSCNetworkIdentificationStoreKey); - if (dict != NULL) { - updated = TRUE; - SCLog(S_NetworkIdentification_debug, - LOG_NOTICE, CFSTR("Removing %@"), - kSCNetworkIdentificationStoreKey); - SCDynamicStoreRemoveValue(watcher->store, - kSCNetworkIdentificationStoreKey); - CFRelease(dict); - } - } - else { - int count; - CFDictionaryRef dict; - int i; - CFMutableArrayRef id_list; - CFStringRef keys[3]; - int keys_count; - service_order_with_range_t order; - CFStringRef primary_ipv4_id = NULL; - CFMutableArrayRef serviceID_list; - CFDictionaryRef store_dict; - CFTypeRef values[3]; - - order.service_order = copy_service_order(watcher->store, - watcher->setup_ipv4_key); - if (order.service_order != NULL) { - order.range = CFRangeMake(0, CFArrayGetCount(order.service_order)); - } - id_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - serviceID_list = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - count = CFArrayGetCount(watcher->active_signatures); - for (i = 0; i < count; i++) { - CFStringRef this_id; - CFStringRef serviceID; - CFArrayRef this_list; - - dict = CFArrayGetValueAtIndex(watcher->active_signatures, i); - this_id = CFDictionaryGetValue(dict, kIdentifier); - this_list = CFDictionaryGetValue(dict, kServiceIdentifiers); - if (primary_ipv4_id == NULL && watcher->primary_ipv4 != NULL) { - CFRange range; - - range = CFRangeMake(0, CFArrayGetCount(this_list)); - if (CFArrayContainsValue(this_list, range, - watcher->primary_ipv4)) { - primary_ipv4_id = this_id; - } - } - serviceID = get_best_serviceID(this_list, order.service_order); - add_netID_and_serviceID(&order, i, id_list, this_id, - serviceID_list, serviceID); - } - keys[0] = kStoreKeyActiveIdentifiers; - values[0] = id_list; - keys[1] = kStoreKeyServiceIdentifiers; - values[1] = serviceID_list; - if (primary_ipv4_id != NULL) { - keys_count = 3; - keys[2] = kStoreKeyPrimaryIPv4Identifier; - values[2] = primary_ipv4_id; - } - else { - keys_count = 2; - } - dict = CFDictionaryCreate(NULL, (const void * *)keys, - (const void * *)values, keys_count, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - store_dict - = SCDynamicStoreCopyValue(watcher->store, - kSCNetworkIdentificationStoreKey); - if (isA_CFDictionary(store_dict) == NULL - || CFEqual(store_dict, dict) == FALSE) { - updated = TRUE; - SCDynamicStoreSetValue(watcher->store, - kSCNetworkIdentificationStoreKey, dict); - SCLog(S_NetworkIdentification_debug, - LOG_NOTICE, CFSTR("Setting %@ = %@"), - kSCNetworkIdentificationStoreKey, - dict); - } - else { - SCLog(S_NetworkIdentification_debug, - LOG_NOTICE, CFSTR("Not setting %@"), - kSCNetworkIdentificationStoreKey); - } - CFRelease(dict); - CFRelease(id_list); - CFRelease(serviceID_list); - if (order.service_order != NULL) { - CFRelease(order.service_order); - } - if (store_dict != NULL) { - CFRelease(store_dict); - } - } - return (updated); -} - -static CFDictionaryRef -signature_dict_create(CFStringRef this_sig, CFDictionaryRef service) -{ - CFDictionaryRef dict; - const void * keys[4]; - const void * values[4]; - - keys[0] = kSignature; - values[0] = this_sig; - - keys[1] = kServices; - values[1] = CFArrayCreate(NULL, (const void * *)&service, 1, - &kCFTypeArrayCallBacks); - keys[2] = kIdentifier; - values[2] = this_sig; - - keys[3] = kTimestamp; - values[3] = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()); - - dict = CFDictionaryCreate(NULL, keys, values, - sizeof(keys) / sizeof(keys[0]), - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFRelease(values[1]); - CFRelease(values[3]); - return (dict); -} - -static void -ServiceWatcherRemoveStaleSignatures(ServiceWatcherRef watcher) -{ - int active_count = 0; - int count; - int i; - int remove_count; - - count = CFArrayGetCount(watcher->signatures); - if (watcher->active_signatures != NULL) { - active_count = CFArrayGetCount(watcher->active_signatures); - } - if ((count - active_count) <= SIGNATURE_HISTORY_MAX) { - return; - } - remove_count = count - active_count - SIGNATURE_HISTORY_MAX; - for (i = count - 1; i >= 0 && remove_count > 0; i--) { - CFDictionaryRef sig_dict; - CFStringRef sig_str; - - sig_dict = CFArrayGetValueAtIndex(watcher->signatures, i); - sig_str = CFDictionaryGetValue(sig_dict, kSignature); - - if (myCFDictionaryArrayGetValue(watcher->active_signatures, - kSignature, sig_str, NULL) - != NULL) { - /* skip anything that's currently active */ - SCLog(S_NetworkIdentification_debug, - LOG_NOTICE, CFSTR("Skipping %@"), sig_dict); - } - else { - SCLog(S_NetworkIdentification_debug, - LOG_NOTICE, CFSTR("ServiceWatcher: Removing %@"), - sig_dict); - CFArrayRemoveValueAtIndex(watcher->signatures, i); - remove_count--; - } - } - return; -} - -static void -ServiceWatcherSaveSignatures(ServiceWatcherRef watcher) -{ - SCPreferencesRef prefs; - - prefs = SCPreferencesCreate(NULL, CFSTR("ServiceWatcher"), - kSCNetworkIdentificationPrefsKey); - if (prefs == NULL) { - SCLog(TRUE, LOG_NOTICE, CFSTR("ServiceWatcherSaveSignatures: Create failed %s"), - SCErrorString(SCError())); - return; - } - ServiceWatcherRemoveStaleSignatures(watcher); - if (SCPreferencesSetValue(prefs, kSignatures, watcher->signatures) - == FALSE) { - SCLog(TRUE, LOG_NOTICE, CFSTR("ServiceWatcherSaveSignatures: Set failed %s"), - SCErrorString(SCError())); - } - else if (SCPreferencesCommitChanges(prefs) == FALSE) { - // An EROFS error is expected during installation. All other - // errors should be reported. - if (SCError() != EROFS) { - SCLog(TRUE, LOG_NOTICE, CFSTR("ServiceWatcherSaveSignatures: Commit failed %s"), - SCErrorString(SCError())); - } - } - CFRelease(prefs); - return; - -} - -static void -ServiceWatcherLoadSignatures(ServiceWatcherRef watcher) -{ - int count; - int i; - SCPreferencesRef prefs; - CFArrayRef signatures; - - watcher->signatures - = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - prefs = SCPreferencesCreate(NULL, CFSTR("ServiceWatcher"), - kSCNetworkIdentificationPrefsKey); - if (prefs == NULL) { - SCLog(TRUE, LOG_NOTICE, CFSTR("ServiceWatcherLoadSignatures: Create failed %s"), - SCErrorString(SCError())); - return; - } - signatures = SCPreferencesGetValue(prefs, kSignatures); - if (signatures == NULL) { - goto done; - } - if (isA_CFArray(signatures) == NULL) { - SCLog(TRUE, LOG_NOTICE, - CFSTR("ServiceWatcherLoadSignatures: Signatures is not an array")); - goto done; - } - count = CFArrayGetCount(signatures); - for (i = 0; i < count; i++) { - CFDictionaryRef dict; - CFArrayRef services; - CFStringRef sig_id; - CFStringRef sig_str; - CFDateRef timestamp; - - dict = CFArrayGetValueAtIndex(signatures, i); - if (isA_CFDictionary(dict) == NULL) { - continue; - } - sig_id = CFDictionaryGetValue(dict, kIdentifier); - if (isA_CFString(sig_id) == NULL) { - continue; - } - sig_str = CFDictionaryGetValue(dict, kSignature); - if (isA_CFString(sig_str) == NULL) { - continue; - } - timestamp = CFDictionaryGetValue(dict, kTimestamp); - if (isA_CFDate(timestamp) == NULL) { - continue; - } - services = CFDictionaryGetValue(dict, kServices); - if (isA_CFArray(services) == NULL) { - continue; - } - CFArrayAppendValue(watcher->signatures, dict); - } - - done: - CFRelease(prefs); - return; - -} - -static void -ServiceWatcherUpdate(ServiceWatcherRef watcher, Boolean update_signatures) -{ - CFMutableArrayRef active_signatures = NULL; - int count; - int i; - Boolean save_signatures = FALSE; - CFArrayRef service_list; - Boolean update_store = FALSE; - - service_list = ServiceWatcherCopyCurrent(watcher); - SCLog(S_NetworkIdentification_debug, - LOG_NOTICE, CFSTR("service_list = %@"), service_list); - if (service_list == NULL) { - goto done; - } - active_signatures = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); - count = CFArrayGetCount(service_list); - for (i = 0; i < count; i++) { - CFDictionaryRef dict; - CFDictionaryRef active_dict; - CFArrayRef id_list; - CFMutableDictionaryRef new_active_dict; - CFDictionaryRef new_sig_dict; - CFStringRef serviceID; - CFStringRef sig_id; - CFDictionaryRef service; - CFDictionaryRef sig_dict; - CFStringRef this_sig; - int where; - - dict = CFArrayGetValueAtIndex(service_list, i); - service = CFDictionaryGetValue(dict, kService); - this_sig = CFDictionaryGetValue(dict, kSignature); - if (this_sig == NULL) { - /* service has no signature */ - continue; - } - sig_dict = myCFDictionaryArrayGetValue(watcher->signatures, kSignature, - this_sig, &where); - if (sig_dict == NULL) { - /* add a new signature entry */ - sig_dict = signature_dict_create(this_sig, service); - CFArrayInsertValueAtIndex(watcher->signatures, 0, sig_dict); - CFRelease(sig_dict); - save_signatures = TRUE; - sig_id = CFDictionaryGetValue(sig_dict, kIdentifier); - active_dict = NULL; - } - else { - /* update an existing signature entry */ - - sig_id = CFDictionaryGetValue(sig_dict, kIdentifier); - new_sig_dict = signature_add_service(sig_dict, service, - service_list); - if (new_sig_dict != NULL) { - CFArrayRemoveValueAtIndex(watcher->signatures, where); - CFArrayInsertValueAtIndex(watcher->signatures, 0, - new_sig_dict); - CFRelease(new_sig_dict); - save_signatures = TRUE; - } - active_dict - = myCFDictionaryArrayGetValue(active_signatures, - kSignature, this_sig, - &where); - } - if (active_dict == NULL) { - /* signature now active, this is the first/only service */ - new_active_dict - = CFDictionaryCreateMutable(NULL, 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - CFDictionarySetValue(new_active_dict, kSignature, this_sig); - CFDictionarySetValue(new_active_dict, kIdentifier, sig_id); - serviceID = CFDictionaryGetValue(service, kServiceID); - id_list = CFArrayCreate(NULL, (const void * *)&serviceID, 1, - &kCFTypeArrayCallBacks); - CFDictionarySetValue(new_active_dict, kServiceIdentifiers, - id_list); - CFArrayAppendValue(active_signatures, new_active_dict); - CFRelease(new_active_dict); - CFRelease(id_list); - } - else { - /* signature already active, add this serviceID */ - CFRange range; - - id_list = CFDictionaryGetValue(active_dict, - kServiceIdentifiers); - range = CFRangeMake(0, CFArrayGetCount(id_list)); - serviceID = CFDictionaryGetValue(service, kServiceID); - if (CFArrayContainsValue(id_list, range, serviceID) == FALSE) { - CFMutableDictionaryRef new_active_dict; - CFMutableArrayRef new_id_list; - - new_id_list = CFArrayCreateMutableCopy(NULL, 0, id_list); - CFArrayAppendValue(new_id_list, serviceID); - new_active_dict - = CFDictionaryCreateMutableCopy(NULL, 0, active_dict); - CFDictionarySetValue(new_active_dict, kServiceIdentifiers, - new_id_list); - CFArraySetValueAtIndex(active_signatures, where, - new_active_dict); - CFRelease(new_active_dict); - CFRelease(new_id_list); - } - } - } - done: - if (active_signatures == NULL - || CFArrayGetCount(active_signatures) == 0) { - update_store - = ServiceWatcherSetActiveSignatures(watcher, NULL); - } - else { - update_store - = ServiceWatcherSetActiveSignatures(watcher, active_signatures); - } - if (save_signatures) { - /* write out the file */ - ServiceWatcherSaveSignatures(watcher); - } - - if (service_list != NULL) { - CFRelease(service_list); - } - if (active_signatures != NULL) { - CFRelease(active_signatures); - } - if (update_signatures || update_store) { - if (ServiceWatcherPublishActiveIdentifiers(watcher)) { - notify_post(kSCNetworkSignatureActiveChangedNotifyName); - } - } - return; -} - -static Boolean -update_primary_ipv4(ServiceWatcherRef watcher) -{ - Boolean changed = FALSE; - CFDictionaryRef global_ipv4; - - global_ipv4 = SCDynamicStoreCopyValue(watcher->store, - watcher->state_ipv4_key); - if (isA_CFDictionary(global_ipv4) != NULL) { - CFStringRef primary_ipv4; - - primary_ipv4 - = CFDictionaryGetValue(global_ipv4, - kSCDynamicStorePropNetPrimaryService); - changed = ServiceWatcherSetPrimaryIPv4(watcher, - isA_CFString(primary_ipv4)); - } - if (global_ipv4 != NULL) { - CFRelease(global_ipv4); - } - return (changed); -} - -static void -ServiceWatcherNotifier(SCDynamicStoreRef not_used, CFArrayRef changes, - void * info) -{ - int count; - int i; - Boolean order_changed = FALSE; - Boolean global_ipv4_changed = FALSE; - Boolean primary_ipv4_changed = FALSE; - ServiceWatcherRef watcher = (ServiceWatcherRef)info; - - count = CFArrayGetCount(changes); - if (count == 0) { - return; - } - for (i = 0; i < count; i++) { - CFStringRef key = CFArrayGetValueAtIndex(changes, i); - - if (CFStringHasPrefix(key, kSCDynamicStoreDomainSetup)) { - order_changed = TRUE; - } - else if (CFEqual(key, watcher->state_ipv4_key)) { - global_ipv4_changed = TRUE; - } - } - if (global_ipv4_changed) { - primary_ipv4_changed = update_primary_ipv4(watcher); - } - if (count == 1 - && (order_changed || primary_ipv4_changed)) { - /* just the service order or the primary service changed */ - if (ServiceWatcherPublishActiveIdentifiers(watcher)) { - notify_post(kSCNetworkSignatureActiveChangedNotifyName); - } - } - else { - ServiceWatcherUpdate(watcher, order_changed || primary_ipv4_changed); - } - return; -} - -static ServiceWatcherRef -ServiceWatcherCreate() -{ - SCDynamicStoreContext context = { 0, 0, 0, 0, 0}; - CFArrayRef patterns; - CFStringRef keys[2]; - CFArrayRef key_list; - ServiceWatcherRef watcher; - - watcher = malloc(sizeof(*watcher)); - bzero(watcher, sizeof(*watcher)); - context.info = watcher; - watcher->store = SCDynamicStoreCreate(NULL, CFSTR("Service Watcher"), - ServiceWatcherNotifier, &context); - if (watcher->store == NULL) { - SCLog(TRUE, LOG_NOTICE, CFSTR("SCDynamicStoreCreate failed: %s"), - SCErrorString(SCError())); - goto failed; - } - watcher->setup_ipv4_key - = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, - kSCDynamicStoreDomainSetup, - kSCEntNetIPv4); - watcher->state_ipv4_key - = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, - kSCDynamicStoreDomainState, - kSCEntNetIPv4); - keys[0] = watcher->setup_ipv4_key; - keys[1] = watcher->state_ipv4_key; - key_list = CFArrayCreate(NULL, (const void * *)keys, sizeof(keys) / sizeof(keys[0]), - &kCFTypeArrayCallBacks); - patterns = ServiceWatcherNotificationPatterns(); - (void)SCDynamicStoreSetNotificationKeys(watcher->store, key_list, patterns); - CFRelease(patterns); - CFRelease(key_list); - watcher->rls = SCDynamicStoreCreateRunLoopSource(NULL, watcher->store, 0); - CFRunLoopAddSource(CFRunLoopGetCurrent(), watcher->rls, - kCFRunLoopDefaultMode); - ServiceWatcherLoadSignatures(watcher); - update_primary_ipv4(watcher); - return (watcher); - failed: - ServiceWatcherFree(&watcher); - return (NULL); -} - -void -ServiceWatcherFree(ServiceWatcherRef * watcher_p) -{ - ServiceWatcherRef watcher; - - if (watcher_p == NULL) { - return; - } - watcher = *watcher_p; - if (watcher == NULL) { - return; - } - *watcher_p = NULL; - if (watcher->store != NULL) { - CFRelease(watcher->store); - watcher->store = NULL; - } - if (watcher->rls != NULL) { - CFRunLoopSourceInvalidate(watcher->rls); - CFRelease(watcher->rls); - watcher->rls = NULL; - } - if (watcher->signatures != NULL) { - CFRelease(watcher->signatures); - watcher->signatures = NULL; - } - if (watcher->state_ipv4_key != NULL) { - CFRelease(watcher->state_ipv4_key); - watcher->state_ipv4_key = NULL; - } - if (watcher->setup_ipv4_key != NULL) { - CFRelease(watcher->setup_ipv4_key); - watcher->setup_ipv4_key = NULL; - } - free(watcher); - return; -} - -/* global service watcher instance */ -static ServiceWatcherRef S_watcher; - -__private_extern__ -void -prime_NetworkIdentification() -{ - if (S_NetworkIdentification_disabled) { - return; - } - S_watcher = ServiceWatcherCreate(); - ServiceWatcherUpdate(S_watcher, TRUE); -} - -__private_extern__ -void -load_NetworkIdentification(CFBundleRef bundle, Boolean bundleVerbose) -{ - if (bundleVerbose) { - S_NetworkIdentification_debug = 1; - } - return; -} - -#ifdef TEST_NETWORKIDENTIFICATION -#undef TEST_NETWORKIDENTIFICATION - -int -main(int argc, char **argv) -{ - _sc_log = FALSE; - _sc_verbose = (argc > 1) ? TRUE : FALSE; - - load_NetworkIdentification(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE); - prime_NetworkIdentification(); - CFRunLoopRun(); - /* not reached */ - exit(0); - return 0; -} -#endif - diff --git a/Plugins/PreferencesMonitor/Info.plist b/Plugins/PreferencesMonitor/Info.plist index bc7fbcb..8cf44b4 100644 --- a/Plugins/PreferencesMonitor/Info.plist +++ b/Plugins/PreferencesMonitor/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.11.3 + 1.12 CFBundleSignature ???? CFBundleVersion - 1.11 + 1.12 Builtin Requires diff --git a/Plugins/PreferencesMonitor/prefsmon.c b/Plugins/PreferencesMonitor/prefsmon.c index bd496eb..0200299 100644 --- a/Plugins/PreferencesMonitor/prefsmon.c +++ b/Plugins/PreferencesMonitor/prefsmon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2008, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2008, 2010, 2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -72,6 +72,7 @@ establishNewPreferences() { CFBundleRef bundle; SCNetworkSetRef current = NULL; + CFStringRef new_model; Boolean ok = FALSE; int sc_status = kSCStatusFailed; SCNetworkSetRef set = NULL; @@ -95,6 +96,59 @@ establishNewPreferences() } } + /* Ensure that the preferences has the new model */ + new_model = _SC_hw_model(); + + /* Need to regenerate the new configuration for new model */ + if (new_model != NULL) { + CFStringRef old_model; + + old_model = SCPreferencesGetValue(prefs, MODEL); + if ((old_model != NULL) && !_SC_CFEqual(old_model, new_model)) { + CFIndex count; + CFIndex index; + CFArrayRef keys; + + keys = SCPreferencesCopyKeyList(prefs); + count = (keys != NULL) ? CFArrayGetCount(keys) : 0; + // if new hardware + for (index = 0; index < count; index++) { + CFStringRef existing_key; + + existing_key = CFArrayGetValueAtIndex(keys, index); + + if (isA_CFString(existing_key) != NULL) { + CFStringRef new_key; + CFPropertyListRef value; + + /* If it already contains a Model + or if it already contains a MODEL:KEY key skip it*/ + if (CFEqual(existing_key, MODEL) + || CFStringFind(existing_key, CFSTR(":"), 0).location + != kCFNotFound) { + continue; + } + + value = SCPreferencesGetValue(prefs, existing_key); + + /* Create a new key as OLD_MODEL:OLD_KEY */ + new_key = CFStringCreateWithFormat(NULL, NULL, CFSTR("%@:%@"), + old_model, existing_key); + SCPreferencesSetValue(prefs, new_key, value); + SCPreferencesRemoveValue(prefs, existing_key); + CFRelease(new_key); + } + } + + if (keys != NULL) { + CFRelease(keys); + } + } + + /* Set the new model */ + SCPreferencesSetValue(prefs, MODEL, new_model); + } + current = SCNetworkSetCopyCurrent(prefs); if (current != NULL) { set = current; @@ -569,11 +623,18 @@ updateSCDynamicStore(SCPreferencesRef prefs) } /* Update the dynamic store */ +#ifndef MAIN if (!SCDynamicStoreSetMultiple(store, newPrefs, removedPrefsKeys, NULL)) { SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSetMultiple() failed: %s"), SCErrorString(SCError())); } +#else // !MAIN + SCLog(TRUE, LOG_NOTICE, + CFSTR("SCDynamicStore\nset: %@\nremove: %@\n"), + newPrefs, + removedPrefsKeys); +#endif // !MAIN CFRelease(currentPrefs); CFRelease(newPrefs); @@ -663,15 +724,37 @@ load_PreferencesMonitor(CFBundleRef bundle, Boolean bundleVerbose) } /* open a SCPreferences session */ +#ifndef MAIN prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), NULL); +#else // !MAIN + prefs = SCPreferencesCreate(NULL, CFSTR("PreferencesMonitor.bundle"), CFSTR("/tmp/preferences.plist")); +#endif // !MAIN if (prefs != NULL) { - SCNetworkSetRef current; + Boolean need_update = FALSE; + CFStringRef new_model; - current = SCNetworkSetCopyCurrent(prefs); - if (current != NULL) { - /* network configuration available, disable template creation */ - initPrefs = FALSE; - CFRelease(current); + new_model = _SC_hw_model(); + + /* Need to regenerate the new configuration for new model */ + if (new_model != NULL) { + CFStringRef old_model; + + old_model = SCPreferencesGetValue(prefs, MODEL); + if (old_model != NULL && !_SC_CFEqual(old_model, new_model)) { + // if new hardware + need_update = TRUE; + } + } + + if (need_update == FALSE) { + SCNetworkSetRef current; + + current = SCNetworkSetCopyCurrent(prefs); + if (current != NULL) { + /* network configuration available, disable template creation */ + initPrefs = FALSE; + CFRelease(current); + } } } else { SCLog(TRUE, LOG_ERR, diff --git a/Plugins/SCNetworkReachability/Info.plist b/Plugins/SCNetworkReachability/Info.plist new file mode 100644 index 0000000..172cd34 --- /dev/null +++ b/Plugins/SCNetworkReachability/Info.plist @@ -0,0 +1,26 @@ + + + + + Builtin + + CFBundleDevelopmentRegion + English + CFBundleExecutable + SCNetworkReachability + CFBundleIdentifier + com.apple.SystemConfiguration.SCNetworkReachability + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + com.apple.SystemConfiguration.SCNetworkReachability + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.12 + CFBundleSignature + ???? + CFBundleVersion + 1.12 + + diff --git a/Plugins/SCNetworkReachability/Makefile b/Plugins/SCNetworkReachability/Makefile new file mode 100644 index 0000000..d1576e4 --- /dev/null +++ b/Plugins/SCNetworkReachability/Makefile @@ -0,0 +1,56 @@ +ARCHS = -arch i386 -arch x86_64 +CFLAGS = -Wall -pipe -O0 -gdwarf-2 + +REACH_SERVER_C = ../../SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_server.c + +REACH_SERVER_PLIST = /Library/LaunchDaemons/com.apple.SCNetworkReachability.plist +SYMROOT = ${shell basename ${shell dirname ${shell dirname ${PWD}}}} + +all: /var/tmp/reach_server ${REACH_SERVER_PLIST} + +${REACH_SERVER_PLIST}: Makefile + @sudo mkdir -p ${shell dirname ${REACH_SERVER_PLIST}} + @sudo launchctl unload -w ${REACH_SERVER_PLIST} > /dev/null 2>&1 || /usr/bin/true + @sudo rm -f ${REACH_SERVER_PLIST} + @sudo defaults write ${REACH_SERVER_PLIST} Label \ + SCNetworkReachability-DEBUG + @sudo defaults write ${REACH_SERVER_PLIST} MachServices \ + -dict \ + SCNetworkReachability-DEBUG \ + -bool TRUE + @sudo defaults write ${REACH_SERVER_PLIST} Program \ + /var/tmp/reach_server + @sudo defaults write ${REACH_SERVER_PLIST} ProgramArguments \ + -array \ + SCNetworkReachability-DEBUG \ + verbose + @sudo defaults write ${REACH_SERVER_PLIST} EnvironmentVariables \ + -dict \ + DYLD_FRAMEWORK_PATH \ + ${BUILDIT_DIR}/${SYMROOT}.roots/${SYMROOT}~sym \ + REACH_SERVER \ + SCNetworkReachability-DEBUG + @sudo defaults write ${REACH_SERVER_PLIST} ThrottleInterval \ + -int 5 + @sudo chown root:wheel ${REACH_SERVER_PLIST} + @sudo chmod 644 ${REACH_SERVER_PLIST} + sudo launchctl load -w ${REACH_SERVER_PLIST} + +reach_server.o: ${REACH_SERVER_C} + cc ${ARCHS} ${CFLAGS} -DMAIN -I ../../SystemConfiguration.fproj -F ${BUILDIT_DIR}/${SYMROOT}.roots/${SYMROOT}~sym -c -o reach_server.o ${REACH_SERVER_C} + +reach_server: reach_server.o + cc ${ARCHS} -o reach_server reach_server.o -framework CoreFoundation -F ${BUILDIT_DIR}/${SYMROOT}.roots/${SYMROOT}~sym -framework SystemConfiguration + dsymutil reach_server -o reach_server.dSYM + +/var/tmp/reach_server: reach_server + @sudo rm -f /var/tmp/reach_server + cp -p reach_server /var/tmp/reach_server + @sudo chown root:wheel /var/tmp/reach_server + @sudo chmod 755 /var/tmp/reach_server + +clean: + sudo launchctl unload -w ${REACH_SERVER_PLIST} > /dev/null 2>&1 || /usr/bin/true + @sudo rm -f ${REACH_SERVER_PLIST} + @sudo rm -rf /var/tmp/reach_server + rm -rf *.o reach_server reach_server.dSYM diff --git a/Plugins/common/cache.c b/Plugins/common/cache.c index fbc326f..fe4e0de 100644 --- a/Plugins/common/cache.c +++ b/Plugins/common/cache.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2003, 2004, 2006, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -81,6 +81,7 @@ cache_SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key) CFRangeMake(0, CFArrayGetCount(cached_removals)), key)) { // if we have "removed" the key + _SCErrorSet(kSCStatusNoKey); return NULL; } diff --git a/SCMonitor/Info.plist b/SCMonitor/Info.plist index 8789a63..153ad6f 100644 --- a/SCMonitor/Info.plist +++ b/SCMonitor/Info.plist @@ -15,11 +15,11 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 1.11.3 + 1.12 CFBundleSignature ???? CFBundleVersion - 1.11 + 1.12 CFPlugInDynamicRegistration NO CFPlugInFactories diff --git a/SCMonitor/monitor.c b/SCMonitor/monitor.c index a7d3fef..ca34028 100644 --- a/SCMonitor/monitor.c +++ b/SCMonitor/monitor.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2011 Apple Inc. All rights reserved. + * Copyright (c) 2007-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -61,9 +61,10 @@ * "Configure" Automatically configure this interface without any * intervention. * - * Note: automatic configuration may require authorization if the logged - * in user is NOT "root" (eUID==0) or if the "system.preferences" - * administrator right is not currently available. + * Note: automatic configuration may not be possible if the logged in user + * is NOT "root" (eUID==0) or if the authorization right that governs + * SCHelper write operations (kSCPreferencesWriteAuthorizationRight) + * is not currently available. * * An [older] "User Intervention" key is also supported. That CFBoolean * key, if present and TRUE, implies "Configure" configuration of the @@ -144,7 +145,7 @@ hasAuthorization(MyType *myInstance) AuthorizationRights rights; OSStatus status; - items[0].name = "system.preferences"; + items[0].name = kSCPreferencesWriteAuthorizationRight; items[0].value = NULL; items[0].valueLength = 0; items[0].flags = 0; @@ -606,7 +607,8 @@ updateInterfaceList(MyType *myInstance) } CFArrayAppendValue(myInstance->interfaces_configure, interface); } else if (hasAuthorization(myInstance)) { - // if we already have the "admin" (system.preferences) right, configure automatically (without user intervention) + // if we already have the "admin" (kSCPreferencesWriteAuthorizationRight) + // right, configure automatically (without user intervention) if (myInstance->interfaces_configure == NULL) { myInstance->interfaces_configure = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } @@ -797,7 +799,8 @@ update_node(void *refCon, io_service_t service, natural_t messageType, void *mes MyType *myInstance; MyNode *myNode; - myNode = (MyNode *)CFDataGetBytePtr(myData); + /* ALIGN: CF aligns to at least >8 bytes */ + myNode = (MyNode *)(void *)CFDataGetBytePtr(myData); myInstance = myNode->myInstance; switch (messageType) { @@ -871,7 +874,10 @@ add_node_watcher(MyType *myInstance, io_registry_entry_t node, io_registry_entry // wait for initialization to complete myData = CFDataCreateMutable(NULL, sizeof(MyNode)); CFDataSetLength(myData, sizeof(MyNode)); - myNode = (MyNode *)CFDataGetBytePtr(myData); + + /* ALIGN: CF aligns to at least >8 bytes */ + myNode = (MyNode *)(void *)CFDataGetBytePtr(myData); + bzero(myNode, sizeof(MyNode)); if (interface != MACH_PORT_NULL) { IOObjectRetain(interface); @@ -1034,7 +1040,10 @@ watcher_remove_serial(MyType *myInstance) MyNode *myNode; myData = CFArrayGetValueAtIndex(myInstance->notifyNodes, i); - myNode = (MyNode *)CFDataGetBytePtr(myData); + + /* ALIGN: CF aligns to at least >8 bytes */ + myNode = (MyNode *)(void *)CFDataGetBytePtr(myData); + if (myNode->interface != MACH_PORT_NULL) { IOObjectRelease(myNode->interface); } diff --git a/SystemConfiguration.fproj/BridgeConfiguration.c b/SystemConfiguration.fproj/BridgeConfiguration.c index 806856c..3124eb1 100644 --- a/SystemConfiguration.fproj/BridgeConfiguration.c +++ b/SystemConfiguration.fproj/BridgeConfiguration.c @@ -279,12 +279,14 @@ SCBridgeInterfaceCopyAvailableMemberInterfaces(SCPreferencesRef prefs) available = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); excluded = CFSetCreateMutable (NULL, 0, &kCFTypeSetCallBacks); +#if !TARGET_OS_IPHONE // exclude Bond [member] interfaces interfaces = SCBondInterfaceCopyAll(prefs); if (interfaces != NULL) { __SCBondInterfaceListCollectMembers(interfaces, excluded); CFRelease(interfaces); } +#endif // !TARGET_OS_IPHONE // exclude Bridge [member] interfaces interfaces = SCBridgeInterfaceCopyAll(prefs); diff --git a/SystemConfiguration.fproj/CaptiveNetwork.c b/SystemConfiguration.fproj/CaptiveNetwork.c index 413ebce..f295bb6 100644 --- a/SystemConfiguration.fproj/CaptiveNetwork.c +++ b/SystemConfiguration.fproj/CaptiveNetwork.c @@ -33,9 +33,13 @@ #pragma mark - #pragma mark CaptiveNetwork.framework APIs (exported through the SystemConfiguration.framework) + +#if TARGET_OS_EMBEDDED const CFStringRef kCNNetworkInfoKeySSIDData = CFSTR("SSIDDATA"); const CFStringRef kCNNetworkInfoKeySSID = CFSTR("SSID"); const CFStringRef kCNNetworkInfoKeyBSSID = CFSTR("BSSID"); +#endif // TARGET_OS_EMBEDDED + static void * __loadCaptiveNetwork(void) { @@ -104,6 +108,8 @@ CNCopySupportedInterfaces(void) return dyfunc ? dyfunc() : NULL; } + +#if TARGET_OS_EMBEDDED CFDictionaryRef CNCopyCurrentNetworkInfo(CFStringRef interfaceName) { @@ -114,3 +120,4 @@ CNCopyCurrentNetworkInfo(CFStringRef interfaceName) } return dyfunc ? dyfunc(interfaceName) : NULL; } +#endif // TARGET_OS_EMBEDDED diff --git a/SystemConfiguration.fproj/CaptiveNetwork.h b/SystemConfiguration.fproj/CaptiveNetwork.h index 78d8fb9..12fd409 100644 --- a/SystemConfiguration.fproj/CaptiveNetwork.h +++ b/SystemConfiguration.fproj/CaptiveNetwork.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -56,15 +56,22 @@ __BEGIN_DECLS @function CNSetSupportedSSIDs @discussion Provides Captive Network Support with an updated list of SSIDs that this application will perform authentication on. - When Captive Network Support would show the Web Sheet for a - network with an SSID the application has registered for, it - will suppress showing the Web Sheet if the application is - still installed. + + Captive Network Support suppresses showing the Web Sheet + for a captive Wi-Fi network if that network's SSID is in the + specified list. + + On iOS, the registrations persist until the application is + removed from the device. + + On MacOSX, the registrations persist as long as the application + is running. + @param ssidArray A CFArray of CFStrings of the SSIDs. @result Returns TRUE if the operation succeeded, FALSE otherwise. */ Boolean -CNSetSupportedSSIDs (CFArrayRef ssidArray) __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0); +CNSetSupportedSSIDs (CFArrayRef ssidArray) __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_4_0); /*! @function CNMarkPortalOnline @@ -76,7 +83,7 @@ CNSetSupportedSSIDs (CFArrayRef ssidArray) __OSX_AVAILABLE_STARTING(__MAC_NA,__ @result Returns TRUE if the operation succeeded, FALSE otherwise. */ Boolean -CNMarkPortalOnline (CFStringRef interfaceName) __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0); +CNMarkPortalOnline (CFStringRef interfaceName) __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_4_0); /*! @function CNMarkPortalOffline @@ -86,7 +93,7 @@ CNMarkPortalOnline (CFStringRef interfaceName) __OSX_AVAILABLE_STARTING(__MAC_N @result Returns TRUE if the operation succeeded, FALSE otherwise. */ Boolean -CNMarkPortalOffline (CFStringRef interfaceName) __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_0); +CNMarkPortalOffline (CFStringRef interfaceName) __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_4_0); /*! @@ -97,7 +104,9 @@ CNMarkPortalOffline (CFStringRef interfaceName) __OSX_AVAILABLE_STARTING(__MAC_ You MUST release the returned value. */ CFArrayRef -CNCopySupportedInterfaces (void) __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_1); +CNCopySupportedInterfaces (void) __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_4_1); + +#if TARGET_OS_EMBEDDED /*! @constant kCNNetworkInfoKeySSIDData @@ -139,6 +148,8 @@ extern const CFStringRef kCNNetworkInfoKeyBSSID __OSX_AVAILABLE_STARTING(__MAC CFDictionaryRef CNCopyCurrentNetworkInfo (CFStringRef interfaceName) __OSX_AVAILABLE_STARTING(__MAC_NA,__IPHONE_4_1); +#endif // TARGET_OS_EMBEDDED + __END_DECLS #endif /* _CAPTIVENETWORK_H */ diff --git a/SystemConfiguration.fproj/DHCP.c b/SystemConfiguration.fproj/DHCP.c index 2a8b390..873046d 100644 --- a/SystemConfiguration.fproj/DHCP.c +++ b/SystemConfiguration.fproj/DHCP.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001, 2003-2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2001, 2003-2005, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -90,7 +90,7 @@ my_CFArrayAppendUniqueValue(CFMutableArrayRef arr, CFTypeRef new) return; } -static __inline__ CFStringRef +static __inline__ CF_RETURNS_RETAINED CFStringRef S_application_path(CFStringRef applicationID) { return (CFStringCreateWithFormat(NULL, NULL, @@ -240,19 +240,8 @@ SCDynamicStoreCopyDHCPInfo(SCDynamicStoreRef store, CFStringRef serviceID) { CFDictionaryRef dhcp_dict = NULL; CFStringRef key = NULL; - boolean_t needs_close = FALSE; CFDictionaryRef primary_dict = NULL; - if (store == NULL) { - needs_close = TRUE; - store = SCDynamicStoreCreate(NULL, - CFSTR("SCDynamicStoreCopyDHCPInfo"), - NULL, NULL); - if (store == NULL) { - goto done; - } - } - if (serviceID == NULL) { /* get the primary service name */ key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, @@ -287,9 +276,6 @@ SCDynamicStoreCopyDHCPInfo(SCDynamicStoreRef store, CFStringRef serviceID) if (primary_dict) { CFRelease(primary_dict); } - if (needs_close == TRUE && store != NULL) { - CFRelease(store); - } return (dhcp_dict); } @@ -319,6 +305,12 @@ DHCPInfoGetLeaseStartTime(CFDictionaryRef dhcp_dict) return (CFDictionaryGetValue(dhcp_dict, CFSTR("LeaseStartTime"))); } +CFDateRef +DHCPInfoGetLeaseExpirationTime(CFDictionaryRef dhcp_dict) +{ + return (CFDictionaryGetValue(dhcp_dict, CFSTR("LeaseExpirationTime"))); +} + #ifdef TEST_DHCPCLIENT_PREFERENCES void print_data(u_char * data_p, int n_bytes) @@ -626,5 +618,5 @@ main(int argc, char * argv[]) exit(0); return(0); } -#endif TEST_DHCPCLIENT_PREFERENCES +#endif // TEST_DHCPCLIENT_PREFERENCES diff --git a/SystemConfiguration.fproj/English.lproj/NetworkInterface.strings b/SystemConfiguration.fproj/English.lproj/NetworkInterface.strings index c88493f..2ea9adb 100644 Binary files a/SystemConfiguration.fproj/English.lproj/NetworkInterface.strings and b/SystemConfiguration.fproj/English.lproj/NetworkInterface.strings differ diff --git a/SystemConfiguration.fproj/Info-Embedded.plist b/SystemConfiguration.fproj/Info-Embedded.plist index e399493..f9008ac 100644 --- a/SystemConfiguration.fproj/Info-Embedded.plist +++ b/SystemConfiguration.fproj/Info-Embedded.plist @@ -7,7 +7,7 @@ CFBundleExecutable SystemConfiguration CFBundleGetInfoString - 1.11 + 1.12 CFBundleIdentifier com.apple.SystemConfiguration CFBundleInfoDictionaryVersion @@ -17,10 +17,10 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.11.3 + 1.12 CFBundleSignature ???? CFBundleVersion - 1.11 + 1.12 diff --git a/SystemConfiguration.fproj/Info.plist b/SystemConfiguration.fproj/Info.plist index e399493..f9008ac 100644 --- a/SystemConfiguration.fproj/Info.plist +++ b/SystemConfiguration.fproj/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable SystemConfiguration CFBundleGetInfoString - 1.11 + 1.12 CFBundleIdentifier com.apple.SystemConfiguration CFBundleInfoDictionaryVersion @@ -17,10 +17,10 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.11.3 + 1.12 CFBundleSignature ???? CFBundleVersion - 1.11 + 1.12 diff --git a/SystemConfiguration.fproj/SCD.c b/SystemConfiguration.fproj/SCD.c index 5f92caa..43a2101 100644 --- a/SystemConfiguration.fproj/SCD.c +++ b/SystemConfiguration.fproj/SCD.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2008, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2008, 2010, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -39,6 +39,7 @@ #include #include +#include "SCD.h" #include "SCDynamicStoreInternal.h" #include "config.h" /* MiG generated file */ @@ -55,12 +56,6 @@ int _sc_log = TRUE; /* 0 if SC messages should be written to stdout/stderr, #pragma mark Thread specific data -typedef struct { - aslclient _asl; - int _sc_error; -} __SCThreadSpecificData, *__SCThreadSpecificDataRef; - - static pthread_once_t tsKeyInitialized = PTHREAD_ONCE_INIT; static pthread_key_t tsDataKey; @@ -71,7 +66,8 @@ __SCThreadSpecificDataFinalize(void *arg) __SCThreadSpecificDataRef tsd = (__SCThreadSpecificDataRef)arg; if (tsd != NULL) { - if (tsd->_asl != NULL) asl_close(tsd->_asl); + if (tsd->_asl != NULL) asl_close(tsd->_asl); + if (tsd->_sc_store != NULL) CFRelease(tsd->_sc_store); CFAllocatorDeallocate(kCFAllocatorSystemDefault, tsd); } return; @@ -86,7 +82,8 @@ __SCThreadSpecificKeyInitialize() } -static __SCThreadSpecificDataRef +__private_extern__ +__SCThreadSpecificDataRef __SCGetThreadSpecificData() { __SCThreadSpecificDataRef tsd; @@ -96,9 +93,9 @@ __SCGetThreadSpecificData() tsd = pthread_getspecific(tsDataKey); if (tsd == NULL) { tsd = CFAllocatorAllocate(kCFAllocatorSystemDefault, sizeof(__SCThreadSpecificData), 0); - tsd->_asl = asl_open(NULL, NULL, 0); - asl_set_filter(tsd->_asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); + tsd->_asl = NULL; tsd->_sc_error = kSCStatusOK; + tsd->_sc_store = NULL; pthread_setspecific(tsDataKey, tsd); } @@ -370,6 +367,10 @@ __SCLog(aslclient asl, aslmsg msg, int level, CFStringRef formatString, va_list __SCThreadSpecificDataRef tsd; tsd = __SCGetThreadSpecificData(); + if (tsd->_asl == NULL) { + tsd->_asl = asl_open(NULL, NULL, 0); + asl_set_filter(tsd->_asl, ASL_FILTER_MASK_UPTO(ASL_LEVEL_DEBUG)); + } asl = tsd->_asl; } diff --git a/SystemConfiguration.fproj/SCD.h b/SystemConfiguration.fproj/SCD.h new file mode 100644 index 0000000..78a3c35 --- /dev/null +++ b/SystemConfiguration.fproj/SCD.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2011 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, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * 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@ + */ + +#ifndef _SCD_H +#define _SCD_H + +#include +#include +#include +#include +#include + + +typedef struct { + aslclient _asl; + int _sc_error; + SCDynamicStoreRef _sc_store; +} __SCThreadSpecificData, *__SCThreadSpecificDataRef; + + + +__BEGIN_DECLS + +__SCThreadSpecificDataRef +__SCGetThreadSpecificData (void); + +__END_DECLS + +#endif /* _SCD_H */ diff --git a/SystemConfiguration.fproj/SCDAdd.c b/SystemConfiguration.fproj/SCDAdd.c index 74c9bd1..767277d 100644 --- a/SystemConfiguration.fproj/SCDAdd.c +++ b/SystemConfiguration.fproj/SCDAdd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2005, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -89,21 +89,11 @@ SCDynamicStoreAddTemporaryValue(SCDynamicStoreRef store, CFStringRef key, CFProp &newInstance, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreAddTemporaryValue configadd_s(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreAddTemporaryValue configadd_s()")) { + goto retry; } /* clean up */ @@ -121,7 +111,7 @@ SCDynamicStoreAddTemporaryValue(SCDynamicStoreRef store, CFStringRef key, CFProp Boolean SCDynamicStoreAddValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; + SCDynamicStorePrivateRef storePrivate; kern_return_t status; CFDataRef utfKey; /* serialized key */ xmlData_t myKeyRef; @@ -133,11 +123,15 @@ SCDynamicStoreAddValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListR int sc_status; if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return FALSE; + store = __SCDynamicStoreNullSession(); + if (store == NULL) { + /* sorry, you must provide a session */ + _SCErrorSet(kSCStatusNoStoreSession); + return FALSE; + } } + storePrivate = (SCDynamicStorePrivateRef)store; if (storePrivate->server == MACH_PORT_NULL) { /* sorry, you must have an open session to play */ _SCErrorSet(kSCStatusNoStoreServer); @@ -168,21 +162,11 @@ SCDynamicStoreAddValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListR &newInstance, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreAddValue configadd(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreAddValue configadd()")) { + goto retry; } /* clean up */ diff --git a/SystemConfiguration.fproj/SCDConsoleUser.c b/SystemConfiguration.fproj/SCDConsoleUser.c index 0504412..58cb1c6 100644 --- a/SystemConfiguration.fproj/SCDConsoleUser.c +++ b/SystemConfiguration.fproj/SCDConsoleUser.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005, 2009 Apple Inc. All rights reserved. + * Copyright (c) 2000-2005, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -86,18 +86,6 @@ SCDynamicStoreCopyConsoleUser(SCDynamicStoreRef store, CFStringRef consoleUser = NULL; CFDictionaryRef dict = NULL; CFStringRef key; - Boolean tempSession = FALSE; - - if (store == NULL) { - store = SCDynamicStoreCreate(NULL, - CFSTR("SCDynamicStoreCopyConsoleUser"), - NULL, - NULL); - if (store == NULL) { - return NULL; - } - tempSession = TRUE; - } key = SCDynamicStoreKeyCreateConsoleUser(NULL); dict = SCDynamicStoreCopyValue(store, key); @@ -142,7 +130,6 @@ SCDynamicStoreCopyConsoleUser(SCDynamicStoreRef store, done : - if (tempSession) CFRelease(store); if (dict) CFRelease(dict); return consoleUser; } @@ -154,18 +141,6 @@ SCDynamicStoreCopyConsoleInformation(SCDynamicStoreRef store) CFDictionaryRef dict = NULL; CFArrayRef info = NULL; CFStringRef key; - Boolean tempSession = FALSE; - - if (store == NULL) { - store = SCDynamicStoreCreate(NULL, - CFSTR("SCDynamicStoreCopyConsoleUser"), - NULL, - NULL); - if (store == NULL) { - return NULL; - } - tempSession = TRUE; - } key = SCDynamicStoreKeyCreateConsoleUser(NULL); dict = SCDynamicStoreCopyValue(store, key); @@ -186,7 +161,6 @@ SCDynamicStoreCopyConsoleInformation(SCDynamicStoreRef store) done : - if (tempSession) CFRelease(store); if (dict) CFRelease(dict); return info; } @@ -203,18 +177,6 @@ SCDynamicStoreSetConsoleInformation(SCDynamicStoreRef store, CFMutableDictionaryRef dict = NULL; CFStringRef key = SCDynamicStoreKeyCreateConsoleUser(NULL); Boolean ok = FALSE; - Boolean tempSession = FALSE; - - if (store == NULL) { - store = SCDynamicStoreCreate(NULL, - CFSTR("SCDynamicStoreSetConsoleUser"), - NULL, - NULL); - if (store == NULL) { - goto done; - } - tempSession = TRUE; - } if ((user == NULL) && (sessions == NULL)) { ok = SCDynamicStoreRemoveValue(store, key); @@ -252,7 +214,6 @@ SCDynamicStoreSetConsoleInformation(SCDynamicStoreRef store, if (dict) CFRelease(dict); if (key) CFRelease(key); - if (tempSession) CFRelease(store); return ok; } @@ -268,18 +229,6 @@ SCDynamicStoreSetConsoleUser(SCDynamicStoreRef store, CFStringRef key = SCDynamicStoreKeyCreateConsoleUser(NULL); CFNumberRef num; Boolean ok = FALSE; - Boolean tempSession = FALSE; - - if (store == NULL) { - store = SCDynamicStoreCreate(NULL, - CFSTR("SCDynamicStoreSetConsoleUser"), - NULL, - NULL); - if (store == NULL) { - goto done; - } - tempSession = TRUE; - } if (user == NULL) { ok = SCDynamicStoreRemoveValue(store, key); @@ -309,6 +258,5 @@ SCDynamicStoreSetConsoleUser(SCDynamicStoreRef store, if (dict) CFRelease(dict); if (key) CFRelease(key); - if (tempSession) CFRelease(store); return ok; } diff --git a/SystemConfiguration.fproj/SCDGet.c b/SystemConfiguration.fproj/SCDGet.c index 9ce5a19..16784d3 100644 --- a/SystemConfiguration.fproj/SCDGet.c +++ b/SystemConfiguration.fproj/SCDGet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2005, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -45,7 +45,7 @@ SCDynamicStoreCopyMultiple(SCDynamicStoreRef store, CFArrayRef keys, CFArrayRef patterns) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; + SCDynamicStorePrivateRef storePrivate; kern_return_t status; CFDataRef xmlKeys = NULL; /* keys (XML serialized) */ xmlData_t myKeysRef = NULL; /* keys (serialized) */ @@ -60,11 +60,15 @@ SCDynamicStoreCopyMultiple(SCDynamicStoreRef store, int sc_status; if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return NULL; + store = __SCDynamicStoreNullSession(); + if (store == NULL) { + /* sorry, you must provide a session */ + _SCErrorSet(kSCStatusNoStoreSession); + return NULL; + } } + storePrivate = (SCDynamicStorePrivateRef)store; if (storePrivate->server == MACH_PORT_NULL) { _SCErrorSet(kSCStatusNoStoreServer); return NULL; /* you must have an open session to play */ @@ -99,21 +103,11 @@ SCDynamicStoreCopyMultiple(SCDynamicStoreRef store, &xmlDictLen, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCopyMultiple configget_m(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreCopyMultiple configget_m()")) { + goto retry; } /* clean up */ @@ -144,7 +138,7 @@ SCDynamicStoreCopyMultiple(SCDynamicStoreRef store, CFPropertyListRef SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; + SCDynamicStorePrivateRef storePrivate; kern_return_t status; CFDataRef utfKey; /* key (XML serialized) */ xmlData_t myKeyRef; /* key (serialized) */ @@ -156,11 +150,15 @@ SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key) int sc_status; if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return NULL; + store = __SCDynamicStoreNullSession(); + if (store == NULL) { + /* sorry, you must provide a session */ + _SCErrorSet(kSCStatusNoStoreSession); + return NULL; + } } + storePrivate = (SCDynamicStorePrivateRef)store; if (storePrivate->server == MACH_PORT_NULL) { _SCErrorSet(kSCStatusNoStoreServer); return NULL; /* you must have an open session to play */ @@ -183,21 +181,11 @@ SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key) &newInstance, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCopyValue configget(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreCopyValue configget()")) { + goto retry; } /* clean up */ diff --git a/SystemConfiguration.fproj/SCDHostName.c b/SystemConfiguration.fproj/SCDHostName.c index 3a0e61f..d16f6d1 100644 --- a/SystemConfiguration.fproj/SCDHostName.c +++ b/SystemConfiguration.fproj/SCDHostName.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2008 Apple Inc. All rights reserved. + * Copyright (c) 2000-2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -111,21 +111,9 @@ CFStringRef SCDynamicStoreCopyComputerName(SCDynamicStoreRef store, CFStringEncoding *nameEncoding) { - CFDictionaryRef dict; + CFDictionaryRef dict = NULL; CFStringRef key; CFStringRef name = NULL; - Boolean tempSession = FALSE; - - if (store == NULL) { - store = SCDynamicStoreCreate(NULL, - CFSTR("SCDynamicStoreCopyComputerName"), - NULL, - NULL); - if (store == NULL) { - return NULL; - } - tempSession = TRUE; - } key = SCDynamicStoreKeyCreateComputerName(NULL); dict = SCDynamicStoreCopyValue(store, key); @@ -166,7 +154,6 @@ SCDynamicStoreCopyComputerName(SCDynamicStoreRef store, done : - if (tempSession) CFRelease(store); if (dict != NULL) CFRelease(dict); return name; } @@ -404,21 +391,9 @@ SCDynamicStoreKeyCreateHostNames(CFAllocatorRef allocator) CFStringRef SCDynamicStoreCopyLocalHostName(SCDynamicStoreRef store) { - CFDictionaryRef dict; + CFDictionaryRef dict = NULL; CFStringRef key; CFStringRef name = NULL; - Boolean tempSession = FALSE; - - if (store == NULL) { - store = SCDynamicStoreCreate(NULL, - CFSTR("SCDynamicStoreCopyLocalHostName"), - NULL, - NULL); - if (store == NULL) { - return NULL; - } - tempSession = TRUE; - } key = SCDynamicStoreKeyCreateHostNames(NULL); dict = SCDynamicStoreCopyValue(store, key); @@ -447,7 +422,6 @@ SCDynamicStoreCopyLocalHostName(SCDynamicStoreRef store) done : - if (tempSession) CFRelease(store); if (dict != NULL) CFRelease(dict); return name; } diff --git a/SystemConfiguration.fproj/SCDList.c b/SystemConfiguration.fproj/SCDList.c index 5ba13bb..f77c219 100644 --- a/SystemConfiguration.fproj/SCDList.c +++ b/SystemConfiguration.fproj/SCDList.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2005, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -42,7 +42,7 @@ CFArrayRef SCDynamicStoreCopyKeyList(SCDynamicStoreRef store, CFStringRef pattern) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; + SCDynamicStorePrivateRef storePrivate; kern_return_t status; CFDataRef utfPattern; /* serialized pattern */ xmlData_t myPatternRef; @@ -53,11 +53,15 @@ SCDynamicStoreCopyKeyList(SCDynamicStoreRef store, CFStringRef pattern) CFArrayRef allKeys; if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return NULL; + store = __SCDynamicStoreNullSession(); + if (store == NULL) { + /* sorry, you must provide a session */ + _SCErrorSet(kSCStatusNoStoreSession); + return NULL; + } } + storePrivate = (SCDynamicStorePrivateRef)store; if (storePrivate->server == MACH_PORT_NULL) { _SCErrorSet(kSCStatusNoStoreServer); return NULL; @@ -80,21 +84,11 @@ SCDynamicStoreCopyKeyList(SCDynamicStoreRef store, CFStringRef pattern) &xmlDataLen, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCopyKeyList configlist(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreCopyKeyList configlist()")) { + goto retry; } /* clean up */ diff --git a/SystemConfiguration.fproj/SCDLock.c b/SystemConfiguration.fproj/SCDLock.c deleted file mode 100644 index 90617fd..0000000 --- a/SystemConfiguration.fproj/SCDLock.c +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2000, 2001, 2004, 2005, 2009, 2010 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, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * 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@ - */ - -/* - * Modification History - * - * June 1, 2001 Allan Nathanson - * - public API conversion - * - * March 24, 2000 Allan Nathanson - * - initial revision - */ - -#include -#include - -#include -#include -#include "SCDynamicStoreInternal.h" -#include "config.h" /* MiG generated file */ - -Boolean -SCDynamicStoreLock(SCDynamicStoreRef store) -{ - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - kern_return_t status; - int sc_status; - - if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return FALSE; - } - - if (storePrivate->server == MACH_PORT_NULL) { - /* sorry, you must have an open session to play */ - _SCErrorSet(kSCStatusNoStoreServer); - return FALSE; - } - - retry : - - /* get the lock from the server */ - status = configlock(storePrivate->server, (int *)&sc_status); - - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreLock configlock(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; - } - - if (sc_status != kSCStatusOK) { - _SCErrorSet(sc_status); - return FALSE; - } - - return TRUE; -} diff --git a/SystemConfiguration.fproj/SCDNotifierAdd.c b/SystemConfiguration.fproj/SCDNotifierAdd.c index 40b7569..901278c 100644 --- a/SystemConfiguration.fproj/SCDNotifierAdd.c +++ b/SystemConfiguration.fproj/SCDNotifierAdd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2005, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -89,21 +89,11 @@ SCDynamicStoreAddWatchedKey(SCDynamicStoreRef store, CFStringRef key, Boolean is isRegex, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreAddWatchedKey notifyadd(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreAddWatchedKey notifyadd()")) { + goto retry; } /* clean up */ diff --git a/SystemConfiguration.fproj/SCDNotifierCancel.c b/SystemConfiguration.fproj/SCDNotifierCancel.c index ca0454d..673f2a5 100644 --- a/SystemConfiguration.fproj/SCDNotifierCancel.c +++ b/SystemConfiguration.fproj/SCDNotifierCancel.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005, 2008-2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2005, 2008-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -56,25 +56,6 @@ SCDynamicStoreNotifyCancel(SCDynamicStoreRef store) case NotifierNotRegistered : /* if no notifications have been registered */ return TRUE; - case Using_NotifierInformViaCallback : - /* invalidate and release the run loop source */ - if (storePrivate->callbackRLS != NULL) { - CFRunLoopSourceInvalidate(storePrivate->callbackRLS); - CFRelease(storePrivate->callbackRLS); - storePrivate->callbackRLS = NULL; - } - - /* invalidate and release the callback mach port */ - if (storePrivate->callbackPort != NULL) { - __MACH_PORT_DEBUG(TRUE, "*** SCDynamicStoreNotifyCancel", CFMachPortGetPort(storePrivate->callbackPort)); - CFMachPortInvalidate(storePrivate->callbackPort); - CFRelease(storePrivate->callbackPort); - storePrivate->callbackPort = NULL; - } - - storePrivate->callbackArgument = NULL; - storePrivate->callbackFunction = NULL; - break; case Using_NotifierInformViaRunLoop : CFRunLoopSourceInvalidate(storePrivate->rls); storePrivate->rls = NULL; @@ -93,21 +74,12 @@ SCDynamicStoreNotifyCancel(SCDynamicStoreRef store) } status = notifycancel(storePrivate->server, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCancel notifycancel(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if (((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) - && __SCDynamicStoreReconnect(store)) { - sc_status = kSCStatusOK; - } else { - sc_status = status; - } + + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreNotifyCancel notifycancel()")) { + sc_status = kSCStatusOK; } done : diff --git a/SystemConfiguration.fproj/SCDNotifierGetChanges.c b/SystemConfiguration.fproj/SCDNotifierGetChanges.c index bbfe5e4..cb8b7cc 100644 --- a/SystemConfiguration.fproj/SCDNotifierGetChanges.c +++ b/SystemConfiguration.fproj/SCDNotifierGetChanges.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003-2005, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003-2005, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -68,21 +68,11 @@ SCDynamicStoreCopyNotifiedKeys(SCDynamicStoreRef store) &xmlDataLen, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCopyNotifiedKeys notifychanges(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreCopyNotifiedKeys notifychanges()")) { + goto retry; } if (sc_status != kSCStatusOK) { diff --git a/SystemConfiguration.fproj/SCDNotifierInformViaCallback.c b/SystemConfiguration.fproj/SCDNotifierInformViaCallback.c index 166c0ce..cf3ec8e 100644 --- a/SystemConfiguration.fproj/SCDNotifierInformViaCallback.c +++ b/SystemConfiguration.fproj/SCDNotifierInformViaCallback.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005, 2008-2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2005, 2008-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -44,72 +44,6 @@ #include "config.h" /* MiG generated file */ -static void -informCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) -{ - SCDynamicStoreRef store = (SCDynamicStoreRef)info; - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - mach_no_senders_notification_t *buf = msg; - mach_msg_id_t msgid = buf->not_header.msgh_id; - SCDynamicStoreCallBack_v1 cbFunc = storePrivate->callbackFunction; - void *cbArg = storePrivate->callbackArgument; - - if (msgid == MACH_NOTIFY_NO_SENDERS) { - /* the server died, disable additional callbacks */ -#ifdef DEBUG - SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" notifier port closed, disabling notifier")); -#endif /* DEBUG */ - } else if (cbFunc == NULL) { - /* there is no (longer) a callback function, disable additional callbacks */ -#ifdef DEBUG - SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" no callback function, disabling notifier")); -#endif /* DEBUG */ - } else { -#ifdef DEBUG - SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" executing notification function")); -#endif /* DEBUG */ - if ((*cbFunc)(store, cbArg)) { - /* - * callback function returned success. - */ - return; - } else { -#ifdef DEBUG - SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" callback returned error, disabling notifier")); -#endif /* DEBUG */ - } - } - -#ifdef DEBUG - if (port != storePrivate->callbackPort) { - SCLog(_sc_verbose, LOG_DEBUG, CFSTR("informCallback, why is port != callbackPort?")); - } -#endif /* DEBUG */ - - /* invalidate the run loop source */ - if (storePrivate->callbackRLS != NULL) { - CFRunLoopSourceInvalidate(storePrivate->callbackRLS); - CFRelease(storePrivate->callbackRLS); - storePrivate->callbackRLS = NULL; - } - - /* invalidate port */ - if (storePrivate->callbackPort != NULL) { - __MACH_PORT_DEBUG(TRUE, "*** informCallback", CFMachPortGetPort(storePrivate->callbackPort)); - CFMachPortInvalidate(storePrivate->callbackPort); - CFRelease(storePrivate->callbackPort); - storePrivate->callbackPort = NULL; - } - - /* disable notifier */ - storePrivate->notifyStatus = NotifierNotRegistered; - storePrivate->callbackArgument = NULL; - storePrivate->callbackFunction = NULL; - - return; -} - - static CFStringRef notifyMPCopyDescription(const void *info) { @@ -122,141 +56,6 @@ notifyMPCopyDescription(const void *info) } -Boolean -SCDynamicStoreNotifyCallback(SCDynamicStoreRef store, - CFRunLoopRef runLoop, - SCDynamicStoreCallBack_v1 func, - void *arg) -{ - CFMachPortContext context = { 0 - , (void *)store - , CFRetain - , CFRelease - , notifyMPCopyDescription - }; - mach_port_t oldNotify; - mach_port_t port; - int sc_status; - kern_return_t status; - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - - if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return FALSE; - } - - if (storePrivate->server == MACH_PORT_NULL) { - /* sorry, you must have an open session to play */ - _SCErrorSet(kSCStatusNoStoreServer); - return FALSE; - } - - if (storePrivate->notifyStatus != NotifierNotRegistered) { - /* sorry, you can only have one notification registered at once */ - _SCErrorSet(kSCStatusNotifierActive); - return FALSE; - } - - /* Allocating port (for server response) */ - status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &port); - if (status != KERN_SUCCESS) { - SCLog(TRUE, LOG_ERR, CFSTR("mach_port_allocate(): %s"), mach_error_string(status)); - _SCErrorSet(status); - return FALSE; - } - - status = mach_port_insert_right(mach_task_self(), - port, - port, - MACH_MSG_TYPE_MAKE_SEND); - if (status != KERN_SUCCESS) { - /* - * We can't insert a send right into our own port! This should - * only happen if someone stomped on OUR port (so let's leave - * the port alone). - */ - SCLog(TRUE, LOG_ERR, CFSTR("mach_port_insert_right(): %s"), mach_error_string(status)); - _SCErrorSet(status); - return FALSE; - } - - /* Request a notification when/if the server dies */ - status = mach_port_request_notification(mach_task_self(), - port, - MACH_NOTIFY_NO_SENDERS, - 1, - port, - MACH_MSG_TYPE_MAKE_SEND_ONCE, - &oldNotify); - if (status != KERN_SUCCESS) { - /* - * We can't request a notification for our own port! This should - * only happen if someone stomped on OUR port (so let's leave - * the port alone). - */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCallback mach_port_request_notification(): %s"), mach_error_string(status)); - _SCErrorSet(status); - return FALSE; - } - - if (oldNotify != MACH_PORT_NULL) { - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCallback(): oldNotify != MACH_PORT_NULL")); - } - - retry : - - /* Requesting notification via mach port */ - status = notifyviaport(storePrivate->server, - port, - 0, - (int *)&sc_status); - - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyCallback notifyviaport(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - /* remove the send right that we tried (but failed) to pass to the server */ - (void) mach_port_deallocate(mach_task_self(), port); - } - - /* remove our receive right */ - (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1); - sc_status = status; - } - - if (sc_status != kSCStatusOK) { - _SCErrorSet(sc_status); - return FALSE; - } - - /* set notifier active */ - storePrivate->notifyStatus = Using_NotifierInformViaCallback; - - /* Creating/adding a run loop source for the port */ - __MACH_PORT_DEBUG(TRUE, "*** SCDynamicStoreNotifyCallback", port); - storePrivate->callbackArgument = arg; - storePrivate->callbackFunction = func; - storePrivate->callbackPort = _SC_CFMachPortCreateWithPort("SCDynamicStoreNotifyCallback", - port, - informCallback, - &context); - storePrivate->callbackRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->callbackPort, 0); - CFRunLoopAddSource(runLoop, storePrivate->callbackRLS, kCFRunLoopDefaultMode); - - return TRUE; -} - - static void rlsCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) { @@ -272,8 +71,8 @@ rlsCallback(CFMachPortRef port, void *msg, CFIndex size, void *info) #endif /* DEBUG */ #ifdef DEBUG - if (port != storePrivate->callbackPort) { - SCLog(_sc_verbose, LOG_DEBUG, CFSTR("rlsCallback(), why is port != callbackPort?")); + if (port != storePrivate->rlsNotifyPort) { + SCLog(_sc_verbose, LOG_DEBUG, CFSTR("rlsCallback(), why is port != rlsNotifyPort?")); } #endif /* DEBUG */ @@ -374,19 +173,16 @@ rlsSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule", port); status = notifyviaport(storePrivate->server, port, 0, (int *)&sc_status); + + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "rlsSchedule notifyviaport()")) { + goto retry; + } + if (status != KERN_SUCCESS) { if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("rlsSchedule notifyviaport(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } /* remove the send right that we tried (but failed) to pass to the server */ (void) mach_port_deallocate(mach_task_self(), port); } @@ -403,23 +199,23 @@ rlsSchedule(void *info, CFRunLoopRef rl, CFStringRef mode) } __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after notifyviaport)", port); - storePrivate->callbackPort = _SC_CFMachPortCreateWithPort("SCDynamicStore", - port, - rlsCallback, - &context); - CFMachPortSetInvalidationCallBack(storePrivate->callbackPort, portInvalidate); - storePrivate->callbackRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->callbackPort, 0); + storePrivate->rlsNotifyPort = _SC_CFMachPortCreateWithPort("SCDynamicStore", + port, + rlsCallback, + &context); + CFMachPortSetInvalidationCallBack(storePrivate->rlsNotifyPort, portInvalidate); + storePrivate->rlsNotifyRLS = CFMachPortCreateRunLoopSource(NULL, storePrivate->rlsNotifyPort, 0); storePrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } - if ((rl != NULL) && (storePrivate->callbackRLS != NULL)) { + if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) { if (!_SC_isScheduled(store, rl, mode, storePrivate->rlList)) { /* * if we are not already scheduled with this runLoop / runLoopMode */ - CFRunLoopAddSource(rl, storePrivate->callbackRLS, mode); - __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate->callbackPort)); + CFRunLoopAddSource(rl, storePrivate->rlsNotifyRLS, mode); + __MACH_PORT_DEBUG(TRUE, "*** rlsSchedule (after CFRunLoopAddSource)", CFMachPortGetPort(storePrivate->rlsNotifyPort)); } _SC_schedule(store, rl, mode, storePrivate->rlList); @@ -442,7 +238,7 @@ rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode) (rl != NULL) ? mode : CFSTR("libdispatch")); #endif /* DEBUG */ - if ((rl != NULL) && (storePrivate->callbackRLS != NULL)) { + if ((rl != NULL) && (storePrivate->rlsNotifyRLS != NULL)) { if (_SC_unschedule(store, rl, mode, storePrivate->rlList, FALSE)) { /* * if currently scheduled on this runLoop / runLoopMode @@ -453,7 +249,7 @@ rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode) * if we are no longer scheduled to receive notifications for * this runLoop / runLoopMode */ - CFRunLoopRemoveSource(rl, storePrivate->callbackRLS, mode); + CFRunLoopRemoveSource(rl, storePrivate->rlsNotifyRLS, mode); } } } @@ -465,44 +261,41 @@ rlsCancel(void *info, CFRunLoopRef rl, CFStringRef mode) #ifdef DEBUG SCLog(_sc_verbose, LOG_DEBUG, CFSTR(" cancel callback runloop source")); #endif /* DEBUG */ - __MACH_PORT_DEBUG((storePrivate->callbackPort != NULL), + __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL), "*** rlsCancel", - CFMachPortGetPort(storePrivate->callbackPort)); + CFMachPortGetPort(storePrivate->rlsNotifyPort)); - CFRelease(storePrivate->rlList); - storePrivate->rlList = NULL; + if (storePrivate->rlList != NULL) { + CFRelease(storePrivate->rlList); + storePrivate->rlList = NULL; + } - if (storePrivate->callbackRLS != NULL) { + if (storePrivate->rlsNotifyRLS != NULL) { /* invalidate & remove the run loop source */ - CFRunLoopSourceInvalidate(storePrivate->callbackRLS); - CFRelease(storePrivate->callbackRLS); - storePrivate->callbackRLS = NULL; + CFRunLoopSourceInvalidate(storePrivate->rlsNotifyRLS); + CFRelease(storePrivate->rlsNotifyRLS); + storePrivate->rlsNotifyRLS = NULL; } - if (storePrivate->callbackPort != NULL) { + if (storePrivate->rlsNotifyPort != NULL) { /* invalidate port */ - __MACH_PORT_DEBUG((storePrivate->callbackPort != NULL), + __MACH_PORT_DEBUG((storePrivate->rlsNotifyPort != NULL), "*** rlsCancel (before invalidating CFMachPort)", - CFMachPortGetPort(storePrivate->callbackPort)); - CFMachPortInvalidate(storePrivate->callbackPort); - CFRelease(storePrivate->callbackPort); - storePrivate->callbackPort = NULL; + CFMachPortGetPort(storePrivate->rlsNotifyPort)); + CFMachPortInvalidate(storePrivate->rlsNotifyPort); + CFRelease(storePrivate->rlsNotifyPort); + storePrivate->rlsNotifyPort = NULL; } if (storePrivate->server != MACH_PORT_NULL) { status = notifycancel(storePrivate->server, (int *)&sc_status); + + (void) __SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "rlsCancel notifycancel()"); + if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("rlsCancel notifycancel(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - (void) __SCDynamicStoreReconnect(store); - } return; } } @@ -638,9 +431,6 @@ rlsCopyDescription(const void *info) } CFStringAppendFormat(result, NULL, CFSTR(", context = %@"), description); CFRelease(description); - } else { - CFStringAppendFormat(result, NULL, CFSTR(", callout = %p"), storePrivate->callbackFunction); - CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->callbackArgument); } CFStringAppendFormat(result, NULL, CFSTR("}")); @@ -703,151 +493,160 @@ SCDynamicStoreCreateRunLoopSource(CFAllocatorRef allocator, } -static boolean_t -SCDynamicStoreNotifyMIGCallback(mach_msg_header_t *message, mach_msg_header_t *reply) -{ - mach_msg_empty_rcv_t *buf = (mach_msg_empty_rcv_t *)message; - mach_msg_id_t msgid = buf->header.msgh_id; - SCDynamicStoreRef store; - - store = dispatch_get_context(dispatch_get_current_queue()); - if (store != NULL) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - - CFRetain(storePrivate); - dispatch_async(storePrivate->dispatchQueue, ^{ - if (msgid == MACH_NOTIFY_NO_SENDERS) { - /* re-establish notification and inform the client */ - (void)__SCDynamicStoreReconnectNotifications(store); - } - rlsPerform(storePrivate); - CFRelease(storePrivate); - }); - } - reply->msgh_remote_port = MACH_PORT_NULL; - return false; -} - - Boolean SCDynamicStoreSetDispatchQueue(SCDynamicStoreRef store, dispatch_queue_t queue) { + dispatch_group_t drainGroup = NULL; + dispatch_queue_t drainQueue = NULL; + mach_port_t mp; Boolean ok = FALSE; + dispatch_source_t source; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; if (store == NULL) { - /* sorry, you must provide a session */ + // sorry, you must provide a session _SCErrorSet(kSCStatusNoStoreSession); return FALSE; } - if (queue != NULL) { - mach_port_t mp; - - if (storePrivate->server == MACH_PORT_NULL) { - /* sorry, you must have an open session to play */ - _SCErrorSet(kSCStatusNoStoreServer); - return FALSE; - } - - if ((storePrivate->dispatchQueue != NULL) || (storePrivate->rls != NULL)) { + if (queue == NULL) { + if (storePrivate->dispatchQueue == NULL) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } - if (storePrivate->notifyStatus != NotifierNotRegistered) { - /* sorry, you can only have one notification registered at once... */ - _SCErrorSet(kSCStatusNotifierActive); - return FALSE; - } + ok = TRUE; + goto cleanup; + } - /* - * mark our using of the SCDynamicStore notifications, create and schedule - * the notification port (storePrivate->callbackPort), and a bunch of other - * "setup" - */ - storePrivate->notifyStatus = Using_NotifierInformViaDispatch; - rlsSchedule((void*)store, NULL, NULL); - storePrivate->dispatchQueue = queue; - dispatch_retain(storePrivate->dispatchQueue); - - if (storePrivate->callbackPort == NULL) { - /* if we could not schedule the notification */ - _SCErrorSet(kSCStatusFailed); - goto cleanup; - } + if (storePrivate->server == MACH_PORT_NULL) { + // sorry, you must have an open session to play + _SCErrorSet(kSCStatusNoStoreServer); + return FALSE; + } - /* - * create a dispatch queue for the mach notifications source, we'll use - * this queue's context to carry the store pointer for the callback code. - */ - storePrivate->callbackQueue = dispatch_queue_create("com.apple.SCDynamicStore.notifications", NULL); - if (storePrivate->callbackQueue == NULL){ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_queue_create() failed")); - _SCErrorSet(kSCStatusFailed); - goto cleanup; - } - CFRetain(store); // Note: will be released when the dispatch queue is released - dispatch_set_context(storePrivate->callbackQueue, (void *)store); - dispatch_set_finalizer_f(storePrivate->callbackQueue, (dispatch_function_t)CFRelease); - - /* - * create a dispatch source for the mach notifications - */ - mp = CFMachPortGetPort(storePrivate->callbackPort); - storePrivate->callbackSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, - mp, - 0, - storePrivate->callbackQueue); - if (storePrivate->callbackSource == NULL) { - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_source_create() failed")); - _SCErrorSet(kSCStatusFailed); - goto cleanup; + if ((storePrivate->dispatchQueue != NULL) || (storePrivate->rls != NULL)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + if (storePrivate->notifyStatus != NotifierNotRegistered) { + // sorry, you can only have one notification registered at once... + _SCErrorSet(kSCStatusNotifierActive); + return FALSE; + } + + /* + * mark our using of the SCDynamicStore notifications, create and schedule + * the notification port (storePrivate->rlsNotifyPort), and a bunch of other + * "setup" + */ + storePrivate->notifyStatus = Using_NotifierInformViaDispatch; + rlsSchedule((void*)store, NULL, NULL); + if (storePrivate->rlsNotifyPort == NULL) { + /* if we could not schedule the notification */ + _SCErrorSet(kSCStatusFailed); + goto cleanup; + } + + // retain the dispatch queue + storePrivate->dispatchQueue = queue; + dispatch_retain(storePrivate->dispatchQueue); + + // + // We've taken a reference to the callers dispatch_queue and we + // want to hold on to that reference until we've processed any/all + // notifications. To facilitate this we create a group, dispatch + // any notification blocks to via that group, and when the caller + // has told us to stop the notifications (unschedule) we wait for + // the group to empty and use the group's finalizer to release + // our reference to the SCDynamicStore. + // + storePrivate->dispatchGroup = dispatch_group_create(); + CFRetain(store); + dispatch_set_context(storePrivate->dispatchGroup, (void *)store); + dispatch_set_finalizer_f(storePrivate->dispatchGroup, (dispatch_function_t)CFRelease); + + // create a dispatch source for the mach notifications + mp = CFMachPortGetPort(storePrivate->rlsNotifyPort); + source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, queue); + if (source == NULL) { + SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStore dispatch_source_create() failed")); + _SCErrorSet(kSCStatusFailed); + goto cleanup; + } + + dispatch_source_set_event_handler(source, ^{ + kern_return_t kr; + mach_msg_id_t msgid; + union { + u_int8_t buf[sizeof(mach_msg_empty_t) + MAX_TRAILER_SIZE]; + mach_msg_empty_rcv_t msg; + mach_no_senders_notification_t no_senders; + } notify_msg; + + kr = mach_msg(¬ify_msg.msg.header, // msg + MACH_RCV_MSG, // options + 0, // send_size + sizeof(notify_msg), // rcv_size + mp, // rcv_name + MACH_MSG_TIMEOUT_NONE, // timeout + MACH_PORT_NULL); // notify + if (kr != KERN_SUCCESS) { + SCLog(TRUE, LOG_ERR, + CFSTR("SCDynamicStore notification handler, kr=0x%x"), + kr); + return; } - dispatch_source_set_event_handler(storePrivate->callbackSource, ^{ - union MaxMsgSize { - mach_msg_empty_rcv_t normal; - mach_no_senders_notification_t no_senders; - }; - - dispatch_mig_server(storePrivate->callbackSource, - sizeof(union MaxMsgSize), - SCDynamicStoreNotifyMIGCallback); + + msgid = notify_msg.msg.header.msgh_id; + + CFRetain(store); + dispatch_group_async(storePrivate->dispatchGroup, storePrivate->dispatchQueue, ^{ + if (msgid == MACH_NOTIFY_NO_SENDERS) { + // re-establish notification and inform the client + (void)__SCDynamicStoreReconnectNotifications(store); + } + rlsPerform(storePrivate); + CFRelease(store); }); - dispatch_resume(storePrivate->callbackSource); + }); - ok = TRUE; - goto done; - } else { - if (storePrivate->dispatchQueue == NULL) { - _SCErrorSet(kSCStatusInvalidArgument); - return FALSE; - } + dispatch_source_set_cancel_handler(source, ^{ + dispatch_release(source); + }); - ok = TRUE; - } + storePrivate->dispatchSource = source; + dispatch_resume(source); + + return TRUE; cleanup : - if (storePrivate->callbackSource != NULL) { - dispatch_source_cancel(storePrivate->callbackSource); - if (storePrivate->callbackQueue != dispatch_get_current_queue()) { - // ensure the cancellation has completed - dispatch_sync(storePrivate->callbackQueue, ^{}); - } - dispatch_release(storePrivate->callbackSource); - storePrivate->callbackSource = NULL; - } - if (storePrivate->callbackQueue != NULL) { - dispatch_release(storePrivate->callbackQueue); - storePrivate->callbackQueue = NULL; + CFRetain(store); + + if (storePrivate->dispatchSource != NULL) { + dispatch_source_cancel(storePrivate->dispatchSource); + storePrivate->dispatchSource = NULL; } - dispatch_release(storePrivate->dispatchQueue); + drainGroup = storePrivate->dispatchGroup; + storePrivate->dispatchGroup = NULL; + drainQueue = storePrivate->dispatchQueue; storePrivate->dispatchQueue = NULL; + rlsCancel((void*)store, NULL, NULL); + + if (drainGroup != NULL) { + dispatch_group_notify(drainGroup, drainQueue, ^{ + // release group/queue references + dispatch_release(drainQueue); + dispatch_release(drainGroup); // releases our store reference + }); + } + storePrivate->notifyStatus = NotifierNotRegistered; - done : + CFRelease(store); return ok; } diff --git a/SystemConfiguration.fproj/SCDNotifierInformViaFD.c b/SystemConfiguration.fproj/SCDNotifierInformViaFD.c index f1b6f65..f5505ce 100644 --- a/SystemConfiguration.fproj/SCDNotifierInformViaFD.c +++ b/SystemConfiguration.fproj/SCDNotifierInformViaFD.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2004, 2005, 2008-2010 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2004, 2005, 2008-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -126,20 +126,14 @@ SCDynamicStoreNotifyFileDescriptor(SCDynamicStoreRef store, identifier, (int *)&sc_status); + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreNotifyFileDescriptor notifyviafd()")) { + goto retry; + } + if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyFileDescriptor notifyviafd(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } _SCErrorSet(status); return FALSE; } diff --git a/SystemConfiguration.fproj/SCDNotifierInformViaMachPort.c b/SystemConfiguration.fproj/SCDNotifierInformViaMachPort.c deleted file mode 100644 index 4d0f145..0000000 --- a/SystemConfiguration.fproj/SCDNotifierInformViaMachPort.c +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2000, 2001, 2004, 2005, 2009, 2010 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, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * 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@ - */ - -/* - * Modification History - * - * June 1, 2001 Allan Nathanson - * - public API conversion - * - * March 31, 2000 Allan Nathanson - * - initial revision - */ - -#include -#include - -#include -#include -#include "SCDynamicStoreInternal.h" -#include "config.h" /* MiG generated file */ - -Boolean -SCDynamicStoreNotifyMachPort(SCDynamicStoreRef store, mach_msg_id_t identifier, mach_port_t *port) -{ - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - kern_return_t status; - mach_port_t oldNotify; - int sc_status; - - if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return FALSE; - } - - if (storePrivate->server == MACH_PORT_NULL) { - /* sorry, you must have an open session to play */ - _SCErrorSet(kSCStatusNoStoreServer); - return FALSE; - } - - if (storePrivate->notifyStatus != NotifierNotRegistered) { - /* sorry, you can only have one notification registered at once */ - _SCErrorSet(kSCStatusNotifierActive); - return FALSE; - } - - /* Allocating port (for server response) */ - status = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, port); - if (status != KERN_SUCCESS) { - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyMachPort mach_port_allocate(): %s"), mach_error_string(status)); - _SCErrorSet(status); - return FALSE; - } - - status = mach_port_insert_right(mach_task_self(), - *port, - *port, - MACH_MSG_TYPE_MAKE_SEND); - if (status != KERN_SUCCESS) { - /* - * We can't insert a send right into our own port! This should - * only happen if someone stomped on OUR port (so let's leave - * the port alone). - */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyMachPort mach_port_insert_right(): %s"), mach_error_string(status)); - *port = MACH_PORT_NULL; - _SCErrorSet(status); - return FALSE; - } - - /* Request a notification when/if the server dies */ - status = mach_port_request_notification(mach_task_self(), - *port, - MACH_NOTIFY_NO_SENDERS, - 1, - *port, - MACH_MSG_TYPE_MAKE_SEND_ONCE, - &oldNotify); - if (status != KERN_SUCCESS) { - /* - * We can't request a notification for our own port! This should - * only happen if someone stomped on OUR port (so let's leave - * the port alone). - */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyMachPort mach_port_request_notification(): %s"), mach_error_string(status)); - *port = MACH_PORT_NULL; - _SCErrorSet(status); - return FALSE; - } - - if (oldNotify != MACH_PORT_NULL) { - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyMachPort(): oldNotify != MACH_PORT_NULL")); - } - - retry : - - status = notifyviaport(storePrivate->server, - *port, - identifier, - (int *)&sc_status); - - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyMachPort notifyviaport(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - /* remove the send right that we tried (but failed) to pass to the server */ - (void) mach_port_deallocate(mach_task_self(), *port); - } - - /* remove our receive right */ - (void) mach_port_mod_refs(mach_task_self(), *port, MACH_PORT_RIGHT_RECEIVE, -1); - *port = MACH_PORT_NULL; - _SCErrorSet(status); - return FALSE; - } - - /* set notifier active */ - __MACH_PORT_DEBUG(TRUE, "*** SCDynamicStoreNotifyMachPort", *port); - storePrivate->notifyStatus = Using_NotifierInformViaMachPort; - - return TRUE; -} diff --git a/SystemConfiguration.fproj/SCDNotifierInformViaSignal.c b/SystemConfiguration.fproj/SCDNotifierInformViaSignal.c index 3b81fc8..ddae17a 100644 --- a/SystemConfiguration.fproj/SCDNotifierInformViaSignal.c +++ b/SystemConfiguration.fproj/SCDNotifierInformViaSignal.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2004, 2005, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2004, 2005, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -76,20 +76,14 @@ SCDynamicStoreNotifySignal(SCDynamicStoreRef store, pid_t pid, int sig) status = notifyviasignal(storePrivate->server, task, sig, (int *)&sc_status); + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreNotifySignal notifyviasignal()")) { + goto retry; + } + if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifySignal notifyviasignal(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } _SCErrorSet(status); return FALSE; } diff --git a/SystemConfiguration.fproj/SCDNotifierRemove.c b/SystemConfiguration.fproj/SCDNotifierRemove.c index be63da6..739f4e8 100644 --- a/SystemConfiguration.fproj/SCDNotifierRemove.c +++ b/SystemConfiguration.fproj/SCDNotifierRemove.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2005, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -99,21 +99,11 @@ SCDynamicStoreRemoveWatchedKey(SCDynamicStoreRef store, CFStringRef key, Boolean isRegex, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreRemoveWatchedKey notifyremove(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreRemoveWatchedKey notifyremove()")) { + goto retry; } /* clean up */ diff --git a/SystemConfiguration.fproj/SCDNotifierSetKeys.c b/SystemConfiguration.fproj/SCDNotifierSetKeys.c index 23777fa..1ffb863 100644 --- a/SystemConfiguration.fproj/SCDNotifierSetKeys.c +++ b/SystemConfiguration.fproj/SCDNotifierSetKeys.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003-2005, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003-2005, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -91,21 +91,11 @@ SCDynamicStoreSetNotificationKeys(SCDynamicStoreRef store, myPatternsLen, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSetNotificationKeys notifyset(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreSetNotificationKeys notifyset()")) { + goto retry; } /* clean up */ diff --git a/SystemConfiguration.fproj/SCDNotifierWait.c b/SystemConfiguration.fproj/SCDNotifierWait.c index 707fc82..751f47f 100644 --- a/SystemConfiguration.fproj/SCDNotifierWait.c +++ b/SystemConfiguration.fproj/SCDNotifierWait.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2004, 2006, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2004, 2006, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -145,26 +145,21 @@ SCDynamicStoreNotifyWait(SCDynamicStoreRef store) 0, (int *)&sc_status); + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreNotifyWait notifyviaport()")) { + goto retry; + } + if (status != KERN_SUCCESS) { if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyWait notifyviaport(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } /* remove the send right that we tried (but failed) to pass to the server */ (void) mach_port_deallocate(mach_task_self(), port); } /* remove our receive right */ (void) mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, -1); - sc_status = status; } if (sc_status != kSCStatusOK) { @@ -203,21 +198,11 @@ SCDynamicStoreNotifyWait(SCDynamicStoreRef store) status = notifycancel(storePrivate->server, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyWait notifycancel(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if (((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) && - __SCDynamicStoreReconnect(store)) { - sc_status = kSCStatusOK; - } else { - sc_status = status; - } + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreNotifyWait notifycancel()")) { + sc_status = kSCStatusOK; } /* remove our receive right */ diff --git a/SystemConfiguration.fproj/SCDNotify.c b/SystemConfiguration.fproj/SCDNotify.c index 36394bf..d55a46e 100644 --- a/SystemConfiguration.fproj/SCDNotify.c +++ b/SystemConfiguration.fproj/SCDNotify.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003-2005, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003-2005, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -40,7 +40,7 @@ Boolean SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; + SCDynamicStorePrivateRef storePrivate; kern_return_t status; CFDataRef utfKey; /* serialized key */ xmlData_t myKeyRef; @@ -48,11 +48,15 @@ SCDynamicStoreNotifyValue(SCDynamicStoreRef store, int sc_status; if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return FALSE; + store = __SCDynamicStoreNullSession(); + if (store == NULL) { + /* sorry, you must provide a session */ + _SCErrorSet(kSCStatusNoStoreSession); + return FALSE; + } } + storePrivate = (SCDynamicStorePrivateRef)store; if (storePrivate->server == MACH_PORT_NULL) { /* sorry, you must have an open session to play */ _SCErrorSet(kSCStatusNoStoreServer); @@ -73,21 +77,11 @@ SCDynamicStoreNotifyValue(SCDynamicStoreRef store, myKeyLen, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreNotifyValue confignotify(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreNotifyValue confignotify()")) { + goto retry; } /* clean up */ diff --git a/SystemConfiguration.fproj/SCDOpen.c b/SystemConfiguration.fproj/SCDOpen.c index f21d49c..c8090bb 100644 --- a/SystemConfiguration.fproj/SCDOpen.c +++ b/SystemConfiguration.fproj/SCDOpen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2006, 2008-2011 Apple Inc. All rights reserved. + * Copyright (c) 2000-2006, 2008-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -42,13 +42,14 @@ #include #include +#include "SCD.h" #include "SCDynamicStoreInternal.h" #include "config.h" /* MiG generated file */ -static CFStringRef _sc_bundleID = NULL; -static pthread_mutex_t _sc_lock = PTHREAD_MUTEX_INITIALIZER; -static mach_port_t _sc_server = MACH_PORT_NULL; +static CFStringRef _sc_bundleID = NULL; +static pthread_mutex_t _sc_lock = PTHREAD_MUTEX_INITIALIZER; +static mach_port_t _sc_server = MACH_PORT_NULL; static const char *notifyType[] = { @@ -76,9 +77,6 @@ __SCDynamicStoreCopyDescription(CFTypeRef cf) { } else { CFStringAppendFormat(result, NULL, CFSTR("server not (no longer) available")); } - if (storePrivate->locked) { - CFStringAppendFormat(result, NULL, CFSTR(", locked")); - } if (storePrivate->disconnectFunction != NULL) { CFStringAppendFormat(result, NULL, CFSTR(", disconnect = %p"), storePrivate->disconnectFunction); } @@ -96,19 +94,21 @@ __SCDynamicStoreCopyDescription(CFTypeRef cf) { CFStringAppendFormat(result, NULL, CFSTR(", BSD signal notifications")); break; case Using_NotifierInformViaRunLoop : - case Using_NotifierInformViaCallback : + case Using_NotifierInformViaDispatch : if (storePrivate->notifyStatus == Using_NotifierInformViaRunLoop) { CFStringAppendFormat(result, NULL, CFSTR(", runloop notifications")); CFStringAppendFormat(result, NULL, CFSTR(" {callout = %p"), storePrivate->rlsFunction); CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->rlsContext.info); CFStringAppendFormat(result, NULL, CFSTR(", rls = %p"), storePrivate->rls); - } else { - CFStringAppendFormat(result, NULL, CFSTR(", mach port/callback notifications")); - CFStringAppendFormat(result, NULL, CFSTR(" {callout = %p"), storePrivate->callbackFunction); - CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->callbackArgument); + } else if (storePrivate->notifyStatus == Using_NotifierInformViaDispatch) { + CFStringAppendFormat(result, NULL, CFSTR(", dispatch notifications")); + CFStringAppendFormat(result, NULL, CFSTR(" {callout = %p"), storePrivate->rlsFunction); + CFStringAppendFormat(result, NULL, CFSTR(", info = %p"), storePrivate->rlsContext.info); + CFStringAppendFormat(result, NULL, CFSTR(", queue = %p"), storePrivate->dispatchQueue); + CFStringAppendFormat(result, NULL, CFSTR(", source = %p"), storePrivate->dispatchSource); } - if (storePrivate->callbackRLS != NULL) { - CFStringAppendFormat(result, NULL, CFSTR(", notify rls = %@" ), storePrivate->callbackRLS); + if (storePrivate->rlsNotifyRLS != NULL) { + CFStringAppendFormat(result, NULL, CFSTR(", notify rls = %@" ), storePrivate->rlsNotifyRLS); } CFStringAppendFormat(result, NULL, CFSTR("}")); break; @@ -127,7 +127,6 @@ static void __SCDynamicStoreDeallocate(CFTypeRef cf) { int oldThreadState; - int sc_status; SCDynamicStoreRef store = (SCDynamicStoreRef)cf; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; @@ -136,24 +135,16 @@ __SCDynamicStoreDeallocate(CFTypeRef cf) /* Remove/cancel any outstanding notification requests. */ (void) SCDynamicStoreNotifyCancel(store); - if ((storePrivate->server != MACH_PORT_NULL) && storePrivate->locked) { - (void) SCDynamicStoreUnlock(store); /* release the lock */ - } - if (storePrivate->server != MACH_PORT_NULL) { - __MACH_PORT_DEBUG(TRUE, "*** __SCDynamicStoreDeallocate", storePrivate->server); - (void) configclose(storePrivate->server, (int *)&sc_status); - __MACH_PORT_DEBUG(TRUE, "*** __SCDynamicStoreDeallocate (after configclose)", storePrivate->server); + if (!storePrivate->serverNullSession) { + /* + * Remove our send right to the SCDynamicStore server (and that will + * result in our session being closed). + */ + __MACH_PORT_DEBUG(TRUE, "*** __SCDynamicStoreDeallocate", storePrivate->server); + (void) mach_port_deallocate(mach_task_self(), storePrivate->server); + } - /* - * the above call to configclose() should result in the SCDynamicStore - * server code deallocating it's receive right. That, in turn, should - * result in our send becoming a dead name. We could explicitly remove - * the dead name right with a call to mach_port_mod_refs() but, to be - * sure, we use mach_port_deallocate() since that will get rid of a - * send, send_once, or dead name right. - */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); storePrivate->server = MACH_PORT_NULL; } @@ -313,14 +304,14 @@ __SCDynamicStoreCreatePrivate(CFAllocatorRef allocator, } /* client side of the "configd" session */ - storePrivate->name = NULL; + storePrivate->name = (name != NULL) ? CFRetain(name) : NULL; storePrivate->options = NULL; /* server side of the "configd" session */ storePrivate->server = MACH_PORT_NULL; + storePrivate->serverNullSession = FALSE; /* flags */ - storePrivate->locked = FALSE; storePrivate->useSessionKeys = FALSE; /* Notification status */ @@ -340,17 +331,13 @@ __SCDynamicStoreCreatePrivate(CFAllocatorRef allocator, storePrivate->rlsContext.info = (void *)(*context->retain)(context->info); } } - - /* "client" information associated with SCDynamicStoreNotifyCallback() */ - storePrivate->callbackFunction = NULL; - storePrivate->callbackArgument = NULL; - storePrivate->callbackPort = NULL; - storePrivate->callbackRLS = NULL; + storePrivate->rlsNotifyPort = NULL; + storePrivate->rlsNotifyRLS = NULL; /* "client" information associated with SCDynamicStoreSetDispatchQueue() */ + storePrivate->dispatchGroup = NULL; storePrivate->dispatchQueue = NULL; - storePrivate->callbackSource = NULL; - storePrivate->callbackQueue = NULL; + storePrivate->dispatchSource = NULL; /* "client" information associated with SCDynamicStoreSetDisconnectCallBack() */ storePrivate->disconnectFunction = NULL; @@ -379,15 +366,15 @@ __SCDynamicStoreCreatePrivate(CFAllocatorRef allocator, static Boolean __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate) { - CFDataRef myName; /* serialized name */ - xmlData_t myNameRef; - CFIndex myNameLen; - CFDataRef myOptions = NULL; /* serialized options */ - xmlData_t myOptionsRef = NULL; - CFIndex myOptionsLen = 0; - int sc_status = kSCStatusFailed; - mach_port_t server; - kern_return_t status = KERN_SUCCESS; + CFDataRef myName; /* serialized name */ + xmlData_t myNameRef; + CFIndex myNameLen; + CFDataRef myOptions = NULL; /* serialized options */ + xmlData_t myOptionsRef = NULL; + CFIndex myOptionsLen = 0; + int sc_status = kSCStatusFailed; + mach_port_t server; + kern_return_t status = KERN_SUCCESS; if (!_SCSerializeString(storePrivate->name, &myName, (void **)&myNameRef, &myNameLen)) { goto done; @@ -405,13 +392,29 @@ __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate) server = _sc_server; while (TRUE) { if (server != MACH_PORT_NULL) { - status = configopen(server, - myNameRef, - myNameLen, - myOptionsRef, - myOptionsLen, - &storePrivate->server, - (int *)&sc_status); + if (!storePrivate->serverNullSession) { + // if SCDynamicStore session + status = configopen(server, + myNameRef, + myNameLen, + myOptionsRef, + myOptionsLen, + &storePrivate->server, + (int *)&sc_status); + } else { + // if NULL session + if (storePrivate->server == MACH_PORT_NULL) { + // use the [main] SCDynamicStore server port + storePrivate->server = server; + sc_status = kSCStatusOK; + status = KERN_SUCCESS; + } else { + // if the server port we used returned an error + storePrivate->server = MACH_PORT_NULL; + status = MACH_SEND_INVALID_DEST; + } + } + if (status == KERN_SUCCESS) { break; } @@ -427,8 +430,11 @@ __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate) pthread_mutex_lock(&_sc_lock); if (_sc_server != MACH_PORT_NULL) { if (server == _sc_server) { - // if the server we tried returned the error + // if the server we tried returned the error, deallocate + // our send [or dead name] right (void)mach_port_deallocate(mach_task_self(), _sc_server); + + // and [re-]lookup the name to the server _sc_server = __SCDynamicStoreServerPort(&sc_status); } else { // another thread has refreshed the SCDynamicStore server port @@ -459,11 +465,12 @@ __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate) SCLog(TRUE, (status == KERN_SUCCESS) ? LOG_DEBUG : LOG_ERR, CFSTR("SCDynamicStore server not available")); + sc_status = kSCStatusNoStoreServer; break; default : SCLog(TRUE, (status == KERN_SUCCESS) ? LOG_DEBUG : LOG_ERR, - CFSTR("SCDynamicStoreCreateAddSession configopen(): %s"), + CFSTR("SCDynamicStoreAddSession configopen(): %s"), SCErrorString(sc_status)); break; } @@ -474,7 +481,52 @@ __SCDynamicStoreAddSession(SCDynamicStorePrivateRef storePrivate) __private_extern__ -Boolean +SCDynamicStoreRef +__SCDynamicStoreNullSession(void) +{ + SCDynamicStorePrivateRef storePrivate; + Boolean ok = TRUE; + __SCThreadSpecificDataRef tsd; + + tsd = __SCGetThreadSpecificData(); + if (tsd->_sc_store == NULL) { +#if !TARGET_IPHONE_SIMULATOR + storePrivate = __SCDynamicStoreCreatePrivate(NULL, + CFSTR("NULL session"), + NULL, + NULL); + storePrivate->server = _sc_server; + storePrivate->serverNullSession = TRUE; +#else + /* + * In the simulator, this code may be talking to an older version of + * configd that still requires a valid session. Instead of using a + * "NULL" session that uses the server mach port, set up a "normal" + * session in thread-local storage. + */ + storePrivate = __SCDynamicStoreCreatePrivate(NULL, + CFSTR("Thread local session"), + NULL, + NULL); + /* + * Use MACH_PORT_NULL here to trigger the call to + * __SCDynamicStoreAddSession below. + */ + storePrivate->server = MACH_PORT_NULL; +#endif /* TARGET_IPHONE_SIMULATOR */ + tsd->_sc_store = (SCDynamicStoreRef)storePrivate; + } + + storePrivate = (SCDynamicStorePrivateRef)tsd->_sc_store; + if (storePrivate->server == MACH_PORT_NULL) { + ok = __SCDynamicStoreAddSession(storePrivate); + } + + return ok ? tsd->_sc_store : NULL; +} + + +static Boolean __SCDynamicStoreReconnect(SCDynamicStoreRef store) { Boolean ok; @@ -485,6 +537,47 @@ __SCDynamicStoreReconnect(SCDynamicStoreRef store) } +__private_extern__ +Boolean +__SCDynamicStoreCheckRetryAndHandleError(SCDynamicStoreRef store, + kern_return_t status, + int *sc_status, + const char *log_str) +{ + SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; + + if (status == KERN_SUCCESS) { + /* no error */ + return FALSE; + } + + if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { + /* the server's gone */ + if (!storePrivate->serverNullSession) { + /* + * remove the session's dead name right (and not the + * not the "server" port) + */ + (void) mach_port_deallocate(mach_task_self(), storePrivate->server); + } + storePrivate->server = MACH_PORT_NULL; + + /* reconnect */ + if (__SCDynamicStoreReconnect(store)) { + /* retry needed */ + return TRUE; + } + } else { + /* an unexpected error, leave the [session] port alone */ + SCLog(TRUE, LOG_ERR, CFSTR("%s: %s"), log_str, mach_error_string(status)); + storePrivate->server = MACH_PORT_NULL; + } + + *sc_status = status; + return FALSE; +} + + static void pushDisconnect(SCDynamicStoreRef store) { @@ -545,25 +638,13 @@ __SCDynamicStoreReconnectNotifications(SCDynamicStoreRef store) break; } -#ifdef NOTNOW - // invalidate the run loop source(s) - if (storePrivate->callbackRLS != NULL) { - CFRunLoopSourceInvalidate(storePrivate->callbackRLS); - CFRelease(storePrivate->callbackRLS); - storePrivate->callbackRLS = NULL; - } - - // invalidate port - if (storePrivate->callbackPort != NULL) { - __MACH_PORT_DEBUG(TRUE, "*** __SCDynamicStoreReconnectNotifications w/MACH_NOTIFY_NO_SENDERS", CFMachPortGetPort(storePrivate->callbackPort)); - CFMachPortInvalidate(storePrivate->callbackPort); - CFRelease(storePrivate->callbackPort); - storePrivate->callbackPort = NULL; - } -#endif // NOTNOW - // cancel [old] notifications - SCDynamicStoreNotifyCancel(store); + if (!SCDynamicStoreNotifyCancel(store)) { + // if we could not cancel / reconnect + SCLog(TRUE, LOG_DEBUG, + CFSTR("__SCDynamicStoreReconnectNotifications: SCDynamicStoreNotifyCancel() failed: %s"), + SCErrorString(SCError())); + } // set notification keys & patterns if ((storePrivate->keys != NULL) || (storePrivate->patterns)) { @@ -662,7 +743,7 @@ SCDynamicStoreCreateWithOptions(CFAllocatorRef allocator, SCDynamicStorePrivateRef storePrivate; // allocate and initialize a new session - storePrivate = __SCDynamicStoreCreatePrivate(allocator, name, callout, context); + storePrivate = __SCDynamicStoreCreatePrivate(allocator, NULL, callout, context); if (storePrivate == NULL) { return NULL; } diff --git a/SystemConfiguration.fproj/SCDPrivate.c b/SystemConfiguration.fproj/SCDPrivate.c index 5a1bf29..0f3e346 100644 --- a/SystemConfiguration.fproj/SCDPrivate.c +++ b/SystemConfiguration.fproj/SCDPrivate.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Apple Inc. All rights reserved. + * Copyright (c) 2000-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -52,7 +52,6 @@ #include #include -#include #include #include @@ -129,38 +128,47 @@ _SC_cfstring_to_cstring(CFStringRef cfstr, char *buf, CFIndex bufLen, CFStringEn void _SC_sockaddr_to_string(const struct sockaddr *address, char *buf, size_t bufLen) { + union { + const struct sockaddr *sa; + const struct sockaddr_in *sin; + const struct sockaddr_in6 *sin6; + const struct sockaddr_dl *sdl; + } addr; + + addr.sa = address; + bzero(buf, bufLen); switch (address->sa_family) { case AF_INET : - (void)inet_ntop(((struct sockaddr_in *)address)->sin_family, - &((struct sockaddr_in *)address)->sin_addr, + (void)inet_ntop(addr.sin->sin_family, + &addr.sin->sin_addr, buf, bufLen); break; case AF_INET6 : { - (void)inet_ntop(((struct sockaddr_in6 *)address)->sin6_family, - &((struct sockaddr_in6 *)address)->sin6_addr, + (void)inet_ntop(addr.sin6->sin6_family, + &addr.sin6->sin6_addr, buf, bufLen); - if (((struct sockaddr_in6 *)address)->sin6_scope_id != 0) { + if (addr.sin6->sin6_scope_id != 0) { int n; n = strlen(buf); if ((n+IF_NAMESIZE+1) <= (int)bufLen) { buf[n++] = '%'; - if_indextoname(((struct sockaddr_in6 *)address)->sin6_scope_id, &buf[n]); + if_indextoname(addr.sin6->sin6_scope_id, &buf[n]); } } break; } case AF_LINK : - if (((struct sockaddr_dl *)address)->sdl_len < bufLen) { - bufLen = ((struct sockaddr_dl *)address)->sdl_len; + if (addr.sdl->sdl_len < bufLen) { + bufLen = addr.sdl->sdl_len; } else { bufLen = bufLen - 1; } - bcopy(((struct sockaddr_dl *)address)->sdl_data, buf, bufLen); + bcopy(addr.sdl->sdl_data, buf, bufLen); break; default : snprintf(buf, bufLen, "unexpected address family %d", address->sa_family); @@ -171,6 +179,66 @@ _SC_sockaddr_to_string(const struct sockaddr *address, char *buf, size_t bufLen) } +struct sockaddr * +_SC_string_to_sockaddr(const char *str, sa_family_t af, void *buf, size_t bufLen) +{ + union { + void *buf; + struct sockaddr *sa; + struct sockaddr_in *sin; + struct sockaddr_in6 *sin6; + } addr; + + if (buf == NULL) { + bufLen = sizeof(struct sockaddr_storage); + addr.buf = CFAllocatorAllocate(NULL, bufLen, 0); + } else { + addr.buf = buf; + } + + bzero(addr.buf, bufLen); + if (((af == AF_UNSPEC) || (af == AF_INET)) && + (bufLen >= sizeof(struct sockaddr_in)) && + inet_aton(str, &addr.sin->sin_addr) == 1) { + // if IPv4 address + addr.sin->sin_len = sizeof(struct sockaddr_in); + addr.sin->sin_family = AF_INET; + } else if (((af == AF_UNSPEC) || (af == AF_INET6)) && + (bufLen >= sizeof(struct sockaddr_in6)) && + inet_pton(AF_INET6, str, &addr.sin6->sin6_addr) == 1) { + // if IPv6 address + char *p; + + addr.sin6->sin6_len = sizeof(struct sockaddr_in6); + addr.sin6->sin6_family = AF_INET6; + + p = strchr(buf, '%'); + if (p != NULL) { + addr.sin6->sin6_scope_id = if_nametoindex(p + 1); + } + + if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6->sin6_addr) || + IN6_IS_ADDR_MC_LINKLOCAL(&addr.sin6->sin6_addr)) { + uint16_t if_index; + + if_index = ntohs(addr.sin6->sin6_addr.__u6_addr.__u6_addr16[1]); + addr.sin6->sin6_addr.__u6_addr.__u6_addr16[1] = 0; + if (addr.sin6->sin6_scope_id == 0) { + // use the scope id that was embedded in the [link local] IPv6 address + addr.sin6->sin6_scope_id = if_index; + } + } + } else { + if (addr.buf != buf) { + CFAllocatorDeallocate(NULL, addr.buf); + } + addr.buf = NULL; + } + + return addr.sa; +} + + void _SC_sendMachMessage(mach_port_t port, mach_msg_id_t msg_id) { @@ -305,7 +373,7 @@ _SCSerialize(CFPropertyListRef obj, CFDataRef *xml, void **dataRef, CFIndex *dat Boolean _SCUnserialize(CFPropertyListRef *obj, CFDataRef xml, void *dataRef, CFIndex dataLen) { - CFErrorRef error; + CFErrorRef error = NULL; if (xml == NULL) { kern_return_t status; @@ -471,7 +539,7 @@ _SCUnserializeData(CFDataRef *data, void *dataRef, CFIndex dataLen) } -CFDictionaryRef +CF_RETURNS_RETAINED CFDictionaryRef _SCSerializeMultiple(CFDictionaryRef dict) { const void * keys_q[N_QUICK]; @@ -529,6 +597,7 @@ _SCSerializeMultiple(CFDictionaryRef dict) } +CF_RETURNS_RETAINED CFDictionaryRef _SCUnserializeMultiple(CFDictionaryRef dict) { @@ -821,48 +890,92 @@ _SC_CFBundleGet(void) CFStringRef _SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle, CFStringRef key, CFStringRef value, CFStringRef tableName) { + CFDataRef data = NULL; + SInt32 errCode = 0; + CFURLRef resourcesURL; CFStringRef str = NULL; CFURLRef url; if ((tableName == NULL) || CFEqual(tableName, CFSTR(""))) tableName = CFSTR("Localizable"); - url = CFBundleCopyResourceURLForLocalization(bundle, - tableName, - CFSTR("strings"), - NULL, - CFSTR("English")); - if (url != NULL) { - CFDataRef data = NULL; - SInt32 errCode = 0; - - if (CFURLCreateDataAndPropertiesFromResource(NULL, - url, - &data, - NULL, - NULL, - &errCode)) { - CFDictionaryRef table; + /* + * First, try getting the requested string using a manually constructed + * URL to /Resources/English.lproj/.strings. Do this + * because CFBundleCopyResourceURLForLocalization() uses CFPreferences + * to get the preferred localizations, CFPreferences talks to + * OpenDirectory, and OpenDirectory tries to obtain the platform UUID. + * On machines where the platform UUID is set by InterfaceNamer, a + * deadlock can occur if InterfaceNamer calls + * CFBundleCopyResourceURLForLocalization() before setting the + * platform UUID in the kernel. + */ + resourcesURL = CFBundleCopyResourcesDirectoryURL(bundle); + if (resourcesURL != NULL) { + CFStringRef fileName = CFStringCreateWithFormat( + NULL, NULL, CFSTR("%@.strings"), tableName); + CFURLRef enlproj = CFURLCreateCopyAppendingPathComponent( + NULL, resourcesURL, CFSTR("English.lproj"), true); + url = CFURLCreateCopyAppendingPathComponent( + NULL, enlproj, fileName, false); + CFRelease(enlproj); + CFRelease(fileName); + CFRelease(resourcesURL); + + if (!CFURLCreateDataAndPropertiesFromResource(NULL, + url, + &data, + NULL, + NULL, + &errCode)) { + /* + * Failed to get the data using a manually-constructed URL + * for the given strings table. Fall back to using + * CFBundleCopyResourceURLForLocalization() below. + */ + data = NULL; + } + CFRelease(url); + } - table = CFPropertyListCreateWithData(NULL, - data, - kCFPropertyListImmutable, + if (data == NULL) { + url = CFBundleCopyResourceURLForLocalization(bundle, + tableName, + CFSTR("strings"), NULL, - NULL); - if (table != NULL) { - if (isA_CFDictionary(table)) { - str = CFDictionaryGetValue(table, key); - if (str != NULL) { - CFRetain(str); - } - } + CFSTR("English")); + if (url != NULL) { + if (!CFURLCreateDataAndPropertiesFromResource(NULL, + url, + &data, + NULL, + NULL, + &errCode)) { + data = NULL; + } + CFRelease(url); + } + } - CFRelease(table); + if (data != NULL) { + CFDictionaryRef table; + + table = CFPropertyListCreateWithData(NULL, + data, + kCFPropertyListImmutable, + NULL, + NULL); + if (table != NULL) { + if (isA_CFDictionary(table)) { + str = CFDictionaryGetValue(table, key); + if (str != NULL) { + CFRetain(str); + } } - CFRelease(data); + CFRelease(table); } - CFRelease(url); + CFRelease(data); } if (str == NULL) { @@ -879,9 +992,9 @@ _SC_CFBundleCopyNonLocalizedString(CFBundleRef bundle, CFStringRef key, CFString CFMachPortRef _SC_CFMachPortCreateWithPort(const char *portDescription, - mach_port_t portNum, - CFMachPortCallBack callout, - CFMachPortContext *context) + mach_port_t portNum, + CFMachPortCallBack callout, + CFMachPortContext *context) { CFMachPortRef port; Boolean shouldFree = FALSE; @@ -890,7 +1003,6 @@ _SC_CFMachPortCreateWithPort(const char *portDescription, if ((port == NULL) || shouldFree) { CFStringRef err; char *crash_info = NULL; - char name[64] = ""; SCLog(TRUE, LOG_ERR, CFSTR("%s: CFMachPortCreateWithPort() failed , port = %p"), @@ -908,11 +1020,10 @@ _SC_CFMachPortCreateWithPort(const char *portDescription, crash_info = _SC_cfstring_to_cstring(err, NULL, 0, kCFStringEncodingASCII); CFRelease(err); - (void) proc_name(getpid(), name, sizeof(name)); err = CFStringCreateWithFormat(NULL, NULL, CFSTR("A recycled mach_port has been detected by \"%s\"."), - name); + getprogname()); _SC_crash(crash_info, CFSTR("CFMachPort error"), err); CFAllocatorDeallocate(NULL, crash_info); CFRelease(err); @@ -1086,10 +1197,7 @@ _SC_logMachPortReferences(const char *str, mach_port_t port) static int is_configd = -1; if (is_configd == -1) { - char name[64] = ""; - - (void) proc_name(getpid(), name, sizeof(name)); - is_configd = (strncmp(name, "configd", sizeof(name)) == 0); + is_configd = (strcmp(getprogname(), "configd") == 0); } if (is_configd == 1) { // if "configd", add indication if this is the M[ain] or [P]lugin thread @@ -1111,20 +1219,22 @@ _SC_logMachPortReferences(const char *str, mach_port_t port) status = mach_port_type(mach_task_self(), port, &pt); if (status != KERN_SUCCESS) { SCLog(TRUE, LOG_NOTICE, - CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_SEND): %s"), + CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND): %s"), buf, port, mach_error_string(status)); + return; } if ((pt & MACH_PORT_TYPE_SEND) != 0) { status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, &refs_send); if (status != KERN_SUCCESS) { SCLog(TRUE, LOG_NOTICE, - CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_SEND): %s"), + CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND): %s"), buf, port, mach_error_string(status)); + return; } } @@ -1134,10 +1244,11 @@ _SC_logMachPortReferences(const char *str, mach_port_t port) status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_RECEIVE, &refs_recv); if (status != KERN_SUCCESS) { SCLog(TRUE, LOG_NOTICE, - CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_RECEIVE): %s"), + CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_RECEIVE): %s"), buf, port, mach_error_string(status)); + return; } count = MACH_PORT_RECEIVE_STATUS_COUNT; @@ -1148,10 +1259,11 @@ _SC_logMachPortReferences(const char *str, mach_port_t port) &count); if (status != KERN_SUCCESS) { SCLog(TRUE, LOG_NOTICE, - CFSTR("%mach_port_get_attributes(..., %d, MACH_PORT_RECEIVE_STATUS): %s"), + CFSTR("%smach_port_get_attributes(..., 0x%x, MACH_PORT_RECEIVE_STATUS): %s"), buf, port, mach_error_string(status)); + return; } } @@ -1159,10 +1271,11 @@ _SC_logMachPortReferences(const char *str, mach_port_t port) status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND_ONCE, &refs_once); if (status != KERN_SUCCESS) { SCLog(TRUE, LOG_NOTICE, - CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_SEND_ONCE): %s"), + CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_SEND_ONCE): %s"), buf, port, mach_error_string(status)); + return; } } @@ -1170,10 +1283,11 @@ _SC_logMachPortReferences(const char *str, mach_port_t port) status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_PORT_SET, &refs_pset); if (status != KERN_SUCCESS) { SCLog(TRUE, LOG_NOTICE, - CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_PORT_SET): %s"), + CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_PORT_SET): %s"), buf, port, mach_error_string(status)); + return; } } @@ -1181,10 +1295,11 @@ _SC_logMachPortReferences(const char *str, mach_port_t port) status = mach_port_get_refs(mach_task_self(), port, MACH_PORT_RIGHT_DEAD_NAME, &refs_dead); if (status != KERN_SUCCESS) { SCLog(TRUE, LOG_NOTICE, - CFSTR("%smach_port_get_refs(..., %d, MACH_PORT_RIGHT_DEAD_NAME): %s"), + CFSTR("%smach_port_get_refs(..., 0x%x, MACH_PORT_RIGHT_DEAD_NAME): %s"), buf, port, mach_error_string(status)); + return; } } @@ -1244,16 +1359,14 @@ asm(".desc ___crashreporter_info__, 0x10"); static Boolean _SC_SimulateCrash(const char *crash_info, CFStringRef notifyHeader, CFStringRef notifyMessage) { + Boolean ok = FALSE; + +#if ! TARGET_IPHONE_SIMULATOR static bool (*dyfunc_SimulateCrash)(pid_t, mach_exception_data_type_t, CFStringRef) = NULL; static void *image = NULL; - Boolean ok = FALSE; if ((dyfunc_SimulateCrash == NULL) && (image == NULL)) { - const char *framework = "/System/Library/PrivateFrameworks/CrashReporterSupport.framework/" -#if !TARGET_OS_EMBEDDED - "Versions/A/" -#endif // !TARGET_OS_EMBEDDED - "CrashReporterSupport"; + const char *framework = "/System/Library/PrivateFrameworks/CrashReporterSupport.framework/CrashReporterSupport"; struct stat statbuf; const char *suffix = getenv("DYLD_IMAGE_SUFFIX"); char path[MAXPATHLEN]; @@ -1303,6 +1416,7 @@ _SC_SimulateCrash(const char *crash_info, CFStringRef notifyHeader, CFStringRef } } #endif // TARGET_OS_EMBEDDED && !TARGET_OS_EMBEDDED_OTHER && !defined(DO_NOT_INFORM) +#endif /* ! TARGET_IPHONE_SIMULATOR */ return ok; } diff --git a/SystemConfiguration.fproj/SCDRemove.c b/SystemConfiguration.fproj/SCDRemove.c index 5f1230d..38fc2ff 100644 --- a/SystemConfiguration.fproj/SCDRemove.c +++ b/SystemConfiguration.fproj/SCDRemove.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2005, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -42,7 +42,7 @@ Boolean SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; + SCDynamicStorePrivateRef storePrivate; kern_return_t status; CFDataRef utfKey; /* serialized key */ xmlData_t myKeyRef; @@ -50,11 +50,15 @@ SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key) int sc_status; if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return FALSE; + store = __SCDynamicStoreNullSession(); + if (store == NULL) { + /* sorry, you must provide a session */ + _SCErrorSet(kSCStatusNoStoreSession); + return FALSE; + } } + storePrivate = (SCDynamicStorePrivateRef)store; if (storePrivate->server == MACH_PORT_NULL) { /* sorry, you must have an open session to play */ _SCErrorSet(kSCStatusNoStoreServer); @@ -75,21 +79,11 @@ SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key) myKeyLen, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreRemoveValue configremove(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreRemoveValue configremove()")) { + goto retry; } /* clean up */ diff --git a/SystemConfiguration.fproj/SCDSet.c b/SystemConfiguration.fproj/SCDSet.c index a0b2221..81afaf4 100644 --- a/SystemConfiguration.fproj/SCDSet.c +++ b/SystemConfiguration.fproj/SCDSet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2006, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2006, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -46,7 +46,7 @@ SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFArrayRef keysToRemove, CFArrayRef keysToNotify) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; + SCDynamicStorePrivateRef storePrivate; kern_return_t status; CFDataRef xmlSet = NULL; /* key/value pairs to set (XML serialized) */ xmlData_t mySetRef = NULL; /* key/value pairs to set (serialized) */ @@ -60,11 +60,15 @@ SCDynamicStoreSetMultiple(SCDynamicStoreRef store, int sc_status; if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return FALSE; + store = __SCDynamicStoreNullSession(); + if (store == NULL) { + /* sorry, you must provide a session */ + _SCErrorSet(kSCStatusNoStoreSession); + return FALSE; + } } + storePrivate = (SCDynamicStorePrivateRef)store; if (storePrivate->server == MACH_PORT_NULL) { _SCErrorSet(kSCStatusNoStoreServer); return FALSE; /* you must have an open session to play */ @@ -120,21 +124,11 @@ SCDynamicStoreSetMultiple(SCDynamicStoreRef store, myNotifyLen, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSetMultiple configset_m(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreSetMultiple configset_m()")) { + goto retry; } /* clean up */ @@ -153,7 +147,7 @@ SCDynamicStoreSetMultiple(SCDynamicStoreRef store, Boolean SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; + SCDynamicStorePrivateRef storePrivate; kern_return_t status; CFDataRef utfKey; /* serialized key */ xmlData_t myKeyRef; @@ -165,11 +159,15 @@ SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListR int newInstance; if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return FALSE; + store = __SCDynamicStoreNullSession(); + if (store == NULL) { + /* sorry, you must provide a session */ + _SCErrorSet(kSCStatusNoStoreSession); + return FALSE; + } } + storePrivate = (SCDynamicStorePrivateRef)store; if (storePrivate->server == MACH_PORT_NULL) { /* sorry, you must have an open session to play */ _SCErrorSet(kSCStatusNoStoreServer); @@ -201,21 +199,11 @@ SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListR &newInstance, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSetValue configset(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreSetValue configset()")) { + goto retry; } /* clean up */ diff --git a/SystemConfiguration.fproj/SCDSnapshot.c b/SystemConfiguration.fproj/SCDSnapshot.c index 4227790..3c8ac05 100644 --- a/SystemConfiguration.fproj/SCDSnapshot.c +++ b/SystemConfiguration.fproj/SCDSnapshot.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2004, 2005, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2004, 2005, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -42,16 +42,20 @@ Boolean SCDynamicStoreSnapshot(SCDynamicStoreRef store) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; + SCDynamicStorePrivateRef storePrivate; kern_return_t status; int sc_status; if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return FALSE; + store = __SCDynamicStoreNullSession(); + if (store == NULL) { + /* sorry, you must provide a session */ + _SCErrorSet(kSCStatusNoStoreSession); + return FALSE; + } } + storePrivate = (SCDynamicStorePrivateRef)store; if (storePrivate->server == MACH_PORT_NULL) { /* sorry, you must have an open session to play */ _SCErrorSet(kSCStatusNoStoreServer); @@ -62,21 +66,11 @@ SCDynamicStoreSnapshot(SCDynamicStoreRef store) status = snapshot(storePrivate->server, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSnapshot snapshot(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; + if (__SCDynamicStoreCheckRetryAndHandleError(store, + status, + &sc_status, + "SCDynamicStoreSnapshot snapshot()")) { + goto retry; } if (sc_status != kSCStatusOK) { diff --git a/SystemConfiguration.fproj/SCDTouch.c b/SystemConfiguration.fproj/SCDTouch.c deleted file mode 100644 index ca7ea4e..0000000 --- a/SystemConfiguration.fproj/SCDTouch.c +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2000-2005, 2009, 2010 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, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * 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@ - */ - -/* - * Modification History - * - * June 1, 2001 Allan Nathanson - * - public API conversion - * - * June 20, 2000 Allan Nathanson - * - initial revision - */ - -#include -#include - -#include -#include -#include "SCDynamicStoreInternal.h" -#include "config.h" /* MiG generated file */ - -Boolean -SCDynamicStoreTouchValue(SCDynamicStoreRef store, CFStringRef key) -{ - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - kern_return_t status; - CFDataRef utfKey; /* serialized key */ - xmlData_t myKeyRef; - CFIndex myKeyLen; - int sc_status; - - if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return FALSE; - } - - if (storePrivate->server == MACH_PORT_NULL) { - /* sorry, you must have an open session to play */ - _SCErrorSet(kSCStatusNoStoreServer); - return FALSE; - } - - /* serialize the key */ - if (!_SCSerializeString(key, &utfKey, (void **)&myKeyRef, &myKeyLen)) { - _SCErrorSet(kSCStatusFailed); - return FALSE; - } - - retry : - - /* send the key to the server */ - status = configtouch(storePrivate->server, - myKeyRef, - myKeyLen, - (int *)&sc_status); - - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreTouchValue configtouch(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - if (__SCDynamicStoreReconnect(store)) { - goto retry; - } - } - sc_status = status; - } - - /* clean up */ - CFRelease(utfKey); - - if (sc_status != kSCStatusOK) { - _SCErrorSet(sc_status); - return FALSE; - } - - return TRUE; -} diff --git a/SystemConfiguration.fproj/SCDUnlock.c b/SystemConfiguration.fproj/SCDUnlock.c deleted file mode 100644 index 06ac770..0000000 --- a/SystemConfiguration.fproj/SCDUnlock.c +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2000, 2001, 2004, 2005, 2009, 2010 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, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * 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@ - */ - -/* - * Modification History - * - * June 1, 2001 Allan Nathanson - * - public API conversion - * - * March 24, 2000 Allan Nathanson - * - initial revision - */ - -#include -#include - -#include -#include -#include "SCDynamicStoreInternal.h" -#include "config.h" /* MiG generated file */ - -Boolean -SCDynamicStoreUnlock(SCDynamicStoreRef store) -{ - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - kern_return_t status; - int sc_status; - - if (store == NULL) { - /* sorry, you must provide a session */ - _SCErrorSet(kSCStatusNoStoreSession); - return FALSE; - } - - if (storePrivate->server == MACH_PORT_NULL) { - /* sorry, you must have an open session to play */ - _SCErrorSet(kSCStatusNoStoreServer); - return FALSE; - } - - /* (attempt to) release the servers lock */ - status = configunlock(storePrivate->server, (int *)&sc_status); - if (status != KERN_SUCCESS) { - if ((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) { - /* the server's gone and our session port's dead, remove the dead name right */ - (void) mach_port_deallocate(mach_task_self(), storePrivate->server); - } else { - /* we got an unexpected error, leave the [session] port alone */ - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreUnlock configunlock(): %s"), mach_error_string(status)); - } - storePrivate->server = MACH_PORT_NULL; - if (((status == MACH_SEND_INVALID_DEST) || (status == MIG_SERVER_DIED)) - && __SCDynamicStoreReconnect(store)) { - sc_status = kSCStatusOK; - } else { - sc_status = status; - } - } - - if (sc_status != kSCStatusOK) { - _SCErrorSet(sc_status); - return FALSE; - } - - return TRUE; -} diff --git a/SystemConfiguration.fproj/SCDynamicStoreCopyDHCPInfo.h b/SystemConfiguration.fproj/SCDynamicStoreCopyDHCPInfo.h index db0590a..7682d42 100644 --- a/SystemConfiguration.fproj/SCDynamicStoreCopyDHCPInfo.h +++ b/SystemConfiguration.fproj/SCDynamicStoreCopyDHCPInfo.h @@ -95,6 +95,23 @@ DHCPInfoGetOptionData (CFDictionaryRef info, CFDateRef DHCPInfoGetLeaseStartTime (CFDictionaryRef info) __OSX_AVAILABLE_STARTING(__MAC_10_1,__IPHONE_2_0/*SPI*/); + +/*! + @function DHCPInfoGetLeaseExpirationTime + @discussion Returns a CFDateRef corresponding to the lease expiration time, + if present. + @param info The non-NULL DHCP information dictionary returned by + calling SCDynamicStoreCopyDHCPInfo. + @result Returns a non-NULL CFDateRef if the DHCP lease has an expiration; + NULL if the lease is infinite i.e. has no expiration, or the + configuration method is not DHCP. An infinite lease can be determined + by a non-NULL lease start time (see DHCPInfoGetLeaseStartTime above). + + The return value must NOT be released. +*/ +CFDateRef +DHCPInfoGetLeaseExpirationTime (CFDictionaryRef info) __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_NA); + __END_DECLS #endif /* USE_SYSTEMCONFIGURATION_PRIVATE_HEADERS */ diff --git a/SystemConfiguration.fproj/SCDynamicStoreInternal.h b/SystemConfiguration.fproj/SCDynamicStoreInternal.h index 04dc0ff..a32aa7f 100644 --- a/SystemConfiguration.fproj/SCDynamicStoreInternal.h +++ b/SystemConfiguration.fproj/SCDynamicStoreInternal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2006, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2004, 2006, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -41,7 +41,6 @@ typedef enum { NotifierNotRegistered = 0, Using_NotifierWait, - Using_NotifierInformViaCallback, Using_NotifierInformViaMachPort, Using_NotifierInformViaFD, Using_NotifierInformViaSignal, @@ -61,9 +60,9 @@ typedef struct { /* server side of the "configd" session */ mach_port_t server; + Boolean serverNullSession; /* per-session flags */ - Boolean locked; Boolean useSessionKeys; /* current status of notification requests */ @@ -74,27 +73,23 @@ typedef struct { CFRunLoopSourceRef rls; SCDynamicStoreCallBack rlsFunction; SCDynamicStoreContext rlsContext; - - /* "client" information associated with SCDynamicStoreNotifyCallback() */ - SCDynamicStoreCallBack_v1 callbackFunction; - void *callbackArgument; - CFMachPortRef callbackPort; - CFRunLoopSourceRef callbackRLS; + CFMachPortRef rlsNotifyPort; + CFRunLoopSourceRef rlsNotifyRLS; /* "client" information associated with SCDynamicStoreSetDispatchQueue() */ + dispatch_group_t dispatchGroup; dispatch_queue_t dispatchQueue; - dispatch_source_t callbackSource; - dispatch_queue_t callbackQueue; + dispatch_source_t dispatchSource; /* "client" information associated with SCDynamicStoreSetDisconnectCallBack() */ SCDynamicStoreDisconnectCallBack disconnectFunction; Boolean disconnectForceCallBack; - /* "server" SCDynamicStoreKeys being watched */ + /* SCDynamicStoreKeys being watched */ CFMutableArrayRef keys; CFMutableArrayRef patterns; - /* "server" information associated with SCDynamicStoreNotifyMachPort() */ + /* "server" information associated with mach port based notifications */ mach_port_t notifyPort; mach_msg_id_t notifyPortIdentifier; @@ -117,8 +112,14 @@ __SCDynamicStoreCreatePrivate (CFAllocatorRef allocator, SCDynamicStoreCallBack callout, SCDynamicStoreContext *context); +SCDynamicStoreRef +__SCDynamicStoreNullSession (void); + Boolean -__SCDynamicStoreReconnect (SCDynamicStoreRef store); +__SCDynamicStoreCheckRetryAndHandleError(SCDynamicStoreRef store, + kern_return_t status, + int *sc_status, + const char *func); Boolean __SCDynamicStoreReconnectNotifications (SCDynamicStoreRef store); diff --git a/SystemConfiguration.fproj/SCDynamicStorePrivate.h b/SystemConfiguration.fproj/SCDynamicStorePrivate.h index 1837b6a..af5a5cc 100644 --- a/SystemConfiguration.fproj/SCDynamicStorePrivate.h +++ b/SystemConfiguration.fproj/SCDynamicStorePrivate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2004, 2005, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2004, 2005, 2010, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -96,18 +96,6 @@ not make multiple calls to SCDynamicStoreSetValue). */ -/*! - @typedef SCDynamicStoreCallBack - @discussion Type of the callback function used when a - dynamic store change is delivered. - @param store The "dynamic store" session. - @param info .... - */ -typedef boolean_t (*SCDynamicStoreCallBack_v1) ( - SCDynamicStoreRef store, - void *info - ); - /*! @typedef SCDynamicStoreDisconnectCallBack @discussion Type of callback function used when notification of @@ -123,45 +111,6 @@ typedef void (*SCDynamicStoreDisconnectCallBack) ( __BEGIN_DECLS -/*! - @function SCDynamicStoreLock - @discussion Locks access to the configuration "dynamic store". All - other clients attempting to access the "dynamic store" will - block. All change notifications will be deferred until the - lock is released. - @param store The "dynamic store" session that should be locked. - @result TRUE if the lock was obtained; FALSE if an error was encountered. - */ -Boolean -SCDynamicStoreLock (SCDynamicStoreRef store); - -/*! - @function SCDynamicStoreUnlock - @discussion Unlocks access to the configuration "dynamic store". Other - clients will be able to access the "dynamic store". Any change - notifications will be delivered. - @param store The "dynamic store" session that should be unlocked. - @result TRUE if the lock was released; FALSE if an error was encountered. - */ -Boolean -SCDynamicStoreUnlock (SCDynamicStoreRef store); - -/*! - @function SCDynamicStoreTouchValue - @discussion Updates the value of the specified key in the - "dynamic store". - If the value does not exist then a CFDate object - will be associated with the key. - If the associated data is already a CFDate object - then it will be updated with the current time. - @param store The "dynamic store" session. - @param key The key of the value to updated. - @result TRUE if the value was updated; FALSE if an error was encountered. - */ -Boolean -SCDynamicStoreTouchValue (SCDynamicStoreRef store, - CFStringRef key); - /*! @function SCDynamicStoreAddWatchedKey @discussion Adds the specified key to the list of "dynamic store" @@ -196,61 +145,6 @@ SCDynamicStoreRemoveWatchedKey (SCDynamicStoreRef store, CFStringRef key, Boolean isRegex); -/*! - @function SCDynamicStoreNotifyCallback - @discussion Requests that the specified function be called whenever a - change has been detected to one of the "dynamic store" values - being monitored. - - The callback function will be called with two arguments, store and - context, that correspond to the current "dynamic store" session and - the provided context argument. - - The callback function should return a Boolean value indicating - whether an error occurred during execution of the callback. - - Note: An additional run loop source will be added for the notification. - This additional source will be removed if the notification is cancelled - or if the callback indicates that an error was detected. - - @param store The "dynamic store" session. - @param runLoop A pointer to the run loop. - @param func The callback function to call for each notification. - If this parameter is not a pointer to a function of the - correct prototype, the behavior is undefined. - @param context A pointer-sized user-defined value, that is passed as - the second parameter to the notification callback function, - but is otherwise unused by this function. If the context - is not what is expected by the notification function, the - behavior is undefined. - @result TRUE if the notification callback runloop source was - successfully added; FALSE if an error was encountered. - */ -Boolean -SCDynamicStoreNotifyCallback (SCDynamicStoreRef store, - CFRunLoopRef runLoop, - SCDynamicStoreCallBack_v1 func, - void *context); - -/*! - @function SCDynamicStoreNotifyMachPort - @discussion Allocates a mach port that can be used to detect changes to - one of the system configuration data entries associated with the - current session's notifier keys. When a change is detected, an - empty (no data) mach message with the specified identifier will - be delivered to the calling application via the allocated port. - - @param store An SCDynamicStoreRef that should be used for communication with the server. - @param msgid A mach message ID to be included with any notifications. - @param port A pointer to a mach port. Upon return, port will be filled - with the mach port that will be used for any notifications. - @result A boolean indicating the success (or failure) of the call. - */ -Boolean -SCDynamicStoreNotifyMachPort (SCDynamicStoreRef store, - mach_msg_id_t msgid, - mach_port_t *port); - /*! @function SCDynamicStoreNotifyFileDescriptor @discussion Allocates a file descriptor that can be used to detect changes diff --git a/SystemConfiguration.fproj/SCLocation.c b/SystemConfiguration.fproj/SCLocation.c index 06f71cd..41449cd 100644 --- a/SystemConfiguration.fproj/SCLocation.c +++ b/SystemConfiguration.fproj/SCLocation.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2002, 2004, 2006, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2002, 2004, 2006, 2010, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -47,19 +47,6 @@ SCDynamicStoreCopyLocation(SCDynamicStoreRef store) CFDictionaryRef dict = NULL; CFStringRef key; CFStringRef location = NULL; - Boolean tempSession = FALSE; - - if (store == NULL) { - store = SCDynamicStoreCreate(NULL, - CFSTR("SCDynamicStoreCopyLocation"), - NULL, - NULL); - if (store == NULL) { - SCLog(_sc_verbose, LOG_INFO, CFSTR("SCDynamicStoreCreate() failed")); - return NULL; - } - tempSession = TRUE; - } key = SCDynamicStoreKeyCreateLocation(NULL); dict = SCDynamicStoreCopyValue(store, key); @@ -70,7 +57,8 @@ SCDynamicStoreCopyLocation(SCDynamicStoreRef store) } location = CFDictionaryGetValue(dict, kSCDynamicStorePropSetupCurrentSet); - if (!isA_CFString(location)) { + location = isA_CFString(location); + if (location == NULL) { _SCErrorSet(kSCStatusNoKey); goto done; } @@ -80,7 +68,6 @@ SCDynamicStoreCopyLocation(SCDynamicStoreRef store) done : - if (tempSession) CFRelease(store); if (dict) CFRelease(dict); return location; diff --git a/SystemConfiguration.fproj/SCNetworkConfigurationInternal.c b/SystemConfiguration.fproj/SCNetworkConfigurationInternal.c index 088b769..2342887 100644 --- a/SystemConfiguration.fproj/SCNetworkConfigurationInternal.c +++ b/SystemConfiguration.fproj/SCNetworkConfigurationInternal.c @@ -72,7 +72,7 @@ __setPrefsConfiguration(SCPreferencesRef prefs, CFDictionaryRef config, Boolean keepInactive) { - CFMutableDictionaryRef newConfig = NULL; + CFMutableDictionaryRef newConfig = NULL; Boolean ok; if ((config != NULL) && !isA_CFDictionary(config)) { @@ -601,3 +601,50 @@ __remove_password(SCPreferencesRef prefs, return ok; } + + +__private_extern__ Boolean +__rank_to_str(SCNetworkServicePrimaryRank rank, CFStringRef *rankStr) +{ + switch (rank) { + case kSCNetworkServicePrimaryRankDefault : + *rankStr = NULL; + break; + case kSCNetworkServicePrimaryRankFirst : + *rankStr = kSCValNetServicePrimaryRankFirst; + break; + case kSCNetworkServicePrimaryRankLast : + *rankStr = kSCValNetServicePrimaryRankLast; + break; + case kSCNetworkServicePrimaryRankNever : + *rankStr = kSCValNetServicePrimaryRankNever; + break; + default : + return FALSE; + } + + return TRUE; +} + + +__private_extern__ Boolean +__str_to_rank(CFStringRef rankStr, SCNetworkServicePrimaryRank *rank) +{ + if (isA_CFString(rankStr)) { + if (CFEqual(rankStr, kSCValNetServicePrimaryRankFirst)) { + *rank = kSCNetworkServicePrimaryRankFirst; + } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankLast)) { + *rank = kSCNetworkServicePrimaryRankLast; + } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankNever)) { + *rank = kSCNetworkServicePrimaryRankNever; + } else { + return FALSE; + } + } else if (rankStr == NULL) { + *rank = kSCNetworkServicePrimaryRankDefault; + } else { + return FALSE; + } + + return TRUE; +} diff --git a/SystemConfiguration.fproj/SCNetworkConfigurationInternal.h b/SystemConfiguration.fproj/SCNetworkConfigurationInternal.h index ead47e5..ba253f0 100644 --- a/SystemConfiguration.fproj/SCNetworkConfigurationInternal.h +++ b/SystemConfiguration.fproj/SCNetworkConfigurationInternal.h @@ -29,6 +29,7 @@ #include #include #include +#include #include @@ -112,6 +113,9 @@ typedef struct { // prefs (for associated service, BOND interfaces, and VLAN interfaces) SCPreferencesRef prefs; + // SCDynamicStore + SCDynamicStoreRef store; + // serviceID (NULL if not associated with a service) CFStringRef serviceID; @@ -309,6 +313,7 @@ Boolean __SCNetworkServiceExistsForInterface (CFArrayRef services, SCNetworkInterfaceRef interface); +CF_RETURNS_RETAINED CFStringRef __SCNetworkServiceNextName (SCNetworkServiceRef service); @@ -380,6 +385,14 @@ __remove_password (SCPreferencesRef prefs, CFStringRef unique_id, CFDictionaryRef *newConfig); +Boolean +__rank_to_str (SCNetworkServicePrimaryRank rank, + CFStringRef *rankStr); + +Boolean +__str_to_rank (CFStringRef rankStr, + SCNetworkServicePrimaryRank *rank); + __END_DECLS #endif /* _SCNETWORKCONFIGURATIONINTERNAL_H */ diff --git a/SystemConfiguration.fproj/SCNetworkConfigurationPrivate.h b/SystemConfiguration.fproj/SCNetworkConfigurationPrivate.h index e04c5cc..fb1987b 100644 --- a/SystemConfiguration.fproj/SCNetworkConfigurationPrivate.h +++ b/SystemConfiguration.fproj/SCNetworkConfigurationPrivate.h @@ -44,7 +44,7 @@ __BEGIN_DECLS */ #pragma mark - -#pragma mark SCNetworkInterface configuration (typedefs, consts) +#pragma mark SCNetworkInterface configuration (typedefs, consts, enums) /*! @const kSCNetworkInterfaceTypeBridge @@ -79,6 +79,14 @@ extern const CFStringRef kSCNetworkInterfaceTypeVPN __OSX_AVAILABLE_STARTIN */ typedef SCNetworkInterfaceRef SCBridgeInterfaceRef; +enum { + kSCNetworkServicePrimaryRankDefault = 0, + kSCNetworkServicePrimaryRankFirst = 1, + kSCNetworkServicePrimaryRankLast = 2, + kSCNetworkServicePrimaryRankNever = 3 +}; +typedef uint32_t SCNetworkServicePrimaryRank; + #pragma mark - #pragma mark SCNetworkInterface configuration (SPI) @@ -162,6 +170,18 @@ _SCNetworkInterfaceCompare (const void *val1, const void *val2, void *context) __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0); +/*! + @function _SCNetworkInterfaceCopyActive + @discussion Creates an SCNetworkInterface and associated with interface name + and SCDynamicStoreRef + @param the interface name + @param the SCDynamicStoreRef + @result the SCNetworkInterface + */ +SCNetworkInterfaceRef +_SCNetworkInterfaceCopyActive (SCDynamicStoreRef store, + CFStringRef bsdName) __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_0); + /*! @function _SCNetworkInterfaceCopyAllWithPreferences Returns all network capable interfaces on the system. @@ -229,6 +249,27 @@ _SCNetworkInterfaceCreateWithEntity (CFAllocatorRef allocator, SCNetworkInterfaceRef _SCNetworkInterfaceCreateWithIONetworkInterfaceObject (io_object_t if_obj) __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0); +/*! + @function SCNetworkInterfaceGetPrimaryRank + @discussion We allow caller to retrieve the rank on an interface. + The key is stored in State:/Network/Interface//Service + @param the interface to get the rank + @result SCNetworkServicePrimaryRank + */ +SCNetworkServicePrimaryRank +SCNetworkInterfaceGetPrimaryRank (SCNetworkInterfaceRef interface) __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_0); + +/*! + @function SCNetworkInterfaceSetPrimaryRank + @discussion We allow caller to set an assertion on an interface. + @param the interface to set the rank assertion + @param the new rank to be set + @result TRUE if operation is successful; FALSE if an error was encountered. + */ +Boolean +SCNetworkInterfaceSetPrimaryRank (SCNetworkInterfaceRef interface, + SCNetworkServicePrimaryRank newRank) __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_0); + #define kSCNetworkInterfaceConfigurationActionKey CFSTR("New Interface Detected Action") #define kSCNetworkInterfaceConfigurationActionValueNone CFSTR("None") #define kSCNetworkInterfaceConfigurationActionValuePrompt CFSTR("Prompt") @@ -307,7 +348,7 @@ _SCNetworkInterfaceGetIOPath (SCNetworkInterfaceRef interface) __OSX_AVAILAB Zero if no entry ID is available. */ uint64_t -_SCNetworkInterfaceGetIORegistryEntryID (SCNetworkInterfaceRef interface) __OSX_AVAILABLE_STARTING(__MAC_10_7/*FIXME*/,__IPHONE_5_0); +_SCNetworkInterfaceGetIORegistryEntryID (SCNetworkInterfaceRef interface) __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_0); /*! @function _SCNetworkInterfaceIsBluetoothPAN @@ -671,14 +712,6 @@ isA_SCNetworkService(CFTypeRef obj) return (isA_CFType(obj, SCNetworkServiceGetTypeID())); } -enum { - kSCNetworkServicePrimaryRankDefault = 0, - kSCNetworkServicePrimaryRankFirst = 1, - kSCNetworkServicePrimaryRankLast = 2, - kSCNetworkServicePrimaryRankNever = 3 -}; -typedef uint32_t SCNetworkServicePrimaryRank; - /*! @function _SCNetworkServiceCompare @discussion Compares two SCNetworkService objects. @@ -829,5 +862,4 @@ SCNetworkSetSetSelectedVPNService (SCNetworkSetRef set, SCNetworkServiceRef service) __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0); __END_DECLS - #endif /* _SCNETWORKCONFIGURATIONPRIVATE_H */ diff --git a/SystemConfiguration.fproj/SCNetworkConnection.c b/SystemConfiguration.fproj/SCNetworkConnection.c index abaefee..e54ea07 100644 --- a/SystemConfiguration.fproj/SCNetworkConnection.c +++ b/SystemConfiguration.fproj/SCNetworkConnection.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2011 Apple Inc. All rights reserved. + * Copyright (c) 2003-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -88,6 +88,12 @@ typedef struct { /* service */ SCNetworkServiceRef service; + /* client info (if we are proxying for another process */ + mach_port_t client_audit_session; + uid_t client_uid; + gid_t client_gid; + pid_t client_pid; + /* ref to PPP controller for control messages */ mach_port_t session_port; @@ -105,9 +111,9 @@ typedef struct { CFMutableArrayRef rlList; /* SCNetworkConnectionSetDispatchQueue */ + dispatch_group_t dispatchGroup; dispatch_queue_t dispatchQueue; - dispatch_queue_t callbackQueue; - dispatch_source_t callbackSource; + dispatch_source_t dispatchSource; } SCNetworkConnectionPrivate, *SCNetworkConnectionPrivateRef; @@ -146,6 +152,13 @@ __SCNetworkConnectionDeallocate(CFTypeRef cf) /* release resources */ pthread_mutex_destroy(&connectionPrivate->lock); + if (connectionPrivate->client_audit_session != MACH_PORT_NULL) { + mach_port_mod_refs(mach_task_self(), + connectionPrivate->client_audit_session, + MACH_PORT_RIGHT_SEND, + -1); + } + if (connectionPrivate->rls != NULL) { CFRunLoopSourceInvalidate(connectionPrivate->rls); CFRelease(connectionPrivate->rls); @@ -334,6 +347,11 @@ __SCNetworkConnectionCreatePrivate(CFAllocatorRef allocator, /* save the service */ connectionPrivate->service = CFRetain(service); + connectionPrivate->client_audit_session = MACH_PORT_NULL; + connectionPrivate->client_uid = geteuid(); + connectionPrivate->client_gid = getegid(); + connectionPrivate->client_pid = getpid(); + connectionPrivate->rlsFunction = callout; if (context) { @@ -396,6 +414,16 @@ __SCNetworkConnectionServerPort(kern_return_t *status) } +#if ((__MAC_OS_X_VERSION_MIN_REQUIRED >= 1070) || (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000)) && !TARGET_IPHONE_SIMULATOR +#define HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION +#endif + + +#if ((__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) || (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000)) && !TARGET_IPHONE_SIMULATOR +#define HAVE_PPPCONTROLLER_ATTACHWITHPROXY +#endif + + static mach_port_t __SCNetworkConnectionSessionPort(SCNetworkConnectionPrivateRef connectionPrivate) { @@ -408,7 +436,10 @@ __SCNetworkConnectionSessionPort(SCNetworkConnectionPrivateRef connectionPrivate int sc_status = kSCStatusFailed; mach_port_t server = scnc_server; kern_return_t status = KERN_SUCCESS; + +#ifdef HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION mach_port_t au_session = MACH_PORT_NULL; +#endif // HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION if (connectionPrivate->session_port != MACH_PORT_NULL) { return connectionPrivate->session_port; @@ -428,7 +459,9 @@ __SCNetworkConnectionSessionPort(SCNetworkConnectionPrivateRef connectionPrivate mach_port_mod_refs(mach_task_self(), mp, MACH_PORT_RIGHT_RECEIVE, -1); } +#ifdef HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION au_session = audit_session_self(); +#endif // HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION // open a new session with the server while (TRUE) { @@ -455,14 +488,46 @@ __SCNetworkConnectionSessionPort(SCNetworkConnectionPrivateRef connectionPrivate } if (server != MACH_PORT_NULL) { - status = pppcontroller_attach(server, - data, - dataLen, - bootstrap_port, - notify_port, - au_session, - &connectionPrivate->session_port, - &sc_status); +#ifdef HAVE_PPPCONTROLLER_ATTACHWITHPROXY + if ((connectionPrivate->client_audit_session == MACH_PORT_NULL) && + (connectionPrivate->client_uid == geteuid()) && + (connectionPrivate->client_gid == getegid()) && + (connectionPrivate->client_pid == getpid()) + ) { +#endif // HAVE_PPPCONTROLLER_ATTACHWITHPROXY + status = pppcontroller_attach(server, + data, + dataLen, + bootstrap_port, + notify_port, +#ifdef HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION + au_session, +#endif // HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION + &connectionPrivate->session_port, + &sc_status); +#ifdef HAVE_PPPCONTROLLER_ATTACHWITHPROXY + } else { + mach_port_t client_au_session; + + if (connectionPrivate->client_audit_session == MACH_PORT_NULL) { + client_au_session = au_session; + } else { + client_au_session = connectionPrivate->client_audit_session; + } + + status = pppcontroller_attach_proxy(server, + data, + dataLen, + bootstrap_port, + notify_port, + client_au_session, + connectionPrivate->client_uid, + connectionPrivate->client_gid, + connectionPrivate->client_pid, + &connectionPrivate->session_port, + &sc_status); + } +#endif // HAVE_PPPCONTROLLER_ATTACHWITHPROXY if (status == KERN_SUCCESS) { if (sc_status != kSCStatusOK) { SCLog(TRUE, LOG_DEBUG, @@ -598,9 +663,12 @@ __SCNetworkConnectionSessionPort(SCNetworkConnectionPrivateRef connectionPrivate done : // clean up - if (au_session != MACH_PORT_NULL) { + +#ifdef HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION + if (au_session != MACH_PORT_NULL){ (void)mach_port_deallocate(mach_task_self(), au_session); } +#endif // HAVE_PPPCONTROLLER_ATTACHWITHAUDITSESSION if (dataRef != NULL) CFRelease(dataRef); @@ -649,6 +717,7 @@ static Boolean __SCNetworkConnectionReconnectNotifications(SCNetworkConnectionRef connection) { SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection; + dispatch_group_t dispatchGroup = NULL; dispatch_queue_t dispatchQueue = NULL; Boolean ok = TRUE; CFArrayRef rlList = NULL; @@ -663,7 +732,14 @@ __SCNetworkConnectionReconnectNotifications(SCNetworkConnectionRef connection) rlList = CFArrayCreateCopy(NULL, connectionPrivate->rlList); } if (connectionPrivate->dispatchQueue != NULL) { + // save dispatchQueue, release reference when we've queue'd blocks + // complete, allow re-scheduling + dispatchGroup = connectionPrivate->dispatchGroup; + connectionPrivate->dispatchGroup = NULL; dispatchQueue = connectionPrivate->dispatchQueue; + connectionPrivate->dispatchQueue = NULL; + + // and take an extra reference for rescheduling dispatch_retain(dispatchQueue); } @@ -677,28 +753,23 @@ __SCNetworkConnectionReconnectNotifications(SCNetworkConnectionRef connection) CFRelease(connectionPrivate->rls); connectionPrivate->rls = NULL; } - if (connectionPrivate->callbackSource != NULL) { - dispatch_source_cancel(connectionPrivate->callbackSource); - if (connectionPrivate->callbackQueue != dispatch_get_current_queue()) { - // ensure the cancellation has completed - dispatch_sync(connectionPrivate->callbackQueue, ^{}); - } - dispatch_release(connectionPrivate->callbackSource); - connectionPrivate->callbackSource = NULL; - } - if (connectionPrivate->callbackQueue != NULL) { - dispatch_release(connectionPrivate->callbackQueue); - connectionPrivate->callbackQueue = NULL; - } - if (connectionPrivate->dispatchQueue != NULL) { - dispatch_release(connectionPrivate->dispatchQueue); - connectionPrivate->dispatchQueue = NULL; + if (connectionPrivate->dispatchSource != NULL) { + dispatch_source_cancel(connectionPrivate->dispatchSource); + connectionPrivate->dispatchSource = NULL; } connectionPrivate->scheduled = FALSE; pthread_mutex_unlock(&connectionPrivate->lock); + if (dispatchGroup != NULL) { + dispatch_group_notify(dispatchGroup, dispatchQueue, ^{ + // release group/queue references + dispatch_release(dispatchQueue); + dispatch_release(dispatchGroup); // releases our connection reference + }); + } + // re-schedule if (rlList != NULL) { CFIndex i; @@ -905,6 +976,45 @@ SCNetworkConnectionCopyServiceID(SCNetworkConnectionRef connection) } +Boolean +SCNetworkConnectionSetClientInfo(SCNetworkConnectionRef connection, + mach_port_t client_audit_session, + uid_t client_uid, + gid_t client_gid, + pid_t client_pid) +{ + SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection; + + if (!isA_SCNetworkConnection(connection)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + // save client bootstrap port + if (connectionPrivate->client_audit_session != MACH_PORT_NULL) { + mach_port_mod_refs(mach_task_self(), + connectionPrivate->client_audit_session, + MACH_PORT_RIGHT_SEND, + -1); + connectionPrivate->client_audit_session = MACH_PORT_NULL; + } + connectionPrivate->client_audit_session = client_audit_session; + if (connectionPrivate->client_audit_session != MACH_PORT_NULL) { + mach_port_mod_refs(mach_task_self(), + connectionPrivate->client_audit_session, + MACH_PORT_RIGHT_SEND, + 1); + } + + // save client UID, GID, and PID + connectionPrivate->client_uid = client_uid; + connectionPrivate->client_gid = client_gid; + connectionPrivate->client_pid = client_pid; + + return TRUE; +} + + CFDictionaryRef SCNetworkConnectionCopyStatistics(SCNetworkConnectionRef connection) { @@ -1449,30 +1559,6 @@ SCNetworkConnectionCopyUserOptions(SCNetworkConnectionRef connection) } -static boolean_t -SCNetworkConnectionNotifyMIGCallback(mach_msg_header_t *message, mach_msg_header_t *reply) -{ - SCNetworkConnectionPrivateRef connectionPrivate = dispatch_get_context(dispatch_get_current_queue()); - - if (connectionPrivate != NULL) { - mach_msg_empty_rcv_t *buf = malloc(sizeof(*buf)); - - bcopy(message, buf, sizeof(*buf)); - CFRetain(connectionPrivate); - dispatch_async(connectionPrivate->dispatchQueue, ^{ - __SCNetworkConnectionCallBack(connectionPrivate->notify_port, - buf, - sizeof(*buf), - connectionPrivate); - CFRelease(connectionPrivate); - free(buf); - }); - } - reply->msgh_remote_port = MACH_PORT_NULL; - return false; -} - - static Boolean __SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection, CFRunLoopRef runLoop, @@ -1529,42 +1615,80 @@ __SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection, } if (queue != NULL) { - mach_port_t mp; - char qname[256]; - - connectionPrivate->dispatchQueue = queue; - dispatch_retain(connectionPrivate->dispatchQueue); - - snprintf(qname, sizeof(qname), "com.apple.SCNetworkConnection.%p", connection); - connectionPrivate->callbackQueue = dispatch_queue_create(qname, NULL); - if (connectionPrivate->callbackQueue == NULL){ - SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkConnection dispatch_queue_create() failed")); - goto fail; - } - CFRetain(connection); // Note: will be released when the dispatch queue is released - dispatch_set_context(connectionPrivate->callbackQueue, connectionPrivate); - dispatch_set_finalizer_f(connectionPrivate->callbackQueue, (dispatch_function_t)CFRelease); + mach_port_t mp; + dispatch_source_t source; mp = CFMachPortGetPort(connectionPrivate->notify_port); - connectionPrivate->callbackSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, - mp, - 0, - connectionPrivate->callbackQueue); - if (connectionPrivate->callbackSource == NULL) { + source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, mp, 0, queue); + if (source == NULL) { SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkConnection dispatch_source_create() failed")); - goto fail; + _SCErrorSet(kSCStatusFailed); + goto done; } - dispatch_source_set_event_handler(connectionPrivate->callbackSource, ^{ - union MaxMsgSize { - mach_msg_empty_rcv_t normal; + + // have our dispatch source hold a reference to the notification CFMachPort + CFRetain(connectionPrivate->notify_port); + dispatch_set_context(source, (void *)connectionPrivate->notify_port); + dispatch_set_finalizer_f(source, (dispatch_function_t)CFRelease); + + // retain the dispatch queue + connectionPrivate->dispatchQueue = queue; + dispatch_retain(connectionPrivate->dispatchQueue); + + // + // We've taken a reference to the callers dispatch_queue and we + // want to hold on to that reference until we've processed any/all + // notifications. To facilitate this we create a group, dispatch + // any notification blocks to via that group, and when the caller + // has told us to stop the notifications (unschedule) we wait for + // the group to empty and use the group's finalizer to release + // our reference to the SCNetworkConnection. + // + connectionPrivate->dispatchGroup = dispatch_group_create(); + CFRetain(connection); + dispatch_set_context(connectionPrivate->dispatchGroup, (void *)connection); + dispatch_set_finalizer_f(connectionPrivate->dispatchGroup, (dispatch_function_t)CFRelease); + + dispatch_source_set_event_handler(source, ^{ + kern_return_t kr; + union { + u_int8_t buf[sizeof(mach_msg_empty_t) + MAX_TRAILER_SIZE]; + mach_msg_empty_rcv_t msg; mach_no_senders_notification_t no_senders; - }; + } notify_msg; + CFMachPortRef notify_port; + + kr = mach_msg(¬ify_msg.msg.header, // msg + MACH_RCV_MSG, // options + 0, // send_size + sizeof(notify_msg), // rcv_size + mp, // rcv_name + MACH_MSG_TIMEOUT_NONE, // timeout + MACH_PORT_NULL); // notify + if (kr != KERN_SUCCESS) { + SCLog(TRUE, LOG_ERR, + CFSTR("SCDynamicStore notification handler, kr=0x%x"), + kr); + return; + } - dispatch_mig_server(connectionPrivate->callbackSource, - sizeof(union MaxMsgSize), - SCNetworkConnectionNotifyMIGCallback); + CFRetain(connection); + notify_port = dispatch_get_context(source); + dispatch_group_async(connectionPrivate->dispatchGroup, connectionPrivate->dispatchQueue, ^{ + __SCNetworkConnectionCallBack(notify_port, + (void *)¬ify_msg.msg, + sizeof(notify_msg), + (void *)connection); + CFRelease(connection); + }); }); - dispatch_resume(connectionPrivate->callbackSource); + + dispatch_source_set_cancel_handler(source, ^{ + dispatch_release(source); + }); + + connectionPrivate->dispatchSource = source; + dispatch_resume(source); } else { if (!_SC_isScheduled(NULL, runLoop, runLoopMode, connectionPrivate->rlList)) { /* @@ -1578,24 +1702,6 @@ __SCNetworkConnectionScheduleWithRunLoop(SCNetworkConnectionRef connection, } ok = TRUE; - goto done; - - fail : - - if (connectionPrivate->callbackSource != NULL) { - dispatch_source_cancel(connectionPrivate->callbackSource); - dispatch_release(connectionPrivate->callbackSource); - connectionPrivate->callbackSource = NULL; - } - if (connectionPrivate->callbackQueue != NULL) { - dispatch_release(connectionPrivate->callbackQueue); - connectionPrivate->callbackQueue = NULL; - } - if (connectionPrivate->dispatchQueue != NULL) { - dispatch_release(connectionPrivate->dispatchQueue); - connectionPrivate->dispatchQueue = NULL; - } - _SCErrorSet(kSCStatusFailed); done : @@ -1611,12 +1717,17 @@ __SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection, dispatch_queue_t queue) { SCNetworkConnectionPrivateRef connectionPrivate = (SCNetworkConnectionPrivateRef)connection; + dispatch_group_t drainGroup = NULL; + dispatch_queue_t drainQueue = NULL; int sc_status = kSCStatusFailed; CFIndex n = 0; Boolean ok = FALSE; mach_port_t session_port; kern_return_t status; + // hold a reference while we unschedule + CFRetain(connection); + pthread_mutex_lock(&connectionPrivate->lock); if ((runLoop != NULL) && !connectionPrivate->scheduled) { // if we should be scheduled (but are not) @@ -1635,17 +1746,18 @@ __SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection, goto done; } - if (runLoop == NULL) { - dispatch_source_cancel(connectionPrivate->callbackSource); - if (connectionPrivate->callbackQueue != dispatch_get_current_queue()) { - // ensure the cancellation has completed - dispatch_sync(connectionPrivate->callbackQueue, ^{}); + if (connectionPrivate->dispatchQueue != NULL) { + // cancel dispatchSource + if (connectionPrivate->dispatchSource != NULL) { + dispatch_source_cancel(connectionPrivate->dispatchSource); + connectionPrivate->dispatchSource = NULL; } - dispatch_release(connectionPrivate->callbackSource); - connectionPrivate->callbackSource = NULL; - dispatch_release(connectionPrivate->callbackQueue); - connectionPrivate->callbackQueue = NULL; - dispatch_release(connectionPrivate->dispatchQueue); + + // save dispatchQueue/group, release reference when all queue'd blocks + // have been processed, allow re-scheduling + drainGroup = connectionPrivate->dispatchGroup; + connectionPrivate->dispatchGroup = NULL; + drainQueue = connectionPrivate->dispatchQueue; connectionPrivate->dispatchQueue = NULL; } else { if (!_SC_unschedule(connection, runLoop, runLoopMode, connectionPrivate->rlList, FALSE)) { @@ -1697,6 +1809,18 @@ __SCNetworkConnectionUnscheduleFromRunLoop(SCNetworkConnectionRef connection, done : pthread_mutex_unlock(&connectionPrivate->lock); + + if (drainGroup != NULL) { + dispatch_group_notify(drainGroup, drainQueue, ^{ + // release group/queue references + dispatch_release(drainQueue); + dispatch_release(drainGroup); // releases our connection reference + }); + } + + // release our reference + CFRelease(connection); + return ok; } @@ -1780,8 +1904,8 @@ static int onDemand_notify_token = -1; /* * return TRUE if domain1 ends with domain2, and will check for trailing "." */ -static Boolean -domainEndsWithDomain(CFStringRef domain1, CFStringRef domain2) +Boolean +_SC_domainEndsWithDomain(CFStringRef compare_domain, CFStringRef match_domain) { CFRange range; Boolean ret = FALSE; @@ -1789,29 +1913,44 @@ domainEndsWithDomain(CFStringRef domain1, CFStringRef domain2) Boolean s1_created = FALSE; CFStringRef s2 = NULL; Boolean s2_created = FALSE; + CFStringRef s3 = NULL; - if (CFStringHasSuffix(domain1, CFSTR("."))) { + if (CFStringHasSuffix(compare_domain, CFSTR("."))) { range.location = 0; - range.length = CFStringGetLength(domain1) - 1; - s1 = CFStringCreateWithSubstring(NULL, domain1, range); + range.length = CFStringGetLength(compare_domain) - 1; + s1 = CFStringCreateWithSubstring(NULL, compare_domain, range); if (s1 == NULL) { goto done; } s1_created = TRUE; } else { - s1 = domain1; + s1 = compare_domain; } - if (CFStringHasSuffix(domain2, CFSTR("."))) { + if (CFStringHasSuffix(match_domain, CFSTR("."))) { range.location = 0; - range.length = CFStringGetLength(domain2) - 1; - s2 = CFStringCreateWithSubstring(NULL, domain2, range); + range.length = CFStringGetLength(match_domain) - 1; + s2 = CFStringCreateWithSubstring(NULL, match_domain, range); if (s2 == NULL) { goto done; } s2_created = TRUE; } else { - s2 = domain2; + s2 = match_domain; + } + + if (CFStringHasPrefix(s2, CFSTR("*."))) { + range.location = 2; + range.length = CFStringGetLength(s2)-2; + s3 = CFStringCreateWithSubstring(NULL, s2, range); + if (s3 == NULL) { + goto done; + } + if (s2_created) { + CFRelease(s2); + } + s2 = s3; + s2_created = TRUE; } ret = CFStringHasSuffix(s1, s2); @@ -1949,7 +2088,7 @@ __SCNetworkConnectionCopyOnDemandInfoWithName(SCDynamicStoreRef *storeP, continue; } - if (domainEndsWithDomain(hostName, domain)) { + if (_SC_domainEndsWithDomain(hostName, domain)) { CFArrayRef exceptions; int exceptionsCount; int exceptionsIndex; @@ -1968,7 +2107,7 @@ __SCNetworkConnectionCopyOnDemandInfoWithName(SCDynamicStoreRef *storeP, continue; } - if (domainEndsWithDomain(hostName, exception)) { + if (_SC_domainEndsWithDomain(hostName, exception)) { // found matching exception if (_sc_debug || (debug > 0)) { SCLog(TRUE, LOG_INFO, CFSTR("OnDemand match exception")); @@ -1980,6 +2119,8 @@ __SCNetworkConnectionCopyOnDemandInfoWithName(SCDynamicStoreRef *storeP, // if we have a matching domain and there were no exceptions // then we pass back the OnDemand info + ok = TRUE; + if (!CFDictionaryGetValueIfPresent(trigger, kSCNetworkConnectionOnDemandStatus, (const void **)&num) || @@ -1994,20 +2135,45 @@ __SCNetworkConnectionCopyOnDemandInfoWithName(SCDynamicStoreRef *storeP, if (connectionServiceID != NULL) { *connectionServiceID = CFDictionaryGetValue(trigger, kSCNetworkConnectionOnDemandServiceID); *connectionServiceID = isA_CFString(*connectionServiceID); - if (*connectionServiceID != NULL) { + if ((*connectionServiceID != NULL) && (CFStringGetLength(*connectionServiceID) > 0)) { CFRetain(*connectionServiceID); - } + } else { + SCLog(TRUE, LOG_INFO, + CFSTR("OnDemand%s configuration error, no serviceID"), + onDemandRetry ? " (on retry)" : ""); + *connectionServiceID = NULL; + ok = FALSE; + } } if (vpnRemoteAddress != NULL) { *vpnRemoteAddress = CFDictionaryGetValue(trigger, kSCNetworkConnectionOnDemandRemoteAddress); *vpnRemoteAddress = isA_CFString(*vpnRemoteAddress); - if (*vpnRemoteAddress != NULL) { + if ((*vpnRemoteAddress != NULL) && (CFStringGetLength(*vpnRemoteAddress) > 0)) { CFRetain(*vpnRemoteAddress); + } else { + SCLog(TRUE, LOG_INFO, + CFSTR("OnDemand%s configuration error, no server address"), + onDemandRetry ? " (on retry)" : ""); + + *vpnRemoteAddress = NULL; + ok = FALSE; } } + if (!ok) { + if ((connectionServiceID != NULL) && (*connectionServiceID != NULL)) { + CFRelease(*connectionServiceID); + *connectionServiceID = NULL; + } + if ((vpnRemoteAddress != NULL) && (*vpnRemoteAddress != NULL)) { + CFRelease(*vpnRemoteAddress); + *vpnRemoteAddress = NULL; + } + continue; + } + if (_sc_debug || (debug > 0)) { SCLog(TRUE, LOG_INFO, CFSTR("OnDemand%s match, connection status = %d"), @@ -2015,7 +2181,6 @@ __SCNetworkConnectionCopyOnDemandInfoWithName(SCDynamicStoreRef *storeP, onDemandStatus); } - ok = TRUE; goto done; } } @@ -2231,7 +2396,7 @@ SCNetworkConnectionCopyUserPreferences(CFDictionaryRef selectionOptions, catchAllConfig = configIndex; } - if (domainEndsWithDomain(hostName, domain)) { + if (_SC_domainEndsWithDomain(hostName, domain)) { // found matching configuration *serviceID = serviceName; CFRetain(*serviceID); diff --git a/SystemConfiguration.fproj/SCNetworkConnectionPrivate.c b/SystemConfiguration.fproj/SCNetworkConnectionPrivate.c index 381f753..6e98de1 100644 --- a/SystemConfiguration.fproj/SCNetworkConnectionPrivate.c +++ b/SystemConfiguration.fproj/SCNetworkConnectionPrivate.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2006-2010 Apple Inc. All rights reserved. + * Copyright (c) 2006-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -530,7 +530,7 @@ SCUserPreferencesRemove(SCUserPreferencesRef userPreferences) } -static CFDictionaryRef +static CF_RETURNS_RETAINED CFDictionaryRef setCurrentCallout(CFStringRef serviceID, CFDictionaryRef current, void *context1, @@ -644,7 +644,7 @@ SCUserPreferencesCopyName(SCUserPreferencesRef userPreferences) } -static CFDictionaryRef +static CF_RETURNS_RETAINED CFDictionaryRef setNameCallout(CFStringRef serviceID, CFDictionaryRef current, void *context1, @@ -790,7 +790,7 @@ SCUserPreferencesCopyInterfaceConfiguration(SCUserPreferencesRef userPreferences } -static CFDictionaryRef +static CF_RETURNS_RETAINED CFDictionaryRef setInterfaceConfigurationCallout(CFStringRef serviceID, CFDictionaryRef current, void *context1, diff --git a/SystemConfiguration.fproj/SCNetworkConnectionPrivate.h b/SystemConfiguration.fproj/SCNetworkConnectionPrivate.h index a3ec9ff..d790dbb 100644 --- a/SystemConfiguration.fproj/SCNetworkConnectionPrivate.h +++ b/SystemConfiguration.fproj/SCNetworkConnectionPrivate.h @@ -68,6 +68,13 @@ SCNetworkConnectionSuspend (SCNetworkConnectionRef connection) __OSX_AVAILAB Boolean SCNetworkConnectionResume (SCNetworkConnectionRef connection) __OSX_AVAILABLE_STARTING(__MAC_10_3,__IPHONE_2_0); +Boolean +SCNetworkConnectionSetClientInfo (SCNetworkConnectionRef connection, + mach_port_t client_audit_session, + uid_t client_uid, + gid_t client_gid, + pid_t client_pid) __OSX_AVAILABLE_STARTING(__MAC_10_8,__IPHONE_5_0); + #pragma mark - #pragma mark SCNetworkConnection "VPN on Demand" SPIs @@ -137,7 +144,6 @@ SCNetworkConnectionResume (SCNetworkConnectionRef connection) __OSX_AVAILABL #define kSCNetworkConnectionOnDemandMatchDomainsNever CFSTR("OnDemandMatchDomainsNever") -__private_extern__ Boolean __SCNetworkConnectionCopyOnDemandInfoWithName (SCDynamicStoreRef *storeP, CFStringRef nodeName, diff --git a/SystemConfiguration.fproj/SCNetworkInterface.c b/SystemConfiguration.fproj/SCNetworkInterface.c index 6c5fc48..a9cbfc0 100644 --- a/SystemConfiguration.fproj/SCNetworkInterface.c +++ b/SystemConfiguration.fproj/SCNetworkInterface.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2011 Apple Inc. All rights reserved. + * Copyright (c) 2004-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -161,6 +161,7 @@ static SCNetworkInterfacePrivate __kSCNetworkInterfaceIPv4 = { NULL, // localization arg2 NULL, // [layered] interface NULL, // prefs + NULL, // store NULL, // serviceID NULL, // unsaved NULL, // entity_device @@ -203,6 +204,7 @@ static SCNetworkInterfacePrivate __kSCNetworkInterfaceLoopback = { NULL, // localization arg2 NULL, // [layered] interface NULL, // prefs + NULL, // store NULL, // serviceID NULL, // unsaved NULL, // entity_device @@ -515,6 +517,9 @@ __SCNetworkInterfaceDeallocate(CFTypeRef cf) if (interfacePrivate->prefs != NULL) CFRelease(interfacePrivate->prefs); + if (interfacePrivate->store != NULL) + CFRelease(interfacePrivate->store); + if (interfacePrivate->serviceID != NULL) CFRelease(interfacePrivate->serviceID); @@ -748,6 +753,7 @@ __SCNetworkInterfaceCreatePrivate(CFAllocatorRef allocator, interfacePrivate->localized_arg2 = NULL; interfacePrivate->interface = (interface != NULL) ? CFRetain(interface) : NULL; interfacePrivate->prefs = (prefs != NULL) ? CFRetain(prefs) : NULL; + interfacePrivate->store = NULL; interfacePrivate->serviceID = (serviceID != NULL) ? CFRetain(serviceID) : NULL; interfacePrivate->unsaved = NULL; interfacePrivate->entity_device = NULL; @@ -832,7 +838,8 @@ __SCNetworkInterfaceSupportsVLAN(CFStringRef bsd_if) } // check the link type and hwassist flags - ifm = (struct if_msghdr *)buf; + // ALIGN: buf is aligned + ifm = (struct if_msghdr *)(void *)buf; switch (ifm->ifm_type) { case RTM_IFINFO : { #if defined(IF_HWASSIST_VLAN_TAGGING) && defined(IF_HWASSIST_VLAN_MTU) @@ -947,7 +954,7 @@ _SCVLANInterfaceCreatePrivate(CFAllocatorRef allocator, #pragma mark Interface ordering -static CFArrayRef +static CF_RETURNS_RETAINED CFArrayRef split_path(CFStringRef path) { CFArrayRef components; @@ -1239,7 +1246,7 @@ static const CFStringRef slot_prefixes[] = { }; -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef pci_slot(io_registry_entry_t interface, CFTypeRef *pci_slot_name) { kern_return_t kr; @@ -1335,7 +1342,7 @@ compare_bsdNames(const void *val1, const void *val2, void *context) } -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef pci_port(CFTypeRef slot_name, int ift, CFStringRef bsdName) { CFIndex n; @@ -2485,7 +2492,7 @@ createInterface(io_registry_entry_t interface, processInterface func) } -static CFArrayRef +static CF_RETURNS_RETAINED CFArrayRef findMatchingInterfaces(CFDictionaryRef matching, processInterface func) { CFMutableArrayRef interfaces; @@ -2686,7 +2693,7 @@ __addExtendedConfigurationType(const void *key, const void *value, void *context } -static CFArrayRef +static CF_RETURNS_RETAINED CFArrayRef extendedConfigurationTypes(SCNetworkInterfaceRef interface) { CFIndex i; @@ -2975,6 +2982,7 @@ findInterface(CFArrayRef interfaces, CFStringRef match_if) return NULL; } +#if !TARGET_OS_IPHONE static SCNetworkInterfaceRef findBondInterface(SCPreferencesRef prefs, CFStringRef ifDevice) { @@ -2993,6 +3001,7 @@ findBondInterface(SCPreferencesRef prefs, CFStringRef ifDevice) } return interface; } +#endif // !TARGET_OS_IPHONE static SCNetworkInterfaceRef findBridgeInterface(SCPreferencesRef prefs, CFStringRef ifDevice) @@ -3047,9 +3056,11 @@ _SCNetworkInterfaceCreateWithBSDName(CFAllocatorRef allocator, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(entity, kSCPropNetInterfaceDeviceName, bsdName); +#if !TARGET_OS_IPHONE if ((flags & kIncludeBondInterfaces) == 0) { CFDictionarySetValue(entity, CFSTR("_NO_BOND_INTERFACES_"), kCFBooleanTrue); } +#endif // !TARGET_OS_IPHONE if ((flags & kIncludeBridgeInterfaces) == 0) { CFDictionarySetValue(entity, CFSTR("_NO_BRIDGE_INTERFACES_"), kCFBooleanTrue); @@ -3321,10 +3332,11 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, if (prefs == NULL) { break; } +#if !TARGET_OS_IPHONE if (!CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BOND_INTERFACES_"))) { interfacePrivate = (SCNetworkInterfacePrivateRef)findBondInterface(prefs, ifDevice); } - +#endif // !TARGET_OS_IPHONE if ((interfacePrivate == NULL) && !CFDictionaryContainsKey(interface_entity, CFSTR("_NO_BRIDGE_INTERFACES_"))) { interfacePrivate = (SCNetworkInterfacePrivateRef)findBridgeInterface(prefs, ifDevice); @@ -3512,6 +3524,7 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, __SCNetworkInterfaceSetService((SCNetworkInterfaceRef)interfacePrivate, service); +#if !TARGET_OS_IPHONE // set prefs & serviceID to Bond member interfaces if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBond)) { CFIndex i; @@ -3527,6 +3540,7 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, __SCNetworkInterfaceSetService(member, service); } } +#endif // !TARGET_OS_IPHONE // set prefs & serviceID to Bridge member interfaces if (CFEqual(interfacePrivate->interface_type, kSCNetworkInterfaceTypeBridge)) { @@ -3654,6 +3668,50 @@ __SCNetworkInterfaceCopyAll_RS232() } +#if !TARGET_OS_IPHONE +static void +addBTPANInterface(SCPreferencesRef prefs, CFMutableArrayRef all_interfaces) +{ + CFIndex i; + CFIndex n; + CFArrayRef services; + + n = CFArrayGetCount(all_interfaces); + for (i = 0; i < n; i++) { + SCNetworkInterfaceRef interface; + + interface = CFArrayGetValueAtIndex(all_interfaces, i); + if (_SCNetworkInterfaceIsBluetoothPAN(interface)) { + // if we already have a BT-PAN interface + return; + } + } + + services = SCNetworkServiceCopyAll(prefs); + if (services != NULL) { + n = CFArrayGetCount(services); + for (i = 0; i < n; i++) { + SCNetworkInterfaceRef interface; + SCNetworkServiceRef service; + + service = CFArrayGetValueAtIndex(services, i); + interface = SCNetworkServiceGetInterface(service); + if ((interface != NULL) && + _SCNetworkInterfaceIsBluetoothPAN(interface)) { + // include BT-PAN interface + CFArrayAppendValue(all_interfaces, interface); + break; + } + } + + CFRelease(services); + } + + return; +} +#endif // !TARGET_OS_IPHONE + + static void add_interfaces(CFMutableArrayRef all_interfaces, CFArrayRef new_interfaces) { @@ -3783,11 +3841,13 @@ _SCNetworkInterfaceCopyAllWithPreferences(SCPreferencesRef prefs) } } if (prefs != NULL) { +#if !TARGET_OS_IPHONE new_interfaces = SCBondInterfaceCopyAll(prefs); if (new_interfaces != NULL) { add_interfaces(all_interfaces, new_interfaces); CFRelease(new_interfaces); } +#endif // !TARGET_OS_IPHONE new_interfaces = SCBridgeInterfaceCopyAll(prefs); if (new_interfaces != NULL) { @@ -3801,6 +3861,11 @@ _SCNetworkInterfaceCopyAllWithPreferences(SCPreferencesRef prefs) CFRelease(new_interfaces); } +#if !TARGET_OS_IPHONE + // add BT-PAN interface + addBTPANInterface(prefs, all_interfaces); +#endif // !TARGET_OS_IPHONE + if (temp_preferences) CFRelease(prefs); } @@ -4740,25 +4805,18 @@ _SCNetworkInterfaceForceConfigurationRefresh(CFStringRef ifName) { CFStringRef key; Boolean ok = FALSE; - SCDynamicStoreRef store; if (!isA_CFString(ifName)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } - store = SCDynamicStoreCreate(NULL, CFSTR("_SCNetworkInterfaceForceConfigurationRefresh"), NULL, NULL); - if (store == NULL) { - return FALSE; - } - key = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, kSCDynamicStoreDomainState, ifName, kSCEntNetRefreshConfiguration); - ok = SCDynamicStoreNotifyValue(store, key); + ok = SCDynamicStoreNotifyValue(NULL, key); CFRelease(key); - CFRelease(store); return ok; } @@ -6422,12 +6480,14 @@ __SCNetworkInterfaceIsMember(SCPreferencesRef prefs, SCNetworkInterfaceRef inter members = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); +#if !TARGET_OS_IPHONE // add Bond [member] interfaces interfaces = SCBondInterfaceCopyAll(prefs); if (interfaces != NULL) { __SCBondInterfaceListCollectMembers(interfaces, members); CFRelease(interfaces); } +#endif // !TARGET_OS_IPHONE // add Bridge [member] interfaces interfaces = SCBridgeInterfaceCopyAll(prefs); @@ -6530,3 +6590,141 @@ __SCNetworkInterfaceSetDeepConfiguration(SCNetworkSetRef set, SCNetworkInterface return; } + + +SCNetworkInterfaceRef +_SCNetworkInterfaceCopyActive(SCDynamicStoreRef store, CFStringRef bsdName) +{ + SCNetworkInterfaceRef interface; + + interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeAllVirtualInterfaces); + if (interface == NULL) { + return NULL; + } + + if (store != NULL) { + SCNetworkInterfacePrivateRef interfacePrivate = + (SCNetworkInterfacePrivateRef)interface; + + CFRetain(store); + interfacePrivate->store = store; + } + + return interface; +} + + +SCNetworkServicePrimaryRank +SCNetworkInterfaceGetPrimaryRank(SCNetworkInterfaceRef interface) +{ + CFDictionaryRef entity; + SCNetworkInterfacePrivateRef interfacePrivate = + (SCNetworkInterfacePrivateRef)interface; + CFStringRef ifName; + Boolean ok = FALSE; + CFStringRef path; + SCNetworkServicePrimaryRank rank = kSCNetworkServicePrimaryRankDefault; + SCDynamicStoreRef session; + + ifName = SCNetworkInterfaceGetBSDName(interface); + if ((ifName == NULL) || (interfacePrivate->store == NULL)) { + _SCErrorSet(kSCStatusInvalidArgument); + return rank; + } + + session = interfacePrivate->store; + + path = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, + kSCDynamicStoreDomainState, + ifName, + kSCEntNetService); + entity = SCDynamicStoreCopyValue(session, path); + CFRelease(path); + + if (entity != NULL) { + if (isA_CFDictionary(entity)) { + CFStringRef rankStr = + CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank); + ok = __str_to_rank(rankStr, &rank); + } + CFRelease(entity); + } + + if (!ok) { + rank = kSCNetworkServicePrimaryRankDefault; + _SCErrorSet(kSCStatusInvalidArgument); + } else if (rank == kSCNetworkServicePrimaryRankDefault) { + _SCErrorSet(kSCStatusOK); + } + + return (rank); +} + +Boolean +SCNetworkInterfaceSetPrimaryRank(SCNetworkInterfaceRef interface, + SCNetworkServicePrimaryRank newRank) +{ + CFDictionaryRef entity; + SCNetworkInterfacePrivateRef interfacePrivate = + (SCNetworkInterfacePrivateRef)interface; + CFStringRef ifName; + CFMutableDictionaryRef newEntity; + Boolean ok = TRUE; + CFStringRef path = NULL; + CFStringRef rankStr; + SCDynamicStoreRef session; + + ifName = SCNetworkInterfaceGetBSDName(interface); + if ((ifName == NULL) || (interfacePrivate->store == NULL)) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + session = interfacePrivate->store; + + ok = __rank_to_str(newRank, &rankStr); + if (!ok) { + _SCErrorSet(kSCStatusInvalidArgument); + return FALSE; + } + + path = SCDynamicStoreKeyCreateNetworkInterfaceEntity(NULL, + kSCDynamicStoreDomainState, + ifName, + kSCEntNetService); + + entity = SCDynamicStoreCopyValue(session, path); + if (entity != NULL) { + if (!isA_CFDictionary(entity)) { + CFRelease(entity); + _SCErrorSet(kSCStatusFailed); + goto done; + } + newEntity = CFDictionaryCreateMutableCopy(NULL, 0, entity); + CFRelease(entity); + } else { + newEntity = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + + if (rankStr != NULL) { + CFDictionarySetValue(newEntity, kSCPropNetServicePrimaryRank, rankStr); + } else { + CFDictionaryRemoveValue(newEntity, kSCPropNetServicePrimaryRank); + } + + if (CFDictionaryGetCount(newEntity) > 0) { + ok = SCDynamicStoreSetValue(session, path, newEntity); + } else { + ok = SCDynamicStoreRemoveValue(session, path); + } + + CFRelease(newEntity); + + done : + + if (path != NULL) CFRelease(path); + return ok; +} diff --git a/SystemConfiguration.fproj/SCNetworkReachability.c b/SystemConfiguration.fproj/SCNetworkReachability.c index 4b6ebd0..2d0c04f 100644 --- a/SystemConfiguration.fproj/SCNetworkReachability.c +++ b/SystemConfiguration.fproj/SCNetworkReachability.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2011 Apple Inc. All rights reserved. + * Copyright (c) 2003-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,6 +24,9 @@ /* * Modification History * + * April 12, 2011 Allan Nathanson + * - add SCNetworkReachability "server" + * * March 31, 2004 Allan Nathanson * - use [SC] DNS configuration information * @@ -35,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -68,6 +72,8 @@ #define s6_addr16 __u6_addr.__u6_addr16 #endif +#include "SCNetworkReachabilityInternal.h" + #include #if !TARGET_IPHONE_SIMULATOR @@ -88,6 +94,39 @@ +#define DEBUG_REACHABILITY_TYPE_NAME "create w/name" +#define DEBUG_REACHABILITY_TYPE_NAME_OPTIONS " + options" + +#define DEBUG_REACHABILITY_TYPE_ADDRESS "create w/address" +#define DEBUG_REACHABILITY_TYPE_ADDRESS_OPTIONS " + options" + +#define DEBUG_REACHABILITY_TYPE_ADDRESSPAIR "create w/address pair" +#define DEBUG_REACHABILITY_TYPE_ADDRESSPAIR_OPTIONS " + options" + + +static pthread_mutexattr_t lock_attr; + +#define MUTEX_INIT(m) { \ + int _lock_ = (pthread_mutex_init(m, &lock_attr) == 0); \ + assert(_lock_); \ +} + +#define MUTEX_LOCK(m) { \ + int _lock_ = (pthread_mutex_lock(m) == 0); \ + assert(_lock_); \ +} + +#define MUTEX_UNLOCK(m) { \ + int _unlock_ = (pthread_mutex_unlock(m) == 0); \ + assert(_unlock_); \ +} + +#define MUTEX_ASSERT_HELD(m) { \ + int _locked_ = (pthread_mutex_lock(m) == EDEADLK); \ + assert(_locked_); \ +} + + #ifdef HAVE_GETADDRINFO_INTERFACE_ASYNC_CALL /* Libinfo SPI */ mach_port_t @@ -100,33 +139,28 @@ _getaddrinfo_interface_async_call(const char *nodename, #endif /* HAVE_GETADDRINFO_INTERFACE_ASYNC_CALL */ -#define kSCNetworkReachabilityFlagsFirstResolvePending (1<<31) +#define SCNETWORKREACHABILITY_TRIGGER_KEY CFSTR("com.apple.SCNetworkReachability:FORCE-CHANGE") -#define N_QUICK 64 - - -typedef enum { NO = 0, YES, UNKNOWN } lazyBoolean; +// how long (minimum time, us) to wait before retrying DNS query after EAI_NONAME +#define EAI_NONAME_RETRY_DELAY_USEC 250000 // 250ms +// how long (maximum time, us) after DNS configuration change we accept EAI_NONAME +// without question. +#define EAI_NONAME_RETRY_LIMIT_USEC 2500000 // 2.5s -typedef enum { - reachabilityTypeAddress, - reachabilityTypeAddressPair, - reachabilityTypeName -} addressType; +// how long (maximum time, ns) to wait for a long-lived-query callback before +// we assume EAI_NONAME. +#define LLQ_TIMEOUT_NSEC 30 * NSEC_PER_SEC // 30s -// how long (minimum time, us) to wait before retrying DNS query after EAI_NONAME -#define EAI_NONAME_RETRY_DELAY_USEC 250000 -// how long (maximum time, us) after DNS configuration change we accept EAI_NONAME -// without question. -#define EAI_NONAME_RETRY_LIMIT_USEC 2500000 +#define N_QUICK 64 static CFStringRef __SCNetworkReachabilityCopyDescription (CFTypeRef cf); static void __SCNetworkReachabilityDeallocate (CFTypeRef cf); -static void rlsPerform(void *info); +static void reachPerform (void *info); static Boolean @@ -143,82 +177,6 @@ __SCNetworkReachabilityUnscheduleFromRunLoop (SCNetworkReachabilityRef target, Boolean onDemand); -typedef struct { - SCNetworkReachabilityFlags flags; - unsigned int if_index; - Boolean sleeping; -} ReachabilityInfo; - - -typedef struct { - - /* base CFType information */ - CFRuntimeBase cfBase; - - /* lock */ - pthread_mutex_t lock; - - /* address type */ - addressType type; - - /* target host name */ - const char *name; - const char *serv; - struct addrinfo hints; - Boolean needResolve; - CFArrayRef resolvedAddress; /* CFArray[CFData] */ - int resolvedAddressError; - - /* [scoped routing] interface constraints */ - unsigned int if_index; - char if_name[IFNAMSIZ]; - - /* local & remote addresses */ - struct sockaddr *localAddress; - struct sockaddr *remoteAddress; - - /* current reachability flags */ - ReachabilityInfo info; - ReachabilityInfo last_notify; - - /* run loop source, callout, context, rl scheduling info */ - Boolean scheduled; - CFRunLoopSourceRef rls; - SCNetworkReachabilityCallBack rlsFunction; - SCNetworkReachabilityContext rlsContext; - CFMutableArrayRef rlList; - - dispatch_queue_t dispatchQueue; // SCNetworkReachabilitySetDispatchQueue - dispatch_queue_t asyncDNSQueue; - dispatch_source_t asyncDNSSource; - - /* [async] DNS query info */ - Boolean haveDNS; - mach_port_t dnsMP; - CFMachPortRef dnsPort; - CFRunLoopSourceRef dnsRLS; - struct timeval dnsQueryStart; - struct timeval dnsQueryEnd; - dispatch_source_t dnsRetry; // != NULL if DNS retry request queued - int dnsRetryCount; // number of retry attempts - - /* [async] processing info */ - struct timeval last_dns; - - /* on demand info */ - Boolean onDemandBypass; - CFStringRef onDemandName; - CFStringRef onDemandRemoteAddress; - SCNetworkReachabilityRef onDemandServer; - CFStringRef onDemandServiceID; - - - /* logging */ - char log_prefix[32]; - -} SCNetworkReachabilityPrivate, *SCNetworkReachabilityPrivateRef; - - static CFTypeID __kSCNetworkReachabilityTypeID = _kCFRuntimeNotATypeID; @@ -236,14 +194,34 @@ static const CFRuntimeClass __SCNetworkReachabilityClass = { static pthread_once_t initialized = PTHREAD_ONCE_INIT; -static const ReachabilityInfo NOT_REACHABLE = { 0, 0, FALSE }; -static const ReachabilityInfo NOT_REPORTED = { 0xFFFFFFFF, 0, FALSE }; +static const ReachabilityInfo NOT_REACHABLE = { 0, 0, 0, { 0 }, FALSE }; +static const ReachabilityInfo NOT_REPORTED = { 0, 0xFFFFFFFF, 0, { 0 }, FALSE }; static int rtm_seq = 0; +static const struct addrinfo HINTS_DEFAULT = { +#ifdef AI_PARALLEL + .ai_flags = AI_ADDRCONFIG | AI_PARALLEL, +#else // AI_PARALLEL + .ai_flags = AI_ADDRCONFIG, +#endif // AI_PARALLEL +}; + + static const struct timeval TIME_ZERO = { 0, 0 }; +static Boolean D_llqBypass = FALSE; +static int llqCount = 0; +static DNSServiceRef llqMain = NULL; +static CFMutableSetRef llqUpdated = NULL; + + +#ifdef HAVE_REACHABILITY_SERVER +static Boolean D_serverBypass = FALSE; +#endif // HAVE_REACHABILITY_SERVER + + #if !TARGET_OS_IPHONE /* * Power capabilities (sleep/wake) @@ -256,7 +234,6 @@ static IOPMSystemPowerStateCapabilities power_capabilities = kIOPMSytemPowerStat * host "something has changed" notifications */ -static pthread_mutex_t hn_lock = PTHREAD_MUTEX_INITIALIZER; static SCDynamicStoreRef hn_store = NULL; static dispatch_queue_t hn_dispatchQueue = NULL; static CFMutableSetRef hn_targets = NULL; @@ -278,11 +255,11 @@ static int dns_token; static Boolean dns_token_valid = FALSE; -static __inline__ CFTypeRef -isA_SCNetworkReachability(CFTypeRef obj) -{ - return (isA_CFType(obj, SCNetworkReachabilityGetTypeID())); -} +typedef enum { + dns_query_sync, + dns_query_async, + dns_query_llq +} dns_query_type; static void @@ -299,62 +276,106 @@ __dns_query_start(struct timeval *dnsQueryStart, static void __dns_query_end(SCNetworkReachabilityRef target, Boolean found, - Boolean async, + dns_query_type query_type, struct timeval *dnsQueryStart, struct timeval *dnsQueryEnd) { struct timeval dnsQueryElapsed; + Boolean firstQuery; SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + // report initial or updated query time + firstQuery = !timerisset(dnsQueryEnd); + (void) gettimeofday(dnsQueryEnd, NULL); if (!_sc_debug) { return; } - if (dnsQueryStart->tv_sec == 0) { + if (!timerisset(dnsQueryStart)) { return; } timersub(dnsQueryEnd, dnsQueryStart, &dnsQueryElapsed); - SCLog(TRUE, LOG_INFO, - CFSTR("%s%ssync DNS complete%s (query time = %d.%3.3d)"), - targetPrivate->log_prefix, - async ? "a" : "", - found ? "" : ", host not found", - dnsQueryElapsed.tv_sec, - dnsQueryElapsed.tv_usec / 1000); + switch (query_type) { + +// #define QUERY_TIME__FMT "%d.%3.3d" +// #define QUERY_TIME__DIV 1000 + + #define QUERY_TIME__FMT "%d.%6.6d" + #define QUERY_TIME__DIV 1 + + case dns_query_sync : + SCLog(TRUE, LOG_INFO, + CFSTR("%ssync DNS complete%s (query time = " QUERY_TIME__FMT ")"), + targetPrivate->log_prefix, + found ? "" : ", host not found", + dnsQueryElapsed.tv_sec, + dnsQueryElapsed.tv_usec / QUERY_TIME__DIV); + break; + case dns_query_async : + SCLog(TRUE, LOG_INFO, + CFSTR("%sasync DNS complete%s (query time = " QUERY_TIME__FMT ")"), + targetPrivate->log_prefix, + found ? "" : ", host not found", + dnsQueryElapsed.tv_sec, + dnsQueryElapsed.tv_usec / QUERY_TIME__DIV); + break; + case dns_query_llq : + SCLog(TRUE, LOG_INFO, + CFSTR("%sDNS updated%s (%s = " QUERY_TIME__FMT ")"), + targetPrivate->log_prefix, + found ? "" : ", host not found", + firstQuery ? "query time" : "updated after", + dnsQueryElapsed.tv_sec, + dnsQueryElapsed.tv_usec / QUERY_TIME__DIV); + break; + } return; } static __inline__ Boolean -__reach_equal(ReachabilityInfo *r1, ReachabilityInfo *r2) +__reach_changed(ReachabilityInfo *r1, ReachabilityInfo *r2) { if (r1->flags != r2->flags) { // if the reachability flags changed - return FALSE; + return TRUE; } if (r1->if_index != r2->if_index) { // if the target interface changed - return FALSE; + return TRUE; } if ((r1->sleeping != r2->sleeping) && !r2->sleeping) { // if our sleep/wake status changed and if we // are no longer sleeping - return FALSE; + return TRUE; } - return TRUE; + return FALSE; +} + + +static __inline__ void +_reach_set(ReachabilityInfo *dst, const ReachabilityInfo *src, uint64_t cycle) +{ + memcpy(dst, src, sizeof(ReachabilityInfo)); + dst->cycle = cycle; + + return; } +#pragma mark - +#pragma mark SCDynamicStore info + + typedef struct { SCDynamicStoreRef store; - Boolean storeAdded; CFStringRef entity; CFDictionaryRef dict; CFIndex n; @@ -365,66 +386,132 @@ typedef struct { } ReachabilityStoreInfo, *ReachabilityStoreInfoRef; +static ReachabilityStoreInfo S_storeInfo = { 0 }; +static Boolean S_storeInfoActive = FALSE; + + +static dispatch_queue_t +_storeInfo_queue() +{ + static dispatch_once_t once; + static dispatch_queue_t q; + + dispatch_once(&once, ^{ + q = dispatch_queue_create("SCNetworkReachabilty.storeInfo", NULL); + }); + + return q; +} + + static void -initReachabilityStoreInfo(ReachabilityStoreInfoRef store_info) +ReachabilityStoreInfo_copy(ReachabilityStoreInfoRef src, + ReachabilityStoreInfoRef dst) { - bzero(store_info, sizeof(ReachabilityStoreInfo)); + if (src->dict != NULL) { + dst->store = src->store; + CFRetain(dst->store); + + dst->dict = src->dict; + CFRetain(dst->dict); + + dst->n = src->n; + if (dst->n > 0) { + if (dst->n <= (CFIndex)(sizeof(dst->keys_q) / sizeof(CFTypeRef))) { + dst->keys = dst->keys_q; + dst->values = dst->values_q; + } else { + dst->keys = CFAllocatorAllocate(NULL, dst->n * sizeof(CFTypeRef), 0); + dst->values = CFAllocatorAllocate(NULL, dst->n * sizeof(CFTypeRef), 0); + } + memcpy(dst->keys, src->keys, dst->n * sizeof(CFTypeRef)); + memcpy(dst->values, src->values, dst->n * sizeof(CFTypeRef)); + } + } + return; } -static Boolean -updateReachabilityStoreInfo(ReachabilityStoreInfoRef store_info, - SCDynamicStoreRef *storeP, - sa_family_t sa_family) +static void +ReachabilityStoreInfo_enable(Boolean enable) { - CFStringRef pattern; - CFMutableArrayRef patterns; + dispatch_sync(_storeInfo_queue(), ^{ + S_storeInfoActive = enable; + }); - switch (sa_family) { - case AF_UNSPEC : - store_info->entity = NULL; - break; - case AF_INET : - store_info->entity = kSCEntNetIPv4; - break; - case AF_INET6 : - store_info->entity = kSCEntNetIPv6; - break; - default : - return FALSE; + return; +} + + +static void +ReachabilityStoreInfo_free(ReachabilityStoreInfoRef store_info) +{ + if ((store_info->n > 0) && (store_info->keys != store_info->keys_q)) { + CFAllocatorDeallocate(NULL, store_info->keys); + store_info->keys = NULL; + + CFAllocatorDeallocate(NULL, store_info->values); + store_info->values = NULL; } + store_info->n = 0; if (store_info->dict != NULL) { - // if info already available - return TRUE; + CFRelease(store_info->dict); + store_info->dict = NULL; } - if (store_info->store == NULL) { - store_info->store = (storeP != NULL) ? *storeP : NULL; - if (store_info->store == NULL) { - store_info->store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkReachability"), NULL, NULL); - if (store_info->store == NULL) { - SCLog(TRUE, LOG_ERR, CFSTR("updateReachabilityStoreInfo SCDynamicStoreCreate() failed")); - return FALSE; - } + if (store_info->store != NULL) { + CFRelease(store_info->store); + store_info->store = NULL; + } - if (storeP != NULL) { - /// pass back the allocated SCDynamicStoreRef - *storeP = store_info->store; - } else { - // this one is ours - store_info->storeAdded = TRUE; + return; +} + + +static void +ReachabilityStoreInfo_init(ReachabilityStoreInfoRef store_info) +{ + dispatch_sync(_storeInfo_queue(), ^{ + bzero(store_info, sizeof(ReachabilityStoreInfo)); + + if (S_storeInfoActive && (S_storeInfo.dict != NULL)) { + ReachabilityStoreInfo_copy(&S_storeInfo, store_info); + } + }); + + return; +} + + +static void +ReachabilityStoreInfo_save(ReachabilityStoreInfoRef store_info) +{ + dispatch_sync(_storeInfo_queue(), ^{ + if ((store_info == NULL) || + !_SC_CFEqual(store_info->dict, S_storeInfo.dict)) { + // free any old info + ReachabilityStoreInfo_free(&S_storeInfo); + + // save new info + if (S_storeInfoActive && + (store_info != NULL) && + (store_info->dict != NULL)) { + ReachabilityStoreInfo_copy(store_info, &S_storeInfo); } } - } + }); - if (sa_family == AF_UNSPEC) { - // if the address family was not specified than - // all we wanted, for now, was to establish the - // SCDynamicStore session - return TRUE; - } + return; +} + + +static Boolean +ReachabilityStoreInfo_fill(ReachabilityStoreInfoRef store_info) +{ + CFStringRef pattern; + CFMutableArrayRef patterns; patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); @@ -535,31 +622,98 @@ updateReachabilityStoreInfo(ReachabilityStoreInfoRef store_info, } -static void -freeReachabilityStoreInfo(ReachabilityStoreInfoRef store_info) +static Boolean +ReachabilityStoreInfo_update(ReachabilityStoreInfoRef store_info, + SCDynamicStoreRef *storeP, + sa_family_t sa_family) { - if ((store_info->n > 0) && (store_info->keys != store_info->keys_q)) { - CFAllocatorDeallocate(NULL, store_info->keys); - store_info->keys = NULL; + __block Boolean ok = TRUE; - CFAllocatorDeallocate(NULL, store_info->values); - store_info->values = NULL; + switch (sa_family) { + case AF_UNSPEC : + store_info->entity = NULL; + break; + case AF_INET : + store_info->entity = kSCEntNetIPv4; + break; + case AF_INET6 : + store_info->entity = kSCEntNetIPv6; + break; + default : + return FALSE; } if (store_info->dict != NULL) { - CFRelease(store_info->dict); - store_info->dict = NULL; + // if info already available + return TRUE; } - if (store_info->storeAdded && (store_info->store != NULL)) { - CFRelease(store_info->store); - store_info->store = NULL; - } + dispatch_sync(_storeInfo_queue(), ^{ + if (S_storeInfoActive && (S_storeInfo.dict != NULL)) { + // free any info + ReachabilityStoreInfo_free(store_info); - return; + // copy the shared/available info + ReachabilityStoreInfo_copy(&S_storeInfo, store_info); + } + + if (store_info->store == NULL) { + store_info->store = (storeP != NULL) ? *storeP : NULL; + if (store_info->store != NULL) { + // keep a reference to the passed in SCDynamicStore + CFRetain(store_info->store); + } else { + store_info->store = SCDynamicStoreCreate(NULL, CFSTR("SCNetworkReachability"), NULL, NULL); + if (store_info->store == NULL) { + SCLog(TRUE, LOG_ERR, CFSTR("ReachabilityStoreInfo_update SCDynamicStoreCreate() failed")); + return; + } + + if (storeP != NULL) { + // and pass back a reference + *storeP = store_info->store; + CFRetain(*storeP); + } + } + } + + if (sa_family == AF_UNSPEC) { + // if the address family was not specified than + // all we wanted, for now, was to establish the + // SCDynamicStore session + return; + } + + if (store_info->dict != NULL) { + // or we have picked up the shared info + return; + } + + ok = ReachabilityStoreInfo_fill(store_info); + if (!ok) { + return; + } + + if (!_SC_CFEqual(store_info->dict, S_storeInfo.dict)) { + // free any old info + ReachabilityStoreInfo_free(&S_storeInfo); + + // save new info + if (S_storeInfoActive && + (store_info->dict != NULL)) { + ReachabilityStoreInfo_copy(store_info, &S_storeInfo); + } + } + }); + + return ok; } +#pragma mark - +#pragma mark PPP info + + static int updatePPPStatus(ReachabilityStoreInfoRef store_info, const struct sockaddr *sa, @@ -572,7 +726,7 @@ updatePPPStatus(ReachabilityStoreInfoRef store_info, CFStringRef ppp_if; int sc_status = kSCStatusNoKey; - if (!updateReachabilityStoreInfo(store_info, NULL, sa->sa_family)) { + if (!ReachabilityStoreInfo_update(store_info, NULL, sa->sa_family)) { return kSCStatusReachabilityUnknown; } @@ -727,7 +881,7 @@ updatePPPAvailable(ReachabilityStoreInfoRef store_info, CFIndex i; int sc_status = kSCStatusNoKey; - if (!updateReachabilityStoreInfo(store_info, + if (!ReachabilityStoreInfo_update(store_info, NULL, (sa != NULL) ? sa->sa_family : AF_INET)) { return kSCStatusReachabilityUnknown; @@ -830,6 +984,10 @@ updatePPPAvailable(ReachabilityStoreInfoRef store_info, } +#pragma mark - +#pragma mark VPN info + + #if !TARGET_IPHONE_SIMULATOR static int updateVPNStatus(ReachabilityStoreInfoRef store_info, @@ -843,7 +1001,7 @@ updateVPNStatus(ReachabilityStoreInfoRef store_info, CFStringRef vpn_if; int sc_status = kSCStatusNoKey; - if (!updateReachabilityStoreInfo(store_info, NULL, sa->sa_family)) { + if (!ReachabilityStoreInfo_update(store_info, NULL, sa->sa_family)) { return kSCStatusReachabilityUnknown; } @@ -971,7 +1129,7 @@ updateVPNAvailable(ReachabilityStoreInfoRef store_info, CFIndex i; int sc_status = kSCStatusNoKey; - if (!updateReachabilityStoreInfo(store_info, + if (!ReachabilityStoreInfo_update(store_info, NULL, (sa != NULL) ? sa->sa_family : AF_INET)) { return kSCStatusReachabilityUnknown; @@ -1061,6 +1219,10 @@ updateVPNAvailable(ReachabilityStoreInfoRef store_info, #endif // !TARGET_IPHONE_SIMULATOR +#pragma mark - +#pragma mark IPSec info + + static int updateIPSecStatus(ReachabilityStoreInfoRef store_info, const struct sockaddr *sa, @@ -1073,7 +1235,7 @@ updateIPSecStatus(ReachabilityStoreInfoRef store_info, CFStringRef ipsec_if; int sc_status = kSCStatusNoKey; - if (!updateReachabilityStoreInfo(store_info, NULL, sa->sa_family)) { + if (!ReachabilityStoreInfo_update(store_info, NULL, sa->sa_family)) { return kSCStatusReachabilityUnknown; } @@ -1192,6 +1354,10 @@ updateIPSecStatus(ReachabilityStoreInfoRef store_info, +#pragma mark - +#pragma mark Reachability engine + + #define ROUNDUP(a, size) \ (((a) & ((size)-1)) ? (1 + ((a) | ((size)-1))) : (a)) @@ -1219,7 +1385,10 @@ get_rtaddrs(int addrs, struct sockaddr *sa, struct sockaddr **rti_info) typedef struct { - char buf[BUFLEN]; + union { + char bytes[BUFLEN]; + struct rt_msghdr rtm; + } buf; int error; struct sockaddr *rti_info[RTAX_MAX]; struct rt_msghdr *rtm; @@ -1251,7 +1420,7 @@ route_get(const struct sockaddr *address, bzero(info, sizeof(*info)); - info->rtm = (struct rt_msghdr *)&info->buf; + info->rtm = &info->buf.rtm; info->rtm->rtm_msglen = sizeof(struct rt_msghdr); info->rtm->rtm_version = RTM_VERSION; #ifdef RTM_GET_SILENT @@ -1273,7 +1442,8 @@ route_get(const struct sockaddr *address, case AF_INET6: { struct sockaddr_in6 *sin6; - sin6 = (struct sockaddr_in6 *)address; + /* ALIGN: caller ensures that the address is aligned */ + sin6 = (struct sockaddr_in6 *)(void *)address; if ((IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) || IN6_IS_ADDR_MC_LINKLOCAL(&sin6->sin6_addr)) && (sin6->sin6_scope_id != 0)) { @@ -1352,7 +1522,7 @@ route_get(const struct sockaddr *address, while (TRUE) { int n; - n = read(rsock, (void *)&info->buf, sizeof(info->buf)); + n = read(rsock, &info->buf, sizeof(info->buf)); if (n == -1) { int error = errno; @@ -1411,7 +1581,8 @@ route_get(const struct sockaddr *address, return EINVAL; } - info->sdl = (struct sockaddr_dl *) info->rti_info[RTAX_IFP]; + /* ALIGN: accessors are retrieving byte values, cast ok. */ + info->sdl = (struct sockaddr_dl *)(void *) info->rti_info[RTAX_IFP]; if ((info->sdl->sdl_nlen == 0) || (info->sdl->sdl_nlen > IFNAMSIZ)) { /* no interface name */ return EHOSTUNREACH; @@ -1438,7 +1609,7 @@ checkAddress(ReachabilityStoreInfoRef store_info, char *statusMessage = NULL; struct sockaddr_in v4mapped; - *reach_info = NOT_REACHABLE; + _reach_set(reach_info, &NOT_REACHABLE, reach_info->cycle); if (address == NULL) { /* special case: check only for available paths off the system */ @@ -1479,7 +1650,8 @@ checkAddress(ReachabilityStoreInfoRef store_info, } if (address->sa_family == AF_INET6) { - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)address; + /* ALIGN: sin6_addr accessed aligned, cast ok. */ + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)(void *)address; if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { bzero(&v4mapped, sizeof(v4mapped)); @@ -1552,21 +1724,24 @@ checkAddress(ReachabilityStoreInfoRef store_info, switch (address->sa_family) { case AF_INET : - addr1 = &((struct sockaddr_in *)address)->sin_addr; - addr2 = &((struct sockaddr_in *)info.rti_info[RTAX_IFA])->sin_addr; + /* ALIGN: cast ok, because only bcmp is used. */ + addr1 = &((struct sockaddr_in *)(void *)address)->sin_addr; + addr2 = &((struct sockaddr_in *)(void *)info.rti_info[RTAX_IFA])->sin_addr; len = sizeof(struct in_addr); /* * check if 0.0.0.0 */ - if (((struct sockaddr_in *)address)->sin_addr.s_addr == 0) { + /* ALIGN: sin_addr should be aligned, cast ok. */ + if (((struct sockaddr_in *)(void *)address)->sin_addr.s_addr == 0) { statusMessage = "isReachable (this host)"; reach_info->flags |= kSCNetworkReachabilityFlagsIsLocalAddress; } break; case AF_INET6 : - addr1 = &((struct sockaddr_in6 *)address)->sin6_addr; - addr2 = &((struct sockaddr_in6 *)info.rti_info[RTAX_IFA])->sin6_addr; + /* ALIGN: cast ok, because only bcmp is used. */ + addr1 = &((struct sockaddr_in6 *)(void *)address)->sin6_addr; + addr2 = &((struct sockaddr_in6 *)(void *)info.rti_info[RTAX_IFA])->sin6_addr; len = sizeof(struct in6_addr); break; default : @@ -1591,6 +1766,7 @@ checkAddress(ReachabilityStoreInfoRef store_info, if_name, (info.sdl->sdl_nlen <= IFNAMSIZ) ? info.sdl->sdl_nlen : IFNAMSIZ); + strlcpy(reach_info->if_name, if_name, sizeof(reach_info->if_name)); reach_info->if_index = info.sdl->sdl_index; if (_sc_debug) { @@ -1671,15 +1847,21 @@ checkAddress(ReachabilityStoreInfoRef store_info, #pragma mark SCNetworkReachability APIs -static CFStringRef -__SCNetworkReachabilityCopyDescription(CFTypeRef cf) +static __inline__ CFTypeRef +isA_SCNetworkReachability(CFTypeRef obj) { - CFAllocatorRef allocator = CFGetAllocator(cf); - CFMutableStringRef result; - SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)cf; + return (isA_CFType(obj, SCNetworkReachabilityGetTypeID())); +} - result = CFStringCreateMutable(allocator, 0); - CFStringAppendFormat(result, NULL, CFSTR(" {"), cf, allocator); + +CFStringRef +_SCNetworkReachabilityCopyTargetDescription(SCNetworkReachabilityRef target) +{ + CFAllocatorRef allocator = CFGetAllocator(target); + CFMutableStringRef str; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + str = CFStringCreateMutable(allocator, 0); switch (targetPrivate->type) { case reachabilityTypeAddress : case reachabilityTypeAddressPair : { @@ -1687,13 +1869,13 @@ __SCNetworkReachabilityCopyDescription(CFTypeRef cf) if (targetPrivate->localAddress != NULL) { _SC_sockaddr_to_string(targetPrivate->localAddress, buf, sizeof(buf)); - CFStringAppendFormat(result, NULL, CFSTR("local address = %s"), + CFStringAppendFormat(str, NULL, CFSTR("local address = %s"), buf); } if (targetPrivate->remoteAddress != NULL) { _SC_sockaddr_to_string(targetPrivate->remoteAddress, buf, sizeof(buf)); - CFStringAppendFormat(result, NULL, CFSTR("%s%saddress = %s"), + CFStringAppendFormat(str, NULL, CFSTR("%s%saddress = %s"), targetPrivate->localAddress ? ", " : "", (targetPrivate->type == reachabilityTypeAddressPair) ? "remote " : "", buf); @@ -1702,53 +1884,107 @@ __SCNetworkReachabilityCopyDescription(CFTypeRef cf) } case reachabilityTypeName : { if ((targetPrivate->name != NULL)) { - CFStringAppendFormat(result, NULL, CFSTR("name = %s"), targetPrivate->name); + CFStringAppendFormat(str, NULL, CFSTR("name = %s"), targetPrivate->name); } if ((targetPrivate->serv != NULL)) { - CFStringAppendFormat(result, NULL, CFSTR("%sserv = %s"), + CFStringAppendFormat(str, NULL, CFSTR("%sserv = %s"), targetPrivate->name != NULL ? ", " : "", targetPrivate->serv); } - if ((targetPrivate->resolvedAddress != NULL) || (targetPrivate->resolvedAddressError != NETDB_SUCCESS)) { - if (targetPrivate->resolvedAddress != NULL) { - if (isA_CFArray(targetPrivate->resolvedAddress)) { - CFIndex i; - CFIndex n = CFArrayGetCount(targetPrivate->resolvedAddress); - - CFStringAppendFormat(result, NULL, CFSTR(" (")); - for (i = 0; i < n; i++) { - CFDataRef address; - char buf[64]; - struct sockaddr *sa; - - address = CFArrayGetValueAtIndex(targetPrivate->resolvedAddress, i); - sa = (struct sockaddr *)CFDataGetBytePtr(address); - _SC_sockaddr_to_string(sa, buf, sizeof(buf)); - CFStringAppendFormat(result, NULL, CFSTR("%s%s"), - i > 0 ? ", " : "", - buf); - } - CFStringAppendFormat(result, NULL, CFSTR(")")); - } else { - CFStringAppendFormat(result, NULL, CFSTR(" (no addresses)")); + break; + } + } + + return str; +} + + +CFStringRef +_SCNetworkReachabilityCopyTargetFlags(SCNetworkReachabilityRef target) +{ + CFAllocatorRef allocator = CFGetAllocator(target); + CFStringRef str; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + str = CFStringCreateWithFormat(allocator, + NULL, + CFSTR("flags = 0x%08x, if_index = %hu%s"), + targetPrivate->info.flags, + targetPrivate->info.if_index, + targetPrivate->info.sleeping ? ", z" : ""); + return str; +} + + +static CFStringRef +__SCNetworkReachabilityCopyDescription(CFTypeRef cf) +{ + CFAllocatorRef allocator = CFGetAllocator(cf); + CFMutableStringRef result; + CFStringRef str; + SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)cf; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + result = CFStringCreateMutable(allocator, 0); + CFStringAppendFormat(result, NULL, CFSTR(" {"), cf, allocator); + + // add target description + str = _SCNetworkReachabilityCopyTargetDescription(target); + CFStringAppend(result, str); + CFRelease(str); + + // add additional "name" info + if (targetPrivate->type == reachabilityTypeName) { + if (targetPrivate->dnsMP != MACH_PORT_NULL) { + CFStringAppendFormat(result, NULL, CFSTR(" (DNS query active)")); + } else if (targetPrivate->dnsRetry != NULL) { + CFStringAppendFormat(result, NULL, CFSTR(" (DNS retry queued)")); + } else if ((targetPrivate->resolvedAddress != NULL) || (targetPrivate->resolvedAddressError != NETDB_SUCCESS)) { + if (targetPrivate->resolvedAddress != NULL) { + if (isA_CFArray(targetPrivate->resolvedAddress)) { + CFIndex i; + CFIndex n = CFArrayGetCount(targetPrivate->resolvedAddress); + + CFStringAppendFormat(result, NULL, CFSTR(" (")); + for (i = 0; i < n; i++) { + CFDataRef address; + char buf[64]; + struct sockaddr *sa; + + address = CFArrayGetValueAtIndex(targetPrivate->resolvedAddress, i); + sa = (struct sockaddr *)CFDataGetBytePtr(address); + _SC_sockaddr_to_string(sa, buf, sizeof(buf)); + CFStringAppendFormat(result, NULL, CFSTR("%s%s"), + i > 0 ? ", " : "", + buf); } - } else { - CFStringAppendFormat(result, NULL, CFSTR(" (%s)"), + } else if (CFEqual(targetPrivate->resolvedAddress, kCFNull)) { + CFStringAppendFormat(result, NULL, CFSTR(" (%s"), gai_strerror(targetPrivate->resolvedAddressError)); + } else { + CFStringAppendFormat(result, NULL, CFSTR(" (no addresses")); } - } else if (targetPrivate->dnsPort != NULL) { - CFStringAppendFormat(result, NULL, CFSTR(" (DNS query active)")); + } else { + CFStringAppendFormat(result, NULL, CFSTR(" (%s"), + gai_strerror(targetPrivate->resolvedAddressError)); } - break; + if (targetPrivate->llqActive) { + CFStringAppendFormat(result, NULL, CFSTR("), DNS llq active")); + } else { + CFStringAppendFormat(result, NULL, CFSTR(")")); + } + } else if (targetPrivate->llqActive) { + CFStringAppendFormat(result, NULL, CFSTR(" (DNS llq active)")); } } + + // add flags if (targetPrivate->scheduled) { - CFStringAppendFormat(result, - NULL, - CFSTR(", flags = 0x%08x, if_index = %hu"), - targetPrivate->info.flags, - targetPrivate->info.if_index); + str = _SCNetworkReachabilityCopyTargetFlags(target); + CFStringAppendFormat(result, NULL, CFSTR(", %@"), str); + CFRelease(str); } + CFStringAppendFormat(result, NULL, CFSTR("}")); return result; @@ -1758,11 +1994,20 @@ __SCNetworkReachabilityCopyDescription(CFTypeRef cf) static void __SCNetworkReachabilityDeallocate(CFTypeRef cf) { - SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)cf; + SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)cf; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%srelease"), targetPrivate->log_prefix); +#ifdef HAVE_REACHABILITY_SERVER + /* disconnect from the reachability server */ + + if (targetPrivate->serverActive) { + __SCNetworkReachabilityServer_targetRemove(target); + } +#endif // HAVE_REACHABILITY_SERVER + /* release resources */ pthread_mutex_destroy(&targetPrivate->lock); @@ -1802,6 +2047,24 @@ __SCNetworkReachabilityDeallocate(CFTypeRef cf) CFRelease(targetPrivate->onDemandServiceID); } +#ifdef HAVE_REACHABILITY_SERVER + if (targetPrivate->serverDigest != NULL) { + CFRelease(targetPrivate->serverDigest); + } + + if (targetPrivate->serverGroup != NULL) { + dispatch_release(targetPrivate->serverGroup); + } + + if (targetPrivate->serverQueue != NULL) { + dispatch_release(targetPrivate->serverQueue); + } + + if (targetPrivate->serverWatchers != NULL) { + CFRelease(targetPrivate->serverWatchers); + } +#endif // HAVE_REACHABILITY_SERVER + return; } @@ -1817,24 +2080,57 @@ __SCNetworkReachabilityInitialize(void) _sc_debug = TRUE; } + // set per-process "bypass" of the SCNetworkReachability server + if (getenv("LONG_LIVED_QUERY_BYPASS") != NULL) { + D_llqBypass = TRUE; + } + +#ifdef HAVE_REACHABILITY_SERVER + // set per-process "bypass" of the SCNetworkReachability server + if (getenv("REACH_SERVER_BYPASS") != NULL) { + D_serverBypass = TRUE; + } +#endif // HAVE_REACHABILITY_SERVER + + pthread_mutexattr_init(&lock_attr); + pthread_mutexattr_settype(&lock_attr, PTHREAD_MUTEX_ERRORCHECK); + return; } +__private_extern__ +dispatch_queue_t +__SCNetworkReachability_concurrent_queue() +{ + static dispatch_once_t once; + static dispatch_queue_t q; + + dispatch_once(&once, ^{ + q = dispatch_queue_create("SCNetworkReachabilty.concurrent", + DISPATCH_QUEUE_CONCURRENT); + dispatch_queue_set_width(q, 32); + }); + + return q; +} + + /* - * __SCNetworkReachabilityPerformInline + * __SCNetworkReachabilityPerformInlineNoLock * - * Calls rlsPerform() + * Calls reachPerform() * - caller must be holding a reference to the target * - caller must *not* be holding the target lock + * - caller must be running on the __SCNetworkReachability_concurrent_queue() */ static __inline__ void -__SCNetworkReachabilityPerformInline(SCNetworkReachabilityRef target, Boolean needResolve) +__SCNetworkReachabilityPerformInlineNoLock(SCNetworkReachabilityRef target, Boolean needResolve) { dispatch_queue_t queue; SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; - pthread_mutex_lock(&targetPrivate->lock); + MUTEX_LOCK(&targetPrivate->lock); if (needResolve) { // allow the DNS query to be [re-]started @@ -1843,12 +2139,18 @@ __SCNetworkReachabilityPerformInline(SCNetworkReachabilityRef target, Boolean ne queue = targetPrivate->dispatchQueue; if (queue != NULL) { + dispatch_group_t group; + dispatch_retain(queue); - pthread_mutex_unlock(&targetPrivate->lock); + group = targetPrivate->dispatchGroup; + dispatch_group_enter(group); + + MUTEX_UNLOCK(&targetPrivate->lock); dispatch_sync(queue, ^{ - rlsPerform((void *)target); + reachPerform((void *)target); + dispatch_group_leave(group); dispatch_release(queue); }); } else { @@ -1857,25 +2159,97 @@ __SCNetworkReachabilityPerformInline(SCNetworkReachabilityRef target, Boolean ne _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList); } - pthread_mutex_unlock(&targetPrivate->lock); + MUTEX_UNLOCK(&targetPrivate->lock); + } + + return; +} + + +#ifdef HAVE_REACHABILITY_SERVER +/* + * __SCNetworkReachabilityPerformNoLock + * + * Calls reachPerform() + * - caller must *not* be holding the target lock + * - caller must *not* running on the __SCNetworkReachability_concurrent_queue() + */ +__private_extern__ +void +__SCNetworkReachabilityPerformNoLock(SCNetworkReachabilityRef target) +{ + CFRetain(target); + dispatch_async(__SCNetworkReachability_concurrent_queue(), ^{ + __SCNetworkReachabilityPerformInlineNoLock(target, FALSE); + CFRelease(target); + }); + + return; +} +#endif // HAVE_REACHABILITY_SERVER + + +/* + * __SCNetworkReachabilityPerformConcurrent + * + * Calls reachPerform() + * - caller must be holding the target lock + * - caller running on the __SCNetworkReachability_concurrent_queue() + */ +static __inline__ void +__SCNetworkReachabilityPerformConcurrent(SCNetworkReachabilityRef target) +{ + dispatch_queue_t queue; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + MUTEX_ASSERT_HELD(&targetPrivate->lock); + + queue = targetPrivate->dispatchQueue; + if (queue != NULL) { + dispatch_retain(queue); + CFRetain(target); + dispatch_group_async(targetPrivate->dispatchGroup, queue, ^{ + reachPerform((void *)target); + CFRelease(target); + dispatch_release(queue); + }); + } else { + if (targetPrivate->rls != NULL) { + CFRunLoopSourceSignal(targetPrivate->rls); + _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList); + } } return; } +/* + * __SCNetworkReachabilityPerform + * + * Calls reachPerform() + * - caller must be holding the target lock + * - caller not running on the __SCNetworkReachability_concurrent_queue() + */ static void __SCNetworkReachabilityPerform(SCNetworkReachabilityRef target) { + dispatch_queue_t queue; SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; - if (targetPrivate->dispatchQueue != NULL) { + MUTEX_ASSERT_HELD(&targetPrivate->lock); + + queue = targetPrivate->dispatchQueue; + if (queue != NULL) { + dispatch_retain(queue); CFRetain(target); - dispatch_async(targetPrivate->dispatchQueue, - ^{ - rlsPerform((void *)target); - CFRelease(target); - }); + dispatch_group_async(targetPrivate->dispatchGroup, __SCNetworkReachability_concurrent_queue(), ^{ + dispatch_sync(queue, ^{ + reachPerform((void *)target); + CFRelease(target); + dispatch_release(queue); + }); + }); } else if (targetPrivate->rls != NULL) { CFRunLoopSourceSignal(targetPrivate->rls); _SC_signalRunLoop(target, targetPrivate->rls, targetPrivate->rlList); @@ -1884,6 +2258,7 @@ __SCNetworkReachabilityPerform(SCNetworkReachabilityRef target) return; } + static SCNetworkReachabilityPrivateRef __SCNetworkReachabilityCreatePrivate(CFAllocatorRef allocator) { @@ -1903,16 +2278,11 @@ __SCNetworkReachabilityCreatePrivate(CFAllocatorRef allocator) return NULL; } - pthread_mutex_init(&targetPrivate->lock, NULL); + MUTEX_INIT(&targetPrivate->lock); targetPrivate->name = NULL; targetPrivate->serv = NULL; - bzero(&targetPrivate->hints, sizeof(targetPrivate->hints)); - targetPrivate->hints.ai_flags = AI_ADDRCONFIG; -#ifdef AI_PARALLEL - targetPrivate->hints.ai_flags |= AI_PARALLEL; -#endif /* AI_PARALLEL */ - + targetPrivate->hints = HINTS_DEFAULT; targetPrivate->needResolve = FALSE; targetPrivate->resolvedAddress = NULL; targetPrivate->resolvedAddressError = NETDB_SUCCESS; @@ -1922,6 +2292,7 @@ __SCNetworkReachabilityCreatePrivate(CFAllocatorRef allocator) targetPrivate->localAddress = NULL; targetPrivate->remoteAddress = NULL; + targetPrivate->cycle = 1; targetPrivate->info = NOT_REACHABLE; targetPrivate->last_notify = NOT_REPORTED; @@ -1938,12 +2309,18 @@ __SCNetworkReachabilityCreatePrivate(CFAllocatorRef allocator) targetPrivate->dnsMP = MACH_PORT_NULL; targetPrivate->dnsPort = NULL; targetPrivate->dnsRLS = NULL; + targetPrivate->dnsSource = NULL; targetPrivate->dnsQueryStart = TIME_ZERO; targetPrivate->dnsQueryEnd = TIME_ZERO; targetPrivate->dnsRetry = NULL; targetPrivate->dnsRetryCount = 0; targetPrivate->last_dns = TIME_ZERO; + targetPrivate->last_network = TIME_ZERO; +#if !TARGET_OS_IPHONE + targetPrivate->last_power = TIME_ZERO; +#endif // !TARGET_OS_IPHONE + targetPrivate->last_push = TIME_ZERO; targetPrivate->onDemandBypass = FALSE; targetPrivate->onDemandName = NULL; @@ -1952,6 +2329,26 @@ __SCNetworkReachabilityCreatePrivate(CFAllocatorRef allocator) targetPrivate->onDemandServiceID = NULL; + targetPrivate->llqActive = FALSE; + targetPrivate->llqBypass = D_llqBypass; + targetPrivate->llqTarget = NULL; + targetPrivate->llqTimer = NULL; + +#ifdef HAVE_REACHABILITY_SERVER + targetPrivate->serverActive = FALSE; + targetPrivate->serverBypass = D_serverBypass; + targetPrivate->serverScheduled = FALSE; + targetPrivate->serverInfo = NOT_REACHABLE; + + targetPrivate->serverDigest = NULL; + targetPrivate->serverGroup = NULL; + targetPrivate->serverInfoValid = FALSE; + targetPrivate->serverQueryActive = 0; + targetPrivate->serverQueue = NULL; + targetPrivate->serverReferences = 0; + targetPrivate->serverWatchers = NULL; +#endif // HAVE_REACHABILITY_SERVER + targetPrivate->log_prefix[0] = '\0'; if (_sc_log > 0) { snprintf(targetPrivate->log_prefix, @@ -2034,8 +2431,9 @@ SCNetworkReachabilityCreateWithAddress(CFAllocatorRef allocator, targetPrivate->remoteAddress = CFAllocatorAllocate(NULL, address->sa_len, 0); bcopy(address, targetPrivate->remoteAddress, address->sa_len); - SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%screate w/address %@"), + SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%s%s %@"), targetPrivate->log_prefix, + DEBUG_REACHABILITY_TYPE_ADDRESS, targetPrivate); return (SCNetworkReachabilityRef)targetPrivate; @@ -2087,8 +2485,9 @@ SCNetworkReachabilityCreateWithAddressPair(CFAllocatorRef allocator, bcopy(remoteAddress, targetPrivate->remoteAddress, remoteAddress->sa_len); } - SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%screate w/address pair %@"), + SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%s%s %@"), targetPrivate->log_prefix, + DEBUG_REACHABILITY_TYPE_ADDRESSPAIR, targetPrivate); return (SCNetworkReachabilityRef)targetPrivate; @@ -2099,9 +2498,12 @@ SCNetworkReachabilityRef SCNetworkReachabilityCreateWithName(CFAllocatorRef allocator, const char *nodename) { + union { + struct sockaddr sa; + struct sockaddr_in sin; + struct sockaddr_in6 sin6; + } addr; int nodenameLen; - struct sockaddr_in sin; - struct sockaddr_in6 sin6; SCNetworkReachabilityPrivateRef targetPrivate; if (nodename == NULL) { @@ -2115,29 +2517,9 @@ SCNetworkReachabilityCreateWithName(CFAllocatorRef allocator, return NULL; } - /* check if this "nodename" is really an IP[v6] address in disguise */ - - bzero(&sin, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - if (inet_aton(nodename, &sin.sin_addr) == 1) { - /* if IPv4 address */ - return SCNetworkReachabilityCreateWithAddress(allocator, (struct sockaddr *)&sin); - } - - bzero(&sin6, sizeof(sin6)); - sin6.sin6_len = sizeof(sin6); - sin6.sin6_family = AF_INET6; - if (inet_pton(AF_INET6, nodename, &sin6.sin6_addr) == 1) { - /* if IPv6 address */ - char *p; - - p = strchr(nodename, '%'); - if (p != NULL) { - sin6.sin6_scope_id = if_nametoindex(p + 1); - } - - return SCNetworkReachabilityCreateWithAddress(allocator, (struct sockaddr *)&sin6); + if (_SC_string_to_sockaddr(nodename, AF_UNSPEC, (void *)&addr, sizeof(addr)) != NULL) { + /* if this "nodename" is really an IP[v6] address in disguise */ + return SCNetworkReachabilityCreateWithAddress(allocator, &addr.sa); } targetPrivate = __SCNetworkReachabilityCreatePrivate(allocator); @@ -2152,9 +2534,13 @@ SCNetworkReachabilityCreateWithName(CFAllocatorRef allocator, targetPrivate->needResolve = TRUE; targetPrivate->info.flags |= kSCNetworkReachabilityFlagsFirstResolvePending; +#ifdef HAVE_REACHABILITY_SERVER + targetPrivate->serverInfo.flags |= kSCNetworkReachabilityFlagsFirstResolvePending; +#endif // HAVE_REACHABILITY_SERVER - SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%screate w/name %@"), + SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%s%s %@"), targetPrivate->log_prefix, + DEBUG_REACHABILITY_TYPE_NAME, targetPrivate); return (SCNetworkReachabilityRef)targetPrivate; @@ -2169,11 +2555,16 @@ SCNetworkReachabilityCreateWithOptions(CFAllocatorRef allocator, { const struct sockaddr *addr_l = NULL; const struct sockaddr *addr_r = NULL; - CFBooleanRef bypass; CFDataRef data; struct addrinfo *hints = NULL; CFStringRef interface = NULL; + CFBooleanRef llqBypass; CFStringRef nodename; + CFBooleanRef onDemandBypass; + CFBooleanRef resolverBypass; +#ifdef HAVE_REACHABILITY_SERVER + CFBooleanRef serverBypass; +#endif // HAVE_REACHABILITY_SERVER CFStringRef servname; SCNetworkReachabilityRef target; SCNetworkReachabilityPrivateRef targetPrivate; @@ -2218,7 +2609,8 @@ SCNetworkReachabilityCreateWithOptions(CFAllocatorRef allocator, return NULL; } - hints = (struct addrinfo *)CFDataGetBytePtr(data); + /* ALIGN: CF aligns to >8 byte boundries */ + hints = (struct addrinfo *)(void *)CFDataGetBytePtr(data); if ((hints->ai_addrlen != 0) || (hints->ai_addr != NULL) || (hints->ai_canonname != NULL) || @@ -2233,13 +2625,32 @@ SCNetworkReachabilityCreateWithOptions(CFAllocatorRef allocator, _SCErrorSet(kSCStatusInvalidArgument); return NULL; } - bypass = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionConnectionOnDemandByPass); - if ((bypass != NULL) && !isA_CFBoolean(bypass)) { + onDemandBypass = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionConnectionOnDemandBypass); + if ((onDemandBypass != NULL) && !isA_CFBoolean(onDemandBypass)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + resolverBypass = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionResolverBypass); + if ((resolverBypass != NULL) && !isA_CFBoolean(resolverBypass)) { _SCErrorSet(kSCStatusInvalidArgument); return NULL; } + llqBypass = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionLongLivedQueryBypass); + if ((llqBypass != NULL) && !isA_CFBoolean(llqBypass)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + +#ifdef HAVE_REACHABILITY_SERVER + serverBypass = CFDictionaryGetValue(options, kSCNetworkReachabilityOptionServerBypass); + if ((serverBypass != NULL) && !isA_CFBoolean(serverBypass)) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } +#endif // HAVE_REACHABILITY_SERVER + if ((nodename != NULL) || (servname != NULL)) { const char *name; @@ -2291,13 +2702,47 @@ SCNetworkReachabilityCreateWithOptions(CFAllocatorRef allocator, } - if (bypass != NULL) { - targetPrivate->onDemandBypass = CFBooleanGetValue(bypass); + if (llqBypass != NULL) { + targetPrivate->llqBypass = CFBooleanGetValue(llqBypass); } - SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%s + options %@"), - targetPrivate->log_prefix, - targetPrivate); + if (onDemandBypass != NULL) { + targetPrivate->onDemandBypass = CFBooleanGetValue(onDemandBypass); + } + + if (resolverBypass != NULL) { + targetPrivate->resolverBypass = CFBooleanGetValue(resolverBypass); + } + +#ifdef HAVE_REACHABILITY_SERVER + if (serverBypass != NULL) { + targetPrivate->serverBypass = CFBooleanGetValue(serverBypass); + } +#endif // HAVE_REACHABILITY_SERVER + + if (_sc_debug && (_sc_log > 0)) { + const char *opt; + + switch (targetPrivate->type) { + case reachabilityTypeName : + opt = DEBUG_REACHABILITY_TYPE_NAME_OPTIONS; + break; + case reachabilityTypeAddress : + opt = DEBUG_REACHABILITY_TYPE_ADDRESS_OPTIONS; + break; + case reachabilityTypeAddressPair : + opt = DEBUG_REACHABILITY_TYPE_ADDRESSPAIR_OPTIONS; + break; + default : + opt = "???"; + break; + } + + SCLog(TRUE, LOG_INFO, CFSTR("%s%s %@"), + targetPrivate->log_prefix, + opt, + targetPrivate); + } return (SCNetworkReachabilityRef)targetPrivate; } @@ -2354,6 +2799,8 @@ __SCNetworkReachabilitySetResolvedAddress(int32_t status, struct addrinfo *resP; SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + MUTEX_ASSERT_HELD(&targetPrivate->lock); + if (targetPrivate->resolvedAddress != NULL) { CFRelease(targetPrivate->resolvedAddress); targetPrivate->resolvedAddress = NULL; @@ -2409,7 +2856,7 @@ __SCNetworkReachabilityCallbackSetResolvedAddress(int32_t status, struct addrinf __dns_query_end(target, ((status == 0) && (res != NULL)), // if successful query - TRUE, // async + dns_query_async, // async &targetPrivate->dnsQueryStart, // start time &targetPrivate->dnsQueryEnd); // end time @@ -2458,132 +2905,219 @@ replyMPCopyDescription(const void *info) static void -processAsyncDNSReply(mach_port_t mp, void *msg, SCNetworkReachabilityRef target); +getaddrinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info); -static void -getaddrinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info) +static Boolean +enqueueAsyncDNSQuery_dispatch(SCNetworkReachabilityRef target) { - mach_port_t mp = CFMachPortGetPort(port); - SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)info; + mach_port_t mp; + dispatch_source_t source; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; - processAsyncDNSReply(mp, msg, target); - return; -} + MUTEX_ASSERT_HELD(&targetPrivate->lock); + mp = targetPrivate->dnsMP; -static boolean_t -SCNetworkReachabilityNotifyMIGCallback(mach_msg_header_t *message, mach_msg_header_t *reply) -{ - mach_port_t mp = message->msgh_local_port; - SCNetworkReachabilityRef target = dispatch_get_context(dispatch_get_current_queue()); + // mach_port context <-- NULL (no msg received) + mach_port_set_context(mach_task_self(), mp, (mach_vm_address_t)(uintptr_t)NULL); - processAsyncDNSReply(mp, message, target); - reply->msgh_remote_port = MACH_PORT_NULL; - return false; + // create dispatch source to handle DNS reply + source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, + mp, + 0, + __SCNetworkReachability_concurrent_queue()); + if (source == NULL) { + SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability dispatch_source_create() failed")); + return FALSE; + } + + // + // We created the dispatch_source to listen for (and process) the mach IPC + // reply to our async DNS query. Because the source handler runs asychronously + // we need to ensure that we're holding a reference to the target. Here, we take + // a reference and setup the dispatch_source finalizer to drop it. + // + CFRetain(target); + dispatch_set_context(source, (void *)target); + dispatch_set_finalizer_f(source, (dispatch_function_t)CFRelease); + + dispatch_source_set_event_handler(source, ^{ + mach_msg_size_t msg_size = 8192; + const mach_msg_options_t options = MACH_RCV_MSG + | MACH_RCV_LARGE + | MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_CTX) + | MACH_RCV_TRAILER_TYPE(MACH_MSG_TRAILER_FORMAT_0); + + while (TRUE) { + kern_return_t kr; + mach_msg_header_t *msg = (mach_msg_header_t *)malloc(msg_size); + + kr = mach_msg(msg, /* msg */ + options, /* options */ + 0, /* send_size */ + msg_size, /* rcv_size */ + mp, /* rcv_name */ + MACH_MSG_TIMEOUT_NONE, /* timeout */ + MACH_PORT_NULL); /* notify */ + if (kr == KERN_SUCCESS) { + // mach_port context <-- msg + mach_port_set_context(mach_task_self(), + mp, + (mach_vm_address_t)(uintptr_t)msg); + } else if (kr == MACH_RCV_TOO_LARGE) { + msg_size *= 2; + free(msg); + continue; + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("SCNetworkReachability async DNS handler, kr=0x%x"), + kr); + free(msg); + } + break; + } + + dispatch_source_cancel(source); + }); + + dispatch_source_set_cancel_handler(source, ^{ +#if !TARGET_OS_EMBEDDED + mach_vm_address_t context; +#else // !TARGET_OS_EMBEDDED + mach_port_context_t context; +#endif // !TARGET_OS_EMBEDDED + kern_return_t kr; + mach_port_t mp; + + // get the [async DNS query] mach port + mp = (mach_port_t)dispatch_source_get_handle(source); + + // check if we have a received message + kr = mach_port_get_context(mach_task_self(), mp, &context); + if (kr == KERN_SUCCESS) { + void *msg; + + msg = (void *)(uintptr_t)context; + if (msg != NULL) { + MUTEX_LOCK(&targetPrivate->lock); + getaddrinfo_async_handle_reply(msg); + targetPrivate->dnsSource = NULL; + targetPrivate->dnsMP = MACH_PORT_NULL; + MUTEX_UNLOCK(&targetPrivate->lock); + free(msg); + } else { + getaddrinfo_async_cancel(mp); + } + } + + dispatch_release(source); + }); + + targetPrivate->dnsSource = source; + dispatch_resume(source); + + return TRUE; } static Boolean -enqueueAsyncDNSQuery(SCNetworkReachabilityRef target, mach_port_t mp) +enqueueAsyncDNSQuery_CF(SCNetworkReachabilityRef target) { - CFMachPortContext context = { 0 - , (void *)target - , CFRetain - , CFRelease - , replyMPCopyDescription - }; + CFMachPortContext context = { 0 + , (void *)target + , CFRetain + , CFRelease + , replyMPCopyDescription + }; + CFIndex i; + mach_port_t mp; + CFIndex n; SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; - targetPrivate->dnsMP = mp; + MUTEX_ASSERT_HELD(&targetPrivate->lock); + + mp = targetPrivate->dnsMP; + targetPrivate->dnsPort = _SC_CFMachPortCreateWithPort("SCNetworkReachability", mp, getaddrinfo_async_handleCFReply, &context); - if (targetPrivate->dispatchQueue != NULL) { - targetPrivate->asyncDNSQueue = dispatch_queue_create("com.apple.SCNetworkReachabilty.async_DNS_query", NULL); - if (targetPrivate->asyncDNSQueue == NULL) { - SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability dispatch_queue_create() failed")); - goto fail; - } - CFRetain(target); // Note: will be released when the dispatch queue is released - dispatch_set_context(targetPrivate->asyncDNSQueue, (void *)target); - dispatch_set_finalizer_f(targetPrivate->asyncDNSQueue, (dispatch_function_t)CFRelease); - - targetPrivate->asyncDNSSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, - mp, - 0, - targetPrivate->asyncDNSQueue); - if (targetPrivate->asyncDNSSource == NULL) { - SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability dispatch_source_create() failed")); - goto fail; - } - dispatch_source_set_event_handler(targetPrivate->asyncDNSSource, ^{ - dispatch_mig_server(targetPrivate->asyncDNSSource, - sizeof(mach_msg_header_t), - SCNetworkReachabilityNotifyMIGCallback); - }); - dispatch_resume(targetPrivate->asyncDNSSource); - } else if (targetPrivate->rls != NULL) { - CFIndex i; - CFIndex n; + if (targetPrivate->dnsPort == NULL) { + SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability CFMachPortCreateWithPort() failed")); + goto fail; + } - targetPrivate->dnsRLS = CFMachPortCreateRunLoopSource(NULL, targetPrivate->dnsPort, 0); + targetPrivate->dnsRLS = CFMachPortCreateRunLoopSource(NULL, targetPrivate->dnsPort, 0); + if (targetPrivate->dnsRLS == NULL) { + SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability CFMachPortCreateRunLoopSource() failed")); + goto fail; + } - n = CFArrayGetCount(targetPrivate->rlList); - for (i = 0; i < n; i += 3) { - CFRunLoopRef rl = (CFRunLoopRef)CFArrayGetValueAtIndex(targetPrivate->rlList, i+1); - CFStringRef rlMode = (CFStringRef) CFArrayGetValueAtIndex(targetPrivate->rlList, i+2); + n = CFArrayGetCount(targetPrivate->rlList); + for (i = 0; i < n; i += 3) { + CFRunLoopRef rl = (CFRunLoopRef)CFArrayGetValueAtIndex(targetPrivate->rlList, i+1); + CFStringRef rlMode = (CFStringRef) CFArrayGetValueAtIndex(targetPrivate->rlList, i+2); - CFRunLoopAddSource(rl, targetPrivate->dnsRLS, rlMode); - } + CFRunLoopAddSource(rl, targetPrivate->dnsRLS, rlMode); } return TRUE; fail : - if (targetPrivate->asyncDNSSource != NULL) { - dispatch_source_cancel(targetPrivate->asyncDNSSource); - dispatch_release(targetPrivate->asyncDNSSource); - targetPrivate->asyncDNSSource = NULL; + if (targetPrivate->dnsRLS != NULL) { + CFRunLoopSourceInvalidate(targetPrivate->dnsRLS); + CFRelease(targetPrivate->dnsRLS); + targetPrivate->dnsRLS = NULL; } - if (targetPrivate->asyncDNSQueue != NULL) { - dispatch_release(targetPrivate->asyncDNSQueue); - targetPrivate->asyncDNSQueue = NULL; + if (targetPrivate->dnsPort != NULL) { + CFMachPortInvalidate(targetPrivate->dnsPort); + CFRelease(targetPrivate->dnsPort); + targetPrivate->dnsPort = NULL; } - CFMachPortInvalidate(targetPrivate->dnsPort); - CFRelease(targetPrivate->dnsPort); - targetPrivate->dnsPort = NULL; - targetPrivate->dnsMP = MACH_PORT_NULL; - - _SCErrorSet(kSCStatusFailed); return FALSE; } -static void -dequeueAsyncDNSQuery(SCNetworkReachabilityRef target) +static Boolean +enqueueAsyncDNSQuery(SCNetworkReachabilityRef target, mach_port_t mp) { + Boolean ok = FALSE; SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; - if (targetPrivate->asyncDNSSource != NULL) { - dispatch_source_cancel(targetPrivate->asyncDNSSource); - if (targetPrivate->asyncDNSQueue != dispatch_get_current_queue()) { - // ensure the cancellation has completed - pthread_mutex_unlock(&targetPrivate->lock); - dispatch_sync(targetPrivate->asyncDNSQueue, ^{}); - pthread_mutex_lock(&targetPrivate->lock); - } + MUTEX_ASSERT_HELD(&targetPrivate->lock); + + targetPrivate->dnsMP = mp; + + if (targetPrivate->dispatchQueue != NULL) { + ok = enqueueAsyncDNSQuery_dispatch(target); + } else if (targetPrivate->rls != NULL) { + ok = enqueueAsyncDNSQuery_CF(target); } - if (targetPrivate->asyncDNSSource != NULL) { - dispatch_release(targetPrivate->asyncDNSSource); - targetPrivate->asyncDNSSource = NULL; + + if (!ok) { + targetPrivate->dnsMP = MACH_PORT_NULL; + _SCErrorSet(kSCStatusFailed); + return FALSE; } - if (targetPrivate->asyncDNSQueue != NULL) { - dispatch_release(targetPrivate->asyncDNSQueue); - targetPrivate->asyncDNSQueue = NULL; + + return TRUE; +} + + +static void +dequeueAsyncDNSQuery(SCNetworkReachabilityRef target, Boolean cancel) +{ + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + MUTEX_ASSERT_HELD(&targetPrivate->lock); + + if (targetPrivate->dnsPort != NULL) { + CFMachPortInvalidate(targetPrivate->dnsPort); + CFRelease(targetPrivate->dnsPort); + targetPrivate->dnsPort = NULL; } if (targetPrivate->dnsRLS != NULL) { @@ -2591,10 +3125,16 @@ dequeueAsyncDNSQuery(SCNetworkReachabilityRef target) targetPrivate->dnsRLS = NULL; } - if (targetPrivate->dnsPort != NULL) { - CFMachPortInvalidate(targetPrivate->dnsPort); - CFRelease(targetPrivate->dnsPort); - targetPrivate->dnsPort = NULL; + if (targetPrivate->dnsSource != NULL) { + dispatch_source_cancel(targetPrivate->dnsSource); + targetPrivate->dnsSource = NULL; + cancel = FALSE; // the cancellation handler does the work + } + + if (targetPrivate->dnsMP != MACH_PORT_NULL) { + if (cancel) { + getaddrinfo_async_cancel(targetPrivate->dnsMP); + } targetPrivate->dnsMP = MACH_PORT_NULL; } @@ -2603,23 +3143,25 @@ dequeueAsyncDNSQuery(SCNetworkReachabilityRef target) static void -processAsyncDNSReply(mach_port_t mp, void *msg, SCNetworkReachabilityRef target) +getaddrinfo_async_handleCFReply(CFMachPortRef port, void *msg, CFIndex size, void *info) { + mach_port_t mp = CFMachPortGetPort(port); int32_t status; + SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)info; SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; - pthread_mutex_lock(&targetPrivate->lock); + MUTEX_LOCK(&targetPrivate->lock); if (mp != targetPrivate->dnsMP) { // we've received a callback on the async DNS port but since the // associated CFMachPort doesn't match than the request must have // already been cancelled. SCLog(TRUE, LOG_ERR, CFSTR("processAsyncDNSReply(): mp != targetPrivate->dnsMP")); - pthread_mutex_unlock(&targetPrivate->lock); + MUTEX_UNLOCK(&targetPrivate->lock); return; } - dequeueAsyncDNSQuery(target); + dequeueAsyncDNSQuery(target, FALSE); status = getaddrinfo_async_handle_reply(msg); if ((status == 0) && (targetPrivate->resolvedAddress == NULL) && (targetPrivate->resolvedAddressError == NETDB_SUCCESS)) { @@ -2632,7 +3174,7 @@ processAsyncDNSReply(mach_port_t mp, void *msg, SCNetworkReachabilityRef target) } } - pthread_mutex_unlock(&targetPrivate->lock); + MUTEX_UNLOCK(&targetPrivate->lock); return; } @@ -2643,43 +3185,50 @@ check_resolver_reachability(ReachabilityStoreInfoRef store_info, dns_resolver_t *resolver, SCNetworkReachabilityFlags *flags, Boolean *haveDNS, + uint32_t *resolver_if_index, const char *log_prefix) { - int i; Boolean ok = TRUE; - *flags = kSCNetworkReachabilityFlagsReachable; - *haveDNS = FALSE; + if (resolver_if_index) *resolver_if_index = 0; - for (i = 0; i < resolver->n_nameserver; i++) { - struct sockaddr *address = resolver->nameserver[i]; - ReachabilityInfo ns_info; + if (resolver->n_nameserver > 0) { +#if !TARGET_IPHONE_SIMULATOR + *flags = (SCNetworkReachabilityFlags)resolver->reach_flags; + if (resolver_if_index != NULL) { + *resolver_if_index = resolver->if_index; + } +#else // !TARGET_IPHONE_SIMULATOR + int i; - *haveDNS = TRUE; + *flags = kSCNetworkReachabilityFlagsReachable; - if (address->sa_family != AF_INET) { - /* - * we need to skip non-IPv4 DNS server - * addresses (at least until [3510431] has - * been resolved). - */ - continue; - } + for (i = 0; i < resolver->n_nameserver; i++) { + struct sockaddr *address = resolver->nameserver[i]; + ReachabilityInfo ns_info; - ok = checkAddress(store_info, address, resolver->if_index, &ns_info, log_prefix); - if (!ok) { - /* not today */ - goto done; - } + ok = checkAddress(store_info, address, resolver->if_index, &ns_info, log_prefix); + if (!ok) { + /* not today */ + break; + } - if (rankReachability(ns_info.flags) < rankReachability(*flags)) { - /* return the worst case result */ - *flags = ns_info.flags; + if ((i == 0) || + (rankReachability(ns_info.flags) < rankReachability(*flags))) { + /* return the worst case result */ + *flags = ns_info.flags; + if (resolver_if_index != NULL) { + *resolver_if_index = ns_info.if_index; + } + } } +#endif // !TARGET_IPHONE_SIMULATOR + *haveDNS = TRUE; + } else { + *flags = kSCNetworkReachabilityFlagsReachable; + *haveDNS = FALSE; } - done : - return ok; } @@ -2691,6 +3240,8 @@ check_matching_resolvers(ReachabilityStoreInfoRef store_info, unsigned int if_index, SCNetworkReachabilityFlags *flags, Boolean *haveDNS, + uint32_t *resolver_if_index, + int *dns_config_index, const char *log_prefix) { int i; @@ -2707,6 +3258,11 @@ check_matching_resolvers(ReachabilityStoreInfoRef store_info, resolvers = dns_config->scoped_resolver; } + /* In case we couldn't find a match, setting an index of -1 + and resolver_if_index 0 */ + if (dns_config_index != NULL) *dns_config_index = -1; + if (resolver_if_index != NULL) *resolver_if_index = 0; + while (!matched && (name != NULL)) { int len; @@ -2733,11 +3289,13 @@ check_matching_resolvers(ReachabilityStoreInfoRef store_info, * if name matches domain */ matched = TRUE; - ok = check_resolver_reachability(store_info, resolver, flags, haveDNS, log_prefix); + ok = check_resolver_reachability(store_info, resolver, flags, haveDNS, + resolver_if_index, log_prefix); if (!ok) { /* not today */ return FALSE; } + if (dns_config_index != NULL) *dns_config_index = i; } } } @@ -2931,7 +3489,10 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef store_info, const char *nodename, const char *servname, unsigned int if_index, - const char *log_prefix) + uint32_t *resolver_if_index, + int *dns_config_index, + const char *log_prefix + ) { dns_resolver_t *default_resolver; dns_configuration_t *dns; @@ -2944,6 +3505,9 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef store_info, Boolean ok = TRUE; Boolean useDefault = FALSE; + if (resolver_if_index) *resolver_if_index = 0; + if (dns_config_index) *dns_config_index = -1; + /* * We first assume that all of the configured DNS servers * are available. Since we don't know which name server will @@ -2977,8 +3541,6 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef store_info, goto done; } - *flags = kSCNetworkReachabilityFlagsReachable; - if (fqdn[len - 1] == '.') { isFQDN = TRUE; @@ -2996,7 +3558,9 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef store_info, /* * check if the provided name matches a supplemental domain */ - found = check_matching_resolvers(store_info, dns->config, fqdn, if_index, flags, haveDNS, log_prefix); + found = check_matching_resolvers(store_info, dns->config, fqdn, if_index, + flags, haveDNS, resolver_if_index, + dns_config_index, log_prefix); if (!found && !isFQDN) { /* @@ -3059,6 +3623,8 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef store_info, if_index, flags, haveDNS, + resolver_if_index, + dns_config_index, log_prefix); free(search_fqdn); } @@ -3101,6 +3667,8 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef store_info, if_index, flags, haveDNS, + resolver_if_index, + dns_config_index, log_prefix); free(search_fqdn); @@ -3114,7 +3682,9 @@ _SC_R_checkResolverReachability(ReachabilityStoreInfoRef store_info, /* * check the reachability of the default resolver */ - ok = check_resolver_reachability(store_info, default_resolver, flags, haveDNS, log_prefix); + ok = check_resolver_reachability(store_info, default_resolver, flags, haveDNS, + resolver_if_index, log_prefix); + if (ok && dns_config_index != NULL) *dns_config_index = 0; } if (fqdn != nodename) free(fqdn); @@ -3139,20 +3709,47 @@ _SC_checkResolverReachability(SCDynamicStoreRef *storeP, Boolean ok; ReachabilityStoreInfo store_info; - initReachabilityStoreInfo(&store_info); - ok = updateReachabilityStoreInfo(&store_info, storeP, AF_UNSPEC); + ReachabilityStoreInfo_init(&store_info); + ok = ReachabilityStoreInfo_update(&store_info, storeP, AF_UNSPEC); if (!ok) { goto done; } - ok = _SC_R_checkResolverReachability(&store_info, flags, haveDNS, nodename, servname, 0, ""); + ok = _SC_R_checkResolverReachability(&store_info, flags, haveDNS, nodename, + servname, 0, NULL, NULL, ""); done : - freeReachabilityStoreInfo(&store_info); + ReachabilityStoreInfo_free(&store_info); return ok; } +Boolean +__SC_checkResolverReachabilityInternal(SCDynamicStoreRef *storeP, + SCNetworkReachabilityFlags *flags, + Boolean *haveDNS, + const char *nodename, + const char *servname, + uint32_t *resolver_if_index, + int *dns_config_index) +{ + Boolean ok; + ReachabilityStoreInfo store_info; + + ReachabilityStoreInfo_init(&store_info); + ok = ReachabilityStoreInfo_update(&store_info, storeP, AF_UNSPEC); + if (!ok) { + goto done; + } + + ok = _SC_R_checkResolverReachability(&store_info, flags, haveDNS, nodename, + servname, 0, resolver_if_index, dns_config_index, ""); + + done : + + ReachabilityStoreInfo_free(&store_info); + return ok; +} /* * _SC_checkResolverReachabilityByAddress() @@ -3171,8 +3768,8 @@ _SC_checkResolverReachabilityByAddress(SCDynamicStoreRef *storeP, char ptr_name[128]; ReachabilityStoreInfo store_info; - initReachabilityStoreInfo(&store_info); - ok = updateReachabilityStoreInfo(&store_info, storeP, AF_UNSPEC); + ReachabilityStoreInfo_init(&store_info); + ok = ReachabilityStoreInfo_update(&store_info, storeP, AF_UNSPEC); if (!ok) { goto done; } @@ -3192,7 +3789,8 @@ _SC_checkResolverReachabilityByAddress(SCDynamicStoreRef *storeP, in_addr_t s_addr; unsigned char b[4]; } rev; - struct sockaddr_in *sin = (struct sockaddr_in *)sa; + /* ALIGN: assuming sa is aligned, then cast ok. */ + struct sockaddr_in *sin = (struct sockaddr_in *)(void *)sa; /* * build "PTR" query name @@ -3210,7 +3808,8 @@ _SC_checkResolverReachabilityByAddress(SCDynamicStoreRef *storeP, case AF_INET6 : { int s = 0; - struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; + /* ALIGN: assume sa is aligned, cast ok. */ + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)(void *)sa; int x = sizeof(ptr_name); int n; @@ -3242,17 +3841,18 @@ _SC_checkResolverReachabilityByAddress(SCDynamicStoreRef *storeP, goto done; } - ok = _SC_R_checkResolverReachability(&store_info, flags, haveDNS, ptr_name, NULL, 0, ""); + ok = _SC_R_checkResolverReachability(&store_info, flags, haveDNS, ptr_name, NULL, 0, NULL, NULL, ""); done : - freeReachabilityStoreInfo(&store_info); + ReachabilityStoreInfo_free(&store_info); return ok; } static Boolean -startAsyncDNSQuery(SCNetworkReachabilityRef target) { +startAsyncDNSQuery(SCNetworkReachabilityRef target) +{ int error = 0; mach_port_t mp = MACH_PORT_NULL; Boolean ok; @@ -3293,57 +3893,419 @@ startAsyncDNSQuery(SCNetworkReachabilityRef target) { } -#pragma mark - +#pragma mark - + + +static Boolean +enqueueAsyncDNSRetry(SCNetworkReachabilityRef target) +{ + int64_t delay; + dispatch_source_t source; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + MUTEX_ASSERT_HELD(&targetPrivate->lock); + + source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, + 0, + 0, + __SCNetworkReachability_concurrent_queue()); + if (source == NULL) { + SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability retry dispatch_source_create() failed")); + return FALSE; + } + + // retain the target ... and release it when the [timer] source is released + CFRetain(target); + dispatch_set_context(source, (void *)target); + dispatch_set_finalizer_f(source, (dispatch_function_t)CFRelease); + + dispatch_source_set_event_handler(source, ^(void) { + __SCNetworkReachabilityPerformInlineNoLock(target, TRUE); + }); + + // start a one-shot timer + delay = targetPrivate->dnsRetryCount * EAI_NONAME_RETRY_DELAY_USEC * NSEC_PER_USEC; + dispatch_source_set_timer(source, + dispatch_time(DISPATCH_TIME_NOW, delay), // start + 0, // interval + 10 * NSEC_PER_MSEC); // leeway + + targetPrivate->dnsRetry = source; + dispatch_resume(source); + + return TRUE; +} + + +static void +dequeueAsyncDNSRetry(SCNetworkReachabilityRef target) +{ + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + MUTEX_ASSERT_HELD(&targetPrivate->lock); + + if (targetPrivate->dnsRetry != NULL) { + dispatch_source_cancel(targetPrivate->dnsRetry); + dispatch_release(targetPrivate->dnsRetry); + targetPrivate->dnsRetry = NULL; + } + + return; +} + + +#pragma mark - + + +static dispatch_queue_t +_llq_queue() +{ + static dispatch_once_t once; + static dispatch_queue_t q; + + dispatch_once(&once, ^{ + q = dispatch_queue_create("SCNetworkReachabilty.longLivedQueries", NULL); + }); + + return q; +} + + +/* + * _llq_notify + * + * Called to push out a target's DNS changes + * - caller must be running on the _llq_queue() + */ +static void +_llq_notify(const void *value, void *context) +{ + SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)value; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + MUTEX_LOCK(&targetPrivate->lock); + + __dns_query_end(target, + (targetPrivate->resolvedAddressError == NETDB_SUCCESS), // if successful query + dns_query_llq, // long-lived-query + &targetPrivate->dnsQueryStart, // start time + &targetPrivate->dnsQueryEnd); // end time + + if (targetPrivate->scheduled) { + __SCNetworkReachabilityPerform(target); + } + + // last long-lived-query end time is new start time + targetPrivate->dnsQueryStart = targetPrivate->dnsQueryEnd; + + MUTEX_UNLOCK(&targetPrivate->lock); + return; +} + + +/* + * _llq_callback + * + * Called to process mDNSResponder long-lived-query updates + * - caller must be running on the _llq_queue() + */ +static void +_llq_callback(DNSServiceRef sdRef, + DNSServiceFlags flags, + uint32_t interfaceIndex, + DNSServiceErrorType errorCode, + const char *hostname, + const struct sockaddr *address, + uint32_t ttl, + void *context) +{ + SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)context; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + MUTEX_LOCK(&targetPrivate->lock); + + if (targetPrivate->llqTimer != NULL) { + dispatch_source_cancel(targetPrivate->llqTimer); + dispatch_release(targetPrivate->llqTimer); + targetPrivate->llqTimer = NULL; + } + + switch (errorCode) { + case kDNSServiceErr_NoError : + if (address != NULL) { + CFMutableArrayRef addresses; + CFDataRef llqAddress; + + if (targetPrivate->resolvedAddress != NULL) { + if (isA_CFArray(targetPrivate->resolvedAddress)) { + addresses = CFArrayCreateMutableCopy(NULL, 0, targetPrivate->resolvedAddress); + } else { + addresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + + CFRelease(targetPrivate->resolvedAddress); + targetPrivate->resolvedAddress = NULL; + } else { + addresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + } + + llqAddress = CFDataCreate(NULL, (void *)address, address->sa_len); + if (flags & kDNSServiceFlagsAdd) { + // add address + CFArrayAppendValue(addresses, llqAddress); + } else { + CFIndex i; + + // remove address + i = CFArrayGetFirstIndexOfValue(addresses, + CFRangeMake(0, CFArrayGetCount(addresses)), + llqAddress); + if (i != kCFNotFound) { + CFArrayRemoveValueAtIndex(addresses, i); + } + } + CFRelease(llqAddress); + + if (CFArrayGetCount(addresses) > 0) { + targetPrivate->resolvedAddress = addresses; + targetPrivate->resolvedAddressError = NETDB_SUCCESS; + } else { + // if host not found + targetPrivate->resolvedAddress = CFRetain(kCFNull); + targetPrivate->resolvedAddressError = EAI_NONAME; + CFRelease(addresses); + } + + targetPrivate->needResolve = FALSE; + } + break; + case kDNSServiceErr_NoSuchRecord : + if (address != NULL) { + // no IPv4/IPv6 address for name (NXDOMAIN) + if (targetPrivate->resolvedAddress == NULL) { + targetPrivate->resolvedAddress = CFRetain(kCFNull); + targetPrivate->resolvedAddressError = EAI_NONAME; + } + targetPrivate->needResolve = FALSE; + } + break; + case kDNSServiceErr_Timeout : + if (targetPrivate->resolvedAddress == NULL) { + targetPrivate->resolvedAddress = CFRetain(kCFNull); + targetPrivate->resolvedAddressError = EAI_NONAME; + } + targetPrivate->needResolve = FALSE; + break; + default : + SCLog(TRUE, LOG_ERR, + CFSTR("%sSCNetworkReachability _llq_callback w/error=%d"), + targetPrivate->log_prefix, + errorCode); + break; + } + + MUTEX_UNLOCK(&targetPrivate->lock); + + // the "more coming" flag applies to DNSService callouts for any/all + // hosts that are being watched so we need to keep track of the targets + // we have updated. When we [finally] have the last callout then we + // push our notifications for all of the updated targets. + + if (llqUpdated == NULL) { + llqUpdated = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); + } + CFSetAddValue(llqUpdated, target); + + if (!(flags & kDNSServiceFlagsMoreComing)) { + CFSetApplyFunction(llqUpdated, _llq_notify, NULL); + CFRelease(llqUpdated); + llqUpdated = NULL; + } + + return; +} + + +static Boolean +enqueueLongLivedQuery(SCNetworkReachabilityRef target) +{ + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + MUTEX_ASSERT_HELD(&targetPrivate->lock); + + if (targetPrivate->serv != NULL) { + // if "serv" provided, can't use DNSServiceGetAddrInfo + return FALSE; + } + + if (memcmp(&targetPrivate->hints, &HINTS_DEFAULT, sizeof(targetPrivate->hints)) != 0) { + // non-default "hints" provided, can't use DNSServiceGetAddrInfo + return FALSE; + } + + // mark the long lived query active + targetPrivate->llqActive = TRUE; + + // track the DNS resolution time + __dns_query_start(&targetPrivate->dnsQueryStart, &targetPrivate->dnsQueryEnd); + + CFRetain(target); + dispatch_async(_llq_queue(), ^{ + DNSServiceErrorType err; + dispatch_source_t source; + + MUTEX_LOCK(&targetPrivate->lock); + + if (targetPrivate->llqTarget != NULL) { + // if already running + MUTEX_UNLOCK(&targetPrivate->lock); + CFRelease(target); + return; + } + + // if needed, start interacting with mDNSResponder + + if (llqMain == NULL) { + err = DNSServiceCreateConnection(&llqMain); + if (err != kDNSServiceErr_NoError) { + SCLog(TRUE, LOG_ERR, + CFSTR("DNSServiceCreateConnection(&llqMain) failed, error = %d"), + err); + + targetPrivate->llqActive = FALSE; + + MUTEX_UNLOCK(&targetPrivate->lock); + CFRelease(target); + return; + } + err = DNSServiceSetDispatchQueue(llqMain, _llq_queue()); + if (err != kDNSServiceErr_NoError) { + SCLog(TRUE, LOG_ERR, + CFSTR("DNSServiceSetDispatchQueue() failed, error = %d"), + err); + DNSServiceRefDeallocate(llqMain); + llqMain = NULL; -static Boolean -enqueueAsyncDNSRetry(SCNetworkReachabilityRef target) -{ - int64_t delay; - dispatch_source_t source; - SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + targetPrivate->llqActive = FALSE; - source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, - 0, - 0, - dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); - if (source == NULL) { - SCLog(TRUE, LOG_ERR, CFSTR("SCNetworkReachability retry dispatch_source_create() failed")); - return FALSE; - } + MUTEX_UNLOCK(&targetPrivate->lock); + CFRelease(target); + return; + } + } - // retain the target ... and release it when the [timer] source is released - CFRetain(target); - dispatch_set_context(source, (void *)target); - dispatch_set_finalizer_f(source, (dispatch_function_t)CFRelease); + // start a long-lived-query for this target - dispatch_source_set_event_handler(source, ^(void) { - __SCNetworkReachabilityPerformInline(target, TRUE); - }); + targetPrivate->llqTarget = llqMain; + err = DNSServiceGetAddrInfo(&targetPrivate->llqTarget, // sdRef + kDNSServiceFlagsReturnIntermediates // flags + | kDNSServiceFlagsShareConnection, + targetPrivate->if_index, // interfaceIndex + 0, // protocol + targetPrivate->name, // hostname + _llq_callback, // callback + (void *)target); // context + if (err != kDNSServiceErr_NoError) { + SCLog(TRUE, LOG_ERR, + CFSTR("DNSServiceGetAddrInfo() failed, error = %d"), + err); + targetPrivate->llqTarget = NULL; + if (llqCount == 0) { + // if this was the first request + DNSServiceRefDeallocate(llqMain); + llqMain = NULL; + } - // start a one-shot timer - delay = targetPrivate->dnsRetryCount * EAI_NONAME_RETRY_DELAY_USEC * NSEC_PER_USEC; - dispatch_source_set_timer(source, - dispatch_time(DISPATCH_TIME_NOW, delay), // start - 0, // interval - 10 * NSEC_PER_MSEC); // leeway + targetPrivate->llqActive = FALSE; + + MUTEX_UNLOCK(&targetPrivate->lock); + CFRelease(target); + return; + } + + llqCount++; + + // if case we don't get any callbacks from our long-lived-query (this + // could happen if the DNS servers do not respond), we start a timer + // to ensure that we fire off at least one reachability callback. + + source = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, + 0, + 0, + _llq_queue()); + if (source != NULL) { + // retain the target ... and release it when the [timer] source is released + CFRetain(target); + dispatch_set_context(source, (void *)target); + dispatch_set_finalizer_f(source, (dispatch_function_t)CFRelease); + + dispatch_source_set_event_handler(source, ^(void) { + _llq_callback(NULL, // sdRef + 0, // flags + 0, // interfaceIndex + kDNSServiceErr_Timeout, // errorCode + NULL, // hostname + NULL, // address + 0, // ttl + (void *)target); // context + }); + + dispatch_source_set_timer(source, + dispatch_time(DISPATCH_TIME_NOW, + LLQ_TIMEOUT_NSEC), // start + 0, // interval + 10 * NSEC_PER_MSEC); // leeway + + targetPrivate->llqTimer = source; + dispatch_resume(source); + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("SCNetworkReachability llq dispatch_source_create(no-reply) failed")); + } - targetPrivate->dnsRetry = source; - dispatch_resume(source); + MUTEX_UNLOCK(&targetPrivate->lock); + return; + }); return TRUE; } static void -dequeueAsyncDNSRetry(SCNetworkReachabilityRef target) +dequeueLongLivedQuery(SCNetworkReachabilityRef target) { + DNSServiceRef sdRef; SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; - if (targetPrivate->dnsRetry != NULL) { - dispatch_source_cancel(targetPrivate->dnsRetry); - dispatch_release(targetPrivate->dnsRetry); - targetPrivate->dnsRetry = NULL; + MUTEX_ASSERT_HELD(&targetPrivate->lock); + + // terminate the [target] llq timer + if (targetPrivate->llqTimer != NULL) { + dispatch_source_cancel(targetPrivate->llqTimer); + dispatch_release(targetPrivate->llqTimer); + targetPrivate->llqTimer = NULL; + } + + // terminate the [target] long lived query + sdRef = targetPrivate->llqTarget; + targetPrivate->llqTarget = NULL; + + // mark the long lived query NOT active + targetPrivate->llqActive = FALSE; + + if (sdRef != NULL) { + dispatch_async(_llq_queue(), ^{ + DNSServiceRefDeallocate(sdRef); + CFRelease(target); + + llqCount--; + if (llqCount == 0) { + // if no more queries active + DNSServiceRefDeallocate(llqMain); + llqMain = NULL; + } + }); } return; @@ -3391,11 +4353,11 @@ __SCNetworkReachabilityOnDemandCheckCallback(SCNetworkReachabilityRef onDemandSe SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)info; SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; - pthread_mutex_lock(&targetPrivate->lock); + MUTEX_LOCK(&targetPrivate->lock); if (!targetPrivate->scheduled) { // if not currently scheduled - pthread_mutex_unlock(&targetPrivate->lock); + MUTEX_UNLOCK(&targetPrivate->lock); return; } @@ -3403,7 +4365,7 @@ __SCNetworkReachabilityOnDemandCheckCallback(SCNetworkReachabilityRef onDemandSe targetPrivate->log_prefix); __SCNetworkReachabilityPerform(target); - pthread_mutex_unlock(&targetPrivate->lock); + MUTEX_UNLOCK(&targetPrivate->lock); return; } @@ -3423,6 +4385,8 @@ __SCNetworkReachabilityOnDemandCheck(ReachabilityStoreInfoRef store_info, SCDynamicStoreRef store; SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + MUTEX_ASSERT_HELD(&targetPrivate->lock); + // SCLog(_sc_debug, LOG_INFO, // CFSTR("%s__SCNetworkReachabilityOnDemandCheck %s"), // targetPrivate->log_prefix, @@ -3442,9 +4406,9 @@ __SCNetworkReachabilityOnDemandCheck(ReachabilityStoreInfoRef store_info, &onDemandServiceID, &onDemandStatus, &onDemandRemoteAddress); - if (store_info->store != store) { + if ((store_info->store == NULL) && (store != NULL)) { + // if an SCDynamicStore session was added, keep it store_info->store = store; - store_info->storeAdded = TRUE; } if (!_SC_CFEqual(targetPrivate->onDemandRemoteAddress, onDemandRemoteAddress) || !_SC_CFEqual(targetPrivate->onDemandServiceID, onDemandServiceID)) { @@ -3494,7 +4458,10 @@ __SCNetworkReachabilityOnDemandCheck(ReachabilityStoreInfoRef store_info, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, onDemandRemoteAddress); - CFDictionarySetValue(options, kSCNetworkReachabilityOptionConnectionOnDemandByPass, kCFBooleanTrue); + CFDictionarySetValue(options, kSCNetworkReachabilityOptionConnectionOnDemandBypass, kCFBooleanTrue); +#ifdef HAVE_REACHABILITY_SERVER + CFDictionarySetValue(options, kSCNetworkReachabilityOptionServerBypass, kCFBooleanTrue); +#endif // HAVE_REACHABILITY_SERVER targetPrivate->onDemandServer = SCNetworkReachabilityCreateWithOptions(NULL, options); CFRelease(options); @@ -3666,13 +4633,40 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info, ReachabilityInfo my_info = NOT_REACHABLE; Boolean ok = TRUE; - *reach_info = NOT_REACHABLE; + MUTEX_ASSERT_HELD(&targetPrivate->lock); + + _reach_set(reach_info, &NOT_REACHABLE, reach_info->cycle); if (!isA_SCNetworkReachability(target)) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; } +#ifdef HAVE_REACHABILITY_SERVER + if (!targetPrivate->serverBypass) { + if (!targetPrivate->serverActive) { + ok = __SCNetworkReachabilityServer_targetAdd(target); + if (!ok) { + targetPrivate->serverBypass = TRUE; + } + } + + if (targetPrivate->serverActive) { + ok = __SCNetworkReachabilityServer_targetStatus(target); + if (!ok) { + SCLog(TRUE, LOG_DEBUG, + CFSTR("__SCNetworkReachabilityGetFlags _targetStatus() failed")); + _SCErrorSet(kSCStatusFailed); + goto done; + } + + targetPrivate->cycle = targetPrivate->serverInfo.cycle; + _reach_set(&my_info, &targetPrivate->serverInfo, targetPrivate->cycle); + goto done; + } + } +#endif // HAVE_REACHABILITY_SERVER + switch (targetPrivate->type) { case reachabilityTypeAddress : case reachabilityTypeAddressPair : { @@ -3729,6 +4723,7 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info, struct timeval dnsQueryEnd; int error; SCNetworkReachabilityFlags ns_flags; + uint32_t ns_if_index; struct addrinfo *res; addresses = (CFMutableArrayRef)SCNetworkReachabilityCopyResolvedAddress(target, &error); @@ -3737,6 +4732,9 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info, if (!async) { /* if not an async request */ goto checkResolvedAddress; + } else if (targetPrivate->llqActive) { + /* if long-lived-query active */ + goto checkResolvedAddress; } else if ((targetPrivate->dnsMP == MACH_PORT_NULL) && !targetPrivate->needResolve) { struct timeval elapsed; const struct timeval retry_limit = { EAI_NONAME_RETRY_LIMIT_USEC / USEC_PER_SEC, @@ -3844,7 +4842,6 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info, targetPrivate->serv != NULL ? targetPrivate->serv : ""); enqueueAsyncDNSRetry(target); - break; } } @@ -3870,6 +4867,8 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info, targetPrivate->name, targetPrivate->serv, targetPrivate->if_index, + &ns_if_index, + NULL, targetPrivate->log_prefix); if (!ok) { /* if we could not get DNS server info */ @@ -3914,11 +4913,19 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info, break; } + if (targetPrivate->resolverBypass) { + /* if we are not resolving the name, + * set the flags of the resolvers */ + my_info.flags = ns_flags; + my_info.if_index = ns_if_index; + break; + } + if (async) { /* for async requests we return the last known status */ my_info = targetPrivate->info; - if (targetPrivate->dnsPort != NULL) { + if (targetPrivate->dnsMP != MACH_PORT_NULL) { /* if request already in progress */ SCLog(_sc_debug, LOG_INFO, CFSTR("%swaiting for DNS reply"), @@ -3935,6 +4942,37 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info, break; } + if (targetPrivate->llqActive) { + /* if long-lived-query active */ + SCLog(_sc_debug, LOG_INFO, + CFSTR("%swaiting for DNS updates"), + targetPrivate->log_prefix); + if ((addresses != NULL) || (error != NETDB_SUCCESS)) { + /* updated reachability based on the previous reply */ + goto checkResolvedAddress; + } + break; + } + + if (!targetPrivate->llqBypass) { + SCLog(_sc_debug, LOG_INFO, + CFSTR("%sstart long-lived DNS query for %s%s%s%s%s"), + targetPrivate->log_prefix, + targetPrivate->name != NULL ? "name = " : "", + targetPrivate->name != NULL ? targetPrivate->name : "", + targetPrivate->name != NULL && targetPrivate->serv != NULL ? ", " : "", + targetPrivate->serv != NULL ? "serv = " : "", + targetPrivate->serv != NULL ? targetPrivate->serv : ""); + + /* + * initiate an long-lived DNS query + */ + if (enqueueLongLivedQuery(target)) { + /* request initiated */ + break; + } + } + SCLog(_sc_debug, LOG_INFO, CFSTR("%sstart DNS query for %s%s%s%s%s"), targetPrivate->log_prefix, @@ -3947,13 +4985,13 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info, /* * initiate an async DNS query */ - if (!startAsyncDNSQuery(target)) { - /* if we could not initiate the request, process error */ - goto checkResolvedAddress; + if (startAsyncDNSQuery(target)) { + /* request initiated */ + break; } - /* request initiated */ - break; + /* if we could not initiate the request, process error */ + goto checkResolvedAddress; } SCLog(_sc_debug, LOG_INFO, @@ -3990,7 +5028,7 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info, __dns_query_end(target, ((error == 0) && (res != NULL)), // if successful query - FALSE, // sync + dns_query_sync, // sync &dnsQueryStart, // start time &dnsQueryEnd); // end time @@ -4094,7 +5132,7 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info, done: - *reach_info = my_info; + _reach_set(reach_info, &my_info, targetPrivate->cycle); error : @@ -4102,6 +5140,47 @@ __SCNetworkReachabilityGetFlags(ReachabilityStoreInfoRef store_info, return ok; } +int +SCNetworkReachabilityGetInterfaceIndex(SCNetworkReachabilityRef target) +{ + SCNetworkReachabilityFlags flags; + int if_index = -1; + Boolean ok = TRUE; + ReachabilityStoreInfo store_info; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + if (!isA_SCNetworkReachability(target)) { + _SCErrorSet(kSCStatusInvalidArgument); + return if_index; + } + + ReachabilityStoreInfo_init(&store_info); + + MUTEX_LOCK(&targetPrivate->lock); + + if (targetPrivate->scheduled) { + // if being watched, return the last known (and what should be current) status + flags = targetPrivate->info.flags & ~kSCNetworkReachabilityFlagsFirstResolvePending; + goto done; + } + + + ok = __SCNetworkReachabilityGetFlags(&store_info, target, &targetPrivate->info, FALSE); + flags = targetPrivate->info.flags & ~kSCNetworkReachabilityFlagsFirstResolvePending; + + done : + + /* Only return the if_index if the connection is reachable not for reachable connection + * required etc ... */ + if (ok && rankReachability(flags) == 2) { + if_index = targetPrivate->info.if_index; + } + + MUTEX_UNLOCK(&targetPrivate->lock); + ReachabilityStoreInfo_free(&store_info); + return if_index; +} + Boolean SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef target, @@ -4116,8 +5195,9 @@ SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef target, return FALSE; } - initReachabilityStoreInfo(&store_info); - pthread_mutex_lock(&targetPrivate->lock); + ReachabilityStoreInfo_init(&store_info); + + MUTEX_LOCK(&targetPrivate->lock); if (targetPrivate->scheduled) { // if being watched, return the last known (and what should be current) status @@ -4131,8 +5211,8 @@ SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef target, done : - pthread_mutex_unlock(&targetPrivate->lock); - freeReachabilityStoreInfo(&store_info); + MUTEX_UNLOCK(&targetPrivate->lock); + ReachabilityStoreInfo_free(&store_info); return ok; } @@ -4270,6 +5350,9 @@ __SCNetworkReachabilityReachabilitySetNotifications(SCDynamicStoreRef store) #endif // TARGET_OS_IPHONE + // SCDynamicStore key to force posting a reachability change + CFArrayAppendValue(keys, SCNETWORKREACHABILITY_TRIGGER_KEY); + (void)SCDynamicStoreSetNotificationKeys(store, keys, patterns); CFRelease(keys); CFRelease(patterns); @@ -4278,6 +5361,20 @@ __SCNetworkReachabilityReachabilitySetNotifications(SCDynamicStoreRef store) } +static dispatch_queue_t +_hn_queue() +{ + static dispatch_once_t once; + static dispatch_queue_t q; + + dispatch_once(&once, ^{ + q = dispatch_queue_create("SCNetworkReachabilty.changes", NULL); + }); + + return q; +} + + static void __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store, CFArrayRef changedKeys, @@ -4288,9 +5385,12 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store, #endif // !TARGET_OS_IPHONE Boolean dnsConfigChanged = FALSE; CFIndex i; + Boolean forcedChange = FALSE; CFStringRef key; - CFIndex nChanges = CFArrayGetCount(changedKeys); + CFIndex nChanges; + CFIndex nGlobals = 0; CFIndex nTargets; + Boolean networkConfigChanged = FALSE; struct timeval now; #if !TARGET_OS_IPHONE Boolean powerStatusChanged = FALSE; @@ -4298,15 +5398,25 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store, ReachabilityStoreInfo store_info; const void * targets_q[N_QUICK]; const void ** targets = targets_q; + __block CFSetRef watchers = NULL; + nChanges = CFArrayGetCount(changedKeys); if (nChanges == 0) { /* if no changes */ return; } - pthread_mutex_lock(&hn_lock); + /* "something" changed, start fresh */ + ReachabilityStoreInfo_save(NULL); + + dispatch_sync(_hn_queue(), ^{ + /* grab the currently watched targets */ + if (hn_targets != NULL) { + watchers = CFSetCreateCopy(NULL, hn_targets); + } + }); - nTargets = (hn_targets != NULL) ? CFSetGetCount(hn_targets) : 0; + nTargets = (watchers != NULL) ? CFSetGetCount(watchers) : 0; if (nTargets == 0) { /* if no addresses being monitored */ goto done; @@ -4322,6 +5432,8 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store, if (CFArrayContainsValue(changedKeys, CFRangeMake(0, nChanges), key)) { CFNumberRef num; + nGlobals++; + num = SCDynamicStoreCopyValue(store, key); if (num != NULL) { if (isA_CFNumber(num) && @@ -4356,10 +5468,20 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store, kSCDynamicStoreDomainState, kSCEntNetDNS); if (CFArrayContainsValue(changedKeys, CFRangeMake(0, nChanges), key)) { + nGlobals++; dnsConfigChanged = TRUE; /* the DNS server(s) have changed */ } CFRelease(key); + if (CFArrayContainsValue(changedKeys, CFRangeMake(0, nChanges), SCNETWORKREACHABILITY_TRIGGER_KEY)) { + nGlobals++; + forcedChange = TRUE; /* an SCDynamicStore driven "network" change */ + } + + if (nChanges > nGlobals) { + networkConfigChanged = TRUE; + } + if (_sc_debug) { unsigned int changes = 0; static const char *change_strings[] = { @@ -4375,7 +5497,7 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store, "DNS and power ", "network, DNS, and power ", - // with no "power" status change (including CPU "on") + // with "power" status change (including CPU "on") "power* ", "network and power* ", "DNS and power* ", @@ -4390,42 +5512,51 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store, if (cpuStatusChanged) { changes += PWR; } - nChanges -= 1; } #endif // !TARGET_OS_IPHONE #define DNS 2 if (dnsConfigChanged) { changes |= DNS; - nChanges -= 1; } #define NET 1 - if (nChanges > 0) { + if (networkConfigChanged) { changes |= NET; } SCLog(TRUE, LOG_INFO, - CFSTR("process %sconfiguration change"), + CFSTR("process %s%sconfiguration change"), + forcedChange ? "[forced] " : "", change_strings[changes]); } - initReachabilityStoreInfo(&store_info); + ReachabilityStoreInfo_init(&store_info); if (nTargets > (CFIndex)(sizeof(targets_q) / sizeof(CFTypeRef))) targets = CFAllocatorAllocate(NULL, nTargets * sizeof(CFTypeRef), 0); - CFSetGetValues(hn_targets, targets); + CFSetGetValues(watchers, targets); for (i = 0; i < nTargets; i++) { SCNetworkReachabilityRef target = targets[i]; SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; - pthread_mutex_lock(&targetPrivate->lock); + MUTEX_LOCK(&targetPrivate->lock); if (dnsConfigChanged) { targetPrivate->last_dns = now; targetPrivate->dnsRetryCount = 0; } + if (networkConfigChanged) { + targetPrivate->last_network = now; + } + +#if !TARGET_OS_IPHONE + if (powerStatusChanged) { + targetPrivate->last_power = now; + } +#endif // !TARGET_OS_IPHONE + if (targetPrivate->type == reachabilityTypeName) { Boolean dnsChanged = dnsConfigChanged; @@ -4438,7 +5569,7 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store, Boolean ok; /* check the reachability of the DNS servers */ - ok = updateReachabilityStoreInfo(&store_info, &store, AF_UNSPEC); + ok = ReachabilityStoreInfo_update(&store_info, &store, AF_UNSPEC); if (ok) { ok = _SC_R_checkResolverReachability(&store_info, &ns_flags, @@ -4446,6 +5577,8 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store, targetPrivate->name, targetPrivate->serv, targetPrivate->if_index, + NULL, + NULL, targetPrivate->log_prefix); } @@ -4467,9 +5600,7 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store, } if (dnsChanged) { - if (targetPrivate->dnsPort != NULL) { - mach_port_t mp = CFMachPortGetPort(targetPrivate->dnsPort); - + if (targetPrivate->dnsMP != MACH_PORT_NULL) { /* cancel the outstanding DNS query */ SCLog(_sc_debug, LOG_INFO, CFSTR("%scancel DNS query for %s%s%s%s%s"), @@ -4479,8 +5610,7 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store, targetPrivate->name != NULL && targetPrivate->serv != NULL ? ", " : "", targetPrivate->serv != NULL ? "serv = " : "", targetPrivate->serv != NULL ? targetPrivate->serv : ""); - dequeueAsyncDNSQuery(target); - getaddrinfo_async_cancel(mp); + dequeueAsyncDNSQuery(target, TRUE); } if (targetPrivate->dnsRetry != NULL) { @@ -4493,17 +5623,23 @@ __SCNetworkReachabilityHandleChanges(SCDynamicStoreRef store, } } - __SCNetworkReachabilityPerform(target); + if (forcedChange) { + targetPrivate->cycle++; + } + + if (targetPrivate->scheduled) { + __SCNetworkReachabilityPerform(target); + } - pthread_mutex_unlock(&targetPrivate->lock); + MUTEX_UNLOCK(&targetPrivate->lock); } if (targets != targets_q) CFAllocatorDeallocate(NULL, targets); - freeReachabilityStoreInfo(&store_info); + ReachabilityStoreInfo_free(&store_info); done : - pthread_mutex_unlock(&hn_lock); + if (watchers != NULL) CFRelease(watchers); return; } @@ -4548,11 +5684,13 @@ systemIsAwake(IOPMSystemPowerStateCapabilities power_capabilities) static void -rlsPerform(void *info) +reachPerform(void *info) { void *context_info; void (*context_release)(const void *); + uint64_t cycle; Boolean defer = FALSE; + Boolean forced; Boolean ok; ReachabilityInfo reach_info = NOT_REACHABLE; SCNetworkReachabilityCallBack rlsFunction; @@ -4564,7 +5702,7 @@ rlsPerform(void *info) targetPrivate->log_prefix); - pthread_mutex_lock(&targetPrivate->lock); + MUTEX_LOCK(&targetPrivate->lock); if (targetPrivate->dnsRetry != NULL) { // cancel DNS retry @@ -4573,14 +5711,14 @@ rlsPerform(void *info) if (!targetPrivate->scheduled) { // if not currently scheduled - pthread_mutex_unlock(&targetPrivate->lock); + MUTEX_UNLOCK(&targetPrivate->lock); return; } /* update reachability, notify if status changed */ - initReachabilityStoreInfo(&store_info); + ReachabilityStoreInfo_init(&store_info); ok = __SCNetworkReachabilityGetFlags(&store_info, target, &reach_info, TRUE); - freeReachabilityStoreInfo(&store_info); + ReachabilityStoreInfo_free(&store_info); if (!ok) { /* if reachability status not available */ SCLog(_sc_debug, LOG_INFO, CFSTR("%flags not available"), @@ -4604,7 +5742,7 @@ rlsPerform(void *info) * the same or "better" */ defer = !darkWakeNotify(target); - } else if (__reach_equal(&targetPrivate->last_notify, &reach_info)) { + } else if (!__reach_changed(&targetPrivate->last_notify, &reach_info)) { /* * if we have already posted this change */ @@ -4613,7 +5751,10 @@ rlsPerform(void *info) } #endif // !TARGET_OS_IPHONE - if (__reach_equal(&targetPrivate->info, &reach_info)) { + cycle = targetPrivate->cycle; + forced = ((cycle != 0) && (targetPrivate->info.cycle != cycle)); + + if (!forced && !__reach_changed(&targetPrivate->info, &reach_info)) { if (_sc_debug) { if (targetPrivate->info.sleeping == reach_info.sleeping) { SCLog(TRUE, LOG_INFO, @@ -4635,12 +5776,12 @@ rlsPerform(void *info) } } - pthread_mutex_unlock(&targetPrivate->lock); + MUTEX_UNLOCK(&targetPrivate->lock); return; } SCLog(_sc_debug, LOG_INFO, - CFSTR("%sflags/interface have changed (was 0x%08x/%hu%s, now 0x%08x/%hu%s)%s"), + CFSTR("%sflags/interface have changed (was 0x%08x/%hu%s, now 0x%08x/%hu%s)%s%s"), targetPrivate->log_prefix, targetPrivate->info.flags, targetPrivate->info.if_index, @@ -4648,19 +5789,23 @@ rlsPerform(void *info) reach_info.flags, reach_info.if_index, reach_info.sleeping ? ", z" : "", - defer ? ", deferred" : ""); + defer ? ", deferred" : "", + forced ? ", forced" : ""); /* as needed, defer the notification */ if (defer) { - pthread_mutex_unlock(&targetPrivate->lock); + MUTEX_UNLOCK(&targetPrivate->lock); return; } /* update flags / interface */ - targetPrivate->info = reach_info; + _reach_set(&targetPrivate->info, &reach_info, cycle); /* save last notification info */ - targetPrivate->last_notify = reach_info; + _reach_set(&targetPrivate->last_notify, &reach_info, cycle); + + /* save last notification time */ + (void)gettimeofday(&targetPrivate->last_push, NULL); /* callout */ rlsFunction = targetPrivate->rlsFunction; @@ -4672,7 +5817,7 @@ rlsPerform(void *info) context_release = NULL; } - pthread_mutex_unlock(&targetPrivate->lock); + MUTEX_UNLOCK(&targetPrivate->lock); if (rlsFunction != NULL) { (*rlsFunction)(target, @@ -4695,7 +5840,7 @@ SCNetworkReachabilitySetCallback(SCNetworkReachabilityRef target, { SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; - pthread_mutex_lock(&targetPrivate->lock); + MUTEX_LOCK(&targetPrivate->lock); if (targetPrivate->rlsContext.release != NULL) { /* let go of the current context */ @@ -4714,7 +5859,7 @@ SCNetworkReachabilitySetCallback(SCNetworkReachabilityRef target, } } - pthread_mutex_unlock(&targetPrivate->lock); + MUTEX_UNLOCK(&targetPrivate->lock); return TRUE; } @@ -4741,12 +5886,9 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef target, { SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; Boolean init = FALSE; - Boolean ok = FALSE; + __block Boolean ok = FALSE; - if (!onDemand) { - pthread_mutex_lock(&hn_lock); - } - pthread_mutex_lock(&targetPrivate->lock); + MUTEX_LOCK(&targetPrivate->lock); if ((targetPrivate->dispatchQueue != NULL) || // if we are already scheduled with a dispatch queue ((queue != NULL) && targetPrivate->scheduled)) { // if we are already scheduled on a CFRunLoop @@ -4754,53 +5896,99 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef target, goto done; } - /* schedule the SCNetworkReachability run loop source */ - - if (!onDemand && (hn_store == NULL)) { - /* - * if we are not monitoring any hosts, start watching - */ - if (!dns_configuration_watch()) { - // if error - _SCErrorSet(kSCStatusFailed); - goto done; +#ifdef HAVE_REACHABILITY_SERVER + if (!targetPrivate->serverBypass) { + if (!targetPrivate->serverActive) { + ok = __SCNetworkReachabilityServer_targetAdd(target); + if (!ok) { + targetPrivate->serverBypass = TRUE; + } } - hn_store = SCDynamicStoreCreate(NULL, - CFSTR("SCNetworkReachability"), - __SCNetworkReachabilityHandleChanges, - NULL); - if (hn_store == NULL) { - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCreate() failed")); - goto done; - } + if (targetPrivate->serverActive) { + if (targetPrivate->scheduled) { + // if already scheduled + goto watch; + } - __SCNetworkReachabilityReachabilitySetNotifications(hn_store); + ok = __SCNetworkReachabilityServer_targetSchedule(target); + if (!ok) { + SCLog(TRUE, LOG_DEBUG, + CFSTR("__SCNetworkReachabilityScheduleWithRunLoop _targetMonitor() failed")); + _SCErrorSet(kSCStatusFailed); + goto done; + } - hn_dispatchQueue = dispatch_queue_create("com.apple.SCNetworkReachabilty.network_changes", NULL); - if (hn_dispatchQueue == NULL) { - SCLog(TRUE, LOG_ERR, CFSTR("__SCNetworkReachabilityScheduleWithRunLoop dispatch_queue_create() failed")); - _SCErrorSet(kSCStatusFailed); - CFRelease(hn_store); - hn_store = NULL; - goto done; + goto watch; } - CFRetain(hn_store); // Note: will be released when the dispatch queue is released - dispatch_set_context(hn_dispatchQueue, (void *)hn_store); - dispatch_set_finalizer_f(hn_dispatchQueue, (dispatch_function_t)CFRelease); + } +#endif // HAVE_REACHABILITY_SERVER - ok = SCDynamicStoreSetDispatchQueue(hn_store, hn_dispatchQueue); - if (!ok) { - SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSetDispatchQueue() failed")); - dispatch_release(hn_dispatchQueue); - hn_dispatchQueue = NULL; - CFRelease(hn_store); - hn_store = NULL; - goto done; + /* schedule the SCNetworkReachability did-something-change handler */ + + dispatch_sync(_hn_queue(), ^{ + ok = FALSE; + + if (!onDemand && (hn_store == NULL)) { + /* + * if we are not monitoring any hosts, start watching + */ + if (!dns_configuration_watch()) { + // if error + _SCErrorSet(kSCStatusFailed); + return; + } + + hn_store = SCDynamicStoreCreate(NULL, + CFSTR("SCNetworkReachability"), + __SCNetworkReachabilityHandleChanges, + NULL); + if (hn_store == NULL) { + SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreCreate() failed")); + dns_configuration_unwatch(); + return; + } + + __SCNetworkReachabilityReachabilitySetNotifications(hn_store); + + hn_dispatchQueue = dispatch_queue_create("SCNetworkReachabilty.changes", NULL); + if (hn_dispatchQueue == NULL) { + SCLog(TRUE, LOG_ERR, CFSTR("__SCNetworkReachabilityScheduleWithRunLoop dispatch_queue_create() failed")); + CFRelease(hn_store); + hn_store = NULL; + dns_configuration_unwatch(); + _SCErrorSet(kSCStatusFailed); + return; + } + + ok = SCDynamicStoreSetDispatchQueue(hn_store, hn_dispatchQueue); + if (!ok) { + SCLog(TRUE, LOG_ERR, CFSTR("SCDynamicStoreSetDispatchQueue() failed")); + dispatch_release(hn_dispatchQueue); + hn_dispatchQueue = NULL; + CFRelease(hn_store); + hn_store = NULL; + dns_configuration_unwatch(); + return; + } + hn_targets = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); + + ReachabilityStoreInfo_enable(TRUE); } - hn_targets = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); + + CFSetAddValue(hn_targets, target); + + ok = TRUE; + }); + + if (!ok) { + goto done; } +#ifdef HAVE_REACHABILITY_SERVER + watch : +#endif // HAVE_REACHABILITY_SERVER + if (!targetPrivate->scheduled) { CFRunLoopSourceContext context = { 0 // version , (void *)target // info @@ -4811,7 +5999,7 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef target, , CFHash // hash , NULL // schedule , NULL // cancel - , rlsPerform // perform + , reachPerform // perform }; if (runLoop != NULL) { @@ -4819,16 +6007,53 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef target, targetPrivate->rlList = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } - targetPrivate->scheduled = TRUE; if (targetPrivate->type == reachabilityTypeName) { + /* + * we're now scheduled so let's ensure that we + * are starting with a clean slate before we + * resolve the name + */ + if (targetPrivate->resolvedAddress != NULL) { + CFRelease(targetPrivate->resolvedAddress); + targetPrivate->resolvedAddress = NULL; + } + targetPrivate->resolvedAddressError = NETDB_SUCCESS; targetPrivate->needResolve = TRUE; + _reach_set(&targetPrivate->info, &NOT_REACHABLE, targetPrivate->info.cycle); + targetPrivate->info.flags |= kSCNetworkReachabilityFlagsFirstResolvePending; +#ifdef HAVE_REACHABILITY_SERVER + _reach_set(&targetPrivate->serverInfo, &NOT_REACHABLE, targetPrivate->serverInfo.cycle); + targetPrivate->serverInfo.flags |= kSCNetworkReachabilityFlagsFirstResolvePending; +#endif // HAVE_REACHABILITY_SERVER } + + targetPrivate->scheduled = TRUE; + init = TRUE; } if (queue != NULL) { + // retain dispatch queue + dispatch_retain(queue); targetPrivate->dispatchQueue = queue; - dispatch_retain(targetPrivate->dispatchQueue); + + // + // We've taken a reference to the client's dispatch_queue and we + // want to hold on to that reference until we've processed any/all + // notifications. To facilitate this we create a group, dispatch + // any notification blocks to via that group, and when the caller + // has told us to stop the notifications (unschedule) we wait for + // the group to empty and use the group's finalizer to release + // our reference to the client's queue. + // + + // make sure that we have group to track any async requests + targetPrivate->dispatchGroup = dispatch_group_create(); + + // retain the target ... and release it when the group is released + CFRetain(target); + dispatch_set_context(targetPrivate->dispatchGroup, (void *)target); + dispatch_set_finalizer_f(targetPrivate->dispatchGroup, (dispatch_function_t)CFRelease); } else { if (!_SC_isScheduled(NULL, runLoop, runLoopMode, targetPrivate->rlList)) { /* @@ -4838,7 +6063,7 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef target, CFRunLoopAddSource(runLoop, targetPrivate->rls, runLoopMode); if (targetPrivate->dnsRLS != NULL) { - /* if we have an active async DNS query too */ + // if we have an active async DNS query too CFRunLoopAddSource(runLoop, targetPrivate->dnsRLS, runLoopMode); } } @@ -4846,8 +6071,6 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef target, _SC_schedule(target, runLoop, runLoopMode, targetPrivate->rlList); } - CFSetAddValue(hn_targets, target); - if (init) { ReachabilityInfo reach_info = NOT_REACHABLE; ReachabilityStoreInfo store_info; @@ -4856,20 +6079,26 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef target, * if we have yet to schedule SC notifications for this address * - initialize current reachability status */ - initReachabilityStoreInfo(&store_info); + ReachabilityStoreInfo_init(&store_info); if (__SCNetworkReachabilityGetFlags(&store_info, target, &reach_info, TRUE)) { /* * if reachability status available * - set flags * - schedule notification to report status via callback */ - targetPrivate->info = reach_info; +#ifdef HAVE_REACHABILITY_SERVER + reach_info.flags |= (targetPrivate->info.flags & kSCNetworkReachabilityFlagsFirstResolvePending); +#endif // HAVE_REACHABILITY_SERVER + _reach_set(&targetPrivate->info, &reach_info, targetPrivate->cycle); __SCNetworkReachabilityPerform(target); } else { /* if reachability status not available, async lookup started */ - targetPrivate->info = NOT_REACHABLE; + _reach_set(&targetPrivate->info, &NOT_REACHABLE, targetPrivate->cycle); +#ifdef HAVE_REACHABILITY_SERVER + _reach_set(&targetPrivate->serverInfo, &NOT_REACHABLE, targetPrivate->cycle); +#endif // HAVE_REACHABILITY_SERVER } - freeReachabilityStoreInfo(&store_info); + ReachabilityStoreInfo_free(&store_info); } if (targetPrivate->onDemandServer != NULL) { @@ -4883,10 +6112,7 @@ __SCNetworkReachabilityScheduleWithRunLoop(SCNetworkReachabilityRef target, done : - pthread_mutex_unlock(&targetPrivate->lock); - if (!onDemand) { - pthread_mutex_unlock(&hn_lock); - } + MUTEX_UNLOCK(&targetPrivate->lock); return ok; } @@ -4897,14 +6123,16 @@ __SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef target, CFStringRef runLoopMode, Boolean onDemand) { - SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + dispatch_group_t drainGroup = NULL; + dispatch_queue_t drainQueue = NULL; CFIndex n = 0; Boolean ok = FALSE; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; - if (!onDemand) { - pthread_mutex_lock(&hn_lock); - } - pthread_mutex_lock(&targetPrivate->lock); + // hold a reference while we unschedule + CFRetain(target); + + MUTEX_LOCK(&targetPrivate->lock); if (((runLoop == NULL) && (targetPrivate->dispatchQueue == NULL)) || // if we should be scheduled on a dispatch queue (but are not) ((runLoop != NULL) && (targetPrivate->dispatchQueue != NULL))) { // if we should be scheduled on a CFRunLoop (but are not) @@ -4918,11 +6146,17 @@ __SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef target, goto done; } - // first, unschedule the target specific sources + // unschedule the target specific sources if (targetPrivate->dispatchQueue != NULL) { if (targetPrivate->onDemandServer != NULL) { __SCNetworkReachabilityUnscheduleFromRunLoop(targetPrivate->onDemandServer, NULL, NULL, TRUE); } + + // save dispatchQueue, release reference when we've queue'd blocks complete, allow re-scheduling + drainGroup = targetPrivate->dispatchGroup; + targetPrivate->dispatchGroup = NULL; + drainQueue = targetPrivate->dispatchQueue; + targetPrivate->dispatchQueue = NULL; } else { if (!_SC_unschedule(target, runLoop, runLoopMode, targetPrivate->rlList, FALSE)) { // if not currently scheduled @@ -4956,51 +6190,82 @@ __SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef target, } if (n == 0) { +#ifdef HAVE_REACHABILITY_SERVER + // + // Cancel our request for server monitoring + // + if (targetPrivate->serverActive) { + ok = __SCNetworkReachabilityServer_targetUnschedule(target); + if (!ok) { + SCLog(TRUE, LOG_DEBUG, + CFSTR("__SCNetworkReachabilityUnscheduleFromRunLoop _targetMonitor() failed")); + _SCErrorSet(kSCStatusFailed); + } + } +#endif // HAVE_REACHABILITY_SERVER + // if *all* notifications have been unscheduled targetPrivate->scheduled = FALSE; + } - if (!onDemand) { - CFSetRemoveValue(hn_targets, target); // cleanup notification resources - } - - if (targetPrivate->dnsPort != NULL) { - mach_port_t mp = CFMachPortGetPort(targetPrivate->dnsPort); +#ifdef HAVE_REACHABILITY_SERVER + if (targetPrivate->serverActive) { + goto unwatch; + } +#endif // HAVE_REACHABILITY_SERVER + if (n == 0) { + if (targetPrivate->dnsMP != MACH_PORT_NULL) { // if we have an active async DNS query - dequeueAsyncDNSQuery(target); - getaddrinfo_async_cancel(mp); + dequeueAsyncDNSQuery(target, TRUE); } if (targetPrivate->dnsRetry != NULL) { // if we have an outstanding DNS retry dequeueAsyncDNSRetry(target); } - } - if (runLoop == NULL) { - dispatch_release(targetPrivate->dispatchQueue); - targetPrivate->dispatchQueue = NULL; - } + if (targetPrivate->llqActive) { + // if we have a long-lived-query + dequeueLongLivedQuery(target); + } - n = CFSetGetCount(hn_targets); - if (n == 0) { - // if we are no longer monitoring any targets - SCDynamicStoreSetDispatchQueue(hn_store, NULL); - dispatch_release(hn_dispatchQueue); - hn_dispatchQueue = NULL; - CFRelease(hn_store); - hn_store = NULL; - CFRelease(hn_targets); - hn_targets = NULL; + dispatch_sync(_hn_queue(), ^{ + CFSetRemoveValue(hn_targets, target); - /* - * until we start monitoring again, ensure that - * any resources associated with tracking the - * DNS configuration have been released. - */ - dns_configuration_unwatch(); + if (onDemand) { + return; + } + + if (CFSetGetCount(hn_targets) > 0) { + return; + } + + // if we are no longer monitoring any targets + SCDynamicStoreSetDispatchQueue(hn_store, NULL); + dispatch_release(hn_dispatchQueue); + hn_dispatchQueue = NULL; + CFRelease(hn_store); + hn_store = NULL; + CFRelease(hn_targets); + hn_targets = NULL; + + ReachabilityStoreInfo_enable(FALSE); + ReachabilityStoreInfo_save(NULL); + + /* + * until we start monitoring again, ensure that + * any resources associated with tracking the + * DNS configuration have been released. + */ + dns_configuration_unwatch(); + }); } +#ifdef HAVE_REACHABILITY_SERVER + unwatch : +#endif // HAVE_REACHABILITY_SERVER + SCLog((_sc_debug && (_sc_log > 0)), LOG_INFO, CFSTR("%sunscheduled"), targetPrivate->log_prefix); @@ -5008,10 +6273,19 @@ __SCNetworkReachabilityUnscheduleFromRunLoop(SCNetworkReachabilityRef target, done : - pthread_mutex_unlock(&targetPrivate->lock); - if (!onDemand) { - pthread_mutex_unlock(&hn_lock); + MUTEX_UNLOCK(&targetPrivate->lock); + + if (drainGroup != NULL) { + dispatch_group_notify(drainGroup, __SCNetworkReachability_concurrent_queue(), ^{ + // release group/queue references + dispatch_release(drainQueue); + dispatch_release(drainGroup); // releases our target reference + }); } + + // release our reference + CFRelease(target); + return ok; } diff --git a/SystemConfiguration.fproj/SCNetworkReachabilityInternal.h b/SystemConfiguration.fproj/SCNetworkReachabilityInternal.h new file mode 100644 index 0000000..f0caeaa --- /dev/null +++ b/SystemConfiguration.fproj/SCNetworkReachabilityInternal.h @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2003-2012 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, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * 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@ + */ + +#ifndef _SCNETWORKREACHABILITYINTERNAL_H +#define _SCNETWORKREACHABILITYINTERNAL_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#if ((__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) || (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000)) && !TARGET_IPHONE_SIMULATOR +#define HAVE_REACHABILITY_SERVER +#include +#endif // ((__MAC_OS_X_VERSION_MIN_REQUIRED >= 1080) || (__IPHONE_OS_VERSION_MIN_REQUIRED >= 50000)) && !TARGET_IPHONE_SIMULATOR + + +#pragma mark - +#pragma mark SCNetworkReachability + + +#define kSCNetworkReachabilityFlagsFirstResolvePending (1<<31) + + +typedef enum { NO = 0, YES, UNKNOWN } lazyBoolean; + + +typedef enum { + reachabilityTypeAddress, + reachabilityTypeAddressPair, + reachabilityTypeName +} ReachabilityAddressType; + + +typedef struct { + uint64_t cycle; + SCNetworkReachabilityFlags flags; + unsigned int if_index; + char if_name[IFNAMSIZ]; + Boolean sleeping; +} ReachabilityInfo; + + +typedef struct { + + /* base CFType information */ + CFRuntimeBase cfBase; + + /* lock */ + pthread_mutex_t lock; + + /* address type */ + ReachabilityAddressType type; + + /* target host name */ + const char *name; + const char *serv; + struct addrinfo hints; + Boolean needResolve; + CFArrayRef resolvedAddress; /* CFArray[CFData] */ + int resolvedAddressError; + + /* [scoped routing] interface constraints */ + unsigned int if_index; + char if_name[IFNAMSIZ]; + + /* local & remote addresses */ + struct sockaddr *localAddress; + struct sockaddr *remoteAddress; + + /* current reachability flags */ + uint64_t cycle; + ReachabilityInfo info; + ReachabilityInfo last_notify; + + /* run loop source, callout, context, rl scheduling info */ + Boolean scheduled; + CFRunLoopSourceRef rls; + SCNetworkReachabilityCallBack rlsFunction; + SCNetworkReachabilityContext rlsContext; + CFMutableArrayRef rlList; + + dispatch_group_t dispatchGroup; + dispatch_queue_t dispatchQueue; // SCNetworkReachabilitySetDispatchQueue + + /* [async] DNS query info */ + Boolean haveDNS; + mach_port_t dnsMP; // != MACH_PORT_NULL (if active) + CFMachPortRef dnsPort; // for CFRunLoop queries + CFRunLoopSourceRef dnsRLS; // for CFRunLoop queries + dispatch_source_t dnsSource; // for dispatch queries + struct timeval dnsQueryStart; + struct timeval dnsQueryEnd; + dispatch_source_t dnsRetry; // != NULL if DNS retry request queued + int dnsRetryCount; // number of retry attempts + + /* [async] processing info */ + struct timeval last_dns; + struct timeval last_network; +#if !TARGET_OS_IPHONE + struct timeval last_power; +#endif // !TARGET_OS_IPHONE + struct timeval last_push; + + /* on demand info */ + Boolean onDemandBypass; + CFStringRef onDemandName; + CFStringRef onDemandRemoteAddress; + SCNetworkReachabilityRef onDemandServer; + CFStringRef onDemandServiceID; + + + Boolean llqActive; + Boolean llqBypass; + DNSServiceRef llqTarget; + dispatch_source_t llqTimer; // != NULL while waiting for first callback + +#ifdef HAVE_REACHABILITY_SERVER + /* SCNetworkReachability server "client" info */ + Boolean serverActive; + Boolean serverBypass; + Boolean serverScheduled; + ReachabilityInfo serverInfo; + + /* SCNetworkReachability server "server" info */ + CFDataRef serverDigest; + dispatch_group_t serverGroup; + Boolean serverInfoValid; + unsigned int serverQueryActive; // 0 == no query active, else # waiting on group + dispatch_queue_t serverQueue; + unsigned int serverReferences; // how many [client] targets + CFMutableDictionaryRef serverWatchers; // [client_id/target_id] watchers +#endif // HAVE_REACHABILITY_SERVER + Boolean resolverBypass; // set this flag to bypass resolving the name + + /* logging */ + char log_prefix[32]; + +} SCNetworkReachabilityPrivate, *SCNetworkReachabilityPrivateRef; + + +#ifdef HAVE_REACHABILITY_SERVER + +// ------------------------------------------------------------ + +#pragma mark - +#pragma mark [XPC] Reachability Server + + +#define REACH_SERVER_VERSION 20110323 +#define REACH_SERVICE_NAME "com.apple.SystemConfiguration.SCNetworkReachability" + +// ------------------------------------------------------------ + + +#pragma mark - +#pragma mark [XPC] Reachability Server (client->server request) + + +#define REACH_CLIENT_PROC_NAME "proc_name" // string +#define REACH_CLIENT_TARGET_ID "target_id" // uint64 + +#define REACH_REQUEST "request_op" // int64 + +enum { + REACH_REQUEST_CREATE = 0x0001, + REACH_REQUEST_REMOVE, + REACH_REQUEST_SCHEDULE, + REACH_REQUEST_STATUS, + REACH_REQUEST_UNSCHEDULE, + REACH_REQUEST_SNAPSHOT = 0x0101, +}; + +#define REACH_TARGET_NAME "name" // string +#define REACH_TARGET_SERV "serv" // string +#define REACH_TARGET_HINTS "hints" // data (struct addrinfo) +#define REACH_TARGET_IF_INDEX "if_index" // int64 +#define REACH_TARGET_IF_NAME "if_name" // string +#define REACH_TARGET_LOCAL_ADDR "localAddress" // data (struct sockaddr) +#define REACH_TARGET_REMOTE_ADDR "remoteAddress" // data (struct sockaddr) +#define REACH_TARGET_ONDEMAND_BYPASS "onDemandBypass" // bool +#define REACH_TARGET_RESOLVER_BYPASS "resolverBypass" // bool + + +#define REACH_REQUEST_REPLY "reply" // int64 +#define REACH_REQUEST_REPLY_DETAIL "reply_detail" // string + +enum { + REACH_REQUEST_REPLY_OK = 0x0000, + REACH_REQUEST_REPLY_FAILED, + REACH_REQUEST_REPLY_UNKNOWN, +}; + + +// ------------------------------------------------------------ + + +#pragma mark - +#pragma mark [XPC] Reachability Server (server->client request) + + +#define MESSAGE_NOTIFY "notify_op" // int64 + +enum { + MESSAGE_REACHABILITY_STATUS = 0x1001, +}; + +#define REACH_STATUS_CYCLE "cycle" // uint64 +#define REACH_STATUS_FLAGS "flags" // uint64 +#define REACH_STATUS_IF_INDEX "if_index" // uint64 +#define REACH_STATUS_IF_NAME "if_name" // data (char if_name[IFNAMSIZ]) +#define REACH_STATUS_RESOLVED_ADDRESS "resolvedAddress" // array[data] +#define REACH_STATUS_RESOLVED_ADDRESS_ERROR "resolvedAddressError" // int64 +#define REACH_STATUS_SLEEPING "sleeping" // bool + + +// ------------------------------------------------------------ + +#endif // HAVE_REACHABILITY_SERVER + + +__BEGIN_DECLS + +CFStringRef +_SCNetworkReachabilityCopyTargetDescription (SCNetworkReachabilityRef target); + +CFStringRef +_SCNetworkReachabilityCopyTargetFlags (SCNetworkReachabilityRef target); + +#ifdef HAVE_REACHABILITY_SERVER + +dispatch_queue_t +__SCNetworkReachability_concurrent_queue (void); + +void +__SCNetworkReachabilityPerformNoLock (SCNetworkReachabilityRef target); + +#pragma mark - +#pragma mark [XPC] Reachability Server (client APIs) + +Boolean +_SCNetworkReachabilityServer_snapshot (void); + +Boolean +__SCNetworkReachabilityServer_targetAdd (SCNetworkReachabilityRef target); + +void +__SCNetworkReachabilityServer_targetRemove (SCNetworkReachabilityRef target); + +Boolean +__SCNetworkReachabilityServer_targetSchedule (SCNetworkReachabilityRef target); + +Boolean +__SCNetworkReachabilityServer_targetStatus (SCNetworkReachabilityRef target); + +Boolean +__SCNetworkReachabilityServer_targetUnschedule (SCNetworkReachabilityRef target); + +Boolean +__SC_checkResolverReachabilityInternal (SCDynamicStoreRef *storeP, + SCNetworkReachabilityFlags *flags, + Boolean *haveDNS, + const char *nodename, + const char *servname, + uint32_t *resolver_if_index, + int *dns_config_index); + +#endif // HAVE_REACHABILITY_SERVER + +__END_DECLS + +#endif // _SCNETWORKREACHABILITYINTERNAL_H diff --git a/SystemConfiguration.fproj/SCNetworkService.c b/SystemConfiguration.fproj/SCNetworkService.c index efdc4b7..1d85e43 100644 --- a/SystemConfiguration.fproj/SCNetworkService.c +++ b/SystemConfiguration.fproj/SCNetworkService.c @@ -296,7 +296,7 @@ __SCNetworkServiceExistsForInterface(CFArrayRef services, SCNetworkInterfaceRef } -__private_extern__ CFStringRef +__private_extern__ CF_RETURNS_RETAINED CFStringRef __SCNetworkServiceNextName(SCNetworkServiceRef service) { CFArrayRef components; @@ -353,7 +353,7 @@ mergeDict(const void *key, const void *value, void *context) } -static CFDictionaryRef +static CF_RETURNS_RETAINED CFDictionaryRef _protocolTemplate(SCNetworkServiceRef service, CFStringRef protocolType) { SCNetworkInterfaceRef interface; @@ -1514,29 +1514,6 @@ SCNetworkServiceSetName(SCNetworkServiceRef service, CFStringRef name) #pragma mark SCNetworkService SPIs -static Boolean -str_to_rank(CFStringRef rankStr, SCNetworkServicePrimaryRank *rank) -{ - if (isA_CFString(rankStr)) { - if (CFEqual(rankStr, kSCValNetServicePrimaryRankFirst)) { - *rank = kSCNetworkServicePrimaryRankFirst; - } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankLast)) { - *rank = kSCNetworkServicePrimaryRankLast; - } else if (CFEqual(rankStr, kSCValNetServicePrimaryRankNever)) { - *rank = kSCNetworkServicePrimaryRankNever; - } else { - return FALSE; - } - } else if (rankStr == NULL) { - *rank = kSCNetworkServicePrimaryRankDefault; - } else { - return FALSE; - } - - return TRUE; -} - - SCNetworkServicePrimaryRank SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service) { @@ -1560,7 +1537,7 @@ SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service) CFRelease(path); if (isA_CFDictionary(entity)) { rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank); - ok = str_to_rank(rankStr, &rank); + ok = __str_to_rank(rankStr, &rank); } } else if (servicePrivate->store != NULL) { path = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, @@ -1572,7 +1549,7 @@ SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service) if (entity != NULL) { if (isA_CFDictionary(entity)) { rankStr = CFDictionaryGetValue(entity, kSCPropNetServicePrimaryRank); - ok = str_to_rank(rankStr, &rank); + ok = __str_to_rank(rankStr, &rank); } CFRelease(entity); } @@ -1592,30 +1569,6 @@ SCNetworkServiceGetPrimaryRank(SCNetworkServiceRef service) } -static Boolean -rank_to_str(SCNetworkServicePrimaryRank rank, CFStringRef *rankStr) -{ - switch (rank) { - case kSCNetworkServicePrimaryRankDefault : - *rankStr = NULL; - break; - case kSCNetworkServicePrimaryRankFirst : - *rankStr = kSCValNetServicePrimaryRankFirst; - break; - case kSCNetworkServicePrimaryRankLast : - *rankStr = kSCValNetServicePrimaryRankLast; - break; - case kSCNetworkServicePrimaryRankNever : - *rankStr = kSCValNetServicePrimaryRankNever; - break; - default : - return FALSE; - } - - return TRUE; -} - - Boolean SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service, SCNetworkServicePrimaryRank newRank) @@ -1632,7 +1585,7 @@ SCNetworkServiceSetPrimaryRank(SCNetworkServiceRef service, return FALSE; } - ok = rank_to_str(newRank, &rankStr); + ok = __rank_to_str(newRank, &rankStr); if (!ok) { _SCErrorSet(kSCStatusInvalidArgument); return FALSE; diff --git a/SystemConfiguration.fproj/SCNetworkSet.c b/SystemConfiguration.fproj/SCNetworkSet.c index dad99e7..126300f 100644 --- a/SystemConfiguration.fproj/SCNetworkSet.c +++ b/SystemConfiguration.fproj/SCNetworkSet.c @@ -1138,12 +1138,14 @@ copyExcludedInterfaces(SCPreferencesRef prefs) excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); +#if !TARGET_OS_IPHONE // exclude Bond [member] interfaces interfaces = SCBondInterfaceCopyAll(prefs); if (interfaces != NULL) { __SCBondInterfaceListCollectMembers(interfaces, excluded); CFRelease(interfaces); } +#endif // !TARGET_OS_IPHONE // exclude Bridge [member] interfaces interfaces = SCBridgeInterfaceCopyAll(prefs); diff --git a/SystemConfiguration.fproj/SCNetworkSignature.c b/SystemConfiguration.fproj/SCNetworkSignature.c index d0296ae..2be8e9b 100644 --- a/SystemConfiguration.fproj/SCNetworkSignature.c +++ b/SystemConfiguration.fproj/SCNetworkSignature.c @@ -49,46 +49,82 @@ const char * kSCNetworkSignatureActiveChangedNotifyName = NETWORK_ID_KEY ".active"; +#pragma mark SCNetworkSignature Supporting APIs -#pragma mark SCNetworkSignature support routines +static CFStringRef +create_global_state_v4_key(void) +{ + return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, + kSCDynamicStoreDomainState, + kSCEntNetIPv4); + +} + +static CFStringRef +create_global_setup_v4_key(void) +{ + return SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, + kSCDynamicStoreDomainSetup, + kSCEntNetIPv4); +} -static __inline__ SCDynamicStoreRef -store_create(CFAllocatorRef alloc) +static CFStringRef +create_ipv4_services_pattern(void) { - return (SCDynamicStoreCreate(alloc, CFSTR("SCNetworkSignature"), - NULL, NULL)); + return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainState, + kSCCompAnyRegex, + kSCEntNetIPv4); +} + +static CFStringRef +create_ipv6_services_pattern(void) +{ + return SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainState, + kSCCompAnyRegex, + kSCEntNetIPv6); } static CFDictionaryRef -store_copy_id_dict(CFAllocatorRef alloc, SCDynamicStoreRef store) +copy_services_for_address_family(CFAllocatorRef alloc, + int af) { - CFDictionaryRef id_dict = NULL; - Boolean release_store = FALSE; + CFDictionaryRef info; + CFArrayRef patterns; + CFStringRef pattern; + CFStringRef prop; + + prop = (af == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6; + pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainState, + kSCCompAnyRegex, + prop); + patterns = CFArrayCreate(NULL, + (const void * *)&pattern, 1, + &kCFTypeArrayCallBacks); + CFRelease(pattern); + info = SCDynamicStoreCopyMultiple(NULL, NULL, patterns); + CFRelease(patterns); + + return (info); +} - if (store == NULL) { - store = store_create(alloc); - if (store == NULL) { - goto done; - } - release_store = TRUE; - } - id_dict = SCDynamicStoreCopyValue(store, - kSCNetworkIdentificationStoreKey); - if (isA_CFDictionary(id_dict) == NULL) { - if (id_dict != NULL) { - CFRelease(id_dict); - id_dict = NULL; - } - goto done; - } - done: - if (release_store) { - CFRelease(store); + +static CF_RETURNS_RETAINED CFStringRef +my_IPAddressToCFString(int af, const void * src_p) +{ + char ntopbuf[INET6_ADDRSTRLEN]; + + if (inet_ntop(af, src_p, ntopbuf, sizeof(ntopbuf)) != NULL) { + return (CFStringCreateWithCString(NULL, ntopbuf, + kCFStringEncodingASCII)); } - return (id_dict); + return (NULL); } -#pragma - +#pragma mark - + #pragma mark SCNetworkSignature APIs @@ -96,35 +132,100 @@ CFStringRef SCNetworkSignatureCopyActiveIdentifierForAddress(CFAllocatorRef alloc, const struct sockaddr * addr) { - CFDictionaryRef id_dict = NULL; - CFStringRef ident = NULL; + CFStringRef ident = NULL; + CFDictionaryRef info = NULL; + CFStringRef global_state_v4_key = NULL; + CFDictionaryRef global_v4_state_dict = NULL; + CFArrayRef keys = NULL; + CFArrayRef patterns = NULL; + in_addr_t s_addr; + CFStringRef service = NULL; + CFDictionaryRef service_dict = NULL; + CFStringRef service_id = NULL; struct sockaddr_in * sin_p; - + CFStringRef v4_service_pattern = NULL; /* only accept 0.0.0.0 (i.e. default) for now */ - sin_p = (struct sockaddr_in *)addr; if (addr == NULL || addr->sa_family != AF_INET - || addr->sa_len != sizeof(struct sockaddr_in) - || sin_p->sin_addr.s_addr != 0) { + || addr->sa_len != sizeof(struct sockaddr_in)){ _SCErrorSet(kSCStatusInvalidArgument); goto done; } - id_dict = store_copy_id_dict(alloc, NULL); - if (id_dict == NULL) { - _SCErrorSet(kSCStatusFailed); + + /* ALIGN: force alignment */ + sin_p = (struct sockaddr_in *)(void *)addr; + bcopy(&sin_p->sin_addr.s_addr, &s_addr, sizeof(s_addr)); + if (s_addr != 0) { + _SCErrorSet(kSCStatusInvalidArgument); goto done; } - ident = CFDictionaryGetValue(id_dict, kStoreKeyPrimaryIPv4Identifier); - if (isA_CFString(ident) != NULL) { - CFRetain(ident); + + global_state_v4_key = create_global_state_v4_key(); + keys = CFArrayCreate(NULL, (const void * *)&global_state_v4_key, + 1, &kCFTypeArrayCallBacks); + + v4_service_pattern = create_ipv4_services_pattern(); + patterns = CFArrayCreate(NULL, (const void * *)&v4_service_pattern, 1, + &kCFTypeArrayCallBacks); + + info = SCDynamicStoreCopyMultiple(NULL, keys, patterns); + + if (info == NULL + || CFDictionaryGetCount(info) == 0) { + goto done; } - else { + + global_v4_state_dict = CFDictionaryGetValue(info, global_state_v4_key); + + if (isA_CFDictionary(global_v4_state_dict) == NULL) { + goto done; + } + + service_id = CFDictionaryGetValue(global_v4_state_dict, + kSCDynamicStorePropNetPrimaryService); + + if (isA_CFString(service_id) == NULL) { + goto done; + } + + service = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainState, + service_id, kSCEntNetIPv4); + + service_dict = CFDictionaryGetValue(info, service); + + + if (isA_CFDictionary(service_dict) == NULL + || CFDictionaryGetCount(service_dict) == 0) { + goto done; + } + + ident = CFDictionaryGetValue(service_dict, kStoreKeyNetworkSignature); + ident = isA_CFString(ident); +done: + if (ident != NULL) { + CFRetain(ident); + } else { _SCErrorSet(kSCStatusFailed); } - done: - if (id_dict != NULL) { - CFRelease(id_dict); + if (info != NULL) { + CFRelease(info); + } + if (global_state_v4_key != NULL) { + CFRelease(global_state_v4_key); + } + if (service != NULL) { + CFRelease(service); + } + if (keys != NULL) { + CFRelease(keys); + } + if (patterns != NULL) { + CFRelease(patterns); + } + if (v4_service_pattern != NULL) { + CFRelease(v4_service_pattern); } return (ident); } @@ -132,36 +233,157 @@ SCNetworkSignatureCopyActiveIdentifierForAddress(CFAllocatorRef alloc, CFArrayRef /* of CFStringRef's */ SCNetworkSignatureCopyActiveIdentifiers(CFAllocatorRef alloc) { - CFArrayRef active = NULL; - int i; + CFMutableArrayRef active = NULL; int count = 0; - CFDictionaryRef id_dict = NULL; + CFStringRef global_setup_v4_key = NULL; + CFDictionaryRef global_v4_dict; + int i; + CFDictionaryRef info = NULL; + CFArrayRef keys = NULL; + CFMutableArrayRef patterns = NULL; + CFRange range; + CFMutableDictionaryRef services_dict = NULL; + CFArrayRef service_order; + CFStringRef v4_service_pattern = NULL; + CFStringRef v6_service_pattern = NULL; + const void * * values = NULL; +#define KEYS_STATIC_COUNT 10 + const void * values_static[KEYS_STATIC_COUNT]; - id_dict = store_copy_id_dict(alloc, NULL); - if (id_dict == NULL) { + patterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + global_setup_v4_key = create_global_setup_v4_key(); + keys = CFArrayCreate(NULL, (const void * *)&global_setup_v4_key, 1, + &kCFTypeArrayCallBacks); + + v4_service_pattern = create_ipv4_services_pattern(); + CFArrayAppendValue(patterns, v4_service_pattern); + + v6_service_pattern = create_ipv6_services_pattern(); + CFArrayAppendValue(patterns, v6_service_pattern); + + info = SCDynamicStoreCopyMultiple(NULL, keys, patterns); + + if (info == NULL + || CFDictionaryGetCount(info) == 0) { goto done; } - active = CFDictionaryGetValue(id_dict, kStoreKeyActiveIdentifiers); - if (isA_CFArray(active) != NULL) { - count = CFArrayGetCount(active); + + services_dict = CFDictionaryCreateMutableCopy(NULL, 0, info); + /* + * The service_dict should only contain services and once each + * service has been visited, it will be removed from the dictionary. + */ + CFDictionaryRemoveValue(services_dict, global_setup_v4_key); + + global_v4_dict = CFDictionaryGetValue(info, global_setup_v4_key); + + if (isA_CFDictionary(global_v4_dict) == NULL) { + service_order = CFDictionaryGetValue(global_v4_dict, + kSCPropNetServiceOrder); + if (isA_CFArray(service_order) != NULL) { + count = CFArrayGetCount(service_order); + } } - if (count == 0) { - active = NULL; - goto done; + + active = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + range = CFRangeMake(0, 0); + + for (i = 0; i < count ; i++) { + int j; + CFStringRef network_sig; + CFStringRef service; + CFStringRef service_id; + CFDictionaryRef service_info; + CFStringRef afs[2] = {kSCEntNetIPv4, kSCEntNetIPv6}; + + service_id = CFArrayGetValueAtIndex(service_order, i); + + if (isA_CFString(service_id) == NULL) { + continue; + } + + for (j = 0; j < 2; j++) { + service = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, + kSCDynamicStoreDomainState, + service_id, afs[j]); + + service_info = CFDictionaryGetValue(services_dict, service); + + /* Does this service have a signature? */ + if (isA_CFDictionary(service_info) != NULL) { + network_sig = CFDictionaryGetValue(service_info, kStoreKeyNetworkSignature); + if (isA_CFString(network_sig) != NULL + && CFArrayContainsValue(active, range, network_sig) == FALSE) { + CFArrayAppendValue(active, network_sig); + network_sig = NULL; + range.length++; + } + CFDictionaryRemoveValue(services_dict, service); + } + CFRelease(service); + } } - for (i = 0; i < count; i++) { - CFStringRef ident = CFArrayGetValueAtIndex(active, i); - if (isA_CFString(ident) == NULL) { - active = NULL; - goto done; + count = CFDictionaryGetCount(services_dict); + + if (count != 0) { + if (count > KEYS_STATIC_COUNT) { + values = (const void * *)malloc(sizeof(*values) * count); + } else { + values = values_static; } + CFDictionaryGetKeysAndValues(services_dict, NULL, + (const void * *)values); } - CFRetain(active); + + for (i = 0; i < count; i++) { + CFStringRef network_sig; + CFDictionaryRef service_dict = (CFDictionaryRef)values[i]; + if (isA_CFDictionary(service_dict) == NULL) { + continue; + } + + network_sig = CFDictionaryGetValue(service_dict, + kStoreKeyNetworkSignature); + /* Does this service have a signature? */ + if (isA_CFString(network_sig) != NULL + && CFArrayContainsValue(active, range, network_sig) == FALSE) { + CFArrayAppendValue(active, network_sig); + range.length++; + network_sig = NULL; + } + } done: - if (id_dict != NULL) { - CFRelease(id_dict); + if (info != NULL) { + CFRelease(info); + } + if (services_dict != NULL) { + CFRelease(services_dict); + } + if (global_setup_v4_key != NULL) { + CFRelease(global_setup_v4_key); + } + if (v4_service_pattern != NULL) { + CFRelease(v4_service_pattern); + } + if (v6_service_pattern != NULL) { + CFRelease(v6_service_pattern); + } + if (values != NULL && values != values_static) { + free(values); + } + if (keys != NULL) { + CFRelease(keys); + } + if (patterns != NULL) { + CFRelease(patterns); + } + if (active != NULL && CFArrayGetCount(active) == 0) { + CFRelease(active); + active = NULL; } if (active == NULL) { _SCErrorSet(kSCStatusFailed); @@ -169,51 +391,6 @@ SCNetworkSignatureCopyActiveIdentifiers(CFAllocatorRef alloc) return (active); } -static CFDictionaryRef -copy_services_for_address_family(CFAllocatorRef alloc, - SCDynamicStoreRef store, int af) -{ - CFDictionaryRef info; - CFArrayRef patterns; - CFStringRef pattern; - CFStringRef prop; - Boolean release_store = FALSE; - - if (store == NULL) { - store = store_create(alloc); - if (store == NULL) { - return (NULL); - } - release_store = TRUE; - } - prop = (af == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6; - pattern = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, - kSCDynamicStoreDomainState, - kSCCompAnyRegex, - prop); - patterns = CFArrayCreate(NULL, - (const void * *)&pattern, 1, - &kCFTypeArrayCallBacks); - CFRelease(pattern); - info = SCDynamicStoreCopyMultiple(store, NULL, patterns); - CFRelease(patterns); - if (release_store) { - CFRelease(store); - } - return (info); -} - -static CFStringRef -my_IPAddressToCFString(int af, const void * src_p) -{ - char ntopbuf[INET6_ADDRSTRLEN]; - - if (inet_ntop(af, src_p, ntopbuf, sizeof(ntopbuf)) != NULL) { - return (CFStringCreateWithCString(NULL, ntopbuf, - kCFStringEncodingASCII)); - } - return (NULL); -} CFStringRef SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc, @@ -226,7 +403,7 @@ SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc, const void * * keys = NULL; #define KEYS_STATIC_COUNT 10 const void * keys_static[KEYS_STATIC_COUNT]; - static const void * local_ip_p; + const void * local_ip_p; CFStringRef local_ip_str = NULL; CFStringRef ret_signature = NULL; CFDictionaryRef service_info = NULL; @@ -258,7 +435,7 @@ SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc, } /* find a service matching the local IP and get its network signature */ - service_info = copy_services_for_address_family(alloc, NULL, af); + service_info = copy_services_for_address_family(alloc, af); if (service_info == NULL) { goto done; } diff --git a/SystemConfiguration.fproj/SCNetworkSignature.h b/SystemConfiguration.fproj/SCNetworkSignature.h index 41bd0d7..10926a6 100644 --- a/SystemConfiguration.fproj/SCNetworkSignature.h +++ b/SystemConfiguration.fproj/SCNetworkSignature.h @@ -25,10 +25,13 @@ #define _SCNETWORKSIGNATURE_H #include +#include #include #include #include +__BEGIN_DECLS + /*! @header SCNetworkSignature @discussion The SCNetworkSignature API provides access to the @@ -98,4 +101,7 @@ SCNetworkSignatureCopyActiveIdentifierForAddress(CFAllocatorRef alloc, CFStringRef SCNetworkSignatureCopyIdentifierForConnectedSocket(CFAllocatorRef alloc, int sock_fd) __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0/*SPI*/); + +__END_DECLS + #endif /* _SCNETWORKSIGNATURE_H */ diff --git a/SystemConfiguration.fproj/SCP.c b/SystemConfiguration.fproj/SCP.c index fc79654..344b420 100644 --- a/SystemConfiguration.fproj/SCP.c +++ b/SystemConfiguration.fproj/SCP.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003-2005, 2007-2009 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003-2005, 2007-2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -41,7 +41,7 @@ #include #include -__private_extern__ CFDataRef +__private_extern__ CF_RETURNS_RETAINED CFDataRef __SCPSignatureFromStatbuf(const struct stat *statBuf) { CFMutableDataRef signature; @@ -49,7 +49,10 @@ __SCPSignatureFromStatbuf(const struct stat *statBuf) signature = CFDataCreateMutable(NULL, sizeof(SCPSignatureData)); CFDataSetLength(signature, sizeof(SCPSignatureData)); - sig = (SCPSignatureDataRef)CFDataGetBytePtr(signature); + + /* ALIGN: CFDataGetBytePtr aligns to at least 8 bytes */ + sig = (SCPSignatureDataRef)(void *)CFDataGetBytePtr(signature); + sig->st_dev = statBuf->st_dev; sig->st_ino = statBuf->st_ino; sig->tv_sec = statBuf->st_mtimespec.tv_sec; @@ -126,7 +129,7 @@ SCPreferencesGetSignature(SCPreferencesRef prefs) } -__private_extern__ CFStringRef +__private_extern__ CF_RETURNS_RETAINED CFStringRef _SCPNotificationKey(CFAllocatorRef allocator, CFStringRef prefsID, int keyType) diff --git a/SystemConfiguration.fproj/SCPOpen.c b/SystemConfiguration.fproj/SCPOpen.c index b6fa454..7558a9e 100644 --- a/SystemConfiguration.fproj/SCPOpen.c +++ b/SystemConfiguration.fproj/SCPOpen.c @@ -47,12 +47,14 @@ #include "dy_framework.h" #include -#include #include #include #include +const AuthorizationRef kSCPreferencesUseEntitlementAuthorization = (AuthorizationRef)CFSTR("UseEntitlement"); + + static __inline__ CFTypeRef isA_SCPreferences(CFTypeRef obj) { @@ -218,7 +220,6 @@ __SCPreferencesCreate_helper(SCPreferencesRef prefs) { CFDataRef data = NULL; CFMutableDictionaryRef info; - char name[64] = "???"; CFNumberRef num; Boolean ok; SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs; @@ -258,8 +259,7 @@ __SCPreferencesCreate_helper(SCPreferencesRef prefs) CFRelease(num); // save process name - (void) proc_name(getpid(), name, sizeof(name)); - str = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8); + str = CFStringCreateWithCString(NULL, getprogname(), kCFStringEncodingUTF8); CFDictionarySetValue(info, CFSTR("PROC_NAME"), str); CFRelease(str); @@ -542,7 +542,7 @@ __SCPreferencesAccess(SCPreferencesRef prefs) if (statBuf.st_size > 0) { CFDictionaryRef dict; - CFErrorRef error; + CFErrorRef error = NULL; CFMutableDataRef xmlData; /* @@ -631,9 +631,13 @@ SCPreferencesCreateWithAuthorization(CFAllocatorRef allocator, { SCPreferencesRef prefs; -#if TARGET_OS_IPHONE - authorization = (AuthorizationRef)1; -#endif // TARGET_OS_IPHONE +#if !TARGET_OS_IPHONE + if (authorization == NULL) { + authorization = kSCPreferencesUseEntitlementAuthorization; + } +#else // !TARGET_OS_IPHONE + authorization = kSCPreferencesUseEntitlementAuthorization; +#endif // !TARGET_OS_IPHONE prefs = SCPreferencesCreateWithOptions(allocator, name, prefsID, authorization, NULL); return prefs; @@ -658,21 +662,35 @@ SCPreferencesCreateWithOptions(CFAllocatorRef allocator, } if (authorization != NULL) { + CFMutableDictionaryRef authorizationDict; + CFBundleRef bundle; + CFStringRef bundleID = NULL; + + authorizationDict = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); #if !TARGET_OS_IPHONE - AuthorizationExternalForm extForm; - OSStatus os_status; + if (authorization != kSCPreferencesUseEntitlementAuthorization) { + CFDataRef authorizationRefData; + AuthorizationExternalForm extForm; + OSStatus os_status; + + os_status = AuthorizationMakeExternalForm(authorization, &extForm); + if (os_status != errAuthorizationSuccess) { + SCLog(TRUE, LOG_INFO, CFSTR("_SCHelperOpen AuthorizationMakeExternalForm() failed")); + _SCErrorSet(kSCStatusInvalidArgument); + CFRelease(authorizationDict); + return NULL; + } - os_status = AuthorizationMakeExternalForm(authorization, &extForm); - if (os_status != errAuthorizationSuccess) { - SCLog(TRUE, LOG_INFO, CFSTR("_SCHelperOpen AuthorizationMakeExternalForm() failed")); - _SCErrorSet(kSCStatusInvalidArgument); - return NULL; + authorizationRefData = CFDataCreate(NULL, (const UInt8 *)extForm.bytes, sizeof(extForm.bytes)); + CFDictionaryAddValue(authorizationDict, + kSCHelperAuthAuthorization, + authorizationRefData); + CFRelease(authorizationRefData); } - - authorizationData = CFDataCreate(NULL, (const UInt8 *)extForm.bytes, sizeof(extForm.bytes)); -#else // !TARGET_OS_IPHONE - CFBundleRef bundle; - CFStringRef bundleID = NULL; +#endif /* get the application/executable/bundle name */ bundle = CFBundleGetMainBundle(); @@ -700,10 +718,18 @@ SCPreferencesCreateWithOptions(CFAllocatorRef allocator, if (bundleID == NULL) { bundleID = CFStringCreateWithFormat(NULL, NULL, CFSTR("Unknown(%d)"), getpid()); } - - _SCSerializeString(bundleID, &authorizationData, NULL, NULL); + CFDictionaryAddValue(authorizationDict, + kSCHelperAuthCallerInfo, + bundleID); CFRelease(bundleID); -#endif // !TARGET_OS_IPHONE + + if (authorizationDict != NULL) { + _SCSerialize((CFPropertyListRef)authorizationDict, + &authorizationData, + NULL, + NULL); + CFRelease(authorizationDict); + } } prefsPrivate = __SCPreferencesCreate(allocator, name, prefsID, authorizationData, options); diff --git a/SystemConfiguration.fproj/SCPPath.c b/SystemConfiguration.fproj/SCPPath.c index 0794553..bd94742 100644 --- a/SystemConfiguration.fproj/SCPPath.c +++ b/SystemConfiguration.fproj/SCPPath.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2006, 2008 Apple Inc. All rights reserved. + * Copyright (c) 2000-2006, 2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -38,7 +38,7 @@ #define MAXLINKS 8 -static CFMutableArrayRef +static CF_RETURNS_RETAINED CFMutableArrayRef normalizePath(CFStringRef path) { CFMutableArrayRef elements; diff --git a/SystemConfiguration.fproj/SCPreferencesInternal.h b/SystemConfiguration.fproj/SCPreferencesInternal.h index 7d62507..aca0a16 100644 --- a/SystemConfiguration.fproj/SCPreferencesInternal.h +++ b/SystemConfiguration.fproj/SCPreferencesInternal.h @@ -126,6 +126,7 @@ __SCPreferencesAccess (SCPreferencesRef prefs); Boolean __SCPreferencesAddSession (SCPreferencesRef prefs); +CF_RETURNS_RETAINED CFDataRef __SCPSignatureFromStatbuf (const struct stat *statBuf); @@ -134,6 +135,7 @@ __SCPreferencesPath (CFAllocatorRef allocator, CFStringRef prefsID, Boolean useNewPrefs); +CF_RETURNS_RETAINED CFStringRef _SCPNotificationKey (CFAllocatorRef allocator, CFStringRef prefsID, diff --git a/SystemConfiguration.fproj/SCPreferencesPrivate.h b/SystemConfiguration.fproj/SCPreferencesPrivate.h index 95f18f9..2690e17 100644 --- a/SystemConfiguration.fproj/SCPreferencesPrivate.h +++ b/SystemConfiguration.fproj/SCPreferencesPrivate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005, 2007-2009, 2011 Apple Inc. All rights reserved. + * Copyright (c) 2000-2005, 2007-2009, 2011, 2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -37,6 +37,8 @@ #define kSCPreferencesOptionRemoveWhenEmpty CFSTR("remove-when-empty") // CFBooleanRef +#define kSCPreferencesWriteAuthorizationRight "system.services.systemconfiguration.network" + /*! @enum SCPreferencesKeyType @discussion Used with the SCDynamicStoreKeyCreatePreferences() function @@ -56,6 +58,19 @@ typedef int32_t SCPreferencesKeyType; __BEGIN_DECLS +/*! + @const kSCPreferencesUseEntitlementAuthorization + @discussion An authorization value that can be passed to + the SCPreferencesCreateWithAuthorization API (or + the SCPreferencesCreateWithOptions SPI) to indicate + that the entitlements of the current process should + be used for authorization purposes. + + This value can ONLY be used with the SCPreferences + APIs. + */ +extern const AuthorizationRef kSCPreferencesUseEntitlementAuthorization; + /*! @function SCDynamicStoreKeyCreatePreferences @discussion Creates a key that can be used by the SCDynamicStoreSetNotificationKeys() diff --git a/SystemConfiguration.fproj/SCPrivate.h b/SystemConfiguration.fproj/SCPrivate.h index 96d5a39..509c59e 100644 --- a/SystemConfiguration.fproj/SCPrivate.h +++ b/SystemConfiguration.fproj/SCPrivate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Apple Inc. All rights reserved. + * Copyright (c) 2000-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -30,6 +30,7 @@ #include #include #include +#include #include @@ -59,6 +60,14 @@ @header SCPrivate */ + +/* atomic operations */ +#define _SC_ATOMIC_CMPXCHG(p, o, n) __sync_bool_compare_and_swap((p), (o), (n)) +#define _SC_ATOMIC_INC(p) __sync_fetch_and_add((p), 1) // return (n++); +#define _SC_ATOMIC_DEC(p) __sync_sub_and_fetch((p), 1) // return (--n); +#define _SC_ATOMIC_ZERO(p) __sync_fetch_and_and((p), 0) // old_n = n; n = 0; return(old_n); + + /* framework variables */ extern int _sc_debug; /* non-zero if debugging enabled */ extern int _sc_verbose; /* non-zero if verbose logging enabled */ @@ -119,14 +128,35 @@ extern int _sc_log; /* 0 if SC messages should be written to stdout/stderr, */ #define kSCNetworkReachabilityOptionInterface CFSTR("interface") - /*! - @constant kSCNetworkReachabilityOptionConnectionOnDemandByPass + @constant kSCNetworkReachabilityOptionConnectionOnDemandBypass @discussion A CFBoolean that indicates if we should bypass the VPNOnDemand checks for this target. */ -#define kSCNetworkReachabilityOptionConnectionOnDemandByPass CFSTR("ConnectionOnDemandByPass") +#define kSCNetworkReachabilityOptionConnectionOnDemandBypass CFSTR("ConnectionOnDemandBypass") +/*! + @constant kSCNetworkReachabilityOptionResolverBypass + @discussion A CFBoolean that indicates if we should bypass resolving any + node names. Instead, the status of the DNS server configuration + associated with the name will be returned. */ +#define kSCNetworkReachabilityOptionResolverBypass CFSTR("ResolverBypass") + + +/*! + @constant kSCNetworkReachabilityOptionLongLivedQueryBypass + @discussion A CFBoolean that indicates if we should bypass usage of any + long-lived-queries (w/DNSServiceCreateConnection) when resolving + hostnames for this target. + */ +#define kSCNetworkReachabilityOptionLongLivedQueryBypass CFSTR("LongLivedQueryBypass") + +/*! + @constant kSCNetworkReachabilityOptionServerBypass + @discussion A CFBoolean that indicates if we should bypass usage of the + SCNetworkReachability "server" for this target. + */ +#define kSCNetworkReachabilityOptionServerBypass CFSTR("ServerBypass") /*! @group @@ -251,6 +281,7 @@ Boolean _SCUnserializeData (CFDataRef *data, @param dict The CFDictionary with CFPropertyList values. @result The serialized CFDictionary with CFData values */ +CF_RETURNS_RETAINED CFDictionaryRef _SCSerializeMultiple (CFDictionaryRef dict); /*! @@ -261,6 +292,7 @@ CFDictionaryRef _SCSerializeMultiple (CFDictionaryRef dict); @param dict The CFDictionary with CFData values. @result The serialized CFDictionary with CFPropertyList values */ +CF_RETURNS_RETAINED CFDictionaryRef _SCUnserializeMultiple (CFDictionaryRef dict); @@ -299,12 +331,31 @@ void _SC_sockaddr_to_string (const struct sockaddr *address, size_t bufLen); +/*! + * @function _SC_string_to_sockaddr + * @discussion Parses a string into a "struct sockaddr" + * @param str The address string to parse + * @param af Allowed address families (AF_UNSPEC, AF_INET, AF_INET6) + * @param buf A user provided buffer of the specified length; NULL + * if a new buffer should be allocated (and deallocated by the + * caller). + * @param bufLen The size of the user provided buffer. + * @result A pointer to the parsed "struct sockaddr"; NULL if + * the string could not be parsed as an IP[v6] address. + */ +struct sockaddr * +_SC_string_to_sockaddr (const char *str, + sa_family_t af, + void *buf, + size_t bufLen); + /*! * @function _SC_trimDomain * @discussion Trims leading and trailing "."s from a domain or host name * @param domain The domain name to trim * @result The trimmed domain name. */ +CF_RETURNS_RETAINED CFStringRef _SC_trimDomain (CFStringRef domain); @@ -483,6 +534,33 @@ _SC_checkResolverReachabilityByAddress (SCDynamicStoreRef *storeP, Boolean *haveDNS, struct sockaddr *sa); +/*! + @function SCNetworkReachabilityGetInterfaceIndex + @discussion Returns the interface index associated with network interface that will + be used to interact with the target host. + @param target The SCNetworkReachability reference associated with the address or + name to be checked for reachability. + @result Returns the interface index associated with the target. Returning -1 means that + the target is not reachable. + */ +int +SCNetworkReachabilityGetInterfaceIndex (SCNetworkReachabilityRef target); + +#pragma mark - +#pragma mark Domain + +/*! + @function _SC_domainEndsWithDomain + @discussion Checks if one domain is a subset of another + @param compare_domain The domain to be compared. + @param match_domain The domain to be matched. + @return TRUE if the match_domain is contained in the compare_domain. + FLASE otherwise. + */ +Boolean +_SC_domainEndsWithDomain (CFStringRef compare_domain, + CFStringRef match_domain); + #pragma mark - #pragma mark NetBIOS @@ -589,6 +667,39 @@ _SC_isAppleInternal() return (isInternal == 1); } +#define MODEL CFSTR("Model") + +static __inline__ CFStringRef +_SC_hw_model() +{ + /* + * S_model + * Hardware model for this network configuration. + */ + static CFStringRef model = NULL; + + if (model == NULL) { + char hwModel[64]; + int mib[] = { CTL_HW, HW_MODEL }; + size_t n = sizeof(hwModel); + int ret; + + // get HW model name + bzero(&hwModel, sizeof(hwModel)); + ret = sysctl(mib, sizeof(mib) / sizeof(mib[0]), &hwModel, &n, NULL, 0); + if (ret != 0) { + SCLog(TRUE, LOG_ERR, CFSTR("sysctl() CTL_HW/HW_MODEL failed: %s"), strerror(errno)); + return NULL; + } + hwModel[sizeof(hwModel) - 1] = '\0'; + + model = CFStringCreateWithCString(NULL, hwModel, kCFStringEncodingASCII); + } + + return model; + +} + /* * debugging */ diff --git a/SystemConfiguration.fproj/SCProxies.c b/SystemConfiguration.fproj/SCProxies.c index 68fa5e0..b041e3c 100644 --- a/SystemConfiguration.fproj/SCProxies.c +++ b/SystemConfiguration.fproj/SCProxies.c @@ -123,90 +123,73 @@ validate_proxy_content(CFMutableDictionaryRef proxies, } -CFDictionaryRef -SCDynamicStoreCopyProxies(SCDynamicStoreRef store) -{ - CFArrayRef array; - CFStringRef key; - CFMutableDictionaryRef newProxies = NULL; - CFNumberRef num; - CFDictionaryRef proxies; - Boolean tempSession = FALSE; +static void +normalize_scoped_proxy(const void *key, const void *value, void *context); - /* copy proxy information from dynamic store */ - - if (store == NULL) { - store = SCDynamicStoreCreate(NULL, - CFSTR("SCDynamicStoreCopyProxies"), - NULL, - NULL); - if (store == NULL) { - return NULL; - } - tempSession = TRUE; - } - - key = SCDynamicStoreKeyCreateProxies(NULL); - proxies = SCDynamicStoreCopyValue(store, key); - CFRelease(key); +static void +normalize_supplemental_proxy(const void *value, void *context); - validate : - if (proxies != NULL) { - if (isA_CFDictionary(proxies)) { - newProxies = CFDictionaryCreateMutableCopy(NULL, 0, proxies); - } - CFRelease(proxies); - } - - if (newProxies == NULL) { - newProxies = CFDictionaryCreateMutable(NULL, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); +static CF_RETURNS_RETAINED CFDictionaryRef +__SCNetworkProxiesCopyNormalized(CFDictionaryRef proxy) +{ + CFArrayRef array; + CFMutableDictionaryRef newProxy; + CFNumberRef num; + CFDictionaryRef scoped; + CFArrayRef supplemental; + + if (!isA_CFDictionary(proxy)) { + proxy = CFDictionaryCreate(NULL, + NULL, + NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + return proxy; } - /* validate [and augment] proxy content */ + newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy); - validate_proxy_content(newProxies, + validate_proxy_content(newProxy, kSCPropNetProxiesFTPEnable, kSCPropNetProxiesFTPProxy, kSCPropNetProxiesFTPPort, "ftp", 21); - validate_proxy_content(newProxies, + validate_proxy_content(newProxy, kSCPropNetProxiesGopherEnable, kSCPropNetProxiesGopherProxy, kSCPropNetProxiesGopherPort, "gopher", 70); - validate_proxy_content(newProxies, + validate_proxy_content(newProxy, kSCPropNetProxiesHTTPEnable, kSCPropNetProxiesHTTPProxy, kSCPropNetProxiesHTTPPort, "http", 80); - validate_proxy_content(newProxies, + validate_proxy_content(newProxy, kSCPropNetProxiesHTTPSEnable, kSCPropNetProxiesHTTPSProxy, kSCPropNetProxiesHTTPSPort, "https", 443); - validate_proxy_content(newProxies, + validate_proxy_content(newProxy, kSCPropNetProxiesRTSPEnable, kSCPropNetProxiesRTSPProxy, kSCPropNetProxiesRTSPPort, "rtsp", 554); - validate_proxy_content(newProxies, + validate_proxy_content(newProxy, kSCPropNetProxiesSOCKSEnable, kSCPropNetProxiesSOCKSProxy, kSCPropNetProxiesSOCKSPort, "socks", 1080); - if (CFDictionaryContainsKey(newProxies, kSCPropNetProxiesProxyAutoConfigURLString)) { - validate_proxy_content(newProxies, + if (CFDictionaryContainsKey(newProxy, kSCPropNetProxiesProxyAutoConfigURLString)) { + validate_proxy_content(newProxy, kSCPropNetProxiesProxyAutoConfigEnable, kSCPropNetProxiesProxyAutoConfigURLString, NULL, @@ -214,16 +197,16 @@ SCDynamicStoreCopyProxies(SCDynamicStoreRef store) 0); // and we can't have both URLString and JavaScript keys - CFDictionaryRemoveValue(newProxies, kSCPropNetProxiesProxyAutoConfigJavaScript); + CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesProxyAutoConfigJavaScript); } else { - validate_proxy_content(newProxies, + validate_proxy_content(newProxy, kSCPropNetProxiesProxyAutoConfigEnable, kSCPropNetProxiesProxyAutoConfigJavaScript, NULL, NULL, 0); } - validate_proxy_content(newProxies, + validate_proxy_content(newProxy, kSCPropNetProxiesProxyAutoDiscoveryEnable, NULL, NULL, @@ -231,7 +214,7 @@ SCDynamicStoreCopyProxies(SCDynamicStoreRef store) 0); // validate FTP passive setting - num = CFDictionaryGetValue(newProxies, kSCPropNetProxiesFTPPassive); + num = CFDictionaryGetValue(newProxy, kSCPropNetProxiesFTPPassive); if (num != NULL) { int enabled = 0; @@ -240,7 +223,7 @@ SCDynamicStoreCopyProxies(SCDynamicStoreRef store) // if we don't like the enabled key/value enabled = 1; num = CFNumberCreate(NULL, kCFNumberIntType, &enabled); - CFDictionarySetValue(newProxies, + CFDictionarySetValue(newProxy, kSCPropNetProxiesFTPPassive, num); CFRelease(num); @@ -248,7 +231,7 @@ SCDynamicStoreCopyProxies(SCDynamicStoreRef store) } // validate proxy exception list - array = CFDictionaryGetValue(newProxies, kSCPropNetProxiesExceptionsList); + array = CFDictionaryGetValue(newProxy, kSCPropNetProxiesExceptionsList); if (array != NULL) { CFIndex i; CFIndex n; @@ -266,12 +249,12 @@ SCDynamicStoreCopyProxies(SCDynamicStoreRef store) } if (n == 0) { - CFDictionaryRemoveValue(newProxies, kSCPropNetProxiesExceptionsList); + CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesExceptionsList); } } // validate exclude simple hostnames setting - num = CFDictionaryGetValue(newProxies, kSCPropNetProxiesExcludeSimpleHostnames); + num = CFDictionaryGetValue(newProxy, kSCPropNetProxiesExcludeSimpleHostnames); if (num != NULL) { int enabled; @@ -280,18 +263,110 @@ SCDynamicStoreCopyProxies(SCDynamicStoreRef store) // if we don't like the enabled key/value enabled = 0; num = CFNumberCreate(NULL, kCFNumberIntType, &enabled); - CFDictionarySetValue(newProxies, + CFDictionarySetValue(newProxy, kSCPropNetProxiesExcludeSimpleHostnames, num); CFRelease(num); } } + // cleanup scoped proxies + scoped = CFDictionaryGetValue(newProxy, kSCPropNetProxiesScoped); + if (isA_CFDictionary(scoped)) { + CFMutableDictionaryRef newScoped; + + newScoped = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionaryApplyFunction(scoped, + normalize_scoped_proxy, + newScoped); + CFDictionarySetValue(newProxy, kSCPropNetProxiesScoped, newScoped); + CFRelease(newScoped); + } + + // cleanup split/supplemental proxies + supplemental = CFDictionaryGetValue(newProxy, kSCPropNetProxiesSupplemental); + if (isA_CFArray(supplemental)) { + CFMutableArrayRef newSupplemental; + + newSupplemental = CFArrayCreateMutable(NULL, + 0, + &kCFTypeArrayCallBacks); + CFArrayApplyFunction(supplemental, + CFRangeMake(0, CFArrayGetCount(supplemental)), + normalize_supplemental_proxy, + newSupplemental); + CFDictionarySetValue(newProxy, kSCPropNetProxiesSupplemental, newSupplemental); + CFRelease(newSupplemental); + } + + proxy = CFDictionaryCreateCopy(NULL,newProxy); + CFRelease(newProxy); + + return proxy; +} + + +static void +normalize_scoped_proxy(const void *key, const void *value, void *context) +{ + CFStringRef interface = (CFStringRef)key; + CFDictionaryRef proxy = (CFDictionaryRef)value; + CFMutableDictionaryRef newScoped = (CFMutableDictionaryRef)context; + + proxy = __SCNetworkProxiesCopyNormalized(proxy); + CFDictionarySetValue(newScoped, interface, proxy); + CFRelease(proxy); + + return; +} + + +static void +normalize_supplemental_proxy(const void *value, void *context) +{ + CFDictionaryRef proxy = (CFDictionaryRef)value; + CFMutableArrayRef newSupplemental = (CFMutableArrayRef)context; + + proxy = __SCNetworkProxiesCopyNormalized(proxy); + CFArrayAppendValue(newSupplemental, proxy); + CFRelease(proxy); + + return; +} + + +CFDictionaryRef +SCDynamicStoreCopyProxies(SCDynamicStoreRef store) +{ + CFStringRef key; + CFDictionaryRef proxies; + + + /* copy proxy information from dynamic store */ + + key = SCDynamicStoreKeyCreateProxies(NULL); + proxies = SCDynamicStoreCopyValue(store, key); + CFRelease(key); + + + if (proxies != NULL) { + CFDictionaryRef base = proxies; + + proxies = __SCNetworkProxiesCopyNormalized(base); + CFRelease(base); + } else { + proxies = CFDictionaryCreate(NULL, + NULL, + NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } - proxies = CFDictionaryCreateCopy(NULL, newProxies); - CFRelease(newProxies); - if (tempSession) CFRelease(store); return proxies; } @@ -356,7 +431,7 @@ SCNetworkProxiesCopyMatching(CFDictionaryRef globalConfiguration, if (server != NULL) { CFIndex i; CFMutableArrayRef matching = NULL; - CFIndex n; + CFIndex n = 0; CFIndex server_len; CFArrayRef supplemental; @@ -370,18 +445,16 @@ SCNetworkProxiesCopyMatching(CFDictionaryRef globalConfiguration, server_len = CFStringGetLength(server); supplemental = CFDictionaryGetValue(globalConfiguration, kSCPropNetProxiesSupplemental); - if (supplemental == NULL) { - // if no supplemental configurations - goto done; - } + if (supplemental != NULL) { + if (!isA_CFArray(supplemental)) { + // if corrupt proxy configuration + sc_status = kSCStatusFailed; + goto done; + } - if (!isA_CFArray(supplemental)) { - // if corrupt proxy configuration - sc_status = kSCStatusFailed; - goto done; + n = CFArrayGetCount(supplemental); } - n = CFArrayGetCount(supplemental); for (i = 0; i < n; i++) { CFStringRef domain; CFIndex domain_len; diff --git a/SystemConfiguration.fproj/SCSchemaDefinitions.c b/SystemConfiguration.fproj/SCSchemaDefinitions.c index 159a37d..583307d 100644 --- a/SystemConfiguration.fproj/SCSchemaDefinitions.c +++ b/SystemConfiguration.fproj/SCSchemaDefinitions.c @@ -62,6 +62,7 @@ const CFStringRef kSCEntNet6to4 = CFSTR("6to4 const CFStringRef kSCEntNetEAPOL = CFSTR("EAPOL"); +const CFStringRef kSCEntNetLinkQuality = CFSTR("LinkQuality"); const CFStringRef kSCEntNetLoopback = CFSTR("Loopback"); const CFStringRef kSCEntNetOnDemand = CFSTR("OnDemand"); const CFStringRef kSCEntNetService = CFSTR("__SERVICE__"); @@ -187,6 +188,8 @@ const CFStringRef kSCValNetIPv4ConfigMethodFailover = CFSTR("Fail const CFStringRef kSCPropNetIPv4RouteDestinationAddress = CFSTR("DestinationAddress"); const CFStringRef kSCPropNetIPv4RouteSubnetMask = CFSTR("SubnetMask"); const CFStringRef kSCPropNetIPv4RouteGatewayAddress = CFSTR("GatewayAddress"); +const CFStringRef kSCPropNetIPv4ARPResolvedHardwareAddress = CFSTR("ARPResolvedHardwareAddress"); +const CFStringRef kSCPropNetIPv4ARPResolvedIPAddress = CFSTR("ARPResolvedIPAddress"); const CFStringRef kSCPropNetIPv6Addresses = CFSTR("Addresses"); const CFStringRef kSCPropNetIPv6ConfigMethod = CFSTR("ConfigMethod"); const CFStringRef kSCPropNetIPv6DestAddresses = CFSTR("DestAddresses"); @@ -206,6 +209,7 @@ const CFStringRef kSCPropNetIPv6RouteGatewayAddress = CFSTR("Gate const CFStringRef kSCPropNet6to4Relay = CFSTR("Relay"); const CFStringRef kSCPropNetLinkActive = CFSTR("Active"); const CFStringRef kSCPropNetLinkDetaching = CFSTR("Detaching"); +const CFStringRef kSCPropNetLinkQuality = CFSTR("LinkQuality"); const CFStringRef kSCPropNetModemAccessPointName = CFSTR("AccessPointName"); const CFStringRef kSCPropNetModemConnectionPersonality = CFSTR("ConnectionPersonality"); const CFStringRef kSCPropNetModemConnectionScript = CFSTR("ConnectionScript"); diff --git a/SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h b/SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h index f7cebc1..ee3ca28 100644 --- a/SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h +++ b/SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h @@ -35,6 +35,7 @@ * * kSCEntNetCommCenter "com.apple.CommCenter" CFDictionary * kSCEntNetEAPOL "EAPOL" CFDictionary + * kSCEntNetLinkQuality "LinkQuality" CFDictionary * kSCEntNetLoopback "Loopback" CFDictionary * kSCEntNetOnDemand "OnDemand" CFDictionary * kSCEntNetService "__SERVICE__" CFDictionary @@ -91,6 +92,9 @@ * kSCPropNetIPv4RouteSubnetMask "SubnetMask" CFString * kSCPropNetIPv4RouteGatewayAddress "GatewayAddress" CFString * + * kSCPropNetIPv4ARPResolvedHardwareAddress "ARPResolvedHardwareAddress" CFString + * kSCPropNetIPv4ARPResolvedIPAddress "ARPResolvedIPAddress" CFString + * * kSCEntNetIPv6 Entity Keys * * kSCPropNetIPv6ExcludedRoutes "ExcludedRoutes" CFArray[CFDictionary] @@ -101,6 +105,10 @@ * kSCPropNetIPv6RoutePrefixLength "PrefixLength" CFNumber * kSCPropNetIPv6RouteGatewayAddress "GatewayAddress" CFString * + * kSCEntNetLinkQuality Entity Keys + * + * kSCPropNetLinkQuality "LinkQuality" CFNumber + * * kSCEntNetPPP Entity Keys * * --- OnDemand: --- @@ -234,6 +242,12 @@ extern const CFStringRef kSCEntNetCommCenter; */ extern const CFStringRef kSCEntNetEAPOL; +/*! + @const kSCEntNetLinkQuality + @availability Introduced in Mac OS X 10.7. + */ +extern const CFStringRef kSCEntNetLinkQuality; + /*! @const kSCEntNetLoopback @availability Introduced in Mac OS X 10.7. @@ -438,6 +452,18 @@ extern const CFStringRef kSCPropNetIPv4RouteSubnetMask; */ extern const CFStringRef kSCPropNetIPv4RouteGatewayAddress; +/*! + @const kSCPropNetIPv4ARPResolvedHardwareAddress + @availability Introduced in Mac OS X 10.7. + */ +extern const CFStringRef kSCPropNetIPv4ARPResolvedHardwareAddress; + +/*! + @const kSCPropNetIPv4ARPResolvedIPAddress + @availability Introduced in Mac OS X 10.7. + */ +extern const CFStringRef kSCPropNetIPv4ARPResolvedIPAddress; + /*! @group kSCEntNetIPv6 Entity Keys */ @@ -472,6 +498,16 @@ extern const CFStringRef kSCPropNetIPv6RoutePrefixLength; */ extern const CFStringRef kSCPropNetIPv6RouteGatewayAddress; +/*! + @group kSCEntNetLinkQuality Entity Keys + */ + +/*! + @const kSCPropNetLinkQuality + @availability Introduced in Mac OS X 10.7. + */ +extern const CFStringRef kSCPropNetLinkQuality; + /*! @group kSCEntNetPPP Entity Keys */ @@ -863,6 +899,12 @@ extern const CFStringRef kSCPropVirtualNetworkInterfacesVLANOptions; ,"EAPOL" \ ,CFDictionary ) + SC_SCHEMA_DECLARATION(kSCEntNetLinkQuality, __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0/*SPI*/)) + #define kSCEntNetLinkQuality \ + SC_SCHEMA_KV(kSCEntNetLinkQuality \ + ,"LinkQuality" \ + ,CFDictionary ) + SC_SCHEMA_DECLARATION(kSCEntNetLoopback, __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0/*SPI*/)) #define kSCEntNetLoopback \ SC_SCHEMA_KV(kSCEntNetLoopback \ @@ -1032,6 +1074,18 @@ extern const CFStringRef kSCPropVirtualNetworkInterfacesVLANOptions; ,"GatewayAddress" \ ,CFString ) + SC_SCHEMA_DECLARATION(kSCPropNetIPv4ARPResolvedHardwareAddress, __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0/*SPI*/)) + #define kSCPropNetIPv4ARPResolvedHardwareAddress \ + SC_SCHEMA_KV(kSCPropNetIPv4ARPResolvedHardwareAddress \ + ,"ARPResolvedHardwareAddress" \ + ,CFString ) + + SC_SCHEMA_DECLARATION(kSCPropNetIPv4ARPResolvedIPAddress, __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0/*SPI*/)) + #define kSCPropNetIPv4ARPResolvedIPAddress \ + SC_SCHEMA_KV(kSCPropNetIPv4ARPResolvedIPAddress \ + ,"ARPResolvedIPAddress" \ + ,CFString ) + SC_SCHEMA_DECLARATION(kSCPropNetIPv6ExcludedRoutes, __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_4_0/*SPI*/)) #define kSCPropNetIPv6ExcludedRoutes \ SC_SCHEMA_KV(kSCPropNetIPv6ExcludedRoutes \ @@ -1062,6 +1116,12 @@ extern const CFStringRef kSCPropVirtualNetworkInterfacesVLANOptions; ,"GatewayAddress" \ ,CFString ) + SC_SCHEMA_DECLARATION(kSCPropNetLinkQuality, __OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0/*SPI*/)) + #define kSCPropNetLinkQuality \ + SC_SCHEMA_KV(kSCPropNetLinkQuality \ + ,"LinkQuality" \ + ,CFNumber ) + SC_SCHEMA_DECLARATION(kSCPropNetPPPOnDemandDomains, __OSX_AVAILABLE_STARTING(__MAC_10_5,__IPHONE_2_0/*SPI*/)) #define kSCPropNetPPPOnDemandDomains \ SC_SCHEMA_KV(kSCPropNetPPPOnDemandDomains \ diff --git a/SystemConfiguration.fproj/VLANConfiguration.c b/SystemConfiguration.fproj/VLANConfiguration.c index 0323b94..a73c910 100644 --- a/SystemConfiguration.fproj/VLANConfiguration.c +++ b/SystemConfiguration.fproj/VLANConfiguration.c @@ -378,11 +378,13 @@ SCVLANInterfaceCopyAvailablePhysicalInterfaces() prefs = SCPreferencesCreate(NULL, CFSTR("SCVLANInterfaceCopyAvailablePhysicalInterfaces"), NULL); if (prefs != NULL) { +#if !TARGET_OS_IPHONE bond_interfaces = SCBondInterfaceCopyAll(prefs); if (bond_interfaces != NULL) { excluded = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); __SCBondInterfaceListCollectMembers(bond_interfaces, excluded); } +#endif // !TARGET_OS_IPHONE bridge_interfaces = SCBridgeInterfaceCopyAll(prefs); if (bridge_interfaces != NULL) { diff --git a/SystemConfiguration.fproj/config.defs b/SystemConfiguration.fproj/config.defs index 4b09c0a..a6665c3 100644 --- a/SystemConfiguration.fproj/config.defs +++ b/SystemConfiguration.fproj/config.defs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003-2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003-2005, 2011, 2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -71,14 +71,9 @@ routine configopen ( server : mach_port_t; out status : int; ServerAuditToken audit_token : audit_token_t); -routine configclose ( server : mach_port_t; - out status : int); - -routine configlock ( server : mach_port_t; - out status : int); - -routine configunlock ( server : mach_port_t; - out status : int); + skip; /* was configclose */ + skip; /* was configlock */ + skip; /* was configunlock */ skip; /* reserved for future use */ skip; /* reserved for future use */ @@ -93,34 +88,37 @@ routine configlist ( server : mach_port_t; xmlData : xmlData; isRegex : int; out list : xmlDataOut, dealloc; - out status : int); + out status : int; + ServerAuditToken audit_token : audit_token_t); routine configadd ( server : mach_port_t; key : xmlData; data : xmlData; out newInstance : int; - out status : int); + out status : int; + ServerAuditToken audit_token : audit_token_t); routine configget ( server : mach_port_t; key : xmlData; out data : xmlDataOut, dealloc; out newInstance : int; - out status : int); + out status : int; + ServerAuditToken audit_token : audit_token_t); routine configset ( server : mach_port_t; key : xmlData; data : xmlData; instance : int; out newInstance : int; - out status : int); + out status : int; + ServerAuditToken audit_token : audit_token_t); routine configremove ( server : mach_port_t; key : xmlData; - out status : int); + out status : int; + ServerAuditToken audit_token : audit_token_t); -routine configtouch ( server : mach_port_t; - key : xmlData; - out status : int); + skip; /* was configtouch */ routine configadd_s ( server : mach_port_t; key : xmlData; @@ -130,19 +128,22 @@ routine configadd_s ( server : mach_port_t; routine confignotify ( server : mach_port_t; key : xmlData; - out status : int); + out status : int; + ServerAuditToken audit_token : audit_token_t); routine configget_m ( server : mach_port_t; keys : xmlData; patterns : xmlData; out data : xmlDataOut, dealloc; - out status : int); + out status : int; + ServerAuditToken audit_token : audit_token_t); routine configset_m ( server : mach_port_t; data : xmlData; remove : xmlData; notify : xmlData; - out status : int); + out status : int; + ServerAuditToken audit_token : audit_token_t); /* * Notification API's @@ -194,4 +195,5 @@ routine notifyset ( server : mach_port_t; */ routine snapshot ( server : mach_port_t; - out status : int); + out status : int; + ServerAuditToken audit_token : audit_token_t); diff --git a/SystemConfiguration.fproj/dy_framework.c b/SystemConfiguration.fproj/dy_framework.c index e69f9ab..4cb153a 100644 --- a/SystemConfiguration.fproj/dy_framework.c +++ b/SystemConfiguration.fproj/dy_framework.c @@ -45,7 +45,7 @@ static void * __loadIOKit(void) { static void *image = NULL; if (NULL == image) { - const char *framework = "/System/Library/Frameworks/IOKit.framework/Versions/A/IOKit"; + const char *framework = "/System/Library/Frameworks/IOKit.framework/IOKit"; struct stat statbuf; const char *suffix = getenv("DYLD_IMAGE_SUFFIX"); char path[MAXPATHLEN]; @@ -276,11 +276,7 @@ static void * __loadSecurity(void) { static void *image = NULL; if (NULL == image) { -#if TARGET_OS_IPHONE const char *framework = "/System/Library/Frameworks/Security.framework/Security"; -#else - const char *framework = "/System/Library/Frameworks/Security.framework/Versions/A/Security"; -#endif struct stat statbuf; const char *suffix = getenv("DYLD_IMAGE_SUFFIX"); char path[MAXPATHLEN]; @@ -296,8 +292,6 @@ __loadSecurity(void) { return (void *)image; } -#if !TARGET_OS_IPHONE - #define SECURITY_FRAMEWORK_EXTERN(t, s) \ __private_extern__ t \ _ ## s() \ @@ -310,6 +304,7 @@ __loadSecurity(void) { return (dysym != NULL) ? *dysym : NULL; \ } +#if !TARGET_OS_IPHONE SECURITY_FRAMEWORK_EXTERN(CFTypeRef, kSecAttrService) SECURITY_FRAMEWORK_EXTERN(CFTypeRef, kSecClass) SECURITY_FRAMEWORK_EXTERN(CFTypeRef, kSecClassGenericPassword) @@ -513,7 +508,24 @@ _SecTrustedApplicationCreateFromPath(const char *path, SecTrustedApplicationRef return dyfunc ? dyfunc(path, app) : -1; } -#endif // !TARGET_OS_IPHONE +#else // TARGET_OS_IPHONE + +SECURITY_FRAMEWORK_EXTERN(CFStringRef, kSecPropertyKeyValue) +SECURITY_FRAMEWORK_EXTERN(CFStringRef, kSecPropertyKeyLabel) + +__private_extern__ CFArrayRef +_SecCertificateCopyProperties(SecCertificateRef certRef) +{ + #undef SecCertificateCopyProperties + static typeof (SecCertificateCopyProperties) *dyfunc = NULL; + if (!dyfunc) { + void *image = __loadSecurity(); + if (image) dyfunc = dlsym(image, "SecCertificateCopyProperties"); + } + return dyfunc ? dyfunc(certRef) : NULL; +} + +#endif // TARGET_OS_IPHONE __private_extern__ SecCertificateRef _SecCertificateCreateWithData(CFAllocatorRef allocator, CFDataRef data) diff --git a/SystemConfiguration.fproj/dy_framework.h b/SystemConfiguration.fproj/dy_framework.h index 6a4359f..09d4f11 100644 --- a/SystemConfiguration.fproj/dy_framework.h +++ b/SystemConfiguration.fproj/dy_framework.h @@ -32,6 +32,7 @@ #include #include #include +#include #include // only needed for Mac OS X 10.6[.x] __BEGIN_DECLS @@ -144,7 +145,7 @@ _IORegistryEntrySearchCFProperty ( CFStringRef key, CFAllocatorRef allocator, IOOptionBits options - ); + ) CF_RETURNS_RETAINED; #define IORegistryEntrySearchCFProperty _IORegistryEntrySearchCFProperty kern_return_t @@ -232,34 +233,34 @@ _SecItemCopyMatching ( OSStatus _SecKeychainCopyDomainDefault ( - SecPreferencesDomain domain, - SecKeychainRef *keychain + SecPreferencesDomain domain, + SecKeychainRef *keychain ); #define SecKeychainCopyDomainDefault _SecKeychainCopyDomainDefault OSStatus _SecKeychainGetPreferenceDomain ( - SecPreferencesDomain *domain + SecPreferencesDomain *domain ); #define SecKeychainGetPreferenceDomain _SecKeychainGetPreferenceDomain OSStatus _SecKeychainOpen ( - const char *pathName, - SecKeychainRef *keychain + const char *pathName, + SecKeychainRef *keychain ); #define SecKeychainOpen _SecKeychainOpen OSStatus _SecKeychainSetDomainDefault ( - SecPreferencesDomain domain, - SecKeychainRef keychain + SecPreferencesDomain domain, + SecKeychainRef keychain ); #define SecKeychainSetDomainDefault _SecKeychainSetDomainDefault OSStatus _SecKeychainSetPreferenceDomain ( - SecPreferencesDomain domain + SecPreferencesDomain domain ); #define SecKeychainSetPreferenceDomain _SecKeychainSetPreferenceDomain @@ -315,13 +316,27 @@ _SecTrustedApplicationCreateFromPath ( ); #define SecTrustedApplicationCreateFromPath _SecTrustedApplicationCreateFromPath -#endif // !TARGET_OS_IPHONE +#else // TARGET_OS_IPHONE + +CFStringRef _kSecPropertyKeyValue(); +#define kSecPropertyKeyValue _kSecPropertyKeyValue() + +CFStringRef _kSecPropertyKeyLabel(); +#define kSecPropertyKeyLabel _kSecPropertyKeyLabel() + +CFArrayRef +_SecCertificateCopyProperties ( + SecCertificateRef certRef + ); +#define SecCertificateCopyProperties _SecCertificateCopyProperties + +#endif // TARGET_OS_IPHONE SecCertificateRef -_SecCertificateCreateWithData( - CFAllocatorRef allocator, - CFDataRef data - ); +_SecCertificateCreateWithData ( + CFAllocatorRef allocator, + CFDataRef data + ); #define SecCertificateCreateWithData _SecCertificateCreateWithData __END_DECLS diff --git a/SystemConfiguration.fproj/genSCPreferences.c b/SystemConfiguration.fproj/genSCPreferences.c index ec98374..5cff797 100644 --- a/SystemConfiguration.fproj/genSCPreferences.c +++ b/SystemConfiguration.fproj/genSCPreferences.c @@ -146,6 +146,7 @@ typedef enum { #define CFNUMBER_BOOL "CFNumber (0 or 1)" #define CFSTRING "CFString" +#define ARP "ARP" #define ACCESSPOINTNAME "AccessPointName" #define ACSP "ACSP" // Apple Client Server Protocol #define ACTIVE "Active" @@ -274,6 +275,7 @@ typedef enum { #define LCP "LCP" #define LINK "Link" #define LINKLOCAL "LinkLocal" +#define LINKQUALITY "LinkQuality" #define LOCALCERTIFICATE "LocalCertificate" #define LOCALHOSTNAME "LocalHostName" #define LOCALIDENTIFIER "LocalIdentifier" @@ -348,6 +350,7 @@ typedef enum { #define REMINDER "Reminder" #define REMINDERTIME "ReminderTime" #define REMOTEADDRESS "RemoteAddress" +#define RESOLVED "Resolved" #define RETRYCONNECTTIME "RetryConnectTime" #define ROOTSEPARATOR "RootSeparator" #define ROUTE "Route" @@ -503,6 +506,7 @@ static schemaDefinition names[] = { { GROUP_PRIVATE, NETENT, "Network Entity Keys", NULL, NULL }, { SC_10_5_PRIVATE, NETENT, EAPOL, NULL, CFDICTIONARY }, + { SC_10_7_IPHONE_5_0_PRIVATE, NETENT, LINKQUALITY, NULL, CFDICTIONARY}, { SC_10_7_IPHONE_4_0_PRIVATE, NETENT, LOOPBACK, NULL, CFDICTIONARY }, { SC_10_6_IPHONE_3_0_PRIVATE, NETENT, ONDEMAND, NULL, CFDICTIONARY }, { SC_10_6_IPHONE_2_0_PRIVATE, NETENT, SERVICE, "__SERVICE__", CFDICTIONARY }, @@ -718,6 +722,9 @@ static schemaDefinition names[] = { { SC_10_7_IPHONE_4_0_PRIVATE, NETPROP IPV4 ROUTE, SUBNETMASK, NULL, CFSTRING }, { SC_10_7_IPHONE_4_0_PRIVATE, NETPROP IPV4 ROUTE, GATEWAY ADDRESS, NULL, CFSTRING }, { COMMENT_PRIVATE, "", NULL, NULL, NULL }, + { SC_10_7_IPHONE_5_0_PRIVATE, NETPROP IPV4, ARP RESOLVED HARDWARE ADDRESS, NULL, CFSTRING }, + { SC_10_7_IPHONE_5_0_PRIVATE, NETPROP IPV4, ARP RESOLVED IP ADDRESS, NULL, CFSTRING }, + { COMMENT_PRIVATE, "", NULL, NULL, NULL }, { GROUP, NETPROP IPV6, KEY_PREFIX NETENT IPV6 " Entity Keys", NULL, NULL }, @@ -758,6 +765,11 @@ static schemaDefinition names[] = { { SC_10_2, NETPROP LINK, DETACHING, NULL, CFBOOLEAN }, { COMMENT, "", NULL, NULL, NULL }, + { GROUP_PRIVATE, NETPROP LINK, KEY_PREFIX NETENT LINKQUALITY " Entity Keys", NULL, NULL }, + + { SC_10_7_IPHONE_5_0_PRIVATE, NETPROP, LINKQUALITY, NULL, CFNUMBER}, + { COMMENT_PRIVATE, "", NULL, NULL, NULL }, + { GROUP, NETPROP MODEM, KEY_PREFIX NETENT MODEM " (Hardware) Entity Keys", NULL, NULL }, { SC_10_5, NETPROP MODEM, ACCESSPOINTNAME, NULL, CFSTRING }, diff --git a/SystemConfiguration.fproj/helper/SCHelper_client.c b/SystemConfiguration.fproj/helper/SCHelper_client.c index 7c69a2f..1dc443c 100644 --- a/SystemConfiguration.fproj/helper/SCHelper_client.c +++ b/SystemConfiguration.fproj/helper/SCHelper_client.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2007, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2005-2007, 2010, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -208,6 +209,33 @@ _SCHelperClose(mach_port_t *helper_port) } +static CFDataRef +_SCHelperExecCopyBacktrace() +{ + static Boolean loggingEnabled = FALSE; + static dispatch_once_t once; + CFDataRef traceData = NULL; + + dispatch_once(&once, ^{ + if(getenv("ENABLE_SCHELPER_BACKTRACES")) { + loggingEnabled = TRUE; + } + }); + + if (loggingEnabled) { + CFStringRef backtrace; + + backtrace = _SC_copyBacktrace(); + if (backtrace != NULL) { + _SCSerializeString(backtrace, &traceData, NULL, NULL); + CFRelease(backtrace); + } + } + + return traceData; +} + + Boolean _SCHelperExec(mach_port_t port, uint32_t msgID, CFDataRef data, uint32_t *status, CFDataRef *reply) { @@ -216,14 +244,24 @@ _SCHelperExec(mach_port_t port, uint32_t msgID, CFDataRef data, uint32_t *status xmlDataOut_t replyRef = NULL; /* raw bytes */ mach_msg_type_number_t replyLen = 0; uint32_t replyStatus = 0; + CFDataRef traceData; + + traceData = _SCHelperExecCopyBacktrace(); kr = helperexec(port, msgID, (data != NULL) ? (void *)CFDataGetBytePtr(data) : NULL, - (data != NULL) ? CFDataGetLength(data) : 0, + (data != NULL) ? CFDataGetLength(data) : 0, + (traceData != NULL) ? (void *)CFDataGetBytePtr(traceData) : NULL, + (traceData != NULL) ? CFDataGetLength(traceData) : 0, &replyStatus, &replyRef, &replyLen); + + if (traceData != NULL) { + CFRelease(traceData); + } + if (kr != KERN_SUCCESS) { if (replyRef != NULL) { (void) vm_deallocate(mach_task_self(), (vm_address_t)replyRef, replyLen); diff --git a/SystemConfiguration.fproj/helper/SCHelper_client.h b/SystemConfiguration.fproj/helper/SCHelper_client.h index 02ecf75..0db8a11 100644 --- a/SystemConfiguration.fproj/helper/SCHelper_client.h +++ b/SystemConfiguration.fproj/helper/SCHelper_client.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2007, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2005-2007, 2010, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -35,6 +35,9 @@ #define kSCKeychainOptionsPassword CFSTR("Password") // CFData #define kSCKeychainOptionsUniqueID CFSTR("UniqueID") // CFString +#define kSCHelperAuthAuthorization CFSTR("Authorization") // CFData[AuthorizationExternalForm] +#define kSCHelperAuthCallerInfo CFSTR("CallerInfo") // CFString + enum { // authorization SCHELPER_MSG_AUTH = 1, diff --git a/SystemConfiguration.fproj/helper/SCHelper_server.c b/SystemConfiguration.fproj/helper/SCHelper_server.c index 62957bd..ad83e9c 100644 --- a/SystemConfiguration.fproj/helper/SCHelper_server.c +++ b/SystemConfiguration.fproj/helper/SCHelper_server.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2005-2011 Apple Inc. All rights reserved. + * Copyright (c) 2005-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -35,6 +35,8 @@ #include #include +#include +#include #include #include #include @@ -48,8 +50,6 @@ #pragma mark SCHelper session managment -#if TARGET_OS_IPHONE - // // entitlement used to control write access to a given "prefsID" // @@ -60,9 +60,6 @@ // #define kSCVPNFilterEntitlementName CFSTR("com.apple.networking.vpn.configuration") -#endif // TARGET_OS_IPHONE - - typedef enum { NO = 0, YES, UNKNOWN } lazyBoolean; typedef const struct __SCHelperSession * SCHelperSessionRef; @@ -77,6 +74,7 @@ typedef struct { // authorization AuthorizationRef authorization; + Boolean use_entitlement; // session mach port mach_port_t port; @@ -94,6 +92,9 @@ typedef struct { // preferences SCPreferencesRef prefs; + /* backtraces */ + CFMutableSetRef backtraces; + } SCHelperSessionPrivate, *SCHelperSessionPrivateRef; @@ -101,6 +102,9 @@ static CFStringRef __SCHelperSessionCopyDescription (CFTypeRef cf); static void __SCHelperSessionDeallocate (CFTypeRef cf); +static void __SCHelperSessionLogBacktrace (const void *value, void *context); + + static CFTypeID __kSCHelperSessionTypeID = _kCFRuntimeNotATypeID; static Boolean debug = FALSE; static pthread_once_t initialized = PTHREAD_ONCE_INIT; @@ -112,6 +116,18 @@ static pthread_mutex_t sessions_lock = PTHREAD_MUTEX_INITIALIZER; #pragma mark - +#pragma mark Helper session management + + +#if !TARGET_OS_IPHONE +static Boolean + __SCHelperSessionUseEntitlement(SCHelperSessionRef session) +{ + SCHelperSessionPrivateRef sessionPrivate = (SCHelperSessionPrivateRef)session; + + return sessionPrivate->use_entitlement; +} +#endif //!TARGET_OS_IPHONE static AuthorizationRef @@ -131,13 +147,23 @@ __SCHelperSessionSetAuthorization(SCHelperSessionRef session, CFTypeRef authoriz pthread_mutex_lock(&sessionPrivate->lock); -#if !TARGET_OS_IPHONE if (sessionPrivate->authorization != NULL) { - AuthorizationFree(sessionPrivate->authorization, kAuthorizationFlagDefaults); -// AuthorizationFree(sessionPrivate->authorization, kAuthorizationFlagDestroyRights); - sessionPrivate->authorization = NULL; +#if !TARGET_OS_IPHONE + if (!__SCHelperSessionUseEntitlement(session)) { + AuthorizationFree(sessionPrivate->authorization, kAuthorizationFlagDefaults); +// AuthorizationFree(sessionPrivate->authorization, kAuthorizationFlagDestroyRights); + sessionPrivate->authorization = NULL; + } else { +#endif //!TARGET_OS_IPHONE + CFRelease(sessionPrivate->authorization); + sessionPrivate->authorization = NULL; +#if !TARGET_OS_IPHONE + } +#endif //!TARGET_OS_IPHONE + sessionPrivate->use_entitlement = FALSE; } +#if !TARGET_OS_IPHONE if (isA_CFData(authorizationData)) { AuthorizationExternalForm extForm; @@ -155,17 +181,13 @@ __SCHelperSessionSetAuthorization(SCHelperSessionRef session, CFTypeRef authoriz ok = FALSE; } } - } -#else // !TARGET_OS_IPHONE - if (sessionPrivate->authorization != NULL) { - CFRelease(sessionPrivate->authorization); - sessionPrivate->authorization = NULL; - } + } else +#endif //!TARGET_OS_IPHONE if (isA_CFString(authorizationData)) { sessionPrivate->authorization = (void *)CFRetain(authorizationData); + sessionPrivate->use_entitlement = TRUE; } -#endif // !TARGET_OS_IPHONE pthread_mutex_unlock(&sessionPrivate->lock); @@ -300,6 +322,7 @@ __SCHelperSessionLog(const void *value, void *context) { SCHelperSessionRef session = (SCHelperSessionRef)value; SCHelperSessionPrivateRef sessionPrivate = (SCHelperSessionPrivateRef)session; + FILE **logFile = (FILE **)context; pthread_mutex_lock(&sessionPrivate->lock); @@ -313,6 +336,19 @@ __SCHelperSessionLog(const void *value, void *context) prefsPrivate->name, prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path, prefsPrivate->locked ? ", locked" : ""); + + if ((sessionPrivate->backtraces != NULL) && + (CFSetGetCount(sessionPrivate->backtraces) > 0)) { + // log/report all collected backtraces + CFSetApplyFunction(sessionPrivate->backtraces, + __SCHelperSessionLogBacktrace, + (void *)logFile); + + // to ensure that we don't log the same backtraces multiple + // times we remove any reported traces + CFRelease(sessionPrivate->backtraces); + sessionPrivate->backtraces = NULL; + } } pthread_mutex_unlock(&sessionPrivate->lock); @@ -380,6 +416,9 @@ __SCHelperSessionDeallocate(CFTypeRef cf) __SCHelperSessionSetPreferences (session, NULL); __SCHelperSessionSetVPNFilter (session, NULL); pthread_mutex_destroy(&sessionPrivate->lock); + if (sessionPrivate->backtraces != NULL) { + CFRelease(sessionPrivate->backtraces); + } // we no longer need/want to track this session CFSetRemoveValue(sessions, sessionPrivate); @@ -427,11 +466,13 @@ __SCHelperSessionCreate(CFAllocatorRef allocator) return NULL; } sessionPrivate->authorization = NULL; + sessionPrivate->use_entitlement = FALSE; sessionPrivate->port = MACH_PORT_NULL; sessionPrivate->mp = NULL; sessionPrivate->callerWriteAccess = UNKNOWN; sessionPrivate->vpnFilter = NULL; sessionPrivate->prefs = NULL; + sessionPrivate->backtraces = NULL; // keep track this session pthread_mutex_lock(&sessions_lock); @@ -486,6 +527,84 @@ __SCHelperSessionFindWithPort(mach_port_t port) } +#pragma mark - +#pragma mark Session backtrace logging + + +static void +__SCHelperSessionAddBacktrace(SCHelperSessionRef session, CFStringRef backtrace, const char * command) +{ + CFStringRef logEntry; + SCPreferencesRef prefs; + SCPreferencesPrivateRef prefsPrivate; + SCHelperSessionPrivateRef sessionPrivate = (SCHelperSessionPrivateRef)session; + + prefs = __SCHelperSessionGetPreferences((SCHelperSessionRef)sessionPrivate); + if (prefs == NULL) { + // if no prefs + return; + } + prefsPrivate = (SCPreferencesPrivateRef)prefs; + + logEntry = CFStringCreateWithFormat(NULL, NULL, + CFSTR("%@ [%s]: %s\n\n%@"), + prefsPrivate->name, + prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path, + command, + backtrace); + + pthread_mutex_lock(&sessionPrivate->lock); + + if (sessionPrivate->backtraces == NULL) { + sessionPrivate->backtraces = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); + } + CFSetSetValue(sessionPrivate->backtraces, logEntry); + + pthread_mutex_unlock(&sessionPrivate->lock); + + CFRelease(logEntry); + return; +} + + +static void +__SCHelperSessionLogBacktrace(const void *value, void *context) +{ + CFSetRef backtrace = (CFSetRef)value; + FILE **logFile = (FILE **)context; + + if (*logFile == NULL) { + char path[PATH_MAX]; + struct tm tm_now; + struct timeval tv_now; + + (void)gettimeofday(&tv_now, NULL); + (void)localtime_r(&tv_now.tv_sec, &tm_now); + + snprintf(path, + sizeof(path), + "/Library/Logs/CrashReporter/SCHelper-%4d-%02d-%02d-%02d%02d%02d.log", + tm_now.tm_year + 1900, + tm_now.tm_mon + 1, + tm_now.tm_mday, + tm_now.tm_hour, + tm_now.tm_min, + tm_now.tm_sec); + + *logFile = fopen(path, "a"); + if (*logFile == NULL) { + // if log file could not be created + return; + } + + SCLog(TRUE, LOG_INFO, CFSTR("created backtrace log: %s"), path); + } + + SCPrint(TRUE, *logFile, CFSTR("%@\n"), backtrace); + return; +} + + #pragma mark - #pragma mark Helpers @@ -506,37 +625,46 @@ do_Exit(SCHelperSessionRef session, void *info, CFDataRef data, uint32_t *status /* * AUTHORIZE - * (in) data = AuthorizationExternalForm + * (in) data = authorizationDict (in 2 flavors) + * kSCHelperAuthAuthorization - use provided AuthorizationExternalForm + * kSCHelperAuthCallerInfo - use entitlement * (out) status = OSStatus * (out) reply = N/A */ static Boolean do_Auth(SCHelperSessionRef session, void *info, CFDataRef data, uint32_t *status, CFDataRef *reply) { - Boolean ok; + CFDictionaryRef authorizationDict; +#if !TARGET_OS_IPHONE + CFDataRef authorizationData = NULL; +#endif + Boolean ok = FALSE; -#if !TARGET_OS_IPHONE - - ok = __SCHelperSessionSetAuthorization(session, data); - -#else //!TARGET_OS_IPHONE - - CFStringRef authorizationInfo = NULL; - - if ((data != NULL) && !_SCUnserializeString(&authorizationInfo, data, NULL, 0)) { + if (_SCUnserialize((CFPropertyListRef*)&authorizationDict, data, NULL, 0) == FALSE) { return FALSE; } - if (!isA_CFString(authorizationInfo)) { - if (authorizationInfo != NULL) CFRelease(authorizationInfo); + if (isA_CFDictionary(authorizationDict) == FALSE) { + CFRelease(authorizationDict); return FALSE; } - ok = __SCHelperSessionSetAuthorization(session, authorizationInfo); - if (authorizationInfo != NULL) CFRelease(authorizationInfo); +#if !TARGET_OS_IPHONE + authorizationData = CFDictionaryGetValue(authorizationDict, kSCHelperAuthAuthorization); + if (authorizationData != NULL && isA_CFData(authorizationData)) { + ok = __SCHelperSessionSetAuthorization(session, authorizationData); + } else +#endif + { + CFStringRef authorizationInfo; -#endif // !TARGET_OS_IPHONE + authorizationInfo = CFDictionaryGetValue(authorizationDict, kSCHelperAuthCallerInfo); + if (authorizationInfo != NULL && isA_CFString(authorizationInfo)) { + ok = __SCHelperSessionSetAuthorization(session, authorizationInfo); + } + } + CFRelease(authorizationDict); *status = ok ? 0 : 1; return TRUE; } @@ -749,25 +877,33 @@ do_interface_refresh(SCHelperSessionRef session, void *info, CFDataRef data, uin Boolean ok = FALSE; if ((data != NULL) && !_SCUnserializeString(&ifName, data, NULL, 0)) { + *status = kSCStatusInvalidArgument; SCLog(TRUE, LOG_ERR, CFSTR("interface name not valid")); return FALSE; } - if (ifName != NULL) { - if (isA_CFString(ifName)) { - ok = _SCNetworkInterfaceForceConfigurationRefresh(ifName); - if (!ok) { - *status = SCError(); - } - } - - CFRelease(ifName); + if (ifName == NULL) { + *status = kSCStatusInvalidArgument; + SCLog(TRUE, LOG_ERR, CFSTR("interface name not valid")); + return FALSE; } - if (!ok) { + if (isA_CFString(ifName)) { + ok = _SCNetworkInterfaceForceConfigurationRefresh(ifName); + if (!ok) { + *status = SCError(); + SCLog(TRUE, LOG_ERR, + CFSTR("interface \"%@\" not refreshed: %s"), + ifName, + SCErrorString(*status)); + } + } else { + *status = kSCStatusInvalidArgument; SCLog(TRUE, LOG_ERR, CFSTR("interface name not valid")); } + CFRelease(ifName); + return ok; } @@ -1211,11 +1347,6 @@ do_prefs_Synchronize(SCHelperSessionRef session, void *info, CFDataRef data, uin #pragma mark Process commands -#if TARGET_OS_IPHONE - -#include -#include - static CFStringRef sessionName(SCHelperSessionRef session) { @@ -1273,52 +1404,50 @@ copyEntitlement(SCHelperSessionRef session, CFStringRef entitlement) return value; } -#endif // TARGET_OS_IPHONE - - - static Boolean hasAuthorization(SCHelperSessionRef session) { - AuthorizationRef authorization = __SCHelperSessionGetAuthorization(session); + AuthorizationRef authorization = __SCHelperSessionGetAuthorization(session); + SCHelperSessionPrivateRef sessionPrivate = (SCHelperSessionPrivateRef)session; if (authorization == NULL) { return FALSE; } -#if !TARGET_OS_IPHONE - AuthorizationFlags flags; - AuthorizationItem items[1]; - AuthorizationRights rights; - OSStatus status; - - items[0].name = "system.preferences"; - items[0].value = NULL; - items[0].valueLength = 0; - items[0].flags = 0; - - rights.count = sizeof(items) / sizeof(items[0]); - rights.items = items; - - flags = kAuthorizationFlagDefaults; - flags |= kAuthorizationFlagExtendRights; - flags |= kAuthorizationFlagInteractionAllowed; -// flags |= kAuthorizationFlagPartialRights; -// flags |= kAuthorizationFlagPreAuthorize; - - status = AuthorizationCopyRights(authorization, - &rights, - kAuthorizationEmptyEnvironment, - flags, - NULL); - if (status != errAuthorizationSuccess) { - return FALSE; - } +#if !TARGET_OS_IPHONE + if (!__SCHelperSessionUseEntitlement(session)) { + AuthorizationFlags flags; + AuthorizationItem items[1]; + AuthorizationRights rights; + OSStatus status; + + items[0].name = kSCPreferencesWriteAuthorizationRight; + items[0].value = NULL; + items[0].valueLength = 0; + items[0].flags = 0; + + rights.count = sizeof(items) / sizeof(items[0]); + rights.items = items; + + flags = kAuthorizationFlagDefaults; + flags |= kAuthorizationFlagExtendRights; + flags |= kAuthorizationFlagInteractionAllowed; +// flags |= kAuthorizationFlagPartialRights; +// flags |= kAuthorizationFlagPreAuthorize; + + status = AuthorizationCopyRights(authorization, + &rights, + kAuthorizationEmptyEnvironment, + flags, + NULL); + if (status != errAuthorizationSuccess) { + return FALSE; + } - return TRUE; -#else // !TARGET_OS_IPHONE - SCHelperSessionPrivateRef sessionPrivate = (SCHelperSessionPrivateRef)session; + return TRUE; + } +#endif // !TARGET_OS_IPHONE if (sessionPrivate->callerWriteAccess == UNKNOWN) { CFArrayRef entitlement; @@ -1393,7 +1522,6 @@ hasAuthorization(SCHelperSessionRef session) } return (sessionPrivate->callerWriteAccess == YES) ? TRUE : FALSE; -#endif // TARGET_OS_IPHONE } @@ -1799,13 +1927,16 @@ _helperexec(mach_port_t server, uint32_t msgID, xmlData_t dataRef, /* raw XML bytes */ mach_msg_type_number_t dataLen, + xmlData_t traceRef, /* raw XML bytes */ + mach_msg_type_number_t traceLen, uint32_t *status, xmlDataOut_t *replyRef, /* raw XML bytes */ mach_msg_type_number_t *replyLen) { - CFDataRef data = NULL; + CFStringRef backtrace = NULL; + CFDataRef data = NULL; int i; - CFDataRef reply = NULL; + CFDataRef reply = NULL; SCHelperSessionRef session; *status = kSCStatusOK; @@ -1815,10 +1946,19 @@ _helperexec(mach_port_t server, if ((dataRef != NULL) && (dataLen > 0)) { if (!_SCUnserializeData(&data, (void *)dataRef, dataLen)) { *status = SCError(); - return KERN_SUCCESS; } } + if ((traceRef != NULL) && (traceLen > 0)) { + if (!_SCUnserializeString(&backtrace, NULL, (void *)traceRef, traceLen)) { + *status = SCError(); + } + } + + if (*status != kSCStatusOK) { + goto done; + } + session = __SCHelperSessionFindWithPort(server); if (session == NULL) { *status = kSCStatusFailed; /* you must have an open session to play */ @@ -1847,6 +1987,9 @@ _helperexec(mach_port_t server, } if (*status == kSCStatusOK) { + if (backtrace != NULL) { + __SCHelperSessionAddBacktrace(session, backtrace, helpers[i].commandName); + } (*helpers[i].func)(session, helpers[i].info, data, status, &reply); } @@ -1861,7 +2004,10 @@ _helperexec(mach_port_t server, /* serialize the data */ if (reply != NULL) { - ok = _SCSerializeData(reply, (void **)replyRef, (CFIndex *)replyLen); + CFIndex len; + + ok = _SCSerializeData(reply, (void **)replyRef, &len); + *replyLen = len; CFRelease(reply); reply = NULL; if (!ok) { @@ -1874,6 +2020,7 @@ _helperexec(mach_port_t server, done : if (data != NULL) CFRelease(data); + if (backtrace != NULL) CFRelease(backtrace); if (reply != NULL) CFRelease(reply); return KERN_SUCCESS; } @@ -1971,7 +2118,7 @@ main(int argc, char **argv) launch_data_t l_reply; launch_data_type_t l_type; int n_listeners = 0; - extern int optind; +// extern int optind; int opt; int opti; @@ -2058,9 +2205,15 @@ main(int argc, char **argv) if (!done && (idle >= (2 * 60 / 15))) { if (gen_reported != gen_current) { + FILE *logFile = NULL; + SCLog(TRUE, LOG_NOTICE, CFSTR("active (but IDLE) sessions")); - CFSetApplyFunction(sessions, __SCHelperSessionLog, NULL); + CFSetApplyFunction(sessions, __SCHelperSessionLog, (void *)&logFile); gen_reported = gen_current; + + if (logFile != NULL) { + (void) fclose(logFile); + } } idle = 0; } diff --git a/SystemConfiguration.fproj/helper/helper.defs b/SystemConfiguration.fproj/helper/helper.defs index e7d0b77..e254418 100644 --- a/SystemConfiguration.fproj/helper/helper.defs +++ b/SystemConfiguration.fproj/helper/helper.defs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010 Apple Inc. All rights reserved. + * Copyright (c) 2010, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -61,5 +61,6 @@ routine helperinit ( server : mach_port_t; routine helperexec ( server : mach_port_t; msgID : uint32_t; data : xmlData; + trace : xmlData; out status : uint32_t; out reply : xmlDataOut, dealloc); diff --git a/SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_client.c b/SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_client.c new file mode 100644 index 0000000..09c0ea6 --- /dev/null +++ b/SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_client.c @@ -0,0 +1,1186 @@ +/* + * Copyright (c) 2011, 2012 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, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * 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 +#include +#include +#include "SCNetworkReachabilityInternal.h" + +#ifdef HAVE_REACHABILITY_SERVER + +#include +#include + +#include "rb.h" + + +#pragma mark - +#pragma mark Globals + + +static const struct addrinfo hints0 = { +#ifdef AI_PARALLEL + .ai_flags = AI_PARALLEL | AI_ADDRCONFIG +#else // AI_PARALLEL + .ai_flags = AI_ADDRCONFIG +#endif // AI_PARALLEL +}; + + +static Boolean serverAvailable = TRUE; + + +#pragma mark - +#pragma mark Support functions + + +static void +log_xpc_object(const char *msg, xpc_object_t obj) +{ + char *desc; + + desc = xpc_copy_description(obj); + SCLog(TRUE, LOG_DEBUG, CFSTR("%s = %s"), msg, desc); + free(desc); +} + + +#pragma mark - +#pragma mark Reachability [RBT] client support + + +typedef struct { + struct rb_node rbn; + SCNetworkReachabilityRef target; +} reach_request_t; + + +#define RBNODE_TO_REACH_REQUEST(node) \ + ((reach_request_t *)((uintptr_t)node - offsetof(reach_request_t, rbn))) + + +static int +_rbt_compare_transaction_nodes(const struct rb_node *n1, const struct rb_node *n2) +{ + uint64_t a = (uintptr_t)(RBNODE_TO_REACH_REQUEST(n1)->target); + uint64_t b = (uintptr_t)(RBNODE_TO_REACH_REQUEST(n2)->target); + + return (a - b); +} + + +static int +_rbt_compare_transaction_key(const struct rb_node *n1, const void *key) +{ + uint64_t a = (uintptr_t)(RBNODE_TO_REACH_REQUEST(n1)->target); + uint64_t b = *(uint64_t *)key; + + return (a - b); +} + + +static struct rb_tree * +_reach_requests_rbt() +{ + static dispatch_once_t once; + static const struct rb_tree_ops ops = { + .rbto_compare_nodes = _rbt_compare_transaction_nodes, + .rbto_compare_key = _rbt_compare_transaction_key, + }; + static struct rb_tree rbtree; + + dispatch_once(&once, ^{ + rb_tree_init(&rbtree, &ops); + }); + + return &rbtree; +} + + +static dispatch_queue_t +_reach_requests_rbt_queue() +{ + static dispatch_once_t once; + static dispatch_queue_t q; + + dispatch_once(&once, ^{ + q = dispatch_queue_create(REACH_SERVICE_NAME ".rbt", NULL); + }); + + return q; +} + + +static reach_request_t * +_reach_request_create(SCNetworkReachabilityRef target) +{ + reach_request_t *request; + + request = calloc(1, sizeof(*request)); + request->target = CFRetain(target); + + return request; +} + + +static void +_reach_request_release(reach_request_t *request) +{ + SCNetworkReachabilityRef target = request->target; + + CFRelease(target); + free(request); + + return; +} + + +static void +_reach_request_add(SCNetworkReachabilityRef target) +{ + uint64_t target_id = (uintptr_t)target; + + dispatch_sync(_reach_requests_rbt_queue(), ^{ + struct rb_node *rbn; + + rbn = rb_tree_find_node(_reach_requests_rbt(), &target_id); + if (rbn == NULL) { + reach_request_t *request; + + request = _reach_request_create(target); + if (request == NULL || !rb_tree_insert_node(_reach_requests_rbt(), &request->rbn)) { + __builtin_trap(); + } + } + }); + + return; +} + + +static void +_reach_request_remove(SCNetworkReachabilityRef target) +{ + uint64_t target_id = (uintptr_t)target; + + dispatch_sync(_reach_requests_rbt_queue(), ^{ // FIXME ?? use dispatch_async? + struct rb_node *rbn; + struct rb_tree *rbtree = _reach_requests_rbt(); + + rbn = rb_tree_find_node(rbtree, &target_id); + if (rbn != NULL) { + reach_request_t *request = RBNODE_TO_REACH_REQUEST(rbn); + + rb_tree_remove_node(rbtree, rbn); + _reach_request_release(request); + } + }); +} + + +static SCNetworkReachabilityRef +_reach_request_copy_target(uint64_t target_id) +{ + __block SCNetworkReachabilityRef target = NULL; + + dispatch_sync(_reach_requests_rbt_queue(), ^{ + struct rb_node *rbn; + + rbn = rb_tree_find_node(_reach_requests_rbt(), &target_id); + if (rbn != NULL) { + // handle the [async] reply + target = (SCNetworkReachabilityRef)(uintptr_t)target_id; + CFRetain(target); + } + }); + + return target; +} + + +#pragma mark - +#pragma mark Reachability [XPC] client support + + +static void +handle_reachability_status(SCNetworkReachabilityRef target, xpc_object_t dict) +{ + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + if (_sc_debug) { + SCLog(TRUE, LOG_INFO, CFSTR("%sgot [async] notification"), + targetPrivate->log_prefix); +// log_xpc_object(" status", dict); + } + + __SCNetworkReachabilityPerformNoLock(target); + + return; +} + + +static void +handle_async_notification(SCNetworkReachabilityRef target, xpc_object_t dict) +{ + int64_t op; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + op = xpc_dictionary_get_int64(dict, MESSAGE_NOTIFY); + switch (op) { + case MESSAGE_REACHABILITY_STATUS : + handle_reachability_status(target, dict); + break; + default : + SCLog(TRUE, LOG_ERR, CFSTR("%sgot [async] unknown reply : %d"), + targetPrivate->log_prefix, + op); + log_xpc_object(" reply", dict); + break; + } + + return; +} + + +static dispatch_queue_t +_reach_xpc_queue() +{ + static dispatch_once_t once; + static dispatch_queue_t q; + + dispatch_once(&once, ^{ + q = dispatch_queue_create(REACH_SERVICE_NAME ".xpc", NULL); + }); + + return q; +} + + +static void +_reach_connection_reconnect(xpc_connection_t connection); + + +static xpc_connection_t +_reach_connection_create() +{ + xpc_connection_t c; + const char *name; + dispatch_queue_t q = _reach_xpc_queue(); + + // create XPC connection + name = getenv("REACH_SERVER"); + if ((name == NULL) || (issetugid() != 0)) { + name = REACH_SERVICE_NAME; + } + + c = xpc_connection_create_mach_service(name, + q, + XPC_CONNECTION_MACH_SERVICE_PRIVILEGED); + + xpc_connection_set_event_handler(c, ^(xpc_object_t xobj) { + xpc_type_t type; + + type = xpc_get_type(xobj); + if (type == XPC_TYPE_DICTIONARY) { + SCNetworkReachabilityRef target; + uint64_t target_id; + + target_id = xpc_dictionary_get_uint64(xobj, REACH_CLIENT_TARGET_ID); + if (target_id == 0) { + SCLog(TRUE, LOG_ERR, + CFSTR("reach client %p: async reply with no target [ID]"), + c); + log_xpc_object(" reply", xobj); + return; + } + + target = _reach_request_copy_target(target_id); + if (target == NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR("received unexpected target [ID] from SCNetworkReachability server")); + log_xpc_object(" reply", xobj); + return; + } + + handle_async_notification(target, xobj); + CFRelease(target); + + } else if (type == XPC_TYPE_ERROR) { + if (xobj == XPC_ERROR_CONNECTION_INVALID) { + SCLog(TRUE, LOG_ERR, + CFSTR("SCNetworkReachability server not available")); + serverAvailable = FALSE; + } else if (xobj == XPC_ERROR_CONNECTION_INTERRUPTED) { + SCLog(TRUE, LOG_DEBUG, + CFSTR("SCNetworkReachability server failure, reconnecting")); + _reach_connection_reconnect(c); + } else { + const char *desc; + + desc = xpc_dictionary_get_string(xobj, XPC_ERROR_KEY_DESCRIPTION); + SCLog(TRUE, LOG_ERR, + CFSTR("reach client %p: Connection error: %s"), + c, + desc); + } + + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("reach client %p: unknown event type : %x"), + c, + type); + } + }); + xpc_connection_resume(c); + + return c; +} + + +static xpc_connection_t +_reach_connection() +{ + static xpc_connection_t c; + static dispatch_once_t once; + static dispatch_queue_t q; + + if (!serverAvailable) { + // if SCNetworkReachabilty [XPC] server not available + return NULL; + } + + dispatch_once(&once, ^{ + q = dispatch_queue_create(REACH_SERVICE_NAME ".connection", NULL); + }); + + dispatch_sync(q, ^{ + if (c == NULL) { + c = _reach_connection_create(); + } + }); + + return c; +} + + +typedef void (^reach_server_reply_handler_t)(xpc_object_t reply); + + +static void +add_proc_name(xpc_object_t reqdict) +{ + static const char *name = NULL; + static dispatch_once_t once; + + // add the process name + dispatch_once(&once, ^{ + name = getprogname(); + }); + xpc_dictionary_set_string(reqdict, REACH_CLIENT_PROC_NAME, name); + + return; +} + + +static void +_reach_server_target_reconnect(xpc_connection_t connection, SCNetworkReachabilityRef target); + + +static Boolean +_reach_server_target_add(xpc_connection_t connection, SCNetworkReachabilityRef target) +{ + Boolean ok = FALSE; + xpc_object_t reply; + xpc_object_t reqdict; + Boolean retry = FALSE; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + // create message + reqdict = xpc_dictionary_create(NULL, NULL, 0); + + // set request + xpc_dictionary_set_int64(reqdict, REACH_REQUEST, REACH_REQUEST_CREATE); + + // add reachability target info + if (targetPrivate->name != NULL) { + xpc_dictionary_set_string(reqdict, + REACH_TARGET_NAME, + targetPrivate->name); + } + if (targetPrivate->serv != NULL) { + xpc_dictionary_set_string(reqdict, + REACH_TARGET_SERV, + targetPrivate->serv); + } + if (targetPrivate->localAddress != NULL) { + xpc_dictionary_set_data(reqdict, + REACH_TARGET_LOCAL_ADDR, + targetPrivate->localAddress, + targetPrivate->localAddress->sa_len); + } + if (targetPrivate->remoteAddress != NULL) { + xpc_dictionary_set_data(reqdict, + REACH_TARGET_REMOTE_ADDR, + targetPrivate->remoteAddress, + targetPrivate->remoteAddress->sa_len); + } + if (bcmp(&targetPrivate->hints, &hints0, sizeof(struct addrinfo)) != 0) { + xpc_dictionary_set_data(reqdict, + REACH_TARGET_HINTS, + &targetPrivate->hints, + sizeof(targetPrivate->hints)); + } + if (targetPrivate->if_index != 0) { + xpc_dictionary_set_int64(reqdict, + REACH_TARGET_IF_INDEX, + targetPrivate->if_index); + xpc_dictionary_set_string(reqdict, + REACH_TARGET_IF_NAME, + targetPrivate->if_name); + } + if (targetPrivate->onDemandBypass) { + xpc_dictionary_set_bool(reqdict, + REACH_TARGET_ONDEMAND_BYPASS, + TRUE); + } + if (targetPrivate->resolverBypass) { + xpc_dictionary_set_bool(reqdict, + REACH_TARGET_RESOLVER_BYPASS, + TRUE); + } + + + // add the target [ID] + xpc_dictionary_set_uint64(reqdict, REACH_CLIENT_TARGET_ID, (uintptr_t)target); + + // add the process name (for debugging) + add_proc_name(reqdict); + + retry : + + // send request to the SCNetworkReachability server + reply = xpc_connection_send_message_with_reply_sync(connection, reqdict); + if (reply != NULL) { + xpc_type_t type; + + type = xpc_get_type(reply); + if (type == XPC_TYPE_DICTIONARY) { + int64_t status; + + status = xpc_dictionary_get_int64(reply, REACH_REQUEST_REPLY); + ok = (status == REACH_REQUEST_REPLY_OK); + } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) { + SCLog(TRUE, LOG_ERR, + CFSTR("SCNetworkReachability server not available")); + serverAvailable = FALSE; + } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) { + SCLog(TRUE, LOG_DEBUG, + CFSTR("reach target %p: SCNetworkReachability server failure, retrying"), + target); + retry = TRUE; + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("reach target %p: _targetAdd with unexpected reply"), + target); + log_xpc_object(" reply", reply); + } + + xpc_release(reply); + } + + if (retry) { + retry = FALSE; + goto retry; + } + + xpc_release(reqdict); + return ok; +} + + +static Boolean +_reach_server_target_remove(xpc_connection_t connection, SCNetworkReachabilityRef target) +{ + Boolean ok = FALSE; + xpc_object_t reply; + xpc_object_t reqdict; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + // create message + reqdict = xpc_dictionary_create(NULL, NULL, 0); + + // set request + xpc_dictionary_set_int64(reqdict, REACH_REQUEST, REACH_REQUEST_REMOVE); + + // add the target [ID] + xpc_dictionary_set_uint64(reqdict, REACH_CLIENT_TARGET_ID, (uintptr_t)target); + + reply = xpc_connection_send_message_with_reply_sync(connection, reqdict); + if (reply != NULL) { + xpc_type_t type; + + type = xpc_get_type(reply); + if (type == XPC_TYPE_DICTIONARY) { + int64_t status; + + status = xpc_dictionary_get_int64(reply, REACH_REQUEST_REPLY); + switch (status) { + case REACH_REQUEST_REPLY_OK : + ok = TRUE; + break; + case REACH_REQUEST_REPLY_UNKNOWN : + SCLog(TRUE, LOG_DEBUG, + CFSTR("reach target %p: SCNetworkReachability server failure, no need to remove"), + target); + ok = TRUE; + break; + default : { + SCLog(TRUE, LOG_ERR, CFSTR("%s target remove failed"), + targetPrivate->log_prefix); + log_xpc_object(" reply", reply); + } + } + } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) { + SCLog(TRUE, LOG_ERR, + CFSTR("SCNetworkReachability server not available")); + serverAvailable = FALSE; + ok = TRUE; + } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) { + SCLog(TRUE, LOG_DEBUG, + CFSTR("reach target %p: SCNetworkReachability server failure, no need to remove"), + target); + ok = TRUE; + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("reach target %p: _targetRemove with unexpected reply"), + target); + log_xpc_object(" reply", reply); + } + + xpc_release(reply); + } + + xpc_release(reqdict); + return ok; +} + + +static Boolean +_reach_server_target_schedule(xpc_connection_t connection, SCNetworkReachabilityRef target) +{ + Boolean ok = FALSE; + xpc_object_t reply; + xpc_object_t reqdict; + Boolean retry = FALSE; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + // create message + reqdict = xpc_dictionary_create(NULL, NULL, 0); + + // set request + xpc_dictionary_set_int64(reqdict, REACH_REQUEST, REACH_REQUEST_SCHEDULE); + + // add the target [ID] + xpc_dictionary_set_uint64(reqdict, REACH_CLIENT_TARGET_ID, (uintptr_t)target); + + retry : + + reply = xpc_connection_send_message_with_reply_sync(connection, reqdict); + if (reply != NULL) { + xpc_type_t type; + + type = xpc_get_type(reply); + if (type == XPC_TYPE_DICTIONARY) { + int64_t status; + + status = xpc_dictionary_get_int64(reply, REACH_REQUEST_REPLY); + switch (status) { + case REACH_REQUEST_REPLY_OK : + ok = TRUE; + break; + case REACH_REQUEST_REPLY_UNKNOWN : + SCLog(TRUE, LOG_DEBUG, + CFSTR("reach target %p: SCNetworkReachability server failure, retry schedule"), + target); + retry = TRUE; + break; + default : { + SCLog(TRUE, LOG_ERR, CFSTR("%s target schedule failed"), + targetPrivate->log_prefix); + log_xpc_object(" reply", reply); + } + } + + if (ok) { + CFRetain(target); + } + } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) { + SCLog(TRUE, LOG_ERR, + CFSTR("SCNetworkReachability server not available")); + serverAvailable = FALSE; + } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) { + SCLog(TRUE, LOG_DEBUG, + CFSTR("reach target %p: SCNetworkReachability server failure, retry schedule"), + target); + retry = TRUE; + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("reach target %p: _targetSchedule with unexpected reply"), + target); + log_xpc_object(" reply", reply); + } + + xpc_release(reply); + } + + if (retry) { + // reconnect + _reach_server_target_reconnect(connection, target); + + // and retry + retry = FALSE; + goto retry; + } + + xpc_release(reqdict); + return ok; +} + + +static void +_reach_reply_set_reachability(SCNetworkReachabilityRef target, + xpc_object_t reply) +{ + char *if_name; + size_t len = 0; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + targetPrivate->serverInfo.cycle = xpc_dictionary_get_uint64(reply, + REACH_STATUS_CYCLE); + + targetPrivate->serverInfo.flags = xpc_dictionary_get_uint64(reply, + REACH_STATUS_FLAGS); + + targetPrivate->serverInfo.if_index = xpc_dictionary_get_uint64(reply, + REACH_STATUS_IF_INDEX); + + bzero(&targetPrivate->serverInfo.if_name, sizeof(targetPrivate->serverInfo.if_name)); + if_name = (void *)xpc_dictionary_get_data(reply, + REACH_STATUS_IF_NAME, + &len); + if ((if_name != NULL) && (len > 0)) { + if (len > sizeof(targetPrivate->serverInfo.if_name)) { + len = sizeof(targetPrivate->serverInfo.if_name); + } + + bcopy(if_name, targetPrivate->serverInfo.if_name, len); + } + + targetPrivate->serverInfo.sleeping = xpc_dictionary_get_bool(reply, + REACH_STATUS_SLEEPING); + + if (targetPrivate->type == reachabilityTypeName) { + xpc_object_t addresses; + + if (targetPrivate->resolvedAddress != NULL) { + CFRelease(targetPrivate->resolvedAddress); + targetPrivate->resolvedAddress = NULL; + } + + targetPrivate->resolvedAddressError = xpc_dictionary_get_int64(reply, + REACH_STATUS_RESOLVED_ADDRESS_ERROR); + + addresses = xpc_dictionary_get_value(reply, REACH_STATUS_RESOLVED_ADDRESS); + if ((addresses != NULL) && (xpc_get_type(addresses) != XPC_TYPE_ARRAY)) { + addresses = NULL; + } + + if ((targetPrivate->resolvedAddressError == 0) && (addresses != NULL)) { + int i; + int n; + CFMutableArrayRef newAddresses; + + newAddresses = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + + n = xpc_array_get_count(addresses); + for (i = 0; i < n; i++) { + struct addrinfo *sa; + size_t len; + CFDataRef newAddress; + + sa = (struct addrinfo *)xpc_array_get_data(addresses, i, &len); + newAddress = CFDataCreate(NULL, (const UInt8 *)sa, len); + CFArrayAppendValue(newAddresses, newAddress); + CFRelease(newAddress); + } + + targetPrivate->resolvedAddress = newAddresses; + } else { + /* save the error associated with the attempt to resolve the name */ + targetPrivate->resolvedAddress = CFRetain(kCFNull); + } + targetPrivate->needResolve = FALSE; + } + + return; +} + + +__private_extern__ +Boolean +_reach_server_target_status(xpc_connection_t connection, SCNetworkReachabilityRef target) +{ + Boolean ok = FALSE; + xpc_object_t reply; + xpc_object_t reqdict; + Boolean retry = FALSE; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + if (_sc_debug) { + CFStringRef str; + + str = _SCNetworkReachabilityCopyTargetDescription(target); + SCLog(TRUE, LOG_INFO, CFSTR("%scheckReachability(%@)"), + targetPrivate->log_prefix, + str); + CFRelease(str); + } + + // create message + reqdict = xpc_dictionary_create(NULL, NULL, 0); + + // set request + xpc_dictionary_set_int64(reqdict, REACH_REQUEST, REACH_REQUEST_STATUS); + + // add the target [ID] + xpc_dictionary_set_uint64(reqdict, REACH_CLIENT_TARGET_ID, (uintptr_t)target); + + retry : + + reply = xpc_connection_send_message_with_reply_sync(connection, reqdict); + if (reply != NULL) { + xpc_type_t type; + + type = xpc_get_type(reply); + if (type == XPC_TYPE_DICTIONARY) { + int64_t status; + + status = xpc_dictionary_get_int64(reply, REACH_REQUEST_REPLY); + switch (status) { + case REACH_REQUEST_REPLY_OK : + ok = TRUE; + break; + case REACH_REQUEST_REPLY_UNKNOWN : + SCLog(TRUE, LOG_DEBUG, + CFSTR("reach target %p: SCNetworkReachability server failure, retry status"), + target); + retry = TRUE; + break; + default : + SCLog(TRUE, LOG_INFO, CFSTR("%s target status failed"), + targetPrivate->log_prefix); + log_xpc_object(" reply", reply); + } + + if (ok) { + _reach_reply_set_reachability(target, reply); + + if (_sc_debug) { + SCLog(TRUE, LOG_INFO, CFSTR("%s flags = 0x%08x"), + targetPrivate->log_prefix, + targetPrivate->serverInfo.flags); + if (targetPrivate->serverInfo.if_index != 0) { + SCLog(TRUE, LOG_INFO, CFSTR("%s device = %s (%hu%s)"), + targetPrivate->log_prefix, + targetPrivate->serverInfo.if_name, + targetPrivate->serverInfo.if_index, + targetPrivate->serverInfo.sleeping ? ", z" : ""); + } + if (targetPrivate->serverInfo.cycle != targetPrivate->cycle) { + SCLog(TRUE, LOG_INFO, CFSTR("%s forced"), + targetPrivate->log_prefix); + } + } + } + } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) { + SCLog(TRUE, LOG_ERR, + CFSTR("SCNetworkReachability server not available")); + serverAvailable = FALSE; + ok = TRUE; + } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) { + SCLog(TRUE, LOG_DEBUG, + CFSTR("reach target %p: SCNetworkReachability server failure, retry status"), + target); + retry = TRUE; + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("reach target %p: _targetStatus with unexpected reply"), + target); + log_xpc_object(" reply", reply); + } + + xpc_release(reply); + } + + if (retry) { + // reconnect + _reach_server_target_reconnect(connection, target); + + // and retry + retry = FALSE; + goto retry; + } + + xpc_release(reqdict); + return ok; +} + + +static Boolean +_reach_server_target_unschedule(xpc_connection_t connection, SCNetworkReachabilityRef target) +{ + Boolean ok = FALSE; + xpc_object_t reply; + xpc_object_t reqdict; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + // create message + reqdict = xpc_dictionary_create(NULL, NULL, 0); + + // set request + xpc_dictionary_set_int64(reqdict, REACH_REQUEST, REACH_REQUEST_UNSCHEDULE); + + // add the target [ID] + xpc_dictionary_set_uint64(reqdict, REACH_CLIENT_TARGET_ID, (uintptr_t)target); + + reply = xpc_connection_send_message_with_reply_sync(connection, reqdict); + if (reply != NULL) { + xpc_type_t type; + + type = xpc_get_type(reply); + if (type == XPC_TYPE_DICTIONARY) { + int64_t status; + + status = xpc_dictionary_get_int64(reply, REACH_REQUEST_REPLY); + switch (status) { + case REACH_REQUEST_REPLY_OK : + ok = TRUE; + break; + case REACH_REQUEST_REPLY_UNKNOWN : + SCLog(TRUE, LOG_DEBUG, + CFSTR("reach target %p: SCNetworkReachability server failure, no need to unschedule"), + target); + break; + default : + SCLog(TRUE, LOG_INFO, CFSTR("%s target unschedule failed"), + targetPrivate->log_prefix); + log_xpc_object(" reply", reply); + } + + if (ok) { + CFRelease(target); + } + } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) { + SCLog(TRUE, LOG_ERR, + CFSTR("SCNetworkReachability server not available")); + serverAvailable = FALSE; + ok = TRUE; + } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) { + SCLog(TRUE, LOG_DEBUG, + CFSTR("reach target %p: SCNetworkReachability server failure, no need to unschedule"), + target); + ok = TRUE; + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("reach target %p: _targetUnschedule with unexpected reply"), + target); + log_xpc_object(" reply", reply); + } + + xpc_release(reply); + } + + xpc_release(reqdict); + return ok; +} + + +#pragma mark - +#pragma mark Reconnect + + +static void +_reach_server_target_reconnect(xpc_connection_t connection, SCNetworkReachabilityRef target) +{ + Boolean ok; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + if (!targetPrivate->serverActive) { + // if target already removed + return; + } + + // server has been restarted + targetPrivate->cycle = 0; + + // re-associate with server + ok = _reach_server_target_add(connection, target); + if (!ok) { + // if we could not add the target + return; + } + + if (!targetPrivate->serverScheduled) { + // if not scheduled + return; + } + + // ... and re-schedule with server + ok = _reach_server_target_schedule(connection, target); + if (!ok) { + // if we could not reschedule the target + return; + } + + // .. and update our status + __SCNetworkReachabilityPerformNoLock(target); + + return; +} + + +static void +_reach_connection_reconnect(xpc_connection_t connection) +{ + dispatch_queue_t q; + + q = _reach_requests_rbt_queue(); + dispatch_sync(q, ^{ + struct rb_node *rbn; + struct rb_tree *rbt; + + rbt = _reach_requests_rbt(); + rbn = rb_tree_iterate(rbt, NULL, RB_DIR_RIGHT); + for ( ; rbn != NULL ; rbn = rb_tree_iterate(rbt, rbn, RB_DIR_LEFT)) { + reach_request_t *rbt_request; + SCNetworkReachabilityRef target; + + rbt_request = RBNODE_TO_REACH_REQUEST(rbn); + + target = rbt_request->target; + CFRetain(target); + dispatch_async(__SCNetworkReachability_concurrent_queue(), ^{ + _reach_server_target_reconnect(connection, target); + CFRelease(target); + }); + } + }); + + return; +} + + +#pragma mark - +#pragma mark SPI (exposed) + + +Boolean +_SCNetworkReachabilityServer_snapshot(void) +{ + xpc_connection_t c; + Boolean ok = FALSE; + xpc_object_t reply; + xpc_object_t reqdict; + + // initialize connection with SCNetworkReachability server + c = _reach_connection(); + if (c == NULL) { + return FALSE; + } + + // create message + reqdict = xpc_dictionary_create(NULL, NULL, 0); + + // set request + xpc_dictionary_set_int64(reqdict, REACH_REQUEST, REACH_REQUEST_SNAPSHOT); + + // add the process name (for debugging) + add_proc_name(reqdict); + + retry : + + // send request + reply = xpc_connection_send_message_with_reply_sync(c, reqdict); + if (reply != NULL) { + xpc_type_t type; + + type = xpc_get_type(reply); + if (type == XPC_TYPE_DICTIONARY) { + int64_t status; + + status = xpc_dictionary_get_int64(reply, REACH_REQUEST_REPLY); + ok = (status == REACH_REQUEST_REPLY_OK); + } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INVALID)) { + SCLog(TRUE, LOG_ERR, + CFSTR("SCNetworkReachability server not available")); + serverAvailable = FALSE; + } else if ((type == XPC_TYPE_ERROR) && (reply == XPC_ERROR_CONNECTION_INTERRUPTED)) { + SCLog(TRUE, LOG_DEBUG, + CFSTR("SCNetworkReachability server failure, retrying")); + xpc_release(reply); + goto retry; + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("_snapshot with unexpected reply")); + log_xpc_object(" reply", reply); + } + + xpc_release(reply); + } + + xpc_release(reqdict); + return ok; +} + + +__private_extern__ +Boolean +__SCNetworkReachabilityServer_targetAdd(SCNetworkReachabilityRef target) +{ + xpc_connection_t c; + Boolean ok; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + c = _reach_connection(); + if (c == NULL) { + return FALSE; + } + + ok = _reach_server_target_add(c, target); + if (ok) { + _SC_ATOMIC_CMPXCHG(&targetPrivate->serverActive, FALSE, TRUE); + } + + return ok; +} + + +__private_extern__ +void +__SCNetworkReachabilityServer_targetRemove(SCNetworkReachabilityRef target) +{ + xpc_connection_t c; + Boolean ok; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + if (!targetPrivate->serverActive) { + // if not active + return; + } + + c = _reach_connection(); + if (c == NULL) { + return; + } + + ok = _reach_server_target_remove(c, target); + if (ok) { + _SC_ATOMIC_CMPXCHG(&targetPrivate->serverActive, TRUE, FALSE); + } + + return; +} + + +__private_extern__ +Boolean +__SCNetworkReachabilityServer_targetSchedule(SCNetworkReachabilityRef target) +{ + xpc_connection_t c; + Boolean ok; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + c = _reach_connection(); + if (c == NULL) { + return FALSE; + } + + _reach_request_add(target); + ok = _reach_server_target_schedule(c, target); + if (ok) { + _SC_ATOMIC_CMPXCHG(&targetPrivate->serverScheduled, FALSE, TRUE); + } else { + _reach_request_remove(target); + } + + return ok; +} + + +__private_extern__ +Boolean +__SCNetworkReachabilityServer_targetStatus(SCNetworkReachabilityRef target) +{ + xpc_connection_t c; + Boolean ok; + + c = _reach_connection(); + if (c == NULL) { + return FALSE; + } + + ok = _reach_server_target_status(c, target); + return ok; +} + + +__private_extern__ +Boolean +__SCNetworkReachabilityServer_targetUnschedule(SCNetworkReachabilityRef target) +{ + xpc_connection_t c; + Boolean ok; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + if (!targetPrivate->serverScheduled) { + // if not scheduled + return TRUE; + } + + c = _reach_connection(); + if (c == NULL) { + return FALSE; + } + + ok = _reach_server_target_unschedule(c, target); + if (ok) { + _SC_ATOMIC_CMPXCHG(&targetPrivate->serverScheduled, TRUE, FALSE); + _reach_request_remove(target); + } else { + // if unschedule failed + } + + return ok; +} + +#endif // HAVE_REACHABILITY_SERVER diff --git a/SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_server.c b/SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_server.c new file mode 100644 index 0000000..27753af --- /dev/null +++ b/SystemConfiguration.fproj/reachability/SCNetworkReachabilityServer_server.c @@ -0,0 +1,2033 @@ +/* + * Copyright (c) 2011, 2012 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, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * 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 +#include +#include +#include "SCNetworkReachabilityInternal.h" + +#ifdef HAVE_REACHABILITY_SERVER + +#include +#include +#include +#include +#include +#include +#include + +#include "rb.h" + + +#pragma mark - +#pragma mark Globals + + +/* + * S_debug + * A boolean that enables additional logging. + */ +static boolean_t S_debug = FALSE; + + +#pragma mark - +#pragma mark Support functions + + +static void +log_xpc_object(const char *msg, xpc_object_t obj) +{ + char *desc; + + desc = xpc_copy_description(obj); + SCLog(S_debug, LOG_INFO, CFSTR("%s = %s"), msg, desc); + free(desc); +} + + +static __inline__ void +my_CFDictionaryApplyFunction(CFDictionaryRef theDict, + CFDictionaryApplierFunction applier, + void *context) +{ + CFAllocatorRef myAllocator; + CFDictionaryRef myDict; + + myAllocator = CFGetAllocator(theDict); + myDict = CFDictionaryCreateCopy(myAllocator, theDict); + CFDictionaryApplyFunction(myDict, applier, context); + CFRelease(myDict); + return; +} + + +#pragma mark - +#pragma mark SCNetworkReachability target support + + +static CFMutableDictionaryRef reach_digest_map; + + +static dispatch_queue_t +_server_concurrent_queue() +{ + static dispatch_once_t once; + static dispatch_queue_t q; + + dispatch_once(&once, ^{ + q = dispatch_queue_create(REACH_SERVICE_NAME ".concurrent", + DISPATCH_QUEUE_CONCURRENT); + dispatch_queue_set_width(q, 32); + }); + + return q; +} + + +static dispatch_queue_t +_server_digest_queue() +{ + static dispatch_once_t once; + static dispatch_queue_t q; + + dispatch_once(&once, ^{ + q = dispatch_queue_create(REACH_SERVICE_NAME ".digest", NULL); + }); + + return q; +} + + +static dispatch_group_t +_target_group(SCNetworkReachabilityRef target) +{ + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + return targetPrivate->serverGroup; +} + + +static dispatch_queue_t +_target_queue(SCNetworkReachabilityRef target) +{ + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + return targetPrivate->serverQueue; +} + + +#pragma mark - + + +/* + * _target_reference_add + * + * Note: use dispatch_sync(_server_digest_queue(), ^{ ... }); + */ +static void +_target_reference_add(SCNetworkReachabilityRef target, CFDataRef digest, xpc_connection_t connection) +{ + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + // take a reference to the target + CFRetain(target); + + // ensure that we have a dispatch group + if (targetPrivate->serverGroup == NULL) { + targetPrivate->serverGroup = dispatch_group_create(); + } + + // ensure that we have a dispatch queue + if (targetPrivate->serverQueue == NULL) { + char qname[256]; + + snprintf(qname, sizeof(qname), "com.apple.SCNetworkReachability.%p.server", target); + targetPrivate->serverQueue = dispatch_queue_create(qname, NULL); + } + + // bump the reference count + if (_SC_ATOMIC_INC(&targetPrivate->serverReferences) == 0) { + // and maintain a digest-->target mapping + targetPrivate->serverDigest = CFRetain(digest); + CFDictionarySetValue(reach_digest_map, digest, target); + } + + if (S_debug) { + CFStringRef str; + + str = _SCNetworkReachabilityCopyTargetDescription(target); + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> target %p: reference added (%@, %d)"), + connection, + target, + str, + targetPrivate->serverReferences); + CFRelease(str); + } + + return; +} + + +/* + * _target_reference_remove + * + * Note: use dispatch_sync(_server_digest_queue(), ^{ ... }); + */ +static void +_target_reference_remove(SCNetworkReachabilityRef target, xpc_connection_t connection) +{ + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + // drop the reference count + if (_SC_ATOMIC_DEC(&targetPrivate->serverReferences) == 0) { + /* + * if that was the last reference, we no longer need to + * keep the digest-->target mapping + */ + CFDictionaryRemoveValue(reach_digest_map, targetPrivate->serverDigest); + CFRelease(targetPrivate->serverDigest); + targetPrivate->serverDigest = NULL; + } + + if (S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> target %p: reference removed (%d)"), + connection, + target, + targetPrivate->serverReferences); + } + + // release a reference to the target + CFRelease(target); + + return; +} + + +#pragma mark - + + +#define MUTEX_LOCK(m) { \ + int _lock_ = (pthread_mutex_lock(m) == 0); \ + assert(_lock_); \ +} + +#define MUTEX_UNLOCK(m) { \ + int _unlock_ = (pthread_mutex_unlock(m) == 0); \ + assert(_unlock_); \ +} + + +static void +_target_reply_add_reachability(SCNetworkReachabilityRef target, + xpc_object_t reply) +{ + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + MUTEX_LOCK(&targetPrivate->lock); + + xpc_dictionary_set_uint64(reply, + REACH_STATUS_CYCLE, + targetPrivate->info.cycle); + xpc_dictionary_set_uint64(reply, + REACH_STATUS_FLAGS, + targetPrivate->info.flags); + xpc_dictionary_set_uint64(reply, + REACH_STATUS_IF_INDEX, + targetPrivate->info.if_index); + xpc_dictionary_set_data (reply, + REACH_STATUS_IF_NAME, + targetPrivate->info.if_name, + sizeof(targetPrivate->info.if_name)); + xpc_dictionary_set_bool (reply, + REACH_STATUS_SLEEPING, + targetPrivate->info.sleeping); + if (targetPrivate->type == reachabilityTypeName) { + if (isA_CFArray(targetPrivate->resolvedAddress)) { + xpc_object_t addresses; + CFIndex i; + CFIndex n; + + addresses = xpc_array_create(NULL, 0); + + n = CFArrayGetCount(targetPrivate->resolvedAddress); + for (i = 0; i < n; i++) { + CFDataRef address; + + address = CFArrayGetValueAtIndex(targetPrivate->resolvedAddress, i); + xpc_array_set_data(addresses, + XPC_ARRAY_APPEND, + CFDataGetBytePtr(address), + CFDataGetLength(address)); + } + + xpc_dictionary_set_value(reply, + REACH_STATUS_RESOLVED_ADDRESS, + addresses); + xpc_release(addresses); + } + xpc_dictionary_set_int64(reply, + REACH_STATUS_RESOLVED_ADDRESS_ERROR, + targetPrivate->resolvedAddressError); + } + + MUTEX_UNLOCK(&targetPrivate->lock); + + return; +} + + +#pragma mark - + + +typedef struct { + xpc_connection_t connection; + uint64_t target_id; +} reach_watcher_key_t; + +typedef struct { + unsigned int n_changes; +} reach_watcher_val_t; + + +static CFDataRef +_target_watcher_key_create(xpc_connection_t connection, + uint64_t target_id) +{ + CFDataRef key; + reach_watcher_key_t watcher_key; + + watcher_key.connection = connection; + watcher_key.target_id = target_id; + + key = CFDataCreate(NULL, (UInt8 *)&watcher_key, sizeof(watcher_key)); + return key; +} + + +static Boolean +_target_watcher_add(SCNetworkReachabilityRef target, + xpc_connection_t connection, + uint64_t target_id) +{ + __block Boolean ok = TRUE; + dispatch_queue_t q; + + q = _target_queue(target); + dispatch_sync(q, ^{ + CFDataRef key; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + if (targetPrivate->serverWatchers == NULL) { + ok = SCNetworkReachabilitySetDispatchQueue(target, q); + if (!ok) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> target %p: _watcher_add SCNetworkReachabilitySetDispatchQueue() failed: %s"), + connection, + target, + SCErrorString(SCError())); + return; + } + + targetPrivate->serverWatchers = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + + xpc_retain(connection); + + key = _target_watcher_key_create(connection, target_id); + if (CFDictionaryContainsKey(targetPrivate->serverWatchers, key)) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> target %p: watcher not added, c=0x%0llx, \"serverWatchers\" key exists"), + connection, + target, + target_id); + } else { + CFDataRef val; + static const reach_watcher_val_t watcher_val0 = { 0 }; + + val = CFDataCreate(NULL, (UInt8 *)&watcher_val0, sizeof(watcher_val0)); + CFDictionaryAddValue(targetPrivate->serverWatchers, key, val); + CFRelease(val); + + if (S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> target %p: watcher added, c=0x%0llx, n=%d"), + connection, + target, + target_id, + CFDictionaryGetCount(targetPrivate->serverWatchers)); + } + } + CFRelease(key); + }); + + return ok; +} + + +static Boolean +_target_watcher_checkin(SCNetworkReachabilityRef target, + xpc_connection_t connection, + uint64_t target_id) +{ + __block Boolean scheduled = FALSE; + + dispatch_sync(_target_queue(target), ^{ + CFDataRef key; + unsigned int n; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + CFDataRef val; + reach_watcher_val_t *watcher_val; + + if (targetPrivate->serverWatchers == NULL) { + // if no watchers + return; + } + + key = _target_watcher_key_create(connection, target_id); + val = CFDictionaryGetValue(targetPrivate->serverWatchers, key); + CFRelease(key); + if (val == NULL) { + // if the target [for this client] was not scheduled + return; + } + + // indicate that the target was scheduled + scheduled = TRUE; + + /* + * and note that the reachability flags for this target have + * been picked up by the client + */ + /* ALIGN: CF aligns to at least >8 byte boundries */ + watcher_val = (reach_watcher_val_t *)(void *)CFDataGetBytePtr(val); + n = _SC_ATOMIC_ZERO(&watcher_val->n_changes); + if (S_debug && (n > 0)) { + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> target %p: SCNetworkReachabilityGetFlags() after %d notification%s"), + connection, + target, + n, + (n == 1) ? "" : "s"); + } + }); + + return scheduled; +} + + +static Boolean +_target_watcher_remove(SCNetworkReachabilityRef target, + xpc_connection_t connection, + uint64_t target_id) +{ + __block Boolean ok = TRUE; + + dispatch_sync(_target_queue(target), ^{ + CFDataRef key; + CFIndex n; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + if (targetPrivate->serverWatchers == NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> target %p: watcher not removed, c=0x%0llx, no \"serverWatchers\""), + connection, + target, + target_id); + return; + } + + key = _target_watcher_key_create(connection, target_id); + if (!CFDictionaryContainsKey(targetPrivate->serverWatchers, key)) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> target %p: watcher not removed, c=0x%0llx, no \"serverWatchers\" key"), + connection, + target, + target_id); + CFRelease(key); + return; + } + + CFDictionaryRemoveValue(targetPrivate->serverWatchers, key); + xpc_release(connection); + CFRelease(key); + + n = CFDictionaryGetCount(targetPrivate->serverWatchers); + + if (S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> target %p: watcher removed, c=0x%0llx, n=%d"), + connection, + target, // server + target_id, // client + n); + } + + if (n == 0) { + CFRelease(targetPrivate->serverWatchers); + targetPrivate->serverWatchers = NULL; + + ok = SCNetworkReachabilitySetDispatchQueue(target, NULL); + if (!ok) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> target %p: _watcher_remove SCNetworkReachabilitySetDispatchQueue() failed: %s"), + connection, + target, + SCErrorString(SCError())); + return; + } + + // no more watchers, flags are no longer valid + (void) _SC_ATOMIC_CMPXCHG(&targetPrivate->serverInfoValid, TRUE, FALSE); + } + }); + + return ok; +} + + +#pragma mark - +#pragma mark Reachability [RBT] client support + + +typedef struct { + struct rb_node rbn; + xpc_connection_t connection; + pid_t pid; + const char *proc_name; + CFMutableDictionaryRef targets; // target_id --> SCNetworkReachabilityRef +} reach_client_t; + + +#define RBNODE_TO_REACH_CLIENT(node) \ + ((reach_client_t *)((uintptr_t)node - offsetof(reach_client_t, rbn))) + + +static int +_rbt_compare_transaction_nodes(const struct rb_node *n1, const struct rb_node *n2) +{ + uint64_t a = (uintptr_t)RBNODE_TO_REACH_CLIENT(n1)->connection; + uint64_t b = (uintptr_t)RBNODE_TO_REACH_CLIENT(n2)->connection; + + return (a - b); +} + + +static int +_rbt_compare_transaction_key(const struct rb_node *n1, const void *key) +{ + uint64_t a = (uintptr_t)RBNODE_TO_REACH_CLIENT(n1)->connection; + uint64_t b = *(uintptr_t *)key; + + return (a - b); +} + + +static struct rb_tree * +_reach_clients_rbt() +{ + static dispatch_once_t once; + static const struct rb_tree_ops ops = { + .rbto_compare_nodes = _rbt_compare_transaction_nodes, + .rbto_compare_key = _rbt_compare_transaction_key, + }; + static struct rb_tree rbtree; + + dispatch_once(&once, ^{ + rb_tree_init(&rbtree, &ops); + }); + + return &rbtree; +} + + +static dispatch_queue_t +_reach_connection_queue() +{ + static dispatch_once_t once; + static dispatch_queue_t q; + + dispatch_once(&once, ^{ + q = dispatch_queue_create(REACH_SERVICE_NAME ".connection", NULL); + }); + + return q; +} + + +static reach_client_t * +_reach_client_create(xpc_connection_t connection) +{ + reach_client_t *client; + + client = calloc(1, sizeof(*client)); + client->connection = connection; + client->pid = xpc_connection_get_pid(connection); + client->proc_name = NULL; + client->targets = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + return client; +} + + +static void +_reach_client_release(reach_client_t *client) +{ + if (client->proc_name != NULL) { + free((void *)client->proc_name); + } + CFRelease(client->targets); + free(client); + return; +} + + +static void +_reach_client_remove_target(const void *key, const void *value, void *context) +{ + xpc_connection_t connection = (xpc_connection_t)context; + SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)value; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + // check if we have anyone watching this target + if (targetPrivate->serverWatchers != NULL) { + CFIndex n; + + n = CFDictionaryGetCount(targetPrivate->serverWatchers); + if (n > 0) { + CFIndex i; + const void * watchers_q[32]; + const void ** watchers = watchers_q; + + if (n > sizeof(watchers_q)/sizeof(watchers[0])) { + watchers = CFAllocatorAllocate(NULL, n * sizeof(CFDataRef), 0); + } + CFDictionaryGetKeysAndValues(targetPrivate->serverWatchers, watchers, NULL); + + for (i = 0; i < n; i++) { + CFDataRef key; + reach_watcher_key_t *watcher_key; + + key = (CFDataRef)watchers[i]; + /* ALIGN: CF aligns to >8 byte boundries */ + watcher_key = (reach_watcher_key_t *)(void *)CFDataGetBytePtr(key); + if (watcher_key->connection == connection) { + // remove watcher references for THIS connection + _target_watcher_remove(target, + watcher_key->connection, + watcher_key->target_id); + } + } + + if (watchers != watchers_q) { + CFAllocatorDeallocate(NULL, watchers); + } + } + } + + // remove our reference to this target + dispatch_sync(_server_digest_queue(), ^{ + _target_reference_remove(target, connection); + }); + + return; +} + + +static void +_reach_client_remove(xpc_connection_t connection) +{ + struct rb_tree *rbtree = _reach_clients_rbt(); + struct rb_node *rbn; + + rbn = rb_tree_find_node(rbtree, &connection); + if (rbn != NULL) { + reach_client_t *client; + + client = RBNODE_TO_REACH_CLIENT(rbn); + + // remove any remaining target references (for this client) + my_CFDictionaryApplyFunction(client->targets, + _reach_client_remove_target, + (void *)connection); + + rb_tree_remove_node(rbtree, rbn); + _reach_client_release(client); + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> _reach_client_remove: unexpected client"), + connection); + } + + return; +} + + +static __inline__ CFDataRef +_client_target_key_create(uint64_t target_id) +{ + CFDataRef target_key; + + target_key = CFDataCreate(NULL, (UInt8 *)&target_id, sizeof(target_id)); + return target_key; +} + + +static SCNetworkReachabilityRef +_client_target_copy(reach_client_t *client, uint64_t target_id) +{ + SCNetworkReachabilityRef target; + CFDataRef target_key; + + target_key = _client_target_key_create(target_id); + target = CFDictionaryGetValue(client->targets, target_key); + CFRelease(target_key); + + if (target != NULL) { + CFRetain(target); + } + + return target; +} + + +static Boolean +_client_target_set(reach_client_t *client, uint64_t target_id, SCNetworkReachabilityRef target) +{ + Boolean added; + CFDataRef target_key; + + target_key = _client_target_key_create(target_id); + added = !CFDictionaryContainsKey(client->targets, target_key); + if (added) { + CFDictionarySetValue(client->targets, target_key, target); + } + CFRelease(target_key); + + return added; +} + + +static void +_client_target_remove(reach_client_t *client, uint64_t target_id) +{ + CFDataRef target_key; + + target_key = _client_target_key_create(target_id); + CFDictionaryRemoveValue(client->targets, target_key); + CFRelease(target_key); + + return; +} + + +#pragma mark - +#pragma mark Reachability [XPC] server functions + +/* + * _reach_changed + * + * Note: should be exec'd on the target queue + */ +static void +_reach_changed(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) +{ + CFIndex i; + CFIndex n; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + const void * watcher_keys_q[32]; + const void ** watcher_keys = watcher_keys_q; + const void * watcher_vals_q[32]; + const void ** watcher_vals = watcher_vals_q; + + if (S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("%sprocess reachability changed, flags = 0x%08x"), + targetPrivate->log_prefix, + flags); + } + + if (targetPrivate->serverWatchers == NULL) { + // if no watchers + return; + } + + n = CFDictionaryGetCount(targetPrivate->serverWatchers); + if (n == 0) { + // if no watchers + return; + } + + /* + * Because we are actively watching for additional changes + * we mark the flags as "valid" + */ + if (_SC_ATOMIC_CMPXCHG(&targetPrivate->serverInfoValid, FALSE, TRUE)) { + if (S_debug) { + SCLog(TRUE, LOG_INFO, CFSTR(" flags are now \"valid\"")); + } + } + + // notify all of the watchers + if (n > sizeof(watcher_keys_q)/sizeof(watcher_keys[0])) { + watcher_keys = CFAllocatorAllocate(NULL, n * sizeof(CFDataRef), 0); + watcher_vals = CFAllocatorAllocate(NULL, n * sizeof(CFDataRef), 0); + } + + CFDictionaryGetKeysAndValues(targetPrivate->serverWatchers, + watcher_keys, + watcher_vals); + + for (i = 0; i < n; i++) { + xpc_connection_t connection; + CFDataRef key; + uint64_t target_id; + CFDataRef val; + reach_watcher_key_t *watcher_key; + reach_watcher_val_t *watcher_val; + + val = (CFDataRef)watcher_vals[i]; + /* ALIGN: CF aligns to >8 byte boundries */ + watcher_val = (reach_watcher_val_t *)(void *)CFDataGetBytePtr(val); + + if (_SC_ATOMIC_INC(&watcher_val->n_changes) > 0) { + // if we've already sent a notification + continue; + } + + key = (CFDataRef)watcher_keys[i]; + /* ALIGN: CF aligns to >8 byte boundries */ + watcher_key = (reach_watcher_key_t *)(void *)CFDataGetBytePtr(key); + + connection = xpc_retain(watcher_key->connection); + target_id = watcher_key->target_id; + dispatch_async(_reach_connection_queue(), ^{ + xpc_object_t reply; + + // create our [async] notification + reply = xpc_dictionary_create(NULL, NULL, 0); + + // set notification + xpc_dictionary_set_int64(reply, + MESSAGE_NOTIFY, + MESSAGE_REACHABILITY_STATUS); + + // set target ID + xpc_dictionary_set_uint64(reply, + REACH_CLIENT_TARGET_ID, + target_id); + + log_xpc_object(" reply [async]", reply); + xpc_connection_send_message(connection, reply); + + xpc_release(reply); + xpc_release(connection); + }); + } + + if (n > sizeof(watcher_keys_q)/sizeof(watcher_keys[0])) { + CFAllocatorDeallocate(NULL, watcher_keys); + CFAllocatorDeallocate(NULL, watcher_vals); + } + + return; +} + + +static void +sanitize_address(const struct sockaddr *from, struct sockaddr *to) +{ + switch (from->sa_family) { + case AF_INET : { + /* ALIGN: cast okay, alignment not assumed. */ + struct sockaddr_in *from4 = (struct sockaddr_in *)(void *)from; + struct sockaddr_in *to4 = (struct sockaddr_in *)(void *)to; + + bzero(to4, sizeof(*to4)); + to4->sin_len = sizeof(*to4); + to4->sin_family = AF_INET; + bcopy(&from4->sin_addr, &to4->sin_addr, sizeof(to4->sin_addr)); + break; + } + + case AF_INET6 : { + /* ALIGN: cast okay, alignment not assumed. */ + struct sockaddr_in6 *from6 = (struct sockaddr_in6 *)(void *)from; + struct sockaddr_in6 *to6 = (struct sockaddr_in6 *)(void *)to; + + bzero(to6, sizeof(*to6)); + to6->sin6_len = sizeof(*to6); + to6->sin6_family = AF_INET6; + bcopy(&from6->sin6_addr, &to6->sin6_addr, sizeof(to6->sin6_addr)); + to6->sin6_scope_id = from6->sin6_scope_id; + break; + } + + default: + bcopy(from, to, from->sa_len); + break; + } + + return; +} + + +static void +target_add(reach_client_t *client, xpc_object_t request) +{ + const char *name; + const char *serv; + const struct sockaddr *localAddress; + struct sockaddr_storage localAddress0; + const struct sockaddr *remoteAddress; + struct sockaddr_storage remoteAddress0; + const struct addrinfo *hints; + int64_t if_index; + const char *if_name = NULL; + bool onDemandBypass = FALSE; + uint64_t target_id; + + + unsigned char bytes[CC_SHA1_DIGEST_LENGTH]; + CC_SHA1_CTX ctx; + CFDataRef digest = NULL; + size_t len; + xpc_connection_t remote; + xpc_object_t reply; + bool resolverBypass = FALSE; + uint64_t status = REACH_REQUEST_REPLY_FAILED; + + Boolean added; + __block Boolean ok = TRUE; + __block SCNetworkReachabilityRef target = NULL; + + if (S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> create reachability target"), + client->connection); +// log_xpc_object(" create", request); + } + + remote = xpc_dictionary_get_remote_connection(request); + reply = xpc_dictionary_create_reply(request); + if (reply == NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> target_add: xpc_dictionary_create_reply: failed"), + client->connection); + return; + } + + target_id = xpc_dictionary_get_uint64(request, REACH_CLIENT_TARGET_ID); + if (target_id == 0) { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "no target ID"); + goto done; + } + + // create a "digest" of the [new] target + + CC_SHA1_Init(&ctx); + + name = xpc_dictionary_get_string(request, REACH_TARGET_NAME); + if (name != NULL) { + CC_SHA1_Update(&ctx, name, strlen(name)); + } + + serv = xpc_dictionary_get_string(request, REACH_TARGET_SERV); + if (serv != NULL) { + CC_SHA1_Update(&ctx, serv, strlen(serv)); + } + + localAddress = xpc_dictionary_get_data(request, REACH_TARGET_LOCAL_ADDR, &len); + if (localAddress != NULL) { + if ((len == localAddress->sa_len) && (len <= sizeof(struct sockaddr_storage))) { + sanitize_address(localAddress, (struct sockaddr *)&localAddress0); + CC_SHA1_Update(&ctx, &localAddress0, len); + } else { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "local address: size error"); + goto done; + } + } + + remoteAddress = xpc_dictionary_get_data(request, REACH_TARGET_REMOTE_ADDR, &len); + if (remoteAddress != NULL) { + if ((len == remoteAddress->sa_len) && (len <= sizeof(struct sockaddr_storage))) { + sanitize_address(remoteAddress, (struct sockaddr *)&remoteAddress0); + CC_SHA1_Update(&ctx, &remoteAddress0, len); + } else { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "remote address: size error"); + goto done; + } + } + + hints = xpc_dictionary_get_data(request, REACH_TARGET_HINTS, &len); + if (hints != NULL) { + if (len == sizeof(struct addrinfo)) { + CC_SHA1_Update(&ctx, hints, len); + } else { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "hints: size error"); + goto done; + } + } + + if_index = xpc_dictionary_get_int64(request, REACH_TARGET_IF_INDEX); + if (if_index != 0) { + if_name = xpc_dictionary_get_string(request, REACH_TARGET_IF_NAME); + if (if_name != NULL) { + CC_SHA1_Update(&ctx, if_name, strlen(if_name)); + } + } + + onDemandBypass = xpc_dictionary_get_bool(request, REACH_TARGET_ONDEMAND_BYPASS); + if (onDemandBypass) { + CC_SHA1_Update(&ctx, &onDemandBypass, sizeof(onDemandBypass)); + } + + resolverBypass = xpc_dictionary_get_bool(request, REACH_TARGET_RESOLVER_BYPASS); + if (resolverBypass) { + CC_SHA1_Update(&ctx, &resolverBypass, sizeof(resolverBypass)); + } + + + CC_SHA1_Final(bytes, &ctx); + digest = CFDataCreate(NULL, bytes, sizeof(bytes)); + + /* + * Check to see if we already have a SCNetworkReachability object + * for this digest. If so, we'll share the existing target. If not, + * create a new [shared] target. + */ + dispatch_sync(_server_digest_queue(), ^{ + target = CFDictionaryGetValue(reach_digest_map, digest); + if (target != NULL) { + CFRetain(target); + } else { + CFDataRef data; + CFMutableDictionaryRef options; + CFStringRef str; + + options = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (name != NULL) { + str = CFStringCreateWithCString(NULL, name, kCFStringEncodingUTF8); + CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str); + CFRelease(str); + } + if (serv != NULL) { + str = CFStringCreateWithCString(NULL, serv, kCFStringEncodingUTF8); + CFDictionarySetValue(options, kSCNetworkReachabilityOptionServName, str); + CFRelease(str); + } + if (localAddress != NULL) { + data = CFDataCreate(NULL, (const UInt8 *)&localAddress0, localAddress0.ss_len); + CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data); + CFRelease(data); + } + if (remoteAddress != NULL) { + data = CFDataCreate(NULL, (const UInt8 *)&remoteAddress0, remoteAddress0.ss_len); + CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data); + CFRelease(data); + } + if (hints != NULL) { + data = CFDataCreate(NULL, (const UInt8 *)hints, sizeof(struct addrinfo)); + CFDictionarySetValue(options, kSCNetworkReachabilityOptionHints, data); + CFRelease(data); + } + if (onDemandBypass) { + CFDictionarySetValue(options, + kSCNetworkReachabilityOptionConnectionOnDemandBypass, + kCFBooleanTrue); + } + if (resolverBypass) { + CFDictionarySetValue(options, + kSCNetworkReachabilityOptionResolverBypass, + kCFBooleanTrue); + } + CFDictionarySetValue(options, + kSCNetworkReachabilityOptionServerBypass, + kCFBooleanTrue); + target = SCNetworkReachabilityCreateWithOptions(NULL, options); + CFRelease(options); + if (target == NULL) { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "SCNetworkReachabilityCreateWithOptions failed"); + ok = FALSE; + return; + } + + // because the interface name may not (no longer) be valid we set + // this after we've created the SCNetworkReachabilty object + if ((if_index != 0) && (if_name != NULL)) { + SCNetworkReachabilityPrivateRef targetPrivate; + + targetPrivate = (SCNetworkReachabilityPrivateRef)target; + targetPrivate->if_index = if_index; + strlcpy(targetPrivate->if_name, if_name, sizeof(targetPrivate->if_name)); + } + + + ok = SCNetworkReachabilitySetCallback(target, _reach_changed, NULL); + if (!ok) { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "SCNetworkReachabilitySetCallback failed"); + CFRelease(target); + target = NULL; + return; + } + } + + // bump the number of references to this target + _target_reference_add(target, digest, client->connection); + }); + + if (!ok) { + goto done; + } + + /* + * add an association for the client's target_id to the [shared] + * SCNetworkReachability object. + */ + added = _client_target_set(client, target_id, target); + if (!added) { + // if we already had a reference to the target (e.g. reconnect) + dispatch_sync(_server_digest_queue(), ^{ + _target_reference_remove(target, client->connection); + }); + } + + status = REACH_REQUEST_REPLY_OK; + + done : + + xpc_dictionary_set_int64(reply, REACH_REQUEST_REPLY, status); +// log_xpc_object(" reply", reply); + xpc_connection_send_message(remote, reply); + xpc_release(reply); + + if (digest != NULL) CFRelease(digest); + if (target != NULL) CFRelease(target); + return; +} + + +static void +target_remove(reach_client_t *client, xpc_object_t request) +{ + xpc_connection_t remote; + xpc_object_t reply; + uint64_t status = REACH_REQUEST_REPLY_FAILED; + SCNetworkReachabilityRef target = NULL; + uint64_t target_id; + + if (S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> remove reachability target"), + client->connection); +// log_xpc_object(" remove", request); + } + + remote = xpc_dictionary_get_remote_connection(request); + reply = xpc_dictionary_create_reply(request); + if (reply == NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> target_remove: xpc_dictionary_create_reply: failed"), + client->connection); + return; + } + + target_id = xpc_dictionary_get_uint64(request, REACH_CLIENT_TARGET_ID); + if (target_id == 0) { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "no target ID"); + goto done; + } + + target = _client_target_copy(client, target_id); + if (target == NULL) { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "no target"); + status = REACH_REQUEST_REPLY_UNKNOWN; + goto done; + } + + /* + * remove the association from the client's target_id to the [shared] + * SCNetworkReachability object. + */ + _client_target_remove(client, target_id); + + // drop the number of references to this target + dispatch_sync(_server_digest_queue(), ^{ + _target_reference_remove(target, client->connection); + }); + + status = REACH_REQUEST_REPLY_OK; + + done : + + xpc_dictionary_set_int64(reply, REACH_REQUEST_REPLY, status); +// log_xpc_object(" reply", reply); + xpc_connection_send_message(remote, reply); + xpc_release(reply); + + if (target != NULL) CFRelease(target); + return; +} + + +static void +target_schedule(reach_client_t *client, xpc_object_t request) +{ + Boolean ok; + xpc_connection_t remote; + xpc_object_t reply; + uint64_t status = REACH_REQUEST_REPLY_FAILED; + SCNetworkReachabilityRef target = NULL; + uint64_t target_id; + + if (S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> schedule reachability target"), + client->connection); +// log_xpc_object(" schedule", request); + } + + remote = xpc_dictionary_get_remote_connection(request); + reply = xpc_dictionary_create_reply(request); + if (reply == NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> target_schedule: xpc_dictionary_create_reply: failed"), + client->connection); + return; + } + + target_id = xpc_dictionary_get_uint64(request, REACH_CLIENT_TARGET_ID); + if (target_id == 0) { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "no target ID"); + goto done; + } + + target = _client_target_copy(client, target_id); + if (target == NULL) { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "no target"); + status = REACH_REQUEST_REPLY_UNKNOWN; + goto done; + } + + // enable monitoring + ok = _target_watcher_add(target, client->connection, target_id); + if (ok) { + status = REACH_REQUEST_REPLY_OK; + } + + done : + + xpc_dictionary_set_int64(reply, REACH_REQUEST_REPLY, status); +// log_xpc_object(" reply", reply); + xpc_connection_send_message(remote, reply); + xpc_release(reply); + + if (target != NULL) CFRelease(target); + return; +} + + +static void +target_status(reach_client_t *client, xpc_object_t request) +{ + xpc_connection_t remote; + xpc_object_t reply; + __block Boolean reply_now = TRUE; + Boolean scheduled; + uint64_t status = REACH_REQUEST_REPLY_FAILED; + SCNetworkReachabilityRef target = NULL; + uint64_t target_id; + + if(S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> get status of reachability target"), + client->connection); +// log_xpc_object(" status", request); + } + + remote = xpc_dictionary_get_remote_connection(request); + reply = xpc_dictionary_create_reply(request); + if (reply == NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> target_status: xpc_dictionary_create_reply: failed"), + client->connection); + return; + } + + target_id = xpc_dictionary_get_uint64(request, REACH_CLIENT_TARGET_ID); + if (target_id == 0) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> target_status: no target"), + client->connection); + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "no target ID"); + goto done; + } + + target = _client_target_copy(client, target_id); + if (target == NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> target_status: no target (0x%0llx)"), + client->connection, + target_id); + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "no target"); + status = REACH_REQUEST_REPLY_UNKNOWN; + goto done; + } + + /* + * Check to see if the target [for this client] had been "scheduled". + * + * If so, also mark that we've picked up the current reachability + * flags and that any pending notifications have been processed. + */ + scheduled = _target_watcher_checkin(target, client->connection, target_id); + + /* + * return current reachability information to the caller + */ + dispatch_sync(_target_queue(target), ^{ + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + if (scheduled) { + /* + * The client "scheduled" this target. As such, we + * know that this an async query and that we only + * need to return the "last known" flags. + */ + _target_reply_add_reachability(target, reply); +// log_xpc_object(" reply [scheduled]", reply); + + if (S_debug) { + CFStringRef str; + + str = _SCNetworkReachabilityCopyTargetFlags(target); + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> reply [scheduled], %@"), + client->connection, + str); + CFRelease(str); + } + } else { + /* + * The client has NOT "scheduled" this target. As + * such, we know that this is a sync query and that + * must return "current" flags. + */ + if (targetPrivate->scheduled && targetPrivate->serverInfoValid) { + /* + * The server target has been "scheduled" and we + * have flags that are "current". + */ + _target_reply_add_reachability(target, reply); +// log_xpc_object(" reply [scheduled/valid]", reply); + + if (S_debug) { + CFStringRef str; + + str = _SCNetworkReachabilityCopyTargetFlags(target); + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> reply [scheduled/valid], %@"), + client->connection, + str); + CFRelease(str); + } + } else { + dispatch_group_t group; + + /* + * The server target has NOT been "scheduled" (or + * we do not have "current" flags. This means that + * we must query for the current information and + * return the flags to the client when they are + * available. + */ + + reply_now = FALSE; + + group = _target_group(target); + if (_SC_ATOMIC_INC(&targetPrivate->serverQueryActive) == 0) { + CFRetain(target); + dispatch_group_async(group, _server_concurrent_queue(), ^{ + SCNetworkReachabilityFlags flags; + unsigned int n; + Boolean ok; + + // query for the flags + ok = SCNetworkReachabilityGetFlags(target, &flags); + flags = targetPrivate->info.flags; // get the "raw" flags + if (!ok) { + SCLog(TRUE, LOG_ERR, + CFSTR("SCNetworkReachabilityGetFlags() [sync query] failed" + "\n target = %@" + "\n status = %s"), + target, + SCErrorString(SCError())); + } + + // flags are now available + n = _SC_ATOMIC_ZERO(&targetPrivate->serverQueryActive); + if (S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("%sSCNetworkReachabilityGetFlags() [sync query] complete, n = %d"), + targetPrivate->log_prefix, + n); + } + + CFRelease(target); + }); + } + + CFRetain(target); + dispatch_group_notify(group, _target_queue(target), ^{ + // flags are now available + _target_reply_add_reachability(target, reply); + xpc_dictionary_set_int64(reply, REACH_REQUEST_REPLY, REACH_REQUEST_REPLY_OK); +// log_xpc_object(" reply [delayed]", reply); + + if (S_debug) { + CFStringRef str; + + str = _SCNetworkReachabilityCopyTargetFlags(target); + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> reply [delayed], %@"), + client->connection, + str); + CFRelease(str); + } + + xpc_connection_send_message(remote, reply); + xpc_release(reply); + + CFRelease(target); + }); + } + } + }); + + status = REACH_REQUEST_REPLY_OK; + + done : + + if (reply_now) { + xpc_dictionary_set_int64(reply, REACH_REQUEST_REPLY, status); + + if (status != REACH_REQUEST_REPLY_OK) { +// log_xpc_object(" reply [!]", reply); + + if (S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> reply [!]"), + client->connection); + } + } + + xpc_connection_send_message(remote, reply); + xpc_release(reply); + } else if (S_debug) { + CFStringRef str; + + str = _SCNetworkReachabilityCopyTargetFlags(target); + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> no reply [yet], %@"), + client->connection, + str); + CFRelease(str); + } + + if (target != NULL) CFRelease(target); + return; +} + + +static void +target_unschedule(reach_client_t *client, xpc_object_t request) +{ + Boolean ok; + xpc_connection_t remote; + xpc_object_t reply; + uint64_t status = REACH_REQUEST_REPLY_FAILED; + SCNetworkReachabilityRef target = NULL; + uint64_t target_id; + + if (S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> unschedule reachability target"), + client->connection); +// log_xpc_object(" unschedule", request); + } + + remote = xpc_dictionary_get_remote_connection(request); + reply = xpc_dictionary_create_reply(request); + if (reply == NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> target_unschedule: xpc_dictionary_create_reply: failed"), + client->connection); + return; + } + + target_id = xpc_dictionary_get_uint64(request, REACH_CLIENT_TARGET_ID); + if (target_id == 0) { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "no target ID"); + goto done; + } + + target = _client_target_copy(client, target_id); + if (target == NULL) { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "no target"); + status = REACH_REQUEST_REPLY_UNKNOWN; + goto done; + } + + // disable monitoring + ok = _target_watcher_remove(target, client->connection, target_id); + if (ok) { + status = REACH_REQUEST_REPLY_OK; + } + + done : + + xpc_dictionary_set_int64(reply, REACH_REQUEST_REPLY, status); +// log_xpc_object(" reply", reply); + xpc_connection_send_message(remote, reply); + xpc_release(reply); + + if (target != NULL) CFRelease(target); + return; +} + + +#define SNAPSHOT_PATH_STATE _PATH_VARTMP "configd-reachability" + + +static void +_snapshot_digest_watcher(const void *key, const void *value, void *context) +{ + FILE *f = (FILE *)context; + static reach_client_t no_client = { + .pid = 0, + .proc_name = "?", + }; + struct rb_node *rbn; + reach_client_t *rbt_client; + reach_watcher_key_t *watcher_key; + reach_watcher_val_t *watcher_val; + + /* ALIGN: CF aligns to >8 byte boundries */ + watcher_key = (reach_watcher_key_t *)(void *)CFDataGetBytePtr(key); + watcher_val = (reach_watcher_val_t *)(void *)CFDataGetBytePtr(value); + + rbn = rb_tree_find_node(_reach_clients_rbt(), &watcher_key->connection); + if (rbn == NULL) { + rbn = &no_client.rbn; + } + + rbt_client = RBNODE_TO_REACH_CLIENT(rbn); + + SCPrint(TRUE, f, + CFSTR(" connection = %p, target(c) = 0x%0llx, command = %s, pid = %d, changes = %u\n"), + watcher_key->connection, + watcher_key->target_id, + rbt_client->proc_name, + rbt_client->pid, + watcher_val->n_changes); + + return; +} + + +static void +_snapshot_digest(const void *key, const void *value, void *context) +{ + FILE *f = (FILE *)context; + CFStringRef digest = (CFStringRef)key; + dispatch_queue_t q; + SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)value; + SCNetworkReachabilityPrivateRef targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + q = _target_queue(target); + dispatch_sync(q, ^{ + SCPrint(TRUE, f, CFSTR("\n digest : %@\n"), digest); + SCPrint(TRUE, f, CFSTR(" %@\n"), target); + SCPrint(TRUE, f, CFSTR(" valid = %s, active = %u, refs = %u\n"), + targetPrivate->serverInfoValid ? "Y" : "N", + targetPrivate->serverQueryActive, + targetPrivate->serverReferences); + + SCPrint(TRUE, f, CFSTR(" network %d.%3.3d"), + targetPrivate->last_network.tv_sec, + targetPrivate->last_network.tv_usec / 1000); +#if !TARGET_OS_IPHONE + SCPrint(TRUE, f, CFSTR(", power %d.%3.3d"), + targetPrivate->last_power.tv_sec, + targetPrivate->last_power.tv_usec / 1000); +#endif // !TARGET_OS_IPHONE + if (targetPrivate->type == reachabilityTypeName) { + SCPrint(TRUE, f, CFSTR(", DNS %d.%3.3d"), + targetPrivate->last_dns.tv_sec, + targetPrivate->last_dns.tv_usec / 1000); + if (timerisset(&targetPrivate->dnsQueryEnd)) { + struct timeval dnsQueryElapsed; + + timersub(&targetPrivate->dnsQueryEnd, + &targetPrivate->dnsQueryStart, + &dnsQueryElapsed); + SCPrint(TRUE, f, CFSTR(" (query %d.%3.3d / reply %d.%3.3d)"), + targetPrivate->dnsQueryStart.tv_sec, + targetPrivate->dnsQueryStart.tv_usec / 1000, + dnsQueryElapsed.tv_sec, + dnsQueryElapsed.tv_usec / 1000); + } + } + if (timerisset(&targetPrivate->last_push)) { + SCPrint(TRUE, f, CFSTR(", last notify %d.%3.3d"), + targetPrivate->last_push.tv_sec, + targetPrivate->last_push.tv_usec / 1000); + } + SCPrint(TRUE, f, CFSTR("\n")); + + if (targetPrivate->serverWatchers != NULL) { + CFDictionaryApplyFunction(targetPrivate->serverWatchers, + _snapshot_digest_watcher, + f); + } + }); + + return; +} + + +static void +_snapshot_target(const void *key, const void *value, void *context) +{ + FILE *f = (FILE *)context; + SCNetworkReachabilityRef target = (SCNetworkReachabilityRef)value; + uint64_t target_id; + CFDataRef target_key = (CFDataRef)key; + + /* ALIGN: CF aligns > 8 byte boundries */ + target_id = *(uint64_t *)(void *)CFDataGetBytePtr(target_key); + + SCPrint(TRUE, f, + CFSTR(" target(c) = 0x%0llx, target(s) = %@\n"), + target_id, + target); + + return; +} + + +static void +_snapshot(reach_client_t *client, xpc_object_t request) +{ + uid_t euid; + FILE *f; + int fd; + Boolean ok = FALSE; + struct rb_node *rbn; + struct rb_tree *rbt; + xpc_connection_t remote; + xpc_object_t reply; + + if (S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("<%p> snapshot"), + client->connection); +// log_xpc_object(" create", request); + } + + remote = xpc_dictionary_get_remote_connection(request); + reply = xpc_dictionary_create_reply(request); + if (reply == NULL) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> _snapshot: xpc_dictionary_create_reply: failed"), + client->connection); + return; + } + + euid = xpc_connection_get_euid(remote); + if (euid != 0) { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "Permission denied."); + goto done; + } + + // Save a snapshot of the SCNetworkReachability server "state" + + (void) unlink(SNAPSHOT_PATH_STATE); + fd = open(SNAPSHOT_PATH_STATE, O_WRONLY|O_CREAT|O_TRUNC|O_EXCL, 0644); + if (fd == -1) { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "open: failed"); + goto done; + } + f = fdopen(fd, "w"); + if (f == NULL) { + xpc_dictionary_set_string(reply, + REACH_REQUEST_REPLY_DETAIL, + "fdopen: failed"); + goto done; + } + + // provide connection/client info + + SCPrint(TRUE, f, CFSTR("Clients :\n")); + rbt = _reach_clients_rbt(); + rbn = rb_tree_iterate(rbt, NULL, RB_DIR_RIGHT); + if (rbn != NULL) { + while (rbn != NULL) { + reach_client_t *rbt_client; + + rbt_client = RBNODE_TO_REACH_CLIENT(rbn); + SCPrint(TRUE, f, + CFSTR("\n connection = %p, client = %p, command = %s, pid = %d\n"), + rbt_client->connection, + rbt_client, + rbt_client->proc_name != NULL ? rbt_client->proc_name : "?", + rbt_client->pid); + my_CFDictionaryApplyFunction(rbt_client->targets, + _snapshot_target, + f); + + rbn = rb_tree_iterate(rbt, rbn, RB_DIR_LEFT); + } + } else { + SCPrint(TRUE, f, CFSTR(" None.\n")); + } + SCPrint(TRUE, f, CFSTR("\n")); + + // provide "digest" info + + SCPrint(TRUE, f, CFSTR("Digests :\n")); + dispatch_sync(_server_digest_queue(), ^{ + if (reach_digest_map != NULL) { + CFDictionaryApplyFunction(reach_digest_map, + _snapshot_digest, + f); + } + }); + + (void) fclose(f); + + ok = TRUE; + + done : + + xpc_dictionary_set_int64(reply, + REACH_REQUEST_REPLY, + ok ? REACH_REQUEST_REPLY_OK : REACH_REQUEST_REPLY_FAILED); +// log_xpc_object(" reply", reply); + xpc_connection_send_message(remote, reply); + xpc_release(reply); + + return; +} + + +static __inline__ void +_extract_client_info(reach_client_t *client, xpc_object_t request) +{ + // if available/needed, save the process name + if (client->proc_name == NULL) { + const char *proc_name; + + proc_name = xpc_dictionary_get_string(request, REACH_CLIENT_PROC_NAME); + if (proc_name != NULL) { + client->proc_name = strdup(proc_name); + } + } + + return; +} + + +static void +process_request(reach_client_t *client, xpc_object_t request) +{ + int64_t op; + + op = xpc_dictionary_get_int64(request, REACH_REQUEST); + switch (op) { + case REACH_REQUEST_CREATE : + _extract_client_info(client, request); + target_add(client, request); + break; + case REACH_REQUEST_REMOVE : + target_remove(client, request); + break; + case REACH_REQUEST_STATUS : + target_status(client, request); + break; + case REACH_REQUEST_SCHEDULE : + target_schedule(client, request); + break; + case REACH_REQUEST_UNSCHEDULE : + target_unschedule(client, request); + break; + case REACH_REQUEST_SNAPSHOT : + _extract_client_info(client, request); + _snapshot(client, request); + break; + default : + SCLog(TRUE, LOG_ERR, + CFSTR("<%p> unknown request : %d"), + client->connection, + op); + break; + } + + return; +} + + +static void +process_new_connection(xpc_connection_t connection) +{ + if (S_debug) { + SCLog(TRUE, LOG_INFO, CFSTR("<%p> new reach client, pid=%d"), + connection, + xpc_connection_get_pid(connection)); + } + + dispatch_sync(_reach_connection_queue(), ^{ + reach_client_t *client; + + client = _reach_client_create(connection); + if (client == NULL || !rb_tree_insert_node(_reach_clients_rbt(), &client->rbn)) { + __builtin_trap(); + } + }); + + xpc_connection_set_event_handler(connection, ^(xpc_object_t xobj) { + xpc_type_t type; + + type = xpc_get_type(xobj); + if (type == XPC_TYPE_DICTIONARY) { + dispatch_sync(_reach_connection_queue(), ^{ + struct rb_node *rbn; + + rbn = rb_tree_find_node(_reach_clients_rbt(), &connection); + if (rbn != NULL) { + reach_client_t *client; + + // process the request + client = RBNODE_TO_REACH_CLIENT(rbn); + process_request(client, xobj); + } else { + char *desc; + + SCLog(TRUE, LOG_ERR, + CFSTR("<%p:%d> unexpected SCNetworkReachability request"), + connection, + xpc_connection_get_pid(connection)); + + desc = xpc_copy_description(xobj); + SCLog(TRUE, LOG_ERR, + CFSTR(" request = %s"), + desc); + free(desc); + + xpc_connection_cancel(connection); + } + }); + + } else if (type == XPC_TYPE_ERROR) { + const char *desc; + + desc = xpc_dictionary_get_string(xobj, XPC_ERROR_KEY_DESCRIPTION); + if (xobj == XPC_ERROR_CONNECTION_INVALID) { + if (S_debug) { + SCLog(TRUE, LOG_INFO, + CFSTR("<%p:%d> %s"), + connection, + xpc_connection_get_pid(connection), + desc); + } + + xpc_retain(connection); + dispatch_async(_reach_connection_queue(), ^{ + _reach_client_remove(connection); + xpc_release(connection); + }); + + } else if (xobj == XPC_ERROR_CONNECTION_INTERRUPTED) { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p:%d> %s"), + connection, + xpc_connection_get_pid(connection), + desc); + + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p:%d> Connection error: %d : %s"), + connection, + xpc_connection_get_pid(connection), + xobj, + desc); + } + + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("<%p:%d> unknown event type : %x"), + connection, + xpc_connection_get_pid(connection), + type); + } + }); + + xpc_connection_resume(connection); + + return; +} + + +#pragma mark - +#pragma mark Reachability server "main" + + +__private_extern__ +void +load_SCNetworkReachability(CFBundleRef bundle, Boolean bundleVerbose) +{ + xpc_connection_t connection; + const char *name; + dispatch_queue_t reach_server_q; + + S_debug = bundleVerbose; + + /* + * create a dictionary mapping SCNetworkReachability [CFData] digests + * to SCNetworkReachability objects. + */ + reach_digest_map = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + /* + * create dispatch queue for processing SCNetworkReachability + * service requests + */ + reach_server_q = dispatch_queue_create(REACH_SERVICE_NAME, NULL); + + // create XPC listener + name = getenv("REACH_SERVER"); + if (name == NULL) { + name = REACH_SERVICE_NAME; + } + connection = xpc_connection_create_mach_service(name, + reach_server_q, + XPC_CONNECTION_MACH_SERVICE_LISTENER); + + xpc_connection_set_event_handler(connection, ^(xpc_object_t event) { + xpc_type_t type; + + type = xpc_get_type(event); + if (type == XPC_TYPE_CONNECTION) { + process_new_connection(event); + + } else if (type == XPC_TYPE_ERROR) { + const char *desc; + + desc = xpc_dictionary_get_string(event, XPC_ERROR_KEY_DESCRIPTION); + if (event == XPC_ERROR_CONNECTION_INVALID) { + SCLog(TRUE, LOG_ERR, CFSTR("reach server: %s"), desc); + xpc_release(connection); + } else if (event == XPC_ERROR_CONNECTION_INTERRUPTED) { + SCLog(TRUE, LOG_ERR, CFSTR("reach server: %s"), desc); + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("reach server: Connection error: %d : %s"), + event, + desc); + } + + } else { + SCLog(TRUE, LOG_ERR, + CFSTR("reach server: unknown event type : %x"), + type); + } + }); + xpc_connection_resume(connection); + + return; +} + +#ifdef MAIN + +int +main(int argc, char **argv) +{ +// _sc_log = FALSE; + _sc_verbose = (argc > 1) ? TRUE : FALSE; + _sc_debug = TRUE; + + load_SCNetworkReachability(CFBundleGetMainBundle(), (argc > 1) ? TRUE : FALSE); + CFRunLoopRun(); + /* not reached */ + exit(0); + return 0; +} + +#endif /* MAIN */ + +#endif // HAVE_REACHABILITY_SERVER diff --git a/SystemConfiguration.fproj/reachability/client.c b/SystemConfiguration.fproj/reachability/client.c new file mode 100644 index 0000000..85279fb --- /dev/null +++ b/SystemConfiguration.fproj/reachability/client.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include + +#include "SCNetworkReachabilityInternal.h" + +int +main(int argc, char **argv) +{ + Boolean ok; + SCNetworkReachabilityRef target1; + SCNetworkReachabilityRef target2; + SCNetworkReachabilityRef target3; + SCNetworkReachabilityRef target4; + SCNetworkReachabilityRef target5; + + _sc_log = FALSE; + _sc_debug = TRUE; // extra reachability logging + + target1 = SCNetworkReachabilityCreateWithName(NULL, "web.apple.com"); + ok = __SCNetworkReachabilityServer_targetAdd(target1); + if (!ok) { + SCLog(TRUE, LOG_ERR, CFSTR("No reachability server")); + exit(1); + } + + target2 = SCNetworkReachabilityCreateWithName(NULL, "www.comcast.net"); + __SCNetworkReachabilityServer_targetAdd(target2); + + target3 = SCNetworkReachabilityCreateWithName(NULL, "www.comcast.net"); + __SCNetworkReachabilityServer_targetAdd(target3); + + target4 = SCNetworkReachabilityCreateWithName(NULL, "www.nonexistenthost.com"); + __SCNetworkReachabilityServer_targetAdd(target4); + + target5 = SCNetworkReachabilityCreateWithName(NULL, "www.washingtonpost.com"); + __SCNetworkReachabilityServer_targetAdd(target5); + + __SCNetworkReachabilityServer_targetStatus(target1); + __SCNetworkReachabilityServer_targetStatus(target2); + __SCNetworkReachabilityServer_targetStatus(target3); + __SCNetworkReachabilityServer_targetStatus(target4); + + __SCNetworkReachabilityServer_targetMonitor(target1, TRUE); + __SCNetworkReachabilityServer_targetMonitor(target4, TRUE); + __SCNetworkReachabilityServer_targetMonitor(target5, TRUE); + + __SCNetworkReachabilityServer_targetStatus(target4); + __SCNetworkReachabilityServer_targetStatus(target3); + __SCNetworkReachabilityServer_targetStatus(target2); + __SCNetworkReachabilityServer_targetStatus(target1); + + sleep(2); + + __SCNetworkReachabilityServer_targetStatus(target1); + __SCNetworkReachabilityServer_targetStatus(target4); + __SCNetworkReachabilityServer_targetStatus(target1); + __SCNetworkReachabilityServer_targetStatus(target4); + + __SCNetworkReachabilityServer_targetMonitor(target1, FALSE); + + __SCNetworkReachabilityServer_targetStatus(target1); + __SCNetworkReachabilityServer_targetStatus(target4); + __SCNetworkReachabilityServer_targetStatus(target1); + __SCNetworkReachabilityServer_targetStatus(target4); + + __SCNetworkReachabilityServer_targetMonitor(target4, FALSE); + + __SCNetworkReachabilityServer_targetStatus(target1); + __SCNetworkReachabilityServer_targetStatus(target4); + +// SCLog(TRUE, LOG_DEBUG, CFSTR("starting CFRunLoop")); +// CFRunLoopRun(); +// SCLog(TRUE, LOG_DEBUG, CFSTR("CFRunLoop complete")); + + SCLog(TRUE, LOG_DEBUG, CFSTR("sleeping")); + sleep(60); + + __SCNetworkReachabilityServer_targetStatus(target5); + __SCNetworkReachabilityServer_targetRemove(target5); + CFRelease(target5); + + __SCNetworkReachabilityServer_targetRemove(target4); + CFRelease(target4); + + __SCNetworkReachabilityServer_targetRemove(target3); + CFRelease(target3); + +// __SCNetworkReachabilityServer_targetRemove(target2); +// CFRelease(target2); + +// __SCNetworkReachabilityServer_targetRemove(target1); +// CFRelease(target1); + + exit(0); +} + diff --git a/SystemConfiguration.fproj/reachability/rb.c b/SystemConfiguration.fproj/reachability/rb.c new file mode 100644 index 0000000..21205db --- /dev/null +++ b/SystemConfiguration.fproj/reachability/rb.c @@ -0,0 +1,1323 @@ +/* $NetBSD: rb.c,v 1.4 2009/05/19 22:48:19 yamt Exp $ */ + +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if !defined(_KERNEL) && !defined(_STANDALONE) +#include +#include +#include +#include +#ifdef RBDEBUG +#define KASSERT(s) assert(s) +#else +#define KASSERT(s) do { } while (/*CONSTCOND*/ 0) +#endif +#else +#include +#endif + +#ifdef _LIBC +__weak_alias(rb_tree_init, _rb_tree_init) +__weak_alias(rb_tree_find_node, _rb_tree_find_node) +__weak_alias(rb_tree_find_node_geq, _rb_tree_find_node_geq) +__weak_alias(rb_tree_find_node_leq, _rb_tree_find_node_leq) +__weak_alias(rb_tree_insert_node, _rb_tree_insert_node) +__weak_alias(rb_tree_remove_node, _rb_tree_remove_node) +__weak_alias(rb_tree_iterate, _rb_tree_iterate) +#ifdef RBDEBUG +__weak_alias(rb_tree_check, _rb_tree_check) +__weak_alias(rb_tree_depths, _rb_tree_depths) +#endif + +#define rb_tree_init _rb_tree_init +#define rb_tree_find_node _rb_tree_find_node +#define rb_tree_find_node_geq _rb_tree_find_node_geq +#define rb_tree_find_node_leq _rb_tree_find_node_leq +#define rb_tree_insert_node _rb_tree_insert_node +#define rb_tree_remove_node _rb_tree_remove_node +#define rb_tree_iterate _rb_tree_iterate +#ifdef RBDEBUG +#define rb_tree_check _rb_tree_check +#define rb_tree_depths _rb_tree_depths +#endif +#endif + +#if defined(RBTEST) || defined(__APPLE__) +#include "rb.h" +#else +#include +#endif + +#ifdef __APPLE__ +#define __predict_true(exp) __builtin_expect((exp), 1) +#define __predict_false(exp) __builtin_expect((exp), 0) +#endif + +static void rb_tree_insert_rebalance(struct rb_tree *, struct rb_node *); +static void rb_tree_removal_rebalance(struct rb_tree *, struct rb_node *, + unsigned int); +#ifdef RBDEBUG +static const struct rb_node *rb_tree_iterate_const(const struct rb_tree *, + const struct rb_node *, const unsigned int); +static bool rb_tree_check_node(const struct rb_tree *, const struct rb_node *, + const struct rb_node *, bool); +#else +#define rb_tree_check_node(a, b, c, d) true +#endif + +#define RB_SENTINEL_NODE NULL + +void +rb_tree_init(struct rb_tree *rbt, const struct rb_tree_ops *ops) +{ + rbt->rbt_ops = ops; + *((const struct rb_node **)&rbt->rbt_root) = RB_SENTINEL_NODE; + RB_TAILQ_INIT(&rbt->rbt_nodes); +#ifndef RBSMALL + rbt->rbt_minmax[RB_DIR_LEFT] = rbt->rbt_root; /* minimum node */ + rbt->rbt_minmax[RB_DIR_RIGHT] = rbt->rbt_root; /* maximum node */ +#endif + rbt->rbt_count = 0; +#ifdef RBSTATS + rbt->rbt_insertions = 0; + rbt->rbt_removals = 0; + rbt->rbt_insertion_rebalance_calls = 0; + rbt->rbt_insertion_rebalance_passes = 0; + rbt->rbt_removal_rebalance_calls = 0; + rbt->rbt_removal_rebalance_passes = 0; +#endif +} + +struct rb_node * +rb_tree_find_node(struct rb_tree *rbt, const void *key) +{ + rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key; + struct rb_node *parent = rbt->rbt_root; + + while (!RB_SENTINEL_P(parent)) { + const signed int diff = (*compare_key)(parent, key); + if (diff == 0) + return parent; + parent = parent->rb_nodes[diff > 0]; + } + + return NULL; +} + +struct rb_node * +rb_tree_find_node_geq(struct rb_tree *rbt, const void *key) +{ + rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key; + struct rb_node *parent = rbt->rbt_root; + struct rb_node *last = NULL; + + while (!RB_SENTINEL_P(parent)) { + const signed int diff = (*compare_key)(parent, key); + if (diff == 0) + return parent; + if (diff < 0) + last = parent; + parent = parent->rb_nodes[diff > 0]; + } + + return last; +} + +struct rb_node * +rb_tree_find_node_leq(struct rb_tree *rbt, const void *key) +{ + rbto_compare_key_fn compare_key = rbt->rbt_ops->rbto_compare_key; + struct rb_node *parent = rbt->rbt_root; + struct rb_node *last = NULL; + + while (!RB_SENTINEL_P(parent)) { + const signed int diff = (*compare_key)(parent, key); + if (diff == 0) + return parent; + if (diff > 0) + last = parent; + parent = parent->rb_nodes[diff > 0]; + } + + return last; +} + +bool +rb_tree_insert_node(struct rb_tree *rbt, struct rb_node *self) +{ + rbto_compare_nodes_fn compare_nodes = rbt->rbt_ops->rbto_compare_nodes; + struct rb_node *parent, *tmp; + unsigned int position; + bool rebalance; + + RBSTAT_INC(rbt->rbt_insertions); + + tmp = rbt->rbt_root; + /* + * This is a hack. Because rbt->rbt_root is just a struct rb_node *, + * just like rb_node->rb_nodes[RB_DIR_LEFT], we can use this fact to + * avoid a lot of tests for root and know that even at root, + * updating RB_FATHER(rb_node)->rb_nodes[RB_POSITION(rb_node)] will + * update rbt->rbt_root. + */ + parent = (struct rb_node *)(void *)&rbt->rbt_root; + position = RB_DIR_LEFT; + + /* + * Find out where to place this new leaf. + */ + while (!RB_SENTINEL_P(tmp)) { + const signed int diff = (*compare_nodes)(tmp, self); + if (__predict_false(diff == 0)) { + /* + * Node already exists; don't insert. + */ + return false; + } + parent = tmp; + position = (diff > 0); + tmp = parent->rb_nodes[position]; + } + +#ifdef RBDEBUG + { + struct rb_node *prev = NULL, *next = NULL; + + if (position == RB_DIR_RIGHT) + prev = parent; + else if (tmp != rbt->rbt_root) + next = parent; + + /* + * Verify our sequential position + */ + KASSERT(prev == NULL || !RB_SENTINEL_P(prev)); + KASSERT(next == NULL || !RB_SENTINEL_P(next)); + if (prev != NULL && next == NULL) + next = TAILQ_NEXT(prev, rb_link); + if (prev == NULL && next != NULL) + prev = TAILQ_PREV(next, rb_node_qh, rb_link); + KASSERT(prev == NULL || !RB_SENTINEL_P(prev)); + KASSERT(next == NULL || !RB_SENTINEL_P(next)); + KASSERT(prev == NULL || (*compare_nodes)(prev, self) > 0); + KASSERT(next == NULL || (*compare_nodes)(self, next) > 0); + } +#endif + + /* + * Initialize the node and insert as a leaf into the tree. + */ + RB_SET_FATHER(self, parent); + RB_SET_POSITION(self, position); + if (__predict_false(parent == (struct rb_node *)(void *)&rbt->rbt_root)) { + RB_MARK_BLACK(self); /* root is always black */ +#ifndef RBSMALL + rbt->rbt_minmax[RB_DIR_LEFT] = self; + rbt->rbt_minmax[RB_DIR_RIGHT] = self; +#endif + rebalance = false; + } else { + KASSERT(position == RB_DIR_LEFT || position == RB_DIR_RIGHT); +#ifndef RBSMALL + /* + * Keep track of the minimum and maximum nodes. If our + * parent is a minmax node and we on their min/max side, + * we must be the new min/max node. + */ + if (parent == rbt->rbt_minmax[position]) + rbt->rbt_minmax[position] = self; +#endif /* !RBSMALL */ + /* + * All new nodes are colored red. We only need to rebalance + * if our parent is also red. + */ + RB_MARK_RED(self); + rebalance = RB_RED_P(parent); + } + KASSERT(RB_SENTINEL_P(parent->rb_nodes[position])); + self->rb_left = parent->rb_nodes[position]; + self->rb_right = parent->rb_nodes[position]; + parent->rb_nodes[position] = self; + KASSERT(RB_CHILDLESS_P(self)); + + /* + * Insert the new node into a sorted list for easy sequential access + */ + rbt->rbt_count++; +#ifdef RBDEBUG + if (RB_ROOT_P(rbt, self)) { + RB_TAILQ_INSERT_HEAD(&rbt->rbt_nodes, self, rb_link); + } else if (position == RB_DIR_LEFT) { + KASSERT((*compare_nodes)(self, RB_FATHER(self)) > 0); + RB_TAILQ_INSERT_BEFORE(RB_FATHER(self), self, rb_link); + } else { + KASSERT((*compare_nodes)(RB_FATHER(self), self) > 0); + RB_TAILQ_INSERT_AFTER(&rbt->rbt_nodes, RB_FATHER(self), + self, rb_link); + } +#endif + KASSERT(rb_tree_check_node(rbt, self, NULL, !rebalance)); + + /* + * Rebalance tree after insertion + */ + if (rebalance) { + rb_tree_insert_rebalance(rbt, self); + KASSERT(rb_tree_check_node(rbt, self, NULL, true)); + } + + return true; +} + +/* + * Swap the location and colors of 'self' and its child @ which. The child + * can not be a sentinel node. This is our rotation function. However, + * since it preserves coloring, it great simplifies both insertion and + * removal since rotation almost always involves the exchanging of colors + * as a separate step. + */ +/*ARGSUSED*/ +static void +rb_tree_reparent_nodes(struct rb_tree *rbt, struct rb_node *old_father, + const unsigned int which) +{ + const unsigned int other = which ^ RB_DIR_OTHER; + struct rb_node * const grandpa = RB_FATHER(old_father); + struct rb_node * const old_child = old_father->rb_nodes[which]; + struct rb_node * const new_father = old_child; + struct rb_node * const new_child = old_father; + + KASSERT(which == RB_DIR_LEFT || which == RB_DIR_RIGHT); + + KASSERT(!RB_SENTINEL_P(old_child)); + KASSERT(RB_FATHER(old_child) == old_father); + + KASSERT(rb_tree_check_node(rbt, old_father, NULL, false)); + KASSERT(rb_tree_check_node(rbt, old_child, NULL, false)); + KASSERT(RB_ROOT_P(rbt, old_father) || rb_tree_check_node(rbt, grandpa, NULL, false)); + + /* + * Exchange descendant linkages. + */ + grandpa->rb_nodes[RB_POSITION(old_father)] = new_father; + new_child->rb_nodes[which] = old_child->rb_nodes[other]; + new_father->rb_nodes[other] = new_child; + + /* + * Update ancestor linkages + */ + RB_SET_FATHER(new_father, grandpa); + RB_SET_FATHER(new_child, new_father); + + /* + * Exchange properties between new_father and new_child. The only + * change is that new_child's position is now on the other side. + */ +#if 0 + { + struct rb_node tmp; + tmp.rb_info = 0; + RB_COPY_PROPERTIES(&tmp, old_child); + RB_COPY_PROPERTIES(new_father, old_father); + RB_COPY_PROPERTIES(new_child, &tmp); + } +#else + RB_SWAP_PROPERTIES(new_father, new_child); +#endif + RB_SET_POSITION(new_child, other); + + /* + * Make sure to reparent the new child to ourself. + */ + if (!RB_SENTINEL_P(new_child->rb_nodes[which])) { + RB_SET_FATHER(new_child->rb_nodes[which], new_child); + RB_SET_POSITION(new_child->rb_nodes[which], which); + } + + KASSERT(rb_tree_check_node(rbt, new_father, NULL, false)); + KASSERT(rb_tree_check_node(rbt, new_child, NULL, false)); + KASSERT(RB_ROOT_P(rbt, new_father) || rb_tree_check_node(rbt, grandpa, NULL, false)); +} + +static void +rb_tree_insert_rebalance(struct rb_tree *rbt, struct rb_node *self) +{ + struct rb_node * father = RB_FATHER(self); + struct rb_node * grandpa; + struct rb_node * uncle; + unsigned int which; + unsigned int other; + + KASSERT(!RB_ROOT_P(rbt, self)); + KASSERT(RB_RED_P(self)); + KASSERT(RB_RED_P(father)); + RBSTAT_INC(rbt->rbt_insertion_rebalance_calls); + + for (;;) { + KASSERT(!RB_SENTINEL_P(self)); + + KASSERT(RB_RED_P(self)); + KASSERT(RB_RED_P(father)); + /* + * We are red and our parent is red, therefore we must have a + * grandfather and he must be black. + */ + grandpa = RB_FATHER(father); + KASSERT(RB_BLACK_P(grandpa)); + KASSERT(RB_DIR_RIGHT == 1 && RB_DIR_LEFT == 0); + which = (father == grandpa->rb_right); + other = which ^ RB_DIR_OTHER; + uncle = grandpa->rb_nodes[other]; + + if (RB_BLACK_P(uncle)) + break; + + RBSTAT_INC(rbt->rbt_insertion_rebalance_passes); + /* + * Case 1: our uncle is red + * Simply invert the colors of our parent and + * uncle and make our grandparent red. And + * then solve the problem up at his level. + */ + RB_MARK_BLACK(uncle); + RB_MARK_BLACK(father); + if (__predict_false(RB_ROOT_P(rbt, grandpa))) { + /* + * If our grandpa is root, don't bother + * setting him to red, just return. + */ + KASSERT(RB_BLACK_P(grandpa)); + return; + } + RB_MARK_RED(grandpa); + self = grandpa; + father = RB_FATHER(self); + KASSERT(RB_RED_P(self)); + if (RB_BLACK_P(father)) { + /* + * If our greatgrandpa is black, we're done. + */ + KASSERT(RB_BLACK_P(rbt->rbt_root)); + return; + } + } + + KASSERT(!RB_ROOT_P(rbt, self)); + KASSERT(RB_RED_P(self)); + KASSERT(RB_RED_P(father)); + KASSERT(RB_BLACK_P(uncle)); + KASSERT(RB_BLACK_P(grandpa)); + /* + * Case 2&3: our uncle is black. + */ + if (self == father->rb_nodes[other]) { + /* + * Case 2: we are on the same side as our uncle + * Swap ourselves with our parent so this case + * becomes case 3. Basically our parent becomes our + * child. + */ + rb_tree_reparent_nodes(rbt, father, other); + KASSERT(RB_FATHER(father) == self); + KASSERT(self->rb_nodes[which] == father); + KASSERT(RB_FATHER(self) == grandpa); +#ifdef RBDEBUG + // only read when RBDEBUG is enabled with KASSERT + self = father; + father = RB_FATHER(self); +#endif + } + KASSERT(RB_RED_P(self) && RB_RED_P(father)); + KASSERT(grandpa->rb_nodes[which] == father); + /* + * Case 3: we are opposite a child of a black uncle. + * Swap our parent and grandparent. Since our grandfather + * is black, our father will become black and our new sibling + * (former grandparent) will become red. + */ + rb_tree_reparent_nodes(rbt, grandpa, which); + KASSERT(RB_FATHER(self) == father); + KASSERT(RB_FATHER(self)->rb_nodes[RB_POSITION(self) ^ RB_DIR_OTHER] == grandpa); + KASSERT(RB_RED_P(self)); + KASSERT(RB_BLACK_P(father)); + KASSERT(RB_RED_P(grandpa)); + + /* + * Final step: Set the root to black. + */ + RB_MARK_BLACK(rbt->rbt_root); +} + +static void +rb_tree_prune_node(struct rb_tree *rbt, struct rb_node *self, bool rebalance) +{ + const unsigned int which = RB_POSITION(self); + struct rb_node *father = RB_FATHER(self); + const bool was_root = RB_ROOT_P(rbt, self); + + KASSERT(rebalance || (RB_ROOT_P(rbt, self) || RB_RED_P(self))); + KASSERT(!rebalance || RB_BLACK_P(self)); + KASSERT(RB_CHILDLESS_P(self)); + KASSERT(rb_tree_check_node(rbt, self, NULL, false)); + + /* + * Since we are childless, we know that self->rb_left is pointing + * to the sentinel node. + */ + father->rb_nodes[which] = self->rb_left; + + /* + * Remove ourselves from the node list, decrement the count, + * and update min/max. + */ + RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link); + rbt->rbt_count--; +#ifndef RBSMALL + if (__predict_false(rbt->rbt_minmax[RB_POSITION(self)] == self)) { + rbt->rbt_minmax[RB_POSITION(self)] = father; + /* + * When removing the root, rbt->rbt_minmax[RB_DIR_LEFT] is + * updated automatically, but we also need to update + * rbt->rbt_minmax[RB_DIR_RIGHT]; + */ + if (__predict_false(was_root)) { + rbt->rbt_minmax[RB_DIR_RIGHT] = father; + } + } + RB_SET_FATHER(self, NULL); +#endif + + /* + * Rebalance if requested. + */ + if (rebalance) + rb_tree_removal_rebalance(rbt, father, which); + KASSERT(was_root || rb_tree_check_node(rbt, father, NULL, true)); +} + +/* + * When deleting an interior node + */ +static void +rb_tree_swap_prune_and_rebalance(struct rb_tree *rbt, struct rb_node *self, + struct rb_node *standin) +{ + const unsigned int standin_which = RB_POSITION(standin); + unsigned int standin_other = standin_which ^ RB_DIR_OTHER; + struct rb_node *standin_son; + struct rb_node *standin_father = RB_FATHER(standin); + bool rebalance = RB_BLACK_P(standin); + + if (standin_father == self) { + /* + * As a child of self, any childen would be opposite of + * our parent. + */ + KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_other])); + standin_son = standin->rb_nodes[standin_which]; + } else { + /* + * Since we aren't a child of self, any childen would be + * on the same side as our parent. + */ + KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_which])); + standin_son = standin->rb_nodes[standin_other]; + } + + /* + * the node we are removing must have two children. + */ + KASSERT(RB_TWOCHILDREN_P(self)); + /* + * If standin has a child, it must be red. + */ + KASSERT(RB_SENTINEL_P(standin_son) || RB_RED_P(standin_son)); + + /* + * Verify things are sane. + */ + KASSERT(rb_tree_check_node(rbt, self, NULL, false)); + KASSERT(rb_tree_check_node(rbt, standin, NULL, false)); + + if (__predict_false(RB_RED_P(standin_son))) { + /* + * We know we have a red child so if we flip it to black + * we don't have to rebalance. + */ + KASSERT(rb_tree_check_node(rbt, standin_son, NULL, true)); + RB_MARK_BLACK(standin_son); + rebalance = false; + + if (standin_father == self) { + KASSERT(RB_POSITION(standin_son) == standin_which); + } else { + KASSERT(RB_POSITION(standin_son) == standin_other); + /* + * Change the son's parentage to point to his grandpa. + */ + RB_SET_FATHER(standin_son, standin_father); + RB_SET_POSITION(standin_son, standin_which); + } + } + + if (standin_father == self) { + /* + * If we are about to delete the standin's father, then when + * we call rebalance, we need to use ourselves as our father. + * Otherwise remember our original father. Also, sincef we are + * our standin's father we only need to reparent the standin's + * brother. + * + * | R --> S | + * | Q S --> Q T | + * | t --> | + */ + KASSERT(RB_SENTINEL_P(standin->rb_nodes[standin_other])); + KASSERT(!RB_SENTINEL_P(self->rb_nodes[standin_other])); + KASSERT(self->rb_nodes[standin_which] == standin); + /* + * Have our son/standin adopt his brother as his new son. + */ + standin_father = standin; + } else { + /* + * | R --> S . | + * | / \ | T --> / \ | / | + * | ..... | S --> ..... | T | + * + * Sever standin's connection to his father. + */ + standin_father->rb_nodes[standin_which] = standin_son; + /* + * Adopt the far son. + */ + standin->rb_nodes[standin_other] = self->rb_nodes[standin_other]; + RB_SET_FATHER(standin->rb_nodes[standin_other], standin); + KASSERT(RB_POSITION(self->rb_nodes[standin_other]) == standin_other); + /* + * Use standin_other because we need to preserve standin_which + * for the removal_rebalance. + */ + standin_other = standin_which; + } + + /* + * Move the only remaining son to our standin. If our standin is our + * son, this will be the only son needed to be moved. + */ + KASSERT(standin->rb_nodes[standin_other] != self->rb_nodes[standin_other]); + standin->rb_nodes[standin_other] = self->rb_nodes[standin_other]; + RB_SET_FATHER(standin->rb_nodes[standin_other], standin); + + /* + * Now copy the result of self to standin and then replace + * self with standin in the tree. + */ + RB_COPY_PROPERTIES(standin, self); + RB_SET_FATHER(standin, RB_FATHER(self)); + RB_FATHER(standin)->rb_nodes[RB_POSITION(standin)] = standin; + + /* + * Remove ourselves from the node list, decrement the count, + * and update min/max. + */ + RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link); + rbt->rbt_count--; +#ifndef RBSMALL + if (__predict_false(rbt->rbt_minmax[RB_POSITION(self)] == self)) + rbt->rbt_minmax[RB_POSITION(self)] = RB_FATHER(self); + RB_SET_FATHER(self, NULL); +#endif + + KASSERT(rb_tree_check_node(rbt, standin, NULL, false)); + KASSERT(RB_FATHER_SENTINEL_P(standin) + || rb_tree_check_node(rbt, standin_father, NULL, false)); + KASSERT(RB_LEFT_SENTINEL_P(standin) + || rb_tree_check_node(rbt, standin->rb_left, NULL, false)); + KASSERT(RB_RIGHT_SENTINEL_P(standin) + || rb_tree_check_node(rbt, standin->rb_right, NULL, false)); + + if (!rebalance) + return; + + rb_tree_removal_rebalance(rbt, standin_father, standin_which); + KASSERT(rb_tree_check_node(rbt, standin, NULL, true)); +} + +/* + * We could do this by doing + * rb_tree_node_swap(rbt, self, which); + * rb_tree_prune_node(rbt, self, false); + * + * But it's more efficient to just evalate and recolor the child. + */ +static void +rb_tree_prune_blackred_branch(struct rb_tree *rbt, struct rb_node *self, + unsigned int which) +{ + struct rb_node *father = RB_FATHER(self); + struct rb_node *son = self->rb_nodes[which]; + const bool was_root = RB_ROOT_P(rbt, self); + + KASSERT(which == RB_DIR_LEFT || which == RB_DIR_RIGHT); + KASSERT(RB_BLACK_P(self) && RB_RED_P(son)); + KASSERT(!RB_TWOCHILDREN_P(son)); + KASSERT(RB_CHILDLESS_P(son)); + KASSERT(rb_tree_check_node(rbt, self, NULL, false)); + KASSERT(rb_tree_check_node(rbt, son, NULL, false)); + + /* + * Remove ourselves from the tree and give our former child our + * properties (position, color, root). + */ + RB_COPY_PROPERTIES(son, self); + father->rb_nodes[RB_POSITION(son)] = son; + RB_SET_FATHER(son, father); + + /* + * Remove ourselves from the node list, decrement the count, + * and update minmax. + */ + RB_TAILQ_REMOVE(&rbt->rbt_nodes, self, rb_link); + rbt->rbt_count--; +#ifndef RBSMALL + if (__predict_false(was_root)) { + KASSERT(rbt->rbt_minmax[which] == son); + rbt->rbt_minmax[which ^ RB_DIR_OTHER] = son; + } else if (rbt->rbt_minmax[RB_POSITION(self)] == self) { + rbt->rbt_minmax[RB_POSITION(self)] = son; + } + RB_SET_FATHER(self, NULL); +#endif + + KASSERT(was_root || rb_tree_check_node(rbt, father, NULL, true)); + KASSERT(rb_tree_check_node(rbt, son, NULL, true)); +} +/* + * + */ +void +rb_tree_remove_node(struct rb_tree *rbt, struct rb_node *self) +{ + struct rb_node *standin; + unsigned int which; + + KASSERT(!RB_SENTINEL_P(self)); + RBSTAT_INC(rbt->rbt_removals); + + /* + * In the following diagrams, we (the node to be removed) are S. Red + * nodes are lowercase. T could be either red or black. + * + * Remember the major axiom of the red-black tree: the number of + * black nodes from the root to each leaf is constant across all + * leaves, only the number of red nodes varies. + * + * Thus removing a red leaf doesn't require any other changes to a + * red-black tree. So if we must remove a node, attempt to rearrange + * the tree so we can remove a red node. + * + * The simpliest case is a childless red node or a childless root node: + * + * | T --> T | or | R --> * | + * | s --> * | + */ + if (RB_CHILDLESS_P(self)) { + const bool rebalance = RB_BLACK_P(self) && !RB_ROOT_P(rbt, self); + rb_tree_prune_node(rbt, self, rebalance); + return; + } + KASSERT(!RB_CHILDLESS_P(self)); + if (!RB_TWOCHILDREN_P(self)) { + /* + * The next simpliest case is the node we are deleting is + * black and has one red child. + * + * | T --> T --> T | + * | S --> R --> R | + * | r --> s --> * | + */ + which = RB_LEFT_SENTINEL_P(self) ? RB_DIR_RIGHT : RB_DIR_LEFT; + KASSERT(RB_BLACK_P(self)); + KASSERT(RB_RED_P(self->rb_nodes[which])); + KASSERT(RB_CHILDLESS_P(self->rb_nodes[which])); + rb_tree_prune_blackred_branch(rbt, self, which); + return; + } + KASSERT(RB_TWOCHILDREN_P(self)); + + /* + * We invert these because we prefer to remove from the inside of + * the tree. + */ + which = RB_POSITION(self) ^ RB_DIR_OTHER; + + /* + * Let's find the node closes to us opposite of our parent + * Now swap it with ourself, "prune" it, and rebalance, if needed. + */ + standin = rb_tree_iterate(rbt, self, which); + rb_tree_swap_prune_and_rebalance(rbt, self, standin); +} + +static void +rb_tree_removal_rebalance(struct rb_tree *rbt, struct rb_node *parent, + unsigned int which) +{ + KASSERT(!RB_SENTINEL_P(parent)); + KASSERT(RB_SENTINEL_P(parent->rb_nodes[which])); + KASSERT(which == RB_DIR_LEFT || which == RB_DIR_RIGHT); + RBSTAT_INC(rbt->rbt_removal_rebalance_calls); + + while (RB_BLACK_P(parent->rb_nodes[which])) { + unsigned int other = which ^ RB_DIR_OTHER; + struct rb_node *brother = parent->rb_nodes[other]; + + RBSTAT_INC(rbt->rbt_removal_rebalance_passes); + + KASSERT(!RB_SENTINEL_P(brother)); + /* + * For cases 1, 2a, and 2b, our brother's children must + * be black and our father must be black + */ + if (RB_BLACK_P(parent) + && RB_BLACK_P(brother->rb_left) + && RB_BLACK_P(brother->rb_right)) { + if (RB_RED_P(brother)) { + /* + * Case 1: Our brother is red, swap its + * position (and colors) with our parent. + * This should now be case 2b (unless C or E + * has a red child which is case 3; thus no + * explicit branch to case 2b). + * + * B -> D + * A d -> b E + * C E -> A C + */ + KASSERT(RB_BLACK_P(parent)); + rb_tree_reparent_nodes(rbt, parent, other); + brother = parent->rb_nodes[other]; + KASSERT(!RB_SENTINEL_P(brother)); + KASSERT(RB_RED_P(parent)); + KASSERT(RB_BLACK_P(brother)); + KASSERT(rb_tree_check_node(rbt, brother, NULL, false)); + KASSERT(rb_tree_check_node(rbt, parent, NULL, false)); + } else { + /* + * Both our parent and brother are black. + * Change our brother to red, advance up rank + * and go through the loop again. + * + * B -> *B + * *A D -> A d + * C E -> C E + */ + RB_MARK_RED(brother); + KASSERT(RB_BLACK_P(brother->rb_left)); + KASSERT(RB_BLACK_P(brother->rb_right)); + if (RB_ROOT_P(rbt, parent)) + return; /* root == parent == black */ + KASSERT(rb_tree_check_node(rbt, brother, NULL, false)); + KASSERT(rb_tree_check_node(rbt, parent, NULL, false)); + if (parent != NULL) { + which = RB_POSITION(parent); + parent = RB_FATHER(parent); + } + continue; + } + } + /* + * Avoid an else here so that case 2a above can hit either + * case 2b, 3, or 4. + */ + if (RB_RED_P(parent) + && (RB_SENTINEL_P(brother) + || (RB_BLACK_P(brother) + && RB_BLACK_P(brother->rb_left) + && RB_BLACK_P(brother->rb_right)))) { + KASSERT(RB_RED_P(parent)); + KASSERT(RB_BLACK_P(brother)); + KASSERT(RB_BLACK_P(brother->rb_left)); + KASSERT(RB_BLACK_P(brother->rb_right)); + /* + * We are black, our father is red, our brother and + * both nephews are black. Simply invert/exchange the + * colors of our father and brother (to black and red + * respectively). + * + * | f --> F | + * | * B --> * b | + * | N N --> N N | + */ + RB_MARK_BLACK(parent); + if (!RB_SENTINEL_P(brother)) { + RB_MARK_RED(brother); + } + KASSERT(rb_tree_check_node(rbt, brother, NULL, true)); + break; /* We're done! */ + } else { + /* + * Our brother must be black and have at least one + * red child (it may have two). + */ + KASSERT(RB_BLACK_P(brother)); + KASSERT(RB_RED_P(brother->rb_nodes[which]) || + RB_RED_P(brother->rb_nodes[other])); + if (RB_BLACK_P(brother->rb_nodes[other])) { + /* + * Case 3: our brother is black, our near + * nephew is red, and our far nephew is black. + * Swap our brother with our near nephew. + * This result in a tree that matches case 4. + * (Our father could be red or black). + * + * | F --> F | + * | x B --> x B | + * | n --> n | + */ + KASSERT(RB_RED_P(brother->rb_nodes[which])); + rb_tree_reparent_nodes(rbt, brother, which); + KASSERT(RB_FATHER(brother) == parent->rb_nodes[other]); + brother = parent->rb_nodes[other]; + KASSERT(RB_RED_P(brother->rb_nodes[other])); + } + /* + * Case 4: our brother is black and our far nephew + * is red. Swap our father and brother locations and + * change our far nephew to black. (these can be + * done in either order so we change the color first). + * The result is a valid red-black tree and is a + * terminal case. (again we don't care about the + * father's color) + * + * If the father is red, we will get a red-black-black + * tree: + * | f -> f --> b | + * | B -> B --> F N | + * | n -> N --> | + * + * If the father is black, we will get an all black + * tree: + * | F -> F --> B | + * | B -> B --> F N | + * | n -> N --> | + * + * If we had two red nephews, then after the swap, + * our former father would have a red grandson. + */ + KASSERT(RB_BLACK_P(brother)); + KASSERT(RB_RED_P(brother->rb_nodes[other])); + RB_MARK_BLACK(brother->rb_nodes[other]); + rb_tree_reparent_nodes(rbt, parent, other); + break; /* We're done! */ + } + } + KASSERT(rb_tree_check_node(rbt, parent, NULL, true)); +} + +struct rb_node * +rb_tree_iterate(struct rb_tree *rbt, struct rb_node *self, + const unsigned int direction) +{ + const unsigned int other = direction ^ RB_DIR_OTHER; + KASSERT(direction == RB_DIR_LEFT || direction == RB_DIR_RIGHT); + + if (self == NULL) { +#ifndef RBSMALL + if (RB_SENTINEL_P(rbt->rbt_root)) + return NULL; + return rbt->rbt_minmax[direction]; +#else + self = rbt->rbt_root; + if (RB_SENTINEL_P(self)) + return NULL; + while (!RB_SENTINEL_P(self->rb_nodes[other])) + self = self->rb_nodes[other]; + return self; +#endif /* !RBSMALL */ + } + KASSERT(!RB_SENTINEL_P(self)); + /* + * We can't go any further in this direction. We proceed up in the + * opposite direction until our parent is in direction we want to go. + */ + if (RB_SENTINEL_P(self->rb_nodes[direction])) { + while (!RB_ROOT_P(rbt, self)) { + if (other == RB_POSITION(self)) + return RB_FATHER(self); + self = RB_FATHER(self); + } + return NULL; + } + + /* + * Advance down one in current direction and go down as far as possible + * in the opposite direction. + */ + self = self->rb_nodes[direction]; + KASSERT(!RB_SENTINEL_P(self)); + while (!RB_SENTINEL_P(self->rb_nodes[other])) + self = self->rb_nodes[other]; + return self; +} + +#ifdef RBDEBUG +static const struct rb_node * +rb_tree_iterate_const(const struct rb_tree *rbt, const struct rb_node *self, + const unsigned int direction) +{ + const unsigned int other = direction ^ RB_DIR_OTHER; + KASSERT(direction == RB_DIR_LEFT || direction == RB_DIR_RIGHT); + + if (self == NULL) { +#ifndef RBSMALL + if (RB_SENTINEL_P(rbt->rbt_root)) + return NULL; + return rbt->rbt_minmax[direction]; +#else + self = rbt->rbt_root; + if (RB_SENTINEL_P(self)) + return NULL; + while (!RB_SENTINEL_P(self->rb_nodes[other])) + self = self->rb_nodes[other]; + return self; +#endif /* !RBSMALL */ + } + KASSERT(!RB_SENTINEL_P(self)); + /* + * We can't go any further in this direction. We proceed up in the + * opposite direction until our parent is in direction we want to go. + */ + if (RB_SENTINEL_P(self->rb_nodes[direction])) { + while (!RB_ROOT_P(rbt, self)) { + if (other == RB_POSITION(self)) + return RB_FATHER(self); + self = RB_FATHER(self); + } + return NULL; + } + + /* + * Advance down one in current direction and go down as far as possible + * in the opposite direction. + */ + self = self->rb_nodes[direction]; + KASSERT(!RB_SENTINEL_P(self)); + while (!RB_SENTINEL_P(self->rb_nodes[other])) + self = self->rb_nodes[other]; + return self; +} + +static unsigned int +rb_tree_count_black(const struct rb_node *self) +{ + unsigned int left, right; + + if (RB_SENTINEL_P(self)) + return 0; + + left = rb_tree_count_black(self->rb_left); + right = rb_tree_count_black(self->rb_right); + + KASSERT(left == right); + + return left + RB_BLACK_P(self); +} + +static bool +rb_tree_check_node(const struct rb_tree *rbt, const struct rb_node *self, + const struct rb_node *prev, bool red_check) +{ + rbto_compare_nodes_fn compare_nodes = rbt->rbt_ops->rbto_compare_nodes; + + KASSERT(!RB_SENTINEL_P(self)); + KASSERT(prev == NULL || (*compare_nodes)(prev, self) > 0); + + /* + * Verify our relationship to our parent. + */ + if (RB_ROOT_P(rbt, self)) { + KASSERT(self == rbt->rbt_root); + KASSERT(RB_POSITION(self) == RB_DIR_LEFT); + KASSERT(RB_FATHER(self)->rb_nodes[RB_DIR_LEFT] == self); + KASSERT(RB_FATHER(self) == (const struct rb_node *) &rbt->rbt_root); + } else { + KASSERT(self != rbt->rbt_root); + KASSERT(!RB_FATHER_SENTINEL_P(self)); + if (RB_POSITION(self) == RB_DIR_LEFT) { + KASSERT((*compare_nodes)(self, RB_FATHER(self)) > 0); + KASSERT(RB_FATHER(self)->rb_nodes[RB_DIR_LEFT] == self); + } else { + KASSERT((*compare_nodes)(self, RB_FATHER(self)) < 0); + KASSERT(RB_FATHER(self)->rb_nodes[RB_DIR_RIGHT] == self); + } + } + + /* + * Verify our position in the linked list against the tree itself. + */ + { + const struct rb_node *prev0 = rb_tree_iterate_const(rbt, self, RB_DIR_LEFT); + const struct rb_node *next0 = rb_tree_iterate_const(rbt, self, RB_DIR_RIGHT); + KASSERT(prev0 == TAILQ_PREV(self, rb_node_qh, rb_link)); + KASSERT(next0 == TAILQ_NEXT(self, rb_link)); +#ifndef RBSMALL + KASSERT(prev0 != NULL || self == rbt->rbt_minmax[RB_DIR_LEFT]); + KASSERT(next0 != NULL || self == rbt->rbt_minmax[RB_DIR_RIGHT]); +#endif + } + + /* + * The root must be black. + * There can never be two adjacent red nodes. + */ + if (red_check) { + KASSERT(!RB_ROOT_P(rbt, self) || RB_BLACK_P(self)); + (void) rb_tree_count_black(self); + if (RB_RED_P(self)) { + const struct rb_node *brother; + KASSERT(!RB_ROOT_P(rbt, self)); + brother = RB_FATHER(self)->rb_nodes[RB_POSITION(self) ^ RB_DIR_OTHER]; + KASSERT(RB_BLACK_P(RB_FATHER(self))); + /* + * I'm red and have no children, then I must either + * have no brother or my brother also be red and + * also have no children. (black count == 0) + */ + KASSERT(!RB_CHILDLESS_P(self) + || RB_SENTINEL_P(brother) + || RB_RED_P(brother) + || RB_CHILDLESS_P(brother)); + /* + * If I'm not childless, I must have two children + * and they must be both be black. + */ + KASSERT(RB_CHILDLESS_P(self) + || (RB_TWOCHILDREN_P(self) + && RB_BLACK_P(self->rb_left) + && RB_BLACK_P(self->rb_right))); + /* + * If I'm not childless, thus I have black children, + * then my brother must either be black or have two + * black children. + */ + KASSERT(RB_CHILDLESS_P(self) + || RB_BLACK_P(brother) + || (RB_TWOCHILDREN_P(brother) + && RB_BLACK_P(brother->rb_left) + && RB_BLACK_P(brother->rb_right))); + } else { + /* + * If I'm black and have one child, that child must + * be red and childless. + */ + KASSERT(RB_CHILDLESS_P(self) + || RB_TWOCHILDREN_P(self) + || (!RB_LEFT_SENTINEL_P(self) + && RB_RIGHT_SENTINEL_P(self) + && RB_RED_P(self->rb_left) + && RB_CHILDLESS_P(self->rb_left)) + || (!RB_RIGHT_SENTINEL_P(self) + && RB_LEFT_SENTINEL_P(self) + && RB_RED_P(self->rb_right) + && RB_CHILDLESS_P(self->rb_right))); + + /* + * If I'm a childless black node and my parent is + * black, my 2nd closet relative away from my parent + * is either red or has a red parent or red children. + */ + if (!RB_ROOT_P(rbt, self) + && RB_CHILDLESS_P(self) + && RB_BLACK_P(RB_FATHER(self))) { + const unsigned int which = RB_POSITION(self); + const unsigned int other = which ^ RB_DIR_OTHER; + const struct rb_node *relative0, *relative; + + relative0 = rb_tree_iterate_const(rbt, + self, other); + KASSERT(relative0 != NULL); + relative = rb_tree_iterate_const(rbt, + relative0, other); + KASSERT(relative != NULL); + KASSERT(RB_SENTINEL_P(relative->rb_nodes[which])); +#if 0 + KASSERT(RB_RED_P(relative) + || RB_RED_P(relative->rb_left) + || RB_RED_P(relative->rb_right) + || RB_RED_P(RB_FATHER(relative))); +#endif + } + } + /* + * A grandparent's children must be real nodes and not + * sentinels. First check out grandparent. + */ + KASSERT(RB_ROOT_P(rbt, self) + || RB_ROOT_P(rbt, RB_FATHER(self)) + || RB_TWOCHILDREN_P(RB_FATHER(RB_FATHER(self)))); + /* + * If we are have grandchildren on our left, then + * we must have a child on our right. + */ + KASSERT(RB_LEFT_SENTINEL_P(self) + || RB_CHILDLESS_P(self->rb_left) + || !RB_RIGHT_SENTINEL_P(self)); + /* + * If we are have grandchildren on our right, then + * we must have a child on our left. + */ + KASSERT(RB_RIGHT_SENTINEL_P(self) + || RB_CHILDLESS_P(self->rb_right) + || !RB_LEFT_SENTINEL_P(self)); + + /* + * If we have a child on the left and it doesn't have two + * children make sure we don't have great-great-grandchildren on + * the right. + */ + KASSERT(RB_TWOCHILDREN_P(self->rb_left) + || RB_CHILDLESS_P(self->rb_right) + || RB_CHILDLESS_P(self->rb_right->rb_left) + || RB_CHILDLESS_P(self->rb_right->rb_left->rb_left) + || RB_CHILDLESS_P(self->rb_right->rb_left->rb_right) + || RB_CHILDLESS_P(self->rb_right->rb_right) + || RB_CHILDLESS_P(self->rb_right->rb_right->rb_left) + || RB_CHILDLESS_P(self->rb_right->rb_right->rb_right)); + + /* + * If we have a child on the right and it doesn't have two + * children make sure we don't have great-great-grandchildren on + * the left. + */ + KASSERT(RB_TWOCHILDREN_P(self->rb_right) + || RB_CHILDLESS_P(self->rb_left) + || RB_CHILDLESS_P(self->rb_left->rb_left) + || RB_CHILDLESS_P(self->rb_left->rb_left->rb_left) + || RB_CHILDLESS_P(self->rb_left->rb_left->rb_right) + || RB_CHILDLESS_P(self->rb_left->rb_right) + || RB_CHILDLESS_P(self->rb_left->rb_right->rb_left) + || RB_CHILDLESS_P(self->rb_left->rb_right->rb_right)); + + /* + * If we are fully interior node, then our predecessors and + * successors must have no children in our direction. + */ + if (RB_TWOCHILDREN_P(self)) { + const struct rb_node *prev0; + const struct rb_node *next0; + + prev0 = rb_tree_iterate_const(rbt, self, RB_DIR_LEFT); + KASSERT(prev0 != NULL); + KASSERT(RB_RIGHT_SENTINEL_P(prev0)); + + next0 = rb_tree_iterate_const(rbt, self, RB_DIR_RIGHT); + KASSERT(next0 != NULL); + KASSERT(RB_LEFT_SENTINEL_P(next0)); + } + } + + return true; +} + +void +rb_tree_check(const struct rb_tree *rbt, bool red_check) +{ + const struct rb_node *self; + const struct rb_node *prev; +#ifdef RBSTATS + unsigned int count = 0; +#endif + + KASSERT(rbt->rbt_root != NULL); + KASSERT(RB_LEFT_P(rbt->rbt_root)); + +#if defined(RBSTATS) && !defined(RBSMALL) + KASSERT(rbt->rbt_count > 1 + || rbt->rbt_minmax[RB_DIR_LEFT] == rbt->rbt_minmax[RB_DIR_RIGHT]); +#endif + + prev = NULL; + TAILQ_FOREACH(self, &rbt->rbt_nodes, rb_link) { + rb_tree_check_node(rbt, self, prev, false); +#ifdef RBSTATS + count++; +#endif + } +#ifdef RBSTATS + KASSERT(rbt->rbt_count == count); +#endif + if (red_check) { + KASSERT(RB_BLACK_P(rbt->rbt_root)); + KASSERT(RB_SENTINEL_P(rbt->rbt_root) + || rb_tree_count_black(rbt->rbt_root)); + + /* + * The root must be black. + * There can never be two adjacent red nodes. + */ + TAILQ_FOREACH(self, &rbt->rbt_nodes, rb_link) { + rb_tree_check_node(rbt, self, NULL, true); + } + } +} +#endif /* RBDEBUG */ + +#ifdef RBSTATS +static void +rb_tree_mark_depth(const struct rb_tree *rbt, const struct rb_node *self, + size_t *depths, size_t depth) +{ + if (RB_SENTINEL_P(self)) + return; + + if (RB_TWOCHILDREN_P(self)) { + rb_tree_mark_depth(rbt, self->rb_left, depths, depth + 1); + rb_tree_mark_depth(rbt, self->rb_right, depths, depth + 1); + return; + } + depths[depth]++; + if (!RB_LEFT_SENTINEL_P(self)) { + rb_tree_mark_depth(rbt, self->rb_left, depths, depth + 1); + } + if (!RB_RIGHT_SENTINEL_P(self)) { + rb_tree_mark_depth(rbt, self->rb_right, depths, depth + 1); + } +} + +void +rb_tree_depths(const struct rb_tree *rbt, size_t *depths) +{ + rb_tree_mark_depth(rbt, rbt->rbt_root, depths, 1); +} +#endif /* RBSTATS */ diff --git a/SystemConfiguration.fproj/reachability/rb.h b/SystemConfiguration.fproj/reachability/rb.h new file mode 100644 index 0000000..56f910d --- /dev/null +++ b/SystemConfiguration.fproj/reachability/rb.h @@ -0,0 +1,195 @@ +/* $NetBSD: rb.h,v 1.13 2009/08/16 10:57:01 yamt Exp $ */ + +/*- + * Copyright (c) 2001 The NetBSD Foundation, Inc. + * All rights reserved. + * + * Portions Copyright (c) 2009 Apple Inc. All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Matt Thomas . + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#ifndef _SYS_RB_H_ +#define _SYS_RB_H_ + +#if defined(_KERNEL) || defined(_STANDALONE) +#include +#else +#include +#include +#endif +#include +#ifndef __APPLE__ +#include +#endif + +struct rb_node { + struct rb_node *rb_nodes[2]; +#define RB_DIR_LEFT 0 +#define RB_DIR_RIGHT 1 +#define RB_DIR_OTHER 1 +#define rb_left rb_nodes[RB_DIR_LEFT] +#define rb_right rb_nodes[RB_DIR_RIGHT] + + /* + * rb_info contains the two flags and the parent back pointer. + * We put the two flags in the low two bits since we know that + * rb_node will have an alignment of 4 or 8 bytes. + */ + uintptr_t rb_info; +#define RB_FLAG_POSITION 0x2 +#define RB_FLAG_RED 0x1 +#define RB_FLAG_MASK (RB_FLAG_POSITION|RB_FLAG_RED) +#define RB_FATHER(rb) \ + ((struct rb_node *)((rb)->rb_info & ~RB_FLAG_MASK)) +#define RB_SET_FATHER(rb, father) \ + ((void)((rb)->rb_info = (uintptr_t)(father)|((rb)->rb_info & RB_FLAG_MASK))) + +#define RB_SENTINEL_P(rb) ((rb) == NULL) +#define RB_LEFT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_left) +#define RB_RIGHT_SENTINEL_P(rb) RB_SENTINEL_P((rb)->rb_right) +#define RB_FATHER_SENTINEL_P(rb) RB_SENTINEL_P(RB_FATHER((rb))) +#define RB_CHILDLESS_P(rb) \ + (RB_SENTINEL_P(rb) || (RB_LEFT_SENTINEL_P(rb) && RB_RIGHT_SENTINEL_P(rb))) +#define RB_TWOCHILDREN_P(rb) \ + (!RB_SENTINEL_P(rb) && !RB_LEFT_SENTINEL_P(rb) && !RB_RIGHT_SENTINEL_P(rb)) + +#define RB_POSITION(rb) \ + (((rb)->rb_info & RB_FLAG_POSITION) ? RB_DIR_RIGHT : RB_DIR_LEFT) +#define RB_RIGHT_P(rb) (RB_POSITION(rb) == RB_DIR_RIGHT) +#define RB_LEFT_P(rb) (RB_POSITION(rb) == RB_DIR_LEFT) +#define RB_RED_P(rb) (!RB_SENTINEL_P(rb) && ((rb)->rb_info & RB_FLAG_RED) != 0) +#define RB_BLACK_P(rb) (RB_SENTINEL_P(rb) || ((rb)->rb_info & RB_FLAG_RED) == 0) +#define RB_MARK_RED(rb) ((void)((rb)->rb_info |= RB_FLAG_RED)) +#define RB_MARK_BLACK(rb) ((void)((rb)->rb_info &= ~RB_FLAG_RED)) +#define RB_INVERT_COLOR(rb) ((void)((rb)->rb_info ^= RB_FLAG_RED)) +#define RB_ROOT_P(rbt, rb) ((rbt)->rbt_root == (rb)) +#define RB_SET_POSITION(rb, position) \ + ((void)((position) ? ((rb)->rb_info |= RB_FLAG_POSITION) : \ + ((rb)->rb_info &= ~RB_FLAG_POSITION))) +#define RB_ZERO_PROPERTIES(rb) ((void)((rb)->rb_info &= ~RB_FLAG_MASK)) +#define RB_COPY_PROPERTIES(dst, src) \ + ((void)((dst)->rb_info ^= ((dst)->rb_info ^ (src)->rb_info) & RB_FLAG_MASK)) +#define RB_SWAP_PROPERTIES(a, b) do { \ + uintptr_t xorinfo = ((a)->rb_info ^ (b)->rb_info) & RB_FLAG_MASK; \ + (a)->rb_info ^= xorinfo; \ + (b)->rb_info ^= xorinfo; \ + } while (/*CONSTCOND*/ 0) +#ifdef RBDEBUG + TAILQ_ENTRY(rb_node) rb_link; +#endif +}; + +#define RB_TREE_MIN(T) rb_tree_iterate((T), NULL, RB_DIR_LEFT) +#define RB_TREE_MAX(T) rb_tree_iterate((T), NULL, RB_DIR_RIGHT) +#define RB_TREE_FOREACH(N, T) \ + for ((N) = RB_TREE_MIN(T); (N); \ + (N) = rb_tree_iterate((T), (N), RB_DIR_RIGHT)) +#define RB_TREE_FOREACH_REVERSE(N, T) \ + for ((N) = RB_TREE_MAX(T); (N); \ + (N) = rb_tree_iterate((T), (N), RB_DIR_LEFT)) + +#ifdef RBDEBUG +TAILQ_HEAD(rb_node_qh, rb_node); + +#define RB_TAILQ_REMOVE(a, b, c) TAILQ_REMOVE(a, b, c) +#define RB_TAILQ_INIT(a) TAILQ_INIT(a) +#define RB_TAILQ_INSERT_HEAD(a, b, c) TAILQ_INSERT_HEAD(a, b, c) +#define RB_TAILQ_INSERT_BEFORE(a, b, c) TAILQ_INSERT_BEFORE(a, b, c) +#define RB_TAILQ_INSERT_AFTER(a, b, c, d) TAILQ_INSERT_AFTER(a, b, c, d) +#else +#define RB_TAILQ_REMOVE(a, b, c) do { } while (/*CONSTCOND*/0) +#define RB_TAILQ_INIT(a) do { } while (/*CONSTCOND*/0) +#define RB_TAILQ_INSERT_HEAD(a, b, c) do { } while (/*CONSTCOND*/0) +#define RB_TAILQ_INSERT_BEFORE(a, b, c) do { } while (/*CONSTCOND*/0) +#define RB_TAILQ_INSERT_AFTER(a, b, c, d) do { } while (/*CONSTCOND*/0) +#endif /* RBDEBUG */ + +/* + * rbto_compare_nodes_fn: + * return a positive value if the first node < the second node. + * return a negative value if the first node > the second node. + * return 0 if they are considered same. + * + * rbto_compare_key_fn: + * return a positive value if the node < the key. + * return a negative value if the node > the key. + * return 0 if they are considered same. + */ + +typedef signed int (*const rbto_compare_nodes_fn)(const struct rb_node *, + const struct rb_node *); +typedef signed int (*const rbto_compare_key_fn)(const struct rb_node *, + const void *); + +struct rb_tree_ops { + rbto_compare_nodes_fn rbto_compare_nodes; + rbto_compare_key_fn rbto_compare_key; +}; + +struct rb_tree { + struct rb_node *rbt_root; + const struct rb_tree_ops *rbt_ops; + struct rb_node *rbt_minmax[2]; +#ifdef RBDEBUG + struct rb_node_qh rbt_nodes; +#endif + unsigned int rbt_count; +#ifdef RBSTATS + unsigned int rbt_insertions; + unsigned int rbt_removals; + unsigned int rbt_insertion_rebalance_calls; + unsigned int rbt_insertion_rebalance_passes; + unsigned int rbt_removal_rebalance_calls; + unsigned int rbt_removal_rebalance_passes; +#endif +}; + +#ifdef RBSTATS +#define RBSTAT_INC(v) ((void)((v)++)) +#define RBSTAT_DEC(v) ((void)((v)--)) +#else +#define RBSTAT_INC(v) do { } while (/*CONSTCOND*/0) +#define RBSTAT_DEC(v) do { } while (/*CONSTCOND*/0) +#endif + +void rb_tree_init(struct rb_tree *, const struct rb_tree_ops *); +bool rb_tree_insert_node(struct rb_tree *, struct rb_node *); +struct rb_node * + rb_tree_find_node(struct rb_tree *, const void *); +struct rb_node * + rb_tree_find_node_geq(struct rb_tree *, const void *); +struct rb_node * + rb_tree_find_node_leq(struct rb_tree *, const void *); +void rb_tree_remove_node(struct rb_tree *, struct rb_node *); +struct rb_node * + rb_tree_iterate(struct rb_tree *, struct rb_node *, const unsigned int); +#ifdef RBDEBUG +void rb_tree_check(const struct rb_tree *, bool); +#endif +#ifdef RBSTATS +void rb_tree_depths(const struct rb_tree *, size_t *); +#endif + +#endif /* _SYS_RB_H_*/ diff --git a/SystemConfiguration.fproj/reachability/server.c b/SystemConfiguration.fproj/reachability/server.c new file mode 100644 index 0000000..09e97c6 --- /dev/null +++ b/SystemConfiguration.fproj/reachability/server.c @@ -0,0 +1,23 @@ +#include +#include +#include +#include +#include +#include + +#include "SCNetworkReachabilityInternal.h" + +int +main(int argc, char **argv) +{ + _sc_log = FALSE; // no syslog + _sc_debug = TRUE; // extra reachability logging + + _SCNetworkReachabilityServer_start(); + + SCLog(TRUE, LOG_DEBUG, CFSTR("starting CFRunLoop")); + CFRunLoopRun(); + SCLog(TRUE, LOG_DEBUG, CFSTR("CFRunLoop complete")); + + exit(0); +} diff --git a/configd.tproj/_SCD.c b/configd.tproj/_SCD.c index 7a8b084..bb64497 100644 --- a/configd.tproj/_SCD.c +++ b/configd.tproj/_SCD.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003-2005, 2009 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003-2005, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -42,54 +42,17 @@ __private_extern__ CFMutableDictionaryRef sessionData = NULL; __private_extern__ CFMutableDictionaryRef storeData = NULL; -__private_extern__ CFMutableDictionaryRef storeData_s = NULL; __private_extern__ CFMutableDictionaryRef patternData = NULL; -__private_extern__ CFMutableDictionaryRef patternData_s = NULL; __private_extern__ CFMutableSetRef changedKeys = NULL; -__private_extern__ CFMutableSetRef changedKeys_s = NULL; __private_extern__ CFMutableSetRef deferredRemovals = NULL; -__private_extern__ CFMutableSetRef deferredRemovals_s = NULL; __private_extern__ CFMutableSetRef removedSessionKeys = NULL; -__private_extern__ CFMutableSetRef removedSessionKeys_s = NULL; __private_extern__ CFMutableSetRef needsNotification = NULL; -__private_extern__ int storeLocked = 0; /* > 0 if dynamic store locked */ - - -__private_extern__ -void -_swapLockedStoreData() -{ - void *temp; - - temp = storeData; - storeData = storeData_s; - storeData_s = temp; - - temp = patternData; - patternData = patternData_s; - patternData_s = temp; - - temp = changedKeys; - changedKeys = changedKeys_s; - changedKeys_s = temp; - - temp = deferredRemovals; - deferredRemovals = deferredRemovals_s; - deferredRemovals_s = temp; - - temp = removedSessionKeys; - removedSessionKeys = removedSessionKeys_s; - removedSessionKeys_s = temp; - - return; -} - __private_extern__ void diff --git a/configd.tproj/_SCD.h b/configd.tproj/_SCD.h index 4b0ea50..bcc94e4 100644 --- a/configd.tproj/_SCD.h +++ b/configd.tproj/_SCD.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2009 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -77,7 +77,6 @@ #define kSCDSessionKeys CFSTR("sessionKeys") -extern int storeLocked; extern CFMutableDictionaryRef storeData; extern CFMutableDictionaryRef sessionData; extern CFMutableDictionaryRef patternData; @@ -86,12 +85,6 @@ extern CFMutableSetRef deferredRemovals; extern CFMutableSetRef removedSessionKeys; extern CFMutableSetRef needsNotification; -extern CFMutableDictionaryRef storeData_s; -extern CFMutableDictionaryRef patternData_s; -extern CFMutableSetRef changedKeys_s; -extern CFMutableSetRef deferredRemovals_s; -extern CFMutableSetRef removedSessionKeys_s; - __BEGIN_DECLS @@ -99,16 +92,10 @@ int __SCDynamicStoreOpen (SCDynamicStoreRef *store, CFStringRef name); int -__SCDynamicStoreClose (SCDynamicStoreRef *store, - Boolean internal); +__SCDynamicStoreClose (SCDynamicStoreRef *store); int -__SCDynamicStoreLock (SCDynamicStoreRef store, - Boolean recursive); - -int -__SCDynamicStoreUnlock (SCDynamicStoreRef store, - Boolean recursive); +__SCDynamicStorePush (void); int __SCDynamicStoreCopyKeyList (SCDynamicStoreRef store, @@ -119,8 +106,7 @@ __SCDynamicStoreCopyKeyList (SCDynamicStoreRef store, int __SCDynamicStoreAddValue (SCDynamicStoreRef store, CFStringRef key, - CFDataRef value, - Boolean internal); + CFDataRef value); int __SCDynamicStoreCopyValue (SCDynamicStoreRef store, @@ -151,10 +137,6 @@ __SCDynamicStoreRemoveValue (SCDynamicStoreRef store, CFStringRef key, Boolean internal); -int -__SCDynamicStoreTouchValue (SCDynamicStoreRef store, - CFStringRef key); - int __SCDynamicStoreNotifyValue (SCDynamicStoreRef store, CFStringRef key, @@ -202,9 +184,6 @@ __SCDynamicStoreNotifySignal (SCDynamicStoreRef store, int __SCDynamicStoreNotifyCancel (SCDynamicStoreRef store); -void -_swapLockedStoreData (void); - void _addWatcher (CFNumberRef sessionNum, CFStringRef watchedKey); diff --git a/configd.tproj/_configadd.c b/configd.tproj/_configadd.c index e1a0168..f532b47 100644 --- a/configd.tproj/_configadd.c +++ b/configd.tproj/_configadd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -36,35 +36,23 @@ __private_extern__ int -__SCDynamicStoreAddValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef value, Boolean internal) +__SCDynamicStoreAddValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef value) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; int sc_status = kSCStatusOK; + SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; CFDataRef tempValue; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (_configd_trace) { SCTrace(TRUE, _configd_trace, CFSTR("%s%s : %5d : %@\n"), - internal ? "*add " : "add ", + "add ", storePrivate->useSessionKeys ? "t " : " ", storePrivate->server, key); } /* - * 1. Ensure that we hold the lock. - */ - sc_status = __SCDynamicStoreLock(store, TRUE); - if (sc_status != kSCStatusOK) { - return sc_status; - } - - /* - * 2. Ensure that this is a new key. + * Ensure that this is a new key. */ sc_status = __SCDynamicStoreCopyValue(store, key, &tempValue, TRUE); switch (sc_status) { @@ -86,18 +74,15 @@ __SCDynamicStoreAddValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef val } /* - * 3. Save the new key. + * Save the new key. */ sc_status = __SCDynamicStoreSetValue(store, key, value, TRUE); - /* - * 4. Release our lock. - */ + /* push changes */ + __SCDynamicStorePush(); done: - __SCDynamicStoreUnlock(store, TRUE); - return sc_status; } @@ -110,8 +95,8 @@ _configadd(mach_port_t server, xmlData_t dataRef, /* raw XML bytes */ mach_msg_type_number_t dataLen, int *newInstance, - int *sc_status -) + int *sc_status, + audit_token_t audit_token) { CFStringRef key = NULL; /* key (un-serialized) */ CFDataRef data = NULL; /* data (un-serialized) */ @@ -141,11 +126,20 @@ _configadd(mach_port_t server, mySession = getSession(server); if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ + mySession = tempSession(server, CFSTR("SCDynamicStoreAddValue"), audit_token); + if (mySession == NULL) { + /* you must have an open session to play */ + *sc_status = kSCStatusNoStoreSession; + goto done; + } + } + + if (!hasWriteAccess(mySession)) { + *sc_status = kSCStatusAccessError; goto done; } - *sc_status = __SCDynamicStoreAddValue(mySession->store, key, data, FALSE); + *sc_status = __SCDynamicStoreAddValue(mySession->store, key, data); if (*sc_status == kSCStatusOK) { *newInstance = 0; } @@ -167,8 +161,7 @@ _configadd_s(mach_port_t server, xmlData_t dataRef, /* raw XML bytes */ mach_msg_type_number_t dataLen, int *newInstance, - int *sc_status -) + int *sc_status) { CFDataRef data = NULL; /* data (un-serialized) */ CFStringRef key = NULL; /* key (un-serialized) */ @@ -199,7 +192,8 @@ _configadd_s(mach_port_t server, mySession = getSession(server); if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ + /* you must have an open session to play */ + *sc_status = kSCStatusNoStoreSession; goto done; } @@ -208,7 +202,7 @@ _configadd_s(mach_port_t server, useSessionKeys = storePrivate->useSessionKeys; storePrivate->useSessionKeys = TRUE; - *sc_status = __SCDynamicStoreAddValue(mySession->store, key, data, FALSE); + *sc_status = __SCDynamicStoreAddValue(mySession->store, key, data); if (*sc_status == kSCStatusOK) { *newInstance = 0; } diff --git a/configd.tproj/_configclose.c b/configd.tproj/_configclose.c index df4a366..34e46b3 100644 --- a/configd.tproj/_configclose.c +++ b/configd.tproj/_configclose.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003, 2004, 2006-2010 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003, 2004, 2006-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -94,7 +94,7 @@ removeAllKeys(SCDynamicStoreRef store, Boolean isRegex) __private_extern__ int -__SCDynamicStoreClose(SCDynamicStoreRef *store, Boolean internal) +__SCDynamicStoreClose(SCDynamicStoreRef *store) { CFDictionaryRef dict; CFArrayRef keys; @@ -103,14 +103,9 @@ __SCDynamicStoreClose(SCDynamicStoreRef *store, Boolean internal) CFStringRef sessionKey; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)*store; - if ((*store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (_configd_trace) { SCTrace(TRUE, _configd_trace, - CFSTR("%s : %5d\n"), - internal ? "*close " : "close ", + CFSTR("close : %5d\n"), storePrivate->server); } @@ -127,48 +122,24 @@ __SCDynamicStoreClose(SCDynamicStoreRef *store, Boolean internal) dict = CFDictionaryGetValue(sessionData, sessionKey); keys = CFDictionaryGetValue(dict, kSCDSessionKeys); if (keys && ((keyCnt = CFArrayGetCount(keys)) > 0)) { - Boolean wasLocked; CFIndex i; + Boolean push = FALSE; - /* - * if necessary, claim a lock to ensure that we inform - * any processes that a session key was removed. - */ - wasLocked = (storeLocked > 0); - if (!wasLocked) { - (void) __SCDynamicStoreLock(*store, FALSE); - } - - /* remove keys from "locked" store" */ + /* remove session keys */ for (i = 0; i < keyCnt; i++) { if (isMySessionKey(sessionKey, CFArrayGetValueAtIndex(keys, i))) { (void) __SCDynamicStoreRemoveValue(*store, CFArrayGetValueAtIndex(keys, i), TRUE); + push = TRUE; } } - if (wasLocked) { - /* remove keys from "unlocked" store" */ - _swapLockedStoreData(); - for (i = 0; i < keyCnt; i++) { - if (isMySessionKey(sessionKey, CFArrayGetValueAtIndex(keys, i))) - (void) __SCDynamicStoreRemoveValue(*store, CFArrayGetValueAtIndex(keys, i), TRUE); - } - _swapLockedStoreData(); + if (push) { + /* push changes */ + (void) __SCDynamicStorePush(); } - - /* - * Note: everyone who calls __SCDynamicStoreClose() ends - * up removing this sessions dictionary. As such, - * we don't need to worry about the session keys. - */ } CFRelease(sessionKey); - /* release the lock */ - if (storePrivate->locked) { - (void) __SCDynamicStoreUnlock(*store, FALSE); - } - /* * invalidate and release our run loop source on the server * port (for this client). Then, release the port. @@ -191,45 +162,3 @@ __SCDynamicStoreClose(SCDynamicStoreRef *store, Boolean internal) return kSCStatusOK; } - - -__private_extern__ -kern_return_t -_configclose(mach_port_t server, int *sc_status) -{ - serverSessionRef mySession = getSession(server); - - if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ - return KERN_SUCCESS; - } - - /* - * Close the session. - */ - __MACH_PORT_DEBUG(TRUE, "*** _configclose", server); - *sc_status = __SCDynamicStoreClose(&mySession->store, FALSE); - if (*sc_status != kSCStatusOK) { - SCLog(TRUE, LOG_ERR, - CFSTR("_configclose __SCDynamicStoreClose() failed, status = %s"), - SCErrorString(*sc_status)); - return KERN_SUCCESS; - } - __MACH_PORT_DEBUG(TRUE, "*** _configclose (after __SCDynamicStoreClose)", server); - - /* - * Remove our receive right. - * - * Note: there is no need to cancel the notification request because the - * kernel will have no way to deliver the notification once the - * receive right has been removed. - */ - (void) mach_port_mod_refs(mach_task_self(), server, MACH_PORT_RIGHT_RECEIVE, -1); - - /* - * Remove the session entry. - */ - removeSession(server); - - return KERN_SUCCESS; -} diff --git a/configd.tproj/_configget.c b/configd.tproj/_configget.c index 13bc53f..d2a334e 100644 --- a/configd.tproj/_configget.c +++ b/configd.tproj/_configget.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (c) 2000-2004, 2006, 2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -41,10 +41,6 @@ __SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef *v SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; CFDictionaryRef dict; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (_configd_trace) { SCTrace(TRUE, _configd_trace, CFSTR("%s : %5d : %@\n"), @@ -73,10 +69,11 @@ _configget(mach_port_t server, xmlDataOut_t *dataRef, /* raw XML bytes */ mach_msg_type_number_t *dataLen, int *newInstance, - int *sc_status -) + int *sc_status, + audit_token_t audit_token) { CFStringRef key = NULL; /* key (un-serialized) */ + CFIndex len; serverSessionRef mySession; Boolean ok; CFDataRef value; @@ -97,8 +94,12 @@ _configget(mach_port_t server, mySession = getSession(server); if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ - goto done; + mySession = tempSession(server, CFSTR("SCDynamicStoreCopyValue"), audit_token); + if (mySession == NULL) { + /* you must have an open session to play */ + *sc_status = kSCStatusNoStoreSession; + goto done; + } } *sc_status = __SCDynamicStoreCopyValue(mySession->store, key, &value, FALSE); @@ -107,7 +108,8 @@ _configget(mach_port_t server, } /* serialize the data */ - ok = _SCSerializeData(value, (void **)dataRef, (CFIndex *)dataLen); + ok = _SCSerializeData(value, (void **)dataRef, &len); + *dataLen = len; CFRelease(value); if (!ok) { *sc_status = kSCStatusFailed; @@ -185,10 +187,6 @@ __SCDynamicStoreCopyMultiple(SCDynamicStoreRef store, CFArrayRef keys, CFArrayRe SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; addSpecific myContext; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (_configd_trace) { SCTrace(TRUE, _configd_trace, CFSTR("copy m : %5d : %d keys, %d patterns\n"), @@ -232,10 +230,12 @@ _configget_m(mach_port_t server, mach_msg_type_number_t patternsLen, xmlDataOut_t *dataRef, mach_msg_type_number_t *dataLen, - int *sc_status) + int *sc_status, + audit_token_t audit_token) { CFDictionaryRef dict = NULL; /* keys/values (un-serialized) */ CFArrayRef keys = NULL; /* keys (un-serialized) */ + CFIndex len; serverSessionRef mySession; Boolean ok; CFArrayRef patterns = NULL; /* patterns (un-serialized) */ @@ -275,15 +275,20 @@ _configget_m(mach_port_t server, mySession = getSession(server); if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ - goto done; + mySession = tempSession(server, CFSTR("SCDynamicStoreCopyMultiple"), audit_token); + if (mySession == NULL) { + /* you must have an open session to play */ + *sc_status = kSCStatusNoStoreSession; + goto done; + } } /* fetch the requested information */ *sc_status = __SCDynamicStoreCopyMultiple(mySession->store, keys, patterns, &dict); /* serialize the dictionary of matching keys/patterns */ - ok = _SCSerialize(dict, NULL, (void **)dataRef, (CFIndex *)dataLen); + ok = _SCSerialize(dict, NULL, (void **)dataRef, &len); + *dataLen = len; CFRelease(dict); if (!ok) { *sc_status = kSCStatusFailed; diff --git a/configd.tproj/_configlist.c b/configd.tproj/_configlist.c index cbc7e36..87ba955 100644 --- a/configd.tproj/_configlist.c +++ b/configd.tproj/_configlist.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2006-2008 Apple Inc. All rights reserved. + * Copyright (c) 2000-2004, 2006-2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -41,16 +41,11 @@ __private_extern__ int __SCDynamicStoreCopyKeyList(SCDynamicStoreRef store, CFStringRef key, Boolean isRegex, CFArrayRef *subKeys) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; CFMutableArrayRef keyArray; CFIndex storeCnt; CFStringRef storeStr; CFDictionaryRef storeValue; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (isRegex) { *subKeys = patternCopyMatches(key); return (*subKeys != NULL) ? kSCStatusOK : kSCStatusFailed; @@ -104,10 +99,11 @@ _configlist(mach_port_t server, int isRegex, xmlDataOut_t *listRef, /* raw XML bytes */ mach_msg_type_number_t *listLen, - int *sc_status -) + int *sc_status, + audit_token_t audit_token) { CFStringRef key = NULL; /* key (un-serialized) */ + CFIndex len; serverSessionRef mySession; Boolean ok; CFArrayRef subKeys; /* array of CFStringRef's */ @@ -128,8 +124,12 @@ _configlist(mach_port_t server, mySession = getSession(server); if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ - goto done; + mySession = tempSession(server, CFSTR("SCDynamicStoreCopyKeyList"), audit_token); + if (mySession == NULL) { + /* you must have an open session to play */ + *sc_status = kSCStatusNoStoreSession; + goto done; + } } *sc_status = __SCDynamicStoreCopyKeyList(mySession->store, key, isRegex != 0, &subKeys); @@ -138,7 +138,8 @@ _configlist(mach_port_t server, } /* serialize the list of keys */ - ok = _SCSerialize(subKeys, NULL, (void **)listRef, (CFIndex *)listLen); + ok = _SCSerialize(subKeys, NULL, (void **)listRef, &len); + *listLen = len; CFRelease(subKeys); if (!ok) { *sc_status = kSCStatusFailed; diff --git a/configd.tproj/_configlock.c b/configd.tproj/_configlock.c deleted file mode 100644 index 29b9726..0000000 --- a/configd.tproj/_configlock.c +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2009 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, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * 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@ - */ - -/* - * Modification History - * - * June 1, 2001 Allan Nathanson - * - public API conversion - * - * March 24, 2000 Allan Nathanson - * - initial revision - */ - -#include "configd.h" -#include "configd_server.h" -#include "session.h" - - -__private_extern__ -int -__SCDynamicStoreLock(SCDynamicStoreRef store, Boolean recursive) -{ - serverSessionRef mySession; - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - - if (storeLocked > 0) { - if (storePrivate->locked && recursive) { - /* if this session holds the lock and this is a recursive (internal) request */ - storeLocked++; - return kSCStatusOK; - } - return kSCStatusLocked; /* sorry, someone (you) already have the lock */ - } - - /* check credentials */ - mySession = getSession(storePrivate->server); - if (!hasWriteAccess(mySession)) { - return kSCStatusAccessError; - } - - if (!recursive && _configd_trace) { - SCTrace(TRUE, _configd_trace, CFSTR("lock : %5d\n"), storePrivate->server); - } - - storeLocked = 1; /* global lock flag */ - storePrivate->locked = TRUE; /* per-session lock flag */ - - /* - * defer all (actually, most) changes until the call to __SCDynamicStoreUnlock() - */ - if (storeData_s) { - CFRelease(storeData_s); - CFRelease(patternData_s); - CFRelease(changedKeys_s); - CFRelease(deferredRemovals_s); - CFRelease(removedSessionKeys_s); - } - storeData_s = CFDictionaryCreateMutableCopy(NULL, 0, storeData); - patternData_s = CFDictionaryCreateMutableCopy(NULL, 0, patternData); - changedKeys_s = CFSetCreateMutableCopy(NULL, 0, changedKeys); - deferredRemovals_s = CFSetCreateMutableCopy(NULL, 0, deferredRemovals); - removedSessionKeys_s = CFSetCreateMutableCopy(NULL, 0, removedSessionKeys); - - /* Add a "locked" mode run loop source for this port */ - CFRunLoopAddSource(CFRunLoopGetCurrent(), mySession->serverRunLoopSource, CFSTR("locked")); - - return kSCStatusOK; -} - - -__private_extern__ -kern_return_t -_configlock(mach_port_t server, int *sc_status) -{ - serverSessionRef mySession = getSession(server); - - if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ - return KERN_SUCCESS; - } - - *sc_status = __SCDynamicStoreLock(mySession->store, FALSE); - if (*sc_status != kSCStatusOK) { - return KERN_SUCCESS; - } - - return KERN_SUCCESS; -} diff --git a/configd.tproj/_confignotify.c b/configd.tproj/_confignotify.c index ab26edf..52db0f8 100644 --- a/configd.tproj/_confignotify.c +++ b/configd.tproj/_confignotify.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (c) 2000-2004, 2006, 2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -35,16 +35,12 @@ __private_extern__ int __SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key, Boolean internal) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - int sc_status = kSCStatusOK; CFDictionaryRef dict; Boolean newValue = FALSE; + SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; + int sc_status = kSCStatusOK; CFDataRef value; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (_configd_trace) { SCTrace(TRUE, _configd_trace, CFSTR("%s : %5d : %@\n"), @@ -54,15 +50,7 @@ __SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key, Boolean in } /* - * 1. Ensure that we hold the lock. - */ - sc_status = __SCDynamicStoreLock(store, TRUE); - if (sc_status != kSCStatusOK) { - return sc_status; - } - - /* - * 2. Tickle the value in the dynamic store + * Tickle the value in the dynamic store */ dict = CFDictionaryGetValue(storeData, key); if (!dict || !CFDictionaryGetValueIfPresent(dict, kSCDData, (const void **)&value)) { @@ -80,10 +68,10 @@ __SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key, Boolean in CFRelease(value); } - /* - * 3. Release our lock. - */ - __SCDynamicStoreUnlock(store, TRUE); + if (!internal) { + /* push changes */ + __SCDynamicStorePush(); + } return sc_status; } @@ -94,8 +82,8 @@ kern_return_t _confignotify(mach_port_t server, xmlData_t keyRef, /* raw XML bytes */ mach_msg_type_number_t keyLen, - int *sc_status -) + int *sc_status, + audit_token_t audit_token) { CFStringRef key = NULL; /* key (un-serialized) */ serverSessionRef mySession; @@ -113,7 +101,16 @@ _confignotify(mach_port_t server, mySession = getSession(server); if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ + mySession = tempSession(server, CFSTR("SCDynamicStoreNotifyValue"), audit_token); + if (mySession == NULL) { + /* you must have an open session to play */ + *sc_status = kSCStatusNoStoreSession; + goto done; + } + } + + if (!hasWriteAccess(mySession)) { + *sc_status = kSCStatusAccessError; goto done; } diff --git a/configd.tproj/_configopen.c b/configd.tproj/_configopen.c index 5f70aeb..07a49f9 100644 --- a/configd.tproj/_configopen.c +++ b/configd.tproj/_configopen.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2009 Apple Inc. All rights reserved. + * Copyright (c) 2000-2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -149,8 +149,11 @@ _configopen(mach_port_t server, } } - mySession = getSession(server); - if ((mySession != NULL) && (mySession->store != NULL)) { + /* + * establish the new session + */ + mySession = addSession(server, openMPCopyDescription); + if (mySession == NULL) { #ifdef DEBUG SCLog(TRUE, LOG_DEBUG, CFSTR("_configopen(): session is already open.")); #endif /* DEBUG */ @@ -158,10 +161,6 @@ _configopen(mach_port_t server, goto done; } - /* - * establish the new session - */ - mySession = addSession(MACH_PORT_NULL, openMPCopyDescription); *newServer = mySession->key; __MACH_PORT_DEBUG(TRUE, "*** _configopen (after addSession)", *newServer); diff --git a/configd.tproj/_configremove.c b/configd.tproj/_configremove.c index 9bb06b8..2d43008 100644 --- a/configd.tproj/_configremove.c +++ b/configd.tproj/_configremove.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (c) 2000-2004, 2006, 2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -38,16 +38,12 @@ __private_extern__ int __SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key, Boolean internal) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - int sc_status = kSCStatusOK; CFDictionaryRef dict; CFMutableDictionaryRef newDict; + SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; + int sc_status = kSCStatusOK; CFStringRef sessionKey; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (_configd_trace) { SCTrace(TRUE, _configd_trace, CFSTR("%s : %5d : %@\n"), @@ -57,15 +53,7 @@ __SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key, Boolean in } /* - * 1. Ensure that we hold the lock. - */ - sc_status = __SCDynamicStoreLock(store, TRUE); - if (sc_status != kSCStatusOK) { - return sc_status; - } - - /* - * 2. Ensure that this key exists. + * Ensure that this key exists. */ dict = CFDictionaryGetValue(storeData, key); if ((dict == NULL) || (CFDictionaryContainsKey(dict, kSCDData) == FALSE)) { @@ -76,21 +64,21 @@ __SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key, Boolean in newDict = CFDictionaryCreateMutableCopy(NULL, 0, dict); /* - * 3. Mark this key as "changed". Any "watchers" will be - * notified as soon as the lock is released. + * Mark this key as "changed". Any "watchers" will be + * notified as soon as the lock is released. */ CFSetAddValue(changedKeys, key); /* - * 4. Add this key to a deferred cleanup list so that, after - * the change notifications are posted, any associated - * regex keys can be removed. + * Add this key to a deferred cleanup list so that, after + * the change notifications are posted, any associated + * regex keys can be removed. */ CFSetAddValue(deferredRemovals, key); /* - * 5. Check if this is a session key and, if so, add it - * to the (session) removal list + * Check if this is a session key and, if so, add it + * to the (session) removal list */ sessionKey = CFDictionaryGetValue(newDict, kSCDSession); if (sessionKey) { @@ -106,7 +94,7 @@ __SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key, Boolean in } /* - * 6. Remove data and update/remove the dictionary store entry. + * Remove data and update/remove the dictionary store entry. */ CFDictionaryRemoveValue(newDict, kSCDData); if (CFDictionaryGetCount(newDict) > 0) { @@ -118,11 +106,12 @@ __SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key, Boolean in } CFRelease(newDict); - /* - * 7. Release our lock. - */ + if (!internal) { + /* push changes */ + __SCDynamicStorePush(); + } + done: - __SCDynamicStoreUnlock(store, TRUE); return sc_status; } @@ -133,8 +122,8 @@ kern_return_t _configremove(mach_port_t server, xmlData_t keyRef, /* raw XML bytes */ mach_msg_type_number_t keyLen, - int *sc_status -) + int *sc_status, + audit_token_t audit_token) { CFStringRef key = NULL; /* key (un-serialized) */ serverSessionRef mySession; @@ -152,7 +141,16 @@ _configremove(mach_port_t server, mySession = getSession(server); if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ + mySession = tempSession(server, CFSTR("SCDynamicStoreRemoveValue"), audit_token); + if (mySession == NULL) { + /* you must have an open session to play */ + *sc_status = kSCStatusNoStoreSession; + goto done; + } + } + + if (!hasWriteAccess(mySession)) { + *sc_status = kSCStatusAccessError; goto done; } diff --git a/configd.tproj/_configset.c b/configd.tproj/_configset.c index a15b3ec..ee05645 100644 --- a/configd.tproj/_configset.c +++ b/configd.tproj/_configset.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2006, 2008 Apple Inc. All rights reserved. + * Copyright (c) 2000-2004, 2006, 2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -41,18 +41,14 @@ __private_extern__ int __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef value, Boolean internal) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - int sc_status = kSCStatusOK; CFDictionaryRef dict; CFMutableDictionaryRef newDict; Boolean newEntry = FALSE; + int sc_status = kSCStatusOK; CFStringRef sessionKey; + SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; CFStringRef storeSessionKey; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (_configd_trace) { SCTrace(TRUE, _configd_trace, CFSTR("%s%s : %5d : %@\n"), @@ -63,15 +59,7 @@ __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef val } /* - * 1. Ensure that we hold the lock. - */ - sc_status = __SCDynamicStoreLock(store, TRUE); - if (sc_status != kSCStatusOK) { - return sc_status; - } - - /* - * 2. Grab the current (or establish a new) dictionary for this key. + * Grab the current (or establish a new) dictionary for this key. */ dict = CFDictionaryGetValue(storeData, key); @@ -87,7 +75,7 @@ __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef val } /* - * 3. Update the dictionary entry to be saved to the store. + * Update the dictionary entry to be saved to the store. */ newEntry = !CFDictionaryContainsKey(newDict, kSCDData); CFDictionarySetValue(newDict, kSCDData, value); @@ -95,7 +83,7 @@ __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef val sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server); /* - * 4. Manage per-session keys. + * Manage per-session keys. */ if (storePrivate->useSessionKeys) { if (newEntry) { @@ -180,20 +168,20 @@ __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef val CFRelease(sessionKey); /* - * 5. Update the dictionary entry in the store. + * Update the dictionary entry in the store. */ CFDictionarySetValue(storeData, key, newDict); CFRelease(newDict); /* - * 6. For "new" entries to the store, check the deferred cleanup - * list. If the key is flagged for removal, remove it from the - * list since any defined regex's for this key are still defined - * and valid. If the key is not flagged then iterate over the - * sessionData dictionary looking for regex keys which match the - * updated key. If a match is found then we mark those keys as - * being watched. + * For "new" entries to the store, check the deferred cleanup + * list. If the key is flagged for removal, remove it from the + * list since any defined regex's for this key are still defined + * and valid. If the key is not flagged then iterate over the + * sessionData dictionary looking for regex keys which match the + * updated key. If a match is found then we mark those keys as + * being watched. */ if (newEntry) { @@ -205,17 +193,17 @@ __SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFDataRef val } /* - * 7. Mark this key as "changed". Any "watchers" will be notified - * as soon as the lock is released. + * Mark this key as "changed". Any "watchers" will be notified + * as soon as the lock is released. */ CFSetAddValue(changedKeys, key); done : - /* - * 8. Release our lock. - */ - __SCDynamicStoreUnlock(store, TRUE); + if (!internal) { + /* push changes */ + __SCDynamicStorePush(); + } return sc_status; } @@ -229,8 +217,8 @@ _configset(mach_port_t server, mach_msg_type_number_t dataLen, int oldInstance, int *newInstance, - int *sc_status -) + int *sc_status, + audit_token_t audit_token) { CFDataRef data = NULL; /* data (un-serialized) */ CFStringRef key = NULL; /* key (un-serialized) */ @@ -259,7 +247,16 @@ _configset(mach_port_t server, mySession = getSession(server); if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ + mySession = tempSession(server, CFSTR("SCDynamicStoreSetValue"), audit_token); + if (mySession == NULL) { + /* you must have an open session to play */ + *sc_status = kSCStatusNoStoreSession; + goto done; + } + } + + if (!hasWriteAccess(mySession)) { + *sc_status = kSCStatusAccessError; goto done; } @@ -327,12 +324,8 @@ __private_extern__ int __SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFDictionaryRef keysToSet, CFArrayRef keysToRemove, CFArrayRef keysToNotify) { - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; int sc_status = kSCStatusOK; - - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } + SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; if (_configd_trace) { SCTrace(TRUE, _configd_trace, @@ -343,14 +336,6 @@ __SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFDictionaryRef keysToSet, keysToNotify ? CFArrayGetCount (keysToNotify) : 0); } - /* - * Ensure that we hold the lock - */ - sc_status = __SCDynamicStoreLock(store, TRUE); - if (sc_status != kSCStatusOK) { - return sc_status; - } - /* * Set the new/updated keys */ @@ -380,8 +365,8 @@ __SCDynamicStoreSetMultiple(SCDynamicStoreRef store, CFDictionaryRef keysToSet, (void *)store); } - /* Release our lock */ - __SCDynamicStoreUnlock(store, TRUE); + /* push changes */ + __SCDynamicStorePush(); return sc_status; } @@ -395,7 +380,8 @@ _configset_m(mach_port_t server, mach_msg_type_number_t removeLen, xmlData_t notifyRef, mach_msg_type_number_t notifyLen, - int *sc_status) + int *sc_status, + audit_token_t audit_token) { CFDictionaryRef dict = NULL; /* key/value dictionary (un-serialized) */ serverSessionRef mySession; @@ -446,8 +432,16 @@ _configset_m(mach_port_t server, mySession = getSession(server); if (mySession == NULL) { - /* you must have an open session to play */ - *sc_status = kSCStatusNoStoreSession; + mySession = tempSession(server, CFSTR("SCDynamicStoreSetMultiple"), audit_token); + if (mySession == NULL) { + /* you must have an open session to play */ + *sc_status = kSCStatusNoStoreSession; + goto done; + } + } + + if (!hasWriteAccess(mySession)) { + *sc_status = kSCStatusAccessError; goto done; } diff --git a/configd.tproj/_configtouch.c b/configd.tproj/_configtouch.c deleted file mode 100644 index fb30131..0000000 --- a/configd.tproj/_configtouch.c +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (c) 2000-2004, 2006, 2008, 2009 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, - * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, - * 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@ - */ - -/* - * Modification History - * - * June 1, 2001 Allan Nathanson - * - public API conversion - * - * June 20, 2000 Allan Nathanson - * - initial revision - */ - -#include "configd.h" -#include "session.h" - -__private_extern__ -int -__SCDynamicStoreTouchValue(SCDynamicStoreRef store, CFStringRef key) -{ - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - int sc_status = kSCStatusOK; - CFDataRef value; - - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - - if (_configd_trace) { - SCTrace(TRUE, _configd_trace, CFSTR("touch : %5d : %@\n"), storePrivate->server, key); - } - - /* - * 1. Ensure that we hold the lock. - */ - sc_status = __SCDynamicStoreLock(store, TRUE); - if (sc_status != kSCStatusOK) { - return sc_status; - } - - /* - * 2. Grab the current (or establish a new) store entry for this key. - */ - sc_status = __SCDynamicStoreCopyValue(store, key, &value, TRUE); - switch (sc_status) { - case kSCStatusNoKey : { - CFDateRef now; - - /* store entry does not exist, create */ - - now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()); - (void) _SCSerialize(now, &value, NULL, NULL); - CFRelease(now); - break; - } - - case kSCStatusOK : { - CFDateRef now; - - /* store entry exists */ - - (void) _SCUnserialize((CFPropertyListRef *)&now, value, NULL, 0); - if (isA_CFDate(now)) { - /* the value is a CFDate, update the time stamp */ - CFRelease(now); - CFRelease(value); - now = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()); - (void) _SCSerialize(now, &value, NULL, NULL); - } /* else, we'll just save the data (again) to bump the instance */ - CFRelease(now); - - break; - } - default : - goto done; - } - - sc_status = __SCDynamicStoreSetValue(store, key, value, TRUE); - CFRelease(value); - - done : - - /* - * 8. Release our lock. - */ - __SCDynamicStoreUnlock(store, TRUE); - - return sc_status; -} - - -__private_extern__ -kern_return_t -_configtouch(mach_port_t server, - xmlData_t keyRef, /* raw XML bytes */ - mach_msg_type_number_t keyLen, - int *sc_status -) -{ - CFStringRef key = NULL; /* key (un-serialized) */ - serverSessionRef mySession; - - /* un-serialize the key */ - if (!_SCUnserializeString(&key, NULL, (void *)keyRef, keyLen)) { - *sc_status = kSCStatusFailed; - goto done; - } - - if (!isA_CFString(key)) { - *sc_status = kSCStatusInvalidArgument; - goto done; - } - - mySession = getSession(server); - if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ - goto done; - } - - *sc_status = __SCDynamicStoreTouchValue(mySession->store, key); - - done : - - if (key) CFRelease(key); - return KERN_SUCCESS; -} diff --git a/configd.tproj/_configunlock.c b/configd.tproj/_configunlock.c index e441ec3..c5df463 100644 --- a/configd.tproj/_configunlock.c +++ b/configd.tproj/_configunlock.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2004, 2006, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -250,38 +250,8 @@ _cleanupRemovedSessionKeys(const void *value, void *context) __private_extern__ int -__SCDynamicStoreUnlock(SCDynamicStoreRef store, Boolean recursive) +__SCDynamicStorePush(void) { - serverSessionRef mySession; - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - - if ((storeLocked == 0) || !storePrivate->locked) { - return kSCStatusNeedLock; /* sorry, you don't have the lock */ - } - - if ((storeLocked > 1) && recursive) { - /* if the lock is being held for a recursive (internal) request */ - storeLocked--; - return kSCStatusOK; - } - - if (!recursive && _configd_trace) { - SCTrace(TRUE, _configd_trace, CFSTR("unlock : %5d\n"), storePrivate->server); - } - - /* - * all of the changes can be committed to the (real) store. - */ - CFDictionaryRemoveAllValues(storeData_s); - CFDictionaryRemoveAllValues(patternData_s); - CFSetRemoveAllValues (changedKeys_s); - CFSetRemoveAllValues (deferredRemovals_s); - CFSetRemoveAllValues (removedSessionKeys_s); - /* * push notifications to any session watching those keys which * were recently changed. @@ -299,32 +269,5 @@ __SCDynamicStoreUnlock(SCDynamicStoreRef store, Boolean recursive) CFSetApplyFunction(removedSessionKeys, _cleanupRemovedSessionKeys, NULL); CFSetRemoveAllValues(removedSessionKeys); - /* Remove the "locked" run loop source for this port */ - mySession = getSession(storePrivate->server); - CFRunLoopRemoveSource(CFRunLoopGetCurrent(), mySession->serverRunLoopSource, CFSTR("locked")); - - storeLocked = 0; /* global lock flag */ - storePrivate->locked = FALSE; /* per-session lock flag */ - return kSCStatusOK; } - - -__private_extern__ -kern_return_t -_configunlock(mach_port_t server, int *sc_status) -{ - serverSessionRef mySession = getSession(server); - - if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ - return KERN_SUCCESS; - } - - *sc_status = __SCDynamicStoreUnlock(mySession->store, FALSE); - if (*sc_status != kSCStatusOK) { - return KERN_SUCCESS; - } - - return KERN_SUCCESS; -} diff --git a/configd.tproj/_notifyadd.c b/configd.tproj/_notifyadd.c index 5fd22f6..22468ff 100644 --- a/configd.tproj/_notifyadd.c +++ b/configd.tproj/_notifyadd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2006, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2004, 2006, 2008, 2010, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -89,10 +89,6 @@ __SCDynamicStoreAddWatchedKey(SCDynamicStoreRef store, CFStringRef key, Boolean CFNumberRef sessionNum = NULL; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (_configd_trace) { SCTrace(TRUE, _configd_trace, CFSTR("%s : %5d : %s : %@\n"), @@ -250,10 +246,6 @@ __SCDynamicStoreSetNotificationKeys(SCDynamicStoreRef store, CFArrayRef keys, CF updateKeysContext myContext; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (_configd_trace) { SCTrace(TRUE, _configd_trace, CFSTR("watch : %5d : %d keys, %d patterns\n"), diff --git a/configd.tproj/_notifychanges.c b/configd.tproj/_notifychanges.c index 1c1ec6f..a40fb6e 100644 --- a/configd.tproj/_notifychanges.c +++ b/configd.tproj/_notifychanges.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2003, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2003, 2006, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -43,10 +43,6 @@ __SCDynamicStoreCopyNotifiedKeys(SCDynamicStoreRef store, CFArrayRef *notifierKe CFDictionaryRef info; CFMutableDictionaryRef newInfo; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), storePrivate->server); info = CFDictionaryGetValue(sessionData, sessionKey); if ((info == NULL) || @@ -81,6 +77,7 @@ _notifychanges(mach_port_t server, int *sc_status ) { + CFIndex len; serverSessionRef mySession = getSession(server); CFArrayRef notifierKeys; /* array of CFStringRef's */ Boolean ok; @@ -99,7 +96,8 @@ _notifychanges(mach_port_t server, } /* serialize the array of keys */ - ok = _SCSerialize(notifierKeys, NULL, (void **)listRef, (CFIndex *)listLen); + ok = _SCSerialize(notifierKeys, NULL, (void **)listRef, &len); + *listLen = len; CFRelease(notifierKeys); if (!ok) { *sc_status = kSCStatusFailed; diff --git a/configd.tproj/_notifyremove.c b/configd.tproj/_notifyremove.c index 5af6405..bd4a261 100644 --- a/configd.tproj/_notifyremove.c +++ b/configd.tproj/_notifyremove.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2006, 2008, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2004, 2006, 2008, 2010, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -69,10 +69,6 @@ __SCDynamicStoreRemoveWatchedKey(SCDynamicStoreRef store, CFStringRef key, Boole CFNumberRef sessionNum; SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (_configd_trace) { SCTrace(TRUE, _configd_trace, CFSTR("%s : %5d : %s : %@\n"), diff --git a/configd.tproj/_notifyviafd.c b/configd.tproj/_notifyviafd.c index 2cda2b7..f855c6b 100644 --- a/configd.tproj/_notifyviafd.c +++ b/configd.tproj/_notifyviafd.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003-2006, 2008-2010 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003-2006, 2008-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -53,10 +53,6 @@ __SCDynamicStoreNotifyFileDescriptor(SCDynamicStoreRef store, CFStringRef sessionKey; CFDictionaryRef info; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (storePrivate->notifyStatus != NotifierNotRegistered) { /* sorry, you can only have one notification registered at once */ return kSCStatusNotifierActive; diff --git a/configd.tproj/_notifyviaport.c b/configd.tproj/_notifyviaport.c index 8456108..8f52a78 100644 --- a/configd.tproj/_notifyviaport.c +++ b/configd.tproj/_notifyviaport.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2009 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003, 2004, 2006, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -44,10 +44,6 @@ __SCDynamicStoreNotifyMachPort(SCDynamicStoreRef store, CFStringRef sessionKey; CFDictionaryRef info; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (storePrivate->notifyStatus != NotifierNotRegistered) { /* sorry, you can only have one notification registered at once */ return kSCStatusNotifierActive; diff --git a/configd.tproj/_notifyviasignal.c b/configd.tproj/_notifyviasignal.c index 4021c40..9d15ce9 100644 --- a/configd.tproj/_notifyviasignal.c +++ b/configd.tproj/_notifyviasignal.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2006, 2009 Apple Inc. All rights reserved. + * Copyright (c) 2000-2004, 2006, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -46,10 +46,6 @@ __SCDynamicStoreNotifySignal(SCDynamicStoreRef store, pid_t pid, int sig) CFStringRef sessionKey; CFDictionaryRef info; - if ((store == NULL) || (storePrivate->server == MACH_PORT_NULL)) { - return kSCStatusNoStoreSession; /* you must have an open session to play */ - } - if (storePrivate->notifyStatus != NotifierNotRegistered) { /* sorry, you can only have one notification registered at once */ return kSCStatusNotifierActive; diff --git a/configd.tproj/_snapshot.c b/configd.tproj/_snapshot.c index 2c94f85..be7b77b 100644 --- a/configd.tproj/_snapshot.c +++ b/configd.tproj/_snapshot.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2006, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2006, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -49,7 +49,7 @@ #define N_QUICK 100 -static CFDictionaryRef +static CF_RETURNS_RETAINED CFDictionaryRef _expandStore(CFDictionaryRef storeData) { const void * keys_q[N_QUICK]; @@ -125,17 +125,8 @@ __SCDynamicStoreSnapshot(SCDynamicStoreRef store) CFDictionaryRef expandedStoreData; FILE *f; int fd; - serverSessionRef mySession; - SCDynamicStorePrivateRef storePrivate = (SCDynamicStorePrivateRef)store; CFDataRef xmlData; - /* check credentials */ - - mySession = getSession(storePrivate->server); - if (!hasRootAccess(mySession)) { - return kSCStatusAccessError; - } - /* Save a snapshot of configd's "state" */ (void) unlink(SNAPSHOT_PATH_STATE); @@ -218,13 +209,21 @@ __SCDynamicStoreSnapshot(SCDynamicStoreRef store) __private_extern__ kern_return_t -_snapshot(mach_port_t server, int *sc_status) +_snapshot(mach_port_t server, int *sc_status, audit_token_t audit_token) { - serverSessionRef mySession = getSession(server); + serverSessionRef mySession; + mySession = getSession(server); if (mySession == NULL) { - *sc_status = kSCStatusNoStoreSession; /* you must have an open session to play */ - return KERN_SUCCESS; + mySession = tempSession(server, CFSTR("SCDynamicStoreSnapshot"), audit_token); + if (mySession == NULL) { + /* you must have an open session to play */ + return kSCStatusNoStoreSession; + } + } + + if (!hasRootAccess(mySession)) { + return kSCStatusAccessError; } *sc_status = __SCDynamicStoreSnapshot(mySession->store); diff --git a/configd.tproj/com.apple.configd.plist b/configd.tproj/com.apple.configd.plist index 3ffea54..33473f1 100644 --- a/configd.tproj/com.apple.configd.plist +++ b/configd.tproj/com.apple.configd.plist @@ -12,7 +12,11 @@ com.apple.SystemConfiguration.configd + com.apple.SystemConfiguration.SCNetworkReachability + + POSIXSpawnType + Interactive ProgramArguments /usr/libexec/configd diff --git a/configd.tproj/configd.h b/configd.tproj/configd.h index ce441fa..0a6b13c 100644 --- a/configd.tproj/configd.h +++ b/configd.tproj/configd.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003, 2006, 2007 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003, 2006, 2007, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -53,6 +53,7 @@ extern Boolean _configd_verbose; /* TRUE if verbose logging enabled */ extern FILE *_configd_trace; /* non-NULL if tracing enabled */ +extern CFMutableSetRef _plugins_allowed; /* bundle identifiers to allow when loading */ extern CFMutableSetRef _plugins_exclude; /* bundle identifiers to exclude from loading */ extern Boolean _plugins_fork; /* TRUE if plugins should be exec'd in their own process */ extern CFMutableSetRef _plugins_verbose; /* bundle identifiers to enable verbose logging */ diff --git a/configd.tproj/configd.m b/configd.tproj/configd.m index d701c24..0a52729 100644 --- a/configd.tproj/configd.m +++ b/configd.tproj/configd.m @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -34,7 +34,7 @@ * - created */ -//#define DO_NOT_INFORM +#define DO_NOT_INFORM #include #include @@ -65,6 +65,9 @@ Boolean _configd_verbose = FALSE; /* TRUE if verbose logging enabled */ __private_extern__ FILE *_configd_trace = NULL; /* non-NULL if tracing enabled */ +__private_extern__ +CFMutableSetRef _plugins_allowed = NULL; /* bundle identifiers to allow when loading */ + __private_extern__ CFMutableSetRef _plugins_exclude = NULL; /* bundle identifiers to exclude from loading */ @@ -78,6 +81,7 @@ static CFMachPortRef termRequested = NULL; /* Mach port used to notify runloop static const struct option longopts[] = { +// { "include-plugin", required_argument, 0, 'A' }, // { "no-bundles", no_argument, 0, 'b' }, // { "exclude-plugin", required_argument, 0, 'B' }, // { "no-fork", no_argument, 0, 'd' }, @@ -93,7 +97,7 @@ static const struct option longopts[] = { static void usage(const char *prog) { - SCPrint(TRUE, stderr, CFSTR("%s: [-d] [-v] [-V bundleID] [-b] [-B bundleID] [-t bundle-path]\n"), prog); + SCPrint(TRUE, stderr, CFSTR("%s: [-d] [-v] [-V bundleID] [-b] [-B bundleID] [-A bundleID] [-t bundle-path]\n"), prog); SCPrint(TRUE, stderr, CFSTR("options:\n")); SCPrint(TRUE, stderr, CFSTR("\t-d\tdisable daemon/run in foreground\n")); SCPrint(TRUE, stderr, CFSTR("\t-v\tenable verbose logging\n")); @@ -101,6 +105,7 @@ usage(const char *prog) SCPrint(TRUE, stderr, CFSTR("\t-f\tload ALL plug-ins in a separate process\n")); SCPrint(TRUE, stderr, CFSTR("\t-b\tdisable loading of ALL plug-ins\n")); SCPrint(TRUE, stderr, CFSTR("\t-B\tdisable loading of the specified plug-in\n")); + SCPrint(TRUE, stderr, CFSTR("\t-A\tenable loading of the specified plug-in\n")); SCPrint(TRUE, stderr, CFSTR("\t-t\tload/test the specified plug-in\n")); SCPrint(TRUE, stderr, CFSTR("\t\t (Note: only the plug-in will be started)\n")); exit (EX_USAGE); @@ -260,20 +265,6 @@ fork_child() return 0; } - -static void -writepid(void) -{ - FILE *fp; - - fp = fopen("/var/run/configd.pid", "w"); - if (fp != NULL) { - fprintf(fp, "%d\n", getpid()); - fclose(fp); - } -} - - static CFStringRef termMPCopyDescription(const void *info) { @@ -297,20 +288,26 @@ main(int argc, char * const argv[]) Boolean loadBundles = TRUE; struct sigaction nact; int opt; - extern int optind; +// extern int optind; const char *prog = argv[0]; CFRunLoopSourceRef rls; kern_return_t status; CFStringRef str; const char *testBundle = NULL; + _plugins_allowed = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); _plugins_exclude = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); _plugins_verbose = CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks); /* process any arguments */ - while ((opt = getopt_long(argc, argv, "bB:dt:vV:f", longopts, NULL)) != -1) { + while ((opt = getopt_long(argc, argv, "A:bB:dt:vV:f", longopts, NULL)) != -1) { switch(opt) { + case 'A': + str = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingMacRoman); + CFSetSetValue(_plugins_allowed, str); + CFRelease(str); + break; case 'b': loadBundles = FALSE; break; @@ -437,11 +434,6 @@ main(int argc, char * const argv[]) /* check/enable trace logging */ set_trace(); - /* record process id */ - if (testBundle == NULL) { - writepid(); - } - /* add signal handler to catch a SIGHUP */ nact.sa_handler = catcher; sigemptyset(&nact.sa_mask); diff --git a/configd.tproj/configd_server.c b/configd.tproj/configd_server.c index dce8172..99240d5 100644 --- a/configd.tproj/configd_server.c +++ b/configd.tproj/configd_server.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -251,14 +251,10 @@ server_init() /* * Create and add a run loop source for the port and add this source - * to both the default run loop mode and the "locked" mode. These two - * modes will be used for normal (unlocked) communication with the - * server and when multiple (locked) updates are requested by a single - * session. + * to the default run loop mode. */ rls = CFMachPortCreateRunLoopSource(NULL, configd_port, 0); CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, kCFRunLoopDefaultMode); - CFRunLoopAddSource(CFRunLoopGetCurrent(), rls, CFSTR("locked")); CFRelease(rls); return; @@ -293,16 +289,13 @@ __private_extern__ void server_loop() { - CFStringRef rlMode; - pthread_setname_np("SCDynamicStore"); while (TRUE) { /* * process one run loop event */ - rlMode = (storeLocked > 0) ? CFSTR("locked") : kCFRunLoopDefaultMode; - CFRunLoopRunInMode(rlMode, 1.0e10, TRUE); + CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, TRUE); /* * check for, and if necessary, push out change notifications diff --git a/configd.tproj/configd_server.h b/configd.tproj/configd_server.h index 934c91b..7363bd6 100644 --- a/configd.tproj/configd_server.h +++ b/configd.tproj/configd_server.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2006, 2008 Apple Inc. All rights reserved. + * Copyright (c) 2000-2006, 2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -52,7 +52,8 @@ int server_shutdown (void); void server_loop (void); kern_return_t _snapshot (mach_port_t server, - int *sc_status); + int *sc_status, + audit_token_t audit_token); kern_return_t _configopen (mach_port_t server, xmlData_t nameRef, @@ -63,22 +64,14 @@ kern_return_t _configopen (mach_port_t server, int *sc_status, audit_token_t audit_token); -kern_return_t _configclose (mach_port_t server, - int *sc_status); - -kern_return_t _configlock (mach_port_t server, - int *sc_status); - -kern_return_t _configunlock (mach_port_t server, - int *sc_status); - kern_return_t _configlist (mach_port_t server, xmlData_t keyRef, mach_msg_type_number_t keyLen, int isRegex, xmlDataOut_t *listRef, mach_msg_type_number_t *listLen, - int *sc_status); + int *sc_status, + audit_token_t audit_token); kern_return_t _configadd (mach_port_t server, xmlData_t keyRef, @@ -86,7 +79,8 @@ kern_return_t _configadd (mach_port_t server, xmlData_t dataRef, mach_msg_type_number_t dataLen, int *newInstance, - int *sc_status); + int *sc_status, + audit_token_t audit_token); kern_return_t _configadd_s (mach_port_t server, xmlData_t keyRef, @@ -102,7 +96,8 @@ kern_return_t _configget (mach_port_t server, xmlDataOut_t *dataRef, mach_msg_type_number_t *dataLen, int *newInstance, - int *sc_status); + int *sc_status, + audit_token_t audit_token); kern_return_t _configset (mach_port_t server, xmlData_t keyRef, @@ -110,22 +105,20 @@ kern_return_t _configset (mach_port_t server, xmlData_t dataRef, mach_msg_type_number_t dataLen, int *newInstance, - int *sc_status); + int *sc_status, + audit_token_t audit_token); kern_return_t _configremove (mach_port_t server, xmlData_t keyRef, mach_msg_type_number_t keyLen, - int *sc_status); - -kern_return_t _configtouch (mach_port_t server, - xmlData_t keyRef, - mach_msg_type_number_t keyLen, - int *sc_status); + int *sc_status, + audit_token_t audit_token); kern_return_t _confignotify (mach_port_t server, xmlData_t keyRef, mach_msg_type_number_t keyLen, - int *sc_status); + int *sc_status, + audit_token_t audit_token); kern_return_t _configget_m (mach_port_t server, xmlData_t keysRef, @@ -134,7 +127,8 @@ kern_return_t _configget_m (mach_port_t server, mach_msg_type_number_t patternsLen, xmlDataOut_t *dataRef, mach_msg_type_number_t *dataLen, - int *sc_status); + int *sc_status, + audit_token_t audit_token); kern_return_t _configset_m (mach_port_t server, xmlData_t dataRef, @@ -143,7 +137,8 @@ kern_return_t _configset_m (mach_port_t server, mach_msg_type_number_t removeLen, xmlData_t notifyRef, mach_msg_type_number_t notifyLen, - int *sc_status); + int *sc_status, + audit_token_t audit_token); kern_return_t _notifyadd (mach_port_t server, xmlData_t keyRef, diff --git a/configd.tproj/entitlements.plist b/configd.tproj/entitlements.plist index 9309ae1..5b7d736 100644 --- a/configd.tproj/entitlements.plist +++ b/configd.tproj/entitlements.plist @@ -5,13 +5,14 @@ keychain-access-groups apple + com.apple.certificates com.apple.identities com.apple.springboard.launchapplications - com.apple.wifi.manager-access + com.apple.multitasking.unlimitedassertions - com.apple.MobileInternetSharing.allow + com.apple.wifi.manager-access diff --git a/configd.tproj/pattern.c b/configd.tproj/pattern.c index 58a87be..f307903 100644 --- a/configd.tproj/pattern.c +++ b/configd.tproj/pattern.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2004, 2006-2008 Apple Inc. All rights reserved. + * Copyright (c) 2003, 2004, 2006-2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -199,7 +199,7 @@ patternCompile(CFStringRef pattern, regex_t *preg, CFStringRef *error) } -static CFMutableArrayRef +static CF_RETURNS_RETAINED CFMutableArrayRef patternCopy(CFStringRef pattern) { CFArrayRef pInfo; @@ -209,7 +209,7 @@ patternCopy(CFStringRef pattern) } -static CFMutableArrayRef +static CF_RETURNS_RETAINED CFMutableArrayRef patternNew(CFStringRef pattern) { addContext context; @@ -224,7 +224,8 @@ patternNew(CFStringRef pattern) /* compile the regular expression from the pattern string. */ pRegex = CFDataCreateMutable(NULL, sizeof(regex_t)); CFDataSetLength(pRegex, sizeof(regex_t)); - if (!patternCompile(pattern, (regex_t *)CFDataGetBytePtr(pRegex), &err)) { + /* ALIGN: CF aligns to >8 byte boundries */ + if (!patternCompile(pattern, (regex_t *)(void *)CFDataGetBytePtr(pRegex), &err)) { CFRelease(err); CFRelease(pRegex); CFRelease(pInfo); @@ -241,7 +242,8 @@ patternNew(CFStringRef pattern) /* identify/add all existing keys that match the specified pattern */ context.pInfo = pInfo; - context.preg = (regex_t *)CFDataGetBytePtr(pRegex); + /* ALIGN: CF aligns to >8 byte boundries */ + context.preg = (regex_t *)(void *)CFDataGetBytePtr(pRegex); my_CFDictionaryApplyFunction(storeData, (CFDictionaryApplierFunction)identifyKeyForPattern, &context); @@ -275,7 +277,8 @@ patternCopyMatches(CFStringRef pattern) CFDataRef pRegex; pRegex = CFArrayGetValueAtIndex(pInfo, 0); - regfree((regex_t *)CFDataGetBytePtr(pRegex)); + /* ALIGN: CF aligns to >8 byte boundries */ + regfree((regex_t *)(void *)CFDataGetBytePtr(pRegex)); } CFArrayReplaceValues(pInfo, CFRangeMake(0, 2), NULL, 0); @@ -368,7 +371,8 @@ patternRemoveSession(CFStringRef pattern, CFNumberRef sessionNum) /* if no other sessions are watching this pattern */ pRegex = CFArrayGetValueAtIndex(pInfo, 0); - regfree((regex_t *)CFDataGetBytePtr(pRegex)); + /* ALIGN: CF aligns to >8 byte boundries */ + regfree((regex_t *)(void *)CFDataGetBytePtr(pRegex)); CFDictionaryRemoveValue(patternData, pattern); } @@ -400,7 +404,8 @@ addKeyForPattern(const void *key, void *val, void *context) } /* compare new store key to regular expression pattern */ - preg = (regex_t *)CFDataGetBytePtr(CFArrayGetValueAtIndex(pInfo, 0)); + /* ALIGN: CF aligns to >8 byte boundries */ + preg = (regex_t *)(void *)CFDataGetBytePtr(CFArrayGetValueAtIndex(pInfo, 0)); reError = regexec(preg, str, 0, NULL, 0); switch (reError) { case 0 : { diff --git a/configd.tproj/plugin_support.c b/configd.tproj/plugin_support.c index eded4d6..309631d 100644 --- a/configd.tproj/plugin_support.c +++ b/configd.tproj/plugin_support.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2009, 2011 Apple Inc. All rights reserved. + * Copyright (c) 2000-2009, 2011, 2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -49,6 +49,7 @@ #include "configd.h" #include "configd_server.h" #include +#include "SCNetworkReachabilityInternal.h" void _SCDPluginExecInit(); @@ -59,11 +60,44 @@ void _SCDPluginExecInit(); #define BUNDLE_DIR_EXTENSION ".bundle" +#define PLUGIN_ALL(p) CFSTR(p) +#if !TARGET_OS_EMBEDDED +#define PLUGIN_MACOSX(p) CFSTR(p) +#define PLUGIN_IOS(p) NULL +#else // !TARGET_OS_EMBEDDED +#define PLUGIN_MACOSX(p) NULL +#define PLUGIN_IOS(p) CFSTR(p) +#endif // !TARGET_OS_EMBEDDED + +// white-listed (ok-to-load) bundle identifiers +static const CFStringRef pluginWhitelist[] = { + PLUGIN_MACOSX("com.apple.SystemConfiguration.Apple80211"), + PLUGIN_MACOSX("com.apple.SystemConfiguration.ApplicationFirewall"), + PLUGIN_MACOSX("com.apple.SystemConfiguration.Bluetooth"), + PLUGIN_ALL ("com.apple.SystemConfiguration.EAPOLController"), + PLUGIN_ALL ("com.apple.SystemConfiguration.IPConfiguration"), + PLUGIN_ALL ("com.apple.SystemConfiguration.IPMonitor"), + PLUGIN_ALL ("com.apple.SystemConfiguration.InterfaceNamer"), + PLUGIN_ALL ("com.apple.SystemConfiguration.KernelEventMonitor"), + PLUGIN_ALL ("com.apple.SystemConfiguration.LinkConfiguration"), + PLUGIN_ALL ("com.apple.SystemConfiguration.Logger"), + PLUGIN_ALL ("com.apple.SystemConfiguration.PPPController"), + PLUGIN_ALL ("com.apple.SystemConfiguration.PreferencesMonitor"), +#ifdef HAVE_REACHABILITY_SERVER + PLUGIN_ALL ("com.apple.SystemConfiguration.SCNetworkReachability"), +#endif // HAVE_REACHABILITY_SERVER + PLUGIN_MACOSX("com.apple.SystemConfiguration.wwanConfig"), + PLUGIN_MACOSX("com.apple.print.notification"), +}; +#define N_PLUGIN_WHITELIST (sizeof(pluginWhitelist) / sizeof(pluginWhitelist[0])) + + typedef struct { CFBundleRef bundle; Boolean loaded; Boolean builtin; Boolean enabled; + Boolean forced; Boolean verbose; SCDynamicStoreBundleLoadFunction load; SCDynamicStoreBundleStartFunction start; @@ -91,8 +125,9 @@ extern SCDynamicStoreBundlePrimeFunction prime_KernelEventMonitor; extern SCDynamicStoreBundleLoadFunction load_LinkConfiguration; extern SCDynamicStoreBundleLoadFunction load_PreferencesMonitor; extern SCDynamicStoreBundlePrimeFunction prime_PreferencesMonitor; -extern SCDynamicStoreBundleLoadFunction load_NetworkIdentification; -extern SCDynamicStoreBundlePrimeFunction prime_NetworkIdentification; +#ifdef HAVE_REACHABILITY_SERVER +extern SCDynamicStoreBundleLoadFunction load_SCNetworkReachability; +#endif // HAVE_REACHABILITY_SERVER typedef struct { @@ -134,19 +169,21 @@ static const builtin builtin_plugins[] = { NULL }, { - CFSTR("com.apple.SystemConfiguration.NetworkIdentification"), - &load_NetworkIdentification, + CFSTR("com.apple.SystemConfiguration.PreferencesMonitor"), + &load_PreferencesMonitor, NULL, - &prime_NetworkIdentification, + &prime_PreferencesMonitor, NULL }, +#ifdef HAVE_REACHABILITY_SERVER { - CFSTR("com.apple.SystemConfiguration.PreferencesMonitor"), - &load_PreferencesMonitor, + CFSTR("com.apple.SystemConfiguration.SCNetworkReachability"), + &load_SCNetworkReachability, + NULL, NULL, - &prime_PreferencesMonitor, NULL - } + }, +#endif // HAVE_REACHABILITY_SERVER }; @@ -185,6 +222,7 @@ addBundle(CFBundleRef bundle, Boolean forceEnabled) bundleInfo->loaded = FALSE; bundleInfo->builtin = FALSE; bundleInfo->enabled = TRUE; + bundleInfo->forced = forceEnabled; bundleInfo->verbose = FALSE; bundleInfo->load = NULL; bundleInfo->start = NULL; @@ -211,16 +249,12 @@ addBundle(CFBundleRef bundle, Boolean forceEnabled) } } - if (forceEnabled) { - bundleInfo->enabled = TRUE; - } - CFArrayAppendValue(allBundles, bundleInfo); return; } -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef shortBundleIdentifier(CFStringRef bundleID) { CFIndex len = CFStringGetLength(bundleID); @@ -363,6 +397,7 @@ forkBundle(CFBundleRef bundle, CFStringRef bundleID) static void loadBundle(const void *value, void *context) { CFStringRef bundleID; + Boolean bundleAllowed; bundleInfoRef bundleInfo = (bundleInfoRef)value; Boolean bundleExclude; CFIndex *nLoaded = (CFIndex *)context; @@ -377,26 +412,35 @@ loadBundle(const void *value, void *context) { shortID = shortBundleIdentifier(bundleID); - bundleExclude = CFSetContainsValue(_plugins_exclude, bundleID); - if (!bundleExclude) { - if (shortID != NULL) { - bundleExclude = CFSetContainsValue(_plugins_exclude, shortID); - } + bundleAllowed = ((CFSetGetCount(_plugins_allowed) == 0) || // if no white-listing + CFSetContainsValue(_plugins_allowed, bundleID) || // if [bundleID] white-listed + ((shortID != NULL) && + CFSetContainsValue(_plugins_allowed, shortID))|| // if [short bundleID] white-listed + bundleInfo->forced // if "testing" plugin + ); + if (!bundleAllowed) { + SCLog(TRUE, LOG_WARNING, CFSTR("skipped %@ (not allowed)"), bundleID); + goto done; } + bundleExclude = (CFSetContainsValue(_plugins_exclude, bundleID) || // if [bundleID] excluded + ((shortID != NULL) && + CFSetContainsValue(_plugins_exclude, shortID)) // if [short bundleID] excluded + ); if (bundleExclude) { // sorry, this bundle has been excluded SCLog(TRUE, LOG_NOTICE, CFSTR("skipped %@ (excluded)"), bundleID); goto done; } - if (!bundleInfo->enabled) { + if (!bundleInfo->enabled && !bundleInfo->forced) { // sorry, this bundle has not been enabled SCLog(TRUE, LOG_INFO, CFSTR("skipped %@ (disabled)"), bundleID); goto done; } - if (_plugins_fork) { + if (_plugins_fork && + !_SC_CFEqual(bundleID, CFSTR("com.apple.SystemConfiguration.SCNetworkReachability"))) { forkBundle(bundleInfo->bundle, bundleID); goto done; } @@ -899,11 +943,19 @@ __private_extern__ void * plugin_exec(void *arg) { + int i; CFIndex nLoaded = 0; /* keep track of bundles */ allBundles = CFArrayCreateMutable(NULL, 0, NULL); + /* add white-listed plugins to those we'll allow to be loaded */ + for (i = 0; i < N_PLUGIN_WHITELIST; i++) { + if (pluginWhitelist[i] != NULL) { + CFSetSetValue(_plugins_allowed, pluginWhitelist[i]); + } + } + /* allow plug-ins to exec child/helper processes */ _SCDPluginExecInit(); @@ -976,6 +1028,39 @@ plugin_exec(void *arg) CFRelease(url); } + /* + * Look for the InterfaceNamer plugin, and move it to the start + * of the list. + * + * Load the InterfaceNamer plugin (and thereby start its thread) + * first in an attempt to minimize the amount of time that + * opendirectoryd has to wait for the platform UUID to appear in + * nvram. + * + * InterfaceNamer is responsible for creating the platform UUID on + * platforms without a UUID in ROM. Until the platform UUID is created + * and stashed in nvram, all calls to opendirectoryd to do things like + * getpwuid() will block, because opendirectoryd will block while trying + * to read the platform UUID from the kernel. + * + * As an example, dlopen() causes XPC to do some intialization, and + * part of that initialization involves communicating with xpcd. + * Since xpcd calls getpwuid_r() during its initialization, it will + * block until the platform UUID is available. + */ + for (int i = 0; i < CFArrayGetCount(allBundles); i++) { + bundleInfoRef bi = (bundleInfoRef)CFArrayGetValueAtIndex(allBundles, i); + CFStringRef bundleID = CFBundleGetIdentifier(bi->bundle); + + if (_SC_CFEqual(bundleID, + CFSTR("com.apple.SystemConfiguration.InterfaceNamer"))) + { + CFArrayRemoveValueAtIndex(allBundles, i); + CFArrayInsertValueAtIndex(allBundles, 0, bi); + break; + } + } + #ifdef DEBUG traceBundle("before loading any plugins", NULL); #endif /* DEBUG */ diff --git a/configd.tproj/session.c b/configd.tproj/session.c index 1b77827..cbb5b96 100644 --- a/configd.tproj/session.c +++ b/configd.tproj/session.c @@ -41,12 +41,16 @@ /* information maintained for each active session */ -static serverSessionRef *sessions = NULL; -static int nSessions = 0; +static serverSessionRef *sessions = NULL; +static int nSessions = 0; /* # of allocated sessions */ +static int lastSession = -1; /* # of last used session */ /* CFMachPortInvalidation runloop */ static CFRunLoopRef sessionRunLoop = NULL; +/* temp session */ +static serverSessionRef temp_session = NULL; + static void CFMachPortInvalidateSessionCallback(CFMachPortRef port, void *info) @@ -73,16 +77,23 @@ getSession(mach_port_t server) return NULL; } - for (i = 0; i < nSessions; i++) { + /* look for matching session (note: slot 0 is the "server" port) */ + for (i = 1; i <= lastSession; i++) { serverSessionRef thisSession = sessions[i]; if (thisSession == NULL) { /* found an empty slot, skip it */ continue; - } else if (thisSession->key == server) { - return thisSession; /* we've seen this server before */ - } else if (thisSession->store && - (((SCDynamicStorePrivateRef)thisSession->store)->notifySignalTask == server)) { + } + + if (thisSession->key == server) { + /* we've seen this server before */ + return thisSession; + } + + if ((thisSession->store != NULL) && + (((SCDynamicStorePrivateRef)thisSession->store)->notifySignalTask == server)) { + /* we've seen this task port before */ return thisSession; } } @@ -92,6 +103,38 @@ getSession(mach_port_t server) } +__private_extern__ +serverSessionRef +tempSession(mach_port_t server, CFStringRef name, audit_token_t auditToken) +{ + static dispatch_once_t once; + SCDynamicStorePrivateRef storePrivate; + + if (sessions[0]->key != server) { + // if not SCDynamicStore "server" port + return NULL; + } + + dispatch_once(&once, ^{ + temp_session = sessions[0]; /* use "server" session */ + (void) __SCDynamicStoreOpen(&temp_session->store, NULL); + }); + + /* save audit token */ + temp_session->auditToken = auditToken; + temp_session->callerEUID = -1; /* not "root" */ + temp_session->callerRootAccess = UNKNOWN; + temp_session->callerWriteAccess = UNKNOWN; + + /* save name */ + storePrivate = (SCDynamicStorePrivateRef)temp_session->store; + if (storePrivate->name != NULL) CFRelease(storePrivate->name); + storePrivate->name = CFRetain(name); + + return temp_session; +} + + __private_extern__ serverSessionRef addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info)) @@ -106,26 +149,58 @@ addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info)) } if (nSessions <= 0) { - /* new session (actually, the first) found */ - sessions = malloc(sizeof(serverSessionRef)); - n = 0; - nSessions = 1; + /* if first session (the "server" port) */ + n = 0; /* use slot "0" */ + lastSession = 0; /* last used slot */ + + nSessions = 64; + sessions = malloc(nSessions * sizeof(serverSessionRef)); } else { int i; - for (i = 0; i < nSessions; i++) { - if (sessions[i] == NULL) { - /* found an empty slot, use it */ - n = i; - break; + /* check to see if we already have an open session (note: slot 0 is the "server" port) */ + for (i = 1; i <= lastSession; i++) { + serverSessionRef thisSession = sessions[i]; + + if (thisSession == NULL) { + /* found an empty slot */ + if (n < 0) { + /* keep track of the first [empty] slot */ + n = i; + } + + /* and keep looking for a matching session */ + continue; + } + + if (thisSession->key == server) { + /* we've seen this server before */ + return NULL; + } + + if ((thisSession->store != NULL) && + (((SCDynamicStorePrivateRef)thisSession->store)->notifySignalTask == server)) { + /* we've seen this task port before */ + return NULL; } } - /* new session identified */ + + /* add a new session */ if (n < 0) { - /* no empty slots, add one to the list */ - n = nSessions++; - sessions = reallocf(sessions, ((nSessions) * sizeof(serverSessionRef))); + /* if no empty slots */ + n = ++lastSession; + if (lastSession >= nSessions) { + /* expand the session list */ + nSessions *= 2; + sessions = reallocf(sessions, (nSessions * sizeof(serverSessionRef))); + } } + + // create mach port for SCDynamicStore client + mp = MACH_PORT_NULL; + (void) mach_port_allocate(mach_task_self(), + MACH_PORT_RIGHT_RECEIVE, + &mp); } // allocate a new session for this server @@ -133,15 +208,8 @@ addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info)) bzero(sessions[n], sizeof(serverSession)); // create server port - context.info = sessions[n]; - context.copyDescription = copyDescription; - - if (server == MACH_PORT_NULL) { - // create mach port for SCDynamicStore client - (void) mach_port_allocate(mach_task_self(), - MACH_PORT_RIGHT_RECEIVE, - &mp); - } + context.info = sessions[n]; + context.copyDescription = copyDescription; // // Note: we create the CFMachPort *before* we insert a send @@ -160,7 +228,7 @@ addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info)) CFMachPortSetInvalidationCallBack(sessions[n]->serverPort, CFMachPortInvalidateSessionCallback); - if (server == MACH_PORT_NULL) { + if (n > 0) { // insert send right that will be moved to the client (void) mach_port_insert_right(mach_task_self(), mp, @@ -181,51 +249,20 @@ addSession(mach_port_t server, CFStringRef (*copyDescription)(const void *info)) __private_extern__ void -removeSession(mach_port_t server) +cleanupSession(mach_port_t server) { - int i; - serverSessionRef thisSession; - CFStringRef sessionKey; + int i; - for (i = 0; i < nSessions; i++) { - thisSession = sessions[i]; + for (i = 1; i <= lastSession; i++) { + CFStringRef sessionKey; + serverSessionRef thisSession = sessions[i]; if (thisSession == NULL) { /* found an empty slot, skip it */ continue; - } else if (thisSession->key == server) { - /* - * We don't need any remaining information in the - * sessionData dictionary, remove it. - */ - sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), server); - CFDictionaryRemoveValue(sessionData, sessionKey); - CFRelease(sessionKey); - - /* - * Lastly, get rid of the per-session structure. - */ - free(thisSession); - sessions[i] = NULL; - - return; } - } - - return; -} - - -__private_extern__ -void -cleanupSession(mach_port_t server) -{ - int i; - for (i = 0; i < nSessions; i++) { - serverSessionRef thisSession = sessions[i]; - - if ((thisSession != NULL) && (thisSession->key == server)) { + if (thisSession->key == server) { /* * session entry still exists. */ @@ -234,26 +271,12 @@ cleanupSession(mach_port_t server) SCTrace(TRUE, _configd_trace, CFSTR("cleanup : %5d\n"), server); } - /* - * Ensure that any changes made while we held the "lock" - * are discarded. - */ - if ((storeLocked > 0) && - ((SCDynamicStorePrivateRef)thisSession->store)->locked) { - /* - * swap store and associated data which, after - * being closed, will result in the restoration - * of the original pre-"locked" data. - */ - _swapLockedStoreData(); - } - /* * Close any open connections including cancelling any outstanding * notification requests and releasing any locks. */ __MACH_PORT_DEBUG(TRUE, "*** cleanupSession", server); - (void) __SCDynamicStoreClose(&thisSession->store, TRUE); + (void) __SCDynamicStoreClose(&thisSession->store); __MACH_PORT_DEBUG(TRUE, "*** cleanupSession (after __SCDynamicStoreClose)", server); /* @@ -262,9 +285,27 @@ cleanupSession(mach_port_t server) (void) mach_port_mod_refs(mach_task_self(), server, MACH_PORT_RIGHT_RECEIVE, -1); /* - * Lastly, remove the session entry. + * We don't need any remaining information in the + * sessionData dictionary, remove it. + */ + sessionKey = CFStringCreateWithFormat(NULL, NULL, CFSTR("%d"), server); + CFDictionaryRemoveValue(sessionData, sessionKey); + CFRelease(sessionKey); + + /* + * get rid of the per-session structure. */ - removeSession(server); + free(thisSession); + sessions[i] = NULL; + + if (i == lastSession) { + /* we are removing the last session, update last used slot */ + while (--lastSession > 0) { + if (sessions[lastSession] != NULL) { + break; + } + } + } return; } @@ -283,7 +324,7 @@ listSessions(FILE *f) int i; SCPrint(TRUE, f, CFSTR("Current sessions :\n")); - for (i = 0; i < nSessions; i++) { + for (i = 0; i <= lastSession; i++) { serverSessionRef thisSession = sessions[i]; if (thisSession == NULL) { diff --git a/configd.tproj/session.h b/configd.tproj/session.h index 6e4962f..68d8f91 100644 --- a/configd.tproj/session.h +++ b/configd.tproj/session.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2005-2007, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2005-2007, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -78,11 +78,13 @@ __BEGIN_DECLS serverSessionRef getSession (mach_port_t server); +serverSessionRef tempSession (mach_port_t server, + CFStringRef name, + audit_token_t auditToken); + serverSessionRef addSession (mach_port_t server, CFStringRef (*copyDescription)(const void *info)); -void removeSession (mach_port_t server); - void cleanupSession (mach_port_t server); void listSessions (FILE *f); diff --git a/configd.xcodeproj/project.pbxproj b/configd.xcodeproj/project.pbxproj index b572e25..ebce9e4 100644 --- a/configd.xcodeproj/project.pbxproj +++ b/configd.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 45; + objectVersion = 46; objects = { /* Begin PBXAggregateTarget section */ @@ -41,6 +41,7 @@ 1558480607550D470046C2E9 /* PBXTargetDependency */, 1558480807550D470046C2E9 /* PBXTargetDependency */, 1558480A07550D470046C2E9 /* PBXTargetDependency */, + D6DDAC3D147A24BC00A2E902 /* PBXTargetDependency */, 150ECB300D0042DA0065E94D /* PBXTargetDependency */, ); name = configd_executables; @@ -53,7 +54,6 @@ ); dependencies = ( 157BB8C0075924460025DA7A /* PBXTargetDependency */, - 1520A386084681350010B584 /* PBXTargetDependency */, ); name = configd_base; productName = Frameworks; @@ -76,19 +76,19 @@ buildPhases = ( ); dependencies = ( - 157A85480D56CA0B00B6F1A0 /* PBXTargetDependency */, - 158317BB0CFB8660006F62B9 /* PBXTargetDependency */, 157A854A0D56CA2300B6F1A0 /* PBXTargetDependency */, 158317B90CFB8660006F62B9 /* PBXTargetDependency */, + 157A85480D56CA0B00B6F1A0 /* PBXTargetDependency */, + 158317BB0CFB8660006F62B9 /* PBXTargetDependency */, 157A854C0D56CA5100B6F1A0 /* PBXTargetDependency */, 158317B70CFB8660006F62B9 /* PBXTargetDependency */, 157A854E0D56CA6F00B6F1A0 /* PBXTargetDependency */, 158317B50CFB8660006F62B9 /* PBXTargetDependency */, 156CA4A80EF8550800C59A18 /* PBXTargetDependency */, - 157A85500D56CA8800B6F1A0 /* PBXTargetDependency */, - 158317B30CFB8660006F62B9 /* PBXTargetDependency */, 157A85520D56CA9E00B6F1A0 /* PBXTargetDependency */, 157A85540D56CACA00B6F1A0 /* PBXTargetDependency */, + 1528C00F135741C300691881 /* PBXTargetDependency */, + 1528C011135741C300691881 /* PBXTargetDependency */, ); name = "configd_plugins-Embedded"; productName = Plugins; @@ -149,19 +149,19 @@ buildPhases = ( ); dependencies = ( - 15AC5189108396D2004A9ED5 /* PBXTargetDependency */, - 15AC5187108396D2004A9ED5 /* PBXTargetDependency */, 15AC5185108396D2004A9ED5 /* PBXTargetDependency */, 15AC5183108396D2004A9ED5 /* PBXTargetDependency */, + 15AC5189108396D2004A9ED5 /* PBXTargetDependency */, + 15AC5187108396D2004A9ED5 /* PBXTargetDependency */, 15AC5181108396D2004A9ED5 /* PBXTargetDependency */, 15AC517F108396D2004A9ED5 /* PBXTargetDependency */, 15AC517D108396D2004A9ED5 /* PBXTargetDependency */, 15AC517B108396D2004A9ED5 /* PBXTargetDependency */, 15AC5179108396D2004A9ED5 /* PBXTargetDependency */, - 15AC5177108396D2004A9ED5 /* PBXTargetDependency */, - 15AC5175108396D2004A9ED5 /* PBXTargetDependency */, 15AC5173108396D2004A9ED5 /* PBXTargetDependency */, 15AC5171108396D2004A9ED5 /* PBXTargetDependency */, + 1528C0131357420300691881 /* PBXTargetDependency */, + 1528C0151357420300691881 /* PBXTargetDependency */, ); name = "configd_plugins-EmbeddedOther"; productName = Plugins; @@ -185,19 +185,19 @@ buildPhases = ( ); dependencies = ( - 159D542807528E85004F8947 /* PBXTargetDependency */, - 158AD9860754E72500124717 /* PBXTargetDependency */, - 159D542607528E85004F8947 /* PBXTargetDependency */, - 158AD9880754E72500124717 /* PBXTargetDependency */, 15828B070753B77E00AD4710 /* PBXTargetDependency */, 159D542207528E85004F8947 /* PBXTargetDependency */, + 159D542607528E85004F8947 /* PBXTargetDependency */, + 158AD9880754E72500124717 /* PBXTargetDependency */, + 159D542807528E85004F8947 /* PBXTargetDependency */, + 158AD9860754E72500124717 /* PBXTargetDependency */, 159D542A07528E85004F8947 /* PBXTargetDependency */, 158AD98C0754E72500124717 /* PBXTargetDependency */, 1521405B0E9400BF00DACD2C /* PBXTargetDependency */, 159D542C07528E85004F8947 /* PBXTargetDependency */, 158AD98E0754E72500124717 /* PBXTargetDependency */, - F95B8A790B03FB9100993BA3 /* PBXTargetDependency */, - F95B8A770B03FB9100993BA3 /* PBXTargetDependency */, + 1528BFEC135731B800691881 /* PBXTargetDependency */, + 1528BFEE135731B800691881 /* PBXTargetDependency */, ); name = configd_plugins; productName = Plugins; @@ -255,21 +255,26 @@ 15060818075A00A300B147BA /* SCSchemaDefinitions.c in Sources */ = {isa = PBXBuildFile; fileRef = 150607BD075A00A200B147BA /* SCSchemaDefinitions.c */; }; 1506081A075A00A300B147BA /* SCSchemaDefinitions.h in Headers */ = {isa = PBXBuildFile; fileRef = 150607DE075A00A300B147BA /* SCSchemaDefinitions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 150D7E1E0D16DC6C00AF4BED /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1520A3DE0846B2DC0010B584 /* Security.framework */; }; + 151E0CA31378EE1000C5DA2A /* network_information.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986A781368913C0091C931 /* network_information.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 151E0CA51378EE3B00C5DA2A /* network_information.c in Sources */ = {isa = PBXBuildFile; fileRef = D6986A77136891300091C931 /* network_information.c */; }; 1520A3870846829A0010B584 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15CB6A6F05C0722B0099E85F /* CoreFoundation.framework */; }; 1520A3DF0846B2DD0010B584 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1520A3DE0846B2DC0010B584 /* Security.framework */; }; 152140020E93EC6500DACD2C /* logger.c in Sources */ = {isa = PBXBuildFile; fileRef = 1531D3DB0E93E6DA00248432 /* logger.c */; }; 1521400C0E93FFF500DACD2C /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15CB6A6F05C0722B0099E85F /* CoreFoundation.framework */; }; 152140580E93FFFC00DACD2C /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1559C4440D349A4E0098FD59 /* SystemConfiguration.framework */; }; 1522FCFB0FA7FE4B00B24128 /* dnsinfo_flatfile.c in Sources */ = {isa = PBXBuildFile; fileRef = 1522FCE50FA7FD7000B24128 /* dnsinfo_flatfile.c */; }; - 152691D81129EE8A006BD2D5 /* BondConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 9EE943F306AF409B00772EB5 /* BondConfiguration.c */; }; - 152691D91129EE94006BD2D5 /* BondConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 9EE943F306AF409B00772EB5 /* BondConfiguration.c */; }; - 152691DA1129EE98006BD2D5 /* BondConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 9EE943F306AF409B00772EB5 /* BondConfiguration.c */; }; 152691DB1129EEA6006BD2D5 /* BridgeConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 15FD7B3B101E439200C56621 /* BridgeConfiguration.c */; }; 152691DC1129EEAD006BD2D5 /* BridgeConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 15FD7B3B101E439200C56621 /* BridgeConfiguration.c */; }; 152691DD1129EEB1006BD2D5 /* BridgeConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 15FD7B3B101E439200C56621 /* BridgeConfiguration.c */; }; 152691DE1129EEC2006BD2D5 /* VLANConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69B605C0722B0099E85F /* VLANConfiguration.c */; }; 152691DF1129EEC8006BD2D5 /* VLANConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69B605C0722B0099E85F /* VLANConfiguration.c */; }; 152691E01129EECB006BD2D5 /* VLANConfiguration.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69B605C0722B0099E85F /* VLANConfiguration.c */; }; + 1528BFEF135733F500691881 /* SCNetworkReachabilityServer_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */; }; + 1528BFF313573FEE00691881 /* SCNetworkReachabilityServer_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */; }; + 1528C0021357401900691881 /* SCNetworkReachabilityServer_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */; }; + 1528C0171357465900691881 /* libSCNetworkReachability.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1528BFF713573FEE00691881 /* libSCNetworkReachability.a */; }; + 1528C019135746BB00691881 /* libSCNetworkReachability.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1528BFE21357305400691881 /* libSCNetworkReachability.a */; }; + 1528C01A135746D700691881 /* libSCNetworkReachability.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1528C0061357401900691881 /* libSCNetworkReachability.a */; }; 152E0E7F10FE820E00E402F2 /* helper.defs in Sources */ = {isa = PBXBuildFile; fileRef = 152E0E7E10FE820E00E402F2 /* helper.defs */; settings = {ATTRIBUTES = (Server, ); }; }; 152E0E8010FE820E00E402F2 /* helper.defs in Sources */ = {isa = PBXBuildFile; fileRef = 152E0E7E10FE820E00E402F2 /* helper.defs */; settings = {ATTRIBUTES = (Server, ); }; }; 152E0E8110FE820E00E402F2 /* helper.defs in Sources */ = {isa = PBXBuildFile; fileRef = 152E0E7E10FE820E00E402F2 /* helper.defs */; settings = {ATTRIBUTES = (Server, ); }; }; @@ -278,7 +283,6 @@ 152E0E8B10FE824000E402F2 /* helper_types.h in Headers */ = {isa = PBXBuildFile; fileRef = 152E0E8810FE824000E402F2 /* helper_types.h */; }; 152E68C10A2C89C70011FDA8 /* SCPreferencesKeychainPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 152E68C00A2C89C70011FDA8 /* SCPreferencesKeychainPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 152E68C30A2C89E30011FDA8 /* SCPreferencesKeychainPrivate.c in Sources */ = {isa = PBXBuildFile; fileRef = 152E68C20A2C89E30011FDA8 /* SCPreferencesKeychainPrivate.c */; }; - 1533D77B0B10A14300CA4946 /* libNetworkIdentification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F95B8A5F0B03F81400993BA3 /* libNetworkIdentification.a */; }; 1540E3610987DA9500157C07 /* com.apple.configd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1540E3600987DA9500157C07 /* com.apple.configd.plist */; }; 154361E00752C81800A8EC6C /* set-hostname.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53AB07528B36004F8947 /* set-hostname.c */; }; 1543636B0752D03C00A8EC6C /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1543636A0752D03C00A8EC6C /* IOKit.framework */; }; @@ -384,14 +388,11 @@ 1572C4E20CFB55B400E2776E /* SCDPrivate.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695405C0722B0099E85F /* SCDPrivate.c */; settings = {ATTRIBUTES = (); }; }; 1572C4E30CFB55B400E2776E /* SCDPlugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695605C0722B0099E85F /* SCDPlugin.c */; settings = {ATTRIBUTES = (); }; }; 1572C4E40CFB55B400E2776E /* SCDOpen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695805C0722B0099E85F /* SCDOpen.c */; settings = {ATTRIBUTES = (); }; }; - 1572C4E50CFB55B400E2776E /* SCDLock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695A05C0722B0099E85F /* SCDLock.c */; settings = {ATTRIBUTES = (); }; }; - 1572C4E60CFB55B400E2776E /* SCDUnlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695C05C0722B0099E85F /* SCDUnlock.c */; settings = {ATTRIBUTES = (); }; }; 1572C4E70CFB55B400E2776E /* SCDList.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695E05C0722B0099E85F /* SCDList.c */; settings = {ATTRIBUTES = (); }; }; 1572C4E80CFB55B400E2776E /* SCDAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696005C0722B0099E85F /* SCDAdd.c */; settings = {ATTRIBUTES = (); }; }; 1572C4E90CFB55B400E2776E /* SCDGet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696405C0722B0099E85F /* SCDGet.c */; settings = {ATTRIBUTES = (); }; }; 1572C4EA0CFB55B400E2776E /* SCDSet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696605C0722B0099E85F /* SCDSet.c */; settings = {ATTRIBUTES = (); }; }; 1572C4EB0CFB55B400E2776E /* SCDRemove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696805C0722B0099E85F /* SCDRemove.c */; settings = {ATTRIBUTES = (); }; }; - 1572C4EC0CFB55B400E2776E /* SCDTouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696A05C0722B0099E85F /* SCDTouch.c */; settings = {ATTRIBUTES = (); }; }; 1572C4ED0CFB55B400E2776E /* SCDNotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696C05C0722B0099E85F /* SCDNotify.c */; settings = {ATTRIBUTES = (); }; }; 1572C4EE0CFB55B400E2776E /* SCDNotifierSetKeys.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696E05C0722B0099E85F /* SCDNotifierSetKeys.c */; settings = {ATTRIBUTES = (); }; }; 1572C4EF0CFB55B400E2776E /* SCDNotifierAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697005C0722B0099E85F /* SCDNotifierAdd.c */; settings = {ATTRIBUTES = (); }; }; @@ -399,7 +400,6 @@ 1572C4F10CFB55B400E2776E /* SCDNotifierGetChanges.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697405C0722B0099E85F /* SCDNotifierGetChanges.c */; settings = {ATTRIBUTES = (); }; }; 1572C4F20CFB55B400E2776E /* SCDNotifierWait.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697605C0722B0099E85F /* SCDNotifierWait.c */; settings = {ATTRIBUTES = (); }; }; 1572C4F30CFB55B400E2776E /* SCDNotifierInformViaCallback.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697805C0722B0099E85F /* SCDNotifierInformViaCallback.c */; settings = {ATTRIBUTES = (); }; }; - 1572C4F40CFB55B400E2776E /* SCDNotifierInformViaMachPort.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697A05C0722B0099E85F /* SCDNotifierInformViaMachPort.c */; settings = {ATTRIBUTES = (); }; }; 1572C4F50CFB55B400E2776E /* SCDNotifierInformViaFD.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697C05C0722B0099E85F /* SCDNotifierInformViaFD.c */; settings = {ATTRIBUTES = (); }; }; 1572C4F60CFB55B400E2776E /* SCDNotifierInformViaSignal.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697E05C0722B0099E85F /* SCDNotifierInformViaSignal.c */; settings = {ATTRIBUTES = (); }; }; 1572C4F70CFB55B400E2776E /* SCDNotifierCancel.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB698005C0722B0099E85F /* SCDNotifierCancel.c */; settings = {ATTRIBUTES = (); }; }; @@ -502,7 +502,6 @@ 157A851D0D56C8E000B6F1A0 /* ev_ipv6.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53B407528B36004F8947 /* ev_ipv6.c */; }; 157A851E0D56C8E000B6F1A0 /* eventmon.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53B007528B36004F8947 /* eventmon.c */; }; 157A85290D56C91100B6F1A0 /* linkconfig.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53C107528B36004F8947 /* linkconfig.c */; }; - 157A85340D56C94F00B6F1A0 /* NetworkIdentification.c in Sources */ = {isa = PBXBuildFile; fileRef = F95B8A680B03F97800993BA3 /* NetworkIdentification.c */; }; 157A853F0D56C96F00B6F1A0 /* prefsmon.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53C307528B36004F8947 /* prefsmon.c */; }; 157A88890A470D0F003A4256 /* SCSchemaDefinitionsPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 157A88880A470D0F003A4256 /* SCSchemaDefinitionsPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 158317250CFB80A1006F62B9 /* configd.h in Headers */ = {isa = PBXBuildFile; fileRef = 15CB69CF05C0722B0099E85F /* configd.h */; }; @@ -521,14 +520,12 @@ 158317330CFB80A1006F62B9 /* pattern.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69EC05C0722B0099E85F /* pattern.c */; settings = {ATTRIBUTES = (); }; }; 158317340CFB80A1006F62B9 /* _configopen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F005C0722B0099E85F /* _configopen.c */; settings = {ATTRIBUTES = (); }; }; 158317350CFB80A1006F62B9 /* _configclose.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F205C0722B0099E85F /* _configclose.c */; settings = {ATTRIBUTES = (); }; }; - 158317360CFB80A1006F62B9 /* _configlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F405C0722B0099E85F /* _configlock.c */; settings = {ATTRIBUTES = (); }; }; 158317370CFB80A1006F62B9 /* _configunlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F605C0722B0099E85F /* _configunlock.c */; settings = {ATTRIBUTES = (); }; }; 158317380CFB80A1006F62B9 /* _configlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F805C0722B0099E85F /* _configlist.c */; settings = {ATTRIBUTES = (); }; }; 158317390CFB80A1006F62B9 /* _configadd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69FA05C0722B0099E85F /* _configadd.c */; settings = {ATTRIBUTES = (); }; }; 1583173A0CFB80A1006F62B9 /* _configget.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69FE05C0722B0099E85F /* _configget.c */; settings = {ATTRIBUTES = (); }; }; 1583173B0CFB80A1006F62B9 /* _configset.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0005C0722B0099E85F /* _configset.c */; settings = {ATTRIBUTES = (); }; }; 1583173C0CFB80A1006F62B9 /* _configremove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0205C0722B0099E85F /* _configremove.c */; settings = {ATTRIBUTES = (); }; }; - 1583173D0CFB80A1006F62B9 /* _configtouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0405C0722B0099E85F /* _configtouch.c */; settings = {ATTRIBUTES = (); }; }; 1583173E0CFB80A1006F62B9 /* _confignotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0605C0722B0099E85F /* _confignotify.c */; settings = {ATTRIBUTES = (); }; }; 1583173F0CFB80A1006F62B9 /* _notifyadd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0805C0722B0099E85F /* _notifyadd.c */; settings = {ATTRIBUTES = (); }; }; 158317400CFB80A1006F62B9 /* _notifyremove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0A05C0722B0099E85F /* _notifyremove.c */; settings = {ATTRIBUTES = (); }; }; @@ -549,7 +546,6 @@ 158317530CFB80A1006F62B9 /* libInterfaceNamer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53E507528C4A004F8947 /* libInterfaceNamer.a */; }; 158317540CFB80A1006F62B9 /* libIPMonitor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53EC07528C61004F8947 /* libIPMonitor.a */; }; 158317550CFB80A1006F62B9 /* libLinkConfiguration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53F307528C79004F8947 /* libLinkConfiguration.a */; }; - 158317560CFB80A1006F62B9 /* libNetworkIdentification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F95B8A5F0B03F81400993BA3 /* libNetworkIdentification.a */; }; 158317570CFB80A1006F62B9 /* libPreferencesMonitor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53FA07528C95004F8947 /* libPreferencesMonitor.a */; }; 1583175C0CFB80A1006F62B9 /* com.apple.configd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1540E3600987DA9500157C07 /* com.apple.configd.plist */; }; 1583379C0CFB6B9E0033AB93 /* SCHelper_client.h in Headers */ = {isa = PBXBuildFile; fileRef = 155B7BF60847776D00F0E262 /* SCHelper_client.h */; }; @@ -613,14 +609,11 @@ 1583EA53108395BB00A3BC0C /* SCDPrivate.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695405C0722B0099E85F /* SCDPrivate.c */; settings = {ATTRIBUTES = (); }; }; 1583EA54108395BB00A3BC0C /* SCDPlugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695605C0722B0099E85F /* SCDPlugin.c */; settings = {ATTRIBUTES = (); }; }; 1583EA55108395BB00A3BC0C /* SCDOpen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695805C0722B0099E85F /* SCDOpen.c */; settings = {ATTRIBUTES = (); }; }; - 1583EA56108395BB00A3BC0C /* SCDLock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695A05C0722B0099E85F /* SCDLock.c */; settings = {ATTRIBUTES = (); }; }; - 1583EA57108395BB00A3BC0C /* SCDUnlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695C05C0722B0099E85F /* SCDUnlock.c */; settings = {ATTRIBUTES = (); }; }; 1583EA58108395BB00A3BC0C /* SCDList.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695E05C0722B0099E85F /* SCDList.c */; settings = {ATTRIBUTES = (); }; }; 1583EA59108395BB00A3BC0C /* SCDAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696005C0722B0099E85F /* SCDAdd.c */; settings = {ATTRIBUTES = (); }; }; 1583EA5A108395BB00A3BC0C /* SCDGet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696405C0722B0099E85F /* SCDGet.c */; settings = {ATTRIBUTES = (); }; }; 1583EA5B108395BB00A3BC0C /* SCDSet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696605C0722B0099E85F /* SCDSet.c */; settings = {ATTRIBUTES = (); }; }; 1583EA5C108395BB00A3BC0C /* SCDRemove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696805C0722B0099E85F /* SCDRemove.c */; settings = {ATTRIBUTES = (); }; }; - 1583EA5D108395BB00A3BC0C /* SCDTouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696A05C0722B0099E85F /* SCDTouch.c */; settings = {ATTRIBUTES = (); }; }; 1583EA5E108395BB00A3BC0C /* SCDNotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696C05C0722B0099E85F /* SCDNotify.c */; settings = {ATTRIBUTES = (); }; }; 1583EA5F108395BB00A3BC0C /* SCDNotifierSetKeys.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696E05C0722B0099E85F /* SCDNotifierSetKeys.c */; settings = {ATTRIBUTES = (); }; }; 1583EA60108395BB00A3BC0C /* SCDNotifierAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697005C0722B0099E85F /* SCDNotifierAdd.c */; settings = {ATTRIBUTES = (); }; }; @@ -628,7 +621,6 @@ 1583EA62108395BB00A3BC0C /* SCDNotifierGetChanges.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697405C0722B0099E85F /* SCDNotifierGetChanges.c */; settings = {ATTRIBUTES = (); }; }; 1583EA63108395BB00A3BC0C /* SCDNotifierWait.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697605C0722B0099E85F /* SCDNotifierWait.c */; settings = {ATTRIBUTES = (); }; }; 1583EA64108395BB00A3BC0C /* SCDNotifierInformViaCallback.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697805C0722B0099E85F /* SCDNotifierInformViaCallback.c */; settings = {ATTRIBUTES = (); }; }; - 1583EA65108395BB00A3BC0C /* SCDNotifierInformViaMachPort.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697A05C0722B0099E85F /* SCDNotifierInformViaMachPort.c */; settings = {ATTRIBUTES = (); }; }; 1583EA66108395BB00A3BC0C /* SCDNotifierInformViaFD.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697C05C0722B0099E85F /* SCDNotifierInformViaFD.c */; settings = {ATTRIBUTES = (); }; }; 1583EA67108395BB00A3BC0C /* SCDNotifierInformViaSignal.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697E05C0722B0099E85F /* SCDNotifierInformViaSignal.c */; settings = {ATTRIBUTES = (); }; }; 1583EA68108395BB00A3BC0C /* SCDNotifierCancel.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB698005C0722B0099E85F /* SCDNotifierCancel.c */; settings = {ATTRIBUTES = (); }; }; @@ -701,7 +693,6 @@ 1583EB1A108395BC00A3BC0C /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15CB6A6F05C0722B0099E85F /* CoreFoundation.framework */; }; 1583EB1B108395BC00A3BC0C /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1559C4440D349A4E0098FD59 /* SystemConfiguration.framework */; }; 1583EB1C108395BC00A3BC0C /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1543636A0752D03C00A8EC6C /* IOKit.framework */; }; - 1583EB26108395BD00A3BC0C /* NetworkIdentification.c in Sources */ = {isa = PBXBuildFile; fileRef = F95B8A680B03F97800993BA3 /* NetworkIdentification.c */; }; 1583EB35108395BD00A3BC0C /* prefsmon.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53C307528B36004F8947 /* prefsmon.c */; }; 1583EB4D108395BD00A3BC0C /* configd.h in Headers */ = {isa = PBXBuildFile; fileRef = 15CB69CF05C0722B0099E85F /* configd.h */; }; 1583EB4E108395BD00A3BC0C /* _SCD.h in Headers */ = {isa = PBXBuildFile; fileRef = 15CB69D105C0722B0099E85F /* _SCD.h */; }; @@ -719,14 +710,12 @@ 1583EB5B108395BD00A3BC0C /* pattern.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69EC05C0722B0099E85F /* pattern.c */; settings = {ATTRIBUTES = (); }; }; 1583EB5C108395BD00A3BC0C /* _configopen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F005C0722B0099E85F /* _configopen.c */; settings = {ATTRIBUTES = (); }; }; 1583EB5D108395BD00A3BC0C /* _configclose.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F205C0722B0099E85F /* _configclose.c */; settings = {ATTRIBUTES = (); }; }; - 1583EB5E108395BD00A3BC0C /* _configlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F405C0722B0099E85F /* _configlock.c */; settings = {ATTRIBUTES = (); }; }; 1583EB5F108395BD00A3BC0C /* _configunlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F605C0722B0099E85F /* _configunlock.c */; settings = {ATTRIBUTES = (); }; }; 1583EB60108395BD00A3BC0C /* _configlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F805C0722B0099E85F /* _configlist.c */; settings = {ATTRIBUTES = (); }; }; 1583EB61108395BD00A3BC0C /* _configadd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69FA05C0722B0099E85F /* _configadd.c */; settings = {ATTRIBUTES = (); }; }; 1583EB62108395BD00A3BC0C /* _configget.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69FE05C0722B0099E85F /* _configget.c */; settings = {ATTRIBUTES = (); }; }; 1583EB63108395BD00A3BC0C /* _configset.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0005C0722B0099E85F /* _configset.c */; settings = {ATTRIBUTES = (); }; }; 1583EB64108395BD00A3BC0C /* _configremove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0205C0722B0099E85F /* _configremove.c */; settings = {ATTRIBUTES = (); }; }; - 1583EB65108395BD00A3BC0C /* _configtouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0405C0722B0099E85F /* _configtouch.c */; settings = {ATTRIBUTES = (); }; }; 1583EB66108395BD00A3BC0C /* _confignotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0605C0722B0099E85F /* _confignotify.c */; settings = {ATTRIBUTES = (); }; }; 1583EB67108395BD00A3BC0C /* _notifyadd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0805C0722B0099E85F /* _notifyadd.c */; settings = {ATTRIBUTES = (); }; }; 1583EB68108395BD00A3BC0C /* _notifyremove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0A05C0722B0099E85F /* _notifyremove.c */; settings = {ATTRIBUTES = (); }; }; @@ -749,7 +738,6 @@ 1583EB7A108395BD00A3BC0C /* libInterfaceNamer.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53E507528C4A004F8947 /* libInterfaceNamer.a */; }; 1583EB7B108395BD00A3BC0C /* libIPMonitor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53EC07528C61004F8947 /* libIPMonitor.a */; }; 1583EB7C108395BD00A3BC0C /* libLinkConfiguration.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53F307528C79004F8947 /* libLinkConfiguration.a */; }; - 1583EB7D108395BD00A3BC0C /* libNetworkIdentification.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F95B8A5F0B03F81400993BA3 /* libNetworkIdentification.a */; }; 1583EB7E108395BD00A3BC0C /* libPreferencesMonitor.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 159D53FA07528C95004F8947 /* libPreferencesMonitor.a */; }; 1583EB80108395BD00A3BC0C /* com.apple.configd.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 1540E3600987DA9500157C07 /* com.apple.configd.plist */; }; 1583EB89108395BE00A3BC0C /* scselect.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A2E05C0722B0099E85F /* scselect.c */; settings = {ATTRIBUTES = (); }; }; @@ -833,14 +821,12 @@ 159D54B207529FFF004F8947 /* pattern.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69EC05C0722B0099E85F /* pattern.c */; settings = {ATTRIBUTES = (); }; }; 159D54B307529FFF004F8947 /* _configopen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F005C0722B0099E85F /* _configopen.c */; settings = {ATTRIBUTES = (); }; }; 159D54B407529FFF004F8947 /* _configclose.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F205C0722B0099E85F /* _configclose.c */; settings = {ATTRIBUTES = (); }; }; - 159D54B507529FFF004F8947 /* _configlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F405C0722B0099E85F /* _configlock.c */; settings = {ATTRIBUTES = (); }; }; 159D54B607529FFF004F8947 /* _configunlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F605C0722B0099E85F /* _configunlock.c */; settings = {ATTRIBUTES = (); }; }; 159D54B707529FFF004F8947 /* _configlist.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69F805C0722B0099E85F /* _configlist.c */; settings = {ATTRIBUTES = (); }; }; 159D54B807529FFF004F8947 /* _configadd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69FA05C0722B0099E85F /* _configadd.c */; settings = {ATTRIBUTES = (); }; }; 159D54B907529FFF004F8947 /* _configget.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB69FE05C0722B0099E85F /* _configget.c */; settings = {ATTRIBUTES = (); }; }; 159D54BA07529FFF004F8947 /* _configset.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0005C0722B0099E85F /* _configset.c */; settings = {ATTRIBUTES = (); }; }; 159D54BB07529FFF004F8947 /* _configremove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0205C0722B0099E85F /* _configremove.c */; settings = {ATTRIBUTES = (); }; }; - 159D54BC07529FFF004F8947 /* _configtouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0405C0722B0099E85F /* _configtouch.c */; settings = {ATTRIBUTES = (); }; }; 159D54BD07529FFF004F8947 /* _confignotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0605C0722B0099E85F /* _confignotify.c */; settings = {ATTRIBUTES = (); }; }; 159D54BE07529FFF004F8947 /* _notifyadd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0805C0722B0099E85F /* _notifyadd.c */; settings = {ATTRIBUTES = (); }; }; 159D54BF07529FFF004F8947 /* _notifyremove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB6A0A05C0722B0099E85F /* _notifyremove.c */; settings = {ATTRIBUTES = (); }; }; @@ -918,14 +904,11 @@ 15A5A2210D5B94190087BDA0 /* SCDPrivate.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695405C0722B0099E85F /* SCDPrivate.c */; settings = {ATTRIBUTES = (); }; }; 15A5A2220D5B94190087BDA0 /* SCDPlugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695605C0722B0099E85F /* SCDPlugin.c */; settings = {ATTRIBUTES = (); }; }; 15A5A2230D5B94190087BDA0 /* SCDOpen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695805C0722B0099E85F /* SCDOpen.c */; settings = {ATTRIBUTES = (); }; }; - 15A5A2240D5B94190087BDA0 /* SCDLock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695A05C0722B0099E85F /* SCDLock.c */; settings = {ATTRIBUTES = (); }; }; - 15A5A2250D5B94190087BDA0 /* SCDUnlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695C05C0722B0099E85F /* SCDUnlock.c */; settings = {ATTRIBUTES = (); }; }; 15A5A2260D5B94190087BDA0 /* SCDList.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695E05C0722B0099E85F /* SCDList.c */; settings = {ATTRIBUTES = (); }; }; 15A5A2270D5B94190087BDA0 /* SCDAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696005C0722B0099E85F /* SCDAdd.c */; settings = {ATTRIBUTES = (); }; }; 15A5A2280D5B94190087BDA0 /* SCDGet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696405C0722B0099E85F /* SCDGet.c */; settings = {ATTRIBUTES = (); }; }; 15A5A2290D5B94190087BDA0 /* SCDSet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696605C0722B0099E85F /* SCDSet.c */; settings = {ATTRIBUTES = (); }; }; 15A5A22A0D5B94190087BDA0 /* SCDRemove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696805C0722B0099E85F /* SCDRemove.c */; settings = {ATTRIBUTES = (); }; }; - 15A5A22B0D5B94190087BDA0 /* SCDTouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696A05C0722B0099E85F /* SCDTouch.c */; settings = {ATTRIBUTES = (); }; }; 15A5A22C0D5B94190087BDA0 /* SCDNotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696C05C0722B0099E85F /* SCDNotify.c */; settings = {ATTRIBUTES = (); }; }; 15A5A22D0D5B94190087BDA0 /* SCDNotifierSetKeys.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696E05C0722B0099E85F /* SCDNotifierSetKeys.c */; settings = {ATTRIBUTES = (); }; }; 15A5A22E0D5B94190087BDA0 /* SCDNotifierAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697005C0722B0099E85F /* SCDNotifierAdd.c */; settings = {ATTRIBUTES = (); }; }; @@ -933,7 +916,6 @@ 15A5A2300D5B94190087BDA0 /* SCDNotifierGetChanges.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697405C0722B0099E85F /* SCDNotifierGetChanges.c */; settings = {ATTRIBUTES = (); }; }; 15A5A2310D5B94190087BDA0 /* SCDNotifierWait.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697605C0722B0099E85F /* SCDNotifierWait.c */; settings = {ATTRIBUTES = (); }; }; 15A5A2320D5B94190087BDA0 /* SCDNotifierInformViaCallback.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697805C0722B0099E85F /* SCDNotifierInformViaCallback.c */; settings = {ATTRIBUTES = (); }; }; - 15A5A2330D5B94190087BDA0 /* SCDNotifierInformViaMachPort.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697A05C0722B0099E85F /* SCDNotifierInformViaMachPort.c */; settings = {ATTRIBUTES = (); }; }; 15A5A2340D5B94190087BDA0 /* SCDNotifierInformViaFD.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697C05C0722B0099E85F /* SCDNotifierInformViaFD.c */; settings = {ATTRIBUTES = (); }; }; 15A5A2350D5B94190087BDA0 /* SCDNotifierInformViaSignal.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697E05C0722B0099E85F /* SCDNotifierInformViaSignal.c */; settings = {ATTRIBUTES = (); }; }; 15A5A2360D5B94190087BDA0 /* SCDNotifierCancel.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB698005C0722B0099E85F /* SCDNotifierCancel.c */; settings = {ATTRIBUTES = (); }; }; @@ -987,12 +969,34 @@ 15B274A5114467CD003414AD /* nc.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B43727113C7BFC00EBF1B6 /* nc.c */; }; 15B274A6114467D8003414AD /* nc.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B43726113C7BFC00EBF1B6 /* nc.h */; }; 15BAA32307F0699A00D9EC95 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 15BAA32207F0699A00D9EC95 /* libbsm.dylib */; }; + 15C330BC134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B7134B92780028E36B /* SCNetworkReachabilityServer_client.c */; }; + 15C330BD134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B7134B92780028E36B /* SCNetworkReachabilityServer_client.c */; }; + 15C330BE134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B7134B92780028E36B /* SCNetworkReachabilityServer_client.c */; }; + 15C330BF134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B7134B92780028E36B /* SCNetworkReachabilityServer_client.c */; }; + 15C330C0134B92780028E36B /* rb.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B8134B92780028E36B /* rb.c */; }; + 15C330C1134B92780028E36B /* rb.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B8134B92780028E36B /* rb.c */; }; + 15C330C2134B92780028E36B /* rb.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B8134B92780028E36B /* rb.c */; }; + 15C330C3134B92780028E36B /* rb.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330B8134B92780028E36B /* rb.c */; }; + 15C330C4134B92780028E36B /* rb.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330B9134B92780028E36B /* rb.h */; }; + 15C330C5134B92780028E36B /* rb.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330B9134B92780028E36B /* rb.h */; }; + 15C330C6134B92780028E36B /* rb.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330B9134B92780028E36B /* rb.h */; }; + 15C330C7134B92780028E36B /* rb.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330B9134B92780028E36B /* rb.h */; }; + 15C330D1134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330D0134B95AA0028E36B /* SCNetworkReachabilityInternal.h */; }; + 15C330D2134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330D0134B95AA0028E36B /* SCNetworkReachabilityInternal.h */; }; + 15C330D3134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330D0134B95AA0028E36B /* SCNetworkReachabilityInternal.h */; }; + 15C330D4134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */ = {isa = PBXBuildFile; fileRef = 15C330D0134B95AA0028E36B /* SCNetworkReachabilityInternal.h */; }; + 15C330E5134BD2AC0028E36B /* SCNetworkReachabilityServer_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */; }; + 15C330E6134BD2BB0028E36B /* SCNetworkReachabilityServer_server.c in Sources */ = {isa = PBXBuildFile; fileRef = 15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */; }; 15D48EBF0F67061600B4711E /* dnsinfo_create.c in Sources */ = {isa = PBXBuildFile; fileRef = 1521FC5C060F296A003B28F5 /* dnsinfo_create.c */; }; 15D48EC00F67061700B4711E /* dnsinfo_create.h in Headers */ = {isa = PBXBuildFile; fileRef = 1532629006281C9D00B1C10C /* dnsinfo_create.h */; }; 15D48EC10F67061F00B4711E /* dnsinfo_create.c in Sources */ = {isa = PBXBuildFile; fileRef = 1521FC5C060F296A003B28F5 /* dnsinfo_create.c */; }; 15D48EC20F67061F00B4711E /* dnsinfo_create.h in Headers */ = {isa = PBXBuildFile; fileRef = 1532629006281C9D00B1C10C /* dnsinfo_create.h */; }; 15D48ED30F67079B00B4711E /* shared_dns_info.defs in Sources */ = {isa = PBXBuildFile; fileRef = 15FCAAD005FD0EBF00CB79E6 /* shared_dns_info.defs */; }; 15D48ED40F6707A600B4711E /* shared_dns_info.defs in Sources */ = {isa = PBXBuildFile; fileRef = 15FCAAD005FD0EBF00CB79E6 /* shared_dns_info.defs */; }; + 15D8B22A1450D8450090CECF /* SCD.h in Headers */ = {isa = PBXBuildFile; fileRef = 15D8B2291450D8450090CECF /* SCD.h */; }; + 15D8B22B1450D8450090CECF /* SCD.h in Headers */ = {isa = PBXBuildFile; fileRef = 15D8B2291450D8450090CECF /* SCD.h */; }; + 15D8B22C1450D8450090CECF /* SCD.h in Headers */ = {isa = PBXBuildFile; fileRef = 15D8B2291450D8450090CECF /* SCD.h */; }; + 15D8B22D1450D8450090CECF /* SCD.h in Headers */ = {isa = PBXBuildFile; fileRef = 15D8B2291450D8450090CECF /* SCD.h */; }; 15D9DCFB10DD90A1004E545D /* AppWorkaround.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 15D9DCFA10DD90A1004E545D /* AppWorkaround.plist */; }; 15DAD5E1075913CE0084A6ED /* dnsinfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 15B73F0905FD1B670096477F /* dnsinfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; 15DAD5E2075913CE0084A6ED /* dnsinfo_private.h in Headers */ = {isa = PBXBuildFile; fileRef = 15B73F0C05FD1B670096477F /* dnsinfo_private.h */; }; @@ -1038,14 +1042,11 @@ 15DAD66F07591A1A0084A6ED /* SCDPrivate.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695405C0722B0099E85F /* SCDPrivate.c */; settings = {ATTRIBUTES = (); }; }; 15DAD67007591A1A0084A6ED /* SCDPlugin.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695605C0722B0099E85F /* SCDPlugin.c */; settings = {ATTRIBUTES = (); }; }; 15DAD67107591A1A0084A6ED /* SCDOpen.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695805C0722B0099E85F /* SCDOpen.c */; settings = {ATTRIBUTES = (); }; }; - 15DAD67207591A1A0084A6ED /* SCDLock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695A05C0722B0099E85F /* SCDLock.c */; settings = {ATTRIBUTES = (); }; }; - 15DAD67307591A1A0084A6ED /* SCDUnlock.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695C05C0722B0099E85F /* SCDUnlock.c */; settings = {ATTRIBUTES = (); }; }; 15DAD67407591A1A0084A6ED /* SCDList.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB695E05C0722B0099E85F /* SCDList.c */; settings = {ATTRIBUTES = (); }; }; 15DAD67507591A1A0084A6ED /* SCDAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696005C0722B0099E85F /* SCDAdd.c */; settings = {ATTRIBUTES = (); }; }; 15DAD67607591A1A0084A6ED /* SCDGet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696405C0722B0099E85F /* SCDGet.c */; settings = {ATTRIBUTES = (); }; }; 15DAD67707591A1A0084A6ED /* SCDSet.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696605C0722B0099E85F /* SCDSet.c */; settings = {ATTRIBUTES = (); }; }; 15DAD67807591A1A0084A6ED /* SCDRemove.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696805C0722B0099E85F /* SCDRemove.c */; settings = {ATTRIBUTES = (); }; }; - 15DAD67907591A1A0084A6ED /* SCDTouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696A05C0722B0099E85F /* SCDTouch.c */; settings = {ATTRIBUTES = (); }; }; 15DAD67A07591A1A0084A6ED /* SCDNotify.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696C05C0722B0099E85F /* SCDNotify.c */; settings = {ATTRIBUTES = (); }; }; 15DAD67B07591A1A0084A6ED /* SCDNotifierSetKeys.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB696E05C0722B0099E85F /* SCDNotifierSetKeys.c */; settings = {ATTRIBUTES = (); }; }; 15DAD67C07591A1A0084A6ED /* SCDNotifierAdd.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697005C0722B0099E85F /* SCDNotifierAdd.c */; settings = {ATTRIBUTES = (); }; }; @@ -1053,7 +1054,6 @@ 15DAD67E07591A1A0084A6ED /* SCDNotifierGetChanges.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697405C0722B0099E85F /* SCDNotifierGetChanges.c */; settings = {ATTRIBUTES = (); }; }; 15DAD67F07591A1A0084A6ED /* SCDNotifierWait.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697605C0722B0099E85F /* SCDNotifierWait.c */; settings = {ATTRIBUTES = (); }; }; 15DAD68007591A1A0084A6ED /* SCDNotifierInformViaCallback.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697805C0722B0099E85F /* SCDNotifierInformViaCallback.c */; settings = {ATTRIBUTES = (); }; }; - 15DAD68107591A1A0084A6ED /* SCDNotifierInformViaMachPort.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697A05C0722B0099E85F /* SCDNotifierInformViaMachPort.c */; settings = {ATTRIBUTES = (); }; }; 15DAD68207591A1A0084A6ED /* SCDNotifierInformViaFD.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697C05C0722B0099E85F /* SCDNotifierInformViaFD.c */; settings = {ATTRIBUTES = (); }; }; 15DAD68307591A1A0084A6ED /* SCDNotifierInformViaSignal.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB697E05C0722B0099E85F /* SCDNotifierInformViaSignal.c */; settings = {ATTRIBUTES = (); }; }; 15DAD68407591A1A0084A6ED /* SCDNotifierCancel.c in Sources */ = {isa = PBXBuildFile; fileRef = 15CB698005C0722B0099E85F /* SCDNotifierCancel.c */; settings = {ATTRIBUTES = (); }; }; @@ -1104,15 +1104,26 @@ 15FEE80E0CCFD341001312F9 /* ApplicationServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15FEE80D0CCFD341001312F9 /* ApplicationServices.framework */; }; 15FEE81F0CD03E75001312F9 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 15FEE8180CD03CBB001312F9 /* Localizable.strings */; }; 15FF5C370CDF776200EEC8AA /* com.apple.SCHelper.plist in CopyFiles */ = {isa = PBXBuildFile; fileRef = 15FF5C290CDF770500EEC8AA /* com.apple.SCHelper.plist */; }; + 7264C144147319E7004FD76D /* CaptiveNetwork.c in Sources */ = {isa = PBXBuildFile; fileRef = 15A1FF3110597F17004C9CC9 /* CaptiveNetwork.c */; }; + 7264C14614731A1F004FD76D /* CaptiveNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 15A1FF3010597F17004C9CC9 /* CaptiveNetwork.h */; settings = {ATTRIBUTES = (Public, ); }; }; 72B43728113C7BFC00EBF1B6 /* nc.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B43726113C7BFC00EBF1B6 /* nc.h */; }; 72B43729113C7BFC00EBF1B6 /* nc.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B43727113C7BFC00EBF1B6 /* nc.c */; }; 72B4372A113C7BFC00EBF1B6 /* nc.h in Headers */ = {isa = PBXBuildFile; fileRef = 72B43726113C7BFC00EBF1B6 /* nc.h */; }; 72B4372B113C7BFC00EBF1B6 /* nc.c in Sources */ = {isa = PBXBuildFile; fileRef = 72B43727113C7BFC00EBF1B6 /* nc.c */; }; + D661C2EF1368BB280030B977 /* network_information.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986A781368913C0091C931 /* network_information.h */; settings = {ATTRIBUTES = (Public, ); }; }; + D661C2F11368BB600030B977 /* network_information.c in Sources */ = {isa = PBXBuildFile; fileRef = D6986A77136891300091C931 /* network_information.c */; }; + D661C2F21368BB720030B977 /* network_information.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986A781368913C0091C931 /* network_information.h */; settings = {ATTRIBUTES = (Public, ); }; }; D6623873120B2AA7007F8E95 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1520A3DE0846B2DC0010B584 /* Security.framework */; }; + D6986A79136891650091C931 /* network_information.c in Sources */ = {isa = PBXBuildFile; fileRef = D6986A77136891300091C931 /* network_information.c */; }; + E49173E1137C4E4F0000089F /* network_information_priv.c in Sources */ = {isa = PBXBuildFile; fileRef = D6986A75136891120091C931 /* network_information_priv.c */; }; + E4F211D3137B0AB900BBB915 /* network_information_priv.c in Sources */ = {isa = PBXBuildFile; fileRef = D6986A75136891120091C931 /* network_information_priv.c */; }; + E4F211D4137B0ABD00BBB915 /* network_information_priv.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986A761368911E0091C931 /* network_information_priv.h */; }; + E4F211D5137B0AD700BBB915 /* network_information_priv.c in Sources */ = {isa = PBXBuildFile; fileRef = D6986A75136891120091C931 /* network_information_priv.c */; }; + E4F211D6137B0ADB00BBB915 /* network_information_priv.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986A761368911E0091C931 /* network_information_priv.h */; }; + E4F211D7137B0AF200BBB915 /* network_information_priv.h in Headers */ = {isa = PBXBuildFile; fileRef = D6986A761368911E0091C931 /* network_information_priv.h */; }; F95B8A430B03E07A00993BA3 /* SCNetworkSignature.c in Sources */ = {isa = PBXBuildFile; fileRef = F95B8A420B03E07A00993BA3 /* SCNetworkSignature.c */; }; F95B8A460B03E09300993BA3 /* SCNetworkSignature.h in Headers */ = {isa = PBXBuildFile; fileRef = F95B8A440B03E09300993BA3 /* SCNetworkSignature.h */; settings = {ATTRIBUTES = (Private, ); }; }; F95B8A470B03E09300993BA3 /* SCNetworkSignaturePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = F95B8A450B03E09300993BA3 /* SCNetworkSignaturePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; - F95B8A690B03F9B500993BA3 /* NetworkIdentification.c in Sources */ = {isa = PBXBuildFile; fileRef = F95B8A680B03F97800993BA3 /* NetworkIdentification.c */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -1130,19 +1141,54 @@ remoteGlobalIDString = 151FE2DD0D5B7046000D6DB1; remoteInfo = "configd_base-EmbeddedSimulator"; }; - 1520A385084681350010B584 /* PBXContainerItemProxy */ = { + 1521405A0E9400BF00DACD2C /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; proxyType = 1; - remoteGlobalIDString = 1547001808455B98006787CE; - remoteInfo = SCHelper; + remoteGlobalIDString = 15213FF90E93E9F500DACD2C; + remoteInfo = Logger.bundle; }; - 1521405A0E9400BF00DACD2C /* PBXContainerItemProxy */ = { + 1528BFEB135731B800691881 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; proxyType = 1; - remoteGlobalIDString = 15213FF90E93E9F500DACD2C; - remoteInfo = Logger.bundle; + remoteGlobalIDString = 1528BFDB1357305400691881; + remoteInfo = SCNetworkReachability; + }; + 1528BFED135731B800691881 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1528BFE31357309700691881; + remoteInfo = SCNetworkReachability.bundle; + }; + 1528C00E135741C300691881 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1528BFF013573FEE00691881; + remoteInfo = "SCNetworkReachability-Embedded"; + }; + 1528C010135741C300691881 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1528BFF813573FF500691881; + remoteInfo = "SCNetworkReachability.bundle-Embedded"; + }; + 1528C0121357420300691881 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1528BFFF1357401900691881; + remoteInfo = "SCNetworkReachability-EmbeddedOther"; + }; + 1528C0141357420300691881 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1528C0071357401D00691881; + remoteInfo = "SCNetworkReachability.bundle-EmbeddedOther"; }; 1558480507550D470046C2E9 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; @@ -1221,13 +1267,6 @@ remoteGlobalIDString = 157A85260D56C91100B6F1A0; remoteInfo = "LinkConfiguration-Embedded"; }; - 157A854F0D56CA8800B6F1A0 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; - proxyType = 1; - remoteGlobalIDString = 157A85310D56C94F00B6F1A0; - remoteInfo = "NetworkIdentification-Embedded"; - }; 157A85510D56CA9E00B6F1A0 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; @@ -1305,13 +1344,6 @@ remoteGlobalIDString = 158317230CFB80A1006F62B9; remoteInfo = "configd-Embedded"; }; - 158317B20CFB8660006F62B9 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; - proxyType = 1; - remoteGlobalIDString = 158317A00CFB8626006F62B9; - remoteInfo = "NetworkIdentification.bundle-Embedded"; - }; 158317B40CFB8660006F62B9 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; @@ -1501,20 +1533,6 @@ remoteGlobalIDString = 1583EB32108395BD00A3BC0C; remoteInfo = "PreferencesMonitor-EmbeddedOther"; }; - 15AC5174108396D2004A9ED5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; - proxyType = 1; - remoteGlobalIDString = 1583EB2B108395BD00A3BC0C; - remoteInfo = "NetworkIdentification.bundle-EmbeddedOther"; - }; - 15AC5176108396D2004A9ED5 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; - proxyType = 1; - remoteGlobalIDString = 1583EB23108395BD00A3BC0C; - remoteInfo = "NetworkIdentification-EmbeddedOther"; - }; 15AC5178108396D2004A9ED5 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; @@ -1606,19 +1624,12 @@ remoteGlobalIDString = 157A84D80D56C63900B6F1A0; remoteInfo = "DNSConfiguration-Embedded"; }; - F95B8A760B03FB9100993BA3 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; - proxyType = 1; - remoteGlobalIDString = F95B8A6A0B03F9D100993BA3; - remoteInfo = NetworkIdentification.bundle; - }; - F95B8A780B03FB9100993BA3 /* PBXContainerItemProxy */ = { + D6DDAC3C147A24BC00A2E902 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; proxyType = 1; - remoteGlobalIDString = F95B8A5E0B03F81400993BA3; - remoteInfo = NetworkIdentification; + remoteGlobalIDString = 1547001808455B98006787CE; + remoteInfo = SCHelper; }; /* End PBXContainerItemProxy section */ @@ -1738,6 +1749,13 @@ 15213FFA0E93E9F500DACD2C /* Logger.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Logger.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 1521FC5C060F296A003B28F5 /* dnsinfo_create.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = dnsinfo_create.c; path = dnsinfo/dnsinfo_create.c; sourceTree = SOURCE_ROOT; }; 1522FCE50FA7FD7000B24128 /* dnsinfo_flatfile.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dnsinfo_flatfile.c; path = dnsinfo/dnsinfo_flatfile.c; sourceTree = ""; }; + 1528BFE21357305400691881 /* libSCNetworkReachability.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSCNetworkReachability.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 1528BFE81357309800691881 /* SCNetworkReachability.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SCNetworkReachability.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 1528BFE91357312E00691881 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = Plugins/SCNetworkReachability/Info.plist; sourceTree = ""; }; + 1528BFF713573FEE00691881 /* libSCNetworkReachability.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSCNetworkReachability.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 1528BFFE13573FF500691881 /* SCNetworkReachability.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SCNetworkReachability.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 1528C0061357401900691881 /* libSCNetworkReachability.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libSCNetworkReachability.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 1528C00D1357401D00691881 /* SCNetworkReachability.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SCNetworkReachability.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 152CEED0070CF6640050F23C /* libedit.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libedit.dylib; path = /usr/lib/libedit.2.dylib; sourceTree = ""; }; 152E0E7E10FE820E00E402F2 /* helper.defs */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.mig; name = helper.defs; path = SystemConfiguration.fproj/helper/helper.defs; sourceTree = ""; }; 152E0E8810FE824000E402F2 /* helper_types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = helper_types.h; path = SystemConfiguration.fproj/helper/helper_types.h; sourceTree = ""; }; @@ -1762,7 +1780,6 @@ 1559C4520D349A4E0098FD59 /* KernelEventMonitor.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KernelEventMonitor.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 1559C4530D349A4E0098FD59 /* LinkConfiguration.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LinkConfiguration.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 1559C4540D349A4E0098FD59 /* PreferencesMonitor.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PreferencesMonitor.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; - 1559C4550D349A4E0098FD59 /* NetworkIdentification.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NetworkIdentification.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 155A1E6B081079CC00F70D98 /* SCNetworkConfigurationPrivate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SCNetworkConfigurationPrivate.h; sourceTree = ""; }; 155B7BF60847776D00F0E262 /* SCHelper_client.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SCHelper_client.h; path = helper/SCHelper_client.h; sourceTree = ""; }; 155D22380AF13A7300D52ED0 /* dns-configuration.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "dns-configuration.h"; sourceTree = ""; }; @@ -1783,11 +1800,10 @@ 157A850D0D56C8AA00B6F1A0 /* libInterfaceNamer.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libInterfaceNamer.a; sourceTree = BUILT_PRODUCTS_DIR; }; 157A85230D56C8E000B6F1A0 /* libKernelEventMonitor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libKernelEventMonitor.a; sourceTree = BUILT_PRODUCTS_DIR; }; 157A852E0D56C91100B6F1A0 /* libLinkConfiguration.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libLinkConfiguration.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 157A85390D56C94F00B6F1A0 /* libNetworkIdentification.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libNetworkIdentification.a; sourceTree = BUILT_PRODUCTS_DIR; }; 157A85440D56C96F00B6F1A0 /* libPreferencesMonitor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPreferencesMonitor.a; sourceTree = BUILT_PRODUCTS_DIR; }; 157A88880A470D0F003A4256 /* SCSchemaDefinitionsPrivate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SCSchemaDefinitionsPrivate.h; sourceTree = ""; }; 15828AE70753B5F900AD4710 /* KernelEventMonitor.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = KernelEventMonitor.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; - 1583EA10108395BB00A3BC0C /* dnsinfo.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = dnsinfo.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; + 1583EA10108395BB00A3BC0C /* libdnsinfo.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdnsinfo.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 1583EA99108395BB00A3BC0C /* SystemConfiguration.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SystemConfiguration.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 1583EAAA108395BB00A3BC0C /* SCHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = SCHelper; sourceTree = BUILT_PRODUCTS_DIR; }; 1583EAD8108395BB00A3BC0C /* libIPMonitor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libIPMonitor.a; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1799,8 +1815,6 @@ 1583EB0E108395BC00A3BC0C /* libLinkConfiguration.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libLinkConfiguration.a; sourceTree = BUILT_PRODUCTS_DIR; }; 1583EB14108395BC00A3BC0C /* LinkConfiguration.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = LinkConfiguration.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 1583EB21108395BC00A3BC0C /* Logger.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = Logger.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; - 1583EB2A108395BD00A3BC0C /* libNetworkIdentification.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libNetworkIdentification.a; sourceTree = BUILT_PRODUCTS_DIR; }; - 1583EB30108395BD00A3BC0C /* NetworkIdentification.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NetworkIdentification.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 1583EB39108395BD00A3BC0C /* libPreferencesMonitor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libPreferencesMonitor.a; sourceTree = BUILT_PRODUCTS_DIR; }; 1583EB3F108395BD00A3BC0C /* PreferencesMonitor.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = PreferencesMonitor.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; 1583EB84108395BD00A3BC0C /* configd */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = configd; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1863,6 +1877,11 @@ 15B73F0D05FD1B670096477F /* dnsinfo_server.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = dnsinfo_server.c; path = dnsinfo/dnsinfo_server.c; sourceTree = ""; }; 15B73F0E05FD1B670096477F /* dnsinfo_server.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = dnsinfo_server.h; path = dnsinfo/dnsinfo_server.h; sourceTree = ""; }; 15BAA32207F0699A00D9EC95 /* libbsm.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libbsm.dylib; path = /usr/lib/libbsm.dylib; sourceTree = ""; }; + 15C330B7134B92780028E36B /* SCNetworkReachabilityServer_client.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SCNetworkReachabilityServer_client.c; path = reachability/SCNetworkReachabilityServer_client.c; sourceTree = ""; }; + 15C330B8134B92780028E36B /* rb.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = rb.c; path = reachability/rb.c; sourceTree = ""; }; + 15C330B9134B92780028E36B /* rb.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = rb.h; path = reachability/rb.h; sourceTree = ""; }; + 15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SCNetworkReachabilityServer_server.c; path = reachability/SCNetworkReachabilityServer_server.c; sourceTree = ""; }; + 15C330D0134B95AA0028E36B /* SCNetworkReachabilityInternal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCNetworkReachabilityInternal.h; sourceTree = ""; }; 15CB691305C0722B0099E85F /* SystemConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SystemConfiguration.h; sourceTree = ""; }; 15CB691505C0722B0099E85F /* SCPrivate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCPrivate.h; sourceTree = ""; }; 15CB691705C0722B0099E85F /* SCDPlugin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCDPlugin.h; sourceTree = ""; }; @@ -1894,14 +1913,11 @@ 15CB695405C0722B0099E85F /* SCDPrivate.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDPrivate.c; sourceTree = ""; }; 15CB695605C0722B0099E85F /* SCDPlugin.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDPlugin.c; sourceTree = ""; }; 15CB695805C0722B0099E85F /* SCDOpen.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDOpen.c; sourceTree = ""; }; - 15CB695A05C0722B0099E85F /* SCDLock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDLock.c; sourceTree = ""; }; - 15CB695C05C0722B0099E85F /* SCDUnlock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDUnlock.c; sourceTree = ""; }; 15CB695E05C0722B0099E85F /* SCDList.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDList.c; sourceTree = ""; }; 15CB696005C0722B0099E85F /* SCDAdd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDAdd.c; sourceTree = ""; }; 15CB696405C0722B0099E85F /* SCDGet.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDGet.c; sourceTree = ""; }; 15CB696605C0722B0099E85F /* SCDSet.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDSet.c; sourceTree = ""; }; 15CB696805C0722B0099E85F /* SCDRemove.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDRemove.c; sourceTree = ""; }; - 15CB696A05C0722B0099E85F /* SCDTouch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDTouch.c; sourceTree = ""; }; 15CB696C05C0722B0099E85F /* SCDNotify.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotify.c; sourceTree = ""; }; 15CB696E05C0722B0099E85F /* SCDNotifierSetKeys.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierSetKeys.c; sourceTree = ""; }; 15CB697005C0722B0099E85F /* SCDNotifierAdd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierAdd.c; sourceTree = ""; }; @@ -1909,7 +1925,6 @@ 15CB697405C0722B0099E85F /* SCDNotifierGetChanges.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierGetChanges.c; sourceTree = ""; }; 15CB697605C0722B0099E85F /* SCDNotifierWait.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierWait.c; sourceTree = ""; }; 15CB697805C0722B0099E85F /* SCDNotifierInformViaCallback.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierInformViaCallback.c; sourceTree = ""; }; - 15CB697A05C0722B0099E85F /* SCDNotifierInformViaMachPort.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierInformViaMachPort.c; sourceTree = ""; }; 15CB697C05C0722B0099E85F /* SCDNotifierInformViaFD.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierInformViaFD.c; sourceTree = ""; }; 15CB697E05C0722B0099E85F /* SCDNotifierInformViaSignal.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierInformViaSignal.c; sourceTree = ""; }; 15CB698005C0722B0099E85F /* SCDNotifierCancel.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCDNotifierCancel.c; sourceTree = ""; }; @@ -1957,14 +1972,12 @@ 15CB69EC05C0722B0099E85F /* pattern.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = pattern.c; sourceTree = ""; }; 15CB69F005C0722B0099E85F /* _configopen.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configopen.c; sourceTree = ""; }; 15CB69F205C0722B0099E85F /* _configclose.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configclose.c; sourceTree = ""; }; - 15CB69F405C0722B0099E85F /* _configlock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configlock.c; sourceTree = ""; }; 15CB69F605C0722B0099E85F /* _configunlock.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configunlock.c; sourceTree = ""; }; 15CB69F805C0722B0099E85F /* _configlist.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configlist.c; sourceTree = ""; }; 15CB69FA05C0722B0099E85F /* _configadd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configadd.c; sourceTree = ""; }; 15CB69FE05C0722B0099E85F /* _configget.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configget.c; sourceTree = ""; }; 15CB6A0005C0722B0099E85F /* _configset.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configset.c; sourceTree = ""; }; 15CB6A0205C0722B0099E85F /* _configremove.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configremove.c; sourceTree = ""; }; - 15CB6A0405C0722B0099E85F /* _configtouch.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _configtouch.c; sourceTree = ""; }; 15CB6A0605C0722B0099E85F /* _confignotify.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _confignotify.c; sourceTree = ""; }; 15CB6A0805C0722B0099E85F /* _notifyadd.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _notifyadd.c; sourceTree = ""; }; 15CB6A0A05C0722B0099E85F /* _notifyremove.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = _notifyremove.c; sourceTree = ""; }; @@ -1996,6 +2009,7 @@ 15CB6A6A05C0722B0099E85F /* scutil.8 */ = {isa = PBXFileReference; explicitFileType = text.man; path = scutil.8; sourceTree = ""; }; 15CB6A6F05C0722B0099E85F /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = ""; }; 15CFC229068B222F00123568 /* get-mobility-info */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.script.sh; path = "get-mobility-info"; sourceTree = SOURCE_ROOT; }; + 15D8B2291450D8450090CECF /* SCD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCD.h; sourceTree = ""; }; 15D9DCFA10DD90A1004E545D /* AppWorkaround.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = AppWorkaround.plist; sourceTree = ""; }; 15DAD5EE075913CE0084A6ED /* libdnsinfo.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = libdnsinfo.dylib; sourceTree = BUILT_PRODUCTS_DIR; }; 15DAF2D808466D4900D1B2BD /* SCHelper_client.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; name = SCHelper_client.c; path = helper/SCHelper_client.c; sourceTree = ""; }; @@ -2029,13 +2043,13 @@ 72B43726113C7BFC00EBF1B6 /* nc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = nc.h; sourceTree = ""; }; 72B43727113C7BFC00EBF1B6 /* nc.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = nc.c; sourceTree = ""; }; 9EE943F306AF409B00772EB5 /* BondConfiguration.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = BondConfiguration.c; sourceTree = ""; }; + D6986A75136891120091C931 /* network_information_priv.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = network_information_priv.c; path = nwi/network_information_priv.c; sourceTree = ""; }; + D6986A761368911E0091C931 /* network_information_priv.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = network_information_priv.h; path = nwi/network_information_priv.h; sourceTree = ""; }; + D6986A77136891300091C931 /* network_information.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = network_information.c; path = nwi/network_information.c; sourceTree = ""; }; + D6986A781368913C0091C931 /* network_information.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = network_information.h; path = nwi/network_information.h; sourceTree = ""; }; F95B8A420B03E07A00993BA3 /* SCNetworkSignature.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = SCNetworkSignature.c; sourceTree = ""; }; F95B8A440B03E09300993BA3 /* SCNetworkSignature.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SCNetworkSignature.h; sourceTree = ""; }; F95B8A450B03E09300993BA3 /* SCNetworkSignaturePrivate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = SCNetworkSignaturePrivate.h; sourceTree = ""; }; - F95B8A5F0B03F81400993BA3 /* libNetworkIdentification.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libNetworkIdentification.a; sourceTree = BUILT_PRODUCTS_DIR; }; - F95B8A670B03F97800993BA3 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - F95B8A680B03F97800993BA3 /* NetworkIdentification.c */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.c; path = NetworkIdentification.c; sourceTree = ""; }; - F95B8A700B03F9D100993BA3 /* NetworkIdentification.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NetworkIdentification.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -2147,8 +2161,8 @@ 158317530CFB80A1006F62B9 /* libInterfaceNamer.a in Frameworks */, 158317540CFB80A1006F62B9 /* libIPMonitor.a in Frameworks */, 158317550CFB80A1006F62B9 /* libLinkConfiguration.a in Frameworks */, - 158317560CFB80A1006F62B9 /* libNetworkIdentification.a in Frameworks */, 158317570CFB80A1006F62B9 /* libPreferencesMonitor.a in Frameworks */, + 1528C0171357465900691881 /* libSCNetworkReachability.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2212,8 +2226,8 @@ 1583EB7A108395BD00A3BC0C /* libInterfaceNamer.a in Frameworks */, 1583EB7B108395BD00A3BC0C /* libIPMonitor.a in Frameworks */, 1583EB7C108395BD00A3BC0C /* libLinkConfiguration.a in Frameworks */, - 1583EB7D108395BD00A3BC0C /* libNetworkIdentification.a in Frameworks */, 1583EB7E108395BD00A3BC0C /* libPreferencesMonitor.a in Frameworks */, + 1528C01A135746D700691881 /* libSCNetworkReachability.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2249,8 +2263,8 @@ 159D54D007529FFF004F8947 /* libInterfaceNamer.a in Frameworks */, 159D54D107529FFF004F8947 /* libIPMonitor.a in Frameworks */, 159D54D207529FFF004F8947 /* libLinkConfiguration.a in Frameworks */, - 1533D77B0B10A14300CA4946 /* libNetworkIdentification.a in Frameworks */, 159D54D307529FFF004F8947 /* libPreferencesMonitor.a in Frameworks */, + 1528C019135746BB00691881 /* libSCNetworkReachability.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2283,7 +2297,7 @@ 1513E399108420A700088779 /* EmbeddedOther */ = { isa = PBXGroup; children = ( - 1583EA10108395BB00A3BC0C /* dnsinfo.dylib */, + 1583EA10108395BB00A3BC0C /* libdnsinfo.dylib */, 1583EA99108395BB00A3BC0C /* SystemConfiguration.framework */, 1513E39D108420DE00088779 /* Plugins */, 1583EAAA108395BB00A3BC0C /* SCHelper */, @@ -2304,10 +2318,10 @@ 1583EB0E108395BC00A3BC0C /* libLinkConfiguration.a */, 1583EB14108395BC00A3BC0C /* LinkConfiguration.bundle */, 1583EB21108395BC00A3BC0C /* Logger.bundle */, - 1583EB2A108395BD00A3BC0C /* libNetworkIdentification.a */, - 1583EB30108395BD00A3BC0C /* NetworkIdentification.bundle */, 1583EB39108395BD00A3BC0C /* libPreferencesMonitor.a */, 1583EB3F108395BD00A3BC0C /* PreferencesMonitor.bundle */, + 1528C0061357401900691881 /* libSCNetworkReachability.a */, + 1528C00D1357401D00691881 /* SCNetworkReachability.bundle */, ); name = Plugins; sourceTree = ""; @@ -2332,6 +2346,14 @@ name = SCMonitor; sourceTree = ""; }; + 1528BFDA13572FC200691881 /* SCNetworkReachability */ = { + isa = PBXGroup; + children = ( + 1528BFE91357312E00691881 /* Info.plist */, + ); + name = SCNetworkReachability; + sourceTree = ""; + }; 1531D3D90E93E6AA00248432 /* Logger */ = { isa = PBXGroup; children = ( @@ -2389,8 +2411,8 @@ 156CA4850EF853BB00C59A18 /* Logger.bundle */, 157A85440D56C96F00B6F1A0 /* libPreferencesMonitor.a */, 1559C4540D349A4E0098FD59 /* PreferencesMonitor.bundle */, - 157A85390D56C94F00B6F1A0 /* libNetworkIdentification.a */, - 1559C4550D349A4E0098FD59 /* NetworkIdentification.bundle */, + 1528BFF713573FEE00691881 /* libSCNetworkReachability.a */, + 1528BFFE13573FF500691881 /* SCNetworkReachability.bundle */, ); name = Plugins; sourceTree = ""; @@ -2413,7 +2435,6 @@ 15FF5C390CDF9C4000EEC8AA /* Supporting Files */, ); name = SCHelper; - path = SystemConfiguration.fproj; sourceTree = ""; }; 1547002F084561ED006787CE /* Headers */ = { @@ -2476,11 +2497,11 @@ 15828AE70753B5F900AD4710 /* KernelEventMonitor.bundle */, 159D53F307528C79004F8947 /* libLinkConfiguration.a */, 15FD72B50754DA69001CC321 /* LinkConfiguration.bundle */, - F95B8A5F0B03F81400993BA3 /* libNetworkIdentification.a */, 15213FFA0E93E9F500DACD2C /* Logger.bundle */, - F95B8A700B03F9D100993BA3 /* NetworkIdentification.bundle */, 159D53FA07528C95004F8947 /* libPreferencesMonitor.a */, 15FD72C90754DA7E001CC321 /* PreferencesMonitor.bundle */, + 1528BFE21357305400691881 /* libSCNetworkReachability.a */, + 1528BFE81357309800691881 /* SCNetworkReachability.bundle */, ); name = Plugins; sourceTree = ""; @@ -2504,8 +2525,8 @@ 159D53AF07528B36004F8947 /* KernelEventMonitor */, 159D53C007528B36004F8947 /* LinkConfiguration */, 1531D3D90E93E6AA00248432 /* Logger */, - F95B8A660B03F97800993BA3 /* NetworkIdentification */, 159D53C207528B36004F8947 /* PreferencesMonitor */, + 1528BFDA13572FC200691881 /* SCNetworkReachability */, ); name = Plugins; sourceTree = ""; @@ -2598,60 +2619,49 @@ name = "Supporting Files"; sourceTree = ""; }; - 15CB68FC05C072220099E85F /* configd */ = { + 15C330B4134B91930028E36B /* SCNetworkReachability */ = { isa = PBXGroup; children = ( - 15CB6A8605C072500099E85F /* MiG */, - 15CB6A8305C072410099E85F /* Schema */, - 1582B36B05FD1A4D009C2750 /* DNSConfiguration */, - 15CB690705C0722A0099E85F /* SystemConfiguration */, - 1547002E084561B4006787CE /* SCHelper */, - 151F5DA80CCE995D0093AC3B /* SCMonitor */, - 15CB69C205C0722B0099E85F /* configd */, - 15CB6A2205C0722B0099E85F /* scselect */, - 15CB6A3705C0722B0099E85F /* scutil */, - 159D53A207528B06004F8947 /* Plugins */, - 15CB6A6E05C0722B0099E85F /* External Frameworks and Libraries */, - 15CB690F05C0722B0099E85F /* Products */, - 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */, - 15FD147B0D594FE700F9409C /* IndigoSDK.xcconfig */, + 15C330B5134B91C40028E36B /* Headers */, + 15C330B6134B91CB0028E36B /* Sources */, ); - indentWidth = 8; - name = configd; + name = SCNetworkReachability; sourceTree = ""; - tabWidth = 8; - usesTabs = 1; }; - 15CB690705C0722A0099E85F /* SystemConfiguration */ = { + 15C330B5134B91C40028E36B /* Headers */ = { isa = PBXGroup; children = ( - 15CB691205C0722B0099E85F /* Headers */, - 15CB694F05C0722B0099E85F /* Sources */, - 15B6861D0678B61900FF4023 /* Supporting Files */, + 15CB693705C0722B0099E85F /* SCNetworkReachability.h */, + 15C330D0134B95AA0028E36B /* SCNetworkReachabilityInternal.h */, + 15C330B9134B92780028E36B /* rb.h */, ); - name = SystemConfiguration; - path = SystemConfiguration.fproj; + name = Headers; sourceTree = ""; }; - 15CB690F05C0722B0099E85F /* Products */ = { + 15C330B6134B91CB0028E36B /* Sources */ = { isa = PBXGroup; children = ( - 151F63EC09328A3C0096DCC9 /* genSCPreferences */, - 154083530D5B824400E07907 /* MacOSX */, - 1540835A0D5B825200E07907 /* Embedded */, - 154083890D5B82A900E07907 /* EmbeddedSimulator */, - 1513E399108420A700088779 /* EmbeddedOther */, + 15CB69A205C0722B0099E85F /* SCNetwork.c */, + 15CB69A605C0722B0099E85F /* SCNetworkReachability.c */, + 15C330B7134B92780028E36B /* SCNetworkReachabilityServer_client.c */, + 15C330BB134B92780028E36B /* SCNetworkReachabilityServer_server.c */, + 15C330B8134B92780028E36B /* rb.c */, ); - name = Products; + name = Sources; sourceTree = ""; }; - 15CB691205C0722B0099E85F /* Headers */ = { + 15C330D5134B99EF0028E36B /* SCDynamicStore */ = { + isa = PBXGroup; + children = ( + 15C330D6134B9A1C0028E36B /* Headers */, + 15C330D7134B9A290028E36B /* Sources */, + ); + name = SCDynamicStore; + sourceTree = ""; + }; + 15C330D6134B9A1C0028E36B /* Headers */ = { isa = PBXGroup; children = ( - 15CB691305C0722B0099E85F /* SystemConfiguration.h */, - 150607DE075A00A300B147BA /* SCSchemaDefinitions.h */, - 157A88880A470D0F003A4256 /* SCSchemaDefinitionsPrivate.h */, - 15CB691705C0722B0099E85F /* SCDPlugin.h */, 15CB691B05C0722B0099E85F /* SCDynamicStoreInternal.h */, 15CB691D05C0722B0099E85F /* SCDynamicStore.h */, 15CB691F05C0722B0099E85F /* SCDynamicStorePrivate.h */, @@ -2660,58 +2670,20 @@ 15CB692305C0722B0099E85F /* SCDynamicStoreCopySpecific.h */, 15CB692505C0722B0099E85F /* SCDynamicStoreCopySpecificPrivate.h */, 15CB692705C0722B0099E85F /* SCDynamicStoreSetSpecificPrivate.h */, - 15CB692905C0722B0099E85F /* SCPreferencesInternal.h */, - 15CB692B05C0722B0099E85F /* SCPreferences.h */, - 15CB692D05C0722B0099E85F /* SCPreferencesPrivate.h */, - 15CB692F05C0722B0099E85F /* SCPreferencesPath.h */, - 151BDA2B05D9E28B00657BC7 /* SCPreferencesPathKey.h */, - 154CF3F307E1EA4D00D8302E /* SCPreferencesGetSpecificPrivate.h */, - 15CB693105C0722B0099E85F /* SCPreferencesSetSpecific.h */, - 156BD6BB07E0DFA9008698FF /* SCPreferencesSetSpecificPrivate.h */, - 152E68C00A2C89C70011FDA8 /* SCPreferencesKeychainPrivate.h */, - 15CB691505C0722B0099E85F /* SCPrivate.h */, - 15AD7A380670A85900BFE03C /* SCNetworkConfiguration.h */, - 155A1E6B081079CC00F70D98 /* SCNetworkConfigurationPrivate.h */, - 15AD7A3A0670A85900BFE03C /* SCNetworkConfigurationInternal.h */, - 15CB693305C0722B0099E85F /* SCNetwork.h */, - 15CB693505C0722B0099E85F /* SCNetworkConnection.h */, - 15A2972E0A13C08C009879B3 /* SCNetworkConnectionPrivate.h */, - 15CB693705C0722B0099E85F /* SCNetworkReachability.h */, - F95B8A440B03E09300993BA3 /* SCNetworkSignature.h */, - F95B8A450B03E09300993BA3 /* SCNetworkSignaturePrivate.h */, - 15CB693905C0722B0099E85F /* SCValidation.h */, - 15A1FF3010597F17004C9CC9 /* CaptiveNetwork.h */, - 15CB694505C0722B0099E85F /* DeviceOnHold.h */, - 15CB693D05C0722B0099E85F /* DHCPClientPreferences.h */, - 15CB694705C0722B0099E85F /* LinkConfiguration.h */, - 15CB694905C0722B0099E85F /* dy_framework.h */, - 15CB694305C0722B0099E85F /* moh.h */, - 15CB694105C0722B0099E85F /* moh_msg.h */, - 23C1E2BE062DD5DB00835B54 /* pppcontroller.h */, - 159A7513107FEAA400A57EAB /* VPNPrivate.h */, - 159A7515107FEAA400A57EAB /* VPNConfiguration.h */, - 15AAA7F2108E310700C2A607 /* VPNTunnel.h */, - 15AAA7F1108E310700C2A607 /* VPNTunnelPrivate.h */, ); name = Headers; sourceTree = ""; }; - 15CB694F05C0722B0099E85F /* Sources */ = { + 15C330D7134B9A290028E36B /* Sources */ = { isa = PBXGroup; children = ( - 150607BD075A00A200B147BA /* SCSchemaDefinitions.c */, - 15CB695005C0722B0099E85F /* SCD.c */, - 15CB695405C0722B0099E85F /* SCDPrivate.c */, 15CB695205C0722B0099E85F /* SCDKeys.c */, 15CB695805C0722B0099E85F /* SCDOpen.c */, - 15CB695A05C0722B0099E85F /* SCDLock.c */, - 15CB695C05C0722B0099E85F /* SCDUnlock.c */, 15CB695E05C0722B0099E85F /* SCDList.c */, 15CB696005C0722B0099E85F /* SCDAdd.c */, 15CB696405C0722B0099E85F /* SCDGet.c */, 15CB696605C0722B0099E85F /* SCDSet.c */, 15CB696805C0722B0099E85F /* SCDRemove.c */, - 15CB696A05C0722B0099E85F /* SCDTouch.c */, 15CB696C05C0722B0099E85F /* SCDNotify.c */, 15CB696E05C0722B0099E85F /* SCDNotifierSetKeys.c */, 15CB697005C0722B0099E85F /* SCDNotifierAdd.c */, @@ -2719,11 +2691,42 @@ 15CB697405C0722B0099E85F /* SCDNotifierGetChanges.c */, 15CB697605C0722B0099E85F /* SCDNotifierWait.c */, 15CB697805C0722B0099E85F /* SCDNotifierInformViaCallback.c */, - 15CB697A05C0722B0099E85F /* SCDNotifierInformViaMachPort.c */, 15CB697C05C0722B0099E85F /* SCDNotifierInformViaFD.c */, 15CB697E05C0722B0099E85F /* SCDNotifierInformViaSignal.c */, 15CB698005C0722B0099E85F /* SCDNotifierCancel.c */, 15CB698205C0722B0099E85F /* SCDSnapshot.c */, + ); + name = Sources; + sourceTree = ""; + }; + 15C330D8134B9A730028E36B /* SCPreferences */ = { + isa = PBXGroup; + children = ( + 15C330D9134B9A850028E36B /* Headers */, + 15C330DA134B9A940028E36B /* Sources */, + ); + name = SCPreferences; + sourceTree = ""; + }; + 15C330D9134B9A850028E36B /* Headers */ = { + isa = PBXGroup; + children = ( + 15CB692905C0722B0099E85F /* SCPreferencesInternal.h */, + 15CB692B05C0722B0099E85F /* SCPreferences.h */, + 15CB692D05C0722B0099E85F /* SCPreferencesPrivate.h */, + 15CB692F05C0722B0099E85F /* SCPreferencesPath.h */, + 151BDA2B05D9E28B00657BC7 /* SCPreferencesPathKey.h */, + 154CF3F307E1EA4D00D8302E /* SCPreferencesGetSpecificPrivate.h */, + 15CB693105C0722B0099E85F /* SCPreferencesSetSpecific.h */, + 156BD6BB07E0DFA9008698FF /* SCPreferencesSetSpecificPrivate.h */, + 152E68C00A2C89C70011FDA8 /* SCPreferencesKeychainPrivate.h */, + ); + name = Headers; + sourceTree = ""; + }; + 15C330DA134B9A940028E36B /* Sources */ = { + isa = PBXGroup; + children = ( 15CB698405C0722B0099E85F /* SCP.c */, 15CB698605C0722B0099E85F /* SCPOpen.c */, 15CB698805C0722B0099E85F /* SCPLock.c */, @@ -2738,6 +2741,33 @@ 15CB699A05C0722B0099E85F /* SCPPath.c */, 151BDA5D05D9E2ED00657BC7 /* SCPreferencesPathKey.c */, 152E68C20A2C89E30011FDA8 /* SCPreferencesKeychainPrivate.c */, + ); + name = Sources; + sourceTree = ""; + }; + 15C330DB134B9B8B0028E36B /* SCNetworkConfiguration */ = { + isa = PBXGroup; + children = ( + 15C330DC134B9BA20028E36B /* Headers */, + 15C330DD134B9BB20028E36B /* Sources */, + ); + name = SCNetworkConfiguration; + sourceTree = ""; + }; + 15C330DC134B9BA20028E36B /* Headers */ = { + isa = PBXGroup; + children = ( + 15AD7A380670A85900BFE03C /* SCNetworkConfiguration.h */, + 155A1E6B081079CC00F70D98 /* SCNetworkConfigurationPrivate.h */, + 15AD7A3A0670A85900BFE03C /* SCNetworkConfigurationInternal.h */, + 15CB694705C0722B0099E85F /* LinkConfiguration.h */, + ); + name = Headers; + sourceTree = ""; + }; + 15C330DD134B9BB20028E36B /* Sources */ = { + isa = PBXGroup; + children = ( 15AD7A390670A85900BFE03C /* SCNetworkConfigurationInternal.c */, 15AD7A3B0670A85900BFE03C /* SCNetworkInterface.c */, 15AD7A3C0670A85900BFE03C /* SCNetworkProtocol.c */, @@ -2747,73 +2777,209 @@ 9EE943F306AF409B00772EB5 /* BondConfiguration.c */, 15FD7B3B101E439200C56621 /* BridgeConfiguration.c */, 15CB69B605C0722B0099E85F /* VLANConfiguration.c */, - 15CB695605C0722B0099E85F /* SCDPlugin.c */, - 15CB699C05C0722B0099E85F /* SCDConsoleUser.c */, - 15CB699E05C0722B0099E85F /* SCDHostName.c */, - 15CB69A005C0722B0099E85F /* SCLocation.c */, - 15CB69A205C0722B0099E85F /* SCNetwork.c */, + ); + name = Sources; + sourceTree = ""; + }; + 15C330DE134B9C290028E36B /* SCNetworkConnection */ = { + isa = PBXGroup; + children = ( + 15C330E0134B9C4C0028E36B /* Headers */, + 15C330DF134B9C3F0028E36B /* Sources */, + ); + name = SCNetworkConnection; + sourceTree = ""; + }; + 15C330DF134B9C3F0028E36B /* Sources */ = { + isa = PBXGroup; + children = ( 15CB69A405C0722B0099E85F /* SCNetworkConnection.c */, 15A2972D0A13C08C009879B3 /* SCNetworkConnectionPrivate.c */, - 15CB69A605C0722B0099E85F /* SCNetworkReachability.c */, - F95B8A420B03E07A00993BA3 /* SCNetworkSignature.c */, - 15CB69A805C0722B0099E85F /* SCProxies.c */, - 15A1FF3110597F17004C9CC9 /* CaptiveNetwork.c */, - 15CB69AC05C0722B0099E85F /* DHCP.c */, - 15CB69AE05C0722B0099E85F /* moh.c */, - 15CB69B005C0722B0099E85F /* DeviceOnHold.c */, - 15CB69B405C0722B0099E85F /* dy_framework.c */, - 159A7517107FEAA400A57EAB /* VPNPrivate.c */, - 159A7519107FEAA400A57EAB /* VPNConfiguration.c */, - 15AAA7F3108E310700C2A607 /* VPNTunnel.c */, ); name = Sources; sourceTree = ""; }; - 15CB69C205C0722B0099E85F /* configd */ = { + 15C330E0134B9C4C0028E36B /* Headers */ = { isa = PBXGroup; children = ( - 15CB69CE05C0722B0099E85F /* Headers */, - 15CB69DF05C0722B0099E85F /* Sources */, - 15CB6A1805C0722B0099E85F /* Supporting Files */, + 15CB693505C0722B0099E85F /* SCNetworkConnection.h */, + 15A2972E0A13C08C009879B3 /* SCNetworkConnectionPrivate.h */, + 23C1E2BE062DD5DB00835B54 /* pppcontroller.h */, ); - name = configd; - path = configd.tproj; + name = Headers; sourceTree = ""; }; - 15CB69CE05C0722B0099E85F /* Headers */ = { + 15C330E1134B9C8E0028E36B /* VPN */ = { isa = PBXGroup; children = ( - 15CB69CF05C0722B0099E85F /* configd.h */, - 15CB69D105C0722B0099E85F /* _SCD.h */, - 15CB69D305C0722B0099E85F /* configd_server.h */, - 15CB69D505C0722B0099E85F /* notify_server.h */, - 15CB69D705C0722B0099E85F /* plugin_support.h */, - 15CB69D905C0722B0099E85F /* session.h */, - 15CB69DB05C0722B0099E85F /* pattern.h */, + 15C330E3134B9CA30028E36B /* Headers */, + 15C330E2134B9C9B0028E36B /* Sources */, ); - name = Headers; + name = VPN; sourceTree = ""; }; - 15CB69DF05C0722B0099E85F /* Sources */ = { + 15C330E2134B9C9B0028E36B /* Sources */ = { isa = PBXGroup; children = ( - 15CB69E005C0722B0099E85F /* configd.m */, - 15CB69E205C0722B0099E85F /* _SCD.c */, - 15CB69E405C0722B0099E85F /* configd_server.c */, - 15CB69E605C0722B0099E85F /* notify_server.c */, - 15CB69E805C0722B0099E85F /* plugin_support.c */, - 15CB69EA05C0722B0099E85F /* session.c */, - 15CB69EC05C0722B0099E85F /* pattern.c */, - 15CB69F005C0722B0099E85F /* _configopen.c */, - 15CB69F205C0722B0099E85F /* _configclose.c */, - 15CB69F405C0722B0099E85F /* _configlock.c */, - 15CB69F605C0722B0099E85F /* _configunlock.c */, - 15CB69F805C0722B0099E85F /* _configlist.c */, + 159A7517107FEAA400A57EAB /* VPNPrivate.c */, + 159A7519107FEAA400A57EAB /* VPNConfiguration.c */, + 15AAA7F3108E310700C2A607 /* VPNTunnel.c */, + ); + name = Sources; + sourceTree = ""; + }; + 15C330E3134B9CA30028E36B /* Headers */ = { + isa = PBXGroup; + children = ( + 159A7513107FEAA400A57EAB /* VPNPrivate.h */, + 159A7515107FEAA400A57EAB /* VPNConfiguration.h */, + 15AAA7F2108E310700C2A607 /* VPNTunnel.h */, + 15AAA7F1108E310700C2A607 /* VPNTunnelPrivate.h */, + ); + name = Headers; + sourceTree = ""; + }; + 15CB68FC05C072220099E85F /* configd */ = { + isa = PBXGroup; + children = ( + 15CB6A8605C072500099E85F /* MiG */, + 15CB6A8305C072410099E85F /* Schema */, + D6986A70136890B60091C931 /* NetworkInformation */, + 1582B36B05FD1A4D009C2750 /* DNSConfiguration */, + 15CB690705C0722A0099E85F /* SystemConfiguration */, + 151F5DA80CCE995D0093AC3B /* SCMonitor */, + 15CB69C205C0722B0099E85F /* configd */, + 15CB6A2205C0722B0099E85F /* scselect */, + 15CB6A3705C0722B0099E85F /* scutil */, + 159D53A207528B06004F8947 /* Plugins */, + 15CB6A6E05C0722B0099E85F /* External Frameworks and Libraries */, + 15CB690F05C0722B0099E85F /* Products */, + 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */, + 15FD147B0D594FE700F9409C /* IndigoSDK.xcconfig */, + ); + indentWidth = 8; + name = configd; + sourceTree = ""; + tabWidth = 8; + usesTabs = 1; + }; + 15CB690705C0722A0099E85F /* SystemConfiguration */ = { + isa = PBXGroup; + children = ( + 15C330D5134B99EF0028E36B /* SCDynamicStore */, + 15C330D8134B9A730028E36B /* SCPreferences */, + 1547002E084561B4006787CE /* SCHelper */, + 15C330DB134B9B8B0028E36B /* SCNetworkConfiguration */, + 15C330DE134B9C290028E36B /* SCNetworkConnection */, + 15C330B4134B91930028E36B /* SCNetworkReachability */, + 15C330E1134B9C8E0028E36B /* VPN */, + 15CB691205C0722B0099E85F /* Other Headers */, + 15CB694F05C0722B0099E85F /* Other Sources */, + 15B6861D0678B61900FF4023 /* Supporting Files */, + ); + name = SystemConfiguration; + path = SystemConfiguration.fproj; + sourceTree = ""; + }; + 15CB690F05C0722B0099E85F /* Products */ = { + isa = PBXGroup; + children = ( + 151F63EC09328A3C0096DCC9 /* genSCPreferences */, + 154083530D5B824400E07907 /* MacOSX */, + 1540835A0D5B825200E07907 /* Embedded */, + 154083890D5B82A900E07907 /* EmbeddedSimulator */, + 1513E399108420A700088779 /* EmbeddedOther */, + ); + name = Products; + sourceTree = ""; + }; + 15CB691205C0722B0099E85F /* Other Headers */ = { + isa = PBXGroup; + children = ( + 15D8B2291450D8450090CECF /* SCD.h */, + 15CB691305C0722B0099E85F /* SystemConfiguration.h */, + 150607DE075A00A300B147BA /* SCSchemaDefinitions.h */, + 157A88880A470D0F003A4256 /* SCSchemaDefinitionsPrivate.h */, + 15CB691705C0722B0099E85F /* SCDPlugin.h */, + 15CB691505C0722B0099E85F /* SCPrivate.h */, + 15CB693305C0722B0099E85F /* SCNetwork.h */, + F95B8A440B03E09300993BA3 /* SCNetworkSignature.h */, + F95B8A450B03E09300993BA3 /* SCNetworkSignaturePrivate.h */, + 15CB693905C0722B0099E85F /* SCValidation.h */, + 15A1FF3010597F17004C9CC9 /* CaptiveNetwork.h */, + 15CB694505C0722B0099E85F /* DeviceOnHold.h */, + 15CB693D05C0722B0099E85F /* DHCPClientPreferences.h */, + 15CB694905C0722B0099E85F /* dy_framework.h */, + 15CB694305C0722B0099E85F /* moh.h */, + 15CB694105C0722B0099E85F /* moh_msg.h */, + ); + name = "Other Headers"; + sourceTree = ""; + }; + 15CB694F05C0722B0099E85F /* Other Sources */ = { + isa = PBXGroup; + children = ( + 150607BD075A00A200B147BA /* SCSchemaDefinitions.c */, + 15CB695005C0722B0099E85F /* SCD.c */, + 15CB695405C0722B0099E85F /* SCDPrivate.c */, + 15CB695605C0722B0099E85F /* SCDPlugin.c */, + 15CB699C05C0722B0099E85F /* SCDConsoleUser.c */, + 15CB699E05C0722B0099E85F /* SCDHostName.c */, + 15CB69A005C0722B0099E85F /* SCLocation.c */, + F95B8A420B03E07A00993BA3 /* SCNetworkSignature.c */, + 15CB69A805C0722B0099E85F /* SCProxies.c */, + 15A1FF3110597F17004C9CC9 /* CaptiveNetwork.c */, + 15CB69AC05C0722B0099E85F /* DHCP.c */, + 15CB69AE05C0722B0099E85F /* moh.c */, + 15CB69B005C0722B0099E85F /* DeviceOnHold.c */, + 15CB69B405C0722B0099E85F /* dy_framework.c */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 15CB69C205C0722B0099E85F /* configd */ = { + isa = PBXGroup; + children = ( + 15CB69CE05C0722B0099E85F /* Headers */, + 15CB69DF05C0722B0099E85F /* Sources */, + 15CB6A1805C0722B0099E85F /* Supporting Files */, + ); + name = configd; + path = configd.tproj; + sourceTree = ""; + }; + 15CB69CE05C0722B0099E85F /* Headers */ = { + isa = PBXGroup; + children = ( + 15CB69CF05C0722B0099E85F /* configd.h */, + 15CB69D105C0722B0099E85F /* _SCD.h */, + 15CB69D305C0722B0099E85F /* configd_server.h */, + 15CB69D505C0722B0099E85F /* notify_server.h */, + 15CB69D705C0722B0099E85F /* plugin_support.h */, + 15CB69D905C0722B0099E85F /* session.h */, + 15CB69DB05C0722B0099E85F /* pattern.h */, + ); + name = Headers; + sourceTree = ""; + }; + 15CB69DF05C0722B0099E85F /* Sources */ = { + isa = PBXGroup; + children = ( + 15CB69E005C0722B0099E85F /* configd.m */, + 15CB69E205C0722B0099E85F /* _SCD.c */, + 15CB69E405C0722B0099E85F /* configd_server.c */, + 15CB69E605C0722B0099E85F /* notify_server.c */, + 15CB69E805C0722B0099E85F /* plugin_support.c */, + 15CB69EA05C0722B0099E85F /* session.c */, + 15CB69EC05C0722B0099E85F /* pattern.c */, + 15CB69F005C0722B0099E85F /* _configopen.c */, + 15CB69F205C0722B0099E85F /* _configclose.c */, + 15CB69F605C0722B0099E85F /* _configunlock.c */, + 15CB69F805C0722B0099E85F /* _configlist.c */, 15CB69FA05C0722B0099E85F /* _configadd.c */, 15CB69FE05C0722B0099E85F /* _configget.c */, 15CB6A0005C0722B0099E85F /* _configset.c */, 15CB6A0205C0722B0099E85F /* _configremove.c */, - 15CB6A0405C0722B0099E85F /* _configtouch.c */, 15CB6A0605C0722B0099E85F /* _confignotify.c */, 15CB6A0805C0722B0099E85F /* _notifyadd.c */, 15CB6A0A05C0722B0099E85F /* _notifyremove.c */, @@ -2970,19 +3136,57 @@ name = "Supporting Files"; sourceTree = ""; }; - F95B8A660B03F97800993BA3 /* NetworkIdentification */ = { + D6986A70136890B60091C931 /* NetworkInformation */ = { + isa = PBXGroup; + children = ( + D6986A72136890C90091C931 /* Headers */, + D6986A74136890DB0091C931 /* Sources */, + ); + name = NetworkInformation; + sourceTree = ""; + }; + D6986A72136890C90091C931 /* Headers */ = { + isa = PBXGroup; + children = ( + D6986A781368913C0091C931 /* network_information.h */, + D6986A761368911E0091C931 /* network_information_priv.h */, + ); + name = Headers; + sourceTree = ""; + }; + D6986A74136890DB0091C931 /* Sources */ = { isa = PBXGroup; children = ( - F95B8A670B03F97800993BA3 /* Info.plist */, - F95B8A680B03F97800993BA3 /* NetworkIdentification.c */, + D6986A77136891300091C931 /* network_information.c */, + D6986A75136891120091C931 /* network_information_priv.c */, ); - name = NetworkIdentification; - path = Plugins/NetworkIdentification; + name = Sources; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ + 1528BFDC1357305400691881 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1528BFF113573FEE00691881 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1528C0001357401900691881 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 1547001908455B98006787CE /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -3069,6 +3273,9 @@ 159A751C107FEAA400A57EAB /* VPNConfiguration.h in Headers */, 15AAA7F5108E310700C2A607 /* VPNTunnel.h in Headers */, 15AAA7F4108E310700C2A607 /* VPNTunnelPrivate.h in Headers */, + 15C330C5134B92780028E36B /* rb.h in Headers */, + 15C330D2134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */, + 15D8B22B1450D8450090CECF /* SCD.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3105,6 +3312,7 @@ buildActionMask = 2147483647; files = ( 157A84DA0D56C63900B6F1A0 /* dnsinfo.h in Headers */, + D661C2F21368BB720030B977 /* network_information.h in Headers */, 157A84DB0D56C63900B6F1A0 /* dnsinfo_private.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3114,9 +3322,10 @@ buildActionMask = 2147483647; files = ( 157A84F60D56C7E800B6F1A0 /* dns-configuration.h in Headers */, + 15D48EC20F67061F00B4711E /* dnsinfo_create.h in Headers */, + E4F211D4137B0ABD00BBB915 /* network_information_priv.h in Headers */, 1575FD2812CD15C60003D86E /* proxy-configuration.h in Headers */, 157A84F70D56C7E800B6F1A0 /* set-hostname.h in Headers */, - 15D48EC20F67061F00B4711E /* dnsinfo_create.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3146,13 +3355,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 157A85320D56C94F00B6F1A0 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 157A853D0D56C96F00B6F1A0 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -3188,6 +3390,7 @@ buildActionMask = 2147483647; files = ( 1583EA06108395BB00A3BC0C /* dnsinfo.h in Headers */, + 151E0CA31378EE1000C5DA2A /* network_information.h in Headers */, 1583EA07108395BB00A3BC0C /* dnsinfo_private.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3237,6 +3440,9 @@ 1583EA42108395BB00A3BC0C /* SCNetworkSignature.h in Headers */, 1583EA43108395BB00A3BC0C /* SCNetworkSignaturePrivate.h in Headers */, 1583EA44108395BB00A3BC0C /* CaptiveNetwork.h in Headers */, + 15C330C7134B92780028E36B /* rb.h in Headers */, + 15C330D4134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */, + 15D8B22D1450D8450090CECF /* SCD.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3254,9 +3460,10 @@ buildActionMask = 2147483647; files = ( 1583EACC108395BB00A3BC0C /* dns-configuration.h in Headers */, + 1583EACE108395BB00A3BC0C /* dnsinfo_create.h in Headers */, + E4F211D6137B0ADB00BBB915 /* network_information_priv.h in Headers */, 1575FD2C12CD15C60003D86E /* proxy-configuration.h in Headers */, 1583EACD108395BB00A3BC0C /* set-hostname.h in Headers */, - 1583EACE108395BB00A3BC0C /* dnsinfo_create.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3286,13 +3493,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 1583EB24108395BD00A3BC0C /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 1583EB33108395BD00A3BC0C /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -3366,10 +3566,11 @@ buildActionMask = 2147483647; files = ( 155D223B0AF13A7300D52ED0 /* dns-configuration.h in Headers */, + 15D48EC00F67061700B4711E /* dnsinfo_create.h in Headers */, + E4F211D7137B0AF200BBB915 /* network_information_priv.h in Headers */, 1575FD2A12CD15C60003D86E /* proxy-configuration.h in Headers */, 155D223C0AF13A7300D52ED0 /* set-hostname.h in Headers */, 155D223D0AF13A7300D52ED0 /* smb-configuration.h in Headers */, - 15D48EC00F67061700B4711E /* dnsinfo_create.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3450,6 +3651,9 @@ 15A1FF3410597F17004C9CC9 /* CaptiveNetwork.h in Headers */, 159A7528107FEAA400A57EAB /* VPNPrivate.h in Headers */, 159A752A107FEAA400A57EAB /* VPNConfiguration.h in Headers */, + 15C330C6134B92780028E36B /* rb.h in Headers */, + 15C330D3134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */, + 15D8B22C1450D8450090CECF /* SCD.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3458,6 +3662,7 @@ buildActionMask = 2147483647; files = ( 15DAD5E1075913CE0084A6ED /* dnsinfo.h in Headers */, + D661C2EF1368BB280030B977 /* network_information.h in Headers */, 15DAD5E2075913CE0084A6ED /* dnsinfo_private.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -3478,6 +3683,7 @@ 15DAD64B07591A1A0084A6ED /* SCDynamicStoreCopySpecificPrivate.h in Headers */, 15DAD64C07591A1A0084A6ED /* SCDynamicStoreSetSpecificPrivate.h in Headers */, 15DAD64D07591A1A0084A6ED /* SCPreferencesInternal.h in Headers */, + 7264C14614731A1F004FD76D /* CaptiveNetwork.h in Headers */, 15DAD64E07591A1A0084A6ED /* SCPreferences.h in Headers */, 15DAD64F07591A1A0084A6ED /* SCPreferencesPrivate.h in Headers */, 15DAD65007591A1A0084A6ED /* SCPreferencesPath.h in Headers */, @@ -3502,6 +3708,7 @@ 154CF3F407E1EA4D00D8302E /* SCPreferencesGetSpecificPrivate.h in Headers */, 155A1E6C081079CC00F70D98 /* SCNetworkConfigurationPrivate.h in Headers */, 155B7BF80847776D00F0E262 /* SCHelper_client.h in Headers */, + 15D8B22A1450D8450090CECF /* SCD.h in Headers */, 15A297300A13C08C009879B3 /* SCNetworkConnectionPrivate.h in Headers */, 152E68C10A2C89C70011FDA8 /* SCPreferencesKeychainPrivate.h in Headers */, 157A88890A470D0F003A4256 /* SCSchemaDefinitionsPrivate.h in Headers */, @@ -3511,13 +3718,8 @@ 159A7523107FEAA400A57EAB /* VPNConfiguration.h in Headers */, 15AAA7F8108E310700C2A607 /* VPNTunnel.h in Headers */, 15AAA7F7108E310700C2A607 /* VPNTunnelPrivate.h in Headers */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - F95B8A5B0B03F81400993BA3 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( + 15C330C4134B92780028E36B /* rb.h in Headers */, + 15C330D1134B95AA0028E36B /* SCNetworkReachabilityInternal.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3574,6 +3776,102 @@ productReference = 15213FFA0E93E9F500DACD2C /* Logger.bundle */; productType = "com.apple.product-type.bundle"; }; + 1528BFDB1357305400691881 /* SCNetworkReachability */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1528BFDF1357305400691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability" */; + buildPhases = ( + 1528BFDC1357305400691881 /* Headers */, + 1528BFDD1357305400691881 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SCNetworkReachability; + productName = PreferencesMonitor; + productReference = 1528BFE21357305400691881 /* libSCNetworkReachability.a */; + productType = "com.apple.product-type.library.static"; + }; + 1528BFE31357309700691881 /* SCNetworkReachability.bundle */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1528BFE51357309700691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability.bundle" */; + buildPhases = ( + 1528BFE41357309700691881 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = SCNetworkReachability.bundle; + productInstallPath = "$(USER_LIBRARY_DIR)/Bundles"; + productName = PreferencesMonitor.bundle; + productReference = 1528BFE81357309800691881 /* SCNetworkReachability.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 1528BFF013573FEE00691881 /* SCNetworkReachability-Embedded */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1528BFF413573FEE00691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability-Embedded" */; + buildPhases = ( + 1528BFF113573FEE00691881 /* Headers */, + 1528BFF213573FEE00691881 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SCNetworkReachability-Embedded"; + productName = PreferencesMonitor; + productReference = 1528BFF713573FEE00691881 /* libSCNetworkReachability.a */; + productType = "com.apple.product-type.library.static"; + }; + 1528BFF813573FF500691881 /* SCNetworkReachability.bundle-Embedded */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1528BFFB13573FF500691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability.bundle-Embedded" */; + buildPhases = ( + 1528BFF913573FF500691881 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SCNetworkReachability.bundle-Embedded"; + productInstallPath = "$(USER_LIBRARY_DIR)/Bundles"; + productName = PreferencesMonitor.bundle; + productReference = 1528BFFE13573FF500691881 /* SCNetworkReachability.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 1528BFFF1357401900691881 /* SCNetworkReachability-EmbeddedOther */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1528C0031357401900691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability-EmbeddedOther" */; + buildPhases = ( + 1528C0001357401900691881 /* Headers */, + 1528C0011357401900691881 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SCNetworkReachability-EmbeddedOther"; + productName = PreferencesMonitor; + productReference = 1528C0061357401900691881 /* libSCNetworkReachability.a */; + productType = "com.apple.product-type.library.static"; + }; + 1528C0071357401D00691881 /* SCNetworkReachability.bundle-EmbeddedOther */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1528C00A1357401D00691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability.bundle-EmbeddedOther" */; + buildPhases = ( + 1528C0081357401D00691881 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "SCNetworkReachability.bundle-EmbeddedOther"; + productInstallPath = "$(USER_LIBRARY_DIR)/Bundles"; + productName = PreferencesMonitor.bundle; + productReference = 1528C00D1357401D00691881 /* SCNetworkReachability.bundle */; + productType = "com.apple.product-type.bundle"; + }; 1547001808455B98006787CE /* SCHelper */ = { isa = PBXNativeTarget; buildConfigurationList = 156EB5E20905594A00EEF749 /* Build configuration list for PBXNativeTarget "SCHelper" */; @@ -3787,22 +4085,6 @@ productReference = 157A852E0D56C91100B6F1A0 /* libLinkConfiguration.a */; productType = "com.apple.product-type.library.static"; }; - 157A85310D56C94F00B6F1A0 /* NetworkIdentification-Embedded */ = { - isa = PBXNativeTarget; - buildConfigurationList = 157A85350D56C94F00B6F1A0 /* Build configuration list for PBXNativeTarget "NetworkIdentification-Embedded" */; - buildPhases = ( - 157A85320D56C94F00B6F1A0 /* Headers */, - 157A85330D56C94F00B6F1A0 /* Sources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "NetworkIdentification-Embedded"; - productName = NetworkIdentification; - productReference = 157A85390D56C94F00B6F1A0 /* libNetworkIdentification.a */; - productType = "com.apple.product-type.library.static"; - }; 157A853C0D56C96F00B6F1A0 /* PreferencesMonitor-Embedded */ = { isa = PBXNativeTarget; buildConfigurationList = 157A85400D56C96F00B6F1A0 /* Build configuration list for PBXNativeTarget "PreferencesMonitor-Embedded" */; @@ -3916,22 +4198,6 @@ productReference = 1559C4530D349A4E0098FD59 /* LinkConfiguration.bundle */; productType = "com.apple.product-type.bundle"; }; - 158317A00CFB8626006F62B9 /* NetworkIdentification.bundle-Embedded */ = { - isa = PBXNativeTarget; - buildConfigurationList = 158317A20CFB8626006F62B9 /* Build configuration list for PBXNativeTarget "NetworkIdentification.bundle-Embedded" */; - buildPhases = ( - 158317A10CFB8626006F62B9 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "NetworkIdentification.bundle-Embedded"; - productInstallPath = "$(USER_LIBRARY_DIR)/Bundles"; - productName = NetworkIdentification.bundle; - productReference = 1559C4550D349A4E0098FD59 /* NetworkIdentification.bundle */; - productType = "com.apple.product-type.bundle"; - }; 158317A80CFB8639006F62B9 /* PreferencesMonitor.bundle-Embedded */ = { isa = PBXNativeTarget; buildConfigurationList = 158317AA0CFB8639006F62B9 /* Build configuration list for PBXNativeTarget "PreferencesMonitor.bundle-Embedded" */; @@ -3982,7 +4248,7 @@ name = "DNSConfiguration-EmbeddedOther"; productInstallPath = /usr/local/lib/system; productName = DNSConfiguration; - productReference = 1583EA10108395BB00A3BC0C /* dnsinfo.dylib */; + productReference = 1583EA10108395BB00A3BC0C /* libdnsinfo.dylib */; productType = "com.apple.product-type.library.dynamic"; }; 1583EA19108395BB00A3BC0C /* SystemConfiguration.framework-EmbeddedOther */ = { @@ -4164,41 +4430,9 @@ ); dependencies = ( ); - name = "Logger.bundle-EmbeddedOther"; - productName = Logger.bundle; - productReference = 1583EB21108395BC00A3BC0C /* Logger.bundle */; - productType = "com.apple.product-type.bundle"; - }; - 1583EB23108395BD00A3BC0C /* NetworkIdentification-EmbeddedOther */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1583EB27108395BD00A3BC0C /* Build configuration list for PBXNativeTarget "NetworkIdentification-EmbeddedOther" */; - buildPhases = ( - 1583EB24108395BD00A3BC0C /* Headers */, - 1583EB25108395BD00A3BC0C /* Sources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "NetworkIdentification-EmbeddedOther"; - productName = NetworkIdentification; - productReference = 1583EB2A108395BD00A3BC0C /* libNetworkIdentification.a */; - productType = "com.apple.product-type.library.static"; - }; - 1583EB2B108395BD00A3BC0C /* NetworkIdentification.bundle-EmbeddedOther */ = { - isa = PBXNativeTarget; - buildConfigurationList = 1583EB2D108395BD00A3BC0C /* Build configuration list for PBXNativeTarget "NetworkIdentification.bundle-EmbeddedOther" */; - buildPhases = ( - 1583EB2C108395BD00A3BC0C /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = "NetworkIdentification.bundle-EmbeddedOther"; - productInstallPath = "$(USER_LIBRARY_DIR)/Bundles"; - productName = NetworkIdentification.bundle; - productReference = 1583EB30108395BD00A3BC0C /* NetworkIdentification.bundle */; + name = "Logger.bundle-EmbeddedOther"; + productName = Logger.bundle; + productReference = 1583EB21108395BC00A3BC0C /* Logger.bundle */; productType = "com.apple.product-type.bundle"; }; 1583EB32108395BD00A3BC0C /* PreferencesMonitor-EmbeddedOther */ = { @@ -4513,45 +4747,16 @@ productReference = 15FD72C90754DA7E001CC321 /* PreferencesMonitor.bundle */; productType = "com.apple.product-type.bundle"; }; - F95B8A5E0B03F81400993BA3 /* NetworkIdentification */ = { - isa = PBXNativeTarget; - buildConfigurationList = F95B8A610B03F83200993BA3 /* Build configuration list for PBXNativeTarget "NetworkIdentification" */; - buildPhases = ( - F95B8A5B0B03F81400993BA3 /* Headers */, - F95B8A5C0B03F81400993BA3 /* Sources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = NetworkIdentification; - productName = NetworkIdentification; - productReference = F95B8A5F0B03F81400993BA3 /* libNetworkIdentification.a */; - productType = "com.apple.product-type.library.static"; - }; - F95B8A6A0B03F9D100993BA3 /* NetworkIdentification.bundle */ = { - isa = PBXNativeTarget; - buildConfigurationList = F95B8A6C0B03F9D100993BA3 /* Build configuration list for PBXNativeTarget "NetworkIdentification.bundle" */; - buildPhases = ( - F95B8A6B0B03F9D100993BA3 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = NetworkIdentification.bundle; - productInstallPath = "$(USER_LIBRARY_DIR)/Bundles"; - productName = NetworkIdentification.bundle; - productReference = F95B8A700B03F9D100993BA3 /* NetworkIdentification.bundle */; - productType = "com.apple.product-type.bundle"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 15CB6A7705C0722B0099E85F /* Project object */ = { isa = PBXProject; + attributes = { + LastUpgradeCheck = 0430; + }; buildConfigurationList = 156EB63E0905594A00EEF749 /* Build configuration list for PBXProject "configd" */; - compatibilityVersion = "Xcode 3.1"; + compatibilityVersion = "Xcode 3.2"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( @@ -4581,10 +4786,10 @@ 159D53F207528C79004F8947 /* LinkConfiguration */, 15FD72B10754DA69001CC321 /* LinkConfiguration.bundle */, 15213FF90E93E9F500DACD2C /* Logger.bundle */, - F95B8A5E0B03F81400993BA3 /* NetworkIdentification */, - F95B8A6A0B03F9D100993BA3 /* NetworkIdentification.bundle */, 159D53F907528C95004F8947 /* PreferencesMonitor */, 15FD72C50754DA7E001CC321 /* PreferencesMonitor.bundle */, + 1528BFDB1357305400691881 /* SCNetworkReachability */, + 1528BFE31357309700691881 /* SCNetworkReachability.bundle */, 155847FA07550D210046C2E9 /* configd_executables */, 159D549F07529FFF004F8947 /* configd */, 1558481207550EC10046C2E9 /* scselect */, @@ -4606,10 +4811,10 @@ 157A85260D56C91100B6F1A0 /* LinkConfiguration-Embedded */, 158317980CFB860C006F62B9 /* LinkConfiguration.bundle-Embedded */, 156CA4790EF853BB00C59A18 /* Logger.bundle-Embedded */, - 157A85310D56C94F00B6F1A0 /* NetworkIdentification-Embedded */, - 158317A00CFB8626006F62B9 /* NetworkIdentification.bundle-Embedded */, 157A853C0D56C96F00B6F1A0 /* PreferencesMonitor-Embedded */, 158317A80CFB8639006F62B9 /* PreferencesMonitor.bundle-Embedded */, + 1528BFF013573FEE00691881 /* SCNetworkReachability-Embedded */, + 1528BFF813573FF500691881 /* SCNetworkReachability.bundle-Embedded */, 158317040CFB7782006F62B9 /* configd_executables-Embedded */, 158317230CFB80A1006F62B9 /* configd-Embedded */, 157433DD0D4A8122002ACA73 /* scselect-Embedded */, @@ -4634,10 +4839,10 @@ 1583EB07108395BC00A3BC0C /* LinkConfiguration-EmbeddedOther */, 1583EB0F108395BC00A3BC0C /* LinkConfiguration.bundle-EmbeddedOther */, 1583EB16108395BC00A3BC0C /* Logger.bundle-EmbeddedOther */, - 1583EB23108395BD00A3BC0C /* NetworkIdentification-EmbeddedOther */, - 1583EB2B108395BD00A3BC0C /* NetworkIdentification.bundle-EmbeddedOther */, 1583EB32108395BD00A3BC0C /* PreferencesMonitor-EmbeddedOther */, 1583EB3A108395BD00A3BC0C /* PreferencesMonitor.bundle-EmbeddedOther */, + 1528BFFF1357401900691881 /* SCNetworkReachability-EmbeddedOther */, + 1528C0071357401D00691881 /* SCNetworkReachability.bundle-EmbeddedOther */, 1583EB41108395BD00A3BC0C /* configd_executables-EmbeddedOther */, 1583EB4B108395BD00A3BC0C /* configd-EmbeddedOther */, 1583EB86108395BE00A3BC0C /* scselect-EmbeddedOther */, @@ -4662,6 +4867,27 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1528BFE41357309700691881 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1528BFF913573FF500691881 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1528C0081357401D00691881 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 156CA4810EF853BB00C59A18 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -4715,13 +4941,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 158317A10CFB8626006F62B9 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 158317A90CFB8639006F62B9 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -4775,13 +4994,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 1583EB2C108395BD00A3BC0C /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; 1583EB3B108395BD00A3BC0C /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -4838,13 +5050,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - F95B8A6B0B03F9D100993BA3 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXResourcesBuildPhase section */ /* Begin PBXShellScriptBuildPhase section */ @@ -5008,6 +5213,30 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1528BFDD1357305400691881 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1528BFEF135733F500691881 /* SCNetworkReachabilityServer_server.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1528BFF213573FEE00691881 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1528BFF313573FEE00691881 /* SCNetworkReachabilityServer_server.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1528C0011357401900691881 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1528C0021357401900691881 /* SCNetworkReachabilityServer_server.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 1547001A08455B98006787CE /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -5064,14 +5293,11 @@ 1572C4E20CFB55B400E2776E /* SCDPrivate.c in Sources */, 1572C4E30CFB55B400E2776E /* SCDPlugin.c in Sources */, 1572C4E40CFB55B400E2776E /* SCDOpen.c in Sources */, - 1572C4E50CFB55B400E2776E /* SCDLock.c in Sources */, - 1572C4E60CFB55B400E2776E /* SCDUnlock.c in Sources */, 1572C4E70CFB55B400E2776E /* SCDList.c in Sources */, 1572C4E80CFB55B400E2776E /* SCDAdd.c in Sources */, 1572C4E90CFB55B400E2776E /* SCDGet.c in Sources */, 1572C4EA0CFB55B400E2776E /* SCDSet.c in Sources */, 1572C4EB0CFB55B400E2776E /* SCDRemove.c in Sources */, - 1572C4EC0CFB55B400E2776E /* SCDTouch.c in Sources */, 1572C4ED0CFB55B400E2776E /* SCDNotify.c in Sources */, 1572C4EE0CFB55B400E2776E /* SCDNotifierSetKeys.c in Sources */, 1572C4EF0CFB55B400E2776E /* SCDNotifierAdd.c in Sources */, @@ -5079,7 +5305,6 @@ 1572C4F10CFB55B400E2776E /* SCDNotifierGetChanges.c in Sources */, 1572C4F20CFB55B400E2776E /* SCDNotifierWait.c in Sources */, 1572C4F30CFB55B400E2776E /* SCDNotifierInformViaCallback.c in Sources */, - 1572C4F40CFB55B400E2776E /* SCDNotifierInformViaMachPort.c in Sources */, 1572C4F50CFB55B400E2776E /* SCDNotifierInformViaFD.c in Sources */, 1572C4F60CFB55B400E2776E /* SCDNotifierInformViaSignal.c in Sources */, 1572C4F70CFB55B400E2776E /* SCDNotifierCancel.c in Sources */, @@ -5125,9 +5350,10 @@ 159A7520107FEAA400A57EAB /* VPNConfiguration.c in Sources */, 15AAA7F6108E310700C2A607 /* VPNTunnel.c in Sources */, 158E595F1107CAE80062081E /* helper.defs in Sources */, - 152691D81129EE8A006BD2D5 /* BondConfiguration.c in Sources */, 152691DB1129EEA6006BD2D5 /* BridgeConfiguration.c in Sources */, 152691DE1129EEC2006BD2D5 /* VLANConfiguration.c in Sources */, + 15C330BD134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */, + 15C330C1134B92780028E36B /* rb.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5167,6 +5393,7 @@ 157A84DE0D56C63900B6F1A0 /* shared_dns_info.defs in Sources */, 157A84DF0D56C63900B6F1A0 /* dnsinfo_copy.c in Sources */, 157A84E00D56C63900B6F1A0 /* dnsinfo_private.c in Sources */, + D661C2F11368BB600030B977 /* network_information.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5174,11 +5401,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 155281020E3E4A0F00C54315 /* ip_plugin.c in Sources */, 157A84FB0D56C7E800B6F1A0 /* dns-configuration.c in Sources */, + 15D48EC10F67061F00B4711E /* dnsinfo_create.c in Sources */, + 155281020E3E4A0F00C54315 /* ip_plugin.c in Sources */, + E4F211D3137B0AB900BBB915 /* network_information_priv.c in Sources */, 1575FD2712CD15C60003D86E /* proxy-configuration.c in Sources */, 157A84FC0D56C7E800B6F1A0 /* set-hostname.c in Sources */, - 15D48EC10F67061F00B4711E /* dnsinfo_create.c in Sources */, 15D48ED40F6707A600B4711E /* shared_dns_info.defs in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -5211,14 +5439,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 157A85330D56C94F00B6F1A0 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 157A85340D56C94F00B6F1A0 /* NetworkIdentification.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 157A853E0D56C96F00B6F1A0 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -5240,14 +5460,12 @@ 158317330CFB80A1006F62B9 /* pattern.c in Sources */, 158317340CFB80A1006F62B9 /* _configopen.c in Sources */, 158317350CFB80A1006F62B9 /* _configclose.c in Sources */, - 158317360CFB80A1006F62B9 /* _configlock.c in Sources */, 158317370CFB80A1006F62B9 /* _configunlock.c in Sources */, 158317380CFB80A1006F62B9 /* _configlist.c in Sources */, 158317390CFB80A1006F62B9 /* _configadd.c in Sources */, 1583173A0CFB80A1006F62B9 /* _configget.c in Sources */, 1583173B0CFB80A1006F62B9 /* _configset.c in Sources */, 1583173C0CFB80A1006F62B9 /* _configremove.c in Sources */, - 1583173D0CFB80A1006F62B9 /* _configtouch.c in Sources */, 1583173E0CFB80A1006F62B9 /* _confignotify.c in Sources */, 1583173F0CFB80A1006F62B9 /* _notifyadd.c in Sources */, 158317400CFB80A1006F62B9 /* _notifyremove.c in Sources */, @@ -5261,6 +5479,7 @@ 158317480CFB80A1006F62B9 /* dnsinfo_private.c in Sources */, 158317490CFB80A1006F62B9 /* dnsinfo_server.c in Sources */, 1583174A0CFB80A1006F62B9 /* shared_dns_info.defs in Sources */, + 15C330E5134BD2AC0028E36B /* SCNetworkReachabilityServer_server.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5280,6 +5499,7 @@ 1583EA09108395BB00A3BC0C /* shared_dns_info.defs in Sources */, 1583EA0A108395BB00A3BC0C /* dnsinfo_copy.c in Sources */, 1583EA0B108395BB00A3BC0C /* dnsinfo_private.c in Sources */, + 151E0CA51378EE3B00C5DA2A /* network_information.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5293,14 +5513,11 @@ 1583EA53108395BB00A3BC0C /* SCDPrivate.c in Sources */, 1583EA54108395BB00A3BC0C /* SCDPlugin.c in Sources */, 1583EA55108395BB00A3BC0C /* SCDOpen.c in Sources */, - 1583EA56108395BB00A3BC0C /* SCDLock.c in Sources */, - 1583EA57108395BB00A3BC0C /* SCDUnlock.c in Sources */, 1583EA58108395BB00A3BC0C /* SCDList.c in Sources */, 1583EA59108395BB00A3BC0C /* SCDAdd.c in Sources */, 1583EA5A108395BB00A3BC0C /* SCDGet.c in Sources */, 1583EA5B108395BB00A3BC0C /* SCDSet.c in Sources */, 1583EA5C108395BB00A3BC0C /* SCDRemove.c in Sources */, - 1583EA5D108395BB00A3BC0C /* SCDTouch.c in Sources */, 1583EA5E108395BB00A3BC0C /* SCDNotify.c in Sources */, 1583EA5F108395BB00A3BC0C /* SCDNotifierSetKeys.c in Sources */, 1583EA60108395BB00A3BC0C /* SCDNotifierAdd.c in Sources */, @@ -5308,7 +5525,6 @@ 1583EA62108395BB00A3BC0C /* SCDNotifierGetChanges.c in Sources */, 1583EA63108395BB00A3BC0C /* SCDNotifierWait.c in Sources */, 1583EA64108395BB00A3BC0C /* SCDNotifierInformViaCallback.c in Sources */, - 1583EA65108395BB00A3BC0C /* SCDNotifierInformViaMachPort.c in Sources */, 1583EA66108395BB00A3BC0C /* SCDNotifierInformViaFD.c in Sources */, 1583EA67108395BB00A3BC0C /* SCDNotifierInformViaSignal.c in Sources */, 1583EA68108395BB00A3BC0C /* SCDNotifierCancel.c in Sources */, @@ -5351,9 +5567,10 @@ 1583EA8E108395BB00A3BC0C /* SCNetworkSignature.c in Sources */, 1583EA8F108395BB00A3BC0C /* CaptiveNetwork.c in Sources */, 158E59601107CAF10062081E /* helper.defs in Sources */, - 152691D91129EE94006BD2D5 /* BondConfiguration.c in Sources */, 152691DD1129EEB1006BD2D5 /* BridgeConfiguration.c in Sources */, 152691E01129EECB006BD2D5 /* VLANConfiguration.c in Sources */, + 15C330BF134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */, + 15C330C3134B92780028E36B /* rb.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5370,11 +5587,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1583EAD0108395BB00A3BC0C /* ip_plugin.c in Sources */, 1583EAD1108395BB00A3BC0C /* dns-configuration.c in Sources */, + 1583EAD3108395BB00A3BC0C /* dnsinfo_create.c in Sources */, + 1583EAD0108395BB00A3BC0C /* ip_plugin.c in Sources */, + E4F211D5137B0AD700BBB915 /* network_information_priv.c in Sources */, 1575FD2B12CD15C60003D86E /* proxy-configuration.c in Sources */, 1583EAD2108395BB00A3BC0C /* set-hostname.c in Sources */, - 1583EAD3108395BB00A3BC0C /* dnsinfo_create.c in Sources */, 1583EAD4108395BB00A3BC0C /* shared_dns_info.defs in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -5415,14 +5633,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 1583EB25108395BD00A3BC0C /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 1583EB26108395BD00A3BC0C /* NetworkIdentification.c in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 1583EB34108395BD00A3BC0C /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -5444,14 +5654,12 @@ 1583EB5B108395BD00A3BC0C /* pattern.c in Sources */, 1583EB5C108395BD00A3BC0C /* _configopen.c in Sources */, 1583EB5D108395BD00A3BC0C /* _configclose.c in Sources */, - 1583EB5E108395BD00A3BC0C /* _configlock.c in Sources */, 1583EB5F108395BD00A3BC0C /* _configunlock.c in Sources */, 1583EB60108395BD00A3BC0C /* _configlist.c in Sources */, 1583EB61108395BD00A3BC0C /* _configadd.c in Sources */, 1583EB62108395BD00A3BC0C /* _configget.c in Sources */, 1583EB63108395BD00A3BC0C /* _configset.c in Sources */, 1583EB64108395BD00A3BC0C /* _configremove.c in Sources */, - 1583EB65108395BD00A3BC0C /* _configtouch.c in Sources */, 1583EB66108395BD00A3BC0C /* _confignotify.c in Sources */, 1583EB67108395BD00A3BC0C /* _notifyadd.c in Sources */, 1583EB68108395BD00A3BC0C /* _notifyremove.c in Sources */, @@ -5465,6 +5673,7 @@ 1583EB70108395BD00A3BC0C /* dnsinfo_private.c in Sources */, 1583EB71108395BD00A3BC0C /* dnsinfo_server.c in Sources */, 1583EB72108395BD00A3BC0C /* shared_dns_info.defs in Sources */, + 15C330E6134BD2BB0028E36B /* SCNetworkReachabilityServer_server.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5521,14 +5730,15 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 159D541707528E05004F8947 /* ip_plugin.c in Sources */, 159D541807528E09004F8947 /* dns-configuration.c in Sources */, + 15D48EBF0F67061600B4711E /* dnsinfo_create.c in Sources */, + 1522FCFB0FA7FE4B00B24128 /* dnsinfo_flatfile.c in Sources */, + 159D541707528E05004F8947 /* ip_plugin.c in Sources */, + E49173E1137C4E4F0000089F /* network_information_priv.c in Sources */, 1575FD2912CD15C60003D86E /* proxy-configuration.c in Sources */, 154361E00752C81800A8EC6C /* set-hostname.c in Sources */, 1572EB7B0A506D3B00D02459 /* smb-configuration.c in Sources */, - 15D48EBF0F67061600B4711E /* dnsinfo_create.c in Sources */, 15D48ED30F67079B00B4711E /* shared_dns_info.defs in Sources */, - 1522FCFB0FA7FE4B00B24128 /* dnsinfo_flatfile.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5561,14 +5771,12 @@ 159D54B207529FFF004F8947 /* pattern.c in Sources */, 159D54B307529FFF004F8947 /* _configopen.c in Sources */, 159D54B407529FFF004F8947 /* _configclose.c in Sources */, - 159D54B507529FFF004F8947 /* _configlock.c in Sources */, 159D54B607529FFF004F8947 /* _configunlock.c in Sources */, 159D54B707529FFF004F8947 /* _configlist.c in Sources */, 159D54B807529FFF004F8947 /* _configadd.c in Sources */, 159D54B907529FFF004F8947 /* _configget.c in Sources */, 159D54BA07529FFF004F8947 /* _configset.c in Sources */, 159D54BB07529FFF004F8947 /* _configremove.c in Sources */, - 159D54BC07529FFF004F8947 /* _configtouch.c in Sources */, 159D54BD07529FFF004F8947 /* _confignotify.c in Sources */, 159D54BE07529FFF004F8947 /* _notifyadd.c in Sources */, 159D54BF07529FFF004F8947 /* _notifyremove.c in Sources */, @@ -5595,14 +5803,11 @@ 15A5A2210D5B94190087BDA0 /* SCDPrivate.c in Sources */, 15A5A2220D5B94190087BDA0 /* SCDPlugin.c in Sources */, 15A5A2230D5B94190087BDA0 /* SCDOpen.c in Sources */, - 15A5A2240D5B94190087BDA0 /* SCDLock.c in Sources */, - 15A5A2250D5B94190087BDA0 /* SCDUnlock.c in Sources */, 15A5A2260D5B94190087BDA0 /* SCDList.c in Sources */, 15A5A2270D5B94190087BDA0 /* SCDAdd.c in Sources */, 15A5A2280D5B94190087BDA0 /* SCDGet.c in Sources */, 15A5A2290D5B94190087BDA0 /* SCDSet.c in Sources */, 15A5A22A0D5B94190087BDA0 /* SCDRemove.c in Sources */, - 15A5A22B0D5B94190087BDA0 /* SCDTouch.c in Sources */, 15A5A22C0D5B94190087BDA0 /* SCDNotify.c in Sources */, 15A5A22D0D5B94190087BDA0 /* SCDNotifierSetKeys.c in Sources */, 15A5A22E0D5B94190087BDA0 /* SCDNotifierAdd.c in Sources */, @@ -5610,7 +5815,6 @@ 15A5A2300D5B94190087BDA0 /* SCDNotifierGetChanges.c in Sources */, 15A5A2310D5B94190087BDA0 /* SCDNotifierWait.c in Sources */, 15A5A2320D5B94190087BDA0 /* SCDNotifierInformViaCallback.c in Sources */, - 15A5A2330D5B94190087BDA0 /* SCDNotifierInformViaMachPort.c in Sources */, 15A5A2340D5B94190087BDA0 /* SCDNotifierInformViaFD.c in Sources */, 15A5A2350D5B94190087BDA0 /* SCDNotifierInformViaSignal.c in Sources */, 15A5A2360D5B94190087BDA0 /* SCDNotifierCancel.c in Sources */, @@ -5657,9 +5861,10 @@ 159A752C107FEAA400A57EAB /* VPNPrivate.c in Sources */, 159A752E107FEAA400A57EAB /* VPNConfiguration.c in Sources */, 158E59611107CAF40062081E /* helper.defs in Sources */, - 152691DA1129EE98006BD2D5 /* BondConfiguration.c in Sources */, 152691DC1129EEAD006BD2D5 /* BridgeConfiguration.c in Sources */, 152691DF1129EEC8006BD2D5 /* VLANConfiguration.c in Sources */, + 15C330BE134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */, + 15C330C2134B92780028E36B /* rb.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5670,6 +5875,7 @@ 15DAD5E5075913CE0084A6ED /* shared_dns_info.defs in Sources */, 15DAD5E6075913CE0084A6ED /* dnsinfo_copy.c in Sources */, 15DAD5E7075913CE0084A6ED /* dnsinfo_private.c in Sources */, + D6986A79136891650091C931 /* network_information.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5682,15 +5888,13 @@ 15DAD66E07591A1A0084A6ED /* SCDKeys.c in Sources */, 15DAD66F07591A1A0084A6ED /* SCDPrivate.c in Sources */, 15DAD67007591A1A0084A6ED /* SCDPlugin.c in Sources */, + 7264C144147319E7004FD76D /* CaptiveNetwork.c in Sources */, 15DAD67107591A1A0084A6ED /* SCDOpen.c in Sources */, - 15DAD67207591A1A0084A6ED /* SCDLock.c in Sources */, - 15DAD67307591A1A0084A6ED /* SCDUnlock.c in Sources */, 15DAD67407591A1A0084A6ED /* SCDList.c in Sources */, 15DAD67507591A1A0084A6ED /* SCDAdd.c in Sources */, 15DAD67607591A1A0084A6ED /* SCDGet.c in Sources */, 15DAD67707591A1A0084A6ED /* SCDSet.c in Sources */, 15DAD67807591A1A0084A6ED /* SCDRemove.c in Sources */, - 15DAD67907591A1A0084A6ED /* SCDTouch.c in Sources */, 15DAD67A07591A1A0084A6ED /* SCDNotify.c in Sources */, 15DAD67B07591A1A0084A6ED /* SCDNotifierSetKeys.c in Sources */, 15DAD67C07591A1A0084A6ED /* SCDNotifierAdd.c in Sources */, @@ -5698,7 +5902,6 @@ 15DAD67E07591A1A0084A6ED /* SCDNotifierGetChanges.c in Sources */, 15DAD67F07591A1A0084A6ED /* SCDNotifierWait.c in Sources */, 15DAD68007591A1A0084A6ED /* SCDNotifierInformViaCallback.c in Sources */, - 15DAD68107591A1A0084A6ED /* SCDNotifierInformViaMachPort.c in Sources */, 15DAD68207591A1A0084A6ED /* SCDNotifierInformViaFD.c in Sources */, 15DAD68307591A1A0084A6ED /* SCDNotifierInformViaSignal.c in Sources */, 15DAD68407591A1A0084A6ED /* SCDNotifierCancel.c in Sources */, @@ -5747,14 +5950,8 @@ 159A7527107FEAA400A57EAB /* VPNConfiguration.c in Sources */, 15AAA7F9108E310700C2A607 /* VPNTunnel.c in Sources */, 158E595E1107CAE40062081E /* helper.defs in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - F95B8A5C0B03F81400993BA3 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - F95B8A690B03F9B500993BA3 /* NetworkIdentification.c in Sources */, + 15C330BC134B92780028E36B /* SCNetworkReachabilityServer_client.c in Sources */, + 15C330C0134B92780028E36B /* rb.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5771,16 +5968,41 @@ target = 151FE2DD0D5B7046000D6DB1 /* configd_base-EmbeddedSimulator */; targetProxy = 151FE3790D5B713C000D6DB1 /* PBXContainerItemProxy */; }; - 1520A386084681350010B584 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 1547001808455B98006787CE /* SCHelper */; - targetProxy = 1520A385084681350010B584 /* PBXContainerItemProxy */; - }; 1521405B0E9400BF00DACD2C /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 15213FF90E93E9F500DACD2C /* Logger.bundle */; targetProxy = 1521405A0E9400BF00DACD2C /* PBXContainerItemProxy */; }; + 1528BFEC135731B800691881 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1528BFDB1357305400691881 /* SCNetworkReachability */; + targetProxy = 1528BFEB135731B800691881 /* PBXContainerItemProxy */; + }; + 1528BFEE135731B800691881 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1528BFE31357309700691881 /* SCNetworkReachability.bundle */; + targetProxy = 1528BFED135731B800691881 /* PBXContainerItemProxy */; + }; + 1528C00F135741C300691881 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1528BFF013573FEE00691881 /* SCNetworkReachability-Embedded */; + targetProxy = 1528C00E135741C300691881 /* PBXContainerItemProxy */; + }; + 1528C011135741C300691881 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1528BFF813573FF500691881 /* SCNetworkReachability.bundle-Embedded */; + targetProxy = 1528C010135741C300691881 /* PBXContainerItemProxy */; + }; + 1528C0131357420300691881 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1528BFFF1357401900691881 /* SCNetworkReachability-EmbeddedOther */; + targetProxy = 1528C0121357420300691881 /* PBXContainerItemProxy */; + }; + 1528C0151357420300691881 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1528C0071357401D00691881 /* SCNetworkReachability.bundle-EmbeddedOther */; + targetProxy = 1528C0141357420300691881 /* PBXContainerItemProxy */; + }; 1558480607550D470046C2E9 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 159D549F07529FFF004F8947 /* configd */; @@ -5836,11 +6058,6 @@ target = 157A85260D56C91100B6F1A0 /* LinkConfiguration-Embedded */; targetProxy = 157A854D0D56CA6F00B6F1A0 /* PBXContainerItemProxy */; }; - 157A85500D56CA8800B6F1A0 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 157A85310D56C94F00B6F1A0 /* NetworkIdentification-Embedded */; - targetProxy = 157A854F0D56CA8800B6F1A0 /* PBXContainerItemProxy */; - }; 157A85520D56CA9E00B6F1A0 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 157A853C0D56C96F00B6F1A0 /* PreferencesMonitor-Embedded */; @@ -5896,11 +6113,6 @@ target = 158317230CFB80A1006F62B9 /* configd-Embedded */; targetProxy = 158317650CFB80D5006F62B9 /* PBXContainerItemProxy */; }; - 158317B30CFB8660006F62B9 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 158317A00CFB8626006F62B9 /* NetworkIdentification.bundle-Embedded */; - targetProxy = 158317B20CFB8660006F62B9 /* PBXContainerItemProxy */; - }; 158317B50CFB8660006F62B9 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 158317980CFB860C006F62B9 /* LinkConfiguration.bundle-Embedded */; @@ -6036,16 +6248,6 @@ target = 1583EB32108395BD00A3BC0C /* PreferencesMonitor-EmbeddedOther */; targetProxy = 15AC5172108396D2004A9ED5 /* PBXContainerItemProxy */; }; - 15AC5175108396D2004A9ED5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 1583EB2B108395BD00A3BC0C /* NetworkIdentification.bundle-EmbeddedOther */; - targetProxy = 15AC5174108396D2004A9ED5 /* PBXContainerItemProxy */; - }; - 15AC5177108396D2004A9ED5 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 1583EB23108395BD00A3BC0C /* NetworkIdentification-EmbeddedOther */; - targetProxy = 15AC5176108396D2004A9ED5 /* PBXContainerItemProxy */; - }; 15AC5179108396D2004A9ED5 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 1583EB16108395BC00A3BC0C /* Logger.bundle-EmbeddedOther */; @@ -6111,15 +6313,10 @@ target = 157A84D80D56C63900B6F1A0 /* DNSConfiguration-Embedded */; targetProxy = 15C64A300F684C8F00D78394 /* PBXContainerItemProxy */; }; - F95B8A770B03FB9100993BA3 /* PBXTargetDependency */ = { + D6DDAC3D147A24BC00A2E902 /* PBXTargetDependency */ = { isa = PBXTargetDependency; - target = F95B8A6A0B03F9D100993BA3 /* NetworkIdentification.bundle */; - targetProxy = F95B8A760B03FB9100993BA3 /* PBXContainerItemProxy */; - }; - F95B8A790B03FB9100993BA3 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = F95B8A5E0B03F81400993BA3 /* NetworkIdentification */; - targetProxy = F95B8A780B03FB9100993BA3 /* PBXContainerItemProxy */; + target = 1547001808455B98006787CE /* SCHelper */; + targetProxy = D6DDAC3C147A24BC00A2E902 /* PBXContainerItemProxy */; }; /* End PBXTargetDependency section */ @@ -6153,6 +6350,7 @@ /* Begin XCBuildConfiguration section */ 151C1CC70CFB487000C5AFD6 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd (Aggregate/Embedded)"; }; @@ -6160,6 +6358,7 @@ }; 151C1CC80CFB487000C5AFD6 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd (Aggregate/Embedded)"; }; @@ -6187,73 +6386,213 @@ FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)"; INFOPLIST_FILE = SCMonitor/Info.plist; INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = /System/Library/UserEventPlugins; - PRODUCT_NAME = SCMonitor; - WRAPPER_EXTENSION = plugin; + INSTALL_PATH = /System/Library/UserEventPlugins; + PRODUCT_NAME = SCMonitor; + WRAPPER_EXTENSION = plugin; + }; + name = Release; + }; + 151F63DD09328A3C0096DCC9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = NO; + INSTALLHDRS_SCRIPT_PHASE = YES; + PRODUCT_NAME = genSCPreferences; + WARNING_CFLAGS = ( + "-Wall", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + }; + name = Debug; + }; + 151F63DE09328A3C0096DCC9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + COPY_PHASE_STRIP = YES; + INSTALLHDRS_SCRIPT_PHASE = YES; + PRODUCT_NAME = genSCPreferences; + WARNING_CFLAGS = ( + "-Wall", + "-Wno-four-char-constants", + "-Wno-unknown-pragmas", + ); + }; + name = Release; + }; + 151FE2E50D5B7046000D6DB1 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 15FD147B0D594FE700F9409C /* IndigoSDK.xcconfig */; + buildSettings = { + PRODUCT_NAME = "configd_base (EmbeddedSimulator)"; + }; + name = Debug; + }; + 151FE2E60D5B7046000D6DB1 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 15FD147B0D594FE700F9409C /* IndigoSDK.xcconfig */; + buildSettings = { + PRODUCT_NAME = "configd_base (EmbeddedSimulator)"; + }; + name = Release; + }; + 15213FFC0E93E9F600DACD2C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = Plugins/Logger/Info.plist; + INSTALL_MODE_FLAG = "a-w,a+rX"; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; + PRODUCT_NAME = Logger; + }; + name = Debug; + }; + 15213FFD0E93E9F600DACD2C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = Plugins/Logger/Info.plist; + INSTALL_MODE_FLAG = "a-w,a+rX"; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; + PRODUCT_NAME = Logger; + }; + name = Release; + }; + 1528BFE01357305400691881 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEBUG_INFORMATION_FORMAT = dwarf; + INSTALL_MODE_FLAG = "a-w,a+rX"; + INSTALL_PATH = /usr/local/lib/SystemConfiguration; + LIBRARY_STYLE = STATIC; + PRODUCT_NAME = SCNetworkReachability; + STRIP_INSTALLED_PRODUCT = NO; + }; + name = Debug; + }; + 1528BFE11357305400691881 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + DEBUG_INFORMATION_FORMAT = dwarf; + INSTALL_MODE_FLAG = "a-w,a+rX"; + INSTALL_PATH = /usr/local/lib/SystemConfiguration; + LIBRARY_STYLE = STATIC; + PRODUCT_NAME = SCNetworkReachability; + STRIP_INSTALLED_PRODUCT = NO; + }; + name = Release; + }; + 1528BFE61357309700691881 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = Plugins/SCNetworkReachability/Info.plist; + INSTALL_MODE_FLAG = "a-w,a+rX"; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; + PRODUCT_NAME = SCNetworkReachability; + }; + name = Debug; + }; + 1528BFE71357309700691881 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + INFOPLIST_FILE = Plugins/SCNetworkReachability/Info.plist; + INSTALL_MODE_FLAG = "a-w,a+rX"; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; + PRODUCT_NAME = SCNetworkReachability; + }; + name = Release; + }; + 1528BFF513573FEE00691881 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; + buildSettings = { + DEBUG_INFORMATION_FORMAT = dwarf; + INSTALL_MODE_FLAG = "a-w,a+rX"; + INSTALL_PATH = /usr/local/lib/SystemConfiguration; + LIBRARY_STYLE = STATIC; + PRODUCT_NAME = SCNetworkReachability; + STRIP_INSTALLED_PRODUCT = NO; + }; + name = Debug; + }; + 1528BFF613573FEE00691881 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; + buildSettings = { + DEBUG_INFORMATION_FORMAT = dwarf; + INSTALL_MODE_FLAG = "a-w,a+rX"; + INSTALL_PATH = /usr/local/lib/SystemConfiguration; + LIBRARY_STYLE = STATIC; + PRODUCT_NAME = SCNetworkReachability; + STRIP_INSTALLED_PRODUCT = NO; }; name = Release; }; - 151F63DD09328A3C0096DCC9 /* Debug */ = { + 1528BFFC13573FF500691881 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { - COPY_PHASE_STRIP = NO; - INSTALLHDRS_SCRIPT_PHASE = YES; - PRODUCT_NAME = genSCPreferences; - WARNING_CFLAGS = ( - "-Wall", - "-Wno-four-char-constants", - "-Wno-unknown-pragmas", - ); + INFOPLIST_FILE = Plugins/SCNetworkReachability/Info.plist; + INSTALL_MODE_FLAG = "a-w,a+rX"; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; + PRODUCT_NAME = SCNetworkReachability; }; name = Debug; }; - 151F63DE09328A3C0096DCC9 /* Release */ = { + 1528BFFD13573FF500691881 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { - COPY_PHASE_STRIP = YES; - INSTALLHDRS_SCRIPT_PHASE = YES; - PRODUCT_NAME = genSCPreferences; - WARNING_CFLAGS = ( - "-Wall", - "-Wno-four-char-constants", - "-Wno-unknown-pragmas", - ); + INFOPLIST_FILE = Plugins/SCNetworkReachability/Info.plist; + INSTALL_MODE_FLAG = "a-w,a+rX"; + INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; + PRODUCT_NAME = SCNetworkReachability; }; name = Release; }; - 151FE2E50D5B7046000D6DB1 /* Debug */ = { + 1528C0041357401900691881 /* Debug */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 15FD147B0D594FE700F9409C /* IndigoSDK.xcconfig */; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { - PRODUCT_NAME = "configd_base (EmbeddedSimulator)"; + DEBUG_INFORMATION_FORMAT = dwarf; + INSTALL_MODE_FLAG = "a-w,a+rX"; + INSTALL_PATH = /usr/local/lib/SystemConfiguration; + LIBRARY_STYLE = STATIC; + PRODUCT_NAME = SCNetworkReachability; + STRIP_INSTALLED_PRODUCT = NO; }; name = Debug; }; - 151FE2E60D5B7046000D6DB1 /* Release */ = { + 1528C0051357401900691881 /* Release */ = { isa = XCBuildConfiguration; - baseConfigurationReference = 15FD147B0D594FE700F9409C /* IndigoSDK.xcconfig */; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { - PRODUCT_NAME = "configd_base (EmbeddedSimulator)"; + DEBUG_INFORMATION_FORMAT = dwarf; + INSTALL_MODE_FLAG = "a-w,a+rX"; + INSTALL_PATH = /usr/local/lib/SystemConfiguration; + LIBRARY_STYLE = STATIC; + PRODUCT_NAME = SCNetworkReachability; + STRIP_INSTALLED_PRODUCT = NO; }; name = Release; }; - 15213FFC0E93E9F600DACD2C /* Debug */ = { + 1528C00B1357401D00691881 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { - INFOPLIST_FILE = Plugins/Logger/Info.plist; + INFOPLIST_FILE = Plugins/SCNetworkReachability/Info.plist; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; - PRODUCT_NAME = Logger; + PRODUCT_NAME = SCNetworkReachability; }; name = Debug; }; - 15213FFD0E93E9F600DACD2C /* Release */ = { + 1528C00C1357401D00691881 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { - INFOPLIST_FILE = Plugins/Logger/Info.plist; + INFOPLIST_FILE = Plugins/SCNetworkReachability/Info.plist; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; - PRODUCT_NAME = Logger; + PRODUCT_NAME = SCNetworkReachability; }; name = Release; }; @@ -6291,6 +6630,7 @@ INSTALLHDRS_COPY_PHASE = YES; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = /usr/lib/system; + LD_DYLIB_INSTALL_NAME = /usr/lib/system/libdnsinfo.dylib; MACH_O_TYPE = mh_dylib; OTHER_CFLAGS_debug = "-O0"; OTHER_LDFLAGS = ( @@ -6317,6 +6657,7 @@ INSTALLHDRS_COPY_PHASE = YES; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = /usr/lib/system; + LD_DYLIB_INSTALL_NAME = /usr/lib/system/libdnsinfo.dylib; MACH_O_TYPE = mh_dylib; OTHER_CFLAGS_debug = "-O0"; OTHER_CFLAGS_normal = ""; @@ -6380,6 +6721,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "-"; FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)"; + GCC_DYNAMIC_NO_PIC = NO; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/SystemConfiguration.framework/Versions/A/Resources"; PRODUCT_NAME = SCHelper; @@ -6391,6 +6733,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "-"; FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)"; + GCC_DYNAMIC_NO_PIC = NO; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/Frameworks/SystemConfiguration.framework/Versions/A/Resources"; PRODUCT_NAME = SCHelper; @@ -6654,6 +6997,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "-"; FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)"; + GCC_DYNAMIC_NO_PIC = NO; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = /usr/libexec; LIBRARY_SEARCH_PATHS = ( @@ -6669,6 +7013,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "-"; FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)"; + GCC_DYNAMIC_NO_PIC = NO; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = /usr/libexec; LIBRARY_SEARCH_PATHS = ( @@ -6684,6 +7029,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "-"; FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)"; + GCC_DYNAMIC_NO_PIC = NO; INSTALL_MODE_FLAG = "a-w,a+rX,u+s"; INSTALL_PATH = /usr/sbin; PRODUCT_NAME = scselect; @@ -6695,6 +7041,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "-"; FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)"; + GCC_DYNAMIC_NO_PIC = NO; INSTALL_MODE_FLAG = "a-w,a+rX,u+s"; INSTALL_PATH = /usr/sbin; PRODUCT_NAME = scselect; @@ -6706,6 +7053,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "-"; FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)"; + GCC_DYNAMIC_NO_PIC = NO; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = /usr/sbin; LIBRARY_SEARCH_PATHS = ( @@ -6721,6 +7069,7 @@ buildSettings = { CODE_SIGN_IDENTITY = "-"; FRAMEWORK_SEARCH_PATHS = "$(SYMROOT)"; + GCC_DYNAMIC_NO_PIC = NO; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = /usr/sbin; LIBRARY_SEARCH_PATHS = ( @@ -6762,9 +7111,12 @@ 156EB63F0905594A00EEF749 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + "ARCHS[sdk=iphoneos*]" = "$(NATIVE_ARCH)"; + "ARCHS[sdk=macosx*]" = "$(ARCHS_STANDARD_32_64_BIT)"; COPY_PHASE_STRIP = NO; CURRENT_PROJECT_VERSION = "$(RC_ProjectSourceVersion)"; DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = "$(RC_ProjectSourceVersion)"; GCC_OPTIMIZATION_LEVEL = 0; @@ -6784,6 +7136,7 @@ "-Wno-four-char-constants", "-Wno-unknown-pragmas", "-Wformat-security", + "-Wcast-align", ); }; name = Debug; @@ -6811,6 +7164,7 @@ "-Wno-four-char-constants", "-Wno-unknown-pragmas", "-Wformat-security", + "-Wcast-align", ); }; name = Release; @@ -6910,6 +7264,7 @@ INSTALLHDRS_COPY_PHASE = YES; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = /usr/lib/system; + LD_DYLIB_INSTALL_NAME = /usr/lib/system/libdnsinfo.dylib; MACH_O_TYPE = mh_dylib; OTHER_CFLAGS_debug = "-O0"; OTHER_CFLAGS_normal = ""; @@ -6939,6 +7294,7 @@ INSTALLHDRS_COPY_PHASE = YES; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = /usr/lib/system; + LD_DYLIB_INSTALL_NAME = /usr/lib/system/libdnsinfo.dylib; MACH_O_TYPE = mh_dylib; OTHER_CFLAGS_debug = "-O0"; OTHER_CFLAGS_normal = ""; @@ -7063,32 +7419,6 @@ }; name = Release; }; - 157A85360D56C94F00B6F1A0 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; - buildSettings = { - DEBUG_INFORMATION_FORMAT = dwarf; - INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = /usr/local/lib/SystemConfiguration; - LIBRARY_STYLE = STATIC; - PRODUCT_NAME = NetworkIdentification; - STRIP_INSTALLED_PRODUCT = NO; - }; - name = Debug; - }; - 157A85370D56C94F00B6F1A0 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; - buildSettings = { - DEBUG_INFORMATION_FORMAT = dwarf; - INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = /usr/local/lib/SystemConfiguration; - LIBRARY_STYLE = STATIC; - PRODUCT_NAME = NetworkIdentification; - STRIP_INSTALLED_PRODUCT = NO; - }; - name = Release; - }; 157A85410D56C96F00B6F1A0 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; @@ -7117,6 +7447,7 @@ }; 158316D90CFB774B006F62B9 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd_base (Embedded)"; }; @@ -7124,6 +7455,7 @@ }; 158316DA0CFB774B006F62B9 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd_base (Embedded)"; }; @@ -7131,6 +7463,7 @@ }; 158317010CFB7761006F62B9 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd_plugins (Embedded)"; }; @@ -7138,6 +7471,7 @@ }; 158317020CFB7761006F62B9 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd_plugins (Embedded)"; }; @@ -7145,6 +7479,7 @@ }; 1583170C0CFB7782006F62B9 /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd_executables (Embedded)"; }; @@ -7152,6 +7487,7 @@ }; 1583170D0CFB7782006F62B9 /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd_executables (Embedded)"; }; @@ -7279,28 +7615,6 @@ }; name = Release; }; - 158317A30CFB8626006F62B9 /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; - buildSettings = { - INFOPLIST_FILE = Plugins/NetworkIdentification/Info.plist; - INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; - PRODUCT_NAME = NetworkIdentification; - }; - name = Debug; - }; - 158317A40CFB8626006F62B9 /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; - buildSettings = { - INFOPLIST_FILE = Plugins/NetworkIdentification/Info.plist; - INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; - PRODUCT_NAME = NetworkIdentification; - }; - name = Release; - }; 158317AB0CFB8639006F62B9 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; @@ -7349,6 +7663,7 @@ }; 1583E9EA1083959E00A3BC0C /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd (Aggregate/EmbeddedOther)"; }; @@ -7356,6 +7671,7 @@ }; 1583E9EB1083959E00A3BC0C /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd (Aggregate/EmbeddedOther)"; }; @@ -7392,6 +7708,7 @@ INSTALLHDRS_COPY_PHASE = YES; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = /usr/lib/system; + LD_DYLIB_INSTALL_NAME = /usr/lib/system/libdnsinfo.dylib; MACH_O_TYPE = mh_dylib; OTHER_CFLAGS_debug = "-O0"; OTHER_CFLAGS_normal = ""; @@ -7401,7 +7718,7 @@ System, ); OTHER_MIGFLAGS = "-DLIBDNSINFO"; - PRODUCT_NAME = dnsinfo; + PRODUCT_NAME = libdnsinfo; STRIP_INSTALLED_PRODUCT_debug = NO; STRIP_INSTALLED_PRODUCT_normal = YES; STRIP_INSTALLED_PRODUCT_profile = NO; @@ -7421,6 +7738,7 @@ INSTALLHDRS_COPY_PHASE = YES; INSTALL_MODE_FLAG = "a-w,a+rX"; INSTALL_PATH = /usr/lib/system; + LD_DYLIB_INSTALL_NAME = /usr/lib/system/libdnsinfo.dylib; MACH_O_TYPE = mh_dylib; OTHER_CFLAGS_debug = "-O0"; OTHER_CFLAGS_normal = ""; @@ -7430,7 +7748,7 @@ System, ); OTHER_MIGFLAGS = "-DLIBDNSINFO"; - PRODUCT_NAME = dnsinfo; + PRODUCT_NAME = libdnsinfo; STRIP_INSTALLED_PRODUCT_debug = NO; STRIP_INSTALLED_PRODUCT_normal = YES; STRIP_INSTALLED_PRODUCT_profile = NO; @@ -7439,6 +7757,7 @@ }; 1583EA17108395BB00A3BC0C /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd_base (EmbeddedOther)"; }; @@ -7446,6 +7765,7 @@ }; 1583EA18108395BB00A3BC0C /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd_base (EmbeddedOther)"; }; @@ -7509,6 +7829,7 @@ }; 1583EAC8108395BB00A3BC0C /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd_plugins (EmbeddedOther)"; }; @@ -7516,6 +7837,7 @@ }; 1583EAC9108395BB00A3BC0C /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd_plugins (EmbeddedOther)"; }; @@ -7737,54 +8059,6 @@ }; name = Release; }; - 1583EB28108395BD00A3BC0C /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; - buildSettings = { - DEBUG_INFORMATION_FORMAT = dwarf; - INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = /usr/local/lib/SystemConfiguration; - LIBRARY_STYLE = STATIC; - PRODUCT_NAME = NetworkIdentification; - STRIP_INSTALLED_PRODUCT = NO; - }; - name = Debug; - }; - 1583EB29108395BD00A3BC0C /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; - buildSettings = { - DEBUG_INFORMATION_FORMAT = dwarf; - INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = /usr/local/lib/SystemConfiguration; - LIBRARY_STYLE = STATIC; - PRODUCT_NAME = NetworkIdentification; - STRIP_INSTALLED_PRODUCT = NO; - }; - name = Release; - }; - 1583EB2E108395BD00A3BC0C /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; - buildSettings = { - INFOPLIST_FILE = Plugins/NetworkIdentification/Info.plist; - INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; - PRODUCT_NAME = NetworkIdentification; - }; - name = Debug; - }; - 1583EB2F108395BD00A3BC0C /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; - buildSettings = { - INFOPLIST_FILE = Plugins/NetworkIdentification/Info.plist; - INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; - PRODUCT_NAME = NetworkIdentification; - }; - name = Release; - }; 1583EB37108395BD00A3BC0C /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; @@ -7835,6 +8109,7 @@ }; 1583EB49108395BD00A3BC0C /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd_executables (EmbeddedOther)"; }; @@ -7842,6 +8117,7 @@ }; 1583EB4A108395BD00A3BC0C /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 15AEABBC0DAD5B3000D1C969 /* AspenSDK.xcconfig */; buildSettings = { PRODUCT_NAME = "configd_executables (EmbeddedOther)"; }; @@ -8023,50 +8299,6 @@ }; name = Release; }; - F95B8A620B03F83200993BA3 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEBUG_INFORMATION_FORMAT = dwarf; - INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = /usr/local/lib/SystemConfiguration; - LIBRARY_STYLE = STATIC; - PRODUCT_NAME = NetworkIdentification; - STRIP_INSTALLED_PRODUCT = NO; - }; - name = Debug; - }; - F95B8A630B03F83200993BA3 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - DEBUG_INFORMATION_FORMAT = dwarf; - INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = /usr/local/lib/SystemConfiguration; - LIBRARY_STYLE = STATIC; - PRODUCT_NAME = NetworkIdentification; - STRIP_INSTALLED_PRODUCT = NO; - }; - name = Release; - }; - F95B8A6D0B03F9D100993BA3 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - INFOPLIST_FILE = Plugins/NetworkIdentification/Info.plist; - INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; - PRODUCT_NAME = NetworkIdentification; - }; - name = Debug; - }; - F95B8A6E0B03F9D100993BA3 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - INFOPLIST_FILE = Plugins/NetworkIdentification/Info.plist; - INSTALL_MODE_FLAG = "a-w,a+rX"; - INSTALL_PATH = "$(SYSTEM_LIBRARY_DIR)/SystemConfiguration"; - PRODUCT_NAME = NetworkIdentification; - }; - name = Release; - }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ @@ -8115,6 +8347,60 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 1528BFDF1357305400691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1528BFE01357305400691881 /* Debug */, + 1528BFE11357305400691881 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1528BFE51357309700691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability.bundle" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1528BFE61357309700691881 /* Debug */, + 1528BFE71357309700691881 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1528BFF413573FEE00691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability-Embedded" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1528BFF513573FEE00691881 /* Debug */, + 1528BFF613573FEE00691881 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1528BFFB13573FF500691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability.bundle-Embedded" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1528BFFC13573FF500691881 /* Debug */, + 1528BFFD13573FF500691881 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1528C0031357401900691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability-EmbeddedOther" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1528C0041357401900691881 /* Debug */, + 1528C0051357401900691881 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1528C00A1357401D00691881 /* Build configuration list for PBXNativeTarget "SCNetworkReachability.bundle-EmbeddedOther" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1528C00B1357401D00691881 /* Debug */, + 1528C00C1357401D00691881 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 156CA4820EF853BB00C59A18 /* Build configuration list for PBXNativeTarget "Logger.bundle-Embedded" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -8385,15 +8671,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 157A85350D56C94F00B6F1A0 /* Build configuration list for PBXNativeTarget "NetworkIdentification-Embedded" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 157A85360D56C94F00B6F1A0 /* Debug */, - 157A85370D56C94F00B6F1A0 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 157A85400D56C96F00B6F1A0 /* Build configuration list for PBXNativeTarget "PreferencesMonitor-Embedded" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -8475,15 +8752,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 158317A20CFB8626006F62B9 /* Build configuration list for PBXNativeTarget "NetworkIdentification.bundle-Embedded" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 158317A30CFB8626006F62B9 /* Debug */, - 158317A40CFB8626006F62B9 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 158317AA0CFB8639006F62B9 /* Build configuration list for PBXNativeTarget "PreferencesMonitor.bundle-Embedded" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -8646,24 +8914,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 1583EB27108395BD00A3BC0C /* Build configuration list for PBXNativeTarget "NetworkIdentification-EmbeddedOther" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1583EB28108395BD00A3BC0C /* Debug */, - 1583EB29108395BD00A3BC0C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 1583EB2D108395BD00A3BC0C /* Build configuration list for PBXNativeTarget "NetworkIdentification.bundle-EmbeddedOther" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1583EB2E108395BD00A3BC0C /* Debug */, - 1583EB2F108395BD00A3BC0C /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 1583EB36108395BD00A3BC0C /* Build configuration list for PBXNativeTarget "PreferencesMonitor-EmbeddedOther" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -8754,24 +9004,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - F95B8A610B03F83200993BA3 /* Build configuration list for PBXNativeTarget "NetworkIdentification" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - F95B8A620B03F83200993BA3 /* Debug */, - F95B8A630B03F83200993BA3 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - F95B8A6C0B03F9D100993BA3 /* Build configuration list for PBXNativeTarget "NetworkIdentification.bundle" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - F95B8A6D0B03F9D100993BA3 /* Debug */, - F95B8A6E0B03F9D100993BA3 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = 15CB6A7705C0722B0099E85F /* Project object */; diff --git a/dnsinfo/dnsinfo.h b/dnsinfo/dnsinfo.h index 8700305..020e51a 100644 --- a/dnsinfo/dnsinfo.h +++ b/dnsinfo/dnsinfo.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (c) 2004-2006, 2008, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -35,7 +35,7 @@ #include #include -#define DNSINFO_VERSION 20091104 +#define DNSINFO_VERSION 20111104 #define DEFAULT_SEARCH_ORDER 200000 /* search order for the "default" resolver domain name */ @@ -72,12 +72,13 @@ typedef struct { DNS_VAR(uint32_t, search_order); /* search_order */ DNS_VAR(uint32_t, if_index); DNS_VAR(uint32_t, flags); - DNS_VAR(uint32_t, reserved[6]); + DNS_VAR(uint32_t, reach_flags); /* SCNetworkReachabilityFlags */ + DNS_VAR(uint32_t, reserved[5]); } dns_resolver_t; #pragma pack() -#define DNS_RESOLVER_FLAGS_SCOPED 1 +#define DNS_RESOLVER_FLAGS_SCOPED 1 /* configuration is for scoped questions */ #pragma pack(4) @@ -105,6 +106,10 @@ dns_configuration_copy () __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0); void dns_configuration_free (dns_config_t *config) __OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0); +void +_dns_configuration_ack (dns_config_t *config, + const char *bundle_id) __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0); + __END_DECLS #endif /* __DNSINFO_H__ */ diff --git a/dnsinfo/dnsinfo_copy.c b/dnsinfo/dnsinfo_copy.c index 1a2ea6f..26b1e9d 100644 --- a/dnsinfo/dnsinfo_copy.c +++ b/dnsinfo/dnsinfo_copy.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2006, 2008-2010 Apple Inc. All rights reserved. + * Copyright (c) 2004, 2006, 2008-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -37,12 +37,19 @@ #include "dnsinfo.h" #include "dnsinfo_private.h" #include "shared_dns_info.h" +#include "network_information_priv.h" static pthread_once_t _dns_initialized = PTHREAD_ONCE_INIT; static pthread_mutex_t _dns_lock = PTHREAD_MUTEX_INITIALIZER; static mach_port_t _dns_server = MACH_PORT_NULL; +enum { + get_dns_info = 1, + get_nwi_state = 2, +}; + +typedef uint32_t getflags; static void __dns_fork_handler() @@ -83,14 +90,10 @@ add_list(void **padding, uint32_t *n_padding, int32_t count, int32_t size, void #define DNS_CONFIG_BUF_MAX 1024*1024 -static _dns_config_buf_t * -copy_dns_info() -{ - uint8_t *buf = NULL; - dnsDataOut_t dataRef = NULL; - mach_msg_type_number_t dataLen = 0; - mach_port_t server; - kern_return_t status; +static kern_return_t +_dns_server_copy(void* dataRef, mach_msg_type_number_t* dataLen, getflags flags){ + mach_port_t server; + kern_return_t status = KERN_FAILURE; // initialize runtime pthread_once(&_dns_initialized, __dns_initialize); @@ -99,7 +102,11 @@ copy_dns_info() server = _dns_server; while (TRUE) { if (server != MACH_PORT_NULL) { - status = shared_dns_infoGet(server, &dataRef, &dataLen); + if (flags == get_dns_info) { + status = shared_dns_infoGet(server, dataRef, dataLen); + } else { + status = shared_nwi_stateGet(server, dataRef, dataLen); + } if (status == KERN_SUCCESS) { break; } @@ -135,10 +142,62 @@ copy_dns_info() } } + return status; +} + + +__private_extern__ +nwi_state* +_nwi_state_copy() { + dnsDataOut_t dataRef = NULL; + mach_msg_type_number_t dataLen = 0; + kern_return_t status; + nwi_state* state = NULL; + + status = _dns_server_copy(&dataRef, &dataLen, get_nwi_state); + if (status != KERN_SUCCESS) { + return NULL; + } + + if (dataRef != NULL) { + state = malloc(dataLen); + if (state == NULL) { + vm_deallocate(mach_task_self(), (vm_address_t)dataRef, + dataLen); + return NULL; + } + memcpy((void*) state, (void*) dataRef, dataLen); + state->ref = 0; + status = vm_deallocate(mach_task_self(), (vm_address_t)dataRef, dataLen); + if (status != KERN_SUCCESS) { + mach_error("vm_deallocate():", status); + free(state); + return NULL; + } + } + + return state; +} + + +static _dns_config_buf_t * +copy_dns_info() +{ + uint8_t *buf = NULL; + dnsDataOut_t dataRef = NULL; + mach_msg_type_number_t dataLen = 0; + kern_return_t status; + + status = _dns_server_copy(&dataRef, &dataLen, get_dns_info); + if (status != KERN_SUCCESS) { + return NULL; + } + if (dataRef != NULL) { if ((dataLen >= sizeof(_dns_config_buf_t)) && (dataLen <= DNS_CONFIG_BUF_MAX)) { - _dns_config_buf_t *config = (_dns_config_buf_t *)dataRef; - uint32_t n_padding = ntohl(config->n_padding); + /* ALIGN: cast okay since _dns_config_buf_t is int aligned */ + _dns_config_buf_t *config = (_dns_config_buf_t *)(void *)dataRef; + uint32_t n_padding = ntohl(config->n_padding); if (n_padding <= (DNS_CONFIG_BUF_MAX - dataLen)) { uint32_t len; @@ -158,7 +217,8 @@ copy_dns_info() } } - return (_dns_config_buf_t *)buf; + /* ALIGN: buf malloc'ed, should be aligned >8 bytes */ + return (_dns_config_buf_t *)(void *)buf; } @@ -237,10 +297,15 @@ expand_resolver(_dns_resolver_buf_t *buf, uint32_t n_buf, void **padding, uint32 resolver->flags = ntohl(resolver->flags); + // initialize SCNetworkReachability flags + + resolver->reach_flags = ntohl(resolver->reach_flags); + // process resolver buffer "attribute" data n_attribute = n_buf - sizeof(_dns_resolver_buf_t); - attribute = (dns_attribute_t *)&buf->attribute[0]; + /* ALIGN: alignment not assumed, using accessors */ + attribute = (dns_attribute_t *)(void *)&buf->attribute[0]; if (n_attribute != ntohl(buf->n_attribute)) { goto error; } @@ -262,7 +327,7 @@ expand_resolver(_dns_resolver_buf_t *buf, uint32_t n_buf, void **padding, uint32 break; case RESOLVER_ATTRIBUTE_SORTADDR : - resolver->sortaddr[n_sortaddr++] = (dns_sortaddr_t *)&attribute->attribute[0]; + resolver->sortaddr[n_sortaddr++] = (dns_sortaddr_t *)(void *)&attribute->attribute[0]; break; case RESOLVER_ATTRIBUTE_OPTIONS : @@ -330,7 +395,7 @@ expand_config(_dns_config_buf_t *buf) // process configuration buffer "attribute" data n_attribute = ntohl(buf->n_attribute); - attribute = (dns_attribute_t *)&buf->attribute[0]; + attribute = (dns_attribute_t *)(void *)&buf->attribute[0]; while (n_attribute >= sizeof(dns_attribute_t)) { uint32_t attribute_length = ntohl(attribute->length); @@ -343,7 +408,7 @@ expand_config(_dns_config_buf_t *buf) // expand resolver buffer - resolver = expand_resolver((_dns_resolver_buf_t *)&attribute->attribute[0], + resolver = expand_resolver((_dns_resolver_buf_t *)(void *)&attribute->attribute[0], attribute_length - sizeof(dns_attribute_t), &padding, &n_padding); @@ -431,6 +496,13 @@ dns_configuration_free(dns_config_t *config) return; } + +void +_dns_configuration_ack(dns_config_t *config, const char *bundle_id) +{ + return; +} + #ifdef MAIN int diff --git a/dnsinfo/dnsinfo_create.c b/dnsinfo/dnsinfo_create.c index 820797a..db361d5 100644 --- a/dnsinfo/dnsinfo_create.c +++ b/dnsinfo/dnsinfo_create.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2006, 2009 Apple Inc. All rights reserved. + * Copyright (c) 2004, 2006, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -25,10 +25,12 @@ #include #include #include +#include #include "dnsinfo_create.h" #include "dnsinfo_private.h" #include "shared_dns_info.h" +#include "network_information_priv.h" #define ROUNDUP(a, size) \ @@ -92,7 +94,8 @@ config_add_attribute(dns_create_config_t *_config, // add attribute [header] - header = (dns_attribute_t *)&config->attribute[oldLen]; + /* ALIGN: _dns_config_buf_t is int aligned */ + header = (dns_attribute_t *)(void *)&config->attribute[oldLen]; header->type = htonl(attribute_type); header->length = htonl(newLen); @@ -151,6 +154,61 @@ _dns_configuration_add_resolver(dns_create_config_t *_config, return; } +_Bool +_nwi_state_store(nwi_state* state) +{ + mach_port_t server; + kern_return_t status; + dnsDataOut_t dataRef = (dnsDataOut_t) state; + mach_msg_type_number_t dataLen = state->size; + + server = _dns_configuration_server_port(); + if (server == MACH_PORT_NULL) { + return FALSE; + } + + status = shared_nwi_stateSet(server, dataRef, dataLen); + + (void) mach_port_deallocate(mach_task_self(), server); + + if (status != KERN_SUCCESS) { + return FALSE; + } + + return TRUE; +} + + +void +_dns_configuration_signature(dns_create_config_t *_config, + unsigned char *signature, + size_t signature_len) +{ + bzero(signature, signature_len); + + if (_config != NULL) { + _dns_config_buf_t *config = (_dns_config_buf_t *)*_config; + + if (config != NULL) { + CC_SHA1_CTX ctx; + unsigned char *sha1; + unsigned char sha1_buf[CC_SHA1_DIGEST_LENGTH]; + + sha1 = (signature_len >= CC_SHA1_DIGEST_LENGTH) ? signature : sha1_buf; + CC_SHA1_Init(&ctx); + CC_SHA1_Update(&ctx, + config, + sizeof(_dns_config_buf_t) + ntohl(config->n_attribute)); + CC_SHA1_Final(sha1, &ctx); + if (sha1 != signature) { + bcopy(sha1, signature, signature_len); + } + } + } + + return; +} + _Bool _dns_configuration_store(dns_create_config_t *_config) @@ -238,7 +296,8 @@ _dns_resolver_add_attribute(dns_create_resolver_t *_resolver, // add attribute [header] - header = (dns_attribute_t *)&resolver->attribute[oldLen]; + /* ALIGN: _dns_config_buf_t is int aligned */ + header = (dns_attribute_t *)(void *)&resolver->attribute[oldLen]; header->type = htonl(attribute_type); header->length = htonl(newLen); @@ -276,6 +335,17 @@ _dns_resolver_add_search(dns_create_resolver_t *_resolver, const char *search) } +void +_dns_resolver_add_sortaddr(dns_create_resolver_t *_resolver, dns_sortaddr_t *sortaddr) +{ + _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver; + + resolver->resolver.n_sortaddr = htonl(ntohl(resolver->resolver.n_sortaddr) + 1); + _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_SORTADDR, sizeof(dns_sortaddr_t), (void *)sortaddr); + return; +} + + void _dns_resolver_set_domain(dns_create_resolver_t *_resolver, const char *domain) { @@ -333,12 +403,11 @@ _dns_resolver_set_port(dns_create_resolver_t *_resolver, uint16_t port) void -_dns_resolver_add_sortaddr(dns_create_resolver_t *_resolver, dns_sortaddr_t *sortaddr) +_dns_resolver_set_reach_flags(dns_create_resolver_t *_resolver, uint32_t reach_flags) { _dns_resolver_buf_t *resolver = (_dns_resolver_buf_t *)*_resolver; - resolver->resolver.n_sortaddr = htonl(ntohl(resolver->resolver.n_sortaddr) + 1); - _dns_resolver_add_attribute(_resolver, RESOLVER_ATTRIBUTE_SORTADDR, sizeof(dns_sortaddr_t), (void *)sortaddr); + resolver->resolver.reach_flags = htonl(reach_flags); return; } diff --git a/dnsinfo/dnsinfo_create.h b/dnsinfo/dnsinfo_create.h index 5ad526d..89c71b5 100644 --- a/dnsinfo/dnsinfo_create.h +++ b/dnsinfo/dnsinfo_create.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2006, 2008, 2009 Apple Inc. All rights reserved. + * Copyright (c) 2004-2006, 2008, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -66,6 +66,12 @@ void _dns_configuration_add_resolver (dns_create_config_t *_config, dns_create_resolver_t _resolver) /*__OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0)*/; +__private_extern__ +void +_dns_configuration_signature (dns_create_config_t *_config, + unsigned char *signature, + size_t signature_len) /*__OSX_AVAILABLE_STARTING(__MAC_10_7+,__IPHONE_5_0)*/; // signature_len >= CC_SHA1_DIGEST_LENGTH + __private_extern__ _Bool _dns_configuration_store (dns_create_config_t *_config) /*__OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0)*/; @@ -126,6 +132,11 @@ void _dns_resolver_set_port (dns_create_resolver_t *_resolver, uint16_t port) /*__OSX_AVAILABLE_STARTING(__MAC_10_4,__IPHONE_2_0)*/; // host byte order +__private_extern__ +void +_dns_resolver_set_reach_flags (dns_create_resolver_t *_resolver, + uint32_t reach_flags) /*__OSX_AVAILABLE_STARTING(__MAC_10_7,__IPHONE_5_0)*/; + __private_extern__ void _dns_resolver_set_timeout (dns_create_resolver_t *_resolver, diff --git a/dnsinfo/dnsinfo_flatfile.c b/dnsinfo/dnsinfo_flatfile.c index 664fcb4..e052d2e 100644 --- a/dnsinfo/dnsinfo_flatfile.c +++ b/dnsinfo/dnsinfo_flatfile.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009 Apple Inc. All rights reserved. + * Copyright (c) 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -143,10 +143,12 @@ _dnsinfo_parse_nameserver(char *token) switch (sa->sa_family) { case AF_INET : - ((struct sockaddr_in *)sa)->sin_port = port; + /* ALIGN: cast ok, sockaddr was malloc'd */ + ((struct sockaddr_in *)(void *)sa)->sin_port = port; break; case AF_INET6 : - ((struct sockaddr_in6 *)sa)->sin6_port = port; + /* ALIGN: cast ok, sockaddr was malloc'd */ + ((struct sockaddr_in6 *)(void *)sa)->sin6_port = port; break; } } @@ -182,7 +184,8 @@ _dnsinfo_parse_sortaddr(char *token) // if not AF_INET goto done; } else { - addr = ((struct sockaddr_in *)sa)->sin_addr; + /* ALIGN: cast ok, sockaddr was malloc'd */ + addr = ((struct sockaddr_in *)(void *)sa)->sin_addr; free(sa); sa = NULL; } @@ -196,7 +199,8 @@ _dnsinfo_parse_sortaddr(char *token) // if mask not AF_INET goto done; } else { - mask = ((struct sockaddr_in *)sa)->sin_addr; + /* ALIGN: cast ok, sockaddr was malloc'd */ + mask = ((struct sockaddr_in *)(void *)sa)->sin_addr; free(sa); sa = NULL; } diff --git a/dnsinfo/dnsinfo_server.c b/dnsinfo/dnsinfo_server.c index 9613311..1d8bcac 100644 --- a/dnsinfo/dnsinfo_server.c +++ b/dnsinfo/dnsinfo_server.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2008 Apple Inc. All rights reserved. + * Copyright (c) 2004-2008, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -43,8 +43,10 @@ #include "dnsinfo_server.h" #include "dnsinfo_private.h" +#include -static CFDataRef shared_dns_info = NULL; +static CFDataRef shared_dns_info = NULL; +static CFDataRef shared_nwi_state = NULL; __private_extern__ kern_return_t @@ -54,7 +56,12 @@ _shared_dns_infoGet(mach_port_t server, dnsDataOut_t *dataRef, mach_msg_type_num *dataLen = 0; if (shared_dns_info != NULL) { - if (!_SCSerializeData(shared_dns_info, (void **)dataRef, (CFIndex *)dataLen)) { + CFIndex len; + Boolean ok; + + ok = _SCSerializeData(shared_dns_info, (void **)dataRef, &len); + *dataLen = len; + if (!ok) { return KERN_FAILURE; } } @@ -63,19 +70,21 @@ _shared_dns_infoGet(mach_port_t server, dnsDataOut_t *dataRef, mach_msg_type_num } -__private_extern__ +static kern_return_t -_shared_dns_infoSet(mach_port_t server, - dnsData_t dataRef, - mach_msg_type_number_t dataLen, - audit_token_t audit_token) +_shared_infoSet_common(mach_port_t server, + dnsData_t dataRef, + mach_msg_type_number_t dataLen, + audit_token_t audit_token, + CFDataRef* cache, + const char* notify_key) { uid_t euid = 0; - CFDataRef new_dns_info = NULL; - const char *notify_key; + CFDataRef new_info = NULL; + CFDataRef n_cache = *cache; if ((dataRef != NULL) && (dataLen > 0)) { - if (!_SCUnserializeData(&new_dns_info, (void *)dataRef, dataLen)) { + if (!_SCUnserializeData(&new_info, (void *)dataRef, dataLen)) { goto error; } } @@ -93,17 +102,16 @@ _shared_dns_infoSet(mach_port_t server, goto error; } - if ((shared_dns_info != NULL) && - (new_dns_info != NULL) && - CFEqual(shared_dns_info, new_dns_info)) { - CFRelease(new_dns_info); + if ((n_cache != NULL) && + (new_info != NULL) && + CFEqual(n_cache, new_info)) { + CFRelease(new_info); return KERN_SUCCESS; } - if (shared_dns_info != NULL) CFRelease(shared_dns_info); - shared_dns_info = new_dns_info; + if (n_cache != NULL) CFRelease(n_cache); + *cache = new_info; - notify_key = _dns_configuration_notify_key(); if (notify_key != NULL) { uint32_t status; @@ -118,6 +126,62 @@ _shared_dns_infoSet(mach_port_t server, error : - if (new_dns_info != NULL) CFRelease(new_dns_info); + if (new_info != NULL) CFRelease(new_info); return KERN_FAILURE; } + + +__private_extern__ +kern_return_t +_shared_dns_infoSet(mach_port_t server, + dnsData_t dataRef, + mach_msg_type_number_t dataLen, + audit_token_t audit_token) +{ + const char *notify_key; + + notify_key = _dns_configuration_notify_key(); + return _shared_infoSet_common(server, dataRef, dataLen, + audit_token, &shared_dns_info, + notify_key); +} + + +__private_extern__ +kern_return_t +_shared_nwi_stateGet(mach_port_t server, dnsDataOut_t *dataRef, mach_msg_type_number_t *dataLen) +{ + *dataRef = NULL; + *dataLen = 0; + + if (shared_nwi_state != NULL) { + CFIndex len; + Boolean ok; + + ok = _SCSerializeData(shared_nwi_state, (void **)dataRef, &len); + *dataLen = len; + if (!ok) { + return KERN_FAILURE; + } + } + + return KERN_SUCCESS; + +} + + +__private_extern__ +kern_return_t +_shared_nwi_stateSet(mach_port_t server, + dnsData_t dataRef, + mach_msg_type_number_t dataLen, + audit_token_t audit_token) +{ + const char *notify_key; + + notify_key = nwi_state_get_notify_key(); + + return _shared_infoSet_common(server, dataRef, dataLen, + audit_token, &shared_nwi_state, + notify_key); +} diff --git a/dnsinfo/dnsinfo_server.h b/dnsinfo/dnsinfo_server.h index 44350a8..7483a3e 100644 --- a/dnsinfo/dnsinfo_server.h +++ b/dnsinfo/dnsinfo_server.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2005, 2009 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004, 2005, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -43,6 +43,17 @@ kern_return_t _shared_dns_infoSet (mach_port_t server, mach_msg_type_number_t dataLen, audit_token_t audit_token); +__private_extern__ +kern_return_t _shared_nwi_stateGet (mach_port_t server, + dnsDataOut_t *dataRef, + mach_msg_type_number_t *dataLen); + +__private_extern__ +kern_return_t _shared_nwi_stateSet (mach_port_t server, + dnsData_t dataRef, + mach_msg_type_number_t dataLen, + audit_token_t audit_token); + __END_DECLS #endif /* !_S_DNSINFO_SERVER_H */ diff --git a/dnsinfo/shared_dns_info.defs b/dnsinfo/shared_dns_info.defs index bbb1e84..4a24c43 100644 --- a/dnsinfo/shared_dns_info.defs +++ b/dnsinfo/shared_dns_info.defs @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2005, 2009 Apple Inc. All rights reserved. + * Copyright (c) 2004, 2005, 2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -61,4 +61,16 @@ routine shared_dns_infoSet ( server : mach_port_t; ServerAuditToken audit_token : audit_token_t); #else // LIBDNSINFO_A skip; /* shared_dns_infoSet */ -#endif LIBDNSINFO_A +#endif // LIBDNSINFO_A + +routine shared_nwi_stateGet ( server : mach_port_t; + out data : dnsDataOut, dealloc); + +#ifndef LIBDNSINFO_A +routine shared_nwi_stateSet ( server : mach_port_t; + data : dnsData; + ServerAuditToken audit_token : audit_token_t); +#else // LIBDNSINFO_A + skip; /* shared_nwi_stateSet */ +#endif // LIBDNSINFO_A + diff --git a/get-mobility-info b/get-mobility-info index adc3d6a..818391c 100755 --- a/get-mobility-info +++ b/get-mobility-info @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (c) 2004-2011 Apple Inc. +# Copyright (c) 2004-2012 Apple Inc. # # get-mobility-info # @@ -46,6 +46,10 @@ fi cd "${WORKDIR}" +echo "" +echo "Please wait, collecting information and statistics" +echo "" + # # processes # @@ -102,6 +106,29 @@ fi ioreg -i -l -w 0 > ioreg 2>&1 ioreg -i -l -p IODeviceTree -w 0 >> ioreg 2>&1 +# +# Power Management info +# +echo "#" > pmset +echo "# pmset -g" >> pmset +echo "#" >> pmset +pmset -g >> pmset 2>&1 + +echo "#" >> pmset +echo "# pmset -g ps" >> pmset +echo "#" >> pmset +pmset -g ps >> pmset 2>&1 + +echo "#" >> pmset +echo "# pmset -g assertions" >> pmset +echo "#" >> pmset +pmset -g assertions >> pmset 2>&1 + +echo "#" >> pmset +echo "# pmset -g log" >> pmset +echo "#" >> pmset +pmset -g log | tail -n 25000 >> pmset 2>&1 + # # Host name # @@ -129,7 +156,12 @@ fi # # Proxy configuration # -scutil --proxy > proxy-configuration 2>&1 +scutil -d -v --proxy > proxy-configuration 2>&1 + +# +# Network information +# +scutil --nwi > network-information 2>&1 # # System / network preferences @@ -139,7 +171,6 @@ for f in \ /Library/Preferences/SystemConfiguration/com.apple.PowerManagement.plist \ /Library/Preferences/SystemConfiguration/com.apple.airport.preferences.plist \ /Library/Preferences/SystemConfiguration/com.apple.nat.plist \ - /Library/Preferences/SystemConfiguration/com.apple.network.identification.plist \ /Library/Preferences/SystemConfiguration/com.apple.smb.server.plist \ /Library/Preferences/SystemConfiguration/com.apple.wifi.plist \ /Library/Preferences/SystemConfiguration/preferences.plist \ @@ -159,20 +190,16 @@ done # if [ -e /etc/bootpd.plist ]; then cat /etc/bootpd.plist > bootpd.plist 2>&1 - cat /etc/com.apple.named.proxy.conf > com.apple.named.proxy.conf 2>&1 + cat /etc/com.apple.named.proxy.conf > com.apple.named.proxy.conf 2>/dev/null elif [ -e /Library/Preferences/SystemConfiguration/bootpd.plist ]; then cat /Library/Preferences/SystemConfiguration/bootpd.plist > bootpd.plist 2>&1 - cat /Library/Preferences/SystemConfiguration/com.apple.named.proxy.conf > com.apple.named.proxy.conf 2>&1 + cat /Library/Preferences/SystemConfiguration/com.apple.named.proxy.conf > com.apple.named.proxy.conf 2>/dev/null fi # # configd's cache # -${PRIV} scutil -p <<_END_OF_INPUT -open -snapshot -quit -_END_OF_INPUT +${PRIV} scutil -p --snapshot if [ -f /var/tmp/configd-store.plist ]; then cat /var/tmp/configd-store.plist > configd-store.plist 2>&1 fi @@ -185,26 +212,14 @@ fi if [ -f /var/tmp/configd-state ]; then cat /var/tmp/configd-state > configd-state 2>&1 fi - -# -# check configd's executable -# -if [ -x /usr/bin/codesign ]; then - echo "#" >> configd-state - echo "# codesign --verbose --display --entitlements - /usr/libexec/configd" >> configd-state - echo "#" >> configd-state - /usr/bin/codesign --verbose --display --entitlements - /usr/libexec/configd >> configd-state 2>&1 - - echo "#" >> configd-state - echo "# codesign --verbose --verify /usr/libexec/configd" >> configd-state - echo "#" >> configd-state - /usr/bin/codesign --verbose --verify /usr/libexec/configd >> configd-state 2>&1 +if [ -f /var/tmp/configd-reachability ]; then + cat /var/tmp/configd-reachability > configd-reachability 2>&1 fi # # network reachability # -scutil -d -v -r www.apple.com > reachability-info 2>&1 +scutil -d -v -r www.apple.com "" no-server > reachability-info 2>&1 if [ -x /usr/bin/dig -a -f /etc/resolv.conf ]; then /usr/bin/dig -t any -c any www.apple.com > dig-results 2>/dev/null fi @@ -215,10 +230,11 @@ fi mount > mounted-filesystems 2>&1 # -# mDNSResponder info +# mDNSResponder, networkd info # if [ -x /usr/bin/killall ]; then ${PRIV} killall -INFO mDNSResponder + ${PRIV} killall -INFO networkd # and wait a short amount of time for mDNSResponder # to actually log the requested information @@ -344,6 +360,11 @@ echo "# netstat -i -n -d" >> network-statistics echo "#" >> network-statistics netstat -i -n -d >> network-statistics 2>&1 +echo "#" >> network-statistics +echo "# netstat -g -n -s" >> network-statistics +echo "#" >> network-statistics +netstat -g -n -s >> network-statistics 2>&1 + if [ -x /usr/sbin/ndp ]; then echo "#" >> network-statistics echo "# ndp -n -a" >> network-statistics @@ -359,6 +380,14 @@ if [ -x /usr/sbin/ndp ]; then echo "# ndp -n -r" >> network-statistics echo "#" >> network-statistics ndp -n -r >> network-statistics 2>&1 + + for if in `ifconfig -l` + do + echo "#" >> network-statistics + echo "# ndp -i ${if}" >> network-statistics + echo "#" >> network-statistics + ndp -i ${if} >> network-statistics 2>&1 + done fi if [ -x /sbin/ipfw ]; then @@ -368,6 +397,13 @@ if [ -x /sbin/ipfw ]; then ${PRIV} ipfw -at show >> network-statistics 2>&1 fi +if [ -x /sbin/ip6fw ]; then + echo "#" >> network-statistics + echo "# ip6fw -at show" >> network-statistics + echo "#" >> network-statistics + ${PRIV} ip6fw -at show >> network-statistics 2>&1 +fi + if [ -x /sbin/pfctl ]; then echo "#" > pf echo "# pfctl -s all" >> pf @@ -378,7 +414,7 @@ if [ -x /sbin/pfctl ]; then echo "# pfctl -s References" >> pf echo "#" >> pf ${PRIV} pfctl -s References >> pf 2>&1 - for ANCHOR in `pfctl -s Anchors 2>/dev/null` + for ANCHOR in `${PRIV} pfctl -s Anchors -v 2>/dev/null` do echo "==============================" >> pf echo "#" >> pf @@ -427,10 +463,9 @@ echo "#" > ipsec echo "# setkey -D" >> ipsec echo "#" >> ipsec ${PRIV} setkey -D \ -| perl -nle ' +| perl -M'Digest::MD5 qw(md5_hex)' -l -n -e ' if (/^(\s+[AE]:\s+\S+\s+)"?(.*)"?\s*$/) { - chop($sha1=`echo "$2" | openssl sha1`); - printf "%s[SHA-1:%s]\n", $1, $sha1; + printf "%s[MD5:%s]%s\n", $1, md5_hex($2 . "\n"), $3; } else { printf "%s\n", $_; } @@ -453,10 +488,9 @@ do echo "# ${CF}" >> ipsec echo "#" >> ipsec ${PRIV} cat ${CF} \ - | perl -nle ' + | perl -M'Digest::MD5 qw(md5_hex)' -l -n -e ' if (/^(\s+shared_secret\s+use\s+)"?([^\s;"]+)"?(.*)/) { - chop($sha1=`echo "$2" | openssl sha1`); - printf "%s[SHA-1:%s]%s\n", $1, $sha1, $3; + printf "%s[MD5:%s]%s\n", $1, md5_hex($2 . "\n"), $3; } else { printf "%s\n", $_; } @@ -514,23 +548,23 @@ BTMM_CHECKMACDOTCOM() BTMM_DIG() { rm -f .digsync - + nc -6 -l "${BTMMPORT}" < .btmmfifo \ | openssl s_client -connect "${HOSTPORT}" -quiet > .btmmfifo 2>.digsync & - + N_RETRY=0 while [ $N_RETRY -lt 50 -a ! -s .digsync ] do N_RETRY=$((N_RETRY + 1)) sleep 0.1 done - + dig @::1 -p "${BTMMPORT}" \ -y "${TSIG}" \ +short \ +tcp \ "${1}" "${2}" 2>/dev/null - + wait %1 } @@ -546,7 +580,7 @@ BTMM_UNIQUEIDFROMZONE() fi } -# get hostname, port, TSIG name and TSIG data from keychain +# get hostname, port, TSIG name and TSIG data from keychain # params: UNIQUEID BTMM_GETINFO() { @@ -556,7 +590,7 @@ BTMM_GETINFO() ${PRIV} security find-generic-password \ -s "${1}" \ -g /Library/Keychains/System.keychain \ - 2>&1 \ + 2>&1 > /dev/null \ | sed -n 's/^password: \"\(.*\)\"$/\1/p' } @@ -577,22 +611,24 @@ BTMM_RELAYINFO() if [ $? -eq 0 ]; then return fi - + SECRET=`BTMM_GETINFO "btmmrelay:${1}"` - + if [ -z "${SECRET}" ]; then echo " No Relay keychain item." >> btmm return fi - + if [ `echo "${SECRET}" | wc -l` -ne 1 ]; then echo " More than one Relay keychain item." >> btmm return fi - + URLISH=`BTMM_URLISH "${DOMAIN}"` ACCOUNT=`cat .btmminfo | sed -n 's/.*\"acct\"=\"\(.*\)\"/\1/p'` - KEYHASH="[SHA-1:`echo ${SECRET} | openssl sha1`]" + KEYHASH="`perl -M'Digest::SHA1 qw(sha1_hex)' -l -e ' + printf "[SHA1:%s]\n", sha1_hex($ARGV[0] . "\n"); + ' ${SECRET}`" echo " RHP: ${URLISH}" >> btmm echo " RAC: ${ACCOUNT}" >> btmm echo " RKY: ${KEYHASH}" >> btmm @@ -601,10 +637,10 @@ BTMM_RELAYINFO() BTMM_REPORTZONE() { DOMAIN="${1}" - + echo >> btmm echo "${DOMAIN}" >> btmm - + DNSID=`BTMM_UNIQUEIDFROMZONE "${DOMAIN}"` SECRET=`BTMM_GETINFO "${DNSID}"` @@ -612,25 +648,37 @@ BTMM_REPORTZONE() echo " No DNS keychain item." >> btmm return fi - + if [ `echo "${SECRET}" | wc -l` -ne 1 ]; then echo " More than one DNS keychain item." >> btmm return fi - + URLISH=`BTMM_URLISH "${DOMAIN}"` HOSTPORT=`echo "${URLISH}" | cut -d@ -f2` ACCOUNT=`cat .btmminfo | sed -n 's/.*\"acct\"=\"\(.*\)\"/\1/p'` TSIG="${ACCOUNT}:${SECRET}" - KEYHASH="[SHA-1:`echo ${SECRET} | openssl sha1`]" + KEYHASH="`perl -M'Digest::SHA1 qw(sha1_hex)' -l -e ' + printf "[SHA1:%s]\n", sha1_hex($ARGV[0] . "\n"); + ' ${SECRET}`" echo "" >> btmm echo " DHP: ${URLISH}" >> btmm echo " DAC: ${ACCOUNT}" >> btmm echo " DKY: ${KEYHASH}" >> btmm - + BTMM_RELAYINFO "${DOMAIN}" + REACHHOST=`echo "${HOSTPORT}" | cut -d: -f1` + STATUSES=`scutil -r "${REACHHOST}"` + for REACHSTATUS in `echo ${STATUSES} | tr -d ' ' | tr ',' ' '`; do + if [ "$REACHSTATUS" == "NotReachable" ] \ + || [ "$REACHSTATUS" == "ConnectionRequired" ]; then + echo " Skipping DNS queries, no connectivity" >> btmm + return + fi + done + for TYPE in \ _afpovertcp._tcp \ _airport._tcp \ @@ -744,12 +792,14 @@ for daemon in \ pppd \ racoon \ socketfilterfw \ + InternetSharing \ SCHelper \ SCMonitor \ do /bin/ls -1 /Library/Logs/DiagnosticReports/${daemon}_*.crash \ /Library/Logs/CrashReporter/${daemon}_*.crash \ + /Library/Logs/CrashReporter/${daemon}_*.plist \ 2>/dev/null \ | while read log do @@ -760,6 +810,21 @@ do done done +# +# system profiler +# +if [ -x /usr/sbin/system_profiler ]; then + system_profiler -xml SPEthernetDataType \ + SPFibreChannelDataType \ + SPFireWireDataType \ + SPFirewallDataType \ + SPModemDataType \ + SPNetworkDataType \ + SPThunderboltDataType \ + SPWWANDataType \ + SPAirPortDataType > system_profiler.spx 2>&1 +fi + # # system usage statistics # @@ -781,9 +846,6 @@ zprint >> system-statistics 2>&1 echo "#" >> system-statistics echo "# top -l5 -s2" >> system-statistics echo "#" >> system-statistics -echo "" -echo "Please wait, collecting statistics" -echo "" top -s 2 -l 5 >> system-statistics 2>&1 # diff --git a/nwi/network_information.c b/nwi/network_information.c new file mode 100644 index 0000000..18b4c6b --- /dev/null +++ b/nwi/network_information.c @@ -0,0 +1,372 @@ +/* + * Copyright (c) 2011 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, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * 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 +#include +#include +#include +#include +#include "network_information.h" +#include "network_information_priv.h" + +static nwi_state_t G_nwi_state = NULL; +static pthread_mutex_t nwi_store_lock = PTHREAD_MUTEX_INITIALIZER; +static boolean_t nwi_store_token_valid = FALSE; + +static pthread_once_t initialized = PTHREAD_ONCE_INIT; +static int nwi_store_token; + + +/* Private */ +static +void +_nwi_state_initialize(void) +{ + const char *nwi_key = nwi_state_get_notify_key(); + uint32_t status = notify_register_check(nwi_key, + &nwi_store_token); + + if (status != NOTIFY_STATUS_OK) { + fprintf(stderr, "nwi_state: registration failed (%u)\n", status); + } + else { + nwi_store_token_valid = TRUE; + } +} + +static +void +nwi_set_alias(nwi_state* state, nwi_ifstate* ifstate) +{ + nwi_ifstate* ifstate_alias; + int af = ifstate->af; + int af_alias; + + af_alias = (af == AF_INET)?AF_INET6:AF_INET; + + ifstate_alias = + nwi_state_get_ifstate_with_name(state, af_alias, + ifstate->ifname); + + if (ifstate_alias != NULL) { + ifstate_alias->af_alias = ifstate; + } + ifstate->af_alias = ifstate_alias; + return; +} + +static +void +_nwi_state_reset_alias(nwi_state_t state) { + int i; + + for (i = 0; i < state->ipv4_count; i++) { + state->nwi_ifstates[i].af_alias = NULL; + } + + for (i = state->ipv6_start; + i < state->ipv6_start + state->ipv6_count; i++) { + nwi_set_alias(state, &state->nwi_ifstates[i]); + } +} + +/* Public APIs' */ +/* + * Function: nwi_state_get_notify_key + * Purpose: + * Returns the BSD notify key to use to monitor when the state changes. + * + * Note: + * The nwi_state_copy API uses this notify key to monitor when the state + * changes, so each invocation of nwi_state_copy returns the current + * information. + */ +const char * +nwi_state_get_notify_key() +{ + return "com.apple.system.SystemConfiguration.nwi"; +} + +#define ATOMIC_INC(p) __sync_fetch_and_add((p), 1) // return (n++); +#define ATOMIC_DEC(p) __sync_sub_and_fetch((p), 1) // return (--n); + +static void +nwi_state_retain(nwi_state_t state) +{ + ATOMIC_INC(&state->ref); + return; +} + +/* + * Function: nwi_state_release + * Purpose: + * Release the memory associated with the network state. + */ +void +nwi_state_release(nwi_state_t state) +{ + if (ATOMIC_DEC(&state->ref) == 0) { + free(state); + } + return; +} + +/* + * Function: nwi_state_copy + * Purpose: + * Returns the current network state information. + * Release after use by calling nwi_state_release(). + */ +nwi_state_t +nwi_state_copy(void) +{ + nwi_state_t nwi_state = NULL; + nwi_state_t old_state = NULL; + + pthread_once(&initialized, _nwi_state_initialize); + pthread_mutex_lock(&nwi_store_lock); + + if (G_nwi_state != NULL) { + int check = 0; + uint32_t status; + + if (nwi_store_token_valid == FALSE) { + /* have to throw cached copy away every time */ + check = 1; + } + else { + status = notify_check(nwi_store_token, &check); + if (status != NOTIFY_STATUS_OK) { + fprintf(stderr, "nwi notify_check: failed with %u\n", + status); + /* assume that it changed, throw cached copy away */ + check = 1; + } + } + if (check != 0) { + /* new need snapshot */ + old_state = G_nwi_state; + G_nwi_state = NULL; + } + } + /* Let's populate the cache if it's empty */ + if (G_nwi_state == NULL) { + G_nwi_state = _nwi_state_copy(); + if (G_nwi_state != NULL) { + /* one reference for G_nwi_state */ + nwi_state_retain(G_nwi_state); + _nwi_state_reset_alias(G_nwi_state); + } + } + if (G_nwi_state != NULL) { + /* another reference for this caller */ + nwi_state_retain(G_nwi_state); + } + nwi_state = G_nwi_state; + pthread_mutex_unlock(&nwi_store_lock); + + if (old_state != NULL) { + /* get rid of G_nwi_state reference */ + nwi_state_release(old_state); + } + return nwi_state; +} + +/* + * Function: _nwi_state_ack + * Purpose: + * Acknowledge receipt and any changes associated with the [new or + * updated] network state. + */ +void +_nwi_state_ack(nwi_state_t state, const char *bundle_id) +{ + return; +} + +/* + * Function: nwi_state_get_generation + * Purpose: + * Returns the generation (mach_time) of the nwi_state data. + * Every time the data is updated due to changes + * in the network, this value will change. + */ +uint64_t +nwi_state_get_generation(nwi_state_t state) +{ + return (state->generation_count); +} + +/* + * Function: nwi_ifstate_get_ifname + * Purpose: + * Return the interface name of the specified ifstate. + */ +const char * +nwi_ifstate_get_ifname(nwi_ifstate_t ifstate) +{ + return (ifstate != NULL?ifstate->ifname:NULL); + +} + +static uint64_t +flags_from_af(int af) +{ + return ((af == AF_INET) + ? NWI_IFSTATE_FLAGS_HAS_IPV4 + : NWI_IFSTATE_FLAGS_HAS_IPV6); +} +/* + * Function: nwi_ifstate_get_flags + * Purpose: + * Return the flags for the given ifstate (see above for bit definitions). + */ +nwi_ifstate_flags +nwi_ifstate_get_flags(nwi_ifstate_t ifstate) +{ + nwi_ifstate_t alias = ifstate->af_alias; + nwi_ifstate_flags flags = 0ULL; + + flags |= flags_from_af(ifstate->af); + if ((ifstate->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0) { + flags |= NWI_IFSTATE_FLAGS_HAS_DNS; + + } + if (alias != NULL) { + flags |= flags_from_af(alias->af); + if ((alias->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0) { + flags |= NWI_IFSTATE_FLAGS_HAS_DNS; + } + } + return flags; +} + +/* + * Function: nwi_state_get_first_ifstate + * Purpose: + * Returns the first and highest priority interface that has connectivity + * for the specified address family 'af'. 'af' is either AF_INET or AF_INET6. + * The connectivity provided is for general networking. To get information + * about an interface that isn't available for general networking, use + * nwi_state_get_ifstate(). + * + * Use nwi_ifstate_get_next() to get the next, lower priority interface + * in the list. + * + * Returns NULL if no connectivity for the specified address family is + * available. + */ +nwi_ifstate_t +nwi_state_get_first_ifstate(nwi_state_t state, int af) +{ + nwi_ifstate_t ifstate; + + if (state == NULL) { + return NULL; + } + + ifstate = + nwi_state_get_ifstate_with_index(state, af, 0); + + if ((ifstate->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) + != 0) { + ifstate = NULL; + } + + return ifstate; + +} + +/* + * Function: nwi_state_get_ifstate + * Purpose: + * Return information for the specified interface 'ifname'. + * + * This API directly returns the ifstate for the specified interface. + * This is the only way to access information about an interface that isn't + * available for general networking. + * + * Returns NULL if no information is available for that interface. + */ +nwi_ifstate_t +nwi_state_get_ifstate(nwi_state_t state, const char * ifname) +{ + nwi_ifstate_t ifstate = nwi_state_get_ifstate_with_name(state, AF_INET, ifname); + if (ifstate == NULL) { + ifstate = nwi_state_get_ifstate_with_name(state, AF_INET6, ifname); + } + return ifstate; + +} + +/* + * Function: nwi_ifstate_get_next + * Purpose: + * Returns the next, lower priority nwi_ifstate_t after the specified + * 'ifstate' for the protocol family 'af'. + * + * Returns NULL when the end of the list is reached. + */ +nwi_ifstate_t +nwi_ifstate_get_next(nwi_ifstate_t ifstate, int af) +{ + nwi_ifstate_t alias, next; + + alias = + (af == ifstate->af)?ifstate:ifstate->af_alias; + + if (alias == NULL) { + return NULL; + } + + /* We don't return interfaces marked rank never */ + if ((alias->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) != 0) { + return NULL; + } + + next = ++alias; + + if ((next->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) == 0) { + return next; + } + return NULL; +} + +/* + * Function: nwi_ifstate_compare_rank + * Purpose: + * Compare the relative rank of two nwi_ifstate_t objects. + * + * The "rank" indicates the importance of the underlying interface. + * + * Returns: + * 0 if ifstate1 and ifstate2 are ranked equally + * -1 if ifstate1 is ranked ahead of ifstate2 + * 1 if ifstate2 is ranked ahead of ifstate1 + */ +int +nwi_ifstate_compare_rank(nwi_ifstate_t ifstate1, nwi_ifstate_t ifstate2) +{ + return RankCompare(ifstate1->rank, ifstate2->rank); +} diff --git a/nwi/network_information.h b/nwi/network_information.h new file mode 100644 index 0000000..418b304 --- /dev/null +++ b/nwi/network_information.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 2011 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, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * 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@ + */ + + +#ifndef _NETWORK_INFORMATION_H_ +#define _NETWORK_INFORMATION_H_ + +#include + +typedef struct _nwi_state * nwi_state_t; +typedef struct _nwi_ifstate * nwi_ifstate_t; + +/* + * Function: nwi_state_copy + * Purpose: + * Returns the current network state information. + * Release after use by calling nwi_state_release(). + */ +nwi_state_t +nwi_state_copy(void); + +/* + * Function: nwi_state_release + * Purpose: + * Release the memory associated with the network state. + */ +void +nwi_state_release(nwi_state_t state); + +/* + * Function: nwi_state_get_notify_key + * Purpose: + * Returns the BSD notify key to use to monitor when the state changes. + * + * Note: + * The nwi_state_copy API uses this notify key to monitor when the state + * changes, so each invocation of nwi_state_copy returns the current + * information. + */ +const char * +nwi_state_get_notify_key(void); + +/* + * Function: nwi_state_get_first_ifstate + * Purpose: + * Returns the first and highest priority interface that has connectivity + * for the specified address family 'af'. 'af' is either AF_INET or AF_INET6. + * The connectivity provided is for general networking. To get information + * about an interface that isn't available for general networking, use + * nwi_state_get_ifstate(). + * + * Use nwi_ifstate_get_next() to get the next, lower priority interface + * in the list. + * + * Returns NULL if no connectivity for the specified address family is + * available. + */ +nwi_ifstate_t +nwi_state_get_first_ifstate(nwi_state_t state, int af); + +/* + * Function: nwi_state_get_generation + * Purpose: + * Returns the generation (mach_time) of the nwi_state data. + * Every time the data is updated due to changes + * in the network, this value will change. + */ +uint64_t +nwi_state_get_generation(nwi_state_t state); + +/* + * Function: nwi_state_get_ifstate + * Purpose: + * Return information for the specified interface 'ifname'. + * + * This API directly returns the ifstate for the specified interface. + * This is the only way to access information about an interface that isn't + * available for general networking. + * + * Returns NULL if no information is available for that interface. + */ +nwi_ifstate_t +nwi_state_get_ifstate(nwi_state_t state, const char * ifname); + +/* + * Function: nwi_ifstate_get_ifname + * Purpose: + * Return the interface name of the specified ifstate. + */ +const char * +nwi_ifstate_get_ifname(nwi_ifstate_t ifstate); + +/* + * Type: nwi_ifstate_flags + * Purpose: + * Provide information about the interface, including its IPv4 and IPv6 + * connectivity, and whether DNS is configured or not. + */ +#define NWI_IFSTATE_FLAGS_HAS_IPV4 0x1 /* has IPv4 connectivity */ +#define NWI_IFSTATE_FLAGS_HAS_IPV6 0x2 /* has IPv6 connectivity */ +#define NWI_IFSTATE_FLAGS_HAS_DNS 0x4 /* has DNS configured */ + +typedef uint64_t nwi_ifstate_flags; +/* + * Function: nwi_ifstate_get_flags + * Purpose: + * Return the flags for the given ifstate (see above for bit definitions). + */ +nwi_ifstate_flags +nwi_ifstate_get_flags(nwi_ifstate_t ifstate); + +/* + * Function: nwi_ifstate_get_next + * Purpose: + * Returns the next, lower priority nwi_ifstate_t after the specified + * 'ifstate' for the protocol family 'af'. + * + * Returns NULL when the end of the list is reached. + */ +nwi_ifstate_t +nwi_ifstate_get_next(nwi_ifstate_t ifstate, int af); + +/* + * Function: nwi_ifstate_compare_rank + * Purpose: + * Compare the relative rank of two nwi_ifstate_t objects. + * + * The "rank" indicates the importance of the underlying interface. + * + * Returns: + * 0 if ifstate1 and ifstate2 are ranked equally + * -1 if ifstate1 is ranked ahead of ifstate2 + * 1 if ifstate2 is ranked ahead of ifstate1 + */ +int +nwi_ifstate_compare_rank(nwi_ifstate_t ifstate1, nwi_ifstate_t ifstate2); + +/* + * Function: _nwi_state_ack + * Purpose: + * Acknowledge receipt and any changes associated with the [new or + * updated] network state. + */ +void +_nwi_state_ack(nwi_state_t state, const char *bundle_id) + __OSX_AVAILABLE_STARTING(__MAC_10_8, __IPHONE_6_0); + +#endif diff --git a/nwi/network_information_priv.c b/nwi/network_information_priv.c new file mode 100644 index 0000000..7dfc706 --- /dev/null +++ b/nwi/network_information_priv.c @@ -0,0 +1,459 @@ +/* + * Copyright (c) 2011 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, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * 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 +#include +#include +#include +#include +#include +#include +#include "network_information_priv.h" +#include + +sa_family_t nwi_af_list[] = {AF_INET, AF_INET6}; + +static __inline__ unsigned int +nwi_state_compute_size(unsigned int n) +{ + return (offsetof(nwi_state, nwi_ifstates[n])); + +} +__private_extern__ +nwi_state_t +nwi_state_copy_priv(nwi_state_t src) +{ + nwi_state_t dest = NULL; + + if (src == NULL) { + return dest; + } + + dest = malloc(src->size); + + if (dest != NULL) { + bcopy(src, dest, src->size); + + dest->ref = 1; + } + return dest; +} + +__private_extern__ +nwi_state_t +nwi_state_new(nwi_state_t old_state, int elems) +{ + nwi_state_t state = NULL; + int new_size; + + if (old_state == NULL && elems == 0) { + return NULL; + } + + /* Need to insert a last node for each of the v4/v6 list */ + new_size = (elems != 0)? + (sizeof(nwi_state) + nwi_state_compute_size((elems+1) * 2)):0; + + /* Should we reallocate? */ + if (old_state != NULL) { + if (old_state->size >= new_size) { + return (old_state); + } + } + + state = malloc(new_size); + if (state == NULL) { + return NULL; + } + + state->size = new_size; + + /* + * v4 list is stored 0 to elems, + * v6 list is stored elems + 1 to 2 * elems + 2 + */ + state->ipv6_start = elems + 1; + + if (old_state != NULL) { + state->ipv6_count = old_state->ipv6_count; + if (state->ipv6_count > 0) { + bcopy((void*) &old_state->nwi_ifstates[old_state->ipv6_start], + (void*) &state->nwi_ifstates[state->ipv6_start], + old_state->ipv6_count * sizeof(nwi_ifstate)); + } + + state->ipv4_count = old_state->ipv4_count; + + if (state->ipv4_count > 0) { + bcopy((void*) old_state->nwi_ifstates, + (void*) state->nwi_ifstates, + old_state->ipv4_count * sizeof(nwi_ifstate)); + } + + free(old_state); + } else { + state->ipv4_count = 0; + state->ipv6_count = 0; + } + nwi_state_set_last(state, AF_INET); + nwi_state_set_last(state, AF_INET6); + + state->ref = 1; + return state; +} + +static inline +nwi_ifstate_t nwi_ifstate_get_last(nwi_state_t state, int af, uint32_t** last) +{ + uint32_t* count; + int idx; + + count = (af == AF_INET) + ?&state->ipv4_count:&state->ipv6_count; + + idx = (af == AF_INET) + ?state->ipv4_count:(state->ipv6_start + state->ipv6_count); + + *last = count; + + return &state->nwi_ifstates[idx]; + +} + +__private_extern__ +void +nwi_insert_ifstate(nwi_state_t state, + const char* ifname, int af, + uint64_t flags, Rank rank, + void* ifa) +{ + nwi_ifstate_t ifstate; + + /* Will only insert unique elements in the list */ + ifstate = nwi_state_get_ifstate_with_name(state, af, ifname); + + /* Already present, just ignore it */ + if (ifstate != NULL) { + if (ifstate->rank < rank) { + return; + } + } + + if (ifstate == NULL) { + uint32_t *last; + + /* We need to append it as the last element */ + ifstate = nwi_ifstate_get_last(state, af, &last); + strcpy(ifstate->ifname, ifname); + ifstate->af_alias = NULL; + ifstate->af = af; + ifstate->diff_ch = NULL; + (*last)++; + } + + /* We need to update the address/rank/flag fields for the existing/new + * element */ + if (ifa != NULL) { + switch (af) { + case AF_INET: + ifstate->iaddr = *((struct in_addr *) ifa); + break; + case AF_INET6: + ifstate->iaddr6 = *((struct in6_addr *) ifa); + break; + default: + break; + } + + } + + ifstate->rank = rank; + ifstate->flags = flags; + + return; +} + +__private_extern__ +void +nwi_state_clear(nwi_state_t state, int af) +{ + uint32_t* count; + + count = (af == AF_INET) + ?&state->ipv4_count:&state->ipv6_count; + + *count = 0; + nwi_state_set_last(state, af); + return; + +} + +__private_extern__ +void +nwi_state_set_last(nwi_state_t state, int af) +{ + int last_elem_idx; + + if (state == NULL) { + return; + } + + /* The last element is an element with the flags set as + * NWI_IFSTATE_FLAGS_NOT_IN_LIST */ + last_elem_idx = (af == AF_INET) + ?state->ipv4_count + :(state->ipv6_start + state->ipv6_count); + + state->nwi_ifstates[last_elem_idx].ifname[0] = '\0'; + state->nwi_ifstates[last_elem_idx].flags + |= NWI_IFSTATE_FLAGS_NOT_IN_LIST; +} + +__private_extern__ +void +_nwi_state_dump(int level, nwi_state_t state) +{ + const char * addr_str; + void * address; + int i; + char ntopbuf[INET6_ADDRSTRLEN]; + nwi_ifstate_t scan; + + + if (state == NULL) { + syslog(level, ""); + return; + } + syslog(level, "nwi_state = { gen = %llu size = %u #ipv4 = %u #ipv6 = %u }", + state->generation_count, + state->size, + state->ipv4_count, + state->ipv6_count); + + if (state->ipv4_count) { + syslog(level, "IPv4:"); + for (i = 0, scan = state->nwi_ifstates; + i < state->ipv4_count; i++, scan++) { + bool has_dns = (scan->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0; + bool never = (scan->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) != 0; + + address = nwi_ifstate_get_address(scan); + addr_str = inet_ntop(scan->af, address, ntopbuf, sizeof(ntopbuf)); + + syslog(level, " [%d]: %s%s%s%s rank %u iaddr: %s " , + i, scan->ifname, scan->diff_ch != NULL?scan->diff_ch:"", + has_dns ? " dns" : "", + never ? " never" : "", + scan->rank, + addr_str); + } + } + if (state->ipv6_count) { + syslog(level, "IPv6:"); + for (i = 0, scan = state->nwi_ifstates + state->ipv6_start; + i < state->ipv6_count; i++, scan++) { + bool has_dns = (scan->flags & NWI_IFSTATE_FLAGS_HAS_DNS) != 0; + bool never = (scan->flags & NWI_IFSTATE_FLAGS_NOT_IN_LIST) != 0; + + address = nwi_ifstate_get_address(scan); + addr_str = inet_ntop(scan->af, address, ntopbuf, sizeof(ntopbuf)); + syslog(level, " [%d]: %s%s%s%s rank %u iaddr6: %s ", + i, scan->ifname, scan->diff_ch != NULL?scan->diff_ch:"", + has_dns ? " dns" : "", + never ? " never" : "", + scan->rank, + addr_str); + } + } + return; +} + + +#define unchanged "" +#define added "+" +#define deleted "-" +#define changed "!" + +__private_extern__ +void * +nwi_ifstate_get_address(nwi_ifstate_t ifstate) +{ + return (void *)&ifstate->iaddr; +} + +__private_extern__ +const char * +nwi_ifstate_get_diff_str(nwi_ifstate_t ifstate) +{ + return ifstate->diff_ch; +} + +static +inline +boolean_t +nwi_ifstate_has_changed(nwi_ifstate_t ifstate1, nwi_ifstate_t ifstate2) +{ + if (ifstate1->rank != ifstate2->rank) { + return TRUE; + } + + if (ifstate1->flags != ifstate2->flags) { + return TRUE; + } + + if (ifstate1->af == AF_INET) { + if (memcmp(&ifstate1->iaddr, &ifstate2->iaddr, sizeof(struct in_addr)) != 0) { + return TRUE; + } + } else { + if (memcmp(&ifstate1->iaddr6, &ifstate2->iaddr6, sizeof(struct in6_addr)) != 0) { + return TRUE; + } + } + return FALSE; +} + +static +inline +nwi_ifstate_t +nwi_ifstate_append(nwi_state_t state, nwi_ifstate_t scan) +{ + nwi_ifstate_t new_ifstate = NULL; + uint32_t *last; + + new_ifstate = nwi_ifstate_get_last(state, scan->af, &last); + memcpy(new_ifstate, scan, sizeof(*scan)); + (*last)++; + return new_ifstate; +} + +static +inline +void +nwi_ifstate_set_diff_str(nwi_ifstate_t ifstate, const char * ch) +{ + ifstate->diff_ch = ch; +} + +static +void +nwi_state_merge_added(nwi_state_t state, nwi_state_t old_state, + nwi_state_t new_state) +{ + int idx; + nwi_ifstate_t scan; + + /* Iterate through v4 and v6 list and annotate the diff flags */ + for (idx = 0; idx < sizeof(nwi_af_list)/sizeof(nwi_af_list[0]); idx++) { + scan = nwi_state_get_first_ifstate(new_state, nwi_af_list[idx]); + + while (scan != NULL) { + nwi_ifstate_t existing_ifstate, new_ifstate; + const char* ifname; + + ifname = nwi_ifstate_get_ifname(scan); + + existing_ifstate = nwi_state_get_ifstate_with_name(old_state, scan->af, ifname); + + /* Add the element that is not in the store */ + new_ifstate = nwi_ifstate_append(state, scan); + + /* These are potentially "added" elements unless they are + * in the old list */ + nwi_ifstate_set_diff_str(new_ifstate, added); + + if (existing_ifstate != NULL) { + if (nwi_ifstate_has_changed(existing_ifstate, new_ifstate) == TRUE) { + nwi_ifstate_set_diff_str(new_ifstate, changed); + } else { + nwi_ifstate_set_diff_str(new_ifstate, unchanged); + } + } + scan = nwi_ifstate_get_next(scan, scan->af); + } + nwi_state_set_last(state, nwi_af_list[idx]); + } + + return; +} + +static +void +nwi_state_merge_removed(nwi_state_t state, nwi_state_t old_state) +{ + int idx; + nwi_ifstate_t scan; + + /* Iterate through v4 and v6 list and annotate the diff flags */ + for (idx = 0; idx < sizeof(nwi_af_list)/sizeof(nwi_af_list[0]); idx++) { + scan = nwi_state_get_first_ifstate(old_state, nwi_af_list[idx]); + + while (scan != NULL) { + nwi_ifstate_t existing_ifstate; + const char* ifname; + + ifname = nwi_ifstate_get_ifname(scan); + + existing_ifstate = nwi_state_get_ifstate_with_name(state, scan->af, ifname); + + /* Any elements that has not been added means that they are removed */ + if (existing_ifstate == NULL) { + nwi_ifstate_t new_ifstate = nwi_ifstate_append(state, scan); + nwi_ifstate_set_diff_str(new_ifstate, deleted); + } + scan = nwi_ifstate_get_next(scan, scan->af); + } + nwi_state_set_last(state, nwi_af_list[idx]); + } + +} + + +__private_extern__ +nwi_state_t +nwi_state_diff(nwi_state_t old_state, nwi_state_t new_state) +{ + nwi_state_t diff; + int total_count = 0; + + if (old_state != NULL) { + total_count = old_state->ipv4_count + old_state->ipv6_count; + } + + if (new_state != NULL) { + total_count += new_state->ipv4_count + new_state->ipv6_count; + } + + if (total_count == 0) { + return NULL; + } + + diff = nwi_state_new(NULL, total_count); + + nwi_state_merge_added(diff, old_state, new_state); + nwi_state_merge_removed(diff, old_state); + + /* Diff consists of a nwi_state_t with annotated diff_ch's */ + return diff; +} + diff --git a/nwi/network_information_priv.h b/nwi/network_information_priv.h new file mode 100644 index 0000000..3eb3c12 --- /dev/null +++ b/nwi/network_information_priv.h @@ -0,0 +1,252 @@ +/* + * Copyright (c) 2011 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, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * 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@ + */ + +#ifndef _NETWORK_INFORMATION_PRIV_H_ +#define _NETWORK_INFORMATION_PRIV_H_ + +#include +#include +#include +#include +#include + +#include "network_information.h" + +__private_extern__ +sa_family_t nwi_af_list[2]; + +#define NWI_IFSTATE_FLAGS_NOT_IN_LIST 0x8 + +typedef uint32_t Rank; + +typedef struct _nwi_ifstate { + char ifname[IFNAMSIZ]; + uint64_t flags; + nwi_ifstate_t af_alias; + Rank rank; + int af; + union { + struct in_addr iaddr; + struct in6_addr iaddr6; + }; + const char* diff_ch; +} nwi_ifstate; + +/* + * nwi_state + * + *+---------------------------------------------+ + *| generation_count | + *| | + *----------------------------------------------+ + *| size | + *| | + *|---------------------------------------------+ + *| ipv4_count | + *| | + *|---------------------------------------------+ + *| ipv6_count | + *| | + *|---------------------------------------------+ + *| ipv6_start |-------+ + *| | | + *|---------------------------------------------+ |ipv6_start stores the index of the start of the v6 list. + *| ref | | + *| | | + *|---------------------------------------------+ | + *| IPv4 nwi_ifstates | | + *| |<------|-------+ + *| ... | | | + *|---------------------------------------------+ | | + *| Sentinel nwi_ifstates | | | + *| flags =NWI_IFSTATE_FLAGS_RANK_NEVER) | | | af_alias points to the same ifstate in the + *| | | | opposite (v4 -> v6 and vice versa) af list. + *|---------------------------------------------+ | | + *| IPv6 nwi_ifstates |<------+ | + *| |<--------------+ + *| ... | + *|---------------------------------------------+ + *| Sentinel nwi_ifstates | + *| flags =NWI_IFSTATE_FLAGS_RANK_NEVER) | + *| | + *|---------------------------------------------+ + * + */ +typedef struct _nwi_state { + uint64_t generation_count; + uint32_t size; + uint32_t ipv4_count; + uint32_t ipv6_count; + uint32_t ipv6_start; + uint32_t ref; + nwi_ifstate nwi_ifstates[0]; +} nwi_state; + +static __inline__ int +uint32_cmp(uint32_t a, uint32_t b) +{ + int ret; + + if (a == b) { + ret = 0; + } + else if (a < b) { + ret = -1; + } + else { + ret = 1; + } + return (ret); +} + +static __inline__ int +RankCompare(Rank a, Rank b) +{ + return (uint32_cmp(a, b)); +} + +/* + * Function: nwi_state_get_ifstate_count + * Purpose: + * Return the number of ifstate elements for the specified address family + * 'af'. 'af' is either AF_INET or AF_INET6. + * + * Returns zero if there are no elements. + */ +static __inline__ +int +nwi_state_get_ifstate_count(nwi_state_t state, int af) +{ + return (af == AF_INET)?state->ipv4_count:state->ipv6_count; +} + +/* + * The ifstate list is sorted in order of decreasing priority, with the + * highest priority element appearing at index zero. + * + * If 'idx' is outside of the bounds of the corresponding array, returns NULL. + */ +static __inline__ +nwi_ifstate_t +nwi_state_get_ifstate_with_index(nwi_state_t state, int af, int idx) +{ + nwi_ifstate_t nwi_ifstate = NULL; + int i_idx = idx; + + if (idx > nwi_state_get_ifstate_count(state, af)) { + return (nwi_ifstate); + } + + if (af == AF_INET6) { + i_idx = idx + state->ipv6_start; + } + + return &state->nwi_ifstates[i_idx]; +} + +/* + * Function: nwi_state_get_ifstate_with_name + * Purpose: + * Return the ifstate for the specified ifstate for the specified address + * family 'af'. 'af' is either AF_INET or AF_INET6. + * + * Returns NULL if no such information exists. + */ +static __inline__ +nwi_ifstate_t +nwi_state_get_ifstate_with_name(nwi_state_t state, + int af, const char * name) +{ + int idx = 0; + int count; + nwi_ifstate_t ifstate = NULL; + + if (state == NULL) { + return ifstate; + } + + count = (af == AF_INET) + ?state->ipv4_count:state->ipv6_count; + + + while (idx < count) { + ifstate = nwi_state_get_ifstate_with_index(state, af, idx); + if (ifstate == NULL) { + break; + } + if (strcmp(name, + nwi_ifstate_get_ifname(ifstate)) == 0) { + return (ifstate); + } + idx++; + } + return (NULL); +} + +__private_extern__ +nwi_state_t +nwi_state_new(nwi_state_t old_state, int elems); + +__private_extern__ +nwi_state_t +nwi_state_copy_priv(nwi_state_t old_state); + +__private_extern__ +void +nwi_insert_ifstate(nwi_state_t state, const char* ifname, int af, + uint64_t flags, Rank rank, + void * ifa); + +__private_extern__ +void +nwi_state_clear(nwi_state_t state, int af); + +__private_extern__ +void +nwi_state_set_last(nwi_state_t state, int af); + +__private_extern__ +nwi_state_t +nwi_state_diff(nwi_state_t old_state, nwi_state_t new_state); + +__private_extern__ +void * +nwi_ifstate_get_address(nwi_ifstate_t ifstate); + +__private_extern__ +const char * +nwi_ifstate_get_diff_str(nwi_ifstate_t ifstate); + +__private_extern__ +_Bool +_nwi_state_store(nwi_state_t state); + +__private_extern__ +nwi_state_t +_nwi_state_copy(void); + +__private_extern__ +void +_nwi_state_dump(int level, nwi_state_t state); + +#endif diff --git a/scselect.tproj/scselect.c b/scselect.tproj/scselect.c index 7a89d37..4d9e278 100644 --- a/scselect.tproj/scselect.c +++ b/scselect.tproj/scselect.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2009 Apple Inc. All rights reserved. + * Copyright (c) 2000-2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -109,7 +109,7 @@ static void * __loadSecurity(void) { static void *image = NULL; if (NULL == image) { - const char *framework = "/System/Library/Frameworks/Security.framework/Versions/A/Security"; + const char *framework = "/System/Library/Frameworks/Security.framework/Security"; struct stat statbuf; const char *suffix = getenv("DYLD_IMAGE_SUFFIX"); char path[MAXPATHLEN]; @@ -181,53 +181,58 @@ main(int argc, char **argv) /* process any arguments */ - while ((opt = getopt_long(argc, argv, "dvn", longopts, NULL)) != -1) + while ((opt = getopt_long(argc, argv, "dvn", longopts, NULL)) != -1) { switch(opt) { - case 'd': - _sc_debug = TRUE; - _sc_log = FALSE; /* enable framework logging */ - break; - case 'v': - _sc_verbose = TRUE; - break; - case 'n': - apply = FALSE; - break; - case '?': - default : - usage(command); + case 'd': + _sc_debug = TRUE; + _sc_log = FALSE; /* enable framework logging */ + break; + case 'v': + _sc_verbose = TRUE; + break; + case 'n': + apply = FALSE; + break; + case '?': + default : + usage(command); + } } argc -= optind; argv += optind; prefix = CFStringCreateWithFormat(NULL, NULL, CFSTR("/%@/"), kSCPrefSets); - newSet = (argc == 1) - ? CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman) - : CFRetain(CFSTR("")); + if (argc == 1) { + newSet = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingMacRoman); - prefs = SCPreferencesCreate(NULL, CFSTR("Select Set Command"), NULL); - if (prefs == NULL) { - SCPrint(TRUE, stderr, CFSTR("SCPreferencesCreate() failed\n")); - exit (1); - } + /* check if a full path to the new "set" was specified */ + if ((CFStringGetLength(newSet) > 0) && CFStringHasPrefix(newSet, prefix)) { + CFRange range; + CFMutableStringRef str; - /* check if a full path to the new "set" was specified */ - if ((CFStringGetLength(newSet) > 0) && CFStringHasPrefix(newSet, prefix)) { - CFRange range; - CFMutableStringRef str; + str = CFStringCreateMutableCopy(NULL, 0, newSet); + CFRelease(newSet); - str = CFStringCreateMutableCopy(NULL, 0, newSet); - CFStringDelete(str, CFRangeMake(0, CFStringGetLength(prefix))); + CFStringDelete(str, CFRangeMake(0, CFStringGetLength(prefix))); + newSet = CFStringCreateCopy(NULL, newSet); + CFRelease(str); - range = CFStringFind(str, CFSTR("/"), 0); - if (range.location != kCFNotFound) { - SCPrint(TRUE, stderr, CFSTR("Set \"%@\" not available\n."), newSet); - exit (1); + range = CFStringFind(newSet, CFSTR("/"), 0); + if (range.location != kCFNotFound) { + SCPrint(TRUE, stderr, CFSTR("Set \"%@\" not available\n."), newSet); + exit (1); + } } + } else { + newSet = CFRetain(CFSTR("")); + } - CFRelease(newSet); - newSet = str; + + prefs = SCPreferencesCreate(NULL, CFSTR("Select Set Command"), NULL); + if (prefs == NULL) { + SCPrint(TRUE, stderr, CFSTR("SCPreferencesCreate() failed\n")); + exit (1); } sets = SCPreferencesGetValue(prefs, kSCPrefSets); diff --git a/scutil.tproj/cache.c b/scutil.tproj/cache.c index 84d96d2..76fd819 100644 --- a/scutil.tproj/cache.c +++ b/scutil.tproj/cache.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000-2005, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -37,6 +37,226 @@ #include "cache.h" +#pragma mark - +#pragma mark SCDynamicStore "cache" + + +static Boolean use_cache = FALSE; + +static CFMutableDictionaryRef cached_keys = NULL; +static CFMutableDictionaryRef cached_set = NULL; +static CFMutableArrayRef cached_removals = NULL; +static CFMutableArrayRef cached_notifys = NULL; + + +static void +cache_open(void) +{ + if (use_cache) { + // if we are already using the cache + cache_close(); + } + + cached_keys = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + cached_set = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + cached_removals = CFArrayCreateMutable(NULL, + 0, + &kCFTypeArrayCallBacks); + cached_notifys = CFArrayCreateMutable(NULL, + 0, + &kCFTypeArrayCallBacks); + + use_cache = TRUE; + return; +} + + +static CFPropertyListRef +cache_SCDynamicStoreCopyValue(SCDynamicStoreRef store, CFStringRef key) +{ + CFPropertyListRef value; + + value = CFDictionaryGetValue(cached_set, key); + if (value) { + // if we have "set" a new value + return (CFRetain(value)); + } + + if (CFArrayContainsValue(cached_removals, + CFRangeMake(0, CFArrayGetCount(cached_removals)), + key)) { + // if we have "removed" the key + _SCErrorSet(kSCStatusNoKey); + return NULL; + } + + value = CFDictionaryGetValue(cached_keys, key); + if (value) { + // if we have a cached value + return (CFRetain(value)); + } + + value = SCDynamicStoreCopyValue(store, key); + if (value) { + CFDictionarySetValue(cached_keys, key, value); + } + + return value; +} + + +static void +cache_SCDynamicStoreSetValue(SCDynamicStoreRef store, CFStringRef key, CFPropertyListRef value) +{ + CFIndex i; + + i = CFArrayGetFirstIndexOfValue(cached_removals, + CFRangeMake(0, CFArrayGetCount(cached_removals)), + key); + if (i != kCFNotFound) { + // if previously "removed" + CFArrayRemoveValueAtIndex(cached_removals, i); + } + + CFDictionarySetValue(cached_set, key, value); + + return; +} + +static void +cache_SCDynamicStoreRemoveValue(SCDynamicStoreRef store, CFStringRef key) +{ + CFDictionaryRemoveValue(cached_set, key); + + if (!CFArrayContainsValue(cached_removals, + CFRangeMake(0, CFArrayGetCount(cached_removals)), + key)) { + CFArrayAppendValue(cached_removals, key); + } + + return; +} + + +static void +cache_SCDynamicStoreNotifyValue(SCDynamicStoreRef store, CFStringRef key) +{ + if (!CFArrayContainsValue(cached_notifys, + CFRangeMake(0, CFArrayGetCount(cached_notifys)), + key)) { + CFArrayAppendValue(cached_notifys, key); + } + + return; +} + + +static void +cache_write(SCDynamicStoreRef store) +{ + if ((CFDictionaryGetCount(cached_set) > 0) || + (CFArrayGetCount(cached_removals) > 0) || + (CFArrayGetCount(cached_notifys) > 0)) { + if (!SCDynamicStoreSetMultiple(store, + cached_set, + cached_removals, + cached_notifys)) { + SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + } + } + + return; +} + + +__private_extern__ +void +cache_close(void) +{ + if (!use_cache) { + return; + } + + CFRelease(cached_keys); + CFRelease(cached_set); + CFRelease(cached_removals); + CFRelease(cached_notifys); + + use_cache = FALSE; + return; +} + + +#pragma mark - +#pragma mark SCDynamicStore operations + + +__private_extern__ +void +do_block(int argc, char **argv) +{ + Boolean enable = FALSE; + + if (argc >= 1) { + if ((strcasecmp(argv[0], "begin") == 0) || + (strcasecmp(argv[0], "start") == 0) || + (strcasecmp(argv[0], "on" ) == 0) || + (strcasecmp(argv[0], "1" ) == 0)) { + enable = TRUE; + } else if ((strcasecmp(argv[0], "end" ) == 0) || + (strcasecmp(argv[0], "stop" ) == 0) || + (strcasecmp(argv[0], "off" ) == 0) || + (strcasecmp(argv[0], "0" ) == 0)) { + enable = FALSE; + } else { + SCPrint(TRUE, stdout, CFSTR("invalid value\n")); + return; + } + } else { + enable = !use_cache; // toggle + } + + if (enable) { + // begin block of SCDynamicStore operations + if (use_cache) { + SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusLocked)); + return; + } + + SCPrint(TRUE, stdout, CFSTR("Begin block of SCDynamicStore operations\n")); + + cache_open(); + } else { + CFIndex n; + + // end block of SCDynamicStore operations + if (!use_cache) { + SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusNeedLock)); + return; + } + + n = CFDictionaryGetCount(cached_keys) + + CFArrayGetCount(cached_removals) + + CFArrayGetCount(cached_notifys); + SCPrint(TRUE, stdout, + CFSTR("End block of SCDynamicStore operations%s\n"), + (n > 0) ? ", posting changes" : ""); + if (n > 0) { + cache_write(store); + } + cache_close(); + } + + return; +} + + static CFComparisonResult sort_keys(const void *p1, const void *p2, void *context) { CFStringRef key1 = (CFStringRef)p1; @@ -45,6 +265,9 @@ sort_keys(const void *p1, const void *p2, void *context) { } +#define N_QUICK 64 + + __private_extern__ void do_list(int argc, char **argv) @@ -64,10 +287,37 @@ do_list(int argc, char **argv) if (list == NULL) { if (SCError() != kSCStatusOK) { SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + return; } else { + if (!use_cache) { SCPrint(TRUE, stdout, CFSTR(" no keys.\n")); + return; + } else { + CFIndex n; + + n = CFDictionaryGetCount(cached_set); + if (n > 0){ + const void * cachedKeys_q[N_QUICK]; + const void ** cachedKeys = cachedKeys_q; + + if (n > (CFIndex)(sizeof(cachedKeys_q) / sizeof(CFStringRef))) { + cachedKeys = CFAllocatorAllocate(NULL, n * sizeof(CFStringRef), 0); + } + CFDictionaryGetKeysAndValues(cached_set, cachedKeys, NULL); + list = CFArrayCreate(NULL, cachedKeys, n, &kCFTypeArrayCallBacks); + if (cachedKeys != cachedKeys_q) { + CFAllocatorDeallocate(NULL, cachedKeys); + } + } else { + SCPrint(TRUE, stdout, CFSTR(" no keys.\n")); + return; + } + } } - return; + } else if (use_cache && + ((CFDictionaryGetCount(cached_set) > 0) || (CFArrayGetCount(cached_removals) > 0))) { + SCPrint(TRUE, stdout, + CFSTR(" Note: SCDynamicStore transactions in progress, key list (below) may be out of date.\n\n")); } listCnt = CFArrayGetCount(list); @@ -104,12 +354,41 @@ do_add(int argc, char **argv) key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); if (argc < 2) { - if (!SCDynamicStoreAddValue(store, key, value)) { - SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + if (!use_cache) { + if (!SCDynamicStoreAddValue(store, key, value)) { + SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + } + } else { + CFTypeRef val; + + val = cache_SCDynamicStoreCopyValue(store, key); + if (val != NULL) { + CFRelease(val); + SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusKeyExists)); + } else { + cache_SCDynamicStoreSetValue(store, key, value); + } } } else { - if (!SCDynamicStoreAddTemporaryValue(store, key, value)) { - SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + if (!use_cache) { + if (!SCDynamicStoreAddTemporaryValue(store, key, value)) { + SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + } + } else { + CFTypeRef val; + + val = cache_SCDynamicStoreCopyValue(store, key); + if (val != NULL) { + CFRelease(val); + SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(kSCStatusKeyExists)); + } else { + if (!SCDynamicStoreAddTemporaryValue(store, key, value)) { + SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + } else { + // and save the temp value in the cache too! + cache_SCDynamicStoreSetValue(store, key, value); + } + } } } @@ -126,7 +405,11 @@ do_get(int argc, char **argv) CFPropertyListRef newValue; key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); - newValue = SCDynamicStoreCopyValue(store, key); + if (!use_cache) { + newValue = SCDynamicStoreCopyValue(store, key); + } else { + newValue = cache_SCDynamicStoreCopyValue(store, key); + } CFRelease(key); if (newValue == NULL) { SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); @@ -149,8 +432,12 @@ do_set(int argc, char **argv) CFStringRef key; key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); - if (!SCDynamicStoreSetValue(store, key, value)) { - SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + if (!use_cache) { + if (!SCDynamicStoreSetValue(store, key, value)) { + SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + } + } else { + cache_SCDynamicStoreSetValue(store, key, value); } CFRelease(key); return; @@ -167,12 +454,51 @@ do_show(int argc, char **argv) key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); if (argc == 1) { - newValue = SCDynamicStoreCopyValue(store, key); + if (!use_cache) { + newValue = SCDynamicStoreCopyValue(store, key); + } else { + newValue = cache_SCDynamicStoreCopyValue(store, key); + } } else { CFArrayRef patterns; patterns = CFArrayCreate(NULL, (const void **)&key, 1, &kCFTypeArrayCallBacks); - newValue = SCDynamicStoreCopyMultiple(store, NULL, patterns); + if (!use_cache) { + newValue = SCDynamicStoreCopyMultiple(store, NULL, patterns); + } else { + CFArrayRef keys; + CFMutableDictionaryRef newDict; + + newDict = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + keys = SCDynamicStoreCopyKeyList(store, key); + if (keys != NULL) { + CFIndex i; + CFIndex n; + + n = CFArrayGetCount(keys); + for (i = 0; i < n; i++) { + CFStringRef storeKey; + CFTypeRef storeVal; + + storeKey = CFArrayGetValueAtIndex(keys, i); + storeVal = cache_SCDynamicStoreCopyValue(store, storeKey); + if (storeVal != NULL) { + CFDictionarySetValue(newDict, storeKey, storeVal); + CFRelease(storeVal); + } + } + CFRelease(keys); + } + + if ((CFDictionaryGetCount(cached_set) > 0) || (CFArrayGetCount(cached_removals) > 0)) { + SCPrint(TRUE, stdout, CFSTR(" Note: SCDynamicStore locked, keys included (below) may be out of date.\n\n")); + } + + newValue = newDict; + } CFRelease(patterns); } @@ -195,8 +521,12 @@ do_remove(int argc, char **argv) CFStringRef key; key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); - if (!SCDynamicStoreRemoveValue(store, key)) { - SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + if (!use_cache) { + if (!SCDynamicStoreRemoveValue(store, key)) { + SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + } + } else { + cache_SCDynamicStoreRemoveValue(store, key); } CFRelease(key); return; @@ -210,23 +540,12 @@ do_notify(int argc, char **argv) CFStringRef key; key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); - if (!SCDynamicStoreNotifyValue(store, key)) { - SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); - } - CFRelease(key); - return; -} - - -__private_extern__ -void -do_touch(int argc, char **argv) -{ - CFStringRef key; - - key = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); - if (!SCDynamicStoreTouchValue(store, key)) { - SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + if (!use_cache) { + if (!SCDynamicStoreNotifyValue(store, key)) { + SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); + } + } else { + cache_SCDynamicStoreNotifyValue(store, key); } CFRelease(key); return; diff --git a/scutil.tproj/cache.h b/scutil.tproj/cache.h index acace78..ef14ef2 100644 --- a/scutil.tproj/cache.h +++ b/scutil.tproj/cache.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -34,10 +34,16 @@ #ifndef _CACHE_H #define _CACHE_H +#include +#include #include __BEGIN_DECLS +void cache_close (void); + +void do_block (int argc, char **argv); + void do_list (int argc, char **argv); void do_add (int argc, char **argv); void do_get (int argc, char **argv); @@ -45,7 +51,6 @@ void do_set (int argc, char **argv); void do_show (int argc, char **argv); void do_remove (int argc, char **argv); void do_notify (int argc, char **argv); -void do_touch (int argc, char **argv); __END_DECLS diff --git a/scutil.tproj/commands.c b/scutil.tproj/commands.c index 59d929d..5b93ff6 100644 --- a/scutil.tproj/commands.c +++ b/scutil.tproj/commands.c @@ -76,7 +76,7 @@ const cmdInfo commands_store[] = { { "d.add", 2, 101, do_dictSetKey, 1, 0, " d.add key [*#?] val [v2 ...] : add information to dictionary\n" - " (*=array, #=number, ?=boolean)" }, + " (*=array, #=number, ?=boolean, %=hex data)" }, { "d.remove", 1, 1, do_dictRemoveKey, 1, 0, " d.remove key : remove key from dictionary" }, @@ -89,11 +89,8 @@ const cmdInfo commands_store[] = { { "close", 0, 0, do_close, 2, 1, " close : close current \"configd\" session" }, - { "lock", 0, 0, do_lock, 3, 1, - " lock : locks write access to data store" }, - - { "unlock", 0, 0, do_unlock, 3, 1, - " unlock : unlocks write access to data store" }, + { "block", 0, 1, do_block, 3, 1, + " block [\"begin\" | \"end\"] : block multiple data store transactions" }, { "list", 0, 2, do_list, 4, 0, " list [pattern] : list keys in data store" }, @@ -116,9 +113,6 @@ const cmdInfo commands_store[] = { { "notify", 1, 1, do_notify, 4, 0, " notify key : notify key in data store" }, - { "touch", 1, 1, do_touch, 4, 1, - " touch key : touch key in data store" }, - { "n.list", 0, 1, do_notify_list, 5, 0, " n.list [\"pattern\"] : list notification keys" }, @@ -137,9 +131,6 @@ const cmdInfo commands_store[] = { { "n.wait", 0, 0, do_notify_wait, 5, 2, " n.wait : wait for changes" }, - { "n.callback", 0, 1, do_notify_callback, 5, 2, - " n.callback [\"verbose\"] : watch for changes" }, - { "n.signal", 1, 2, do_notify_signal, 5, 2, " n.signal sig [pid] : signal changes" }, @@ -272,7 +263,7 @@ const cmdInfo commands_prefs[] = { { "d.add", 2, 101, do_dictSetKey, 1, 0, " d.add key [*#?] val [v2 ...] : add information to dictionary\n" - " (*=array, #=number, ?=boolean)" }, + " (*=array, #=number, ?=boolean, %=hex data)" }, { "d.remove", 1, 1, do_dictRemoveKey, 1, 0, " d.remove key : remove key from dictionary" }, diff --git a/scutil.tproj/dictionary.c b/scutil.tproj/dictionary.c index 396e3ab..790aab4 100644 --- a/scutil.tproj/dictionary.c +++ b/scutil.tproj/dictionary.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2009, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2004, 2009-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -79,6 +79,7 @@ do_dictSetKey(int argc, char **argv) CFMutableArrayRef array = NULL; Boolean doArray = FALSE; Boolean doBoolean = FALSE; + Boolean doData = FALSE; Boolean doNumeric = FALSE; CFStringRef key; CFMutableDictionaryRef newValue; @@ -106,6 +107,9 @@ do_dictSetKey(int argc, char **argv) } else if (strcmp(argv[0], "?") == 0) { /* if boolean values requested */ doBoolean = TRUE; + } else if (strcmp(argv[0], "%") == 0) { + /* if [hex] data values requested */ + doData = TRUE; } else if (strcmp(argv[0], "#") == 0) { /* if numeric values requested */ doNumeric = TRUE; @@ -148,6 +152,51 @@ do_dictSetKey(int argc, char **argv) CFRelease(key); return; } + } else if (doData) { + uint8_t *bytes; + CFMutableDataRef data; + int i; + int j; + int n; + + n = strlen(argv[0]); + if ((n % 2) == 1) { + SCPrint(TRUE, stdout, CFSTR("d.add: not enough bytes.\n")); + if (doArray) CFRelease(array); + CFRelease(key); + return; + } + + data = CFDataCreateMutable(NULL, (n / 2)); + CFDataSetLength(data, (n / 2)); + + bytes = (uint8_t *)CFDataGetBytePtr(data); + for (i = 0, j = 0; i < n; i += 2, j++) { + unsigned long byte; + char *end; + char str[3] = { 0 }; + + str[0] = argv[0][i]; + str[1] = argv[0][i + 1]; + errno = 0; + byte = strtoul(str, &end, 16); + if ((*end != '\0') || (errno != 0)) { + CFRelease(data); + data = NULL; + break; + } + + bytes[j] = byte; + } + + if (data == NULL) { + SCPrint(TRUE, stdout, CFSTR("d.add: invalid data.\n")); + if (doArray) CFRelease(array); + CFRelease(key); + return; + } + + val = data; } else if (doNumeric) { int intValue; diff --git a/scutil.tproj/nc.c b/scutil.tproj/nc.c index 48806d0..551289c 100644 --- a/scutil.tproj/nc.c +++ b/scutil.tproj/nc.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2011 Apple Inc. All rights reserved. + * Copyright (c) 2010-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,6 +28,12 @@ * - initial revision * February 8, 2011 Kevin Wells * - added "select" command + * January 2012 Kevin Wells + * - added arguments to "start" command to pass authentication credentials + * - "show" now takes a service name as an alternative to a service ID + * - fixes a bug whereby "IPv4" was being displayed as a subtype to IPsec services + * - improved format of "list" output + * - general cleanup of error messages and some variable names */ @@ -37,8 +43,11 @@ #include +CFStringRef username = NULL; +CFStringRef password = NULL; +CFStringRef sharedsecret = NULL; -static SCNetworkConnectionRef connectionRef = NULL; +static SCNetworkConnectionRef connection = NULL; static int n_callback = 0; @@ -56,19 +65,18 @@ my_CFRelease(void *t) } /* ----------------------------------------------------------------------------- ------------------------------------------------------------------------------ */ -static CFStringRef -nc_copy_serviceID(int argc, char **argv) -{ - CFStringRef serviceIDRef = NULL; + ----------------------------------------------------------------------------- */ +static void +nc_get_service_type_and_subtype(SCNetworkServiceRef service, CFStringRef *iftype, CFStringRef *ifsubtype) { + SCNetworkInterfaceRef interface = SCNetworkServiceGetInterface(service); + SCNetworkInterfaceRef child = SCNetworkInterfaceGetInterface(interface); - if (argc == 0) { - serviceIDRef = _copyStringFromSTDIN(); - } else { - serviceIDRef = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); + *iftype = SCNetworkInterfaceGetInterfaceType(interface); + *ifsubtype = NULL; + if (CFEqual(*iftype, kSCNetworkInterfaceTypePPP) || + CFEqual(*iftype, kSCNetworkInterfaceTypeVPN)) { + *ifsubtype = (child != NULL) ? SCNetworkInterfaceGetInterfaceType(child) : NULL; } - - return serviceIDRef; } /* ----------------------------------------------------------------------------- @@ -114,19 +122,40 @@ nc_copy_service(SCNetworkSetRef set, CFStringRef identifier) } else { // if multiple services match selected = NULL; - SCPrint(TRUE, stdout, CFSTR("multiple services match\n")); + SCPrint(TRUE, stderr, CFSTR("Multiple services match\n")); goto done; } } } - done : +done : if (selected != NULL) CFRetain(selected); if (services != NULL) CFRelease(services); return selected; } +/* ----------------------------------------------------------------------------- + ----------------------------------------------------------------------------- */ +static SCNetworkServiceRef +nc_copy_service_from_arguments(int argc, char **argv, SCNetworkSetRef set) { + CFStringRef serviceID = NULL; + SCNetworkServiceRef service = NULL; + + if (argc == 0) { + serviceID = _copyStringFromSTDIN(); + } else { + serviceID = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); + } + if (serviceID == NULL) { + SCPrint(TRUE, stderr, CFSTR("No service ID specified\n")); + return NULL; + } + service = nc_copy_service(set, serviceID); + my_CFRelease(&serviceID); + return service; +} + /* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ @@ -194,18 +223,8 @@ nc_create_connection(int argc, char **argv, Boolean exit_on_failure) { SCNetworkConnectionContext context = { 0, &n_callback, NULL, NULL, NULL }; SCNetworkServiceRef service; - CFStringRef serviceIDRef; - serviceIDRef = nc_copy_serviceID(argc, argv); - if (serviceIDRef == NULL) { - SCPrint(TRUE, stderr, CFSTR("No service identifier\n")); - if (exit_on_failure) - exit(1); - return; - } - - service = nc_copy_service(NULL, serviceIDRef); - CFRelease(serviceIDRef); + service = nc_copy_service_from_arguments(argc, argv, NULL); if (service == NULL) { SCPrint(TRUE, stderr, CFSTR("No service\n")); if (exit_on_failure) @@ -213,9 +232,10 @@ nc_create_connection(int argc, char **argv, Boolean exit_on_failure) return; } - connectionRef = SCNetworkConnectionCreateWithService(NULL, service, nc_callback, &context); - if (connectionRef == NULL) { - SCPrint(TRUE, stderr, CFSTR("nc_create_connection SCNetworkConnectionCreateWithServiceID() failed to create connectionRef: %s\n"), SCErrorString(SCError())); + connection = SCNetworkConnectionCreateWithService(NULL, service, nc_callback, &context); + CFRelease(service); + if (connection == NULL) { + SCPrint(TRUE, stderr, CFSTR("Could not create connection: %s\n"), SCErrorString(SCError())); if (exit_on_failure) exit(1); return; @@ -227,7 +247,7 @@ nc_create_connection(int argc, char **argv, Boolean exit_on_failure) static void nc_release_connection() { - my_CFRelease(&connectionRef); + my_CFRelease(&connection); } /* ----------------------------------------------------------------------------- @@ -235,10 +255,76 @@ nc_release_connection() static void nc_start(int argc, char **argv) { + CFMutableDictionaryRef userOptions = NULL; + CFStringRef iftype = NULL; + CFStringRef ifsubtype = NULL; + SCNetworkServiceRef service = NULL; + nc_create_connection(argc, argv, TRUE); - SCNetworkConnectionStart(connectionRef, 0, TRUE); + service = SCNetworkConnectionGetService(connection); + nc_get_service_type_and_subtype(service, &iftype, &ifsubtype); + + userOptions = CFDictionaryCreateMutable(NULL, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + Boolean isL2TP = (CFEqual(iftype, kSCEntNetPPP) && + (ifsubtype != NULL) && CFEqual(ifsubtype, kSCValNetInterfaceSubTypeL2TP)); + + if (CFEqual(iftype, kSCEntNetPPP)) { + CFMutableDictionaryRef pppEntity = CFDictionaryCreateMutable(NULL, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + if (username != NULL) { + CFDictionarySetValue(pppEntity, kSCPropNetPPPAuthName, username); + } + if (password != NULL) { + CFDictionarySetValue(pppEntity, kSCPropNetPPPAuthPassword, password); + } + CFDictionarySetValue(userOptions, kSCEntNetPPP, pppEntity); + my_CFRelease(&pppEntity); + } + if (CFEqual(iftype, kSCEntNetIPSec) || isL2TP) { + CFMutableDictionaryRef ipsecEntity = CFDictionaryCreateMutable(NULL, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (!isL2TP) { + if (username != NULL) { + CFDictionarySetValue(ipsecEntity, kSCPropNetIPSecXAuthName, username); + } + if (password != NULL) { + CFDictionarySetValue(ipsecEntity, kSCPropNetIPSecXAuthPassword, password); + } + } + if (sharedsecret != NULL) { + CFDictionarySetValue(ipsecEntity, kSCPropNetIPSecSharedSecret, sharedsecret); + } + CFDictionarySetValue(userOptions, kSCEntNetIPSec, ipsecEntity); + my_CFRelease(&ipsecEntity); + } + if (CFEqual(iftype, kSCEntNetVPN)) { + CFMutableDictionaryRef vpnEntity = CFDictionaryCreateMutable(NULL, 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + if (username != NULL) { + CFDictionarySetValue(vpnEntity, kSCPropNetVPNAuthName, username); + } + if (password != NULL) { + CFDictionarySetValue(vpnEntity, kSCPropNetVPNAuthPassword, password); + } + CFDictionarySetValue(userOptions, kSCEntNetVPN, vpnEntity); + my_CFRelease(&vpnEntity); + } + // If it doesn't match any VPN type, fail silently + + if (!SCNetworkConnectionStart(connection, userOptions, TRUE)) { + SCPrint(TRUE, stderr, CFSTR("Could not start connection: %s\n"), SCErrorString(SCError())); + exit(1); + }; + + CFRelease(userOptions); nc_release_connection(); exit(0); } @@ -250,7 +336,10 @@ nc_stop(int argc, char **argv) { nc_create_connection(argc, argv, TRUE); - SCNetworkConnectionStop(connectionRef, TRUE); + if (!SCNetworkConnectionStop(connection, TRUE)) { + SCPrint(TRUE, stderr, CFSTR("Could not stop connection: %s\n"), SCErrorString(SCError())); + exit(1); + }; nc_release_connection(); exit(0); @@ -263,7 +352,7 @@ nc_suspend(int argc, char **argv) { nc_create_connection(argc, argv, TRUE); - SCNetworkConnectionSuspend(connectionRef); + SCNetworkConnectionSuspend(connection); nc_release_connection(); exit(0); @@ -276,7 +365,7 @@ nc_resume(int argc, char **argv) { nc_create_connection(argc, argv, TRUE); - SCNetworkConnectionResume(connectionRef); + SCNetworkConnectionResume(connection); nc_release_connection(); exit(0); @@ -291,8 +380,8 @@ nc_status(int argc, char **argv) nc_create_connection(argc, argv, TRUE); - status = SCNetworkConnectionGetStatus(connectionRef); - nc_callback(connectionRef, status, NULL); + status = SCNetworkConnectionGetStatus(connection); + nc_callback(connection, status, NULL); nc_release_connection(); exit(0); @@ -305,21 +394,21 @@ nc_watch(int argc, char **argv) nc_create_connection(argc, argv, TRUE); - status = SCNetworkConnectionGetStatus(connectionRef); + status = SCNetworkConnectionGetStatus(connection); // report initial status n_callback = 0; - nc_callback(connectionRef, status, &n_callback); + nc_callback(connection, status, &n_callback); // setup watcher if (doDispatch) { - if (!SCNetworkConnectionSetDispatchQueue(connectionRef, dispatch_get_current_queue())) { - printf("SCNetworkConnectionSetDispatchQueue() failed: %s\n", SCErrorString(SCError())); + if (!SCNetworkConnectionSetDispatchQueue(connection, dispatch_get_current_queue())) { + SCPrint(TRUE, stderr, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError())); exit(1); } } else { - if (!SCNetworkConnectionScheduleWithRunLoop(connectionRef, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { - printf("SCNetworkConnectinScheduleWithRunLoop() failed: %s\n", SCErrorString(SCError())); + if (!SCNetworkConnectionScheduleWithRunLoop(connection, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode)) { + SCPrint(TRUE, stderr, CFSTR("Unable to schedule watch process: %s\n"), SCErrorString(SCError())); exit(1); } } @@ -340,7 +429,7 @@ nc_statistics(int argc, char **argv) nc_create_connection(argc, argv, TRUE); - stats_dict = SCNetworkConnectionCopyStatistics(connectionRef); + stats_dict = SCNetworkConnectionCopyStatistics(connection); if (stats_dict) { SCPrint(TRUE, stdout, CFSTR("%@\n"), stats_dict); @@ -356,6 +445,47 @@ nc_statistics(int argc, char **argv) /* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ +static void +checkOnDemandHost(SCDynamicStoreRef store, CFStringRef nodeName, Boolean retry) +{ + Boolean ok; + CFStringRef connectionServiceID = NULL; + SCNetworkConnectionStatus connectionStatus = 0; + CFStringRef vpnRemoteAddress = NULL; + + SCPrint(TRUE, stdout, CFSTR("OnDemand host/domain check (%sretry)\n"), retry ? "" : "no "); + + ok = __SCNetworkConnectionCopyOnDemandInfoWithName(&store, + nodeName, + retry, + &connectionServiceID, + &connectionStatus, + &vpnRemoteAddress); + + if (ok) { + SCPrint(TRUE, stdout, CFSTR(" serviceID = %@\n"), connectionServiceID); + SCPrint(TRUE, stdout, CFSTR(" remote address = %@\n"), vpnRemoteAddress); + } else if (SCError() != kSCStatusOK) { + SCPrint(TRUE, stdout, CFSTR("%sretry\n"), retry ? "" : "no "); + SCPrint(TRUE, stdout, + CFSTR(" Unable to copy OnDemand information for connection: %s\n"), + SCErrorString(SCError())); + } else { + SCPrint(TRUE, stdout, CFSTR(" no match\n")); + } + + if (connectionServiceID != NULL) { + CFRelease(connectionServiceID); + connectionServiceID = NULL; + } + if (vpnRemoteAddress != NULL) { + CFRelease(vpnRemoteAddress); + vpnRemoteAddress = NULL; + } + + return; +} + static void nc_ondemand(int argc, char **argv) { @@ -366,16 +496,21 @@ nc_ondemand(int argc, char **argv) store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), NULL, NULL); if (store == NULL) { - SCPrint(TRUE, stderr, CFSTR("do_nc_ondemand SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError())); + SCPrint(TRUE, stderr, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError())); goto done; } - key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetOnDemand); - if (key == NULL) { - SCPrint(TRUE, stderr, CFSTR("do_nc_ondemand SCDynamicStoreKeyCreateNetworkGlobalEntity() failed: %s\n"), SCErrorString(SCError())); + if (argc > 0) { + CFStringRef nodeName; + + nodeName = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); + checkOnDemandHost(store, nodeName, FALSE); + checkOnDemandHost(store, nodeName, TRUE); goto done; } + key = SCDynamicStoreKeyCreateNetworkGlobalEntity(NULL, kSCDynamicStoreDomainState, kSCEntNetOnDemand); + ondemand_dict = SCDynamicStoreCopyValue(store, key); if (ondemand_dict) { SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), kSCEntNetOnDemand, ondemand_dict); @@ -391,33 +526,60 @@ done: exit(exit_code); } + /* ----------------------------------------------------------------------------- - Given a string 'key' and a string prefix 'prefix', - return the next component in the slash '/' separated - key. If no slash follows the prefix, return NULL. + ----------------------------------------------------------------------------- */ +#define MAX(a, b) ((a) > (b) ? (a) : (b)) - Examples: - 1. key = "a/b/c" prefix = "a/" returns "b" - 2. key = "a/b/c" prefix = "a/b/" returns NULL ------------------------------------------------------------------------------ */ -CFStringRef parse_component(CFStringRef key, CFStringRef prefix) +CFStringRef +copy_padded_string(CFStringRef original, int width) { - CFMutableStringRef comp; - CFRange range; + CFMutableStringRef padded; - if (!CFStringHasPrefix(key, prefix)) - return NULL; + padded = CFStringCreateMutableCopy(NULL, 0, original); + CFStringPad(padded, CFSTR(" "), MAX(CFStringGetLength(original), width), 0); + return padded; +} - comp = CFStringCreateMutableCopy(NULL, 0, key); - CFStringDelete(comp, CFRangeMake(0, CFStringGetLength(prefix))); - range = CFStringFind(comp, CFSTR("/"), 0); - if (range.location == kCFNotFound) { - CFRelease(comp); - return NULL; - } - range.length = CFStringGetLength(comp) - range.location; - CFStringDelete(comp, range); - return comp; + +static void +nc_print_VPN_service(SCNetworkServiceRef service) +{ + CFStringRef type = NULL; + CFStringRef sub_type = NULL; + + nc_get_service_type_and_subtype(service, &type, &sub_type); + + CFStringRef service_name = SCNetworkServiceGetName(service); + if (service_name == NULL) + service_name = CFSTR(""); + CFStringRef service_name_quoted = CFStringCreateWithFormat(NULL, NULL, CFSTR("\"%@\""), service_name); + if (service_name_quoted == NULL) { + service_name_quoted = CFRetain(CFSTR("")); + } + CFStringRef service_name_padded = copy_padded_string(service_name, 30); + + CFStringRef service_id = SCNetworkServiceGetServiceID(service); + SCNetworkInterfaceRef interface = SCNetworkServiceGetInterface(service); + CFStringRef display_name = SCNetworkInterfaceGetLocalizedDisplayName(interface); + if (display_name == NULL) + display_name = CFSTR(""); + CFStringRef display_name_padded = copy_padded_string(display_name, 18); + + + SCPrint(TRUE, + stdout, + CFSTR("%@ %@ %@ %@ [%@%@%@]\n"), + SCNetworkServiceGetEnabled(service) ? CFSTR("*") : CFSTR(" "), + service_id, + display_name_padded, + service_name_padded, + type, + (sub_type == NULL) ? CFSTR("") : CFSTR(":"), + (sub_type == NULL) ? CFSTR("") : sub_type); + CFRelease(service_name_quoted); + CFRelease(display_name_padded); + CFRelease(service_name_padded); } @@ -427,208 +589,79 @@ static void nc_list(int argc, char **argv) { int count; - int exit_code = 1; int i; - CFStringRef key = NULL; - CFMutableDictionaryRef names = NULL; CFArrayRef services = NULL; - CFStringRef setup = NULL; - SCDynamicStoreRef store; - store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), NULL, NULL); - if (store == NULL) { - SCPrint(TRUE, stderr, CFSTR("nc_list SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError())); - goto done; - } - key = SCDynamicStoreKeyCreateNetworkServiceEntity(0, kSCDynamicStoreDomainSetup, kSCCompAnyRegex, kSCEntNetInterface); - if (key == NULL ) { - SCPrint(TRUE, stderr, CFSTR("nc_list SCDynamicStoreKeyCreateNetworkServiceEntity() failed to create key string\n")); - goto done; - } - setup = SCDynamicStoreKeyCreate(0, CFSTR("%@/%@/%@/"), kSCDynamicStoreDomainSetup, kSCCompNetwork, kSCCompService); - if (setup == NULL) { - SCPrint(TRUE, stderr, CFSTR("nc_list SCDynamicStoreKeyCreate() failed to create setup string\n")); - goto done; - } - names = CFDictionaryCreateMutable(NULL, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); - if (names == NULL) { - SCPrint(TRUE, stderr, CFSTR("nc_list CFDictionaryCreateMutable() failed to create names dictionary\n")); - goto done; - } + SCPrint(TRUE, stdout, CFSTR("Available network connection services in the current set (*=enabled):\n")); services = SCNetworkConnectionCopyAvailableServices(NULL); if (services != NULL) { count = CFArrayGetCount(services); for (i = 0; i < count; i++) { SCNetworkServiceRef service; - CFStringRef serviceID; - CFStringRef serviceName; service = CFArrayGetValueAtIndex(services, i); - serviceID = SCNetworkServiceGetServiceID(service); - serviceName = SCNetworkServiceGetName(service); - if (serviceName != NULL) { - CFDictionarySetValue(names, serviceID, serviceName); - } + nc_print_VPN_service(service); } - CFRelease(services); - } - - services = SCDynamicStoreCopyKeyList(store, key); - if (services == NULL ) { - SCPrint(TRUE, stderr, CFSTR("nc_list SCDynamicStoreCopyKeyList() failed: %s\n"), SCErrorString(SCError())); - goto done; } - - count = CFArrayGetCount(services); - for (i = 0; i < count; i++) { - CFStringRef serviceID; - - serviceID = parse_component(CFArrayGetValueAtIndex(services, i), setup); - if (serviceID) { - CFStringRef iftype; - CFStringRef ifsubtype; - CFStringRef interface_key = NULL; - CFDictionaryRef interface_dict = NULL; - CFStringRef service_name; - - interface_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, kSCEntNetInterface); - if (!interface_key) { - SCPrint(TRUE, stderr, CFSTR("nc_list SCDynamicStoreKeyCreateNetworkServiceEntity() failed to interface key string\n")); - goto endloop; - } - - interface_dict = SCDynamicStoreCopyValue(store, interface_key); - if (!interface_dict) { - SCPrint(TRUE, stderr, CFSTR("nc_list SCDynamicStoreCopyValue() to copy interface dictionary: %s\n"), SCErrorString(SCError())); - goto endloop; - } - - iftype = CFDictionaryGetValue(interface_dict, kSCPropNetInterfaceType); - if (!iftype) { - // is that an error condition ??? - goto endloop; - } - - if (!CFEqual(iftype, kSCEntNetPPP) && - !CFEqual(iftype, kSCEntNetIPSec) && - !CFEqual(iftype, kSCEntNetVPN)) - goto endloop; - - ifsubtype = CFDictionaryGetValue(interface_dict, kSCPropNetInterfaceSubType); - - service_name = CFDictionaryGetValue(names, serviceID); - - SCPrint(TRUE, stdout, CFSTR("[%@%@%@] %@%s%@\n"), - iftype ? iftype : CFSTR("?"), - ifsubtype ? CFSTR("/") : CFSTR(""), - ifsubtype ? ifsubtype : CFSTR(""), - serviceID, - service_name ? " : " : "", - service_name ? service_name : CFSTR("")); - - endloop: - my_CFRelease(&interface_key); - my_CFRelease(&interface_dict); - my_CFRelease(&serviceID); - } - } - - exit_code = 0; -done: my_CFRelease(&services); - my_CFRelease(&names); - my_CFRelease(&setup); - my_CFRelease(&key); - my_CFRelease(&store); - exit(exit_code); + exit(0); } + /* ----------------------------------------------------------------------------- ----------------------------------------------------------------------------- */ static void nc_show(int argc, char **argv) { + SCNetworkServiceRef service = NULL; SCDynamicStoreRef store = NULL; int exit_code = 1; - CFStringRef setup = NULL; - CFStringRef serviceIDRef = NULL; - CFArrayRef services = NULL; + CFStringRef serviceID = NULL; CFStringRef iftype = NULL; CFStringRef ifsubtype = NULL; - CFStringRef interface_key = NULL; - CFDictionaryRef interface_dict = NULL; CFStringRef type_entity_key = NULL; CFStringRef subtype_entity_key = NULL; CFDictionaryRef type_entity_dict = NULL; CFDictionaryRef subtype_entity_dict = NULL; - serviceIDRef = nc_copy_serviceID(argc, argv); - if (serviceIDRef == NULL) { - SCPrint(TRUE, stderr, CFSTR("No service ID\n")); - goto done; - } - - store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), NULL, NULL); - if (store == NULL) { - SCPrint(TRUE, stderr, CFSTR("nc_show SCDynamicStoreCreate() failed: %s\n"), SCErrorString(SCError())); - goto done; + service = nc_copy_service_from_arguments(argc, argv, NULL); + if (service == NULL) { + SCPrint(TRUE, stderr, CFSTR("No service\n")); + exit(exit_code); } - interface_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceIDRef, kSCEntNetInterface); - if (!interface_key) { - SCPrint(TRUE, stderr, CFSTR("nc_show SCDynamicStoreKeyCreateNetworkServiceEntity() failed to create interface key\n")); - goto done; - } + serviceID = SCNetworkServiceGetServiceID(service); - interface_dict = SCDynamicStoreCopyValue(store, interface_key); - if (!interface_dict) { - SCPrint(TRUE, stdout, CFSTR("Interface dictionary missing for service ID : %@\n"), serviceIDRef); - goto done; - } - - iftype = CFDictionaryGetValue(interface_dict, kSCPropNetInterfaceType); - if (!iftype) { - SCPrint(TRUE, stdout, CFSTR("Interface Type missing for service ID : %@\n"), serviceIDRef); - goto done; - } + nc_get_service_type_and_subtype(service, &iftype, &ifsubtype); if (!CFEqual(iftype, kSCEntNetPPP) && - !CFEqual(iftype, kSCEntNetIPSec) && - !CFEqual(iftype, kSCEntNetVPN)) { - SCPrint(TRUE, stdout, CFSTR("Interface Type [%@] invalid for service ID : %@\n"), iftype, serviceIDRef); + !CFEqual(iftype, kSCEntNetIPSec) && + !CFEqual(iftype, kSCEntNetVPN)) { + SCPrint(TRUE, stderr, CFSTR("Not a connection oriented service: %@\n"), serviceID); goto done; } - ifsubtype = CFDictionaryGetValue(interface_dict, kSCPropNetInterfaceSubType); - SCPrint(TRUE, stdout, CFSTR("[%@%@%@] %@\n"), - iftype ? iftype : CFSTR("?"), - ifsubtype ? CFSTR("/") : CFSTR(""), - ifsubtype ? ifsubtype : CFSTR(""), - serviceIDRef); + type_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, iftype); + + nc_print_VPN_service(service); - type_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceIDRef, iftype); - if (!type_entity_key) { - SCPrint(TRUE, stderr, CFSTR("nc_show SCDynamicStoreKeyCreateNetworkServiceEntity() failed to create type entity key\n")); + store = SCDynamicStoreCreate(NULL, CFSTR("scutil --nc"), NULL, NULL); + if (store == NULL) { + SCPrint(TRUE, stderr, CFSTR("Unable to create dynamic store: %s\n"), SCErrorString(SCError())); goto done; } type_entity_dict = SCDynamicStoreCopyValue(store, type_entity_key); + if (!type_entity_dict) { - SCPrint(TRUE, stdout, CFSTR("%@ dictionary missing for service ID : %@\n"), iftype, serviceIDRef); + SCPrint(TRUE, stderr, CFSTR("No \"%@\" configuration available\n"), iftype); } else { SCPrint(TRUE, stdout, CFSTR("%@ %@\n"), iftype, type_entity_dict); } if (ifsubtype) { - subtype_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceIDRef, ifsubtype); - if (!subtype_entity_key) { - SCPrint(TRUE, stderr, CFSTR("nc_show SCDynamicStoreKeyCreateNetworkServiceEntity() failed to create subtype entity key\n")); - goto done; - } + subtype_entity_key = SCDynamicStoreKeyCreateNetworkServiceEntity(NULL, kSCDynamicStoreDomainSetup, serviceID, ifsubtype); subtype_entity_dict = SCDynamicStoreCopyValue(store, subtype_entity_key); if (!subtype_entity_dict) { // @@ -641,17 +674,12 @@ nc_show(int argc, char **argv) exit_code = 0; done: - my_CFRelease(&serviceIDRef); - my_CFRelease(&interface_key); - my_CFRelease(&interface_dict); my_CFRelease(&type_entity_key); my_CFRelease(&type_entity_dict); my_CFRelease(&subtype_entity_key); my_CFRelease(&subtype_entity_dict); - my_CFRelease(&services); - my_CFRelease(&setup); my_CFRelease(&store); - + my_CFRelease(&service); exit(exit_code); } @@ -663,40 +691,33 @@ nc_select(int argc, char **argv) SCNetworkSetRef current_set; int exit_code = 1; SCNetworkServiceRef service = NULL; - CFStringRef service_id; Boolean status; - service_id = nc_copy_serviceID(argc, argv); - if (service_id == NULL) { - SCPrint(TRUE, stderr, CFSTR("No service identifier\n")); - exit(exit_code); - } - do_prefs_init(); /* initialization */ do_prefs_open(0, NULL); /* open default prefs */ current_set = SCNetworkSetCopyCurrent(prefs); if (current_set == NULL) { - SCPrint(TRUE, stdout, CFSTR("nc_select SCNetworkSetCopyCurrent() failed: %s\n"), SCErrorString(SCError())); + SCPrint(TRUE, stderr, CFSTR("No current location\n"), SCErrorString(SCError())); goto done; } - service = nc_copy_service(current_set, service_id); + service = nc_copy_service_from_arguments(argc, argv, current_set); if (service == NULL) { - SCPrint(TRUE, stdout, CFSTR("No service\n")); + SCPrint(TRUE, stderr, CFSTR("No service\n")); goto done; } #if !TARGET_OS_IPHONE status = SCNetworkServiceSetEnabled(service, TRUE); if (!status) { - SCPrint(TRUE, stdout, CFSTR("nc_select SCNetworkServiceSetEnabled() failed: %s\n"), SCErrorString(SCError())); + SCPrint(TRUE, stderr, CFSTR("Unable to enable service: %s\n"), SCErrorString(SCError())); goto done; } #else status = SCNetworkSetSetSelectedVPNService(current_set, service); if (!status) { - SCPrint(TRUE, stdout, CFSTR("nc_select SCNetworkSetSetSelectedVPNService() failed: %s\n"), SCErrorString(SCError())); + SCPrint(TRUE, stderr, CFSTR("Unable to select service: %s\n"), SCErrorString(SCError())); goto done; } #endif @@ -704,8 +725,7 @@ nc_select(int argc, char **argv) _prefs_save(); exit_code = 0; done: - - my_CFRelease(&service_id); + my_CFRelease(&service); my_CFRelease(¤t_set); _prefs_close(); exit(exit_code); diff --git a/scutil.tproj/nc.h b/scutil.tproj/nc.h index 0541324..817bbee 100644 --- a/scutil.tproj/nc.h +++ b/scutil.tproj/nc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010, 2011 Apple Inc. All rights reserved. + * Copyright (c) 2010-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -24,7 +24,7 @@ /* * Modification History * - * March1, 2010 Christophe Allie + * March 1, 2010 Christophe Allie * - initial revision */ @@ -34,6 +34,9 @@ #include #include +extern CFStringRef username; +extern CFStringRef password; +extern CFStringRef sharedsecret; __BEGIN_DECLS diff --git a/scutil.tproj/net.c b/scutil.tproj/net.c index 550032d..cb1ebfb 100644 --- a/scutil.tproj/net.c +++ b/scutil.tproj/net.c @@ -61,7 +61,7 @@ __private_extern__ CFNumberRef CFNumberRef_1 = NULL; __private_extern__ -CFNumberRef +CF_RETURNS_RETAINED CFNumberRef _copy_number(const char *arg) { int val; @@ -883,6 +883,7 @@ do_net_update(int argc, char **argv) n = CFArrayGetCount(sets); CFRelease(sets); + sets = NULL; if (n > 0) { SCPrint(TRUE, stdout, CFSTR("no current set\n")); return; diff --git a/scutil.tproj/net.h b/scutil.tproj/net.h index 05bbb8e..bd57435 100644 --- a/scutil.tproj/net.h +++ b/scutil.tproj/net.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004, 2006 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004, 2006, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -96,6 +96,7 @@ Boolean _process_options(optionsRef options, char **argv, CFMutableDictionaryRef newConfiguration); +CF_RETURNS_RETAINED CFNumberRef _copy_number (const char *arg); CFIndex _find_option (const char *option, @@ -108,24 +109,24 @@ CFIndex _find_selection (CFStringRef choice, void _show_entity (CFDictionaryRef entity, CFStringRef prefix); -void do_net_init (void); -void do_net_quit (int argc, char **argv); +void do_net_init (void); +void do_net_quit (int argc, char **argv); -void do_net_open (int argc, char **argv); -void do_net_commit (int argc, char **argv); -void do_net_apply (int argc, char **argv); -void do_net_close (int argc, char **argv); +void do_net_open (int argc, char **argv); +void do_net_commit (int argc, char **argv); +void do_net_apply (int argc, char **argv); +void do_net_close (int argc, char **argv); -void do_net_create (int argc, char **argv); -void do_net_disable (int argc, char **argv); -void do_net_enable (int argc, char **argv); -void do_net_remove (int argc, char **argv); -void do_net_select (int argc, char **argv); -void do_net_set (int argc, char **argv); -void do_net_show (int argc, char **argv); -void do_net_update (int argc, char **argv); +void do_net_create (int argc, char **argv); +void do_net_disable (int argc, char **argv); +void do_net_enable (int argc, char **argv); +void do_net_remove (int argc, char **argv); +void do_net_select (int argc, char **argv); +void do_net_set (int argc, char **argv); +void do_net_show (int argc, char **argv); +void do_net_update (int argc, char **argv); -void do_net_snapshot (int argc, char **argv); +void do_net_snapshot (int argc, char **argv); __END_DECLS diff --git a/scutil.tproj/net_interface.c b/scutil.tproj/net_interface.c index 4303b33..ba12204 100644 --- a/scutil.tproj/net_interface.c +++ b/scutil.tproj/net_interface.c @@ -29,6 +29,7 @@ */ +#include #include "scutil.h" #include "net.h" #include "prefs.h" @@ -36,6 +37,11 @@ #include +#if TARGET_OS_EMBEDDED +#define INLINE_PASSWORDS_USE_CFSTRING +#endif // TARGET_OS_EMBEDDED + + #pragma mark - #pragma mark Interface management @@ -119,6 +125,7 @@ _find_interface(int argc, char **argv, int *nArgs) goto done; } +#if !TARGET_OS_IPHONE else if (strcasecmp(argv[0], "$bond") == 0) { CFStringRef interfaceType; @@ -148,6 +155,7 @@ _find_interface(int argc, char **argv, int *nArgs) } allowIndex = FALSE; } +#endif // !TARGET_OS_IPHONE else if (strcasecmp(argv[0], "$bridge") == 0) { CFStringRef interfaceType; @@ -924,6 +932,63 @@ show_interfaces(int argc, char **argv) /* -------------------- */ +static int +__doRank(CFStringRef key, const char *description, void *info, int argc, char **argv, CFMutableDictionaryRef newConfiguration) +{ + SCNetworkInterfaceRef interface; + CFStringRef interfaceName; + Boolean ok = FALSE; + SCNetworkServicePrimaryRank rank = kSCNetworkServicePrimaryRankDefault; + SCDynamicStoreRef store; + + if (argc < 1) { + SCPrint(TRUE, stdout, + CFSTR("%s not specified\n"), + description != NULL ? description : "rank"); + return -1; + } + + if (strlen(argv[0]) == 0) { + rank = kSCNetworkServicePrimaryRankDefault; + } else if ((strcasecmp(argv[0], "First") == 0)) { + rank = kSCNetworkServicePrimaryRankFirst; + } else if ((strcasecmp(argv[0], "Last") == 0)) { + rank = kSCNetworkServicePrimaryRankLast; + } else if ((strcasecmp(argv[0], "Never") == 0)) { + rank = kSCNetworkServicePrimaryRankNever; + } else { + SCPrint(TRUE, stdout, CFSTR("invalid rank\n")); + return -1; + } + + interfaceName = SCNetworkInterfaceGetBSDName(net_interface); + if (interfaceName == NULL) { + SCPrint(TRUE, stdout, CFSTR("no BSD interface\n")); + return FALSE; + } + + store = SCDynamicStoreCreate(NULL, CFSTR("scutil --net"), NULL, NULL); + interface = _SCNetworkInterfaceCopyActive(store, interfaceName); + CFRelease(store); + if (interface == NULL) { + SCPrint(TRUE, stdout, CFSTR("No active interface\n")); + return -1; + } + + ok = SCNetworkInterfaceSetPrimaryRank(interface, rank); + CFRelease(interface); + if (!ok) { + SCPrint(TRUE, stdout, CFSTR("could not update per-interface rank\n")); + return -1; + } + + return 1; +} + + +/* -------------------- */ + + static void _replaceOne(const void *key, const void *value, void *context) { @@ -1041,7 +1106,9 @@ static options airportOptions[] = { { "media" , NULL, isString , &kSCPropNetEthernetMediaSubType, NULL, NULL }, { "mediaopt" , NULL, isStringArray, &kSCPropNetEthernetMediaOptions, NULL, NULL }, - { "?" , NULL , isHelp , NULL , NULL, + { "rank" , NULL, isOther , NULL , __doRank, NULL }, + + { "?" , NULL, isHelp , NULL , NULL, "\nAirPort configuration commands\n\n" " set interface [mtu n] [media type] [mediaopts opts]\n" } @@ -1131,7 +1198,9 @@ static options ethernetOptions[] = { { "tso" , NULL, isOther , &kSCPropNetEthernetCapabilityTSO , __doCapability, NULL }, { "txcsum" , NULL, isOther , &kSCPropNetEthernetCapabilityTXCSUM, __doCapability, NULL }, - { "?" , NULL , isHelp , NULL , NULL, + { "rank" , NULL, isOther , NULL , __doRank, NULL }, + + { "?" , NULL, isHelp , NULL , NULL, "\nEthernet configuration commands\n\n" " set interface [mtu n] [media type] [mediaopts opts]\n" } @@ -1180,6 +1249,11 @@ __doIPSecSharedSecret(CFStringRef key, const char *description, void *info, int encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecSharedSecretEncryption); if (strlen(argv[0]) > 0) { if (encryptionType == NULL) { +#ifdef INLINE_PASSWORDS_USE_CFSTRING + CFStringRef pw; + + pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); +#else // INLINE_PASSWORDS_USE_CFSTRING CFIndex n; CFMutableDataRef pw; CFStringRef str; @@ -1188,10 +1262,12 @@ __doIPSecSharedSecret(CFStringRef key, const char *description, void *info, int n = CFStringGetLength(str); pw = CFDataCreateMutable(NULL, n * sizeof(UniChar)); CFDataSetLength(pw, n * sizeof(UniChar)); + /* ALIGN: CF aligns to at least >8 bytes */ CFStringGetCharacters(str, CFRangeMake(0, n), - (UniChar *)CFDataGetMutableBytePtr(pw)); + (UniChar *)(void *)CFDataGetMutableBytePtr(pw)); CFRelease(str); +#endif // INLINE_PASSWORDS_USE_CFSTRING CFDictionarySetValue(newConfiguration, key, pw); CFRelease(pw); @@ -1277,6 +1353,11 @@ __doIPSecXAuthPassword(CFStringRef key, const char *description, void *info, int encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetIPSecXAuthPasswordEncryption); if (strlen(argv[0]) > 0) { if (encryptionType == NULL) { +#ifdef INLINE_PASSWORDS_USE_CFSTRING + CFStringRef pw; + + pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); +#else // INLINE_PASSWORDS_USE_CFSTRING CFIndex n; CFMutableDataRef pw; CFStringRef str; @@ -1285,10 +1366,12 @@ __doIPSecXAuthPassword(CFStringRef key, const char *description, void *info, int n = CFStringGetLength(str); pw = CFDataCreateMutable(NULL, n * sizeof(UniChar)); CFDataSetLength(pw, n * sizeof(UniChar)); + /* ALIGN: CF aligns to at least >8 byte boundries */ CFStringGetCharacters(str, CFRangeMake(0, n), - (UniChar *)CFDataGetMutableBytePtr(pw)); + (UniChar *)(void *)CFDataGetMutableBytePtr(pw)); CFRelease(str); +#endif // INLINE_PASSWORDS_USE_CFSTRING CFDictionarySetValue(newConfiguration, key, pw); CFRelease(pw); @@ -1362,7 +1445,7 @@ __doIPSecXAuthPasswordType(CFStringRef key, const char *description, void *info, } -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef __cleanupDomainName(CFStringRef domain) { CFMutableStringRef newDomain; @@ -1642,6 +1725,11 @@ __doPPPAuthPW(CFStringRef key, const char *description, void *info, int argc, ch encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetPPPAuthPasswordEncryption); if (strlen(argv[0]) > 0) { if (encryptionType == NULL) { +#ifdef INLINE_PASSWORDS_USE_CFSTRING + CFStringRef pw; + + pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); +#else // INLINE_PASSWORDS_USE_CFSTRING CFIndex n; CFMutableDataRef pw; CFStringRef str; @@ -1650,10 +1738,12 @@ __doPPPAuthPW(CFStringRef key, const char *description, void *info, int argc, ch n = CFStringGetLength(str); pw = CFDataCreateMutable(NULL, n * sizeof(UniChar)); CFDataSetLength(pw, n * sizeof(UniChar)); + /* ALIGN: CF aligns to at least >8 byte boundries */ CFStringGetCharacters(str, CFRangeMake(0, n), - (UniChar *)CFDataGetMutableBytePtr(pw)); + (UniChar *)(void *)CFDataGetMutableBytePtr(pw)); CFRelease(str); +#endif // INLINE_PASSWORDS_USE_CFSTRING CFDictionarySetValue(newConfiguration, key, pw); CFRelease(pw); @@ -1992,7 +2082,11 @@ __doVPNAuthPW(CFStringRef key, const char *description, void *info, int argc, ch encryptionType = CFDictionaryGetValue(newConfiguration, kSCPropNetVPNAuthPasswordEncryption); if (strlen(argv[0]) > 0) { if (encryptionType == NULL) { -#ifdef USE_INLINE_CFDATA +#ifdef INLINE_PASSWORDS_USE_CFSTRING + CFStringRef pw; + + pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); +#else // INLINE_PASSWORDS_USE_CFSTRING CFIndex n; CFMutableDataRef pw; CFStringRef str; @@ -2003,13 +2097,9 @@ __doVPNAuthPW(CFStringRef key, const char *description, void *info, int argc, ch CFDataSetLength(pw, n * sizeof(UniChar)); CFStringGetCharacters(str, CFRangeMake(0, n), - (UniChar *)CFDataGetMutableBytePtr(pw)); + (UniChar *)(void *)CFDataGetMutableBytePtr(pw)); CFRelease(str); -#else // USE_INLINE_CFDATA - CFStringRef pw; - - pw = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); -#endif // USE_INLINE_CFDATA +#endif // INLINE_PASSWORDS_USE_CFSTRING CFDictionarySetValue(newConfiguration, key, pw); CFRelease(pw); @@ -2251,7 +2341,7 @@ show_interface(int argc, char **argv) __private_extern__ -CFStringRef +CF_RETURNS_RETAINED CFStringRef _interface_description(SCNetworkInterfaceRef interface) { CFMutableStringRef description; diff --git a/scutil.tproj/net_interface.h b/scutil.tproj/net_interface.h index af42956..4d1ed4a 100644 --- a/scutil.tproj/net_interface.h +++ b/scutil.tproj/net_interface.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -35,14 +35,16 @@ __BEGIN_DECLS +CF_RETURNS_RETAINED CFStringRef _interface_description (SCNetworkInterfaceRef interface); + SCNetworkInterfaceRef _find_interface (int argc, char **argv, int *nArgs); -void create_interface (int argc, char **argv); -void select_interface (int argc, char **argv); -void set_interface (int argc, char **argv); -void show_interface (int argc, char **argv); -void show_interfaces (int argc, char **argv); +void create_interface (int argc, char **argv); +void select_interface (int argc, char **argv); +void set_interface (int argc, char **argv); +void show_interface (int argc, char **argv); +void show_interfaces (int argc, char **argv); __END_DECLS diff --git a/scutil.tproj/net_protocol.c b/scutil.tproj/net_protocol.c index 2da53af..46869de 100644 --- a/scutil.tproj/net_protocol.c +++ b/scutil.tproj/net_protocol.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2009 Apple Inc. All rights reserved. + * Copyright (c) 2004-2009, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -66,10 +66,7 @@ __copyIPv4Address(const char *arg) char buf[128]; struct sockaddr_in sin; - bzero(&sin, sizeof(sin)); - sin.sin_len = sizeof(sin); - sin.sin_family = AF_INET; - if (inet_aton(arg, &sin.sin_addr) != 1) { + if (_SC_string_to_sockaddr(arg, AF_INET, (void *)&sin, sizeof(sin)) == NULL) { return NULL; } @@ -82,21 +79,12 @@ static CFStringRef __copyIPv6Address(const char *arg) { char buf[128]; - char *p; struct sockaddr_in6 sin6; - bzero(&sin6, sizeof(sin6)); - sin6.sin6_len = sizeof(sin6); - sin6.sin6_family = AF_INET6; - if (inet_pton(AF_INET6, arg, &sin6.sin6_addr) != 1) { + if (_SC_string_to_sockaddr(arg, AF_INET6, (void *)&sin6, sizeof(sin6)) == NULL) { return NULL; } - p = strchr(arg, '%'); - if (p != NULL) { - sin6.sin6_scope_id = if_nametoindex(p + 1); - } - _SC_sockaddr_to_string((struct sockaddr *)&sin6, buf, sizeof(buf)); return CFStringCreateWithCString(NULL, buf, kCFStringEncodingUTF8); } @@ -421,7 +409,7 @@ select_protocol(int argc, char **argv) #pragma mark DNS -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef __cleanupDomainName(CFStringRef domain) { CFMutableStringRef newDomain; @@ -1173,6 +1161,7 @@ __doProxyPort(CFStringRef key, const char *description, void *info, int argc, ch !CFNumberGetValue(num, kCFNumberIntType, &port) || (port < 0) || (port > 65535)) { SCPrint(TRUE, stdout, CFSTR("invalid %s proxy port number\n"), currentProxy->proxy); + if (num != NULL) CFRelease(num); return -1; } @@ -1257,7 +1246,7 @@ set_protocol_proxies(int argc, char **argv, CFMutableDictionaryRef newConfigurat #if !TARGET_OS_IPHONE -static CFStringRef +static CF_RETURNS_RETAINED CFStringRef __cleanupName(CFStringRef name) { CFMutableStringRef newName; @@ -1628,7 +1617,7 @@ show_protocols(int argc, char **argv) __private_extern__ -CFStringRef +CF_RETURNS_RETAINED CFStringRef _protocol_description(SCNetworkProtocolRef protocol, Boolean skipEmpty) { CFDictionaryRef configuration; diff --git a/scutil.tproj/net_protocol.h b/scutil.tproj/net_protocol.h index 30b650e..976cf11 100644 --- a/scutil.tproj/net_protocol.h +++ b/scutil.tproj/net_protocol.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2004, 2011 Apple Computer, Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -36,16 +36,18 @@ __BEGIN_DECLS CFComparisonResult _compare_protocols (const void *val1, const void *val2, void *context); + +CF_RETURNS_RETAINED CFStringRef _protocol_description (SCNetworkProtocolRef protocol, Boolean skipEmpty); -void create_protocol (int argc, char **argv); -void disable_protocol (int argc, char **argv); -void enable_protocol (int argc, char **argv); -void remove_protocol (int argc, char **argv); -void select_protocol (int argc, char **argv); -void set_protocol (int argc, char **argv); -void show_protocol (int argc, char **argv); -void show_protocols (int argc, char **argv); +void create_protocol (int argc, char **argv); +void disable_protocol (int argc, char **argv); +void enable_protocol (int argc, char **argv); +void remove_protocol (int argc, char **argv); +void select_protocol (int argc, char **argv); +void set_protocol (int argc, char **argv); +void show_protocol (int argc, char **argv); +void show_protocols (int argc, char **argv); __END_DECLS diff --git a/scutil.tproj/notifications.c b/scutil.tproj/notifications.c index aadfbe0..a50302e 100644 --- a/scutil.tproj/notifications.c +++ b/scutil.tproj/notifications.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2008-2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2004, 2008-2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -45,6 +46,39 @@ static int osig; static struct sigaction *oact = NULL; +static char * +elapsed() +{ + int n; + static char str[128]; + struct tm tm_diff; + struct tm tm_now; + struct timeval tv_diff; + struct timeval tv_now; + static struct timeval tv_then = { 0, 0 }; + + (void)gettimeofday(&tv_now, NULL); + + (void)localtime_r(&tv_now.tv_sec, &tm_now); + + timersub(&tv_now, &tv_then, &tv_diff); + (void)localtime_r(&tv_diff.tv_sec, &tm_diff); + n = snprintf(str, sizeof(str), "%2d:%02d:%02d.%03d", + tm_now.tm_hour, + tm_now.tm_min, + tm_now.tm_sec, + tv_now.tv_usec / 1000); + if (((tv_then.tv_sec != 0) || (tv_then.tv_usec != 0)) && (n < sizeof(str))) { + snprintf(&str[n], sizeof(str) - n, " (+%ld.%03d)", + tv_diff.tv_sec, + tv_diff.tv_usec / 1000); + } + + tv_then = tv_now; + return str; +} + + static CFComparisonResult sort_keys(const void *p1, const void *p2, void *context) { CFStringRef key1 = (CFStringRef)p1; @@ -67,7 +101,8 @@ storeCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) for (i = 0; i < n; i++) { SCPrint(TRUE, stdout, - CFSTR(" changed key [%d] = %@\n"), + CFSTR(" %s changedKey [%d] = %@\n"), + elapsed(), i, CFArrayGetValueAtIndex(changedKeys, i)); } @@ -227,7 +262,8 @@ do_notify_changes(int argc, char **argv) for (i = 0; i < listCnt; i++) { SCPrint(TRUE, stdout, - CFSTR(" changedKey [%d] = %@\n"), + CFSTR(" %s changedKey [%d] = %@\n"), + elapsed(), i, CFArrayGetValueAtIndex(list, i)); } @@ -308,77 +344,6 @@ do_notify_wait(int argc, char **argv) } -static boolean_t -notificationWatcher(SCDynamicStoreRef store, void *arg) -{ - SCPrint(TRUE, stdout, CFSTR("notification callback (store address = %p).\n"), store); - SCPrint(TRUE, stdout, CFSTR(" arg = %s.\n"), (char *)arg); - return TRUE; -} - - -static boolean_t -notificationWatcherVerbose(SCDynamicStoreRef store, void *arg) -{ - SCPrint(TRUE, stdout, CFSTR("notification callback (store address = %p).\n"), store); - SCPrint(TRUE, stdout, CFSTR(" arg = %s.\n"), (char *)arg); - do_notify_changes(0, NULL); /* report the keys that changed */ - return TRUE; -} - - -static void * -_callback(void *arg) -{ - SCDynamicStoreCallBack_v1 func = (SCDynamicStoreCallBack_v1)arg; - - notifyRl = CFRunLoopGetCurrent(); - if (notifyRl == NULL) { - SCPrint(TRUE, stdout, CFSTR(" CFRunLoopGetCurrent() failed\n")); - return NULL; - } - - if (!SCDynamicStoreNotifyCallback(store, notifyRl, func, "Changed detected by callback handler!")) { - SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); - notifyRl = NULL; - return NULL; - } - - pthread_setname_np("n.callback"); - CFRunLoopRun(); - notifyRl = NULL; - return NULL; -} - - -__private_extern__ -void -do_notify_callback(int argc, char **argv) -{ - SCDynamicStoreCallBack_v1 func = notificationWatcher; - pthread_attr_t tattr; - pthread_t tid; - - if (notifyRl != NULL) { - SCPrint(TRUE, stdout, CFSTR("already active\n")); - return; - } - - if ((argc == 1) && (strcmp(argv[0], "verbose") == 0)) { - func = notificationWatcherVerbose; - } - - pthread_attr_init(&tattr); - pthread_attr_setscope(&tattr, PTHREAD_SCOPE_SYSTEM); - pthread_attr_setdetachstate(&tattr, PTHREAD_CREATE_DETACHED); -// pthread_attr_setstacksize(&tattr, 96 * 1024); // each thread gets a 96K stack - pthread_create(&tid, &tattr, _callback, (void *)func); - pthread_attr_destroy(&tattr); - - return; -} - - __private_extern__ void do_notify_file(int argc, char **argv) diff --git a/scutil.tproj/notifications.h b/scutil.tproj/notifications.h index ec73edf..27a9f39 100644 --- a/scutil.tproj/notifications.h +++ b/scutil.tproj/notifications.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2004 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2004, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -48,7 +48,6 @@ void do_notify_remove (int argc, char **argv); void do_notify_changes (int argc, char **argv); void do_notify_watch (int argc, char **argv); void do_notify_wait (int argc, char **argv); -void do_notify_callback (int argc, char **argv); void do_notify_signal (int argc, char **argv); void do_notify_file (int argc, char **argv); void do_notify_cancel (int argc, char **argv); diff --git a/scutil.tproj/prefs.c b/scutil.tproj/prefs.c index 4e201e1..34e534d 100644 --- a/scutil.tproj/prefs.c +++ b/scutil.tproj/prefs.c @@ -52,7 +52,7 @@ static void * __loadSecurity(void) { static void *image = NULL; if (NULL == image) { - const char *framework = "/System/Library/Frameworks/Security.framework/Versions/A/Security"; + const char *framework = "/System/Library/Frameworks/Security.framework/Security"; struct stat statbuf; const char *suffix = getenv("DYLD_IMAGE_SUFFIX"); char path[MAXPATHLEN]; @@ -145,6 +145,8 @@ _prefs_open(CFStringRef name, CFStringRef prefsID) #if !TARGET_OS_IPHONE authorization = _createAuthorization(); +#else + authorization = (AuthorizationRef)kSCPreferencesUseEntitlementAuthorization; #endif /* !TARGET_OS_IPHONE */ } diff --git a/scutil.tproj/scutil.c b/scutil.tproj/scutil.c index c506724..7578f44 100644 --- a/scutil.tproj/scutil.c +++ b/scutil.tproj/scutil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Apple Inc. All rights reserved. + * Copyright (c) 2000-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -97,11 +97,16 @@ static const struct option longopts[] = { { "dns", no_argument, NULL, 0 }, { "get", required_argument, NULL, 0 }, { "help", no_argument, NULL, '?' }, + { "nc", required_argument, NULL, 0 }, { "net", no_argument, NULL, 0 }, + { "nwi", no_argument, NULL, 0 }, { "prefs", no_argument, NULL, 0 }, { "proxy", no_argument, NULL, 0 }, { "set", required_argument, NULL, 0 }, - { "nc", required_argument, NULL, 0 }, + { "snapshot", no_argument, NULL, 0 }, + { "user", required_argument, NULL, 0 }, + { "password", required_argument, NULL, 0 }, + { "secret", required_argument, NULL, 0 }, { NULL, 0, NULL, 0 } }; @@ -299,6 +304,9 @@ usage(const char *command) SCPrint(TRUE, stderr, CFSTR("\n")); SCPrint(TRUE, stderr, CFSTR(" or: %s --proxy\n"), command); SCPrint(TRUE, stderr, CFSTR("\tshow \"proxy\" configuration.\n")); + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR(" or: %s --nwi\n"), command); + SCPrint(TRUE, stderr, CFSTR("\tshow network information\n")); if (getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) { SCPrint(TRUE, stderr, CFSTR("\n")); @@ -322,9 +330,11 @@ main(int argc, char * const argv[]) { Boolean doDNS = FALSE; Boolean doNet = FALSE; + Boolean doNWI = FALSE; Boolean doPrefs = FALSE; Boolean doProxy = FALSE; Boolean doReach = FALSE; + Boolean doSnap = FALSE; char *get = NULL; extern int optind; int opt; @@ -377,9 +387,15 @@ main(int argc, char * const argv[]) } else if (strcmp(longopts[opti].name, "get") == 0) { get = optarg; xStore++; + } else if (strcmp(longopts[opti].name, "nc") == 0) { + nc_cmd = optarg; + xStore++; } else if (strcmp(longopts[opti].name, "net") == 0) { doNet = TRUE; xStore++; + } else if (strcmp(longopts[opti].name, "nwi") == 0) { + doNWI = TRUE; + xStore++; } else if (strcmp(longopts[opti].name, "prefs") == 0) { doPrefs = TRUE; xStore++; @@ -389,9 +405,15 @@ main(int argc, char * const argv[]) } else if (strcmp(longopts[opti].name, "set") == 0) { set = optarg; xStore++; - } else if (strcmp(longopts[opti].name, "nc") == 0) { - nc_cmd = optarg; + } else if (strcmp(longopts[opti].name, "snapshot") == 0) { + doSnap = TRUE; xStore++; + } else if (strcmp(longopts[opti].name, "user") == 0) { + username = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8); + } else if (strcmp(longopts[opti].name, "password") == 0) { + password = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8); + } else if (strcmp(longopts[opti].name, "secret") == 0) { + sharedsecret = CFStringCreateWithCString(NULL, optarg, kCFStringEncodingUTF8); } break; case '?': @@ -430,6 +452,21 @@ main(int argc, char * const argv[]) /* NOT REACHED */ } + if (doNWI) { + do_nwi(argc, (char**)argv); + /* NOT REACHED */ + } + + if (doSnap) { + if (!enablePrivateAPI || (geteuid() != 0)) { + usage(prog); + } + + do_open(0, NULL); /* open the dynamic store */ + do_snapshot(argc, (char**)argv); + exit(0); + } + /* are we looking up a preference value */ if (get) { if (findPref(get) < 0) { diff --git a/scutil.tproj/session.c b/scutil.tproj/session.c index 6f00f38..ed31af1 100644 --- a/scutil.tproj/session.c +++ b/scutil.tproj/session.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2004, 2010 Apple Inc. All rights reserved. + * Copyright (c) 2000-2004, 2010, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -32,6 +32,7 @@ */ #include "scutil.h" +#include "cache.h" #include "session.h" #include "notifications.h" @@ -81,6 +82,8 @@ do_open(int argc, char **argv) watchedKeys = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); watchedPatterns = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + cache_close(); + return; } @@ -112,27 +115,8 @@ do_close(int argc, char **argv) CFRelease(watchedPatterns); watchedPatterns = NULL; } - return; -} + cache_close(); -__private_extern__ -void -do_lock(int argc, char **argv) -{ - if (!SCDynamicStoreLock(store)) { - SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); - } - return; -} - - -__private_extern__ -void -do_unlock(int argc, char **argv) -{ - if (!SCDynamicStoreUnlock(store)) { - SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); - } return; } diff --git a/scutil.tproj/session.h b/scutil.tproj/session.h index b26bf4b..6c11ffa 100644 --- a/scutil.tproj/session.h +++ b/scutil.tproj/session.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001 Apple Computer, Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -37,8 +37,6 @@ __BEGIN_DECLS void do_open (int argc, char **argv); void do_close (int argc, char **argv); -void do_lock (int argc, char **argv); -void do_unlock (int argc, char **argv); __END_DECLS diff --git a/scutil.tproj/tests.c b/scutil.tproj/tests.c index 471ac4c..bc9160e 100644 --- a/scutil.tproj/tests.c +++ b/scutil.tproj/tests.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2003-2005, 2007-2011 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2003-2005, 2007-2012 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -47,15 +47,151 @@ #include #include +#include +#include "SCNetworkReachabilityInternal.h" + +static Boolean resolver_bypass; + +static CF_RETURNS_RETAINED CFMutableDictionaryRef +_setupReachabilityOptions(int argc, char **argv, const char *interface) +{ + CFMutableDictionaryRef options; + + options = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + + if (argc > 2) { + struct addrinfo hints = { 0 }; + int n_hints = 0; + int i; + + for (i = 2; i < argc; i++) { + if (strcasecmp(argv[i], "interface") == 0) { + if (++i >= argc) { + SCPrint(TRUE, stderr, CFSTR("No interface\n")); + CFRelease(options); + exit(1); + } + + interface = argv[i]; + continue; + } + + + if (strcasecmp(argv[i], "llq") == 0) { + CFDictionarySetValue(options, + kSCNetworkReachabilityOptionLongLivedQueryBypass, + kCFBooleanFalse); + continue; + } else if (strcasecmp(argv[i], "no-llq") == 0) { + CFDictionarySetValue(options, + kSCNetworkReachabilityOptionLongLivedQueryBypass, + kCFBooleanTrue); + continue; + } + + if (strcasecmp(argv[i], "server") == 0) { + CFDictionarySetValue(options, + kSCNetworkReachabilityOptionServerBypass, + kCFBooleanFalse); + continue; + } else if (strcasecmp(argv[i], "no-server") == 0) { + CFDictionarySetValue(options, + kSCNetworkReachabilityOptionServerBypass, + kCFBooleanTrue); + continue; + } + + if (strcasecmp(argv[i], "no-resolve") == 0) { + CFDictionarySetValue(options, + kSCNetworkReachabilityOptionResolverBypass, + kCFBooleanTrue); + resolver_bypass = TRUE; + continue; + } + + if (strcasecmp(argv[i], "AI_ADDRCONFIG") == 0) { + hints.ai_flags |= AI_ADDRCONFIG; + } else if (strcasecmp(argv[i], "AI_ALL") == 0) { + hints.ai_flags |= AI_ALL; + } else if (strcasecmp(argv[i], "AI_V4MAPPED") == 0) { + hints.ai_flags |= AI_V4MAPPED; + } else if (strcasecmp(argv[i], "AI_V4MAPPED_CFG") == 0) { + hints.ai_flags |= AI_V4MAPPED_CFG; + } else if (strcasecmp(argv[i], "AI_ADDRCONFIG") == 0) { + hints.ai_flags |= AI_ADDRCONFIG; + } else if (strcasecmp(argv[i], "AI_V4MAPPED") == 0) { + hints.ai_flags |= AI_V4MAPPED; + } else if (strcasecmp(argv[i], "AI_DEFAULT") == 0) { + hints.ai_flags |= AI_DEFAULT; +#ifdef AI_PARALLEL + } else if (strcasecmp(argv[i], "AI_PARALLEL") == 0) { + hints.ai_flags |= AI_PARALLEL; +#endif // AI_PARALLEL + } else if (strcasecmp(argv[i], "PF_INET") == 0) { + hints.ai_family = PF_INET; + } else if (strcasecmp(argv[i], "PF_INET6") == 0) { + hints.ai_family = PF_INET6; + } else if (strcasecmp(argv[i], "SOCK_STREAM") == 0) { + hints.ai_socktype = SOCK_STREAM; + } else if (strcasecmp(argv[i], "SOCK_DGRAM") == 0) { + hints.ai_socktype = SOCK_DGRAM; + } else if (strcasecmp(argv[i], "SOCK_RAW") == 0) { + hints.ai_socktype = SOCK_RAW; + } else if (strcasecmp(argv[i], "IPPROTO_TCP") == 0) { + hints.ai_protocol = IPPROTO_TCP; + } else if (strcasecmp(argv[i], "IPPROTO_UDP") == 0) { + hints.ai_protocol = IPPROTO_UDP; + } else { + SCPrint(TRUE, stderr, CFSTR("Unrecognized hint: %s\n"), argv[i]); + CFRelease(options); + exit(1); + } + n_hints++; + } + + if (n_hints > 0) { + CFDataRef data; + + data = CFDataCreate(NULL, (const UInt8 *)&hints, sizeof(hints)); + CFDictionarySetValue(options, kSCNetworkReachabilityOptionHints, data); + CFRelease(data); + } + } + + if (interface != NULL) { + CFStringRef str; + + if (if_nametoindex(interface) == 0) { + SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), interface); + exit(1); + } + + str = CFStringCreateWithCString(NULL, interface, kCFStringEncodingASCII); + CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str); + CFRelease(str); + } + + if (CFDictionaryGetCount(options) == 0) { + CFRelease(options); + options = NULL; + } + + return options; +} + static SCNetworkReachabilityRef _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context) { char *ip_address = argv[0]; const char *interface; + CFMutableDictionaryRef options = NULL; struct sockaddr_in sin; struct sockaddr_in6 sin6; - SCNetworkReachabilityRef target = NULL; + SCNetworkReachabilityRef target = NULL; bzero(&sin, sizeof(sin)); sin.sin_len = sizeof(sin); @@ -73,37 +209,33 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context) } if (inet_aton(ip_address, &sin.sin_addr) == 1) { - if (argc == 1) { - if (interface == NULL) { + if ((argc == 1) || + ((argc > 1) && (strlen(argv[1]) == 0))) { + options = _setupReachabilityOptions(argc, argv, interface); + if (options == NULL) { target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin); if (context != NULL) { context->info = "by address"; } } else { - CFDataRef data; - CFStringRef str; - CFMutableDictionaryRef options; + CFDataRef data; - if (if_nametoindex(interface) == 0) { - SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), interface); - exit(1); - } - - options = CFDictionaryCreateMutable(NULL, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin)); CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data); CFRelease(data); - str = CFStringCreateWithCString(NULL, interface, kCFStringEncodingASCII); - CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str); - CFRelease(str); - target = SCNetworkReachabilityCreateWithOptions(NULL, options); + if (context != NULL) { - context->info = "by address w/scope"; + if (CFDictionaryContainsKey(options, + kSCNetworkReachabilityOptionInterface)) { + if (CFDictionaryGetCount(options) == 2) { + context->info = "by address w/scope"; + } else { + context->info = "by address w/scope and options"; + } + } else { + context->info = "by address w/options"; + } } - CFRelease(options); } } else { char *remote_address = argv[1]; @@ -139,7 +271,8 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context) free(remote_address); } - if (interface == NULL) { + options = _setupReachabilityOptions(argc, argv, interface); + if (options == NULL) { target = SCNetworkReachabilityCreateWithAddressPair(NULL, (struct sockaddr *)&sin, (struct sockaddr *)&r_sin); @@ -147,33 +280,27 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context) context->info = "by address pair"; } } else { - CFDataRef data; - CFStringRef str; - CFMutableDictionaryRef options; - - if (if_nametoindex(interface) == 0) { - SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), interface); - exit(1); - } + CFDataRef data; - options = CFDictionaryCreateMutable(NULL, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); data = CFDataCreate(NULL, (const UInt8 *)&sin, sizeof(sin)); CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data); CFRelease(data); data = CFDataCreate(NULL, (const UInt8 *)&r_sin, sizeof(r_sin)); CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data); CFRelease(data); - str = CFStringCreateWithCString(NULL, interface, kCFStringEncodingASCII); - CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str); - CFRelease(str); - target = SCNetworkReachabilityCreateWithOptions(NULL, options); + if (context != NULL) { - context->info = "by address pair w/scope"; + if (CFDictionaryContainsKey(options, + kSCNetworkReachabilityOptionInterface)) { + if (CFDictionaryGetCount(options) == 3) { + context->info = "by address pair w/scope"; + } else { + context->info = "by address pair w/scope and options"; + } + } else { + context->info = "by address pair w/options"; + } } - CFRelease(options); } } } else if (inet_pton(AF_INET6, argv[0], &sin6.sin6_addr) == 1) { @@ -181,10 +308,24 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context) sin6.sin6_scope_id = if_nametoindex(interface); } - if (argc == 1) { - target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin6); - if (context != NULL) { - context->info = "by (v6) address"; + if ((argc == 1) || + ((argc > 1) && (strlen(argv[1]) == 0))) { + options = _setupReachabilityOptions(argc, argv, NULL); + if (options == NULL) { + target = SCNetworkReachabilityCreateWithAddress(NULL, (struct sockaddr *)&sin6); + if (context != NULL) { + context->info = "by (v6) address"; + } + } else { + CFDataRef data; + + data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6)); + CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data); + CFRelease(data); + + if (context != NULL) { + context->info = "by (v6) address w/options"; + } } } else { struct sockaddr_in6 r_sin6; @@ -202,27 +343,61 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context) r_sin6.sin6_scope_id = if_nametoindex(interface); } - target = SCNetworkReachabilityCreateWithAddressPair(NULL, - (struct sockaddr *)&sin6, - (struct sockaddr *)&r_sin6); - if (context != NULL) { - context->info = "by (v6) address pair"; + options = _setupReachabilityOptions(argc, argv, NULL); + if (options == NULL) { + target = SCNetworkReachabilityCreateWithAddressPair(NULL, + (struct sockaddr *)&sin6, + (struct sockaddr *)&r_sin6); + if (context != NULL) { + context->info = "by (v6) address pair"; + } + } else { + CFDataRef data; + + data = CFDataCreate(NULL, (const UInt8 *)&sin6, sizeof(sin6)); + CFDictionarySetValue(options, kSCNetworkReachabilityOptionLocalAddress, data); + CFRelease(data); + data = CFDataCreate(NULL, (const UInt8 *)&r_sin6, sizeof(r_sin6)); + CFDictionarySetValue(options, kSCNetworkReachabilityOptionRemoteAddress, data); + CFRelease(data); + + if (context != NULL) { + context->info = "by (v6) address pair w/options"; + } } } } else { - if (argc == 1) { - target = SCNetworkReachabilityCreateWithName(NULL, argv[0]); - if (context != NULL) { - context->info = "by name"; + CFStringRef str; + + options = _setupReachabilityOptions(argc, argv, NULL); + + if (((argc == 1) && (strlen(argv[0]) > 0)) || + ((argc > 1) && (strlen(argv[0]) > 0) && (strlen(argv[1]) == 0))) { + if (options == NULL) { + target = SCNetworkReachabilityCreateWithName(NULL, argv[0]); + if (context != NULL) { + context->info = "by name"; + } + } else { + str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); + CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str); + CFRelease(str); + + if (context != NULL) { + context->info = "by name w/options"; + } } } else { - CFStringRef str; - CFMutableDictionaryRef options; + CFIndex n_options; + + if (options == NULL) { + options = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + } + n_options = CFDictionaryGetCount(options); - options = CFDictionaryCreateMutable(NULL, - 0, - &kCFTypeDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks); if (strlen(argv[0]) > 0) { str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8); CFDictionarySetValue(options, kSCNetworkReachabilityOptionNodeName, str); @@ -233,87 +408,20 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context) CFDictionarySetValue(options, kSCNetworkReachabilityOptionServName, str); CFRelease(str); } - if (argc > 2) { - CFDataRef data; - struct addrinfo hints = { 0 }; - int i; - int n_hints = 0; - - for (i = 2; i < argc; i++) { - if (strcasecmp(argv[i], "interface") == 0) { - if (++i >= argc) { - SCPrint(TRUE, stderr, CFSTR("No interface\n")); - CFRelease(options); - exit(1); - } - if (if_nametoindex(argv[i]) == 0) { - SCPrint(TRUE, stderr, CFSTR("No interface: %s\n"), argv[i]); - CFRelease(options); - exit(1); - } - str = CFStringCreateWithCString(NULL, argv[i], kCFStringEncodingASCII); - CFDictionarySetValue(options, kSCNetworkReachabilityOptionInterface, str); - CFRelease(str); - continue; - } - if (strcasecmp(argv[i], "AI_ADDRCONFIG") == 0) { - hints.ai_flags |= AI_ADDRCONFIG; - } else if (strcasecmp(argv[i], "AI_ALL") == 0) { - hints.ai_flags |= AI_ALL; - } else if (strcasecmp(argv[i], "AI_V4MAPPED") == 0) { - hints.ai_flags |= AI_V4MAPPED; - } else if (strcasecmp(argv[i], "AI_V4MAPPED_CFG") == 0) { - hints.ai_flags |= AI_V4MAPPED_CFG; - } else if (strcasecmp(argv[i], "AI_ADDRCONFIG") == 0) { - hints.ai_flags |= AI_ADDRCONFIG; - } else if (strcasecmp(argv[i], "AI_V4MAPPED") == 0) { - hints.ai_flags |= AI_V4MAPPED; - } else if (strcasecmp(argv[i], "AI_DEFAULT") == 0) { - hints.ai_flags |= AI_DEFAULT; -#ifdef AI_PARALLEL - } else if (strcasecmp(argv[i], "AI_PARALLEL") == 0) { - hints.ai_flags |= AI_PARALLEL; -#endif // AI_PARALLEL - } else if (strcasecmp(argv[i], "PF_INET") == 0) { - hints.ai_family = PF_INET; - } else if (strcasecmp(argv[i], "PF_INET6") == 0) { - hints.ai_family = PF_INET6; - } else if (strcasecmp(argv[i], "SOCK_STREAM") == 0) { - hints.ai_socktype = SOCK_STREAM; - } else if (strcasecmp(argv[i], "SOCK_DGRAM") == 0) { - hints.ai_socktype = SOCK_DGRAM; - } else if (strcasecmp(argv[i], "SOCK_RAW") == 0) { - hints.ai_socktype = SOCK_RAW; - } else if (strcasecmp(argv[i], "IPPROTO_TCP") == 0) { - hints.ai_protocol = IPPROTO_TCP; - } else if (strcasecmp(argv[i], "IPPROTO_UDP") == 0) { - hints.ai_protocol = IPPROTO_UDP; + if (CFDictionaryGetCount(options) > n_options) { + if (context != NULL) { + if (n_options == 0) { + context->info = "by (node and/or serv) name"; } else { - SCPrint(TRUE, stderr, CFSTR("Unrecognized hint: %s\n"), argv[i]); - CFRelease(options); - exit(1); + context->info = "by (node and/or serv) name w/options"; } - n_hints++; - } - - if (n_hints > 0) { - data = CFDataCreate(NULL, (const UInt8 *)&hints, sizeof(hints)); - CFDictionarySetValue(options, kSCNetworkReachabilityOptionHints, data); - CFRelease(data); - } - } - if (CFDictionaryGetCount(options) > 0) { - target = SCNetworkReachabilityCreateWithOptions(NULL, options); - if (context != NULL) { - context->info = "by (node and/or serv) name"; } } else { SCPrint(TRUE, stderr, CFSTR("Must specify nodename or servname\n")); CFRelease(options); exit(1); } - CFRelease(options); } } @@ -321,24 +429,18 @@ _setupReachability(int argc, char **argv, SCNetworkReachabilityContext *context) free(ip_address); } + if ((target == NULL) && (options != NULL)) { + target = SCNetworkReachabilityCreateWithOptions(NULL, options); + CFRelease(options); + } + return target; } static void -_printReachability(SCNetworkReachabilityRef target) +_printReachabilityFlags(SCNetworkReachabilityFlags flags) { - SCNetworkReachabilityFlags flags; - Boolean ok; - - ok = SCNetworkReachabilityGetFlags(target, &flags); - if (!ok) { - printf(" could not determine reachability, %s\n", SCErrorString(SCError())); - return; - } - - SCPrint(_sc_debug, stdout, CFSTR("flags = 0x%08x"), flags); if (flags != 0) { - SCPrint(_sc_debug, stdout, CFSTR(" (")); if (flags & kSCNetworkReachabilityFlagsReachable) { SCPrint(TRUE, stdout, CFSTR("Reachable")); flags &= ~kSCNetworkReachabilityFlagsReachable; @@ -389,12 +491,35 @@ _printReachability(SCNetworkReachabilityRef target) if (flags != 0) { SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags); } - SCPrint(_sc_debug, stdout, CFSTR(")")); } else { - SCPrint(_sc_debug, stdout, CFSTR(" (")); SCPrint(TRUE, stdout, CFSTR("Not Reachable")); - SCPrint(_sc_debug, stdout, CFSTR(")")); } + + return; +} + +static void +_printReachability(SCNetworkReachabilityRef target) +{ + SCNetworkReachabilityFlags flags; + Boolean ok; + + ok = SCNetworkReachabilityGetFlags(target, &flags); + if (!ok) { + printf(" could not determine reachability, %s\n", SCErrorString(SCError())); + return; + } + + SCPrint(_sc_debug, stdout, CFSTR("flags = 0x%08x ("), flags); + _printReachabilityFlags(flags); + SCPrint(_sc_debug, stdout, CFSTR(")")); + + if (resolver_bypass) { + int if_index = + SCNetworkReachabilityGetInterfaceIndex(target); + SCPrint(_sc_debug, stdout, CFSTR("interface index = %d"), if_index); + } + SCPrint(TRUE, stdout, CFSTR("\n")); return; @@ -419,6 +544,115 @@ do_checkReachability(int argc, char **argv) } +static void +_printNWIFlags(nwi_ifstate_flags flags) +{ + if (flags == 0) { + return; + } + + SCPrint(TRUE, stdout, CFSTR(" (")); + if (flags & NWI_IFSTATE_FLAGS_HAS_IPV4) { + SCPrint(TRUE, stdout, CFSTR("IPv4")); + flags &= ~NWI_IFSTATE_FLAGS_HAS_IPV4; + SCPrint(flags != 0, stdout, CFSTR(",")); + } + if (flags & NWI_IFSTATE_FLAGS_HAS_IPV6) { + SCPrint(TRUE, stdout, CFSTR("IPv6")); + flags &= ~NWI_IFSTATE_FLAGS_HAS_IPV6; + SCPrint(flags != 0, stdout, CFSTR(",")); + } + if (flags & NWI_IFSTATE_FLAGS_HAS_DNS) { + SCPrint(TRUE, stdout, CFSTR("DNS")); + flags &= ~NWI_IFSTATE_FLAGS_HAS_DNS; + SCPrint(flags != 0, stdout, CFSTR(",")); + } + if (flags != 0) { + SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags); + } + SCPrint(TRUE, stdout, CFSTR(")")); + + return; +} + + +__private_extern__ +void +do_nwi(int argc, char **argv) +{ + nwi_ifstate_t ifstate; + nwi_state_t state = nwi_state_copy(); + + if (state == NULL) { + SCPrint(TRUE, stdout, CFSTR("No network information\n")); + exit(1); + } + + if (argc > 0) { + ifstate = nwi_state_get_ifstate(state, argv[0]); + if (ifstate != NULL) { + nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifstate); + + SCPrint(TRUE, stdout, CFSTR("Network interface information\n"), argv[0]); + SCPrint(TRUE, stdout, + CFSTR(" %7s : flags %p"), + nwi_ifstate_get_ifname(ifstate), + flags); + _printNWIFlags(flags); + SCPrint(TRUE, stdout, CFSTR("\n")); + } else { + SCPrint(TRUE, stdout, CFSTR("No network information (for %s)\n"), argv[0]); + } + + goto done; + } + + SCPrint(TRUE, stdout, CFSTR("Network information\n")); + SCPrint(TRUE, stdout, CFSTR("\nIPv4 network interface information\n")); + ifstate = nwi_state_get_first_ifstate(state, AF_INET); + + if (ifstate == NULL) { + SCPrint(TRUE, stdout, CFSTR(" No IPv4 states found\n")); + } + + while (ifstate != NULL) { + nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifstate); + + SCPrint(TRUE, stdout, + CFSTR(" %7s : flags %p"), + nwi_ifstate_get_ifname(ifstate), + flags); + _printNWIFlags(flags); + SCPrint(TRUE, stdout, CFSTR("\n")); + ifstate = nwi_ifstate_get_next(ifstate, AF_INET); + } + + SCPrint(TRUE, stdout, CFSTR("\nIPv6 network interface information\n")); + ifstate = nwi_state_get_first_ifstate(state, AF_INET6); + + if (ifstate == NULL) { + SCPrint(TRUE, stdout, CFSTR(" No IPv6 states found\n")); + } + + while (ifstate != NULL) { + nwi_ifstate_flags flags = nwi_ifstate_get_flags(ifstate); + + SCPrint(TRUE, stdout, + CFSTR(" %7s : flags %p"), + nwi_ifstate_get_ifname(ifstate), + flags); + _printNWIFlags(flags); + SCPrint(TRUE, stdout, CFSTR("\n")); + ifstate = nwi_ifstate_get_next(ifstate, AF_INET6); + } + + done : + + nwi_state_release(state); + exit(0); +} + + static void callout(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) { @@ -466,7 +700,7 @@ do_watchReachability(int argc, char **argv) // until after the "target" has been scheduled on a run loop. Otherwise, we'll // end up making a synchronous DNS request and that's not what we want. // - // But, to test the case were an application call SCNetworkReachabilityGetFlags() + // To test the case were an application first calls SCNetworkReachabilityGetFlags() // we provide the "CHECK_REACHABILITY_BEFORE_SCHEDULING" environment variable. if (getenv("CHECK_REACHABILITY_BEFORE_SCHEDULING") != NULL) { CFRelease(target_async); @@ -483,7 +717,7 @@ do_watchReachability(int argc, char **argv) // schedule the target SCPrint(TRUE, stdout, CFSTR(" 1: start\n")); SCPrint(TRUE, stdout, CFSTR(" %@\n"), target_async); - //_printReachability(target_async); +// _printReachability(target_async); SCPrint(TRUE, stdout, CFSTR("\n")); if (!SCNetworkReachabilitySetCallback(target_async, callout, &context)) { @@ -572,6 +806,7 @@ showResolver(dns_resolver_t *resolver, int index) uint32_t flags = resolver->flags; SCPrint(TRUE, stdout, CFSTR(" flags : ")); + SCPrint(_sc_debug, stdout, CFSTR("0x%08x ("), flags); if (flags & DNS_RESOLVER_FLAGS_SCOPED) { SCPrint(TRUE, stdout, CFSTR("Scoped")); flags &= ~DNS_RESOLVER_FLAGS_SCOPED; @@ -580,6 +815,17 @@ showResolver(dns_resolver_t *resolver, int index) if (flags != 0) { SCPrint(TRUE, stdout, CFSTR("0x%08x"), flags); } + SCPrint(_sc_debug, stdout, CFSTR(")")); + SCPrint(TRUE, stdout, CFSTR("\n")); + } + + if (resolver->reach_flags != 0) { + uint32_t flags = resolver->reach_flags; + + SCPrint(TRUE, stdout, CFSTR(" reach : ")); + SCPrint(_sc_debug, stdout, CFSTR("0x%08x ("), flags); + _printReachabilityFlags(flags); + SCPrint(_sc_debug, stdout, CFSTR(")")); SCPrint(TRUE, stdout, CFSTR("\n")); } @@ -595,10 +841,56 @@ __private_extern__ void do_showDNSConfiguration(int argc, char **argv) { - dns_config_t *dns_config; + dns_config_t *dns_config; + SCNetworkReachabilityRef target; dns_config = dns_configuration_copy(); - if (dns_config) { + + if (dns_config == NULL) { + SCPrint(TRUE, stdout, CFSTR("No DNS configuration available\n")); + exit(1); + } + + if (argc > 1) { + int dns_config_index = -1; + SCNetworkReachabilityFlags flags = 0; + Boolean haveDNS = FALSE; + Boolean ok = FALSE; + dns_resolver_t *resolver; + uint32_t resolver_if_index; + SCNetworkReachabilityPrivateRef targetPrivate; + + target = _setupReachability(argc, argv, NULL); + + targetPrivate = (SCNetworkReachabilityPrivateRef)target; + + if (targetPrivate->type != reachabilityTypeName) { + SCPrint(TRUE, stdout, CFSTR("\"%s\" is not a hostname.\n"), argv[0]); + exit(1); + } + + ok = __SC_checkResolverReachabilityInternal(&store, &flags, + &haveDNS, targetPrivate->name, NULL, + &resolver_if_index, &dns_config_index); + + if (!ok) { + SCPrint(TRUE, stdout, CFSTR("No DNS configuration available.\n" )); + exit(1); + } + + SCPrint(TRUE, stdout, CFSTR("DNS configuration for %s\n"), + targetPrivate->name); + + if (targetPrivate->if_index == 0) { + resolver = dns_config->resolver[dns_config_index]; + } else { + resolver = dns_config->scoped_resolver[dns_config_index]; + } + + showResolver(resolver, dns_config_index + 1); + + if (target != NULL) CFRelease(target); + } else { int i; SCPrint(TRUE, stdout, CFSTR("DNS configuration\n")); @@ -618,12 +910,9 @@ do_showDNSConfiguration(int argc, char **argv) showResolver(resolver, i + 1); } } - - dns_configuration_free(dns_config); - } else { - SCPrint(TRUE, stdout, CFSTR("No DNS configuration available\n")); } + dns_configuration_free(dns_config); exit(0); } @@ -746,6 +1035,11 @@ do_snapshot(int argc, char **argv) if (!SCDynamicStoreSnapshot(store)) { SCPrint(TRUE, stdout, CFSTR(" %s\n"), SCErrorString(SCError())); } + +#ifdef HAVE_REACHABILITY_SERVER + (void) _SCNetworkReachabilityServer_snapshot(); +#endif // HAVE_REACHABILITY_SERVER + return; } diff --git a/scutil.tproj/tests.h b/scutil.tproj/tests.h index 6de629b..6b5c0e9 100644 --- a/scutil.tproj/tests.h +++ b/scutil.tproj/tests.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000, 2001, 2004, 2007 Apple Inc. All rights reserved. + * Copyright (c) 2000, 2001, 2004, 2007, 2011 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -46,6 +46,7 @@ void do_showDNSConfiguration (int argc, char **argv); void do_showProxyConfiguration (int argc, char **argv); void do_snapshot (int argc, char **argv); void do_wait (char *waitKey, int timeout); +void do_nwi (int argc, char **argv); __END_DECLS