Skip to content

Commit

Permalink
Clean up extra for VPN start intents and try to avoid replacing VPN o…
Browse files Browse the repository at this point in the history
…n autostarts
  • Loading branch information
schwabe committed Nov 30, 2023
1 parent a85b59e commit b4b37f1
Show file tree
Hide file tree
Showing 13 changed files with 71 additions and 46 deletions.
6 changes: 4 additions & 2 deletions main/src/main/java/de/blinkt/openvpn/LaunchVPN.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

package de.blinkt.openvpn;

import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_START_REASON;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.Activity;
Expand Down Expand Up @@ -73,7 +75,7 @@ public class LaunchVPN extends Activity {
public static final String EXTRA_KEY = "de.blinkt.openvpn.shortcutProfileUUID";
public static final String EXTRA_NAME = "de.blinkt.openvpn.shortcutProfileName";
public static final String EXTRA_HIDELOG = "de.blinkt.openvpn.showNoLogWindow";
public static final String EXTRA_START_REASON = "de.blinkt.openvpn.start_reason";

public static final String CLEARLOG = "clearlogconnect";


Expand Down Expand Up @@ -255,7 +257,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (!mhideLog && showLogWindow)
showLogWindow();
ProfileManager.updateLRU(this, mSelectedProfile);
VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext(), mSelectedProfileReason);
VPNLaunchHelper.startOpenVpn(mSelectedProfile, getBaseContext(), mSelectedProfileReason, true);
finish();
}
} else if (resultCode == Activity.RESULT_CANCELED) {
Expand Down
2 changes: 1 addition & 1 deletion main/src/main/java/de/blinkt/openvpn/OnBootReceiver.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,6 @@ public void onReceive(Context context, Intent intent) {
}

void launchVPN(VpnProfile profile, Context context) {
VPNLaunchHelper.startOpenVpn(profile, context.getApplicationContext(), "on Boot receiver");
VPNLaunchHelper.startOpenVpn(profile, context.getApplicationContext(), "on Boot receiver", false);
}
}
20 changes: 10 additions & 10 deletions main/src/main/java/de/blinkt/openvpn/VpnProfile.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

package de.blinkt.openvpn;

import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_DO_NOT_REPLACE_RUNNING_VPN;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
Expand All @@ -31,20 +33,16 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.*;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.MGF1ParameterSpec;
import java.security.spec.PSSParameterSpec;
import java.util.Collection;
Expand All @@ -67,6 +65,8 @@ public class VpnProfile implements Serializable, Cloneable {
transient public static final long MAX_EMBED_FILE_SIZE = 2048 * 1024; // 2048kB
// Don't change this, not all parts of the program use this constant
public static final String EXTRA_PROFILEUUID = "de.blinkt.openvpn.profileUUID";
public static final String EXTRA_PROFILE_VERSION = "de.blinkt.openvpn.profileVersion";

public static final String INLINE_TAG = "[[INLINE]]";
public static final String DISPLAYNAME_TAG = "[[NAME]]";
public static final int MAXLOGLEVEL = 4;
Expand Down Expand Up @@ -816,14 +816,14 @@ public void writeConfigFileOutput(Context context, OutputStream out) throws IOEx
cfg.close();
}

