From: Apple Date: Wed, 29 Mar 2017 20:14:01 +0000 (+0000) Subject: configd-888.51.2.tar.gz X-Git-Tag: macos-10124^0 X-Git-Url: https://git.saurik.com/apple/configd.git/commitdiff_plain/43bfd57e6ff96d4b423acdd689985cb60fe778d3?hp=ac69cfdd85e5930844f9540dd410753a9709574d configd-888.51.2.tar.gz --- diff --git a/Plugins/IPMonitor/configAgentDefines.h b/Plugins/IPMonitor/configAgentDefines.h index 1d31c94..d2c61c5 100644 --- a/Plugins/IPMonitor/configAgentDefines.h +++ b/Plugins/IPMonitor/configAgentDefines.h @@ -24,11 +24,10 @@ #ifndef CONFIGAGENTDEFINES_H #define CONFIGAGENTDEFINES_H -#define kConfigAgentDomain "SystemConfig" +#import "config_agent_info.h" + #define kConfigAgentType "AgentType" #define kConfigAgentTypeGeneric "ConfigAgent" -#define kConfigAgentTypeProxy "ProxyAgent" -#define kConfigAgentTypeDNS "DNSAgent" #define kConfigAgentTypeDNSMulticast kConfigAgentTypeDNS "(m)" #define kConfigAgentTypeDNSPrivate kConfigAgentTypeDNS "(p)" diff --git a/Plugins/IPMonitor/controller.m b/Plugins/IPMonitor/controller.m index 12f4997..2a7e06f 100644 --- a/Plugins/IPMonitor/controller.m +++ b/Plugins/IPMonitor/controller.m @@ -241,19 +241,15 @@ typedef struct resolverList { - (NSData *)dataForProxyArray:(CFArrayRef)proxy_array_for_data { - NSData *data = [NSPropertyListSerialization dataWithPropertyList:(__bridge id _Nonnull)(proxy_array_for_data) - format:NSPropertyListBinaryFormat_v1_0 - options:0 - error:nil]; - - return data; + CFDataRef data = NULL; + (void)_SCSerialize(proxy_array_for_data, &data, NULL, NULL); + return (__bridge_transfer NSData *)data; } - (NSData *)dataForProxyDictionary:(CFDictionaryRef)domain_proxy { NSData * data = nil; CFMutableDictionaryRef domain_proxy_dict; - CFArrayRef domain_proxy_array; if (domain_proxy == NULL) { SC_log(LOG_NOTICE, "Invalid domain proxy dict"); @@ -263,12 +259,9 @@ typedef struct resolverList { domain_proxy_dict = CFDictionaryCreateMutableCopy(NULL, 0, domain_proxy); CFDictionaryRemoveValue(domain_proxy_dict, kSCPropNetProxiesSupplementalMatchDomain); - domain_proxy_array = CFArrayCreate(NULL, (const void **)&domain_proxy_dict, 1, &kCFTypeArrayCallBacks); + data = (__bridge_transfer NSData *)(SCNetworkProxiesCreateProxyAgentData(domain_proxy_dict)); CFRelease(domain_proxy_dict); - data = [self dataForProxyArray:domain_proxy_array]; - CFRelease(domain_proxy_array); - return data; } diff --git a/Plugins/IPMonitor/dns-configuration.c b/Plugins/IPMonitor/dns-configuration.c index 6fff6a0..cb92244 100644 --- a/Plugins/IPMonitor/dns-configuration.c +++ b/Plugins/IPMonitor/dns-configuration.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2016 Apple Inc. All rights reserved. + * Copyright (c) 2004-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -263,20 +263,29 @@ add_supplemental(CFMutableArrayRef resolvers, CFIndex i; CFIndex n_domains; CFArrayRef orders; + CFArrayRef servers; domains = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchDomains); n_domains = isA_CFArray(domains) ? CFArrayGetCount(domains) : 0; if (n_domains == 0) { + // if no supplemental match domains return; } orders = CFDictionaryGetValue(dns, kSCPropNetDNSSupplementalMatchOrders); if (orders != NULL) { if (!isA_CFArray(orders) || (n_domains != CFArrayGetCount(orders))) { + // if supplemental match orders... but too many/not enough return; } } + servers = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses); + if (!isA_CFArray(servers) || (CFArrayGetCount(servers) == 0)) { + // if no DNS server addresses + return; + } + /* * yes, this is a "supplemental" resolver configuration, expand * the match domains and add each to the resolvers list. @@ -894,6 +903,7 @@ add_scoped_resolvers(CFMutableArrayRef scoped, CFArrayRef searchDomains; CFDictionaryRef service; CFStringRef serviceID; + CFArrayRef servers; serviceID = CFArrayGetValueAtIndex(order, i); service = CFDictionaryGetValue(services, serviceID); @@ -908,6 +918,12 @@ add_scoped_resolvers(CFMutableArrayRef scoped, continue; } + servers = CFDictionaryGetValue(dns, kSCPropNetDNSServerAddresses); + if (!isA_CFArray(servers) || (CFArrayGetCount(servers) == 0)) { + // if no DNS server addresses + continue; + } + interface = CFDictionaryGetValue(dns, kSCPropInterfaceName); if ((interface == NULL) || CFEqual(interface, CFSTR("*"))) { // if no [scoped] interface or supplemental configuration w/match-all @@ -1528,6 +1544,16 @@ dns_configuration_set(CFDictionaryRef defaultResolver, // add the "default" resolver + if (defaultResolver != NULL) { + CFArrayRef servers; + + servers = CFDictionaryGetValue(defaultResolver, kSCPropNetDNSServerAddresses); + if (!isA_CFArray(servers) || (CFArrayGetCount(servers) == 0)) { + // if no DNS server addresses + defaultResolver = NULL; + } + } + add_default_resolver(resolvers, defaultResolver, &myOrderAdded, &mySearchDomains); // collect (and add) any "multicast" resolver configurations diff --git a/Plugins/IPMonitor/ip_plugin.c b/Plugins/IPMonitor/ip_plugin.c index 4270658..413217f 100644 --- a/Plugins/IPMonitor/ip_plugin.c +++ b/Plugins/IPMonitor/ip_plugin.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2000-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -3797,30 +3797,47 @@ parse_component(CFStringRef key, CFStringRef prefix) return (comp); } -__private_extern__ boolean_t -service_contains_protocol(CFDictionaryRef service, int af) + +static boolean_t +entity_routes_protocol(CFDictionaryRef entity_dict) { - boolean_t contains_protocol = FALSE; - CFStringRef entity; RouteListRef routes; - CFDictionaryRef dict; - entity = (af == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6; - dict = CFDictionaryGetValue(service, entity); - if (dict == NULL) { - goto done; - } - routes = ipdict_get_routelist(dict); + routes = ipdict_get_routelist(entity_dict); if (routes == NULL) { - goto done; + // if no routes + return FALSE; + } + + if ((routes->flags & kRouteListFlagsHasDefault) == 0) { + // if service has no default route + return FALSE; } + if ((routes->flags & kRouteListFlagsExcludeNWI) != 0) { - goto done; + // if service should be excluded from NWI + return FALSE; } - contains_protocol = TRUE; - done: - return (contains_protocol); + return TRUE; +} + + +__private_extern__ boolean_t +service_contains_protocol(CFDictionaryRef service_dict, int af) +{ + boolean_t contains_protocol; + CFStringRef entity; + CFDictionaryRef entity_dict; + + entity = (af == AF_INET) ? kSCEntNetIPv4 : kSCEntNetIPv6; + entity_dict = CFDictionaryGetValue(service_dict, entity); + if (entity_dict == NULL) { + return FALSE; + } + + contains_protocol = entity_routes_protocol(entity_dict); + return contains_protocol; } @@ -4598,9 +4615,8 @@ order_dns_servers(CFArrayRef servers, ProtocolFlags active_protos) if (((proto == kProtocolFlagsIPv4) && (v4_n == 1)) || ((proto == kProtocolFlagsIPv6) && (v6_n == 1))) { /* if we now have the 1st server address of another protocol */ - favor_v4 = (sa_dst_compare_no_stats((struct sockaddr *)&v4_dns1, - (struct sockaddr *)&v6_dns1, - 0) >= 0); + favor_v4 = (sa_dst_compare_no_dependencies((struct sockaddr *)&v4_dns1, + (struct sockaddr *)&v6_dns1) >= 0); #ifdef TEST_DNS_ORDER char v4_buf[INET_ADDRSTRLEN]; char v6_buf[INET6_ADDRSTRLEN]; @@ -4754,7 +4770,7 @@ get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict, } ipv4 = service_dict_get(serviceID, kSCEntNetIPv4); - if (ipv4 != NULL) { + if (entity_routes_protocol(ipv4)) { if (get_service_setup_entity(info, serviceID, kSCEntNetIPv4) != NULL) { have_setup = TRUE; } @@ -4763,10 +4779,9 @@ get_dns_changes(CFStringRef serviceID, CFDictionaryRef state_dict, } ipv6 = service_dict_get(serviceID, kSCEntNetIPv6); - if (ipv6 != NULL) { - if (!have_setup - && (get_service_setup_entity(info, serviceID, kSCEntNetIPv6) - != NULL)) { + if (entity_routes_protocol(ipv6)) { + if (!have_setup && + (get_service_setup_entity(info, serviceID, kSCEntNetIPv6) != NULL)) { have_setup = TRUE; } active_protos |= kProtocolFlagsIPv6; @@ -5014,12 +5029,12 @@ get_proxies_changes(CFStringRef serviceID, CFDictionaryRef state_dict, goto done; } ipv4 = service_dict_get(serviceID, kSCEntNetIPv4); - if (ipdict_get_routelist(ipv4) != NULL) { + if (entity_routes_protocol(ipv4)) { active_protos |= kProtocolFlagsIPv4; interface = ipdict_get_ifname(ipv4); } ipv6 = service_dict_get(serviceID, kSCEntNetIPv6); - if (ipdict_get_routelist(ipv6) != NULL) { + if (entity_routes_protocol(ipv6)) { active_protos |= kProtocolFlagsIPv6; if (interface == NULL) { interface = ipdict_get_ifname(ipv6); diff --git a/Plugins/IPMonitor/ip_plugin.h b/Plugins/IPMonitor/ip_plugin.h index 85e4727..7fdb1b0 100644 --- a/Plugins/IPMonitor/ip_plugin.h +++ b/Plugins/IPMonitor/ip_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2016 Apple Inc. All Rights Reserved. + * Copyright (c) 2012-2017 Apple Inc. All Rights Reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -74,10 +74,10 @@ const char * my_if_indextoname(unsigned int idx, char if_name[IFNAMSIZ]); boolean_t -service_contains_protocol(CFDictionaryRef service, int af); +service_contains_protocol(CFDictionaryRef service_dict, int af); boolean_t -service_is_scoped_only(CFDictionaryRef service); +service_is_scoped_only(CFDictionaryRef service_dict); boolean_t check_if_service_expensive(CFStringRef serviceID); diff --git a/Plugins/InterfaceNamer/ifnamer.c b/Plugins/InterfaceNamer/ifnamer.c index 82ae985..68c9942 100644 --- a/Plugins/InterfaceNamer/ifnamer.c +++ b/Plugins/InterfaceNamer/ifnamer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2016 Apple Inc. All rights reserved. + * Copyright (c) 2001-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -81,9 +81,13 @@ #include #include #include "plugin_shared.h" +#if !TARGET_OS_IPHONE +#include "InterfaceNamerControlPrefs.h" +#endif // !TARGET_OS_IPHONE #include #include +#include #include #include #include @@ -1466,6 +1470,96 @@ builtinCount(CFArrayRef if_list, CFIndex last, CFNumberRef if_type) return n; } +#if !TARGET_OS_IPHONE +static boolean_t +blockNewInterfaces() +{ + static boolean_t allow = TRUE; + static dispatch_once_t once; + + dispatch_once(&once, ^{ + allow = InterfaceNamerControlPrefsAllowNewInterfaces(); + }); + + return !allow; +} + + +static boolean_t +isConsoleLocked() +{ + CFArrayRef console_sessions; + boolean_t locked = FALSE; + io_registry_entry_t root; + + root = IORegistryGetRootEntry(kIOMasterPortDefault); + console_sessions = IORegistryEntryCreateCFProperty(root, + CFSTR(kIOConsoleUsersKey), + NULL, + 0); + if (isA_CFArray(console_sessions)) { + CFIndex n; + + n = CFArrayGetCount(console_sessions); + for (CFIndex i = 0; i < n; i++) { + CFBooleanRef isLocked; + CFBooleanRef isLoginDone; + CFBooleanRef onConsole; + CFDictionaryRef session; + + session = CFArrayGetValueAtIndex(console_sessions, i); + if (!isA_CFDictionary(session)) { + // if not dictionary + continue; + } + + if (!CFDictionaryGetValueIfPresent(session, + CFSTR(kIOConsoleSessionOnConsoleKey), + (const void **)&onConsole) || + !isA_CFBoolean(onConsole) || + !CFBooleanGetValue(onConsole)) { + // if not "on console" session + continue; + } + + if ((n > 1) && + CFDictionaryGetValueIfPresent(session, + CFSTR(kIOConsoleSessionLoginDoneKey), + (const void **)&isLoginDone) && + isA_CFBoolean(isLoginDone) && + !CFBooleanGetValue(isLoginDone)) { + // if @ loginwindow + SC_log(LOG_INFO, "multiple sessions, console @ loginwindow"); + locked = TRUE; + goto done; + } + + if (CFDictionaryGetValueIfPresent(session, + CFSTR(kIOConsoleSessionScreenIsLockedKey), + (const void **)&isLocked) && + isA_CFBoolean(isLocked) && + CFBooleanGetValue(isLocked)) { + // if screen locked + SC_log(LOG_INFO, "console screen locked"); + locked = TRUE; + goto done; + } + } + } + + SC_log(LOG_INFO, "console not locked"); + + done : + + if (console_sessions != NULL) { + CFRelease(console_sessions); + } + IOObjectRelease(root); + + return locked; +} +#endif // !TARGET_OS_IPHONE + static __inline__ boolean_t isQuiet(void) { @@ -1537,6 +1631,26 @@ nameInterfaces(CFMutableArrayRef if_list) if_list, i + 1, is_builtin ? kCFBooleanTrue : kCFBooleanFalse); + +#if !TARGET_OS_IPHONE + if (!is_builtin && + (dbdict != NULL) && + blockNewInterfaces() && + !_SCNetworkInterfaceIsApplePreconfigured(interface) && + isConsoleLocked()) { + CFDataRef addr; + + // if new (but matching) interface and console locked, ignore + SC_log(LOG_NOTICE, "Console locked, network interface* ignored"); + SC_log(LOG_INFO, " path = %@", path); + addr = _SCNetworkInterfaceGetHardwareAddress(interface); + if (addr != NULL) { + SC_log(LOG_INFO, " addr = %@", addr); + } + continue; + } +#endif // !TARGET_OS_IPHONE + if (dbdict != NULL) { unit = CFDictionaryGetValue(dbdict, CFSTR(kIOInterfaceUnit)); CFRetain(unit); @@ -1579,6 +1693,25 @@ nameInterfaces(CFMutableArrayRef if_list) } } +#if !TARGET_OS_IPHONE + if (!is_builtin && + (unit == NULL) && + blockNewInterfaces() && + !_SCNetworkInterfaceIsApplePreconfigured(interface) && + isConsoleLocked()) { + CFDataRef addr; + + // if new interface and console locked, ignore + SC_log(LOG_NOTICE, "Console locked, network interface ignored"); + SC_log(LOG_INFO, " path = %@", path); + addr = _SCNetworkInterfaceGetHardwareAddress(interface); + if (addr != NULL) { + SC_log(LOG_INFO, " addr = %@", addr); + } + continue; + } +#endif // !TARGET_OS_IPHONE + if (unit == NULL) { // not built-in (or built-in unit not available), allocate from // the non-reserved slots diff --git a/Plugins/PreferencesMonitor/prefsmon.c b/Plugins/PreferencesMonitor/prefsmon.c index 8a091e2..52e7fe9 100644 --- a/Plugins/PreferencesMonitor/prefsmon.c +++ b/Plugins/PreferencesMonitor/prefsmon.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2008, 2010, 2012-2016 Apple Inc. All rights reserved. + * Copyright (c) 2000-2008, 2010, 2012-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -60,7 +60,8 @@ static SCDynamicStoreRef store = NULL; /* InterfaceNamer[.plugin] monitoring globals */ Boolean haveConfiguration = FALSE; static CFStringRef namerKey = NULL; -static CFArrayRef preconfigured = NULL; +static CFMutableArrayRef preconfigured_names = NULL; // of CFStringRef (BSD name) +static CFMutableArrayRef preconfigured_interfaces= NULL; // of SCNetworkInterfaceRef /* KernelEventMonitor[.plugin] monitoring globals */ static CFStringRef interfacesKey = NULL; @@ -408,40 +409,20 @@ static void storeCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) { CFDictionaryRef dict; - CFArrayRef interfaces = NULL; Boolean quiet = FALSE; Boolean timeout = FALSE; Boolean updated = FALSE; - /* - * Capture/process KernelEventMonitor[.bundle] info - * 1. get list of active network interfaces - */ - dict = SCDynamicStoreCopyValue(store, interfacesKey); - if (dict != NULL) { - if (isA_CFDictionary(dict)) { - interfaces = CFDictionaryGetValue(dict, kSCPropNetInterfaces); - interfaces = isA_CFArray(interfaces); - if (interfaces != NULL) { - CFRetain(interfaces); - } - } - - CFRelease(dict); - } - /* * Capture/process InterfaceNamer[.bundle] info * 1. check if IORegistry "quiet", "timeout" - * 2. get list of named pre-configured interfaces - * 3. merge list of active interfaces (from KEV) with the - * list of preconfigured interfaces. + * 2. update list of named pre-configured interfaces */ dict = SCDynamicStoreCopyValue(store, namerKey); if (dict != NULL) { if (isA_CFDictionary(dict)) { - CFArrayRef cur_preconfigured; - CFMutableArrayRef new_preconfigured = NULL; + CFIndex n; + CFArrayRef preconfigured; if (CFDictionaryContainsKey(dict, kInterfaceNamerKey_Quiet)) { quiet = TRUE; @@ -450,56 +431,82 @@ storeCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *info) timeout = TRUE; } - cur_preconfigured = CFDictionaryGetValue(dict, kInterfaceNamerKey_PreConfiguredInterfaces); - cur_preconfigured = isA_CFArray(cur_preconfigured); - if ((cur_preconfigured != NULL) && (interfaces != NULL)) { - CFIndex i; - CFIndex n; - CFRange r = CFRangeMake(0, CFArrayGetCount(interfaces)); + preconfigured = CFDictionaryGetValue(dict, kInterfaceNamerKey_PreConfiguredInterfaces); + preconfigured = isA_CFArray(preconfigured); - n = CFArrayGetCount(cur_preconfigured); - for (i = 0; i < n; i++) { - CFStringRef bsdName; + n = (preconfigured != NULL) ? CFArrayGetCount(preconfigured) : 0; + for (CFIndex i = 0; i < n; i++) { + CFStringRef bsdName = CFArrayGetValueAtIndex(preconfigured, i); + SCNetworkInterfaceRef interface; + CFRange range; - bsdName = CFArrayGetValueAtIndex(cur_preconfigured, i); - if (!CFArrayContainsValue(interfaces, r, bsdName)) { - // if interface not currently active - continue; + range.location = 0; + range.length = (preconfigured_names != NULL) ? CFArrayGetCount(preconfigured_names) : 0; + if ((range.length > 0) && + CFArrayContainsValue(preconfigured_names, range, bsdName)) { + // if we already know about this interface + continue; + } + + for (int retry = 0; retry < 10; retry++) { + if (retry != 0) { + // add short delay (before retry) + usleep(20 * 1000); // 20ms + } + + interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeNoVirtualInterfaces); + if (interface == NULL) { + SC_log(LOG_ERR, "could not create network interface for %@", bsdName); + } else if (_SCNetworkInterfaceGetIOPath(interface) == NULL) { + SC_log(LOG_ERR, "could not get IOPath for %@", bsdName); + CFRelease(interface); + interface = NULL; } - if (new_preconfigured == NULL) { - new_preconfigured = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); + if (interface != NULL) { + // if we have an interface + break; } - CFArrayAppendValue(new_preconfigured, bsdName); } - } - if (!_SC_CFEqual(preconfigured, new_preconfigured)) { - SC_log(LOG_INFO, "pre-configured interface list changed"); + if (interface == NULL) { + // if SCNetworkInterface not [currently] available + continue; + } - if (preconfigured != NULL) { - CFRelease(preconfigured); + // keep track of the interface name (quicker than having to iterate the list + // of SCNetworkInterfaces, extract the name, and compare). + if (preconfigured_names == NULL) { + preconfigured_names = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } - if (new_preconfigured != NULL) { - CFRetain(new_preconfigured); + CFArrayAppendValue(preconfigured_names, bsdName); + + if (preconfigured_interfaces == NULL) { + preconfigured_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); } - preconfigured = new_preconfigured; + CFArrayAppendValue(preconfigured_interfaces, interface); + CFRelease(interface); updated = TRUE; } - if (new_preconfigured != NULL) { - CFRelease(new_preconfigured); + if (updated) { + CFStringRef interfaces = CFSTR(""); + + // report [new] pre-configured interfaces + if (preconfigured_names != NULL) { + interfaces = CFStringCreateByCombiningStrings(NULL, preconfigured_names, CFSTR(",")); + } else { + CFRetain(interfaces); + } + SC_log(LOG_INFO, "pre-configured interface list changed: %@", interfaces); + CFRelease(interfaces); } } CFRelease(dict); } - if (interfaces != NULL) { - CFRelease(interfaces); - } - if (!haveConfiguration && (quiet || timeout)) { static int logged = 0; @@ -736,7 +743,7 @@ updatePreConfiguredConfiguration(SCPreferencesRef prefs) SCNetworkSetRef set; Boolean updated = FALSE; - range.length = (preconfigured != NULL) ? CFArrayGetCount(preconfigured) : 0; + range.length = (preconfigured_names != NULL) ? CFArrayGetCount(preconfigured_names) : 0; if (range.length == 0) { // if no [preconfigured] interfaces return; @@ -748,10 +755,10 @@ updatePreConfiguredConfiguration(SCPreferencesRef prefs) CFArrayRef services; /* - * Check for (and remove) and network services associated with + * Check for (and remove) any network services associated with * a pre-configured interface from the prefs. */ - services = SCNetworkSetCopyServices(set); + services = SCNetworkServiceCopyAll(prefs); if (services != NULL) { CFIndex n; @@ -775,14 +782,18 @@ updatePreConfiguredConfiguration(SCPreferencesRef prefs) continue; } - if (!CFArrayContainsValue(preconfigured, range, bsdName)) { + if (!CFArrayContainsValue(preconfigured_names, range, bsdName)) { // if not preconfigured continue; } // remove [preconfigured] network service from the prefs SC_log(LOG_NOTICE, "removing network service for %@", bsdName); - SCNetworkServiceRemove(service); + ok = SCNetworkServiceRemove(service); + if (!ok) { + SC_log(LOG_ERR, "SCNetworkServiceRemove() failed: %s", + SCErrorString(SCError())); + } updated = TRUE; } @@ -794,7 +805,7 @@ updatePreConfiguredConfiguration(SCPreferencesRef prefs) ok = SCPreferencesCommitChanges(prefs); if (!ok) { if (SCError() != EROFS) { - SC_log(LOG_NOTICE, "SCPreferencesCommitChanges() failed: %s", + SC_log(LOG_ERR, "SCPreferencesCommitChanges() failed: %s", SCErrorString(SCError())); } } @@ -803,28 +814,18 @@ updatePreConfiguredConfiguration(SCPreferencesRef prefs) /* * Now, add a new network service for each pre-configured interface */ + range.length = (preconfigured_interfaces != NULL) ? CFArrayGetCount(preconfigured_interfaces) : 0; for (CFIndex i = 0; i < range.length; i++) { CFStringRef bsdName; - SCNetworkInterfaceRef interface; + SCNetworkInterfaceRef interface = CFArrayGetValueAtIndex(preconfigured_interfaces, i); SCNetworkServiceRef service; - bsdName = CFArrayGetValueAtIndex(preconfigured, i); - interface = _SCNetworkInterfaceCreateWithBSDName(NULL, bsdName, kIncludeNoVirtualInterfaces); - if (interface == NULL) { - SC_log(LOG_ERR, "could not create network interface for %@", bsdName); - continue; - } - - if (_SCNetworkInterfaceGetIOPath(interface) == NULL) { - // if no [real] interface exists - CFRelease(interface); - continue; - } - + bsdName = SCNetworkInterfaceGetBSDName(interface); ok = SCNetworkSetEstablishDefaultInterfaceConfiguration(set, interface); - CFRelease(interface); if (!ok) { - SC_log(LOG_ERR, "could not create network service for %@", bsdName); + SC_log(LOG_ERR, "could not establish network service for %@: %s", + bsdName, + SCErrorString(SCError())); continue; } diff --git a/Plugins/common/InterfaceNamerControlPrefs.c b/Plugins/common/InterfaceNamerControlPrefs.c new file mode 100644 index 0000000..c559026 --- /dev/null +++ b/Plugins/common/InterfaceNamerControlPrefs.c @@ -0,0 +1,307 @@ +/* + * Copyright (c) 2017 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@ + */ + +/* + * InterfaceNamerControlPrefs.c + * - definitions for accessing InterfaceNamer control preferences + */ + +/* + * Modification History + * + * January 12, 2017 Allan Nathanson (ajn@apple.com) + * - created + */ + +#include +#include +#include +#include +#include "InterfaceNamerControlPrefs.h" + +os_log_t __log_InterfaceNamer(); + +/* + * kInterfaceNamerControlPrefsID + * - identifies the InterfaceNamer preferences file that contains 'AllowNewInterfaces' + */ +#define kInterfaceNamerControlPrefsIDStr "com.apple.InterfaceNamer.control.plist" +#define kInterfaceNamerControlPrefsID CFSTR(kInterfaceNamerControlPrefsIDStr) + +/* + * kAllowNewInterfaces + * - indicates whether InterfaceNamer is allowed to create new interfaces + * while the screen is locked or not + */ +#define kAllowNewInterfaces CFSTR("AllowNewInterfaces") + +static SCPreferencesRef S_prefs; +static InterfaceNamerControlPrefsCallBack S_callback; + +static SCPreferencesRef +InterfaceNamerControlPrefsGet(void) +{ + if (S_prefs == NULL) { + InterfaceNamerControlPrefsInit(NULL, NULL); + } + + return (S_prefs); +} + +static void +prefs_changed(void * arg) +{ +#pragma unused(arg) + os_activity_t activity; + + activity = os_activity_create("processing InterfaceNamer preference change", + OS_ACTIVITY_CURRENT, + OS_ACTIVITY_FLAG_DEFAULT); + os_activity_scope(activity); + + /* get the current value */ + if (S_callback != NULL) { + (*S_callback)(S_prefs); + } + + os_release(activity); + + return; +} + +#if TARGET_OS_IPHONE +/* + * kInterfaceNamerControlManangedPrefsID + * - identifies the location of the managed preferences file + */ +#define kManagedPrefsDirStr "/Library/Managed Preferences/mobile/" +#define kInterfaceNamerControlManagedPrefsID CFSTR(kManagedPrefsDirStr \ + kInterfaceNamerControlPrefsIDStr) +static SCPreferencesRef S_managed_prefs; + +static SCPreferencesRef +InterfaceNamerControlManagedPrefsGet(void) +{ + if (S_managed_prefs == NULL) { + CFMutableDictionaryRef options; + + options = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(options, kSCPreferencesOptionRemoveWhenEmpty, kCFBooleanTrue); + S_managed_prefs = SCPreferencesCreateWithOptions(NULL, + CFSTR("InterfaceNamerControlPrefs"), + kInterfaceNamerControlManagedPrefsID, + NULL, + options); + CFRelease(options); + } + return (S_managed_prefs); +} + +static void +enable_prefs_observer(CFRunLoopRef runloop) +{ + CFRunLoopSourceContext context; + dispatch_queue_t queue; + CFRunLoopSourceRef source; + + bzero(&context, sizeof(context)); + context.perform = prefs_changed; + source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context); + CFRunLoopAddSource(runloop, source, kCFRunLoopCommonModes); + queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + _scprefs_observer_watch(scprefs_observer_type_global, + kInterfaceNamerControlPrefsIDStr, + queue, + ^{ + if (source != NULL) { + CFRunLoopSourceSignal(source); + if (runloop != NULL) { + CFRunLoopWakeUp(runloop); + } + }; + }); + return; +} + +#else /* TARGET_OS_IPHONE */ + +static void +enable_prefs_observer(CFRunLoopRef runloop) +{ +#pragma unused(runloop) + return; +} + +#endif /* TARGET_OS_IPHONE */ + +static void +InterfaceNamerControlPrefsChanged(SCPreferencesRef prefs, + SCPreferencesNotification type, + void *info) +{ +#pragma unused(prefs) +#pragma unused(type) +#pragma unused(info) + prefs_changed(NULL); + return; +} + +__private_extern__ SCPreferencesRef +InterfaceNamerControlPrefsInit(CFRunLoopRef runloop, + InterfaceNamerControlPrefsCallBack callback) +{ + CFMutableDictionaryRef options; + + options = CFDictionaryCreateMutable(NULL, + 0, + &kCFTypeDictionaryKeyCallBacks, + &kCFTypeDictionaryValueCallBacks); + CFDictionarySetValue(options, kSCPreferencesOptionRemoveWhenEmpty, kCFBooleanTrue); + S_prefs = SCPreferencesCreateWithOptions(NULL, + CFSTR("InterfaceNamerControlPrefs"), + kInterfaceNamerControlPrefsID, + NULL, + options); + CFRelease(options); + + if ((runloop != NULL) && (callback != NULL)) { + S_callback = callback; + if (!SCPreferencesSetCallback(S_prefs, InterfaceNamerControlPrefsChanged, NULL)) { + SC_log(LOG_NOTICE, "SCPreferencesSetCallBack() failed: %s", SCErrorString(SCError())); + goto done; + } + + if (!SCPreferencesScheduleWithRunLoop(S_prefs, runloop, kCFRunLoopCommonModes)) { + SC_log(LOG_NOTICE, "SCPreferencesScheduleWithRunLoop() failed: %s", SCErrorString(SCError())); + (void) SCPreferencesSetCallback(S_prefs, NULL, NULL); + } + + enable_prefs_observer(runloop); + } + + done : + return (S_prefs); +} + +static Boolean +InterfaceNamerControlPrefsSave(void) +{ + Boolean saved = FALSE; + + if (S_prefs != NULL) { + saved = SCPreferencesCommitChanges(S_prefs); + SCPreferencesSynchronize(S_prefs); + } + return (saved); +} + +static CFBooleanRef +prefs_get_boolean(CFStringRef key) +{ + CFBooleanRef b = NULL; + SCPreferencesRef prefs; + +#if TARGET_OS_IPHONE + prefs = InterfaceNamerControlManagedPrefsGet(); + if (prefs != NULL) { + b = SCPreferencesGetValue(prefs, key); + b = isA_CFBoolean(b); + if (b != NULL) { + return (b); + } + } +#endif /* TARGET_OS_IPHONE */ + + prefs = InterfaceNamerControlPrefsGet(); + if (prefs != NULL) { + b = SCPreferencesGetValue(prefs, key); + b = isA_CFBoolean(b); + } + return (b); +} + +static void +prefs_set_boolean(CFStringRef key, CFBooleanRef b) +{ + SCPreferencesRef prefs; + + prefs = InterfaceNamerControlPrefsGet(); + if (prefs != NULL) { + if (isA_CFBoolean(b) == NULL) { + SCPreferencesRemoveValue(prefs, key); + } + else { + SCPreferencesSetValue(prefs, key, b); + } + } + return; +} + +static void +InterfaceNamerControlPrefsRefresh(void) +{ + if (S_prefs != NULL) { + SCPreferencesSynchronize(S_prefs); + } +#if TARGET_OS_IPHONE + if (S_managed_prefs != NULL) { + SCPreferencesSynchronize(S_managed_prefs); + } +#endif /* TARGET_OS_IPHONE */ + return; +} + +/** + ** Get + **/ +__private_extern__ Boolean +InterfaceNamerControlPrefsAllowNewInterfaces(void) +{ + CFBooleanRef b; + Boolean allow = FALSE; + + b = prefs_get_boolean(kAllowNewInterfaces); + if (b != NULL) { + allow = CFBooleanGetValue(b); + } + /* flush the backing store */ + InterfaceNamerControlPrefsRefresh(); + return (allow); +} + +/** + ** Set + **/ +__private_extern__ Boolean +InterfaceNamerControlPrefsSetAllowNewInterfaces(Boolean allow) +{ + if (allow) { + prefs_set_boolean(kAllowNewInterfaces, kCFBooleanTrue); + } else { + prefs_set_boolean(kAllowNewInterfaces, NULL); + } + return (InterfaceNamerControlPrefsSave()); +} diff --git a/Plugins/common/InterfaceNamerControlPrefs.h b/Plugins/common/InterfaceNamerControlPrefs.h new file mode 100644 index 0000000..51daaeb --- /dev/null +++ b/Plugins/common/InterfaceNamerControlPrefs.h @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017 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 _INTERFACENAMERCONTROLPREFS_H +#define _INTERFACENAMERCONTROLPREFS_H + +/* + * InterfaceNamerControlPrefs.h + * - definitions for accessing InterfaceNamer control preferences + */ + +/* + * Modification History + * + * January 12, 2017 Allan Nathanson (ajn@apple.com) + * - created + */ + +typedef void (*InterfaceNamerControlPrefsCallBack)(SCPreferencesRef prefs); + +SCPreferencesRef +InterfaceNamerControlPrefsInit (CFRunLoopRef runloop, + InterfaceNamerControlPrefsCallBack callback); + +Boolean +InterfaceNamerControlPrefsAllowNewInterfaces (void); + +Boolean +InterfaceNamerControlPrefsSetAllowNewInterfaces (Boolean verbose); + +#endif /* _INTERFACENAMERCONTROLPREFS_H */ diff --git a/SCMonitor/monitor.c b/SCMonitor/monitor.c index 678ab93..d0d43f6 100644 --- a/SCMonitor/monitor.c +++ b/SCMonitor/monitor.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2007-2016 Apple Inc. All rights reserved. + * Copyright (c) 2007-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -38,6 +38,7 @@ #include #include +#include #include #include #include "UserEventAgentInterface.h" @@ -549,6 +550,67 @@ notify_configure(MyType *myInstance) } +#pragma mark - + +static Boolean +onConsole() +{ + CFArrayRef console_sessions; + Boolean on = FALSE; + io_registry_entry_t root; + uid_t uid = geteuid(); + + root = IORegistryGetRootEntry(kIOMasterPortDefault); + console_sessions = IORegistryEntryCreateCFProperty(root, + CFSTR(kIOConsoleUsersKey), + NULL, + 0); + if (console_sessions != NULL) { + CFIndex n; + + n = isA_CFArray(console_sessions) ? CFArrayGetCount(console_sessions) : 0; + for (CFIndex i = 0; i < n; i++) { + CFBooleanRef bVal; + CFDictionaryRef session; + uint64_t sessionUID; + CFNumberRef val; + + session = CFArrayGetValueAtIndex(console_sessions, i); + if (!isA_CFDictionary(session)) { + // if not dictionary + continue; + } + + if (!CFDictionaryGetValueIfPresent(session, + CFSTR(kIOConsoleSessionUIDKey), + (const void **)&val) || + !isA_CFNumber(val) || + !CFNumberGetValue(val, kCFNumberSInt64Type, (void *)&sessionUID) || + (uid != sessionUID)) { + // if not my session + continue; + } + + if (CFDictionaryGetValueIfPresent(session, + CFSTR(kIOConsoleSessionOnConsoleKey), + (const void **)&bVal) && + isA_CFBoolean(bVal) && + CFBooleanGetValue(bVal)) { + // if "on console" session + on = TRUE; + } + + break; + } + + CFRelease(console_sessions); + } + IOObjectRelease(root); + + return on; +} + + #pragma mark - @@ -567,6 +629,10 @@ updateInterfaceList(MyType *myInstance) SCPreferencesRef prefs; SCNetworkSetRef set = NULL; + if (!onConsole()) { + return; + } + prefs = SCPreferencesCreate(NULL, CFSTR("SCMonitor"), NULL); if (prefs == NULL) { return; diff --git a/SystemConfiguration.fproj/BondConfiguration.c b/SystemConfiguration.fproj/BondConfiguration.c index 2b8cc83..aaf33be 100644 --- a/SystemConfiguration.fproj/BondConfiguration.c +++ b/SystemConfiguration.fproj/BondConfiguration.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2016 Apple Inc. All rights reserved. + * Copyright (c) 2004-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -364,7 +364,7 @@ SCBondInterfaceCopyAvailableMemberInterfaces(SCPreferencesRef prefs) } // identify available interfaces - interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(); + interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(FALSE); if (interfaces != NULL) { CFIndex i; CFIndex n; diff --git a/SystemConfiguration.fproj/BridgeConfiguration.c b/SystemConfiguration.fproj/BridgeConfiguration.c index 6abafab..3d984a0 100644 --- a/SystemConfiguration.fproj/BridgeConfiguration.c +++ b/SystemConfiguration.fproj/BridgeConfiguration.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2016 Apple Inc. All rights reserved. + * Copyright (c) 2009-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -350,7 +350,7 @@ SCBridgeInterfaceCopyAvailableMemberInterfaces(SCPreferencesRef prefs) } // identify available interfaces - interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(); + interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(FALSE); if (interfaces != NULL) { CFIndex i; CFIndex n; diff --git a/SystemConfiguration.fproj/SCNetworkConfigurationInternal.h b/SystemConfiguration.fproj/SCNetworkConfigurationInternal.h index fbc4a1e..8bce2fd 100644 --- a/SystemConfiguration.fproj/SCNetworkConfigurationInternal.h +++ b/SystemConfiguration.fproj/SCNetworkConfigurationInternal.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2016 Apple Inc. All rights reserved. + * Copyright (c) 2004-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -211,7 +211,7 @@ Boolean __SCNetworkInterfaceMatchesName (CFStringRef name, CFStringRef key); CFArrayRef -__SCNetworkInterfaceCopyAll_IONetworkInterface (void); +__SCNetworkInterfaceCopyAll_IONetworkInterface (Boolean keep_pre_configured); /*! @function __SCNetworkInterfaceCopyStorageEntity diff --git a/SystemConfiguration.fproj/SCNetworkInterface.c b/SystemConfiguration.fproj/SCNetworkInterface.c index 20791fa..cdbbaeb 100644 --- a/SystemConfiguration.fproj/SCNetworkInterface.c +++ b/SystemConfiguration.fproj/SCNetworkInterface.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2016 Apple Inc. All rights reserved. + * Copyright (c) 2004-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -1600,21 +1600,27 @@ processUSBInterface(SCNetworkInterfacePrivateRef interfacePrivate, { #if !TARGET_OS_SIMULATOR // capture USB info - interfacePrivate->usb.name = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR(kUSBProductString), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); - interfacePrivate->usb.vid = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR(kUSBVendorID), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); - interfacePrivate->usb.pid = IORegistryEntrySearchCFProperty(interface, - kIOServicePlane, - CFSTR(kUSBProductID), - NULL, - kIORegistryIterateRecursively | kIORegistryIterateParents); + if (interfacePrivate->usb.name == NULL) { + interfacePrivate->usb.name = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + CFSTR(kUSBProductString), + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + } + if (interfacePrivate->usb.vid == NULL) { + interfacePrivate->usb.vid = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + CFSTR(kUSBVendorID), + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + } + if (interfacePrivate->usb.pid == NULL) { + interfacePrivate->usb.pid = IORegistryEntrySearchCFProperty(interface, + kIOServicePlane, + CFSTR(kUSBProductID), + NULL, + kIORegistryIterateRecursively | kIORegistryIterateParents); + } #endif // !TARGET_OS_SIMULATOR return; @@ -1738,7 +1744,7 @@ processNetworkInterface(SCNetworkInterfacePrivateRef interfacePrivate, CFNumberGetValue(num, kCFNumberIntType, &ift)) { interfacePrivate->type = CFRetain(num); } else { - SC_log(LOG_INFO, "no interface type"); + SC_log(LOG_INFO, "no interface type: %@", interface_dict); return FALSE; } @@ -4401,7 +4407,7 @@ _SCNetworkInterfaceCreateWithEntity(CFAllocatorRef allocator, __private_extern__ CFArrayRef -__SCNetworkInterfaceCopyAll_IONetworkInterface(void) +__SCNetworkInterfaceCopyAll_IONetworkInterface(Boolean keep_pre_configured) { CFDictionaryRef matching; CFArrayRef new_interfaces; @@ -4412,7 +4418,7 @@ __SCNetworkInterfaceCopyAll_IONetworkInterface(void) new_interfaces = findMatchingInterfaces(matching, processNetworkInterface, kSCNetworkInterfaceHiddenInterfaceKey, - FALSE); + keep_pre_configured); CFRelease(matching); return new_interfaces; @@ -4611,7 +4617,7 @@ _SCNetworkInterfaceCopyAllWithPreferences(SCPreferencesRef prefs) all_interfaces = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks); // get Ethernet, Firewire, Thunderbolt, and AirPort interfaces - new_interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(); + new_interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(FALSE); if (new_interfaces != NULL) { add_interfaces(all_interfaces, new_interfaces); CFRelease(new_interfaces); diff --git a/SystemConfiguration.fproj/SCNetworkMigration.c b/SystemConfiguration.fproj/SCNetworkMigration.c index 411c7e7..3d4c53f 100644 --- a/SystemConfiguration.fproj/SCNetworkMigration.c +++ b/SystemConfiguration.fproj/SCNetworkMigration.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2016 Apple Inc. All rights reserved. + * Copyright (c) 2014-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -354,9 +354,7 @@ __SCNetworkCreateDefaultNIPrefs(CFStringRef prefsID) SCPreferencesRef ni_prefs; CFComparisonResult res; - - networkInterfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(); - + networkInterfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(TRUE); if (networkInterfaces == NULL) { SC_log(LOG_NOTICE, "networkInterfaces is NULL"); return NULL; @@ -515,11 +513,12 @@ _SCNetworkConfigurationPerformMigration(CFURLRef sourceDir, CFURLRef currentDir, else { migrationComplete = _SCNetworkConfigurationMigrateConfiguration(sourceDirConfig, targetDirConfig); } - SC_log(LOG_NOTICE, "Migration %s", migrationComplete ? "complete" : "failed"); if (migrationComplete) { + SC_log(LOG_NOTICE, "Migration complete"); paths = _SCNetworkConfigurationCopyMigrationPaths(NULL); - } - else { + } else { + SC_log(LOG_NOTICE, "Migration failed: %s", SCErrorString(SCError())); + // If migration fails, then remove configuration files from target config if they are // copied from the current directory if (removeTargetOnFailure) { @@ -2061,6 +2060,13 @@ done: if (currentSourceSet != NULL) { CFRelease(currentSourceSet); } + + if (setMapping != NULL) { + SC_log(LOG_NOTICE, "Set mapping: %@", setMapping); + } else { + SC_log(LOG_INFO, "Set mapping: NULL"); + } + return setMapping; } @@ -2235,6 +2241,13 @@ done: if (targetSCNetworkServicesMutable != NULL) { CFRelease(targetSCNetworkServicesMutable); } + + if (serviceMapping != NULL) { + SC_log(LOG_NOTICE, "Service mapping: %@", serviceMapping); + } else { + SC_log(LOG_INFO, "Service mapping: NULL"); + } + return serviceMapping; } @@ -3446,12 +3459,9 @@ _SCNetworkConfigurationMigrateConfiguration(CFURLRef sourceDir, CFURLRef targetD } SC_log(LOG_DEBUG, "BSD Name Mapping: %@", bsdNameMapping); serviceMapping = _SCNetworkMigrationCreateServiceMappingUsingBSDMapping(sourcePrefs, targetPrefs, bsdNameMapping); - - if (isA_CFDictionary(serviceMapping) == NULL) { - SC_log(LOG_INFO, "Service mapping is NULL"); + if (serviceMapping == NULL) { goto done; } - SC_log(LOG_NOTICE, "Service mapping: %@", serviceMapping); setMapping = _SCNetworkMigrationCreateSetMapping(sourcePrefs, targetPrefs); sourceServiceSetMapping = _SCNetworkMigrationCreateServiceSetMapping(sourcePrefs); diff --git a/SystemConfiguration.fproj/SCNetworkReachability.c b/SystemConfiguration.fproj/SCNetworkReachability.c index 76afb7f..4553e0e 100644 --- a/SystemConfiguration.fproj/SCNetworkReachability.c +++ b/SystemConfiguration.fproj/SCNetworkReachability.c @@ -752,6 +752,8 @@ SCNetworkReachabilityCreateWithOptions(CFAllocatorRef allocator, SCNetworkReachabilityPrivateRef targetPrivate; unsigned int if_index = 0; char if_name[IFNAMSIZ]; + CFDataRef sourceAppAuditToken = NULL; + CFStringRef sourceAppBundleID = NULL; if (!isA_CFDictionary(options)) { _SCErrorSet(kSCStatusInvalidArgument); @@ -799,6 +801,23 @@ SCNetworkReachabilityCreateWithOptions(CFAllocatorRef allocator, _SCErrorSet(kSCStatusInvalidArgument); return NULL; } + sourceAppAuditToken = + CFDictionaryGetValue(options, kSCNetworkReachabilityOptionSourceAppAuditToken); + if ((sourceAppAuditToken != NULL) && + (!isA_CFData(sourceAppAuditToken) || + (CFDataGetLength(sourceAppAuditToken) != sizeof(audit_token_t)))) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + sourceAppBundleID = + CFDictionaryGetValue(options, kSCNetworkReachabilityOptionSourceAppBundleIdentifier); + if ((sourceAppBundleID != NULL) && + (!isA_CFString(sourceAppBundleID) || + (CFStringGetLength(sourceAppBundleID) == 0))) { + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + if (nodename != NULL) { const char *name; @@ -866,6 +885,28 @@ SCNetworkReachabilityCreateWithOptions(CFAllocatorRef allocator, haveOpt = TRUE; } + if (sourceAppAuditToken != NULL) { + audit_token_t atoken; + CFDataGetBytes(sourceAppAuditToken, + CFRangeMake(0, CFDataGetLength(sourceAppAuditToken)), + (UInt8 *)&atoken); + nw_parameters_set_source_application(targetPrivate->parameters, atoken); + haveOpt = TRUE; + } else if (sourceAppBundleID != NULL) { + char *cBundleID = _SC_cfstring_to_cstring(sourceAppBundleID, + NULL, + 0, + kCFStringEncodingUTF8); + if (cBundleID != NULL) { + nw_parameters_set_source_application_by_bundle_id(targetPrivate->parameters, + cBundleID); + CFAllocatorDeallocate(NULL, (void *)cBundleID); + } else { + SC_log(LOG_WARNING, "failed to convert %@ to a C string", sourceAppBundleID); + } + haveOpt = TRUE; + } + if (haveOpt) { const char *opt = "???"; @@ -1309,10 +1350,13 @@ SCNetworkReachabilityGetFlags(SCNetworkReachabilityRef target, pathEvaluator = nw_path_create_evaluator_for_endpoint(endpoint, targetPrivate->parameters); path = nw_path_evaluator_copy_path(pathEvaluator); - crazyIvanPath = __SCNetworkReachabilityCreateCrazyIvan46Path(path, endpoint, targetPrivate->parameters, FALSE); - if (NULL != crazyIvanPath) { - network_release(path); - path = crazyIvanPath; + if (isReachabilityTypeAddress(targetPrivate->type)) { + crazyIvanPath = __SCNetworkReachabilityCreateCrazyIvan46Path(path, endpoint, + targetPrivate->parameters, FALSE); + if (NULL != crazyIvanPath) { + network_release(path); + path = crazyIvanPath; + } } *flags = __SCNetworkReachabilityGetFlagsFromPath(path, 0, nw_resolver_status_invalid, NULL, FALSE, 0); @@ -1629,11 +1673,22 @@ __SCNetworkReachabilityRestartResolver(SCNetworkReachabilityPrivateRef targetPri if (targetPrivate && !targetPrivate->resolverBypass && isReachabilityTypeName(targetPrivate->type)) { + nw_resolver_t resolver; CFRetain(targetPrivate); if (NULL != targetPrivate->resolver) { nw_resolver_cancel(targetPrivate->resolver); } - nw_resolver_t resolver = nw_resolver_create_with_endpoint(__SCNetworkReachabilityGetPrimaryEndpoint(targetPrivate), targetPrivate->lastPathParameters ? targetPrivate->lastPathParameters : targetPrivate->parameters); + if (targetPrivate->lastPath != NULL) { + resolver = nw_resolver_create_with_path(targetPrivate->lastPath); + } else { + resolver = nw_resolver_create_with_endpoint(__SCNetworkReachabilityGetPrimaryEndpoint(targetPrivate), targetPrivate->lastPathParameters ? targetPrivate->lastPathParameters : targetPrivate->parameters); + } + if (resolver == NULL) { + SC_log(LOG_ERR, "%sfailed to create a nw_resolver", targetPrivate->log_prefix); + targetPrivate->resolver = NULL; + CFRelease(targetPrivate); + return; + } targetPrivate->resolver = resolver; nw_resolver_set_cancel_handler(resolver, ^(void) { MUTEX_LOCK(&targetPrivate->lock); @@ -1743,11 +1798,13 @@ __SCNetworkReachabilitySetDispatchQueue(SCNetworkReachabilityPrivateRef targetPr network_release(targetPrivate->lastPath); targetPrivate->lastPath = nw_path_evaluator_copy_path(pathEvaluator); - crazyIvanPath = __SCNetworkReachabilityCreateCrazyIvan46Path(targetPrivate->lastPath, endpoint, - targetPrivate->parameters, FALSE); - if (NULL != crazyIvanPath) { - network_release(targetPrivate->lastPath); - targetPrivate->lastPath = crazyIvanPath; + if (isReachabilityTypeAddress(targetPrivate->type)) { + crazyIvanPath = __SCNetworkReachabilityCreateCrazyIvan46Path(targetPrivate->lastPath, endpoint, + targetPrivate->parameters, FALSE); + if (NULL != crazyIvanPath) { + network_release(targetPrivate->lastPath); + targetPrivate->lastPath = crazyIvanPath; + } } network_release(targetPrivate->lastPathParameters); @@ -1781,13 +1838,16 @@ __SCNetworkReachabilitySetDispatchQueue(SCNetworkReachabilityPrivateRef targetPr network_release(targetPrivate->lastPath); targetPrivate->lastPath = network_retain(path); - crazyIvanPath = __SCNetworkReachabilityCreateCrazyIvan46Path(targetPrivate->lastPath, + if (isReachabilityTypeAddress(targetPrivate->type)) { + crazyIvanPath = + __SCNetworkReachabilityCreateCrazyIvan46Path(targetPrivate->lastPath, endpoint, targetPrivate->parameters, TRUE); - if (NULL != crazyIvanPath) { - network_release(targetPrivate->lastPath); - targetPrivate->lastPath = crazyIvanPath; + if (NULL != crazyIvanPath) { + network_release(targetPrivate->lastPath); + targetPrivate->lastPath = crazyIvanPath; + } } if (targetPrivate->lastResolverStatus == nw_resolver_status_complete) { diff --git a/SystemConfiguration.fproj/SCNetworkSet.c b/SystemConfiguration.fproj/SCNetworkSet.c index a9ae4e4..60b30ab 100644 --- a/SystemConfiguration.fproj/SCNetworkSet.c +++ b/SystemConfiguration.fproj/SCNetworkSet.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2016 Apple Inc. All rights reserved. + * Copyright (c) 2004-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -1728,7 +1728,7 @@ __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CF service = SCNetworkServiceCreate(setPrivate->prefs, interface); if (service == NULL) { - SC_log(LOG_INFO, "could not create service for \"%@\": %s", + SC_log(LOG_ERR, "could not create service for \"%@\": %s", SCNetworkInterfaceGetLocalizedDisplayName(interface), SCErrorString(SCError())); ok = FALSE; @@ -1737,7 +1737,7 @@ __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CF ok = SCNetworkServiceEstablishDefaultConfiguration(service); if (!ok) { - SC_log(LOG_INFO, "could not estabish default configuration for \"%@\": %s", + SC_log(LOG_ERR, "could not estabish default configuration for \"%@\": %s", SCNetworkInterfaceGetLocalizedDisplayName(interface), SCErrorString(SCError())); SCNetworkServiceRemove(service); @@ -1747,7 +1747,7 @@ __SCNetworkSetEstablishDefaultConfigurationForInterfaces(SCNetworkSetRef set, CF ok = SCNetworkSetAddService(set, service); if (!ok) { - SC_log(LOG_INFO, "could not add service for \"%@\": %s", + SC_log(LOG_ERR, "could not add service for \"%@\": %s", SCNetworkInterfaceGetLocalizedDisplayName(interface), SCErrorString(SCError())); SCNetworkServiceRemove(service); diff --git a/SystemConfiguration.fproj/SCPrivate.h b/SystemConfiguration.fproj/SCPrivate.h index 94b2c9c..53f2234 100644 --- a/SystemConfiguration.fproj/SCPrivate.h +++ b/SystemConfiguration.fproj/SCPrivate.h @@ -179,6 +179,7 @@ extern int _sc_log; /* 0 if SC messages should be written to stdout/stderr, + /*! @group */ @@ -709,6 +710,18 @@ SCNetworkProxiesCopyMatchingWithOptions (CFDictionaryRef globalConfiguration, extern const CFStringRef kSCProxiesNoGlobal; +/*! + @function SCNetworkProxiesCreateProxyAgentData + @discussion + + @param proxyConfig A dictionary representing a proxy configuration + @result returns a CFData representing a proxy configuration. This data is readable by all + "config-agents" (Agents with domain as "SystemConfig") via config_agent_copy_proxy_information(). + You must release the returned value. + */ +CFDataRef +SCNetworkProxiesCreateProxyAgentData(CFDictionaryRef proxyConfig) __OSX_AVAILABLE_STARTING(__MAC_10_12,__IPHONE_10_0/*SPI*/); + /*! @function SCDynamicStoreCopyProxiesWithOptions @discussion @@ -730,7 +743,6 @@ extern const CFStringRef kSCProxiesNoGlobal; CFDictionaryRef SCDynamicStoreCopyProxiesWithOptions(SCDynamicStoreRef store, CFDictionaryRef options) __OSX_AVAILABLE_STARTING(__MAC_10_9,__IPHONE_7_0/*SPI*/); - #pragma mark - #pragma mark Reachability diff --git a/SystemConfiguration.fproj/SCProxies.c b/SystemConfiguration.fproj/SCProxies.c index 4c6a60b..043a0fa 100644 --- a/SystemConfiguration.fproj/SCProxies.c +++ b/SystemConfiguration.fproj/SCProxies.c @@ -680,6 +680,25 @@ _SCNetworkProxiesCopyMatchingInternal(CFDictionaryRef globalConfiguration, return proxies; } +CFDataRef +SCNetworkProxiesCreateProxyAgentData(CFDictionaryRef proxyConfig) +{ + CFDataRef result = NULL; + CFArrayRef newProxy = NULL; + + if (!isA_CFDictionary(proxyConfig)) { + SC_log(LOG_ERR, "Invalid proxy configuration"); + _SCErrorSet(kSCStatusInvalidArgument); + return NULL; + } + + newProxy = CFArrayCreate(NULL, (const void **)&proxyConfig, 1, &kCFTypeArrayCallBacks); + (void)_SCSerialize(newProxy, &result, NULL, NULL); + CFRelease(newProxy); + + return result; +} + CFArrayRef SCNetworkProxiesCopyMatching(CFDictionaryRef globalConfiguration, CFStringRef server, diff --git a/SystemConfiguration.fproj/SCSchemaDefinitions.c b/SystemConfiguration.fproj/SCSchemaDefinitions.c index a357970..ac7e2be 100644 --- a/SystemConfiguration.fproj/SCSchemaDefinitions.c +++ b/SystemConfiguration.fproj/SCSchemaDefinitions.c @@ -213,6 +213,7 @@ const CFStringRef kSCValNetIPv6ConfigMethodManual = CFSTR("Manu const CFStringRef kSCValNetIPv6ConfigMethodRouterAdvertisement = CFSTR("RouterAdvertisement"); const CFStringRef kSCValNetIPv6ConfigMethod6to4 = CFSTR("6to4"); const CFStringRef kSCPropNetIPv6AdditionalRoutes = CFSTR("AdditionalRoutes"); +const CFStringRef kSCPropNetIPv6EnableCGA = CFSTR("EnableCGA"); const CFStringRef kSCPropNetIPv6ExcludedRoutes = CFSTR("ExcludedRoutes"); const CFStringRef kSCPropNetIPv6IncludedRoutes = CFSTR("IncludedRoutes"); const CFStringRef kSCPropNetIPv6RouteDestinationAddress = CFSTR("DestinationAddress"); diff --git a/SystemConfiguration.fproj/SCSchemaDefinitions.h b/SystemConfiguration.fproj/SCSchemaDefinitions.h index 9f8bd6d..d6714c4 100644 --- a/SystemConfiguration.fproj/SCSchemaDefinitions.h +++ b/SystemConfiguration.fproj/SCSchemaDefinitions.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2016 Apple Inc. All rights reserved. + * Copyright (c) 2000-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * diff --git a/SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h b/SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h index 2454232..1efd836 100644 --- a/SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h +++ b/SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2016 Apple Inc. All rights reserved. + * Copyright (c) 2000-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -118,6 +118,7 @@ * kSCEntNetIPv6 Entity Keys * * kSCPropNetIPv6AdditionalRoutes "AdditionalRoutes" CFArray[CFDictionary] + * kSCPropNetIPv6EnableCGA "EnableCGA" CFNumber (0 or 1) * kSCPropNetIPv6ExcludedRoutes "ExcludedRoutes" CFArray[CFDictionary] * kSCPropNetIPv6IncludedRoutes "IncludedRoutes" CFArray[CFDictionary] * @@ -720,6 +721,13 @@ extern const CFStringRef kSCPropNetIPv4ARPResolvedIPAddress __OS extern const CFStringRef kSCPropNetIPv6AdditionalRoutes __OSX_AVAILABLE_STARTING(__MAC_10_10,__IPHONE_8_0/*SPI*/); #define kSCPropNetIPv6AdditionalRoutes kSCPropNetIPv6AdditionalRoutes +/*! + @const kSCPropNetIPv6EnableCGA + @discussion Value is a CFNumber (0 or 1) + */ +extern const CFStringRef kSCPropNetIPv6EnableCGA __OSX_AVAILABLE_STARTING(__MAC_10_12,__IPHONE_10_0/*SPI*/); +#define kSCPropNetIPv6EnableCGA kSCPropNetIPv6EnableCGA + /*! @const kSCPropNetIPv6ExcludedRoutes @discussion Value is a CFArray[CFDictionary] diff --git a/SystemConfiguration.fproj/VLANConfiguration.c b/SystemConfiguration.fproj/VLANConfiguration.c index 8acf6a1..d0d9c30 100644 --- a/SystemConfiguration.fproj/VLANConfiguration.c +++ b/SystemConfiguration.fproj/VLANConfiguration.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2013, 2015, 2016 Apple Inc. All rights reserved. + * Copyright (c) 2003-2013, 2015-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -311,7 +311,7 @@ SCVLANInterfaceCopyAvailablePhysicalInterfaces() } // add real interfaces that aren't part of a bond or bridge - interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(); + interfaces = __SCNetworkInterfaceCopyAll_IONetworkInterface(FALSE); if (interfaces != NULL) { addAvailableInterfaces(available, interfaces, excluded); CFRelease(interfaces); diff --git a/SystemConfiguration.fproj/genSCPreferences.c b/SystemConfiguration.fproj/genSCPreferences.c index dfe409a..b01957b 100644 --- a/SystemConfiguration.fproj/genSCPreferences.c +++ b/SystemConfiguration.fproj/genSCPreferences.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2016 Apple Inc. All rights reserved. + * Copyright (c) 2000-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -62,7 +62,7 @@ char copyright_string[] = "/*\n" -" * Copyright (c) 2000-2016 Apple Inc. All rights reserved.\n" +" * Copyright (c) 2000-2017 Apple Inc. All rights reserved.\n" " *\n" " * @APPLE_LICENSE_HEADER_START@\n" " *\n" @@ -207,6 +207,7 @@ typedef enum { #define CCP "CCP" #define CELLULAR "Cellular" #define CERTIFICATE "Certificate" +#define CGA "CGA" #define CHAP "CHAP" #define COMM "Comm" #define COMPATIBLE "Compatible" @@ -843,6 +844,7 @@ static schemaDefinition names[] = { { GROUP_PRIVATE, NETPROP IPV6, KEY_PREFIX NETENT IPV6 " Entity Keys", NULL, NULL }, { SC_10_10_IPHONE_8_0_PRIVATE, NETPROP IPV6, ADDITIONAL ROUTES, NULL, CFARRAY_CFDICTIONARY }, + { SC_10_12_IPHONE_10_0_PRIVATE, NETPROP IPV6, ENABLE CGA, NULL, CFNUMBER_BOOL }, { SC_10_7_IPHONE_4_0_PRIVATE, NETPROP IPV6, EXCLUDED ROUTES, NULL, CFARRAY_CFDICTIONARY }, { SC_10_7_IPHONE_4_0_PRIVATE, NETPROP IPV6, INCLUDED ROUTES, NULL, CFARRAY_CFDICTIONARY }, { COMMENT_PRIVATE, "", NULL, NULL, NULL }, diff --git a/config-agent-info/config_agent_info.h b/config-agent-info/config_agent_info.h index 7671c6c..9b2fa45 100644 --- a/config-agent-info/config_agent_info.h +++ b/config-agent-info/config_agent_info.h @@ -30,6 +30,11 @@ __BEGIN_DECLS +#define kConfigAgentDomain "SystemConfig" + +#define kConfigAgentTypeProxy "ProxyAgent" +#define kConfigAgentTypeDNS "DNSAgent" + /* Returns true for agent with type DNSAgent and domain SystemConfig */ diff --git a/configd.xcodeproj/project.pbxproj b/configd.xcodeproj/project.pbxproj index 0c0c3df..ddf7c4a 100644 --- a/configd.xcodeproj/project.pbxproj +++ b/configd.xcodeproj/project.pbxproj @@ -48,6 +48,7 @@ 1558480607550D470046C2E9 /* PBXTargetDependency */, 1558480807550D470046C2E9 /* PBXTargetDependency */, D6DDAC3D147A24BC00A2E902 /* PBXTargetDependency */, + 72C12CB11D6EA2CA000EE61C /* PBXTargetDependency */, 150ECB300D0042DA0065E94D /* PBXTargetDependency */, ); name = configd_executables; @@ -118,6 +119,7 @@ 158317660CFB80D5006F62B9 /* PBXTargetDependency */, 157434210D4A8166002ACA73 /* PBXTargetDependency */, 1574341F0D4A815E002ACA73 /* PBXTargetDependency */, + 7271EA341D7660980055B1AA /* PBXTargetDependency */, ); name = "configd_executables-Embedded"; productName = configd_executables; @@ -295,7 +297,6 @@ 1565D85018B847590097062B /* SCNetworkMigration.c in Sources */ = {isa = PBXBuildFile; fileRef = 55A3DB9D183C2A8200ED3DB7 /* SCNetworkMigration.c */; }; 1565D85118B847F20097062B /* SCNetworkMigration.c in Sources */ = {isa = PBXBuildFile; fileRef = 55A3DB9D183C2A8200ED3DB7 /* SCNetworkMigration.c */; }; 156BD6BC07E0DFA9008698FF /* SCPreferencesSetSpecificPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 156BD6BB07E0DFA9008698FF /* SCPreferencesSetSpecificPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 1572AA8C1D8235390021E093 /* plugin_shared.h in Headers */ = {isa = PBXBuildFile; fileRef = 1572AA8B1D8234500021E093 /* plugin_shared.h */; }; 1572AA8D1D8235940021E093 /* plugin_shared.h in Headers */ = {isa = PBXBuildFile; fileRef = 1572AA8B1D8234500021E093 /* plugin_shared.h */; }; 1572AA8E1D8235A40021E093 /* plugin_shared.h in Headers */ = {isa = PBXBuildFile; fileRef = 1572AA8B1D8234500021E093 /* plugin_shared.h */; }; 1572AA8F1D82375A0021E093 /* plugin_shared.h in Headers */ = {isa = PBXBuildFile; fileRef = 1572AA8B1D8234500021E093 /* plugin_shared.h */; }; @@ -537,6 +538,15 @@ 157A85290D56C91100B6F1A0 /* linkconfig.c in Sources */ = {isa = PBXBuildFile; fileRef = 159D53C107528B36004F8947 /* linkconfig.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, ); }; }; + 1581BCD21E28673600F69B1E /* InterfaceNamerControlPrefs.h in Headers */ = {isa = PBXBuildFile; fileRef = 15FB1F891E27E9A000B4F809 /* InterfaceNamerControlPrefs.h */; }; + 1581BCD31E28679A00F69B1E /* InterfaceNamerControlPrefs.h in Headers */ = {isa = PBXBuildFile; fileRef = 15FB1F891E27E9A000B4F809 /* InterfaceNamerControlPrefs.h */; }; + 1581BCD41E2867A300F69B1E /* IPMonitorControlPrefs.h in Headers */ = {isa = PBXBuildFile; fileRef = F9A3780F16A4846E00C57CDC /* IPMonitorControlPrefs.h */; }; + 1581BCD51E2867A500F69B1E /* IPMonitorControlPrefs.h in Headers */ = {isa = PBXBuildFile; fileRef = F9A3780F16A4846E00C57CDC /* IPMonitorControlPrefs.h */; }; + 1581BCD61E2867AF00F69B1E /* IPMonitorControlPrefs.h in Headers */ = {isa = PBXBuildFile; fileRef = F9A3780F16A4846E00C57CDC /* IPMonitorControlPrefs.h */; }; + 1581BCD71E2867B200F69B1E /* IPMonitorControlPrefs.h in Headers */ = {isa = PBXBuildFile; fileRef = F9A3780F16A4846E00C57CDC /* IPMonitorControlPrefs.h */; }; + 1581BCD81E2867BA00F69B1E /* IPMonitorControlPrefs.h in Headers */ = {isa = PBXBuildFile; fileRef = F9A3780F16A4846E00C57CDC /* IPMonitorControlPrefs.h */; }; + 1581BCD91E2867C100F69B1E /* IPMonitorControlPrefs.h in Headers */ = {isa = PBXBuildFile; fileRef = F9A3780F16A4846E00C57CDC /* IPMonitorControlPrefs.h */; }; + 1581BCDD1E286E0000F69B1E /* InterfaceNamerControlPrefs.h in Headers */ = {isa = PBXBuildFile; fileRef = 15FB1F891E27E9A000B4F809 /* InterfaceNamerControlPrefs.h */; }; 158317250CFB80A1006F62B9 /* configd.h in Headers */ = {isa = PBXBuildFile; fileRef = 15CB69CF05C0722B0099E85F /* configd.h */; }; 158317260CFB80A1006F62B9 /* _SCD.h in Headers */ = {isa = PBXBuildFile; fileRef = 15CB69D105C0722B0099E85F /* _SCD.h */; }; 158317270CFB80A1006F62B9 /* configd_server.h in Headers */ = {isa = PBXBuildFile; fileRef = 15CB69D305C0722B0099E85F /* configd_server.h */; }; @@ -755,6 +765,7 @@ 15A5A2610D5B94190087BDA0 /* SCNetworkSignature.c in Sources */ = {isa = PBXBuildFile; fileRef = F95B8A420B03E07A00993BA3 /* SCNetworkSignature.c */; }; 15A5A2630D5B94190087BDA0 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15CB6A6F05C0722B0099E85F /* CoreFoundation.framework */; }; 15A6F7C40A4B266D00B907EA /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 15A6F7C20A4B266D00B907EA /* Localizable.strings */; }; + 15A9BDA81D8DEA67007024DB /* plugin_shared.h in Headers */ = {isa = PBXBuildFile; fileRef = 1572AA8B1D8234500021E093 /* plugin_shared.h */; }; 15AAA7F4108E310700C2A607 /* VPNTunnelPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 15AAA7F1108E310700C2A607 /* VPNTunnelPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 15AAA7F5108E310700C2A607 /* VPNTunnel.h in Headers */ = {isa = PBXBuildFile; fileRef = 15AAA7F2108E310700C2A607 /* VPNTunnel.h */; settings = {ATTRIBUTES = (Private, ); }; }; 15AAA7F6108E310700C2A607 /* VPNTunnel.c in Sources */ = {isa = PBXBuildFile; fileRef = 15AAA7F3108E310700C2A607 /* VPNTunnel.c */; }; @@ -884,6 +895,8 @@ 15E1B05416EBAE3C00E5F06F /* scprefs_observer.c in Sources */ = {isa = PBXBuildFile; fileRef = D61AAEAD1522C99C0066B003 /* scprefs_observer.c */; }; 15E1B05516EBAE3C00E5F06F /* IPMonitorControlPrefs.c in Sources */ = {isa = PBXBuildFile; fileRef = F9A3780E16A4846E00C57CDC /* IPMonitorControlPrefs.c */; }; 15F21618110F823500E89CF7 /* libbsm.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 15BAA32207F0699A00D9EC95 /* libbsm.dylib */; }; + 15FB1F8A1E27EA8700B4F809 /* InterfaceNamerControlPrefs.c in Sources */ = {isa = PBXBuildFile; fileRef = 15FB1F881E27E9A000B4F809 /* InterfaceNamerControlPrefs.c */; }; + 15FB1F8B1E27EA8900B4F809 /* InterfaceNamerControlPrefs.c in Sources */ = {isa = PBXBuildFile; fileRef = 15FB1F881E27E9A000B4F809 /* InterfaceNamerControlPrefs.c */; }; 15FBB54C17D6834C0035D752 /* libCrashReporterClient.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 15FBB54B17D6834C0035D752 /* libCrashReporterClient.a */; }; 15FC130B0CCEA59E0013872C /* monitor.c in Sources */ = {isa = PBXBuildFile; fileRef = 15FC130A0CCEA59E0013872C /* monitor.c */; }; 15FC13180CCF74740013872C /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 15CB6A6F05C0722B0099E85F /* CoreFoundation.framework */; }; @@ -903,6 +916,17 @@ 7214BCE41BEB392300A8F056 /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 728015961BE16B6C009F4F60 /* NetworkExtension.framework */; }; 72499BA41AC9B7AB0090C49F /* get-network-info in Resources */ = {isa = PBXBuildFile; fileRef = 72499BA31AC9B7AB0090C49F /* get-network-info */; }; 72499BA51AC9B7AB0090C49F /* get-network-info in Resources */ = {isa = PBXBuildFile; fileRef = 72499BA31AC9B7AB0090C49F /* get-network-info */; }; + 72573D291D667372004975AD /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D281D667372004975AD /* main.m */; }; + 72573D2E1D6673B6004975AD /* SCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D2D1D6673B6004975AD /* SCTest.m */; }; + 72573D321D667686004975AD /* SCTestUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D311D667686004975AD /* SCTestUtils.m */; }; + 72573D351D6680AA004975AD /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72573D331D66800C004975AD /* SystemConfiguration.framework */; }; + 72573D3A1D6692BA004975AD /* SCTestOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D391D6692BA004975AD /* SCTestOptions.m */; }; + 72573D3C1D6695B4004975AD /* SCTestDynamicStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D3B1D6695B4004975AD /* SCTestDynamicStore.m */; }; + 72573D3E1D669AA6004975AD /* SCTestPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D3D1D669AA6004975AD /* SCTestPreferences.m */; }; + 72573D401D67B2BE004975AD /* SCTestUnitTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D3F1D67B2BE004975AD /* SCTestUnitTest.m */; }; + 72573D421D6B798A004975AD /* SCTestConfigAgents.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D411D6B7989004975AD /* SCTestConfigAgents.m */; }; + 72573D441D6BA051004975AD /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 728015951BE16B6C009F4F60 /* Network.framework */; }; + 72573D451D6BA976004975AD /* libnetwork.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 90507AAF1CE2F55B0067D16B /* libnetwork.dylib */; }; 725CB7551BF439C6000C05A8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 725CB7541BF439C6000C05A8 /* Foundation.framework */; }; 725CB7561BF439D2000C05A8 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 725CB7541BF439C6000C05A8 /* Foundation.framework */; }; 725CB7581BF514F2000C05A8 /* configAgentDefines.h in Headers */ = {isa = PBXBuildFile; fileRef = 725CB7571BF51476000C05A8 /* configAgentDefines.h */; }; @@ -911,6 +935,20 @@ 7264C14614731A1F004FD76D /* CaptiveNetwork.h in Headers */ = {isa = PBXBuildFile; fileRef = 15A1FF3010597F17004C9CC9 /* CaptiveNetwork.h */; settings = {ATTRIBUTES = (Public, ); }; }; 726DB2F41BEA80E5001B2C6C /* config_agent_info.c in Sources */ = {isa = PBXBuildFile; fileRef = 726DB2F11BEA80E5001B2C6C /* config_agent_info.c */; }; 726DB2F61BEA80E5001B2C6C /* config_agent_info.h in Headers */ = {isa = PBXBuildFile; fileRef = 726DB2F21BEA80E5001B2C6C /* config_agent_info.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 7271EA1E1D76600B0055B1AA /* SCTestDynamicStore.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D3B1D6695B4004975AD /* SCTestDynamicStore.m */; }; + 7271EA1F1D76600B0055B1AA /* SCTestOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D391D6692BA004975AD /* SCTestOptions.m */; }; + 7271EA201D76600B0055B1AA /* SCTestUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D311D667686004975AD /* SCTestUtils.m */; }; + 7271EA211D76600B0055B1AA /* SCTestUnitTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D3F1D67B2BE004975AD /* SCTestUnitTest.m */; }; + 7271EA221D76600B0055B1AA /* SCTestReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 728E0E951D70229A00E0613A /* SCTestReachability.m */; }; + 7271EA231D76600B0055B1AA /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D281D667372004975AD /* main.m */; }; + 7271EA241D76600B0055B1AA /* SCTestConfigAgents.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D411D6B7989004975AD /* SCTestConfigAgents.m */; }; + 7271EA251D76600B0055B1AA /* SCTestPreferences.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D3D1D669AA6004975AD /* SCTestPreferences.m */; }; + 7271EA261D76600B0055B1AA /* SCTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 72573D2D1D6673B6004975AD /* SCTest.m */; }; + 7271EA281D76600B0055B1AA /* libnetwork.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 90507AAF1CE2F55B0067D16B /* libnetwork.dylib */; }; + 7271EA291D76600B0055B1AA /* Network.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 728015951BE16B6C009F4F60 /* Network.framework */; }; + 7271EA2A1D76600B0055B1AA /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 72573D331D66800C004975AD /* SystemConfiguration.framework */; }; + 7271EA2B1D76600B0055B1AA /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 728015961BE16B6C009F4F60 /* NetworkExtension.framework */; }; + 7271EA2D1D76600B0055B1AA /* npt_configd.plist in npt_configd.plist */ = {isa = PBXBuildFile; fileRef = 72C12CAA1D6E9ED4000EE61C /* npt_configd.plist */; }; 727AF25419138699009AB153 /* VPNAppLayerPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = B0A88CA616397A1200A60B3A /* VPNAppLayerPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 727AF255191386A0009AB153 /* VPNFlow.h in Headers */ = {isa = PBXBuildFile; fileRef = C4CDB8111631933400819B44 /* VPNFlow.h */; settings = {ATTRIBUTES = (Private, ); }; }; 727AF257191386DA009AB153 /* VPNTunnel.h in Headers */ = {isa = PBXBuildFile; fileRef = 15AAA7F2108E310700C2A607 /* VPNTunnel.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -935,10 +973,13 @@ 7280159E1BE1812B009F4F60 /* proxyAgent.h in Headers */ = {isa = PBXBuildFile; fileRef = 7280157F1BE16833009F4F60 /* proxyAgent.h */; }; 728CEAFF1BEA951A00F13F92 /* config_agent_info.c in Sources */ = {isa = PBXBuildFile; fileRef = 726DB2F11BEA80E5001B2C6C /* config_agent_info.c */; }; 728CEB001BEA993100F13F92 /* config_agent_info.h in Headers */ = {isa = PBXBuildFile; fileRef = 726DB2F21BEA80E5001B2C6C /* config_agent_info.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 728E0E961D70229A00E0613A /* SCTestReachability.m in Sources */ = {isa = PBXBuildFile; fileRef = 728E0E951D70229A00E0613A /* SCTestReachability.m */; }; + 728E0E971D70348D00E0613A /* NetworkExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 728015961BE16B6C009F4F60 /* NetworkExtension.framework */; }; 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 */; }; + 72C12CAB1D6E9F45000EE61C /* npt_configd.plist in npt_configd.plist */ = {isa = PBXBuildFile; fileRef = 72C12CAA1D6E9ED4000EE61C /* npt_configd.plist */; }; 72D3E6611AE6EA3A00DB4C69 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 72D3E6601AE6EA3A00DB4C69 /* main.swift */; }; 72D3E66C1AE6EAF600DB4C69 /* test-objC.m in Sources */ = {isa = PBXBuildFile; fileRef = 72D3E66B1AE6EAF600DB4C69 /* test-objC.m */; }; 90507AB01CE2F55B0067D16B /* libnetwork.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 90507AAF1CE2F55B0067D16B /* libnetwork.dylib */; }; @@ -1415,6 +1456,20 @@ remoteGlobalIDString = 15DAD63F07591A1A0084A6ED; remoteInfo = SystemConfiguration.framework; }; + 7271EA331D7660980055B1AA /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; + proxyType = 1; + remoteGlobalIDString = 7271EA1B1D76600B0055B1AA; + remoteInfo = "sctest-Embedded"; + }; + 72C12CB01D6EA2CA000EE61C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; + proxyType = 1; + remoteGlobalIDString = 72573D251D667372004975AD; + remoteInfo = sctest; + }; 72C4A47F1BE44D19009D570E /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 15CB6A7705C0722B0099E85F /* Project object */; @@ -1557,6 +1612,28 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + 72573D241D667372004975AD /* npt_configd.plist */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /AppleInternal/CoreOS/BATS/npt_tests; + dstSubfolderSpec = 0; + files = ( + 72C12CAB1D6E9F45000EE61C /* npt_configd.plist in npt_configd.plist */, + ); + name = npt_configd.plist; + runOnlyForDeploymentPostprocessing = 1; + }; + 7271EA2C1D76600B0055B1AA /* npt_configd.plist */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /AppleInternal/CoreOS/BATS/npt_tests; + dstSubfolderSpec = 0; + files = ( + 7271EA2D1D76600B0055B1AA /* npt_configd.plist in npt_configd.plist */, + ); + name = npt_configd.plist; + runOnlyForDeploymentPostprocessing = 1; + }; 72D3E65C1AE6EA3900DB4C69 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -1851,6 +1928,8 @@ 15DC346E0711D49400A3311C /* net_set.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = net_set.h; sourceTree = ""; }; 15E1B05916EBAE3C00E5F06F /* libIPMonitor_sim.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libIPMonitor_sim.a; sourceTree = BUILT_PRODUCTS_DIR; }; 15E1B06116EBAE7800E5F06F /* IPMonitor.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = IPMonitor.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 15FB1F881E27E9A000B4F809 /* InterfaceNamerControlPrefs.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = InterfaceNamerControlPrefs.c; sourceTree = ""; }; + 15FB1F891E27E9A000B4F809 /* InterfaceNamerControlPrefs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InterfaceNamerControlPrefs.h; sourceTree = ""; }; 15FBB54B17D6834C0035D752 /* libCrashReporterClient.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libCrashReporterClient.a; path = /usr/local/lib/libCrashReporterClient.a; sourceTree = ""; }; 15FBB54E17D7899C0035D752 /* Info-EmbeddedSimulator.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "Info-EmbeddedSimulator.plist"; sourceTree = ""; }; 15FBB55017D78A780035D752 /* update-mach-services */ = {isa = PBXFileReference; lastKnownFileType = text.script.sh; path = "update-mach-services"; sourceTree = ""; }; @@ -1872,11 +1951,27 @@ 55A3DB9D183C2A8200ED3DB7 /* SCNetworkMigration.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; path = SCNetworkMigration.c; sourceTree = ""; }; 720985431C580D9F00966D30 /* network_config_agent_info_priv.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = network_config_agent_info_priv.h; path = nwi/network_config_agent_info_priv.h; sourceTree = ""; }; 72499BA31AC9B7AB0090C49F /* get-network-info */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = "get-network-info"; sourceTree = SOURCE_ROOT; }; + 72573D261D667372004975AD /* sctest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 72573D281D667372004975AD /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 72573D2D1D6673B6004975AD /* SCTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCTest.m; sourceTree = ""; }; + 72573D2F1D6673C6004975AD /* SCTest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCTest.h; sourceTree = ""; }; + 72573D301D6675AF004975AD /* SCTestUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SCTestUtils.h; sourceTree = ""; }; + 72573D311D667686004975AD /* SCTestUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCTestUtils.m; sourceTree = ""; }; + 72573D331D66800C004975AD /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; }; + 72573D361D668B3C004975AD /* genSCTestOptions.c */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.c; name = genSCTestOptions.c; path = sctest/genSCTestOptions.c; sourceTree = SOURCE_ROOT; }; + 72573D381D6692BA004975AD /* SCTestOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SCTestOptions.h; sourceTree = ""; }; + 72573D391D6692BA004975AD /* SCTestOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCTestOptions.m; sourceTree = ""; }; + 72573D3B1D6695B4004975AD /* SCTestDynamicStore.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCTestDynamicStore.m; sourceTree = ""; }; + 72573D3D1D669AA6004975AD /* SCTestPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCTestPreferences.m; sourceTree = ""; }; + 72573D3F1D67B2BE004975AD /* SCTestUnitTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCTestUnitTest.m; sourceTree = ""; }; + 72573D411D6B7989004975AD /* SCTestConfigAgents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCTestConfigAgents.m; sourceTree = ""; }; + 72573D431D6B9E72004975AD /* sctest-entitlements.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "sctest-entitlements.plist"; path = "sctest/sctest-entitlements.plist"; sourceTree = SOURCE_ROOT; }; 725CB7541BF439C6000C05A8 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 725CB7571BF51476000C05A8 /* configAgentDefines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = configAgentDefines.h; sourceTree = ""; }; 725E53D51A92D2A5009997E1 /* com.apple.networking.IPMonitor */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = com.apple.networking.IPMonitor; sourceTree = ""; }; 726DB2F11BEA80E5001B2C6C /* config_agent_info.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = config_agent_info.c; path = "config-agent-info/config_agent_info.c"; sourceTree = ""; }; 726DB2F21BEA80E5001B2C6C /* config_agent_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = config_agent_info.h; path = "config-agent-info/config_agent_info.h"; sourceTree = ""; }; + 7271EA321D76600B0055B1AA /* sctest */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = sctest; sourceTree = BUILT_PRODUCTS_DIR; }; 728015751BE16833009F4F60 /* agent-monitor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = "agent-monitor.m"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; 728015781BE16833009F4F60 /* configAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = configAgent.h; sourceTree = ""; }; 728015791BE16833009F4F60 /* configAgent.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = configAgent.m; sourceTree = ""; }; @@ -1889,8 +1984,10 @@ 728015931BE1697E009F4F60 /* agent-monitor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "agent-monitor.h"; sourceTree = ""; }; 728015951BE16B6C009F4F60 /* Network.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Network.framework; path = System/Library/PrivateFrameworks/Network.framework; sourceTree = SDKROOT; }; 728015961BE16B6C009F4F60 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; }; + 728E0E951D70229A00E0613A /* SCTestReachability.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SCTestReachability.m; sourceTree = ""; }; 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 = ""; }; + 72C12CAA1D6E9ED4000EE61C /* npt_configd.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = npt_configd.plist; sourceTree = ""; }; 72D3E6591AE6E8A900DB4C69 /* Modules */ = {isa = PBXFileReference; lastKnownFileType = folder; name = Modules; path = SystemConfiguration.fproj/Modules; sourceTree = SOURCE_ROOT; }; 72D3E65E1AE6EA3A00DB4C69 /* SCTest-Swift */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = "SCTest-Swift"; sourceTree = BUILT_PRODUCTS_DIR; }; 72D3E6601AE6EA3A00DB4C69 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; @@ -2108,6 +2205,28 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 72573D231D667372004975AD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 72573D451D6BA976004975AD /* libnetwork.dylib in Frameworks */, + 72573D441D6BA051004975AD /* Network.framework in Frameworks */, + 72573D351D6680AA004975AD /* SystemConfiguration.framework in Frameworks */, + 728E0E971D70348D00E0613A /* NetworkExtension.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7271EA271D76600B0055B1AA /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7271EA281D76600B0055B1AA /* libnetwork.dylib in Frameworks */, + 7271EA291D76600B0055B1AA /* Network.framework in Frameworks */, + 7271EA2A1D76600B0055B1AA /* SystemConfiguration.framework in Frameworks */, + 7271EA2B1D76600B0055B1AA /* NetworkExtension.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 72D3E65B1AE6EA3900DB4C69 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -2395,8 +2514,10 @@ 159D53C907528B36004F8947 /* common */ = { isa = PBXGroup; children = ( - F9A3780E16A4846E00C57CDC /* IPMonitorControlPrefs.c */, + 15FB1F891E27E9A000B4F809 /* InterfaceNamerControlPrefs.h */, + 15FB1F881E27E9A000B4F809 /* InterfaceNamerControlPrefs.c */, F9A3780F16A4846E00C57CDC /* IPMonitorControlPrefs.h */, + F9A3780E16A4846E00C57CDC /* IPMonitorControlPrefs.c */, 159D53CA07528B36004F8947 /* cache.c */, 159D53CB07528B36004F8947 /* cache.h */, 1572AA8B1D8234500021E093 /* plugin_shared.h */, @@ -2674,6 +2795,7 @@ 15CB6A6E05C0722B0099E85F /* External Frameworks and Libraries */, 72D3E65F1AE6EA3A00DB4C69 /* SCTest-Swift */, 72D3E66A1AE6EAF600DB4C69 /* SCTest-ObjC */, + 72573D271D667372004975AD /* sctest */, 15CB690F05C0722B0099E85F /* Products */, 90507AAE1CE2F55B0067D16B /* Frameworks */, ); @@ -2722,6 +2844,8 @@ 155F49931C864F3700E47D08 /* QoSMarking.bundle */, 155F499C1C864F4E00E47D08 /* libQoSMarking.a */, 155F49A21C864F5400E47D08 /* QoSMarking.bundle */, + 72573D261D667372004975AD /* sctest */, + 7271EA321D76600B0055B1AA /* sctest */, ); name = Products; sourceTree = ""; @@ -2981,6 +3105,28 @@ name = "Supporting Files"; sourceTree = ""; }; + 72573D271D667372004975AD /* sctest */ = { + isa = PBXGroup; + children = ( + 72573D361D668B3C004975AD /* genSCTestOptions.c */, + 72573D381D6692BA004975AD /* SCTestOptions.h */, + 72573D391D6692BA004975AD /* SCTestOptions.m */, + 72573D301D6675AF004975AD /* SCTestUtils.h */, + 72573D311D667686004975AD /* SCTestUtils.m */, + 72573D2F1D6673C6004975AD /* SCTest.h */, + 72573D281D667372004975AD /* main.m */, + 72573D2D1D6673B6004975AD /* SCTest.m */, + 72573D3B1D6695B4004975AD /* SCTestDynamicStore.m */, + 72573D3D1D669AA6004975AD /* SCTestPreferences.m */, + 72573D411D6B7989004975AD /* SCTestConfigAgents.m */, + 728E0E951D70229A00E0613A /* SCTestReachability.m */, + 72573D3F1D67B2BE004975AD /* SCTestUnitTest.m */, + 72573D431D6B9E72004975AD /* sctest-entitlements.plist */, + 72C12CAA1D6E9ED4000EE61C /* npt_configd.plist */, + ); + path = sctest; + sourceTree = ""; + }; 725E53D41A92D289009997E1 /* Simulator */ = { isa = PBXGroup; children = ( @@ -3035,6 +3181,7 @@ 90507AAE1CE2F55B0067D16B /* Frameworks */ = { isa = PBXGroup; children = ( + 72573D331D66800C004975AD /* SystemConfiguration.framework */, 90507AB11CE2F5720067D16B /* libnetwork.dylib */, 90507AAF1CE2F55B0067D16B /* libnetwork.dylib */, ); @@ -3116,6 +3263,8 @@ 155847520754FDCD0046C2E9 /* net_service.h in Headers */, 155847530754FDCD0046C2E9 /* net_set.h in Headers */, 72B43728113C7BFC00EBF1B6 /* nc.h in Headers */, + 1581BCD31E28679A00F69B1E /* InterfaceNamerControlPrefs.h in Headers */, + 1581BCD51E2867A500F69B1E /* IPMonitorControlPrefs.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3233,6 +3382,7 @@ 15732ABA16EA511900F3AC4C /* net_service.h in Headers */, 15732ABB16EA511900F3AC4C /* net_set.h in Headers */, 15732ABC16EA511900F3AC4C /* nc.h in Headers */, + 1581BCD91E2867C100F69B1E /* IPMonitorControlPrefs.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3272,6 +3422,8 @@ 157433FD0D4A8137002ACA73 /* net_service.h in Headers */, 157433FE0D4A8137002ACA73 /* net_set.h in Headers */, 72B4372A113C7BFC00EBF1B6 /* nc.h in Headers */, + 1581BCDD1E286E0000F69B1E /* InterfaceNamerControlPrefs.h in Headers */, + 1581BCD71E2867B200F69B1E /* IPMonitorControlPrefs.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3308,6 +3460,7 @@ 153ACCAC14E322D5005029A5 /* network_information_server.h in Headers */, 720A4C0A1C585C7D007436B8 /* configAgent.h in Headers */, 1596A7B514EDB73D00798C39 /* libSystemConfiguration_server.h in Headers */, + 1581BCD61E2867AF00F69B1E /* IPMonitorControlPrefs.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3315,7 +3468,7 @@ isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; files = ( - 1572AA8C1D8235390021E093 /* plugin_shared.h in Headers */, + 15A9BDA81D8DEA67007024DB /* plugin_shared.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3388,6 +3541,7 @@ buildActionMask = 2147483647; files = ( 1572AA8F1D82375A0021E093 /* plugin_shared.h in Headers */, + 1581BCD21E28673600F69B1E /* InterfaceNamerControlPrefs.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3401,6 +3555,7 @@ 7280159D1BE1812B009F4F60 /* dnsAgent.h in Headers */, 7280159E1BE1812B009F4F60 /* proxyAgent.h in Headers */, 155D223B0AF13A7300D52ED0 /* dns-configuration.h in Headers */, + 1581BCD41E2867A300F69B1E /* IPMonitorControlPrefs.h in Headers */, 15D48EC00F67061700B4711E /* dnsinfo_create.h in Headers */, 725CB7581BF514F2000C05A8 /* configAgentDefines.h in Headers */, E4F211D7137B0AF200BBB915 /* network_state_information_priv.h in Headers */, @@ -3593,6 +3748,7 @@ 15E1B04516EBAE3C00E5F06F /* network_state_information_priv.h in Headers */, 15E1B04616EBAE3C00E5F06F /* proxy-configuration.h in Headers */, 15E1B04816EBAE3C00E5F06F /* network_information_server.h in Headers */, + 1581BCD81E2867BA00F69B1E /* IPMonitorControlPrefs.h in Headers */, 15E1B04916EBAE3C00E5F06F /* libSystemConfiguration_server.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; @@ -4398,6 +4554,42 @@ productReference = 15FD72C90754DA7E001CC321 /* PreferencesMonitor.bundle */; productType = "com.apple.product-type.bundle"; }; + 72573D251D667372004975AD /* sctest */ = { + isa = PBXNativeTarget; + buildConfigurationList = 72573D2A1D667372004975AD /* Build configuration list for PBXNativeTarget "sctest" */; + buildPhases = ( + 72573D221D667372004975AD /* Sources */, + 72573D231D667372004975AD /* Frameworks */, + 72573D241D667372004975AD /* npt_configd.plist */, + 72C12CB21D6FEFBE000EE61C /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = sctest; + productName = sctest; + productReference = 72573D261D667372004975AD /* sctest */; + productType = "com.apple.product-type.tool"; + }; + 7271EA1B1D76600B0055B1AA /* sctest-Embedded */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7271EA2F1D76600B0055B1AA /* Build configuration list for PBXNativeTarget "sctest-Embedded" */; + buildPhases = ( + 7271EA1D1D76600B0055B1AA /* Sources */, + 7271EA271D76600B0055B1AA /* Frameworks */, + 7271EA2C1D76600B0055B1AA /* npt_configd.plist */, + 7271EA2E1D76600B0055B1AA /* Fix plist ownership */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "sctest-Embedded"; + productName = sctest; + productReference = 7271EA321D76600B0055B1AA /* sctest */; + productType = "com.apple.product-type.tool"; + }; 72D3E65D1AE6EA3900DB4C69 /* SCTest-Swift */ = { isa = PBXNativeTarget; buildConfigurationList = 72D3E6621AE6EA3A00DB4C69 /* Build configuration list for PBXNativeTarget "SCTest-Swift" */; @@ -4442,6 +4634,10 @@ attributes = { LastUpgradeCheck = 0800; TargetAttributes = { + 72573D251D667372004975AD = { + CreatedOnToolsVersion = 8.0; + ProvisioningStyle = Automatic; + }; 72D3E65D1AE6EA3900DB4C69 = { CreatedOnToolsVersion = 7.0; }; @@ -4527,6 +4723,8 @@ 15E83104167F9AF600FD51EC /* EVERYTHING */, 72D3E65D1AE6EA3900DB4C69 /* SCTest-Swift */, 72D3E6681AE6EAF600DB4C69 /* SCTest-ObjC */, + 72573D251D667372004975AD /* sctest */, + 7271EA1B1D76600B0055B1AA /* sctest-Embedded */, ); }; /* End PBXProject section */ @@ -4939,6 +5137,33 @@ shellScript = "if [ -x ${SCRIPT_INPUT_FILE_0} ]; then\n\t${SCRIPT_INPUT_FILE_0} com.apple.configd_sim.plist\nfi"; showEnvVarsInLog = 0; }; + 7271EA2E1D76600B0055B1AA /* Fix plist ownership */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + inputPaths = ( + ); + name = "Fix plist ownership"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/sh; + shellScript = "if [ ${UID} -eq 0 ]; then\n\tchown 0:0 \"${DSTROOT}/AppleInternal/CoreOS/BATS/npt_tests/npt_configd.plist\"\nfi\n\nexit 0"; + }; + 72C12CB21D6FEFBE000EE61C /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 8; + files = ( + ); + inputPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 1; + shellPath = /bin/sh; + shellScript = "if [ ${UID} -eq 0 ]; then\n\tchown 0:0 \"${DSTROOT}/AppleInternal/CoreOS/BATS/npt_tests/npt_configd.plist\"\nfi\n\nexit 0"; + }; /* End PBXShellScriptBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -4977,6 +5202,7 @@ 155847600754FDCD0046C2E9 /* net_service.c in Sources */, 155847610754FDCD0046C2E9 /* net_set.c in Sources */, 72B43729113C7BFC00EBF1B6 /* nc.c in Sources */, + 15FB1F8B1E27EA8900B4F809 /* InterfaceNamerControlPrefs.c in Sources */, F9B50FF316A4CBB200CA274E /* IPMonitorControlPrefs.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -5306,6 +5532,7 @@ buildActionMask = 2147483647; files = ( 159D541607528DF1004F8947 /* ifnamer.c in Sources */, + 15FB1F8A1E27EA8700B4F809 /* InterfaceNamerControlPrefs.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5318,7 +5545,6 @@ 15D48EBF0F67061600B4711E /* dnsinfo_create.c in Sources */, 1522FCFB0FA7FE4B00B24128 /* dnsinfo_flatfile.c in Sources */, 150BEC1814CA24F900237116 /* dnsinfo_server.c in Sources */, - F9B7AE6A186211D300C78D18 /* IPMonitorControlServer.c in Sources */, 159D541707528E05004F8947 /* ip_plugin.c in Sources */, 7280158D1BE16861009F4F60 /* dnsAgent.m in Sources */, E49173E1137C4E4F0000089F /* network_state_information_priv.c in Sources */, @@ -5332,6 +5558,7 @@ 7280158C1BE1685D009F4F60 /* controller.m in Sources */, D61AAEAF1522C99C0066B003 /* scprefs_observer.c in Sources */, F9A3781016A4847700C57CDC /* IPMonitorControlPrefs.c in Sources */, + F9B7AE6A186211D300C78D18 /* IPMonitorControlServer.c in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -5572,6 +5799,38 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 72573D221D667372004975AD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 72573D3C1D6695B4004975AD /* SCTestDynamicStore.m in Sources */, + 72573D3A1D6692BA004975AD /* SCTestOptions.m in Sources */, + 72573D321D667686004975AD /* SCTestUtils.m in Sources */, + 72573D401D67B2BE004975AD /* SCTestUnitTest.m in Sources */, + 728E0E961D70229A00E0613A /* SCTestReachability.m in Sources */, + 72573D291D667372004975AD /* main.m in Sources */, + 72573D421D6B798A004975AD /* SCTestConfigAgents.m in Sources */, + 72573D3E1D669AA6004975AD /* SCTestPreferences.m in Sources */, + 72573D2E1D6673B6004975AD /* SCTest.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7271EA1D1D76600B0055B1AA /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7271EA1E1D76600B0055B1AA /* SCTestDynamicStore.m in Sources */, + 7271EA1F1D76600B0055B1AA /* SCTestOptions.m in Sources */, + 7271EA201D76600B0055B1AA /* SCTestUtils.m in Sources */, + 7271EA211D76600B0055B1AA /* SCTestUnitTest.m in Sources */, + 7271EA221D76600B0055B1AA /* SCTestReachability.m in Sources */, + 7271EA231D76600B0055B1AA /* main.m in Sources */, + 7271EA241D76600B0055B1AA /* SCTestConfigAgents.m in Sources */, + 7271EA251D76600B0055B1AA /* SCTestPreferences.m in Sources */, + 7271EA261D76600B0055B1AA /* SCTest.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 72D3E65A1AE6EA3900DB4C69 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -5881,6 +6140,16 @@ target = 15DAD63F07591A1A0084A6ED /* SystemConfiguration.framework */; targetProxy = 723050331AE6F29D004AC149 /* PBXContainerItemProxy */; }; + 7271EA341D7660980055B1AA /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 7271EA1B1D76600B0055B1AA /* sctest-Embedded */; + targetProxy = 7271EA331D7660980055B1AA /* PBXContainerItemProxy */; + }; + 72C12CB11D6EA2CA000EE61C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 72573D251D667372004975AD /* sctest */; + targetProxy = 72C12CB01D6EA2CA000EE61C /* PBXContainerItemProxy */; + }; 72C4A4801BE44D19009D570E /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 155847430754FDCD0046C2E9 /* scutil */; @@ -7784,6 +8053,74 @@ }; name = Release; }; + 72573D2B1D667372004975AD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_ENTITLEMENTS = "sctest/sctest-entitlements.plist"; + CODE_SIGN_IDENTITY = "-"; + FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; + HEADER_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders"; + INSTALL_PATH = /usr/local/bin; + MTL_ENABLE_DEBUG_INFO = YES; + PLIST_FILE_OUTPUT_FORMAT = "same-as-input"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 72573D2C1D667372004975AD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_ENTITLEMENTS = "sctest/sctest-entitlements.plist"; + CODE_SIGN_IDENTITY = "-"; + FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; + HEADER_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders"; + INSTALL_PATH = /usr/local/bin; + MTL_ENABLE_DEBUG_INFO = NO; + PLIST_FILE_OUTPUT_FORMAT = "same-as-input"; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; + 7271EA301D76600B0055B1AA /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_ENTITLEMENTS = "sctest/sctest-entitlements.plist"; + CODE_SIGN_IDENTITY = "-"; + FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; + HEADER_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders"; + INSTALL_PATH = /usr/local/bin; + MTL_ENABLE_DEBUG_INFO = YES; + PLIST_FILE_OUTPUT_FORMAT = "same-as-input"; + PRODUCT_NAME = sctest; + SDKROOT = iphoneos.internal; + SUPPORTED_PLATFORMS = iphoneos; + }; + name = Debug; + }; + 7271EA311D76600B0055B1AA /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = NO; + CLANG_ENABLE_OBJC_ARC = YES; + CODE_SIGN_ENTITLEMENTS = "sctest/sctest-entitlements.plist"; + CODE_SIGN_IDENTITY = "-"; + FRAMEWORK_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/PrivateFrameworks"; + HEADER_SEARCH_PATHS = "$(SDKROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/System.framework/PrivateHeaders"; + INSTALL_PATH = /usr/local/bin; + MTL_ENABLE_DEBUG_INFO = NO; + PLIST_FILE_OUTPUT_FORMAT = "same-as-input"; + PRODUCT_NAME = sctest; + SDKROOT = iphoneos.internal; + SUPPORTED_PLATFORMS = iphoneos; + }; + name = Release; + }; 72D3E6631AE6EA3A00DB4C69 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -8481,6 +8818,24 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 72573D2A1D667372004975AD /* Build configuration list for PBXNativeTarget "sctest" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 72573D2B1D667372004975AD /* Debug */, + 72573D2C1D667372004975AD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7271EA2F1D76600B0055B1AA /* Build configuration list for PBXNativeTarget "sctest-Embedded" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7271EA301D76600B0055B1AA /* Debug */, + 7271EA311D76600B0055B1AA /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 72D3E6621AE6EA3A00DB4C69 /* Build configuration list for PBXNativeTarget "SCTest-Swift" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/get-mobility-info b/get-mobility-info index 6df85fd..db30d7b 100755 --- a/get-mobility-info +++ b/get-mobility-info @@ -1,5 +1,5 @@ #!/bin/sh -# Copyright (c) 2004-2015 Apple Inc. +# Copyright (c) 2004-2017 Apple Inc. # # get-mobility-info # @@ -8,6 +8,30 @@ PATH=/bin:/usr/bin:/sbin:/usr/sbin +OUTDIR="" +NO_PCAP=0 +NO_TAR=0 + +while getopts f:PT OPTION ; do + case ${OPTION} in + f) + OUTDIR="${OPTARG}" + if [ ! -d "${OUTDIR}" ]; then + echo "# ${PROGNAME}: \"${OUTDIR}\" is not a directory" + exit 1 + fi + ;; + P) + NO_PCAP=1 + ;; + T) + NO_TAR=1 + ;; + \?) + ;; + esac +done + # # Disclaimer # @@ -45,12 +69,15 @@ else fi OUT="mobility-info-`date +'%Y.%m.%d.%H%M%S'`" -OUTDIR="/var/tmp" -if [ -d ~/Desktop ]; then - OUTDIR=~/Desktop -elif [ "`readlink /tmp`" = "private/var/tmp" ]; then - OUTDIR=/Library/Logs/CrashReporter - mkdir -p ${OUTDIR} + +if [ -z $OUTDIR ]; then + OUTDIR="/var/tmp" + if [ -d ~/Desktop ]; then + OUTDIR=~/Desktop + elif [ "`readlink /tmp`" = "private/var/tmp" ]; then + OUTDIR=/Library/Logs/CrashReporter + mkdir -p ${OUTDIR} + fi fi umask 077 @@ -61,18 +88,20 @@ if [ $? -ne 0 ]; then exit 1 fi -GZ_EXT="" -GZ_OPT="" -if [ -x /usr/bin/gzip ]; then - GZ_EXT=".gz" - GZ_OPT="-z" -fi +if [ $NO_TAR -eq 0 ]; then + GZ_EXT="" + GZ_OPT="" + if [ -x /usr/bin/gzip ]; then + GZ_EXT=".gz" + GZ_OPT="-z" + fi -ARCHIVE=`mktemp -q "${OUTDIR}/${OUT}.tar${GZ_EXT}"` -if [ $? -ne 0 ]; then - echo "Could not create snapshot archive" - rm -rf "${WORKDIR}" - exit 1 + ARCHIVE=`mktemp -q "${OUTDIR}/${OUT}.tar${GZ_EXT}"` + if [ $? -ne 0 ]; then + echo "Could not create snapshot archive" + rm -rf "${WORKDIR}" + exit 1 + fi fi cd "${WORKDIR}" @@ -81,15 +110,22 @@ echo "" echo "Please wait, collecting information and statistics" echo "" +# +# collect packet capture with kernel ring buffer if available +# +if [ -x /usr/local/bin/netdiagnose -a ${NO_PCAP} -ne 1 ]; then + /usr/local/bin/netdiagnose -p "${WORKDIR}" start packetcapture 2>&1 +fi + # # get-network-info # if [ -x /System/Library/Frameworks/SystemConfiguration.framework/Resources/get-network-info ]; then - /System/Library/Frameworks/SystemConfiguration.framework/Resources/get-network-info -s -c "${WORKDIR}" + /System/Library/Frameworks/SystemConfiguration.framework/Resources/get-network-info -s -c -P "${WORKDIR}" elif [ -x /System/Library/Frameworks/SystemConfiguration.framework/get-network-info ]; then - /System/Library/Frameworks/SystemConfiguration.framework/get-network-info -s -c "${WORKDIR}" + /System/Library/Frameworks/SystemConfiguration.framework/get-network-info -s -c -P "${WORKDIR}" elif [ -x /System/Library/PrivateFrameworks/SystemConfiguration.framework/get-network-info ]; then - /System/Library/PrivateFrameworks/SystemConfiguration.framework/get-network-info -s -c "${WORKDIR}" + /System/Library/PrivateFrameworks/SystemConfiguration.framework/get-network-info -s -c -P "${WORKDIR}" fi # @@ -631,19 +667,38 @@ fi wait # -# collect everything into a single archive +# Stop the packet capture # -cd "${WORKDIR}/.." -tar -c ${GZ_OPT} -f "${ARCHIVE}" "${OUT}" -rm -rf "${WORKDIR}" +if [ -x /usr/local/bin/netdiagnose -a ${NO_PCAP} -ne 1 ]; then + /usr/local/bin/netdiagnose stop packetcapture 2>&1 +fi -if [ ${UID} -eq 0 ]; then - if [ -n "${SUDO_UID}" -a -n "${SUDO_GID}" ]; then - if [ ${UID} -ne ${SUDO_UID} ]; then - chown ${SUDO_UID}:${SUDO_GID} "${ARCHIVE}" +if [ $NO_TAR -eq 0 ]; then + # + # collect everything into a single archive + # + cd "${WORKDIR}/.." + tar -c ${GZ_OPT} -f "${ARCHIVE}" "${OUT}" + rm -rf "${WORKDIR}" + + if [ ${UID} -eq 0 ]; then + if [ -n "${SUDO_UID}" -a -n "${SUDO_GID}" ]; then + if [ ${UID} -ne ${SUDO_UID} ]; then + chown ${SUDO_UID}:${SUDO_GID} "${ARCHIVE}" + fi fi fi -fi -echo "Network data collected to \"${ARCHIVE}\"" + echo "Network data collected to \"${ARCHIVE}\"" +else + mv "${WORKDIR}" "${OUTDIR}" + if [ ${UID} -eq 0 ]; then + if [ -n "${SUDO_UID}" -a -n "${SUDO_GID}" ]; then + if [ ${UID} -ne ${SUDO_UID} ]; then + chown -R ${SUDO_UID}:${SUDO_GID} "${OUTDIR}/${OUT}" + fi + fi + fi + echo "Network data collected to \"${OUTDIR}/${OUT}\"" +fi diff --git a/get-network-info b/get-network-info index 81a8229..bcf39c3 100755 --- a/get-network-info +++ b/get-network-info @@ -25,6 +25,10 @@ process_opts () { COLLECT_NDF_INFO="Y" shift ;; + -P) + COLLECT_PCAP="N" + shift + ;; -s) COLLECT_SENSITIVE_INFO="Y" shift @@ -560,11 +564,34 @@ run_lsof () { } +start_pcap() { + + # + # collect a packet capture if netdiagnose is available + # + if [ -x /usr/local/bin/netdiagnose ]; then + /usr/local/bin/netdiagnose -p "${REQUESTED_OUTDIR}" start sysdiagpcap 2>&1 + + PCAP_STARTED=1 + fi +} + +stop_pcap () { + if [ ${PCAP_STARTED} -ne 0 ]; then + /usr/local/bin/netdiagnose stop sysdiagpcap 2>&1 + fi +} + collect_ndf_info () { run_lsof } collect_sensitive_info () { + + if [ "${COLLECT_PCAP}" == "Y" ]; then + start_pcap + fi + collect_state_dump_sensitive run_ndp run_arp @@ -595,6 +622,8 @@ collect_info () { if [ "${COLLECT_CONFIGURATION_FILES}" == "Y" ]; then collect_configuration_files fi + + stop_pcap } # __COMMAND_ROUTINES_END__ @@ -606,6 +635,7 @@ usage () { echo "Usage: get-network-info [-c] [-n] [-s] " echo " -c collects system configuration files" echo " -n collects NDF information (lsof)" + echo " -P do not collect a packet capture" echo " -s collects sensitive information (ARP/NDP/mDNS cache)" echo " path to directory where all the information will be collected" @@ -642,6 +672,9 @@ init_globals () { REQUESTED_OUTDIR="" COLLECT_SENSITIVE_INFO="" COLLECT_CONFIGURATION_FILES="" + COLLECT_PCAP="Y" + PCAP_STARTED=0 + } # __HELPER_ROUTINES_END__ @@ -649,7 +682,7 @@ init_globals () { # # __MAIN__ # -ARGS=`getopt cns $*` +ARGS=`getopt cnPs $*` if [ $? != 0 ]; then usage exit 1 diff --git a/sctest/Makefile b/sctest/Makefile new file mode 100644 index 0000000..bc47fa4 --- /dev/null +++ b/sctest/Makefile @@ -0,0 +1,14 @@ +# +# Makefile for generating the SCTestOptions.[mh] files +# + +all: SCTestOptions.h SCTestOptions.m + +/tmp/genSCTestOptions: genSCTestOptions.c Makefile + cc -g -o /tmp/genSCTestOptions genSCTestOptions.c + +SCTestOptions.h: /tmp/genSCTestOptions + /tmp/genSCTestOptions header > SCTestOptions.h + +SCTestOptions.m: /tmp/genSCTestOptions + /tmp/genSCTestOptions mfile > SCTestOptions.m \ No newline at end of file diff --git a/sctest/SCTest.h b/sctest/SCTest.h new file mode 100644 index 0000000..b798d55 --- /dev/null +++ b/sctest/SCTest.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2016 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 SCTest_h +#define SCTest_h + +#import +#import "SCTestOptions.h" +#import "SCTestUtils.h" + +@interface SCTest : NSObject + +@property (atomic, retain) NSDictionary *options; +@property (atomic) CPUUsageInfo *globalCPU; +@property (atomic) timerInfo *globalTimer; + +- (instancetype)initWithOptions:(NSDictionary *)options; +- (void)start; +- (void)cleanupAndExitWithErrorCode:(int)error; +- (BOOL)unitTest; +- (void)waitFor:(double)seconds; + ++ (NSString *)command; ++ (NSString *)commandDescription; + +@end + +#endif /* SCTest_h */ diff --git a/sctest/SCTest.m b/sctest/SCTest.m new file mode 100644 index 0000000..bc4ce1c --- /dev/null +++ b/sctest/SCTest.m @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016 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@ + */ + +#import "SCTest.h" + +@implementation SCTest + +- (instancetype)initWithOptions:(NSDictionary *)options +{ + self = [super init]; + if (self) { + self.options = options; + self.globalCPU = malloc(sizeof(CPUUsageInfo)); + self.globalTimer = malloc(sizeof(timerInfo)); + } + return self; +} + +- (void)dealloc +{ + if (self.globalTimer != NULL) { + free(self.globalTimer); + } + if (self.globalCPU != NULL) { + free(self.globalCPU); + } +} + ++ (NSString *)command +{ + return @"sctest"; +} + ++ (NSString *)commandDescription +{ + return @"This is a generic class"; +} + ++ (NSString *)commandHelp +{ + return @"This is a generic help"; +} + +- (void)start +{ + return; +} + +- (void)waitFor:(double)seconds +{ + dispatch_semaphore_t sem = dispatch_semaphore_create(0); + dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)); + dispatch_source_set_timer(timer, dispatch_time(DISPATCH_TIME_NOW, seconds * NSEC_PER_SEC), DISPATCH_TIME_FOREVER, 0); + dispatch_source_set_event_handler(timer, ^{ + dispatch_semaphore_signal(sem); + }); + dispatch_resume(timer); + dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); +} + +- (void)cleanupAndExitWithErrorCode:(int)error +{ + if (self.options[kSCTestGlobalOptionTime] != nil) { + timerEnd(self.globalTimer); + SCTestLog("Time: %@ s", createUsageStringForTimer(self.globalTimer)); + } + + if (self.options[kSCTestGlobalOptionCPU] != nil) { + cpuEnd(self.globalCPU); + SCTestLog("CPU: %@", createUsageStringForCPU(self.globalCPU)); + } + + if (self.options[kSCTestGlobalOptionWait] != nil) { + return; + } + exit(error); +} + +- (BOOL)unitTest +{ + return YES; +} + +@end diff --git a/sctest/SCTestConfigAgents.m b/sctest/SCTestConfigAgents.m new file mode 100644 index 0000000..122f258 --- /dev/null +++ b/sctest/SCTestConfigAgents.m @@ -0,0 +1,654 @@ +/* + * Copyright (c) 2016 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@ + */ + +#import "SCTest.h" +#import "SCTestUtils.h" +#import +#import +#import + +#define TEST_DOMAIN "filemaker.com" +#define PATH_QUIESCE_TIME 1.5 // seconds + +@interface SCTestConfigAgent : SCTest +@property NSString *serviceID; +@property NSString *proxyKey; +@property NSString *dnsKey; +@property NSArray *> *testProxy; +@property NSArray *testDNS; +@property SCDynamicStoreRef store; +@property (copy) NSArray *> *pathProxy; +@property (copy) NSArray *pathDNS; +@end + +@implementation SCTestConfigAgent + +- (instancetype)initWithOptions:(NSDictionary *)options +{ + self = [super initWithOptions:options]; + if (self) { + _serviceID = @"8F66B505-EAEF-4611-BD4D-C523FD9451F0"; + _store = SCDynamicStoreCreate(kCFAllocatorDefault, + CFSTR("SCTest"), + NULL, + NULL); + _proxyKey = (__bridge_transfer NSString *)[self copyStateKeyWithServiceID:(__bridge CFStringRef)(self.serviceID) forEntity:kSCEntNetProxies]; + _dnsKey = (__bridge_transfer NSString *)[self copyStateKeyWithServiceID:(__bridge CFStringRef)(self.serviceID) forEntity:kSCEntNetDNS]; + } + return self; +} + +- (void)dealloc +{ + if (self.store != NULL) { + CFRelease(self.store); + self.store = NULL; + } +} + ++ (NSString *)command +{ + return @"config_agent"; +} + ++ (NSString *)commandDescription +{ + return @"Tests the Config Agent code path"; +} + +- (void)start +{ + if (self.options[kSCTestConfigAgentRemoveProxy]) { + [self removeFromSCDynamicStore:self.proxyKey]; + } + + if (self.options[kSCTestConfigAgentRemoveDNS]) { + [self removeFromSCDynamicStore:self.dnsKey]; + } + + NSDictionary *proxyConfig = [self parseProxyAgentOptions]; + if (proxyConfig != nil) { + [self publishToSCDynamicStore:self.proxyKey value:proxyConfig]; + self.testProxy = @[@[proxyConfig]]; + } + + NSDictionary *dnsConfig = [self parseDNSAgentOptions]; + if (dnsConfig != nil) { + [self publishToSCDynamicStore:self.dnsKey value:dnsConfig]; + self.testDNS = [self createDNSArray:dnsConfig]; + } + + [self cleanupAndExitWithErrorCode:0]; +} + +- (CFStringRef)copyStateKeyWithServiceID:(CFStringRef)serviceID + forEntity:(CFStringRef)entity +{ + return SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault, + kSCDynamicStoreDomainState, + serviceID, + entity); +} + +- (NSArray *)createDNSArray:(NSDictionary *)dnsConfig +{ + NSArray *dnsServers; + NSMutableArray *dnsArray; + + dnsServers = [dnsConfig objectForKey:(__bridge NSString *)kSCPropNetDNSServerAddresses]; + if (dnsServers == nil || [dnsServers count] == 0) { + return nil; + } + + dnsArray = [[NSMutableArray alloc] init]; + for (NSString *server in dnsServers) { + NWEndpoint *endpoint = (NWEndpoint *)[NWAddressEndpoint endpointWithHostname:server port:@"0"]; + [dnsArray addObject:endpoint]; + } + + return dnsArray; +} + +- (void)publishToSCDynamicStore:(NSString *)key + value:(NSDictionary *)value +{ + + BOOL ok = SCDynamicStoreSetValue(self.store, (__bridge CFStringRef)key, (__bridge CFPropertyListRef _Nonnull)(value)); + if (!ok) { + int error = SCError(); + if (error == kSCStatusNoKey) { + return; + } + SCTestLog("Could not set in SCDynamicStore: Error: %s", SCErrorString(error)); + return; + } +} + +- (void)removeFromSCDynamicStore:(NSString *)key +{ + BOOL ok = SCDynamicStoreRemoveValue(self.store, (__bridge CFStringRef)key); + if (!ok) { + int error = SCError(); + if (error == kSCStatusNoKey) { + return; + } + SCTestLog("Could not remove key: %@, Error: %s", key, SCErrorString(error)); + return; + } +} + +- (NSDictionary *)parseProxyAgentOptions +{ + NSMutableDictionary *proxyConfig = [[NSMutableDictionary alloc] init]; + +#define NS_NUMBER(x) [NSNumber numberWithInt:x] + +#define SET_PROXY_CONFIG(proxyType) \ + do { \ + if (self.options[kSCTestConfigAgent ## proxyType ## Proxy] != nil) { \ + NSString *serverAndPortString = self.options[kSCTestConfigAgent ## proxyType ## Proxy]; \ + NSArray *serverAndPortArray = [serverAndPortString componentsSeparatedByString:@":"]; \ + if ([serverAndPortArray count] != 2) { \ + SCTestLog("server address or port missing"); \ + ERR_EXIT; \ + } \ + NSString *server = [serverAndPortArray objectAtIndex:0]; \ + NSString *port = [serverAndPortArray objectAtIndex:1]; \ + [proxyConfig setObject:server forKey:(__bridge NSString *)kSCPropNetProxies ## proxyType ## Proxy]; \ + [proxyConfig setObject:NS_NUMBER(port.intValue) forKey:(__bridge NSString *)kSCPropNetProxies ## proxyType ## Port]; \ + [proxyConfig setObject:NS_NUMBER(1) forKey:(__bridge NSString *)kSCPropNetProxies ## proxyType ## Enable]; \ + } \ + } while(0); + + SET_PROXY_CONFIG(HTTP); + SET_PROXY_CONFIG(HTTPS); + SET_PROXY_CONFIG(FTP); + SET_PROXY_CONFIG(Gopher); + SET_PROXY_CONFIG(SOCKS); + + if ([proxyConfig count] > 0) { + NSString *matchDomain = self.options[kSCTestConfigAgentProxyMatchDomain] ? self.options[kSCTestConfigAgentProxyMatchDomain] : @TEST_DOMAIN; + [proxyConfig setObject:@[matchDomain] forKey:(__bridge NSString *)kSCPropNetProxiesSupplementalMatchDomains]; + } else { + proxyConfig = nil; + } + + return proxyConfig; +#undef SET_PROXY_CONFIG +} + +- (NSDictionary *)parseDNSAgentOptions +{ + NSMutableDictionary *dnsConfig; + NSString *dnsServerString; + NSString *dnsDomainString; + NSArray *dnsServers; + NSArray *dnsDomains; + + dnsConfig = [[NSMutableDictionary alloc] init]; + dnsServerString = self.options[kSCTestConfigAgentDNSServers]; + if (dnsServerString == nil) { + return nil; + } + + dnsDomainString = self.options[kSCTestConfigAgentDNSDomains]; + if (dnsDomainString == nil) { + dnsDomainString = @TEST_DOMAIN; + } + + dnsServers = [dnsServerString componentsSeparatedByString:@","]; + [dnsConfig setObject:dnsServers forKey:(__bridge NSString *)kSCPropNetDNSServerAddresses]; + + dnsDomains = [dnsDomainString componentsSeparatedByString:@","]; + [dnsConfig setObject:dnsDomains forKey:(__bridge NSString *)kSCPropNetDNSSupplementalMatchDomains]; + + return dnsConfig; +} + +- (void)cleanupAndExitWithErrorCode:(int)error +{ + CFRelease(self.store); + [super cleanupAndExitWithErrorCode:error]; +} + +- (BOOL)setup +{ + return YES; +} + +- (BOOL)unitTest +{ + if(![self setup]) { + return NO; + } + + BOOL allUnitTestsPassed = YES; + allUnitTestsPassed &= [self unitTestInstallProxy]; + allUnitTestsPassed &= [self unitTestInstallProxyWithLargeConfig]; + allUnitTestsPassed &= [self unitTestInstallProxyWithConflictingDomain]; + allUnitTestsPassed &= [self unitTestInstallDNS]; + allUnitTestsPassed &= [self unitTestInstallDNSWithConflictingDomain]; + + if(![self tearDown]) { + return NO; + } + + return allUnitTestsPassed; +} + +- (BOOL)unitTestInstallProxy +{ + BOOL success = NO; + SCTestConfigAgent *test; + NSDictionary *proxyConfig; + NSString *hostname; + NSNumber *port; + NWHostEndpoint *hostEndpoint; + NWPathEvaluator *pathEvaluator; + NSMutableDictionary *dict; + + test = [[SCTestConfigAgent alloc] initWithOptions:self.options]; + proxyConfig = [test parseProxyAgentOptions]; + if (proxyConfig == nil) { + // Use default options + proxyConfig = @{(__bridge NSString *)kSCPropNetProxiesHTTPEnable:@(1), + (__bridge NSString *)kSCPropNetProxiesHTTPPort:@(80), + (__bridge NSString *)kSCPropNetProxiesHTTPProxy:@"10.10.10.100", + (__bridge NSString *)kSCPropNetProxiesSupplementalMatchDomains:@[@TEST_DOMAIN], + }; + } + + hostname = [[proxyConfig objectForKey:(__bridge NSString *)kSCPropNetProxiesSupplementalMatchDomains] objectAtIndex:0]; + port = [proxyConfig objectForKey:(__bridge NSString *)kSCPropNetProxiesHTTPPort]; + hostEndpoint = [NWHostEndpoint endpointWithHostname:hostname port:port.stringValue]; + pathEvaluator = [[NWPathEvaluator alloc] initWithEndpoint:hostEndpoint parameters:NULL]; + [pathEvaluator addObserver:test + forKeyPath:@"path" + options:NSKeyValueObservingOptionNew + context:nil]; + + do { + [test publishToSCDynamicStore:test.proxyKey value:proxyConfig]; + dict = [NSMutableDictionary dictionaryWithDictionary:proxyConfig]; + [dict removeObjectForKey:(__bridge NSString *)kSCPropNetProxiesSupplementalMatchDomains]; + test.testProxy = @[@[dict]]; + + // Wait for the path changes to quiesce + [test waitFor:PATH_QUIESCE_TIME]; + if (![test.testProxy isEqualToArray:test.pathProxy]) { + SCTestLog("test proxy and applied proxy do not match. Test: %@, Applied: %@", test.testProxy, test.pathProxy); + break; + } + + SCTestLog("Verified the configured proxy is the same as applied proxy"); + [test removeFromSCDynamicStore:test.proxyKey]; + test.testProxy = nil; + // Wait for the path changes to quiesce + [test waitFor:PATH_QUIESCE_TIME]; + if (test.pathProxy != nil) { + SCTestLog("proxy applied when there is no test proxy"); + break; + } + + success = YES; + } while(0); + + [pathEvaluator removeObserver:test + forKeyPath:@"path"]; + + return success; +} + +- (BOOL)unitTestInstallDNS +{ + BOOL success = NO; + SCTestConfigAgent *test; + NSDictionary *dnsConfig; + NSString *hostname; + NWHostEndpoint *hostEndpoint; + NWPathEvaluator *pathEvaluator; + + test = [[SCTestConfigAgent alloc] initWithOptions:self.options]; + dnsConfig = [test parseDNSAgentOptions]; + if (dnsConfig == nil) { + dnsConfig = @{ (__bridge NSString *)kSCPropNetDNSServerAddresses:@[@"10.10.10.101", @"10.10.10.102", @"10.10.10.103"], + (__bridge NSString *)kSCPropNetDNSSupplementalMatchDomains:@[@TEST_DOMAIN], + }; + } + + hostname = [[dnsConfig objectForKey:(__bridge NSString *)kSCPropNetDNSSupplementalMatchDomains] objectAtIndex:0]; + hostEndpoint = [NWHostEndpoint endpointWithHostname:hostname port:@"80"]; + pathEvaluator = [[NWPathEvaluator alloc] initWithEndpoint:hostEndpoint parameters:NULL]; + [pathEvaluator addObserver:test + forKeyPath:@"path" + options:NSKeyValueObservingOptionNew + context:nil]; + + do { + [test publishToSCDynamicStore:test.dnsKey value:dnsConfig]; + test.testDNS = [test createDNSArray:dnsConfig]; + + // Wait for the path changes to quiesce + [test waitFor:PATH_QUIESCE_TIME]; + if (![test.testDNS isEqualToArray:test.pathDNS]) { + SCTestLog("test DNS and applied DNS do not match. Test: %@, Applied: %@", test.testDNS, test.pathDNS); + break; + } + + [test removeFromSCDynamicStore:test.dnsKey]; + test.testDNS = nil; + [test waitFor:PATH_QUIESCE_TIME]; + + SCTestLog("Verified that the configured DNS is same as applied DNS for a domain"); + success = YES; + } while (0); + + [pathEvaluator removeObserver:test + forKeyPath:@"path"]; + + return success; +} + +- (BOOL)unitTestInstallProxyWithLargeConfig +{ + BOOL success = NO; + SCTestConfigAgent *test; + NSString *str = @"0123456789"; + NSMutableString *largeStr; + NSDictionary *proxyConfig; + NSString *hostname; + NSNumber *port; + NWHostEndpoint *hostEndpoint; + NWPathEvaluator *pathEvaluator; + NSMutableDictionary *dict; + + test = [[SCTestConfigAgent alloc] initWithOptions:self.options]; + largeStr = [[NSMutableString alloc] init]; + for (int i = 0; i < 200; i++) { + [largeStr appendString:str]; + } + + // We imitate a proxy config worth 2K bytes. + proxyConfig = @{(__bridge NSString *)kSCPropNetProxiesHTTPEnable:@(1), + (__bridge NSString *)kSCPropNetProxiesHTTPPort:@(80), + (__bridge NSString *)kSCPropNetProxiesHTTPProxy:@"10.10.10.100", + (__bridge NSString *)kSCPropNetProxiesProxyAutoConfigJavaScript:largeStr, + (__bridge NSString *)kSCPropNetProxiesProxyAutoConfigEnable:@(1), + (__bridge NSString *)kSCPropNetProxiesSupplementalMatchDomains:@[@TEST_DOMAIN], + }; + + hostname = [[proxyConfig objectForKey:(__bridge NSString *)kSCPropNetProxiesSupplementalMatchDomains] objectAtIndex:0]; + port = [proxyConfig objectForKey:(__bridge NSString *)kSCPropNetProxiesHTTPPort]; + hostEndpoint = [NWHostEndpoint endpointWithHostname:hostname port:port.stringValue]; + pathEvaluator = [[NWPathEvaluator alloc] initWithEndpoint:hostEndpoint parameters:NULL]; + [pathEvaluator addObserver:test + forKeyPath:@"path" + options:NSKeyValueObservingOptionNew + context:nil]; + + do { + [test publishToSCDynamicStore:test.proxyKey value:proxyConfig]; + dict = [NSMutableDictionary dictionaryWithDictionary:proxyConfig]; + [dict removeObjectForKey:(__bridge NSString *)kSCPropNetProxiesSupplementalMatchDomains]; + test.testProxy = @[@[dict]]; + + // Wait for the path changes to quiesce + [test waitFor:PATH_QUIESCE_TIME]; + if ([test.testProxy isEqualToArray:test.pathProxy]) { + SCTestLog("applied proxy does not contain Out of Band Agent UUID"); + break; + } + + // Now we verify that we are able to fetch the proxy configuration from configd + for (NSArray *config in test.pathProxy) { + xpc_object_t xpcConfig = _CFXPCCreateXPCObjectFromCFObject((__bridge CFArrayRef)config); + xpc_object_t fetchedConfig = config_agent_update_proxy_information(xpcConfig); + if (fetchedConfig != nil) { + NSArray *nsConfig = (__bridge_transfer NSArray *)(_CFXPCCreateCFObjectFromXPCObject(fetchedConfig)); + test.pathProxy = @[nsConfig]; + break; + } + } + + if (![test.testProxy isEqualToArray:test.pathProxy]) { + SCTestLog("Could not fetch proxy configuration from configd. Test: %@, Applied: %@", test.testProxy, test.pathProxy); + break; + } + + SCTestLog("Verified that the proxy configuration is successfully fetched from configd"); + test.testProxy = nil; + [test removeFromSCDynamicStore:test.proxyKey]; + + // Wait for the path changes to quiesce + [test waitFor:PATH_QUIESCE_TIME]; + if (test.pathProxy != nil) { + SCTestLog("proxy applied when there is no test proxy"); + break; + } + + success = YES; + } while (0); + + [pathEvaluator removeObserver:test + forKeyPath:@"path"]; + + return success; +} + +- (BOOL)unitTestInstallDNSWithConflictingDomain +{ + BOOL success = NO; + SCTestConfigAgent *test; + NSDictionary *dnsConfig; + NSString *hostname; + NWHostEndpoint *hostEndpoint; + NWPathEvaluator *pathEvaluator; + + test = [[SCTestConfigAgent alloc] initWithOptions:self.options]; + dnsConfig = @{ (__bridge NSString *)kSCPropNetDNSServerAddresses:@[@"10.10.10.101", @"10.10.10.102", @"10.10.10.103"], + (__bridge NSString *)kSCPropNetDNSSupplementalMatchDomains:@[@TEST_DOMAIN], + }; + + hostname = [[dnsConfig objectForKey:(__bridge NSString *)kSCPropNetDNSSupplementalMatchDomains] objectAtIndex:0]; + hostEndpoint = [NWHostEndpoint endpointWithHostname:hostname port:@"80"]; + pathEvaluator = [[NWPathEvaluator alloc] initWithEndpoint:hostEndpoint parameters:NULL]; + [pathEvaluator addObserver:test + forKeyPath:@"path" + options:NSKeyValueObservingOptionNew + context:nil]; + + do { + NSDictionary *duplicateDnsConfig; + NSString *anotherFakeServiceID; + NSString *anotherDNSKey; + NSArray *array; + NSSet *testDNSSet; + NSSet *pathDNSSet; + + [test publishToSCDynamicStore:test.dnsKey value:dnsConfig]; + test.testDNS = [test createDNSArray:dnsConfig]; + + // Wait for the path changes to quiesce + [test waitFor:PATH_QUIESCE_TIME]; + if (![test.testDNS isEqualToArray:test.pathDNS]) { + SCTestLog("test DNS and applied DNS do not match. Test: %@, Applied: %@", test.testDNS, test.pathDNS); + break; + } + + // Now install the conflicting DNS configuration + duplicateDnsConfig = @{ (__bridge NSString *)kSCPropNetDNSServerAddresses:@[@"10.10.10.104", @"10.10.10.105", @"10.10.10.106"], + (__bridge NSString *)kSCPropNetDNSSupplementalMatchDomains:@[@TEST_DOMAIN], + }; + + anotherFakeServiceID = [NSUUID UUID].UUIDString; + anotherDNSKey = (__bridge_transfer NSString *)[self copyStateKeyWithServiceID:(__bridge CFStringRef)(anotherFakeServiceID) forEntity:kSCEntNetDNS]; + + [test publishToSCDynamicStore:anotherDNSKey value:duplicateDnsConfig]; + array = [test.testDNS arrayByAddingObjectsFromArray:[test createDNSArray:duplicateDnsConfig]]; + test.testDNS = array; + + // Wait for the path changes to quiesce + [test waitFor:PATH_QUIESCE_TIME]; + + // Use NSSet for unordered comparison + testDNSSet = [NSSet setWithArray:test.testDNS]; + pathDNSSet = [NSSet setWithArray:test.pathDNS]; + success = [testDNSSet isEqualToSet:pathDNSSet]; + [test removeFromSCDynamicStore:anotherDNSKey]; + if (!success) { + SCTestLog("test DNS and applied DNS for duplicate domains do not match. Test: %@, Applied: %@", test.testDNS, test.pathDNS); + break; + } + + [test removeFromSCDynamicStore:test.dnsKey]; + test.testDNS = nil; + [test waitFor:PATH_QUIESCE_TIME]; + + SCTestLog("Verified that the configured DNS with duplicate domains is same as applied DNS for a domain"); + success = YES; + + } while (0); + + [pathEvaluator removeObserver:test + forKeyPath:@"path"]; + + return success; +} + +- (BOOL)unitTestInstallProxyWithConflictingDomain +{ + BOOL success = NO; + SCTestConfigAgent *test; + NSDictionary *proxyConfig; + NSString *hostname; + NSNumber *port; + NWHostEndpoint *hostEndpoint; + NWPathEvaluator *pathEvaluator; + + test = [[SCTestConfigAgent alloc] initWithOptions:self.options]; + proxyConfig = @{(__bridge NSString *)kSCPropNetProxiesHTTPEnable:@(1), + (__bridge NSString *)kSCPropNetProxiesHTTPPort:@(80), + (__bridge NSString *)kSCPropNetProxiesHTTPProxy:@"10.10.10.100", + (__bridge NSString *)kSCPropNetProxiesSupplementalMatchDomains:@[@TEST_DOMAIN], + }; + + hostname = [[proxyConfig objectForKey:(__bridge NSString *)kSCPropNetProxiesSupplementalMatchDomains] objectAtIndex:0]; + port = [proxyConfig objectForKey:(__bridge NSString *)kSCPropNetProxiesHTTPPort]; + hostEndpoint = [NWHostEndpoint endpointWithHostname:hostname port:port.stringValue]; + pathEvaluator = [[NWPathEvaluator alloc] initWithEndpoint:hostEndpoint parameters:NULL]; + [pathEvaluator addObserver:test + forKeyPath:@"path" + options:NSKeyValueObservingOptionNew + context:nil]; + + do { + NSMutableDictionary *dict; + NSMutableDictionary *dict2; + NSDictionary *duplicateProxyConfig; + NSString *anotherFakeServiceID; + NSString *anotherProxyKey; + NSSet *testProxySet; + NSSet *pathProxySet; + + [test publishToSCDynamicStore:test.proxyKey value:proxyConfig]; + dict = [NSMutableDictionary dictionaryWithDictionary:proxyConfig]; + [dict removeObjectForKey:(__bridge NSString *)kSCPropNetProxiesSupplementalMatchDomains]; + test.testProxy = @[@[dict]]; + + // Wait for the path changes to quiesce + [test waitFor:PATH_QUIESCE_TIME]; + if (![test.testProxy isEqualToArray:test.pathProxy]) { + SCTestLog("test proxy and applied proxy do not match. Test: %@, Applied: %@", test.testProxy, test.pathProxy); + break; + } + + // Now install the conflicting Proxy configuration + duplicateProxyConfig = @{(__bridge NSString *)kSCPropNetProxiesHTTPSEnable:@(1), + (__bridge NSString *)kSCPropNetProxiesHTTPSPort:@(8080), + (__bridge NSString *)kSCPropNetProxiesHTTPSProxy:@"10.10.10.101", + (__bridge NSString *)kSCPropNetProxiesSupplementalMatchDomains:@[@TEST_DOMAIN], + }; + anotherFakeServiceID = [NSUUID UUID].UUIDString; + anotherProxyKey = (__bridge_transfer NSString *)[self copyStateKeyWithServiceID:(__bridge CFStringRef)(anotherFakeServiceID) forEntity:kSCEntNetProxies]; + + [test publishToSCDynamicStore:anotherProxyKey value:duplicateProxyConfig];; + dict2 = [NSMutableDictionary dictionaryWithDictionary:duplicateProxyConfig]; + [dict2 removeObjectForKey:(__bridge NSString *)kSCPropNetProxiesSupplementalMatchDomains]; + test.testProxy = @[@[dict],@[dict2]]; + + // Wait for the path changes to quiesce + [test waitFor:PATH_QUIESCE_TIME]; + + // Use NSSet for unordered comparison + testProxySet = [NSSet setWithArray:test.testProxy]; + pathProxySet = [NSSet setWithArray:test.pathProxy]; + success = [testProxySet isEqualToSet:pathProxySet]; + [test removeFromSCDynamicStore:anotherProxyKey]; + if (!success) { + SCTestLog("test proxy and applied proxy for duplicate domains do not match. Test: %@, Applied: %@", test.testDNS, test.pathDNS); + break; + } + + SCTestLog("Verified the configured proxy with Duplicate domains is the same as applied proxy"); + + [test removeFromSCDynamicStore:test.proxyKey]; + test.testProxy = nil; + + // Wait for the path changes to quiesce + [test waitFor:PATH_QUIESCE_TIME]; + + if (test.pathProxy != nil) { + SCTestLog("proxy applied when there is no test proxy"); + break; + } + + success = YES; + + } while(0); + + [pathEvaluator removeObserver:test + forKeyPath:@"path"]; + + return success; +} + +- (BOOL)tearDown +{ + [self removeFromSCDynamicStore:self.proxyKey]; + [self removeFromSCDynamicStore:self.dnsKey]; + return YES; +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context +{ + NWPathEvaluator *pathEvaluator = (NWPathEvaluator *)object; + if ([keyPath isEqualToString:@"path"]) { + self.pathProxy = pathEvaluator.path.proxySettings; + self.pathDNS = pathEvaluator.path.dnsServers; + } +} + +@end diff --git a/sctest/SCTestDynamicStore.m b/sctest/SCTestDynamicStore.m new file mode 100644 index 0000000..6ece952 --- /dev/null +++ b/sctest/SCTestDynamicStore.m @@ -0,0 +1,394 @@ +/* + * Copyright (c) 2016 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@ + */ + +#import "SCTest.h" +#import "SCTestUtils.h" + +@interface SCTestDynamicStore : SCTest +@property SCDynamicStoreRef store; +@property dispatch_semaphore_t sem; +@property int counter; +@end + +@implementation SCTestDynamicStore + ++ (NSString *)command +{ + return @"dynamic_store"; +} + ++ (NSString *)commandDescription +{ + return @"Tests the SCDynamicStore code path"; +} + +- (instancetype)initWithOptions:(NSDictionary *)options +{ + self = [super initWithOptions:options]; + if (self) { + _store = SCDynamicStoreCreate(kCFAllocatorDefault, + CFSTR("SCTest"), + NULL, + NULL); + if (_store == NULL) { + SCTestLog("Could not create session"); + ERR_EXIT; + } + } + return self; +} + +- (void)dealloc +{ + if (self.store != NULL) { + CFRelease(self.store); + self.store = NULL; + } +} + +- (void)start +{ + CFStringRef key; + if (self.options[kSCTestDynamicStoreOptionDNS]) { + key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetDNS); + CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key); + SCTestLog("%@ : %@", key, value); + CFRelease(key); + } + + if (self.options[kSCTestDynamicStoreOptionIPv4]) { + key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv4); + CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key); + SCTestLog("%@ : %@", key, value); + CFRelease(key); + } + + if (self.options[kSCTestDynamicStoreOptionIPv6]) { + key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetIPv6); + CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key); + SCTestLog("%@ : %@", key, value); + CFRelease(key); + } + + if (self.options[kSCTestDynamicStoreOptionProxies]) { + key = SCDynamicStoreKeyCreateNetworkGlobalEntity(kCFAllocatorDefault, kSCDynamicStoreDomainState, kSCEntNetProxies); + CFPropertyListRef value = SCDynamicStoreCopyValue(self.store, key); + SCTestLog("%@ : %@", key, value); + CFRelease(key); + } + + [self cleanupAndExitWithErrorCode:0]; +} + +- (void)cleanupAndExitWithErrorCode:(int)error +{ + [super cleanupAndExitWithErrorCode:error]; +} + +- (BOOL)setup +{ + return YES; +} + +- (BOOL)unitTest +{ + if(![self setup]) { + return NO; + } + + BOOL allUnitTestsPassed = YES; + allUnitTestsPassed &= [self unitTestSetAndRemoveValue]; + allUnitTestsPassed &= [self unitTestCopyMultiple]; + allUnitTestsPassed &= [self unitTestSCDynamicStoreCallbackStress]; + allUnitTestsPassed &= [self unitTestSCDynamicStoreSetMultipleStress]; + + if(![self tearDown]) { + return NO; + } + + return allUnitTestsPassed; +} + +- (BOOL)tearDown +{ + return YES; +} + +- (BOOL)unitTestSetAndRemoveValue +{ + int iterations = 1000; + NSDictionary *bogusValue; + SCTestDynamicStore *test; + + test = [[SCTestDynamicStore alloc] initWithOptions:self.options]; + bogusValue = @{@"Pretty":@"Useless"}; + + for (int i = 0; i < iterations; i++) { + NSUUID *uuid = [NSUUID UUID]; + CFStringRef key; + BOOL ok; + + key = SCDynamicStoreKeyCreateNetworkServiceEntity(kCFAllocatorDefault, + CFSTR("SCTest"), + (__bridge CFStringRef)uuid.UUIDString, + kSCEntNetDNS); + ok = SCDynamicStoreSetValue(test.store, key, (__bridge CFDictionaryRef)bogusValue); + if (!ok) { + SCTestLog("Failed to set value in SCDynamicStore. Error: %s", SCErrorString(SCError())); + CFRelease(key); + return NO; + } + + ok = SCDynamicStoreRemoveValue(test.store, key); + if (!ok) { + SCTestLog("Failed to remove value from SCDynamicStore. Error: %s", SCErrorString(SCError())); + CFRelease(key); + return NO; + } + + CFRelease(key); + } + + SCTestLog("Successfully completed setAndRemove unit test"); + return YES; +} + +- (BOOL)unitTestCopyMultiple +{ + NSString *pattern; + SCTestDynamicStore *test; + CFArrayRef keyList; + int iterations = 1000; + + test = [[SCTestDynamicStore alloc] initWithOptions:self.options]; + pattern = (__bridge_transfer NSString *)SCDynamicStoreKeyCreate(kCFAllocatorDefault, + CFSTR("%@/%@/%@/%@/%@"), + kSCDynamicStoreDomainState, + kSCCompNetwork, + kSCCompInterface, + kSCCompAnyRegex, + kSCCompAnyRegex); + + keyList = SCDynamicStoreCopyKeyList(test.store, (__bridge CFStringRef)pattern); + for (int i = 0; i < iterations; i++) { + CFDictionaryRef value = SCDynamicStoreCopyMultiple(test.store, keyList, NULL); + if (value == NULL) { + SCTestLog("Failed to copy multiple values from SCDynamicStore. Error: %s", SCErrorString(SCError())); + CFRelease(keyList); + return NO; + } + CFRelease(value); + } + CFRelease(keyList); + + pattern = (__bridge_transfer NSString *)SCDynamicStoreKeyCreate(kCFAllocatorDefault, + CFSTR("%@/%@/%@/%@/%@"), + kSCDynamicStoreDomainSetup, + kSCCompNetwork, + kSCCompService, + kSCCompAnyRegex, + kSCCompAnyRegex); + + keyList = SCDynamicStoreCopyKeyList(test.store, (__bridge CFStringRef)pattern); + for (int i = 0; i < iterations; i++) { + CFDictionaryRef value = SCDynamicStoreCopyMultiple(test.store, keyList, NULL); + if (value == NULL) { + SCTestLog("Failed to copy multiple values from SCDynamicStore. Error: %s", SCErrorString(SCError())); + CFRelease(keyList); + return NO; + } + CFRelease(value); + } + CFRelease(keyList); + + SCTestLog("Successfully completed copyMultiple unit test"); + return YES; +} + +void +myTestCallback(SCDynamicStoreRef store, CFArrayRef changedKeys, void *ctx) +{ + SCTestDynamicStore *test = (__bridge SCTestDynamicStore *)ctx; + test.counter++; + if (test.sem != NULL) { + dispatch_semaphore_signal(test.sem); + } +} + +- (BOOL)unitTestSCDynamicStoreCallbackStress +{ + SCTestDynamicStore *test; + int iterations = 100; + NSString *testKey = @"State:/myTestKey"; + BOOL ok; + dispatch_queue_t callbackQ; + + test = [[SCTestDynamicStore alloc] initWithOptions:self.options]; + if (test.store != NULL) { + CFRelease(test.store); + test.store = NULL; + } + + SCDynamicStoreContext ctx = {0, (__bridge void * _Nullable)(test), CFRetain, CFRelease, NULL}; + test.store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("SCTest"), myTestCallback, &ctx); + + ok = SCDynamicStoreSetNotificationKeys(test.store, (__bridge CFArrayRef)@[testKey], NULL); + if (!ok) { + SCTestLog("Failed to set notification keys. Error: %s", SCErrorString(SCError())); + return NO; + } + + callbackQ = dispatch_queue_create("SCTestDynamicStore callback queue", NULL); + ok = SCDynamicStoreSetDispatchQueue(test.store, callbackQ); + if (!ok) { + SCTestLog("Failed to set dispatch queue. Error: %s", SCErrorString(SCError())); + return NO; + } + + for (int i = 0; i < iterations; i++) { + NSUUID *uuid = [NSUUID UUID]; + ok = SCDynamicStoreSetValue(test.store, (__bridge CFStringRef)testKey, (__bridge CFStringRef)uuid.UUIDString); + if (!ok) { + SCTestLog("Failed to set value. Error: %s", SCErrorString(SCError())); + return NO; + } + // Perform a write to Dynamic Store every 10ms. + [test waitFor:0.01]; + } + + ok = SCDynamicStoreRemoveValue(test.store, (__bridge CFStringRef)testKey); + if (!ok) { + SCTestLog("Failed to remove value. Error: %s", SCErrorString(SCError())); + return NO; + } + + if (test.counter < iterations) { + // Not all callbacks were received + SCTestLog("Not all SCDynamicStore callbacks were received (%d/%d). Something went wrong", test.counter, iterations); + return NO; + } + + SCTestLog("Successfully completed SCDynamicStore callbacks unit test"); + return YES; +} + +- (BOOL)unitTestSCDynamicStoreSetMultipleStress +{ + SCTestDynamicStore *test; + int iterations = 100; + NSMutableArray *testKeyArray; + NSMutableDictionary *testSetDictionary; + int expectedCallbackCount = 0; + BOOL ok; + dispatch_queue_t callbackQ; + uint8_t waitTime = 1; // second + + test = [[SCTestDynamicStore alloc] initWithOptions:self.options]; + if (test.store != NULL) { + CFRelease(test.store); + test.store = NULL; + } + + SCDynamicStoreContext ctx = {0, (__bridge void * _Nullable)(test), CFRetain, CFRelease, NULL}; + test.store = SCDynamicStoreCreate(kCFAllocatorDefault, CFSTR("SCTest"), myTestCallback, &ctx); + test.sem = dispatch_semaphore_create(0); + + testKeyArray = [[NSMutableArray alloc] init]; + + for (int i = 0; i < iterations; i++) { + NSUUID *uuid = [NSUUID UUID]; + NSString *str = [NSString stringWithFormat:@"State:/%@", uuid]; + [testKeyArray addObject:str]; + } + + testSetDictionary = [[NSMutableDictionary alloc] init]; + for (NSString *key in testKeyArray) { + NSUUID *uuid = [NSUUID UUID]; + [testSetDictionary setObject:@[uuid.UUIDString] forKey:key]; + } + + callbackQ = dispatch_queue_create("SCTestDynamicStore callback queue", NULL); + ok = SCDynamicStoreSetNotificationKeys(test.store, (__bridge CFArrayRef)testKeyArray, NULL); + if (!ok) { + SCTestLog("Failed to set notification keys. Error: %s", SCErrorString(SCError())); + return NO; + } + + ok = SCDynamicStoreSetDispatchQueue(test.store, callbackQ); + if (!ok) { + SCTestLog("Failed to set dispatch queue. Error: %s", SCErrorString(SCError())); + return NO; + } + + ok = SCDynamicStoreSetMultiple(test.store, (__bridge CFDictionaryRef)testSetDictionary, NULL, NULL); + if (!ok) { + SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError())); + return NO; + } else { + expectedCallbackCount++; // One callback for set multiple + } + + if(dispatch_semaphore_wait(test.sem, dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC))) { + SCTestLog("Failed to get a callback when multiple keys are set"); + return NO; + } + + ok = SCDynamicStoreSetMultiple(test.store, NULL, NULL, (__bridge CFArrayRef)testKeyArray); + if (!ok) { + SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError())); + return NO; + } else { + expectedCallbackCount++; // One callback for fake notification + } + + if(dispatch_semaphore_wait(test.sem, dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC))) { + SCTestLog("Failed to get a callback when multiple keys are notified"); + return NO; + } + + ok = SCDynamicStoreSetMultiple(test.store, NULL, (__bridge CFArrayRef)testKeyArray, NULL); + if (!ok) { + SCTestLog("Failed to set multiple keys. Error: %s", SCErrorString(SCError())); + return NO; + } else { + expectedCallbackCount++; // One callback for key removal + } + + if(dispatch_semaphore_wait(test.sem, dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC))) { + SCTestLog("Failed to get a callback when multiple keys are removed"); + return NO; + } + + if (test.counter < expectedCallbackCount) { + // Not all callbacks were received + SCTestLog("Not all SCDynamicStore callbacks were received (%d/%d). Something went wrong", test.counter, expectedCallbackCount); + return NO; + } + + SCTestLog("Successfully completed SCDynamicStore set multiple unit test"); + return YES; + +} + + +@end diff --git a/sctest/SCTestOptions.h b/sctest/SCTestOptions.h new file mode 100644 index 0000000..665987c --- /dev/null +++ b/sctest/SCTestOptions.h @@ -0,0 +1,106 @@ +// +// This file is automatically generated. DO NOT EDIT! +// To add options, see genSCTestOptions.c +// +#import +#import + +extern const NSString * const kSCTestGlobalOptionCPU; +extern const NSString * const kSCTestGlobalOptionHelp; +extern const NSString * const kSCTestGlobalOptionTime; +extern const NSString * const kSCTestGlobalOptionVerbose; +extern const NSString * const kSCTestGlobalOptionWait; +extern const NSString * const kSCTestDynamicStoreOptionDNS; +extern const NSString * const kSCTestDynamicStoreOptionIPv4; +extern const NSString * const kSCTestDynamicStoreOptionIPv6; +extern const NSString * const kSCTestDynamicStoreOptionProxies; +extern const NSString * const kSCTestPreferencesServiceList; +extern const NSString * const kSCTestPreferencesServiceOrder; +extern const NSString * const kSCTestConfigAgentDNSDomains; +extern const NSString * const kSCTestConfigAgentDNSServers; +extern const NSString * const kSCTestConfigAgentRemoveDNS; +extern const NSString * const kSCTestConfigAgentFTPProxy; +extern const NSString * const kSCTestConfigAgentGopherProxy; +extern const NSString * const kSCTestConfigAgentHTTPProxy; +extern const NSString * const kSCTestConfigAgentHTTPSProxy; +extern const NSString * const kSCTestConfigAgentProxyMatchDomain; +extern const NSString * const kSCTestConfigAgentRemoveProxy; +extern const NSString * const kSCTestConfigAgentSOCKSProxy; +extern const NSString * const kSCTestReachabilityAddress; +extern const NSString * const kSCTestReachabilityHost; +extern const NSString * const kSCTestReachabilityInterface; +extern const NSString * const kSCTestReachabilityWatch; +extern const NSString * const kSCTestUnitTestCommand; +extern const NSString * const kSCTestUnitTestListTests; +extern const NSString * const kSCTestUnitTestTestMethod; +extern const NSString * const kSCTestUnitTestTestMethodList; + + + +#define kSCTestOptionEntries \ + {"cpu", 0, NULL, 0}, \ + {"help", 0, NULL, 0}, \ + {"time", 0, NULL, 0}, \ + {"verbose", 0, NULL, 0}, \ + {"wait", 0, NULL, 0}, \ + {"dns", 0, NULL, 0}, \ + {"ipv4", 0, NULL, 0}, \ + {"ipv6", 0, NULL, 0}, \ + {"proxies", 0, NULL, 0}, \ + {"service_list", 0, NULL, 0}, \ + {"service_order", 0, NULL, 0}, \ + {"dns_domain", 1, NULL, 0}, \ + {"dns_servers", 1, NULL, 0}, \ + {"remove_dns", 0, NULL, 0}, \ + {"ftp_proxy", 1, NULL, 0}, \ + {"gopher_proxy", 1, NULL, 0}, \ + {"http_proxy", 1, NULL, 0}, \ + {"https_proxy", 1, NULL, 0}, \ + {"proxy_match_domain", 1, NULL, 0}, \ + {"remove_proxy", 0, NULL, 0}, \ + {"socks_proxy", 1, NULL, 0}, \ + {"address", 1, NULL, 0}, \ + {"host", 1, NULL, 0}, \ + {"interface", 1, NULL, 0}, \ + {"watch", 0, NULL, 0}, \ + {"command", 1, NULL, 0}, \ + {"list_tests", 0, NULL, 0}, \ + {"test_method", 1, NULL, 0}, \ + {"test_method_list", 0, NULL, 0}, \ + +#define kSCTestOptionHelp \ + "\n============== global options =============\n"\ + "-cpu : Prints the CPU usage after the test completes\n"\ + "-help : Prints this very useful help!\n"\ + "-time : Prints the time elapsed since the test was launched\n"\ + "-verbose : Enables verbose mode\n"\ + "-wait : Results in a wait for 'sctest'\n"\ + "\n============== dynamic_store options =============\n"\ + "-dns : Prints the global DNS information from the SCDynamicStore\n"\ + "-ipv4 : Prints the global IPv4 information from the SCDynamicStore\n"\ + "-ipv6 : Prints the global IPv6 information from the SCDynamicStore\n"\ + "-proxies : Prints the global Proxy information from the SCDynamicStore\n"\ + "\n============== preferences options =============\n"\ + "-service_list : Prints the Network Services list from the preferences\n"\ + "-service_order : Prints the Network Service order from the preferences\n"\ + "\n============== config_agent options =============\n"\ + "-dns_domain : Configures the DNS Servers for certain domains. A comma-separated list of domains can be specified. Default is 'apple.com'\n"\ + "-dns_servers : Configures the specified DNS Servers. A comma-separated list of IP Addresses can be specified\n"\ + "-remove_dns : Remove a dns configuration, previously configured via 'sctest'\n"\ + "-ftp_proxy : Add a proxy agent with FTP proxy. Format of the argument is 'server:port'\n"\ + "-gopher_proxy : Add a proxy agent with Gopher proxy. Format of the argument is 'server:port'\n"\ + "-http_proxy : Add a proxy agent with HTTP proxy. Format of the argument is 'server:port'\n"\ + "-https_proxy : Add a proxy agent with HTTPS proxy. Format of the argument is 'server:port'\n"\ + "-proxy_match_domain : Add a proxy agent for a match domain. If this option is not specified, 'apple.com' will be used\n"\ + "-remove_proxy : Remove a proxy configuration, previously configured via 'sctest'\n"\ + "-socks_proxy : Add a proxy agent with SOCKS proxy. Format of the argument is 'server:port'\n"\ + "\n============== reachability options =============\n"\ + "-address : Determine reachability to this address\n"\ + "-host : Determine reachability to this host\n"\ + "-interface : Determine reachability when scoped to this interface\n"\ + "-watch : Watch for reachability changes\n"\ + "\n============== unit_test options =============\n"\ + "-command : Run a unit test for a specific command. If this option is not specified, unit-tests for all commands will be run\n"\ + "-list_tests : List the test commands in a JSON format. This is for NPT compliance\n"\ + "-test_method : Runs a specific unit test. List can be obtained by using the 'test_method_list' option\n"\ + "-test_method_list : Lists all the unit tests. A specific one can be run using the 'test_method' option\n"\ diff --git a/sctest/SCTestOptions.m b/sctest/SCTestOptions.m new file mode 100644 index 0000000..6b1d491 --- /dev/null +++ b/sctest/SCTestOptions.m @@ -0,0 +1,35 @@ +// +// This file is automatically generated. DO NOT EDIT! +// To add options, see genSCTestOptions.c +// +#import "SCTestOptions.h" + +const NSString * const kSCTestGlobalOptionCPU = @"cpu_Str"; +const NSString * const kSCTestGlobalOptionHelp = @"help_Str"; +const NSString * const kSCTestGlobalOptionTime = @"time_Str"; +const NSString * const kSCTestGlobalOptionVerbose = @"verbose_Str"; +const NSString * const kSCTestGlobalOptionWait = @"wait_Str"; +const NSString * const kSCTestDynamicStoreOptionDNS = @"dns_Str"; +const NSString * const kSCTestDynamicStoreOptionIPv4 = @"ipv4_Str"; +const NSString * const kSCTestDynamicStoreOptionIPv6 = @"ipv6_Str"; +const NSString * const kSCTestDynamicStoreOptionProxies = @"proxies_Str"; +const NSString * const kSCTestPreferencesServiceList = @"service_list_Str"; +const NSString * const kSCTestPreferencesServiceOrder = @"service_order_Str"; +const NSString * const kSCTestConfigAgentDNSDomains = @"dns_domain_Str"; +const NSString * const kSCTestConfigAgentDNSServers = @"dns_servers_Str"; +const NSString * const kSCTestConfigAgentRemoveDNS = @"remove_dns_Str"; +const NSString * const kSCTestConfigAgentFTPProxy = @"ftp_proxy_Str"; +const NSString * const kSCTestConfigAgentGopherProxy = @"gopher_proxy_Str"; +const NSString * const kSCTestConfigAgentHTTPProxy = @"http_proxy_Str"; +const NSString * const kSCTestConfigAgentHTTPSProxy = @"https_proxy_Str"; +const NSString * const kSCTestConfigAgentProxyMatchDomain = @"proxy_match_domain_Str"; +const NSString * const kSCTestConfigAgentRemoveProxy = @"remove_proxy_Str"; +const NSString * const kSCTestConfigAgentSOCKSProxy = @"socks_proxy_Str"; +const NSString * const kSCTestReachabilityAddress = @"address_Str"; +const NSString * const kSCTestReachabilityHost = @"host_Str"; +const NSString * const kSCTestReachabilityInterface = @"interface_Str"; +const NSString * const kSCTestReachabilityWatch = @"watch_Str"; +const NSString * const kSCTestUnitTestCommand = @"command_Str"; +const NSString * const kSCTestUnitTestListTests = @"list_tests_Str"; +const NSString * const kSCTestUnitTestTestMethod = @"test_method_Str"; +const NSString * const kSCTestUnitTestTestMethodList = @"test_method_list_Str"; diff --git a/sctest/SCTestPreferences.m b/sctest/SCTestPreferences.m new file mode 100644 index 0000000..f444586 --- /dev/null +++ b/sctest/SCTestPreferences.m @@ -0,0 +1,345 @@ +/* + * Copyright (c) 2016 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@ + */ + +#import "SCTest.h" +#import "SCTestUtils.h" + +@interface SCTestPreferences : SCTest +@property SCPreferencesRef prefs; +@end + +@implementation SCTestPreferences + ++ (NSString *)command +{ + return @"preferences"; +} + ++ (NSString *)commandDescription +{ + return @"Tests the SCPreferences code path"; +} + +- (instancetype)initWithOptions:(NSDictionary *)options +{ + self = [super initWithOptions:options]; + if (self) { + _prefs = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("SCTest"), NULL); + } + return self; +} + +- (void)dealloc +{ + if (self.prefs != NULL) { + CFRelease(self.prefs); + self.prefs = NULL; + } +} + +- (void)start +{ + if (self.options[kSCTestPreferencesServiceList]) { + NSDictionary *services = (__bridge NSDictionary *)SCPreferencesGetValue(self.prefs, kSCPrefNetworkServices); + if (services != nil) { + [self printNetworkServicesFromDict:services]; + } else { + SCTestLog("No services present!"); + } + } + + if (self.options[kSCTestPreferencesServiceOrder]) { + SCNetworkSetRef set = SCNetworkSetCopyCurrent(self.prefs); + NSArray *serviceID = (__bridge NSArray *)SCNetworkSetGetServiceOrder(set); + NSDictionary *services = (__bridge NSDictionary *)SCPreferencesGetValue(self.prefs, kSCPrefNetworkServices); + int counter = 1; + SCTestLog("Network service order"); + for (NSString *key in serviceID) { + NSDictionary *dict = [services objectForKey:key]; + SCTestLog("\n%d: %@\n\tUserDefinedName: %@", counter++, key, [dict objectForKey:(__bridge NSString *)kSCPropNetServiceUserDefinedName]); + } + CFRelease(set); + } + + [self cleanupAndExitWithErrorCode:0]; +} + +- (void)printNetworkServicesFromDict:(NSDictionary *)serviceDict +{ + int counter = 1; + SCTestLog("Network Services"); + for (NSString *key in serviceDict) { + NSDictionary *dict = [serviceDict objectForKey:key]; + SCTestLog("\n%d: %@\n\tUserDefinedName: %@", counter++, key, [dict objectForKey:(__bridge NSString *)kSCPropNetServiceUserDefinedName]); + } +} + +- (BOOL)unitTest +{ + BOOL allUnitTestsPassed = YES; + allUnitTestsPassed &= [self unitTestNetworkServicesSanity]; + allUnitTestsPassed &= [self unitTestPreferencesAPI]; + allUnitTestsPassed &= [self unitTestPreferencesSession]; + return allUnitTestsPassed; + +} + +- (BOOL)unitTestNetworkServicesSanity +{ + // We verify that every service has a unique name, an interface, an IPv4 config method and and IPv6 config method. + NSDictionary *services; + NSMutableArray *serviceNameArray; + SCTestPreferences *test; + + test = [[SCTestPreferences alloc] initWithOptions:self.options]; + services = (__bridge NSDictionary *)SCPreferencesGetValue(test.prefs, kSCPrefNetworkServices); + if (services == NULL) { + SCTestLog("No services present!"); + return NO; + } + + serviceNameArray = [[NSMutableArray alloc] init]; + for (NSString *serviceID in services) { + NSDictionary *serviceDict; + NSString *serviceName; + NSDictionary *interfaceDict; + NSString *interfaceType; + NSDictionary *ipv4Dict; + NSDictionary *ipv6Dict; + + serviceDict = [services objectForKey:serviceID]; + if (![serviceDict isKindOfClass:[NSDictionary class]]) { + SCTestLog("Service is not a dictionary"); + return NO; + } + + serviceName = [serviceDict objectForKey:(__bridge NSString *)kSCPropNetServiceUserDefinedName]; + if (serviceName != nil) { + // Check if the name is unique + BOOL namePresent = [serviceNameArray containsObject:serviceName]; + if (!namePresent) { + [serviceNameArray addObject:serviceName]; + } else { + SCTestLog("Duplicate services with name %@ exist", serviceName); + return NO; + } + } else { + SCTestLog("Service ID %@ does not have a name", serviceID); + return NO; + } + + interfaceDict = [serviceDict objectForKey:(__bridge NSString *)kSCCompInterface]; + if (interfaceDict == nil) { + SCTestLog("Service %@ does not have an interface", serviceName); + return NO; + } + + interfaceType = [interfaceDict objectForKey:(__bridge NSString *)kSCPropNetInterfaceType]; + if (interfaceType != nil && [interfaceType containsString:@"CommCenter"]) { + // CommCenter services typically do not have an ipv4/v6 data OR config method. Skip such services. + continue; + } + + ipv4Dict = [serviceDict objectForKey:(__bridge NSString *)kSCEntNetIPv4]; + ipv6Dict = [serviceDict objectForKey:(__bridge NSString *)kSCEntNetIPv6]; + + // Check that we have at least one IP config method + if (ipv4Dict == nil && ipv6Dict == nil) { + SCTestLog("Service %@ does not have an IP dictionary", serviceName); + return NO; + } + + if ([ipv4Dict objectForKey:(__bridge NSString *)kSCPropNetIPv4ConfigMethod] == nil && + [ipv6Dict objectForKey:(__bridge NSString *)kSCPropNetIPv6ConfigMethod] == nil) { + SCTestLog("Service %@ does not have an IP Config Method", serviceName); + return NO; + } + } + + SCTestLog("Verified that the Network Services have valid configurations"); + + return YES; +} + +- (BOOL)unitTestPreferencesSession +{ + SCPreferencesRef prefs; + prefs = SCPreferencesCreate(kCFAllocatorDefault, CFSTR("SCTest"), NULL); + if (prefs == NULL) { + SCTestLog("Failed to create SCPreferences. Error: %s", SCErrorString(SCError())); + return NO; + } else { + CFRelease(prefs); + } + + prefs = SCPreferencesCreateWithOptions(kCFAllocatorDefault, CFSTR("SCTest"), NULL, kSCPreferencesUseEntitlementAuthorization, NULL); + if (prefs == NULL) { + SCTestLog("Failed to create SCPreferences w/options. Error: %s", SCErrorString(SCError())); + return NO; + } else { + CFRelease(prefs); + } + + prefs = SCPreferencesCreateWithAuthorization(kCFAllocatorDefault, CFSTR("SCTest"), NULL, kSCPreferencesUseEntitlementAuthorization); + if (prefs == NULL) { + SCTestLog("Failed to create SCPreferences w/options. Error: %s", SCErrorString(SCError())); + return NO; + } else { + CFRelease(prefs); + } + + SCTestLog("Verified that the preferences session can be created"); + return YES; +} + +- (BOOL)unitTestPreferencesAPI +{ + BOOL ok = NO; + int iterations = 1000; + NSDictionary *prefsOptions; + NSMutableArray *keys; + NSMutableArray *values; + SCTestPreferences *test; + NSArray *keyList; + + test = [[SCTestPreferences alloc] initWithOptions:self.options]; + if (test.prefs != NULL) { + CFRelease(test.prefs); + test.prefs = NULL; + } + + prefsOptions = @{(__bridge NSString *)kSCPreferencesOptionRemoveWhenEmpty:(__bridge NSNumber *)kCFBooleanTrue}; + test.prefs = SCPreferencesCreateWithOptions(kCFAllocatorDefault, + CFSTR("SCTest"), + CFSTR("SCTestPreferences.plist"), + kSCPreferencesUseEntitlementAuthorization, + (__bridge CFDictionaryRef)prefsOptions); + if (test.prefs == NULL) { + SCTestLog("Failed to create a preferences session. Error: %s", SCErrorString(SCError())); + return NO; + } + + keys = [[NSMutableArray alloc] init]; + values = [[NSMutableArray alloc] init]; + for (int i = 0; i < iterations; i++) { + NSUUID *uuidKey = [NSUUID UUID]; + NSUUID *uuidValue = [NSUUID UUID]; + + ok = SCPreferencesLock(test.prefs, true); + if (!ok) { + SCTestLog("Failed to get preferences lock. Error: %s", SCErrorString(SCError())); + return NO; + } + + ok = SCPreferencesSetValue(test.prefs, (__bridge CFStringRef)uuidKey.UUIDString, (__bridge CFStringRef)uuidValue.UUIDString); + if (!ok) { + SCTestLog("Failed to set preferences value. Error: %s", SCErrorString(SCError())); + return NO; + } + + ok = SCPreferencesUnlock(test.prefs); + if (!ok) { + SCTestLog("Failed to release preferences lock. Error: %s", SCErrorString(SCError())); + return NO; + } + + [keys addObject:uuidKey.UUIDString]; + [values addObject:uuidValue.UUIDString]; + } + + ok = SCPreferencesCommitChanges(test.prefs); + if (!ok) { + SCTestLog("Failed to commit preferences. Error: %s", SCErrorString(SCError())); + return NO; + } + + CFRelease(test.prefs); + test.prefs = SCPreferencesCreateWithOptions(kCFAllocatorDefault, + CFSTR("SCTest"), + CFSTR("SCTestPreferences.plist"), + kSCPreferencesUseEntitlementAuthorization, + (__bridge CFDictionaryRef)prefsOptions); + if (test.prefs == NULL) { + SCTestLog("Failed to create a preferences session. Error: %s", SCErrorString(SCError())); + return NO; + } + + keyList = (__bridge_transfer NSArray *)SCPreferencesCopyKeyList(test.prefs); + if ([keyList count] < [keys count]) { + SCTestLog("Failed to copy all keys from preferences. Error: %s", SCErrorString(SCError())); + return NO; + } + + for (NSString *key in keys) { + NSString *valueString = (__bridge NSString *)SCPreferencesGetValue(test.prefs, (__bridge CFStringRef)key); + if (!valueString) { + SCTestLog("Failed to get value from preferences. Error: %s", SCErrorString(SCError())); + return NO; + } + + BOOL ok = [values containsObject:valueString]; + if (!ok) { + SCTestLog("Incorrect value fetched from preferences"); + return NO; + } + } + + ok = SCPreferencesRemoveAllValues(test.prefs); + if (!ok) { + SCTestLog("Failed to remove values preferences. Error: %s", SCErrorString(SCError())); + return NO; + } + + ok = SCPreferencesCommitChanges(test.prefs); + if (!ok) { + SCTestLog("Failed to commit preferences. Error: %s", SCErrorString(SCError())); + return NO; + } + + CFRelease(test.prefs); + test.prefs = SCPreferencesCreateWithOptions(kCFAllocatorDefault, + CFSTR("SCTest"), + CFSTR("SCTestPreferences.plist"), + kSCPreferencesUseEntitlementAuthorization, + (__bridge CFDictionaryRef)prefsOptions); + if (test.prefs == NULL) { + SCTestLog("Failed to create a preferences session. Error: %s", SCErrorString(SCError())); + return NO; + } + + keyList = (__bridge_transfer NSArray *)SCPreferencesCopyKeyList(test.prefs); + if ([keyList count] > 0) { + SCTestLog("Failed to remove all keys from preferences. Error: %s", SCErrorString(SCError())); + return NO; + } + + SCTestLog("Verified that SCPreferences APIs behave as expected"); + return ok; +} + +- (void)cleanupAndExitWithErrorCode:(int)error +{ + [super cleanupAndExitWithErrorCode:error]; +} + +@end diff --git a/sctest/SCTestReachability.m b/sctest/SCTestReachability.m new file mode 100644 index 0000000..c638a66 --- /dev/null +++ b/sctest/SCTestReachability.m @@ -0,0 +1,376 @@ +/* + * Copyright (c) 2016 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@ + */ + +#import "SCTest.h" +#import "SCTestUtils.h" +#import +#import +#import + +#define REACHABILITY_TEST_HOSTNAME "apple.com" + +@interface SCTestReachability : SCTest +@property SCNetworkReachabilityRef target; +@property dispatch_queue_t callbackQ; +@end + +@implementation SCTestReachability + ++ (NSString *)command +{ + return @"reachability"; +} + ++ (NSString *)commandDescription +{ + return @"Tests the SCNetworkReachability code path"; +} + +- (instancetype)initWithOptions:(NSDictionary *)options +{ + self = [super initWithOptions:options]; + if (self) { + NSMutableDictionary *reachOptions; + if (self.options[kSCTestReachabilityInterface] != nil) { + reachOptions = [[NSMutableDictionary alloc] init]; + [reachOptions setObject:self.options[kSCTestReachabilityInterface] forKey:(__bridge NSString *)kSCNetworkReachabilityOptionInterface]; + if (self.options[kSCTestReachabilityHost] != nil) { + [reachOptions setObject:self.options[kSCTestReachabilityHost] forKey:(__bridge NSString *)kSCNetworkReachabilityOptionNodeName]; + } else if (self.options[kSCTestReachabilityAddress] != nil) { + NSData *data; + NSString *addressString = self.options[kSCTestReachabilityAddress]; + struct sockaddr *sa = _SC_string_to_sockaddr(addressString.UTF8String, AF_INET, NULL, 0); + if (sa == NULL) { + sa = _SC_string_to_sockaddr(addressString.UTF8String, AF_INET6, NULL, 0); + if (sa == NULL) { + SCTestLog("Invalid address"); + ERR_EXIT; + } + } + data = [NSData dataWithBytes:sa length:(sa->sa_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)]; + [reachOptions setObject:data forKey:(__bridge NSString *)kSCNetworkReachabilityOptionRemoteAddress]; + } + + + _target = SCNetworkReachabilityCreateWithOptions(kCFAllocatorDefault, (__bridge CFDictionaryRef)reachOptions); + } else if (self.options[kSCTestReachabilityHost]) { + NSString *host = self.options[kSCTestReachabilityHost]; + _target = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, host.UTF8String); + } else if (self.options[kSCTestReachabilityAddress]) { + NSString *addressString = self.options[kSCTestReachabilityAddress]; + struct sockaddr *sa = _SC_string_to_sockaddr(addressString.UTF8String, AF_INET, NULL, 0); + if (sa == NULL) { + sa = _SC_string_to_sockaddr(addressString.UTF8String, AF_INET6, NULL, 0); + if (sa == NULL) { + SCTestLog("Invalid address"); + ERR_EXIT; + } + } + _target = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, sa); + } + } + return self; +} + +- (void)dealloc +{ + if (self.target != NULL) { + CFRelease(self.target); + self.target = NULL; + } +} + +void +myReachabilityCallback(SCNetworkReachabilityRef target, SCNetworkReachabilityFlags flags, void *info) +{ + struct tm tm_now; + struct timeval tv_now; + (void)gettimeofday(&tv_now, NULL); + (void)localtime_r(&tv_now.tv_sec, &tm_now); + SCTestLog("%2d:%02d:%02d.%03d Reachability changed: %#x", tm_now.tm_hour, tm_now.tm_min, tm_now.tm_sec, tv_now.tv_usec / 1000, flags); +} + +- (void)start +{ + if (self.options[kSCTestReachabilityHost] != nil && self.options[kSCTestReachabilityAddress] != nil) { + SCTestLog("Please specify either a host or address"); + ERR_EXIT; + } + + if (self.options[kSCTestReachabilityWatch]) { + self.callbackQ = dispatch_queue_create("SCTestReachability callback queue", NULL); + SCNetworkReachabilitySetCallback(self.target, myReachabilityCallback, NULL); + SCNetworkReachabilitySetDispatchQueue(self.target, self.callbackQ); + } else { + SCNetworkReachabilityFlags flags; + SCNetworkReachabilityGetFlags(self.target, &flags); + SCTestLog("Reachability: %#x", flags); + [self cleanupAndExitWithErrorCode:0]; + } +} + +- (void)cleanupAndExitWithErrorCode:(int)error +{ + [super cleanupAndExitWithErrorCode:error]; +} + +- (NSString *)primaryInterfaceName +{ + const char *name; + NSString *nsName; + nwi_ifstate_t ifstate; + nwi_state_t nwi; + + nwi = nwi_state_copy(); + ifstate = nwi_state_get_first_ifstate(nwi, AF_INET); + if (ifstate == NULL) { + ifstate = nwi_state_get_first_ifstate(nwi, AF_INET6); + if (ifstate == NULL) { + // May be we are in airplane mode + SCTestLog("No primary interface found"); + return nil; + } + } + + name = nwi_ifstate_get_ifname(ifstate); + nsName = [NSString stringWithCString:name encoding:NSUTF8StringEncoding]; + nwi_state_release(nwi); + + return nsName; +} + +- (BOOL)setup +{ + return YES; +} + +- (BOOL)unitTest +{ + if(![self setup]) { + return NO; + } + + BOOL allUnitTestsPassed = YES; + + allUnitTestsPassed &= [self unitTestBasicReachabilityCheck]; + allUnitTestsPassed &= [self unitTestReachabilityWithPolicy]; + allUnitTestsPassed &= [self unitTestScopedReachabilityWithPolicy]; + + if(![self tearDown]) { + return NO; + } + + return allUnitTestsPassed; +} + +- (BOOL)unitTestBasicReachabilityCheck +{ + SCNetworkReachabilityFlags flags; + SCTestReachability *test; + + test = [[SCTestReachability alloc] initWithOptions:self.options]; + if ([test primaryInterfaceName] == nil) { + return YES; + } + + if (test.target == NULL) { + NSDictionary *options = @{kSCTestReachabilityHost:@REACHABILITY_TEST_HOSTNAME}; + test = [[SCTestReachability alloc] initWithOptions:options]; + } + + + SCNetworkReachabilityGetFlags(test.target, &flags); + if (flags == 0) { + SCTestLog("Reachability reported not reachable"); + return NO; + } + + SCTestLog("Verified that basic reachability check succeeds"); + return YES; +} + +- (BOOL)unitTestReachabilityWithPolicy +{ + NEPolicyCondition *condition1; + NEPolicyCondition *condition2; + SCNetworkReachabilityFlags flags; + BOOL ok; + NEPolicy *policy; + NSUInteger policyID; + NEPolicyResult *result; + NEPolicySession *session; + SCTestReachability *test; + + test = [[SCTestReachability alloc] initWithOptions:self.options]; + if ([test primaryInterfaceName] == nil) { + return YES; + } + + if (test.target == NULL) { + NSDictionary *options = @{kSCTestReachabilityHost:@REACHABILITY_TEST_HOSTNAME}; + test = [[SCTestReachability alloc] initWithOptions:options]; + } + + SCNetworkReachabilityGetFlags(test.target, &flags); + if (flags == 0) { + SCTestLog("Reachability reported not reachable"); + return NO; + } + + session = [[NEPolicySession alloc] init]; + if (session == nil) { + SCTestLog("Failed to create NEPolicySession"); + return NO; + } + + result = [NEPolicyResult drop]; + condition1 = [NEPolicyCondition allInterfaces]; + condition2 = [NEPolicyCondition effectivePID:getpid()]; + policy = [[NEPolicy alloc ] initWithOrder:10 result:result conditions:@[condition1, condition2]]; + policyID = [session addPolicy:policy]; + if (policyID == 0) { + SCTestLog("Failed to add policy"); + return NO; + } + + ok = [session apply]; + if (!ok) { + SCTestLog("Failed to apply policy"); + return NO; + } + + SCNetworkReachabilityGetFlags(test.target, &flags); + if (flags != 0) { + SCTestLog("Reachability reported as reachable, in presence of a drop policy"); + return NO; + } + + ok = [session removeAllPolicies]; + if (!ok) { + SCTestLog("Failed to remove policies from session"); + return NO; + } + + ok = [session apply]; + if (!ok) { + SCTestLog("Failed to apply policy"); + return NO; + } + + SCNetworkReachabilityGetFlags(test.target, &flags); + if (flags == 0) { + SCTestLog("Reachability reported as not reachable, in absence of a drop policy"); + return NO; + } + + SCTestLog("Verified that SCNetworkReachability reports reachability corresponding to the NECP Policies"); + return YES; +} + +- (BOOL)unitTestScopedReachabilityWithPolicy +{ + NEPolicyCondition *condition1; + NEPolicyCondition *condition2; + SCNetworkReachabilityFlags flags; + BOOL ok; + NEPolicy *policy; + NSUInteger policyID; + NSString *primaryInterface; + NEPolicyResult *result; + NEPolicySession *session; + SCTestReachability *test; + + test = [[SCTestReachability alloc] initWithOptions:self.options]; + primaryInterface = [test primaryInterfaceName]; + if (primaryInterface == nil) { + return YES; + } + + if (test.target == NULL) { + NSDictionary *options = @{kSCTestReachabilityHost:@REACHABILITY_TEST_HOSTNAME, + kSCTestReachabilityInterface:primaryInterface}; + test = [[SCTestReachability alloc] initWithOptions:options]; + } + + SCNetworkReachabilityGetFlags(test.target, &flags); + if (flags == 0) { + SCTestLog("Reachability reported not reachable"); + return NO; + } + + session = [[NEPolicySession alloc] init]; + if (session == nil) { + SCTestLog("Failed to create NEPolicySession"); + return NO; + } + + result = [NEPolicyResult drop]; + condition1 = [NEPolicyCondition scopedInterface:primaryInterface]; + condition2 = [NEPolicyCondition effectivePID:getpid()]; + policy = [[NEPolicy alloc ] initWithOrder:10 result:result conditions:@[condition1, condition2]]; + policyID = [session addPolicy:policy]; + if (policyID == 0) { + SCTestLog("Failed to add policy"); + return NO; + } + + ok = [session apply]; + if (!ok) { + SCTestLog("Failed to apply policy"); + return NO; + } + + SCNetworkReachabilityGetFlags(test.target, &flags); + if (flags != 0) { + SCTestLog("Reachability reported as reachable, in presence of a drop policy"); + return NO; + } + + ok = [session removeAllPolicies]; + if (!ok) { + SCTestLog("Failed to remove policies from session"); + return NO; + } + + ok = [session apply]; + if (!ok) { + SCTestLog("Failed to apply policy"); + return NO; + } + + SCNetworkReachabilityGetFlags(test.target, &flags); + if (flags == 0) { + SCTestLog("Reachability reported as not reachable, in absence of a drop policy"); + return NO; + } + + SCTestLog("Verified that SCNetworkReachability for scoped queries report reachability corresponding to the NECP Policies"); + return YES; +} + +- (BOOL)tearDown +{ + return YES; +} + +@end diff --git a/sctest/SCTestUnitTest.m b/sctest/SCTestUnitTest.m new file mode 100644 index 0000000..3f771c2 --- /dev/null +++ b/sctest/SCTestUnitTest.m @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2016 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@ + */ + +#import "SCTest.h" +#import "SCTestUtils.h" + +@interface SCTestUnitTest : SCTest +@end + +@implementation SCTestUnitTest + ++ (NSString *)command +{ + return @"unit_test"; +} + ++ (NSString *)commandDescription +{ + return @"Runs the unit test for all commands"; +} + +- (void)listTests +{ + NSMutableDictionary *testDictionary; + NSMutableArray *testsArray; + NSString *thisClass; + NSArray *testClasses; + NSData *data; + NSString *jsonString; + + testDictionary = [[NSMutableDictionary alloc] init]; + [testDictionary setObject:@"SystemConfiguration Unit Tests" forKey:@"Name"]; + [testDictionary setObject:@"These tests exercise 'configd' and the 'SystemConfiguration' framework" forKey:@"Description"]; + + testsArray = [[NSMutableArray alloc] init]; + thisClass = NSStringFromClass([self class]); + testClasses = getTestClasses(); + for (NSString *className in testClasses) { + Class testClass; + NSMutableDictionary *subTest; + NSArray *list; + NSMutableArray *subTestArray; + + if ([className isEqualToString:thisClass] ) { + continue; + } + + testClass = NSClassFromString(className); + list = getUnitTestListForClass(testClass); + + subTest = [[NSMutableDictionary alloc] init]; + [subTest setObject:@NO forKey:@"RequiresTCPDUMP"]; + [subTest setObject:@YES forKey:@"RequiresNetwork"]; + [subTest setObject:@NO forKey:@"RequiresRoot"]; + [subTest setObject:@NO forKey:@"RequiresPowermetrics"]; + [subTest setObject:[testClass command] forKey:@"Name"]; + [subTest setObject:[testClass commandDescription] forKey:@"Description"]; + subTestArray = [[NSMutableArray alloc] init]; + for (NSString *unitTest in list) { + NSDictionary *testDict = @{@"Command":@[@"/usr/local/bin/sctest", + @"unit_test", + @"-test_method", + unitTest], + @"Name":[unitTest stringByReplacingOccurrencesOfString:@"unitTest" withString:@""], + @"Description":@"Unit test" + }; + [subTestArray addObject:testDict]; + } + [subTest setObject:subTestArray forKey:@"SubTests"]; + [testsArray addObject:subTest]; + } + [testDictionary setObject:testsArray forKey:@"Tests"]; + data = [NSJSONSerialization dataWithJSONObject:testDictionary + options:NSJSONWritingPrettyPrinted + error:nil]; + jsonString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + //SCTestLog("%@", jsonString); + SCPrint(TRUE, stderr, CFSTR("%@"), jsonString); +} + +- (void)start +{ + NSArray *testClasses; + NSString *thisClass = NSStringFromClass([self class]);; + testClasses = getTestClasses(); + BOOL errorOccured = NO; + + if (self.options[kSCTestUnitTestListTests]) { + [self listTests]; + } else if (self.options[kSCTestUnitTestTestMethodList]) { + SCTestLog("List of unit tests:"); + for (NSString *className in testClasses) { + Class testClass; + NSArray *list; + + if ([className isEqualToString:thisClass] ) { + continue; + } + + testClass = NSClassFromString(className); + if (self.options[kSCTestUnitTestCommand] != nil) { + if (![self.options[kSCTestUnitTestCommand] isEqualToString:[testClass command]]) { + // Run unit test only for a specific command + continue; + } + } + + SCTestLog("\n======= '%@' unit tests =======", [testClass command]); + list = getUnitTestListForClass(testClass); + for (NSString *unitTest in list) { + SCTestLog("%@", unitTest); + } + } + + SCTestLog("\nEach of the unit tests can be run with the 'test_method' option\n"); + } else if (self.options[kSCTestUnitTestTestMethod]) { + for (NSString *className in testClasses) { + Class testClass; + NSArray *list; + + if ([className isEqualToString:thisClass] ) { + continue; + } + + testClass = NSClassFromString(className); + if (self.options[kSCTestUnitTestCommand] != nil) { + if (![self.options[kSCTestUnitTestCommand] isEqualToString:[testClass command]]) { + // Run unit test only for a specific command + continue; + } + } + + list = getUnitTestListForClass(testClass); + for (NSString *unitTest in list) { + if ([unitTest isEqualToString:self.options[kSCTestUnitTestTestMethod]]) { + id obj = [(SCTest *)[testClass alloc] initWithOptions:self.options]; + + SCTestLog("Running unit test %@ ...", unitTest); + + SEL methodSelector = NSSelectorFromString(unitTest); + Boolean retVal = false; + if ([obj respondsToSelector:methodSelector]) { + NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[obj methodSignatureForSelector:methodSelector]]; + invocation.target = obj; + invocation.selector = methodSelector; + [invocation invoke]; + [invocation getReturnValue:&retVal]; + } + + if (!retVal) { + SCTestLog("FAILED"); + errorOccured = YES; + } else { + SCTestLog("PASSED"); + } + break; + } + } + } + } else { + // This command runs unit tests for all commands. + for (NSString *className in testClasses) { + Class testClass; + id obj; + + if ([className isEqualToString:thisClass] ) { + continue; + } + + testClass = NSClassFromString(className); + if (self.options[kSCTestUnitTestCommand] != nil) { + if (![self.options[kSCTestUnitTestCommand] isEqualToString:[testClass command]]) { + // Run unit test only for a specific command + continue; + } + } + + obj = [(SCTest *)[testClass alloc] initWithOptions:self.options]; + if ([obj respondsToSelector:@selector(unitTest)]) { + SCTestLog("\n*** Running unit test for \"%@\" command ***\n", [testClass command]); + BOOL passed = [obj unitTest]; + if (!passed) { + SCTestLog("FAILED"); + errorOccured = YES; + } + } + } + } + + [self cleanupAndExitWithErrorCode:errorOccured]; +} + +- (void)cleanupAndExitWithErrorCode:(int)error +{ + [super cleanupAndExitWithErrorCode:error]; +} + +@end diff --git a/sctest/SCTestUtils.h b/sctest/SCTestUtils.h new file mode 100644 index 0000000..2b02800 --- /dev/null +++ b/sctest/SCTestUtils.h @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2016 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 SCTestUtils_h +#define SCTestUtils_h + +#import +#import +#import + +#define SCTestLog(fmt, ...) SCPrint(TRUE, stdout, CFSTR(fmt "\n"), ##__VA_ARGS__) +#define ERR_EXIT exit(1) + +typedef struct { + uint64_t user; + uint64_t sys; + uint64_t idle; +} CPUUsageInfoInner; + +typedef struct { + CPUUsageInfoInner startCPU; + CPUUsageInfoInner endCPU; +} CPUUsageInfo; + +typedef struct { + struct timespec startTime; + struct timespec endTime; +} timerInfo; + +void timerStart(timerInfo *); +void timerEnd(timerInfo *); +NSString * createUsageStringForTimer(timerInfo *); + +void cpuStart(CPUUsageInfo *); +void cpuEnd(CPUUsageInfo *); +NSString * createUsageStringForCPU(CPUUsageInfo *cpu); + +NSArray *getTestClasses(); +NSArray *getUnitTestListForClass(Class base); +NSDictionary *getOptionsDictionary(int argc, const char **argv); + +#endif /* SCTestUtils_h */ diff --git a/sctest/SCTestUtils.m b/sctest/SCTestUtils.m new file mode 100644 index 0000000..d244eb2 --- /dev/null +++ b/sctest/SCTestUtils.m @@ -0,0 +1,260 @@ +/* + * Copyright (c) 2016 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@ + */ + +#import +#import "SCTest.h" +#import "SCTestUtils.h" +#import + +NSArray * +getTestClasses() +{ + static NSMutableArray *subclassNames = nil; + Class base; + unsigned int classListCount; + Class *classList; + + if (subclassNames != nil) { + return subclassNames; + } + + base = [SCTest class]; + classListCount = 0; + classList = objc_copyClassList(&classListCount); + subclassNames = [[NSMutableArray alloc] init]; + + if (classList) { + for (unsigned int i = 0; i < classListCount; i++) { + Class superClass = class_getSuperclass(classList[i]); + while (superClass && superClass != base) { + superClass = class_getSuperclass(superClass); + } + + if (superClass == base) { + [subclassNames addObject:@(class_getName(classList[i]))]; + } + } + free(classList); + } + + [subclassNames sortUsingComparator: ^(id obj1, id obj2) { + NSString *className1 = obj1; + NSString *className2 = obj2; + return [className1 compare:className2 options:NSCaseInsensitiveSearch]; + }]; + + return subclassNames; +} + +NSArray * +getUnitTestListForClass(Class base) +{ + NSMutableArray *unitTestNames = nil; + unsigned int methodListCount = 0; + Method *methodList = NULL; + + methodList = class_copyMethodList(base, &methodListCount); + if (methodList) { + unitTestNames = [[NSMutableArray alloc] initWithCapacity:methodListCount]; + for (unsigned int i = 0; i < methodListCount; i++) { + NSString *name = @(sel_getName(method_getName(methodList[i]))); + if ([name isEqualToString:@"unitTest"]) { + continue; + } else if (![name hasPrefix:@"unitTest"]) { + continue; + } + + [unitTestNames addObject:name]; + } + free(methodList); + } + + return unitTestNames; +} + +NSDictionary * +getOptionsDictionary(int argc, const char **argv) +{ + NSMutableDictionary *options; + NSNumberFormatter *numberFormatter; + int ch; + int i; + struct option entries[] = { + kSCTestOptionEntries + }; + + options = [NSMutableDictionary dictionary]; + optind = 0; + optreset = 1; + numberFormatter = [[NSNumberFormatter alloc] init]; + + while ((ch = getopt_long_only(argc, (char * const *)argv, "", entries, &i)) == 0) { + struct option opt = entries[i]; + NSString *optKey = [NSString stringWithFormat:@"%s_Str", opt.name]; // ... "_Str" suffix is standardized across all keys. + id optVal = nil; + + if (opt.has_arg) { + // Parse the optarg + + // Attempt string + optVal = @(optarg); + + if (optVal == nil) { + // Fall back to NSData + // WARNING: Doesn't work if it contains '\0' + optVal = [NSData dataWithBytes:optarg length:strlen(optarg)]; + } else { + // Use NSNumber if the argument is a number + NSNumber *number = [numberFormatter numberFromString:optVal]; + if (number) { + optVal = number; + } + } + } else { + optVal = @YES; + } + + // Handle multiple option instances + id existingValue = options[optKey]; + if (existingValue) { + if ([existingValue isKindOfClass:[NSMutableArray class]]) { + [(NSMutableArray *)existingValue addObject:optVal]; + optVal = existingValue; + } else if ([existingValue isKindOfClass:[NSArray class]]) { + NSMutableArray *tempArray = [NSMutableArray arrayWithArray:existingValue]; + [tempArray addObject:optVal]; + optVal = tempArray; + } else { + optVal = @[existingValue, optVal]; + } + } + + options[optKey] = optVal; + } + + if (ch > 0) { + return nil; + } + + return options; +} + +static void +cpu_routine(CPUUsageInfoInner *usage) +{ + host_name_port_t host; + host_cpu_load_info_data_t host_load; + mach_msg_type_number_t count; + kern_return_t kret; + + if (usage == NULL) { + return; + } + + host = mach_host_self(); + count = HOST_CPU_LOAD_INFO_COUNT; + kret = host_statistics(host, HOST_CPU_LOAD_INFO, (host_info_t)&host_load, &count); + if (kret) { + return; + } + + // ms per tick. 1 tick is 10 ms. + usage->user = ((uint64_t)host_load.cpu_ticks[CPU_STATE_USER]) * 10; + usage->sys = ((uint64_t)host_load.cpu_ticks[CPU_STATE_SYSTEM]) * 10; + usage->idle = ((uint64_t)host_load.cpu_ticks[CPU_STATE_IDLE]) * 10; +} + +void +cpuStart(CPUUsageInfo *cpu) +{ + cpu_routine(&cpu->startCPU); +} + +void +cpuEnd(CPUUsageInfo *cpu) +{ + cpu_routine(&cpu->endCPU); +} + +NSString * +createUsageStringForCPU(CPUUsageInfo *cpu) +{ + uint64_t userelapsed = cpu->endCPU.user - cpu->startCPU.user; + uint64_t systemelapsed = cpu->endCPU.sys - cpu->startCPU.sys; + uint64_t idleelapsed = cpu->endCPU.idle - cpu->startCPU.idle; + uint64_t totalelapsed = userelapsed + systemelapsed + idleelapsed; + double u = ((double)userelapsed * 100)/totalelapsed; + double s = ((double)systemelapsed * 100)/totalelapsed; + double i = ((double)idleelapsed * 100)/totalelapsed; + + return [NSString stringWithFormat:@"%1.02f%% user %1.02f%% sys %1.02f%% idle", u, s, i]; +} + +static void +timer_routine(struct timespec *ts) +{ + uint64_t diff; + static uint32_t orwl_timebase_numer = 0; + static uint32_t orwl_timebase_denom = 0; + static uint64_t orwl_timestart = 0; + if (orwl_timestart == 0) { + mach_timebase_info_data_t tb = { 0, 0 }; + mach_timebase_info(&tb); + orwl_timebase_numer = tb.numer; + orwl_timebase_denom = tb.denom; + orwl_timestart = mach_absolute_time(); + } + if (0 == orwl_timebase_denom) { + orwl_timebase_denom = 1; + } + diff = ((mach_absolute_time() - orwl_timestart) * orwl_timebase_numer) / orwl_timebase_denom; + ts->tv_sec = (size_t)(diff / NSEC_PER_SEC); + ts->tv_nsec = (size_t)(diff - (ts->tv_sec * NSEC_PER_SEC)); +} + +void +timerStart(timerInfo *timer) +{ + timer_routine(&timer->startTime); +} + +void +timerEnd(timerInfo *timer) +{ + timer_routine(&timer->endTime); +} + +NSString * +createUsageStringForTimer(timerInfo *timer) +{ + double elapsed; + int64_t nsecs = timer->endTime.tv_nsec - timer->startTime.tv_nsec; + uint64_t secs = timer->endTime.tv_sec - timer->startTime.tv_sec; + if (nsecs < 0) { + nsecs += NSEC_PER_SEC; + secs -= 1; + } + + elapsed = (double)secs + (double)nsecs / NSEC_PER_SEC; + return [NSString stringWithFormat:@"%f", elapsed]; +} diff --git a/sctest/genSCTestOptions.c b/sctest/genSCTestOptions.c new file mode 100644 index 0000000..dabf9f3 --- /dev/null +++ b/sctest/genSCTestOptions.c @@ -0,0 +1,184 @@ +/* + * Copyright (c) 2016 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 + +typedef struct { + const char *scope; // Either "global" or for a particular command + const char *optionString; // The option + const char *optionKey; // String representation of the key to be used to access this option's value from the "options" dictionary. + int hasArg; // no_argument, required_argument, optional_argument + const char *usageString; // help string +} SCTestOption; + +// Add the options here and then once finished, go to ${SRCROOT}/sctest/ in Terminal and type "make". +// The options should then be ready to use, through the "options" dictionary. +SCTestOption testOptions[] = { + {"global", "cpu", "kSCTestGlobalOptionCPU", no_argument, "Prints the CPU usage after the test completes"}, + {"global", "help", "kSCTestGlobalOptionHelp", no_argument, "Prints this very useful help!"}, + {"global", "time", "kSCTestGlobalOptionTime", no_argument, "Prints the time elapsed since the test was launched"}, + {"global", "verbose", "kSCTestGlobalOptionVerbose", no_argument, "Enables verbose mode"}, + {"global", "wait", "kSCTestGlobalOptionWait", no_argument, "Results in a wait for 'sctest'"}, + + {"dynamic_store", "dns", "kSCTestDynamicStoreOptionDNS", no_argument, "Prints the global DNS information from the SCDynamicStore"}, + {"dynamic_store", "ipv4", "kSCTestDynamicStoreOptionIPv4", no_argument, "Prints the global IPv4 information from the SCDynamicStore"}, + {"dynamic_store", "ipv6", "kSCTestDynamicStoreOptionIPv6", no_argument, "Prints the global IPv6 information from the SCDynamicStore"}, + {"dynamic_store", "proxies", "kSCTestDynamicStoreOptionProxies", no_argument, "Prints the global Proxy information from the SCDynamicStore"}, + + {"preferences", "service_list", "kSCTestPreferencesServiceList", no_argument, "Prints the Network Services list from the preferences"}, + {"preferences", "service_order", "kSCTestPreferencesServiceOrder", no_argument, "Prints the Network Service order from the preferences"}, + + {"config_agent", "dns_domain", "kSCTestConfigAgentDNSDomains", required_argument, "Configures the DNS Servers for certain domains. A comma-separated list of domains can be specified. Default is 'apple.com'"}, + {"config_agent", "dns_servers", "kSCTestConfigAgentDNSServers", required_argument, "Configures the specified DNS Servers. A comma-separated list of IP Addresses can be specified"}, + {"config_agent", "remove_dns", "kSCTestConfigAgentRemoveDNS", no_argument, "Remove a dns configuration, previously configured via 'sctest'"}, + + {"config_agent", "ftp_proxy", "kSCTestConfigAgentFTPProxy", required_argument, "Add a proxy agent with FTP proxy. Format of the argument is 'server:port'"}, + {"config_agent", "gopher_proxy", "kSCTestConfigAgentGopherProxy", required_argument, "Add a proxy agent with Gopher proxy. Format of the argument is 'server:port'"}, + {"config_agent", "http_proxy", "kSCTestConfigAgentHTTPProxy", required_argument, "Add a proxy agent with HTTP proxy. Format of the argument is 'server:port'"}, + {"config_agent", "https_proxy", "kSCTestConfigAgentHTTPSProxy", required_argument, "Add a proxy agent with HTTPS proxy. Format of the argument is 'server:port'"}, + {"config_agent", "proxy_match_domain", "kSCTestConfigAgentProxyMatchDomain", required_argument, "Add a proxy agent for a match domain. If this option is not specified, 'apple.com' will be used"}, + {"config_agent", "remove_proxy", "kSCTestConfigAgentRemoveProxy", no_argument, "Remove a proxy configuration, previously configured via 'sctest'"}, + {"config_agent", "socks_proxy", "kSCTestConfigAgentSOCKSProxy", required_argument, "Add a proxy agent with SOCKS proxy. Format of the argument is 'server:port'"}, + + {"reachability", "address", "kSCTestReachabilityAddress", required_argument, "Determine reachability to this address"}, + {"reachability", "host", "kSCTestReachabilityHost", required_argument, "Determine reachability to this host"}, + {"reachability", "interface", "kSCTestReachabilityInterface", required_argument, "Determine reachability when scoped to this interface"}, + {"reachability", "watch", "kSCTestReachabilityWatch", no_argument, "Watch for reachability changes"}, + + {"unit_test", "command", "kSCTestUnitTestCommand", required_argument, "Run a unit test for a specific command. If this option is not specified, unit-tests for all commands will be run"}, + {"unit_test", "list_tests", "kSCTestUnitTestListTests", no_argument, "List the test commands in a JSON format. This is for NPT compliance"}, + {"unit_test", "test_method", "kSCTestUnitTestTestMethod", required_argument, "Runs a specific unit test. List can be obtained by using the 'test_method_list' option"}, + {"unit_test", "test_method_list", "kSCTestUnitTestTestMethodList", no_argument, "Lists all the unit tests. A specific one can be run using the 'test_method' option"}, +}; + +static int testOptionsCount = (sizeof(testOptions) / sizeof(testOptions[0])); + +void +printDeclarations() +{ + // Prints to SCTestOptions.h + + const char *keyTemplate = "extern const NSString * const"; + for (int i = 0; i < testOptionsCount; i++) { + char buffer[256] = {0}; + snprintf(buffer, sizeof(buffer), "%s %s;", keyTemplate, testOptions[i].optionKey); + printf("%s\n", buffer); + } +} + +void +printOptionEntries() +{ + // Prints to SCTestOptions.h + + const char *entryTemplate = "#define kSCTestOptionEntries"; + printf("\n%s \\\n", entryTemplate); + for (int i = 0; i < testOptionsCount; i++) { + printf("\t\t{\"%s\", %d, NULL, 0}, \\", testOptions[i].optionString, testOptions[i].hasArg); + printf("\n"); + } +} + +void +printUsage() +{ + // Prints to SCTestOptions.h + + const char *usageTemplate = "#define kSCTestOptionHelp"; + printf("\n%s \\\n", usageTemplate); + const char *last = ""; + for (int i = 0; i < testOptionsCount; i++) { + if (strcmp(last, testOptions[i].scope)) { + last = testOptions[i].scope; + printf("\t\t\"\\n============== %s options =============\\n\"\\\n", testOptions[i].scope); + } + + printf("\t\t\"-%-20s: %s\\n\"\\\n", testOptions[i].optionString, testOptions[i].usageString); + } +} + +void +printDefinitions() +{ + // Prints to SCTestOptions.m + + const char *definitionTemplate = "const NSString * const"; + for (int i = 0; i < testOptionsCount; i++) { + char buffer[256] = {0}; + snprintf(buffer, sizeof(buffer), "%s %-50s= @\"%s_Str\";", definitionTemplate, testOptions[i].optionKey, testOptions[i].optionString); + printf("%s\n", buffer); + } +} + +int +main(int argc, char * argv[]) +{ + char * type = ""; + + if (argc >= 2) { + type = argv[1]; + } + + if (strcmp(type, "header") == 0) { + // Preamble + printf("//\n"); + printf("// This file is automatically generated. DO NOT EDIT!\n"); + printf("// To add options, see genSCTestOptions.c\n"); + printf("//\n"); + + // Import header files + printf("#import \n"); + printf("#import "); + + printf("\n\n"); + + // Print the declarations + printDeclarations(); + + printf("\n\n"); + + // Print the option Entries + printOptionEntries(); + + // Print the usage + printUsage(); + } else if (strcmp(type, "mfile") == 0) { + printf("//\n"); + printf("// This file is automatically generated. DO NOT EDIT!\n"); + printf("// To add options, see genSCTestOptions.c\n"); + printf("//\n"); + + // Import header files + printf("#import \"SCTestOptions.h\""); + + printf("\n\n"); + printDefinitions(); + } + return 0; +} diff --git a/sctest/main.m b/sctest/main.m new file mode 100644 index 0000000..e868110 --- /dev/null +++ b/sctest/main.m @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2016 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@ + */ + +#import "SCTest.h" +#import "SCTestUtils.h" + +static void +usage() +{ + NSArray *testClasses = getTestClasses(); + SCTestLog("\nUsage: sctest "); + SCTestLog("\nCommands:"); + for (NSString *testClassName in testClasses) { + Class testClass = NSClassFromString(testClassName); + SCTestLog(" %15s: %s", [testClass command].UTF8String, [testClass commandDescription].UTF8String); + } + + SCTestLog("\n\nOptions:"); + SCTestLog(kSCTestOptionHelp "\n"); + + ERR_EXIT; +} + +int main(int argc, const char * argv[]) { + @autoreleasepool { + NSString *testCommand; + NSArray *testClasses; + BOOL commandValid = NO; + NSDictionary *options; + Class testClass; + SCTest *testClassObject; + + if (argc == 1) { + usage(); + } + + testCommand = @(argv[1]); + // Check if the command is valid + testClasses = getTestClasses(); + for (NSString *testClassName in testClasses) { + Class testClass = NSClassFromString(testClassName); + if ([[testClass command] isEqualToString:testCommand]) { + commandValid = YES; + break; + } + + } + + if (!commandValid) { + SCTestLog("Invalid command: %@", testCommand); + usage(); + } + + // Create the options dictionary + options = getOptionsDictionary(argc, argv); + if (options == nil) { + usage(); + } + + // Initialize the command + for (NSString *className in testClasses) { + Class commandClass = NSClassFromString(className); + if ([testCommand isEqualToString:[commandClass command]]) { + testClass = commandClass; + break; + } + } + + testClassObject = [(SCTest *)[testClass alloc] initWithOptions:options]; + if (testClassObject.options[kSCTestGlobalOptionCPU] != nil) { + cpuStart(testClassObject.globalCPU); + } + + if (testClassObject.options[kSCTestGlobalOptionTime] != nil) { + timerStart(testClassObject.globalTimer); + } + + [testClassObject start]; + + dispatch_main(); + } + + return 0; +} diff --git a/sctest/npt_configd.plist b/sctest/npt_configd.plist new file mode 100644 index 0000000..5ece97d --- /dev/null +++ b/sctest/npt_configd.plist @@ -0,0 +1,14 @@ + + + + + ID + com.apple.npt.configd + CommandList + + /usr/local/bin/sctest + unit_test + -list_tests + + + diff --git a/sctest/sctest-entitlements.plist b/sctest/sctest-entitlements.plist new file mode 100644 index 0000000..c07263d --- /dev/null +++ b/sctest/sctest-entitlements.plist @@ -0,0 +1,16 @@ + + + + + com.apple.private.nehelper.privileged + + com.apple.private.necp.policies + + com.apple.SystemConfiguration.SCPreferences-write-access + + SCTestPreferences.plist + + com.apple.SystemConfiguration.SCDynamicStore-write-access + + + diff --git a/scutil.tproj/prefs.c b/scutil.tproj/prefs.c index 605cd2a..e2ab8b2 100644 --- a/scutil.tproj/prefs.c +++ b/scutil.tproj/prefs.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003-2008, 2011-2016 Apple Inc. All rights reserved. + * Copyright (c) 2003-2008, 2011-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -28,6 +28,7 @@ * - initial revision */ +#include #include #include #include @@ -979,6 +980,68 @@ on_off_str(Boolean on) /* -------------------- */ +#if !TARGET_OS_IPHONE + +#include "InterfaceNamerControlPrefs.h" + +static void +allow_new_interfaces_usage(void) +{ + fprintf(stderr, "usage: scutil --allow-new-interfaces [on|off|default]\n"); + return; +} + +__private_extern__ +void +do_ifnamer(char * pref, int argc, char **argv) +{ + Boolean allow = FALSE; + + if (argc > 1) { + allow_new_interfaces_usage(); + exit(1); + } + + if (strcmp(pref, "allow-new-interfaces")) { + exit(0); + } + + if (argc == 0) { + SCPrint(TRUE, stdout, CFSTR("AllowNewInterfaces is %s\n"), + on_off_str(InterfaceNamerControlPrefsAllowNewInterfaces())); + exit(0); + } + + if ((strcasecmp(argv[0], "disable") == 0) || + (strcasecmp(argv[0], "no" ) == 0) || + (strcasecmp(argv[0], "off" ) == 0) || + (strcasecmp(argv[0], "0" ) == 0)) { + allow = FALSE; + } else if ((strcasecmp(argv[0], "enable") == 0) || + (strcasecmp(argv[0], "yes" ) == 0) || + (strcasecmp(argv[0], "on" ) == 0) || + (strcasecmp(argv[0], "1" ) == 0)) { + allow = TRUE; + } else if (strcasecmp(argv[0], "default") == 0) { + allow = FALSE; + } else { + allow_new_interfaces_usage(); + exit(1); + } + + if (!InterfaceNamerControlPrefsSetAllowNewInterfaces(allow)) { + SCPrint(TRUE, stderr, CFSTR("failed to set preferences\n")); + exit(2); + } + + exit(0); + return; +} + +#endif // !TARGET_OS_IPHONE + +/* -------------------- */ + #include "IPMonitorControlPrefs.h" __private_extern__ diff --git a/scutil.tproj/prefs.h b/scutil.tproj/prefs.h index fcf3bcb..b4f397a 100644 --- a/scutil.tproj/prefs.h +++ b/scutil.tproj/prefs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2003, 2005-2007, 2012, 2013, 2015, 2016 Apple Inc. All rights reserved. + * Copyright (c) 2003, 2005-2007, 2012, 2013, 2015-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -31,6 +31,7 @@ #ifndef _PREFS_H #define _PREFS_H +#include #include #include @@ -70,6 +71,11 @@ void do_prefs_remove (int argc, char **argv); void do_log (char *pref, int argc, char **argv); void do_disable_until_needed (int argc, char **argv); + +#if !TARGET_OS_IPHONE +void do_ifnamer (char *pref, int argc, char **argv); +#endif // !TARGET_OS_IPHONE + __END_DECLS #endif /* !_PREFS_H */ diff --git a/scutil.tproj/scutil.c b/scutil.tproj/scutil.c index cb15a5a..dda8ac2 100644 --- a/scutil.tproj/scutil.c +++ b/scutil.tproj/scutil.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2016 Apple Inc. All rights reserved. + * Copyright (c) 2000-2017 Apple Inc. All rights reserved. * * @APPLE_LICENSE_HEADER_START@ * @@ -108,7 +108,10 @@ static const struct option longopts[] = { { "password", required_argument, NULL, 0 }, { "secret", required_argument, NULL, 0 }, { "log", required_argument, NULL, 0 }, - { "disable-until-needed", no_argument, NULL, 0 }, +#if !TARGET_OS_IPHONE + { "allow-new-interfaces", no_argument, NULL, 0 }, +#endif // !TARGET_OS_IPHONE + { "disable-until-needed", no_argument, NULL, 0 }, { NULL, 0, NULL, 0 } }; @@ -365,6 +368,12 @@ usage(const char *command) SCPrint(TRUE, stderr, CFSTR("\tmanage secondary interface demand.\n")); } +#if !TARGET_OS_IPHONE + SCPrint(TRUE, stderr, CFSTR("\n")); + SCPrint(TRUE, stderr, CFSTR(" or: %s --allow-new-interfaces [off|on]\n"), command); + SCPrint(TRUE, stderr, CFSTR("\tmanage new interface creation with screen locked.\n")); +#endif // !TARGET_OS_IPHONE + if (getenv("ENABLE_EXPERIMENTAL_SCUTIL_COMMANDS")) { SCPrint(TRUE, stderr, CFSTR("\n")); SCPrint(TRUE, stderr, CFSTR(" or: %s --net\n"), command); @@ -393,29 +402,32 @@ prompt(EditLine *el) int main(int argc, char * const argv[]) { - Boolean disableUntilNeeded = FALSE; - Boolean doDNS = FALSE; - Boolean doNet = FALSE; - Boolean doNWI = FALSE; - Boolean doPrefs = FALSE; - Boolean doProxy = FALSE; - Boolean doReach = FALSE; - Boolean doSnap = FALSE; - char *error = NULL; - char *get = NULL; - char *log = NULL; +#if !TARGET_OS_IPHONE + Boolean allowNewInterfaces = FALSE; +#endif // !TARGET_OS_IPHONE + Boolean disableUntilNeeded = FALSE; + Boolean doDNS = FALSE; + Boolean doNet = FALSE; + Boolean doNWI = FALSE; + Boolean doPrefs = FALSE; + Boolean doProxy = FALSE; + Boolean doReach = FALSE; + Boolean doSnap = FALSE; + char *error = NULL; + char *get = NULL; + char *log = NULL; extern int optind; int opt; int opti; - const char *prog = argv[0]; - char *renew = NULL; - char *set = NULL; - char *nc_cmd = NULL; + const char *prog = argv[0]; + char *renew = NULL; + char *set = NULL; + char *nc_cmd = NULL; InputRef src; - int timeout = 15; /* default timeout (in seconds) */ - char *wait = NULL; - Boolean watch = FALSE; - int xStore = 0; /* non dynamic store command line options */ + int timeout = 15; /* default timeout (in seconds) */ + char *wait = NULL; + Boolean watch = FALSE; + int xStore = 0; /* non dynamic store command line options */ /* process any arguments */ @@ -486,6 +498,11 @@ main(int argc, char * const argv[]) } else if (strcmp(longopts[opti].name, "log") == 0) { log = optarg; xStore++; +#if !TARGET_OS_IPHONE + } else if (strcmp(longopts[opti].name, "allow-new-interfaces") == 0) { + allowNewInterfaces = TRUE; + xStore++; +#endif // !TARGET_OS_IPHONE } else if (strcmp(longopts[opti].name, "disable-until-needed") == 0) { disableUntilNeeded = TRUE; xStore++; @@ -620,11 +637,20 @@ main(int argc, char * const argv[]) /* NOT REACHED */ } +#if !TARGET_OS_IPHONE + /* allowNewInterfaces */ + if (allowNewInterfaces) { + do_ifnamer("allow-new-interfaces", argc, (char * *)argv); + /* NOT REACHED */ + } +#endif // !TARGET_OS_IPHONE + /* disableUntilNeeded */ if (disableUntilNeeded) { do_disable_until_needed(argc, (char * *)argv); /* NOT REACHED */ } + /* network connection commands */ if (nc_cmd) { if (find_nc_cmd(nc_cmd) < 0) {