From: Apple <opensource@apple.com>
Date: Mon, 19 Apr 2021 23:55:01 +0000 (+0000)
Subject: configd-1109.101.1.tar.gz
X-Git-Tag: macos-113^0
X-Git-Url: https://git.saurik.com/apple/configd.git/commitdiff_plain/HEAD

configd-1109.101.1.tar.gz
---

diff --git a/Plugins/IPMonitor/controller.m b/Plugins/IPMonitor/controller.m
index b7b7c5d..6d1bd53 100644
--- a/Plugins/IPMonitor/controller.m
+++ b/Plugins/IPMonitor/controller.m
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2015-2017 Apple Inc. All rights reserved.
+ * Copyright (c) 2015-2017, 2020 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -56,6 +56,7 @@ typedef struct resolverList {
 @interface AgentController()
 
 @property (nonatomic) NSMutableDictionary	*	floatingProxyAgentList;
+@property (nonatomic) NSMutableDictionary	*	floatingProxyAgentList_TCPConverter;
 @property (nonatomic) NSMutableDictionary	*	floatingDNSAgentList;
 @property (nonatomic) NSMutableDictionary	*	policyDB;
 @property (nonatomic) NEPolicySession		*	policySession;
@@ -125,6 +126,14 @@ typedef struct resolverList {
 			}
 		}
 
+		if (self.floatingProxyAgentList_TCPConverter == nil) {
+			self.floatingProxyAgentList_TCPConverter = [NSMutableDictionary dictionary];
+			if (self.floatingProxyAgentList_TCPConverter == nil) {
+				errorMessage = "Failed to create a dictionary";
+				break;
+			}
+		}
+
 		/*	A dictionary of all floating dns agents
 		 *		Key	:	<entity-name> (can be an interface name or domain name)
 		 *		Value	:	agent object
@@ -183,6 +192,7 @@ typedef struct resolverList {
 	/* Make sure that we have all our data structures in place */
 	return ((self.policySession != nil) &&
 		(self.floatingProxyAgentList != nil) &&
+		(self.floatingProxyAgentList_TCPConverter != nil) &&
 		(self.floatingDNSAgentList != nil) &&
 		(self.policyDB != nil) &&
 		(self.controllerQueue != nil));
