From b0dcae3586cee83c2531270c923a8cf77ef41c22 Mon Sep 17 00:00:00 2001 From: albexk Date: Tue, 12 Dec 2023 22:48:18 +0300 Subject: [PATCH] Disable global split tunneling if a non-default route exists in the Wireguard configuration --- client/android/awg/src/main/kotlin/Awg.kt | 2 +- .../amnezia/vpn/protocol/openvpn/OpenVpn.kt | 2 +- .../protocolApi/src/main/kotlin/Protocol.kt | 8 ++++++- .../src/main/kotlin/ProtocolConfig.kt | 15 ++++++++---- .../vpn/protocol/wireguard/Wireguard.kt | 24 +++++++++---------- 5 files changed, 31 insertions(+), 20 deletions(-) diff --git a/client/android/awg/src/main/kotlin/Awg.kt b/client/android/awg/src/main/kotlin/Awg.kt index 29b39705..c21caaff 100644 --- a/client/android/awg/src/main/kotlin/Awg.kt +++ b/client/android/awg/src/main/kotlin/Awg.kt @@ -65,7 +65,7 @@ class Awg : Wireguard() { val configData = parseConfigData(configDataJson.getString("config")) return AwgConfig.build { configWireguard(configData) - configSplitTunnel(config) + configSplitTunneling(config) configData["Jc"]?.let { setJc(it.toInt()) } configData["Jmin"]?.let { setJmin(it.toInt()) } configData["Jmax"]?.let { setJmax(it.toInt()) } diff --git a/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt b/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt index ba7df01a..34069a0d 100644 --- a/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt +++ b/client/android/openvpn/src/main/kotlin/org/amnezia/vpn/protocol/openvpn/OpenVpn.kt @@ -87,7 +87,7 @@ open class OpenVpn : Protocol() { addRoute(InetNetwork("0.0.0.0", 0)) addRoute(InetNetwork("::", 0)) } - configSplitTunnel(config) + configSplitTunneling(config) } scope.launch { diff --git a/client/android/protocolApi/src/main/kotlin/Protocol.kt b/client/android/protocolApi/src/main/kotlin/Protocol.kt index ce3c13f5..b2c52e9a 100644 --- a/client/android/protocolApi/src/main/kotlin/Protocol.kt +++ b/client/android/protocolApi/src/main/kotlin/Protocol.kt @@ -43,7 +43,13 @@ abstract class Protocol { abstract fun reconnectVpn(vpnBuilder: Builder) - protected fun ProtocolConfig.Builder.configSplitTunnel(config: JSONObject) { + protected fun ProtocolConfig.Builder.configSplitTunneling(config: JSONObject) { + if (!allowSplitTunneling) { + Log.i(TAG, "Global address split tunneling is prohibited, " + + "only tunneling from the protocol config is used") + return + } + val splitTunnelType = config.optInt("splitTunnelType") if (splitTunnelType == SPLIT_TUNNEL_DISABLE) return val splitTunnelSites = config.getJSONArray("splitTunnelSites") diff --git a/client/android/protocolApi/src/main/kotlin/ProtocolConfig.kt b/client/android/protocolApi/src/main/kotlin/ProtocolConfig.kt index 7050e79f..a4d7683e 100644 --- a/client/android/protocolApi/src/main/kotlin/ProtocolConfig.kt +++ b/client/android/protocolApi/src/main/kotlin/ProtocolConfig.kt @@ -51,20 +51,23 @@ open class ProtocolConfig protected constructor( internal var blockingMode: Boolean = blockingMode private set + internal var allowSplitTunneling: Boolean = true + private set + open var mtu: Int = 0 protected set fun addAddress(addr: InetNetwork) = apply { this.addresses += addr } - fun addAddresses(addresses: List) = apply { this.addresses += addresses } + fun addAddresses(addresses: Collection) = apply { this.addresses += addresses } fun clearAddresses() = apply { this.addresses.clear() } fun addDnsServer(dnsServer: InetAddress) = apply { this.dnsServers += dnsServer } - fun addDnsServers(dnsServers: List) = apply { this.dnsServers += dnsServers } + fun addDnsServers(dnsServers: Collection) = apply { this.dnsServers += dnsServers } fun setSearchDomain(domain: String) = apply { this.searchDomain = domain } fun addRoute(route: InetNetwork) = apply { this.routes += route } - fun addRoutes(routes: List) = apply { this.routes += routes } + fun addRoutes(routes: Collection) = apply { this.routes += routes } fun removeRoute(route: InetNetwork) = apply { this.routes.remove(route) } fun clearRoutes() = apply { this.routes.clear() } @@ -72,10 +75,10 @@ open class ProtocolConfig protected constructor( fun excludeRoute(route: InetNetwork) = apply { this.excludedRoutes += route } @RequiresApi(Build.VERSION_CODES.TIRAMISU) - fun excludeRoutes(routes: List) = apply { this.excludedRoutes += routes } + fun excludeRoutes(routes: Collection) = apply { this.excludedRoutes += routes } fun excludeApplication(application: String) = apply { this.excludedApplications += application } - fun excludeApplications(applications: List) = apply { this.excludedApplications += applications } + fun excludeApplications(applications: Collection) = apply { this.excludedApplications += applications } @RequiresApi(Build.VERSION_CODES.Q) fun setHttpProxy(httpProxy: ProxyInfo) = apply { this.httpProxy = httpProxy } @@ -84,6 +87,8 @@ open class ProtocolConfig protected constructor( fun setBlockingMode(blockingMode: Boolean) = apply { this.blockingMode = blockingMode } + fun disableSplitTunneling() = apply { this.allowSplitTunneling = false } + fun setMtu(mtu: Int) = apply { this.mtu = mtu } private fun validate() { diff --git a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt index 5bf84139..c676401d 100644 --- a/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt +++ b/client/android/wireguard/src/main/kotlin/org/amnezia/vpn/protocol/wireguard/Wireguard.kt @@ -94,17 +94,7 @@ open class Wireguard : Protocol() { val configData = parseConfigData(configDataJson.getString("config")) return WireguardConfig.build { configWireguard(configData) - // Default Wireguard routes (0.0.0.0/0, ::/0) will be removed, - // allowed routes from the Wireguard configuration will be merged - // with allowed routes from the split tunneling configuration. - // - // Excluded routes from the split tunneling configuration can overwrite - // allowed routes from the Wireguard configuration (two routes are equal - // if they have the same address and prefix). - // - // If multiple routes match the packet destination, - // route with the longest prefix takes precedence - configSplitTunnel(config) + configSplitTunneling(config) } } @@ -113,9 +103,19 @@ open class Wireguard : Protocol() { configData["DNS"]?.split(",")?.map { dns -> parseInetAddress(dns.trim()) }?.forEach(::addDnsServer) + + val defRoutes = listOf( + InetNetwork("0.0.0.0", 0), + InetNetwork("::", 0) + ) + val routes = hashSetOf() configData["AllowedIPs"]?.split(",")?.map { route -> InetNetwork.parse(route.trim()) - }?.forEach(::addRoute) + }?.forEach(routes::add) + // if the allowed IPs list contains at least one non-default route, disable global split tunneling + if (!routes.all { defRoutes.contains(it) }) disableSplitTunneling() + addRoutes(routes) + configData["MTU"]?.let { setMtu(it.toInt()) } configData["Endpoint"]?.let { setEndpoint(InetEndpoint.parse(it)) } configData["PersistentKeepalive"]?.let { setPersistentKeepalive(it.toInt()) }