summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcyBerta <cyberta@riseup.net>2019-07-05 17:18:30 +0200
committercyBerta <cyberta@riseup.net>2019-07-12 16:59:26 +0200
commitf5b8dae753448ed698486af8b49b977a58d4fcdc (patch)
tree06358a7d4e70903b6ce235f16c7e22a4800b8f99
parent962e6261e4024cd8191cf2b0c64fc8a34ea3b425 (diff)
better support for android 8.X always-on killswitch (#8945 & #8928)
-rw-r--r--app/src/main/java/de/blinkt/openvpn/VpnProfile.java52
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java74
-rw-r--r--app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java10
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/Constants.java2
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java4
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/eip/EIP.java1
-rw-r--r--app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java25
7 files changed, 108 insertions, 60 deletions
diff --git a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
index bd28ae16..7028bf62 100644
--- a/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
+++ b/app/src/main/java/de/blinkt/openvpn/VpnProfile.java
@@ -5,9 +5,6 @@
package de.blinkt.openvpn;
-import se.leap.bitmaskclient.R;
-import se.leap.bitmaskclient.BuildConfig;
-
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
@@ -15,7 +12,6 @@ import android.content.SharedPreferences;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.Build;
-import android.os.RemoteException;
import android.preference.PreferenceManager;
import android.security.KeyChain;
import android.security.KeyChainException;
@@ -24,7 +20,8 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Base64;
-import de.blinkt.openvpn.core.*;
+import com.google.gson.Gson;
+
import org.spongycastle.util.io.pem.PemObject;
import org.spongycastle.util.io.pem.PemWriter;
@@ -37,7 +34,11 @@ import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
-import java.security.*;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.PrivateKey;
+import java.security.Signature;
+import java.security.SignatureException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
@@ -52,6 +53,21 @@ import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
+import de.blinkt.openvpn.core.Connection;
+import de.blinkt.openvpn.core.ExtAuthHelper;
+import de.blinkt.openvpn.core.NativeUtils;
+import de.blinkt.openvpn.core.OpenVPNService;
+import de.blinkt.openvpn.core.OrbotHelper;
+import de.blinkt.openvpn.core.PasswordCache;
+import de.blinkt.openvpn.core.Preferences;
+import de.blinkt.openvpn.core.VPNLaunchHelper;
+import de.blinkt.openvpn.core.VpnStatus;
+import de.blinkt.openvpn.core.X509Utils;
+import se.leap.bitmaskclient.BuildConfig;
+import se.leap.bitmaskclient.R;
+
+import static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE;
+
public class VpnProfile implements Serializable, Cloneable {
// Note that this class cannot be moved to core where it belongs since
// the profile loading depends on it being here
@@ -755,11 +771,8 @@ public class VpnProfile implements Serializable, Cloneable {
}
public Intent getStartServiceIntent(Context context) {
- String prefix = context.getPackageName();
-
Intent intent = new Intent(context, OpenVPNService.class);
- intent.putExtra(prefix + ".profileUUID", mUuid.toString());
- intent.putExtra(prefix + ".profileVersion", mVersion);
+ intent.putExtra(PROVIDER_PROFILE, this);
return intent;
}
@@ -1113,6 +1126,25 @@ public class VpnProfile implements Serializable, Cloneable {
return mName;
}
+ public String toJson() {
+ Gson gson = new Gson();
+ try {
+ return gson.toJson(this);
+ } catch (Exception e) {
+ return null;
+ }
+ }
+
+ public static VpnProfile fromJson(String json) {
+ try {
+ Gson gson = new Gson();
+ return gson.fromJson(json, VpnProfile.class);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+
public String getUUIDString() {
return mUuid.toString().toLowerCase(Locale.ENGLISH);
}
diff --git a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
index af31e977..ea782e00 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
@@ -44,10 +44,12 @@ import de.blinkt.openvpn.core.VpnStatus.ByteCountListener;
import de.blinkt.openvpn.core.VpnStatus.StateListener;
import se.leap.bitmaskclient.R;
import se.leap.bitmaskclient.VpnNotificationManager;
+import se.leap.bitmaskclient.utils.PreferenceHelper;
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 static se.leap.bitmaskclient.Constants.PROVIDER_PROFILE;
public class OpenVPNService extends VpnService implements StateListener, Callback, ByteCountListener, IOpenVPNServiceInternal, VpnNotificationManager.VpnServiceCallback {
@@ -61,6 +63,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
public final static String ORBOT_PACKAGE_NAME = "org.torproject.android";
private static final String PAUSE_VPN = "de.blinkt.openvpn.PAUSE_VPN";
private static final String RESUME_VPN = "se.leap.bitmaskclient.RESUME_VPN";
+ private static final String TAG = OpenVPNService.class.getSimpleName();
private static boolean mNotificationAlwaysVisible = false;
private final Vector<String> mDnslist = new Vector<>();
private final NetworkSpace mRoutes = new NetworkSpace();
@@ -177,7 +180,6 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
VpnStatus.removeByteCountListener(this);
unregisterDeviceStateReceiver();
- ProfileManager.setConntectedVpnProfileDisconnected(this);
mOpenVPNThread = null;
if (!mStarting) {
stopForeground(!mNotificationAlwaysVisible);
@@ -312,47 +314,35 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
0,
NOTIFICATION_CHANNEL_NEWSTATUS_ID);
- if (intent != null && intent.hasExtra(getPackageName() + ".profileUUID")) {
- String profileUUID = intent.getStringExtra(getPackageName() + ".profileUUID");
- int profileVersion = intent.getIntExtra(getPackageName() + ".profileVersion", 0);
- // Try for 10s to get current version of the profile
- mProfile = ProfileManager.get(this, profileUUID, profileVersion, 100);
+ if (intent != null && intent.hasExtra(PROVIDER_PROFILE)) {
+ mProfile = (VpnProfile) intent.getSerializableExtra(PROVIDER_PROFILE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
updateShortCutUsage(mProfile);
}
-
+ PreferenceHelper.setAlwaysOn(this, false);
} else {
/* The intent is null when we are set as always-on or the service has been restarted. */
mProfile = ProfileManager.getLastConnectedProfile(this);
VpnStatus.logInfo(R.string.service_restarted);
- /* Got no profile, just stop */
- if (mProfile == null) {
- Log.d("OpenVPN", "Got no last connected profile on null intent. Assuming always on.");
- mProfile = ProfileManager.getAlwaysOnVPN(this);
-
- if (mProfile == null) {
- stopSelf(startId);
- return START_NOT_STICKY;
- }
+ if (mProfile != null) {
+ PreferenceHelper.setAlwaysOn(this, true);
}
- /* Do the asynchronous keychain certificate stuff */
- mProfile.checkForRestart(this);
}
if (mProfile == null) {
- stopSelf(startId);
+ stopService(startId);
+ Log.d(TAG, "Stopping service, no profile found");
return START_NOT_STICKY;
+ } else {
+ Log.d(TAG, "Found profile: " + mProfile.mName);
+ /* Do the asynchronous keychain certificate stuff */
+ mProfile.checkForRestart(this);
}
/* start the OpenVPN process itself in a background thread */
- new Thread(new Runnable() {
- @Override
- public void run() {
- startOpenVPN();
- }
- }).start();
+ new Thread(this::startOpenVPN).start();
ProfileManager.setConnectedVpnProfile(this, mProfile);
@@ -369,6 +359,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
shortcutManager.reportShortcutUsed(profile.getUUIDString());
}
+ private void stopService(int startId) {
+ VpnStatus.updateStateString("NOPROCESS", "VPN STOPPED", R.string.state_noprocess, ConnectionStatus.LEVEL_NOTCONNECTED);
+ stopSelf(startId);
+ }
+
private void startOpenVPN() {
/**
* see change above (l. 292 ff)
@@ -428,21 +423,17 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
}
synchronized (mProcessLock)
-
{
mProcessThread = new Thread(processThread, "OpenVPNProcessThread");
mProcessThread.start();
}
- new Handler(getMainLooper()).post(new Runnable() {
- @Override
- public void run() {
- if (mDeviceStateReceiver != null)
- unregisterDeviceStateReceiver();
-
- registerDeviceStateReceiver(mManagement);
- }
- }
+ new Handler(getMainLooper()).post(() -> {
+ if (mDeviceStateReceiver != null) {
+ unregisterDeviceStateReceiver();
+ }
+ registerDeviceStateReceiver(mManagement);
+ }
);
}
@@ -550,8 +541,17 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
VpnStatus.logInfo(R.string.last_openvpn_tun_config);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && mProfile.mAllowLocalLAN) {
- allowAllAFFamilies(builder);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ if (mProfile.mAllowLocalLAN) {
+ allowAllAFFamilies(builder);
+ }
+ if (PreferenceHelper.isAlwaysOn(this)) {
+ try {
+ builder.addDisallowedApplication(this.getPackageName());
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+ }
}
if (mLocalIP == null && mLocalIPv6 == null) {
diff --git a/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java b/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java
index b9edc4b2..d897e91f 100644
--- a/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java
+++ b/app/src/main/java/de/blinkt/openvpn/core/ProfileManager.java
@@ -75,7 +75,7 @@ public class ProfileManager {
SharedPreferences prefs = Preferences.getDefaultSharedPreferences(c);
Editor prefsedit = prefs.edit();
- prefsedit.putString(LAST_CONNECTED_PROFILE, connectedProfile.getUUIDString());
+ prefsedit.putString(LAST_CONNECTED_PROFILE, connectedProfile.toJson());
prefsedit.apply();
mLastConnectedVpn = connectedProfile;
@@ -87,11 +87,8 @@ public class ProfileManager {
public static VpnProfile getLastConnectedProfile(Context c) {
SharedPreferences prefs = Preferences.getDefaultSharedPreferences(c);
- String lastConnectedProfile = prefs.getString(LAST_CONNECTED_PROFILE, null);
- if (lastConnectedProfile != null)
- return get(c, lastConnectedProfile);
- else
- return null;
+ String lastConnectedProfileJson = prefs.getString(LAST_CONNECTED_PROFILE, null);
+ return VpnProfile.fromJson(lastConnectedProfileJson);
}
@@ -255,7 +252,6 @@ public class ProfileManager {
String uuid = prefs.getString("alwaysOnVpn", null);
return get(uuid);
-
}
public static void updateLRU(Context c, VpnProfile profile) {
diff --git a/app/src/main/java/se/leap/bitmaskclient/Constants.java b/app/src/main/java/se/leap/bitmaskclient/Constants.java
index 8d329002..42df6d1d 100644
--- a/app/src/main/java/se/leap/bitmaskclient/Constants.java
+++ b/app/src/main/java/se/leap/bitmaskclient/Constants.java
@@ -12,6 +12,7 @@ public interface Constants {
String PREFERENCES_APP_VERSION = "bitmask version";
String ALWAYS_ON_SHOW_DIALOG = "DIALOG.ALWAYS_ON_SHOW_DIALOG";
String CLEARLOG = "clearlogconnect";
+ String LAST_USED_PROFILE = "last_used_profile";
//////////////////////////////////////////////
@@ -69,6 +70,7 @@ public interface Constants {
String PROVIDER_CONFIGURED = "Constants.PROVIDER_CONFIGURED";
String PROVIDER_EIP_DEFINITION = "Constants.EIP_DEFINITION";
String PROVIDER_PROFILE_UUID = "Constants.PROVIDER_PROFILE_UUID";
+ String PROVIDER_PROFILE = "Constants.PROVIDER_PROFILE";
//////////////////////////////////////////////
// CREDENTIAL CONSTANTS
diff --git a/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java b/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
index f33bc27e..8339b033 100644
--- a/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
+++ b/app/src/main/java/se/leap/bitmaskclient/OnBootReceiver.java
@@ -6,6 +6,8 @@ import android.content.Intent;
import android.content.SharedPreferences;
import android.util.Log;
+import se.leap.bitmaskclient.utils.PreferenceHelper;
+
import static android.content.Intent.ACTION_BOOT_COMPLETED;
import static se.leap.bitmaskclient.Constants.APP_ACTION_CONFIGURE_ALWAYS_ON_PROFILE;
import static se.leap.bitmaskclient.Constants.EIP_IS_ALWAYS_ON;
@@ -27,7 +29,7 @@ public class OnBootReceiver extends BroadcastReceiver {
preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
boolean providerConfigured = !preferences.getString(PROVIDER_VPN_CERTIFICATE, "").isEmpty();
boolean startOnBoot = preferences.getBoolean(EIP_RESTART_ON_BOOT, false);
- boolean isAlwaysOnConfigured = preferences.getBoolean(EIP_IS_ALWAYS_ON, false);
+ boolean isAlwaysOnConfigured = PreferenceHelper.isAlwaysOn(context);
Log.d("OpenVPN", "OpenVPN onBoot intent received. Provider configured? " + providerConfigured + " Start on boot? " + startOnBoot + " isAlwaysOn feature configured: " + isAlwaysOnConfigured);
if (providerConfigured) {
if (isAlwaysOnConfigured) {
diff --git a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
index 29e2199f..a0c96267 100644
--- a/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
+++ b/app/src/main/java/se/leap/bitmaskclient/eip/EIP.java
@@ -401,7 +401,6 @@ public final class EIP extends JobIntentService implements Observer {
return false;
}
- ProfileManager.setConntectedVpnProfileDisconnected(this);
try {
return openVpnServiceConnection.getService().stopVPN(false);
} catch (RemoteException e) {
diff --git a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java b/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
index 44831049..cff983b9 100644
--- a/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
+++ b/app/src/main/java/se/leap/bitmaskclient/utils/PreferenceHelper.java
@@ -18,8 +18,10 @@ import java.util.Map;
import se.leap.bitmaskclient.Provider;
+import static android.content.Context.MODE_PRIVATE;
import static se.leap.bitmaskclient.Constants.ALWAYS_ON_SHOW_DIALOG;
import static se.leap.bitmaskclient.Constants.DEFAULT_SHARED_PREFS_BATTERY_SAVER;
+import static se.leap.bitmaskclient.Constants.EIP_IS_ALWAYS_ON;
import static se.leap.bitmaskclient.Constants.PREFERENCES_APP_VERSION;
import static se.leap.bitmaskclient.Constants.PROVIDER_CONFIGURED;
import static se.leap.bitmaskclient.Constants.PROVIDER_EIP_DEFINITION;
@@ -206,7 +208,7 @@ public class PreferenceHelper {
if (context == null) {
return;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
preferences.edit().putBoolean(ALWAYS_ON_SHOW_DIALOG, showAlwaysOnDialog).apply();
}
@@ -214,7 +216,7 @@ public class PreferenceHelper {
if (context == null) {
return true;
}
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
return preferences.getBoolean(ALWAYS_ON_SHOW_DIALOG, true);
}
@@ -232,6 +234,20 @@ public class PreferenceHelper {
return result;
}
+ public static void setAlwaysOn(Context context, boolean alwaysOn) {
+ if (context == null) {
+ return;
+ }
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ //needs to be blocking here
+ preferences.edit().putBoolean(EIP_IS_ALWAYS_ON, false).commit();
+ }
+
+ public static boolean isAlwaysOn(Context context) {
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
+ return preferences.getBoolean(EIP_IS_ALWAYS_ON, false);
+ }
+
/*public static void saveLastProfile(Context context, String uuid) {
if (context == null) {
return;
@@ -256,12 +272,13 @@ public class PreferenceHelper {
}
*/
public static String getString(Context context, String key, String defValue) {
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
return preferences.getString(key, defValue);
}
public static void putString(Context context, String key, String value){
- SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, Context.MODE_PRIVATE);
+ SharedPreferences preferences = context.getSharedPreferences(SHARED_PREFERENCES, MODE_PRIVATE);
preferences.edit().putString(key, value).apply();
}
+
}