diff options
| -rw-r--r-- | AndroidManifest.xml | 4 | ||||
| -rw-r--r-- | res/layout/basic_settings.xml | 1 | ||||
| -rw-r--r-- | res/layout/vpn_list_item.xml | 2 | ||||
| -rw-r--r-- | res/menu/logmenu.xml | 19 | ||||
| -rw-r--r-- | res/menu/vpn_context.xml | 3 | ||||
| -rw-r--r-- | res/values/strings.xml | 12 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/LaunchVPN.java | 5 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/LogWindow.java | 7 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVPN.java | 141 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVPNThread.java | 2 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVpnManagementThread.java | 14 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVpnService.java | 73 | 
12 files changed, 194 insertions, 89 deletions
| diff --git a/AndroidManifest.xml b/AndroidManifest.xml index fe250a8e..75fe58dd 100644 --- a/AndroidManifest.xml +++ b/AndroidManifest.xml @@ -17,8 +17,8 @@  <manifest xmlns:android="http://schemas.android.com/apk/res/android"      package="de.blinkt.openvpn" -    android:versionCode="15" -    android:versionName="0.4.7" > +    android:versionCode="16" +    android:versionName="0.4.8" >      <uses-permission android:name="android.permission.INTERNET" /> diff --git a/res/layout/basic_settings.xml b/res/layout/basic_settings.xml index e19ec148..6d4b8cc1 100644 --- a/res/layout/basic_settings.xml +++ b/res/layout/basic_settings.xml @@ -168,7 +168,6 @@                  android:layout_marginLeft="8dip"                  android:layout_marginRight="8dip"                  android:hint="@string/pw_query_hint" -                                  android:inputType="textPassword" />          </LinearLayout> diff --git a/res/layout/vpn_list_item.xml b/res/layout/vpn_list_item.xml index 75da3cf5..16d7d5bd 100644 --- a/res/layout/vpn_list_item.xml +++ b/res/layout/vpn_list_item.xml @@ -23,7 +23,7 @@      <LinearLayout          android:id="@+id/vpn_list_item_left" -        android:layout_width="wrap_content" +        android:layout_width="0dp"          android:layout_height="match_parent"          android:layout_weight="1"          android:background="?android:attr/selectableItemBackground" diff --git a/res/menu/logmenu.xml b/res/menu/logmenu.xml index 80331c5e..b8fd286b 100644 --- a/res/menu/logmenu.xml +++ b/res/menu/logmenu.xml @@ -5,13 +5,18 @@          android:id="@+id/clearlog"
          android:icon="@drawable/ic_menu_trash_holo_light"
          android:showAsAction="ifRoom|withText"
 -        android:title="@string/clear_log"/>
 -    
 -    <item android:id="@+id/cancel"
 +        android:title="@string/clear_log"
 +        android:titleCondensed="@string/clear"/>
 +    <item
 +        android:id="@+id/cancel"
          android:icon="@android:drawable/ic_menu_close_clear_cancel"
          android:showAsAction="ifRoom|withText"
          android:title="@string/cancel_connection"
 -        />
 -    
 -
 -</menu>
\ No newline at end of file +        android:titleCondensed="@string/cancel"/>
 +    <item
 +        android:id="@+id/info"
 +        android:icon="@android:drawable/ic_menu_info_details"
 +        android:showAsAction="ifRoom|withText"
 +        android:title="@string/show_connection_details"
 +        android:titleCondensed="@string/info"/>
 +
