From ab9933e33e5e7b5066659b4c8911480a70f360f5 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sun, 6 May 2012 23:52:22 +0200 Subject: 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 --- src/de/blinkt/openvpn/OpenVPN.java | 16 +---- src/de/blinkt/openvpn/OpenVpnManagementThread.java | 70 +++++++++++++++++++--- src/de/blinkt/openvpn/OpenVpnService.java | 43 ++++++------- src/de/blinkt/openvpn/VpnProfile.java | 65 ++------------------ 4 files changed, 94 insertions(+), 100 deletions(-) (limited to 'src') diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java index cc827aa..e524da1 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 fcdb604..fd7fe8a 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 5937f48..5c9df8b 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 String joinString(Vector 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 75f0235..3cbac8d 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 CREATOR - = new Parcelable.Creator() { - 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); -- cgit v1.2.3