summaryrefslogtreecommitdiff
path: root/app/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java
diff options
context:
space:
mode:
Diffstat (limited to 'app/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java')
-rw-r--r--app/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java317
1 files changed, 317 insertions, 0 deletions
diff --git a/app/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java b/app/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java
new file mode 100644
index 00000000..928a85eb
--- /dev/null
+++ b/app/src/main/java/de/blinkt/openvpn/api/ExternalOpenVPNService.java
@@ -0,0 +1,317 @@
+package de.blinkt.openvpn.api;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.lang.ref.WeakReference;
+import java.util.LinkedList;
+import java.util.List;
+
+import android.annotation.TargetApi;
+import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+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.*;
+import de.blinkt.openvpn.R;
+import de.blinkt.openvpn.VpnProfile;
+import de.blinkt.openvpn.core.ConfigParser;
+import de.blinkt.openvpn.core.ConfigParser.ConfigParseError;
+import de.blinkt.openvpn.core.VpnStatus;
+import de.blinkt.openvpn.core.VpnStatus.ConnectionStatus;
+import de.blinkt.openvpn.core.VpnStatus.StateListener;
+import de.blinkt.openvpn.core.OpenVpnService;
+import de.blinkt.openvpn.core.OpenVpnService.LocalBinder;
+import de.blinkt.openvpn.core.ProfileManager;
+import de.blinkt.openvpn.core.VPNLaunchHelper;
+
+@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1)
+public class ExternalOpenVPNService extends Service implements StateListener {
+
+ private static final int SEND_TOALL = 0;
+
+ final RemoteCallbackList<IOpenVPNStatusCallback> mCallbacks =
+ new RemoteCallbackList<IOpenVPNStatusCallback>();
+
+ private OpenVpnService mService;
+ private ExternalAppDatabase mExtAppDb;
+
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+
+
+ @Override
+ public void onServiceConnected(ComponentName className,
+ IBinder service) {
+ // We've bound to LocalService, cast the IBinder and get LocalService instance
+ LocalBinder binder = (LocalBinder) service;
+ mService = binder.getService();
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName arg0) {
+ mService = null;
+ }
+
+ };
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ VpnStatus.addStateListener(this);
+ mExtAppDb = new ExternalAppDatabase(this);
+
+ Intent intent = new Intent(getBaseContext(), OpenVpnService.class);
+ intent.setAction(OpenVpnService.START_SERVICE);
+
+ bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
+ mHandler.setService(this);
+ }
+
+ private final IOpenVPNAPIService.Stub mBinder = new IOpenVPNAPIService.Stub() {
+
+ private void checkOpenVPNPermission() throws SecurityRemoteException {
+ PackageManager pm = getPackageManager();
+
+ for (String apppackage : mExtAppDb.getExtAppList()) {
+ ApplicationInfo app;
+ try {
+ app = pm.getApplicationInfo(apppackage, 0);
+ if (Binder.getCallingUid() == app.uid) {
+ return;
+ }
+ } catch (NameNotFoundException e) {
+ // App not found. Remove it from the list
+ mExtAppDb.removeApp(apppackage);
+ }
+
+ }
+ throw new SecurityException("Unauthorized OpenVPN API Caller");
+ }
+
+ @Override
+ public List<APIVpnProfile> getProfiles() throws RemoteException {
+ checkOpenVPNPermission();
+
+ ProfileManager pm = ProfileManager.getInstance(getBaseContext());
+
+ List<APIVpnProfile> profiles = new LinkedList<APIVpnProfile>();
+
+ for (VpnProfile vp : pm.getProfiles())
+ profiles.add(new APIVpnProfile(vp.getUUIDString(), vp.mName, vp.mUserEditable));
+
+ return profiles;
+ }
+
+ @Override
+ public void startProfile(String profileUUID) throws RemoteException {
+ checkOpenVPNPermission();
+
+ Intent shortVPNIntent = new Intent(Intent.ACTION_MAIN);
+ shortVPNIntent.setClass(getBaseContext(), de.blinkt.openvpn.LaunchVPN.class);
+ shortVPNIntent.putExtra(de.blinkt.openvpn.LaunchVPN.EXTRA_KEY, profileUUID);
+ shortVPNIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(shortVPNIntent);
+ }
+
+ public void startVPN(String inlineconfig) throws RemoteException {
+ checkOpenVPNPermission();
+
+ ConfigParser cp = new ConfigParser();
+ try {
+ cp.parseConfig(new StringReader(inlineconfig));
+ VpnProfile vp = cp.convertProfile();
+ if (vp.checkProfile(getApplicationContext()) != R.string.no_error_found)
+ throw new RemoteException(getString(vp.checkProfile(getApplicationContext())));
+
+
+ ProfileManager.setTemporaryProfile(vp);
+ VPNLaunchHelper.startOpenVpn(vp, getBaseContext());
+
+
+ } catch (IOException e) {
+ throw new RemoteException(e.getMessage());
+ } catch (ConfigParseError e) {
+ throw new RemoteException(e.getMessage());
+ }
+ }
+
+ @Override
+ public boolean addVPNProfile(String name, String config) throws RemoteException {
+ checkOpenVPNPermission();
+
+ ConfigParser cp = new ConfigParser();
+ try {
+ cp.parseConfig(new StringReader(config));
+ VpnProfile vp = cp.convertProfile();
+ vp.mName = name;
+ ProfileManager pm = ProfileManager.getInstance(getBaseContext());
+ pm.addProfile(vp);
+ } catch (IOException e) {
+ VpnStatus.logException(e);
+ return false;
+ } catch (ConfigParseError e) {
+ VpnStatus.logException(e);
+ return false;
+ }
+
+ return true;
+ }
+
+
+ @Override
+ public Intent prepare(String packagename) {
+ if (new ExternalAppDatabase(ExternalOpenVPNService.this).isAllowed(packagename))
+ return null;
+
+ Intent intent = new Intent();
+ intent.setClass(ExternalOpenVPNService.this, ConfirmDialog.class);
+ return intent;
+ }
+
+ @Override
+ public Intent prepareVPNService() throws RemoteException {
+ checkOpenVPNPermission();
+
+ if (VpnService.prepare(ExternalOpenVPNService.this) == null)
+ return null;
+ else
+ return new Intent(getBaseContext(), GrantPermissionsActivity.class);
+ }
+
+
+ @Override
+ public void registerStatusCallback(IOpenVPNStatusCallback cb)
+ throws RemoteException {
+ checkOpenVPNPermission();
+
+ if (cb != null) {
+ cb.newStatus(mMostRecentState.vpnUUID, mMostRecentState.state,
+ mMostRecentState.logmessage, mMostRecentState.level.name());
+ mCallbacks.register(cb);
+ }
+
+
+ }
+
+ @Override
+ public void unregisterStatusCallback(IOpenVPNStatusCallback cb)
+ throws RemoteException {
+ checkOpenVPNPermission();
+
+ if (cb != null)
+ mCallbacks.unregister(cb);
+ }
+
+ @Override
+ public void disconnect() throws RemoteException {
+ checkOpenVPNPermission();
+ if (mService != null && mService.getManagement() != null)
+ mService.getManagement().stopVPN();
+ }
+
+ @Override
+ public void pause() throws RemoteException {
+ checkOpenVPNPermission();
+ if (mService != null)
+ mService.userPause(true);
+ }
+
+ @Override
+ public void resume() throws RemoteException {
+ checkOpenVPNPermission();
+ if (mService != null)
+ mService.userPause(false);
+
+ }
+ };
+
+
+ private UpdateMessage mMostRecentState;
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mCallbacks.kill();
+ unbindService(mConnection);
+ VpnStatus.removeStateListener(this);
+ }
+
+ class UpdateMessage {
+ public String state;
+ public String logmessage;
+ public ConnectionStatus level;
+ public String vpnUUID;
+
+ public UpdateMessage(String state, String logmessage, ConnectionStatus level) {
+ this.state = state;
+ this.logmessage = logmessage;
+ this.level = level;
+ }
+ }
+
+ @Override
+ public void updateState(String state, String logmessage, int resid, ConnectionStatus level) {
+ mMostRecentState = new UpdateMessage(state, logmessage, level);
+ if (ProfileManager.getLastConnectedVpn() != null)
+ mMostRecentState.vpnUUID = ProfileManager.getLastConnectedVpn().getUUIDString();
+
+ Message msg = mHandler.obtainMessage(SEND_TOALL, mMostRecentState);
+ msg.sendToTarget();
+
+ }
+
+ private static final OpenVPNServiceHandler mHandler = new OpenVPNServiceHandler();
+
+
+ static class OpenVPNServiceHandler extends Handler {
+ WeakReference<ExternalOpenVPNService> service = null;
+
+ private void setService(ExternalOpenVPNService eos) {
+ service = new WeakReference<ExternalOpenVPNService>(eos);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+
+ RemoteCallbackList<IOpenVPNStatusCallback> callbacks;
+ switch (msg.what) {
+ case SEND_TOALL:
+ if (service == null || service.get() == null)
+ return;
+
+ callbacks = service.get().mCallbacks;
+
+
+ // Broadcast to all clients the new value.
+ final int N = callbacks.beginBroadcast();
+ for (int i = 0; i < N; i++) {
+ try {
+ sendUpdate(callbacks.getBroadcastItem(i), (UpdateMessage) msg.obj);
+ } catch (RemoteException e) {
+ // The RemoteCallbackList will take care of removing
+ // the dead object for us.
+ }
+ }
+ callbacks.finishBroadcast();
+ break;
+ }
+ }
+
+ private void sendUpdate(IOpenVPNStatusCallback broadcastItem,
+ UpdateMessage um) throws RemoteException {
+ broadcastItem.newStatus(um.vpnUUID, um.state, um.logmessage, um.level.name());
+ }
+ }
+
+
+} \ No newline at end of file