From 224a76ac58c072282305c736f470e9dc77418025 Mon Sep 17 00:00:00 2001 From: Davide De Rosa Date: Thu, 25 Apr 2019 13:06:22 +0200 Subject: [PATCH] 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. --- .../Sources/Core/ConfigurationParser.swift | 44 +++++++++++++++++++ .../Core/SessionProxy+Configuration.swift | 20 ++++++++- TunnelKitTests/ConfigurationParserTests.swift | 30 ++++++++----- 3 files changed, 82 insertions(+), 12 deletions(-) diff --git a/TunnelKit/Sources/Core/ConfigurationParser.swift b/TunnelKit/Sources/Core/ConfigurationParser.swift index fbfe683..22de246 100644 --- a/TunnelKit/Sources/Core/ConfigurationParser.swift +++ b/TunnelKit/Sources/Core/ConfigurationParser.swift @@ -96,6 +96,8 @@ public class ConfigurationParser { static let proxyBypass = NSRegularExpression("^dhcp-option +PROXY_BYPASS +.+") + static let redirectGateway = NSRegularExpression("^redirect-gateway.*") + // MARK: Unsupported // static let fragment = NSRegularExpression("^fragment +\\d+") @@ -120,6 +122,26 @@ public class ConfigurationParser { 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. public struct Result { @@ -204,6 +226,7 @@ public class ConfigurationParser { var optHTTPProxy: Proxy? var optHTTPSProxy: Proxy? var optProxyBypass: [String]? + var optRedirectGateway: Set? log.verbose("Configuration file:") for line in lines { @@ -515,6 +538,22 @@ public class ConfigurationParser { optProxyBypass = $0 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.proxyBypassDomains = optProxyBypass + // FIXME: only redirects all traffic until --redirect-gateway is properly interpreted + if let _ = optRedirectGateway { + sessionBuilder.routingPolicies = [.IPv4, .IPv6] + } + // return Result( diff --git a/TunnelKit/Sources/Core/SessionProxy+Configuration.swift b/TunnelKit/Sources/Core/SessionProxy+Configuration.swift index de1419a..e90381a 100644 --- a/TunnelKit/Sources/Core/SessionProxy+Configuration.swift +++ b/TunnelKit/Sources/Core/SessionProxy+Configuration.swift @@ -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: private struct Fallback { static let cipher: Cipher = .aes128cbc @@ -238,6 +248,9 @@ extension SessionProxy { /// The list of domains not passing through the proxy. public var proxyBypassDomains: [String]? + /// Policies for redirecting traffic through the VPN gateway. + public var routingPolicies: [RoutingPolicy]? + /// :nodoc: public init() { } @@ -272,7 +285,8 @@ extension SessionProxy { searchDomain: searchDomain, httpProxy: httpProxy, httpsProxy: httpsProxy, - proxyBypassDomains: proxyBypassDomains + proxyBypassDomains: proxyBypassDomains, + routingPolicies: routingPolicies ) } @@ -369,6 +383,9 @@ extension SessionProxy { /// - Seealso: `SessionProxy.ConfigurationBuilder.proxyBypassDomains` public var proxyBypassDomains: [String]? + /// - Seealso: `SessionProxy.ConfigurationBuilder.routingPolicies` + public var routingPolicies: [RoutingPolicy]? + // MARK: Shortcuts /// :nodoc: @@ -422,6 +439,7 @@ extension SessionProxy.Configuration { builder.httpProxy = httpProxy builder.httpsProxy = httpsProxy builder.proxyBypassDomains = proxyBypassDomains + builder.routingPolicies = routingPolicies return builder } } diff --git a/TunnelKitTests/ConfigurationParserTests.swift b/TunnelKitTests/ConfigurationParserTests.swift index 7304490..683a735 100644 --- a/TunnelKitTests/ConfigurationParserTests.swift +++ b/TunnelKitTests/ConfigurationParserTests.swift @@ -27,8 +27,6 @@ import XCTest import TunnelKit class ConfigurationParserTests: XCTestCase { - let base: [String] = ["", "", "remote 1.2.3.4"] - override func setUp() { super.setUp() // 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 func testCompression() throws { -// XCTAssertNotNil(try OptionsBundle.parsed(fromLines: base + ["comp-lzo"]).warning) - XCTAssertNil(try ConfigurationParser.parsed(fromLines: base + ["comp-lzo"]).warning) - XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: base + ["comp-lzo no"])) - XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: base + ["comp-lzo yes"])) -// XCTAssertThrowsError(try ConfigurationParser.parsed(fromLines: base + ["comp-lzo yes"])) +// XCTAssertNotNil(try OptionsBundle.parsed(fromLines: ["comp-lzo"]).warning) + XCTAssertNil(try ConfigurationParser.parsed(fromLines: ["comp-lzo"]).warning) + XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: ["comp-lzo no"])) + XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: ["comp-lzo yes"])) +// XCTAssertThrowsError(try ConfigurationParser.parsed(fromLines: ["comp-lzo yes"])) - XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: base + ["compress"])) - XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: base + ["compress lzo"])) + XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: ["compress"])) + XCTAssertNoThrow(try ConfigurationParser.parsed(fromLines: ["compress lzo"])) } func testDHCPOption() throws { - let lines = base + [ + let lines = [ "dhcp-option DNS 8.8.8.8", "dhcp-option DNS6 ffff::1", "dhcp-option DOMAIN example.com", @@ -73,8 +71,18 @@ class ConfigurationParserTests: XCTestCase { 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 { - let lines = base + ["", ""] + let lines = ["", ""] XCTAssertThrowsError(try ConfigurationParser.parsed(fromLines: lines)) }