diff options
| author | Arne Schwabe <arne@rfc2549.org> | 2012-05-06 23:52:22 +0200 | 
|---|---|---|
| committer | Arne Schwabe <arne@rfc2549.org> | 2012-05-06 23:52:22 +0200 | 
| commit | ef42511eb479c40dc205e21c70e0871f35490e72 (patch) | |
| tree | 48c8f08d3f2ce778a28f17f0abd25f5c75d67814 | |
| parent | 49c3df575626efefe85b2fe14cad2dac6509d10d (diff) | |
All control of openvpn is now over the unix socket. JNI is only used for starting openvpn.
Fix configuration if no DNS information is available. (closes issue #7 hopefully)
Version 0.5.0
| -rw-r--r-- | AndroidManifest.xml | 4 | ||||
| -rw-r--r-- | openvpn/src/openvpn/manage.c | 50 | ||||
| -rw-r--r-- | openvpn/src/openvpn/manage.h | 1 | ||||
| -rw-r--r-- | openvpn/src/openvpn/tun.c | 8 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVPN.java | 16 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVpnManagementThread.java | 70 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVpnService.java | 43 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/VpnProfile.java | 65 | 
8 files changed, 153 insertions, 104 deletions
| diff --git a/AndroidManifest.xml b/AndroidManifest.xml index 263cc8c7..7c1e07b9 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="19" -    android:versionName="0.4.9" > +    android:versionCode="20" +    android:versionName="0.4.10" >      <uses-permission android:name="android.permission.INTERNET" /> diff --git a/openvpn/src/openvpn/manage.c b/openvpn/src/openvpn/manage.c index f28278f9..96ca6eaa 100644 --- a/openvpn/src/openvpn/manage.c +++ b/openvpn/src/openvpn/manage.c @@ -67,6 +67,7 @@ struct management *management; /* GLOBAL */  static void man_output_standalone (struct management *man, volatile int *signal_received);  static void man_reset_client_socket (struct management *man, const bool exiting);  static ssize_t write_fd (int fd, void *ptr, size_t nbytes, int flags, int sendfd); +static ssize_t read_fd(int fd, void *ptr, size_t nbytes, int flags, int *recvfd);  static void @@ -1815,8 +1816,15 @@ man_read (struct management *man)     */    unsigned char buf[256];    int len = 0; +  int fd = -1; -  len = recv (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL); +#ifdef TARGET_ANDROID +    len = read_fd (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL, &fd); +    if(fd >= 0) +        man->connection.lastfdreceived = fd; +#else +    len = recv (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL); +#endif    if (len == 0)      {        man_reset_client_socket (man, false); @@ -3092,6 +3100,7 @@ management_query_rsa_sig (struct management *man,  #endif +#ifdef TARGET_ANDROID  static ssize_t write_fd (int fd, void *ptr, size_t nbytes, int flags, int sendfd)  {      struct msghdr msg; @@ -3123,6 +3132,45 @@ static ssize_t write_fd (int fd, void *ptr, size_t nbytes, int flags, int sendfd      return (sendmsg(fd, &msg, flags));  } +static ssize_t read_fd(int fd, void *ptr, size_t nbytes, int flags, int *recvfd) +{ +    struct msghdr msghdr; +    struct iovec iov[1]; +    ssize_t n; +     +    union { +        struct cmsghdr cm; +        char     control[CMSG_SPACE(sizeof (int))]; +    } control_un; +    struct cmsghdr  *cmptr; +     +    msghdr.msg_control  = control_un.control; +    msghdr.msg_controllen = sizeof(control_un.control); +     +    msghdr.msg_name = NULL; +    msghdr.msg_namelen = 0; +     +    iov[0].iov_base = ptr; +    iov[0].iov_len = nbytes; +    msghdr.msg_iov = iov; +    msghdr.msg_iovlen = 1; +     +    if ( (n = recvmsg(fd, &msghdr, flags)) <= 0) +        return (n); +     +    if ( (cmptr = CMSG_FIRSTHDR(&msghdr)) != NULL && +        cmptr->cmsg_len == CMSG_LEN(sizeof(int))) { +        if (cmptr->cmsg_level != SOL_SOCKET) +            msg (M_ERR, "control level != SOL_SOCKET"); +        if (cmptr->cmsg_type != SCM_RIGHTS) +            msg (M_ERR, "control type != SCM_RIGHTS"); +        *recvfd = *((int *) CMSG_DATA(cmptr)); +    } else +        *recvfd = -1;           /* descriptor was not passed */ +     +    return (n); +} +#endif  /* diff --git a/openvpn/src/openvpn/manage.h b/openvpn/src/openvpn/manage.h index 71e1a84e..c7ffb42a 100644 --- a/openvpn/src/openvpn/manage.h +++ b/openvpn/src/openvpn/manage.h @@ -305,6 +305,7 @@ struct man_connection {  #endif  #ifdef TARGET_ANDROID      int fdtosend; +    int lastfdreceived;  #endif  }; diff --git a/openvpn/src/openvpn/tun.c b/openvpn/src/openvpn/tun.c index 66a09ea0..d2123766 100644 --- a/openvpn/src/openvpn/tun.c +++ b/openvpn/src/openvpn/tun.c @@ -1401,7 +1401,13 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu          management_query_user_pass(management, &up , "DNSDOMAIN", GET_USER_PASS_NEED_OK,(void*) 0);      } -    if((tt->fd = android_open_tun())< 0){ +    strcpy(up.username , dev); +    management_query_user_pass(management, &up , "OPENTUN", GET_USER_PASS_NEED_OK,(void*) 0); + +    tt->fd = management->connection.lastfdreceived; +    management->connection.lastfdreceived=-1; +     +    if( (tt->fd < 0) || ! (strcmp("ok",up.password)==0)) {          msg (M_ERR, "ERROR: Cannot open TUN");      }      gc_free (&gc); diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java index cc827aae..e524da1c 100644 --- a/src/de/blinkt/openvpn/OpenVPN.java +++ b/src/de/blinkt/openvpn/OpenVPN.java @@ -8,7 +8,6 @@ import android.util.Log;  public class OpenVPN {  	private static OpenVpnService mOpenVpnService;  	private static final int MAXLOGENTRIES = 500; -	public static native int startOpenVPNThread();  	public static native int startOpenVPNThreadArgs(String argv[]);  	private static final String TAG = "OpenVpn"; @@ -30,14 +29,9 @@ public class OpenVPN {  		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); +		logbuffer.addLast(prefix +  message);  		if(logbuffer.size()>MAXLOGENTRIES)  			logbuffer.removeFirst(); @@ -49,7 +43,7 @@ public class OpenVPN {  		}  		for (LogListener ll : logListener) { -			ll.newLog(prefix + "  "  + message); +			ll.newLog(prefix + message);  		}  	} @@ -72,11 +66,7 @@ public class OpenVPN {  	public static void setCallback(OpenVpnService openVpnService) {  		mOpenVpnService = openVpnService;  	} -	 -	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() {	} diff --git a/src/de/blinkt/openvpn/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/OpenVpnManagementThread.java index fcdb6046..fd7fe8a8 100644 --- a/src/de/blinkt/openvpn/OpenVpnManagementThread.java +++ b/src/de/blinkt/openvpn/OpenVpnManagementThread.java @@ -34,7 +34,6 @@ public class OpenVpnManagementThread implements Runnable {  			mSocket.getOutputStream().write(cmd.getBytes());
  			mSocket.getOutputStream().flush();
  		} catch (IOException e) {
 -			e.printStackTrace();
  		}
  	}
 @@ -94,7 +93,7 @@ public class OpenVpnManagementThread implements Runnable {  		try {
  			Method getInt = FileDescriptor.class.getDeclaredMethod("getInt$");
  			int fdint = (Integer) getInt.invoke(fd);
 -	
 +
  			Log.d("Openvpn", "Got FD from socket: " + fd + " " + fdint);
  			ParcelFileDescriptor pfd = ParcelFileDescriptor.fromFd(fdint);
  			mOpenVPNService.protect(fdint);
 @@ -146,13 +145,17 @@ public class OpenVpnManagementThread implements Runnable {  			} else if (cmd.equals("NEED-OK")) {
  				processNeedCommand(argument);
  			} else {
 +				OpenVPN.logMessage(0, "MGMT:", "Got unrecognized command" + command);
  				Log.i(TAG, "Got unrecognized command" + command);
  			}
 +		} else if (command.startsWith("SUCCESS:")) {
 +			// ignore
  		} else {
  			Log.i(TAG, "Got unrecognized line from managment" + command);
 +			OpenVPN.logMessage(0, "MGMT:", "Got unrecognized line from management:" + command);
  		}
  	}
 -	
 +
  	private void processNeedCommand(String argument) {
  		int p1 =argument.indexOf('\'');
  		int p2 = argument.indexOf('\'',p1+1);
 @@ -160,6 +163,9 @@ public class OpenVpnManagementThread implements Runnable {  		String needed = argument.substring(p1+1, p2);
  		String extra = argument.split(":",2)[1];
 +		String status = "ok";
 +
 +
  		if (needed.equals("PROTECTFD")) {
  			FileDescriptor fdtoprotect = mFDList.pollFirst();
  			protectFileDescriptor(fdtoprotect);
 @@ -174,16 +180,66 @@ public class OpenVpnManagementThread implements Runnable {  			String[] ifconfigparts = extra.split(" ");
  			int mtu = Integer.parseInt(ifconfigparts[2]);
  			mOpenVPNService.setLocalIP(ifconfigparts[0], ifconfigparts[1],mtu);
 -			
 +		} else if (needed.equals("OPENTUN")) {
 +			if(sendTunFD(needed,extra))
 +				return;
 +			else
 +				status="cancel";
 +			// This not nice or anything but setFileDescriptors accepts only FilDescriptor class :(
 +
  		} else {
  			Log.e(TAG,"Unkown needok command " + argument);
  			return;
  		}
 -		
 -		String cmd = String.format("needok '%s' %s\n", needed, "ok");
 +
 +		String cmd = String.format("needok '%s' %s\n", needed, status);
  		managmentCommand(cmd);
  	}
 +	private boolean sendTunFD (String needed, String extra) {
 +		if(!extra.equals("tun")) {
 +			// We only support tun
 +			String errmsg = String.format("Devicetype %s requested, but only tun is possible with the Android API, sorry!",extra);
 +			OpenVPN.logMessage(0, "", errmsg );
 +					
 +			return false;
 +		}
 +		ParcelFileDescriptor pfd = mOpenVPNService.openTun(); 
 +		if(pfd==null)
 +			return false;
 +
 +		Method setInt;
 +		int fdint = pfd.getFd();
 +		try {
 +			setInt = FileDescriptor.class.getDeclaredMethod("setInt$",int.class);
 +			FileDescriptor fdtosend = new FileDescriptor();
 +
 +			setInt.invoke(fdtosend,fdint);
 +			
 +			FileDescriptor[] fds = {fdtosend};
 +			mSocket.setFileDescriptorsForSend(fds);
 +			
 +			Log.d("Openvpn", "Sending FD tosocket: " + fdtosend + " " + fdint);
 +			// Trigger a send so we can close the fd on our side of the channel
 +			String cmd = String.format("needok '%s' %s\n", needed, "ok");
 +			managmentCommand(cmd);
 +			pfd.close();
 +			return true;
 +		} catch (NoSuchMethodException e) {
 +			e.printStackTrace();
 +		} catch (IllegalArgumentException e) {
 +			e.printStackTrace();
 +		} catch (IllegalAccessException e) {
 +			e.printStackTrace();
 +		} catch (InvocationTargetException e) {
 +			e.printStackTrace();
 +		} catch (IOException e) {
 +			e.printStackTrace();
 +		}
 +		return false;
 +	}
 +
 +
  	private void processPWCommand(String argument) {
  		//argument has the form 	Need 'Private Key' password
  		int p1 =argument.indexOf('\'');
 @@ -192,7 +248,7 @@ public class OpenVpnManagementThread implements Runnable {  		String needed = argument.substring(p1+1, p2);
  		String pw=null;
 -		
 +
  		if(needed.equals("Private Key")) {
  			pw = mProfile.getPasswordPrivateKey();
 diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index 5937f48e..5c9df8b4 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -65,7 +65,7 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  			// Add 33. bit to ensure the loop terminates  			netmask += 1l << 32; -			 +  			int lenZeros = 0;  			while((netmask & 0x1) == 0) {  				lenZeros++; @@ -78,13 +78,13 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  			} else {  				len =32 -lenZeros;   			} -			 +  		}  		@Override  		public String toString() {  			return String.format("%s/%d",mIp,len);  		} -		 +  		public boolean normalise(){  			long ip=0; @@ -94,7 +94,7 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  			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); @@ -213,7 +213,7 @@ public class OpenVpnService extends VpnService implements Handler.Callback { -	public int openTun() { +	public ParcelFileDescriptor openTun() {  		Builder builder = new Builder();  		builder.addAddress(mLocalIP.mIp, mLocalIP.len); @@ -221,7 +221,7 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  		for (String dns : mDnslist ) {  			builder.addDnsServer(dns);  		} -		 +  		builder.setMtu(mMtu); @@ -237,46 +237,47 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  			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,mMtu));  		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);  		builder.setConfigureIntent(startLW);  		try {  			ParcelFileDescriptor pfd = builder.establish(); -			return pfd.detachFd(); +			return pfd;  		} catch (Exception e) {  			OpenVPN.logMessage(0, "", getString(R.string.tun_open_error));  			OpenVPN.logMessage(0, "", getString(R.string.error) + e.getLocalizedMessage());  			OpenVPN.logMessage(0, "", getString(R.string.tun_error_helpful)); -			return -1; +			return null;  		}  	} -	 +  	// 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(); +		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;  	} @@ -303,10 +304,10 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  		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);  	} @@ -314,7 +315,7 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  	public void setLocalIP(String local, String netmask,int mtu) {  		mLocalIP = new CIDRIP(local, netmask);  		mMtu = mtu; -		 +  		if(mLocalIP.len == 32 && !netmask.equals("255.255.255.255")) {  			OpenVPN.logMessage(0, "", String.format(getString(R.string.ip_not_cidr, local,netmask)));  		} diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index 75f0235d..3cbac8d7 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -92,62 +92,6 @@ public class VpnProfile implements  Serializable{  	public String mVerb="1"; - -	public int describeContents() { -		return 0; -	} - -	// Not used  -	public void writeToParcel(Parcel out, int flags) { -		out.writeInt(mAuthenticationType); -		out.writeLong(mUuid.getMostSignificantBits()); -		out.writeLong(mUuid.getLeastSignificantBits()); -		out.writeString(mName); -		out.writeString(mAlias); -		out.writeString(mClientCertFilename); -		out.writeString(mTLSAuthDirection); -		out.writeString(mTLSAuthFilename); -		out.writeString(mClientKeyFilename); -		out.writeString(mCaFilename); -		out.writeValue(mUseLzo); -		out.writeString(mServerPort); -		out.writeValue(mUseUdp); -		out.writeString(mPKCS12Filename); -		out.writeString(mPKCS12Password); -		out.writeValue(mUseTLSAuth); -		out.writeString(mServerName); -	} - -	private VpnProfile(Parcel in) { -		mAuthenticationType = in.readInt(); -		mUuid = new UUID(in.readLong(), in.readLong()); -		mName = in.readString(); -		mAlias = in.readString(); -		mClientCertFilename = in.readString(); -		mTLSAuthDirection = in.readString();  -		mTLSAuthFilename = in.readString(); -		mClientKeyFilename = in.readString(); -		mCaFilename = in.readString(); -		mUseLzo = (Boolean) in.readValue(null); -		mServerPort = in.readString(); -		mUseUdp = (Boolean) in.readValue(null); -		mPKCS12Filename = in.readString(); -		mPKCS12Password = in.readString(); -		mUseTLSAuth = (Boolean) in.readValue(null); -		mServerName = in.readString();  -	} - -	public static final Parcelable.Creator<VpnProfile> CREATOR -	= new Parcelable.Creator<VpnProfile>() { -		public VpnProfile createFromParcel(Parcel in) { -			return new VpnProfile(in); -		} - -		public VpnProfile[] newArray(int size) { -			return new VpnProfile[size]; -		} -	}; -  	public static String openVpnEscape(String unescape) {  		String escapedString = unescape.replace("\\", "\\\\");  		escapedString = escapedString.replace("\"","\\\""); @@ -180,19 +124,22 @@ public class VpnProfile implements  Serializable{  		String cfg=""; -		// Enable managment interface  +		// Enable managment interface +		cfg += "# Enables connection to GUI\n";  		cfg += "management ";  		cfg +=cacheDir.getAbsolutePath() + "/" +  "mgmtsocket";  		cfg += " unix\n";  		cfg += "management-hold\n\n"; -		/* only needed if client is compiled with P2MP Server support as early version  -		 * accidently were */  		cfg+="# /tmp does not exist on Android\n";  		cfg+="tmp-dir ";  		cfg+=cacheDir.getAbsolutePath();  		cfg+="\n\n"; +		 +		cfg+="# Silences script security warning\n"; +		cfg+="script-security 0\n\n"; +		  		boolean useTLSClient = (mAuthenticationType != TYPE_STATICKEYS); | 
