Parse --redirect-gateway from configuration
FIXME: for now only redirects ALL traffic when the option is found in the configuration file, whatever the arguments. Also drop unnecessary base options in tests as everything was made optional recently.
This commit is contained in:
parent
1b8647bcac
commit
224a76ac58
|
@ -96,6 +96,8 @@ public class ConfigurationParser {
|
||||||
|
|
||||||
static let proxyBypass = NSRegularExpression("^dhcp-option +PROXY_BYPASS +.+")
|
static let proxyBypass = NSRegularExpression("^dhcp-option +PROXY_BYPASS +.+")
|
||||||
|
|
||||||
|
static let redirectGateway = NSRegularExpression("^redirect-gateway.*")
|
||||||
|
|
||||||
// MARK: Unsupported
|
// MARK: Unsupported
|
||||||
|
|
||||||
// static let fragment = NSRegularExpression("^fragment +\\d+")
|
// static let fragment = NSRegularExpression("^fragment +\\d+")
|
||||||
|
@ -120,6 +122,26 @@ public class ConfigurationParser {
|
||||||
case subnet
|
case subnet
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private enum RedirectGateway: String {
|
||||||
|
case local
|
||||||
|
|
||||||
|
case autolocal
|
||||||
|
|
||||||
|
case def1
|
||||||
|
|
||||||
|
case bypassDHCP = "bypass-dhcp"
|
||||||
|
|
||||||
|
case bypassDNS = "bypass-dns"
|
||||||
|
|
||||||
|
case blockLocal = "block-local"
|
||||||
|
|
||||||
|
case ipv4
|
||||||
|
|
||||||
|
case noIPv4 = "!ipv4"
|
||||||
|
|
||||||
|
case ipv6
|
||||||
|
}
|
||||||
|
|
||||||
/// Result of the parser.
|
/// Result of the parser.
|
||||||
public struct Result {
|
public struct Result {
|
||||||
|
|
||||||
|
@ -204,6 +226,7 @@ public class ConfigurationParser {
|
||||||
var optHTTPProxy: Proxy?
|
var optHTTPProxy: Proxy?
|
||||||
var optHTTPSProxy: Proxy?
|
var optHTTPSProxy: Proxy?
|
||||||
var optProxyBypass: [String]?
|
var optProxyBypass: [String]?
|
||||||
|
var optRedirectGateway: Set<RedirectGateway>?
|
||||||
|
|
||||||
log.verbose("Configuration file:")
|
log.verbose("Configuration file:")
|
||||||
for line in lines {
|
for line in lines {
|
||||||
|
@ -515,6 +538,22 @@ public class ConfigurationParser {
|
||||||
optProxyBypass = $0
|
optProxyBypass = $0
|
||||||
optProxyBypass?.removeFirst()
|
optProxyBypass?.removeFirst()
|
||||||
}
|
}
|
||||||
|
Regex.redirectGateway.enumerateArguments(in: line) {
|
||||||
|
|
||||||
|
// redirect IPv4 by default
|
||||||
|
optRedirectGateway = [.ipv4]
|
||||||
|
|
||||||
|
for arg in $0 {
|
||||||
|
guard let opt = RedirectGateway(rawValue: arg) else {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if opt == .noIPv4 {
|
||||||
|
optRedirectGateway?.remove(.ipv4)
|
||||||
|
} else {
|
||||||
|
optRedirectGateway?.insert(opt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
|
@ -681,6 +720,11 @@ public class ConfigurationParser {
|
||||||
sessionBuilder.httpsProxy = optHTTPSProxy
|
sessionBuilder.httpsProxy = optHTTPSProxy
|
||||||
sessionBuilder.proxyBypassDomains = optProxyBypass
|
sessionBuilder.proxyBypassDomains = optProxyBypass
|
||||||
|
|
||||||
|
// FIXME: only redirects all traffic until --redirect-gateway is properly interpreted
|
||||||
|
if let _ = optRedirectGateway {
|
||||||
|
sessionBuilder.routingPolicies = [.IPv4, .IPv6]
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
return Result(
|
return Result(
|
||||||
|
|
|
@ -146,6 +146,16 @@ extension SessionProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Routing policy.
|
||||||
|
public enum RoutingPolicy: String, Codable {
|
||||||
|
|
||||||
|
/// All IPv4 traffic goes through the VPN.
|
||||||
|
case IPv4
|
||||||
|
|
||||||
|
/// All IPv6 traffic goes through the VPN.
|
||||||
|
case IPv6
|
||||||
|
}
|
||||||
|
|
||||||
/// :nodoc:
|
/// :nodoc:
|
||||||
private struct Fallback {
|
private struct Fallback {
|
||||||
static let cipher: Cipher = .aes128cbc
|
static let cipher: Cipher = .aes128cbc
|
||||||
|
@ -238,6 +248,9 @@ extension SessionProxy {
|
||||||
/// The list of domains not passing through the proxy.
|
/// The list of domains not passing through the proxy.
|
||||||
public var proxyBypassDomains: [String]?
|
public var proxyBypassDomains: [String]?
|
||||||
|
|
||||||
|
/// Policies for redirecting traffic through the VPN gateway.
|
||||||
|
public var routingPolicies: [RoutingPolicy]?
|
||||||
|
|
||||||
/// :nodoc:
|
/// :nodoc:
|
||||||
public init() {
|
public init() {
|
||||||
}
|
}
|
||||||
|
@ -272,7 +285,8 @@ extension SessionProxy {
|
||||||
searchDomain: searchDomain,
|
searchDomain: searchDomain,
|
||||||
httpProxy: httpProxy,
|
httpProxy: httpProxy,
|
||||||
httpsProxy: httpsProxy,
|
httpsProxy: httpsProxy,
|
||||||
proxyBypassDomains: proxyBypassDomains
|
proxyBypassDomains: proxyBypassDomains,
|
||||||
|
routingPolicies: routingPolicies
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -369,6 +383,9 @@ extension SessionProxy {
|
||||||
/// - Seealso: `SessionProxy.ConfigurationBuilder.proxyBypassDomains`
|
/// - Seealso: `SessionProxy.ConfigurationBuilder.proxyBypassDomains`
|
||||||
public var proxyBypassDomains: [String]?
|
public var proxyBypassDomains: [String]?
|
||||||
|
|
||||||
|
/// - Seealso: `SessionProxy.ConfigurationBuilder.routingPolicies`
|
||||||
|
public var routingPolicies: [RoutingPolicy]?
|
||||||
|
|
||||||
// MARK: Shortcuts
|
// MARK: Shortcuts
|
||||||
|
|
||||||
/// :nodoc:
|
/// :nodoc:
|
||||||
|
@ -422,6 +439,7 @@ extension SessionProxy.Configuration {
|
||||||
builder.httpProxy = httpProxy
|
builder.httpProxy = httpProxy
|
||||||
builder.httpsProxy = httpsProxy
|
builder.httpsProxy = httpsProxy
|
||||||
builder.proxyBypassDomains = proxyBypassDomains
|
builder.proxyBypassDomains = proxyBypassDomains
|
||||||
|
builder.routingPolicies = routingPolicies
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,8 +27,6 @@ import XCTest
|
||||||
import TunnelKit
|
import TunnelKit
|
||||||
|
|
||||||
class ConfigurationParserTests: XCTestCase {
|
class ConfigurationParserTests: XCTestCase {
|
||||||
let base: [String] = ["<ca>", "</ca>", "remote 1.2.3.4"]
|
|
||||||
|
|
||||||
override func setUp() {
|
override func setUp() {
|
||||||
super.setUp()
|
super.setUp()
|
||||||
// Put setup code here. This method is called before the invocation of each test method in the class.
|
// Put setup code here. This method is called before the invocation of each test method in the class.
|
||||||
|
@ -42,18 +40,18 @@ class ConfigurationParserTests: XCTestCase {
|
||||||
// from lines
|
// from lines
|
||||||
|
|
||||||
func testCompression() throws {
|
func testCompression() throws {
|
||||||
// XCTAssertNotNil(try OptionsBundle.parsed(fromLines: base + ["comp-lzo"]).warning)
|
// XCTAssertNotNil(try OptionsBundle.parsed(fromLines: ["comp-lzo"]).warning)
|
||||||
XCTAssertNil(try ConfigurationParser.parsed(fromLines: base + ["comp-lzo"]).warning)
|
XCTAssertNil(try ConfigurationParser.parsed(fromLines: ["comp-lzo"]).warning)
|
||||||
XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: base + ["comp-lzo no"]))
|
XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: ["comp-lzo no"]))
|
||||||
XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: base + ["comp-lzo yes"]))
|
XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: ["comp-lzo yes"]))
|
||||||
// XCTAssertThrowsError(try ConfigurationParser.parsed(fromLines: base + ["comp-lzo yes"]))
|
// XCTAssertThrowsError(try ConfigurationParser.parsed(fromLines: ["comp-lzo yes"]))
|
||||||
|
|
||||||
XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: base + ["compress"]))
|
XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: ["compress"]))
|
||||||
XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: base + ["compress lzo"]))
|
XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: ["compress lzo"]))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testDHCPOption() throws {
|
func testDHCPOption() throws {
|
||||||
let lines = base + [
|
let lines = [
|
||||||
"dhcp-option DNS 8.8.8.8",
|
"dhcp-option DNS 8.8.8.8",
|
||||||
"dhcp-option DNS6 ffff::1",
|
"dhcp-option DNS6 ffff::1",
|
||||||
"dhcp-option DOMAIN example.com",
|
"dhcp-option DOMAIN example.com",
|
||||||
|
@ -73,8 +71,18 @@ class ConfigurationParserTests: XCTestCase {
|
||||||
XCTAssertEqual(parsed.proxyBypassDomains, ["foo.com", "bar.org", "net.chat"])
|
XCTAssertEqual(parsed.proxyBypassDomains, ["foo.com", "bar.org", "net.chat"])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testRedirectGateway() throws {
|
||||||
|
var parsed: SessionProxy.Configuration
|
||||||
|
|
||||||
|
parsed = try! ConfigurationParser.parsed(fromLines: []).configuration
|
||||||
|
XCTAssertEqual(parsed.routingPolicies, nil)
|
||||||
|
XCTAssertNotEqual(parsed.routingPolicies, [])
|
||||||
|
parsed = try! ConfigurationParser.parsed(fromLines: ["redirect-gateway ipv4 block-local"]).configuration
|
||||||
|
XCTAssertEqual(parsed.routingPolicies, [.IPv4, .IPv6])
|
||||||
|
}
|
||||||
|
|
||||||
func testConnectionBlock() throws {
|
func testConnectionBlock() throws {
|
||||||
let lines = base + ["<connection>", "</connection>"]
|
let lines = ["<connection>", "</connection>"]
|
||||||
XCTAssertThrowsError(try ConfigurationParser.parsed(fromLines: lines))
|
XCTAssertThrowsError(try ConfigurationParser.parsed(fromLines: lines))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue