diff options
| -rw-r--r-- | .DS_Store | bin | 12292 -> 0 bytes | |||
| -rw-r--r-- | AndroidManifest.xml | 4 | ||||
| -rw-r--r-- | openvpn/0001-initial-android-hacks.patch | 523 | ||||
| -rw-r--r-- | openvpn/src/openvpn/error.c | 15 | ||||
| -rw-r--r-- | openvpn/src/openvpn/socket.c | 1 | ||||
| -rw-r--r-- | res/values/strings.xml | 4 | ||||
| -rw-r--r-- | res/xml/vpn_authentification.xml | 12 | ||||
| -rw-r--r-- | res/xml/vpn_headers.xml | 3 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/ConfigParser.java | 232 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/LaunchVPN.java | 6 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/OpenVpnService.java | 51 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/Settings_Authentication.java | 14 | ||||
| -rw-r--r-- | src/de/blinkt/openvpn/VpnProfile.java | 19 | ||||
| -rw-r--r-- | todo.txt | 1 | 
14 files changed, 328 insertions, 557 deletions
| diff --git a/.DS_Store b/.DS_StoreBinary files differ deleted file mode 100644 index 2d192e83..00000000 --- a/.DS_Store +++ /dev/null diff --git a/AndroidManifest.xml b/AndroidManifest.xml index bc3f311c..b6cdc32b 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="21" -    android:versionName="0.5.0" > +    android:versionCode="22" +    android:versionName="0.5.1" >      <uses-permission android:name="android.permission.INTERNET" /> diff --git a/openvpn/0001-initial-android-hacks.patch b/openvpn/0001-initial-android-hacks.patch deleted file mode 100644 index e78cc7de..00000000 --- a/openvpn/0001-initial-android-hacks.patch +++ /dev/null @@ -1,523 +0,0 @@ -From d573932062cb4afd7f001899978e37ce446934e7 Mon Sep 17 00:00:00 2001 -From: Arne Schwabe <arne@rfc2549.org> -Date: Tue, 10 Apr 2012 00:34:51 +0200 -Subject: [PATCH] initial android hacks - ---- - src/compat/compat-rsa_generate_key.c |   47 ++++++++++ - src/openvpn/error.c                  |   19 ++++- - src/openvpn/jniglue.c                |  162 ++++++++++++++++++++++++++++++++++ - src/openvpn/jniglue.h                |   19 ++++ - src/openvpn/options.c                |    1 + - src/openvpn/route.c                  |    7 ++- - src/openvpn/socket.c                 |   25 +++++ - src/openvpn/ssl.c                    |    2 + - src/openvpn/syshead.h                |    2 +- - src/openvpn/tun.c                    |   22 ++++- - src/openvpn/tun.h                    |    2 + - 11 files changed, 303 insertions(+), 5 deletions(-) - create mode 100644 src/compat/compat-rsa_generate_key.c - create mode 100644 src/openvpn/jniglue.c - create mode 100644 src/openvpn/jniglue.h - -diff --git a/src/compat/compat-rsa_generate_key.c b/src/compat/compat-rsa_generate_key.c -new file mode 100644 -index 0000000..99725da ---- /dev/null -+++ b/src/compat/compat-rsa_generate_key.c -@@ -0,0 +1,47 @@ -+#include <stdio.h> -+#include <time.h> -+#include "cryptlib.h" -+#include <openssl/bn.h> -+#include <openssl/rsa.h> -+ -+RSA *RSA_generate_key(int bits, unsigned long e_value, -+		      void (*callback)(int,int,void *), void *cb_arg) -+{ -+  BN_GENCB cb; -+  int i; -+  RSA *rsa = RSA_new(); -+  BIGNUM *e = BN_new(); -+ -+  if(!rsa || !e) goto err; -+ -+  /* The problem is when building with 8, 16, or 32 BN_ULONG, -+   * unsigned long can be larger */ -+  for (i=0; i<(int)sizeof(unsigned long)*8; i++) -+    { -+      if (e_value & (1UL<<i)) -+	if (BN_set_bit(e,i) == 0) -+	  goto err; -+    } -+ -+  BN_GENCB_set_old(&cb, callback, cb_arg); -+ -+  if(RSA_generate_key_ex(rsa, bits, e, &cb)) { -+    BN_free(e); -+    return rsa; -+  } -+ err: -+  if(e) BN_free(e); -+  if(rsa) RSA_free(rsa); -+  return 0; -+} -+ -+ -+ -+void mlockall(){} -+char * -+getpass (prompt) -+     const char *prompt; -+{ -+  return ""; -+} -+ -diff --git a/src/openvpn/error.c b/src/openvpn/error.c -index d6ad639..d4a3cff 100644 ---- a/src/openvpn/error.c -+++ b/src/openvpn/error.c -@@ -199,6 +199,16 @@ msg_fp(const unsigned int flags) -  - int x_msg_line_num; /* GLOBAL */ -  -+#include "android/log.h" -+void x_msg2(const unsigned int flags, const char *format, ...) { -+    va_list arglist; -+    va_start(arglist,format); -+    //	vsnprintf(m1, 100, "foo bbaz",arglist); -+    __android_log_vprint(ANDROID_LOG_DEBUG, "openvpn",format, arglist); -+    va_end(arglist); -+} -+ -+ - void x_msg (const unsigned int flags, const char *format, ...) - { -   struct gc_arena gc; -@@ -350,6 +360,10 @@ void x_msg (const unsigned int flags, const char *format, ...) - 	} -     } -  -+#ifdef TARGET_ANDROID -+   android_openvpn_log(prefix,prefix_sep,m1);; -+#endif -+     -   if (flags & M_FATAL) -     msg (M_INFO, "Exiting due to fatal error"); -  -@@ -701,7 +715,10 @@ openvpn_exit (const int status) -       if (status == OPENVPN_EXIT_STATUS_GOOD) - 	perf_output_results (); -     } -- -+#ifdef TARGET_ANDROID -+    android_openvpn_exit(status); -+#endif -+     -   exit (status); - } -  -diff --git a/src/openvpn/jniglue.c b/src/openvpn/jniglue.c -new file mode 100644 -index 0000000..2d52936 ---- /dev/null -+++ b/src/openvpn/jniglue.c -@@ -0,0 +1,162 @@ -+#include <jni.h> -+#include <android/log.h> -+#include <stdlib.h> -+#include <setjmp.h> -+ -+#include "jniglue.h" -+ -+JNIEXPORT jint Java_de_blinkt_OpenVPN_startOpenVPNThread(JNIEnv* env, jclass jc); -+ -+ -+extern int main (int argc, char *argv[]); -+ -+static jmp_buf jump_buffer; -+ -+int callmain (int argc, char *argv[]) { -+    if(!setjmp(jump_buffer)) -+        main(argc,argv); -+} -+ -+ -+void android_openvpn_exit(int status) { -+    longjmp(jump_buffer,status+1); -+} -+ -+ -+void testmsg(char* m1, ...) { -+	va_list arglist; -+	va_start(arglist,m1); -+	//	vsnprintf(m1, 100, "foo bbaz",arglist); -+	__android_log_vprint(ANDROID_LOG_DEBUG, "openvpn",m1, arglist); -+		va_end(arglist); -+} -+ -+// Store env and class, we allow only one instance -+// so make these variables global for now -+jclass openvpnclass; -+JNIEnv* openvpnjenv; -+ -+//Lde/blinkt/openvpn/OpenVPN startOpenVPNThread startOpenVPNThread -+ jint Java_de_blinkt_openvpn_OpenVPN_startOpenVPNThread(JNIEnv* env, jclass jc){ -+    char* argv[] = {"openvpn", "--client", -+                    "--dev","tun", -+                    "--comp-lzo", -+//                    "--redirect-gateway","def1", -+//                    "--pkcs12","/mnt/sdcard/Network_Certificate.p12", -+                    "--remote-cert-eku", "TLS Web Server Authentication", -+                    "--remote","openvpn.uni-paderborn.de", -+                    "--ca","/mnt/sdcard/ca.pem", -+                    "--key","/mnt/sdcard/schwabe.key", -+                    "--cert","/mnt/sdcard/schwabe.pem", -+                    "--verb","4" -+                }; -+      -+     openvpnclass = jc; -+     openvpnjenv= env; -+     int argc=17; -+ -+    return callmain(argc,argv); -+ } -+ -+void Java_de_blinkt_openvpn_OpenVPN_startOpenVPNThreadArgs(JNIEnv *env,jclass jc, jobjectArray stringArray) { -+    openvpnclass = jc; -+    openvpnjenv= env; -+     -+    int stringCount = (*env)->GetArrayLength(env, stringArray); -+     -+     -+    const char** argv = calloc(stringCount,sizeof(const char*)); -+     -+    int i; -+    for (i=0; i<stringCount; i++) { -+        jstring string = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i); -+        jboolean isCopy; -+        const char* rawString = (*env)->GetStringUTFChars(env, string, &isCopy); -+         -+        // Copy the string to able to release it -+        argv[i] = rawString; -+ -+    } -+     -+    // Call main -+    callmain(stringCount,argv); -+     -+    // Release the Strings -+    for(i=0; i<stringCount;i++){ -+        jstring string = (jstring) (*env)->GetObjectArrayElement(env, stringArray, i); -+        (*env)->ReleaseStringUTFChars(env,string,argv[i]); -+    } -+    free(argv); -+} -+     -+ -+ -+ -+jint JNI_OnLoad(JavaVM *vm, void *reserved) { -+    __android_log_write(ANDROID_LOG_DEBUG,"openvpn", "Loading openvpn native library $id$ compiled on "   __DATE__ " " __TIME__ ); -+    return JNI_VERSION_1_2; -+} -+ -+void addInterfaceInformation(int mtu,const char* ifconfig_local, const char* ifconfig_remote) -+{ -+    jstring jlocal = (*openvpnjenv)->NewStringUTF(openvpnjenv, ifconfig_local); -+    jstring jremote = (*openvpnjenv)->NewStringUTF(openvpnjenv, ifconfig_remote); -+ -+    jmethodID aMethodID = (*openvpnjenv)->GetStaticMethodID(openvpnjenv, openvpnclass, "addInterfaceInfo",  -+                                                            "(ILjava/lang/String;Ljava/lang/String;)V"); -+    (*openvpnjenv)->CallStaticVoidMethod(openvpnjenv,openvpnclass,aMethodID,mtu,jlocal,jremote); -+     -+    (*openvpnjenv)->DeleteLocalRef(openvpnjenv,jlocal); -+    (*openvpnjenv)->DeleteLocalRef(openvpnjenv,jremote); -+ -+     -+} -+ -+void android_openvpn_log(int level,const char* prefix,const char* prefix_sep,const char* m1) -+{ -+    __android_log_print(ANDROID_LOG_DEBUG,"openvpn","%s%s%s",prefix,prefix_sep,m1); -+ -+    jstring jprefix = (*openvpnjenv)->NewStringUTF(openvpnjenv, prefix); -+    jstring jmessage = (*openvpnjenv)->NewStringUTF(openvpnjenv, m1); -+     -+    jmethodID aMethodID = (*openvpnjenv)->GetStaticMethodID(openvpnjenv, openvpnclass, "logMessage",  -+                                                            "(ILjava/lang/String;Ljava/lang/String;)V"); -+     -+    (*openvpnjenv)->CallStaticVoidMethod(openvpnjenv,openvpnclass,aMethodID,level,jprefix,jmessage); -+     -+    (*openvpnjenv)->DeleteLocalRef(openvpnjenv,jprefix); -+    (*openvpnjenv)->DeleteLocalRef(openvpnjenv,jmessage); -+     -+} -+ -+ -+unsigned char android_protect_socket(int sockfd) { -+    jmethodID aMethodID = (*openvpnjenv)->GetStaticMethodID(openvpnjenv, openvpnclass, "protectSocket",  -+                                                            "(I)Z"); -+    return (*openvpnjenv)->CallStaticBooleanMethod(openvpnjenv,openvpnclass,aMethodID,sockfd); -+ -+} -+int android_open_tun () { -+    jmethodID aMethodID = (*openvpnjenv)->GetStaticMethodID(openvpnjenv, openvpnclass, "openTunDevice",  -+                                                            "()I"); -+    return (*openvpnjenv)->CallStaticIntMethod(openvpnjenv,openvpnclass,aMethodID); -+ -+} -+ -+void addRouteInformation(const char* dest, const char* mask, const char* gw) { -+     -+    jstring jmask =  (*openvpnjenv)->NewStringUTF(openvpnjenv, mask); -+    jstring jdest =  (*openvpnjenv)->NewStringUTF(openvpnjenv, dest); -+    jstring jgw =    (*openvpnjenv)->NewStringUTF(openvpnjenv, gw); -+    jmethodID aMethodID = (*openvpnjenv)->GetStaticMethodID(openvpnjenv, openvpnclass, "addRoute",  -+                                            "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); -+    (*openvpnjenv)->CallStaticVoidMethod(openvpnjenv,openvpnclass,aMethodID,jdest,jmask,jgw); -+ -+    (*openvpnjenv)->DeleteLocalRef(openvpnjenv,jmask); -+    (*openvpnjenv)->DeleteLocalRef(openvpnjenv,jdest); -+    (*openvpnjenv)->DeleteLocalRef(openvpnjenv,jgw); -+ -+ -+} -+ -+ -diff --git a/src/openvpn/jniglue.h b/src/openvpn/jniglue.h -new file mode 100644 -index 0000000..cb3ae41 ---- /dev/null -+++ b/src/openvpn/jniglue.h -@@ -0,0 +1,19 @@ -+// -+//  jniglue.h -+//  xcopenvpn -+// -+//  Created by Arne Schwabe on 29.03.12. -+//  Copyright (c) 2012 Universität Paderborn. All rights reserved. -+// -+ -+#ifndef xcopenvpn_jniglue_h -+#define xcopenvpn_jniglue_h -+ -+void testmsg(char* m1, ...); -+void addRouteInformation(const char* dest, const char* mask, const char* gw); -+void addInterfaceInformation(int mtu,const char* ifconfig_local, const char* ifconfig_remote); -+void android_openvpn_log(int level,const char* prefix,const char* prefix_sep,const char* m1); -+void android_openvpn_exit(int status); -+ -+ -+#endif -diff --git a/src/openvpn/options.c b/src/openvpn/options.c -index bd83843..fcf436c 100644 ---- a/src/openvpn/options.c -+++ b/src/openvpn/options.c -@@ -560,6 +560,7 @@ static const char usage_message[] = - #if OPENSSL_VERSION_NUMBER >= 0x00907000L -   " and CRLs).\n" - #else /* OPENSSL_VERSION_NUMBER >= 0x00907000L */ -+#error WTF! -   ").\n" -   "                  WARNING: no support of CRL available with this version.\n" - #endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L */ -diff --git a/src/openvpn/route.c b/src/openvpn/route.c -index 7c25c77..6c3ad90 100644 ---- a/src/openvpn/route.c -+++ b/src/openvpn/route.c -@@ -1344,6 +1344,11 @@ add_route (struct route *r, -   argv_msg (D_ROUTE, &argv); -   status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route add command failed"); -  -+#elif defined (TARGET_ANDROID) -+#include "jniglue.h" -+ -+    addRouteInformation(network, netmask, gateway); -+ - #elif defined (WIN32) -   { -     DWORD ai = TUN_ADAPTER_INDEX_INVALID; -@@ -2371,7 +2376,7 @@ show_routes (int msglev) -   gc_free (&gc); - } -  --#elif defined(TARGET_LINUX) -+#elif defined(TARGET_LINUX) || defined(TARGET_ANDROID) -  - void - get_default_gateway (struct route_gateway_info *rgi) -diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c -index 6b1f8d2..364b97e 100644 ---- a/src/openvpn/socket.c -+++ b/src/openvpn/socket.c -@@ -41,6 +41,11 @@ -  - #include "memdbg.h" -  -+#ifdef TARGET_ANDROID -+#include "jniglue.h" -+#endif  -+ -+ - const int proto_overhead[] = { /* indexed by PROTO_x */ -   0, -   IPv4_UDP_HEADER_SIZE, /* IPv4 */ -@@ -858,6 +863,11 @@ create_socket_tcp (void) -   } - #endif -  -+#ifdef TARGET_ANDROID -+    /* Protects the socket from being routed via VPN */ -+    android_protect_socket(sd); -+#endif -+ -   return sd; - } -  -@@ -885,6 +895,12 @@ create_socket_udp (const unsigned int flags) - #endif -     } - #endif -+ -+#ifdef TARGET_ANDROID -+    /* Protects the socket from being routed via VPN */ -+    android_protect_socket(sd); -+#endif -+ -   return sd; - } -  -@@ -904,6 +920,11 @@ create_socket_udp6 (const unsigned int flags) - 	msg(M_SOCKERR, "UDP: failed setsockopt for IPV6_RECVPKTINFO"); -     } - #endif -+#ifdef TARGET_ANDROID -+    /* Protects the socket from being routed via VPN */ -+    android_protect_socket(sd); -+#endif -+ -   return sd; - } -  -@@ -922,6 +943,10 @@ create_socket_tcp6 (void) - 		    (void *) &on, sizeof (on)) < 0) -       msg (M_SOCKERR, "TCP: Cannot setsockopt SO_REUSEADDR on TCP6 socket"); -   } -+#ifdef TARGET_ANDROID -+    /* Protects the socket from being routed via VPN */ -+    android_protect_socket(sd); -+#endif -  -   return sd; - } -diff --git a/src/openvpn/ssl.c b/src/openvpn/ssl.c -index 251f8ed..537fc12 100644 ---- a/src/openvpn/ssl.c -+++ b/src/openvpn/ssl.c -@@ -1645,6 +1645,8 @@ push_peer_info(struct buffer *buf, struct tls_session *session) -       buf_printf (&out, "IV_PLAT=netbsd\n"); - #elif defined(TARGET_FREEBSD) -       buf_printf (&out, "IV_PLAT=freebsd\n"); -+#elif defined(TARGET_ANDROID) -+      buf_printf(&out, "IV_PLAT=android\n"); - #elif defined(WIN32) -       buf_printf (&out, "IV_PLAT=win\n"); - #endif -diff --git a/src/openvpn/syshead.h b/src/openvpn/syshead.h -index 0595b67..56a5429 100644 ---- a/src/openvpn/syshead.h -+++ b/src/openvpn/syshead.h -@@ -211,7 +211,7 @@ - #include <net/if_tap.h> - #endif -  --#ifdef TARGET_LINUX -+#if defined(TARGET_LINUX) || defined (TARGET_ANDROID) -  - #if defined(HAVE_NETINET_IF_ETHER_H) - #include <netinet/if_ether.h> -diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c -index b99071c..db8104d 100644 ---- a/src/openvpn/tun.c -+++ b/src/openvpn/tun.c -@@ -49,6 +49,11 @@ -  - #include "memdbg.h" -  -+#ifdef TARGET_ANDROID -+#include "jniglue.h" -+#endif -+ -+ - #ifdef WIN32 -  - /* #define SIMULATE_DHCP_FAILED */       /* simulate bad DHCP negotiation */ -@@ -768,6 +773,8 @@ do_ifconfig (struct tuntap *tt, -       tt->did_ifconfig = true; -  - #endif /*ENABLE_IPROUTE*/ -+#elif defined(TARGET_ANDROID) -+       addInterfaceInformation(tun_mtu,ifconfig_local, ifconfig_remote_netmask); - #elif defined(TARGET_SOLARIS) -  -       /* Solaris 2.6 (and 7?) cannot set all parameters in one go... -@@ -1365,7 +1372,16 @@ close_tun_generic (struct tuntap *tt) -  - #endif -  --#if defined(TARGET_LINUX) -+#if defined(TARGET_LINUX) || defined(TARGET_ANDROID) -+ -+#if defined (TARGET_ANDROID) -+void -+open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt) -+{ -+    tt->fd = android_open_tun(); -+} -+ -+#else -  - #ifdef HAVE_LINUX_IF_TUN_H	/* New driver support */ -  -@@ -1373,6 +1389,7 @@ close_tun_generic (struct tuntap *tt) - #error header file linux/sockios.h required - #endif -  -+ - #if defined(HAVE_TUN_PI) && defined(HAVE_IPHDR) && defined(HAVE_IOVEC) && defined(ETH_P_IPV6) && defined(ETH_P_IP) && defined(HAVE_READV) && defined(HAVE_WRITEV) - #define LINUX_IPV6 1 - /* #warning IPv6 ON */ -@@ -1426,7 +1443,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu -       if (!tt->ipv6) - 	ifr.ifr_flags = IFF_NO_PI; -  --#if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN) -+#if defined(IFF_ONE_QUEUE) && defined(SIOCSIFTXQLEN) && !defined(TARGET_ANDROID) -       ifr.ifr_flags |= IFF_ONE_QUEUE; - #endif -  -@@ -1516,6 +1533,7 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tu - } -  - #endif /* HAVE_LINUX_IF_TUN_H */ -+#endif /* TARGET_ANDROID */ -  - #ifdef TUNSETPERSIST -  -diff --git a/src/openvpn/tun.h b/src/openvpn/tun.h -index 9bd990f..63ab872 100644 ---- a/src/openvpn/tun.h -+++ b/src/openvpn/tun.h -@@ -292,6 +292,8 @@ ifconfig_order(void) -   return IFCONFIG_AFTER_TUN_OPEN; - #elif defined(WIN32) -   return IFCONFIG_BEFORE_TUN_OPEN; -+#elif defined(TARGET_ANDROID) -+  return IFCONFIG_BEFORE_TUN_OPEN; - #else -   return IFCONFIG_DEFAULT; - #endif ---  -1.7.5.4 - diff --git a/openvpn/src/openvpn/error.c b/openvpn/src/openvpn/error.c index 83a9eb4b..e2e24b1e 100644 --- a/openvpn/src/openvpn/error.c +++ b/openvpn/src/openvpn/error.c @@ -199,11 +199,6 @@ msg_fp(const unsigned int flags)  int x_msg_line_num; /* GLOBAL */ -#include "android/log.h" -  - - -  void x_msg (const unsigned int flags, const char *format, ...)  {    struct gc_arena gc; @@ -219,7 +214,6 @@ void x_msg (const unsigned int flags, const char *format, ...)    const char *prefix_sep;    void usage_small (void); -      #ifndef HAVE_VARARG_MACROS    /* the macro has checked this otherwise */ @@ -304,12 +298,10 @@ void x_msg (const unsigned int flags, const char *format, ...)    if (!prefix)      prefix_sep = prefix = ""; -    /* virtual output capability used to copy output to management subsystem */    if (!forked)      {        const struct virtual_output *vo = msg_get_virtual_output (); -                if (vo)  	{  	  openvpn_snprintf (m2, ERR_BUF_SIZE, "%s%s%s", @@ -331,7 +323,7 @@ void x_msg (const unsigned int flags, const char *format, ...)                      m1);   #endif          } -        else // No Syslog +      else          {              FILE *fp = msg_fp(flags);              const bool show_usec = check_debug_level (DEBUG_LEVEL_USEC_TIME); @@ -356,13 +348,8 @@ void x_msg (const unsigned int flags, const char *format, ...)              fflush(fp);              ++x_msg_line_num;          } -#ifdef TARGET_ANDROID -        android_openvpn_log(prefix,prefix_sep,m1);; -#endif      } - -        if (flags & M_FATAL)      msg (M_INFO, "Exiting due to fatal error"); diff --git a/openvpn/src/openvpn/socket.c b/openvpn/src/openvpn/socket.c index 71010979..b92c2828 100644 --- a/openvpn/src/openvpn/socket.c +++ b/openvpn/src/openvpn/socket.c @@ -859,7 +859,6 @@ create_socket_tcp (void)        msg (M_SOCKERR, "TCP: Cannot setsockopt SO_LINGER on TCP socket");    }  #endif -      return sd;  } diff --git a/res/values/strings.xml b/res/values/strings.xml index 90009e8c..9073c0be 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -185,4 +185,8 @@      <string name="faq_shortcut">Shortcut to start</string>        <string name="faq_howto_shortcut">You can place a shortcut to start OpenVPN on your desktop. Depending on your homescreen program you have to add a shortcut or a widget.</string>        <string name="no_vpn_support_image">Your image does not support the VPNService API,sorry :(</string>   +    <string name="encryption">Encryption</string>   +    <string name="cipher_dialog_title">Enter Encryption method</string>   +    <string name="chipher_dialog_message">Enter the cipher key for openvpn. Leave empty to use default cipher</string> +    <string name="settings_auth">Authentication/Encryption</string>    </resources> diff --git a/res/xml/vpn_authentification.xml b/res/xml/vpn_authentification.xml index bd8d8ca5..79d69697 100644 --- a/res/xml/vpn_authentification.xml +++ b/res/xml/vpn_authentification.xml @@ -28,14 +28,20 @@              android:title="@string/tls_auth_file" />          <ListPreference +            android:dependency="useTLSAuth"              android:entries="@array/tls_directions_entries" -                    android:dependency="useTLSAuth" -                          android:entryValues="@array/tls_directions_values"              android:key="tls_direction"              android:persistent="false"              android:title="@string/tls_direction" />      </PreferenceCategory> -/> +    <PreferenceCategory android:title="@string/encryption" > +        <EditTextPreference +            android:dialogMessage="@string/chipher_dialog_message" +            android:dialogTitle="@string/cipher_dialog_title" +            android:key="cipher" +            android:persistent="false" +            android:title="Encryption cipher" /> +    </PreferenceCategory>  </PreferenceScreen>
\ No newline at end of file diff --git a/res/xml/vpn_headers.xml b/res/xml/vpn_headers.xml index f755dc8c..60ddce7c 100644 --- a/res/xml/vpn_headers.xml +++ b/res/xml/vpn_headers.xml @@ -15,8 +15,7 @@          android:title="IP Settings" />      <header          android:fragment="de.blinkt.openvpn.Settings_Authentication" -        android:summary="Authentication" -        android:title="Authentication" /> +        android:title="@string/settings_auth" />      <!-- android:icon="@drawable/ic_settings_display" -->       <header diff --git a/src/de/blinkt/openvpn/ConfigParser.java b/src/de/blinkt/openvpn/ConfigParser.java new file mode 100644 index 00000000..8497330f --- /dev/null +++ b/src/de/blinkt/openvpn/ConfigParser.java @@ -0,0 +1,232 @@ +package de.blinkt.openvpn; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.Vector; + +//! Openvpn Config FIle Parser, probably not 100% accurate but close enough + +// And rember, this is valid :) +// --<foo> +// bar +// </bar> +public class ConfigParser { + + +	private HashMap<String,Vector<String>> options = new HashMap<String, Vector<String>>(); +	private void parseConfig(String filename) throws IOException, ConfigParseError { + + +		FileReader fr = new FileReader(filename); +		BufferedReader br =new BufferedReader(fr); + +		int lineno=0; + +		while (true){ +			String line = br.readLine(); +			if(line==null) +				break; +			lineno++; +			System.out.print("LINE:"); +			System.out.println(line); +			Vector<String> args = parseline(line); +			if(args.size() ==0) +				continue; + + + +			if(args.get(0).startsWith("--")) +				args.set(0, args.get(0).substring(2)); + +			checkinlinefile(args,br); + +			options.put(args.get(0), args); +		} +	} + +	private void checkinlinefile(Vector<String> args, BufferedReader br) throws IOException, ConfigParseError { +		String arg0 = args.get(0); +		// CHeck for <foo> +		if(arg0.startsWith("<") && arg0.endsWith(">")) { +			String argname = arg0.substring(1, arg0.length()-1); +			String inlinefile = ""; + +			String endtag = String.format("</%s>",argname); +			do { +				String line = br.readLine(); +				if(line==null){ +					throw new ConfigParseError(String.format("No endtag </%s> for starttag <%s> found",argname,argname)); +				} +				if(line.equals(endtag)) +					break; +				else { +					inlinefile+=line; +					inlinefile+= "\n";					 +				} +			} while(true); + +			args.clear(); +			args.add(argname); +			args.add(inlinefile); +		} + +	} + +	enum linestate { +		initial, +		readin_single_quote +		, reading_quoted, reading_unquoted, done} + +	private boolean space(char c) { +		// I really hope nobody is using zero bytes inside his/her config file +		// to sperate parameter but here we go: +		return Character.isSpace(c) || c == '\0'; + +	} + +	public class ConfigParseError extends Exception { +		private static final long serialVersionUID = -60L; + +		public ConfigParseError(String msg) { +			super(msg); +		} +	} + + +	// adapted openvpn's parse function to java +	private Vector<String> parseline(String line) throws ConfigParseError { +		Vector<String> parameters = new Vector<String>();  + +		if (line.length()==0) +			return parameters; + + +		linestate state = linestate.initial; +		boolean backslash = false; +		char out=0; + +		int pos=0; +		String currentarg=""; + +		do {  +			// Emulate the c parsing ... +			char in; +			if(pos < line.length()) +				in = line.charAt(pos); +			else  +				in = '\0'; + +			if (!backslash && in == '\\' && state != linestate.readin_single_quote) +			{ +				backslash = true; +			} +			else +			{ +				if (state == linestate.initial) +				{ +					if (!space (in)) +					{ +						if (in == ';' || in == '#') /* comment */ +							break; +						if (!backslash && in == '\"') +							state = linestate.reading_quoted; +						else if (!backslash && in == '\'') +							state = linestate.readin_single_quote; +						else +						{ +							out = in; +							state = linestate.reading_unquoted; +						} +					} +				} +				else if (state == linestate.reading_unquoted) +				{ +					if (!backslash && space (in)) +						state = linestate.done; +					else +						out = in; +				} +				else if (state == linestate.reading_quoted) +				{ +					if (!backslash && in == '\"') +						state = linestate.done; +					else +						out = in; +				} +				else if (state == linestate.readin_single_quote) +				{ +					if (in == '\'') +						state = linestate.done; +					else +						out = in; +				} + +				if (state == linestate.done) +				{ +					/* ASSERT (parm_len > 0); */ +					state = linestate.initial; +					parameters.add(currentarg); +					currentarg = ""; +					out =0; +				} + +				if (backslash && out!=0) +				{ +					if (!(out == '\\' || out == '\"' || space (out))) +					{ +						throw new ConfigParseError("Options warning: Bad backslash ('\\') usage"); +					} +				} +				backslash = false; +			} + +			/* store parameter character */ +			if (out!=0) +			{ +				currentarg+=out; +			} +		} while (pos++ < line.length()); + +		return parameters; +	} + +	void convertProfile() throws ConfigParseError{ +		VpnProfile newprofile = new VpnProfile("converted Profile"); +		// Pull, client, tls-client +		 +		if(options.containsKey("client") || options.containsKey("pull")) { +			newprofile.mUsePull=true; +			options.remove("pull"); +			options.remove("client"); +		} +		 +		if(options.containsKey("secret")){ +			newprofile.mAuthenticationType=VpnProfile.TYPE_STATICKEYS; +			options.remove("secret"); +		} +		 +		if(options.containsKey("redirect-gateway")) { +			options.remove("redirect-gateway"); +			newprofile.mUseDefaultRoute=true; +		} else { +			newprofile.mUseDefaultRoute=true; +		} +		 +		Vector<String> mode = options.get("mode"); +		if (mode != null){ +			options.remove("mode"); +			if(mode.size() != 2)  +				throw new ConfigParseError("--mode has more than one parameter"); +			if(!mode.get(1).equals("p2p")) +				throw new ConfigParseError("Invalid mode for --mode specified"); +		} +		 +	} + +} + + + + diff --git a/src/de/blinkt/openvpn/LaunchVPN.java b/src/de/blinkt/openvpn/LaunchVPN.java index 858c8d38..8aeb9960 100644 --- a/src/de/blinkt/openvpn/LaunchVPN.java +++ b/src/de/blinkt/openvpn/LaunchVPN.java @@ -212,11 +212,15 @@ public class LaunchVPN extends ListActivity implements OnItemClickListener {  	}  	private boolean writeMiniVPN() { +		File mvpnout = new File(getCacheDir(),"minivpn"); +		if (mvpnout.exists() && mvpnout.canExecute()) +			return true; +			  		if(minivpnwritten)  			return true;  		try {  			InputStream mvpn = getAssets().open("minivpn"); -			File mvpnout = new File(getCacheDir(),"minivpn"); +			  			FileOutputStream fout = new FileOutputStream(mvpnout);  			byte buf[]= new byte[4096]; diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index a3df9fde..9f0f7326 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -17,9 +17,14 @@  package de.blinkt.openvpn;  import java.io.IOException; +import java.util.List;  import java.util.Vector; +import android.R.anim; +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo;  import android.app.PendingIntent; +import android.content.Context;  import android.content.Intent;  import android.net.LocalSocket;  import android.net.LocalSocketAddress; @@ -117,11 +122,10 @@ public class OpenVpnService extends VpnService implements Handler.Callback { -	private LocalSocket openManagmentInterface() { +	private LocalSocket openManagmentInterface(int tries) {  		// Could take a while to open connection  		String socketname = (getCacheDir().getAbsolutePath() + "/" +  "mgmtsocket");  		LocalSocket sock = new LocalSocket(); -		int tries = 8;  		while(tries > 0 && !sock.isConnected()) {  			try { @@ -142,6 +146,14 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  	@Override  	public int onStartCommand(Intent intent, int flags, int startId) { +		// Extract information from the intent. +		String prefix = getPackageName(); +		String[] argv = intent.getStringArrayExtra(prefix + ".ARGV"); + +		String profileUUID = intent.getStringExtra(prefix + ".profileUUID"); +		mProfile = ProfileManager.get(profileUUID); +		 +  		// The handler is only used to show messages.  		if (mHandler == null) {  			mHandler = new Handler(this); @@ -164,13 +176,19 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  			}  		} +		// See if there is a managment socket we can connect to and kill the process too +		LocalSocket mgmtsocket =  openManagmentInterface(1); +		if(mgmtsocket!=null) { +			// Fire and forget :) +			new OpenVpnManagementThread(mProfile,mgmtsocket,this).managmentCommand("signal SIGINT\n"); +			try { +				Thread.sleep(1000); +			} catch (InterruptedException e) { +			} +			//checkForRemainingMiniVpns(); +		} -		// Extract information from the intent. -		String prefix = getPackageName(); -		String[] argv = intent.getStringArrayExtra(prefix + ".ARGV"); -		String profileUUID = intent.getStringExtra(prefix + ".profileUUID"); -		mProfile = ProfileManager.get(profileUUID);  		// Start a new session by creating a new thread. @@ -181,7 +199,7 @@ public class OpenVpnService extends VpnService implements Handler.Callback {  		// Open the Management Interface -		LocalSocket mgmtsocket =  openManagmentInterface(); +		mgmtsocket =  openManagmentInterface(8);  		if(mgmtsocket!=null) {  			// start a Thread that handles incoming messages of the managment socket @@ -197,6 +215,23 @@ public class OpenVpnService extends VpnService implements Handler.Callback { +	private void checkForRemainingMiniVpns() { +		 ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); +	      if (manager == null) +	    	  return; +		List<RunningAppProcessInfo> service= manager.getRunningAppProcesses(); +		// Does not return the minivpn binarys :S +		for(RunningAppProcessInfo rapi:service){ +			if(rapi.processName.equals("minivpn")) +				android.os.Process.killProcess(rapi.pid); +		} +	} + + + + + +  	@Override  	public void onDestroy() {  		if (mServiceThread != null) { diff --git a/src/de/blinkt/openvpn/Settings_Authentication.java b/src/de/blinkt/openvpn/Settings_Authentication.java index 57d99417..4124783b 100644 --- a/src/de/blinkt/openvpn/Settings_Authentication.java +++ b/src/de/blinkt/openvpn/Settings_Authentication.java @@ -24,6 +24,7 @@ public class Settings_Authentication extends PreferenceFragment implements OnPre  	private ListPreference mTLSAuthDirection;  	private Preference mTLSAuthFile;  	private SwitchPreference mUseTLSAuth; +	private EditTextPreference mCipher;  	@Override  	public void onCreate(Bundle savedInstanceState) { @@ -45,6 +46,9 @@ public class Settings_Authentication extends PreferenceFragment implements OnPre  		mProfile = ProfileManager.get(profileUUID);  		mTLSAuthFile.setOnPreferenceClickListener(this);		 +		mCipher =(EditTextPreference) findPreference("cipher"); +		mCipher.setOnPreferenceChangeListener(this); +		  		loadSettings();  	} @@ -59,6 +63,8 @@ public class Settings_Authentication extends PreferenceFragment implements OnPre  		mUseTLSAuth.setChecked(mProfile.mUseTLSAuth);  		mTLSAuthFile.setSummary(mProfile.mTLSAuthFilename);  		mTLSAuthDirection.setValue(mProfile.mTLSAuthDirection); +		mCipher.setText(mProfile.mCipher); +		onPreferenceChange(mCipher, mProfile.mCipher);  	}  	private void saveSettings() { @@ -76,6 +82,12 @@ public class Settings_Authentication extends PreferenceFragment implements OnPre  			mProfile.mTLSAuthDirection=null;  		else  			mProfile.mTLSAuthDirection = mTLSAuthDirection.getValue().toString(); +		 +		if(mCipher.getText()==null) +			mProfile.mCipher=null; +		else +			mProfile.mCipher = mCipher.getText(); +		  	}  	@Override @@ -91,6 +103,8 @@ public class Settings_Authentication extends PreferenceFragment implements OnPre  				preference.setSummary(mProfile.mServerName);  			else  				preference.setSummary((String)newValue); +		} else if (preference == mCipher) { +			preference.setSummary((CharSequence) newValue);  		}  		return true;  	} diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index 26cf50bd..63d6876e 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -90,10 +90,13 @@ public class VpnProfile implements  Serializable{  	public boolean mUseCustomConfig=false;  	public String mCustomConfigOptions="";  	public String mVerb="1"; +	public String mCipher=""; -	public static String openVpnEscape(String unescape) { -		String escapedString = unescape.replace("\\", "\\\\"); +	public static String openVpnEscape(String unescaped) { +		if(unescaped==null) +			return null; +		String escapedString = unescaped.replace("\\", "\\\\");  		escapedString = escapedString.replace("\"","\\\"");  		escapedString = escapedString.replace("\n","\\n");  		return '"' + escapedString + '"'; @@ -269,6 +272,9 @@ public class VpnProfile implements  Serializable{  			cfg += "remote-cert-tls server\n"; +		if(nonNull(mCipher)){ +			cfg += "cipher " + mCipher + "\n"; +		}  		// Obscure Settings dialog @@ -291,6 +297,13 @@ public class VpnProfile implements  Serializable{  		return cfg;  	} +	private boolean nonNull(String val) { +		if(val == null || val.equals(""))  +			return false; +		else +			return true; +	} +  	private Collection<String> getCustomRoutes() {  		Vector<String> cidrRoutes=new Vector<String>();  		if(mCustomRoutes==null) { @@ -343,7 +356,7 @@ public class VpnProfile implements  Serializable{  		Vector<String> args = new Vector<String>();  		// Add fixed paramenters -		//args.add(cacheDir.getAbsolutePath() +"/" +"openvpn"); +		//args.add("/data/data/de.blinkt.openvpn/lib/openvpn");  		args.add(cacheDir.getAbsolutePath() +"/" +"minivpn");  		args.add("--config"); @@ -41,4 +41,5 @@ Requested by users:  cipher  auth  mtu-link +nobind | 
