Merge pull request #125 from ThinkChaos/proxy_auto_conf

Add Proxy Auto-Configuration (PAC) support
This commit is contained in:
Davide De Rosa 2019-10-22 21:55:29 +02:00 committed by GitHub
commit 7d0cba8df8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 44 additions and 4 deletions

View File

@ -183,6 +183,8 @@ extension OpenVPNTunnelProvider {
static let httpsProxy = "HTTPSProxy" static let httpsProxy = "HTTPSProxy"
static let proxyAutoConfigurationURL = "ProxyAutoConfigurationURL"
static let proxyBypassDomains = "ProxyBypassDomains" static let proxyBypassDomains = "ProxyBypassDomains"
static let routingPolicies = "RoutingPolicies" static let routingPolicies = "RoutingPolicies"
@ -603,6 +605,9 @@ private extension OpenVPN.Configuration {
if let httpsProxy = httpsProxy { if let httpsProxy = httpsProxy {
dict[S.httpsProxy] = httpsProxy.rawValue dict[S.httpsProxy] = httpsProxy.rawValue
} }
if let proxyAutoConfigurationURL = proxyAutoConfigurationURL {
dict[S.proxyAutoConfigurationURL] = proxyAutoConfigurationURL.absoluteString
}
if let proxyBypassDomains = proxyBypassDomains { if let proxyBypassDomains = proxyBypassDomains {
dict[S.proxyBypassDomains] = proxyBypassDomains dict[S.proxyBypassDomains] = proxyBypassDomains
} }
@ -681,6 +686,9 @@ private extension OpenVPN.Configuration {
if let httpsProxy = httpsProxy { if let httpsProxy = httpsProxy {
log.info("\tHTTPS proxy: \(httpsProxy.maskedDescription)") log.info("\tHTTPS proxy: \(httpsProxy.maskedDescription)")
} }
if let proxyAutoConfigurationURL = proxyAutoConfigurationURL {
log.info("\tPAC: \(proxyAutoConfigurationURL)")
}
if let proxyBypassDomains = proxyBypassDomains { if let proxyBypassDomains = proxyBypassDomains {
log.info("\tProxy bypass domains: \(proxyBypassDomains.maskedDescription)") log.info("\tProxy bypass domains: \(proxyBypassDomains.maskedDescription)")
} }

View File

@ -514,6 +514,9 @@ extension OpenVPNTunnelProvider: OpenVPNSessionDelegate {
if let proxy = options.httpsProxy { if let proxy = options.httpsProxy {
log.info("\t\tHTTPS: \(proxy.maskedDescription)") log.info("\t\tHTTPS: \(proxy.maskedDescription)")
} }
if let pacURL = options.proxyAutoConfigurationURL {
log.info("\t\tPAC: \(pacURL)")
}
if let bypass = options.proxyBypassDomains { if let bypass = options.proxyBypassDomains {
log.info("\t\tBypass domains: \(bypass.maskedDescription)") log.info("\t\tBypass domains: \(bypass.maskedDescription)")
} }
@ -677,6 +680,14 @@ extension OpenVPNTunnelProvider: OpenVPNSessionDelegate {
proxySettings?.httpEnabled = true proxySettings?.httpEnabled = true
log.info("Routing: Setting HTTP proxy \(httpProxy.address.maskedDescription):\(httpProxy.port)") log.info("Routing: Setting HTTP proxy \(httpProxy.address.maskedDescription):\(httpProxy.port)")
} }
if let pacURL = cfg.sessionConfiguration.proxyAutoConfigurationURL ?? options.proxyAutoConfigurationURL {
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) // only set if there is a proxy (proxySettings set to non-nil above)
if let bypass = cfg.sessionConfiguration.proxyBypassDomains ?? options.proxyBypassDomains { if let bypass = cfg.sessionConfiguration.proxyBypassDomains ?? options.proxyBypassDomains {

View File

@ -247,9 +247,12 @@ extension OpenVPN {
/// The search domain. /// The search domain.
public var searchDomain: String? public var searchDomain: String?
/// The Proxy Auto-Configuration (PAC) url.
public var proxyAutoConfigurationURL: URL?
/// The HTTP proxy. /// The HTTP proxy.
public var httpProxy: Proxy? public var httpProxy: Proxy?
/// The HTTPS proxy. /// The HTTPS proxy.
public var httpsProxy: Proxy? public var httpsProxy: Proxy?
@ -295,6 +298,7 @@ extension OpenVPN {
searchDomain: searchDomain, searchDomain: searchDomain,
httpProxy: httpProxy, httpProxy: httpProxy,
httpsProxy: httpsProxy, httpsProxy: httpsProxy,
proxyAutoConfigurationURL: proxyAutoConfigurationURL,
proxyBypassDomains: proxyBypassDomains, proxyBypassDomains: proxyBypassDomains,
routingPolicies: routingPolicies routingPolicies: routingPolicies
) )
@ -392,10 +396,13 @@ extension OpenVPN {
/// - Seealso: `ConfigurationBuilder.httpProxy` /// - Seealso: `ConfigurationBuilder.httpProxy`
public let httpProxy: Proxy? public let httpProxy: Proxy?
/// - Seealso: `ConfigurationBuilder.httpsProxy` /// - Seealso: `ConfigurationBuilder.httpsProxy`
public let httpsProxy: Proxy? public let httpsProxy: Proxy?
/// - Seealso: `ConfigurationBuilder.proxyAutoConfigurationURL`
public let proxyAutoConfigurationURL: URL?
/// - Seealso: `ConfigurationBuilder.proxyBypassDomains` /// - Seealso: `ConfigurationBuilder.proxyBypassDomains`
public let proxyBypassDomains: [String]? public let proxyBypassDomains: [String]?
@ -457,6 +464,7 @@ extension OpenVPN.Configuration {
builder.searchDomain = searchDomain builder.searchDomain = searchDomain
builder.httpProxy = httpProxy builder.httpProxy = httpProxy
builder.httpsProxy = httpsProxy builder.httpsProxy = httpsProxy
builder.proxyAutoConfigurationURL = proxyAutoConfigurationURL
builder.proxyBypassDomains = proxyBypassDomains builder.proxyBypassDomains = proxyBypassDomains
builder.routingPolicies = routingPolicies builder.routingPolicies = routingPolicies
return builder return builder

View File

@ -96,7 +96,7 @@ extension OpenVPN {
static let domain = NSRegularExpression("^dhcp-option +DOMAIN +[^ ]+") 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 +.+") static let proxyBypass = NSRegularExpression("^dhcp-option +PROXY_BYPASS +.+")
@ -228,6 +228,7 @@ extension OpenVPN {
var optSearchDomain: String? var optSearchDomain: String?
var optHTTPProxy: Proxy? var optHTTPProxy: Proxy?
var optHTTPSProxy: Proxy? var optHTTPSProxy: Proxy?
var optProxyAutoConfigurationURL: URL?
var optProxyBypass: [String]? var optProxyBypass: [String]?
var optRedirectGateway: Set<RedirectGateway>? var optRedirectGateway: Set<RedirectGateway>?
@ -533,6 +534,15 @@ extension OpenVPN {
optSearchDomain = $0[1] optSearchDomain = $0[1]
} }
Regex.proxy.enumerateArguments(in: line) { Regex.proxy.enumerateArguments(in: line) {
if $0.count == 2 {
guard let url = URL(string: $0[1]) else {
unsupportedError = ConfigurationError.malformed(option: "dhcp-option PROXY_AUTO_CONFIG_URL has malformed URL")
return
}
optProxyAutoConfigurationURL = url
return
}
guard $0.count == 3, let port = UInt16($0[2]) else { guard $0.count == 3, let port = UInt16($0[2]) else {
return return
} }
@ -542,7 +552,7 @@ extension OpenVPN {
case "PROXY_HTTP": case "PROXY_HTTP":
optHTTPProxy = Proxy($0[1], port) optHTTPProxy = Proxy($0[1], port)
default: default:
break break
} }
@ -731,6 +741,7 @@ extension OpenVPN {
sessionBuilder.searchDomain = optSearchDomain sessionBuilder.searchDomain = optSearchDomain
sessionBuilder.httpProxy = optHTTPProxy sessionBuilder.httpProxy = optHTTPProxy
sessionBuilder.httpsProxy = optHTTPSProxy sessionBuilder.httpsProxy = optHTTPSProxy
sessionBuilder.proxyAutoConfigurationURL = optProxyAutoConfigurationURL
sessionBuilder.proxyBypassDomains = optProxyBypass sessionBuilder.proxyBypassDomains = optProxyBypass
if let flags = optRedirectGateway { if let flags = optRedirectGateway {

View File

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