From 6f12f5fffbe9f4eeb4a94e1b3d22b6cc9a3603a5 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 15 Apr 2021 19:21:13 +0200 Subject: Implement VPN http proxy support (Android 10+) (closes #1263) Use dhcp-option PROXY_HTTP 1.2.3.4 8080 or push "dhcp-option PROXY_HTTP 1.2.3.4 8080" from a server to use the feature. --- .../de/blinkt/openvpn/core/OpenVPNService.java | 45 ++++++++++++++++++---- .../openvpn/core/OpenVpnManagementThread.java | 8 ++++ main/src/main/res/values/strings.xml | 1 + .../de/blinkt/openvpn/core/OpenVPNThreadv3.java | 13 +++++++ 4 files changed, 60 insertions(+), 7 deletions(-) (limited to 'main') 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 23940760..d37f34ed 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -21,6 +21,7 @@ import android.content.pm.ShortcutManager; import android.content.res.Configuration; import android.content.res.Resources; import android.net.ConnectivityManager; +import android.net.ProxyInfo; import android.net.Uri; import android.net.VpnService; import android.os.Build; @@ -141,6 +142,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac private Handler guiHandler; private Toast mlastToast; private Runnable mOpenVPNThread; + private ProxyInfo mProxyInfo; // From: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java public static String humanReadableByteCount(long bytes, boolean speed, Resources res) { @@ -744,6 +746,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac cfg += "dns: " + TextUtils.join("|", mDnslist); cfg += "domain: " + mDomain; cfg += "mtu: " + mMtu; + cfg += "proxyInfo: " + mProxyInfo; return cfg; } @@ -869,20 +872,18 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } int ipv4len; - if (mLocalIP!=null) { - ipv4len=mLocalIP.len; - ipv4info=mLocalIP.mIp; + if (mLocalIP != null) { + ipv4len = mLocalIP.len; + ipv4info = mLocalIP.mIp; } else { ipv4len = -1; } - if (mLocalIPv6!=null) - { + if (mLocalIPv6 != null) { ipv6info = mLocalIPv6; } - if ((!mRoutes.getNetworks(false).isEmpty() || !mRoutesv6.getNetworks(false).isEmpty()) && isLockdownEnabledCompat()) - { + if ((!mRoutes.getNetworks(false).isEmpty() || !mRoutesv6.getNetworks(false).isEmpty()) && isLockdownEnabledCompat()) { VpnStatus.logInfo("VPN lockdown enabled (do not allow apps to bypass VPN) enabled. Route exclusion will not allow apps to bypass VPN (e.g. bypass VPN for local networks)"); } @@ -890,6 +891,9 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac VpnStatus.logInfo(R.string.dns_server_info, TextUtils.join(", ", mDnslist), mDomain); VpnStatus.logInfo(R.string.routes_info_incl, TextUtils.join(", ", mRoutes.getNetworks(true)), TextUtils.join(", ", mRoutesv6.getNetworks(true))); VpnStatus.logInfo(R.string.routes_info_excl, TextUtils.join(", ", mRoutes.getNetworks(false)), TextUtils.join(", ", mRoutesv6.getNetworks(false))); + 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.LOLLIPOP) { setAllowedVpnPackages(builder); @@ -919,6 +923,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac if (mDnslist.size() == 0) VpnStatus.logInfo(R.string.warn_no_dns); + setHttpProxy(builder); + mLastTunCfg = getTunConfigString(); // Reset information @@ -928,6 +934,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac mLocalIP = null; mLocalIPv6 = null; mDomain = null; + mProxyInfo = null; builder.setConfigureIntent(getGraphPendingIntent()); @@ -948,6 +955,17 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } + private void setHttpProxy(Builder builder) { + if (mProxyInfo != null && Build.VERSION.SDK_INT >= 29) + { + builder.setHttpProxy(mProxyInfo); + } + else if (mProxyInfo != null) + { + VpnStatus.logWarning("HTTP Proxy needs Android 10 or later."); + } + } + private boolean isLockdownEnabledCompat() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return isLockdownEnabled(); @@ -1068,6 +1086,17 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac mRoutes.addIP(route, include); } + public boolean addHttpProxy(String proxy, int port) { + try { + mProxyInfo = ProxyInfo.buildDirectProxy(proxy, port); + } catch (Exception e) + { + VpnStatus.logError("Could not set proxy" + e.getLocalizedMessage()); + return false; + } + return true; + } + public void addRoute(String dest, String mask, String gateway, String device) { CIDRIP route = new CIDRIP(dest, mask); boolean include = isAndroidTunDevice(device); @@ -1342,4 +1371,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac mNotificationManager.notify(notificationId, notification); } + + } diff --git a/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java b/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java index 305ab2a8..8228ccc2 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java @@ -611,6 +611,14 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { status = "cancel"; // This not nice or anything but setFileDescriptors accepts only FilDescriptor class :( + break; + case "HTTPPROXY": + String[] httpproxy = extra.split(" "); + if (httpproxy.length == 2) { + mOpenVPNService.addHttpProxy(httpproxy[0], Integer.parseInt(httpproxy[1])); + } else { + VpnStatus.logError("Unrecognized HTTPPROXY cmd: " + Arrays.toString(httpproxy) + " | " + argument); + } break; default: Log.e(TAG, "Unknown needok command " + argument); diff --git a/main/src/main/res/values/strings.xml b/main/src/main/res/values/strings.xml index fc4f5a74..9a8e5958 100755 --- a/main/src/main/res/values/strings.xml +++ b/main/src/main/res/values/strings.xml @@ -502,5 +502,6 @@ There are some variation of this message depending on the exact situation. They all have in common that server and client could not agree on a common cipher. The main reasons are: <ul><li> You are still relying on the fact that OpenVPN 2.4 and older allowed BF-CBC in the default configuration (if no --cipher was set). OpenVPN 2.5 does not allow it per default anymore since it is a <a href="https://community.openvpn.net/openvpn/wiki/SWEET32">broken/outdated cipher</a>.</li><li>The server runs OpenVPN 2.3 (or even older) with --enable-small (at least 4-5 year old OpenVPN)</li><li>Broken configuration (e.g., mismatching data-ciphers on client and server)</li> <p> The <a href=\"https://github.com/OpenVPN/openvpn/blob/master/doc/man-sections/cipher-negotiation.rst\">OpenVPN manual section on cipher negotiation</a> explains the different scenarios of cipher negotiation very well and what to do in these situation.<p>TP-Link devices use a at least 5 year old OpenVPN 2.3.x version (possibly older) on their devices, even in the 2019/2020 models.<p>Last but not least, there is a popular VPN provider that has a broken server that always says it is using \'BF-CBC\' because its developer thought it would be a good idea to create a proprietary cipher negotiation patch that is incompatible with standard OpenVPN.<p>In summary: all sane configurations should not get these errors. But (apart from the broken VPN provider\'s server) the client can be persuaded to still connect (fixing the sympton and not the real problem). Check peer certificate fingerprint (Enter the SHA256 fingerprint of the server certificate(s)) + HTTP Proxy: %1$s %2$d 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 c250dc5e..419f49e2 100644 --- a/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java +++ b/main/src/ui/java/de/blinkt/openvpn/core/OpenVPNThreadv3.java @@ -107,6 +107,18 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable return true; } + @Override + public boolean tun_builder_set_proxy_http(String host, int port) + { + return mService.addHttpProxy(host, port); + } + + @Override + public boolean tun_builder_set_proxy_https(String host, int port) + { + return false; + } + @Override public int tun_builder_establish() { return mService.openTun().detachFd(); @@ -271,6 +283,7 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable public void setPauseCallback(PausedStateCallback callback) { } + @Override public void sendCRResponse(String response) { post_cc_msg("CR_RESPONSE," + response + "\n"); -- cgit v1.2.3