Add Proxy Auto-Configuration (PAC) support

This commit is contained in:
ThinkChaos 2019-10-21 21:47:45 +02:00
parent 5866c373eb
commit c6cb5a646a
5 changed files with 50 additions and 8 deletions

View File

@ -181,6 +181,8 @@ extension OpenVPNTunnelProvider {
static let httpsProxy = "HTTPSProxy"
static let proxyAutoConfURL = "proxyAutoConfURL"
static let proxyBypassDomains = "ProxyBypassDomains"
static let routingPolicies = "RoutingPolicies"
@ -595,6 +597,9 @@ private extension OpenVPN.Configuration {
if let httpsProxy = httpsProxy {
dict[S.httpsProxy] = httpsProxy.rawValue
}
if let proxyAutoConfURL = proxyAutoConfURL {
dict[S.proxyAutoConfURL] = proxyAutoConfURL.absoluteString
}
if let proxyBypassDomains = proxyBypassDomains {
dict[S.proxyBypassDomains] = proxyBypassDomains
}
@ -668,6 +673,9 @@ private extension OpenVPN.Configuration {
if let httpsProxy = httpsProxy {
log.info("\tHTTPS proxy: \(httpsProxy.maskedDescription)")
}
if let proxyAutoConfURL = proxyAutoConfURL {
log.info("\tPAC: \(proxyAutoConfURL)")
}
if let proxyBypassDomains = proxyBypassDomains {
log.info("\tProxy bypass domains: \(proxyBypassDomains.maskedDescription)")
}

View File

@ -514,6 +514,9 @@ extension OpenVPNTunnelProvider: OpenVPNSessionDelegate {
if let proxy = options.httpsProxy {
log.info("\t\tHTTPS: \(proxy.maskedDescription)")
}
if let pacURL = options.proxyAutoConfURL {
log.info("\t\tPAC: \(pacURL)")
}
if let bypass = options.proxyBypassDomains {
log.info("\t\tBypass domains: \(bypass.maskedDescription)")
}
@ -665,18 +668,26 @@ extension OpenVPNTunnelProvider: OpenVPNSessionDelegate {
var proxySettings: NEProxySettings?
if let httpsProxy = cfg.sessionConfiguration.httpsProxy ?? options.httpsProxy {
proxySettings = NEProxySettings()
proxySettings?.httpsServer = httpsProxy.neProxy()
proxySettings?.httpsEnabled = true
proxySettings!.httpsServer = httpsProxy.neProxy()
proxySettings!.httpsEnabled = true
log.info("Routing: Setting HTTPS proxy \(httpsProxy.address.maskedDescription):\(httpsProxy.port)")
}
if let httpProxy = cfg.sessionConfiguration.httpProxy ?? options.httpProxy {
if proxySettings == nil {
proxySettings = NEProxySettings()
}
proxySettings?.httpServer = httpProxy.neProxy()
proxySettings?.httpEnabled = true
proxySettings!.httpServer = httpProxy.neProxy()
proxySettings!.httpEnabled = true
log.info("Routing: Setting HTTP proxy \(httpProxy.address.maskedDescription):\(httpProxy.port)")
}
if let pacURL = cfg.sessionConfiguration.proxyAutoConfURL ?? options.proxyAutoConfURL {
if proxySettings == nil {
proxySettings = NEProxySettings()
}
proxySettings!.proxyAutoConfigurationURL = pacURL
proxySettings!.autoProxyConfigurationEnabled = true
log.info("Routing: Setting PAC \(pacURL)")
}
// only set if there is a proxy (proxySettings set to non-nil above)
if let bypass = cfg.sessionConfiguration.proxyBypassDomains ?? options.proxyBypassDomains {

View File

@ -244,9 +244,12 @@ extension OpenVPN {
/// The search domain.
public var searchDomain: String?
/// The Proxy Auto-Configuration (PAC) url.
public var proxyAutoConfURL: URL?
/// The HTTP proxy.
public var httpProxy: Proxy?
/// The HTTPS proxy.
public var httpsProxy: Proxy?
@ -291,6 +294,7 @@ extension OpenVPN {
searchDomain: searchDomain,
httpProxy: httpProxy,
httpsProxy: httpsProxy,
proxyAutoConfURL: proxyAutoConfURL,
proxyBypassDomains: proxyBypassDomains,
routingPolicies: routingPolicies
)
@ -385,10 +389,13 @@ extension OpenVPN {
/// - Seealso: `ConfigurationBuilder.httpProxy`
public let httpProxy: Proxy?
/// - Seealso: `ConfigurationBuilder.httpsProxy`
public let httpsProxy: Proxy?
/// - Seealso: `ConfigurationBuilder.proxyAutoConfURL`
public let proxyAutoConfURL: URL?
/// - Seealso: `ConfigurationBuilder.proxyBypassDomains`
public let proxyBypassDomains: [String]?
@ -449,6 +456,7 @@ extension OpenVPN.Configuration {
builder.searchDomain = searchDomain
builder.httpProxy = httpProxy
builder.httpsProxy = httpsProxy
builder.proxyAutoConfURL = proxyAutoConfURL
builder.proxyBypassDomains = proxyBypassDomains
builder.routingPolicies = routingPolicies
return builder

View File

@ -94,7 +94,7 @@ extension OpenVPN {
static let domain = NSRegularExpression("^dhcp-option +DOMAIN +[^ ]+")
static let proxy = NSRegularExpression("^dhcp-option +PROXY_(HTTPS?) +[^ ]+ +\\d+")
static let proxy = NSRegularExpression("^dhcp-option +PROXY_(HTTPS? +[^ ]+ +\\d+|AUTO_CONFIG_URL +[^ ]+)")
static let proxyBypass = NSRegularExpression("^dhcp-option +PROXY_BYPASS +.+")
@ -225,6 +225,7 @@ extension OpenVPN {
var optSearchDomain: String?
var optHTTPProxy: Proxy?
var optHTTPSProxy: Proxy?
var optProxyAutoConfURL: URL?
var optProxyBypass: [String]?
var optRedirectGateway: Set<RedirectGateway>?
@ -517,6 +518,17 @@ extension OpenVPN {
optSearchDomain = $0[1]
}
Regex.proxy.enumerateArguments(in: line) {
if $0.count == 2 {
let maybeURL = URL(string: $0[1])
if maybeURL != nil {
optProxyAutoConfURL = maybeURL!
}
else {
unsupportedError = ConfigurationError.malformed(option: "dhcp-option PROXY_AUTO_CONFIG_URL has malformed URL")
}
return
}
guard $0.count == 3, let port = UInt16($0[2]) else {
return
}
@ -526,7 +538,7 @@ extension OpenVPN {
case "PROXY_HTTP":
optHTTPProxy = Proxy($0[1], port)
default:
break
}
@ -714,6 +726,7 @@ extension OpenVPN {
sessionBuilder.searchDomain = optSearchDomain
sessionBuilder.httpProxy = optHTTPProxy
sessionBuilder.httpsProxy = optHTTPSProxy
sessionBuilder.proxyAutoConfURL = optProxyAutoConfURL
sessionBuilder.proxyBypassDomains = optProxyBypass
if let flags = optRedirectGateway {

View File

@ -56,6 +56,7 @@ class ConfigurationParserTests: XCTestCase {
"dhcp-option DOMAIN example.com",
"dhcp-option PROXY_HTTP 1.2.3.4 8081",
"dhcp-option PROXY_HTTPS 7.8.9.10 8082",
"dhcp-option PROXY_AUTO_CONFIG_URL https://pac/",
"dhcp-option PROXY_BYPASS foo.com bar.org net.chat"
]
XCTAssertNoThrow(try OpenVPN.ConfigurationParser.parsed(fromLines: lines))
@ -67,6 +68,7 @@ class ConfigurationParserTests: XCTestCase {
XCTAssertEqual(parsed.httpProxy?.port, 8081)
XCTAssertEqual(parsed.httpsProxy?.address, "7.8.9.10")
XCTAssertEqual(parsed.httpsProxy?.port, 8082)
XCTAssertEqual(parsed.proxyAutoConfURL?.absoluteString, "https://pac/")
XCTAssertEqual(parsed.proxyBypassDomains, ["foo.com", "bar.org", "net.chat"])
}