diff options
| author | Arne Schwabe <arne@rfc2549.org> | 2013-02-09 17:03:27 +0100 | 
|---|---|---|
| committer | Arne Schwabe <arne@rfc2549.org> | 2013-02-09 17:03:27 +0100 | 
| commit | c89414179f77982751064a5709122913c3ffd6c4 (patch) | |
| tree | 225211a18ce80513c4b05a9525538444b563f18b | |
| parent | 9fab59b5c4b928989eec21bd598c01e5234a18d0 (diff) | |
Merge non OpenVPN3 specific into main
| -rw-r--r-- | .hgignore | 5 | ||||
| -rw-r--r-- | jni/jbcrypto.cpp | 4 | ||||
| -rwxr-xr-x | res/values/strings.xml | 1 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/CIDRIP.java | 6 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/LogWindow.java | 38 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/NetworkSateReceiver.java | 16 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVPN.java | 9 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVPNMangement.java | 13 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVpnManagementThread.java | 120 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVpnService.java | 123 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/ShowConfigFragment.java | 32 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/VpnProfile.java | 148 | 
12 files changed, 338 insertions, 177 deletions
| @@ -24,7 +24,7 @@ openvpn/build/msvc/Makefile.in  openvpn/src/openvpn/.deps  openvpn/src/compat/.deps  *.o - +ovpn3  *.patch  openvpn/distro/Makefile.in  openvpn/distro/rpm/Makefile.in @@ -62,4 +62,5 @@ ics-openvpn.zip  zh-CN.zip  zh-TW.zip  google-breakpad/ -id.zip
\ No newline at end of file +id.zip +ovpn3/boost
\ No newline at end of file diff --git a/jni/jbcrypto.cpp b/jni/jbcrypto.cpp index 8bc6fb8d..77382fb9 100644 --- a/jni/jbcrypto.cpp +++ b/jni/jbcrypto.cpp @@ -17,7 +17,7 @@  extern "C" { -jbyteArray Java_de_blinkt_openvpn_OpenVpnManagementThread_rsasign(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef); +jbyteArray Java_de_blinkt_openvpn_VpnProfile_rsasign(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef);  }  int jniThrowException(JNIEnv* env, const char* className, const char* msg) { @@ -41,7 +41,7 @@ int jniThrowException(JNIEnv* env, const char* className, const char* msg) {  } -jbyteArray Java_de_blinkt_openvpn_OpenVpnManagementThread_rsasign(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef) { +jbyteArray Java_de_blinkt_openvpn_VpnProfile_rsasign(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef) {  	//	EVP_MD_CTX* ctx = reinterpret_cast<EVP_MD_CTX*>(ctxRef);  	EVP_PKEY* pkey = reinterpret_cast<EVP_PKEY*>(pkeyRef); diff --git a/res/values/strings.xml b/res/values/strings.xml index da98236a..8dc15806 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -247,6 +247,7 @@      <string name="state_assign_ip">Assigning IP addresses</string>      <string name="state_add_routes">Adding routes</string>      <string name="state_connected">Connected</string> +    <string name="state_disconnected">Disconnect</string>      <string name="state_reconnecting">Reconnecting</string>      <string name="state_exiting">Exiting</string>      <string name="state_noprocess">Not running</string> diff --git a/src/de/blinkt/openvpn/CIDRIP.java b/src/de/blinkt/openvpn/CIDRIP.java index d3939dfc..41b56d4b 100644 --- a/src/de/blinkt/openvpn/CIDRIP.java +++ b/src/de/blinkt/openvpn/CIDRIP.java @@ -5,6 +5,8 @@ import java.util.Locale;  class CIDRIP{  	String mIp;  	int len; +	 +	  	public CIDRIP(String ip, String mask){  		mIp=ip;  		long netmask=getInt(mask); @@ -26,6 +28,10 @@ class CIDRIP{  		}  	} +	public CIDRIP(String address, int prefix_length) { +		len = prefix_length; +		mIp = address; +	}  	@Override  	public String toString() {  		return String.format(Locale.ENGLISH,"%s/%d",mIp,len); diff --git a/src/de/blinkt/openvpn/LogWindow.java b/src/de/blinkt/openvpn/LogWindow.java index 8d6df5e5..4d2047f8 100644 --- a/src/de/blinkt/openvpn/LogWindow.java +++ b/src/de/blinkt/openvpn/LogWindow.java @@ -7,14 +7,17 @@ import android.app.AlertDialog.Builder;  import android.app.ListActivity;  import android.content.ClipData;  import android.content.ClipboardManager; +import android.content.ComponentName;  import android.content.Context;  import android.content.DialogInterface;  import android.content.DialogInterface.OnClickListener;  import android.content.Intent; +import android.content.ServiceConnection;  import android.database.DataSetObserver;  import android.os.Bundle;  import android.os.Handler;  import android.os.Handler.Callback; +import android.os.IBinder;  import android.os.Message;  import android.view.Menu;  import android.view.MenuInflater; @@ -30,10 +33,31 @@ import android.widget.Toast;  import de.blinkt.openvpn.OpenVPN.LogItem;  import de.blinkt.openvpn.OpenVPN.LogListener;  import de.blinkt.openvpn.OpenVPN.StateListener; +import de.blinkt.openvpn.OpenVpnService.LocalBinder;  public class LogWindow extends ListActivity implements StateListener  {  	private static final int START_VPN_CONFIG = 0;  	private String[] mBconfig=null; +	protected OpenVpnService mService; +	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; +		} + +	}; +  	class LogWindowListAdapter implements ListAdapter, LogListener, Callback { @@ -198,6 +222,7 @@ public class LogWindow extends ListActivity implements StateListener  {  	private LogWindowListAdapter ladapter;  	private TextView mSpeedView; +  	@Override  	public boolean onOptionsItemSelected(MenuItem item) {  		if(item.getItemId()==R.id.clearlog) { @@ -213,7 +238,8 @@ public class LogWindow extends ListActivity implements StateListener  {  				@Override  				public void onClick(DialogInterface dialog, int which) {  					ProfileManager.setConntectedVpnProfileDisconnected(getApplicationContext()); -					OpenVpnManagementThread.stopOpenVPN();		 +					if(mService.getManagement()!=null) +						mService.getManagement().stopVPN();  				}  			}); @@ -335,6 +361,11 @@ public class LogWindow extends ListActivity implements StateListener  {  		mSpeedView = (TextView) findViewById(R.id.speed);  		getActionBar().setDisplayHomeAsUpEnabled(true); +        Intent intent = new Intent(getBaseContext(), OpenVpnService.class); +        intent.setAction(OpenVpnService.START_SERVICE); + +        bindService(intent, mConnection, Context.BIND_AUTO_CREATE); +  	}  	@Override @@ -346,6 +377,8 @@ public class LogWindow extends ListActivity implements StateListener  {  				String prefix=getString(resid) + ":";  				if (status.equals("BYTECOUNT") || status.equals("NOPROCESS") )  					prefix=""; +				if (resid==R.string.unknown_state) +					prefix+=status;  				mSpeedView.setText(prefix + logmessage);  			}  		}); @@ -354,8 +387,9 @@ public class LogWindow extends ListActivity implements StateListener  {  	@Override  	protected void onDestroy() { -		super.onDestroy(); +		unbindService(mConnection);  		OpenVPN.removeLogListener(ladapter); +		super.onDestroy();  	}  } diff --git a/src/de/blinkt/openvpn/NetworkSateReceiver.java b/src/de/blinkt/openvpn/NetworkSateReceiver.java index e20c8e52..487639a9 100644 --- a/src/de/blinkt/openvpn/NetworkSateReceiver.java +++ b/src/de/blinkt/openvpn/NetworkSateReceiver.java @@ -11,13 +11,13 @@ import android.preference.PreferenceManager;  public class NetworkSateReceiver extends BroadcastReceiver {
  	private int lastNetwork=-1;
 -	private OpenVpnManagementThread mManangement;
 +	private OpenVPNMangement mManangement;
  	private String lastStateMsg=null;
 -	public NetworkSateReceiver(OpenVpnManagementThread managementThread) {
 +	public NetworkSateReceiver(OpenVPNMangement magnagement) {
  		super();
 -		mManangement = managementThread;
 +		mManangement = magnagement;
  	}
  	@Override
 @@ -57,15 +57,19 @@ public class NetworkSateReceiver extends BroadcastReceiver {  		if(networkInfo!=null && networkInfo.getState() == State.CONNECTED) {
  				int newnet = networkInfo.getType();
 -				if(sendusr1 && lastNetwork!=newnet)
 -					mManangement.reconnect();
 +				if(sendusr1 && lastNetwork!=newnet) {
 +					if (lastNetwork==-1)
 +						mManangement.resume();
 +					else
 +						mManangement.reconnect();
 +				}
  				lastNetwork = newnet;
  		} else if (networkInfo==null) {
  			// Not connected, stop openvpn, set last connected network to no network
  			lastNetwork=-1;
  			if(sendusr1)
 -				mManangement.signalusr1();
 +				mManangement.pause();
  		}
  		if(!netstatestring.equals(lastStateMsg))
 diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java index c1616f2d..2ca2d259 100644 --- a/src/de/blinkt/openvpn/OpenVPN.java +++ b/src/de/blinkt/openvpn/OpenVPN.java @@ -173,6 +173,8 @@ public class OpenVPN {  			return R.string.state_add_routes;  		else if (state.equals("CONNECTED"))  			return R.string.state_connected; +		else if (state.equals("DISCONNECTED")) +			return R.string.state_disconnected;  		else if (state.equals("RECONNECTING"))  			return R.string.state_reconnecting;  		else if (state.equals("EXITING")) @@ -257,7 +259,12 @@ public class OpenVPN {  		newlogItem(new LogItem(LogItem.ERROR, ressourceId,args));  	} -	public static void updateByteCount(long in, long out, long diffin, long diffout) { +	public static void updateByteCount(long in, long out) { +		long lastIn = mlastByteCount[0]; +		long lastOut = mlastByteCount[1]; +		long diffin = in - lastIn; +		long diffout = out - lastOut; +		  		mlastByteCount = new long[] {in,out,diffin,diffout};  		for(ByteCountListener bcl:byteCountListener){  			bcl.updateByteCount(in, out, diffin,diffout); diff --git a/src/de/blinkt/openvpn/OpenVPNMangement.java b/src/de/blinkt/openvpn/OpenVPNMangement.java new file mode 100644 index 00000000..0c6d7163 --- /dev/null +++ b/src/de/blinkt/openvpn/OpenVPNMangement.java @@ -0,0 +1,13 @@ +package de.blinkt.openvpn; + +public interface OpenVPNMangement { + +	void reconnect(); + +	void pause(); + +	void resume(); + +	boolean stopVPN(); + +} diff --git a/src/de/blinkt/openvpn/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/OpenVpnManagementThread.java index 381fee82..e4528132 100644 --- a/src/de/blinkt/openvpn/OpenVpnManagementThread.java +++ b/src/de/blinkt/openvpn/OpenVpnManagementThread.java @@ -7,28 +7,18 @@ import java.lang.reflect.InvocationTargetException;  import java.lang.reflect.Method;
  import java.net.InetSocketAddress;
  import java.net.SocketAddress;
 -import java.security.InvalidKeyException;
 -import java.security.NoSuchAlgorithmException;
 -import java.security.PrivateKey;
  import java.util.LinkedList;
  import java.util.Locale;
  import java.util.Vector;
 -import javax.crypto.BadPaddingException;
 -import javax.crypto.Cipher;
 -import javax.crypto.IllegalBlockSizeException;
 -import javax.crypto.NoSuchPaddingException;
 -
  import android.content.SharedPreferences;
  import android.net.LocalServerSocket;
  import android.net.LocalSocket;
 -import android.os.Build;
  import android.os.ParcelFileDescriptor;
  import android.preference.PreferenceManager;
 -import android.util.Base64;
  import android.util.Log;
 -public class OpenVpnManagementThread implements Runnable {
 +public class OpenVpnManagementThread implements Runnable, OpenVPNMangement {
  	private static final String TAG = "openvpn";
  	private LocalSocket mSocket;
 @@ -36,8 +26,6 @@ public class OpenVpnManagementThread implements Runnable {  	private OpenVpnService mOpenVPNService;
  	private LinkedList<FileDescriptor> mFDList=new LinkedList<FileDescriptor>();
  	private int mBytecountinterval=2;
 -	private long mLastIn=0; 
 -	private long mLastOut=0;
  	private LocalServerSocket mServerSocket;
  	private boolean mReleaseHold=true;
  	private boolean mWaitingForRelease=false;
 @@ -46,7 +34,6 @@ public class OpenVpnManagementThread implements Runnable {  	private static Vector<OpenVpnManagementThread> active=new Vector<OpenVpnManagementThread>();
  	static private native void jniclose(int fdint);
 -	static private native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException;
  	public OpenVpnManagementThread(VpnProfile profile, LocalServerSocket mgmtsocket, OpenVpnService openVpnService) {
  		mProfile = profile;
 @@ -285,13 +272,7 @@ public class OpenVpnManagementThread implements Runnable {  		long in = Long.parseLong(argument.substring(0, comma));
  		long out = Long.parseLong(argument.substring(comma+1));
 -		long diffin = in - mLastIn; 
 -		long diffout = out - mLastOut;
 -
 -		mLastIn=in;
 -		mLastOut=out;
 -
 -		OpenVPN.updateByteCount(in,out,diffin, diffout);
 +		OpenVPN.updateByteCount(in,out);
  	}
 @@ -449,7 +430,7 @@ public class OpenVpnManagementThread implements Runnable {  	}
 -	public static boolean stopOpenVPN() {
 +	private static boolean stopOpenVPN() {
  		boolean sendCMD=false;
  		for (OpenVpnManagementThread mt: active){
  			mt.managmentCommand("signal SIGINT\n");
 @@ -477,89 +458,24 @@ public class OpenVpnManagementThread implements Runnable {  	private void processSignCommand(String b64data) {
 -		PrivateKey privkey = mProfile.getKeystoreKey();
 -		Exception err =null;
 -
 -		byte[] data = Base64.decode(b64data, Base64.DEFAULT);
 -
 -		// The Jelly Bean *evil* Hack
 -		// 4.2 implements the RSA/ECB/PKCS1PADDING in the OpenSSLprovider
 -		if(Build.VERSION.SDK_INT==Build.VERSION_CODES.JELLY_BEAN){
 -			processSignJellyBeans(privkey,data);
 -			return;
 -		}
 -
 -
 -		try{
 -
 -
 -			Cipher rsasinger = Cipher.getInstance("RSA/ECB/PKCS1PADDING");
 -
 -			rsasinger.init(Cipher.ENCRYPT_MODE, privkey);
 -
 -			byte[] signed_bytes = rsasinger.doFinal(data);
 -			String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP);
 -			managmentCommand("rsa-sig\n");
 -			managmentCommand(signed_string);
 -			managmentCommand("\nEND\n");
 -		} catch (NoSuchAlgorithmException e){
 -			err =e;
 -		} catch (InvalidKeyException e) {
 -			err =e;
 -		} catch (NoSuchPaddingException e) {
 -			err =e;
 -		} catch (IllegalBlockSizeException e) {
 -			err =e;
 -		} catch (BadPaddingException e) {
 -			err =e;
 -		}
 -		if(err !=null) {
 -			OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage());
 -		}
 -
 +		String signed_string = mProfile.getSignedData(b64data);
 +		managmentCommand("rsa-sig\n");
 +		managmentCommand(signed_string);
 +		managmentCommand("\nEND\n");
  	}
 +	@Override
 +	public void pause() {
 +		signalusr1();
 +	}
 -	private void processSignJellyBeans(PrivateKey privkey, byte[] data) {
 -		Exception err =null;
 -		try {
 -			Method[] allm = privkey.getClass().getSuperclass().getDeclaredMethods();
 -			System.out.println(allm);
 -			Method getKey = privkey.getClass().getSuperclass().getDeclaredMethod("getOpenSSLKey");
 -			getKey.setAccessible(true);
 -
 -			// Real object type is OpenSSLKey
 -			Object opensslkey = getKey.invoke(privkey);
 -
 -			getKey.setAccessible(false);
 -
 -			Method getPkeyContext = opensslkey.getClass().getDeclaredMethod("getPkeyContext");
 -
 -			// integer pointer to EVP_pkey
 -			getPkeyContext.setAccessible(true);
 -			int pkey = (Integer) getPkeyContext.invoke(opensslkey);
 -			getPkeyContext.setAccessible(false);
 -
 -			byte[] signed_bytes = rsasign(data, pkey); 
 -			String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP);
 -			managmentCommand("rsa-sig\n");
 -			managmentCommand(signed_string);
 -			managmentCommand("\nEND\n");
 -
 -		} catch (NoSuchMethodException e) {
 -			err=e;
 -		} catch (IllegalArgumentException e) {
 -			err=e;
 -		} catch (IllegalAccessException e) {
 -			err=e;
 -		} catch (InvocationTargetException e) {
 -			err=e;
 -		} catch (InvalidKeyException e) {
 -			err=e;
 -		}
 -		if(err !=null) {
 -			OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage());
 -		}
 +	@Override
 +	public void resume() {
 +		releaseHold();
 +	}
 +	@Override
 +	public boolean stopVPN() {
 +		return stopOpenVPN();
  	}
  }
 diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index 6103ff89..ce9f75a1 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -27,6 +27,7 @@ import android.app.PendingIntent;  import android.content.Context;  import android.content.Intent;  import android.content.IntentFilter; +import android.content.SharedPreferences;  import android.net.ConnectivityManager;  import android.net.LocalServerSocket;  import android.net.LocalSocket; @@ -38,6 +39,7 @@ import android.os.Handler.Callback;  import android.os.IBinder;  import android.os.Message;  import android.os.ParcelFileDescriptor; +import android.preference.PreferenceManager;  import de.blinkt.openvpn.OpenVPN.ByteCountListener;  import de.blinkt.openvpn.OpenVPN.StateListener; @@ -60,9 +62,6 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac  	private CIDRIP mLocalIP=null; -	private OpenVpnManagementThread mManagementThread; - -	private Thread mSocketManagerThread;  	private int mMtu;  	private String mLocalIPv6=null;  	private NetworkSateReceiver mNetworkStateReceiver; @@ -86,6 +85,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac  	private static boolean mNotificationalwaysVisible=false;  	private final IBinder mBinder = new LocalBinder(); +	private boolean mOvpn3; +	private Thread mSocketManagerThread; +	private OpenVPNMangement mManagement;  	public class LocalBinder extends Binder {  		public OpenVpnService getService() { @@ -105,7 +107,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac  	@Override  	public void onRevoke() { -		OpenVpnManagementThread.stopOpenVPN(); +		mManagement.stopVPN();  		endVpnService();  	} @@ -119,10 +121,13 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac  		OpenVPN.logBuilderConfig(null);  		OpenVPN.removeStateListener(this);  		OpenVPN.removeByteCountListener(this); +		unregisterNetworkStateReceiver();  		ProfileManager.setConntectedVpnProfileDisconnected(this);  		if(!mStarting) { -			stopSelf(); -			stopForeground(true); +			stopForeground(!mNotificationalwaysVisible); + +			if( !mNotificationalwaysVisible) +				stopSelf();  		}  	} @@ -171,7 +176,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac  				// PRIORITY_MIN == -2  				setpriority.invoke(nbuilder, -2 ); -				nbuilder.setUsesChronometer(true); +				Method setUsesChronometer = nbuilder.getClass().getMethod("setUsesChronometer", boolean.class); +				setUsesChronometer.invoke(nbuilder,true); +  				/*				PendingIntent cancelconnet=null;  				nbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel,  @@ -229,14 +236,20 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac  	} -	void registerNetworkStateReceiver() { +	void registerNetworkStateReceiver(OpenVPNMangement magnagement) {  		// Registers BroadcastReceiver to track network connection changes.  		IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); -		mNetworkStateReceiver = new NetworkSateReceiver(mManagementThread); +		mNetworkStateReceiver = new NetworkSateReceiver(magnagement);  		this.registerReceiver(mNetworkStateReceiver, filter);  	} - +	void unregisterNetworkStateReceiver() { +		if(mNetworkStateReceiver!=null) +			this.unregisterReceiver(mNetworkStateReceiver); +		mNetworkStateReceiver=null; +	} +	 +	  	@Override  	public int onStartCommand(Intent intent, int flags, int startId) { @@ -263,18 +276,16 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac  		showNotification("Starting VPN " + mProfile.mName,"Starting VPN " + mProfile.mName, false,0,LEVEL_NOTCONNECTED); - -  		// Set a flag that we are starting a new VPN  		mStarting=true;  		// Stop the previous session by interrupting the thread. -		if(OpenVpnManagementThread.stopOpenVPN()){ -			// an old was asked to exit, wait 2s +		if(mManagement!=null && mManagement.stopVPN()) +			// an old was asked to exit, wait 1s  			try {  				Thread.sleep(1000);  			} catch (InterruptedException e) {  			} -		} +  		if (mProcessThread!=null) {  			mProcessThread.interrupt(); @@ -288,33 +299,72 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac  		// Open the Management Interface -		LocalServerSocket mgmtsocket = openManagmentInterface(8); - -		if(mgmtsocket!=null) { -			// start a Thread that handles incoming messages of the managment socket -			mManagementThread=new OpenVpnManagementThread(mProfile,mgmtsocket,this); -			mSocketManagerThread = new Thread(mManagementThread,"OpenVPNMgmtThread"); -			mSocketManagerThread.start(); -			OpenVPN.logInfo("started Socket Thread"); -			registerNetworkStateReceiver(); +		if(!mOvpn3) { +			LocalServerSocket mgmtsocket = openManagmentInterface(8); + +			if(mgmtsocket!=null) { +				// start a Thread that handles incoming messages of the managment socket +				OpenVpnManagementThread ovpnmgmthread = new OpenVpnManagementThread(mProfile,mgmtsocket,this); +				mSocketManagerThread = new Thread(ovpnmgmthread,"OpenVPNMgmtThread"); +				mSocketManagerThread.start(); +				mManagement= ovpnmgmthread; +				OpenVPN.logInfo("started Socket Thread"); +			}  		} -  		// Start a new session by creating a new thread. -		OpenVPNThread processThread = new OpenVPNThread(this, argv,nativelibdir); +		SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);         + +		mOvpn3 = prefs.getBoolean("ovpn3", false); + +		Runnable processThread; +		if(mOvpn3) { +			 +			OpenVPNMangement mOpenVPN3 = instantiateOpenVPN3Core(); +			processThread = (Runnable) mOpenVPN3; +			mManagement = mOpenVPN3; +	 + +		} else { +			processThread = new OpenVPNThread(this, argv,nativelibdir); +		}  		mProcessThread = new Thread(processThread, "OpenVPNProcessThread");  		mProcessThread.start(); +		registerNetworkStateReceiver(mManagement); + +  		ProfileManager.setConnectedVpnProfile(this, mProfile);  		return START_NOT_STICKY;  	} +	private OpenVPNMangement instantiateOpenVPN3Core() { +		//new OpenVPNThreadv3(this,mProfile); +		try { +			Class cl = Class.forName("Lde/blinkt/openvpn/OpenVPNThreadv3;"); +			return (OpenVPNMangement) cl.getConstructor(OpenVpnService.class,VpnProfile.class).newInstance(this,mProfile); +		} catch (IllegalArgumentException e) { +			e.printStackTrace(); +		} catch (InstantiationException e) { +			e.printStackTrace(); +		} catch (IllegalAccessException e) { +			e.printStackTrace(); +		} catch (InvocationTargetException e) { +			e.printStackTrace(); +		} catch (NoSuchMethodException e) { +			e.printStackTrace(); +		} catch (ClassNotFoundException e) { +			e.printStackTrace(); +		} +		return null; +	} +  	@Override  	public void onDestroy() {  		if (mProcessThread != null) { -			mManagementThread.managmentCommand("signal SIGINT\n"); +			mManagement.stopVPN();  			mProcessThread.interrupt();  		} @@ -452,6 +502,10 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac  	} +	public void addRoute(CIDRIP route) +	{ +		mRoutes.add(route ); +	}  	public void addRoute(String dest, String mask) {  		CIDRIP route = new CIDRIP(dest, mask);		  		if(route.len == 32 && !mask.equals("255.255.255.255")) { @@ -468,6 +522,15 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac  		mRoutesv6.add(extra);		  	} +	public void setMtu(int mtu) { +		mMtu=mtu; +	} + +	public void setLocalIP(CIDRIP cdrip) +	{ +		mLocalIP=cdrip; +	} +  	public void setLocalIP(String local, String netmask,int mtu, String mode) {  		mLocalIP = new CIDRIP(local, netmask); @@ -477,7 +540,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac  			// get the netmask as IP  			long netint = CIDRIP.getInt(netmask);  			if(Math.abs(netint - mLocalIP.getInt()) ==1) { -				if(mode.equals("net30")) +				if("net30".equals(mode))  					mLocalIP.len=30;  				else  					mLocalIP.len=31; @@ -559,7 +622,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac  		}  	} -	public OpenVpnManagementThread getManagementThread() { -		return mManagementThread; +	public OpenVPNMangement getManagement() { +		return mManagement;  	}  } diff --git a/src/de/blinkt/openvpn/ShowConfigFragment.java b/src/de/blinkt/openvpn/ShowConfigFragment.java index dae83438..c9c778df 100644 --- a/src/de/blinkt/openvpn/ShowConfigFragment.java +++ b/src/de/blinkt/openvpn/ShowConfigFragment.java @@ -17,21 +17,41 @@ public class ShowConfigFragment extends Fragment {  	public android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)   	{  		String profileUUID = getArguments().getString(getActivity().getPackageName() + ".profileUUID"); -		VpnProfile vp = ProfileManager.get(profileUUID); +		final VpnProfile vp = ProfileManager.get(profileUUID);  		View v=inflater.inflate(R.layout.viewconfig, container,false); -		TextView cv = (TextView) v.findViewById(R.id.configview); +		final TextView cv = (TextView) v.findViewById(R.id.configview);  		int check=vp.checkProfile(getActivity());  		if(check!=R.string.no_error_found) {  			cv.setText(check);  			configtext = getString(check);  		} -		else {  -			String cfg=vp.getConfigFile(getActivity()); -			configtext= cfg; -			cv.setText(cfg); +		else { +			// Run in own Thread since Keystore does not like to be queried from the main thread + +			cv.setText("Generating config..."); +			startGenConfig(vp, cv);  		}  		return v; +	} + +	private void startGenConfig(final VpnProfile vp, final TextView cv) { +		 +		new Thread() { +			public void run() { +				final String cfg=vp.getConfigFile(getActivity(),false); +				configtext= cfg; +				getActivity().runOnUiThread(new Runnable() { +					 +					@Override +					public void run() { +						cv.setText(cfg);		 +					} +				}); +				 +				 +			}; +		}.start();  	};  	@Override diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index 37e9b2ff..ea034b55 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -9,6 +9,11 @@ import java.io.FileWriter;  import java.io.IOException;  import java.io.InputStream;  import java.io.Serializable; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException;  import java.security.PrivateKey;  import java.security.cert.Certificate;  import java.security.cert.CertificateException; @@ -19,6 +24,11 @@ import java.util.Locale;  import java.util.UUID;  import java.util.Vector; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; +  import org.spongycastle.util.io.pem.PemObject;  import org.spongycastle.util.io.pem.PemWriter; @@ -30,6 +40,7 @@ import android.os.Build;  import android.preference.PreferenceManager;  import android.security.KeyChain;  import android.security.KeyChainException; +import android.util.Base64;  public class VpnProfile implements  Serializable{  	// Parcable @@ -112,9 +123,10 @@ public class VpnProfile implements  Serializable{  	static final String MINIVPN = "miniopenvpn"; -	 - - +	static private native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException; +	static { +		System.loadLibrary("opvpnutil"); +	}  	public void clearDefaults() {  		mServerName="unkown"; @@ -140,11 +152,6 @@ public class VpnProfile implements  Serializable{  			return '"' + escapedString + '"';  	} - -	static final String OVPNCONFIGCA = "android-ca.pem"; -	static final String OVPNCONFIGUSERCERT = "android-user.pem"; - -  	public VpnProfile(String name) {  		mUuid = UUID.randomUUID();  		mName = name; @@ -160,7 +167,7 @@ public class VpnProfile implements  Serializable{  	} -	public String getConfigFile(Context context) +	public String getConfigFile(Context context, boolean configForOvpn3)  	{  		File cacheDir= context.getCacheDir(); @@ -255,10 +262,13 @@ public class VpnProfile implements  Serializable{  		case VpnProfile.TYPE_USERPASS_KEYSTORE:  			cfg+="auth-user-pass\n";  		case VpnProfile.TYPE_KEYSTORE: -			cfg+="ca " + cacheDir.getAbsolutePath() + "/" + OVPNCONFIGCA + "\n"; -			cfg+="cert " + cacheDir.getAbsolutePath() + "/" + OVPNCONFIGUSERCERT + "\n"; -			cfg+="management-external-key\n"; -			 +			if(!configForOvpn3) { +				String[] ks =getKeyStoreCertificates(context); +				cfg+="### From Keystore ####\n"; +				cfg+="<ca>\n" + ks[0] + "</ca>\n"; +				cfg+="<cert>\n" + ks[0] + "</cert>\n"; +				cfg+="management-external-key\n"; +			}  			break;  		case VpnProfile.TYPE_USERPASS:  			cfg+="auth-user-pass\n"; @@ -498,7 +508,7 @@ public class VpnProfile implements  Serializable{  		Intent intent = new Intent(context,OpenVpnService.class);  		if(mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { -			if(!saveCertificates(context)) +			if(getKeyStoreCertificates(context)==null)  				return null;  		} @@ -510,7 +520,7 @@ public class VpnProfile implements  Serializable{  		try {  			FileWriter cfg = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE); -			cfg.write(getConfigFile(context)); +			cfg.write(getConfigFile(context,false));  			cfg.flush();  			cfg.close();  		} catch (IOException e) { @@ -520,7 +530,7 @@ public class VpnProfile implements  Serializable{  		return intent;  	} -	private boolean saveCertificates(Context context) { +	String[] getKeyStoreCertificates(Context context) {  		PrivateKey privateKey = null;  		X509Certificate[] cachain=null;  		try { @@ -553,27 +563,30 @@ public class VpnProfile implements  Serializable{  			} -			FileWriter fout = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGCA); -			PemWriter pw = new PemWriter(fout); + +			StringWriter caout = new StringWriter(); + +			PemWriter pw = new PemWriter(caout);  			for(X509Certificate cert:cachain) {  				pw.writeObject(new PemObject("CERTIFICATE", cert.getEncoded()));  			} -  			pw.close(); +			 +			StringWriter certout = new StringWriter(); + +  			if(cachain.length>= 1){  				X509Certificate usercert = cachain[0]; -				FileWriter userout = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGUSERCERT); - -				PemWriter upw = new PemWriter(userout); +				PemWriter upw = new PemWriter(certout);  				upw.writeObject(new PemObject("CERTIFICATE", usercert.getEncoded()));  				upw.close();  			} -			 -			return true; + +			return new String[] {caout.toString(),certout.toString()};  		} catch (InterruptedException e) {  			e.printStackTrace();  		} catch (FileNotFoundException e) { @@ -590,7 +603,7 @@ public class VpnProfile implements  Serializable{  				}  			}  		} -		return false; +		return null;  	}  	private Certificate getCacertFromFile() throws FileNotFoundException, CertificateException {  		 CertificateFactory certFact = CertificateFactory.getInstance("X.509"); @@ -651,7 +664,7 @@ public class VpnProfile implements  Serializable{  			return null;  		}  	} -	private boolean isUserPWAuth() { +	boolean isUserPWAuth() {  		switch(mAuthenticationType) {  		case TYPE_USERPASS:  		case TYPE_USERPASS_CERTIFICATES: @@ -748,6 +761,89 @@ public class VpnProfile implements  Serializable{  		return mPrivateKey;  	} +	public String getSignedData(String b64data) { +		PrivateKey privkey = getKeystoreKey(); +		Exception err =null; + +		byte[] data = Base64.decode(b64data, Base64.DEFAULT); + +		// The Jelly Bean *evil* Hack +		// 4.2 implements the RSA/ECB/PKCS1PADDING in the OpenSSLprovider +		if(Build.VERSION.SDK_INT==Build.VERSION_CODES.JELLY_BEAN){ +			return processSignJellyBeans(privkey,data); +		} + + +		try{ + + +			Cipher rsasinger = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); + +			rsasinger.init(Cipher.ENCRYPT_MODE, privkey); + +			byte[] signed_bytes = rsasinger.doFinal(data); +			return Base64.encodeToString(signed_bytes, Base64.NO_WRAP); +			 +		} catch (NoSuchAlgorithmException e){ +			err =e; +		} catch (InvalidKeyException e) { +			err =e; +		} catch (NoSuchPaddingException e) { +			err =e; +		} catch (IllegalBlockSizeException e) { +			err =e; +		} catch (BadPaddingException e) { +			err =e; +		} +		if(err !=null) { +			OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage()); +		} +		return null; + +	} + + +	private String processSignJellyBeans(PrivateKey privkey, byte[] data) { +		Exception err =null; +		try { +			Method[] allm = privkey.getClass().getSuperclass().getDeclaredMethods(); +			System.out.println(allm); +			Method getKey = privkey.getClass().getSuperclass().getDeclaredMethod("getOpenSSLKey"); +			getKey.setAccessible(true); + +			// Real object type is OpenSSLKey +			Object opensslkey = getKey.invoke(privkey); + +			getKey.setAccessible(false); + +			Method getPkeyContext = opensslkey.getClass().getDeclaredMethod("getPkeyContext"); + +			// integer pointer to EVP_pkey +			getPkeyContext.setAccessible(true); +			int pkey = (Integer) getPkeyContext.invoke(opensslkey); +			getPkeyContext.setAccessible(false); + +			byte[] signed_bytes = rsasign(data, pkey);  +			return Base64.encodeToString(signed_bytes, Base64.NO_WRAP); +			 +		} catch (NoSuchMethodException e) { +			err=e; +		} catch (IllegalArgumentException e) { +			err=e; +		} catch (IllegalAccessException e) { +			err=e; +		} catch (InvocationTargetException e) { +			err=e; +		} catch (InvalidKeyException e) { +			err=e; +		} +		if(err !=null) { +			OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage()); +		} +		return null; + +	} +  } | 
