summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArne Schwabe <arne@rfc2549.org>2012-05-06 23:52:22 +0200
committerArne Schwabe <arne@rfc2549.org>2012-05-06 23:52:22 +0200
commitef42511eb479c40dc205e21c70e0871f35490e72 (patch)
tree48c8f08d3f2ce778a28f17f0abd25f5c75d67814
parent49c3df575626efefe85b2fe14cad2dac6509d10d (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.xml4
-rw-r--r--openvpn/src/openvpn/manage.c50
-rw-r--r--openvpn/src/openvpn/manage.h1
-rw-r--r--openvpn/src/openvpn/tun.c8
-rw-r--r--src/de/blinkt/openvpn/OpenVPN.java16
-rw-r--r--src/de/blinkt/openvpn/OpenVpnManagementThread.java70
-rw-r--r--src/de/blinkt/openvpn/OpenVpnService.java43
-rw-r--r--src/de/blinkt/openvpn/VpnProfile.java65
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);