</menu>
\ No newline at end of file diff --git a/res/menu/vpn_context.xml b/res/menu/vpn_context.xml index 477c6a8a..239f1577 100644 --- a/res/menu/vpn_context.xml +++ b/res/menu/vpn_context.xml @@ -18,9 +18,8 @@      <!--  <item          android:id="@+id/connect_vpn"          android:alphabeticShortcut="c" -        android:          android:icon="@android:drawable/ic_media_play" -        android:showAsAction="withText|ifRoom" +        android:showAsAction="ifRoom|withText"          android:title="@string/connect"/>  	-->  </menu>
\ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 53483b80..cf8cc5c8 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -115,7 +115,6 @@      <string name="custom_config_title">Enable Custom Options</string>      <string name="custom_config_summary">Specify custom options. Use with care!</string>      <string name="route_rejected">Route rejected by Android</string> -    <string formatted="false" name="ip_not_cidr">Cannot make sense of %s and %s as IP and CIDR netmask, assuming second address is peer address of remote. Using /32 netmask for local IP.</string>      <string name="cancel_connection">Disconnect</string>      <string name="clear_log">clear log</string>      <string name="title_cancel">Cancel Confirmation</string> @@ -156,4 +155,15 @@      <string name="tun_error_helpful">" On some custom ICS images the permission on /dev/tun might be wrong, or the tun module might be missing completly"</string>      <string name="tun_open_error">Opening tun interface failed badly.</string>      <string name="error">"Error: "</string> +    <string name="clear">Clear</string> +    <string name="info">info</string> +    <string name="show_connection_details">Show connection details</string> +    <string name="last_openvpn_tun_config">Last interface configuration from Openvpn:</string> +    <string name="local_ip_info">Local IP: %1$s/%2$d</string> +    <string name="dns_server_info">DNS Server: %s</string> +    <string name="dns_domain_info">DNS Domain: %s</string> +    <string name="routes_info">Routes: %s</string> +    <string name="ip_not_cidr">Cannot make sense of %1$s and %2$s as local IP with CIDR netmask, assuming second address is peer address of remote. Using /32 netmask for local IP.</string> +    <string name="route_not_cidr">Cannot make sense of %1$s and %2$s as IP route with CIDR netmask, using /32 as netmask.</string> +    <string name="route_not_netip">Corrected route %1$s/%2$s to %3$s/%2$s</string>    </resources> diff --git a/src/de/blinkt/openvpn/LaunchVPN.java b/src/de/blinkt/openvpn/LaunchVPN.java index d74834ca..2e25f7a2 100644 --- a/src/de/blinkt/openvpn/LaunchVPN.java +++ b/src/de/blinkt/openvpn/LaunchVPN.java @@ -29,6 +29,8 @@ import android.content.Intent;  import android.net.VpnService;  import android.os.Bundle;  import android.os.Parcelable; +import android.text.InputType; +import android.text.method.PasswordTransformationMethod;  import android.view.View;  import android.view.inputmethod.EditorInfo;  import android.widget.AdapterView; @@ -207,7 +209,8 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener {  		final EditText entry = new EditText(this);  		entry.setSingleLine(); -		entry.setInputType(EditorInfo.TYPE_TEXT_VARIATION_PASSWORD); +		entry.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_PASSWORD); +		entry.setTransformationMethod(new PasswordTransformationMethod());  		AlertDialog.Builder dialog = new AlertDialog.Builder(this);  		dialog.setTitle("Need " + type); diff --git a/src/de/blinkt/openvpn/LogWindow.java b/src/de/blinkt/openvpn/LogWindow.java index 001dbf1f..65e8c66c 100644 --- a/src/de/blinkt/openvpn/LogWindow.java +++ b/src/de/blinkt/openvpn/LogWindow.java @@ -23,6 +23,8 @@ import android.widget.TextView;  import de.blinkt.openvpn.OpenVPN.LogListener;  public class LogWindow extends ListActivity  { +	private String[] mBconfig=null; +  	class LogWindowListAdapter implements ListAdapter,LogListener, Callback { @@ -36,6 +38,7 @@ public class LogWindow extends ListActivity  {  		private Vector<DataSetObserver> observers=new Vector<DataSetObserver>(); +  		public LogWindowListAdapter() {  			initLogBuffer(); @@ -159,7 +162,6 @@ public class LogWindow extends ListActivity  {  			OpenVPN.logMessage(0,"","Log cleared.");  			mHandler.sendEmptyMessage(MESSAGE_CLEARLOG);  		} -  	} @@ -185,6 +187,9 @@ public class LogWindow extends ListActivity  {  			builder.setNegativeButton(android.R.string.no, null);  			builder.show();  			return true; +		} else if(item.getItemId()==R.id.info) { +			if(mBconfig==null) +				OpenVPN.triggerLogBuilderConfig();  		}  		return super.onOptionsItemSelected(item); diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java index daa29717..a5f60daf 100644 --- a/src/de/blinkt/openvpn/OpenVPN.java +++ b/src/de/blinkt/openvpn/OpenVPN.java @@ -10,77 +10,79 @@ public class OpenVPN {  	private static final int MAXLOGENTRIES = 500;  	public static native int startOpenVPNThread();  	public static native int startOpenVPNThreadArgs(String argv[]); -    private static final String TAG = "OpenVpn"; +	private static final String TAG = "OpenVpn"; + -	  	public static LinkedList<String> logbuffer = new LinkedList<String>();  	private static int counter=0;  	private static Vector<LogListener> logListener=new Vector<OpenVPN.LogListener>(); -	 +	private static String[] mBconfig=null; +  	public interface LogListener {  		void newLog(String logmessage);  	} -	 static { -		 System.loadLibrary("crypto"); -		 System.loadLibrary("ssl"); -		 System.loadLibrary("lzo"); -		 System.loadLibrary("openvpn"); -	    } - -	 static void addRoute(String dest,String mask, String gw) { -	        Log.i("openvpn" ,"Got Routing information " + dest + " " + mask + "  " + gw  );	 -	        mOpenVpnService.addRoute(dest,mask); -	 } -	  -	 synchronized static void logMessage(int level,String prefix, String message) -	 { -		 logbuffer.addLast(prefix + " " + message); -		 if(logbuffer.size()>MAXLOGENTRIES) -			 logbuffer.removeFirst(); -		  -		 // The garbage collector does not collect the String from native -		 // but kills me for logging 100 messages with too many references :( -		 // Force GC how and then to kill loose ends -		 if(counter++ % 50==0) -			 System.gc(); -		  -		 for (LogListener ll : logListener) { +	static { +		System.loadLibrary("crypto"); +		System.loadLibrary("ssl"); +		System.loadLibrary("lzo"); +		System.loadLibrary("openvpn"); +	} + +	static void addRoute(String dest,String mask, String gw) { +		Log.i("openvpn" ,"Got Routing information " + dest + " " + mask + "  " + gw  );	 +		mOpenVpnService.addRoute(dest,mask); +	} + +	synchronized static void logMessage(int level,String prefix, String message) +	{ +		logbuffer.addLast(prefix + " " + message); +		if(logbuffer.size()>MAXLOGENTRIES) +			logbuffer.removeFirst(); + +		// The garbage collector does not collect the String from native +		// but kills me for logging 100 messages with too many references :( +		// Force GC how and then to kill loose ends +		if(counter++ % 50==0) { +			System.gc(); +		} + +		for (LogListener ll : logListener) {  			ll.newLog(prefix + "  "  + message);  		} -		  -	 } -	  -	 synchronized static void clearLog() { -		 logbuffer.clear(); -	 } -	  -	 synchronized static void addLogListener(LogListener ll){ -		 logListener.add(ll); -	 } -	  -	 synchronized static void removeLogListener(LogListener ll) { -		 logListener.remove(ll); -	 } -	  -	  -	 static void addInterfaceInfo(int mtu, String local, String netmask) -	 { -		 Log.i("openvpn","Got interface info M"  + mtu + " L: " + local + "NM: " + netmask); -		 mOpenVpnService.setLocalIP(local,netmask); -	 } -	  -	 static void addDns(String dns) { -		 Log.i("openvpn","Got DNS Server: " + dns); -		 mOpenVpnService.addDNS(dns); -	 } -	  -	  -	 static void addDomain(String domain) { -		 Log.i("openvpn","Got DNS Domain: " + domain); -		 mOpenVpnService.setDomain(domain); -	 } + +	} + +	synchronized static void clearLog() { +		logbuffer.clear(); +	} + +	synchronized static void addLogListener(LogListener ll){ +		logListener.add(ll); +	} + +	synchronized static void removeLogListener(LogListener ll) { +		logListener.remove(ll); +	} + + +	static void addInterfaceInfo(int mtu, String local, String netmask) +	{ +		Log.i("openvpn","Got interface info M"  + mtu + " L: " + local + "NM: " + netmask); +		mOpenVpnService.setLocalIP(local,netmask); +	} + +	static void addDns(String dns) { +		Log.i("openvpn","Got DNS Server: " + dns); +		mOpenVpnService.addDNS(dns); +	} + + +	static void addDomain(String domain) { +		Log.i("openvpn","Got DNS Domain: " + domain); +		mOpenVpnService.setDomain(domain); +	}  	public static void setCallback(OpenVpnService openVpnService) { @@ -96,19 +98,32 @@ public class OpenVPN {  			Log.e("openvpn","Error protecting socket "+ sockfd);  		return p;  	} -	 +  	public static int openTunDevice() {  		Log.d(TAG,"Opening tun device");  		return mOpenVpnService.openTun();  	}  	//! Dummy method being called to force loading of JNI Libraries  	public static void foo() {	} -	 +  	synchronized public static String[] getlogbuffer() { -		 +  		// The stoned way of java to return an array from a vector  		// brought to you by eclipse auto complete  		return (String[]) logbuffer.toArray(new String[logbuffer.size()]);  	} +	public static void logBuilderConfig(String[] bconfig) { +		mBconfig =bconfig; +	} +	public static void triggerLogBuilderConfig() { +		if(mBconfig==null) { +			logMessage(0, "", "No active interface"); +		} else { +			for (String item : mBconfig) { +				logMessage(0, "", item); +			}	 +		} + +	}  } diff --git a/src/de/blinkt/openvpn/OpenVPNThread.java b/src/de/blinkt/openvpn/OpenVPNThread.java index 124179e5..a5b3e5e4 100644 --- a/src/de/blinkt/openvpn/OpenVPNThread.java +++ b/src/de/blinkt/openvpn/OpenVPNThread.java @@ -55,6 +55,8 @@ public class OpenVPNThread implements Runnable {  			mService.getHandler().sendEmptyMessage(R.string.disconnected);
 +			// Not a good place to do it, but will do
 +			OpenVPN.logBuilderConfig(null);
  			Log.i(TAG, "Exiting");
  		}
  	}
 diff --git a/src/de/blinkt/openvpn/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/OpenVpnManagementThread.java index f05f58dc..2421b28c 100644 --- a/src/de/blinkt/openvpn/OpenVpnManagementThread.java +++ b/src/de/blinkt/openvpn/OpenVpnManagementThread.java @@ -105,13 +105,14 @@ private static Vector<OpenVpnManagementThread> active=new Vector<OpenVpnManageme  			else if (cmd.equals("PASSWORD")) {
  				processPWCommand(argument);
  			} else if (cmd.equals("HOLD")) {
 -				managmentCommand("hold release\n");
 +				managmentCommand("hold release\nlog on\n");
  			} else if (cmd.equals("PROTECT-FD")) {
  				protectFD(argument);
  			}
 +			Log.i(TAG, "Got unrecognized command" + command);
 +		} else {
 +			Log.i(TAG, "Got unrecognized line from managment" + command);
  		}
 -        Log.i(TAG, "Got unrecognized command" + command);
 -
  	}
 @@ -158,10 +159,13 @@ private static Vector<OpenVpnManagementThread> active=new Vector<OpenVpnManageme  	}
 -	public static void stopOpenVPN() {
 +	public static boolean stopOpenVPN() {
 +		boolean sendCMD=false;
  		for (OpenVpnManagementThread mt: active){
  			mt.managmentCommand("signal SIGINT\n");
 -		}		
 +			sendCMD=true;
 +		}
 +		return sendCMD;		
  	}
  }
 diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index 076fe7b5..b4ae411a 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -17,8 +17,11 @@  package de.blinkt.openvpn;  import java.io.IOException; +import java.lang.reflect.Array;  import java.util.Vector; +import de.blinkt.openvpn.OpenVpnService.CIDRIP; +  import android.app.PendingIntent;  import android.content.Intent;  import android.net.LocalSocket; @@ -83,11 +86,30 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  		public String toString() {  			return String.format("%s/%d",mIp,len);  		} +		 +		public boolean normalise(){ +			long ip=0; + +			String[] ipt = mIp.split("\\."); + +			ip += Long.parseLong(ipt[0])<< 24; +			ip += Integer.parseInt(ipt[1])<< 16; +			ip += Integer.parseInt(ipt[2])<< 8; +			ip += Integer.parseInt(ipt[3]); +			 +			long newip = ip & (0xffffffffl << (32 -len)); +			if (newip != ip){ +				mIp = String.format("%d.%d.%d.%d", (newip & 0xff000000) >> 24,(newip & 0xff0000) >> 16, (newip & 0xff00) >> 8 ,newip & 0xff); +				return true; +			} else { +				return false; +			} +		}  	}  	@Override  	public void onRevoke() { -		mSocketManager.managmentCommand("signal SIGINT\n"); +		OpenVpnManagementThread.stopOpenVPN();  		mServiceThread=null;  		stopSelf();  	}; @@ -128,8 +150,12 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  		}  		// Stop the previous session by interrupting the thread. -		if (mSocketManager != null) { -			mSocketManager.managmentCommand("signal SIGINT\n"); +		if(OpenVpnManagementThread.stopOpenVPN()){ +			// an old was asked to exit, wait 2s +			try { +				Thread.sleep(2000); +			} catch (InterruptedException e) { +			}  		}  		if (mServiceThread!=null) { @@ -210,13 +236,25 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  		if(mDomain!=null)  			builder.addSearchDomain(mDomain); - +		String bconfig[] = new String[5]; +		 +		bconfig[0]= getString(R.string.last_openvpn_tun_config); +		bconfig[1] = String.format(getString(R.string.local_ip_info,mLocalIP.mIp,mLocalIP.len)); +		bconfig[2] = String.format(getString(R.string.dns_server_info, joinString(mDnslist))); +		bconfig[3] = String.format(getString(R.string.dns_domain_info, mDomain)); +		bconfig[4] = String.format(getString(R.string.routes_info, joinString(mRoutes))); +		 +		 +		OpenVPN.logBuilderConfig(bconfig); +		  		mDnslist.clear();  		mRoutes.clear();  		builder.setSession(mProfile.mName + " - " + mLocalIP); +		 +		  		// Let the configure Button show the Log  		Intent intent = new Intent(getBaseContext(),LogWindow.class);  		PendingIntent startLW = PendingIntent.getActivity(getApplicationContext(), 0, intent, 0); @@ -233,6 +271,23 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  	} +	 +	// Ugly, but java has no such method +	private <T> String joinString(Vector<T> vec) { +		String ret = ""; +		if(vec.size() > 0); +		ret = vec.get(0).toString(); +		for(int i=1;i < vec.size();i++) { +			ret = ret + ", " + vec.get(i).toString(); +		} +		return ret; +	} + + + + + +  	public void addDNS(String dns) {  		mDnslist.add(dns);		  	} @@ -246,7 +301,15 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  	public void addRoute(String dest, String mask) { -		mRoutes.add(new CIDRIP(dest, mask)); +		CIDRIP route = new CIDRIP(dest, mask);		 +		if(route.len == 32 && !mask.equals("255.255.255.255")) { +			OpenVPN.logMessage(0, "", String.format(getString(R.string.route_not_cidr,dest,mask))); +		} +		 +		if(route.normalise()) +			OpenVPN.logMessage(0, "", String.format(getString(R.string.route_not_netip,dest,route.len,route.mIp))); +		 +		mRoutes.add(route);  	} | 
