diff --git a/ProxyApp/ProxyAppDefault.swift b/ProxyApp/ProxyAppDefault.swift index 355b62b..b4dff70 100644 --- a/ProxyApp/ProxyAppDefault.swift +++ b/ProxyApp/ProxyAppDefault.swift @@ -149,8 +149,7 @@ class ProxyAppDefault : ProxyApp { "logLevel" : "debug", "routeVpn" : true, "isConnected" : true, - // The name of the unix group pia whitelists in the firewall - // This may be different when PIA is white-labeled + // The name of the unix group PIA whitelists in the firewall "whitelistGroupName" : "piavpn" ] as [String : Any]) } catch { diff --git a/ProxyApp/ProxyAppGUI.swift b/ProxyApp/ProxyAppGUI.swift index 5b2fa8f..9bf89c4 100644 --- a/ProxyApp/ProxyAppGUI.swift +++ b/ProxyApp/ProxyAppGUI.swift @@ -1,12 +1,11 @@ /** -This is the main of the ProxyApp GUI client, the extension graphical client. -This is a viable way of managing the system extension, -but it's only used during development work. +This is the main of the ProxyApp GUI client, a graphical client for the extension process. +This is a viable way of managing the system extension. +Right now, it's only used during development work. -This GUI is not shipped with PIA desktop client. -The integrated project communicate with the extension -using only the cli client ProxyCLI. -Both share the same functionalities. +This GUI is not shipped with PIA desktop client, +which uses the cli client ProxyCLI. +Both the gui and the cli client share the same functionalities. */ import SwiftUI diff --git a/ProxyExtension/IO/FlowHandler.swift b/ProxyExtension/IO/FlowHandler.swift index 8e29bc7..8b728ce 100644 --- a/ProxyExtension/IO/FlowHandler.swift +++ b/ProxyExtension/IO/FlowHandler.swift @@ -14,6 +14,7 @@ struct SessionConfig { protocol FlowHandlerProtocol { func handleNewFlow(_ flow: Flow, vpnState: VpnState) -> Bool + func startProxySession(flow: Flow, vpnState: VpnState) -> Bool } // Responsible for handling flows, both new flows and pre-existing @@ -50,7 +51,8 @@ final class FlowHandler: FlowHandlerProtocol { } } - private func startProxySession(flow: Flow, vpnState: VpnState) -> Bool { + // temporarly public + public func startProxySession(flow: Flow, vpnState: VpnState) -> Bool { let interface = networkInterfaceFactory.create(interfaceName: vpnState.bindInterface) // Verify we have a valid bindIp - if not, trace it and ignore the flow diff --git a/ProxyExtension/SplitTunnelDNSProxyProvider/SplitTunnelDNSProxyProvider.swift b/ProxyExtension/SplitTunnelDNSProxyProvider/SplitTunnelDNSProxyProvider.swift index f542c17..2daca0a 100644 --- a/ProxyExtension/SplitTunnelDNSProxyProvider/SplitTunnelDNSProxyProvider.swift +++ b/ProxyExtension/SplitTunnelDNSProxyProvider/SplitTunnelDNSProxyProvider.swift @@ -2,11 +2,42 @@ import Foundation import NetworkExtension final class SplitTunnelDNSProxyProvider : NEDNSProxyProvider { - override init() { - super.init() - } - + + public var flowHandler: FlowHandlerProtocol! + public var vpnState: VpnState! + + // The logger + public var logger: LoggerProtocol! + override func startProxy(options:[String: Any]? = nil, completionHandler: @escaping (Error?) -> Void) { + let logLevel: String = options?["logLevel"] as? String ?? "" + let logFile: String = options?["logFile"] as? String ?? "" + + self.logger = self.logger ?? Logger.instance + + // Ensure the logger is initialized first + logger.updateLogger(logLevel: logLevel, logFile: logFile) + + // init just once, set up swiftNIO event loop + self.flowHandler = FlowHandler() + + var options = [ + "bypassApps" : ["/usr/bin/curl", "org.mozilla.firefox"], + "vpnOnlyApps" : [], + "bindInterface" : "en0", + "serverAddress" : "127.0.0.1", + "logFile" : "/tmp/STProxy.log", + "logLevel" : "debug", + "routeVpn" : true, + "isConnected" : true, + "whitelistGroupName" : "piavpn" + ] as [String : Any] + guard let vpnState2 = VpnStateFactory.create(options: options) else { + log(.error, "provided incorrect list of options. They might be missing or an incorrect type") + return + } + vpnState = vpnState2 + completionHandler(nil) } @@ -14,9 +45,19 @@ final class SplitTunnelDNSProxyProvider : NEDNSProxyProvider { completionHandler() } - // Be aware that by returning false in NEDNSProxyProvider handleNewFlow(), - // the flow is discarded and the connection is closed + // Be aware that by returning false in NEDNSProxyProvider handleNewFlow(), + // the flow is discarded and the connection is closed. + // This is similar to how NEAppProxyProvider works, compared to what we use + // for traffic Split Tunnel which is NETransparentProxyProvider. + // This means that we need to handle ALL DNS requests when DNS Split Tunnel + // is enabled, even for non-managed apps. override func handleNewFlow(_ flow: NEAppProxyFlow) -> Bool { - return false + var appName = flow.sourceAppSigningIdentifier + if appName == "com.apple.nslookup" || appName == "com.apple.curl" { + flowHandler.startProxySession(flow: flow, vpnState: vpnState) + return true + } else { + return false + } } } diff --git a/ProxyTests/Mocks/MockFlowHandler.swift b/ProxyTests/Mocks/MockFlowHandler.swift index b5fd608..634313a 100644 --- a/ProxyTests/Mocks/MockFlowHandler.swift +++ b/ProxyTests/Mocks/MockFlowHandler.swift @@ -11,4 +11,9 @@ final class MockFlowHandler: FlowHandlerProtocol, Mock { record(args: [flow, vpnState]) return true } + + func startProxySession(flow: Flow, vpnState: VpnState) -> Bool { + record(args: [flow, vpnState]) + return true + } }