@@ -259,22 +269,31 @@ typedef struct resolverList {
 
 - (int)countProxyEntriesEnabled:(CFDictionaryRef)proxies
 {
-	int	enabled = 0;
+	const CFStringRef enableKeys[] = {
+		kSCPropNetProxiesHTTPEnable,
+		kSCPropNetProxiesHTTPSEnable,
+		kSCPropNetProxiesProxyAutoConfigEnable,
+		kSCPropNetProxiesFTPEnable,
+		kSCPropNetProxiesGopherEnable,
+		kSCPropNetProxiesRTSPEnable,
+		kSCPropNetProxiesSOCKSEnable,
+		kSCPropNetProxiesTransportConverterEnable,
+		kSCPropNetProxiesProxyAutoDiscoveryEnable,
+	};
 
 	if (proxies == NULL) {
-		SC_log(LOG_NOTICE, "Invalid proxies");
+		SC_log(LOG_NOTICE, "No proxies");
 		return 0;
 	}
 
-	if (([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesHTTPEnable) valuePtr:&enabled] && enabled > 0)	||
-	    ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesHTTPSEnable) valuePtr:&enabled] && enabled > 0)	||
-	    ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesProxyAutoConfigEnable) valuePtr:&enabled] && enabled > 0) ||
-	    ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesFTPEnable) valuePtr:&enabled] && enabled > 0)	||
-	    ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesGopherEnable) valuePtr:&enabled] && enabled > 0)	||
-	    ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesRTSPEnable) valuePtr:&enabled] && enabled > 0)	||
-	    ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesSOCKSEnable) valuePtr:&enabled] && enabled > 0)	||
-	    ([self getIntValue:CFDictionaryGetValue(proxies, kSCPropNetProxiesProxyAutoDiscoveryEnable) valuePtr:&enabled] && enabled > 0)) {
-		return enabled;
+	for (size_t i = 0; i < (sizeof(enableKeys) / sizeof(enableKeys[0])); i++) {
+		int	enabled = 0;
+
+		if ([self getIntValue:CFDictionaryGetValue(proxies, enableKeys[i])
+			     valuePtr:&enabled] &&
+		    (enabled > 0)) {
+			return enabled;
+		}
 	}
 
 	return 0;
@@ -648,6 +667,43 @@ typedef struct resolverList {
 	return NO;
 }
 
+- (BOOL)isTCPConverterProxyEnabled:(CFDictionaryRef)proxies
+{
+	int		enabled	= 0;
+	CFNumberRef	num	= NULL;
+
+	if (CFDictionaryGetValueIfPresent(proxies,
+					  kSCPropNetProxiesTransportConverterEnable,
+					  (const void **)&num) &&
+	    isA_CFNumber(num) &&
+	    CFNumberGetValue(num, kCFNumberIntType, &enabled) &&
+	    (enabled != 0)) {
+		return YES;
+	}
+
+	return NO;
+}
+
+#define	ALLOW_AGGREGATE	"net.inet.mptcp.allow_aggregate"
+
+static void
+updateTransportConverterProxyEnabled(BOOL enabled)
+{
+	int	ret;
+	int	val	= enabled ? 1 : 0;
+
+	ret = sysctlbyname(ALLOW_AGGREGATE, NULL, 0, &val, sizeof(val));
+	if (ret != -1) {
+		SC_log(LOG_NOTICE, "Transport Converter Proxy: sysctl " ALLOW_AGGREGATE "=%d", val);
+	} else {
+		if (errno != ENOENT) {
+			SC_log(LOG_ERR, "sysctlbyname(" ALLOW_AGGREGATE ") failed: %s", strerror(errno));
+		}
+	}
+
+	return;
+}
+
 - (void)processDefaultProxyChanges:(CFDictionaryRef)proxies
 {
 	CFArrayRef			global_proxy;
@@ -684,6 +740,8 @@ typedef struct resolverList {
 		}
 
 		if (spawnAgent) {
+			BOOL	ok;
+
 			AgentSubType subtype = kAgentSubTypeDefault;
 			NEPolicyConditionType conditionType = NEPolicyConditionTypeNone;
 			if ([self isGlobalProxy:proxies_copy]) {
@@ -692,11 +750,22 @@ typedef struct resolverList {
 				subtype = kAgentSubTypeGlobal;
 			}
 
-			[self spawnFloatingAgent:[ProxyAgent class]
-					entity:@proxyAgentDefault
-					agentSubType:subtype
-					addPolicyOfType:conditionType
-					publishData:data];
+			ok = [self spawnFloatingAgent:[ProxyAgent class]
+					       entity:@proxyAgentDefault
+					 agentSubType:subtype
+				      addPolicyOfType:conditionType
+					  publishData:data];
+			if (ok &&
+			    (subtype == kAgentSubTypeGlobal) &&
+			    [self isTCPConverterProxyEnabled:proxies_copy]) {
+				proxyAgent = [self.floatingProxyAgentList objectForKey:@proxyAgentDefault];
+				if ((proxyAgent != nil) &&
+				    [data isEqual:[proxyAgent getAgentData]]) {
+					[self.floatingProxyAgentList_TCPConverter setObject:proxyAgent
+										     forKey:@proxyAgentDefault];
+					updateTransportConverterProxyEnabled(TRUE);	// enable "net.inet.mptcp.allow_aggregate"
+				}
+			}
 		}
 	} else {
 		/* No default proxy config OR generic (no protocols enabled) default proxy config.
@@ -2043,6 +2112,7 @@ done:
 	BOOL ok = NO;
 
 	if ( agent != nil) {
+		NSString *		entity	= [agent getAssociatedEntity];
 		NSMutableArray	*	policyArray;
 
 		policyArray = [self.policyDB objectForKey:[agent getAgentName]];
@@ -2063,8 +2133,15 @@ done:
 			[self.policyDB removeObjectForKey:[agent getAgentName]];
 		}
 
+		SC_log(LOG_INFO, "Destroying floating agent for %@", entity);
+
 		if ([agent getAgentType] == kAgentTypeProxy) {
-			[self.floatingProxyAgentList removeObjectForKey:[agent getAssociatedEntity]];
+			[self.floatingProxyAgentList removeObjectForKey:entity];
+
+			[self.floatingProxyAgentList_TCPConverter removeObjectForKey:entity];
+			if ([self.floatingProxyAgentList_TCPConverter count] == 0) {
+				updateTransportConverterProxyEnabled(FALSE);	// disable "net.inet.mptcp.allow_aggregate"
+			}
 		} else {
 			[self.floatingDNSAgentList removeObjectForKey:[agent getAssociatedEntity]];
 		}
@@ -2073,8 +2150,6 @@ done:
 			[self unregisterAgent:agent];
 		}
 
-		SC_log(LOG_INFO, "X - Destroyed agent %@", [agent getAgentName]);
-
 		/* Check if we need to close the "control" policy session */
 		if (self.controlPolicySession != nil) {
 			NSMutableArray *globalProxyAgentList;
@@ -2091,6 +2166,7 @@ done:
 
 				self.controlPolicySession = nil;
 				SC_log(LOG_NOTICE, "Closed control policy session");
+
 			}
 		}
 
diff --git a/Plugins/IPMonitor/ip_plugin.c b/Plugins/IPMonitor/ip_plugin.c
index 3eb06e5..259fd77 100644
--- a/Plugins/IPMonitor/ip_plugin.c
+++ b/Plugins/IPMonitor/ip_plugin.c
@@ -5173,18 +5173,42 @@ get_proxies_changes(CFStringRef serviceID, CFDictionaryRef state_dict,
 	    CFStringRef	key2;
 	    CFStringRef	key3;
     } pick_list[] = {
-	    { kSCPropNetProxiesFTPEnable,	kSCPropNetProxiesFTPProxy,	kSCPropNetProxiesFTPPort	},
-	    { kSCPropNetProxiesGopherEnable,	kSCPropNetProxiesGopherProxy,	kSCPropNetProxiesGopherPort	},
-	    { kSCPropNetProxiesHTTPEnable,	kSCPropNetProxiesHTTPProxy,	kSCPropNetProxiesHTTPPort	},
-	    { kSCPropNetProxiesHTTPSEnable,	kSCPropNetProxiesHTTPSProxy,	kSCPropNetProxiesHTTPSPort	},
-	    { kSCPropNetProxiesRTSPEnable,	kSCPropNetProxiesRTSPProxy,	kSCPropNetProxiesRTSPPort	},
-	    { kSCPropNetProxiesSOCKSEnable,	kSCPropNetProxiesSOCKSProxy,	kSCPropNetProxiesSOCKSPort	},
+	    { kSCPropNetProxiesFTPEnable,
+	      kSCPropNetProxiesFTPProxy,
+	      kSCPropNetProxiesFTPPort
+	    },
+	    { kSCPropNetProxiesGopherEnable,
+	      kSCPropNetProxiesGopherProxy,
+	      kSCPropNetProxiesGopherPort
+	    },
+	    { kSCPropNetProxiesHTTPEnable,
+	      kSCPropNetProxiesHTTPProxy,
+	      kSCPropNetProxiesHTTPPort
+	    },
+	    { kSCPropNetProxiesHTTPSEnable,
+	      kSCPropNetProxiesHTTPSProxy,
+	      kSCPropNetProxiesHTTPSPort
+	    },
+	    { kSCPropNetProxiesRTSPEnable,
+	      kSCPropNetProxiesRTSPProxy,
+	      kSCPropNetProxiesRTSPPort
+	    },
+	    { kSCPropNetProxiesSOCKSEnable,
+	      kSCPropNetProxiesSOCKSProxy,
+	      kSCPropNetProxiesSOCKSPort
+	    },
+	    { kSCPropNetProxiesTransportConverterEnable,
+	      kSCPropNetProxiesTransportConverterProxy,
+	      kSCPropNetProxiesTransportConverterPort
+	    },
 	    { kSCPropNetProxiesProxyAutoConfigEnable,
 	      kSCPropNetProxiesProxyAutoConfigURLString,
-	      kSCPropNetProxiesProxyAutoConfigJavaScript, },
+	      kSCPropNetProxiesProxyAutoConfigJavaScript
+	    },
 	    { kSCPropNetProxiesProxyAutoDiscoveryEnable,
 	      NULL,
-	      NULL, }
+	      NULL
+	    }
     };
 
     if ((state_dict == NULL) && (setup_dict == NULL)) {
diff --git a/SystemConfiguration.fproj/SCNetworkConfigurationInternal.c b/SystemConfiguration.fproj/SCNetworkConfigurationInternal.c
index bd4da05..f22ed1e 100644
--- a/SystemConfiguration.fproj/SCNetworkConfigurationInternal.c
+++ b/SystemConfiguration.fproj/SCNetworkConfigurationInternal.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2007, 2009, 2010-2013, 2015-2020 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2007, 2009, 2010-2013, 2015-2021 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -183,7 +183,7 @@ logConfiguration_preferences(int level, const char *description, SCPreferencesRe
 						SC_log(level, "    Service %2ld : %@, %2d (%@%s%@%s%@)",
 						       orderIndex + 1,
 						       serviceID,
-						       __SCNetworkInterfaceOrder(SCNetworkServiceGetInterface(service)),	// temp?
+						       __SCNetworkInterfaceOrder(interface),	// temp?
 						       serviceName,
 						       bsdName != NULL ? ", " : "",
 						       bsdName != NULL ? bsdName : CFSTR(""),
@@ -192,7 +192,7 @@ logConfiguration_preferences(int level, const char *description, SCPreferencesRe
 					} else {
 						SC_log(level, "    Service    : %@, %2d (%@%s%@%s%@)",
 						       serviceID,
-						       __SCNetworkInterfaceOrder(SCNetworkServiceGetInterface(service)),	// temp?
+						       __SCNetworkInterfaceOrder(interface),	// temp?
 						       serviceName,
 						       bsdName != NULL ? ", " : "",
 						       bsdName != NULL ? bsdName : CFSTR(""),
diff --git a/SystemConfiguration.fproj/SCNetworkInterface.c b/SystemConfiguration.fproj/SCNetworkInterface.c
index 59a97f0..6d7d409 100644
--- a/SystemConfiguration.fproj/SCNetworkInterface.c
+++ b/SystemConfiguration.fproj/SCNetworkInterface.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2020 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2021 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -1170,6 +1170,10 @@ __SCNetworkInterfaceOrder(SCNetworkInterfaceRef interface)
 	SCNetworkInterfacePrivateRef	interfacePrivate	= (SCNetworkInterfacePrivateRef)interface;
 	int				order;
 
+	if (isA_SCNetworkInterface(interface) == NULL) {
+		// arbitrarily large number
+		return INT_MAX;
+	}
 	order = interfacePrivate->sort_order << 1;
 	if (!interfacePrivate->builtin) {
 		order |= 0x1;	// push non-builtin after built-in
diff --git a/SystemConfiguration.fproj/SCNetworkSet.c b/SystemConfiguration.fproj/SCNetworkSet.c
index 43fca63..86e5d4f 100644
--- a/SystemConfiguration.fproj/SCNetworkSet.c
+++ b/SystemConfiguration.fproj/SCNetworkSet.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2004-2020 Apple Inc. All rights reserved.
+ * Copyright (c) 2004-2021 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -868,7 +868,13 @@ SCNetworkSetCopyServices(SCNetworkSetRef set)
 				       setPrivate->setID);
 				continue;	 // if the service is not a link
 			}
-
+			if (SCPreferencesPathGetValue(setPrivate->prefs, link) == NULL) {
+				SC_log(LOG_INFO, "service \"%@\" for set \"%@\" broken link \"%@\"",
+				       keys[i],
+				       setPrivate->setID,
+				       link);
+				continue;	 // the link is broken
+			}
 			components = CFStringCreateArrayBySeparatingStrings(NULL, link, CFSTR("/"));
 			if (CFArrayGetCount(components) == 3) {
 				CFStringRef serviceID;
diff --git a/SystemConfiguration.fproj/SCP.c b/SystemConfiguration.fproj/SCP.c
index b220ae6..b93d4d1 100644
--- a/SystemConfiguration.fproj/SCP.c
+++ b/SystemConfiguration.fproj/SCP.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2001, 2003-2005, 2007-2009, 2011, 2014-2020 Apple Inc. All rights reserved.
+ * Copyright (c) 2000, 2001, 2003-2005, 2007-2009, 2011, 2014-2021 Apple Inc. All rights reserved.
  *
  * @APPLE_LICENSE_HEADER_START@
  *
@@ -186,6 +186,11 @@ __SCPreferencesUsingDefaultPrefs(SCPreferencesRef prefs)
 	Boolean			isDefault = FALSE;
 	SCPreferencesPrivateRef prefsPrivate = (SCPreferencesPrivateRef)prefs;
 
+	if (prefs == NULL) {
+		// if no prefs, assume that we are using the "default" prefs
+		return TRUE;
+	}
+
 	curPath = prefsPrivate->newPath ? prefsPrivate->newPath : prefsPrivate->path;
 	if (curPath != NULL) {
 		char*	defPath;
diff --git a/SystemConfiguration.fproj/SCProxies.c b/SystemConfiguration.fproj/SCProxies.c
index 043a0fa..53eb323 100644
--- a/SystemConfiguration.fproj/SCProxies.c
+++ b/SystemConfiguration.fproj/SCProxies.c
@@ -50,16 +50,17 @@ SCDynamicStoreKeyCreateProxies(CFAllocatorRef allocator)
 
 static void
 validate_proxy_content(CFMutableDictionaryRef	proxies,
-		       CFStringRef		proxy_enable,
-		       CFStringRef		proxy_host,
-		       CFStringRef		proxy_port,
-		       const char *		proxy_service,
-		       int			proxy_defaultport)
+		       CFStringRef		proxy_enable_key,
+		       CFStringRef		proxy_host_key,
+		       CFStringRef		proxy_port_key,
+		       const char *		proxy_service_name,
+		       int			proxy_defaultport,
+		       Boolean			multiple_proxies)
 {
 	int		enabled	= 0;
 	CFNumberRef	num;
 
-	num = CFDictionaryGetValue(proxies, proxy_enable);
+	num = CFDictionaryGetValue(proxies, proxy_enable_key);
 	if (num != NULL) {
 		if (!isA_CFNumber(num) ||
 		    !CFNumberGetValue(num, kCFNumberIntType, &enabled)) {
@@ -67,25 +68,56 @@ validate_proxy_content(CFMutableDictionaryRef	proxies,
 		}
 	}
 
-	if (proxy_host != NULL) {
-		CFStringRef	host;
+	if (proxy_host_key != NULL) {
+		CFTypeRef	host_val;
 
-		host = CFDictionaryGetValue(proxies, proxy_host);
-		if ((enabled == 0) && (host != NULL)) {
+		host_val = CFDictionaryGetValue(proxies, proxy_host_key);
+		if ((enabled == 0) && (host_val != NULL)) {
 			goto disable;		// if not enabled, remove provided key/value
 		}
 
-		if ((enabled != 0) &&
-		    (!isA_CFString(host) || (CFStringGetLength(host) == 0))) {
-			goto disable;		// if enabled, not provided (or not valid)
+		if (enabled != 0) {
+			if (isA_CFString(host_val)) {
+				CFStringRef	host	= (CFStringRef)host_val;
+
+				if (multiple_proxies) {
+					goto disable;	// if multiple proxies expected
+				}
+
+				if (CFStringGetLength(host) == 0) {
+					goto disable;	// if proxy host string not valid
+				}
+			} else if (isA_CFArray(host_val)) {
+				CFArrayRef	hosts	= (CFArrayRef)host_val;
+				CFIndex		n;
+
+				if (!multiple_proxies) {
+					goto disable;	// if single proxy expected
+				}
+
+				n = CFArrayGetCount(hosts);
+				if (n == 0) {
+					goto disable;	// if no hosts provided
+				}
+
+				for (CFIndex i = 0; i < n; i++) {
+					CFStringRef	host	= CFArrayGetValueAtIndex(hosts, i);
+
+					if (!isA_CFString(host) || (CFStringGetLength(host) == 0)) {
+						goto disable;	// if proxy host string not valid
+					}
+				}
+			} else {
+				goto disable;	// not valid
+			}
 		}
 	}
 
-	if (proxy_port != NULL) {
+	if (proxy_port_key != NULL) {
 		CFNumberRef	port;
 		int		s_port	= 0;
 
-		port = CFDictionaryGetValue(proxies, proxy_port);
+		port = CFDictionaryGetValue(proxies, proxy_port_key);
 		if ((enabled == 0) && (port != NULL)) {
 			goto disable;		// if not enabled, remove provided key/value
 		}
@@ -105,14 +137,18 @@ validate_proxy_content(CFMutableDictionaryRef	proxies,
 		if ((enabled != 0) && (port == NULL)) {
 			struct servent	*service;
 
-			service = getservbyname(proxy_service, "tcp");
+			if (proxy_service_name == NULL) {
+				goto disable;	// no "default" port available
+			}
+
+			service = getservbyname(proxy_service_name, "tcp");
 			if (service != NULL) {
 				s_port = ntohs(service->s_port);
 			} else {
 				s_port = proxy_defaultport;
 			}
 			num = CFNumberCreate(NULL, kCFNumberIntType, &s_port);
-			CFDictionarySetValue(proxies, proxy_port, num);
+			CFDictionarySetValue(proxies, proxy_port_key, num);
 			CFRelease(num);
 		}
 	}
@@ -123,13 +159,13 @@ validate_proxy_content(CFMutableDictionaryRef	proxies,
 
 	enabled = 0;
 	num = CFNumberCreate(NULL, kCFNumberIntType, &enabled);
-	CFDictionarySetValue(proxies, proxy_enable, num);
+	CFDictionarySetValue(proxies, proxy_enable_key, num);
 	CFRelease(num);
-	if (proxy_host != NULL) {
-		CFDictionaryRemoveValue(proxies, proxy_host);
+	if (proxy_host_key != NULL) {
+		CFDictionaryRemoveValue(proxies, proxy_host_key);
 	}
-	if (proxy_port != NULL) {
-		CFDictionaryRemoveValue(proxies, proxy_port);
+	if (proxy_port_key != NULL) {
+		CFDictionaryRemoveValue(proxies, proxy_port_key);
 	}
 
 	return;
@@ -175,44 +211,58 @@ __SCNetworkProxiesCopyNormalized(CFDictionaryRef proxy)
 			       kSCPropNetProxiesFTPProxy,
 			       kSCPropNetProxiesFTPPort,
 			       "ftp",
-			       21);
+			       21,
+			       FALSE);
 	validate_proxy_content(newProxy,
 			       kSCPropNetProxiesGopherEnable,
 			       kSCPropNetProxiesGopherProxy,
 			       kSCPropNetProxiesGopherPort,
 			       "gopher",
-			       70);
+			       70,
+			       FALSE);
 	validate_proxy_content(newProxy,
 			       kSCPropNetProxiesHTTPEnable,
 			       kSCPropNetProxiesHTTPProxy,
 			       kSCPropNetProxiesHTTPPort,
 			       "http",
-			       80);
+			       80,
+			       FALSE);
 	validate_proxy_content(newProxy,
 			       kSCPropNetProxiesHTTPSEnable,
 			       kSCPropNetProxiesHTTPSProxy,
 			       kSCPropNetProxiesHTTPSPort,
 			       "https",
-			       443);
+			       443,
+			       FALSE);
 	validate_proxy_content(newProxy,
 			       kSCPropNetProxiesRTSPEnable,
 			       kSCPropNetProxiesRTSPProxy,
 			       kSCPropNetProxiesRTSPPort,
 			       "rtsp",
-			       554);
+			       554,
+			       FALSE);
 	validate_proxy_content(newProxy,
 			       kSCPropNetProxiesSOCKSEnable,
 			       kSCPropNetProxiesSOCKSProxy,
 			       kSCPropNetProxiesSOCKSPort,
 			       "socks",
-			       1080);
+			       1080,
+			       FALSE);
+	validate_proxy_content(newProxy,
+			       kSCPropNetProxiesTransportConverterEnable,
+			       kSCPropNetProxiesTransportConverterProxy,
+			       kSCPropNetProxiesTransportConverterPort,
+			       NULL,
+			       0,
+			       TRUE);
 	if (CFDictionaryContainsKey(newProxy, kSCPropNetProxiesProxyAutoConfigURLString)) {
 		validate_proxy_content(newProxy,
 				       kSCPropNetProxiesProxyAutoConfigEnable,
 				       kSCPropNetProxiesProxyAutoConfigURLString,
 				       NULL,
 				       NULL,
-				       0);
+				       0,
+				       FALSE);
 
 		// and we can't have both URLString and JavaScript keys
 		CFDictionaryRemoveValue(newProxy, kSCPropNetProxiesProxyAutoConfigJavaScript);
@@ -222,21 +272,24 @@ __SCNetworkProxiesCopyNormalized(CFDictionaryRef proxy)
 				       kSCPropNetProxiesProxyAutoConfigJavaScript,
 				       NULL,
 				       NULL,
-				       0);
+				       0,
+				       FALSE);
 	}
 	validate_proxy_content(newProxy,
 			       kSCPropNetProxiesProxyAutoDiscoveryEnable,
 			       NULL,
 			       NULL,
 			       NULL,
-			       0);
+			       0,
+			       FALSE);
 
 	validate_proxy_content(newProxy,
 			       kSCPropNetProxiesFallBackAllowed,
 			       NULL,
 			       NULL,
 			       NULL,
-			       0);
+			       0,
+			       FALSE);
 
 	// validate FTP passive setting
 	num = CFDictionaryGetValue(newProxy, kSCPropNetProxiesFTPPassive);
diff --git a/SystemConfiguration.fproj/SCSchemaDefinitions.c b/SystemConfiguration.fproj/SCSchemaDefinitions.c
index d6f60d3..b0f9d0f 100644
--- a/SystemConfiguration.fproj/SCSchemaDefinitions.c
+++ b/SystemConfiguration.fproj/SCSchemaDefinitions.c
@@ -371,6 +371,12 @@ const CFStringRef kSCPropNetProxiesProxyAutoConfigEnable           = CFSTR("Prox
 const CFStringRef kSCPropNetProxiesProxyAutoConfigJavaScript       = CFSTR("ProxyAutoConfigJavaScript");
 const CFStringRef kSCPropNetProxiesProxyAutoConfigURLString        = CFSTR("ProxyAutoConfigURLString");
 const CFStringRef kSCPropNetProxiesProxyAutoDiscoveryEnable        = CFSTR("ProxyAutoDiscoveryEnable");
+const CFStringRef kSCPropNetProxiesTransportConverterEnable        = CFSTR("TransportConverterEnable");
+const CFStringRef kSCPropNetProxiesTransportConverterPort          = CFSTR("TransportConverterPort");
+const CFStringRef kSCPropNetProxiesTransportConverterProxy         = CFSTR("TransportConverterProxy");
+const CFStringRef kSCPropNetProxiesTransportConverterFallBackAllowed = CFSTR("TransportConverterFallBackAllowed");
+const CFStringRef kSCPropNetProxiesTransportConverterMultipathServiceType = CFSTR("TransportConverterMultipathServiceType");
+const CFStringRef kSCPropNetProxiesTransportConverterTFOMode       = CFSTR("TransportConverterTFOMode");
 const CFStringRef kSCPropNetProxiesBypassAllowed                   = CFSTR("BypassAllowed");
 const CFStringRef kSCPropNetProxiesFallBackAllowed                 = CFSTR("FallBackAllowed");
 const CFStringRef kSCPropNetProxiesSupplementalMatchDomains        = CFSTR("SupplementalMatchDomains");
diff --git a/SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h b/SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h
index 247f859..c14c6ba 100644
--- a/SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h
+++ b/SystemConfiguration.fproj/SCSchemaDefinitionsPrivate.h
@@ -190,6 +190,13 @@
  *
  * kSCEntNetProxies Entity Keys
  *
+ *   kSCPropNetProxiesTransportConverterEnable          "TransportConverterEnable"     CFNumber (0 or 1)
+ *   kSCPropNetProxiesTransportConverterPort            "TransportConverterPort"       CFNumber
+ *   kSCPropNetProxiesTransportConverterProxy           "TransportConverterProxy"      CFArray[CFString]
+ *   kSCPropNetProxiesTransportConverterFallBackAllowed "TransportConverterFallBackAllowed" CFNumber (0 or 1)
+ *   kSCPropNetProxiesTransportConverterMultipathServiceType "TransportConverterMultipathServiceType" CFNumber
+ *   kSCPropNetProxiesTransportConverterTFOMode         "TransportConverterTFOMode"    CFNumber
+ *
  *   kSCPropNetProxiesBypassAllowed                     "BypassAllowed"                CFNumber (0 or 1)
  *   kSCPropNetProxiesFallBackAllowed                   "FallBackAllowed"              CFNumber (0 or 1)
  *   kSCPropNetProxiesSupplementalMatchDomains          "SupplementalMatchDomains"     CFArray[CFString]
@@ -389,7 +396,7 @@ extern const CFStringRef kSCEntNetAppLayer                                  API_
   @const kSCEntNetCaptivePortal
   @discussion Value is a CFDictionary
  */
-extern const CFStringRef kSCEntNetCaptivePortal                             SPI_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));
+extern const CFStringRef kSCEntNetCaptivePortal                             SPI_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));
 #define kSCEntNetCaptivePortal kSCEntNetCaptivePortal
 
 /*!
@@ -581,7 +588,7 @@ extern const CFStringRef kSCPropNetDNSSupplementalMatchDomainsNoSearch      API_
   @const kSCPropNetCaptivePortalURL
   @discussion Value is a CFString
  */