public Intent getStartServiceIntent(Context context, String startReason) {
String prefix = context.getPackageName();

public Intent getStartServiceIntent(Context context, String startReason, boolean replace_running_vpn) {
Intent intent = new Intent(context, OpenVPNService.class);
intent.putExtra(prefix + ".profileUUID", mUuid.toString());
intent.putExtra(prefix + ".profileVersion", mVersion);
intent.putExtra(EXTRA_PROFILEUUID, mUuid.toString());
intent.putExtra(EXTRA_PROFILE_VERSION, mVersion);
if (startReason != null)
intent.putExtra(prefix + ".startReason", startReason);
intent.putExtra(OpenVPNService.EXTRA_START_REASON, startReason);
if (!replace_running_vpn)
intent.putExtra(EXTRA_DO_NOT_REPLACE_RUNNING_VPN, true);
return intent;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ public void onClick(DialogInterface dialog, int which) {
} else if (which == DialogInterface.BUTTON_NEUTRAL) {
Intent intent = new Intent(this, LaunchVPN.class);
intent.putExtra(LaunchVPN.EXTRA_KEY, VpnStatus.getLastConnectedVPNProfile());
intent.putExtra(LaunchVPN.EXTRA_START_REASON, "Reconnect button pressed.");
intent.putExtra(OpenVPNService.EXTRA_START_REASON, "Reconnect button pressed.");
intent.setAction(Intent.ACTION_MAIN);
startActivity(intent);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,13 @@
package de.blinkt.openvpn.api;

import android.annotation.TargetApi;
import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.VpnService;
import android.os.Binder;
import android.os.Build;
Expand Down Expand Up @@ -146,11 +142,11 @@ private void startProfile(VpnProfile vp)
shortVPNIntent.setClass(getBaseContext(), de.blinkt.openvpn.LaunchVPN.class);
shortVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_KEY, vp.getUUIDString());
shortVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_HIDELOG, true);
shortVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_START_REASON, startReason);
shortVPNIntent.putExtra(de.blinkt.openvpn.core.OpenVPNService.EXTRA_START_REASON, startReason);
shortVPNIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(shortVPNIntent);
} else {
VPNLaunchHelper.startOpenVpn(vp, getBaseContext(), startReason);
VPNLaunchHelper.startOpenVpn(vp, getBaseContext(), startReason, true);
}

}
Expand Down
2 changes: 1 addition & 1 deletion main/src/main/java/de/blinkt/openvpn/api/RemoteAction.java
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ private void performAction() throws RemoteException {
} else {
Intent startVPN = new Intent(this, LaunchVPN.class);
startVPN.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
startVPN.putExtra(LaunchVPN.EXTRA_START_REASON, ".api.ConnectVPN call");
startVPN.putExtra(OpenVPNService.EXTRA_START_REASON, ".api.ConnectVPN call");
startVPN.setAction(Intent.ACTION_MAIN);
startActivity(startVPN);
}
Expand Down
58 changes: 41 additions & 17 deletions main/src/main/java/de/blinkt/openvpn/core/OpenVPNService.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
package de.blinkt.openvpn.core;

import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import static de.blinkt.openvpn.VpnProfile.EXTRA_PROFILEUUID;
import static de.blinkt.openvpn.VpnProfile.EXTRA_PROFILE_VERSION;
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;
Expand Down Expand Up @@ -70,6 +72,11 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
public static final String START_SERVICE = "de.blinkt.openvpn.START_SERVICE";
public static final String START_SERVICE_STICKY = "de.blinkt.openvpn.START_SERVICE_STICKY";
public static final String ALWAYS_SHOW_NOTIFICATION = "de.blinkt.openvpn.NOTIFICATION_ALWAYS_VISIBLE";

public static final String EXTRA_DO_NOT_REPLACE_RUNNING_VPN = "de.blinkt.openvpn.DO_NOT_REPLACE_RUNNING_VPN";

public static final String EXTRA_START_REASON = "de.blinkt.openvpn.startReason";

public static final String DISCONNECT_VPN = "de.blinkt.openvpn.DISCONNECT_VPN";
public static final String NOTIFICATION_CHANNEL_BG_ID = "openvpn_bg";
public static final String NOTIFICATION_CHANNEL_NEWSTATUS_ID = "openvpn_newstat";
Expand All @@ -86,6 +93,7 @@ public class OpenVPNService extends VpnService implements StateListener, Callbac
private static final int PRIORITY_MAX = 2;
private static boolean mNotificationAlwaysVisible = false;


