From 2ea430e30bb5078d52c783018eeb364e6e108138 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Tue, 2 Aug 2022 01:25:40 +0200 Subject: Use route exclusion API available in API 33 --- main/build.gradle.kts | 5 +- main/src/main/cpp/CMakeLists.txt | 2 +- main/src/main/cpp/openvpn3 | 2 +- .../java/de/blinkt/openvpn/core/NetworkSpace.java | 30 +++++++- .../de/blinkt/openvpn/core/OpenVPNService.java | 83 +++++++++++++++------- .../de/blinkt/openvpn/core/OpenVPNThreadv3.java | 1 + 6 files changed, 92 insertions(+), 31 deletions(-) (limited to 'main') diff --git a/main/build.gradle.kts b/main/build.gradle.kts index 8ca1f1a9..ac2eeae0 100644 --- a/main/build.gradle.kts +++ b/main/build.gradle.kts @@ -13,13 +13,13 @@ plugins { } android { - compileSdk = 32 + compileSdk = 33 ndkVersion = "24.0.8215888" defaultConfig { minSdk = 21 - targetSdk = 32 + targetSdk = 33 versionCode = 193 versionName = "0.7.38" externalNativeBuild { @@ -140,6 +140,7 @@ fun registerGenTask(variantName: String, variantDirName: String): File { } commandLine(listOf(swigcmd, "-outdir", genDir, "-outcurrentdir", "-c++", "-java", "-package", "net.openvpn.ovpn3", "-Isrc/main/cpp/openvpn3/client", "-Isrc/main/cpp/openvpn3/", + "-DOPENVPN_PLATFORM_ANDROID", "-o", "${genDir}/ovpncli_wrap.cxx", "-oh", "${genDir}/ovpncli_wrap.h", "src/main/cpp/openvpn3/client/ovpncli.i")) inputs.files( "src/main/cpp/openvpn3/client/ovpncli.i") diff --git a/main/src/main/cpp/CMakeLists.txt b/main/src/main/cpp/CMakeLists.txt index 0921e807..c0222151 100644 --- a/main/src/main/cpp/CMakeLists.txt +++ b/main/src/main/cpp/CMakeLists.txt @@ -45,6 +45,7 @@ if (NOT ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} MATCHES "build/intermediates/cmake/.*s -c++ -java -package net.openvpn.ovpn3 -outcurrentdir + -DOPENVPN_PLATFORM_ANDROID -I${CMAKE_SOURCE_DIR}/openvpn3/client -I${CMAKE_SOURCE_DIR}/openvpn3 ${CMAKE_SOURCE_DIR}/openvpn3/client/ovpncli.i) @@ -92,7 +93,6 @@ if (NOT ${CMAKE_LIBRARY_OUTPUT_DIRECTORY} MATCHES "build/intermediates/cmake/.*s -DASIO_STANDALONE -DUSE_ASIO -DGIT_VERSION_STRING=\"${OPENVPN3_GIT}\" - -DNO_ROUTE_EXCLUDE_EMULATION -DOPENVPN_SHOW_SESSION_TOKEN -DOPENSSL_API_COMPAT=0x10200000L -DOPENVPN_ALLOW_INSECURE_CERTPROFILE diff --git a/main/src/main/cpp/openvpn3 b/main/src/main/cpp/openvpn3 index 9f02ce16..a6296185 160000 --- a/main/src/main/cpp/openvpn3 +++ b/main/src/main/cpp/openvpn3 @@ -1 +1 @@ -Subproject commit 9f02ce1670f75d8f3b9eb903394368fee53cd056 +Subproject commit a6296185ec5d6f604ed2c66a3e1c81ff99e387f9 diff --git a/main/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java b/main/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java index 5876ead5..9c8cf363 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java +++ b/main/src/main/java/de/blinkt/openvpn/core/NetworkSpace.java @@ -5,11 +5,17 @@ package de.blinkt.openvpn.core; -import android.os.Build; +import android.net.IpPrefix; + import androidx.annotation.NonNull; +import java.lang.reflect.Array; import java.math.BigInteger; +import java.net.Inet4Address; import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Arrays; import java.util.Collection; import java.util.Locale; import java.util.PriorityQueue; @@ -203,6 +209,28 @@ public class NetworkSpace { return a && b; } + + public IpPrefix getPrefix() throws UnknownHostException { + if (isV4){ + /* add 0x01 00 00 00 00, so that all representations are 5 byte otherwise + /* numbers that are above 0x7fffffff get a leading 0x00 byte to not be negative + and small number 1-3 bytes*/ + byte[] ipBytes = netAddress.add(BigInteger.valueOf(0x0100000000L)).toByteArray(); + ipBytes = Arrays.copyOfRange(ipBytes, 1, 5); + + InetAddress inet4addr = Inet4Address.getByAddress(ipBytes); + return new IpPrefix(inet4addr, networkMask); + } + else + { + /* same dance for IPv6 */ + byte[] ipBytes = netAddress.add(BigInteger.ONE.shiftLeft(128)).toByteArray(); + ipBytes = Arrays.copyOfRange(ipBytes, 1, 17); + + InetAddress inet6addr = Inet6Address.getByAddress(ipBytes); + return new IpPrefix(inet6addr, networkMask); + } + } } diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java index 8d8ea145..d3de35f9 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -5,9 +5,11 @@ package de.blinkt.openvpn.core; +import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED; +import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; +import static de.blinkt.openvpn.core.NetworkSpace.IpAddress; + import android.Manifest.permission; -import android.annotation.TargetApi; -import android.app.Activity; import android.app.Notification; import android.app.NotificationManager; import android.app.PendingIntent; @@ -21,6 +23,7 @@ import android.content.pm.ShortcutManager; import android.content.res.Configuration; import android.content.res.Resources; import android.net.ConnectivityManager; +import android.net.IpPrefix; import android.net.ProxyInfo; import android.net.Uri; import android.net.VpnService; @@ -62,10 +65,6 @@ import de.blinkt.openvpn.api.ExternalAppDatabase; import de.blinkt.openvpn.core.VpnStatus.ByteCountListener; import de.blinkt.openvpn.core.VpnStatus.StateListener; -import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_CONNECTED; -import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT; -import static de.blinkt.openvpn.core.NetworkSpace.IpAddress; - public class OpenVPNService extends VpnService implements StateListener, Callback, ByteCountListener, IOpenVPNServiceInternal { public static final String START_SERVICE = "de.blinkt.openvpn.START_SERVICE"; public static final String START_SERVICE_STICKY = "de.blinkt.openvpn.START_SERVICE_STICKY"; @@ -813,26 +812,12 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } } - IpAddress multicastRange = new IpAddress(new CIDRIP("224.0.0.0", 3), true); - - for (IpAddress route : positiveIPv4Routes) { - try { - if (multicastRange.containsNet(route)) - VpnStatus.logDebug(R.string.ignore_multicast_route, route.toString()); - else - builder.addRoute(route.getIPv4Address(), route.networkMask); - } catch (IllegalArgumentException ia) { - VpnStatus.logError(getString(R.string.route_rejected) + route + " " + ia.getLocalizedMessage()); - } - } - - for (IpAddress route6 : positiveIPv6Routes) { - try { - builder.addRoute(route6.getIPv6Address(), route6.networkMask); - } catch (IllegalArgumentException ia) { - VpnStatus.logError(getString(R.string.route_rejected) + route6 + " " + ia.getLocalizedMessage()); - } + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { + installRoutesExcluded(builder, mRoutes); + installRoutesExcluded(builder, mRoutesv6); + } else { + installRoutesPostiveOnly(builder, positiveIPv4Routes, positiveIPv6Routes); } @@ -872,7 +857,10 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac if (mProxyInfo != null) { VpnStatus.logInfo(R.string.proxy_info, mProxyInfo.getHost(), mProxyInfo.getPort()); } - VpnStatus.logDebug(R.string.routes_debug, TextUtils.join(", ", positiveIPv4Routes), TextUtils.join(", ", positiveIPv6Routes)); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) { + /* On Tiramisu we install the routes exactly like promised */ + VpnStatus.logDebug(R.string.routes_debug, TextUtils.join(", ", positiveIPv4Routes), TextUtils.join(", ", positiveIPv6Routes)); + } setAllowedVpnPackages(builder); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { // VPN always uses the default network @@ -928,6 +916,49 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } + private void installRoutesExcluded(Builder builder, NetworkSpace routes) + { + for(IpAddress ipIncl: routes.getNetworks(true)) + { + try { + builder.addRoute(ipIncl.getPrefix()); + } catch (UnknownHostException|IllegalArgumentException ia) { + VpnStatus.logError(getString(R.string.route_rejected) + ipIncl + " " + ia.getLocalizedMessage()); + } + } + for(IpAddress ipExcl: routes.getNetworks(false)) + { + try { + builder.excludeRoute(ipExcl.getPrefix()); + } catch (UnknownHostException|IllegalArgumentException ia) { + VpnStatus.logError(getString(R.string.route_rejected) + ipExcl + " " + ia.getLocalizedMessage()); + } + } + } + + private void installRoutesPostiveOnly(Builder builder, Collection positiveIPv4Routes, Collection positiveIPv6Routes) { + IpAddress multicastRange = new IpAddress(new CIDRIP("224.0.0.0", 3), true); + + for (IpAddress route : positiveIPv4Routes) { + try { + if (multicastRange.containsNet(route)) + VpnStatus.logDebug(R.string.ignore_multicast_route, route.toString()); + else + builder.addRoute(route.getIPv4Address(), route.networkMask); + } catch (IllegalArgumentException ia) { + VpnStatus.logError(getString(R.string.route_rejected) + route + " " + ia.getLocalizedMessage()); + } + } + + for (IpAddress route6 : positiveIPv6Routes) { + try { + builder.addRoute(route6.getIPv6Address(), route6.networkMask); + } catch (IllegalArgumentException ia) { + VpnStatus.logError(getString(R.string.route_rejected) + route6 + " " + ia.getLocalizedMessage()); + } + } + } + private void setHttpProxy(Builder builder) { if (mProxyInfo != null && Build.VERSION.SDK_INT >= 29) { builder.setHttpProxy(mProxyInfo); diff --git a/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java b/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java index 0cbd7ce5..75093e14 100644 --- a/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java +++ b/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java @@ -195,6 +195,7 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable boolean retryOnAuthFailed = mVp.mAuthRetry == AUTH_RETRY_NOINTERACT; config.setRetryOnAuthFailed(retryOnAuthFailed); config.setEnableLegacyAlgorithms(mVp.mUseLegacyProvider); + config.setEnableRouteEmulation(false); if (mVp.mCompatMode > 0 && mVp.mCompatMode < 20500) config.setEnableNonPreferredDCAlgorithms(true); if (!TextUtils.isEmpty(mVp.mTlSCertProfile)) -- cgit v1.2.3