From d573932062cb4afd7f001899978e37ce446934e7 Mon Sep 17 00:00:00 2001 From: Arne Schwabe 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 +#include +#include "cryptlib.h" +#include +#include + +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< +#include +#include +#include + +#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; iGetObjectArrayElement(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; iGetObjectArrayElement(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 #endif -#ifdef TARGET_LINUX +#if defined(TARGET_LINUX) || defined (TARGET_ANDROID) #if defined(HAVE_NETINET_IF_ETHER_H) #include 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