-extern const CFStringRef kSCPropNetCaptivePortalURL                         SPI_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));
+extern const CFStringRef kSCPropNetCaptivePortalURL                         SPI_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));
 #define kSCPropNetCaptivePortalURL kSCPropNetCaptivePortalURL
 
 /*!
@@ -1073,6 +1080,48 @@ extern const CFStringRef kSCPropNetNAT64PLATDiscoveryCompletionTime         API_
   @group kSCEntNetProxies Entity Keys
  */
 
+/*!
+  @const kSCPropNetProxiesTransportConverterEnable
+  @discussion Value is a CFNumber (0 or 1)
+ */
+extern const CFStringRef kSCPropNetProxiesTransportConverterEnable          API_AVAILABLE(macos(11.0)) SPI_AVAILABLE(ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));
+#define kSCPropNetProxiesTransportConverterEnable kSCPropNetProxiesTransportConverterEnable
+
+/*!
+  @const kSCPropNetProxiesTransportConverterPort
+  @discussion Value is a CFNumber
+ */
+extern const CFStringRef kSCPropNetProxiesTransportConverterPort            API_AVAILABLE(macos(11.0)) SPI_AVAILABLE(ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));
+#define kSCPropNetProxiesTransportConverterPort kSCPropNetProxiesTransportConverterPort
+
+/*!
+  @const kSCPropNetProxiesTransportConverterProxy
+  @discussion Value is a CFArray[CFString]
+ */
+extern const CFStringRef kSCPropNetProxiesTransportConverterProxy           API_AVAILABLE(macos(11.0)) SPI_AVAILABLE(ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));
+#define kSCPropNetProxiesTransportConverterProxy kSCPropNetProxiesTransportConverterProxy
+
+/*!
+  @const kSCPropNetProxiesTransportConverterFallBackAllowed
+  @discussion Value is a CFNumber (0 or 1)
+ */
+extern const CFStringRef kSCPropNetProxiesTransportConverterFallBackAllowed  API_AVAILABLE(macos(11.0)) SPI_AVAILABLE(ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));
+#define kSCPropNetProxiesTransportConverterFallBackAllowed kSCPropNetProxiesTransportConverterFallBackAllowed
+
+/*!
+  @const kSCPropNetProxiesTransportConverterMultipathServiceType
+  @discussion Value is a CFNumber
+ */
+extern const CFStringRef kSCPropNetProxiesTransportConverterMultipathServiceType  API_AVAILABLE(macos(11.0)) SPI_AVAILABLE(ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));
+#define kSCPropNetProxiesTransportConverterMultipathServiceType kSCPropNetProxiesTransportConverterMultipathServiceType
+
+/*!
+  @const kSCPropNetProxiesTransportConverterTFOMode
+  @discussion Value is a CFNumber
+ */
+extern const CFStringRef kSCPropNetProxiesTransportConverterTFOMode         API_AVAILABLE(macos(11.0)) SPI_AVAILABLE(ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));
+#define kSCPropNetProxiesTransportConverterTFOMode kSCPropNetProxiesTransportConverterTFOMode
+
 /*!
   @const kSCPropNetProxiesBypassAllowed
   @discussion Value is a CFNumber (0 or 1)
diff --git a/SystemConfiguration.fproj/genSCPreferences.c b/SystemConfiguration.fproj/genSCPreferences.c
index 09fd827..238bab5 100644
--- a/SystemConfiguration.fproj/genSCPreferences.c
+++ b/SystemConfiguration.fproj/genSCPreferences.c
@@ -130,6 +130,7 @@ typedef enum {
 	SC_10_14_IPHONE_12_0_PRIVATE,
 	SC_10_15_IPHONE_13_0_PRIVATE,
 	SC_10_15_4_IPHONE_13_4_PRIVATE,
+	SC_11_0_IPHONE_14_0_PRIVATE,
 	SC_IPHONE_2_0_PRIVATE,
 	SC_IPHONE_7_0_PRIVATE,
 	SC_IPHONE_8_0_PRIVATE,
@@ -369,6 +370,7 @@ typedef enum {
 #define MSCHAP1			"MSCHAP1"
 #define MSCHAP2			"MSCHAP2"
 #define MTU			"MTU"
+#define MULTIPATH		"Multipath"
 #define NAME			"Name"
 #define NAT64			"NAT64"
 #define NETBIOS			"NetBIOS"
@@ -492,12 +494,14 @@ typedef enum {
 #define TAG			"Tag"
 #define TAGS			"Tags"
 #define TERMINALSCRIPT		"TerminalScript"
+#define TFO			"TFO"
 #define TIMEOUT			"Timeout"
 #define TIMER			"Timer"
 #define TIMESTAMP		"TimeStamp"
 #define TOKEN			"Token"
 #define TRANSMITACCM		"TransmitACCM"
 #define TRANSPORT		"Transport"
+#define TRANSPORTCONVERTER	"TransportConverter"
 #define TSO			"TSO"
 #define TSO4			"TSO4"
 #define TSO6			"TSO6"
@@ -1151,6 +1155,13 @@ static schemaDefinition names[] = {
 
   { GROUP_PRIVATE, NETPROP PROXIES, KEY_PREFIX NETENT PROXIES " Entity Keys", NULL, NULL },
 
+    { SC_11_0_IPHONE_14_0_PRIVATE, NETPROP PROXIES, TRANSPORTCONVERTER ENABLE, NULL, CFNUMBER_BOOL },
+    { SC_11_0_IPHONE_14_0_PRIVATE, NETPROP PROXIES, TRANSPORTCONVERTER PORT, NULL, CFNUMBER },
+    { SC_11_0_IPHONE_14_0_PRIVATE, NETPROP PROXIES, TRANSPORTCONVERTER PROXY, NULL, CFARRAY_CFSTRING },
+    { SC_11_0_IPHONE_14_0_PRIVATE, NETPROP PROXIES, TRANSPORTCONVERTER FALLBACK ALLOWED, NULL, CFNUMBER_BOOL },
+    { SC_11_0_IPHONE_14_0_PRIVATE, NETPROP PROXIES, TRANSPORTCONVERTER MULTIPATH SERVICE TYPE, NULL, CFNUMBER },
+    { SC_11_0_IPHONE_14_0_PRIVATE, NETPROP PROXIES, TRANSPORTCONVERTER TFO MODE, NULL, CFNUMBER },
+    { COMMENT_PRIVATE, "", NULL, NULL, NULL },
     { SC_10_9_IPHONE_7_0_PRIVATE, NETPROP PROXIES, BYPASS ALLOWED, NULL, CFNUMBER_BOOL },
     { SC_10_9_IPHONE_6_0_PRIVATE, NETPROP PROXIES, FALLBACK ALLOWED, NULL, CFNUMBER_BOOL },
     { SC_10_7_IPHONE_5_0_PRIVATE, NETPROP PROXIES, SUPPLEMENTAL MATCH DOMAINS, NULL, CFARRAY_CFSTRING},
@@ -1532,6 +1543,9 @@ print_headerdoc(schemaDefinition *def)
 	    case SC_10_15_4_IPHONE_13_4_PRIVATE:
 		printf("  API_AVAILABLE(macos(10.15.4)) SPI_AVAILABLE(ios(13.4), tvos(13.4), watchos(6.2), bridgeos(4.0));\n");
 		break;
+	    case SC_11_0_IPHONE_14_0_PRIVATE:
+		printf("  API_AVAILABLE(macos(11.0)) SPI_AVAILABLE(ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));\n");
+		break;
 	    case SC_IPHONE_2_0_PRIVATE:
 		printf("  SPI_AVAILABLE(macos(10.6), ios(2.0), tvos(9.0), watchos(1.0), bridgeos(1.0));\n");
 		break;
@@ -1542,7 +1556,7 @@ print_headerdoc(schemaDefinition *def)
 		printf("  SPI_AVAILABLE(macos(10.0), ios(8.0), tvos(9.0), watchos(1.0), bridgeos(1.0));\n");
 		break;
 	    case SC_IPHONE_14_PRIVATE:
-		printf("  SPI_AVAILABLE(macos(10.16), ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));\n");
+		printf("  SPI_AVAILABLE(macos(11.0), ios(14.0), tvos(14.0), watchos(7.0), bridgeos(5.0));\n");
 		break;
 	    default:
 		printf("\n");
@@ -1724,6 +1738,7 @@ dump_names(int type)
 			    case SC_10_14_IPHONE_12_0_PRIVATE:
 			    case SC_10_15_IPHONE_13_0_PRIVATE:
 			    case SC_10_15_4_IPHONE_13_4_PRIVATE:
+			    case SC_11_0_IPHONE_14_0_PRIVATE:
 			    case SC_IPHONE_2_0_PRIVATE:
 			    case SC_IPHONE_7_0_PRIVATE:
 			    case SC_IPHONE_8_0_PRIVATE:
@@ -1765,6 +1780,7 @@ dump_names(int type)
 			    case SC_10_14_IPHONE_12_0_PRIVATE:
 			    case SC_10_15_IPHONE_13_0_PRIVATE:
 			    case SC_10_15_4_IPHONE_13_4_PRIVATE:
+			    case SC_11_0_IPHONE_14_0_PRIVATE:
 			    case SC_IPHONE_2_0_PRIVATE:
 			    case SC_IPHONE_7_0_PRIVATE:
 			    case SC_IPHONE_8_0_PRIVATE:
@@ -1797,6 +1813,7 @@ dump_names(int type)
 			    case SC_10_14_IPHONE_12_0_PRIVATE:
 			    case SC_10_15_IPHONE_13_0_PRIVATE:
 			    case SC_10_15_4_IPHONE_13_4_PRIVATE:
+			    case SC_11_0_IPHONE_14_0_PRIVATE:
 			    case SC_IPHONE_2_0_PRIVATE:
 			    case SC_IPHONE_7_0_PRIVATE:
 			    case SC_IPHONE_8_0_PRIVATE:
@@ -1827,6 +1844,7 @@ dump_names(int type)
 			    case SC_10_14_IPHONE_12_0_PRIVATE:
 			    case SC_10_15_IPHONE_13_0_PRIVATE:
 			    case SC_10_15_4_IPHONE_13_4_PRIVATE:
+			    case SC_11_0_IPHONE_14_0_PRIVATE:
 			    case SC_IPHONE_2_0_PRIVATE:
 			    case SC_IPHONE_7_0_PRIVATE:
 			    case SC_IPHONE_8_0_PRIVATE:
diff --git a/scutil.tproj/net_protocol.c b/scutil.tproj/net_protocol.c
index b0392fa..5057fd1 100644
--- a/scutil.tproj/net_protocol.c
+++ b/scutil.tproj/net_protocol.c
@@ -962,16 +962,71 @@ typedef const struct {
 	const CFStringRef	*keyProxy;
 	const CFStringRef	*keyPort;
 	const CFStringRef	*keyURL;
+	const Boolean		multiple_proxies;
 } proxyKeys;
 
-static proxyKeys proxyKeys_FTP    = { "FTP"   , &kSCPropNetProxiesFTPEnable               , &kSCPropNetProxiesFTPProxy   , &kSCPropNetProxiesFTPPort   , NULL                                       };
-static proxyKeys proxyKeys_Gopher = { "Gopher", &kSCPropNetProxiesGopherEnable            , &kSCPropNetProxiesGopherProxy, &kSCPropNetProxiesGopherPort, NULL                                       };
-static proxyKeys proxyKeys_HTTP   = { "HTTP"  , &kSCPropNetProxiesHTTPEnable              , &kSCPropNetProxiesHTTPProxy  , &kSCPropNetProxiesHTTPPort  , NULL                                       };
-static proxyKeys proxyKeys_HTTPS  = { "HTTPS" , &kSCPropNetProxiesHTTPSEnable             , &kSCPropNetProxiesHTTPSProxy , &kSCPropNetProxiesHTTPSPort , NULL                                       };
-static proxyKeys proxyKeys_RTSP   = { "RTSP"  , &kSCPropNetProxiesRTSPEnable              , &kSCPropNetProxiesRTSPProxy  , &kSCPropNetProxiesRTSPPort  , NULL                                       };
-static proxyKeys proxyKeys_SOCKS  = { "SOCKS" , &kSCPropNetProxiesSOCKSEnable             , &kSCPropNetProxiesSOCKSProxy , &kSCPropNetProxiesSOCKSPort , NULL                                       };
-static proxyKeys proxyKeys_PAC    = { ".pac"  , &kSCPropNetProxiesProxyAutoConfigEnable   , NULL                         , NULL                        , &kSCPropNetProxiesProxyAutoConfigURLString };
-static proxyKeys proxyKeys_WPAD   = { "WPAD"  , &kSCPropNetProxiesProxyAutoDiscoveryEnable, NULL                         , NULL                        , NULL                                       };
+static proxyKeys proxyKeys_FTP    = { "FTP",
+				      &kSCPropNetProxiesFTPEnable,
+				      &kSCPropNetProxiesFTPProxy,
+				      &kSCPropNetProxiesFTPPort,
+				      NULL,
+				      FALSE
+				    };
+static proxyKeys proxyKeys_Gopher = { "Gopher",
+				      &kSCPropNetProxiesGopherEnable,
+				      &kSCPropNetProxiesGopherProxy,
+				      &kSCPropNetProxiesGopherPort,
+				      NULL,
+				      FALSE
+				    };
+static proxyKeys proxyKeys_HTTP   = { "HTTP",
+				      &kSCPropNetProxiesHTTPEnable,
+				      &kSCPropNetProxiesHTTPProxy,
+				      &kSCPropNetProxiesHTTPPort,
+				      NULL,
+				      FALSE
+				    };
+static proxyKeys proxyKeys_HTTPS  = { "HTTPS",
+				      &kSCPropNetProxiesHTTPSEnable,
+				      &kSCPropNetProxiesHTTPSProxy,
+				      &kSCPropNetProxiesHTTPSPort,
+				      NULL,
+				      FALSE
+				    };
+static proxyKeys proxyKeys_RTSP   = { "RTSP",
+				      &kSCPropNetProxiesRTSPEnable,
+				      &kSCPropNetProxiesRTSPProxy,
+				      &kSCPropNetProxiesRTSPPort,
+				      NULL,
+				      FALSE
+				    };
+static proxyKeys proxyKeys_SOCKS  = { "SOCKS",
+				      &kSCPropNetProxiesSOCKSEnable,
+				      &kSCPropNetProxiesSOCKSProxy,
+				      &kSCPropNetProxiesSOCKSPort,
+				      NULL,
+				      FALSE
+				    };
+static proxyKeys proxyKeys_TransportConverter =
+				    { "TransportConverter",
+				      &kSCPropNetProxiesTransportConverterEnable,
+				      &kSCPropNetProxiesTransportConverterProxy,
+				      &kSCPropNetProxiesTransportConverterPort,
+				      NULL,
+				      TRUE
+				    };
+static proxyKeys proxyKeys_PAC    = { ".pac",
+				      &kSCPropNetProxiesProxyAutoConfigEnable,
+				      NULL,
+				      NULL,
+				      &kSCPropNetProxiesProxyAutoConfigURLString,
+				      FALSE};
+static proxyKeys proxyKeys_WPAD   = { "WPAD",
+				      &kSCPropNetProxiesProxyAutoDiscoveryEnable,
+				      NULL,
+				      NULL,
+				      NULL,
+				      FALSE};
 
 static proxyKeys	*currentProxy	= NULL;
 
@@ -995,6 +1050,7 @@ static options proxyOptions[] = {
 	{ "HTTPS"                 , NULL        , isOther      , NULL                                    , __doProxySelect   , (void *)&proxyKeys_HTTPS  },
 	{ "RTSP"                  , NULL        , isOther      , NULL                                    , __doProxySelect   , (void *)&proxyKeys_RTSP   },
 	{ "SOCKS"                 , NULL        , isOther      , NULL                                    , __doProxySelect   , (void *)&proxyKeys_SOCKS  },
+	{ "TransportConverter"    , NULL        , isOther      , NULL                                    , __doProxySelect   , (void *)&proxyKeys_TransportConverter },
 	{ "ProxyAutoConfig"       , NULL        , isOther      , NULL                                    , __doProxySelect   , (void *)&proxyKeys_PAC    },
 	{   ".pac"                , NULL        , isOther      , NULL                                    , __doProxySelect   , (void *)&proxyKeys_PAC    },
 	{ "ProxyAutoDiscovery"    , NULL        , isOther      , NULL                                    , __doProxySelect   , (void *)&proxyKeys_WPAD   },
@@ -1004,6 +1060,8 @@ static options proxyOptions[] = {
 	{ "enable"                , NULL        , isOther      , NULL                                    , __doProxyEnable    , (void *)TRUE              },
 	{ "proxy"                 , NULL        , isOther      , NULL                                    , __doProxyHost      , NULL                      },
 	{   "host"                , NULL        , isOther      , NULL                                    , __doProxyHost      , NULL                      },
+	{ "proxies"               , NULL        , isOther      , NULL                                    , __doProxyHost      , NULL                      },
+	{   "hosts"               , NULL        , isOther      , NULL                                    , __doProxyHost      , NULL                      },
 	{ "port"                  , NULL        , isOther      , NULL                                    , __doProxyPort      , NULL                      },
 	{ "url"                   , NULL        , isOther      , NULL                                    , __doProxyURL       , NULL                      },
 	// (ftp) proxy modifiers
@@ -1036,6 +1094,10 @@ static options proxyOptions[] = {
 	    " set protocol socks host proxy-host\n"
 	    " set protocol socks port proxy-port\n"
 	    "\n"
+	    " set protocol transportconverter {enable|disable}\n"
+	    " set protocol transportconverter host[s] proxy-host[,proxy-host-2]\n"
+	    " set protocol transportconverter port proxy-port\n"
+	    "\n"
 	    " set protocol .pac {enable|disable}\n"
 	    " set protocol .pac url .pac-url\n"
 	    "\n"
@@ -1163,11 +1225,22 @@ __doProxyHost(CFStringRef key, const char *description, void *info, int argc, ch
 	}
 
 	if (strlen(argv[0]) > 0) {
-		CFStringRef	host;
+		if (!currentProxy->multiple_proxies) {
+			CFStringRef	host;
 
-		host = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
-		CFDictionarySetValue(newConfiguration, *(currentProxy->keyProxy), host);
-		CFRelease(host);
+			host = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+			CFDictionarySetValue(newConfiguration, *(currentProxy->keyProxy), host);
+			CFRelease(host);
+		} else {
+			CFArrayRef	hosts;
+			CFStringRef	hosts_str;
+
+			hosts_str = CFStringCreateWithCString(NULL, argv[0], kCFStringEncodingUTF8);
+			hosts = CFStringCreateArrayBySeparatingStrings(NULL, hosts_str, CFSTR(","));
+			CFDictionarySetValue(newConfiguration, *(currentProxy->keyProxy), hosts);
+			CFRelease(hosts);
+			CFRelease(hosts_str);
+		}
 	} else {
 		CFDictionaryRemoveValue(newConfiguration, *(currentProxy->keyProxy));
 	}