/*
- * Copyright (c) 2011 Apple Inc. All rights reserved.
+ * Copyright (c) 2011-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,
* 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 <SystemConfiguration/SystemConfiguration.h>
#include <SystemConfiguration/SCPrivate.h>
#include <SystemConfiguration/SCValidation.h>
+#include "ip_plugin.h"
#define DEFAULT_MATCH_ORDER 200000 /* match order for the "default" proxy configuration */
defaultOrder = DEFAULT_MATCH_ORDER
- (DEFAULT_MATCH_ORDER / 2)
- + ((DEFAULT_MATCH_ORDER / 1000) * i);
+ + ((DEFAULT_MATCH_ORDER / 1000) * (uint32_t)i);
if ((n_order > 0) &&
!CFArrayContainsValue(service_order, CFRangeMake(0, n_order), keys[i])) {
// push out services not specified in service order
static CFComparisonResult
compareBySearchOrder(const void *val1, const void *val2, void *context)
{
+#pragma unused(context)
CFDictionaryRef proxy1 = (CFDictionaryRef)val1;
CFDictionaryRef proxy2 = (CFDictionaryRef)val2;
CFNumberRef num1;
num1 = CFDictionaryGetValue(proxy1, PROXY_MATCH_ORDER_KEY);
if (!isA_CFNumber(num1) ||
- !CFNumberGetValue(num1, kCFNumberIntType, &order1)) {
+ !CFNumberGetValue(num1, kCFNumberSInt32Type, &order1)) {
order1 = DEFAULT_MATCH_ORDER;
}
num2 = CFDictionaryGetValue(proxy2, PROXY_MATCH_ORDER_KEY);
if (!isA_CFNumber(num2) ||
- !CFNumberGetValue(num2, kCFNumberIntType, &order2)) {
+ !CFNumberGetValue(num2, kCFNumberSInt32Type, &order2)) {
order2 = DEFAULT_MATCH_ORDER;
}
CFDictionaryGetValueIfPresent(proxy2, ORDER_KEY, (const void **)&num2) &&
isA_CFNumber(num1) &&
isA_CFNumber(num2) &&
- CFNumberGetValue(num1, kCFNumberIntType, &order1) &&
- CFNumberGetValue(num2, kCFNumberIntType, &order2)) {
+ CFNumberGetValue(num1, kCFNumberSInt32Type, &order1) &&
+ CFNumberGetValue(num2, kCFNumberSInt32Type, &order2)) {
if (order1 == order2) {
return kCFCompareEqualTo;
} else {
static CFArrayRef
copy_supplemental_proxies(CFArrayRef proxies, Boolean skip)
{
+#pragma unused(skip)
CFIndex i;
CFIndex n_proxies;
CFMutableArrayRef supplemental = NULL;
}
-static CFDictionaryRef
-copy_scoped_proxies(CFDictionaryRef services, CFArrayRef service_order)
+static CFArrayRef
+service_order_copy_all(CFDictionaryRef services, CFArrayRef service_order)
{
const void * keys_q[N_QUICK];
const void ** keys = keys_q;
CFIndex n_order;
CFIndex n_services;
CFMutableArrayRef order;
- CFMutableDictionaryRef scoped = NULL;
+ // ensure that we process all services in order
n_services = isA_CFDictionary(services) ? CFDictionaryGetCount(services) : 0;
if (n_services == 0) {
- return NULL; // if no services
+ // if no services
+ return NULL;
}
// ensure that we process all services in order
n_order = isA_CFArray(service_order) ? CFArrayGetCount(service_order) : 0;
if (n_order > 0) {
order = CFArrayCreateMutableCopy(NULL, 0, service_order);
- } else{
+ } else {
order = CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks);
}
}
CFDictionaryGetKeysAndValues(services, keys, NULL);
for (i = 0; i < n_services; i++) {
- CFStringRef serviceID = (CFStringRef)keys[i];
+ CFStringRef serviceID = (CFStringRef)keys[i];
if (!CFArrayContainsValue(order, CFRangeMake(0, n_order), serviceID)) {
CFArrayAppendValue(order, serviceID);
CFAllocatorDeallocate(NULL, keys);
}
+ return order;
+}
+
+
+static CFDictionaryRef
+copy_app_layer_vpn_proxies(CFDictionaryRef services, CFArrayRef order, CFDictionaryRef services_info)
+{
+ CFMutableDictionaryRef app_layer_proxies = NULL;
+ CFIndex i;
+ CFIndex n_order;
+
+ if (!isA_CFDictionary(services_info)) {
+ return NULL;
+ }
+
// iterate over services
+ n_order = isA_CFArray(order) ? CFArrayGetCount(order) : 0;
for (i = 0; i < n_order; i++) {
+ CFMutableDictionaryRef newProxy;
CFDictionaryRef proxy;
+ CFDictionaryRef service;
+ CFStringRef serviceID;
+ CFNumberRef serviceSpecificIdentifier;
+ int serviceIdentifier = 0;
+ CFStringRef serviceIdentifierString;
+
+ serviceID = CFArrayGetValueAtIndex(order, i);
+ service = CFDictionaryGetValue(services, serviceID);
+ if (!isA_CFDictionary(service)) {
+ // if no service
+ continue;
+ }
+
+ proxy = CFDictionaryGetValue(service, kSCEntNetProxies);
+ if (!isA_CFDictionary(proxy)) {
+ // if no proxy
+ continue;
+ }
+
+ serviceSpecificIdentifier = CFDictionaryGetValue(proxy, kSCPropNetProxiesServiceSpecific);
+ if (!isA_CFNumber(serviceSpecificIdentifier) ||
+ !CFNumberGetValue(serviceSpecificIdentifier, kCFNumberIntType, &serviceIdentifier) ||
+ serviceIdentifier == 0) {
+ // if not a service-specific proxy configuration
+ continue;
+ }
+
+ serviceIdentifierString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL, CFSTR("%u"), serviceIdentifier);
+ if (serviceIdentifierString == NULL) {
+ continue;
+ }
+ if ((app_layer_proxies != NULL) &&
+ CFDictionaryContainsKey(app_layer_proxies, serviceIdentifierString)) {
+ // if we've already processed this [app_layer_proxies] identifier
+ CFRelease(serviceIdentifierString);
+ continue;
+ }
+
+ // add [app_layer_proxies] proxy entry
+ newProxy = CFDictionaryCreateMutableCopy(NULL, 0, proxy);
+ CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchDomains);
+ CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesSupplementalMatchOrders);
+ CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesServiceSpecific);
+ if (app_layer_proxies == NULL) {
+ app_layer_proxies = CFDictionaryCreateMutable(NULL,
+ 0,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks);
+ }
+ CFDictionarySetValue(app_layer_proxies, serviceIdentifierString, newProxy);
+ CFRelease(serviceIdentifierString);
+ CFRelease(newProxy);
+ }
+
+ return app_layer_proxies;
+}
+
+
+static CFDictionaryRef
+copy_scoped_proxies(CFDictionaryRef services, CFArrayRef order)
+{
+ CFIndex i;
+ CFIndex n_order;
+ CFMutableDictionaryRef scoped = NULL;
+
+ // iterate over services
+
+ n_order = isA_CFArray(order) ? CFArrayGetCount(order) : 0;
+ for (i = 0; i < n_order; i++) {
char if_name[IF_NAMESIZE];
CFStringRef interface;
CFMutableDictionaryRef newProxy;
+ CFDictionaryRef proxy;
CFDictionaryRef service;
CFStringRef serviceID;
if_name,
sizeof(if_name),
kCFStringEncodingASCII) == NULL) ||
- ((if_nametoindex(if_name)) == 0)) {
+ ((my_if_nametoindex(if_name)) == 0)) {
// if interface index not available
continue;
}
CFRelease(interface);
}
- CFRelease(order);
return scoped;
}
// ensure that the default proxy has a search order
if (!isA_CFNumber(order) ||
- !CFNumberGetValue(order, kCFNumberIntType, &myOrder)) {
+ !CFNumberGetValue(order, kCFNumberSInt32Type, &myOrder)) {
myOrder = DEFAULT_MATCH_ORDER;
order = CFNumberCreate(NULL, kCFNumberIntType, &myOrder);
CFDictionarySetValue(myDefault, PROXY_MATCH_ORDER_KEY, order);
CF_RETURNS_RETAINED CFDictionaryRef
proxy_configuration_update(CFDictionaryRef defaultProxy,
CFDictionaryRef services,
- CFArrayRef serviceOrder)
+ CFArrayRef serviceOrder,
+ CFDictionaryRef servicesInfo)
{
CFIndex i;
CFMutableDictionaryRef myDefault;
// establish proxy configuration
if (n_proxies > 0) {
+ CFDictionaryRef app_layer;
CFDictionaryRef scoped;
- Boolean skip = FALSE;
+ CFArrayRef serviceOrderAll;
+ Boolean skip = FALSE;
CFArrayRef supplemental;
proxy = CFArrayGetValueAtIndex(proxies, 0);
&kCFTypeDictionaryValueCallBacks);
}
+ serviceOrderAll = service_order_copy_all(services, serviceOrder);
+
// collect (and add) any "supplemental" proxy configurations
supplemental = copy_supplemental_proxies(proxies, skip);
// collect (and add) any "scoped" proxy configurations
- scoped = copy_scoped_proxies(services, serviceOrder);
+ scoped = copy_scoped_proxies(services, serviceOrderAll);
if (scoped != NULL) {
CFDictionarySetValue(newProxy, kSCPropNetProxiesScoped, scoped);
CFRelease(scoped);
}
+
+ // collect (and add) any "services" based proxy configurations
+
+ app_layer = copy_app_layer_vpn_proxies(services, serviceOrderAll, servicesInfo);
+ if (app_layer != NULL) {
+ CFDictionarySetValue(newProxy, kSCPropNetProxiesServices, app_layer);
+ CFRelease(app_layer);
+ }
+
+ if (serviceOrderAll != NULL) {
+ CFRelease(serviceOrderAll);
+ }
} else {
newProxy = NULL;
}
proxy_configuration_init(CFBundleGetMainBundle());
newProxy = proxy_configuration_update(primary_proxy,
service_state_dict,
- service_order);
+ service_order,
+ NULL);
if (newProxy != NULL) {
SCPrint(TRUE, stdout, CFSTR("%@\n"), newProxy);
CFRelease(newProxy);