summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);