static class TunConfig {
private final Vector<String> mDnslist = new Vector<>();
private final NetworkSpace mRoutes = new NetworkSpace();
Expand Down Expand Up @@ -554,45 +562,46 @@ private void updateShortCutUsage(VpnProfile profile) {

private VpnProfile fetchVPNProfile(Intent intent)
{
VpnProfile vpnProfile = null;
String startReason;
if (intent != null && intent.hasExtra(getPackageName() + ".profileUUID")) {
String profileUUID = intent.getStringExtra(getPackageName() + ".profileUUID");
int profileVersion = intent.getIntExtra(getPackageName() + ".profileVersion", 0);
startReason = intent.getStringExtra(getPackageName() + ".startReason");
if (intent != null && intent.hasExtra(EXTRA_PROFILEUUID)) {
String profileUUID = intent.getStringExtra(EXTRA_PROFILEUUID);
int profileVersion = intent.getIntExtra(EXTRA_PROFILE_VERSION, 0);
startReason = intent.getStringExtra(EXTRA_START_REASON);
if (startReason == null)
startReason = "(unknown)";
// Try for 10s to get current version of the profile
mProfile = ProfileManager.get(this, profileUUID, profileVersion, 100);
vpnProfile = ProfileManager.get(this, profileUUID, profileVersion, 100);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1) {
updateShortCutUsage(mProfile);
updateShortCutUsage(vpnProfile);
}

} else {
/* The intent is null when we are set as always-on or the service has been restarted. */
mProfile = ProfileManager.getLastConnectedProfile(this);
vpnProfile = ProfileManager.getLastConnectedProfile(this);
startReason = "Using last connected profile (started with null intent, always-on or restart after crash)";
VpnStatus.logInfo(R.string.service_restarted);

/* Got no profile, just stop */
if (mProfile == null) {
if (vpnProfile == null) {
startReason = "could not get last connected profile, using default (started with null intent, always-on or restart after crash)";

Log.d("OpenVPN", "Got no last connected profile on null intent. Assuming always on.");
mProfile = ProfileManager.getAlwaysOnVPN(this);
vpnProfile = ProfileManager.getAlwaysOnVPN(this);


if (mProfile == null) {
if (vpnProfile == null) {
return null;
}
}
/* Do the asynchronous keychain certificate stuff */
mProfile.checkForRestart(this);
vpnProfile.checkForRestart(this);
}
String name = "(null)";
if (mProfile != null)
name = mProfile.getName();
if (vpnProfile != null)
name = vpnProfile.getName();
VpnStatus.logDebug(String.format("Fetched VPN profile (%s) triggered by %s", name, startReason));
return mProfile;
return vpnProfile;
}

private boolean checkVPNPermission(VpnProfile startprofile) {
Expand All @@ -608,7 +617,7 @@ private boolean checkVPNPermission(VpnProfile startprofile) {

Intent launchVPNIntent = new Intent(this, LaunchVPN.class);
launchVPNIntent.putExtra(LaunchVPN.EXTRA_KEY, startprofile.getUUIDString());
launchVPNIntent.putExtra(LaunchVPN.EXTRA_START_REASON, "OpenService lacks permission");
launchVPNIntent.putExtra(EXTRA_START_REASON, "OpenService lacks permission");
launchVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_HIDELOG, true);
launchVPNIntent.addFlags(FLAG_ACTIVITY_NEW_TASK);
launchVPNIntent.setAction(Intent.ACTION_MAIN);
Expand All @@ -633,8 +642,23 @@ private void startOpenVPN(Intent intent, int startId) {
if (!checkVPNPermission(vp))
return;

ProfileManager.setConnectedVpnProfile(this, mProfile);
VpnStatus.setConnectedVPNProfile(mProfile.getUUIDString());
boolean noReplaceRequested = (intent != null) && intent.getBooleanExtra(EXTRA_DO_NOT_REPLACE_RUNNING_VPN, false);


/* we get an empty start request or explicitly get told to not replace the VPN then ignore
* a start request. This avoids OnBootreciver, Always and user quickly clicking to have
* weird race conditions
*/
if (mProfile != null && mProfile == vp && (intent == null || noReplaceRequested))
{
/* we do not want to replace the running VPN */
VpnStatus.logInfo("VPN already running. Ignoring request to start VPN");
return;
}

mProfile = vp;
ProfileManager.setConnectedVpnProfile(this, vp);
VpnStatus.setConnectedVPNProfile(vp.getUUIDString());
keepVPNAlive.scheduleKeepVPNAliveJobService(this, vp);

String nativeLibraryDirectory = getApplicationInfo().nativeLibraryDir;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,8 +100,8 @@ private static boolean writeMiniVPNBinary(Context context, String abi, File mvpn
}


public static void startOpenVpn(VpnProfile startprofile, Context context, String startReason) {
Intent startVPN = startprofile.getStartServiceIntent(context, startReason);
public static void startOpenVpn(VpnProfile startprofile, Context context, String startReason, boolean replace_running_vpn) {
Intent startVPN = startprofile.getStartServiceIntent(context, startReason, replace_running_vpn);
if (startVPN != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
//noinspection NewApi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public boolean onStartJob(JobParameters jobParameters) {
unscheduleKeepVPNAliveJobService(this);
return false;
}
VPNLaunchHelper.startOpenVpn(vp, getApplicationContext(), "VPN keep alive Job");
VPNLaunchHelper.startOpenVpn(vp, getApplicationContext(), "VPN keep alive Job", false);
} else {
VpnStatus.logDebug("Keepalive service called but VPN still connected.");
}
Expand Down
2 changes: 1 addition & 1 deletion main/src/ui/java/de/blinkt/openvpn/OpenVPNTileService.java
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public void onServiceDisconnected(ComponentName componentName) {
@SuppressLint("Override")
@TargetApi(Build.VERSION_CODES.N)
void launchVPN(VpnProfile profile, Context context) {
VPNLaunchHelper.startOpenVpn(profile, getBaseContext(), "QuickTile");
VPNLaunchHelper.startOpenVpn(profile, getBaseContext(), "QuickTile", true);
}

@TargetApi(Build.VERSION_CODES.N)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

package de.blinkt.openvpn.activities;

import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_START_REASON;

import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
Expand Down Expand Up @@ -126,7 +128,7 @@ private void setupShortcut(VpnProfile profile) {
Intent shortcutIntent = new Intent(Intent.ACTION_MAIN);
shortcutIntent.setClass(this, LaunchVPN.class);
shortcutIntent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
shortcutIntent.putExtra(LaunchVPN.EXTRA_START_REASON, "shortcut");
shortcutIntent.putExtra(EXTRA_START_REASON, "shortcut");

// Then, set up the container intent (the response to the caller)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -538,7 +538,7 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
(dialog1, which) -> {
Intent intent = new Intent(getActivity(), LaunchVPN.class);
intent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUIDString());
intent.putExtra(LaunchVPN.EXTRA_START_REASON, "restart from logwindow");
intent.putExtra(OpenVPNService.EXTRA_START_REASON, "restart from logwindow");
intent.setAction(Intent.ACTION_MAIN);
startActivity(intent);
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import static de.blinkt.openvpn.core.ConnectionStatus.LEVEL_WAITING_FOR_USER_INPUT;
import static de.blinkt.openvpn.core.OpenVPNService.DISCONNECT_VPN;
import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_CHALLENGE_TXT;
import static de.blinkt.openvpn.core.OpenVPNService.EXTRA_START_REASON;


public class VPNProfileList extends ListFragment implements OnClickListener, VpnStatus.StateListener {
Expand Down Expand Up @@ -242,7 +243,7 @@ ShortcutInfo createShortcut(VpnProfile profile) {
shortcutIntent.setClass(requireContext(), LaunchVPN.class);
shortcutIntent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
shortcutIntent.setAction(Intent.ACTION_MAIN);
shortcutIntent.putExtra(LaunchVPN.EXTRA_START_REASON, "shortcut");
shortcutIntent.putExtra(EXTRA_START_REASON, "shortcut");
shortcutIntent.putExtra("EXTRA_HIDELOG", true);

PersistableBundle versionExtras = new PersistableBundle();
Expand Down Expand Up @@ -563,7 +564,7 @@ private void startVPN(VpnProfile profile) {

Intent intent = new Intent(getActivity(), LaunchVPN.class);
intent.putExtra(LaunchVPN.EXTRA_KEY, profile.getUUID().toString());
intent.putExtra(LaunchVPN.EXTRA_START_REASON, "main profile list");
intent.putExtra(EXTRA_START_REASON, "main profile list");
intent.setAction(Intent.ACTION_MAIN);
startActivity(intent);
}
Expand Down

0 comments on commit b4b37f1

Please sign in to comment.