From 811436bea4925a657ce8a986c64513f76a5f2aa5 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 7 Feb 2013 23:40:38 +0100 Subject: First working version of OpenVPN 3 Core (still much left to do --HG-- branch : ovpn3 --- .hgignore | 3 +- jni/Android.mk | 2 +- jni/Application.mk | 3 +- jni/jbcrypto.cpp | 4 +- ovpn3/Android.mk | 37 ++ ovpn3/boostsrc/error_code.cpp | 430 +++++++++++++++++++++ res/xml/general_settings.xml | 7 +- src/de/blinkt/openvpn/CIDRIP.java | 6 + src/de/blinkt/openvpn/OpenVPNThreadv3.java | 201 ++++++++++ src/de/blinkt/openvpn/OpenVpnManagementThread.java | 89 +---- src/de/blinkt/openvpn/OpenVpnService.java | 45 ++- src/de/blinkt/openvpn/ShowConfigFragment.java | 32 +- src/de/blinkt/openvpn/VpnProfile.java | 149 +++++-- 13 files changed, 879 insertions(+), 129 deletions(-) create mode 100644 ovpn3/Android.mk create mode 100644 ovpn3/boostsrc/error_code.cpp create mode 100644 src/de/blinkt/openvpn/OpenVPNThreadv3.java diff --git a/.hgignore b/.hgignore index 7a6193b8..eab1094c 100644 --- a/.hgignore +++ b/.hgignore @@ -62,4 +62,5 @@ ics-openvpn.zip zh-CN.zip zh-TW.zip google-breakpad/ -id.zip \ No newline at end of file +id.zip +ovpn3/boost \ No newline at end of file diff --git a/jni/Android.mk b/jni/Android.mk index 283be302..4cc1d173 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -10,7 +10,7 @@ include google-breakpad/android/google_breakpad/Android.mk endif include openvpn/Android.mk - +include ovpn3/Android.mk LOCAL_PATH := $(JNI_DIR) diff --git a/jni/Application.mk b/jni/Application.mk index 5670b6e3..a9657a19 100644 --- a/jni/Application.mk +++ b/jni/Application.mk @@ -1,7 +1,8 @@ APP_ABI := all NDK_TOOLCHAIN_VERSION=4.4.3 #APP_PLATFORM := android-14 -APP_STL:=stlport_static +#APP_STL:=stlport_static +APP_STL:=gnustl_static #APP_OPTIM := release diff --git a/jni/jbcrypto.cpp b/jni/jbcrypto.cpp index 8bc6fb8d..77382fb9 100644 --- a/jni/jbcrypto.cpp +++ b/jni/jbcrypto.cpp @@ -17,7 +17,7 @@ extern "C" { -jbyteArray Java_de_blinkt_openvpn_OpenVpnManagementThread_rsasign(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef); +jbyteArray Java_de_blinkt_openvpn_VpnProfile_rsasign(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef); } int jniThrowException(JNIEnv* env, const char* className, const char* msg) { @@ -41,7 +41,7 @@ int jniThrowException(JNIEnv* env, const char* className, const char* msg) { } -jbyteArray Java_de_blinkt_openvpn_OpenVpnManagementThread_rsasign(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef) { +jbyteArray Java_de_blinkt_openvpn_VpnProfile_rsasign(JNIEnv* env, jclass, jbyteArray from, jint pkeyRef) { // EVP_MD_CTX* ctx = reinterpret_cast(ctxRef); EVP_PKEY* pkey = reinterpret_cast(pkeyRef); diff --git a/ovpn3/Android.mk b/ovpn3/Android.mk new file mode 100644 index 00000000..0033d45a --- /dev/null +++ b/ovpn3/Android.mk @@ -0,0 +1,37 @@ +LOCAL_PATH:= $(call my-dir)/ + +include $(CLEAR_VARS) + +LOCAL_LDLIBS := -lz +LOCAL_C_INCLUDES := openssl/include lzo/include openssl/crypto openssl openvpn/src/compat ovpn3/client ovpn3 +LOCAL_CPP_FEATURES += exceptions rtti + +LOCAL_SHARED_LIBRARIES := libssl libcrypto +#LOCAL_STATIC_LIBRARIES := libssl_static libcrypto_static liblzo-static + +LOCAL_CFLAGS= -DHAVE_CONFIG_H -DTARGET_ABI=\"${TARGET_ABI}\" -DUSE_OPENSSL -DOPENSSL_NO_ENGINE +LOCAL_STATIC_LIBRARIES := liblzo-static + +#ifneq ($(TARGET_ARCH),mips) +#LOCAL_STATIC_LIBRARIES += breakpad_client +#LOCAL_CFLAGS += -DGOOGLE_BREAKPAD=1 +#endif + +LOCAL_MODULE = ovpn3 + +LOCAL_SRC_FILES:= \ + javacli/ovpncli_wrap.cpp \ + boostsrc/error_code.cpp \ + client/ovpncli.cpp + +#ifneq ($(TARGET_ARCH),mips) +#LOCAL_SRC_FILES+=src/openvpn/breakpad.cpp +#endif + + + +include $(BUILD_SHARED_LIBRARY) +#include $(BUILD_EXECUTABLE) + + + diff --git a/ovpn3/boostsrc/error_code.cpp b/ovpn3/boostsrc/error_code.cpp new file mode 100644 index 00000000..6772d154 --- /dev/null +++ b/ovpn3/boostsrc/error_code.cpp @@ -0,0 +1,430 @@ +// error_code support implementation file ----------------------------------// + +// Copyright Beman Dawes 2002, 2006 + +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// See library home page at http://www.boost.org/libs/system + +//----------------------------------------------------------------------------// + +#include + +// define BOOST_SYSTEM_SOURCE so that knows +// the library is being built (possibly exporting rather than importing code) +#define BOOST_SYSTEM_SOURCE + +#include +#include +#include +#include +#include +#include + +using namespace boost::system; +using namespace boost::system::errc; + +#include // for strerror/strerror_r + +# if defined( BOOST_WINDOWS_API ) +# include +# include "local_free_on_destruction.hpp" +# ifndef ERROR_INCORRECT_SIZE +# define ERROR_INCORRECT_SIZE ERROR_BAD_ARGUMENTS +# endif +# endif + +//----------------------------------------------------------------------------// + +namespace +{ +#if defined(__PGI) + using boost::system::errc::invalid_argument; +#endif + // standard error categories ---------------------------------------------// + + class generic_error_category : public error_category + { + public: + generic_error_category(){} + const char * name() const; + std::string message( int ev ) const; + }; + + class system_error_category : public error_category + { + public: + system_error_category(){} + const char * name() const; + std::string message( int ev ) const; + error_condition default_error_condition( int ev ) const; + }; + + // generic_error_category implementation ---------------------------------// + + const char * generic_error_category::name() const + { + return "generic"; + } + + std::string generic_error_category::message( int ev ) const + { + static std::string unknown_err( "Unknown error" ); + // strerror_r is preferred because it is always thread safe, + // however, we fallback to strerror in certain cases because: + // -- Windows doesn't provide strerror_r. + // -- HP and Sun do provide strerror_r on newer systems, but there is + // no way to tell if is available at runtime and in any case their + // versions of strerror are thread safe anyhow. + // -- Linux only sometimes provides strerror_r. + // -- Tru64 provides strerror_r only when compiled -pthread. + // -- VMS doesn't provide strerror_r, but on this platform, strerror is + // thread safe. + # if defined(BOOST_WINDOWS_API) || defined(__hpux) || defined(__sun)\ + || (defined(__linux) && (!defined(__USE_XOPEN2K) || defined(BOOST_SYSTEM_USE_STRERROR)))\ + || (defined(__osf__) && !defined(_REENTRANT))\ + || (defined(__INTEGRITY))\ + || (defined(__vms))\ + || (defined(__QNXNTO__)) + const char * c_str = std::strerror( ev ); + return c_str + ? std::string( c_str ) + : unknown_err; + # else // use strerror_r + char buf[64]; + char * bp = buf; + std::size_t sz = sizeof(buf); + # if defined(__CYGWIN__) || defined(__USE_GNU) + // Oddball version of strerror_r + const char * c_str = strerror_r( ev, bp, sz ); + return c_str + ? std::string( c_str ) + : unknown_err; + # else + // POSIX version of strerror_r + int result; + for (;;) + { + // strerror_r returns 0 on success, otherwise ERANGE if buffer too small, + // invalid_argument if ev not a valid error number + # if defined (__sgi) + const char * c_str = strerror( ev ); + result = 0; + return c_str + ? std::string( c_str ) + : unknown_err; + # else + result = strerror_r( ev, bp, sz ); + # endif + if (result == 0 ) + break; + else + { + # if defined(__linux) + // Linux strerror_r returns -1 on error, with error number in errno + result = errno; + # endif + if ( result != ERANGE ) break; + if ( sz > sizeof(buf) ) std::free( bp ); + sz *= 2; + if ( (bp = static_cast(std::malloc( sz ))) == 0 ) + return std::string( "ENOMEM" ); + } + } + std::string msg; + try + { + msg = ( ( result == invalid_argument ) ? "Unknown error" : bp ); + } + +# ifndef BOOST_NO_EXCEPTIONS + // See ticket #2098 + catch(...) + { + // just eat the exception + } +# endif + + if ( sz > sizeof(buf) ) std::free( bp ); + sz = 0; + return msg; + # endif // else POSIX version of strerror_r + # endif // else use strerror_r + } + // system_error_category implementation --------------------------------// + + const char * system_error_category::name() const + { + return "system"; + } + + error_condition system_error_category::default_error_condition( int ev ) const + { + switch ( ev ) + { + case 0: return make_error_condition( success ); +# if defined(BOOST_POSIX_API) + // POSIX-like O/S -> posix_errno decode table ---------------------------// + case E2BIG: return make_error_condition( argument_list_too_long ); + case EACCES: return make_error_condition( permission_denied ); + case EADDRINUSE: return make_error_condition( address_in_use ); + case EADDRNOTAVAIL: return make_error_condition( address_not_available ); + case EAFNOSUPPORT: return make_error_condition( address_family_not_supported ); + case EAGAIN: return make_error_condition( resource_unavailable_try_again ); +# if EALREADY != EBUSY // EALREADY and EBUSY are the same on QNX Neutrino + case EALREADY: return make_error_condition( connection_already_in_progress ); +# endif + case EBADF: return make_error_condition( bad_file_descriptor ); + case EBADMSG: return make_error_condition( bad_message ); + case EBUSY: return make_error_condition( device_or_resource_busy ); + case ECANCELED: return make_error_condition( operation_canceled ); + case ECHILD: return make_error_condition( no_child_process ); + case ECONNABORTED: return make_error_condition( connection_aborted ); + case ECONNREFUSED: return make_error_condition( connection_refused ); + case ECONNRESET: return make_error_condition( connection_reset ); + case EDEADLK: return make_error_condition( resource_deadlock_would_occur ); + case EDESTADDRREQ: return make_error_condition( destination_address_required ); + case EDOM: return make_error_condition( argument_out_of_domain ); + case EEXIST: return make_error_condition( file_exists ); + case EFAULT: return make_error_condition( bad_address ); + case EFBIG: return make_error_condition( file_too_large ); + case EHOSTUNREACH: return make_error_condition( host_unreachable ); + case EIDRM: return make_error_condition( identifier_removed ); + case EILSEQ: return make_error_condition( illegal_byte_sequence ); + case EINPROGRESS: return make_error_condition( operation_in_progress ); + case EINTR: return make_error_condition( interrupted ); + case EINVAL: return make_error_condition( invalid_argument ); + case EIO: return make_error_condition( io_error ); + case EISCONN: return make_error_condition( already_connected ); + case EISDIR: return make_error_condition( is_a_directory ); + case ELOOP: return make_error_condition( too_many_symbolic_link_levels ); + case EMFILE: return make_error_condition( too_many_files_open ); + case EMLINK: return make_error_condition( too_many_links ); + case EMSGSIZE: return make_error_condition( message_size ); + case ENAMETOOLONG: return make_error_condition( filename_too_long ); + case ENETDOWN: return make_error_condition( network_down ); + case ENETRESET: return make_error_condition( network_reset ); + case ENETUNREACH: return make_error_condition( network_unreachable ); + case ENFILE: return make_error_condition( too_many_files_open_in_system ); + case ENOBUFS: return make_error_condition( no_buffer_space ); + case ENODATA: return make_error_condition( no_message_available ); + case ENODEV: return make_error_condition( no_such_device ); + case ENOENT: return make_error_condition( no_such_file_or_directory ); + case ENOEXEC: return make_error_condition( executable_format_error ); + case ENOLCK: return make_error_condition( no_lock_available ); + case ENOLINK: return make_error_condition( no_link ); + case ENOMEM: return make_error_condition( not_enough_memory ); + case ENOMSG: return make_error_condition( no_message ); + case ENOPROTOOPT: return make_error_condition( no_protocol_option ); + case ENOSPC: return make_error_condition( no_space_on_device ); + case ENOSR: return make_error_condition( no_stream_resources ); + case ENOSTR: return make_error_condition( not_a_stream ); + case ENOSYS: return make_error_condition( function_not_supported ); + case ENOTCONN: return make_error_condition( not_connected ); + case ENOTDIR: return make_error_condition( not_a_directory ); + # if ENOTEMPTY != EEXIST // AIX treats ENOTEMPTY and EEXIST as the same value + case ENOTEMPTY: return make_error_condition( directory_not_empty ); + # endif // ENOTEMPTY != EEXIST + # if ENOTRECOVERABLE != ECONNRESET // the same on some Broadcom chips + case ENOTRECOVERABLE: return make_error_condition( state_not_recoverable ); + # endif // ENOTRECOVERABLE != ECONNRESET + case ENOTSOCK: return make_error_condition( not_a_socket ); + case ENOTSUP: return make_error_condition( not_supported ); + case ENOTTY: return make_error_condition( inappropriate_io_control_operation ); + case ENXIO: return make_error_condition( no_such_device_or_address ); + # if EOPNOTSUPP != ENOTSUP + case EOPNOTSUPP: return make_error_condition( operation_not_supported ); + # endif // EOPNOTSUPP != ENOTSUP + case EOVERFLOW: return make_error_condition( value_too_large ); + # if EOWNERDEAD != ECONNABORTED // the same on some Broadcom chips + case EOWNERDEAD: return make_error_condition( owner_dead ); + # endif // EOWNERDEAD != ECONNABORTED + case EPERM: return make_error_condition( operation_not_permitted ); + case EPIPE: return make_error_condition( broken_pipe ); + case EPROTO: return make_error_condition( protocol_error ); + case EPROTONOSUPPORT: return make_error_condition( protocol_not_supported ); + case EPROTOTYPE: return make_error_condition( wrong_protocol_type ); + case ERANGE: return make_error_condition( result_out_of_range ); + case EROFS: return make_error_condition( read_only_file_system ); + case ESPIPE: return make_error_condition( invalid_seek ); + case ESRCH: return make_error_condition( no_such_process ); + case ETIME: return make_error_condition( stream_timeout ); + case ETIMEDOUT: return make_error_condition( timed_out ); + case ETXTBSY: return make_error_condition( text_file_busy ); + # if EAGAIN != EWOULDBLOCK + case EWOULDBLOCK: return make_error_condition( operation_would_block ); + # endif // EAGAIN != EWOULDBLOCK + case EXDEV: return make_error_condition( cross_device_link ); + #else + // Windows system -> posix_errno decode table ---------------------------// + // see WinError.h comments for descriptions of errors + case ERROR_ACCESS_DENIED: return make_error_condition( permission_denied ); + case ERROR_ALREADY_EXISTS: return make_error_condition( file_exists ); + case ERROR_BAD_UNIT: return make_error_condition( no_such_device ); + case ERROR_BUFFER_OVERFLOW: return make_error_condition( filename_too_long ); + case ERROR_BUSY: return make_error_condition( device_or_resource_busy ); + case ERROR_BUSY_DRIVE: return make_error_condition( device_or_resource_busy ); + case ERROR_CANNOT_MAKE: return make_error_condition( permission_denied ); + case ERROR_CANTOPEN: return make_error_condition( io_error ); + case ERROR_CANTREAD: return make_error_condition( io_error ); + case ERROR_CANTWRITE: return make_error_condition( io_error ); + case ERROR_CURRENT_DIRECTORY: return make_error_condition( permission_denied ); + case ERROR_DEV_NOT_EXIST: return make_error_condition( no_such_device ); + case ERROR_DEVICE_IN_USE: return make_error_condition( device_or_resource_busy ); + case ERROR_DIR_NOT_EMPTY: return make_error_condition( directory_not_empty ); + case ERROR_DIRECTORY: return make_error_condition( invalid_argument ); // WinError.h: "The directory name is invalid" + case ERROR_DISK_FULL: return make_error_condition( no_space_on_device ); + case ERROR_FILE_EXISTS: return make_error_condition( file_exists ); + case ERROR_FILE_NOT_FOUND: return make_error_condition( no_such_file_or_directory ); + case ERROR_HANDLE_DISK_FULL: return make_error_condition( no_space_on_device ); + case ERROR_INVALID_ACCESS: return make_error_condition( permission_denied ); + case ERROR_INVALID_DRIVE: return make_error_condition( no_such_device ); + case ERROR_INVALID_FUNCTION: return make_error_condition( function_not_supported ); + case ERROR_INVALID_HANDLE: return make_error_condition( invalid_argument ); + case ERROR_INVALID_NAME: return make_error_condition( invalid_argument ); + case ERROR_LOCK_VIOLATION: return make_error_condition( no_lock_available ); + case ERROR_LOCKED: return make_error_condition( no_lock_available ); + case ERROR_NEGATIVE_SEEK: return make_error_condition( invalid_argument ); + case ERROR_NOACCESS: return make_error_condition( permission_denied ); + case ERROR_NOT_ENOUGH_MEMORY: return make_error_condition( not_enough_memory ); + case ERROR_NOT_READY: return make_error_condition( resource_unavailable_try_again ); + case ERROR_NOT_SAME_DEVICE: return make_error_condition( cross_device_link ); + case ERROR_OPEN_FAILED: return make_error_condition( io_error ); + case ERROR_OPEN_FILES: return make_error_condition( device_or_resource_busy ); + case ERROR_OPERATION_ABORTED: return make_error_condition( operation_canceled ); + case ERROR_OUTOFMEMORY: return make_error_condition( not_enough_memory ); + case ERROR_PATH_NOT_FOUND: return make_error_condition( no_such_file_or_directory ); + case ERROR_READ_FAULT: return make_error_condition( io_error ); + case ERROR_RETRY: return make_error_condition( resource_unavailable_try_again ); + case ERROR_SEEK: return make_error_condition( io_error ); + case ERROR_SHARING_VIOLATION: return make_error_condition( permission_denied ); + case ERROR_TOO_MANY_OPEN_FILES: return make_error_condition( too_many_files_open ); + case ERROR_WRITE_FAULT: return make_error_condition( io_error ); + case ERROR_WRITE_PROTECT: return make_error_condition( permission_denied ); + case WSAEACCES: return make_error_condition( permission_denied ); + case WSAEADDRINUSE: return make_error_condition( address_in_use ); + case WSAEADDRNOTAVAIL: return make_error_condition( address_not_available ); + case WSAEAFNOSUPPORT: return make_error_condition( address_family_not_supported ); + case WSAEALREADY: return make_error_condition( connection_already_in_progress ); + case WSAEBADF: return make_error_condition( bad_file_descriptor ); + case WSAECONNABORTED: return make_error_condition( connection_aborted ); + case WSAECONNREFUSED: return make_error_condition( connection_refused ); + case WSAECONNRESET: return make_error_condition( connection_reset ); + case WSAEDESTADDRREQ: return make_error_condition( destination_address_required ); + case WSAEFAULT: return make_error_condition( bad_address ); + case WSAEHOSTUNREACH: return make_error_condition( host_unreachable ); + case WSAEINPROGRESS: return make_error_condition( operation_in_progress ); + case WSAEINTR: return make_error_condition( interrupted ); + case WSAEINVAL: return make_error_condition( invalid_argument ); + case WSAEISCONN: return make_error_condition( already_connected ); + case WSAEMFILE: return make_error_condition( too_many_files_open ); + case WSAEMSGSIZE: return make_error_condition( message_size ); + case WSAENAMETOOLONG: return make_error_condition( filename_too_long ); + case WSAENETDOWN: return make_error_condition( network_down ); + case WSAENETRESET: return make_error_condition( network_reset ); + case WSAENETUNREACH: return make_error_condition( network_unreachable ); + case WSAENOBUFS: return make_error_condition( no_buffer_space ); + case WSAENOPROTOOPT: return make_error_condition( no_protocol_option ); + case WSAENOTCONN: return make_error_condition( not_connected ); + case WSAENOTSOCK: return make_error_condition( not_a_socket ); + case WSAEOPNOTSUPP: return make_error_condition( operation_not_supported ); + case WSAEPROTONOSUPPORT: return make_error_condition( protocol_not_supported ); + case WSAEPROTOTYPE: return make_error_condition( wrong_protocol_type ); + case WSAETIMEDOUT: return make_error_condition( timed_out ); + case WSAEWOULDBLOCK: return make_error_condition( operation_would_block ); + #endif + default: return error_condition( ev, system_category() ); + } + } + +# if !defined( BOOST_WINDOWS_API ) + + std::string system_error_category::message( int ev ) const + { + return generic_category().message( ev ); + } +# else + + std::string system_error_category::message( int ev ) const + { +# ifndef BOOST_NO_ANSI_APIS + LPVOID lpMsgBuf = 0; + DWORD retval = ::FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + ev, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPSTR) &lpMsgBuf, + 0, + NULL + ); + detail::local_free_on_destruction lfod(lpMsgBuf); + if (retval == 0) + return std::string("Unknown error"); + + std::string str( static_cast(lpMsgBuf) ); +# else // WinCE workaround + LPVOID lpMsgBuf = 0; + DWORD retval = ::FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + ev, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language + (LPWSTR) &lpMsgBuf, + 0, + NULL + ); + detail::local_free_on_destruction lfod(lpMsgBuf); + if (retval == 0) + return std::string("Unknown error"); + + int num_chars = (wcslen( static_cast(lpMsgBuf) ) + 1) * 2; + LPSTR narrow_buffer = (LPSTR)_alloca( num_chars ); + if (::WideCharToMultiByte(CP_ACP, 0, static_cast(lpMsgBuf), -1, narrow_buffer, num_chars, NULL, NULL) == 0) + return std::string("Unknown error"); + + std::string str( narrow_buffer ); +# endif + while ( str.size() + && (str[str.size()-1] == '\n' || str[str.size()-1] == '\r') ) + str.erase( str.size()-1 ); + if ( str.size() && str[str.size()-1] == '.' ) + { str.erase( str.size()-1 ); } + return str; + } +# endif + +} // unnamed namespace + +namespace boost +{ + namespace system + { + +# ifndef BOOST_SYSTEM_NO_DEPRECATED + BOOST_SYSTEM_DECL error_code throws; // "throw on error" special error_code; + // note that it doesn't matter if this + // isn't initialized before use since + // the only use is to take its + // address for comparison purposes +# endif + + BOOST_SYSTEM_DECL const error_category & system_category() + { + static const system_error_category system_category_const; + return system_category_const; + } + + BOOST_SYSTEM_DECL const error_category & generic_category() + { + static const generic_error_category generic_category_const; + return generic_category_const; + } + + } // namespace system +} // namespace boost diff --git a/res/xml/general_settings.xml b/res/xml/general_settings.xml index 5b4726d3..37035816 100644 --- a/res/xml/general_settings.xml +++ b/res/xml/general_settings.xml @@ -1,6 +1,5 @@ - + active=new Vector(); static private native void jniclose(int fdint); - static private native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException; public OpenVpnManagementThread(VpnProfile profile, LocalServerSocket mgmtsocket, OpenVpnService openVpnService) { mProfile = profile; @@ -477,89 +476,9 @@ public class OpenVpnManagementThread implements Runnable { private void processSignCommand(String b64data) { - PrivateKey privkey = mProfile.getKeystoreKey(); - Exception err =null; - - byte[] data = Base64.decode(b64data, Base64.DEFAULT); - - // The Jelly Bean *evil* Hack - // 4.2 implements the RSA/ECB/PKCS1PADDING in the OpenSSLprovider - if(Build.VERSION.SDK_INT==Build.VERSION_CODES.JELLY_BEAN){ - processSignJellyBeans(privkey,data); - return; - } - - - try{ - - - Cipher rsasinger = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); - - rsasinger.init(Cipher.ENCRYPT_MODE, privkey); - - byte[] signed_bytes = rsasinger.doFinal(data); - String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP); - managmentCommand("rsa-sig\n"); - managmentCommand(signed_string); - managmentCommand("\nEND\n"); - } catch (NoSuchAlgorithmException e){ - err =e; - } catch (InvalidKeyException e) { - err =e; - } catch (NoSuchPaddingException e) { - err =e; - } catch (IllegalBlockSizeException e) { - err =e; - } catch (BadPaddingException e) { - err =e; - } - if(err !=null) { - OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage()); - } - - } - - - private void processSignJellyBeans(PrivateKey privkey, byte[] data) { - Exception err =null; - try { - Method[] allm = privkey.getClass().getSuperclass().getDeclaredMethods(); - System.out.println(allm); - Method getKey = privkey.getClass().getSuperclass().getDeclaredMethod("getOpenSSLKey"); - getKey.setAccessible(true); - - // Real object type is OpenSSLKey - Object opensslkey = getKey.invoke(privkey); - - getKey.setAccessible(false); - - Method getPkeyContext = opensslkey.getClass().getDeclaredMethod("getPkeyContext"); - - // integer pointer to EVP_pkey - getPkeyContext.setAccessible(true); - int pkey = (Integer) getPkeyContext.invoke(opensslkey); - getPkeyContext.setAccessible(false); - - byte[] signed_bytes = rsasign(data, pkey); - String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP); - managmentCommand("rsa-sig\n"); - managmentCommand(signed_string); - managmentCommand("\nEND\n"); - - } catch (NoSuchMethodException e) { - err=e; - } catch (IllegalArgumentException e) { - err=e; - } catch (IllegalAccessException e) { - err=e; - } catch (InvocationTargetException e) { - err=e; - } catch (InvalidKeyException e) { - err=e; - } - if(err !=null) { - OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage()); - } - + String signed_string = mProfile.getSignedData(b64data); + managmentCommand("rsa-sig\n"); + managmentCommand(signed_string); + managmentCommand("\nEND\n"); } } diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index 6103ff89..bf48bb3f 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -27,6 +27,7 @@ import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.SharedPreferences; import android.net.ConnectivityManager; import android.net.LocalServerSocket; import android.net.LocalSocket; @@ -38,6 +39,7 @@ import android.os.Handler.Callback; import android.os.IBinder; import android.os.Message; import android.os.ParcelFileDescriptor; +import android.preference.PreferenceManager; import de.blinkt.openvpn.OpenVPN.ByteCountListener; import de.blinkt.openvpn.OpenVPN.StateListener; @@ -121,8 +123,10 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac OpenVPN.removeByteCountListener(this); ProfileManager.setConntectedVpnProfileDisconnected(this); if(!mStarting) { - stopSelf(); - stopForeground(true); + stopForeground(!mNotificationalwaysVisible); + + if( !mNotificationalwaysVisible) + stopSelf(); } } @@ -171,7 +175,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // PRIORITY_MIN == -2 setpriority.invoke(nbuilder, -2 ); - nbuilder.setUsesChronometer(true); + Method setUsesChronometer = nbuilder.getClass().getMethod("setPriority", boolean.class); + setUsesChronometer.invoke(nbuilder,true); + /* PendingIntent cancelconnet=null; nbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, @@ -301,8 +307,22 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // Start a new session by creating a new thread. - OpenVPNThread processThread = new OpenVPNThread(this, argv,nativelibdir); + SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); + + boolean ovpn3 = prefs.getBoolean("ovpn3", false); + + Runnable processThread; + if(ovpn3) { + + OpenVPNThreadv3 v3Thread = new OpenVPNThreadv3(this,mProfile); + + processThread = v3Thread; + + } else { + processThread = new OpenVPNThread(this, argv,nativelibdir); + + } mProcessThread = new Thread(processThread, "OpenVPNProcessThread"); mProcessThread.start(); @@ -452,6 +472,10 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac } + public void addRoute(CIDRIP route) + { + mRoutes.add(route ); + } public void addRoute(String dest, String mask) { CIDRIP route = new CIDRIP(dest, mask); if(route.len == 32 && !mask.equals("255.255.255.255")) { @@ -468,7 +492,16 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac mRoutesv6.add(extra); } - + public void setMtu(int mtu) { + mMtu=mtu; + } + + public void setLocalIP(CIDRIP cdrip) + { + mLocalIP=cdrip; + } + + public void setLocalIP(String local, String netmask,int mtu, String mode) { mLocalIP = new CIDRIP(local, netmask); mMtu = mtu; @@ -477,7 +510,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // get the netmask as IP long netint = CIDRIP.getInt(netmask); if(Math.abs(netint - mLocalIP.getInt()) ==1) { - if(mode.equals("net30")) + if("net30".equals(mode)) mLocalIP.len=30; else mLocalIP.len=31; diff --git a/src/de/blinkt/openvpn/ShowConfigFragment.java b/src/de/blinkt/openvpn/ShowConfigFragment.java index dae83438..c9c778df 100644 --- a/src/de/blinkt/openvpn/ShowConfigFragment.java +++ b/src/de/blinkt/openvpn/ShowConfigFragment.java @@ -17,21 +17,41 @@ public class ShowConfigFragment extends Fragment { public android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { String profileUUID = getArguments().getString(getActivity().getPackageName() + ".profileUUID"); - VpnProfile vp = ProfileManager.get(profileUUID); + final VpnProfile vp = ProfileManager.get(profileUUID); View v=inflater.inflate(R.layout.viewconfig, container,false); - TextView cv = (TextView) v.findViewById(R.id.configview); + final TextView cv = (TextView) v.findViewById(R.id.configview); int check=vp.checkProfile(getActivity()); if(check!=R.string.no_error_found) { cv.setText(check); configtext = getString(check); } - else { - String cfg=vp.getConfigFile(getActivity()); - configtext= cfg; - cv.setText(cfg); + else { + // Run in own Thread since Keystore does not like to be queried from the main thread + + cv.setText("Generating config..."); + startGenConfig(vp, cv); } return v; + } + + private void startGenConfig(final VpnProfile vp, final TextView cv) { + + new Thread() { + public void run() { + final String cfg=vp.getConfigFile(getActivity(),false); + configtext= cfg; + getActivity().runOnUiThread(new Runnable() { + + @Override + public void run() { + cv.setText(cfg); + } + }); + + + }; + }.start(); }; @Override diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index 37e9b2ff..2f2a10a8 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -9,6 +9,11 @@ import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.Serializable; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.Certificate; import java.security.cert.CertificateException; @@ -19,6 +24,11 @@ import java.util.Locale; import java.util.UUID; import java.util.Vector; +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; + import org.spongycastle.util.io.pem.PemObject; import org.spongycastle.util.io.pem.PemWriter; @@ -30,6 +40,7 @@ import android.os.Build; import android.preference.PreferenceManager; import android.security.KeyChain; import android.security.KeyChainException; +import android.util.Base64; public class VpnProfile implements Serializable{ // Parcable @@ -112,9 +123,10 @@ public class VpnProfile implements Serializable{ static final String MINIVPN = "miniopenvpn"; - - - + static private native byte[] rsasign(byte[] input,int pkey) throws InvalidKeyException; + static { + System.loadLibrary("opvpnutil"); + } public void clearDefaults() { mServerName="unkown"; @@ -140,11 +152,6 @@ public class VpnProfile implements Serializable{ return '"' + escapedString + '"'; } - - static final String OVPNCONFIGCA = "android-ca.pem"; - static final String OVPNCONFIGUSERCERT = "android-user.pem"; - - public VpnProfile(String name) { mUuid = UUID.randomUUID(); mName = name; @@ -160,7 +167,7 @@ public class VpnProfile implements Serializable{ } - public String getConfigFile(Context context) + public String getConfigFile(Context context, boolean configForOvpn3) { File cacheDir= context.getCacheDir(); @@ -255,10 +262,13 @@ public class VpnProfile implements Serializable{ case VpnProfile.TYPE_USERPASS_KEYSTORE: cfg+="auth-user-pass\n"; case VpnProfile.TYPE_KEYSTORE: - cfg+="ca " + cacheDir.getAbsolutePath() + "/" + OVPNCONFIGCA + "\n"; - cfg+="cert " + cacheDir.getAbsolutePath() + "/" + OVPNCONFIGUSERCERT + "\n"; - cfg+="management-external-key\n"; - + if(!configForOvpn3) { + String[] ks =getKeyStoreCertificates(context); + cfg+="### From Keystore ####\n"; + cfg+="\n" + ks[0] + "\n"; + cfg+="\n" + ks[0] + "\n"; + cfg+="management-external-key\n"; + } break; case VpnProfile.TYPE_USERPASS: cfg+="auth-user-pass\n"; @@ -498,7 +508,7 @@ public class VpnProfile implements Serializable{ Intent intent = new Intent(context,OpenVpnService.class); if(mAuthenticationType == VpnProfile.TYPE_KEYSTORE || mAuthenticationType == VpnProfile.TYPE_USERPASS_KEYSTORE) { - if(!saveCertificates(context)) + if(getKeyStoreCertificates(context)==null) return null; } @@ -510,7 +520,7 @@ public class VpnProfile implements Serializable{ try { FileWriter cfg = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + OVPNCONFIGFILE); - cfg.write(getConfigFile(context)); + cfg.write(getConfigFile(context,false)); cfg.flush(); cfg.close(); } catch (IOException e) { @@ -520,7 +530,7 @@ public class VpnProfile implements Serializable{ return intent; } - private boolean saveCertificates(Context context) { + String[] getKeyStoreCertificates(Context context) { PrivateKey privateKey = null; X509Certificate[] cachain=null; try { @@ -553,27 +563,30 @@ public class VpnProfile implements Serializable{ } - FileWriter fout = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGCA); - PemWriter pw = new PemWriter(fout); + + StringWriter caout = new StringWriter(); + + PemWriter pw = new PemWriter(caout); for(X509Certificate cert:cachain) { pw.writeObject(new PemObject("CERTIFICATE", cert.getEncoded())); } - pw.close(); + + StringWriter certout = new StringWriter(); + + if(cachain.length>= 1){ X509Certificate usercert = cachain[0]; - FileWriter userout = new FileWriter(context.getCacheDir().getAbsolutePath() + "/" + VpnProfile.OVPNCONFIGUSERCERT); - - PemWriter upw = new PemWriter(userout); + PemWriter upw = new PemWriter(certout); upw.writeObject(new PemObject("CERTIFICATE", usercert.getEncoded())); upw.close(); } - - return true; + + return new String[] {caout.toString(),certout.toString()}; } catch (InterruptedException e) { e.printStackTrace(); } catch (FileNotFoundException e) { @@ -590,7 +603,7 @@ public class VpnProfile implements Serializable{ } } } - return false; + return null; } private Certificate getCacertFromFile() throws FileNotFoundException, CertificateException { CertificateFactory certFact = CertificateFactory.getInstance("X.509"); @@ -651,7 +664,7 @@ public class VpnProfile implements Serializable{ return null; } } - private boolean isUserPWAuth() { + boolean isUserPWAuth() { switch(mAuthenticationType) { case TYPE_USERPASS: case TYPE_USERPASS_CERTIFICATES: @@ -748,6 +761,90 @@ public class VpnProfile implements Serializable{ return mPrivateKey; } + public String getSignedData(String b64data) { + PrivateKey privkey = getKeystoreKey(); + Exception err =null; + + byte[] data = Base64.decode(b64data, Base64.DEFAULT); + + // The Jelly Bean *evil* Hack + // 4.2 implements the RSA/ECB/PKCS1PADDING in the OpenSSLprovider + if(Build.VERSION.SDK_INT==Build.VERSION_CODES.JELLY_BEAN){ + return processSignJellyBeans(privkey,data); + } + + + try{ + + + Cipher rsasinger = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); + + rsasinger.init(Cipher.ENCRYPT_MODE, privkey); + + byte[] signed_bytes = rsasinger.doFinal(data); + String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP); + ; + } catch (NoSuchAlgorithmException e){ + err =e; + } catch (InvalidKeyException e) { + err =e; + } catch (NoSuchPaddingException e) { + err =e; + } catch (IllegalBlockSizeException e) { + err =e; + } catch (BadPaddingException e) { + err =e; + } + if(err !=null) { + OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage()); + } + return null; + + } + + + private String processSignJellyBeans(PrivateKey privkey, byte[] data) { + Exception err =null; + try { + Method[] allm = privkey.getClass().getSuperclass().getDeclaredMethods(); + System.out.println(allm); + Method getKey = privkey.getClass().getSuperclass().getDeclaredMethod("getOpenSSLKey"); + getKey.setAccessible(true); + + // Real object type is OpenSSLKey + Object opensslkey = getKey.invoke(privkey); + + getKey.setAccessible(false); + + Method getPkeyContext = opensslkey.getClass().getDeclaredMethod("getPkeyContext"); + + // integer pointer to EVP_pkey + getPkeyContext.setAccessible(true); + int pkey = (Integer) getPkeyContext.invoke(opensslkey); + getPkeyContext.setAccessible(false); + + byte[] signed_bytes = rsasign(data, pkey); + String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP); + return signed_string; + + } catch (NoSuchMethodException e) { + err=e; + } catch (IllegalArgumentException e) { + err=e; + } catch (IllegalAccessException e) { + err=e; + } catch (InvocationTargetException e) { + err=e; + } catch (InvalidKeyException e) { + err=e; + } + if(err !=null) { + OpenVPN.logError(R.string.error_rsa_sign,err.getClass().toString(),err.getLocalizedMessage()); + } + return null; + + } + } -- cgit v1.2.3 From fa9f76f27cf1a50122227e8ff9e98adb8eeb44f0 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Thu, 7 Feb 2013 23:59:39 +0100 Subject: More fixes for OpenVPN v3 Core --HG-- branch : ovpn3 --- src/de/blinkt/openvpn/OpenVPNThreadv3.java | 14 +++++++++----- src/de/blinkt/openvpn/OpenVpnService.java | 15 ++++++++++----- src/de/blinkt/openvpn/VpnProfile.java | 7 +++---- 3 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/de/blinkt/openvpn/OpenVPNThreadv3.java b/src/de/blinkt/openvpn/OpenVPNThreadv3.java index 5981ffbb..36fcc985 100644 --- a/src/de/blinkt/openvpn/OpenVPNThreadv3.java +++ b/src/de/blinkt/openvpn/OpenVPNThreadv3.java @@ -191,11 +191,15 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable } @Override - public void event(ClientAPI_Event arg0) { - if(arg0.getError()) - OpenVPN.logError(String.format("EVENT(Error): %s: %s",arg0.getName(),arg0.getInfo())); - else - OpenVPN.logInfo(String.format("EVENT %s: %s",arg0.getName(),arg0.getInfo())); + public void event(ClientAPI_Event event) { + OpenVPN.updateStateString(event.getName(), event.getInfo()); + if(event.getError()) + OpenVPN.logError(String.format("EVENT(Error): %s: %s",event.getName(),event.getInfo())); + } + + public void stopVPN() { + stop(); + } } diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index bf48bb3f..675e44b9 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -88,6 +88,8 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac private static boolean mNotificationalwaysVisible=false; private final IBinder mBinder = new LocalBinder(); + private boolean mOvpn3; + private OpenVPNThreadv3 mOpenVPN3; public class LocalBinder extends Binder { public OpenVpnService getService() { @@ -107,7 +109,10 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac @Override public void onRevoke() { - OpenVpnManagementThread.stopOpenVPN(); + if(!mOvpn3) + OpenVpnManagementThread.stopOpenVPN(); + else + mOpenVPN3.stopVPN(); endVpnService(); } @@ -309,14 +314,14 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // Start a new session by creating a new thread. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); - boolean ovpn3 = prefs.getBoolean("ovpn3", false); + mOvpn3 = prefs.getBoolean("ovpn3", false); Runnable processThread; - if(ovpn3) { + if(mOvpn3) { - OpenVPNThreadv3 v3Thread = new OpenVPNThreadv3(this,mProfile); + mOpenVPN3 = new OpenVPNThreadv3(this,mProfile); - processThread = v3Thread; + processThread = mOpenVPN3; } else { diff --git a/src/de/blinkt/openvpn/VpnProfile.java b/src/de/blinkt/openvpn/VpnProfile.java index 2f2a10a8..ea034b55 100644 --- a/src/de/blinkt/openvpn/VpnProfile.java +++ b/src/de/blinkt/openvpn/VpnProfile.java @@ -782,8 +782,8 @@ public class VpnProfile implements Serializable{ rsasinger.init(Cipher.ENCRYPT_MODE, privkey); byte[] signed_bytes = rsasinger.doFinal(data); - String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP); - ; + return Base64.encodeToString(signed_bytes, Base64.NO_WRAP); + } catch (NoSuchAlgorithmException e){ err =e; } catch (InvalidKeyException e) { @@ -824,8 +824,7 @@ public class VpnProfile implements Serializable{ getPkeyContext.setAccessible(false); byte[] signed_bytes = rsasign(data, pkey); - String signed_string = Base64.encodeToString(signed_bytes, Base64.NO_WRAP); - return signed_string; + return Base64.encodeToString(signed_bytes, Base64.NO_WRAP); } catch (NoSuchMethodException e) { err=e; -- cgit v1.2.3 From d6c35a95905c276a5241bdbf3a01ca89c3c9fd31 Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sat, 9 Feb 2013 16:44:00 +0100 Subject: More refactoring/complete support for openvpn 3 core --HG-- branch : ovpn3 --- res/values/strings.xml | 1 + src/de/blinkt/openvpn/LogWindow.java | 39 +++++++- src/de/blinkt/openvpn/NetworkSateReceiver.java | 16 ++-- src/de/blinkt/openvpn/OpenVPN.java | 9 +- src/de/blinkt/openvpn/OpenVPNThreadv3.java | 106 +++++++++++++++------ src/de/blinkt/openvpn/OpenVpnManagementThread.java | 39 ++++---- src/de/blinkt/openvpn/OpenVpnService.java | 86 ++++++++++------- 7 files changed, 203 insertions(+), 93 deletions(-) diff --git a/res/values/strings.xml b/res/values/strings.xml index da98236a..8dc15806 100755 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -247,6 +247,7 @@ Assigning IP addresses Adding routes Connected + Disconnect Reconnecting Exiting Not running diff --git a/src/de/blinkt/openvpn/LogWindow.java b/src/de/blinkt/openvpn/LogWindow.java index 88615e12..69d1f859 100644 --- a/src/de/blinkt/openvpn/LogWindow.java +++ b/src/de/blinkt/openvpn/LogWindow.java @@ -7,14 +7,17 @@ import android.app.AlertDialog.Builder; import android.app.ListActivity; import android.content.ClipData; import android.content.ClipboardManager; +import android.content.ComponentName; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; import android.content.Intent; +import android.content.ServiceConnection; import android.database.DataSetObserver; import android.os.Bundle; import android.os.Handler; import android.os.Handler.Callback; +import android.os.IBinder; import android.os.Message; import android.view.Menu; import android.view.MenuInflater; @@ -30,10 +33,31 @@ import android.widget.Toast; import de.blinkt.openvpn.OpenVPN.LogItem; import de.blinkt.openvpn.OpenVPN.LogListener; import de.blinkt.openvpn.OpenVPN.StateListener; +import de.blinkt.openvpn.OpenVpnService.LocalBinder; public class LogWindow extends ListActivity implements StateListener { private static final int START_VPN_CONFIG = 0; private String[] mBconfig=null; + protected OpenVpnService mService; + private ServiceConnection mConnection = new ServiceConnection() { + + + + @Override + public void onServiceConnected(ComponentName className, + IBinder service) { + // We've bound to LocalService, cast the IBinder and get LocalService instance + LocalBinder binder = (LocalBinder) service; + mService = binder.getService(); + } + + @Override + public void onServiceDisconnected(ComponentName arg0) { + mService =null; + } + + }; + class LogWindowListAdapter implements ListAdapter, LogListener, Callback { @@ -198,6 +222,7 @@ public class LogWindow extends ListActivity implements StateListener { private LogWindowListAdapter ladapter; private TextView mSpeedView; + @Override public boolean onOptionsItemSelected(MenuItem item) { if(item.getItemId()==R.id.clearlog) { @@ -213,7 +238,8 @@ public class LogWindow extends ListActivity implements StateListener { @Override public void onClick(DialogInterface dialog, int which) { ProfileManager.setConntectedVpnProfileDisconnected(getApplicationContext()); - OpenVpnManagementThread.stopOpenVPN(); + if(mService.getManagement()!=null) + mService.getManagement().stopVPN(); } }); @@ -324,6 +350,12 @@ public class LogWindow extends ListActivity implements StateListener { lv.setAdapter(ladapter); mSpeedView = (TextView) findViewById(R.id.speed); + + Intent intent = new Intent(getBaseContext(), OpenVpnService.class); + intent.setAction(OpenVpnService.START_SERVICE); + + bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + } @Override @@ -335,6 +367,8 @@ public class LogWindow extends ListActivity implements StateListener { String prefix=getString(resid) + ":"; if (status.equals("BYTECOUNT") || status.equals("NOPROCESS") ) prefix=""; + if (resid==R.string.unknown_state) + prefix+=status; mSpeedView.setText(prefix + logmessage); } }); @@ -343,8 +377,9 @@ public class LogWindow extends ListActivity implements StateListener { @Override protected void onDestroy() { - super.onDestroy(); + unbindService(mConnection); OpenVPN.removeLogListener(ladapter); + super.onDestroy(); } } diff --git a/src/de/blinkt/openvpn/NetworkSateReceiver.java b/src/de/blinkt/openvpn/NetworkSateReceiver.java index e20c8e52..487639a9 100644 --- a/src/de/blinkt/openvpn/NetworkSateReceiver.java +++ b/src/de/blinkt/openvpn/NetworkSateReceiver.java @@ -11,13 +11,13 @@ import android.preference.PreferenceManager; public class NetworkSateReceiver extends BroadcastReceiver { private int lastNetwork=-1; - private OpenVpnManagementThread mManangement; + private OpenVPNMangement mManangement; private String lastStateMsg=null; - public NetworkSateReceiver(OpenVpnManagementThread managementThread) { + public NetworkSateReceiver(OpenVPNMangement magnagement) { super(); - mManangement = managementThread; + mManangement = magnagement; } @Override @@ -57,15 +57,19 @@ public class NetworkSateReceiver extends BroadcastReceiver { if(networkInfo!=null && networkInfo.getState() == State.CONNECTED) { int newnet = networkInfo.getType(); - if(sendusr1 && lastNetwork!=newnet) - mManangement.reconnect(); + if(sendusr1 && lastNetwork!=newnet) { + if (lastNetwork==-1) + mManangement.resume(); + else + mManangement.reconnect(); + } lastNetwork = newnet; } else if (networkInfo==null) { // Not connected, stop openvpn, set last connected network to no network lastNetwork=-1; if(sendusr1) - mManangement.signalusr1(); + mManangement.pause(); } if(!netstatestring.equals(lastStateMsg)) diff --git a/src/de/blinkt/openvpn/OpenVPN.java b/src/de/blinkt/openvpn/OpenVPN.java index c1616f2d..2ca2d259 100644 --- a/src/de/blinkt/openvpn/OpenVPN.java +++ b/src/de/blinkt/openvpn/OpenVPN.java @@ -173,6 +173,8 @@ public class OpenVPN { return R.string.state_add_routes; else if (state.equals("CONNECTED")) return R.string.state_connected; + else if (state.equals("DISCONNECTED")) + return R.string.state_disconnected; else if (state.equals("RECONNECTING")) return R.string.state_reconnecting; else if (state.equals("EXITING")) @@ -257,7 +259,12 @@ public class OpenVPN { newlogItem(new LogItem(LogItem.ERROR, ressourceId,args)); } - public static void updateByteCount(long in, long out, long diffin, long diffout) { + public static void updateByteCount(long in, long out) { + long lastIn = mlastByteCount[0]; + long lastOut = mlastByteCount[1]; + long diffin = in - lastIn; + long diffout = out - lastOut; + mlastByteCount = new long[] {in,out,diffin,diffout}; for(ByteCountListener bcl:byteCountListener){ bcl.updateByteCount(in, out, diffin,diffout); diff --git a/src/de/blinkt/openvpn/OpenVPNThreadv3.java b/src/de/blinkt/openvpn/OpenVPNThreadv3.java index 36fcc985..39c7640f 100644 --- a/src/de/blinkt/openvpn/OpenVPNThreadv3.java +++ b/src/de/blinkt/openvpn/OpenVPNThreadv3.java @@ -9,8 +9,9 @@ import net.openvpn.ovpn3.ClientAPI_LogInfo; import net.openvpn.ovpn3.ClientAPI_OpenVPNClient; import net.openvpn.ovpn3.ClientAPI_ProvideCreds; import net.openvpn.ovpn3.ClientAPI_Status; +import net.openvpn.ovpn3.ClientAPI_TransportStats; -public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable { +public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable, OpenVPNMangement { static { System.loadLibrary("crypto"); @@ -21,6 +22,34 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable private VpnProfile mVp; private OpenVpnService mService; + class StatusPoller implements Runnable + { + private long mSleeptime; + + boolean mStopped=false; + + public StatusPoller(long sleeptime) { + mSleeptime=sleeptime; + } + + public void run() { + while(!mStopped) { + try { + Thread.sleep(mSleeptime); + } catch (InterruptedException e) { + } + ClientAPI_TransportStats t = transport_stats(); + long in = t.getBytesIn(); + long out = t.getBytesOut(); + OpenVPN.updateByteCount(in, out); + } + } + + public void stop() { + mStopped=true; + } + } + @Override public void run() { String configstr = mVp.getConfigFile(mService,true); @@ -28,20 +57,25 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable return; setUserPW(); OpenVPN.logInfo(copyright()); + + StatusPoller statuspoller = new StatusPoller(5000); + new Thread(statuspoller,"Status Poller").start(); + ClientAPI_Status status = connect(); if(status.getError()) { OpenVPN.logError(String.format("connect() error: %s: %s",status.getStatus(),status.getMessage())); } else { - OpenVPN.logInfo(String.format("connect() error: %s: %s",status.getStatus(),status.getMessage())); + OpenVPN.logInfo("OpenVPN3 thread finished"); } + statuspoller.stop(); } - + @Override public boolean tun_builder_set_remote_address(String address, boolean ipv6) { mService.setMtu(1500); return true; } - + @Override public boolean tun_builder_set_mtu(int mtu) { mService.setMtu(mtu); @@ -52,36 +86,39 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable mService.addDNS(address); return true; } - + @Override public boolean tun_builder_add_route(String address, int prefix_length, boolean ipv6) { + if (address.equals("remote_host")) + return false; + if(ipv6) mService.addRoutev6(address + "/" + prefix_length); else mService.addRoute(new CIDRIP(address, prefix_length)); return true; } - + @Override public boolean tun_builder_add_search_domain(String domain) { mService.setDomain(domain); return true; } - + @Override public int tun_builder_establish() { return mService.openTun().detachFd(); } - + @Override public boolean tun_builder_set_session_name(String name) { OpenVPN.logInfo("We should call this session" + name); return true; } - - + + @Override public boolean tun_builder_add_address(String address, int prefix_length, boolean ipv6) { @@ -91,20 +128,20 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable mService.setLocalIPv6(address+ "/" + prefix_length); return true; } - + @Override public boolean tun_builder_new() { - + return true; } - + @Override public boolean tun_builder_reroute_gw(String server_address, boolean server_address_ipv6, boolean ipv4, boolean ipv6, long flags) { // ignore return true; } - + @Override public boolean tun_builder_exclude_route(String address, int prefix_length, boolean ipv6) { @@ -114,15 +151,15 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable private boolean setConfig(String vpnconfig) { - + ClientAPI_Config config = new ClientAPI_Config(); if(mVp.getPasswordPrivateKey()!=null) config.setPrivateKeyPassword(mVp.getPasswordPrivateKey()); - + config.setContent(vpnconfig); config.setTunPersist(mVp.mPersistTun); config.setExternalPkiAlias("extpki"); - + ClientAPI_EvalConfig ec = eval_config(config); if(ec.getExternalPki()) { OpenVPN.logError("OpenVPN seem to think as external PKI"); @@ -135,7 +172,7 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable return true; } } - + @Override public void external_pki_cert_request(ClientAPI_ExternalPKICertRequest certreq) { OpenVPN.logError("EXT PKI CERT"); @@ -145,15 +182,14 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable certreq.setErrorText("Error in pki cert request"); return; } - + certreq.setSupportingChain(ks[0]); certreq.setCert(ks[1]); certreq.setError(false); } - + @Override public void external_pki_sign_request(ClientAPI_ExternalPKISignRequest signreq) { - OpenVPN.logError("EXT PKI Sign"); signreq.setSig(mVp.getSignedData(signreq.getData())); } @@ -170,9 +206,8 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable @Override public boolean socket_protect(int socket) { boolean b= mService.protect(socket); - OpenVPN.logInfo("protect from v3: " + b); - return true; - + return b; + } public OpenVPNThreadv3(OpenVpnService openVpnService, VpnProfile vp) { @@ -186,7 +221,7 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable String logmsg =arg0.getText(); while (logmsg.endsWith("\n")) logmsg = logmsg.substring(0, logmsg.length()-1); - + OpenVPN.logInfo(logmsg); } @@ -197,9 +232,26 @@ public class OpenVPNThreadv3 extends ClientAPI_OpenVPNClient implements Runnable OpenVPN.logError(String.format("EVENT(Error): %s: %s",event.getName(),event.getInfo())); } - public void stopVPN() { + + // When a connection is close to timeout, the core will call this + // method. If it returns false, the core will disconnect with a + // CONNECTION_TIMEOUT event. If true, the core will enter a PAUSE + // state. + + @Override + public boolean pause_on_connection_timeout() { + OpenVPN.logInfo("pause on connection timeout?! "); + return true; + } + + public boolean stopVPN() { stop(); - + return true; + } + + @Override + public void reconnect() { + reconnect(1); } } diff --git a/src/de/blinkt/openvpn/OpenVpnManagementThread.java b/src/de/blinkt/openvpn/OpenVpnManagementThread.java index 538079e8..e4528132 100644 --- a/src/de/blinkt/openvpn/OpenVpnManagementThread.java +++ b/src/de/blinkt/openvpn/OpenVpnManagementThread.java @@ -7,28 +7,18 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.InetSocketAddress; import java.net.SocketAddress; -import java.security.InvalidKeyException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; import java.util.LinkedList; import java.util.Locale; import java.util.Vector; -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.NoSuchPaddingException; - import android.content.SharedPreferences; import android.net.LocalServerSocket; import android.net.LocalSocket; -import android.os.Build; import android.os.ParcelFileDescriptor; import android.preference.PreferenceManager; -import android.util.Base64; import android.util.Log; -public class OpenVpnManagementThread implements Runnable { +public class OpenVpnManagementThread implements Runnable, OpenVPNMangement { private static final String TAG = "openvpn"; private LocalSocket mSocket; @@ -36,8 +26,6 @@ public class OpenVpnManagementThread implements Runnable { private OpenVpnService mOpenVPNService; private LinkedList mFDList=new LinkedList(); private int mBytecountinterval=2; - private long mLastIn=0; - private long mLastOut=0; private LocalServerSocket mServerSocket; private boolean mReleaseHold=true; private boolean mWaitingForRelease=false; @@ -284,13 +272,7 @@ public class OpenVpnManagementThread implements Runnable { long in = Long.parseLong(argument.substring(0, comma)); long out = Long.parseLong(argument.substring(comma+1)); - long diffin = in - mLastIn; - long diffout = out - mLastOut; - - mLastIn=in; - mLastOut=out; - - OpenVPN.updateByteCount(in,out,diffin, diffout); + OpenVPN.updateByteCount(in,out); } @@ -448,7 +430,7 @@ public class OpenVpnManagementThread implements Runnable { } - public static boolean stopOpenVPN() { + private static boolean stopOpenVPN() { boolean sendCMD=false; for (OpenVpnManagementThread mt: active){ mt.managmentCommand("signal SIGINT\n"); @@ -481,4 +463,19 @@ public class OpenVpnManagementThread implements Runnable { managmentCommand(signed_string); managmentCommand("\nEND\n"); } + + @Override + public void pause() { + signalusr1(); + } + + @Override + public void resume() { + releaseHold(); + } + + @Override + public boolean stopVPN() { + return stopOpenVPN(); + } } diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index 675e44b9..d5d75589 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -62,9 +62,6 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac private CIDRIP mLocalIP=null; - private OpenVpnManagementThread mManagementThread; - - private Thread mSocketManagerThread; private int mMtu; private String mLocalIPv6=null; private NetworkSateReceiver mNetworkStateReceiver; @@ -90,6 +87,8 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac private final IBinder mBinder = new LocalBinder(); private boolean mOvpn3; private OpenVPNThreadv3 mOpenVPN3; + private Thread mSocketManagerThread; + private OpenVPNMangement mManagement; public class LocalBinder extends Binder { public OpenVpnService getService() { @@ -109,10 +108,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac @Override public void onRevoke() { - if(!mOvpn3) - OpenVpnManagementThread.stopOpenVPN(); - else - mOpenVPN3.stopVPN(); + mManagement.stopVPN(); endVpnService(); } @@ -126,6 +122,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac OpenVPN.logBuilderConfig(null); OpenVPN.removeStateListener(this); OpenVPN.removeByteCountListener(this); + unregisterNetworkStateReceiver(); ProfileManager.setConntectedVpnProfileDisconnected(this); if(!mStarting) { stopForeground(!mNotificationalwaysVisible); @@ -180,9 +177,9 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // PRIORITY_MIN == -2 setpriority.invoke(nbuilder, -2 ); - Method setUsesChronometer = nbuilder.getClass().getMethod("setPriority", boolean.class); + Method setUsesChronometer = nbuilder.getClass().getMethod("setUsesChronometer", boolean.class); setUsesChronometer.invoke(nbuilder,true); - + /* PendingIntent cancelconnet=null; nbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel, @@ -240,14 +237,20 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac } - void registerNetworkStateReceiver() { + void registerNetworkStateReceiver(OpenVPNMangement magnagement) { // Registers BroadcastReceiver to track network connection changes. IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); - mNetworkStateReceiver = new NetworkSateReceiver(mManagementThread); + mNetworkStateReceiver = new NetworkSateReceiver(magnagement); this.registerReceiver(mNetworkStateReceiver, filter); } - + void unregisterNetworkStateReceiver() { + if(mNetworkStateReceiver!=null) + this.unregisterReceiver(mNetworkStateReceiver); + mNetworkStateReceiver=null; + } + + @Override public int onStartCommand(Intent intent, int flags, int startId) { @@ -274,19 +277,27 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac showNotification("Starting VPN " + mProfile.mName,"Starting VPN " + mProfile.mName, false,0,LEVEL_NOTCONNECTED); - - // Set a flag that we are starting a new VPN mStarting=true; // Stop the previous session by interrupting the thread. - if(OpenVpnManagementThread.stopOpenVPN()){ - // an old was asked to exit, wait 2s + if(mManagement!=null && mManagement.stopVPN()) + // an old was asked to exit, wait 1s + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + } + + + if(mOpenVPN3!=null) { + mOpenVPN3.stopVPN(); try { Thread.sleep(1000); } catch (InterruptedException e) { } + } + if (mProcessThread!=null) { mProcessThread.interrupt(); try { @@ -299,18 +310,19 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac // Open the Management Interface - LocalServerSocket mgmtsocket = openManagmentInterface(8); - - if(mgmtsocket!=null) { - // start a Thread that handles incoming messages of the managment socket - mManagementThread=new OpenVpnManagementThread(mProfile,mgmtsocket,this); - mSocketManagerThread = new Thread(mManagementThread,"OpenVPNMgmtThread"); - mSocketManagerThread.start(); - OpenVPN.logInfo("started Socket Thread"); - registerNetworkStateReceiver(); + if(!mOvpn3) { + LocalServerSocket mgmtsocket = openManagmentInterface(8); + + if(mgmtsocket!=null) { + // start a Thread that handles incoming messages of the managment socket + OpenVpnManagementThread ovpnmgmthread = new OpenVpnManagementThread(mProfile,mgmtsocket,this); + mSocketManagerThread = new Thread(ovpnmgmthread,"OpenVPNMgmtThread"); + mSocketManagerThread.start(); + mManagement= ovpnmgmthread; + OpenVPN.logInfo("started Socket Thread"); + } } - // Start a new session by creating a new thread. SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); @@ -318,19 +330,21 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac Runnable processThread; if(mOvpn3) { - mOpenVPN3 = new OpenVPNThreadv3(this,mProfile); - processThread = mOpenVPN3; + mManagement = mOpenVPN3; + } else { - processThread = new OpenVPNThread(this, argv,nativelibdir); - } + mProcessThread = new Thread(processThread, "OpenVPNProcessThread"); mProcessThread.start(); + registerNetworkStateReceiver(mManagement); + + ProfileManager.setConnectedVpnProfile(this, mProfile); return START_NOT_STICKY; @@ -339,7 +353,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac @Override public void onDestroy() { if (mProcessThread != null) { - mManagementThread.managmentCommand("signal SIGINT\n"); + mManagement.stopVPN(); mProcessThread.interrupt(); } @@ -500,13 +514,13 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac public void setMtu(int mtu) { mMtu=mtu; } - + public void setLocalIP(CIDRIP cdrip) { mLocalIP=cdrip; } - - + + public void setLocalIP(String local, String netmask,int mtu, String mode) { mLocalIP = new CIDRIP(local, netmask); mMtu = mtu; @@ -597,7 +611,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac } } - public OpenVpnManagementThread getManagementThread() { - return mManagementThread; + public OpenVPNMangement getManagement() { + return mManagement; } } -- cgit v1.2.3 From 76355e501a513a66329b062cf3bebd9eff81c0ba Mon Sep 17 00:00:00 2001 From: Arne Schwabe Date: Sun, 10 Feb 2013 12:16:39 +0100 Subject: Remove reflection. --HG-- branch : ovpn3 --- src/de/blinkt/openvpn/OpenVpnService.java | 19 +------------------ 1 file changed, 1 insertion(+), 18 deletions(-) diff --git a/src/de/blinkt/openvpn/OpenVpnService.java b/src/de/blinkt/openvpn/OpenVpnService.java index 34f612c3..c2768347 100644 --- a/src/de/blinkt/openvpn/OpenVpnService.java +++ b/src/de/blinkt/openvpn/OpenVpnService.java @@ -342,24 +342,7 @@ public class OpenVpnService extends VpnService implements StateListener, Callbac } private OpenVPNMangement instantiateOpenVPN3Core() { - //new OpenVPNThreadv3(this,mProfile); - try { - Class cl = Class.forName("Lde/blinkt/openvpn/OpenVPNThreadv3;"); - return (OpenVPNMangement) cl.getConstructor(OpenVpnService.class,VpnProfile.class).newInstance(this,mProfile); - } catch (IllegalArgumentException e) { - e.printStackTrace(); - } catch (InstantiationException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } catch (NoSuchMethodException e) { - e.printStackTrace(); - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } - return null; + return new OpenVPNThreadv3(this,mProfile); } @Override -- cgit v1.2.3