From 6d364856a35661e7dad414d38dc34c8cbd8b5985 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Wed, 4 May 2022 13:21:26 +0200 Subject: Remove API support for API < 21 and lower (Lollipop) Supporting just APIs 19 and 20 keeps a lot of code and the number of users is extremely small. --- main/build.gradle.kts | 5 +- main/src/main/cpp/CMakeLists.txt | 2 +- main/src/main/cpp/ovpnutil/jniglue.c | 5 - main/src/main/cpp/ovpnutil/scan_ifs.c | 109 ------- .../blinkt/openvpn/core/ICSOpenVPNApplication.java | 10 +- .../openvpn/core/LollipopDeviceStateListener.java | 4 - .../java/de/blinkt/openvpn/core/NetworkUtils.java | 58 +--- .../de/blinkt/openvpn/core/OpenVPNService.java | 48 +-- .../openvpn/core/OpenVpnManagementThread.java | 11 +- .../java/de/blinkt/openvpn/core/PRNGFixes.java | 339 --------------------- .../de/blinkt/openvpn/core/VPNLaunchHelper.java | 14 +- main/src/main/res/xml/app_restrictions.xml | 4 +- main/src/ui/AndroidManifest.xml | 4 +- 13 files changed, 36 insertions(+), 577 deletions(-) delete mode 100644 main/src/main/cpp/ovpnutil/scan_ifs.c delete mode 100644 main/src/main/java/de/blinkt/openvpn/core/PRNGFixes.java diff --git a/main/build.gradle.kts b/main/build.gradle.kts index 181cf84c..41a69ed9 100644 --- a/main/build.gradle.kts +++ b/main/build.gradle.kts @@ -18,7 +18,7 @@ android { ndkVersion = "24.0.8215888" defaultConfig { - minSdk = 19 + minSdk = 21 targetSdk = 32 versionCode = 189 versionName = "0.7.34" @@ -188,8 +188,7 @@ dependencies { dependencies.add("uiImplementation", "androidx.webkit:webkit:1.4.0") dependencies.add("uiImplementation", "androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.1") dependencies.add("uiImplementation", "androidx.lifecycle:lifecycle-runtime-ktx:2.4.1") - dependencies.add("uiImplementation", "androidx.multidex:multidex:2.0.1") - + testImplementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.21") testImplementation("junit:junit:4.13.2") testImplementation("org.mockito:mockito-core:3.9.0") diff --git a/main/src/main/cpp/CMakeLists.txt b/main/src/main/cpp/CMakeLists.txt index 72425792..d1f809fb 100644 --- a/main/src/main/cpp/CMakeLists.txt +++ b/main/src/main/cpp/CMakeLists.txt @@ -97,7 +97,7 @@ else () message("Not budiling OpenVPN for output dir ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}") endif () -add_library(ovpnutil SHARED ovpnutil/jniglue.c ovpnutil/scan_ifs.c) +add_library(ovpnutil SHARED ovpnutil/jniglue.c) target_compile_definitions(ovpnutil PRIVATE -DTARGET_ARCH_ABI=\"${ANDROID_ABI}\" -DOPENVPN2_GIT_REVISION=\"${OPENVPN2_GIT}\" -DOPENVPN3_GIT_REVISION=\"${OPENVPN3_GIT}\" diff --git a/main/src/main/cpp/ovpnutil/jniglue.c b/main/src/main/cpp/ovpnutil/jniglue.c index 264b18a8..65a13406 100644 --- a/main/src/main/cpp/ovpnutil/jniglue.c +++ b/main/src/main/cpp/ovpnutil/jniglue.c @@ -19,11 +19,6 @@ void android_openvpn_log(int level,const char* prefix,const char* prefix_sep,con __android_log_print(ANDROID_LOG_DEBUG,"openvpn","%s%s%s",prefix,prefix_sep,m1); } -void Java_de_blinkt_openvpn_core_NativeUtils_jniclose(JNIEnv *env,jclass jo, jint fd) -{ - int ret = close(fd); -} - //! Hack to get the current installed ABI of the libraries. See also https://github.com/schwabe/ics-openvpn/issues/391 jstring Java_de_blinkt_openvpn_core_NativeUtils_getJNIAPI(JNIEnv *env, jclass jo) diff --git a/main/src/main/cpp/ovpnutil/scan_ifs.c b/main/src/main/cpp/ovpnutil/scan_ifs.c deleted file mode 100644 index 85021d88..00000000 --- a/main/src/main/cpp/ovpnutil/scan_ifs.c +++ /dev/null @@ -1,109 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "jniglue.h" - -jobjectArray Java_de_blinkt_openvpn_core_NativeUtils_getIfconfig(JNIEnv* env) -{ - int sd; - if ((sd = socket (AF_INET, SOCK_DGRAM, 0)) < 0) { - __android_log_print(ANDROID_LOG_DEBUG, "openvpn", "Opening socket for intface get failed"); - //jniThrowException(env, "java/lang/IllegalArgumentException", "Opening socket for intface get failed"); - return NULL; - } - - struct ifreq ifs[23]; - - struct ifconf ifc; - ifc.ifc_req = ifs; - ifc.ifc_len = sizeof (ifs); - - if (ioctl (sd, SIOCGIFCONF, &ifc) < 0) { - __android_log_print(ANDROID_LOG_DEBUG, "openvpn", "IOCTL for intface get failed"); - //jniThrowException(env, "java/lang/IllegalArgumentException", "IOTCL socket for intface get failed"); - close(sd); - return NULL; - } - - - - - char buf[NI_MAXHOST]; - - int ji=0; - - /* - jtmp = (*env)->NewStringUTF(env, "HALLO WELT"); - (*env)->SetObjectArrayElement(env, ret, ji++, jtmp); - */ - - size_t num_intf=ifc.ifc_len / sizeof(struct ifreq); - jobjectArray ret= (jobjectArray) (*env)->NewObjectArray(env, num_intf*3,(*env)->FindClass(env, "java/lang/String"), NULL); - - for (struct ifreq* ifr = ifc.ifc_req; ifr < ifs + num_intf; ifr++) { - - if (ifr->ifr_addr.sa_family != AF_INET) { - __android_log_print(ANDROID_LOG_DEBUG, "openvpn", "NOT AF_INET: %s", ifr->ifr_name); - continue; - } - - /* get interface addr, prefilled by SIOGIFCONF */ - - int err; - if ((err=getnameinfo(&ifr->ifr_addr, sizeof(struct sockaddr_in), buf, NI_MAXHOST, NULL, 0, - NI_NUMERICHOST)) !=0) { - __android_log_print(ANDROID_LOG_DEBUG, "openvpn", "getnameinfo failed for %s: %s", ifr->ifr_name, gai_strerror(err)); - continue; - } - jstring jaddr = (*env)->NewStringUTF(env, buf); - jstring jname = (*env)->NewStringUTF(env, ifr->ifr_name); - - - struct ifreq ifreq; - strncpy (ifreq.ifr_name, ifr->ifr_name, sizeof (ifreq.ifr_name)); - - /* interface is up */ - if (ioctl (sd, SIOCGIFFLAGS, &ifreq) < 0) { - __android_log_print(ANDROID_LOG_DEBUG, "openvpn", "SIOCGIFFLAGS failed for %s: %s", ifr->ifr_name, strerror(errno)); - continue; - } - - if (!(ifreq.ifr_flags & IFF_UP)) { - __android_log_print(ANDROID_LOG_DEBUG, "openvpn", "IFF_UP failed for %s", ifr->ifr_name); - continue; - } - - /* interface netmask */ - if (ioctl (sd, SIOCGIFNETMASK, &ifreq) < 0) { - __android_log_print(ANDROID_LOG_DEBUG, "openvpn", "SIOCIFNETMASK failed for %s: %s", ifr->ifr_name, strerror(errno)); - continue; - } - - if ((err=getnameinfo(&ifreq.ifr_netmask, sizeof(struct sockaddr_in), buf, NI_MAXHOST, NULL, 0, - NI_NUMERICHOST)) !=0) { - __android_log_print(ANDROID_LOG_DEBUG, "openvpn", "getnameinfo failed for %s: %s", ifr->ifr_name, gai_strerror(err)); - continue; - } - jstring jnetmask = (*env)->NewStringUTF(env, buf); - - (*env)->SetObjectArrayElement(env, ret, ji++, jname); - (*env)->SetObjectArrayElement(env, ret, ji++, jaddr); - (*env)->SetObjectArrayElement(env, ret, ji++, jnetmask); - } - if (sd >= 0) - close (sd); - - return ret; -} - diff --git a/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java b/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java index b8e3d646..1df46525 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java +++ b/main/src/main/java/de/blinkt/openvpn/core/ICSOpenVPNApplication.java @@ -40,20 +40,12 @@ public class ICSOpenVPNApplication extends Application { LocaleHelper.setDesiredLocale(this); super.onCreate(); - PRNGFixes.apply(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) createNotificationChannels(); mStatus = new StatusListener(); mStatus.init(getApplicationContext()); - - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - AppRestrictions.getInstance(this).checkRestrictions(this); - } - - + AppRestrictions.getInstance(this).checkRestrictions(this); } @Override diff --git a/main/src/main/java/de/blinkt/openvpn/core/LollipopDeviceStateListener.java b/main/src/main/java/de/blinkt/openvpn/core/LollipopDeviceStateListener.java index 04e4e8b4..7017fc1d 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/LollipopDeviceStateListener.java +++ b/main/src/main/java/de/blinkt/openvpn/core/LollipopDeviceStateListener.java @@ -12,10 +12,6 @@ import android.net.Network; import android.net.NetworkCapabilities; import android.os.Build; -/** - * Created by arne on 26.11.14. - */ -@TargetApi(Build.VERSION_CODES.LOLLIPOP) public class LollipopDeviceStateListener extends ConnectivityManager.NetworkCallback { private String mLastConnectedStatus; diff --git a/main/src/main/java/de/blinkt/openvpn/core/NetworkUtils.java b/main/src/main/java/de/blinkt/openvpn/core/NetworkUtils.java index 8710ce7f..00f45ed4 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/NetworkUtils.java +++ b/main/src/main/java/de/blinkt/openvpn/core/NetworkUtils.java @@ -21,56 +21,30 @@ public class NetworkUtils { public static Vector getLocalNetworks(Context c, boolean ipv6) { Vector nets = new Vector<>(); ConnectivityManager conn = (ConnectivityManager) c.getSystemService(Context.CONNECTIVITY_SERVICE); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - Network[] networks = conn.getAllNetworks(); - for (Network network : networks) { - NetworkInfo ni = conn.getNetworkInfo(network); - LinkProperties li = conn.getLinkProperties(network); - NetworkCapabilities nc = conn.getNetworkCapabilities(network); + Network[] networks = conn.getAllNetworks(); + for (Network network : networks) { + NetworkInfo ni = conn.getNetworkInfo(network); + LinkProperties li = conn.getLinkProperties(network); - // Skip VPN networks like ourselves - if (nc.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) - continue; + NetworkCapabilities nc = conn.getNetworkCapabilities(network); - // Also skip mobile networks - if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) - continue; + // Skip VPN networks like ourselves + if (nc.hasTransport(NetworkCapabilities.TRANSPORT_VPN)) + continue; + // Also skip mobile networks + if (nc.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) + continue; - for (LinkAddress la : li.getLinkAddresses()) { - if ((la.getAddress() instanceof Inet4Address && !ipv6) || - (la.getAddress() instanceof Inet6Address && ipv6)) - nets.add(la.toString()); - } - } - } else { - // Old Android Version, use native utils via ifconfig instead - // Add local network interfaces - if (ipv6) - return nets; - - String[] localRoutes = NativeUtils.getIfconfig(); - - // The format of mLocalRoutes is kind of broken because I don't really like JNI - for (int i = 0; i < localRoutes.length; i += 3) { - String intf = localRoutes[i]; - String ipAddr = localRoutes[i + 1]; - String netMask = localRoutes[i + 2]; - - if (intf == null || intf.equals("lo") || - intf.startsWith("tun") || intf.startsWith("rmnet")) - continue; - - if (ipAddr == null || netMask == null) { - VpnStatus.logError("Local routes are broken?! (Report to author) " + TextUtils.join("|", localRoutes)); - continue; - } - nets.add(ipAddr + "/" + CIDRIP.calculateLenFromMask(netMask)); + for (LinkAddress la : li.getLinkAddresses()) { + if ((la.getAddress() instanceof Inet4Address && !ipv6) || + (la.getAddress() instanceof Inet6Address && ipv6)) + nets.add(la.toString()); } - } + return nets; } 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 f1f2edb7..b8871222 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java @@ -278,9 +278,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac // Try to set the priority available since API 16 (Jellybean) jbNotificationExtras(priority, nbuilder); addVpnActionsToNotification(nbuilder); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - lpNotificationExtras(nbuilder, Notification.CATEGORY_SERVICE); + lpNotificationExtras(nbuilder, Notification.CATEGORY_SERVICE); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //noinspection NewApi @@ -324,7 +322,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac }); } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void lpNotificationExtras(Notification.Builder nbuilder, String category) { nbuilder.setCategory(category); nbuilder.setLocalOnly(true); @@ -744,7 +741,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac return null; } - boolean allowUnsetAF = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && !mProfile.mBlockUnusedAddressFamilies; + boolean allowUnsetAF = !mProfile.mBlockUnusedAddressFamilies; if (allowUnsetAF) { allowAllAFFamilies(builder); } @@ -787,19 +784,12 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } String release = Build.VERSION.RELEASE; - if ((Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT && !release.startsWith("4.4.3") - && !release.startsWith("4.4.4") && !release.startsWith("4.4.5") && !release.startsWith("4.4.6")) - && mMtu < 1280) { - VpnStatus.logInfo(String.format(Locale.US, "Forcing MTU to 1280 instead of %d to workaround Android Bug #70916", mMtu)); - builder.setMtu(1280); - } else { - builder.setMtu(mMtu); - } + builder.setMtu(mMtu); Collection positiveIPv4Routes = mRoutes.getPositiveIPList(); Collection positiveIPv6Routes = mRoutesv6.getPositiveIPList(); - if ("samsung".equals(Build.BRAND) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mDnslist.size() >= 1) { + if ("samsung".equals(Build.BRAND) && mDnslist.size() >= 1) { // Check if the first DNS Server is in the VPN range try { IpAddress dnsServer = new IpAddress(new CIDRIP(mDnslist.get(0), 32), true); @@ -877,13 +867,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 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - VpnStatus.logInfo(R.string.proxy_info, mProxyInfo.getHost(), mProxyInfo.getPort()); - } + 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); - } + setAllowedVpnPackages(builder); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { // VPN always uses the default network builder.setUnderlyingNetworks(null); @@ -956,7 +942,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void allowAllAFFamilies(Builder builder) { builder.allowFamily(OsConstants.AF_INET); builder.allowFamily(OsConstants.AF_INET6); @@ -985,8 +970,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) private void setAllowedVpnPackages(Builder builder) { boolean profileUsesOrBot = false; @@ -1064,9 +1047,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } public boolean addHttpProxy(String proxy, int port) { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) - return false; - try { mProxyInfo = ProxyInfo.buildDirectProxy(proxy, port); } catch (Exception e) { @@ -1173,8 +1153,8 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac } - /* Workaround for Lollipop, it does not route traffic to the VPNs own network mask */ - if (mLocalIP.len <= 31 && Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + /* Workaround for Lollipop and higher, it does not route traffic to the VPNs own network mask */ + if (mLocalIP.len <= 31) { CIDRIP interfaceRoute = new CIDRIP(mLocalIP.mIp, mLocalIP.len); interfaceRoute.normalise(); addRoute(interfaceRoute, true); @@ -1268,13 +1248,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac if (currentConfiguration.equals(mLastTunCfg)) { return "NOACTION"; } else { - String release = Build.VERSION.RELEASE; - if (Build.VERSION.SDK_INT == Build.VERSION_CODES.KITKAT && !release.startsWith("4.4.3") - && !release.startsWith("4.4.4") && !release.startsWith("4.4.5") && !release.startsWith("4.4.6")) - // There will be probably no 4.4.4 or 4.4.5 version, so don't waste effort to do parsing here - return "OPEN_AFTER_CLOSE"; - else - return "OPEN_BEFORE_CLOSE"; + return "OPEN_BEFORE_CLOSE"; } } @@ -1362,9 +1336,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac nbuilder.setContentIntent(pIntent); jbNotificationExtras(PRIORITY_MAX, nbuilder); - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - lpNotificationExtras(nbuilder, Notification.CATEGORY_STATUS); + lpNotificationExtras(nbuilder, Notification.CATEGORY_STATUS); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { //noinspection NewApi 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 e32aabe3..11b2608b 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java +++ b/main/src/main/java/de/blinkt/openvpn/core/OpenVpnManagementThread.java @@ -239,14 +239,8 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { if (!result) VpnStatus.logWarning("Could not protect VPN socket"); + fdClose(fd); - //ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(fdint); - //pfd.close(); - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { - fdCloseLollipop(fd); - } else { - NativeUtils.jniclose(fdint); - } return; } catch ( NoSuchMethodException | IllegalArgumentException | InvocationTargetException | IllegalAccessException | NullPointerException e) { VpnStatus.logException("Failed to retrieve fd from socket (" + fd + ")", e); @@ -256,8 +250,7 @@ public class OpenVpnManagementThread implements Runnable, OpenVPNManagement { } - @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) - private void fdCloseLollipop(FileDescriptor fd) { + private void fdClose(FileDescriptor fd) { try { Os.close(fd); } catch (Exception e) { diff --git a/main/src/main/java/de/blinkt/openvpn/core/PRNGFixes.java b/main/src/main/java/de/blinkt/openvpn/core/PRNGFixes.java deleted file mode 100644 index 49a7eaa9..00000000 --- a/main/src/main/java/de/blinkt/openvpn/core/PRNGFixes.java +++ /dev/null @@ -1,339 +0,0 @@ -/* - * Copyright (c) 2012-2016 Arne Schwabe - * Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt - */ - -package de.blinkt.openvpn.core;/* - * This software is provided 'as-is', without any express or implied - * warranty. In no event will Google be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, as long as the origin is not misrepresented. - */ - -import android.os.Build; -import android.os.Process; -import android.util.Log; - -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.io.UnsupportedEncodingException; -import java.security.NoSuchAlgorithmException; -import java.security.Provider; -import java.security.SecureRandom; -import java.security.SecureRandomSpi; -import java.security.Security; - -/** - * Fixes for the output of the default PRNG having low entropy. - * - * The fixes need to be applied via {@link #apply()} before any use of Java - * Cryptography Architecture primitives. A good place to invoke them is in the - * application's {@code onCreate}. - */ -public final class PRNGFixes { - - private static final int VERSION_CODE_JELLY_BEAN = 16; - private static final int VERSION_CODE_JELLY_BEAN_MR2 = 18; - private static final byte[] BUILD_FINGERPRINT_AND_DEVICE_SERIAL = - getBuildFingerprintAndDeviceSerial(); - - /** Hidden constructor to prevent instantiation. */ - private PRNGFixes() {} - - /** - * Applies all fixes. - * - * @throws SecurityException if a fix is needed but could not be applied. - */ - public static void apply() { - applyOpenSSLFix(); - installLinuxPRNGSecureRandom(); - } - - /** - * Applies the fix for OpenSSL PRNG having low entropy. Does nothing if the - * fix is not needed. - * - * @throws SecurityException if the fix is needed but could not be applied. - */ - private static void applyOpenSSLFix() throws SecurityException { - if ((Build.VERSION.SDK_INT < VERSION_CODE_JELLY_BEAN) - || (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2)) { - // No need to apply the fix - return; - } - - try { - // Mix in the device- and invocation-specific seed. - Class.forName("org.apache.harmony.xnet.provider.jsse.NativeCrypto") - .getMethod("RAND_seed", byte[].class) - .invoke(null, generateSeed()); - - // Mix output of Linux PRNG into OpenSSL's PRNG - int bytesRead = (Integer) Class.forName( - "org.apache.harmony.xnet.provider.jsse.NativeCrypto") - .getMethod("RAND_load_file", String.class, long.class) - .invoke(null, "/dev/urandom", 1024); - if (bytesRead != 1024) { - throw new IOException( - "Unexpected number of bytes read from Linux PRNG: " - + bytesRead); - } - } catch (Exception e) { - throw new SecurityException("Failed to seed OpenSSL PRNG", e); - } - } - - /** - * Installs a Linux PRNG-backed {@code SecureRandom} implementation as the - * default. Does nothing if the implementation is already the default or if - * there is not need to install the implementation. - * - * @throws SecurityException if the fix is needed but could not be applied. - */ - private static void installLinuxPRNGSecureRandom() - throws SecurityException { - if (Build.VERSION.SDK_INT > VERSION_CODE_JELLY_BEAN_MR2) { - // No need to apply the fix - return; - } - - // Install a Linux PRNG-based SecureRandom implementation as the - // default, if not yet installed. - Provider[] secureRandomProviders = - Security.getProviders("SecureRandom.SHA1PRNG"); - if ((secureRandomProviders == null) - || (secureRandomProviders.length < 1) - || (!LinuxPRNGSecureRandomProvider.class.equals( - secureRandomProviders[0].getClass()))) { - Security.insertProviderAt(new LinuxPRNGSecureRandomProvider(), 1); - } - - // Assert that new SecureRandom() and - // SecureRandom.getInstance("SHA1PRNG") return a SecureRandom backed - // by the Linux PRNG-based SecureRandom implementation. - SecureRandom rng1 = new SecureRandom(); - if (!LinuxPRNGSecureRandomProvider.class.equals( - rng1.getProvider().getClass())) { - throw new SecurityException( - "new SecureRandom() backed by wrong Provider: " - + rng1.getProvider().getClass()); - } - - SecureRandom rng2; - try { - rng2 = SecureRandom.getInstance("SHA1PRNG"); - } catch (NoSuchAlgorithmException e) { - throw new SecurityException("SHA1PRNG not available", e); - } - if (!LinuxPRNGSecureRandomProvider.class.equals( - rng2.getProvider().getClass())) { - throw new SecurityException( - "SecureRandom.getInstance(\"SHA1PRNG\") backed by wrong" - + " Provider: " + rng2.getProvider().getClass()); - } - } - - /** - * {@code Provider} of {@code SecureRandom} engines which pass through - * all requests to the Linux PRNG. - */ - private static class LinuxPRNGSecureRandomProvider extends Provider { - - public LinuxPRNGSecureRandomProvider() { - super("LinuxPRNG", - 1.0, - "A Linux-specific random number provider that uses" - + " /dev/urandom"); - // Although /dev/urandom is not a SHA-1 PRNG, some apps - // explicitly request a SHA1PRNG SecureRandom and we thus need to - // prevent them from getting the default implementation whose output - // may have low entropy. - put("SecureRandom.SHA1PRNG", LinuxPRNGSecureRandom.class.getName()); - put("SecureRandom.SHA1PRNG ImplementedIn", "Software"); - } - } - - /** - * {@link SecureRandomSpi} which passes all requests to the Linux PRNG - * ({@code /dev/urandom}). - */ - public static class LinuxPRNGSecureRandom extends SecureRandomSpi { - - /* - * IMPLEMENTATION NOTE: Requests to generate bytes and to mix in a seed - * are passed through to the Linux PRNG (/dev/urandom). Instances of - * this class seed themselves by mixing in the current time, PID, UID, - * build fingerprint, and hardware serial number (where available) into - * Linux PRNG. - * - * Concurrency: Read requests to the underlying Linux PRNG are - * serialized (on sLock) to ensure that multiple threads do not get - * duplicated PRNG output. - */ - - private static final File URANDOM_FILE = new File("/dev/urandom"); - - private static final Object sLock = new Object(); - - /** - * Input stream for reading from Linux PRNG or {@code null} if not yet - * opened. - * - * @GuardedBy("sLock") - */ - private static DataInputStream sUrandomIn; - - /** - * Output stream for writing to Linux PRNG or {@code null} if not yet - * opened. - * - * @GuardedBy("sLock") - */ - private static OutputStream sUrandomOut; - - /** - * Whether this engine instance has been seeded. This is needed because - * each instance needs to seed itself if the client does not explicitly - * seed it. - */ - private boolean mSeeded; - - @Override - protected void engineSetSeed(byte[] bytes) { - try { - OutputStream out; - synchronized (sLock) { - out = getUrandomOutputStream(); - } - out.write(bytes); - out.flush(); - } catch (IOException e) { - // On a small fraction of devices /dev/urandom is not writable. - // Log and ignore. - Log.w(PRNGFixes.class.getSimpleName(), - "Failed to mix seed into " + URANDOM_FILE); - } finally { - mSeeded = true; - } - } - - @Override - protected void engineNextBytes(byte[] bytes) { - if (!mSeeded) { - // Mix in the device- and invocation-specific seed. - engineSetSeed(generateSeed()); - } - - try { - DataInputStream in; - synchronized (sLock) { - in = getUrandomInputStream(); - } - synchronized (in) { - in.readFully(bytes); - } - } catch (IOException e) { - throw new SecurityException( - "Failed to read from " + URANDOM_FILE, e); - } - } - - @Override - protected byte[] engineGenerateSeed(int size) { - byte[] seed = new byte[size]; - engineNextBytes(seed); - return seed; - } - - private DataInputStream getUrandomInputStream() { - synchronized (sLock) { - if (sUrandomIn == null) { - // NOTE: Consider inserting a BufferedInputStream between - // DataInputStream and FileInputStream if you need higher - // PRNG output performance and can live with future PRNG - // output being pulled into this process prematurely. - try { - sUrandomIn = new DataInputStream( - new FileInputStream(URANDOM_FILE)); - } catch (IOException e) { - throw new SecurityException("Failed to open " - + URANDOM_FILE + " for reading", e); - } - } - return sUrandomIn; - } - } - - private OutputStream getUrandomOutputStream() throws IOException { - synchronized (sLock) { - if (sUrandomOut == null) { - sUrandomOut = new FileOutputStream(URANDOM_FILE); - } - return sUrandomOut; - } - } - } - - /** - * Generates a device- and invocation-specific seed to be mixed into the - * Linux PRNG. - */ - private static byte[] generateSeed() { - try { - ByteArrayOutputStream seedBuffer = new ByteArrayOutputStream(); - DataOutputStream seedBufferOut = - new DataOutputStream(seedBuffer); - seedBufferOut.writeLong(System.currentTimeMillis()); - seedBufferOut.writeLong(System.nanoTime()); - seedBufferOut.writeInt(Process.myPid()); - seedBufferOut.writeInt(Process.myUid()); - seedBufferOut.write(BUILD_FINGERPRINT_AND_DEVICE_SERIAL); - seedBufferOut.close(); - return seedBuffer.toByteArray(); - } catch (IOException e) { - throw new SecurityException("Failed to generate seed", e); - } - } - - /** - * Gets the hardware serial number of this device. - * - * @return serial number or {@code null} if not available. - */ - private static String getDeviceSerialNumber() { - // We're using the Reflection API because Build.SERIAL is only available - // since API Level 9 (Gingerbread, Android 2.3). - try { - return (String) Build.class.getField("SERIAL").get(null); - } catch (Exception ignored) { - return null; - } - } - - private static byte[] getBuildFingerprintAndDeviceSerial() { - StringBuilder result = new StringBuilder(); - String fingerprint = Build.FINGERPRINT; - if (fingerprint != null) { - result.append(fingerprint); - } - String serial = getDeviceSerialNumber(); - if (serial != null) { - result.append(serial); - } - try { - return result.toString().getBytes("UTF-8"); - } catch (UnsupportedEncodingException e) { - throw new RuntimeException("UTF-8 encoding not supported"); - } - } -} \ No newline at end of file diff --git a/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java b/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java index cbb27c22..c859e845 100644 --- a/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java +++ b/main/src/main/java/de/blinkt/openvpn/core/VPNLaunchHelper.java @@ -5,7 +5,6 @@ package de.blinkt.openvpn.core; -import android.annotation.TargetApi; import android.content.Context; import android.content.Intent; import android.os.Build; @@ -28,12 +27,8 @@ public class VPNLaunchHelper { /* Q does not allow executing binaries written in temp directory anymore */ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) return new File(context.getApplicationInfo().nativeLibraryDir, "libovpnexec.so").getPath(); - String[] abis; - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) - abis = getSupportedABIsLollipop(); - else - //noinspection deprecation - abis = new String[]{Build.CPU_ABI, Build.CPU_ABI2}; + + String[] abis = Build.SUPPORTED_ABIS; if (!nativeAPI.equals(abis[0])) { VpnStatus.logWarning(R.string.abi_mismatch, Arrays.toString(abis), nativeAPI); @@ -51,11 +46,6 @@ public class VPNLaunchHelper { throw new RuntimeException("Cannot find any executable for this device's ABIs " + Arrays.toString(abis)); } - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - private static String[] getSupportedABIsLollipop() { - return Build.SUPPORTED_ABIS; - } - static String[] buildOpenvpnArgv(Context c) { Vector args = new Vector<>(); diff --git a/main/src/main/res/xml/app_restrictions.xml b/main/src/main/res/xml/app_restrictions.xml index bd053388..813e9bd3 100644 --- a/main/src/main/res/xml/app_restrictions.xml +++ b/main/src/main/res/xml/app_restrictions.xml @@ -4,9 +4,7 @@ ~ Distributed under the GNU GPL v2 with additional terms. For full terms see the file doc/LICENSE.txt --> - - + - +