summaryrefslogtreecommitdiff
path: root/app/openvpn/src
diff options
context:
space:
mode:
Diffstat (limited to 'app/openvpn/src')
-rw-r--r--app/openvpn/src/compat/Makefile.am3
-rw-r--r--app/openvpn/src/compat/compat-lz4.c830
-rw-r--r--app/openvpn/src/compat/compat-lz4.h205
-rw-r--r--app/openvpn/src/compat/compat-rsa_generate_key.c47
-rw-r--r--app/openvpn/src/openvpn/Makefile.am9
-rw-r--r--app/openvpn/src/openvpn/base64.c6
-rw-r--r--app/openvpn/src/openvpn/base64.h4
-rw-r--r--app/openvpn/src/openvpn/breakpad.cpp2
-rw-r--r--app/openvpn/src/openvpn/buffer.c72
-rw-r--r--app/openvpn/src/openvpn/buffer.h51
-rw-r--r--app/openvpn/src/openvpn/clinat.c4
-rw-r--r--app/openvpn/src/openvpn/clinat.h2
-rw-r--r--app/openvpn/src/openvpn/common.h2
-rw-r--r--app/openvpn/src/openvpn/comp-lz4.c194
-rw-r--r--app/openvpn/src/openvpn/comp-lz4.h40
-rw-r--r--app/openvpn/src/openvpn/comp.c146
-rw-r--r--app/openvpn/src/openvpn/comp.h180
-rw-r--r--app/openvpn/src/openvpn/compstub.c118
-rw-r--r--app/openvpn/src/openvpn/crypto.c24
-rw-r--r--app/openvpn/src/openvpn/crypto_backend.h12
-rw-r--r--app/openvpn/src/openvpn/crypto_openssl.c83
-rw-r--r--app/openvpn/src/openvpn/crypto_polarssl.c62
-rw-r--r--app/openvpn/src/openvpn/crypto_polarssl.h3
-rw-r--r--app/openvpn/src/openvpn/error.c28
-rw-r--r--app/openvpn/src/openvpn/error.h2
-rw-r--r--app/openvpn/src/openvpn/event.c3
-rw-r--r--app/openvpn/src/openvpn/forward-inline.h1
-rw-r--r--app/openvpn/src/openvpn/forward.c39
-rw-r--r--app/openvpn/src/openvpn/init.c311
-rw-r--r--app/openvpn/src/openvpn/lzo.c154
-rw-r--r--app/openvpn/src/openvpn/lzo.h222
-rw-r--r--app/openvpn/src/openvpn/manage.c256
-rw-r--r--app/openvpn/src/openvpn/manage.h16
-rw-r--r--app/openvpn/src/openvpn/mbuf.h2
-rw-r--r--app/openvpn/src/openvpn/misc.c121
-rw-r--r--app/openvpn/src/openvpn/misc.h7
-rw-r--r--app/openvpn/src/openvpn/mroute.c56
-rw-r--r--app/openvpn/src/openvpn/mroute.h6
-rw-r--r--app/openvpn/src/openvpn/multi.c38
-rw-r--r--app/openvpn/src/openvpn/multi.h1
-rw-r--r--app/openvpn/src/openvpn/openvpn.c3
-rw-r--r--app/openvpn/src/openvpn/openvpn.h25
-rw-r--r--app/openvpn/src/openvpn/options.c768
-rw-r--r--app/openvpn/src/openvpn/options.h40
-rw-r--r--app/openvpn/src/openvpn/pf.c4
-rw-r--r--app/openvpn/src/openvpn/pkcs11_openssl.c14
-rw-r--r--app/openvpn/src/openvpn/pkcs11_polarssl.c13
-rw-r--r--app/openvpn/src/openvpn/platform.c28
-rw-r--r--app/openvpn/src/openvpn/plugin.c7
-rw-r--r--app/openvpn/src/openvpn/plugin.h2
-rw-r--r--app/openvpn/src/openvpn/proto.c2
-rw-r--r--app/openvpn/src/openvpn/proxy.c100
-rw-r--r--app/openvpn/src/openvpn/proxy.h11
-rw-r--r--app/openvpn/src/openvpn/ps.c11
-rw-r--r--app/openvpn/src/openvpn/push.c12
-rw-r--r--app/openvpn/src/openvpn/route.c705
-rw-r--r--app/openvpn/src/openvpn/route.h49
-rw-r--r--app/openvpn/src/openvpn/sig.c6
-rw-r--r--app/openvpn/src/openvpn/snappy.c189
-rw-r--r--app/openvpn/src/openvpn/snappy.h39
-rw-r--r--app/openvpn/src/openvpn/socket.c1029
-rw-r--r--app/openvpn/src/openvpn/socket.h169
-rw-r--r--app/openvpn/src/openvpn/socks.c30
-rw-r--r--app/openvpn/src/openvpn/socks.h3
-rw-r--r--app/openvpn/src/openvpn/ssl.c302
-rw-r--r--app/openvpn/src/openvpn/ssl.h1
-rw-r--r--app/openvpn/src/openvpn/ssl_backend.h101
-rw-r--r--app/openvpn/src/openvpn/ssl_common.h22
-rw-r--r--app/openvpn/src/openvpn/ssl_openssl.c370
-rw-r--r--app/openvpn/src/openvpn/ssl_polarssl.c428
-rw-r--r--app/openvpn/src/openvpn/ssl_polarssl.h13
-rw-r--r--app/openvpn/src/openvpn/ssl_verify.c34
-rw-r--r--app/openvpn/src/openvpn/ssl_verify.h31
-rw-r--r--app/openvpn/src/openvpn/ssl_verify_backend.h27
-rw-r--r--app/openvpn/src/openvpn/ssl_verify_openssl.c24
-rw-r--r--app/openvpn/src/openvpn/ssl_verify_polarssl.c178
-rw-r--r--app/openvpn/src/openvpn/ssl_verify_polarssl.h30
-rw-r--r--app/openvpn/src/openvpn/status.c2
-rw-r--r--app/openvpn/src/openvpn/syshead.h45
-rw-r--r--app/openvpn/src/openvpn/tun.c518
-rw-r--r--app/openvpn/src/openvpn/tun.h5
-rw-r--r--app/openvpn/src/openvpn/win32.c37
-rw-r--r--app/openvpn/src/plugins/auth-pam/Makefile.am5
-rw-r--r--app/openvpn/src/plugins/down-root/Makefile.am3
84 files changed, 5953 insertions, 2844 deletions
diff --git a/app/openvpn/src/compat/Makefile.am b/app/openvpn/src/compat/Makefile.am
index 7ad44525..4591b851 100644
--- a/app/openvpn/src/compat/Makefile.am
+++ b/app/openvpn/src/compat/Makefile.am
@@ -26,4 +26,5 @@ libcompat_la_SOURCES = \
compat-gettimeofday.c \
compat-daemon.c \
compat-inet_ntop.c \
- compat-inet_pton.c
+ compat-inet_pton.c \
+ compat-lz4.c compat-lz4.h
diff --git a/app/openvpn/src/compat/compat-lz4.c b/app/openvpn/src/compat/compat-lz4.c
new file mode 100644
index 00000000..c63c18ba
--- /dev/null
+++ b/app/openvpn/src/compat/compat-lz4.c
@@ -0,0 +1,830 @@
+/*
+ LZ4 - Fast LZ compression algorithm
+ Copyright (C) 2011-2013, Yann Collet.
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ You can contact the author at :
+ - LZ4 source repository : http://code.google.com/p/lz4/
+ - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#ifdef NEED_COMPAT_LZ4
+
+//**************************************
+// Tuning parameters
+//**************************************
+// MEMORY_USAGE :
+// Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.)
+// Increasing memory usage improves compression ratio
+// Reduced memory usage can improve speed, due to cache effect
+// Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache
+#define MEMORY_USAGE 14
+
+// HEAPMODE :
+// Select how default compression functions will allocate memory for their hash table,
+// in memory stack (0:default, fastest), or in memory heap (1:requires memory allocation (malloc)).
+#define HEAPMODE 0
+
+
+//**************************************
+// CPU Feature Detection
+//**************************************
+// 32 or 64 bits ?
+#if (defined(__x86_64__) || defined(_M_X64) || defined(_WIN64) \
+ || defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) \
+ || defined(__64BIT__) || defined(_LP64) || defined(__LP64__) \
+ || defined(__ia64) || defined(__itanium__) || defined(_M_IA64) ) // Detects 64 bits mode
+# define LZ4_ARCH64 1
+#else
+# define LZ4_ARCH64 0
+#endif
+
+// Little Endian or Big Endian ?
+// Overwrite the #define below if you know your architecture endianess
+#if defined (__GLIBC__)
+# include <endian.h>
+# if (__BYTE_ORDER == __BIG_ENDIAN)
+# define LZ4_BIG_ENDIAN 1
+# endif
+#elif (defined(__BIG_ENDIAN__) || defined(__BIG_ENDIAN) || defined(_BIG_ENDIAN)) && !(defined(__LITTLE_ENDIAN__) || defined(__LITTLE_ENDIAN) || defined(_LITTLE_ENDIAN))
+# define LZ4_BIG_ENDIAN 1
+#elif defined(__sparc) || defined(__sparc__) \
+ || defined(__powerpc__) || defined(__ppc__) || defined(__PPC__) \
+ || defined(__hpux) || defined(__hppa) \
+ || defined(_MIPSEB) || defined(__s390__)
+# define LZ4_BIG_ENDIAN 1
+#else
+// Little Endian assumed. PDP Endian and other very rare endian format are unsupported.
+#endif
+
+// Unaligned memory access is automatically enabled for "common" CPU, such as x86.
+// For others CPU, such as ARM, the compiler may be more cautious, inserting unnecessary extra code to ensure aligned access property
+// If you know your target CPU supports unaligned memory access, you want to force this option manually to improve performance
+#if defined(__ARM_FEATURE_UNALIGNED)
+# define LZ4_FORCE_UNALIGNED_ACCESS 1
+#endif
+
+// Define this parameter if your target system or compiler does not support hardware bit count
+#if defined(_MSC_VER) && defined(_WIN32_WCE) // Visual Studio for Windows CE does not support Hardware bit count
+# define LZ4_FORCE_SW_BITCOUNT
+#endif
+
+// BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE :
+// This option may provide a small boost to performance for some big endian cpu, although probably modest.
+// You may set this option to 1 if data will remain within closed environment.
+// This option is useless on Little_Endian CPU (such as x86)
+//#define BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE 1
+
+
+//**************************************
+// Compiler Options
+//**************************************
+#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) // C99
+/* "restrict" is a known keyword */
+#else
+# define restrict // Disable restrict
+#endif
+
+#ifdef _MSC_VER // Visual Studio
+# define FORCE_INLINE static __forceinline
+# include <intrin.h> // For Visual 2005
+# if LZ4_ARCH64 // 64-bits
+# pragma intrinsic(_BitScanForward64) // For Visual 2005
+# pragma intrinsic(_BitScanReverse64) // For Visual 2005
+# else // 32-bits
+# pragma intrinsic(_BitScanForward) // For Visual 2005
+# pragma intrinsic(_BitScanReverse) // For Visual 2005
+# endif
+# pragma warning(disable : 4127) // disable: C4127: conditional expression is constant
+#else
+# ifdef __GNUC__
+# define FORCE_INLINE static inline __attribute__((always_inline))
+# else
+# define FORCE_INLINE static inline
+# endif
+#endif
+
+#ifdef _MSC_VER
+# define lz4_bswap16(x) _byteswap_ushort(x)
+#else
+# define lz4_bswap16(x) ((unsigned short int) ((((x) >> 8) & 0xffu) | (((x) & 0xffu) << 8)))
+#endif
+
+#define GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
+
+#if (GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__)
+# define expect(expr,value) (__builtin_expect ((expr),(value)) )
+#else
+# define expect(expr,value) (expr)
+#endif
+
+#define likely(expr) expect((expr) != 0, 1)
+#define unlikely(expr) expect((expr) != 0, 0)
+
+
+//**************************************
+// Memory routines
+//**************************************
+#include <stdlib.h> // malloc, calloc, free
+#define ALLOCATOR(n,s) calloc(n,s)
+#define FREEMEM free
+#include <string.h> // memset, memcpy
+#define MEM_INIT memset
+
+
+//**************************************
+// Includes
+//**************************************
+#include "compat-lz4.h"
+
+
+//**************************************
+// Basic Types
+//**************************************
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L // C99
+# include <stdint.h>
+ typedef uint8_t BYTE;
+ typedef uint16_t U16;
+ typedef uint32_t U32;
+ typedef int32_t S32;
+ typedef uint64_t U64;
+#else
+ typedef unsigned char BYTE;
+ typedef unsigned short U16;
+ typedef unsigned int U32;
+ typedef signed int S32;
+ typedef unsigned long long U64;
+#endif
+
+#if defined(__GNUC__) && !defined(LZ4_FORCE_UNALIGNED_ACCESS)
+# define _PACKED __attribute__ ((packed))
+#else
+# define _PACKED
+#endif
+
+#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__)
+# if defined(__IBMC__) || defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+# pragma pack(1)
+# else
+# pragma pack(push, 1)
+# endif
+#endif
+
+typedef struct { U16 v; } _PACKED U16_S;
+typedef struct { U32 v; } _PACKED U32_S;
+typedef struct { U64 v; } _PACKED U64_S;
+typedef struct {size_t v;} _PACKED size_t_S;
+
+#if !defined(LZ4_FORCE_UNALIGNED_ACCESS) && !defined(__GNUC__)
+# if defined(__SUNPRO_C) || defined(__SUNPRO_CC)
+# pragma pack(0)
+# else
+# pragma pack(pop)
+# endif
+#endif
+
+#define A16(x) (((U16_S *)(x))->v)
+#define A32(x) (((U32_S *)(x))->v)
+#define A64(x) (((U64_S *)(x))->v)
+#define AARCH(x) (((size_t_S *)(x))->v)
+
+
+//**************************************
+// Constants
+//**************************************
+#define LZ4_HASHLOG (MEMORY_USAGE-2)
+#define HASHTABLESIZE (1 << MEMORY_USAGE)
+#define HASHNBCELLS4 (1 << LZ4_HASHLOG)
+
+#define MINMATCH 4
+
+#define COPYLENGTH 8
+#define LASTLITERALS 5
+#define MFLIMIT (COPYLENGTH+MINMATCH)
+const int LZ4_minLength = (MFLIMIT+1);
+
+#define LZ4_64KLIMIT ((1<<16) + (MFLIMIT-1))
+#define SKIPSTRENGTH 6 // Increasing this value will make the compression run slower on incompressible data
+
+#define MAXD_LOG 16
+#define MAX_DISTANCE ((1 << MAXD_LOG) - 1)
+
+#define ML_BITS 4
+#define ML_MASK ((1U<<ML_BITS)-1)
+#define RUN_BITS (8-ML_BITS)
+#define RUN_MASK ((1U<<RUN_BITS)-1)
+
+#define KB *(1U<<10)
+#define MB *(1U<<20)
+#define GB *(1U<<30)
+
+
+//**************************************
+// Structures and local types
+//**************************************
+
+typedef struct {
+ U32 hashTable[HASHNBCELLS4];
+ const BYTE* bufferStart;
+ const BYTE* base;
+ const BYTE* nextBlock;
+} LZ4_Data_Structure;
+
+typedef enum { notLimited = 0, limited = 1 } limitedOutput_directive;
+typedef enum { byPtr, byU32, byU16 } tableType_t;
+
+typedef enum { noPrefix = 0, withPrefix = 1 } prefix64k_directive;
+
+typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive;
+typedef enum { full = 0, partial = 1 } earlyEnd_directive;
+
+
+//**************************************
+// Architecture-specific macros
+//**************************************
+#define STEPSIZE sizeof(size_t)
+#define LZ4_COPYSTEP(d,s) { AARCH(d) = AARCH(s); d+=STEPSIZE; s+=STEPSIZE; }
+#define LZ4_COPY8(d,s) { LZ4_COPYSTEP(d,s); if (STEPSIZE<8) LZ4_COPYSTEP(d,s); }
+#define LZ4_SECURECOPY(d,s,e) { if ((STEPSIZE==4)||(d<e)) LZ4_WILDCOPY(d,s,e); }
+
+#if LZ4_ARCH64 // 64-bit
+# define HTYPE U32
+# define INITBASE(base) const BYTE* const base = ip
+#else // 32-bit
+# define HTYPE const BYTE*
+# define INITBASE(base) const int base = 0
+#endif
+
+#if (defined(LZ4_BIG_ENDIAN) && !defined(BIG_ENDIAN_NATIVE_BUT_INCOMPATIBLE))
+# define LZ4_READ_LITTLEENDIAN_16(d,s,p) { U16 v = A16(p); v = lz4_bswap16(v); d = (s) - v; }
+# define LZ4_WRITE_LITTLEENDIAN_16(p,i) { U16 v = (U16)(i); v = lz4_bswap16(v); A16(p) = v; p+=2; }
+#else // Little Endian
+# define LZ4_READ_LITTLEENDIAN_16(d,s,p) { d = (s) - A16(p); }
+# define LZ4_WRITE_LITTLEENDIAN_16(p,v) { A16(p) = v; p+=2; }
+#endif
+
+
+//**************************************
+// Macros
+//**************************************
+#define LZ4_WILDCOPY(d,s,e) { do { LZ4_COPY8(d,s) } while (d<e); } // at the end, d>=e;
+
+
+//****************************
+// Private functions
+//****************************
+#if LZ4_ARCH64
+
+FORCE_INLINE int LZ4_NbCommonBytes (register U64 val)
+{
+# if defined(LZ4_BIG_ENDIAN)
+# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r = 0;
+ _BitScanReverse64( &r, val );
+ return (int)(r>>3);
+# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_clzll(val) >> 3);
+# else
+ int r;
+ if (!(val>>32)) { r=4; } else { r=0; val>>=32; }
+ if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
+ r += (!val);
+ return r;
+# endif
+# else
+# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r = 0;
+ _BitScanForward64( &r, val );
+ return (int)(r>>3);
+# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_ctzll(val) >> 3);
+# else
+ static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
+ return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
+# endif
+# endif
+}
+
+#else
+
+FORCE_INLINE int LZ4_NbCommonBytes (register U32 val)
+{
+# if defined(LZ4_BIG_ENDIAN)
+# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r = 0;
+ _BitScanReverse( &r, val );
+ return (int)(r>>3);
+# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_clz(val) >> 3);
+# else
+ int r;
+ if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
+ r += (!val);
+ return r;
+# endif
+# else
+# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ unsigned long r;
+ _BitScanForward( &r, val );
+ return (int)(r>>3);
+# elif defined(__GNUC__) && (GCC_VERSION >= 304) && !defined(LZ4_FORCE_SW_BITCOUNT)
+ return (__builtin_ctz(val) >> 3);
+# else
+ static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
+ return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
+# endif
+# endif
+}
+
+#endif
+
+
+//****************************
+// Compression functions
+//****************************
+FORCE_INLINE int LZ4_hashSequence(U32 sequence, tableType_t tableType)
+{
+ if (tableType == byU16)
+ return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));
+ else
+ return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));
+}
+
+FORCE_INLINE int LZ4_hashPosition(const BYTE* p, tableType_t tableType) { return LZ4_hashSequence(A32(p), tableType); }
+
+FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ switch (tableType)
+ {
+ case byPtr: { const BYTE** hashTable = (const BYTE**) tableBase; hashTable[h] = p; break; }
+ case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); break; }
+ case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); break; }
+ }
+}
+
+FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ U32 h = LZ4_hashPosition(p, tableType);
+ LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase);
+}
+
+FORCE_INLINE const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; }
+ if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; }
+ { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } // default, to ensure a return
+}
+
+FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase)
+{
+ U32 h = LZ4_hashPosition(p, tableType);
+ return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase);
+}
+
+
+FORCE_INLINE int LZ4_compress_generic(
+ void* ctx,
+ const char* source,
+ char* dest,
+ int inputSize,
+ int maxOutputSize,
+
+ limitedOutput_directive limitedOutput,
+ tableType_t tableType,
+ prefix64k_directive prefix)
+{
+ const BYTE* ip = (const BYTE*) source;
+ const BYTE* const base = (prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->base : (const BYTE*) source;
+ const BYTE* const lowLimit = ((prefix==withPrefix) ? ((LZ4_Data_Structure*)ctx)->bufferStart : (const BYTE*)source);
+ const BYTE* anchor = (const BYTE*) source;
+ const BYTE* const iend = ip + inputSize;
+ const BYTE* const mflimit = iend - MFLIMIT;
+ const BYTE* const matchlimit = iend - LASTLITERALS;
+
+ BYTE* op = (BYTE*) dest;
+ BYTE* const oend = op + maxOutputSize;
+
+ int length;
+ const int skipStrength = SKIPSTRENGTH;
+ U32 forwardH;
+
+ // Init conditions
+ if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; // Unsupported input size, too large (or negative)
+ if ((prefix==withPrefix) && (ip != ((LZ4_Data_Structure*)ctx)->nextBlock)) return 0; // must continue from end of previous block
+ if (prefix==withPrefix) ((LZ4_Data_Structure*)ctx)->nextBlock=iend; // do it now, due to potential early exit
+ if ((tableType == byU16) && (inputSize>=LZ4_64KLIMIT)) return 0; // Size too large (not within 64K limit)
+ if (inputSize<LZ4_minLength) goto _last_literals; // Input too small, no compression (all literals)
+
+ // First Byte
+ LZ4_putPosition(ip, ctx, tableType, base);
+ ip++; forwardH = LZ4_hashPosition(ip, tableType);
+
+ // Main Loop
+ for ( ; ; )
+ {
+ int findMatchAttempts = (1U << skipStrength) + 3;
+ const BYTE* forwardIp = ip;
+ const BYTE* ref;
+ BYTE* token;
+
+ // Find a match
+ do {
+ U32 h = forwardH;
+ int step = findMatchAttempts++ >> skipStrength;
+ ip = forwardIp;
+ forwardIp = ip + step;
+
+ if unlikely(forwardIp > mflimit) { goto _last_literals; }
+
+ forwardH = LZ4_hashPosition(forwardIp, tableType);
+ ref = LZ4_getPositionOnHash(h, ctx, tableType, base);
+ LZ4_putPositionOnHash(ip, h, ctx, tableType, base);
+
+ } while ((ref + MAX_DISTANCE < ip) || (A32(ref) != A32(ip)));
+
+ // Catch up
+ while ((ip>anchor) && (ref > lowLimit) && unlikely(ip[-1]==ref[-1])) { ip--; ref--; }
+
+ // Encode Literal length
+ length = (int)(ip - anchor);
+ token = op++;
+ if ((limitedOutput) && unlikely(op + length + (2 + 1 + LASTLITERALS) + (length/255) > oend)) return 0; // Check output limit
+ if (length>=(int)RUN_MASK)
+ {
+ int len = length-RUN_MASK;
+ *token=(RUN_MASK<<ML_BITS);
+ for(; len >= 255 ; len-=255) *op++ = 255;
+ *op++ = (BYTE)len;
+ }
+ else *token = (BYTE)(length<<ML_BITS);
+
+ // Copy Literals
+ { BYTE* end=(op)+(length); LZ4_WILDCOPY(op,anchor,end); op=end; }
+
+_next_match:
+ // Encode Offset
+ LZ4_WRITE_LITTLEENDIAN_16(op,(U16)(ip-ref));
+
+ // Start Counting
+ ip+=MINMATCH; ref+=MINMATCH; // MinMatch already verified
+ anchor = ip;
+ while likely(ip<matchlimit-(STEPSIZE-1))
+ {
+ size_t diff = AARCH(ref) ^ AARCH(ip);
+ if (!diff) { ip+=STEPSIZE; ref+=STEPSIZE; continue; }
+ ip += LZ4_NbCommonBytes(diff);
+ goto _endCount;
+ }
+ if (LZ4_ARCH64) if ((ip<(matchlimit-3)) && (A32(ref) == A32(ip))) { ip+=4; ref+=4; }
+ if ((ip<(matchlimit-1)) && (A16(ref) == A16(ip))) { ip+=2; ref+=2; }
+ if ((ip<matchlimit) && (*ref == *ip)) ip++;
+_endCount:
+
+ // Encode MatchLength
+ length = (int)(ip - anchor);
+ if ((limitedOutput) && unlikely(op + (1 + LASTLITERALS) + (length>>8) > oend)) return 0; // Check output limit
+ if (length>=(int)ML_MASK)
+ {
+ *token += ML_MASK;
+ length -= ML_MASK;
+ for (; length > 509 ; length-=510) { *op++ = 255; *op++ = 255; }
+ if (length >= 255) { length-=255; *op++ = 255; }
+ *op++ = (BYTE)length;
+ }
+ else *token += (BYTE)(length);
+
+ // Test end of chunk
+ if (ip > mflimit) { anchor = ip; break; }
+
+ // Fill table
+ LZ4_putPosition(ip-2, ctx, tableType, base);
+
+ // Test next position
+ ref = LZ4_getPosition(ip, ctx, tableType, base);
+ LZ4_putPosition(ip, ctx, tableType, base);
+ if ((ref + MAX_DISTANCE >= ip) && (A32(ref) == A32(ip))) { token = op++; *token=0; goto _next_match; }
+
+ // Prepare next loop
+ anchor = ip++;
+ forwardH = LZ4_hashPosition(ip, tableType);
+ }
+
+_last_literals:
+ // Encode Last Literals
+ {
+ int lastRun = (int)(iend - anchor);
+ if ((limitedOutput) && (((char*)op - dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) return 0; // Check output limit
+ if (lastRun>=(int)RUN_MASK) { *op++=(RUN_MASK<<ML_BITS); lastRun-=RUN_MASK; for(; lastRun >= 255 ; lastRun-=255) *op++ = 255; *op++ = (BYTE) lastRun; }
+ else *op++ = (BYTE)(lastRun<<ML_BITS);
+ memcpy(op, anchor, iend - anchor);
+ op += iend-anchor;
+ }
+
+ // End
+ return (int) (((char*)op)-dest);
+}
+
+
+int LZ4_compress(const char* source, char* dest, int inputSize)
+{
+#if (HEAPMODE)
+ void* ctx = ALLOCATOR(HASHNBCELLS4, 4); // Aligned on 4-bytes boundaries
+#else
+ U32 ctx[1U<<(MEMORY_USAGE-2)] = {0}; // Ensure data is aligned on 4-bytes boundaries
+#endif
+ int result;
+
+ if (inputSize < (int)LZ4_64KLIMIT)
+ result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, 0, notLimited, byU16, noPrefix);
+ else
+ result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noPrefix);
+
+#if (HEAPMODE)
+ FREEMEM(ctx);
+#endif
+ return result;
+}
+
+int LZ4_compress_continue (void* LZ4_Data, const char* source, char* dest, int inputSize)
+{
+ return LZ4_compress_generic(LZ4_Data, source, dest, inputSize, 0, notLimited, byU32, withPrefix);
+}
+
+
+int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+#if (HEAPMODE)
+ void* ctx = ALLOCATOR(HASHNBCELLS4, 4); // Aligned on 4-bytes boundaries
+#else
+ U32 ctx[1U<<(MEMORY_USAGE-2)] = {0}; // Ensure data is aligned on 4-bytes boundaries
+#endif
+ int result;
+
+ if (inputSize < (int)LZ4_64KLIMIT)
+ result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, maxOutputSize, limited, byU16, noPrefix);
+ else
+ result = LZ4_compress_generic((void*)ctx, source, dest, inputSize, maxOutputSize, limited, (sizeof(void*)==8) ? byU32 : byPtr, noPrefix);
+
+#if (HEAPMODE)
+ FREEMEM(ctx);
+#endif
+ return result;
+}
+
+int LZ4_compress_limitedOutput_continue (void* LZ4_Data, const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+ return LZ4_compress_generic(LZ4_Data, source, dest, inputSize, maxOutputSize, limited, byU32, withPrefix);
+}
+
+
+//****************************
+// Stream functions
+//****************************
+
+FORCE_INLINE void LZ4_init(LZ4_Data_Structure* lz4ds, const BYTE* base)
+{
+ MEM_INIT(lz4ds->hashTable, 0, sizeof(lz4ds->hashTable));
+ lz4ds->bufferStart = base;
+ lz4ds->base = base;
+ lz4ds->nextBlock = base;
+}
+
+
+void* LZ4_create (const char* inputBuffer)
+{
+ void* lz4ds = ALLOCATOR(1, sizeof(LZ4_Data_Structure));
+ LZ4_init ((LZ4_Data_Structure*)lz4ds, (const BYTE*)inputBuffer);
+ return lz4ds;
+}
+
+
+int LZ4_free (void* LZ4_Data)
+{
+ FREEMEM(LZ4_Data);
+ return (0);
+}
+
+
+char* LZ4_slideInputBuffer (void* LZ4_Data)
+{
+ LZ4_Data_Structure* lz4ds = (LZ4_Data_Structure*)LZ4_Data;
+ size_t delta = lz4ds->nextBlock - (lz4ds->bufferStart + 64 KB);
+
+ if ( (lz4ds->base - delta > lz4ds->base) // underflow control
+ || ((size_t)(lz4ds->nextBlock - lz4ds->base) > 0xE0000000) ) // close to 32-bits limit
+ {
+ size_t deltaLimit = (lz4ds->nextBlock - 64 KB) - lz4ds->base;
+ int nH;
+
+ for (nH=0; nH < HASHNBCELLS4; nH++)
+ {
+ if ((size_t)(lz4ds->hashTable[nH]) < deltaLimit) lz4ds->hashTable[nH] = 0;
+ else lz4ds->hashTable[nH] -= (U32)deltaLimit;
+ }
+ memcpy((void*)(lz4ds->bufferStart), (const void*)(lz4ds->nextBlock - 64 KB), 64 KB);
+ lz4ds->base = lz4ds->bufferStart;
+ lz4ds->nextBlock = lz4ds->base + 64 KB;
+ }
+ else
+ {
+ memcpy((void*)(lz4ds->bufferStart), (const void*)(lz4ds->nextBlock - 64 KB), 64 KB);
+ lz4ds->nextBlock -= delta;
+ lz4ds->base -= delta;
+ }
+
+ return (char*)(lz4ds->nextBlock);
+}
+
+
+//****************************
+// Decompression functions
+//****************************
+
+// This generic decompression function cover all use cases.
+// It shall be instanciated several times, using different sets of directives
+// Note that it is essential this generic function is really inlined,
+// in order to remove useless branches during compilation optimisation.
+FORCE_INLINE int LZ4_decompress_generic(
+ const char* source,
+ char* dest,
+ int inputSize, //
+ int outputSize, // If endOnInput==endOnInputSize, this value is the max size of Output Buffer.
+
+ int endOnInput, // endOnOutputSize, endOnInputSize
+ int prefix64k, // noPrefix, withPrefix
+ int partialDecoding, // full, partial
+ int targetOutputSize // only used if partialDecoding==partial
+ )
+{
+ // Local Variables
+ const BYTE* restrict ip = (const BYTE*) source;
+ const BYTE* ref;
+ const BYTE* const iend = ip + inputSize;
+
+ BYTE* op = (BYTE*) dest;
+ BYTE* const oend = op + outputSize;
+ BYTE* cpy;
+ BYTE* oexit = op + targetOutputSize;
+
+ const size_t dec32table[] = {0, 3, 2, 3, 0, 0, 0, 0}; // static reduces speed for LZ4_decompress_safe() on GCC64
+ static const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3};
+
+
+ // Special cases
+ if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; // targetOutputSize too high => decode everything
+ if ((endOnInput) && unlikely(outputSize==0)) return ((inputSize==1) && (*ip==0)) ? 0 : -1; // Empty output buffer
+ if ((!endOnInput) && unlikely(outputSize==0)) return (*ip==0?1:-1);
+
+
+ // Main Loop
+ while (1)
+ {
+ unsigned token;
+ size_t length;
+
+ // get runlength
+ token = *ip++;
+ if ((length=(token>>ML_BITS)) == RUN_MASK)
+ {
+ unsigned s=255;
+ while (((endOnInput)?ip<iend:1) && (s==255))
+ {
+ s = *ip++;
+ length += s;
+ }
+ }
+
+ // copy literals
+ cpy = op+length;
+ if (((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
+ || ((!endOnInput) && (cpy>oend-COPYLENGTH)))
+ {
+ if (partialDecoding)
+ {
+ if (cpy > oend) goto _output_error; // Error : write attempt beyond end of output buffer
+ if ((endOnInput) && (ip+length > iend)) goto _output_error; // Error : read attempt beyond end of input buffer
+ }
+ else
+ {
+ if ((!endOnInput) && (cpy != oend)) goto _output_error; // Error : block decoding must stop exactly there
+ if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; // Error : input must be consumed
+ }
+ memcpy(op, ip, length);
+ ip += length;
+ op += length;
+ break; // Necessarily EOF, due to parsing restrictions
+ }
+ LZ4_WILDCOPY(op, ip, cpy); ip -= (op-cpy); op = cpy;
+
+ // get offset
+ LZ4_READ_LITTLEENDIAN_16(ref,cpy,ip); ip+=2;
+ if ((prefix64k==noPrefix) && unlikely(ref < (BYTE* const)dest)) goto _output_error; // Error : offset outside destination buffer
+
+ // get matchlength
+ if ((length=(token&ML_MASK)) == ML_MASK)
+ {
+ while ((!endOnInput) || (ip<iend-(LASTLITERALS+1))) // Ensure enough bytes remain for LASTLITERALS + token
+ {
+ unsigned s = *ip++;
+ length += s;
+ if (s==255) continue;
+ break;
+ }
+ }
+
+ // copy repeated sequence
+ if unlikely((op-ref)<(int)STEPSIZE)
+ {
+ const size_t dec64 = dec64table[(sizeof(void*)==4) ? 0 : op-ref];
+ op[0] = ref[0];
+ op[1] = ref[1];
+ op[2] = ref[2];
+ op[3] = ref[3];
+ op += 4, ref += 4; ref -= dec32table[op-ref];
+ A32(op) = A32(ref);
+ op += STEPSIZE-4; ref -= dec64;
+ } else { LZ4_COPYSTEP(op,ref); }
+ cpy = op + length - (STEPSIZE-4);
+
+ if unlikely(cpy>oend-COPYLENGTH-(STEPSIZE-4))
+ {
+ if (cpy > oend-LASTLITERALS) goto _output_error; // Error : last 5 bytes must be literals
+ LZ4_SECURECOPY(op, ref, (oend-COPYLENGTH));
+ while(op<cpy) *op++=*ref++;
+ op=cpy;
+ continue;
+ }
+ LZ4_WILDCOPY(op, ref, cpy);
+ op=cpy; // correction
+ }
+
+ // end of decoding
+ if (endOnInput)
+ return (int) (((char*)op)-dest); // Nb of output bytes decoded
+ else
+ return (int) (((char*)ip)-source); // Nb of input bytes read
+
+ // Overflow error detected
+_output_error:
+ return (int) (-(((char*)ip)-source))-1;
+}
+
+
+int LZ4_decompress_safe(const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+ return LZ4_decompress_generic(source, dest, inputSize, maxOutputSize, endOnInputSize, noPrefix, full, 0);
+}
+
+int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int inputSize, int maxOutputSize)
+{
+ return LZ4_decompress_generic(source, dest, inputSize, maxOutputSize, endOnInputSize, withPrefix, full, 0);
+}
+
+int LZ4_decompress_safe_partial(const char* source, char* dest, int inputSize, int targetOutputSize, int maxOutputSize)
+{
+ return LZ4_decompress_generic(source, dest, inputSize, maxOutputSize, endOnInputSize, noPrefix, partial, targetOutputSize);
+}
+
+int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int outputSize)
+{
+ return LZ4_decompress_generic(source, dest, 0, outputSize, endOnOutputSize, withPrefix, full, 0);
+}
+
+int LZ4_decompress_fast(const char* source, char* dest, int outputSize)
+{
+#ifdef _MSC_VER // This version is faster with Visual
+ return LZ4_decompress_generic(source, dest, 0, outputSize, endOnOutputSize, noPrefix, full, 0);
+#else
+ return LZ4_decompress_generic(source, dest, 0, outputSize, endOnOutputSize, withPrefix, full, 0);
+#endif
+}
+#endif
diff --git a/app/openvpn/src/compat/compat-lz4.h b/app/openvpn/src/compat/compat-lz4.h
new file mode 100644
index 00000000..a289fcfd
--- /dev/null
+++ b/app/openvpn/src/compat/compat-lz4.h
@@ -0,0 +1,205 @@
+/*
+ LZ4 - Fast LZ compression algorithm
+ Header File
+ Copyright (C) 2011-2013, Yann Collet.
+ BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+ copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the
+ distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+ You can contact the author at :
+ - LZ4 homepage : http://fastcompression.blogspot.com/p/lz4.html
+ - LZ4 source repository : http://code.google.com/p/lz4/
+*/
+#pragma once
+
+#if defined (__cplusplus)
+extern "C" {
+#endif
+
+
+//**************************************
+// Compiler Options
+//**************************************
+#if defined(_MSC_VER) && !defined(__cplusplus) // Visual Studio
+# define inline __inline // Visual C is not C99, but supports some kind of inline
+#endif
+
+
+//****************************
+// Simple Functions
+//****************************
+
+int LZ4_compress (const char* source, char* dest, int inputSize);
+int LZ4_decompress_safe (const char* source, char* dest, int inputSize, int maxOutputSize);
+
+/*
+LZ4_compress() :
+ Compresses 'inputSize' bytes from 'source' into 'dest'.
+ Destination buffer must be already allocated,
+ and must be sized to handle worst cases situations (input data not compressible)
+ Worst case size evaluation is provided by function LZ4_compressBound()
+ inputSize : Max supported value is LZ4_MAX_INPUT_VALUE
+ return : the number of bytes written in buffer dest
+ or 0 if the compression fails
+
+LZ4_decompress_safe() :
+ maxOutputSize : is the size of the destination buffer (which must be already allocated)
+ return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize)
+ If the source stream is detected malformed, the function will stop decoding and return a negative result.
+ This function is protected against buffer overflow exploits (never writes outside of output buffer, and never reads outside of input buffer). Therefore, it is protected against malicious data packets
+*/
+
+
+//****************************
+// Advanced Functions
+//****************************
+#define LZ4_MAX_INPUT_SIZE 0x7E000000 // 2 113 929 216 bytes
+#define LZ4_COMPRESSBOUND(isize) ((unsigned int)(isize) > (unsigned int)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
+static inline int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); }
+
+/*
+LZ4_compressBound() :
+ Provides the maximum size that LZ4 may output in a "worst case" scenario (input data not compressible)
+ primarily useful for memory allocation of output buffer.
+ inline function is recommended for the general case,
+ macro is also provided when result needs to be evaluated at compilation (such as stack memory allocation).
+
+ isize : is the input size. Max supported value is LZ4_MAX_INPUT_SIZE
+ return : maximum output size in a "worst case" scenario
+ or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE)
+*/
+
+
+int LZ4_compress_limitedOutput (const char* source, char* dest, int inputSize, int maxOutputSize);
+
+/*
+LZ4_compress_limitedOutput() :
+ Compress 'inputSize' bytes from 'source' into an output buffer 'dest' of maximum size 'maxOutputSize'.
+ If it cannot achieve it, compression will stop, and result of the function will be zero.
+ This function never writes outside of provided output buffer.
+
+ inputSize : Max supported value is LZ4_MAX_INPUT_VALUE
+ maxOutputSize : is the size of the destination buffer (which must be already allocated)
+ return : the number of bytes written in buffer 'dest'
+ or 0 if the compression fails
+*/
+
+
+int LZ4_decompress_fast (const char* source, char* dest, int outputSize);
+
+/*
+LZ4_decompress_fast() :
+ outputSize : is the original (uncompressed) size
+ return : the number of bytes read from the source buffer (in other words, the compressed size)
+ If the source stream is malformed, the function will stop decoding and return a negative result.
+ note : This function is a bit faster than LZ4_decompress_safe()
+ This function never writes outside of output buffers, but may read beyond input buffer in case of malicious data packet.
+ Use this function preferably into a trusted environment (data to decode comes from a trusted source).
+ Destination buffer must be already allocated. Its size must be a minimum of 'outputSize' bytes.
+*/
+
+int LZ4_decompress_safe_partial (const char* source, char* dest, int inputSize, int targetOutputSize, int maxOutputSize);
+
+/*
+LZ4_decompress_safe_partial() :
+ This function decompress a compressed block of size 'inputSize' at position 'source'
+ into output buffer 'dest' of size 'maxOutputSize'.
+ The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached,
+ reducing decompression time.
+ return : the number of bytes decoded in the destination buffer (necessarily <= maxOutputSize)
+ Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller.
+ Always control how many bytes were decoded.
+ If the source stream is detected malformed, the function will stop decoding and return a negative result.
+ This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets
+*/
+
+
+//****************************
+// Stream Functions
+//****************************
+
+void* LZ4_create (const char* inputBuffer);
+int LZ4_compress_continue (void* LZ4_Data, const char* source, char* dest, int inputSize);
+int LZ4_compress_limitedOutput_continue (void* LZ4_Data, const char* source, char* dest, int inputSize, int maxOutputSize);
+char* LZ4_slideInputBuffer (void* LZ4_Data);
+int LZ4_free (void* LZ4_Data);
+
+/*
+These functions allow the compression of dependent blocks, where each block benefits from prior 64 KB within preceding blocks.
+In order to achieve this, it is necessary to start creating the LZ4 Data Structure, thanks to the function :
+
+void* LZ4_create (const char* inputBuffer);
+The result of the function is the (void*) pointer on the LZ4 Data Structure.
+This pointer will be needed in all other functions.
+If the pointer returned is NULL, then the allocation has failed, and compression must be aborted.
+The only parameter 'const char* inputBuffer' must, obviously, point at the beginning of input buffer.
+The input buffer must be already allocated, and size at least 192KB.
+'inputBuffer' will also be the 'const char* source' of the first block.
+
+All blocks are expected to lay next to each other within the input buffer, starting from 'inputBuffer'.
+To compress each block, use either LZ4_compress_continue() or LZ4_compress_limitedOutput_continue().
+Their behavior are identical to LZ4_compress() or LZ4_compress_limitedOutput(),
+but require the LZ4 Data Structure as their first argument, and check that each block starts right after the previous one.
+If next block does not begin immediately after the previous one, the compression will fail (return 0).
+
+When it's no longer possible to lay the next block after the previous one (not enough space left into input buffer), a call to :
+char* LZ4_slideInputBuffer(void* LZ4_Data);
+must be performed. It will typically copy the latest 64KB of input at the beginning of input buffer.
+Note that, for this function to work properly, minimum size of an input buffer must be 192KB.
+==> The memory position where the next input data block must start is provided as the result of the function.
+
+Compression can then resume, using LZ4_compress_continue() or LZ4_compress_limitedOutput_continue(), as usual.
+
+When compression is completed, a call to LZ4_free() will release the memory used by the LZ4 Data Structure.
+*/
+
+
+int LZ4_decompress_safe_withPrefix64k (const char* source, char* dest, int inputSize, int maxOutputSize);
+int LZ4_decompress_fast_withPrefix64k (const char* source, char* dest, int outputSize);
+
+/*
+*_withPrefix64k() :
+ These decoding functions work the same as their "normal name" versions,
+ but can use up to 64KB of data in front of 'char* dest'.
+ These functions are necessary to decode inter-dependant blocks.
+*/
+
+
+//****************************
+// Obsolete Functions
+//****************************
+
+static inline int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); }
+static inline int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); }
+
+/*
+These functions are deprecated and should no longer be used.
+They are provided here for compatibility with existing user programs.
+*/
+
+
+
+#if defined (__cplusplus)
+}
+#endif
diff --git a/app/openvpn/src/compat/compat-rsa_generate_key.c b/app/openvpn/src/compat/compat-rsa_generate_key.c
deleted file mode 100644
index 99725da1..00000000
--- a/app/openvpn/src/compat/compat-rsa_generate_key.c
+++ /dev/null
@@ -1,47 +0,0 @@
-#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/app/openvpn/src/openvpn/Makefile.am b/app/openvpn/src/openvpn/Makefile.am
index 5d38628d..fd593c57 100644
--- a/app/openvpn/src/openvpn/Makefile.am
+++ b/app/openvpn/src/openvpn/Makefile.am
@@ -18,7 +18,7 @@ EXTRA_DIST = \
openvpn.vcxproj \
openvpn.vcxproj.filters
-INCLUDES = \
+AM_CPPFLAGS = \
-I$(top_srcdir)/include \
-I$(top_srcdir)/src/compat
@@ -26,6 +26,8 @@ AM_CFLAGS = \
$(TAP_CFLAGS) \
$(OPTIONAL_CRYPTO_CFLAGS) \
$(OPTIONAL_LZO_CFLAGS) \
+ $(OPTIONAL_SNAPPY_CFLAGS) \
+ $(OPTIONAL_LZ4_CFLAGS) \
$(OPTIONAL_PKCS11_HELPER_CFLAGS)
if WIN32
# we want unicode entry point but not the macro
@@ -41,6 +43,8 @@ openvpn_SOURCES = \
circ_list.h \
clinat.c clinat.h \
common.h \
+ comp.c comp.h compstub.c \
+ comp-lz4.c comp-lz4.h \
crypto.c crypto.h crypto_backend.h \
crypto_openssl.c crypto_openssl.h \
crypto_polarssl.c crypto_polarssl.h \
@@ -98,6 +102,7 @@ openvpn_SOURCES = \
session_id.c session_id.h \
shaper.c shaper.h \
sig.c sig.h \
+ snappy.c snappy.h \
socket.c socket.h \
socks.c socks.h \
ssl.c ssl.h ssl_backend.h \
@@ -116,6 +121,8 @@ openvpn_LDADD = \
$(top_builddir)/src/compat/libcompat.la \
$(SOCKETS_LIBS) \
$(OPTIONAL_LZO_LIBS) \
+ $(OPTIONAL_SNAPPY_LIBS) \
+ $(OPTIONAL_LZ4_LIBS) \
$(OPTIONAL_PKCS11_HELPER_LIBS) \
$(OPTIONAL_CRYPTO_LIBS) \
$(OPTIONAL_SELINUX_LIBS) \
diff --git a/app/openvpn/src/openvpn/base64.c b/app/openvpn/src/openvpn/base64.c
index bb89aae3..6dc8479f 100644
--- a/app/openvpn/src/openvpn/base64.c
+++ b/app/openvpn/src/openvpn/base64.c
@@ -39,8 +39,6 @@
#include "syshead.h"
-#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR) || defined(MANAGMENT_EXTERNAL_KEY)
-
#include "base64.h"
#include "memdbg.h"
@@ -163,7 +161,3 @@ openvpn_base64_decode(const char *str, void *data, int size)
}
return q - (unsigned char *) data;
}
-
-#else
-static void dummy(void) {}
-#endif /* ENABLE_HTTP_PROXY, ENABLE_PKCS11, ENABLE_CLIENT_CR */
diff --git a/app/openvpn/src/openvpn/base64.h b/app/openvpn/src/openvpn/base64.h
index 28a9677c..92a195aa 100644
--- a/app/openvpn/src/openvpn/base64.h
+++ b/app/openvpn/src/openvpn/base64.h
@@ -34,11 +34,7 @@
#ifndef _BASE64_H_
#define _BASE64_H_
-#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_PKCS11) || defined(ENABLE_CLIENT_CR) || defined(MANAGMENT_EXTERNAL_KEY)
-
int openvpn_base64_encode(const void *data, int size, char **str);
int openvpn_base64_decode(const char *str, void *data, int size);
#endif
-
-#endif
diff --git a/app/openvpn/src/openvpn/breakpad.cpp b/app/openvpn/src/openvpn/breakpad.cpp
index 77c469f3..cfcc10a8 100644
--- a/app/openvpn/src/openvpn/breakpad.cpp
+++ b/app/openvpn/src/openvpn/breakpad.cpp
@@ -19,7 +19,7 @@ static google_breakpad::ExceptionHandler* eh;
void breakpad_setup(void)
{
printf("Initializing Google Breakpad!\n");
- desc = new google_breakpad::MinidumpDescriptor("/data/data/se.leap.openvpn/cache");
+ desc = new google_breakpad::MinidumpDescriptor("/data/data/de.blinkt.openvpn/cache");
eh = new google_breakpad::ExceptionHandler(*desc, NULL, DumpCallback, NULL, true,-1);
}
diff --git a/app/openvpn/src/openvpn/buffer.c b/app/openvpn/src/openvpn/buffer.c
index 56d14b1a..46f874b2 100644
--- a/app/openvpn/src/openvpn/buffer.c
+++ b/app/openvpn/src/openvpn/buffer.c
@@ -327,19 +327,28 @@ gc_malloc (size_t size, bool clear, struct gc_arena *a)
#endif
{
void *ret;
- struct gc_entry *e;
- ASSERT (NULL != a);
-
+ if (a)
+ {
+ struct gc_entry *e;
#ifdef DMALLOC
- e = (struct gc_entry *) openvpn_dmalloc (file, line, size + sizeof (struct gc_entry));
+ e = (struct gc_entry *) openvpn_dmalloc (file, line, size + sizeof (struct gc_entry));
#else
- e = (struct gc_entry *) malloc (size + sizeof (struct gc_entry));
+ e = (struct gc_entry *) malloc (size + sizeof (struct gc_entry));
#endif
- check_malloc_return (e);
- ret = (char *) e + sizeof (struct gc_entry);
- e->next = a->list;
- a->list = e;
-
+ check_malloc_return (e);
+ ret = (char *) e + sizeof (struct gc_entry);
+ e->next = a->list;
+ a->list = e;
+ }
+ else
+ {
+#ifdef DMALLOC
+ ret = openvpn_dmalloc (file, line, size);
+#else
+ ret = malloc (size);
+#endif
+ check_malloc_return (ret);
+ }
#ifndef ZERO_BUFFER_ON_ALLOC
if (clear)
#endif
@@ -363,6 +372,44 @@ x_gc_free (struct gc_arena *a)
}
/*
+ * Functions to handle special objects in gc_entries
+ */
+
+void
+x_gc_freespecial (struct gc_arena *a)
+{
+ struct gc_entry_special *e;
+ e = a->list_special;
+ a->list_special = NULL;
+
+ while (e != NULL)
+ {
+ struct gc_entry_special *next = e->next;
+ e->free_fnc (e->addr);
+ free(e);
+ e = next;
+ }
+}
+
+void gc_addspecial (void *addr, void (free_function)(void*), struct gc_arena *a)
+{
+ ASSERT(a);
+ struct gc_entry_special *e;
+#ifdef DMALLOC
+ e = (struct gc_entry_special *) openvpn_dmalloc (file, line, sizeof (struct gc_entry_special));
+#else
+ e = (struct gc_entry_special *) malloc (sizeof (struct gc_entry_special));
+#endif
+ check_malloc_return (e);
+ e->free_fnc = free_function;
+ e->addr = addr;
+
+ e->next = a->list_special;
+ a->list_special = e;
+}
+
+
+/*
* Transfer src arena to dest, resetting src to an empty arena.
*/
void
@@ -929,9 +976,6 @@ valign4 (const struct buffer *buf, const char *file, const int line)
/*
* struct buffer_list
*/
-
-#ifdef ENABLE_BUFFER_LIST
-
struct buffer_list *
buffer_list_new (const int max_size)
{
@@ -1107,5 +1151,3 @@ buffer_list_file (const char *fn, int max_line_len)
}
return bl;
}
-
-#endif
diff --git a/app/openvpn/src/openvpn/buffer.h b/app/openvpn/src/openvpn/buffer.h
index 5e11de05..7469da63 100644
--- a/app/openvpn/src/openvpn/buffer.h
+++ b/app/openvpn/src/openvpn/buffer.h
@@ -91,6 +91,18 @@ struct gc_entry
* linked list. */
};
+/**
+ * Gargabe collection entry for a specially allocated structure that needs
+ * a custom free function to be freed like struct addrinfo
+ *
+ */
+struct gc_entry_special
+{
+ struct gc_entry_special *next;
+ void (*free_fnc)(void*);
+ void *addr;
+};
+
/**
* Garbage collection arena used to keep track of dynamically allocated
@@ -106,6 +118,7 @@ struct gc_arena
{
struct gc_entry *list; /**< First element of the linked list of
* \c gc_entry structures. */
+ struct gc_entry_special *list_special;
};
@@ -163,6 +176,9 @@ struct buffer string_alloc_buf (const char *str, struct gc_arena *gc);
#endif
+void gc_addspecial (void *addr, void (*free_function)(void*), struct gc_arena *a);
+
+
#ifdef BUF_INIT_TRACKING
#define buf_init(buf, offset) buf_init_debug (buf, offset, __FILE__, __LINE__)
bool buf_init_debug (struct buffer *buf, int offset, const char *file, int line);
@@ -172,6 +188,11 @@ bool buf_init_debug (struct buffer *buf, int offset, const char *file, int line)
/* inline functions */
+inline static void
+gc_freeaddrinfo_callback (void *addr)
+{
+ freeaddrinfo((struct addrinfo*) addr);
+}
static inline bool
buf_defined (const struct buffer *buf)
@@ -668,6 +689,10 @@ buf_read_u32 (struct buffer *buf, bool *good)
}
}
+/**
+ * Compare src buffer contents with match.
+ * *NOT* constant time. Do not use when comparing HMACs.
+ */
static inline bool
buf_string_match (const struct buffer *src, const void *match, int size)
{
@@ -676,6 +701,10 @@ buf_string_match (const struct buffer *src, const void *match, int size)
return memcmp (BPTR (src), match, size) == 0;
}
+/**
+ * Compare first size bytes of src buffer contents with match.
+ * *NOT* constant time. Do not use when comparing HMACs.
+ */
static inline bool
buf_string_match_head (const struct buffer *src, const void *match, int size)
{
@@ -689,16 +718,6 @@ bool buf_string_compare_advance (struct buffer *src, const char *match);
int buf_substring_len (const struct buffer *buf, int delim);
/*
- * Bitwise operations
- */
-static inline void
-xor (uint8_t *dest, const uint8_t *src, int len)
-{
- while (len-- > 0)
- *dest++ ^= *src++;
-}
-
-/*
* Print a string which might be NULL
*/
const char *np (const char *str);
@@ -780,6 +799,7 @@ void character_class_debug (void);
void gc_transfer (struct gc_arena *dest, struct gc_arena *src);
void x_gc_free (struct gc_arena *a);
+void x_gc_freespecial (struct gc_arena *a);
static inline bool
gc_defined (struct gc_arena *a)
@@ -791,6 +811,7 @@ static inline void
gc_init (struct gc_arena *a)
{
a->list = NULL;
+ a->list_special = NULL;
}
static inline void
@@ -803,7 +824,7 @@ static inline struct gc_arena
gc_new (void)
{
struct gc_arena ret;
- ret.list = NULL;
+ gc_init (&ret);
return ret;
}
@@ -812,6 +833,8 @@ gc_free (struct gc_arena *a)
{
if (a->list)
x_gc_free (a);
+ if (a->list_special)
+ x_gc_freespecial(a);
}
static inline void
@@ -881,9 +904,6 @@ check_malloc_return (void *p)
/*
* Manage lists of buffers
*/
-
-#ifdef ENABLE_BUFFER_LIST
-
struct buffer_entry
{
struct buffer buf;
@@ -913,7 +933,4 @@ void buffer_list_pop (struct buffer_list *ol);
void buffer_list_aggregate (struct buffer_list *bl, const size_t max);
struct buffer_list *buffer_list_file (const char *fn, int max_line_len);
-
-#endif
-
#endif /* BUFFER_H */
diff --git a/app/openvpn/src/openvpn/clinat.c b/app/openvpn/src/openvpn/clinat.c
index af75fc9d..ddefe123 100644
--- a/app/openvpn/src/openvpn/clinat.c
+++ b/app/openvpn/src/openvpn/clinat.c
@@ -30,8 +30,6 @@
#include "syshead.h"
-#if defined(ENABLE_CLIENT_NAT)
-
#include "clinat.h"
#include "proto.h"
#include "socket.h"
@@ -265,5 +263,3 @@ client_nat_transform (const struct client_nat_option_list *list,
}
}
}
-
-#endif
diff --git a/app/openvpn/src/openvpn/clinat.h b/app/openvpn/src/openvpn/clinat.h
index d55a727a..a5779e15 100644
--- a/app/openvpn/src/openvpn/clinat.h
+++ b/app/openvpn/src/openvpn/clinat.h
@@ -22,7 +22,7 @@
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#if !defined(CLINAT_H) && defined(ENABLE_CLIENT_NAT)
+#if !defined(CLINAT_H)
#define CLINAT_H
#include "buffer.h"
diff --git a/app/openvpn/src/openvpn/common.h b/app/openvpn/src/openvpn/common.h
index dd2c83f4..2f85bec2 100644
--- a/app/openvpn/src/openvpn/common.h
+++ b/app/openvpn/src/openvpn/common.h
@@ -100,6 +100,6 @@ typedef unsigned long ptr_type;
/*
* Script security warning
*/
-#define SCRIPT_SECURITY_WARNING "WARNING: External program may not be called unless '--script-security 2' or higher is enabled. Use '--script-security 3 system' for backward compatibility with 2.1_rc8 and earlier. See --help text or man page for detailed info."
+#define SCRIPT_SECURITY_WARNING "WARNING: External program may not be called unless '--script-security 2' or higher is enabled. See --help text or man page for detailed info."
#endif
diff --git a/app/openvpn/src/openvpn/comp-lz4.c b/app/openvpn/src/openvpn/comp-lz4.c
new file mode 100644
index 00000000..46511485
--- /dev/null
+++ b/app/openvpn/src/openvpn/comp-lz4.c
@@ -0,0 +1,194 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2013 Gert Doering <gert@greenie.muc.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if defined(ENABLE_LZ4)
+
+#if defined(NEED_COMPAT_LZ4)
+#include "compat-lz4.h"
+#else
+#include "lz4.h"
+#endif
+
+#include "comp.h"
+#include "error.h"
+
+#include "memdbg.h"
+
+/* Initial command byte to tell our peer if we compressed */
+#define LZ4_COMPRESS_BYTE 0x69
+
+static void
+lz4_compress_init (struct compress_context *compctx)
+{
+ msg (D_INIT_MEDIUM, "LZ4 compression initializing");
+ ASSERT(compctx->flags & COMP_F_SWAP);
+}
+
+static void
+lz4_compress_uninit (struct compress_context *compctx)
+{
+}
+
+static void
+lz4_compress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ bool compressed = false;
+
+ if (buf->len <= 0)
+ return;
+
+ /*
+ * In order to attempt compression, length must be at least COMPRESS_THRESHOLD.
+ */
+ if (buf->len >= COMPRESS_THRESHOLD)
+ {
+ const size_t ps = PAYLOAD_SIZE (frame);
+ int zlen_max = ps + COMP_EXTRA_BUFFER (ps);
+ int zlen;
+
+ ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
+ ASSERT (buf_safe (&work, zlen_max));
+
+ if (buf->len > ps)
+ {
+ dmsg (D_COMP_ERRORS, "LZ4 compression buffer overflow");
+ buf->len = 0;
+ return;
+ }
+
+ zlen = LZ4_compress_limitedOutput((const char *)BPTR(buf), (char *)BPTR(&work), BLEN(buf), zlen_max );
+
+ if (zlen <= 0)
+ {
+ dmsg (D_COMP_ERRORS, "LZ4 compression error");
+ buf->len = 0;
+ return;
+ }
+
+ ASSERT (buf_safe (&work, zlen));
+ work.len = zlen;
+ compressed = true;
+
+ dmsg (D_COMP, "LZ4 compress %d -> %d", buf->len, work.len);
+ compctx->pre_compress += buf->len;
+ compctx->post_compress += work.len;
+ }
+
+ /* did compression save us anything? */
+ {
+ uint8_t comp_head_byte = NO_COMPRESS_BYTE_SWAP;
+ if (compressed && work.len < buf->len)
+ {
+ *buf = work;
+ comp_head_byte = LZ4_COMPRESS_BYTE;
+ }
+
+ {
+ uint8_t *head = BPTR (buf);
+ uint8_t *tail = BEND (buf);
+ ASSERT (buf_safe (buf, 1));
+ ++buf->len;
+
+ /* move head byte of payload to tail */
+ *tail = *head;
+ *head = comp_head_byte;
+ }
+ }
+}
+
+static void
+lz4_decompress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ size_t zlen_max = EXPANDED_SIZE (frame);
+ int uncomp_len;
+ uint8_t c; /* flag indicating whether or not our peer compressed */
+
+ if (buf->len <= 0)
+ return;
+
+ ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
+
+ /* do unframing/swap (assumes buf->len > 0) */
+ {
+ uint8_t *head = BPTR (buf);
+ c = *head;
+ --buf->len;
+ *head = *BEND (buf);
+ }
+
+ if (c == LZ4_COMPRESS_BYTE) /* packet was compressed */
+ {
+ ASSERT (buf_safe (&work, zlen_max));
+ uncomp_len = LZ4_decompress_safe((const char *)BPTR(buf), (char *)BPTR(&work), (size_t)BLEN(buf), zlen_max);
+ if (uncomp_len <= 0)
+ {
+ dmsg (D_COMP_ERRORS, "LZ4 decompression error: %d", uncomp_len);
+ buf->len = 0;
+ return;
+ }
+
+ ASSERT (buf_safe (&work, uncomp_len));
+ work.len = uncomp_len;
+
+ dmsg (D_COMP, "LZ4 decompress %d -> %d", buf->len, work.len);
+ compctx->pre_decompress += buf->len;
+ compctx->post_decompress += work.len;
+
+ *buf = work;
+ }
+ else if (c == NO_COMPRESS_BYTE_SWAP) /* packet was not compressed */
+ {
+ ;
+ }
+ else
+ {
+ dmsg (D_COMP_ERRORS, "Bad LZ4 decompression header byte: %d", c);
+ buf->len = 0;
+ }
+}
+
+const struct compress_alg lz4_alg = {
+ "lz4",
+ lz4_compress_init,
+ lz4_compress_uninit,
+ lz4_compress,
+ lz4_decompress
+};
+
+#else
+static void dummy(void) {}
+#endif /* ENABLE_LZ4 */
diff --git a/app/openvpn/src/openvpn/comp-lz4.h b/app/openvpn/src/openvpn/comp-lz4.h
new file mode 100644
index 00000000..ca1dfa9b
--- /dev/null
+++ b/app/openvpn/src/openvpn/comp-lz4.h
@@ -0,0 +1,40 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2013 Gert Doering <gert@greenie.muc.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef OPENVPN_COMP_LZ4_H
+#define OPENVPN_COMP_LZ4_H
+
+#if defined(ENABLE_LZ4)
+
+#include "buffer.h"
+
+extern const struct compress_alg lz4_alg;
+
+struct lz4_workspace
+{
+};
+
+#endif /* ENABLE_LZ4 */
+#endif
diff --git a/app/openvpn/src/openvpn/comp.c b/app/openvpn/src/openvpn/comp.c
new file mode 100644
index 00000000..4ac589f9
--- /dev/null
+++ b/app/openvpn/src/openvpn/comp.c
@@ -0,0 +1,146 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#ifdef USE_COMP
+
+#include "comp.h"
+#include "error.h"
+#include "otime.h"
+
+#include "memdbg.h"
+
+struct compress_context *
+comp_init(const struct compress_options *opt)
+{
+ struct compress_context *compctx = NULL;
+ switch (opt->alg)
+ {
+ case COMP_ALG_STUB:
+ ALLOC_OBJ_CLEAR (compctx, struct compress_context);
+ compctx->flags = opt->flags;
+ compctx->alg = comp_stub_alg;
+ (*compctx->alg.compress_init)(compctx);
+ break;
+#ifdef ENABLE_LZO
+ case COMP_ALG_LZO:
+ ALLOC_OBJ_CLEAR (compctx, struct compress_context);
+ compctx->flags = opt->flags;
+ compctx->alg = lzo_alg;
+ (*compctx->alg.compress_init)(compctx);
+ break;
+#endif
+#ifdef ENABLE_SNAPPY
+ case COMP_ALG_SNAPPY:
+ ALLOC_OBJ_CLEAR (compctx, struct compress_context);
+ compctx->flags = opt->flags;
+ compctx->alg = snappy_alg;
+ (*compctx->alg.compress_init)(compctx);
+ break;
+#endif
+#ifdef ENABLE_LZ4
+ case COMP_ALG_LZ4:
+ ALLOC_OBJ_CLEAR (compctx, struct compress_context);
+ compctx->flags = opt->flags;
+ compctx->alg = lz4_alg;
+ (*compctx->alg.compress_init)(compctx);
+ break;
+#endif
+ }
+ return compctx;
+}
+
+void
+comp_uninit(struct compress_context *compctx)
+{
+ if (compctx)
+ {
+ (*compctx->alg.compress_uninit)(compctx);
+ free(compctx);
+ }
+}
+
+void
+comp_add_to_extra_frame(struct frame *frame)
+{
+ /* Leave room for our one-byte compressed/didn't-compress prefix byte. */
+ frame_add_to_extra_frame (frame, COMP_PREFIX_LEN);
+}
+
+void
+comp_add_to_extra_buffer(struct frame *frame)
+{
+ /* Leave room for compression buffer to expand in worst case scenario
+ where data is totally uncompressible */
+ frame_add_to_extra_buffer (frame, COMP_EXTRA_BUFFER (EXPANDED_SIZE(frame)));
+}
+
+void
+comp_print_stats (const struct compress_context *compctx, struct status_output *so)
+{
+ if (compctx)
+ {
+ status_printf (so, "pre-compress bytes," counter_format, compctx->pre_compress);
+ status_printf (so, "post-compress bytes," counter_format, compctx->post_compress);
+ status_printf (so, "pre-decompress bytes," counter_format, compctx->pre_decompress);
+ status_printf (so, "post-decompress bytes," counter_format, compctx->post_decompress);
+ }
+}
+
+/*
+ * Tell our peer which compression algorithms we support.
+ */
+void
+comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out)
+{
+ if (opt)
+ {
+ bool lzo_avail = false;
+ if (!(opt->flags & COMP_F_ADVERTISE_STUBS_ONLY))
+ {
+#if defined(ENABLE_LZ4)
+ buf_printf (out, "IV_LZ4=1\n");
+#endif
+#if defined(ENABLE_SNAPPY)
+ buf_printf (out, "IV_SNAPPY=1\n");
+#endif
+#if defined(ENABLE_LZO)
+ buf_printf (out, "IV_LZO=1\n");
+ lzo_avail = true;
+#endif
+ }
+ if (!lzo_avail)
+ buf_printf (out, "IV_LZO_STUB=1\n");
+ buf_printf (out, "IV_COMP_STUB=1\n");
+ }
+}
+
+#endif /* USE_COMP */
diff --git a/app/openvpn/src/openvpn/comp.h b/app/openvpn/src/openvpn/comp.h
new file mode 100644
index 00000000..bfa25fd3
--- /dev/null
+++ b/app/openvpn/src/openvpn/comp.h
@@ -0,0 +1,180 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+/*
+ * Generic compression support. Currently we support
+ * Snappy, LZO 2 and LZ4.
+ */
+#ifndef OPENVPN_COMP_H
+#define OPENVPN_COMP_H
+
+#ifdef USE_COMP
+
+#include "buffer.h"
+#include "mtu.h"
+#include "common.h"
+#include "status.h"
+
+/* algorithms */
+#define COMP_ALG_UNDEF 0
+#define COMP_ALG_STUB 1 /* support compression command byte and framing without actual compression */
+#define COMP_ALG_LZO 2 /* LZO algorithm */
+#define COMP_ALG_SNAPPY 3 /* Snappy algorithm */
+#define COMP_ALG_LZ4 4 /* LZ4 algorithm */
+
+/* Compression flags */
+#define COMP_F_ADAPTIVE (1<<0) /* COMP_ALG_LZO only */
+#define COMP_F_ASYM (1<<1) /* only downlink is compressed, not uplink */
+#define COMP_F_SWAP (1<<2) /* initial command byte is swapped with last byte in buffer to preserve payload alignment */
+#define COMP_F_ADVERTISE_STUBS_ONLY (1<<3) /* tell server that we only support compression stubs */
+
+/*
+ * Length of prepended prefix on compressed packets
+ */
+#define COMP_PREFIX_LEN 1
+
+/*
+ * Prefix bytes
+ */
+#define NO_COMPRESS_BYTE 0xFA
+#define NO_COMPRESS_BYTE_SWAP 0xFB /* to maintain payload alignment, replace this byte with last byte of packet */
+
+/*
+ * Compress worst case size expansion (for any algorithm)
+ *
+ * LZO: len + len/8 + 128 + 3
+ * Snappy: len + len/6 + 32
+ * LZ4: len + len/255 + 16 (LZ4_COMPRESSBOUND(len))
+ */
+#define COMP_EXTRA_BUFFER(len) ((len)/6 + 128 + 3 + COMP_PREFIX_LEN)
+
+/*
+ * Don't try to compress any packet smaller than this.
+ */
+#define COMPRESS_THRESHOLD 100
+
+/* Forward declaration of compression context */
+struct compress_context;
+
+/*
+ * Virtual methods and other static info for each compression algorithm
+ */
+struct compress_alg
+{
+ const char *name;
+ void (*compress_init)(struct compress_context *compctx);
+ void (*compress_uninit)(struct compress_context *compctx);
+ void (*compress)(struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame);
+
+ void (*decompress)(struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame);
+};
+
+/*
+ * Headers for each compression implementation
+ */
+#ifdef ENABLE_LZO
+#include "lzo.h"
+#endif
+
+#ifdef ENABLE_SNAPPY
+#include "snappy.h"
+#endif
+
+#ifdef ENABLE_LZ4
+#include "comp-lz4.h"
+#endif
+
+/*
+ * Information that basically identifies a compression
+ * algorithm and related flags.
+ */
+struct compress_options
+{
+ int alg;
+ unsigned int flags;
+};
+
+/*
+ * Workspace union of all supported compression algorithms
+ */
+union compress_workspace_union
+{
+#ifdef ENABLE_LZO
+ struct lzo_compress_workspace lzo;
+#endif
+#ifdef ENABLE_SNAPPY
+ struct snappy_workspace snappy;
+#endif
+#ifdef ENABLE_LZ4
+ struct lz4_workspace lz4;
+#endif
+};
+
+/*
+ * Context for active compression session
+ */
+struct compress_context
+{
+ unsigned int flags;
+ struct compress_alg alg;
+ union compress_workspace_union wu;
+
+ /* statistics */
+ counter_type pre_decompress;
+ counter_type post_decompress;
+ counter_type pre_compress;
+ counter_type post_compress;
+};
+
+extern const struct compress_alg comp_stub_alg;
+
+struct compress_context *comp_init(const struct compress_options *opt);
+
+void comp_uninit(struct compress_context *compctx);
+
+void comp_add_to_extra_frame(struct frame *frame);
+void comp_add_to_extra_buffer(struct frame *frame);
+
+void comp_print_stats (const struct compress_context *compctx, struct status_output *so);
+
+void comp_generate_peer_info_string(const struct compress_options *opt, struct buffer *out);
+
+static inline bool
+comp_enabled(const struct compress_options *info)
+{
+ return info->alg != COMP_ALG_UNDEF;
+}
+
+static inline bool
+comp_unswapped_prefix(const struct compress_options *info)
+{
+ return !(info->flags & COMP_F_SWAP);
+}
+
+#endif /* USE_COMP */
+#endif
diff --git a/app/openvpn/src/openvpn/compstub.c b/app/openvpn/src/openvpn/compstub.c
new file mode 100644
index 00000000..2ab7163e
--- /dev/null
+++ b/app/openvpn/src/openvpn/compstub.c
@@ -0,0 +1,118 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if defined(USE_COMP)
+
+#include "comp.h"
+#include "error.h"
+#include "otime.h"
+
+#include "memdbg.h"
+
+static void
+stub_compress_init (struct compress_context *compctx)
+{
+}
+
+static void
+stub_compress_uninit (struct compress_context *compctx)
+{
+}
+
+static void
+stub_compress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ if (buf->len <= 0)
+ return;
+ if (compctx->flags & COMP_F_SWAP)
+ {
+ uint8_t *head = BPTR (buf);
+ uint8_t *tail = BEND (buf);
+ ASSERT (buf_safe (buf, 1));
+ ++buf->len;
+
+ /* move head byte of payload to tail */
+ *tail = *head;
+ *head = NO_COMPRESS_BYTE_SWAP;
+ }
+ else
+ {
+ uint8_t *header = buf_prepend (buf, 1);
+ *header = NO_COMPRESS_BYTE;
+ }
+}
+
+static void
+stub_decompress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ uint8_t c;
+ if (buf->len <= 0)
+ return;
+ if (compctx->flags & COMP_F_SWAP)
+ {
+ uint8_t *head = BPTR (buf);
+ c = *head;
+ --buf->len;
+ *head = *BEND (buf);
+ if (c != NO_COMPRESS_BYTE_SWAP)
+ {
+ dmsg (D_COMP_ERRORS, "Bad compression stub (swap) decompression header byte: %d", c);
+ buf->len = 0;
+ }
+ }
+ else
+ {
+ c = *BPTR (buf);
+ ASSERT (buf_advance (buf, 1));
+ if (c != NO_COMPRESS_BYTE)
+ {
+ dmsg (D_COMP_ERRORS, "Bad compression stub decompression header byte: %d", c);
+ buf->len = 0;
+ }
+ }
+}
+
+const struct compress_alg comp_stub_alg = {
+ "stub",
+ stub_compress_init,
+ stub_compress_uninit,
+ stub_compress,
+ stub_decompress
+};
+
+#else
+static void dummy(void) {}
+#endif /* USE_STUB */
diff --git a/app/openvpn/src/openvpn/crypto.c b/app/openvpn/src/openvpn/crypto.c
index ac2eecdd..c4c356dc 100644
--- a/app/openvpn/src/openvpn/crypto.c
+++ b/app/openvpn/src/openvpn/crypto.c
@@ -65,6 +65,24 @@
#define CRYPT_ERROR(format) \
do { msg (D_CRYPT_ERRORS, "%s: " format, error_prefix); goto error_exit; } while (false)
+/**
+ * As memcmp(), but constant-time.
+ * Returns 0 when data is equal, non-zero otherwise.
+ */
+static int
+memcmp_constant_time (const void *a, const void *b, size_t size) {
+ const uint8_t * a1 = a;
+ const uint8_t * b1 = b;
+ int ret = 0;
+ size_t i;
+
+ for (i = 0; i < size; i++) {
+ ret |= *a1++ ^ *b1++;
+ }
+
+ return ret;
+}
+
void
openvpn_encrypt (struct buffer *buf, struct buffer work,
const struct crypto_options *opt,
@@ -244,7 +262,7 @@ openvpn_decrypt (struct buffer *buf, struct buffer work,
hmac_ctx_final (ctx->hmac, local_hmac);
/* Compare locally computed HMAC with packet HMAC */
- if (memcmp (local_hmac, BPTR (buf), hmac_len))
+ if (memcmp_constant_time (local_hmac, BPTR (buf), hmac_len))
CRYPT_ERROR ("packet HMAC authentication failed");
ASSERT (buf_advance (buf, hmac_len));
@@ -401,7 +419,7 @@ init_key_type (struct key_type *kt, const char *ciphername,
CLEAR (*kt);
if (ciphername && ciphername_defined)
{
- kt->cipher = cipher_kt_get (ciphername);
+ kt->cipher = cipher_kt_get (translate_cipher_name_from_openvpn(ciphername));
kt->cipher_length = cipher_kt_key_size (kt->cipher);
if (keysize > 0 && keysize <= MAX_CIPHER_KEY_LENGTH)
kt->cipher_length = keysize;
@@ -1010,7 +1028,6 @@ read_passphrase_hash (const char *passphrase_file,
uint8_t *output,
int len)
{
- unsigned int outlen = 0;
md_ctx_t md;
ASSERT (len >= md_kt_size(digest));
@@ -1343,7 +1360,6 @@ prng_bytes (uint8_t *output, int len)
const int md_size = md_kt_size (nonce_md);
while (len > 0)
{
- unsigned int outlen = 0;
const int blen = min_int (len, md_size);
md_full(nonce_md, nonce_data, md_size + nonce_secret_len, nonce_data);
memcpy (output, nonce_data, blen);
diff --git a/app/openvpn/src/openvpn/crypto_backend.h b/app/openvpn/src/openvpn/crypto_backend.h
index 1eac6115..5ae47e6c 100644
--- a/app/openvpn/src/openvpn/crypto_backend.h
+++ b/app/openvpn/src/openvpn/crypto_backend.h
@@ -63,6 +63,18 @@ void crypto_init_lib_engine (const char *engine_name);
void crypto_init_dmalloc (void);
#endif /* DMALLOC */
+/**
+ * Translate a data channel cipher name from the OpenVPN config file
+ * 'language' to the crypto library specific name.
+ */
+const char * translate_cipher_name_from_openvpn (const char *cipher_name);
+
+/**
+ * Translate a data channel cipher name from the crypto library specific name
+ * to the OpenVPN config file 'language'.
+ */
+const char * translate_cipher_name_from_openvpn (const char *cipher_name);
+
void show_available_ciphers (void);
void show_available_digests (void);
diff --git a/app/openvpn/src/openvpn/crypto_openssl.c b/app/openvpn/src/openvpn/crypto_openssl.c
index 53425029..c3480e02 100644
--- a/app/openvpn/src/openvpn/crypto_openssl.c
+++ b/app/openvpn/src/openvpn/crypto_openssl.c
@@ -57,59 +57,6 @@
#warning Some OpenSSL HMAC message digests now support key lengths greater than MAX_HMAC_KEY_LENGTH -- consider increasing MAX_HMAC_KEY_LENGTH
#endif
-/*
- *
- * Workarounds for incompatibilites between OpenSSL libraries.
- * Right now we accept OpenSSL libraries from 0.9.5 to 0.9.7.
- *
- */
-
-#if SSLEAY_VERSION_NUMBER < 0x00907000L
-
-/* Workaround: EVP_CIPHER_mode is defined wrong in OpenSSL 0.9.6 but is fixed in 0.9.7 */
-#undef EVP_CIPHER_mode
-#define EVP_CIPHER_mode(e) (((e)->flags) & EVP_CIPH_MODE)
-
-#define DES_cblock des_cblock
-#define DES_is_weak_key des_is_weak_key
-#define DES_check_key_parity des_check_key_parity
-#define DES_set_odd_parity des_set_odd_parity
-
-#define HMAC_CTX_init(ctx) CLEAR (*ctx)
-#define HMAC_Init_ex(ctx,sec,len,md,impl) HMAC_Init(ctx, sec, len, md)
-#define HMAC_CTX_cleanup(ctx) HMAC_cleanup(ctx)
-#define EVP_MD_CTX_cleanup(md) CLEAR (*md)
-
-#define INFO_CALLBACK_SSL_CONST
-
-#endif
-
-static inline int
-EVP_CipherInit_ov (EVP_CIPHER_CTX *ctx, const EVP_CIPHER *type, uint8_t *key, uint8_t *iv, int enc)
-{
- return EVP_CipherInit (ctx, type, key, iv, enc);
-}
-
-static inline int
-EVP_CipherUpdate_ov (EVP_CIPHER_CTX *ctx, uint8_t *out, int *outl, uint8_t *in, int inl)
-{
- return EVP_CipherUpdate (ctx, out, outl, in, inl);
-}
-
-static inline bool
-cipher_ok (const char* name)
-{
- return true;
-}
-
-#ifndef EVP_CIPHER_name
-#define EVP_CIPHER_name(e) OBJ_nid2sn(EVP_CIPHER_nid(e))
-#endif
-
-#ifndef EVP_MD_name
-#define EVP_MD_name(e) OBJ_nid2sn(EVP_MD_type(e))
-#endif
-
#if HAVE_OPENSSL_ENGINE
#include <openssl/engine.h>
@@ -194,7 +141,8 @@ crypto_init_lib_engine (const char *engine_name)
void
crypto_init_lib (void)
{
-#ifndef USE_SSL
+#ifndef ENABLE_SSL
+ /* If SSL is enabled init is taken care of in ssl_openssl.c */
#ifndef ENABLE_SMALL
ERR_load_crypto_strings ();
#endif
@@ -215,7 +163,8 @@ crypto_init_lib (void)
void
crypto_uninit_lib (void)
{
-#ifndef USE_SSL
+#ifndef ENABLE_SSL
+ /* If SSL is enabled cleanup is taken care of in ssl_openssl.c */
EVP_cleanup ();
#ifndef ENABLE_SMALL
ERR_free_strings ();
@@ -281,6 +230,18 @@ crypto_init_dmalloc (void)
}
#endif /* DMALLOC */
+const char *
+translate_cipher_name_from_openvpn (const char *cipher_name) {
+ // OpenSSL doesn't require any translation
+ return cipher_name;
+}
+
+const char *
+translate_cipher_name_to_openvpn (const char *cipher_name) {
+ // OpenSSL doesn't require any translation
+ return cipher_name;
+}
+
void
show_available_ciphers ()
{
@@ -298,7 +259,7 @@ show_available_ciphers ()
for (nid = 0; nid < 10000; ++nid) /* is there a better way to get the size of the nid list? */
{
const EVP_CIPHER *cipher = EVP_get_cipherbynid (nid);
- if (cipher && cipher_ok (OBJ_nid2sn (nid)))
+ if (cipher)
{
const unsigned int mode = EVP_CIPHER_mode (cipher);
if (mode == EVP_CIPH_CBC_MODE
@@ -477,7 +438,7 @@ cipher_kt_get (const char *ciphername)
cipher = EVP_get_cipherbyname (ciphername);
- if ((NULL == cipher) || !cipher_ok (OBJ_nid2sn (EVP_CIPHER_nid (cipher))))
+ if (NULL == cipher)
msg (M_SSLERR, "Cipher algorithm '%s' not found", ciphername);
if (EVP_CIPHER_key_length (cipher) > MAX_CIPHER_KEY_LENGTH)
@@ -538,13 +499,13 @@ cipher_ctx_init (EVP_CIPHER_CTX *ctx, uint8_t *key, int key_len,
CLEAR (*ctx);
EVP_CIPHER_CTX_init (ctx);
- if (!EVP_CipherInit_ov (ctx, kt, NULL, NULL, enc))
+ if (!EVP_CipherInit (ctx, kt, NULL, NULL, enc))
msg (M_SSLERR, "EVP cipher init #1");
#ifdef HAVE_EVP_CIPHER_CTX_SET_KEY_LENGTH
if (!EVP_CIPHER_CTX_set_key_length (ctx, key_len))
msg (M_SSLERR, "EVP set key size");
#endif
- if (!EVP_CipherInit_ov (ctx, NULL, key, NULL, enc))
+ if (!EVP_CipherInit (ctx, NULL, key, NULL, enc))
msg (M_SSLERR, "EVP cipher init #2");
/* make sure we used a big enough key */
@@ -578,14 +539,14 @@ cipher_ctx_mode (const EVP_CIPHER_CTX *ctx)
int
cipher_ctx_reset (EVP_CIPHER_CTX *ctx, uint8_t *iv_buf)
{
- return EVP_CipherInit_ov (ctx, NULL, NULL, iv_buf, -1);
+ return EVP_CipherInit (ctx, NULL, NULL, iv_buf, -1);
}
int
cipher_ctx_update (EVP_CIPHER_CTX *ctx, uint8_t *dst, int *dst_len,
uint8_t *src, int src_len)
{
- return EVP_CipherUpdate_ov (ctx, dst, dst_len, src, src_len);
+ return EVP_CipherUpdate (ctx, dst, dst_len, src, src_len);
}
int
diff --git a/app/openvpn/src/openvpn/crypto_polarssl.c b/app/openvpn/src/openvpn/crypto_polarssl.c
index 3978a3c6..7dc8aa5b 100644
--- a/app/openvpn/src/openvpn/crypto_polarssl.c
+++ b/app/openvpn/src/openvpn/crypto_polarssl.c
@@ -94,6 +94,53 @@ crypto_init_dmalloc (void)
}
#endif /* DMALLOC */
+typedef struct { const char * openvpn_name; const char * polarssl_name; } cipher_name_pair;
+cipher_name_pair cipher_name_translation_table[] = {
+ { "BF-CBC", "BLOWFISH-CBC" },
+ { "BF-CFB", "BLOWFISH-CFB64" },
+ { "CAMELLIA-128-CFB", "CAMELLIA-128-CFB128" },
+ { "CAMELLIA-192-CFB", "CAMELLIA-192-CFB128" },
+ { "CAMELLIA-256-CFB", "CAMELLIA-256-CFB128" }
+};
+
+const cipher_name_pair *
+get_cipher_name_pair(const char *cipher_name) {
+ cipher_name_pair *pair;
+ size_t i = 0;
+
+ /* Search for a cipher name translation */
+ for (; i < sizeof (cipher_name_translation_table) / sizeof (*cipher_name_translation_table); i++)
+ {
+ pair = &cipher_name_translation_table[i];
+ if (0 == strcmp (cipher_name, pair->openvpn_name) ||
+ 0 == strcmp (cipher_name, pair->polarssl_name))
+ return pair;
+ }
+
+ /* Nothing found, return null */
+ return NULL;
+}
+
+const char *
+translate_cipher_name_from_openvpn (const char *cipher_name) {
+ const cipher_name_pair *pair = get_cipher_name_pair(cipher_name);
+
+ if (NULL == pair)
+ return cipher_name;
+
+ return pair->polarssl_name;
+}
+
+const char *
+translate_cipher_name_to_openvpn (const char *cipher_name) {
+ const cipher_name_pair *pair = get_cipher_name_pair(cipher_name);
+
+ if (NULL == pair)
+ return cipher_name;
+
+ return pair->openvpn_name;
+}
+
void
show_available_ciphers ()
{
@@ -114,7 +161,7 @@ show_available_ciphers ()
if (info && info->mode == POLARSSL_MODE_CBC)
printf ("%s %d bit default key\n",
- info->name, info->key_length);
+ cipher_kt_name(info), cipher_kt_key_size(info) * 8);
ciphers++;
}
@@ -331,7 +378,8 @@ cipher_kt_name (const cipher_info_t *cipher_kt)
{
if (NULL == cipher_kt)
return "[null-cipher]";
- return cipher_kt->name;
+
+ return translate_cipher_name_to_openvpn(cipher_kt->name);
}
int
@@ -339,6 +387,9 @@ cipher_kt_key_size (const cipher_info_t *cipher_kt)
{
if (NULL == cipher_kt)
return 0;
+ if (POLARSSL_CIPHER_ID_BLOWFISH == cipher_kt->base->cipher)
+ return 128/8; /* Override PolarSSL 32 bit default key size with sane 128 bit default */
+
return cipher_kt->key_length/8;
}
@@ -415,7 +466,12 @@ int cipher_ctx_mode (const cipher_context_t *ctx)
int cipher_ctx_reset (cipher_context_t *ctx, uint8_t *iv_buf)
{
- return 0 == cipher_reset(ctx, iv_buf);
+ int retval = cipher_reset(ctx);
+
+ if (0 == retval)
+ retval = cipher_set_iv(ctx, iv_buf, ctx->cipher_info->iv_size);
+
+ return 0 == retval;
}
int cipher_ctx_update (cipher_context_t *ctx, uint8_t *dst, int *dst_len,
diff --git a/app/openvpn/src/openvpn/crypto_polarssl.h b/app/openvpn/src/openvpn/crypto_polarssl.h
index bfabb91b..b6da4363 100644
--- a/app/openvpn/src/openvpn/crypto_polarssl.h
+++ b/app/openvpn/src/openvpn/crypto_polarssl.h
@@ -30,7 +30,6 @@
#ifndef CRYPTO_POLARSSL_H_
#define CRYPTO_POLARSSL_H_
-#include <polarssl/version.h>
#include <polarssl/cipher.h>
#include <polarssl/md.h>
#include <polarssl/ctr_drbg.h>
@@ -60,7 +59,7 @@ typedef md_context_t hmac_ctx_t;
#define OPENVPN_MODE_OFB POLARSSL_MODE_OFB
/** Cipher is in CFB mode */
-#define OPENVPN_MODE_CFB POLARSSL_MODE_CFB128
+#define OPENVPN_MODE_CFB POLARSSL_MODE_CFB
/** Cipher should encrypt */
#define OPENVPN_OP_ENCRYPT POLARSSL_ENCRYPT
diff --git a/app/openvpn/src/openvpn/error.c b/app/openvpn/src/openvpn/error.c
index 98611a1b..af865f32 100644
--- a/app/openvpn/src/openvpn/error.c
+++ b/app/openvpn/src/openvpn/error.c
@@ -86,6 +86,10 @@ static bool std_redir; /* GLOBAL */
/* Should messages be written to the syslog? */
static bool use_syslog; /* GLOBAL */
+/* Should stdout/stderr be be parsable and always be prefixed with time
+ * and message flags */
+static bool machine_readable_output; /* GLOBAL */
+
/* Should timestamps be included on messages to stdout/stderr? */
static bool suppress_timestamps; /* GLOBAL */
@@ -159,10 +163,17 @@ set_suppress_timestamps (bool suppressed)
}
void
+set_machine_readable_output (bool parsable)
+{
+ machine_readable_output = parsable;
+}
+
+void
error_reset ()
{
use_syslog = std_redir = false;
suppress_timestamps = false;
+ machine_readable_output = false;
x_debug_level = 1;
mute_cutoff = 0;
mute_count = 0;
@@ -334,7 +345,22 @@ void x_msg_va (const unsigned int flags, const char *format, va_list arglist)
FILE *fp = msg_fp(flags);
const bool show_usec = check_debug_level (DEBUG_LEVEL_USEC_TIME);
- if ((flags & M_NOPREFIX) || suppress_timestamps)
+ if (machine_readable_output)
+ {
+ struct timeval tv;
+ gettimeofday (&tv, NULL);
+
+ fprintf (fp, "%lu.%06lu %x %s%s%s%s",
+ tv.tv_sec,
+ tv.tv_usec,
+ flags,
+ prefix,
+ prefix_sep,
+ m1,
+ "\n");
+
+ }
+ else if ((flags & M_NOPREFIX) || suppress_timestamps)
{
fprintf (fp, "%s%s%s%s",
prefix,
diff --git a/app/openvpn/src/openvpn/error.h b/app/openvpn/src/openvpn/error.h
index 27c48b69..1e1f2acf 100644
--- a/app/openvpn/src/openvpn/error.h
+++ b/app/openvpn/src/openvpn/error.h
@@ -194,6 +194,8 @@ void error_reset (void);
void errors_to_stderr (void);
void set_suppress_timestamps (bool suppressed);
+void set_machine_readable_output (bool parsable);
+
#define SDL_CONSTRAIN (1<<0)
bool set_debug_level (const int level, const unsigned int flags);
diff --git a/app/openvpn/src/openvpn/event.c b/app/openvpn/src/openvpn/event.c
index 2a13e1cf..34a3c451 100644
--- a/app/openvpn/src/openvpn/event.c
+++ b/app/openvpn/src/openvpn/event.c
@@ -34,6 +34,7 @@
#include "error.h"
#include "integer.h"
#include "event.h"
+#include "fdmisc.h"
#include "memdbg.h"
@@ -582,6 +583,8 @@ ep_init (int *maxevents, unsigned int flags)
if (fd < 0)
return NULL;
+ set_cloexec (fd);
+
ALLOC_OBJ_CLEAR (eps, struct ep_set);
/* set dispatch functions */
diff --git a/app/openvpn/src/openvpn/forward-inline.h b/app/openvpn/src/openvpn/forward-inline.h
index 7eb480dd..5853ce29 100644
--- a/app/openvpn/src/openvpn/forward-inline.h
+++ b/app/openvpn/src/openvpn/forward-inline.h
@@ -228,7 +228,6 @@ context_reschedule_sec (struct context *c, int sec)
static inline struct link_socket_info *
get_link_socket_info (struct context *c)
{
-
if (c->c2.link_socket_info)
return c->c2.link_socket_info;
else
diff --git a/app/openvpn/src/openvpn/forward.c b/app/openvpn/src/openvpn/forward.c
index 9e9c406c..a43361b4 100644
--- a/app/openvpn/src/openvpn/forward.c
+++ b/app/openvpn/src/openvpn/forward.c
@@ -39,6 +39,7 @@
#include "ps.h"
#include "dhcp.h"
#include "common.h"
+#include "ssl_verify.h"
#include "memdbg.h"
@@ -444,10 +445,10 @@ encrypt_sign (struct context *c, bool comp_frag)
if (comp_frag)
{
-#ifdef ENABLE_LZO
+#ifdef USE_COMP
/* Compress the packet. */
- if (lzo_defined (&c->c2.lzo_compwork))
- lzo_compress (&c->c2.buf, b->lzo_compress_buf, &c->c2.lzo_compwork, &c->c2.frame);
+ if (c->c2.comp_context)
+ (*c->c2.comp_context->alg.compress)(&c->c2.buf, b->compress_buf, c->c2.comp_context, &c->c2.frame);
#endif
#ifdef ENABLE_FRAGMENT
if (c->c2.fragment)
@@ -610,8 +611,6 @@ check_timeout_random_component (struct context *c)
tv_add (&c->c2.timeval, &c->c2.timeout_random_component);
}
-#ifdef ENABLE_SOCKS
-
/*
* Handle addition and removal of the 10-byte Socks5 header
* in UDP packets.
@@ -649,7 +648,6 @@ link_socket_write_post_size_adjust (int *size,
*size = 0;
}
}
-#endif
/*
* Output: c->c2.buf
@@ -718,10 +716,8 @@ read_incoming_link (struct context *c)
/* check recvfrom status */
check_status (status, "read", c->c2.link_socket, NULL);
-#ifdef ENABLE_SOCKS
/* Remove socks header if applicable */
socks_postprocess_incoming_link (c);
-#endif
perf_pop ();
}
@@ -846,10 +842,10 @@ process_incoming_link (struct context *c)
fragment_incoming (c->c2.fragment, &c->c2.buf, &c->c2.frame_fragment);
#endif
-#ifdef ENABLE_LZO
+#ifdef USE_COMP
/* decompress the incoming packet */
- if (lzo_defined (&c->c2.lzo_compwork))
- lzo_decompress (&c->c2.buf, c->c2.buffers->lzo_decompress_buf, &c->c2.lzo_compwork, &c->c2.frame);
+ if (c->c2.comp_context)
+ (*c->c2.comp_context->alg.decompress)(&c->c2.buf, c->c2.buffers->decompress_buf, c->c2.comp_context, &c->c2.frame);
#endif
#ifdef PACKET_TRUNCATION_CHECK
@@ -1017,6 +1013,8 @@ process_ip_header (struct context *c, unsigned int flags, struct buffer *buf)
if (!c->options.passtos)
flags &= ~PIPV4_PASSTOS;
#endif
+ if (!c->options.client_nat)
+ flags &= ~PIPV4_CLIENT_NAT;
if (!c->options.route_gateway_via_dhcp)
flags &= ~PIPV4_EXTRACT_DHCP_ROUTER;
@@ -1026,11 +1024,13 @@ process_ip_header (struct context *c, unsigned int flags, struct buffer *buf)
* The --passtos and --mssfix options require
* us to examine the IPv4 header.
*/
+
+ if (flags & (PIP_MSSFIX
#if PASSTOS_CAPABILITY
- if (flags & (PIPV4_PASSTOS|PIP_MSSFIX))
-#else
- if (flags & PIP_MSSFIX)
+ | PIPV4_PASSTOS
#endif
+ | PIPV4_CLIENT_NAT
+ ))
{
struct buffer ipbuf = *buf;
if (is_ipv4 (TUNNEL_TYPE (c->c1.tuntap), &ipbuf))
@@ -1045,14 +1045,12 @@ process_ip_header (struct context *c, unsigned int flags, struct buffer *buf)
if (flags & PIP_MSSFIX)
mss_fixup_ipv4 (&ipbuf, MTU_TO_MSS (TUN_MTU_SIZE_DYNAMIC (&c->c2.frame)));
-#ifdef ENABLE_CLIENT_NAT
/* possibly do NAT on packet */
if ((flags & PIPV4_CLIENT_NAT) && c->options.client_nat)
{
const int direction = (flags & PIPV4_OUTGOING) ? CN_INCOMING : CN_OUTGOING;
client_nat_transform (c->options.client_nat, &ipbuf, direction);
}
-#endif
/* possibly extract a DHCP router message */
if (flags & PIPV4_EXTRACT_DHCP_ROUTER)
{
@@ -1122,7 +1120,7 @@ process_outgoing_link (struct context *c)
fprintf (stderr, "W");
#endif
msg (D_LINK_RW, "%s WRITE [%d] to %s: %s",
- proto2ascii (c->c2.link_socket->info.proto, c->c2.link_socket->info.proto, true),
+ proto2ascii (c->c2.link_socket->info.proto, c->c2.link_socket->info.af, true),
BLEN (&c->c2.to_link),
print_link_socket_actual (c->c2.to_link_addr, &gc),
PROTO_DUMP (&c->c2.to_link, &gc));
@@ -1130,23 +1128,18 @@ process_outgoing_link (struct context *c)
/* Packet send complexified by possible Socks5 usage */
{
struct link_socket_actual *to_addr = c->c2.to_link_addr;
-#ifdef ENABLE_SOCKS
int size_delta = 0;
-#endif
-#ifdef ENABLE_SOCKS
/* If Socks5 over UDP, prepend header */
socks_preprocess_outgoing_link (c, &to_addr, &size_delta);
-#endif
+
/* Send packet */
size = link_socket_write (c->c2.link_socket,
&c->c2.to_link,
to_addr);
-#ifdef ENABLE_SOCKS
/* Undo effect of prepend */
link_socket_write_post_size_adjust (&size, size_delta, &c->c2.to_link);
-#endif
}
if (size > 0)
diff --git a/app/openvpn/src/openvpn/init.c b/app/openvpn/src/openvpn/init.c
index b3125282..ede955a1 100644
--- a/app/openvpn/src/openvpn/init.c
+++ b/app/openvpn/src/openvpn/init.c
@@ -43,6 +43,7 @@
#include "lladdr.h"
#include "ping.h"
#include "mstats.h"
+#include "ssl_verify.h"
#include "memdbg.h"
@@ -127,11 +128,9 @@ management_callback_proxy_cmd (void *arg, const char **p)
{
if (streq (p[1], "HTTP"))
{
-#ifndef ENABLE_HTTP_PROXY
- msg (M_WARN, "HTTP proxy support is not available");
-#else
struct http_proxy_options *ho;
- if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_CLIENT ) {
+ if (ce->proto != PROTO_TCP && ce->proto != PROTO_TCP_CLIENT )
+ {
msg (M_WARN, "HTTP proxy support only works for TCP based connections");
return false;
}
@@ -141,17 +140,12 @@ management_callback_proxy_cmd (void *arg, const char **p)
ho->retry = true;
ho->auth_retry = (p[4] && streq (p[4], "nct") ? PAR_NCT : PAR_ALL);
ret = true;
-#endif
}
else if (streq (p[1], "SOCKS"))
{
-#ifndef ENABLE_SOCKS
- msg (M_WARN, "SOCKS proxy support is not available");
-#else
ce->socks_proxy_server = string_alloc (p[2], gc);
ce->socks_proxy_port = p[3];
ret = true;
-#endif
}
}
else
@@ -174,10 +168,12 @@ ce_management_query_proxy (struct context *c)
if (management)
{
gc = gc_new ();
- struct buffer out = alloc_buf_gc (256, &gc);
- buf_printf (&out, ">PROXY:%u,%s,%s", (l ? l->current : 0) + 1,
- (proto_is_udp (ce->proto) ? "UDP" : "TCP"), np (ce->remote));
- management_notify_generic (management, BSTR (&out));
+ {
+ struct buffer out = alloc_buf_gc (256, &gc);
+ buf_printf (&out, ">PROXY:%u,%s,%s", (l ? l->current : 0) + 1,
+ (proto_is_udp (ce->proto) ? "UDP" : "TCP"), np (ce->remote));
+ management_notify_generic (management, BSTR (&out));
+ }
ce->flags |= CE_MAN_QUERY_PROXY;
while (ce->flags & CE_MAN_QUERY_PROXY)
{
@@ -282,6 +278,7 @@ static void
init_connection_list (struct context *c)
{
struct connection_list *l = c->options.connection_list;
+
l->current = -1;
if (c->options.remote_random)
{
@@ -303,11 +300,10 @@ init_connection_list (struct context *c)
/*
* Clear the remote address list
*/
-static void clear_remote_addrlist (struct link_socket_addr *lsa)
+static void clear_remote_addrlist (struct link_socket_addr *lsa, bool free)
{
- if (lsa->remote_list) {
- freeaddrinfo(lsa->remote_list);
- }
+ if (lsa->remote_list && free)
+ freeaddrinfo(lsa->remote_list);
lsa->remote_list = NULL;
lsa->current_remote = NULL;
}
@@ -322,7 +318,7 @@ next_connection_entry (struct context *c)
bool ce_defined;
struct connection_entry *ce;
int n_cycles = 0;
-
+
do {
ce_defined = true;
if (c->options.no_advance && l->current >= 0)
@@ -345,9 +341,12 @@ next_connection_entry (struct context *c)
* this is broken probably ever since connection lists and multiple
* remote existed
*/
-
if (!c->options.persist_remote_ip)
- clear_remote_addrlist (&c->c1.link_socket_addr);
+ {
+ /* close_instance should have cleared the addrinfo objects */
+ ASSERT (c->c1.link_socket_addr.current_remote == NULL);
+ ASSERT (c->c1.link_socket_addr.remote_list == NULL);
+ }
else
c->c1.link_socket_addr.current_remote =
c->c1.link_socket_addr.remote_list;
@@ -357,7 +356,7 @@ next_connection_entry (struct context *c)
* If this is connect-retry-max * size(l)
* OpenVPN will quit
*/
-
+
c->options.unsuccessful_attempts++;
if (++l->current >= l->len)
@@ -396,7 +395,7 @@ next_connection_entry (struct context *c)
}
#endif
} while (!ce_defined);
-
+
/* Check if this connection attempt would bring us over the limit */
if (c->options.connect_retry_max > 0 &&
c->options.unsuccessful_attempts > (l->len * c->options.connect_retry_max))
@@ -434,41 +433,30 @@ init_query_passwords (struct context *c)
* Initialize/Uninitialize HTTP or SOCKS proxy
*/
-#ifdef GENERAL_PROXY_SUPPORT
-
static void
uninit_proxy_dowork (struct context *c)
{
-#ifdef ENABLE_HTTP_PROXY
if (c->c1.http_proxy_owned && c->c1.http_proxy)
{
http_proxy_close (c->c1.http_proxy);
c->c1.http_proxy = NULL;
c->c1.http_proxy_owned = false;
}
-#endif
-#ifdef ENABLE_SOCKS
if (c->c1.socks_proxy_owned && c->c1.socks_proxy)
{
socks_proxy_close (c->c1.socks_proxy);
c->c1.socks_proxy = NULL;
c->c1.socks_proxy_owned = false;
}
-#endif
}
static void
init_proxy_dowork (struct context *c)
{
-#ifdef ENABLE_HTTP_PROXY
bool did_http = false;
-#else
- const bool did_http = false;
-#endif
uninit_proxy_dowork (c);
-#ifdef ENABLE_HTTP_PROXY
if (c->options.ce.http_proxy_options)
{
/* Possible HTTP proxy user/pass input */
@@ -479,10 +467,8 @@ init_proxy_dowork (struct context *c)
c->c1.http_proxy_owned = true;
}
}
-#endif
-#ifdef ENABLE_SOCKS
- if (!did_http && c->options.ce.socks_proxy_server)
+ if (!did_http && c->options.ce.socks_proxy_server)
{
c->c1.socks_proxy = socks_proxy_new (c->options.ce.socks_proxy_server,
c->options.ce.socks_proxy_port,
@@ -493,7 +479,6 @@ init_proxy_dowork (struct context *c)
c->c1.socks_proxy_owned = true;
}
}
-#endif
}
static void
@@ -508,20 +493,6 @@ uninit_proxy (struct context *c)
uninit_proxy_dowork (c);
}
-#else
-
-static inline void
-init_proxy (struct context *c, const int scope)
-{
-}
-
-static inline void
-uninit_proxy (struct context *c)
-{
-}
-
-#endif
-
void
context_init_1 (struct context *c)
{
@@ -865,7 +836,7 @@ print_openssl_info (const struct options *options)
#ifdef ENABLE_CRYPTO
if (options->show_ciphers || options->show_digests || options->show_engines
#ifdef ENABLE_SSL
- || options->show_tls_ciphers
+ || options->show_tls_ciphers || options->show_curves
#endif
)
{
@@ -877,7 +848,9 @@ print_openssl_info (const struct options *options)
show_available_engines ();
#ifdef ENABLE_SSL
if (options->show_tls_ciphers)
- show_available_tls_ciphers ();
+ show_available_tls_ciphers (options->cipher_list);
+ if (options->show_curves)
+ show_available_curves();
#endif
return true;
}
@@ -1156,16 +1129,17 @@ do_init_traffic_shaper (struct context *c)
}
/*
- * Allocate a route list structure if at least one
- * --route option was specified.
+ * Allocate route list structures for IPv4 and IPv6
+ * (we do this for IPv4 even if no --route option has been seen, as other
+ * parts of OpenVPN might want to fill the route-list with info, e.g. DHCP)
*/
static void
do_alloc_route_list (struct context *c)
{
- if (c->options.routes && !c->c1.route_list)
- c->c1.route_list = new_route_list (c->options.max_routes, &c->gc);
+ if (!c->c1.route_list)
+ ALLOC_OBJ_CLEAR_GC (c->c1.route_list, struct route_list, &c->gc);
if (c->options.routes_ipv6 && !c->c1.route_ipv6_list)
- c->c1.route_ipv6_list = new_route_ipv6_list (c->options.max_routes, &c->gc);
+ ALLOC_OBJ_CLEAR_GC (c->c1.route_ipv6_list, struct route_ipv6_list, &c->gc);
}
@@ -1215,7 +1189,6 @@ do_init_route_ipv6_list (const struct options *options,
struct env_set *es)
{
const char *gw = NULL;
- int dev = dev_type_enum (options->dev, options->dev_type);
int metric = -1; /* no metric set */
gw = options->ifconfig_ipv6_remote; /* default GW = remote end */
@@ -1251,7 +1224,7 @@ void
initialization_sequence_completed (struct context *c, const unsigned int flags)
{
static const char message[] = "Initialization Sequence Completed";
-
+
/* Reset the unsuccessful connection counter on complete initialisation */
c->options.unsuccessful_attempts=0;
@@ -1420,15 +1393,15 @@ do_open_tun (struct context *c)
if (!c->c1.tuntap)
{
#endif
-
+
#ifdef TARGET_ANDROID
/* If we emulate persist-tun on android we still have to open a new tun and
- then close the old */
+ * then close the old */
int oldtunfd=-1;
- if(c->c1.tuntap)
- oldtunfd = c->c1.tuntap->fd;
+ if (c->c1.tuntap)
+ oldtunfd = c->c1.tuntap->fd;
#endif
-
+
/* initialize (but do not open) tun/tap object */
do_init_tun (c);
@@ -1455,19 +1428,19 @@ do_open_tun (struct context *c)
}
/* possibly add routes */
- if(ifconfig_order() == ROUTE_BEFORE_TUN) {
- /* Ignore route_delay, would cause ROUTE_BEFORE_TUN to be ignored */
- do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
- c->c1.tuntap, c->plugins, c->c2.es);
- }
-
+ if (route_order() == ROUTE_BEFORE_TUN) {
+ /* Ignore route_delay, would cause ROUTE_BEFORE_TUN to be ignored */
+ do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
+ c->c1.tuntap, c->plugins, c->c2.es);
+ }
+#ifdef TARGET_ANDROID
+ /* Store the old fd inside the fd so open_tun can use it */
+ c->c1.tuntap->fd = oldtunfd;
+#endif
/* open the tun device */
open_tun (c->options.dev, c->options.dev_type, c->options.dev_node,
c->c1.tuntap);
-#ifdef TARGET_ANDROID
- if(oldtunfd>=0)
- close(oldtunfd);
-#endif
+
/* set the hardware address */
if (c->options.lladdr)
set_lladdr(c->c1.tuntap->actual_name, c->options.lladdr, c->c2.es);
@@ -1495,7 +1468,7 @@ do_open_tun (struct context *c)
c->c2.es);
/* possibly add routes */
- if ((ifconfig_order() == ROUTE_AFTER_TUN) && (!c->options.route_delay_defined))
+ if ((route_order() == ROUTE_AFTER_TUN) && (!c->options.route_delay_defined))
do_route (&c->options, c->c1.route_list, c->c1.route_ipv6_list,
c->c1.tuntap, c->plugins, c->c2.es);
@@ -1578,7 +1551,7 @@ do_close_tun (struct context *c, bool force)
/* delete any routes we added */
if (c->c1.route_list || c->c1.route_ipv6_list )
- {
+ {
run_up_down (c->options.route_predown_script,
c->plugins,
OPENVPN_PLUGIN_ROUTE_PREDOWN,
@@ -1705,7 +1678,7 @@ do_up (struct context *c, bool pulled_options, unsigned int option_types_found)
#endif
/* if --route-delay was specified, start timer */
- if ((ifconfig_order() == ROUTE_AFTER_TUN) && c->options.route_delay_defined)
+ if ((route_order() == ROUTE_AFTER_TUN) && c->options.route_delay_defined)
{
event_timeout_init (&c->c2.route_wakeup, c->options.route_delay, now);
event_timeout_init (&c->c2.route_wakeup_expire, c->options.route_delay + c->options.route_delay_window, now);
@@ -1783,14 +1756,12 @@ do_deferred_options (struct context *c, const unsigned int found)
}
#endif
-#ifdef ENABLE_LZO
+#ifdef USE_COMP
if (found & OPT_P_COMP)
{
- if (lzo_defined (&c->c2.lzo_compwork))
- {
- msg (D_PUSH, "OPTIONS IMPORT: LZO parms modified");
- lzo_modify_flags (&c->c2.lzo_compwork, c->options.lzo);
- }
+ msg (D_PUSH, "OPTIONS IMPORT: compression parms modified");
+ comp_uninit (c->c2.comp_context);
+ c->c2.comp_context = comp_init (&c->options.comp);
}
#endif
@@ -1853,18 +1824,8 @@ do_hold (struct context *c)
static void
socket_restart_pause (struct context *c)
{
- bool proxy = false;
int sec = 2;
-#ifdef ENABLE_HTTP_PROXY
- if (c->options.ce.http_proxy_options)
- proxy = true;
-#endif
-#ifdef ENABLE_SOCKS
- if (c->options.ce.socks_proxy_server)
- proxy = true;
-#endif
-
switch (c->options.ce.proto)
{
case PROTO_TCP_SERVER:
@@ -2222,7 +2183,12 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
to.renegotiate_seconds = options->renegotiate_seconds;
to.single_session = options->single_session;
#ifdef ENABLE_PUSH_PEER_INFO
- to.push_peer_info = options->push_peer_info;
+ if (options->push_peer_info) /* all there is */
+ to.push_peer_info_detail = 2;
+ else if (options->pull) /* pull clients send some details */
+ to.push_peer_info_detail = 1;
+ else /* default: no peer-info at all */
+ to.push_peer_info_detail = 0;
#endif
/* should we not xmit any packets until we get an initial
@@ -2236,7 +2202,8 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
to.verify_command = options->tls_verify;
to.verify_export_cert = options->tls_export_cert;
- to.verify_x509name = options->tls_remote;
+ to.verify_x509_type = (options->verify_x509_type & 0xff);
+ to.verify_x509_name = options->verify_x509_name;
to.crl_file = options->crl_file;
to.ssl_flags = options->ssl_flags;
to.ns_cert_type = options->ns_cert_type;
@@ -2278,6 +2245,10 @@ do_init_crypto_tls (struct context *c, const unsigned int flags)
#endif
#endif
+#ifdef USE_COMP
+ to.comp_options = options->comp;
+#endif
+
/* TLS handshake authentication (--tls-auth) */
if (options->tls_auth_file)
{
@@ -2360,38 +2331,56 @@ do_init_crypto (struct context *c, const unsigned int flags)
static void
do_init_frame (struct context *c)
{
-#ifdef ENABLE_LZO
+#ifdef USE_COMP
/*
- * Initialize LZO compression library.
+ * modify frame parameters if compression is enabled
*/
- if (c->options.lzo & LZO_SELECTED)
+ if (comp_enabled(&c->options.comp))
{
- lzo_adjust_frame_parameters (&c->c2.frame);
+ comp_add_to_extra_frame (&c->c2.frame);
+#if !defined(ENABLE_SNAPPY) && !defined(ENABLE_LZ4)
/*
- * LZO usage affects buffer alignment.
+ * Compression usage affects buffer alignment when non-swapped algs
+ * such as LZO is used.
+ * Newer algs like Snappy and comp-stub with COMP_F_SWAP don't need
+ * any special alignment because of the control-byte swap approach.
+ * LZO alignment (on the other hand) is problematic because
+ * the presence of the control byte means that either the output of
+ * decryption must be written to an unaligned buffer, or the input
+ * to compression (or packet dispatch if packet is uncompressed)
+ * must be read from an unaligned buffer.
+ * This code tries to align the input to compression (or packet
+ * dispatch if packet is uncompressed) at the cost of requiring
+ * decryption output to be written to an unaligned buffer, so
+ * it's more of a tradeoff than an optimal solution and we don't
+ * include it when we are doing a modern build with Snappy or LZ4.
+ * Strictly speaking, on the server it would be better to execute
+ * this code for every connection after we decide the compression
+ * method, but currently the frame code doesn't appear to be
+ * flexible enough for this, since the frame is already established
+ * before it is known which compression options will be pushed.
*/
- if (CIPHER_ENABLED (c))
+ if (comp_unswapped_prefix (&c->options.comp) && CIPHER_ENABLED (c))
{
- frame_add_to_align_adjust (&c->c2.frame, LZO_PREFIX_LEN);
+ frame_add_to_align_adjust (&c->c2.frame, COMP_PREFIX_LEN);
frame_or_align_flags (&c->c2.frame,
FRAME_HEADROOM_MARKER_FRAGMENT
|FRAME_HEADROOM_MARKER_DECRYPT);
}
+#endif
#ifdef ENABLE_FRAGMENT
- lzo_adjust_frame_parameters (&c->c2.frame_fragment_omit); /* omit LZO frame delta from final frame_fragment */
+ comp_add_to_extra_frame (&c->c2.frame_fragment_omit); /* omit compression frame delta from final frame_fragment */
#endif
}
-#endif /* ENABLE_LZO */
+#endif /* USE_COMP */
-#ifdef ENABLE_SOCKS
/*
* Adjust frame size for UDP Socks support.
*/
if (c->options.ce.socks_proxy_server)
socks_adjust_frame_parameters (&c->c2.frame, c->options.ce.proto);
-#endif
/*
* Adjust frame size based on the --tun-mtu-extra parameter.
@@ -2412,6 +2401,17 @@ do_init_frame (struct context *c)
*/
frame_finalize_options (c, NULL);
+#ifdef USE_COMP
+ /*
+ * Modify frame parameters if compression is compiled in.
+ * Should be called after frame_finalize_options.
+ */
+ comp_add_to_extra_buffer (&c->c2.frame);
+#ifdef ENABLE_FRAGMENT
+ comp_add_to_extra_buffer (&c->c2.frame_fragment_omit); /* omit compression frame delta from final frame_fragment */
+#endif
+#endif /* USE_COMP */
+
#ifdef ENABLE_FRAGMENT
/*
* Set frame parameter for fragment code. This is necessary because
@@ -2498,12 +2498,10 @@ do_option_warnings (struct context *c)
warn_on_use_of_common_subnets ();
if (o->tls_client
&& !o->tls_verify
- && !o->tls_remote
+ && o->verify_x509_type == VERIFY_X509_NONE
&& !(o->ns_cert_type & NS_CERT_CHECK_SERVER)
&& !o->remote_cert_eku)
msg (M_WARN, "WARNING: No server certificate verification method has been enabled. See http://openvpn.net/howto.html#mitm for more info.");
- if (o->tls_remote)
- msg (M_WARN, "WARNING: Make sure you understand the semantics of --tls-remote before using it (see the man page).");
#endif
#endif
@@ -2512,6 +2510,16 @@ do_option_warnings (struct context *c)
msg (M_WARN, "NOTE: --connect-timeout option is not supported on this OS");
#endif
+ /* If a script is used, print appropiate warnings */
+ if (o->user_script_used)
+ {
+ if (script_security >= SSEC_SCRIPTS)
+ msg (M_WARN, "NOTE: the current --script-security setting may allow this configuration to call user-defined scripts");
+ else if (script_security >= SSEC_PW_ENV)
+ msg (M_WARN, "WARNING: the current --script-security setting may allow passwords to be passed to scripts via environmental variables");
+ else
+ msg (M_WARN, "NOTE: starting with " PACKAGE_NAME " 2.1, '--script-security 2' or higher is required to call user-defined scripts or executables");
+ }
}
static void
@@ -2539,9 +2547,9 @@ init_context_buffers (const struct frame *frame)
b->decrypt_buf = alloc_buf (BUF_SIZE (frame));
#endif
-#ifdef ENABLE_LZO
- b->lzo_compress_buf = alloc_buf (BUF_SIZE (frame));
- b->lzo_decompress_buf = alloc_buf (BUF_SIZE (frame));
+#ifdef USE_COMP
+ b->compress_buf = alloc_buf (BUF_SIZE (frame));
+ b->decompress_buf = alloc_buf (BUF_SIZE (frame));
#endif
return b;
@@ -2556,9 +2564,9 @@ free_context_buffers (struct context_buffers *b)
free_buf (&b->read_tun_buf);
free_buf (&b->aux_buf);
-#ifdef ENABLE_LZO
- free_buf (&b->lzo_compress_buf);
- free_buf (&b->lzo_decompress_buf);
+#ifdef USE_COMP
+ free_buf (&b->compress_buf);
+ free_buf (&b->decompress_buf);
#endif
#ifdef ENABLE_CRYPTO
@@ -2638,16 +2646,14 @@ do_init_socket_1 (struct context *c, const int mode)
c->options.ce.local_port,
c->options.ce.remote,
c->options.ce.remote_port,
+ c->c1.dns_cache,
c->options.ce.proto,
- c->options.ce.af,
+ c->options.ce.af,
+ c->options.ce.bind_ipv6_only,
mode,
c->c2.accept_from,
-#ifdef ENABLE_HTTP_PROXY
c->c1.http_proxy,
-#endif
-#ifdef ENABLE_SOCKS
c->c1.socks_proxy,
-#endif
#ifdef ENABLE_DEBUG
c->options.gremlin,
#endif
@@ -2857,7 +2863,7 @@ do_close_link_socket (struct context *c)
|| c->options.no_advance))
)))
{
- clear_remote_addrlist(&c->c1.link_socket_addr);
+ clear_remote_addrlist(&c->c1.link_socket_addr, !c->options.resolve_in_advance);
}
/* Clear the remote actual address when persist_remote_ip is not in use */
@@ -2865,8 +2871,9 @@ do_close_link_socket (struct context *c)
CLEAR (c->c1.link_socket_addr.actual);
if (!(c->sig->signal_received == SIGUSR1 && c->options.persist_local_ip)) {
- if (c->c1.link_socket_addr.bind_local)
- freeaddrinfo(c->c1.link_socket_addr.bind_local);
+ if (c->c1.link_socket_addr.bind_local && !c->options.resolve_in_advance)
+ freeaddrinfo(c->c1.link_socket_addr.bind_local);
+
c->c1.link_socket_addr.bind_local=NULL;
}
}
@@ -3003,7 +3010,7 @@ do_close_ifconfig_pool_persist (struct context *c)
static void
do_inherit_env (struct context *c, const struct env_set *src)
{
- c->c2.es = env_set_create (&c->c2.gc);
+ c->c2.es = env_set_create (NULL);
c->c2.es_owned = true;
env_set_inherit (c->c2.es, src);
}
@@ -3154,6 +3161,20 @@ management_show_net_callback (void *arg, const int msglevel)
#endif
}
+#ifdef TARGET_ANDROID
+int
+managmenet_callback_network_change (void *arg)
+{
+ struct context *c = (struct context *) arg;
+ if (!c->c2.link_socket)
+ return -1;
+ if (c->c2.link_socket->sd == SOCKET_UNDEFINED)
+ return -1;
+
+ return c->c2.link_socket->sd;
+}
+#endif
+
#endif
void
@@ -3169,6 +3190,9 @@ init_management_callback_p2p (struct context *c)
cb.show_net = management_show_net_callback;
cb.proxy_cmd = management_callback_proxy_cmd;
cb.remote_cmd = management_callback_remote_cmd;
+#ifdef TARGET_ANDROID
+ cb.network_change = managmenet_callback_network_change;
+#endif
management_set_callback (management, &cb);
}
#endif
@@ -3288,6 +3312,10 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
/* init garbage collection level */
gc_init (&c->c2.gc);
+ /* inherit environmental variables */
+ if (env)
+ do_inherit_env (c, env);
+
/* signals caught here will abort */
c->sig->signal_received = 0;
c->sig->signal_text = NULL;
@@ -3304,6 +3332,13 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
goto sig;
}
+ if (c->options.resolve_in_advance)
+ {
+ do_preresolve (c);
+ if (IS_SIG (c))
+ goto sig;
+ }
+
/* map in current connection entry */
next_connection_entry (c);
@@ -3339,10 +3374,6 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
if (c->mode == CM_P2P || c->mode == CM_TOP)
do_option_warnings (c);
- /* inherit environmental variables */
- if (env)
- do_inherit_env (c, env);
-
#ifdef ENABLE_PLUGIN
/* initialize plugins */
if (c->mode == CM_P2P || c->mode == CM_TOP)
@@ -3403,10 +3434,10 @@ init_instance (struct context *c, const struct env_set *env, const unsigned int
goto sig;
}
-#ifdef ENABLE_LZO
- /* initialize LZO compression library. */
- if ((options->lzo & LZO_SELECTED) && (c->mode == CM_P2P || child))
- lzo_compress_init (&c->c2.lzo_compwork, options->lzo);
+#ifdef USE_COMP
+ /* initialize compression library. */
+ if (comp_enabled(&options->comp) && (c->mode == CM_P2P || child))
+ c->c2.comp_context = comp_init (&options->comp);
#endif
/* initialize MTU variables */
@@ -3520,9 +3551,12 @@ close_instance (struct context *c)
/* if xinetd/inetd mode, don't allow restart */
do_close_check_if_restart_permitted (c);
-#ifdef ENABLE_LZO
- if (lzo_defined (&c->c2.lzo_compwork))
- lzo_compress_uninit (&c->c2.lzo_compwork);
+#ifdef USE_COMP
+ if (c->c2.comp_context)
+ {
+ comp_uninit (c->c2.comp_context);
+ c->c2.comp_context = NULL;
+ }
#endif
/* free buffers */
@@ -3694,6 +3728,10 @@ inherit_context_top (struct context *dest,
dest->c2.event_set = NULL;
if (proto_is_dgram(src->options.ce.proto))
do_event_set_init (dest, false);
+
+#ifdef USE_COMP
+ dest->c2.comp_context = NULL;
+#endif
}
void
@@ -3737,6 +3775,7 @@ test_crypto_thread (void *arg)
ASSERT (options->test_crypto);
init_verb_mute (c, IVM_LEVEL_1);
context_init_1 (c);
+ next_connection_entry(c);
do_init_crypto_static (c, 0);
frame_finalize_options (c, options);
diff --git a/app/openvpn/src/openvpn/lzo.c b/app/openvpn/src/openvpn/lzo.c
index 195b8194..daa02ed0 100644
--- a/app/openvpn/src/openvpn/lzo.c
+++ b/app/openvpn/src/openvpn/lzo.c
@@ -34,15 +34,17 @@
#include "syshead.h"
-#ifdef ENABLE_LZO
+#if defined(ENABLE_LZO)
-#include "lzo.h"
+#include "comp.h"
#include "error.h"
#include "otime.h"
#include "memdbg.h"
-#ifndef ENABLE_LZO_STUB
+/* Initial command byte to tell our peer if we compressed */
+#define LZO_COMPRESS_BYTE 0x66
+
/**
* Perform adaptive compression housekeeping.
*
@@ -97,101 +99,69 @@ lzo_adaptive_compress_data (struct lzo_adaptive_compress *ac, int n_total, int n
ac->n_comp += n_comp;
}
-#endif /* ENABLE_LZO_STUB */
-
-void lzo_adjust_frame_parameters (struct frame *frame)
-{
- /* Leave room for our one-byte compressed/didn't-compress prefix byte. */
- frame_add_to_extra_frame (frame, LZO_PREFIX_LEN);
-
- /* Leave room for compression buffer to expand in worst case scenario
- where data is totally uncompressible */
- frame_add_to_extra_buffer (frame, LZO_EXTRA_BUFFER (EXPANDED_SIZE(frame)));
-}
-
-void
-lzo_compress_init (struct lzo_compress_workspace *lzowork, unsigned int flags)
+static void
+lzo_compress_init (struct compress_context *compctx)
{
- CLEAR (*lzowork);
-
- lzowork->flags = flags;
-#ifndef ENABLE_LZO_STUB
- lzowork->wmem_size = LZO_WORKSPACE;
-
+ msg (D_INIT_MEDIUM, "LZO compression initializing");
+ ASSERT(!(compctx->flags & COMP_F_SWAP));
+ compctx->wu.lzo.wmem_size = LZO_WORKSPACE;
if (lzo_init () != LZO_E_OK)
msg (M_FATAL, "Cannot initialize LZO compression library");
- lzowork->wmem = (lzo_voidp) lzo_malloc (lzowork->wmem_size);
- check_malloc_return (lzowork->wmem);
- msg (D_INIT_MEDIUM, "LZO compression initialized");
-#else
- msg (D_INIT_MEDIUM, "LZO stub compression initialized");
-#endif
- lzowork->defined = true;
+ compctx->wu.lzo.wmem = (lzo_voidp) lzo_malloc (compctx->wu.lzo.wmem_size);
+ check_malloc_return (compctx->wu.lzo.wmem);
}
-void
-lzo_compress_uninit (struct lzo_compress_workspace *lzowork)
+static void
+lzo_compress_uninit (struct compress_context *compctx)
{
- if (lzowork)
- {
- ASSERT (lzowork->defined);
-#ifndef ENABLE_LZO_STUB
- lzo_free (lzowork->wmem);
- lzowork->wmem = NULL;
-#endif
- lzowork->defined = false;
- }
+ lzo_free (compctx->wu.lzo.wmem);
+ compctx->wu.lzo.wmem = NULL;
}
static inline bool
-lzo_compression_enabled (struct lzo_compress_workspace *lzowork)
+lzo_compression_enabled (struct compress_context *compctx)
{
-#ifndef ENABLE_LZO_STUB
- if ((lzowork->flags & (LZO_SELECTED|LZO_ON)) == (LZO_SELECTED|LZO_ON))
+ if (compctx->flags & COMP_F_ASYM)
+ return false;
+ else
{
- if (lzowork->flags & LZO_ADAPTIVE)
- return lzo_adaptive_compress_test (&lzowork->ac);
+ if (compctx->flags & COMP_F_ADAPTIVE)
+ return lzo_adaptive_compress_test (&compctx->wu.lzo.ac);
else
return true;
}
-#endif
- return false;
}
-void
+static void
lzo_compress (struct buffer *buf, struct buffer work,
- struct lzo_compress_workspace *lzowork,
+ struct compress_context *compctx,
const struct frame* frame)
{
-#ifndef ENABLE_LZO_STUB
lzo_uint zlen = 0;
int err;
bool compressed = false;
-#endif
-
- ASSERT (lzowork->defined);
if (buf->len <= 0)
return;
-#ifndef ENABLE_LZO_STUB
/*
* In order to attempt compression, length must be at least COMPRESS_THRESHOLD,
* and our adaptive level must give the OK.
*/
- if (buf->len >= COMPRESS_THRESHOLD && lzo_compression_enabled (lzowork))
+ if (buf->len >= COMPRESS_THRESHOLD && lzo_compression_enabled (compctx))
{
+ const size_t ps = PAYLOAD_SIZE (frame);
ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
- ASSERT (buf_safe (&work, LZO_EXTRA_BUFFER (PAYLOAD_SIZE (frame))));
+ ASSERT (buf_safe (&work, ps + COMP_EXTRA_BUFFER (ps)));
- if (!(buf->len <= PAYLOAD_SIZE (frame)))
+ if (buf->len > ps)
{
dmsg (D_COMP_ERRORS, "LZO compression buffer overflow");
buf->len = 0;
return;
}
- err = LZO_COMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen, lzowork->wmem);
+ err = LZO_COMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen, compctx->wu.lzo.wmem);
if (err != LZO_E_OK)
{
dmsg (D_COMP_ERRORS, "LZO compression error: %d", err);
@@ -203,43 +173,38 @@ lzo_compress (struct buffer *buf, struct buffer work,
work.len = zlen;
compressed = true;
- dmsg (D_COMP, "compress %d -> %d", buf->len, work.len);
- lzowork->pre_compress += buf->len;
- lzowork->post_compress += work.len;
+ dmsg (D_COMP, "LZO compress %d -> %d", buf->len, work.len);
+ compctx->pre_compress += buf->len;
+ compctx->post_compress += work.len;
/* tell adaptive level about our success or lack thereof in getting any size reduction */
- if (lzowork->flags & LZO_ADAPTIVE)
- lzo_adaptive_compress_data (&lzowork->ac, buf->len, work.len);
+ if (compctx->flags & COMP_F_ADAPTIVE)
+ lzo_adaptive_compress_data (&compctx->wu.lzo.ac, buf->len, work.len);
}
/* did compression save us anything ? */
if (compressed && work.len < buf->len)
{
uint8_t *header = buf_prepend (&work, 1);
- *header = YES_COMPRESS;
+ *header = LZO_COMPRESS_BYTE;
*buf = work;
}
else
-#endif
{
uint8_t *header = buf_prepend (buf, 1);
- *header = NO_COMPRESS;
+ *header = NO_COMPRESS_BYTE;
}
}
-void
+static void
lzo_decompress (struct buffer *buf, struct buffer work,
- struct lzo_compress_workspace *lzowork,
+ struct compress_context *compctx,
const struct frame* frame)
{
-#ifndef ENABLE_LZO_STUB
lzo_uint zlen = EXPANDED_SIZE (frame);
int err;
-#endif
uint8_t c; /* flag indicating whether or not our peer compressed */
- ASSERT (lzowork->defined);
-
if (buf->len <= 0)
return;
@@ -248,12 +213,11 @@ lzo_decompress (struct buffer *buf, struct buffer work,
c = *BPTR (buf);
ASSERT (buf_advance (buf, 1));
- if (c == YES_COMPRESS) /* packet was compressed */
+ if (c == LZO_COMPRESS_BYTE) /* packet was compressed */
{
-#ifndef ENABLE_LZO_STUB
ASSERT (buf_safe (&work, zlen));
err = LZO_DECOMPRESS (BPTR (buf), BLEN (buf), BPTR (&work), &zlen,
- lzowork->wmem);
+ compctx->wu.lzo.wmem);
if (err != LZO_E_OK)
{
dmsg (D_COMP_ERRORS, "LZO decompression error: %d", err);
@@ -264,18 +228,13 @@ lzo_decompress (struct buffer *buf, struct buffer work,
ASSERT (buf_safe (&work, zlen));
work.len = zlen;
- dmsg (D_COMP, "decompress %d -> %d", buf->len, work.len);
- lzowork->pre_decompress += buf->len;
- lzowork->post_decompress += work.len;
+ dmsg (D_COMP, "LZO decompress %d -> %d", buf->len, work.len);
+ compctx->pre_decompress += buf->len;
+ compctx->post_decompress += work.len;
*buf = work;
-#else
- dmsg (D_COMP_ERRORS, "LZO decompression error: LZO capability not compiled");
- buf->len = 0;
- return;
-#endif
}
- else if (c == NO_COMPRESS) /* packet was not compressed */
+ else if (c == NO_COMPRESS_BYTE) /* packet was not compressed */
{
;
}
@@ -286,24 +245,13 @@ lzo_decompress (struct buffer *buf, struct buffer work,
}
}
-void
-lzo_modify_flags (struct lzo_compress_workspace *lzowork, unsigned int flags)
-{
- ASSERT (lzowork->defined);
- lzowork->flags = flags;
-}
-
-void lzo_print_stats (const struct lzo_compress_workspace *lzo_compwork, struct status_output *so)
-{
- ASSERT (lzo_compwork->defined);
-
-#ifndef ENABLE_LZO_STUB
- status_printf (so, "pre-compress bytes," counter_format, lzo_compwork->pre_compress);
- status_printf (so, "post-compress bytes," counter_format, lzo_compwork->post_compress);
- status_printf (so, "pre-decompress bytes," counter_format, lzo_compwork->pre_decompress);
- status_printf (so, "post-decompress bytes," counter_format, lzo_compwork->post_decompress);
-#endif
-}
+const struct compress_alg lzo_alg = {
+ "lzo",
+ lzo_compress_init,
+ lzo_compress_uninit,
+ lzo_compress,
+ lzo_decompress
+};
#else
static void dummy(void) {}
diff --git a/app/openvpn/src/openvpn/lzo.h b/app/openvpn/src/openvpn/lzo.h
index 472204d0..f33e587a 100644
--- a/app/openvpn/src/openvpn/lzo.h
+++ b/app/openvpn/src/openvpn/lzo.h
@@ -32,14 +32,13 @@
*/
-#ifdef ENABLE_LZO
+#if defined(ENABLE_LZO)
/**
* @addtogroup compression
* @{
*/
-#ifndef ENABLE_LZO_STUB
#if defined(HAVE_LZO_LZOUTIL_H)
#include "lzo/lzoutil.h"
#elif defined(HAVE_LZOUTIL_H)
@@ -50,28 +49,16 @@
#elif defined(HAVE_LZO1X_H)
#include "lzo1x.h"
#endif
-#endif
#include "buffer.h"
#include "mtu.h"
#include "common.h"
#include "status.h"
-/**************************************************************************/
-/** @name Bit-flags which control data channel packet compression *//******/
-/** @{ */
-#define LZO_SELECTED (1<<0) /**< Bit-flag indicating that compression
- * of data channel packets is enabled. */
-#define LZO_ON (1<<1) /**< Bit-flag indicating that compression
- * of data channel packets is active. */
-#define LZO_ADAPTIVE (1<<2) /**< Bit-flag indicating that adaptive
- * compression of data channel packets
- * has been selected. */
-/** @} name Bit-flags which control data channel packet compression *//****/
+extern const struct compress_alg lzo_alg;
/**************************************************************************/
/** @name LZO library interface defines *//** @{ *//***********************/
-#ifndef ENABLE_LZO_STUB
#define LZO_COMPRESS lzo1x_1_15_compress
/**< LZO library compression function.
*
@@ -93,36 +80,11 @@
* verify the integrity of incoming
* packets, you might want to consider
* using the non-safe version. */
-#endif /* ENABLE_LZO_STUB */
/** @} name LZO library interface *//**************************************/
/**************************************************************************/
-/** @name Miscellaneous compression defines *//** @{ *//*******************/
-#define LZO_EXTRA_BUFFER(len) ((len)/8 + 128 + 3)
- /**< LZO 2.0 worst-case size expansion. */
-#ifndef ENABLE_LZO_STUB
-#define COMPRESS_THRESHOLD 100 /**< Minimum packet size to attempt
- * compression. */
-#endif /* ENABLE_LZO_STUB */
-/** @} name Miscellaneous compression defines *//**************************/
-
-
-/**************************************************************************/
-/** @name Compression header defines *//** @{ *//**************************/
-#define LZO_PREFIX_LEN 1 /**< Length in bytes of prepended
- * compression header. */
-#define YES_COMPRESS 0x66 /**< Single-byte compression header
- * indicating this packet has been
- * compressed. */
-#define NO_COMPRESS 0xFA /**< Single-byte compression header
- * indicating this packet has not been
- * compressed. */
-/** @} name Compression header defines *//*********************************/
-
-/**************************************************************************/
/** @name Adaptive compression defines *//** @{ *//************************/
-#ifndef ENABLE_LZO_STUB
#define AC_SAMP_SEC 2 /**< Number of seconds in a sample period. */
#define AC_MIN_BYTES 1000 /**< Minimum number of bytes a sample
* period must contain for it to be
@@ -132,11 +94,8 @@
* turned off. */
#define AC_OFF_SEC 60 /**< Seconds to wait after compression has
* been turned off before retesting. */
-#endif /* ENABLE_LZO_STUB */
/** @} name Adaptive compression defines *//*******************************/
-#ifndef ENABLE_LZO_STUB
-
/**
* Adaptive compression state.
*/
@@ -147,8 +106,6 @@ struct lzo_adaptive_compress {
int n_comp;
};
-#endif /* ENABLE_LZO_STUB */
-
/**
* State for the compression and decompression routines.
@@ -162,186 +119,13 @@ struct lzo_adaptive_compress {
*/
struct lzo_compress_workspace
{
- bool defined;
- unsigned int flags;
-#ifndef ENABLE_LZO_STUB
lzo_voidp wmem;
int wmem_size;
struct lzo_adaptive_compress ac;
-
- /* statistics */
- counter_type pre_decompress;
- counter_type post_decompress;
- counter_type pre_compress;
- counter_type post_compress;
-#endif
};
-
-/**************************************************************************/
-/** @name Functions for initialization and cleanup *//** @{ *//************/
-
-/**
- * Adjust %frame parameters for data channel payload compression.
- *
- * Data channel packet compression requires a single-byte header to
- * indicate whether a packet has been compressed or not. The packet
- * handling buffers must also allow for worst-case payload compression
- * where the compressed content size is actually larger than the original
- * content size. This function adjusts the parameters of a given frame
- * structure to include the header and allow for worst-case compression
- * expansion.
- *
- * @param frame - The frame structure to adjust.
- */
-void lzo_adjust_frame_parameters(struct frame *frame);
-
-/**
- * Initialize a compression workspace structure.
- *
- * This function initializes the given workspace structure \a lzowork.
- * This includes allocating a work buffer for internal use and setting its
- * flags to the given value of \a flags.
- *
- * This function also initializes the lzo library.
- *
- * @param lzowork - A pointer to the workspace structure to
- * initialize.
- * @param flags - The initial flags to set in the workspace
- * structure.
- */
-void lzo_compress_init (struct lzo_compress_workspace *lzowork, unsigned int flags);
-
-/**
- * Cleanup a compression workspace structure.
- *
- * This function cleans up the given workspace structure \a lzowork. This
- * includes freeing the structure's internal work buffer.
- *
- * @param lzowork - A pointer to the workspace structure to clean up.
- */
-void lzo_compress_uninit (struct lzo_compress_workspace *lzowork);
-
-/**
- * Set a workspace structure's flags.
- *
- * @param lzowork - The workspace structure of which to modify the
- * flags.
- * @param flags - The new value to assign to the workspace
- * structure's flags.
- */
-void lzo_modify_flags (struct lzo_compress_workspace *lzowork, unsigned int flags);
-
-/** @} name Functions for initialization and cleanup *//*******************/
-
-
-/**************************************************************************/
-/** @name Function for packets to be sent to a remote OpenVPN peer *//*****/
-/** @{ */
-
-/**
- * Process an outgoing packet according to a VPN tunnel's settings.
- * @ingroup compression
- *
- * This function processes the packet contained in \a buf. Its behavior
- * depends on the settings contained within \a lzowork. If compression is
- * enabled and active, this function compresses the packet. After
- * compression, the size of the uncompressed and compressed packets are
- * compared, and the smallest is used.
- *
- * This function prepends a one-byte header indicating whether the packet
- * was or was not compressed, so as to let the peer know how to handle the
- * packet.
- *
- * If an error occurs during processing, an error message is logged and
- * the length of \a buf is set to zero.
- *
- * @param buf - A pointer to the buffer containing the outgoing
- * packet. This pointer will be modified to point
- * to the processed packet on return.
- * @param work - A preallocated working buffer.
- * @param lzowork - The compression workspace structure associated
- * with this VPN tunnel.
- * @param frame - The frame parameters of this tunnel.
- *
- * @return Void.\n On return, \a buf will point to a buffer containing
- * the processed, possibly compressed, packet data with a compression
- * header prepended.
- */
-void lzo_compress (struct buffer *buf, struct buffer work,
- struct lzo_compress_workspace *lzowork,
- const struct frame* frame);
-
-/** @} name Function for packets to be sent to a remote OpenVPN peer *//***/
-
-
-/**************************************************************************/
-/** @name Function for packets received from a remote OpenVPN peer *//*****/
-/** @{ */
-
-/**
- * Inspect an incoming packet and decompress if it is compressed.
- *
- * This function inspects the incoming packet contained in \a buf. If its
- * one-byte compression header indicates that it was compressed (i.e. \c
- * YES_COMPRESS), then it will be decompressed. If its header indicates
- * that it was not compressed (i.e. \c NO_COMPRESS), then the buffer is
- * not modified except for removing the compression header.
- *
- * If an error occurs during processing, for example if the compression
- * header has a value other than \c YES_COMPRESS or \c NO_COMPRESS, then
- * the error is logged and the length of \a buf is set to zero.
- *
- * @param buf - A pointer to the buffer containing the incoming
- * packet. This pointer will be modified to point
- * to the processed packet on return.
- * @param work - A preallocated working buffer.
- * @param lzowork - The compression workspace structure associated
- * with this VPN tunnel.
- * @param frame - The frame parameters of this tunnel.
- *
- * @return Void.\n On return, \a buf will point to a buffer containing
- * the uncompressed packet data and the one-byte compression header
- * will have been removed.
- */
-void lzo_decompress (struct buffer *buf, struct buffer work,
- struct lzo_compress_workspace *lzowork,
- const struct frame* frame);
-
-/** @} name Function for packets received from a remote OpenVPN peer *//***/
-
-
-/**************************************************************************/
-/** @name Utility functions *//** @{ *//***********************************/
-
-/**
- * Print statistics on compression and decompression performance.
- *
- * @param lzo_compwork - The workspace structure from which to get the
- * statistics.
- * @param so - The status output structure to which to write the
- * statistics.
- */
-void lzo_print_stats (const struct lzo_compress_workspace *lzo_compwork, struct status_output *so);
-
-/**
- * Check whether compression is enabled for a workspace structure.
- *
- * @param lzowork - The workspace structure to check.
- *
- * @return true if compression is enabled; false otherwise.
- */
-static inline bool
-lzo_defined (const struct lzo_compress_workspace *lzowork)
-{
- return lzowork->defined;
-}
-
-/** @} name Utility functions *//******************************************/
-
-
/** @} addtogroup compression */
-#endif /* ENABLE_LZO */
+#endif /* ENABLE_LZO && USE_COMP */
#endif
diff --git a/app/openvpn/src/openvpn/manage.c b/app/openvpn/src/openvpn/manage.c
index c4e834b2..e7a7fe85 100644
--- a/app/openvpn/src/openvpn/manage.c
+++ b/app/openvpn/src/openvpn/manage.c
@@ -1105,6 +1105,19 @@ man_remote (struct management *man, const char **p)
}
}
+#ifdef TARGET_ANDROID
+static void
+man_network_change (struct management *man)
+{
+ if (man->persist.callback.network_change)
+ {
+ int fd = (*man->persist.callback.network_change)(man->persist.callback.arg);
+ man->connection.fdtosend = fd;
+ msg (M_CLIENT, "PROTECTFD: fd '%d' sent to be protected", fd);
+ }
+}
+#endif
+
static void
man_dispatch_command (struct management *man, struct status_output *so, const char **p, const int nparms)
{
@@ -1148,6 +1161,12 @@ man_dispatch_command (struct management *man, struct status_output *so, const ch
if (man_need (man, p, 1, 0))
man_signal (man, p[1]);
}
+#ifdef TARGET_ANDROID
+ else if (streq (p[0], "network-change"))
+ {
+ man_network_change(man);
+ }
+#endif
else if (streq (p[0], "load-stats"))
{
man_load_stats (man);
@@ -1568,9 +1587,9 @@ man_listen (struct management *man)
else
#endif
{
- man->connection.sd_top = create_socket_tcp (AF_INET);
+ man->connection.sd_top = create_socket_tcp (man->settings.local);
socket_bind (man->connection.sd_top, man->settings.local,
- AF_INET, "MANAGEMENT");
+ man->settings.local->ai_family, "MANAGEMENT", false);
}
/*
@@ -1635,7 +1654,7 @@ man_connect (struct management *man)
else
#endif
{
- man->connection.sd_cli = create_socket_tcp (AF_INET);
+ man->connection.sd_cli = create_socket_tcp (man->settings.local);
status = openvpn_connect (man->connection.sd_cli,
man->settings.local->ai_addr,
5,
@@ -1781,77 +1800,118 @@ man_io_error (struct management *man, const char *prefix)
}
#ifdef TARGET_ANDROID
-static ssize_t write_fd (int fd, void *ptr, size_t nbytes, int flags, int sendfd)
-{
- struct msghdr msg;
- struct iovec iov[1];
-
- union {
- struct cmsghdr cm;
- char control[CMSG_SPACE(sizeof(int))];
- } control_un;
- struct cmsghdr *cmptr;
-
- msg.msg_control = control_un.control;
- msg.msg_controllen = sizeof(control_un.control);
-
- cmptr = CMSG_FIRSTHDR(&msg);
- cmptr->cmsg_len = CMSG_LEN(sizeof(int));
- cmptr->cmsg_level = SOL_SOCKET;
- cmptr->cmsg_type = SCM_RIGHTS;
- *((int *) CMSG_DATA(cmptr)) = sendfd;
-
- msg.msg_name = NULL;
- msg.msg_namelen = 0;
-
- iov[0].iov_base = ptr;
- iov[0].iov_len = nbytes;
- msg.msg_iov = iov;
- msg.msg_iovlen = 1;
-
- return (sendmsg(fd, &msg, flags));
-}
-
-static ssize_t read_fd(int fd, void *ptr, size_t nbytes, int flags, int *recvfd)
-{
- struct msghdr msghdr;
- struct iovec iov[1];
- ssize_t n;
-
- union {
- struct cmsghdr cm;
- char control[CMSG_SPACE(sizeof (int))];
- } control_un;
- struct cmsghdr *cmptr;
-
- msghdr.msg_control = control_un.control;
- msghdr.msg_controllen = sizeof(control_un.control);
-
- msghdr.msg_name = NULL;
- msghdr.msg_namelen = 0;
-
- iov[0].iov_base = ptr;
- iov[0].iov_len = nbytes;
- msghdr.msg_iov = iov;
- msghdr.msg_iovlen = 1;
-
- if ( (n = recvmsg(fd, &msghdr, flags)) <= 0)
- return (n);
-
- if ( (cmptr = CMSG_FIRSTHDR(&msghdr)) != NULL &&
- cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
- if (cmptr->cmsg_level != SOL_SOCKET)
- msg (M_ERR, "control level != SOL_SOCKET");
- if (cmptr->cmsg_type != SCM_RIGHTS)
- msg (M_ERR, "control type != SCM_RIGHTS");
- *recvfd = *((int *) CMSG_DATA(cmptr));
- } else
- *recvfd = -1; /* descriptor was not passed */
-
+static ssize_t man_send_with_fd (int fd, void *ptr, size_t nbytes, int flags, int sendfd)
+{
+ struct msghdr msg;
+ struct iovec iov[1];
+
+ union {
+ struct cmsghdr cm;
+ char control[CMSG_SPACE(sizeof(int))];
+ } control_un;
+ struct cmsghdr *cmptr;
+
+ msg.msg_control = control_un.control;
+ msg.msg_controllen = sizeof(control_un.control);
+
+ cmptr = CMSG_FIRSTHDR(&msg);
+ cmptr->cmsg_len = CMSG_LEN(sizeof(int));
+ cmptr->cmsg_level = SOL_SOCKET;
+ cmptr->cmsg_type = SCM_RIGHTS;
+ *((int *) CMSG_DATA(cmptr)) = sendfd;
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ iov[0].iov_base = ptr;
+ iov[0].iov_len = nbytes;
+ msg.msg_iov = iov;
+ msg.msg_iovlen = 1;
+
+ return (sendmsg(fd, &msg, flags));
+}
+
+static ssize_t man_recv_with_fd (int fd, void *ptr, size_t nbytes, int flags, int *recvfd)
+{
+ struct msghdr msghdr;
+ struct iovec iov[1];
+ ssize_t n;
+
+ union {
+ struct cmsghdr cm;
+ char control[CMSG_SPACE(sizeof (int))];
+ } control_un;
+ struct cmsghdr *cmptr;
+
+ msghdr.msg_control = control_un.control;
+ msghdr.msg_controllen = sizeof(control_un.control);
+
+ msghdr.msg_name = NULL;
+ msghdr.msg_namelen = 0;
+
+ iov[0].iov_base = ptr;
+ iov[0].iov_len = nbytes;
+ msghdr.msg_iov = iov;
+ msghdr.msg_iovlen = 1;
+
+ if ( (n = recvmsg(fd, &msghdr, flags)) <= 0)
return (n);
+
+ if ( (cmptr = CMSG_FIRSTHDR(&msghdr)) != NULL &&
+ cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
+ if (cmptr->cmsg_level != SOL_SOCKET)
+ msg (M_ERR, "control level != SOL_SOCKET");
+ if (cmptr->cmsg_type != SCM_RIGHTS)
+ msg (M_ERR, "control type != SCM_RIGHTS");
+ *recvfd = *((int *) CMSG_DATA(cmptr));
+ } else
+ *recvfd = -1; /* descriptor was not passed */
+
+ return (n);
+}
+
+/*
+ * The android control method will instruct the GUI part of openvpn to do
+ * the route/ifconfig/open tun command. See doc/android.txt for details.
+ */
+bool management_android_control (struct management *man, const char *command, const char *msg)
+{
+ struct user_pass up;
+ CLEAR(up);
+ strncpy (up.username, msg, sizeof(up.username)-1);
+
+ management_query_user_pass(management, &up , command, GET_USER_PASS_NEED_OK,(void*) 0);
+ return strcmp ("ok", up.password)==0;
}
-#endif
+/*
+ * In Android 4.4 it is not possible to open a new tun device and then close the
+ * old tun device without breaking the whole VPNService stack until the device
+ * is rebooted. This management method ask the UI what method should be taken to
+ * ensure the optimal solution for the situation
+ */
+int managment_android_persisttun_action (struct management *man)
+{
+ struct user_pass up;
+ CLEAR(up);
+ strcpy(up.username,"tunmethod");
+ management_query_user_pass(management, &up , "PERSIST_TUN_ACTION",
+ GET_USER_PASS_NEED_OK,(void*) 0);
+ if (!strcmp("NOACTION", up.password))
+ return ANDROID_KEEP_OLD_TUN;
+ else if (!strcmp ("OPEN_AFTER_CLOSE", up.password))
+ return ANDROID_OPEN_AFTER_CLOSE;
+ else if (!strcmp ("OPEN_BEFORE_CLOSE", up.password))
+ return ANDROID_OPEN_BEFORE_CLOSE;
+ else
+ msg (M_ERR, "Got unrecognised '%s' from management for PERSIST_TUN_ACTION query", up.password);
+
+ ASSERT(0);
+ return ANDROID_OPEN_AFTER_CLOSE;
+}
+
+
+#endif
static int
man_read (struct management *man)
@@ -1864,8 +1924,8 @@ man_read (struct management *man)
#ifdef TARGET_ANDROID
int fd;
- len = read_fd (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL, &fd);
- if(fd >= 0)
+ len = man_recv_with_fd (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL, &fd);
+ if(fd >= 0)
man->connection.lastfdreceived = fd;
#else
len = recv (man->connection.sd_cli, buf, sizeof (buf), MSG_NOSIGNAL);
@@ -1948,9 +2008,9 @@ man_write (struct management *man)
{
const int len = min_int (size_hint, BLEN (buf));
#ifdef TARGET_ANDROID
- if (man->connection.fdtosend > 0)
+ if (man->connection.fdtosend > 0)
{
- sent = write_fd (man->connection.sd_cli, BPTR (buf), len, MSG_NOSIGNAL,man->connection.fdtosend);
+ sent = man_send_with_fd (man->connection.sd_cli, BPTR (buf), len, MSG_NOSIGNAL,man->connection.fdtosend);
man->connection.fdtosend = -1;
} else
#endif
@@ -2110,8 +2170,14 @@ man_settings_init (struct man_settings *ms,
}
else
{
- int status = openvpn_getaddrinfo(GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL,
- addr, port, 0, NULL, AF_INET, &ms->local);
+ int status;
+ int resolve_flags = GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL;
+
+ if (! (flags & MF_CONNECT_AS_CLIENT))
+ resolve_flags |= GETADDR_PASSIVE;
+
+ status = openvpn_getaddrinfo (resolve_flags, addr, port, 0,
+ NULL, AF_UNSPEC, &ms->local);
ASSERT(status==0);
}
}
@@ -2138,6 +2204,8 @@ man_settings_init (struct man_settings *ms,
static void
man_settings_close (struct man_settings *ms)
{
+ if (ms->local)
+ freeaddrinfo(ms->local);
free (ms->write_peer_info_file);
CLEAR (*ms);
}
@@ -2445,33 +2513,6 @@ management_notify_generic (struct management *man, const char *str)
#ifdef MANAGEMENT_DEF_AUTH
-static bool
-validate_peer_info_line(const char *line)
-{
- uint8_t c;
- int state = 0;
- while ((c=*line++))
- {
- switch (state)
- {
- case 0:
- case 1:
- if (c == '=' && state == 1)
- state = 2;
- else if (isalnum(c) || c == '_')
- state = 1;
- else
- return false;
- case 2:
- if (isprint(c))
- ;
- else
- return false;
- }
- }
- return (state == 2);
-}
-
static void
man_output_peer_info_env (struct management *man, struct man_def_auth_context *mdac)
{
@@ -2510,7 +2551,8 @@ management_notify_client_needing_auth (struct management *management,
mode = "REAUTH";
msg (M_CLIENT, ">CLIENT:%s,%lu,%u", mode, mdac->cid, mda_key_id);
man_output_extra_env (management, "CLIENT");
- man_output_peer_info_env(management, mdac);
+ if (management->connection.env_filter_level>0)
+ man_output_peer_info_env(management, mdac);
man_output_env (es, true, management->connection.env_filter_level, "CLIENT");
mdac->flags |= DAF_INITIAL_AUTH;
}
@@ -2599,9 +2641,9 @@ management_post_tunnel_open (struct management *man, const in_addr_t tun_local_i
/* listen on our local TUN/TAP IP address */
struct in_addr ia;
int ret;
-
+
ia.s_addr = htonl(tun_local_ip);
- ret = openvpn_getaddrinfo(0, inet_ntoa(ia), NULL, 0, NULL,
+ ret = openvpn_getaddrinfo(GETADDR_PASSIVE, inet_ntoa(ia), NULL, 0, NULL,
AF_INET, &man->settings.local);
ASSERT (ret==0);
man_connection_init (man);
diff --git a/app/openvpn/src/openvpn/manage.h b/app/openvpn/src/openvpn/manage.h
index d2790dd4..c48875c7 100644
--- a/app/openvpn/src/openvpn/manage.h
+++ b/app/openvpn/src/openvpn/manage.h
@@ -173,6 +173,9 @@ struct management_callback
#endif
bool (*proxy_cmd) (void *arg, const char **p);
bool (*remote_cmd) (void *arg, const char **p);
+#ifdef TARGET_ANDROID
+ int (*network_change) (void *arg);
+#endif
};
/*
@@ -300,8 +303,8 @@ struct man_connection {
struct buffer_list *rsa_sig;
#endif
#ifdef TARGET_ANDROID
- int fdtosend;
- int lastfdreceived;
+ int fdtosend;
+ int lastfdreceived;
#endif
};
@@ -376,6 +379,15 @@ bool management_query_user_pass (struct management *man,
const unsigned int flags,
const char *static_challenge);
+#ifdef TARGET_ANDROID
+bool management_android_control (struct management *man, const char *command, const char *msg);
+
+#define ANDROID_KEEP_OLD_TUN 1
+#define ANDROID_OPEN_AFTER_CLOSE 2
+#define ANDROID_OPEN_BEFORE_CLOSE 3
+int managment_android_persisttun_action (struct management *man);
+#endif
+
bool management_should_daemonize (struct management *man);
bool management_would_hold (struct management *man);
bool management_hold (struct management *man);
diff --git a/app/openvpn/src/openvpn/mbuf.h b/app/openvpn/src/openvpn/mbuf.h
index a0de679d..1085adc7 100644
--- a/app/openvpn/src/openvpn/mbuf.h
+++ b/app/openvpn/src/openvpn/mbuf.h
@@ -83,7 +83,7 @@ mbuf_defined (const struct mbuf_set *ms)
return ms && ms->len;
}
-static inline bool
+static inline unsigned int
mbuf_len (const struct mbuf_set *ms)
{
return ms->len;
diff --git a/app/openvpn/src/openvpn/misc.c b/app/openvpn/src/openvpn/misc.c
index fcc85526..7483184f 100644
--- a/app/openvpn/src/openvpn/misc.c
+++ b/app/openvpn/src/openvpn/misc.c
@@ -701,21 +701,6 @@ env_set_remove_from_environment (const struct env_set *es)
}
}
-#ifdef HAVE_PUTENV
-
-/* companion functions to putenv */
-
-static struct env_item *global_env = NULL; /* GLOBAL */
-
-void
-manage_env (char *str)
-{
- remove_env_item (str, true, &global_env);
- add_env_item (str, false, &global_env, NULL);
-}
-
-#endif
-
/* add/modify/delete environmental strings */
void
@@ -789,27 +774,18 @@ setenv_str_ex (struct env_set *es,
if (value)
val_tmp = string_mod_const (value, value_include, value_exclude, value_replace, &gc);
- if (es)
+ ASSERT (es);
+
+ if (val_tmp)
{
- if (val_tmp)
- {
- const char *str = construct_name_value (name_tmp, val_tmp, &gc);
- env_set_add (es, str);
+ const char *str = construct_name_value (name_tmp, val_tmp, &gc);
+ env_set_add (es, str);
#if DEBUG_VERBOSE_SETENV
- msg (M_INFO, "SETENV_ES '%s'", str);
+ msg (M_INFO, "SETENV_ES '%s'", str);
#endif
- }
- else
- env_set_del (es, name_tmp);
}
else
- {
- char *str = construct_name_value (name_tmp, val_tmp, NULL);
- if (platform_putenv(str))
- {
- msg (M_WARN | M_ERRNO, "putenv('%s') failed", str);
- }
- }
+ env_set_del (es, name_tmp);
gc_free (&gc);
}
@@ -950,32 +926,23 @@ create_temp_file (const char *directory, const char *prefix, struct gc_arena *gc
}
/*
- * Add a random string to first DNS label of hostname to prevent DNS caching.
+ * Prepend a random string to hostname to prevent DNS caching.
* For example, foo.bar.gov would be modified to <random-chars>.foo.bar.gov.
- * Of course, this requires explicit support in the DNS server.
+ * Of course, this requires explicit support in the DNS server (wildcard).
*/
const char *
hostname_randomize(const char *hostname, struct gc_arena *gc)
{
# define n_rnd_bytes 6
- char *hst = string_alloc(hostname, gc);
- char *dot = strchr(hst, '.');
+ uint8_t rnd_bytes[n_rnd_bytes];
+ const char *rnd_str;
+ struct buffer hname = alloc_buf_gc (strlen(hostname)+sizeof(rnd_bytes)*2+4, gc);
- if (dot)
- {
- uint8_t rnd_bytes[n_rnd_bytes];
- const char *rnd_str;
- struct buffer hname = alloc_buf_gc (strlen(hostname)+sizeof(rnd_bytes)*2+4, gc);
-
- *dot++ = '\0';
- prng_bytes (rnd_bytes, sizeof (rnd_bytes));
- rnd_str = format_hex_ex (rnd_bytes, sizeof (rnd_bytes), 40, 0, NULL, gc);
- buf_printf(&hname, "%s-0x%s.%s", hst, rnd_str, dot);
- return BSTR(&hname);
- }
- else
- return hostname;
+ prng_bytes (rnd_bytes, sizeof (rnd_bytes));
+ rnd_str = format_hex_ex (rnd_bytes, sizeof (rnd_bytes), 40, 0, NULL, gc);
+ buf_printf(&hname, "%s.%s", rnd_str, hostname);
+ return BSTR(&hname);
# undef n_rnd_bytes
}
@@ -2087,3 +2054,59 @@ compat_flag (unsigned int flag)
return (compat_flags & (flag >> 1));
}
+
+#if P2MP_SERVER
+
+/* helper to parse peer_info received from multi client, validate
+ * (this is untrusted data) and put into environment
+ */
+bool
+validate_peer_info_line(char *line)
+{
+ uint8_t c;
+ int state = 0;
+ while (*line)
+ {
+ c = *line;
+ switch (state)
+ {
+ case 0:
+ case 1:
+ if (c == '=' && state == 1)
+ state = 2;
+ else if (isalnum(c) || c == '_')
+ state = 1;
+ else
+ return false;
+ case 2:
+ /* after the '=', replace non-printable or shell meta with '_' */
+ if (!isprint(c) || isspace(c) ||
+ c == '$' || c == '(' || c == '`' )
+ *line = '_';
+ }
+ line++;
+ }
+ return (state == 2);
+}
+
+void
+output_peer_info_env (struct env_set *es, const char * peer_info)
+{
+ char line[256];
+ struct buffer buf;
+ buf_set_read (&buf, (const uint8_t *) peer_info, strlen(peer_info));
+ while (buf_parse (&buf, '\n', line, sizeof (line)))
+ {
+ chomp (line);
+ if (validate_peer_info_line(line) &&
+ (strncmp(line, "IV_", 3) == 0 || strncmp(line, "UV_", 3) == 0) )
+ {
+ msg (M_INFO, "peer info: %s", line);
+ env_set_add(es, line);
+ }
+ else
+ msg (M_WARN, "validation failed on peer_info line received from client");
+ }
+}
+
+#endif /* P2MP_SERVER */
diff --git a/app/openvpn/src/openvpn/misc.h b/app/openvpn/src/openvpn/misc.h
index 183898e3..41748bd8 100644
--- a/app/openvpn/src/openvpn/misc.h
+++ b/app/openvpn/src/openvpn/misc.h
@@ -369,4 +369,11 @@ void argv_printf_cat (struct argv *a, const char *format, ...)
#define COMPAT_NO_NAME_REMAPPING (1<<2) /** compat flag: --compat-names without char remapping */
bool compat_flag (unsigned int flag);
+#if P2MP_SERVER
+/* helper to parse peer_info received from multi client, validate
+ * (this is untrusted data) and put into environment */
+bool validate_peer_info_line(char *line);
+void output_peer_info_env (struct env_set *es, const char * peer_info);
+#endif /* P2MP_SERVER */
+
#endif
diff --git a/app/openvpn/src/openvpn/mroute.c b/app/openvpn/src/openvpn/mroute.c
index 850e3363..ba4ef46f 100644
--- a/app/openvpn/src/openvpn/mroute.c
+++ b/app/openvpn/src/openvpn/mroute.c
@@ -487,62 +487,28 @@ mroute_helper_regenerate (struct mroute_helper *mh)
}
void
-mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir)
+mroute_helper_add_iroute46 (struct mroute_helper *mh, int netbits)
{
- if (ir->netbits >= 0)
+ if (netbits >= 0)
{
- ASSERT (ir->netbits < MR_HELPER_NET_LEN);
+ ASSERT (netbits < MR_HELPER_NET_LEN);
++mh->cache_generation;
- ++mh->net_len_refcount[ir->netbits];
- if (mh->net_len_refcount[ir->netbits] == 1)
+ ++mh->net_len_refcount[netbits];
+ if (mh->net_len_refcount[netbits] == 1)
mroute_helper_regenerate (mh);
}
}
void
-mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir)
+mroute_helper_del_iroute46 (struct mroute_helper *mh, int netbits)
{
- if (ir->netbits >= 0)
+ if (netbits >= 0)
{
- ASSERT (ir->netbits < MR_HELPER_NET_LEN);
+ ASSERT (netbits < MR_HELPER_NET_LEN);
++mh->cache_generation;
- --mh->net_len_refcount[ir->netbits];
- ASSERT (mh->net_len_refcount[ir->netbits] >= 0);
- if (!mh->net_len_refcount[ir->netbits])
- mroute_helper_regenerate (mh);
- }
-}
-
-/* this is a bit inelegant, we really should have a helper to that
- * is only passed the netbits value, and not the whole struct iroute *
- * - thus one helper could do IPv4 and IPv6. For the sake of "not change
- * code unrelated to IPv4" this is left for later cleanup, for now.
- */
-void
-mroute_helper_add_iroute6 (struct mroute_helper *mh,
- const struct iroute_ipv6 *ir6)
-{
- if (ir6->netbits >= 0)
- {
- ASSERT (ir6->netbits < MR_HELPER_NET_LEN);
- ++mh->cache_generation;
- ++mh->net_len_refcount[ir6->netbits];
- if (mh->net_len_refcount[ir6->netbits] == 1)
- mroute_helper_regenerate (mh);
- }
-}
-
-void
-mroute_helper_del_iroute6 (struct mroute_helper *mh,
- const struct iroute_ipv6 *ir6)
-{
- if (ir6->netbits >= 0)
- {
- ASSERT (ir6->netbits < MR_HELPER_NET_LEN);
- ++mh->cache_generation;
- --mh->net_len_refcount[ir6->netbits];
- ASSERT (mh->net_len_refcount[ir6->netbits] >= 0);
- if (!mh->net_len_refcount[ir6->netbits])
+ --mh->net_len_refcount[netbits];
+ ASSERT (mh->net_len_refcount[netbits] >= 0);
+ if (!mh->net_len_refcount[netbits])
mroute_helper_regenerate (mh);
}
}
diff --git a/app/openvpn/src/openvpn/mroute.h b/app/openvpn/src/openvpn/mroute.h
index b72b5ffc..608f70be 100644
--- a/app/openvpn/src/openvpn/mroute.h
+++ b/app/openvpn/src/openvpn/mroute.h
@@ -125,10 +125,8 @@ void mroute_addr_mask_host_bits (struct mroute_addr *ma);
struct mroute_helper *mroute_helper_init (int ageable_ttl_secs);
void mroute_helper_free (struct mroute_helper *mh);
-void mroute_helper_add_iroute (struct mroute_helper *mh, const struct iroute *ir);
-void mroute_helper_del_iroute (struct mroute_helper *mh, const struct iroute *ir);
-void mroute_helper_add_iroute6 (struct mroute_helper *mh, const struct iroute_ipv6 *ir6);
-void mroute_helper_del_iroute6 (struct mroute_helper *mh, const struct iroute_ipv6 *ir6);
+void mroute_helper_add_iroute46 (struct mroute_helper *mh, int netbits);
+void mroute_helper_del_iroute46 (struct mroute_helper *mh, int netbits);
/*
* Given a raw packet in buf, return the src and dest
diff --git a/app/openvpn/src/openvpn/multi.c b/app/openvpn/src/openvpn/multi.c
index ab3f10cb..16250dc2 100644
--- a/app/openvpn/src/openvpn/multi.c
+++ b/app/openvpn/src/openvpn/multi.c
@@ -38,6 +38,7 @@
#include "otime.h"
#include "gremlin.h"
#include "mstats.h"
+#include "ssl_verify.h"
#include "memdbg.h"
@@ -450,10 +451,10 @@ multi_del_iroutes (struct multi_context *m,
if (TUNNEL_TYPE (mi->context.c1.tuntap) == DEV_TYPE_TUN)
{
for (ir = mi->context.options.iroutes; ir != NULL; ir = ir->next)
- mroute_helper_del_iroute (m->route_helper, ir);
+ mroute_helper_del_iroute46 (m->route_helper, ir->netbits);
for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next )
- mroute_helper_del_iroute6 (m->route_helper, ir6);
+ mroute_helper_del_iroute46 (m->route_helper, ir6->netbits);
}
}
@@ -807,8 +808,8 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
*/
status_printf (so, "TITLE%c%s", sep, title_string);
status_printf (so, "TIME%c%s%c%u", sep, time_string (now, 0, false, &gc_top), sep, (unsigned int)now);
- status_printf (so, "HEADER%cCLIENT_LIST%cCommon Name%cReal Address%cVirtual Address%cBytes Received%cBytes Sent%cConnected Since%cConnected Since (time_t)%cUsername",
- sep, sep, sep, sep, sep, sep, sep, sep, sep);
+ status_printf (so, "HEADER%cCLIENT_LIST%cCommon Name%cReal Address%cVirtual Address%cVirtual IPv6 Address%cBytes Received%cBytes Sent%cConnected Since%cConnected Since (time_t)%cUsername%cClient ID",
+ sep, sep, sep, sep, sep, sep, sep, sep, sep, sep, sep);
hash_iterator_init (m->hash, &hi);
while ((he = hash_iterator_next (&hi)))
{
@@ -817,15 +818,26 @@ multi_print_status (struct multi_context *m, struct status_output *so, const int
if (!mi->halt)
{
- status_printf (so, "CLIENT_LIST%c%s%c%s%c%s%c" counter_format "%c" counter_format "%c%s%c%u%c%s",
+ status_printf (so, "CLIENT_LIST%c%s%c%s%c%s%c%s%c" counter_format "%c" counter_format "%c%s%c%u%c%s%c"
+#ifdef MANAGEMENT_DEF_AUTH
+ "%lu",
+#else
+ "",
+#endif
sep, tls_common_name (mi->context.c2.tls_multi, false),
sep, mroute_addr_print (&mi->real, &gc),
sep, print_in_addr_t (mi->reporting_addr, IA_EMPTY_IF_UNDEF, &gc),
+ sep, print_in6_addr (mi->reporting_addr_ipv6, IA_EMPTY_IF_UNDEF, &gc),
sep, mi->context.c2.link_read_bytes,
sep, mi->context.c2.link_write_bytes,
sep, time_string (mi->created, 0, false, &gc),
sep, (unsigned int)mi->created,
- sep, tls_username (mi->context.c2.tls_multi, false));
+ sep, tls_username (mi->context.c2.tls_multi, false),
+#ifdef MANAGEMENT_DEF_AUTH
+ sep, mi->context.c2.mda_context.cid);
+#else
+ sep);
+#endif
}
gc_free (&gc);
}
@@ -1158,23 +1170,18 @@ multi_add_iroutes (struct multi_context *m,
print_in_addr_t (ir->network, 0, &gc),
multi_instance_string (mi, false, &gc));
- mroute_helper_add_iroute (m->route_helper, ir);
+ mroute_helper_add_iroute46 (m->route_helper, ir->netbits);
multi_learn_in_addr_t (m, mi, ir->network, ir->netbits, false);
}
for ( ir6 = mi->context.options.iroutes_ipv6; ir6 != NULL; ir6 = ir6->next )
{
- if (ir6->netbits >= 0)
- msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s",
+ msg (D_MULTI_LOW, "MULTI: internal route %s/%d -> %s",
print_in6_addr (ir6->network, 0, &gc),
ir6->netbits,
multi_instance_string (mi, false, &gc));
- else
- msg (D_MULTI_LOW, "MULTI: internal route %s -> %s",
- print_in6_addr (ir6->network, 0, &gc),
- multi_instance_string (mi, false, &gc));
- mroute_helper_add_iroute6 (m->route_helper, ir6);
+ mroute_helper_add_iroute46 (m->route_helper, ir6->netbits);
multi_learn_in6_addr (m, mi, ir6->network, ir6->netbits, false);
}
@@ -1289,9 +1296,7 @@ multi_select_virtual_addr (struct multi_context *m, struct multi_instance *mi)
mi->context.c2.push_ifconfig_defined = true;
mi->context.c2.push_ifconfig_local = mi->context.options.push_ifconfig_local;
mi->context.c2.push_ifconfig_remote_netmask = mi->context.options.push_ifconfig_remote_netmask;
-#ifdef ENABLE_CLIENT_NAT
mi->context.c2.push_ifconfig_local_alias = mi->context.options.push_ifconfig_local_alias;
-#endif
/* the current implementation does not allow "static IPv4, pool IPv6",
* (see below) so issue a warning if that happens - don't break the
@@ -1847,6 +1852,7 @@ multi_connection_established (struct multi_context *m, struct multi_instance *mi
/* set our client's VPN endpoint for status reporting purposes */
mi->reporting_addr = mi->context.c2.push_ifconfig_local;
+ mi->reporting_addr_ipv6 = mi->context.c2.push_ifconfig_ipv6_local;
/* set context-level authentication flag */
mi->context.c2.context_auth = CAS_SUCCEEDED;
diff --git a/app/openvpn/src/openvpn/multi.h b/app/openvpn/src/openvpn/multi.h
index 2bc0c8a1..fc2ffb24 100644
--- a/app/openvpn/src/openvpn/multi.h
+++ b/app/openvpn/src/openvpn/multi.h
@@ -88,6 +88,7 @@ struct multi_instance {
bool socket_set_called;
in_addr_t reporting_addr; /* IP address shown in status listing */
+ struct in6_addr reporting_addr_ipv6; /* IPv6 address in status listing */
bool did_open_context;
bool did_real_hash;
diff --git a/app/openvpn/src/openvpn/openvpn.c b/app/openvpn/src/openvpn/openvpn.c
index a177d9e8..94d0167e 100644
--- a/app/openvpn/src/openvpn/openvpn.c
+++ b/app/openvpn/src/openvpn/openvpn.c
@@ -175,7 +175,7 @@ openvpn_main (int argc, char *argv[])
gc_init (&c.gc);
/* initialize environmental variable store */
- c.es = env_set_create (&c.gc);
+ c.es = env_set_create (NULL);
#ifdef WIN32
set_win_sys_path_via_env (c.es);
#endif
@@ -224,6 +224,7 @@ openvpn_main (int argc, char *argv[])
/* print version number */
msg (M_INFO, "%s", title_string);
+ show_library_versions(M_INFO);
/* misc stuff */
pre_setup (&c.options);
diff --git a/app/openvpn/src/openvpn/openvpn.h b/app/openvpn/src/openvpn/openvpn.h
index bdfa6852..eab8cd5b 100644
--- a/app/openvpn/src/openvpn/openvpn.h
+++ b/app/openvpn/src/openvpn/openvpn.h
@@ -31,7 +31,7 @@
#include "crypto.h"
#include "ssl.h"
#include "packet_id.h"
-#include "lzo.h"
+#include "comp.h"
#include "tun.h"
#include "interval.h"
#include "status.h"
@@ -104,10 +104,10 @@ struct context_buffers
struct buffer decrypt_buf;
#endif
- /* workspace buffers for LZO compression */
-#ifdef ENABLE_LZO
- struct buffer lzo_compress_buf;
- struct buffer lzo_decompress_buf;
+ /* workspace buffers for compression */
+#ifdef USE_COMP
+ struct buffer compress_buf;
+ struct buffer decompress_buf;
#endif
/*
@@ -166,6 +166,9 @@ struct context_1
/* tunnel session keys */
struct key_schedule ks;
+ /* preresolved and cached host names */
+ struct cached_dns_entry *dns_cache;
+
/* persist crypto sequence number to/from file */
struct packet_id_persist pid_persist;
@@ -185,17 +188,13 @@ struct context_1
struct status_output *status_output;
bool status_output_owned;
-#ifdef ENABLE_HTTP_PROXY
/* HTTP proxy object */
struct http_proxy_info *http_proxy;
bool http_proxy_owned;
-#endif
-#ifdef ENABLE_SOCKS
/* SOCKS proxy object */
struct socks_proxy_info *socks_proxy;
bool socks_proxy_owned;
-#endif
#if P2MP
@@ -372,9 +371,9 @@ struct context_2
#endif /* ENABLE_CRYPTO */
-#ifdef ENABLE_LZO
- struct lzo_compress_workspace lzo_compwork;
- /**< Compression workspace used by the
+#ifdef USE_COMP
+ struct compress_context *comp_context;
+ /**< Compression context used by the
* \link compression Data Channel
* Compression module\endlink. */
#endif
@@ -451,9 +450,7 @@ struct context_2
time_t sent_push_reply_expiry;
in_addr_t push_ifconfig_local;
in_addr_t push_ifconfig_remote_netmask;
-#ifdef ENABLE_CLIENT_NAT
in_addr_t push_ifconfig_local_alias;
-#endif
bool push_ifconfig_ipv6_defined;
struct in6_addr push_ifconfig_ipv6_local;
diff --git a/app/openvpn/src/openvpn/options.c b/app/openvpn/src/openvpn/options.c
index 64c81cf2..fc764616 100644
--- a/app/openvpn/src/openvpn/options.c
+++ b/app/openvpn/src/openvpn/options.c
@@ -5,10 +5,8 @@
* packet encryption, packet authentication, and
* packet compression.
*
- * Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
- *
- * Additions for eurephia plugin done by:
- * David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2009
+ * Copyright (C) 2002-2013 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ * Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -58,12 +56,16 @@
#include "helper.h"
#include "manage.h"
#include "forward.h"
+#include "ssl_verify.h"
#include <ctype.h>
#include "memdbg.h"
const char title_string[] =
PACKAGE_STRING
+#ifdef CONFIGURE_GIT_REVISION
+ " [git:" CONFIGURE_GIT_REVISION CONFIGURE_GIT_FLAGS "]"
+#endif
" " TARGET_ALIAS
#ifdef ENABLE_CRYPTO
#ifdef ENABLE_SSL
@@ -84,13 +86,20 @@ const char title_string[] =
#endif /* defined(ENABLE_CRYPTO_POLARSSL) */
#endif /* ENABLE_SSL */
#endif /* ENABLE_CRYPTO */
+#ifdef USE_COMP
#ifdef ENABLE_LZO
-#ifdef ENABLE_LZO_STUB
- " [LZO (STUB)]"
-#else
" [LZO]"
#endif
+#ifdef ENABLE_SNAPPY
+ " [SNAPPY]"
+#endif
+#ifdef ENABLE_LZ4
+ " [LZ4]"
#endif
+#ifdef ENABLE_COMP_STUB
+ " [COMP_STUB]"
+#endif
+#endif /* USE_COMP */
#if EPOLL
" [EPOLL]"
#endif
@@ -100,9 +109,6 @@ const char title_string[] =
#ifdef ENABLE_PKCS11
" [PKCS11]"
#endif
-#ifdef ENABLE_EUREPHIA
- " [eurephia]"
-#endif
#if ENABLE_IP_PKTINFO
" [MH]"
#endif
@@ -134,7 +140,6 @@ static const char usage_message[] =
" between connection retries (default=%d).\n"
"--connect-timeout n : For --proto tcp-client, connection timeout (in seconds).\n"
"--connect-retry-max n : Maximum connection attempt retries, default infinite.\n"
-#ifdef ENABLE_HTTP_PROXY
"--http-proxy s p [up] [auth] : Connect to remote host\n"
" through an HTTP proxy at address s and port p.\n"
" If proxy authentication is required,\n"
@@ -150,15 +155,12 @@ static const char usage_message[] =
" Repeat to set multiple options.\n"
" VERSION version (default=1.0)\n"
" AGENT user-agent\n"
-#endif
-#ifdef ENABLE_SOCKS
"--socks-proxy s [p] [up] : Connect to remote host through a Socks5 proxy at\n"
" address s and port p (default port = 1080).\n"
" If proxy authentication is required,\n"
" up is a file containing username/password on 2 lines, or\n"
" 'stdin' to prompt for console.\n"
"--socks-proxy-retry : Retry indefinitely on Socks proxy errors.\n"
-#endif
"--resolv-retry n: If hostname resolve fails for --remote, retry\n"
" resolve for n seconds before failing (disabled by default).\n"
" Set n=\"infinite\" to retry indefinitely.\n"
@@ -171,12 +173,8 @@ static const char usage_message[] =
"--rport port : TCP/UDP port # for remote (default=%s).\n"
"--bind : Bind to local address and port. (This is the default unless\n"
" --proto tcp-client"
-#ifdef ENABLE_HTTP_PROXY
" or --http-proxy"
-#endif
-#ifdef ENABLE_SOCKS
" or --socks-proxy"
-#endif
" is used).\n"
"--nobind : Do not bind to local address and port.\n"
"--dev tunX|tapX : tun/tap device (X can be omitted for dynamic device.\n"
@@ -212,9 +210,7 @@ static const char usage_message[] =
"--route-ipv6 network/bits [gateway] [metric] :\n"
" Add IPv6 route to routing table after connection\n"
" is established. Multiple routes can be specified.\n"
- " gateway default: taken from --route-ipv6-gateway or --ifconfig\n"
- "--max-routes n : Specify the maximum number of routes that may be defined\n"
- " or pulled from a server.\n"
+ " gateway default: taken from 'remote' in --ifconfig-ipv6\n"
"--route-gateway gw|'dhcp' : Specify a default gateway for use with --route.\n"
"--route-metric m : Specify a default metric for use with --route.\n"
"--route-delay n [w] : Delay n seconds after connection initiation before\n"
@@ -239,15 +235,15 @@ static const char usage_message[] =
" Add 'bypass-dns' flag to similarly bypass tunnel for DNS.\n"
"--redirect-private [flags]: Like --redirect-gateway, but omit actually changing\n"
" the default gateway. Useful when pushing private subnets.\n"
-#ifdef ENABLE_CLIENT_NAT
"--client-nat snat|dnat network netmask alias : on client add 1-to-1 NAT rule.\n"
-#endif
#ifdef ENABLE_PUSH_PEER_INFO
"--push-peer-info : (client only) push client info to server.\n"
#endif
"--setenv name value : Set a custom environmental variable to pass to script.\n"
"--setenv FORWARD_COMPATIBLE 1 : Relax config file syntax checking to allow\n"
" directives for future OpenVPN versions to be ignored.\n"
+ "--ignore-unkown-option opt1 opt2 ...: Relax config file syntax. Allow\n"
+ " these options to be ignored when unknown\n"
"--script-security level: Where level can be:\n"
" 0 -- strictly no calling of external programs\n"
" 1 -- (default) only call built-ins such as ifconfig\n"
@@ -338,6 +334,7 @@ static const char usage_message[] =
"--log file : Output log to file which is created/truncated on open.\n"
"--log-append file : Append log to file, or create file if nonexistent.\n"
"--suppress-timestamps : Don't log timestamps to stdout/stderr.\n"
+ "--machine-readable-output : Always log timestamp, message flags to stdout/stderr.\n"
"--writepid file : Write main process ID to file.\n"
"--nice n : Change process priority (>0 = lower, <0 = higher).\n"
"--echo [parms ...] : Echo parameters to log output.\n"
@@ -362,12 +359,15 @@ static const char usage_message[] =
#ifdef ENABLE_DEBUG
"--gremlin mask : Special stress testing mode (for debugging only).\n"
#endif
-#ifdef ENABLE_LZO
- "--comp-lzo : Use fast LZO compression -- may add up to 1 byte per\n"
+#if defined(USE_COMP)
+ "--compress alg : Use compression algorithm alg\n"
+#if defined(ENABLE_LZO)
+ "--comp-lzo : Use LZO compression -- may add up to 1 byte per\n"
" packet for uncompressible data.\n"
"--comp-noadapt : Don't use adaptive compression when --comp-lzo\n"
" is specified.\n"
#endif
+#endif
#ifdef ENABLE_MANAGEMENT
"--management ip port [pass] : Enable a TCP server on ip:port to handle\n"
" management functions. pass is a password file\n"
@@ -558,12 +558,7 @@ static const char usage_message[] =
" root certificate.\n"
#ifndef ENABLE_CRYPTO_POLARSSL
"--capath dir : A directory of trusted certificates (CAs"
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L
" and CRLs).\n"
-#else /* OPENSSL_VERSION_NUMBER >= 0x00907000L */
- ").\n"
- " WARNING: no support of CRL available with this version.\n"
-#endif /* OPENSSL_VERSION_NUMBER >= 0x00907000L */
#endif /* ENABLE_CRYPTO_POLARSSL */
"--dh file : File containing Diffie Hellman parameters\n"
" in .pem format (for --tls-server only).\n"
@@ -572,6 +567,9 @@ static const char usage_message[] =
" by a Certificate Authority in --ca file.\n"
"--extra-certs file : one or more PEM certs that complete the cert chain.\n"
"--key file : Local private key in .pem format.\n"
+ "--tls-version-min <version> ['or-highest'] : sets the minimum TLS version we\n"
+ " will accept from the peer. If version is unrecognized and 'or-highest'\n"
+ " is specified, require max TLS version supported by SSL implementation.\n"
#ifndef ENABLE_CRYPTO_POLARSSL
"--pkcs12 file : PKCS#12 file containing local private key, local certificate\n"
" and optionally the root CA certificate.\n"
@@ -614,8 +612,8 @@ static const char usage_message[] =
"--tls-export-cert [directory] : Get peer cert in PEM format and store it \n"
" in an openvpn temporary file in [directory]. Peer cert is \n"
" stored before tls-verify script execution and deleted after.\n"
- "--tls-remote x509name: Accept connections only from a host with X509 name\n"
- " x509name. The remote host must also pass all other tests\n"
+ "--verify-x509-name name: Accept connections only from a host with X509 subject\n"
+ " DN name. The remote host must also pass all other tests\n"
" of verification.\n"
"--ns-cert-type t: Require that peer certificate was signed with an explicit\n"
" nsCertType designation t = 'client' | 'server'.\n"
@@ -623,7 +621,6 @@ static const char usage_message[] =
"--x509-track x : Save peer X509 attribute x in environment for use by\n"
" plugins and management interface.\n"
#endif
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L || ENABLE_CRYPTO_POLARSSL
"--remote-cert-ku v ... : Require that the peer certificate was signed with\n"
" explicit key usage, you can specify more than one value.\n"
" value should be given in hex format.\n"
@@ -633,7 +630,6 @@ static const char usage_message[] =
"--remote-cert-tls t: Require that peer certificate was signed with explicit\n"
" key usage and extended key usage based on RFC3280 TLS rules.\n"
" t = 'client' | 'server'.\n"
-#endif /* OPENSSL_VERSION_NUMBER || ENABLE_CRYPTO_POLARSSL */
#endif /* ENABLE_SSL */
#ifdef ENABLE_PKCS11
"\n"
@@ -769,6 +765,7 @@ init_options (struct options *o, const bool init_gc)
o->topology = TOP_NET30;
o->ce.proto = PROTO_UDP;
o->ce.af = AF_UNSPEC;
+ o->ce.bind_ipv6_only = false;
o->ce.connect_retry_seconds = 5;
o->ce.connect_timeout = 10;
o->connect_retry_max = 0;
@@ -782,8 +779,8 @@ init_options (struct options *o, const bool init_gc)
o->ce.mtu_discover_type = -1;
o->ce.mssfix = MSSFIX_DEFAULT;
o->route_delay_window = 30;
- o->max_routes = MAX_ROUTES_DEFAULT;
o->resolve_retry_seconds = RESOLV_RETRY_INFINITE;
+ o->resolve_in_advance = false;
o->proto_force = -1;
#ifdef ENABLE_OCC
o->occ = true;
@@ -848,6 +845,7 @@ init_options (struct options *o, const bool init_gc)
o->renegotiate_seconds = 3600;
o->handshake_window = 60;
o->transition_window = 3600;
+ o->ecdh_curve = NULL;
#ifdef ENABLE_X509ALTUSERNAME
o->x509_username_field = X509_USERNAME_FIELD_DEFAULT;
#endif
@@ -882,7 +880,7 @@ uninit_options (struct options *o)
}
}
-#ifdef ENABLE_DEBUG
+#ifndef ENABLE_SMALL
#define SHOW_PARM(name, value, format) msg(D_SHOW_PARMS, " " #name " = " format, (value))
#define SHOW_STR(var) SHOW_PARM(var, (o->var ? o->var : "[UNDEF]"), "'%s'")
@@ -904,20 +902,16 @@ setenv_connection_entry (struct env_set *es,
setenv_str_i (es, "remote", e->remote, i);
setenv_str_i (es, "remote_port", e->remote_port, i);
-#ifdef ENABLE_HTTP_PROXY
if (e->http_proxy_options)
{
setenv_str_i (es, "http_proxy_server", e->http_proxy_options->server, i);
setenv_str_i (es, "http_proxy_port", e->http_proxy_options->port, i);
}
-#endif
-#ifdef ENABLE_SOCKS
if (e->socks_proxy_server)
{
setenv_str_i (es, "socks_proxy_server", e->socks_proxy_server, i);
setenv_str_i (es, "socks_proxy_port", e->socks_proxy_port, i);
}
-#endif
}
void
@@ -1082,7 +1076,7 @@ parse_hash_fingerprint(const char *str, int nbytes, int msglevel, struct gc_aren
#ifdef WIN32
-#ifdef ENABLE_DEBUG
+#ifndef ENABLE_SMALL
static void
show_dhcp_option_addrs (const char *name, const in_addr_t *array, int len)
@@ -1125,7 +1119,7 @@ show_tuntap_options (const struct tuntap_options *o)
#endif
#endif
-#if defined(WIN32) || defined(TARGET_ANDROID)
+#if defined(WIN32) || defined(TARGET_ANDROID)
static void
dhcp_option_address_parse (const char *name, const char *parm, in_addr_t *array, int *len, int msglevel)
{
@@ -1156,7 +1150,7 @@ dhcp_option_address_parse (const char *name, const char *parm, in_addr_t *array,
#if P2MP
-#ifdef ENABLE_DEBUG
+#ifndef ENABLE_SMALL
static void
show_p2mp_parms (const struct options *o)
@@ -1228,7 +1222,7 @@ show_p2mp_parms (const struct options *o)
gc_free (&gc);
}
-#endif /* ENABLE_DEBUG */
+#endif /* ! ENABLE_SMALL */
#if P2MP_SERVER
@@ -1282,10 +1276,11 @@ option_iroute_ipv6 (struct options *o,
#endif /* P2MP_SERVER */
#endif /* P2MP */
-#if defined(ENABLE_HTTP_PROXY) && defined(ENABLE_DEBUG)
+#ifndef ENABLE_SMALL
static void
show_http_proxy_options (const struct http_proxy_options *o)
{
+ int i;
msg (D_SHOW_PARMS, "BEGIN http_proxy");
SHOW_STR (server);
SHOW_STR (port);
@@ -1295,6 +1290,15 @@ show_http_proxy_options (const struct http_proxy_options *o)
SHOW_INT (timeout);
SHOW_STR (http_version);
SHOW_STR (user_agent);
+ for (i=0; i < MAX_CUSTOM_HTTP_HEADER && o->custom_headers[i].name;i++)
+ {
+ if (o->custom_headers[i].content)
+ msg (D_SHOW_PARMS, " custom_header[%d] = %s: %s", i,
+ o->custom_headers[i].name, o->custom_headers[i].content);
+ else
+ msg (D_SHOW_PARMS, " custom_header[%d] = %s", i,
+ o->custom_headers[i].name);
+ }
msg (D_SHOW_PARMS, "END http_proxy");
}
#endif
@@ -1304,9 +1308,7 @@ options_detach (struct options *o)
{
gc_detach (&o->gc);
o->routes = NULL;
-#ifdef ENABLE_CLIENT_NAT
o->client_nat = NULL;
-#endif
#if P2MP_SERVER
clone_push_list(o);
#endif
@@ -1316,26 +1318,24 @@ void
rol_check_alloc (struct options *options)
{
if (!options->routes)
- options->routes = new_route_option_list (options->max_routes, &options->gc);
+ options->routes = new_route_option_list (&options->gc);
}
void
rol6_check_alloc (struct options *options)
{
if (!options->routes_ipv6)
- options->routes_ipv6 = new_route_ipv6_option_list (options->max_routes, &options->gc);
+ options->routes_ipv6 = new_route_ipv6_option_list (&options->gc);
}
-#ifdef ENABLE_CLIENT_NAT
static void
cnol_check_alloc (struct options *options)
{
if (!options->client_nat)
options->client_nat = new_client_nat_list (&options->gc);
}
-#endif
-#ifdef ENABLE_DEBUG
+#ifndef ENABLE_SMALL
static void
show_connection_entry (const struct connection_entry *o)
{
@@ -1347,18 +1347,15 @@ show_connection_entry (const struct connection_entry *o)
SHOW_BOOL (remote_float);
SHOW_BOOL (bind_defined);
SHOW_BOOL (bind_local);
+ SHOW_BOOL (bind_ipv6_only);
SHOW_INT (connect_retry_seconds);
SHOW_INT (connect_timeout);
-#ifdef ENABLE_HTTP_PROXY
if (o->http_proxy_options)
show_http_proxy_options (o->http_proxy_options);
-#endif
-#ifdef ENABLE_SOCKS
SHOW_STR (socks_proxy_server);
SHOW_STR (socks_proxy_port);
SHOW_BOOL (socks_proxy_retry);
-#endif
SHOW_INT (tun_mtu);
SHOW_BOOL (tun_mtu_defined);
SHOW_INT (link_mtu);
@@ -1382,8 +1379,6 @@ show_connection_entry (const struct connection_entry *o)
static void
show_connection_entries (const struct options *o)
{
- msg (D_SHOW_PARMS, "Connection profiles [default]:");
- show_connection_entry (&o->ce);
if (o->connection_list)
{
const struct connection_list *l = o->connection_list;
@@ -1394,6 +1389,11 @@ show_connection_entries (const struct options *o)
show_connection_entry (l->array[i]);
}
}
+ else
+ {
+ msg (D_SHOW_PARMS, "Connection profiles [default]:");
+ show_connection_entry (&o->ce);
+ }
msg (D_SHOW_PARMS, "Connection profiles END");
}
@@ -1402,7 +1402,7 @@ show_connection_entries (const struct options *o)
void
show_settings (const struct options *o)
{
-#ifdef ENABLE_DEBUG
+#ifndef ENABLE_SMALL
msg (D_SHOW_PARMS, "Current Parameter Settings:");
SHOW_STR (config);
@@ -1472,6 +1472,7 @@ show_settings (const struct options *o)
#endif
SHOW_INT (resolve_retry_seconds);
+ SHOW_BOOL (resolve_in_advance);
SHOW_STR (username);
SHOW_STR (groupname);
@@ -1490,6 +1491,7 @@ show_settings (const struct options *o)
SHOW_INT (inetd);
SHOW_BOOL (log);
SHOW_BOOL (suppress_timestamps);
+ SHOW_BOOL (machine_readable_output);
SHOW_INT (nice);
SHOW_INT (verbosity);
SHOW_INT (mute);
@@ -1512,8 +1514,9 @@ show_settings (const struct options *o)
SHOW_BOOL (fast_io);
-#ifdef ENABLE_LZO
- SHOW_INT (lzo);
+#ifdef USE_COMP
+ SHOW_INT (comp.alg);
+ SHOW_INT (comp.flags);
#endif
SHOW_STR (route_script);
@@ -1525,15 +1528,12 @@ show_settings (const struct options *o)
SHOW_BOOL (route_delay_defined);
SHOW_BOOL (route_nopull);
SHOW_BOOL (route_gateway_via_dhcp);
- SHOW_INT (max_routes);
SHOW_BOOL (allow_pull_fqdn);
if (o->routes)
print_route_options (o->routes, D_SHOW_PARMS);
-
-#ifdef ENABLE_CLIENT_NAT
+
if (o->client_nat)
print_client_nat_list(o->client_nat, D_SHOW_PARMS);
-#endif
#ifdef ENABLE_MANAGEMENT
SHOW_STR (management_addr);
@@ -1599,7 +1599,8 @@ show_settings (const struct options *o)
SHOW_STR (cipher_list);
SHOW_STR (tls_verify);
SHOW_STR (tls_export_cert);
- SHOW_STR (tls_remote);
+ SHOW_INT (verify_x509_type);
+ SHOW_STR (verify_x509_name);
SHOW_STR (crl_file);
SHOW_INT (ns_cert_type);
{
@@ -1672,7 +1673,7 @@ show_settings (const struct options *o)
#undef SHOW_INT
#undef SHOW_BOOL
-#if HTTP_PROXY_OVERRIDE
+#ifdef ENABLE_MANAGEMENT
static struct http_proxy_options *
parse_http_proxy_override (const char *server,
@@ -1961,24 +1962,23 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
if (!ce->remote && ce->proto == PROTO_TCP_CLIENT)
msg (M_USAGE, "--remote MUST be used in TCP Client mode");
-#ifdef ENABLE_HTTP_PROXY
if ((ce->http_proxy_options) && ce->proto != PROTO_TCP_CLIENT)
msg (M_USAGE, "--http-proxy MUST be used in TCP Client mode (i.e. --proto tcp-client)");
-#endif
+ if ((ce->http_proxy_options) && !ce->http_proxy_options->server)
+ msg (M_USAGE, "--http-proxy not specified but other http proxy options present");
-#if defined(ENABLE_HTTP_PROXY) && defined(ENABLE_SOCKS)
if (ce->http_proxy_options && ce->socks_proxy_server)
msg (M_USAGE, "--http-proxy can not be used together with --socks-proxy");
-#endif
-#ifdef ENABLE_SOCKS
if (ce->socks_proxy_server && ce->proto == PROTO_TCP_SERVER)
msg (M_USAGE, "--socks-proxy can not be used in TCP Server mode");
-#endif
if (ce->proto == PROTO_TCP_SERVER && (options->connection_list->len > 1))
msg (M_USAGE, "TCP server mode allows at most one --remote address");
+ if (options->routes && ((options->routes->flags & RG_BLOCK_LOCAL) && (options->routes->flags & RG_UNBLOCK_LOCAL)))
+ msg (M_USAGE, "unblock-local and block-local options of redirect-gateway/redirect-private are mutatlly exclusive");
+
#if P2MP_SERVER
/*
@@ -2005,16 +2005,16 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
msg (M_USAGE, "--remote cannot be used with --mode server");
if (!ce->bind_local)
msg (M_USAGE, "--nobind cannot be used with --mode server");
-#ifdef ENABLE_HTTP_PROXY
if (ce->http_proxy_options)
msg (M_USAGE, "--http-proxy cannot be used with --mode server");
-#endif
-#ifdef ENABLE_SOCKS
if (ce->socks_proxy_server)
msg (M_USAGE, "--socks-proxy cannot be used with --mode server");
-#endif
- if (options->connection_list)
- msg (M_USAGE, "<connection> cannot be used with --mode server");
+ /* <connection> blocks force to have a remote embedded, so we check for the
+ * --remote and bail out if it is present */
+ if (options->connection_list->len >1 ||
+ options->connection_list->array[0]->remote)
+ msg (M_USAGE, "<connection> cannot be used with --mode server");
+
#if 0
if (options->tun_ipv6)
msg (M_USAGE, "--tun-ipv6 cannot be used with --mode server");
@@ -2038,6 +2038,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
#endif
if (options->routes && (options->routes->flags & RG_ENABLE))
msg (M_USAGE, "--redirect-gateway cannot be used with --mode server (however --push \"redirect-gateway\" is fine)");
+
if (options->route_delay_defined)
msg (M_USAGE, "--route-delay cannot be used with --mode server");
if (options->up_delay)
@@ -2115,7 +2116,6 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
if (options->stale_routes_check_interval)
msg (M_USAGE, "--stale-routes-check requires --mode server");
-
if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NO_NAME_REMAPPING))
msg (M_USAGE, "--compat-x509-names no-remapping requires --mode server");
}
@@ -2287,7 +2287,7 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
MUST_BE_UNDEF (cipher_list);
MUST_BE_UNDEF (tls_verify);
MUST_BE_UNDEF (tls_export_cert);
- MUST_BE_UNDEF (tls_remote);
+ MUST_BE_UNDEF (verify_x509_name);
MUST_BE_UNDEF (tls_timeout);
MUST_BE_UNDEF (renegotiate_bytes);
MUST_BE_UNDEF (renegotiate_packets);
@@ -2350,10 +2350,8 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce)
if (ce->proto == PROTO_TCP_CLIENT && !ce->local && !ce->local_port_defined && !ce->bind_defined)
ce->bind_local = false;
-#ifdef ENABLE_SOCKS
if (ce->proto == PROTO_UDP && ce->socks_proxy_server && !ce->local && !ce->local_port_defined && !ce->bind_defined)
ce->bind_local = false;
-#endif
if (!ce->bind_local)
ce->local_port = NULL;
@@ -2361,7 +2359,7 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce)
/* if protocol forcing is enabled, disable all protocols except for the forced one */
if (o->proto_force >= 0 && o->proto_force != ce->proto)
ce->flags |= CE_DISABLED;
-
+
/*
* If --mssfix is supplied without a parameter, default
* it to --fragment value, if --fragment is specified.
@@ -2396,7 +2394,9 @@ options_postprocess_mutate_ce (struct options *o, struct connection_entry *ce)
static void
options_postprocess_mutate_invariant (struct options *options)
{
+#ifdef WIN32
const int dev = dev_type_enum (options->dev, options->dev_type);
+#endif
/*
* In forking TCP server mode, you don't need to ifconfig
@@ -2458,6 +2458,7 @@ options_postprocess_verify (const struct options *o)
static void
options_postprocess_mutate (struct options *o)
{
+ int i;
/*
* Process helper-type options which map to other, more complex
* sequences of options.
@@ -2474,13 +2475,12 @@ options_postprocess_mutate (struct options *o)
* Convert remotes into connection list
*/
const struct remote_list *rl = o->remote_list;
- int i;
for (i = 0; i < rl->len; ++i)
{
const struct remote_entry *re = rl->array[i];
struct connection_entry ce = o->ce;
struct connection_entry *ace;
-
+
ASSERT (re->remote);
connection_entry_load_re (&ce, re);
ace = alloc_connection_entry (o, M_USAGE);
@@ -2497,11 +2497,10 @@ options_postprocess_mutate (struct options *o)
}
ASSERT (o->connection_list);
- int i;
for (i = 0; i < o->connection_list->len; ++i)
options_postprocess_mutate_ce (o, o->connection_list->array[i]);
-
-#if HTTP_PROXY_OVERRIDE
+
+#if ENABLE_MANAGEMENT
if (o->http_proxy_override)
options_postprocess_http_proxy_override(o);
#endif
@@ -2574,6 +2573,44 @@ check_file_access(const int type, const char *file, const int mode, const char *
return (errcode != 0 ? true : false);
}
+/* A wrapper for check_file_access() which also takes a chroot directory.
+ * If chroot is NULL, behaviour is exactly the same as calling check_file_access() directly,
+ * otherwise it will look for the file inside the given chroot directory instead.
+ */
+static bool
+check_file_access_chroot(const char *chroot, const int type, const char *file, const int mode, const char *opt)
+{
+ bool ret = false;
+
+ /* If no file configured, no errors to look for */
+ if (!file)
+ return false;
+
+ /* If chroot is set, look for the file/directory inside the chroot */
+ if( chroot )
+ {
+ struct gc_arena gc = gc_new();
+ struct buffer chroot_file;
+ int len = 0;
+
+ /* Build up a new full path including chroot directory */
+ len = strlen(chroot) + strlen(PATH_SEPARATOR_STR) + strlen(file) + 1;
+ chroot_file = alloc_buf_gc(len, &gc);
+ buf_printf(&chroot_file, "%s%s%s", chroot, PATH_SEPARATOR_STR, file);
+ ASSERT (chroot_file.len > 0);
+
+ ret = check_file_access(type, BSTR(&chroot_file), mode, opt);
+ gc_free(&gc);
+ }
+ else
+ {
+ /* No chroot in play, just call core file check function */
+ ret = check_file_access(type, file, mode, opt);
+ }
+ return ret;
+}
+
+
/*
* Verifies that the path in the "command" that comes after certain script options (e.g., --up) is a
* valid file with appropriate permissions.
@@ -2591,7 +2628,7 @@ check_file_access(const int type, const char *file, const int mode, const char *
* check_file_access() arguments.
*/
static bool
-check_cmd_access(const char *command, const char *opt)
+check_cmd_access(const char *command, const char *opt, const char *chroot)
{
struct argv argv;
bool return_code;
@@ -2610,7 +2647,7 @@ check_cmd_access(const char *command, const char *opt)
* only requires X_OK to function on Unix - a scenario not unlikely to
* be seen on suid binaries.
*/
- return_code = check_file_access(CHKACC_FILE, argv.argv[0], X_OK, opt);
+ return_code = check_file_access_chroot(chroot, CHKACC_FILE, argv.argv[0], X_OK, opt);
else
{
msg (M_NOPREFIX|M_OPTERR, "%s fails with '%s': No path to executable.",
@@ -2636,7 +2673,7 @@ options_postprocess_filechecks (struct options *options)
#ifdef ENABLE_SSL
errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->dh_file, R_OK, "--dh");
errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->ca_file, R_OK, "--ca");
- errs |= check_file_access (CHKACC_FILE, options->ca_path, R_OK, "--capath");
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->ca_path, R_OK, "--capath");
errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->cert_file, R_OK, "--cert");
errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->extra_certs_file, R_OK,
"--extra-certs");
@@ -2649,10 +2686,10 @@ options_postprocess_filechecks (struct options *options)
"--pkcs12");
if (options->ssl_flags & SSLF_CRL_VERIFY_DIR)
- errs |= check_file_access (CHKACC_FILE, options->crl_file, R_OK|X_OK,
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK|X_OK,
"--crl-verify directory");
else
- errs |= check_file_access (CHKACC_FILE, options->crl_file, R_OK,
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->crl_file, R_OK,
"--crl-verify");
errs |= check_file_access (CHKACC_FILE|CHKACC_INLINE, options->tls_auth_file, R_OK,
@@ -2694,37 +2731,15 @@ options_postprocess_filechecks (struct options *options)
/* ** Config related ** */
#ifdef ENABLE_SSL
- errs |= check_file_access (CHKACC_FILE, options->tls_export_cert,
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->tls_export_cert,
R_OK|W_OK|X_OK, "--tls-export-cert");
#endif /* ENABLE_SSL */
#if P2MP_SERVER
- errs |= check_file_access (CHKACC_FILE, options->client_config_dir,
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->client_config_dir,
R_OK|X_OK, "--client-config-dir");
- errs |= check_file_access (CHKACC_FILE, options->tmp_dir,
+ errs |= check_file_access_chroot (options->chroot_dir, CHKACC_FILE, options->tmp_dir,
R_OK|W_OK|X_OK, "Temporary directory (--tmp-dir)");
- /* ** Script hooks that accept an optionally quoted and/or escaped executable path, ** */
- /* ** optionally followed by arguments ** */
- errs |= check_cmd_access (options->auth_user_pass_verify_script,
- "--auth-user-pass-verify script");
- errs |= check_cmd_access (options->client_connect_script,
- "--client-connect script");
- errs |= check_cmd_access (options->client_disconnect_script,
- "--client-disconnect script");
- errs |= check_cmd_access (options->tls_verify,
- "--tls-verify script");
- errs |= check_cmd_access (options->up_script,
- "--up script");
- errs |= check_cmd_access (options->down_script,
- "--down script");
- errs |= check_cmd_access (options->ipchange,
- "--ipchange script");
- errs |= check_cmd_access (options->route_script,
- "--route-up script");
- errs |= check_cmd_access (options->route_predown_script,
- "--route-pre-down script");
- errs |= check_cmd_access (options->learn_address_script,
- "--learn-address script");
#endif /* P2MP_SERVER */
if (errs)
@@ -2772,18 +2787,16 @@ pre_pull_save (struct options *o)
o->pre_pull->routes_ipv6 = clone_route_ipv6_option_list(o->routes_ipv6, &o->gc);
o->pre_pull->routes_ipv6_defined = true;
}
-#ifdef ENABLE_CLIENT_NAT
if (o->client_nat)
{
o->pre_pull->client_nat = clone_client_nat_option_list(o->client_nat, &o->gc);
o->pre_pull->client_nat_defined = true;
}
-#endif
}
}
void
-pre_pull_restore (struct options *o)
+pre_pull_restore (struct options *o, struct gc_arena *gc)
{
const struct options_pre_pull *pp = o->pre_pull;
if (pp)
@@ -2795,7 +2808,7 @@ pre_pull_restore (struct options *o)
if (pp->routes_defined)
{
rol_check_alloc (o);
- copy_route_option_list (o->routes, pp->routes);
+ copy_route_option_list (o->routes, pp->routes, gc);
}
else
o->routes = NULL;
@@ -2803,12 +2816,11 @@ pre_pull_restore (struct options *o)
if (pp->routes_ipv6_defined)
{
rol6_check_alloc (o);
- copy_route_ipv6_option_list (o->routes_ipv6, pp->routes_ipv6);
+ copy_route_ipv6_option_list (o->routes_ipv6, pp->routes_ipv6, gc);
}
else
o->routes_ipv6 = NULL;
-#ifdef ENABLE_CLIENT_NAT
if (pp->client_nat_defined)
{
cnol_check_alloc (o);
@@ -2816,12 +2828,12 @@ pre_pull_restore (struct options *o)
}
else
o->client_nat = NULL;
-#endif
o->foreign_option_index = pp->foreign_option_index;
}
o->push_continuation = 0;
+ o->push_option_types_found = 0;
}
#endif
@@ -2852,6 +2864,7 @@ pre_pull_restore (struct options *o)
* the other end of the connection]
*
* --comp-lzo
+ * --compress alg
* --fragment
*
* Crypto Options:
@@ -2933,9 +2946,9 @@ options_string (const struct options *o,
tt = NULL;
}
-#ifdef ENABLE_LZO
- if (o->lzo & LZO_SELECTED)
- buf_printf (&out, ",comp-lzo");
+#ifdef USE_COMP
+ if (o->comp.alg != COMP_ALG_UNDEF)
+ buf_printf (&out, ",comp-lzo"); /* for compatibility, this simply indicates that compression context is active, not necessarily LZO per-se */
#endif
#ifdef ENABLE_FRAGMENT
@@ -3388,10 +3401,31 @@ usage_small (void)
openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */
}
+void
+show_library_versions(const unsigned int flags)
+{
+#ifdef ENABLE_SSL
+#define SSL_LIB_VER_STR get_ssl_library_version()
+#else
+#define SSL_LIB_VER_STR ""
+#endif
+#ifdef ENABLE_LZO
+#define LZO_LIB_VER_STR ", LZO ", lzo_version_string()
+#else
+#define LZO_LIB_VER_STR "", ""
+#endif
+
+ msg (flags, "library versions: %s%s%s", SSL_LIB_VER_STR, LZO_LIB_VER_STR);
+
+#undef SSL_LIB_VER_STR
+#undef LZO_LIB_VER_STR
+}
+
static void
usage_version (void)
{
msg (M_INFO|M_NOPREFIX, "%s", title_string);
+ show_library_versions( M_INFO|M_NOPREFIX );
msg (M_INFO|M_NOPREFIX, "Originally developed by James Yonan");
msg (M_INFO|M_NOPREFIX, "Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>");
#ifndef ENABLE_SMALL
@@ -3401,9 +3435,6 @@ usage_version (void)
#ifdef CONFIGURE_SPECIAL_BUILD
msg (M_INFO|M_NOPREFIX, "special build: %s", CONFIGURE_SPECIAL_BUILD);
#endif
-#ifdef CONFIGURE_GIT_REVISION
- msg (M_INFO|M_NOPREFIX, "git revision: %s", CONFIGURE_GIT_REVISION);
-#endif
#endif
openvpn_exit (OPENVPN_EXIT_STATUS_USAGE); /* exit point */
}
@@ -3746,9 +3777,13 @@ read_config_file (struct options *options,
line_num = 0;
while (fgets(line, sizeof (line), fp))
{
+ int offset = 0;
CLEAR (p);
++line_num;
- if (parse_line (line, p, SIZE (p), file, line_num, msglevel, &options->gc))
+ /* Ignore UTF-8 BOM at start of stream */
+ if (line_num == 1 && strncmp (line, "\xEF\xBB\xBF", 3) == 0)
+ offset = 3;
+ if (parse_line (line + offset, p, SIZE (p), file, line_num, msglevel, &options->gc))
{
bypass_doubledash (&p[0]);
check_inline_file_via_fp (fp, p, &options->gc);
@@ -3795,7 +3830,7 @@ read_config_string (const char *prefix,
{
bypass_doubledash (&p[0]);
check_inline_file_via_buf (&multiline, p, &options->gc);
- add_option (options, p, NULL, line_num, 0, msglevel, permission_mask, option_types_found, es);
+ add_option (options, p, prefix, line_num, 0, msglevel, permission_mask, option_types_found, es);
}
CLEAR (p);
}
@@ -3915,27 +3950,43 @@ void options_string_import (struct options *options,
#if P2MP
-#define VERIFY_PERMISSION(mask) { if (!verify_permission(p[0], file, (mask), permission_mask, option_types_found, msglevel)) goto err; }
+#define VERIFY_PERMISSION(mask) { if (!verify_permission(p[0], file, line, (mask), permission_mask, option_types_found, msglevel, options)) goto err; }
static bool
verify_permission (const char *name,
const char* file,
+ int line,
const unsigned int type,
const unsigned int allowed,
unsigned int *found,
- const int msglevel)
+ const int msglevel,
+ struct options* options)
{
if (!(type & allowed))
{
msg (msglevel, "option '%s' cannot be used in this context (%s)", name, file);
return false;
}
- else
+
+ if (found)
+ *found |= type;
+
+#ifndef ENABLE_SMALL
+ /* Check if this options is allowed in connection block,
+ * but we are currently not in a connection block
+ * Parsing a connection block uses a temporary options struct without
+ * connection_list
+ */
+
+ if ((type & OPT_P_CONNECTION) && options->connection_list)
{
- if (found)
- *found |= type;
- return true;
+ if (file)
+ msg (M_WARN, "Option '%s' in %s:%d is ignored by previous <connection> blocks ", name, file, line);
+ else
+ msg (M_WARN, "Option '%s' is ignored by previous <connection> blocks", name);
}
+#endif
+ return true;
}
#else
@@ -3982,11 +4033,30 @@ msglevel_forward_compatible (struct options *options, const int msglevel)
}
static void
-warn_multiple_script (const char *script, const char *type) {
- if (script) {
- msg (M_WARN, "Multiple --%s scripts defined. "
- "The previously configured script is overridden.", type);
- }
+set_user_script (struct options *options,
+ const char **script,
+ const char *new_script,
+ const char *type,
+ bool in_chroot)
+{
+ if (*script) {
+ msg (M_WARN, "Multiple --%s scripts defined. "
+ "The previously configured script is overridden.", type);
+ }
+ *script = new_script;
+ options->user_script_used = true;
+
+#ifndef ENABLE_SMALL
+ {
+ char script_name[100];
+ openvpn_snprintf (script_name, sizeof(script_name),
+ "--%s script", type);
+
+ if (check_cmd_access (*script, script_name, (in_chroot ? options->chroot_dir : NULL)))
+ msg (M_USAGE, "Please correct this error.");
+
+ }
+#endif
}
@@ -4005,7 +4075,18 @@ add_option (struct options *options,
const bool pull_mode = BOOL_CAST (permission_mask & OPT_P_PULL_MODE);
int msglevel_fc = msglevel_forward_compatible (options, msglevel);
- ASSERT (MAX_PARMS >= 5);
+ ASSERT (MAX_PARMS >= 7);
+
+ /*
+ * If directive begins with "setenv opt" prefix, don't raise an error if
+ * directive is unrecognized.
+ */
+ if (streq (p[0], "setenv") && p[1] && streq (p[1], "opt") && !(permission_mask & OPT_P_PULL_MODE))
+ {
+ p += 2;
+ msglevel_fc = M_WARN;
+ }
+
if (!file)
{
file = "[CMD-LINE]";
@@ -4031,7 +4112,7 @@ add_option (struct options *options,
read_config_file (options, p[1], level, file, line, msglevel, permission_mask, option_types_found, es);
}
-#ifdef ENABLE_DEBUG
+#if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL)
else if (streq (p[0], "show-gateway"))
{
struct route_gateway_info rgi;
@@ -4354,7 +4435,44 @@ add_option (struct options *options,
uninit_options (&sub);
}
}
-#if HTTP_PROXY_OVERRIDE
+ else if (streq (p[0], "ignore-unknown-option") && p[1])
+ {
+ int i;
+ int j;
+ int numignored=0;
+ const char **ignore;
+
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ /* Find out how many options to be ignored */
+ for (i=1;p[i];i++)
+ numignored++;
+
+ /* add number of options already ignored */
+ for (i=0;options->ignore_unknown_option &&
+ options->ignore_unknown_option[i]; i++)
+ numignored++;
+
+ /* Allocate array */
+ ALLOC_ARRAY_GC (ignore, const char*, numignored+1, &options->gc);
+ for (i=0;options->ignore_unknown_option &&
+ options->ignore_unknown_option[i]; i++)
+ ignore[i]=options->ignore_unknown_option[i];
+
+ options->ignore_unknown_option=ignore;
+
+ for (j=1;p[j];j++)
+ {
+ /* Allow the user to specify ignore-unknown-option --opt too */
+ if (p[j][0]=='-' && p[j][1]=='-')
+ options->ignore_unknown_option[i] = (p[j]+2);
+ else
+ options->ignore_unknown_option[i] = p[j];
+ i++;
+ }
+
+ options->ignore_unknown_option[i] = NULL;
+ }
+#if ENABLE_MANAGEMENT
else if (streq (p[0], "http-proxy-override") && p[1] && p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -4378,14 +4496,14 @@ add_option (struct options *options,
if (p[3])
{
const int proto = ascii2proto (p[3]);
- const sa_family_t af = ascii2af (p[3]);
+ const sa_family_t af = ascii2af (p[3]);
if (proto < 0)
{
msg (msglevel, "remote: bad protocol associated with host %s: '%s'", p[1], p[3]);
goto err;
}
re.proto = proto;
- re.af = af;
+ re.af = af;
}
}
if (permission_mask & OPT_P_GENERAL)
@@ -4408,6 +4526,15 @@ add_option (struct options *options,
else
options->resolve_retry_seconds = positive_atoi (p[1]);
}
+ else if (streq (p[0], "preresolve") || streq (p[0], "ip-remote-hint"))
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->resolve_in_advance = true;
+ /* Note the ip-remote-hint and the argument p[1] are for
+ backward compatibility */
+ if (p[1])
+ options->ip_remote_hint=p[1];
+ }
else if (streq (p[0], "connect-retry") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
@@ -4429,8 +4556,10 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_SCRIPT);
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
- warn_multiple_script (options->ipchange, "ipchange");
- options->ipchange = string_substitute (p[1], ',', ' ', &options->gc);
+ set_user_script (options,
+ &options->ipchange,
+ string_substitute (p[1], ',', ' ', &options->gc),
+ "ipchange", true);
}
else if (streq (p[0], "float"))
{
@@ -4476,16 +4605,14 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_SCRIPT);
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
- warn_multiple_script (options->up_script, "up");
- options->up_script = p[1];
+ set_user_script (options, &options->up_script, p[1], "up", false);
}
else if (streq (p[0], "down") && p[1])
{
VERIFY_PERMISSION (OPT_P_SCRIPT);
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
- warn_multiple_script (options->down_script, "down");
- options->down_script = p[1];
+ set_user_script (options, &options->down_script, p[1], "down", true);
}
else if (streq (p[0], "down-pre"))
{
@@ -4592,6 +4719,12 @@ add_option (struct options *options,
options->suppress_timestamps = true;
set_suppress_timestamps(true);
}
+ else if (streq (p[0], "machine-readable-output"))
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->machine_readable_output = true;
+ set_machine_readable_output(true);
+ }
else if (streq (p[0], "log-append") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -4621,6 +4754,12 @@ add_option (struct options *options,
{
VERIFY_PERMISSION (OPT_P_MESSAGES);
options->verbosity = positive_atoi (p[1]);
+#if !defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL)
+ /* Warn when a debug verbosity is supplied when built without debug support */
+ if (options->verbosity >= 7)
+ msg (M_WARN, "NOTE: debug verbosity (--verb %d) is enabled but this build lacks debug support.",
+ options->verbosity);
+#endif
}
else if (streq (p[0], "mute") && p[1])
{
@@ -4795,6 +4934,9 @@ add_option (struct options *options,
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
options->ce.bind_defined = true;
+ if (p[1] && streq (p[1], "ipv6only"))
+ options->ce.bind_ipv6_only=true;
+
}
else if (streq (p[0], "nobind"))
{
@@ -4842,7 +4984,6 @@ add_option (struct options *options,
}
options->proto_force = proto_force;
}
-#ifdef ENABLE_HTTP_PROXY
else if (streq (p[0], "http-proxy") && p[1])
{
struct http_proxy_options *ho;
@@ -4917,13 +5058,38 @@ add_option (struct options *options,
{
ho->user_agent = p[2];
}
+ else if ((streq (p[1], "EXT1") || streq(p[1], "EXT2") || streq(p[1], "CUSTOM-HEADER"))
+ && p[2])
+ {
+ /* In the wild patched versions use both EXT1/2 and CUSTOM-HEADER
+ * with either two argument or one */
+
+ struct http_custom_header *custom_header = NULL;
+ int i;
+ /* Find the first free header */
+ for (i=0; i < MAX_CUSTOM_HTTP_HEADER; i++) {
+ if (!ho->custom_headers[i].name) {
+ custom_header = &ho->custom_headers[i];
+ break;
+ }
+ }
+ if (!custom_header)
+ {
+ msg (msglevel, "Cannot use more than %d http-proxy-option CUSTOM-HEADER : '%s'", MAX_CUSTOM_HTTP_HEADER, p[1]);
+ }
+ else
+ {
+ /* We will save p[2] and p[3], the proxy code will detect if
+ * p[3] is NULL */
+ custom_header->name = p[2];
+ custom_header->content = p[3];
+ }
+ }
else
{
msg (msglevel, "Bad http-proxy-option or missing parameter: '%s'", p[1]);
}
}
-#endif
-#ifdef ENABLE_SOCKS
else if (streq (p[0], "socks-proxy") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
@@ -4944,7 +5110,6 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
options->ce.socks_proxy_retry = true;
}
-#endif
else if (streq (p[0], "keepalive") && p[1] && p[2])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -4976,8 +5141,7 @@ add_option (struct options *options,
#ifdef ENABLE_OCC
else if (streq (p[0], "explicit-exit-notify"))
{
- VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION);
-/* VERIFY_PERMISSION (OPT_P_EXPLICIT_NOTIFY); */
+ VERIFY_PERMISSION (OPT_P_GENERAL|OPT_P_CONNECTION|OPT_P_EXPLICIT_NOTIFY);
if (p[1])
{
options->ce.explicit_exit_notification = positive_atoi (p[1]);
@@ -5008,14 +5172,12 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_PERSIST_IP);
options->persist_remote_ip = true;
}
-#ifdef ENABLE_CLIENT_NAT
else if (streq (p[0], "client-nat") && p[1] && p[2] && p[3] && p[4])
{
VERIFY_PERMISSION (OPT_P_ROUTE);
cnol_check_alloc (options);
add_client_nat_to_option_list(options->client_nat, p[1], p[2], p[3], p[4], msglevel);
}
-#endif
else if (streq (p[0], "route") && p[1])
{
VERIFY_PERMISSION (OPT_P_ROUTE);
@@ -5060,23 +5222,12 @@ add_option (struct options *options,
}
add_route_ipv6_to_option_list (options->routes_ipv6, p[1], p[2], p[3]);
}
- else if (streq (p[0], "max-routes") && p[1])
+ else if (streq (p[0], "max-routes"))
{
- int max_routes;
-
- VERIFY_PERMISSION (OPT_P_GENERAL);
- max_routes = atoi (p[1]);
- if (max_routes < 0 || max_routes > 100000000)
- {
- msg (msglevel, "--max-routes parameter is out of range");
- goto err;
- }
- if (options->routes || options->routes_ipv6)
- {
- msg (msglevel, "--max-routes must to be specifed before any route/route-ipv6/redirect-gateway option");
- goto err;
- }
- options->max_routes = max_routes;
+ msg (M_WARN, "DEPRECATED OPTION: --max-routes option ignored."
+ "The number of routes is unlimited as of version 2.4. "
+ "This option will be removed in a future version, "
+ "please remove it from your configuration.");
}
else if (streq (p[0], "route-gateway") && p[1])
{
@@ -5125,16 +5276,17 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_SCRIPT);
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
- warn_multiple_script (options->route_script, "route-up");
- options->route_script = p[1];
+ set_user_script (options, &options->route_script, p[1], "route-up", false);
}
else if (streq (p[0], "route-pre-down") && p[1])
{
VERIFY_PERMISSION (OPT_P_SCRIPT);
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
- warn_multiple_script (options->route_predown_script, "route-pre-down");
- options->route_predown_script = p[1];
+ set_user_script (options,
+ &options->route_predown_script,
+ p[1],
+ "route-pre-down", true);
}
else if (streq (p[0], "route-noexec"))
{
@@ -5172,6 +5324,8 @@ add_option (struct options *options,
options->routes->flags |= RG_BYPASS_DNS;
else if (streq (p[j], "block-local"))
options->routes->flags |= RG_BLOCK_LOCAL;
+ else if (streq (p[j], "unblock-local"))
+ options->routes->flags |= RG_UNBLOCK_LOCAL;
else
{
msg (msglevel, "unknown --%s flag: %s", p[0], p[j]);
@@ -5401,9 +5555,9 @@ add_option (struct options *options,
msg (msglevel, "error parsing --ifconfig-ipv6-pool parameters");
goto err;
}
- if ( netbits != 64 )
+ if ( netbits < 64 || netbits > 112 )
{
- msg( msglevel, "--ifconfig-ipv6-pool settings: only /64 supported right now (not /%d)", netbits );
+ msg( msglevel, "--ifconfig-ipv6-pool settings: only /64../112 supported right now (not /%d)", netbits );
goto err;
}
@@ -5474,13 +5628,6 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL);
options->ssl_flags |= SSLF_AUTH_USER_PASS_OPTIONAL;
}
- else if (streq (p[0], "compat-names"))
- {
- VERIFY_PERMISSION (OPT_P_GENERAL);
- compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES);
- if (p[1] && streq (p[1], "no-remapping"))
- compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING);
- }
else if (streq (p[0], "opt-verify"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -5508,32 +5655,33 @@ add_option (struct options *options,
msg (msglevel, "--auth-user-pass-verify requires a second parameter ('via-env' or 'via-file')");
goto err;
}
- warn_multiple_script (options->auth_user_pass_verify_script, "auth-user-pass-verify");
- options->auth_user_pass_verify_script = p[1];
+ set_user_script (options,
+ &options->auth_user_pass_verify_script,
+ p[1], "auth-user-pass-verify", true);
}
else if (streq (p[0], "client-connect") && p[1])
{
VERIFY_PERMISSION (OPT_P_SCRIPT);
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
- warn_multiple_script (options->client_connect_script, "client-connect");
- options->client_connect_script = p[1];
+ set_user_script (options, &options->client_connect_script,
+ p[1], "client-connect", true);
}
else if (streq (p[0], "client-disconnect") && p[1])
{
VERIFY_PERMISSION (OPT_P_SCRIPT);
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
- warn_multiple_script (options->client_disconnect_script, "client-disconnect");
- options->client_disconnect_script = p[1];
+ set_user_script (options, &options->client_disconnect_script,
+ p[1], "client-disconnect", true);
}
else if (streq (p[0], "learn-address") && p[1])
{
VERIFY_PERMISSION (OPT_P_SCRIPT);
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
- warn_multiple_script (options->learn_address_script, "learn-address");
- options->learn_address_script = p[1];
+ set_user_script (options, &options->learn_address_script,
+ p[1], "learn-address", true);
}
else if (streq (p[0], "tmp-dir") && p[1])
{
@@ -5617,10 +5765,8 @@ add_option (struct options *options,
options->push_ifconfig_defined = true;
options->push_ifconfig_local = local;
options->push_ifconfig_remote_netmask = remote_netmask;
-#ifdef ENABLE_CLIENT_NAT
if (p[3])
options->push_ifconfig_local_alias = getaddr (GETADDR_HOST_ORDER|GETADDR_RESOLVE, p[3], 0, NULL, NULL);
-#endif
}
else
{
@@ -6036,18 +6182,31 @@ add_option (struct options *options,
options->passtos = true;
}
#endif
-#ifdef ENABLE_LZO
+#if defined(USE_COMP)
else if (streq (p[0], "comp-lzo"))
{
VERIFY_PERMISSION (OPT_P_COMP);
- if (p[1])
+
+#if defined(ENABLE_LZO)
+ if (p[1] && streq (p[1], "no"))
+#endif
+ {
+ options->comp.alg = COMP_ALG_STUB;
+ options->comp.flags = 0;
+ }
+#if defined(ENABLE_LZO)
+ else if (p[1])
{
if (streq (p[1], "yes"))
- options->lzo = LZO_SELECTED|LZO_ON;
- else if (streq (p[1], "no"))
- options->lzo = LZO_SELECTED;
+ {
+ options->comp.alg = COMP_ALG_LZO;
+ options->comp.flags = 0;
+ }
else if (streq (p[1], "adaptive"))
- options->lzo = LZO_SELECTED|LZO_ON|LZO_ADAPTIVE;
+ {
+ options->comp.alg = COMP_ALG_LZO;
+ options->comp.flags = COMP_F_ADAPTIVE;
+ }
else
{
msg (msglevel, "bad comp-lzo option: %s -- must be 'yes', 'no', or 'adaptive'", p[1]);
@@ -6055,14 +6214,61 @@ add_option (struct options *options,
}
}
else
- options->lzo = LZO_SELECTED|LZO_ON|LZO_ADAPTIVE;
+ {
+ options->comp.alg = COMP_ALG_LZO;
+ options->comp.flags = COMP_F_ADAPTIVE;
+ }
+#endif
}
else if (streq (p[0], "comp-noadapt"))
{
VERIFY_PERMISSION (OPT_P_COMP);
- options->lzo &= ~LZO_ADAPTIVE;
+ options->comp.flags &= ~COMP_F_ADAPTIVE;
}
-#endif /* ENABLE_LZO */
+ else if (streq (p[0], "compress"))
+ {
+ VERIFY_PERMISSION (OPT_P_COMP);
+ if (p[1])
+ {
+ if (streq (p[1], "stub"))
+ {
+ options->comp.alg = COMP_ALG_STUB;
+ options->comp.flags = (COMP_F_SWAP|COMP_F_ADVERTISE_STUBS_ONLY);
+ }
+#if defined(ENABLE_LZO)
+ else if (streq (p[1], "lzo"))
+ {
+ options->comp.alg = COMP_ALG_LZO;
+ options->comp.flags = 0;
+ }
+#endif
+#if defined(ENABLE_SNAPPY)
+ else if (streq (p[1], "snappy"))
+ {
+ options->comp.alg = COMP_ALG_SNAPPY;
+ options->comp.flags = COMP_F_SWAP;
+ }
+#endif
+#if defined(ENABLE_LZ4)
+ else if (streq (p[1], "lz4"))
+ {
+ options->comp.alg = COMP_ALG_LZ4;
+ options->comp.flags = COMP_F_SWAP;
+ }
+#endif
+ else
+ {
+ msg (msglevel, "bad comp option: %s", p[1]);
+ goto err;
+ }
+ }
+ else
+ {
+ options->comp.alg = COMP_ALG_STUB;
+ options->comp.flags = COMP_F_SWAP;
+ }
+ }
+#endif /* USE_COMP */
#ifdef ENABLE_CRYPTO
else if (streq (p[0], "show-ciphers"))
{
@@ -6273,6 +6479,16 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_GENERAL);
options->show_tls_ciphers = true;
}
+ else if (streq (p[0], "show-curves"))
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->show_curves = true;
+ }
+ else if (streq (p[0], "ecdh-curve") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_CRYPTO);
+ options->ecdh_curve= p[1];
+ }
else if (streq (p[0], "tls-server"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
@@ -6347,6 +6563,19 @@ add_option (struct options *options,
options->priv_key_file_inline = p[2];
}
}
+ else if (streq (p[0], "tls-version-min") && p[1])
+ {
+ int ver;
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ ver = tls_version_min_parse(p[1], p[2]);
+ if (ver == TLS_VER_BAD)
+ {
+ msg (msglevel, "unknown tls-version-min parameter: %s", p[1]);
+ goto err;
+ }
+ options->ssl_flags &= ~(SSLF_TLS_VERSION_MASK << SSLF_TLS_VERSION_SHIFT);
+ options->ssl_flags |= (ver << SSLF_TLS_VERSION_SHIFT);
+ }
#ifndef ENABLE_CRYPTO_POLARSSL
else if (streq (p[0], "pkcs12") && p[1])
{
@@ -6416,8 +6645,9 @@ add_option (struct options *options,
VERIFY_PERMISSION (OPT_P_SCRIPT);
if (!no_more_than_n_args (msglevel, p, 2, NM_QUOTE_HINT))
goto err;
- warn_multiple_script (options->tls_verify, "tls-verify");
- options->tls_verify = string_substitute (p[1], ',', ' ', &options->gc);
+ set_user_script (options, &options->tls_verify,
+ string_substitute (p[1], ',', ' ', &options->gc),
+ "tls-verify", true);
}
#ifndef ENABLE_CRYPTO_POLARSSL
else if (streq (p[0], "tls-export-cert") && p[1])
@@ -6426,10 +6656,100 @@ add_option (struct options *options,
options->tls_export_cert = p[1];
}
#endif
+ else if (streq (p[0], "compat-names"))
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ if (options->verify_x509_type != VERIFY_X509_NONE &&
+ options->verify_x509_type != TLS_REMOTE_SUBJECT_DN &&
+ options->verify_x509_type != TLS_REMOTE_SUBJECT_RDN_PREFIX)
+ {
+ msg (msglevel, "you cannot use --compat-names with --verify-x509-name");
+ goto err;
+ }
+ msg (M_WARN, "DEPRECATED OPTION: --compat-names, please update your configuration");
+ compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES);
+#if P2MP_SERVER
+ if (p[1] && streq (p[1], "no-remapping"))
+ compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING);
+ }
+ else if (streq (p[0], "no-name-remapping"))
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ if (options->verify_x509_type != VERIFY_X509_NONE &&
+ options->verify_x509_type != TLS_REMOTE_SUBJECT_DN &&
+ options->verify_x509_type != TLS_REMOTE_SUBJECT_RDN_PREFIX)
+ {
+ msg (msglevel, "you cannot use --no-name-remapping with --verify-x509-name");
+ goto err;
+ }
+ msg (M_WARN, "DEPRECATED OPTION: --no-name-remapping, please update your configuration");
+ compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES);
+ compat_flag (COMPAT_FLAG_SET | COMPAT_NO_NAME_REMAPPING);
+#endif
+ }
else if (streq (p[0], "tls-remote") && p[1])
{
VERIFY_PERMISSION (OPT_P_GENERAL);
- options->tls_remote = p[1];
+
+ if (options->verify_x509_type != VERIFY_X509_NONE &&
+ options->verify_x509_type != TLS_REMOTE_SUBJECT_DN &&
+ options->verify_x509_type != TLS_REMOTE_SUBJECT_RDN_PREFIX)
+ {
+ msg (msglevel, "you cannot use --tls-remote with --verify-x509-name");
+ goto err;
+ }
+ msg (M_WARN, "DEPRECATED OPTION: --tls-remote, please update your configuration");
+
+ if (strlen (p[1]))
+ {
+ int is_username = (!strchr (p[1], '=') || !strstr (p[1], ", "));
+ int type = TLS_REMOTE_SUBJECT_DN;
+ if (p[1][0] != '/' && is_username)
+ type = TLS_REMOTE_SUBJECT_RDN_PREFIX;
+
+ /*
+ * Enable legacy openvpn format for DNs that have not been converted
+ * yet and --x509-username-field (not containing an '=' or ', ')
+ */
+ if (p[1][0] == '/' || is_username)
+ compat_flag (COMPAT_FLAG_SET | COMPAT_NAMES);
+
+ options->verify_x509_type = type;
+ options->verify_x509_name = p[1];
+ }
+ }
+ else if (streq (p[0], "verify-x509-name") && p[1] && strlen (p[1]))
+ {
+ int type = VERIFY_X509_SUBJECT_DN;
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ if (options->verify_x509_type == TLS_REMOTE_SUBJECT_DN ||
+ options->verify_x509_type == TLS_REMOTE_SUBJECT_RDN_PREFIX)
+ {
+ msg (msglevel, "you cannot use --verify-x509-name with --tls-remote");
+ goto err;
+ }
+ if (compat_flag (COMPAT_FLAG_QUERY | COMPAT_NAMES))
+ {
+ msg (msglevel, "you cannot use --verify-x509-name with "
+ "--compat-names or --no-name-remapping");
+ goto err;
+ }
+ if (p[2])
+ {
+ if (streq (p[2], "subject"))
+ type = VERIFY_X509_SUBJECT_DN;
+ else if (streq (p[2], "name"))
+ type = VERIFY_X509_SUBJECT_RDN;
+ else if (streq (p[2], "name-prefix"))
+ type = VERIFY_X509_SUBJECT_RDN_PREFIX;
+ else
+ {
+ msg (msglevel, "unknown X.509 name type: %s", p[2]);
+ goto err;
+ }
+ }
+ options->verify_x509_type = type;
+ options->verify_x509_name = p[1];
}
else if (streq (p[0], "ns-cert-type") && p[1])
{
@@ -6444,7 +6764,6 @@ add_option (struct options *options,
goto err;
}
}
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L || ENABLE_CRYPTO_POLARSSL
else if (streq (p[0], "remote-cert-ku"))
{
int j;
@@ -6482,7 +6801,6 @@ add_option (struct options *options,
goto err;
}
}
-#endif /* OPENSSL_VERSION_NUMBER */
else if (streq (p[0], "tls-timeout") && p[1])
{
VERIFY_PERMISSION (OPT_P_TLS_PARMS);
@@ -6641,10 +6959,22 @@ add_option (struct options *options,
#endif
else
{
+ int i;
+ int msglevel= msglevel_fc;
+ /* Check if an option is in --ignore-unknown-option and
+ set warning level to non fatal */
+ for(i=0; options->ignore_unknown_option && options->ignore_unknown_option[i]; i++)
+ {
+ if (streq(p[0], options->ignore_unknown_option[i]))
+ {
+ msglevel = M_WARN;
+ break;
+ }
+ }
if (file)
- msg (msglevel_fc, "Unrecognized option or missing parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION);
+ msg (msglevel, "Unrecognized option or missing parameter(s) in %s:%d: %s (%s)", file, line, p[0], PACKAGE_VERSION);
else
- msg (msglevel_fc, "Unrecognized option or missing parameter(s): --%s (%s)", p[0], PACKAGE_VERSION);
+ msg (msglevel, "Unrecognized option or missing parameter(s): --%s (%s)", p[0], PACKAGE_VERSION);
}
err:
gc_free (&gc);
diff --git a/app/openvpn/src/openvpn/options.h b/app/openvpn/src/openvpn/options.h
index 909cb38a..21c210ee 100644
--- a/app/openvpn/src/openvpn/options.h
+++ b/app/openvpn/src/openvpn/options.h
@@ -39,7 +39,7 @@
#include "plugin.h"
#include "manage.h"
#include "proxy.h"
-#include "lzo.h"
+#include "comp.h"
#include "pushlist.h"
#include "clinat.h"
@@ -71,10 +71,8 @@ struct options_pre_pull
bool routes_ipv6_defined;
struct route_ipv6_option_list *routes_ipv6;
-#ifdef ENABLE_CLIENT_NAT
bool client_nat_defined;
struct client_nat_option_list *client_nat;
-#endif
int foreign_option_index;
};
@@ -90,24 +88,21 @@ struct connection_entry
sa_family_t af;
const char* local_port;
bool local_port_defined;
- const char* remote_port;
+ const char *remote_port;
const char *local;
const char *remote;
bool remote_float;
bool bind_defined;
+ bool bind_ipv6_only;
bool bind_local;
int connect_retry_seconds;
int connect_timeout;
bool connect_timeout_defined;
-#ifdef ENABLE_HTTP_PROXY
struct http_proxy_options *http_proxy_options;
-#endif
-#ifdef ENABLE_SOCKS
const char *socks_proxy_server;
const char *socks_proxy_port;
const char *socks_proxy_authfile;
bool socks_proxy_retry;
-#endif
int tun_mtu; /* MTU of tun device */
bool tun_mtu_defined; /* true if user overriding parm with command line option */
@@ -186,6 +181,8 @@ struct options
/* enable forward compatibility for post-2.1 features */
bool forward_compatible;
+ /* list of options that should be ignored even if unkown */
+ const char ** ignore_unknown_option;
/* persist parms */
bool persist_config;
@@ -198,6 +195,7 @@ struct options
bool show_engines;
#ifdef ENABLE_SSL
bool show_tls_ciphers;
+ bool show_curves;
#endif
bool genkey;
#endif
@@ -213,7 +211,7 @@ struct options
/* Counts the number of unsuccessful connection attempts */
unsigned int unsuccessful_attempts;
-#if HTTP_PROXY_OVERRIDE
+#if ENABLE_MANAGEMENT
struct http_proxy_options *http_proxy_override;
#endif
@@ -275,6 +273,8 @@ struct options
#endif
int resolve_retry_seconds; /* If hostname resolve fails, retry for n seconds */
+ bool resolve_in_advance;
+ const char *ip_remote_hint;
struct tuntap_options tuntap_options;
@@ -289,6 +289,7 @@ struct options
const char *writepid;
const char *up_script;
const char *down_script;
+ bool user_script_used;
bool down_pre;
bool up_delay;
bool up_restart;
@@ -301,6 +302,7 @@ struct options
bool log;
bool suppress_timestamps;
+ bool machine_readable_output;
int nice;
int verbosity;
int mute;
@@ -316,9 +318,8 @@ struct options
/* optimize TUN/TAP/UDP writes */
bool fast_io;
-#ifdef ENABLE_LZO
- /* LZO_x flags from lzo.h */
- unsigned int lzo;
+#ifdef USE_COMP
+ struct compress_options comp;
#endif
/* buffer sizes */
@@ -340,16 +341,12 @@ struct options
int route_delay;
int route_delay_window;
bool route_delay_defined;
- int max_routes;
struct route_option_list *routes;
struct route_ipv6_option_list *routes_ipv6; /* IPv6 */
bool route_nopull;
bool route_gateway_via_dhcp;
bool allow_pull_fqdn; /* as a client, allow server to push a FQDN for certain parameters */
-
-#ifdef ENABLE_CLIENT_NAT
struct client_nat_option_list *client_nat;
-#endif
#ifdef ENABLE_OCC
/* Enable options consistency check between peers */
@@ -430,9 +427,7 @@ struct options
bool push_ifconfig_defined;
in_addr_t push_ifconfig_local;
in_addr_t push_ifconfig_remote_netmask;
-#ifdef ENABLE_CLIENT_NAT
in_addr_t push_ifconfig_local_alias;
-#endif
bool push_ifconfig_constraint_defined;
in_addr_t push_ifconfig_constraint_network;
in_addr_t push_ifconfig_constraint_netmask;
@@ -461,6 +456,7 @@ struct options
bool client;
bool pull; /* client pull of config options from server */
int push_continuation;
+ unsigned int push_option_types_found;
const char *auth_user_pass_file;
struct options_pre_pull *pre_pull;
@@ -509,9 +505,11 @@ struct options
const char *priv_key_file;
const char *pkcs12_file;
const char *cipher_list;
+ const char *ecdh_curve;
const char *tls_verify;
+ int verify_x509_type;
+ const char *verify_x509_name;
const char *tls_export_cert;
- const char *tls_remote;
const char *crl_file;
const char *ca_file_inline;
@@ -682,6 +680,8 @@ void notnull (const char *arg, const char *description);
void usage_small (void);
+void show_library_versions(const unsigned int flags);
+
void init_options (struct options *o, const bool init_gc);
void uninit_options (struct options *o);
@@ -710,7 +710,7 @@ void options_warning (char *actual, const char *expected);
void options_postprocess (struct options *options);
void pre_pull_save (struct options *o);
-void pre_pull_restore (struct options *o);
+void pre_pull_restore (struct options *o, struct gc_arena *gc);
bool apply_push_options (struct options *options,
struct buffer *buf,
diff --git a/app/openvpn/src/openvpn/pf.c b/app/openvpn/src/openvpn/pf.c
index aafe9ff0..a3208db1 100644
--- a/app/openvpn/src/openvpn/pf.c
+++ b/app/openvpn/src/openvpn/pf.c
@@ -35,8 +35,8 @@
#if defined(ENABLE_PF)
#include "init.h"
-
#include "memdbg.h"
+#include "ssl_verify.h"
#include "pf-inline.h"
@@ -417,7 +417,7 @@ lookup_cn_rule (struct hash *h, const char *cn, const uint32_t cn_hash)
bool
pf_cn_test (struct pf_set *pfs, const struct tls_multi *tm, const int type, const char *prefix)
{
- if (!pfs->kill)
+ if (pfs && !pfs->kill)
{
const char *cn;
uint32_t cn_hash;
diff --git a/app/openvpn/src/openvpn/pkcs11_openssl.c b/app/openvpn/src/openvpn/pkcs11_openssl.c
index af843b7b..87eb166e 100644
--- a/app/openvpn/src/openvpn/pkcs11_openssl.c
+++ b/app/openvpn/src/openvpn/pkcs11_openssl.c
@@ -49,7 +49,7 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate,
int ret = 1;
X509 *x509 = NULL;
- RSA *rsa = NULL;
+ EVP_PKEY *evp = NULL;
pkcs11h_openssl_session_t openssl_session = NULL;
if ((openssl_session = pkcs11h_openssl_createSession (certificate)) == NULL)
@@ -63,9 +63,9 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate,
*/
certificate = NULL;
- if ((rsa = pkcs11h_openssl_session_getRSA (openssl_session)) == NULL)
+ if ((evp = pkcs11h_openssl_session_getEVP (openssl_session)) == NULL)
{
- msg (M_WARN, "PKCS#11: Unable get rsa object");
+ msg (M_WARN, "PKCS#11: Unable get evp object");
goto cleanup;
}
@@ -75,7 +75,7 @@ pkcs11_init_tls_session(pkcs11h_certificate_t certificate,
goto cleanup;
}
- if (!SSL_CTX_use_RSAPrivateKey (ssl_ctx->ctx, rsa))
+ if (!SSL_CTX_use_PrivateKey (ssl_ctx->ctx, evp))
{
msg (M_WARN, "PKCS#11: Cannot set private key for openssl");
goto cleanup;
@@ -108,10 +108,10 @@ cleanup:
x509 = NULL;
}
- if (rsa != NULL)
+ if (evp != NULL)
{
- RSA_free (rsa);
- rsa = NULL;
+ EVP_PKEY_free (evp);
+ evp = NULL;
}
if (openssl_session != NULL)
diff --git a/app/openvpn/src/openvpn/pkcs11_polarssl.c b/app/openvpn/src/openvpn/pkcs11_polarssl.c
index 03b2bab5..be4e9737 100644
--- a/app/openvpn/src/openvpn/pkcs11_polarssl.c
+++ b/app/openvpn/src/openvpn/pkcs11_polarssl.c
@@ -40,6 +40,7 @@
#include "errlevel.h"
#include "pkcs11_backend.h"
#include <polarssl/pkcs11.h>
+#include <polarssl/x509.h>
int
pkcs11_init_tls_session(pkcs11h_certificate_t certificate,
@@ -78,14 +79,14 @@ pkcs11_certificate_dn (pkcs11h_certificate_t cert, struct gc_arena *gc)
char *ret = NULL;
char dn[1024] = {0};
- x509_cert polar_cert = {0};
+ x509_crt polar_cert = {0};
if (pkcs11_x509_cert_init(&polar_cert, cert)) {
msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object");
goto cleanup;
}
- if (-1 == x509parse_dn_gets (dn, sizeof(dn), &polar_cert.subject)) {
+ if (-1 == x509_dn_gets (dn, sizeof(dn), &polar_cert.subject)) {
msg (M_FATAL, "PKCS#11: PolarSSL cannot parse subject");
goto cleanup;
}
@@ -93,7 +94,7 @@ pkcs11_certificate_dn (pkcs11h_certificate_t cert, struct gc_arena *gc)
ret = string_alloc(dn, gc);
cleanup:
- x509_free(&polar_cert);
+ x509_crt_free(&polar_cert);
return ret;
}
@@ -104,14 +105,14 @@ pkcs11_certificate_serial (pkcs11h_certificate_t cert, char *serial,
{
int ret = 1;
- x509_cert polar_cert = {0};
+ x509_crt polar_cert = {0};
if (pkcs11_x509_cert_init(&polar_cert, cert)) {
msg (M_FATAL, "PKCS#11: Cannot retrieve PolarSSL certificate object");
goto cleanup;
}
- if (-1 == x509parse_serial_gets (serial, serial_len, &polar_cert.serial)) {
+ if (-1 == x509_serial_gets (serial, serial_len, &polar_cert.serial)) {
msg (M_FATAL, "PKCS#11: PolarSSL cannot parse serial");
goto cleanup;
}
@@ -119,7 +120,7 @@ pkcs11_certificate_serial (pkcs11h_certificate_t cert, char *serial,
ret = 0;
cleanup:
- x509_free(&polar_cert);
+ x509_crt_free(&polar_cert);
return ret;
}
diff --git a/app/openvpn/src/openvpn/platform.c b/app/openvpn/src/openvpn/platform.c
index e79de7a7..16d4daca 100644
--- a/app/openvpn/src/openvpn/platform.c
+++ b/app/openvpn/src/openvpn/platform.c
@@ -275,34 +275,6 @@ platform_unlink (const char *filename)
#endif
}
-int platform_putenv(char *string)
-{
- int status;
-#if defined(WIN32)
- struct gc_arena gc = gc_new ();
- char *s = string_alloc(string, &gc);
- char *value = strchr(s, '=');
- if (value!=NULL)
- {
- *value = '\0';
- value++;
- if (*value == '\0')
- value = NULL;
- }
-
- status = SetEnvironmentVariableW (wide_string (s, &gc),
- wide_string (value, &gc)) ? 1: 0;
- gc_free (&gc);
-#elif defined(HAVE_PUTENV)
- void manage_env (char *str); /* TODO: Resolve properly */
- status = putenv (string);
- if (!status)
- manage_env (string);
-#endif
-
- return status;
-}
-
FILE *
platform_fopen (const char *path, const char *mode)
{
diff --git a/app/openvpn/src/openvpn/plugin.c b/app/openvpn/src/openvpn/plugin.c
index 83f79e4f..0948f238 100644
--- a/app/openvpn/src/openvpn/plugin.c
+++ b/app/openvpn/src/openvpn/plugin.c
@@ -40,8 +40,8 @@
#include "error.h"
#include "misc.h"
#include "plugin.h"
+#include "ssl_backend.h"
#include "win32.h"
-
#include "memdbg.h"
#define PLUGIN_SYMBOL_REQUIRED (1<<0)
@@ -155,7 +155,7 @@ plugin_option_list_add (struct plugin_option_list *list, char **p, struct gc_are
return false;
}
-#ifdef ENABLE_DEBUG
+#ifndef ENABLE_SMALL
void
plugin_option_list_print (const struct plugin_option_list *list, int msglevel)
{
@@ -374,7 +374,8 @@ plugin_open_item (struct plugin *p,
struct openvpn_plugin_args_open_in args = { p->plugin_type_mask,
(const char ** const) o->argv,
(const char ** const) envp,
- &callbacks };
+ &callbacks,
+ SSLAPI };
struct openvpn_plugin_args_open_return retargs;
CLEAR(retargs);
diff --git a/app/openvpn/src/openvpn/plugin.h b/app/openvpn/src/openvpn/plugin.h
index 4ba150d6..2f8416b1 100644
--- a/app/openvpn/src/openvpn/plugin.h
+++ b/app/openvpn/src/openvpn/plugin.h
@@ -108,7 +108,7 @@ struct plugin_return
struct plugin_option_list *plugin_option_list_new (struct gc_arena *gc);
bool plugin_option_list_add (struct plugin_option_list *list, char **p, struct gc_arena *gc);
-#ifdef ENABLE_DEBUG
+#ifndef ENABLE_SMALL
void plugin_option_list_print (const struct plugin_option_list *list, int msglevel);
#endif
diff --git a/app/openvpn/src/openvpn/proto.c b/app/openvpn/src/openvpn/proto.c
index b437f1ad..7b58e6ab 100644
--- a/app/openvpn/src/openvpn/proto.c
+++ b/app/openvpn/src/openvpn/proto.c
@@ -60,7 +60,7 @@ is_ipv_X ( int tunnel_type, struct buffer *buf, int ip_ver )
+ sizeof (struct openvpn_iphdr)))
return false;
eh = (const struct openvpn_ethhdr *) BPTR (buf);
- if (ntohs (eh->proto) != OPENVPN_ETH_P_IPV4)
+ if (ntohs (eh->proto) != (ip_ver == 6 ? OPENVPN_ETH_P_IPV6 : OPENVPN_ETH_P_IPV4))
return false;
offset = sizeof (struct openvpn_ethhdr);
}
diff --git a/app/openvpn/src/openvpn/proxy.c b/app/openvpn/src/openvpn/proxy.c
index 17748504..2568e191 100644
--- a/app/openvpn/src/openvpn/proxy.c
+++ b/app/openvpn/src/openvpn/proxy.c
@@ -42,8 +42,6 @@
#include "ntlm.h"
#include "memdbg.h"
-#ifdef ENABLE_HTTP_PROXY
-
#define UP_TYPE_PROXY "HTTP Proxy"
struct http_proxy_options *
@@ -439,7 +437,6 @@ struct http_proxy_info *
http_proxy_new (const struct http_proxy_options *o)
{
struct http_proxy_info *p;
- struct http_proxy_options opt;
if (!o || !o->server)
msg (M_FATAL, "HTTP_PROXY: server not specified");
@@ -490,6 +487,67 @@ http_proxy_close (struct http_proxy_info *hp)
}
bool
+add_proxy_headers (struct http_proxy_info *p,
+ socket_descriptor_t sd, /* already open to proxy */
+ const char *host, /* openvpn server remote */
+ const char* port /* openvpn server port */
+ )
+{
+ char buf[512];
+ int i;
+ bool host_header_sent=false;
+
+ /*
+ * Send custom headers if provided
+ * If content is NULL the whole header is in name
+ * Also remember if we already sent a Host: header
+ */
+ for (i=0; i < MAX_CUSTOM_HTTP_HEADER && p->options.custom_headers[i].name;i++)
+ {
+ if (p->options.custom_headers[i].content)
+ {
+ openvpn_snprintf (buf, sizeof(buf), "%s: %s",
+ p->options.custom_headers[i].name,
+ p->options.custom_headers[i].content);
+ if (!strcasecmp(p->options.custom_headers[i].name, "Host"))
+ host_header_sent=true;
+ }
+ else
+ {
+ openvpn_snprintf (buf, sizeof(buf), "%s",
+ p->options.custom_headers[i].name);
+ if (!strncasecmp(p->options.custom_headers[i].name, "Host:", 5))
+ host_header_sent=true;
+ }
+
+ msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
+ if (!send_line_crlf (sd, buf))
+ return false;
+ }
+
+ if (!host_header_sent)
+ {
+ openvpn_snprintf (buf, sizeof(buf), "Host: %s", host);
+ msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
+ if (!send_line_crlf(sd, buf))
+ return false;
+ }
+
+ /* send User-Agent string if provided */
+ if (p->options.user_agent)
+ {
+ openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s",
+ p->options.user_agent);
+ msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
+ if (!send_line_crlf (sd, buf))
+ return false;
+ }
+
+ return true;
+}
+
+
+bool
establish_http_proxy_passthru (struct http_proxy_info *p,
socket_descriptor_t sd, /* already open to proxy */
const char *host, /* openvpn server remote */
@@ -499,7 +557,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
{
struct gc_arena gc = gc_new ();
char buf[512];
- char buf2[128];
+ char buf2[129];
char get[80];
int status;
int nparms;
@@ -532,18 +590,8 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
if (!send_line_crlf (sd, buf))
goto error;
- openvpn_snprintf(buf, sizeof(buf), "Host: %s", host);
- if (!send_line_crlf(sd, buf))
- goto error;
-
- /* send User-Agent string if provided */
- if (p->options.user_agent)
- {
- openvpn_snprintf (buf, sizeof(buf), "User-Agent: %s",
- p->options.user_agent);
- if (!send_line_crlf (sd, buf))
- goto error;
- }
+ if (!add_proxy_headers (p, sd, host, port))
+ goto error;
/* auth specified? */
switch (p->auth_method)
@@ -622,7 +670,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
openvpn_snprintf (get, sizeof get, "%%*s NTLM %%%ds", (int) sizeof (buf2) - 1);
nparms = sscanf (buf, get, buf2);
- buf2[127] = 0; /* we only need the beginning - ensure it's null terminated. */
+ buf2[128] = 0; /* we only need the beginning - ensure it's null terminated. */
/* check for "Proxy-Authenticate: NTLM TlRM..." */
if (nparms == 1)
@@ -658,14 +706,11 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
if (!send_line_crlf (sd, buf))
goto error;
-
/* send HOST etc, */
- openvpn_snprintf (buf, sizeof(buf), "Host: %s", host);
- msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
- if (!send_line_crlf (sd, buf))
- goto error;
+ if (!add_proxy_headers (p, sd, host, port))
+ goto error;
- msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3");
+ msg (D_PROXY, "Attempting NTLM Proxy-Authorization phase 3");
{
const char *np3 = ntlm_phase_3 (p, buf2, &gc);
if (!np3)
@@ -771,9 +816,7 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
goto error;
/* send HOST etc, */
- openvpn_snprintf (buf, sizeof(buf), "Host: %s", host);
- msg (D_PROXY, "Send to HTTP proxy: '%s'", buf);
- if (!send_line_crlf (sd, buf))
+ if (!add_proxy_headers (p, sd, host, port))
goto error;
/* send digest response */
@@ -900,8 +943,3 @@ establish_http_proxy_passthru (struct http_proxy_info *p,
gc_free (&gc);
return ret;
}
-
-#else
-static void dummy(void) {}
-#endif /* ENABLE_HTTP_PROXY */
-
diff --git a/app/openvpn/src/openvpn/proxy.h b/app/openvpn/src/openvpn/proxy.h
index 9d75e063..4715940c 100644
--- a/app/openvpn/src/openvpn/proxy.h
+++ b/app/openvpn/src/openvpn/proxy.h
@@ -28,8 +28,6 @@
#include "buffer.h"
#include "misc.h"
-#ifdef ENABLE_HTTP_PROXY
-
/* HTTP CONNECT authentication methods */
#define HTTP_AUTH_NONE 0
#define HTTP_AUTH_BASIC 1
@@ -38,6 +36,12 @@
#define HTTP_AUTH_NTLM2 4
#define HTTP_AUTH_N 5 /* number of HTTP_AUTH methods */
+struct http_custom_header {
+ const char *name;
+ const char *content;
+};
+
+#define MAX_CUSTOM_HTTP_HEADER 10
struct http_proxy_options {
const char *server;
const char *port;
@@ -53,6 +57,7 @@ struct http_proxy_options {
const char *auth_file;
const char *http_version;
const char *user_agent;
+ struct http_custom_header custom_headers[MAX_CUSTOM_HTTP_HEADER];
};
struct http_proxy_options_simple {
@@ -87,6 +92,4 @@ bool establish_http_proxy_passthru (struct http_proxy_info *p,
uint8_t *make_base64_string2 (const uint8_t *str, int str_len, struct gc_arena *gc);
uint8_t *make_base64_string (const uint8_t *str, struct gc_arena *gc);
-#endif /* ENABLE_HTTP_PROXY */
-
#endif /* PROXY_H */
diff --git a/app/openvpn/src/openvpn/ps.c b/app/openvpn/src/openvpn/ps.c
index c1868642..6807aac0 100644
--- a/app/openvpn/src/openvpn/ps.c
+++ b/app/openvpn/src/openvpn/ps.c
@@ -340,7 +340,8 @@ journal_add (const char *journal_dir, struct proxy_connection *pc, struct proxy_
fd = platform_open (jfn, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR | S_IRGRP);
if (fd != -1)
{
- write(fd, f, strlen(f));
+ if (write(fd, f, strlen(f)) != strlen(f))
+ msg(M_WARN, "PORT SHARE: writing to journal file (%s) failed", jfn);
close (fd);
cp->jfn = jfn;
}
@@ -408,20 +409,18 @@ proxy_entry_new (struct proxy_connection **list,
struct buffer *initial_data,
const char *journal_dir)
{
- struct openvpn_sockaddr osaddr;
socket_descriptor_t sd_server;
int status;
struct proxy_connection *pc;
struct proxy_connection *cp;
/* connect to port share server */
- osaddr.addr.in4 = server_addr;
if ((sd_server = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
msg (M_WARN|M_ERRNO, "PORT SHARE PROXY: cannot create socket");
return false;
}
- status = openvpn_connect (sd_server, &osaddr, 5, NULL);
+ status = openvpn_connect (sd_server,(const struct sockaddr*) &server_addr, 5, NULL);
if (status)
{
msg (M_WARN, "PORT SHARE PROXY: connect to port-share server failed");
@@ -803,8 +802,8 @@ port_share_open (const char *host,
/*
* Get host's IP address
*/
-
- status = openvpn_getaddrinfo (GETADDR_RESOLVE|GETADDR_HOST_ORDER|GETADDR_FATAL,
+
+ status = openvpn_getaddrinfo (GETADDR_RESOLVE|GETADDR_FATAL,
host, port, 0, NULL, AF_INET, &ai);
ASSERT (status==0);
hostaddr = *((struct sockaddr_in*) ai->ai_addr);
diff --git a/app/openvpn/src/openvpn/push.c b/app/openvpn/src/openvpn/push.c
index 994b7ba7..24d12c7b 100644
--- a/app/openvpn/src/openvpn/push.c
+++ b/app/openvpn/src/openvpn/push.c
@@ -33,6 +33,7 @@
#include "push.h"
#include "options.h"
#include "ssl.h"
+#include "ssl_verify.h"
#include "manage.h"
#include "memdbg.h"
@@ -49,7 +50,8 @@ void
receive_auth_failed (struct context *c, const struct buffer *buffer)
{
msg (M_VERB0, "AUTH: Received control message: %s", BSTR(buffer));
- c->options.no_advance=true;
+ c->options.no_advance=true;
+
if (c->options.pull)
{
switch (auth_retry_get ())
@@ -202,8 +204,10 @@ incoming_push_message (struct context *c, const struct buffer *buffer)
msg (D_PUSH_ERRORS, "WARNING: Received bad push/pull message: %s", sanitize_control_message(BSTR(buffer), &gc));
else if (status == PUSH_MSG_REPLY || status == PUSH_MSG_CONTINUATION)
{
+ c->options.push_option_types_found |= option_types_found;
+
if (status == PUSH_MSG_REPLY)
- do_up (c, true, option_types_found); /* delay bringing tun/tap up until --push parms received from remote */
+ do_up (c, true, c->options.push_option_types_found ); /* delay bringing tun/tap up until --push parms received from remote */
event_timeout_clear (&c->c2.push_request_interval);
}
@@ -290,10 +294,8 @@ send_push_reply (struct context *c)
if (c->c2.push_ifconfig_defined && c->c2.push_ifconfig_local && c->c2.push_ifconfig_remote_netmask)
{
in_addr_t ifconfig_local = c->c2.push_ifconfig_local;
-#ifdef ENABLE_CLIENT_NAT
if (c->c2.push_ifconfig_local_alias)
ifconfig_local = c->c2.push_ifconfig_local_alias;
-#endif
buf_printf (&buf, ",ifconfig %s %s",
print_in_addr_t (ifconfig_local, 0, &gc),
print_in_addr_t (c->c2.push_ifconfig_remote_netmask, 0, &gc));
@@ -453,7 +455,7 @@ process_incoming_push_msg (struct context *c,
}
if (!c->c2.did_pre_pull_restore)
{
- pre_pull_restore (&c->options);
+ pre_pull_restore (&c->options, &c->c2.gc);
c->c2.did_pre_pull_restore = true;
}
if (apply_push_options (&c->options,
diff --git a/app/openvpn/src/openvpn/route.c b/app/openvpn/src/openvpn/route.c
index 8a778884..bcc6fcee 100644
--- a/app/openvpn/src/openvpn/route.c
+++ b/app/openvpn/src/openvpn/route.c
@@ -49,7 +49,7 @@
#define METRIC_NOT_USED ((DWORD)-1)
#endif
-static void delete_route (struct route *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es);
+static void delete_route (struct route_ipv4 *r, const struct tuntap *tt, unsigned int flags, const struct route_gateway_info *rgi, const struct env_set *es);
static void get_bypass_addresses (struct route_bypass *rb, const unsigned int flags);
@@ -92,80 +92,66 @@ add_bypass_address (struct route_bypass *rb, const in_addr_t a)
}
struct route_option_list *
-new_route_option_list (const int max_routes, struct gc_arena *a)
+new_route_option_list (struct gc_arena *a)
{
struct route_option_list *ret;
- ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_option_list, struct route_option, max_routes, a);
- ret->capacity = max_routes;
+ ALLOC_OBJ_CLEAR_GC (ret, struct route_option_list, a);
+ ret->gc = a;
return ret;
}
struct route_ipv6_option_list *
-new_route_ipv6_option_list (const int max_routes, struct gc_arena *a)
+new_route_ipv6_option_list (struct gc_arena *a)
{
struct route_ipv6_option_list *ret;
- ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_option_list, struct route_ipv6_option, max_routes, a);
- ret->capacity = max_routes;
+ ALLOC_OBJ_CLEAR_GC (ret, struct route_ipv6_option_list, a);
+ ret->gc = a;
return ret;
}
+/*
+ * NOTE: structs are cloned/copied shallow by design.
+ * The routes list from src will stay intact since it is allocated using
+ * the options->gc. The cloned/copied lists will share this common tail
+ * to avoid copying the data around between pulls. Pulled routes use
+ * the c2->gc so they get freed immediately after a reconnect.
+ */
struct route_option_list *
clone_route_option_list (const struct route_option_list *src, struct gc_arena *a)
{
- const size_t rl_size = array_mult_safe (sizeof(struct route_option), src->capacity, sizeof(struct route_option_list));
- struct route_option_list *ret = gc_malloc (rl_size, false, a);
- memcpy (ret, src, rl_size);
+ struct route_option_list *ret;
+ ALLOC_OBJ_GC (ret, struct route_option_list, a);
+ *ret = *src;
return ret;
}
struct route_ipv6_option_list *
clone_route_ipv6_option_list (const struct route_ipv6_option_list *src, struct gc_arena *a)
{
- const size_t rl_size = array_mult_safe (sizeof(struct route_ipv6_option), src->capacity, sizeof(struct route_ipv6_option_list));
- struct route_ipv6_option_list *ret = gc_malloc (rl_size, false, a);
- memcpy (ret, src, rl_size);
+ struct route_ipv6_option_list *ret;
+ ALLOC_OBJ_GC (ret, struct route_ipv6_option_list, a);
+ *ret = *src;
return ret;
}
void
-copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src)
+copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src, struct gc_arena *a)
{
- const size_t src_size = array_mult_safe (sizeof(struct route_option), src->capacity, sizeof(struct route_option_list));
- if (src->capacity > dest->capacity)
- msg (M_FATAL, PACKAGE_NAME " ROUTE: (copy) number of route options in src (%d) is greater than route list capacity in dest (%d)", src->capacity, dest->capacity);
- memcpy (dest, src, src_size);
+ *dest = *src;
+ dest->gc = a;
}
void
copy_route_ipv6_option_list (struct route_ipv6_option_list *dest,
- const struct route_ipv6_option_list *src)
-{
- const size_t src_size = array_mult_safe (sizeof(struct route_ipv6_option), src->capacity, sizeof(struct route_ipv6_option_list));
- if (src->capacity > dest->capacity)
- msg (M_FATAL, PACKAGE_NAME " ROUTE: (copy) number of route options in src (%d) is greater than route list capacity in dest (%d)", src->capacity, dest->capacity);
- memcpy (dest, src, src_size);
-}
-
-struct route_list *
-new_route_list (const int max_routes, struct gc_arena *a)
-{
- struct route_list *ret;
- ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_list, struct route, max_routes, a);
- ret->capacity = max_routes;
- return ret;
-}
-
-struct route_ipv6_list *
-new_route_ipv6_list (const int max_routes, struct gc_arena *a)
+ const struct route_ipv6_option_list *src,
+ struct gc_arena *a)
{
- struct route_ipv6_list *ret;
- ALLOC_VAR_ARRAY_CLEAR_GC (ret, struct route_ipv6_list, struct route_ipv6, max_routes, a);
- ret->capacity = max_routes;
- return ret;
+ *dest = *src;
+ dest->gc = a;
}
static const char *
-route_string (const struct route *r, struct gc_arena *gc)
+route_string (const struct route_ipv4 *r, struct gc_arena *gc)
{
struct buffer out = alloc_buf_gc (256, gc);
buf_printf (&out, "ROUTE network %s netmask %s gateway %s",
@@ -267,7 +253,7 @@ is_special_addr (const char *addr_str)
}
static bool
-init_route (struct route *r,
+init_route (struct route_ipv4 *r,
struct addrinfo **network_list,
const struct route_option *ro,
const struct route_list *rl)
@@ -452,15 +438,14 @@ add_route_to_option_list (struct route_option_list *l,
const char *metric)
{
struct route_option *ro;
- if (l->n >= l->capacity)
- msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d routes -- please increase the max-routes option in the client configuration file",
- l->capacity);
- ro = &l->routes[l->n];
+ ALLOC_OBJ_GC (ro, struct route_option, l->gc);
ro->network = network;
ro->netmask = netmask;
ro->gateway = gateway;
ro->metric = metric;
- ++l->n;
+ ro->next = l->routes;
+ l->routes = ro;
+
}
void
@@ -470,32 +455,26 @@ add_route_ipv6_to_option_list (struct route_ipv6_option_list *l,
const char *metric)
{
struct route_ipv6_option *ro;
- if (l->n >= l->capacity)
- msg (M_FATAL, PACKAGE_NAME " ROUTE: cannot add more than %d IPv6 routes -- please increase the max-routes option in the client configuration file",
- l->capacity);
- ro = &l->routes_ipv6[l->n];
+ ALLOC_OBJ_GC (ro, struct route_ipv6_option, l->gc);
ro->prefix = prefix;
ro->gateway = gateway;
ro->metric = metric;
- ++l->n;
+ ro->next = l->routes_ipv6;
+ l->routes_ipv6 = ro;
}
void
clear_route_list (struct route_list *rl)
{
- const int capacity = rl->capacity;
- const size_t rl_size = array_mult_safe (sizeof(struct route), capacity, sizeof(struct route_list));
- memset(rl, 0, rl_size);
- rl->capacity = capacity;
+ gc_free (&rl->gc);
+ CLEAR (*rl);
}
void
clear_route_ipv6_list (struct route_ipv6_list *rl6)
{
- const int capacity = rl6->capacity;
- const size_t rl6_size = array_mult_safe (sizeof(struct route_ipv6), capacity, sizeof(struct route_ipv6_list));
- memset(rl6, 0, rl6_size);
- rl6->capacity = capacity;
+ gc_free (&rl6->gc);
+ CLEAR (*rl6);
}
void
@@ -503,6 +482,7 @@ route_list_add_vpn_gateway (struct route_list *rl,
struct env_set *es,
const in_addr_t addr)
{
+ ASSERT(rl);
rl->spec.remote_endpoint = addr;
rl->spec.flags |= RTSA_REMOTE_ENDPOINT;
setenv_route_addr (es, "vpn_gateway", rl->spec.remote_endpoint, -1);
@@ -515,26 +495,76 @@ add_block_local_item (struct route_list *rl,
{
const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED);
if ((rl->rgi.flags & rgi_needed) == rgi_needed
- && rl->rgi.gateway.netmask < 0xFFFFFFFF
- && (rl->n)+2 <= rl->capacity)
+ && rl->rgi.gateway.netmask < 0xFFFFFFFF)
{
- struct route r;
+ struct route_ipv4 *r1, *r2;
unsigned int l2;
+ ALLOC_OBJ_GC (r1, struct route_ipv4, &rl->gc);
+ ALLOC_OBJ_GC (r2, struct route_ipv4, &rl->gc);
+
/* split a route into two smaller blocking routes, and direct them to target */
- CLEAR(r);
- r.flags = RT_DEFINED;
- r.gateway = target;
- r.network = gateway->addr & gateway->netmask;
l2 = ((~gateway->netmask)+1)>>1;
- r.netmask = ~(l2-1);
- rl->routes[rl->n++] = r;
- r.network += l2;
- rl->routes[rl->n++] = r;
+ r1->flags = RT_DEFINED;
+ r1->gateway = target;
+ r1->network = gateway->addr & gateway->netmask;
+ r1->netmask = ~(l2-1);
+ r1->next = rl->routes;
+ rl->routes = r1;
+
+ *r2 = *r1;
+ r2->network += l2;
+ r2->next = rl->routes;
+ rl->routes = r2;
}
}
static void
+add_unblock_local (struct route_list *rl)
+{
+ const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED);
+
+ if (rl->flags & RG_UNBLOCK_LOCAL
+ && (rl->rgi.flags & rgi_needed) == rgi_needed)
+ {
+ /* unblock access to local subnet */
+ struct route_ipv4 *r;
+
+ ALLOC_OBJ_GC (r, struct route_ipv4, &rl->gc);
+ int i;
+
+ CLEAR(*r);
+ r->flags = RT_DEFINED;
+ r->network = rl->rgi.gateway.addr & rl->rgi.gateway.netmask;
+ r->netmask = rl->rgi.gateway.netmask;
+ r->gateway = rl->rgi.gateway.addr;
+ r->next = rl->routes;
+ rl->routes = r;
+
+ /* Additional local networks */
+ for (i = 0; i < rl->rgi.n_addrs; ++i)
+ {
+ const struct route_gateway_address *gwa = &rl->rgi.addrs[i];
+
+ /* omit the add/subnet in &rl->rgi which we processed above */
+ if (!((rl->rgi.gateway.addr & rl->rgi.gateway.netmask) == (gwa->addr & gwa->netmask)
+ && rl->rgi.gateway.netmask == gwa->netmask))
+ {
+ ALLOC_OBJ_GC (r, struct route_ipv4, &rl->gc);
+ CLEAR(*r);
+ r->flags = RT_DEFINED;
+ r->network = gwa->addr & gwa->netmask;
+ r->netmask = gwa->netmask;
+ r->gateway = gwa->addr;
+ r->next = rl->routes;
+ rl->routes=r;
+ }
+ }
+ }
+}
+
+
+static void
add_block_local (struct route_list *rl)
{
const int rgi_needed = (RGI_ADDR_DEFINED|RGI_NETMASK_DEFINED);
@@ -545,8 +575,10 @@ add_block_local (struct route_list *rl)
{
size_t i;
+#ifndef TARGET_ANDROID
/* add bypass for gateway addr */
add_bypass_address (&rl->spec.bypass, rl->rgi.gateway.addr);
+#endif
/* block access to local subnet */
add_block_local_item (rl, &rl->rgi.gateway, rl->spec.remote_endpoint);
@@ -563,6 +595,8 @@ add_block_local (struct route_list *rl)
}
}
+
+
bool
init_route_list (struct route_list *rl,
const struct route_option_list *opt,
@@ -594,7 +628,7 @@ init_route_list (struct route_list *rl,
if (rl->rgi.flags & RGI_ADDR_DEFINED)
{
setenv_route_addr (es, "net_gateway", rl->rgi.gateway.addr, -1);
-#ifdef ENABLE_DEBUG
+#if defined(ENABLE_DEBUG) && !defined(ENABLE_SMALL)
print_default_gateway (D_ROUTE, &rl->rgi);
#endif
}
@@ -631,6 +665,8 @@ init_route_list (struct route_list *rl,
}
}
+
+ add_unblock_local (rl);
if (rl->flags & RG_ENABLE)
{
add_block_local (rl);
@@ -642,42 +678,29 @@ init_route_list (struct route_list *rl,
/* parse the routes from opt to rl */
{
- int i = 0;
- int j = rl->n;
- bool warned = false;
- for (i = 0; i < opt->n; ++i)
+ struct route_option *ro;
+ for (ro = opt->routes; ro; ro = ro->next)
{
struct addrinfo* netlist;
- struct route r;
+ struct route_ipv4 r;
- if (!init_route (&r,
- &netlist,
- &opt->routes[i],
- rl))
+ if (!init_route (&r, &netlist, ro, rl))
ret = false;
else
{
struct addrinfo* curele;
+ gc_addspecial(netlist, &gc_freeaddrinfo_callback, &gc);
for (curele = netlist; curele; curele = curele->ai_next)
{
- if (j < rl->capacity)
- {
- r.network = ntohl(((struct sockaddr_in*)(curele)->ai_addr)->sin_addr.s_addr);
- rl->routes[j++] = r;
- }
- else
- {
- if (!warned)
- {
- msg (M_WARN, PACKAGE_NAME " ROUTE: routes dropped because number of expanded routes is greater than route list capacity (%d)", rl->capacity);
- warned = true;
- }
- }
+ struct route_ipv4 *new;
+ ALLOC_OBJ_GC (new, struct route_ipv4, &rl->gc);
+ *new = r;
+ new->network = ntohl (((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr);
+ new->next = rl->routes;
+ rl->routes = new;
}
- freeaddrinfo(netlist);
}
}
- rl->n = j;
}
gc_free (&gc);
@@ -728,22 +751,21 @@ init_route_ipv6_list (struct route_ipv6_list *rl6,
rl6->remote_endpoint_defined = false;
- if (!(opt6->n >= 0 && opt6->n <= rl6->capacity))
- msg (M_FATAL, PACKAGE_NAME " ROUTE6: (init) number of route options (%d) is greater than route list capacity (%d)", opt6->n, rl6->capacity);
-
- /* parse the routes from opt to rl6 */
+ /* parse the routes from opt6 to rl6 */
{
- int i, j = 0;
- for (i = 0; i < opt6->n; ++i)
+ struct route_ipv6_option *ro6;
+ for (ro6 = opt6->routes_ipv6; ro6; ro6 = ro6->next)
{
- if (!init_route_ipv6 (&rl6->routes_ipv6[j],
- &opt6->routes_ipv6[i],
- rl6 ))
+ struct route_ipv6 *r6;
+ ALLOC_OBJ_GC (r6, struct route_ipv6, &rl6->gc);
+ if (!init_route_ipv6 (r6, ro6, rl6))
ret = false;
else
- ++j;
+ {
+ r6->next = rl6->routes_ipv6;
+ rl6->routes_ipv6 = r6;
+ }
}
- rl6->n = j;
}
gc_free (&gc);
@@ -759,7 +781,7 @@ add_route3 (in_addr_t network,
const struct route_gateway_info *rgi,
const struct env_set *es)
{
- struct route r;
+ struct route_ipv4 r;
CLEAR (r);
r.flags = RT_DEFINED;
r.network = network;
@@ -777,7 +799,7 @@ del_route3 (in_addr_t network,
const struct route_gateway_info *rgi,
const struct env_set *es)
{
- struct route r;
+ struct route_ipv4 r;
CLEAR (r);
r.flags = RT_DEFINED|RT_ADDED;
r.network = network;
@@ -851,6 +873,7 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u
}
else
{
+#ifndef TARGET_ANDROID
bool local = BOOL_CAST(rl->flags & RG_LOCAL);
if (rl->flags & RG_AUTO_LOCAL) {
const int tla = rl->spec.remote_host_local;
@@ -883,6 +906,7 @@ redirect_default_route_to_vpn (struct route_list *rl, const struct tuntap *tt, u
dmsg (D_ROUTE, "ROUTE remote_host protocol differs from tunneled");
}
}
+#endif
/* route DHCP/DNS server traffic through original default gateway */
add_bypass_routes (&rl->spec.bypass, rl->rgi.gateway.addr, tt, flags, &rl->rgi, es);
@@ -1012,10 +1036,10 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun
redirect_default_route_to_vpn (rl, tt, flags, es);
if ( rl && !(rl->iflags & RL_ROUTES_ADDED) )
{
- int i;
+ struct route_ipv4 *r;
#ifdef ENABLE_MANAGEMENT
- if (management && rl->n)
+ if (management && rl->routes)
{
management_set_state (management,
OPENVPN_STATE_ADD_ROUTES,
@@ -1024,10 +1048,9 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun
0);
}
#endif
-
- for (i = 0; i < rl->n; ++i)
+
+ for (r = rl->routes; r; r = r->next)
{
- struct route *r = &rl->routes[i];
check_subnet_conflict (r->network, r->netmask, "route");
if (flags & ROUTE_DELETE_FIRST)
delete_route (r, tt, flags, &rl->rgi, es);
@@ -1037,11 +1060,9 @@ add_routes (struct route_list *rl, struct route_ipv6_list *rl6, const struct tun
}
if (rl6 && !rl6->routes_added)
{
- int i;
-
- for (i = 0; i < rl6->n; ++i)
+ struct route_ipv6 *r;
+ for (r = rl6->routes_ipv6; r; r = r->next)
{
- struct route_ipv6 *r = &rl6->routes_ipv6[i];
if (flags & ROUTE_DELETE_FIRST)
delete_route_ipv6 (r, tt, flags, es);
add_route_ipv6 (r, tt, flags, es);
@@ -1056,10 +1077,9 @@ delete_routes (struct route_list *rl, struct route_ipv6_list *rl6,
{
if ( rl && rl->iflags & RL_ROUTES_ADDED )
{
- int i;
- for (i = rl->n - 1; i >= 0; --i)
+ struct route_ipv4 *r;
+ for (r = rl->routes; r; r = r->next)
{
- struct route * r = &rl->routes[i];
delete_route (r, tt, flags, &rl->rgi, es);
}
rl->iflags &= ~RL_ROUTES_ADDED;
@@ -1074,10 +1094,9 @@ delete_routes (struct route_list *rl, struct route_ipv6_list *rl6,
if ( rl6 && rl6->routes_added )
{
- int i;
- for (i = rl6->n - 1; i >= 0; --i)
+ struct route_ipv6 *r6;
+ for (r6 = rl6->routes_ipv6; r6; r6 = r6->next)
{
- const struct route_ipv6 *r6 = &rl6->routes_ipv6[i];
delete_route_ipv6 (r6, tt, flags, es);
}
rl6->routes_added = false;
@@ -1089,7 +1108,7 @@ delete_routes (struct route_list *rl, struct route_ipv6_list *rl6,
}
}
-#ifdef ENABLE_DEBUG
+#ifndef ENABLE_SMALL
static const char *
show_opt (const char *option)
@@ -1114,12 +1133,12 @@ void
print_route_options (const struct route_option_list *rol,
int level)
{
- int i;
+ struct route_option *ro;
if (rol->flags & RG_ENABLE)
msg (level, " [redirect_default_gateway local=%d]",
(rol->flags & RG_LOCAL) != 0);
- for (i = 0; i < rol->n; ++i)
- print_route_option (&rol->routes[i], level);
+ for (ro = rol->routes; ro; ro = ro->next)
+ print_route_option (ro, level);
}
void
@@ -1153,7 +1172,7 @@ print_default_gateway(const int msglevel, const struct route_gateway_info *rgi)
#endif
static void
-print_route (const struct route *r, int level)
+print_route (const struct route_ipv4 *r, int level)
{
struct gc_arena gc = gc_new ();
if (r->flags & RT_DEFINED)
@@ -1164,13 +1183,13 @@ print_route (const struct route *r, int level)
void
print_routes (const struct route_list *rl, int level)
{
- int i;
- for (i = 0; i < rl->n; ++i)
- print_route (&rl->routes[i], level);
+ struct route_ipv4 *r;
+ for (r = rl->routes; r; r = r->next)
+ print_route (r, level);
}
static void
-setenv_route (struct env_set *es, const struct route *r, int i)
+setenv_route (struct env_set *es, const struct route_ipv4 *r, int i)
{
struct gc_arena gc = gc_new ();
if (r->flags & RT_DEFINED)
@@ -1192,9 +1211,10 @@ setenv_route (struct env_set *es, const struct route *r, int i)
void
setenv_routes (struct env_set *es, const struct route_list *rl)
{
- int i;
- for (i = 0; i < rl->n; ++i)
- setenv_route (es, &rl->routes[i], i + 1);
+ int i = 1;
+ struct route_ipv4 *r;
+ for (r = rl->routes; r; r = r->next)
+ setenv_route (es, r, i++);
}
static void
@@ -1220,9 +1240,10 @@ setenv_route_ipv6 (struct env_set *es, const struct route_ipv6 *r6, int i)
void
setenv_routes_ipv6 (struct env_set *es, const struct route_ipv6_list *rl6)
{
- int i;
- for (i = 0; i < rl6->n; ++i)
- setenv_route_ipv6 (es, &rl6->routes_ipv6[i], i + 1);
+ int i = 1;
+ struct route_ipv6 *r6;
+ for (r6 = rl6->routes_ipv6; r6; r6 = r6->next)
+ setenv_route_ipv6 (es, r6, i++);
}
/*
@@ -1287,7 +1308,7 @@ is_on_link (const int is_local_route, const unsigned int flags, const struct rou
}
void
-add_route (struct route *r,
+add_route (struct route_ipv4 *r,
const struct tuntap *tt,
unsigned int flags,
const struct route_gateway_info *rgi, /* may be NULL */
@@ -1343,15 +1364,13 @@ add_route (struct route *r,
status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route add command failed");
#elif defined (TARGET_ANDROID)
+ struct buffer out = alloc_buf_gc (128, &gc);
- struct user_pass up;
- struct buffer out = alloc_buf_gc (64, &gc);
-
- buf_printf (&out, "%s %s", network, netmask);
-
- strcpy(up.username, buf_bptr(&out));
- management_query_user_pass(management, &up , "ROUTE", GET_USER_PASS_NEED_OK,(void*) 0);
-
+ if (rgi)
+ buf_printf (&out, "%s %s %s dev %s", network, netmask, gateway, rgi->iface);
+ else
+ buf_printf (&out, "%s %s %s", network, netmask, gateway);
+ management_android_control (management, "ROUTE", buf_bptr(&out));
#elif defined (WIN32)
{
@@ -1408,17 +1427,20 @@ add_route (struct route *r,
argv_printf (&argv, "%s add",
ROUTE_PATH);
-#if 0
- if (r->flags & RT_METRIC_DEFINED)
- argv_printf_cat (&argv, "-rtt %d", r->metric);
-#endif
-
argv_printf_cat (&argv, "%s -netmask %s %s",
network,
netmask,
gateway);
- /* FIXME -- add on-link support for Solaris */
+ /* Solaris can only distinguish between "metric 0" == "on-link on the
+ * interface where the IP address given is configured" and "metric > 0"
+ * == "use gateway specified" (no finer-grained route metrics available)
+ *
+ * More recent versions of Solaris can also do "-interface", but that
+ * would break backwards compatibility with older versions for no gain.
+ */
+ if (r->flags & RT_METRIC_DEFINED )
+ argv_printf_cat (&argv, "%d", r->metric);
argv_msg (D_ROUTE, &argv);
status = openvpn_execve_check (&argv, es, 0, "ERROR: Solaris route add command failed");
@@ -1625,13 +1647,11 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
status = openvpn_execve_check (&argv, es, 0, "ERROR: Linux route -6/-A inet6 add command failed");
#elif defined (TARGET_ANDROID)
- struct user_pass up;
struct buffer out = alloc_buf_gc (64, &gc);
-
- buf_printf (&out, "%s/%d", network, r6->netbits);
-
- strcpy(up.username, buf_bptr(&out));
- management_query_user_pass(management, &up , "ROUTE6", GET_USER_PASS_NEED_OK,(void*) 0);
+
+ buf_printf (&out, "%s/%d %s", network, r6->netbits, device);
+
+ management_android_control (management, "ROUTE6", buf_bptr(&out));
#elif defined (WIN32)
@@ -1744,7 +1764,7 @@ add_route_ipv6 (struct route_ipv6 *r6, const struct tuntap *tt, unsigned int fla
}
static void
-delete_route (struct route *r,
+delete_route (struct route_ipv4 *r,
const struct tuntap *tt,
unsigned int flags,
const struct route_gateway_info *rgi,
@@ -1991,10 +2011,16 @@ delete_route_ipv6 (const struct route_ipv6 *r6, const struct tuntap *tt, unsigne
argv_printf_cat (&argv, "METRIC %d", r->metric);
#endif
+ /* Windows XP to 7 "just delete" routes, wherever they came from, but
+ * in Windows 8(.1?), if you create them with "store=active", this is
+ * how you should delete them as well (pointed out by Cedric Tabary)
+ */
+ argv_printf_cat( &argv, " store=active" );
+
argv_msg (D_ROUTE, &argv);
netcmd_semaphore_lock ();
- openvpn_execve_check (&argv, es, 0, "ERROR: Windows route add ipv6 command failed");
+ openvpn_execve_check (&argv, es, 0, "ERROR: Windows route delete ipv6 command failed");
netcmd_semaphore_release ();
#elif defined (TARGET_SOLARIS)
@@ -2140,6 +2166,7 @@ test_routes (const struct route_list *rl, const struct tuntap *tt)
int count = 0;
int good = 0;
int ambig = 0;
+ int len = -1;
bool adapter_up = false;
if (is_adapter_up (tt, adapters))
@@ -2149,9 +2176,9 @@ test_routes (const struct route_list *rl, const struct tuntap *tt)
if (rl)
{
- int i;
- for (i = 0; i < rl->n; ++i)
- test_route_helper (&ret, &count, &good, &ambig, adapters, rl->routes[i].gateway);
+ struct route_ipv4 *r;
+ for (r = rl->routes, len = 0; r; r = r->next, ++len)
+ test_route_helper (&ret, &count, &good, &ambig, adapters, r->gateway);
if ((rl->flags & RG_ENABLE) && (rl->spec.flags & RTSA_REMOTE_ENDPOINT))
test_route_helper (&ret, &count, &good, &ambig, adapters, rl->spec.remote_endpoint);
@@ -2161,7 +2188,7 @@ test_routes (const struct route_list *rl, const struct tuntap *tt)
msg (D_ROUTE, "TEST ROUTES: %d/%d succeeded len=%d ret=%d a=%d u/d=%s",
good,
count,
- rl ? rl->n : -1,
+ len,
(int)ret,
ambig,
adapter_up ? "up" : "down");
@@ -2249,7 +2276,7 @@ get_default_gateway (struct route_gateway_info *rgi)
}
static DWORD
-windows_route_find_if_index (const struct route *r, const struct tuntap *tt)
+windows_route_find_if_index (const struct route_ipv4 *r, const struct tuntap *tt)
{
struct gc_arena gc = gc_new ();
DWORD ret = TUN_ADAPTER_INDEX_INVALID;
@@ -2294,7 +2321,7 @@ windows_route_find_if_index (const struct route *r, const struct tuntap *tt)
}
bool
-add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_index)
+add_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index)
{
struct gc_arena gc = gc_new ();
bool ret = false;
@@ -2368,7 +2395,7 @@ add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_i
}
bool
-del_route_ipapi (const struct route *r, const struct tuntap *tt)
+del_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt)
{
struct gc_arena gc = gc_new ();
bool ret = false;
@@ -2609,164 +2636,9 @@ get_default_gateway (struct route_gateway_info *rgi)
gc_free (&gc);
}
-#elif defined(TARGET_FREEBSD)||defined(TARGET_DRAGONFLY)
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-/* all of this is taken from <net/route.h> in FreeBSD */
-#define RTA_DST 0x1
-#define RTA_GATEWAY 0x2
-#define RTA_NETMASK 0x4
-
-#define RTM_GET 0x4
-#define RTM_VERSION 5
-
-#define RTF_UP 0x1
-#define RTF_GATEWAY 0x2
-
-/*
- * These numbers are used by reliable protocols for determining
- * retransmission behavior and are included in the routing structure.
- */
-struct rt_metrics {
- u_long rmx_locks; /* Kernel must leave these values alone */
- u_long rmx_mtu; /* MTU for this path */
- u_long rmx_hopcount; /* max hops expected */
- u_long rmx_expire; /* lifetime for route, e.g. redirect */
- u_long rmx_recvpipe; /* inbound delay-bandwidth product */
- u_long rmx_sendpipe; /* outbound delay-bandwidth product */
- u_long rmx_ssthresh; /* outbound gateway buffer limit */
- u_long rmx_rtt; /* estimated round trip time */
- u_long rmx_rttvar; /* estimated rtt variance */
- u_long rmx_pksent; /* packets sent using this route */
- u_long rmx_filler[4]; /* will be used for T/TCP later */
-};
-
-/*
- * Structures for routing messages.
- */
-struct rt_msghdr {
- u_short rtm_msglen; /* to skip over non-understood messages */
- u_char rtm_version; /* future binary compatibility */
- u_char rtm_type; /* message type */
- u_short rtm_index; /* index for associated ifp */
- int rtm_flags; /* flags, incl. kern & message, e.g. DONE */
- int rtm_addrs; /* bitmask identifying sockaddrs in msg */
- pid_t rtm_pid; /* identify sender */
- int rtm_seq; /* for sender to identify action */
- int rtm_errno; /* why failed */
- int rtm_use; /* from rtentry */
- u_long rtm_inits; /* which metrics we are initializing */
- struct rt_metrics rtm_rmx; /* metrics themselves */
-};
-
-struct {
- struct rt_msghdr m_rtm;
- char m_space[512];
-} m_rtmsg;
-
-#define ROUNDUP(a) \
- ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-
-/*
- * FIXME -- add support for netmask, hwaddr, and iface
- */
-void
-get_default_gateway (struct route_gateway_info *rgi)
-{
- struct gc_arena gc = gc_new ();
- int s, seq, l, pid, rtm_addrs, i;
- struct sockaddr so_dst, so_mask;
- char *cp = m_rtmsg.m_space;
- struct sockaddr *gate = NULL, *sa;
- struct rt_msghdr *rtm_aux;
-
-#define NEXTADDR(w, u) \
- if (rtm_addrs & (w)) {\
- l = ROUNDUP(u.sa_len); memmove(cp, &(u), l); cp += l;\
- }
-
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-
-#define rtm m_rtmsg.m_rtm
-
- CLEAR(*rgi);
-
- pid = getpid();
- seq = 0;
- rtm_addrs = RTA_DST | RTA_NETMASK;
-
- bzero(&so_dst, sizeof(so_dst));
- bzero(&so_mask, sizeof(so_mask));
- bzero(&rtm, sizeof(struct rt_msghdr));
-
- rtm.rtm_type = RTM_GET;
- rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
- rtm.rtm_version = RTM_VERSION;
- rtm.rtm_seq = ++seq;
- rtm.rtm_addrs = rtm_addrs;
-
- so_dst.sa_family = AF_INET;
- so_dst.sa_len = sizeof(struct sockaddr_in);
- so_mask.sa_family = AF_INET;
- so_mask.sa_len = sizeof(struct sockaddr_in);
-
- NEXTADDR(RTA_DST, so_dst);
- NEXTADDR(RTA_NETMASK, so_mask);
-
- rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
-
- s = socket(PF_ROUTE, SOCK_RAW, 0);
-
- if (write(s, (char *)&m_rtmsg, l) < 0)
- {
- msg(M_WARN|M_ERRNO, "Could not retrieve default gateway from route socket:");
- gc_free (&gc);
- close(s);
- return;
- }
-
- do {
- l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
- } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
-
- close(s);
-
- rtm_aux = &rtm;
-
- cp = ((char *)(rtm_aux + 1));
- if (rtm_aux->rtm_addrs) {
- for (i = 1; i; i <<= 1)
- if (i & rtm_aux->rtm_addrs) {
- sa = (struct sockaddr *)cp;
- if (i == RTA_GATEWAY )
- gate = sa;
- ADVANCE(cp, sa);
- }
- }
- else
- {
- gc_free (&gc);
- return;
- }
-
-
- if (gate != NULL )
- {
- rgi->gateway.addr = ntohl(((struct sockaddr_in *)gate)->sin_addr.s_addr);
- rgi->flags |= RGI_ADDR_DEFINED;
-
- gc_free (&gc);
- }
- else
- {
- gc_free (&gc);
- }
-}
-
-#elif defined(TARGET_DARWIN)
+#elif defined(TARGET_DARWIN) || \
+ defined(TARGET_FREEBSD) || defined(TARGET_DRAGONFLY) || \
+ defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
#include <sys/types.h>
#include <sys/socket.h>
@@ -2779,8 +2651,25 @@ struct rtmsg {
char m_space[512];
};
-#define ROUNDUP(a) \
+/* the route socket code is identical for all 4 supported BSDs and for
+ * MacOS X (Darwin), with one crucial difference: when going from
+ * 32 bit to 64 bit, the BSDs increased the structure size but kept
+ * source code compatibility by keeping the use of "long", while
+ * MacOS X decided to keep binary compatibility by *changing* the API
+ * to use "uint32_t", thus 32 bit on all OS X variants
+ *
+ * We used to have a large amount of duplicate code here which really
+ * differed only in this (long) vs. (uint32_t) - IMHO, worse than
+ * having a combined block for all BSDs with this single #ifdef inside
+ */
+
+#if defined(TARGET_DARWIN)
+# define ROUNDUP(a) \
((a) > 0 ? (1 + (((a) - 1) | (sizeof(uint32_t) - 1))) : sizeof(uint32_t))
+#else
+# define ROUNDUP(a) \
+ ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
+#endif
#define NEXTADDR(w, u) \
if (rtm_addrs & (w)) {\
@@ -2884,7 +2773,6 @@ get_default_gateway (struct route_gateway_info *rgi)
{
/* get interface name */
const struct sockaddr_dl *adl = (struct sockaddr_dl *) ifp;
- int len = adl->sdl_nlen;
if (adl->sdl_nlen && adl->sdl_nlen < sizeof(rgi->iface))
{
memcpy (rgi->iface, adl->sdl_data, adl->sdl_nlen);
@@ -2975,163 +2863,6 @@ get_default_gateway (struct route_gateway_info *rgi)
#undef max
-#elif defined(TARGET_OPENBSD) || defined(TARGET_NETBSD)
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-
-/* all of this is taken from <net/route.h> in OpenBSD 3.6 */
-#define RTA_DST 0x1 /* destination sockaddr present */
-#define RTA_GATEWAY 0x2 /* gateway sockaddr present */
-#define RTA_NETMASK 0x4 /* netmask sockaddr present */
-
-#define RTM_GET 0x4 /* Report Metrics */
-
-#define RTM_VERSION 3 /* Up the ante and ignore older versions */
-
-#define RTF_UP 0x1 /* route usable */
-#define RTF_GATEWAY 0x2 /* destination is a gateway */
-
-/*
- * Huge version for userland compatibility.
- */
-struct rt_metrics {
- u_long rmx_locks; /* Kernel must leave these values alone */
- u_long rmx_mtu; /* MTU for this path */
- u_long rmx_hopcount; /* max hops expected */
- u_long rmx_expire; /* lifetime for route, e.g. redirect */
- u_long rmx_recvpipe; /* inbound delay-bandwidth product */
- u_long rmx_sendpipe; /* outbound delay-bandwidth product */
- u_long rmx_ssthresh; /* outbound gateway buffer limit */
- u_long rmx_rtt; /* estimated round trip time */
- u_long rmx_rttvar; /* estimated rtt variance */
- u_long rmx_pksent; /* packets sent using this route */
-};
-
-/*
- * Structures for routing messages.
- */
-struct rt_msghdr {
- u_short rtm_msglen; /* to skip over non-understood messages */
- u_char rtm_version; /* future binary compatibility */
- u_char rtm_type; /* message type */
- u_short rtm_index; /* index for associated ifp */
- int rtm_flags; /* flags, incl. kern & message, e.g. DONE */
- int rtm_addrs; /* bitmask identifying sockaddrs in msg */
- pid_t rtm_pid; /* identify sender */
- int rtm_seq; /* for sender to identify action */
- int rtm_errno; /* why failed */
- int rtm_use; /* from rtentry */
- u_long rtm_inits; /* which metrics we are initializing */
- struct rt_metrics rtm_rmx; /* metrics themselves */
-};
-
-struct {
- struct rt_msghdr m_rtm;
- char m_space[512];
-} m_rtmsg;
-
-#define ROUNDUP(a) \
- ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) : sizeof(long))
-
-/*
- * FIXME -- add support for netmask, hwaddr, and iface
- */
-void
-get_default_gateway (struct route_gateway_info *rgi)
-{
- struct gc_arena gc = gc_new ();
- int s, seq, l, rtm_addrs, i;
- pid_t pid;
- struct sockaddr so_dst, so_mask;
- char *cp = m_rtmsg.m_space;
- struct sockaddr *gate = NULL, *sa;
- struct rt_msghdr *rtm_aux;
-
-#define NEXTADDR(w, u) \
- if (rtm_addrs & (w)) {\
- l = ROUNDUP(u.sa_len); memmove(cp, &(u), l); cp += l;\
- }
-
-#define ADVANCE(x, n) (x += ROUNDUP((n)->sa_len))
-
-#define rtm m_rtmsg.m_rtm
-
- CLEAR(*rgi);
-
- pid = getpid();
- seq = 0;
- rtm_addrs = RTA_DST | RTA_NETMASK;
-
- bzero(&so_dst, sizeof(so_dst));
- bzero(&so_mask, sizeof(so_mask));
- bzero(&rtm, sizeof(struct rt_msghdr));
-
- rtm.rtm_type = RTM_GET;
- rtm.rtm_flags = RTF_UP | RTF_GATEWAY;
- rtm.rtm_version = RTM_VERSION;
- rtm.rtm_seq = ++seq;
- rtm.rtm_addrs = rtm_addrs;
-
- so_dst.sa_family = AF_INET;
- so_dst.sa_len = sizeof(struct sockaddr_in);
- so_mask.sa_family = AF_INET;
- so_mask.sa_len = sizeof(struct sockaddr_in);
-
- NEXTADDR(RTA_DST, so_dst);
- NEXTADDR(RTA_NETMASK, so_mask);
-
- rtm.rtm_msglen = l = cp - (char *)&m_rtmsg;
-
- s = socket(PF_ROUTE, SOCK_RAW, 0);
-
- if (write(s, (char *)&m_rtmsg, l) < 0)
- {
- msg(M_WARN|M_ERRNO, "Could not retrieve default gateway from route socket:");
- gc_free (&gc);
- close(s);
- return;
- }
-
- do {
- l = read(s, (char *)&m_rtmsg, sizeof(m_rtmsg));
- } while (l > 0 && (rtm.rtm_seq != seq || rtm.rtm_pid != pid));
-
- close(s);
-
- rtm_aux = &rtm;
-
- cp = ((char *)(rtm_aux + 1));
- if (rtm_aux->rtm_addrs) {
- for (i = 1; i; i <<= 1)
- if (i & rtm_aux->rtm_addrs) {
- sa = (struct sockaddr *)cp;
- if (i == RTA_GATEWAY )
- gate = sa;
- ADVANCE(cp, sa);
- }
- }
- else
- {
- gc_free (&gc);
- return;
- }
-
-
- if (gate != NULL )
- {
- rgi->gateway.addr = ntohl(((struct sockaddr_in *)gate)->sin_addr.s_addr);
- rgi->flags |= RGI_ADDR_DEFINED;
-
- gc_free (&gc);
- }
- else
- {
- gc_free (&gc);
- }
-}
-
#else
/*
diff --git a/app/openvpn/src/openvpn/route.h b/app/openvpn/src/openvpn/route.h
index e63db595..2b1ae3e8 100644
--- a/app/openvpn/src/openvpn/route.h
+++ b/app/openvpn/src/openvpn/route.h
@@ -33,8 +33,6 @@
#include "tun.h"
#include "misc.h"
-#define MAX_ROUTES_DEFAULT 100
-
#ifdef WIN32
/*
* Windows route methods
@@ -74,6 +72,7 @@ struct route_special_addr
};
struct route_option {
+ struct route_option *next;
const char *network;
const char *netmask;
const char *gateway;
@@ -89,15 +88,16 @@ struct route_option {
#define RG_REROUTE_GW (1<<5)
#define RG_AUTO_LOCAL (1<<6)
#define RG_BLOCK_LOCAL (1<<7)
+#define RG_UNBLOCK_LOCAL (1<<8)
struct route_option_list {
unsigned int flags; /* RG_x flags */
- int capacity;
- int n;
- struct route_option routes[EMPTY_ARRAY_SIZE];
+ struct route_option *routes;
+ struct gc_arena *gc;
};
struct route_ipv6_option {
+ struct route_ipv6_option *next;
const char *prefix; /* e.g. "2001:db8:1::/64" */
const char *gateway; /* e.g. "2001:db8:0::2" */
const char *metric; /* e.g. "5" */
@@ -105,15 +105,15 @@ struct route_ipv6_option {
struct route_ipv6_option_list {
unsigned int flags;
- int capacity;
- int n;
- struct route_ipv6_option routes_ipv6[EMPTY_ARRAY_SIZE];
+ struct route_ipv6_option *routes_ipv6;
+ struct gc_arena *gc;
};
-struct route {
+struct route_ipv4 {
# define RT_DEFINED (1<<0)
# define RT_ADDED (1<<1)
# define RT_METRIC_DEFINED (1<<2)
+ struct route_ipv4 *next;
unsigned int flags;
const struct route_option *option;
in_addr_t network;
@@ -123,6 +123,7 @@ struct route {
};
struct route_ipv6 {
+ struct route_ipv6 *next;
bool defined;
struct in6_addr network;
unsigned int netbits;
@@ -140,9 +141,8 @@ struct route_ipv6_list {
bool remote_endpoint_defined;
bool did_redirect_default_gateway; /* TODO (?) */
bool did_local; /* TODO (?) */
- int capacity;
- int n;
- struct route_ipv6 routes_ipv6[EMPTY_ARRAY_SIZE];
+ struct route_ipv6 *routes_ipv6;
+ struct gc_arena gc;
};
@@ -188,9 +188,8 @@ struct route_list {
struct route_special_addr spec;
struct route_gateway_info rgi;
unsigned int flags; /* RG_x flags */
- int capacity;
- int n;
- struct route routes[EMPTY_ARRAY_SIZE];
+ struct route_ipv4 *routes;
+ struct gc_arena gc;
};
#if P2MP
@@ -208,22 +207,20 @@ struct iroute_ipv6 {
};
#endif
-struct route_option_list *new_route_option_list (const int max_routes, struct gc_arena *a);
-struct route_ipv6_option_list *new_route_ipv6_option_list (const int max_routes, struct gc_arena *a);
+struct route_option_list *new_route_option_list (struct gc_arena *a);
+struct route_ipv6_option_list *new_route_ipv6_option_list (struct gc_arena *a);
struct route_option_list *clone_route_option_list (const struct route_option_list *src, struct gc_arena *a);
struct route_ipv6_option_list *clone_route_ipv6_option_list (const struct route_ipv6_option_list *src, struct gc_arena *a);
-void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src);
+void copy_route_option_list (struct route_option_list *dest, const struct route_option_list *src, struct gc_arena *a);
void copy_route_ipv6_option_list (struct route_ipv6_option_list *dest,
- const struct route_ipv6_option_list *src);
-
-struct route_list *new_route_list (const int max_routes, struct gc_arena *a);
-struct route_ipv6_list *new_route_ipv6_list (const int max_routes, struct gc_arena *a);
+ const struct route_ipv6_option_list *src,
+ struct gc_arena *a);
void add_route_ipv6 (struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
void delete_route_ipv6 (const struct route_ipv6 *r, const struct tuntap *tt, unsigned int flags, const struct env_set *es);
-void add_route (struct route *r,
+void add_route (struct route_ipv4 *r,
const struct tuntap *tt,
unsigned int flags,
const struct route_gateway_info *rgi,
@@ -290,7 +287,7 @@ void print_default_gateway(const int msglevel, const struct route_gateway_info *
#define TLA_LOCAL 2
int test_local_addr (const in_addr_t addr, const struct route_gateway_info *rgi);
-#ifdef ENABLE_DEBUG
+#ifndef ENABLE_SMALL
void print_route_options (const struct route_option_list *rol,
int level);
#endif
@@ -301,8 +298,8 @@ void print_routes (const struct route_list *rl, int level);
void show_routes (int msglev);
bool test_routes (const struct route_list *rl, const struct tuntap *tt);
-bool add_route_ipapi (const struct route *r, const struct tuntap *tt, DWORD adapter_index);
-bool del_route_ipapi (const struct route *r, const struct tuntap *tt);
+bool add_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt, DWORD adapter_index);
+bool del_route_ipapi (const struct route_ipv4 *r, const struct tuntap *tt);
#else
static inline bool test_routes (const struct route_list *rl, const struct tuntap *tt) { return true; }
diff --git a/app/openvpn/src/openvpn/sig.c b/app/openvpn/src/openvpn/sig.c
index 7ddfd0ed..90e39a42 100644
--- a/app/openvpn/src/openvpn/sig.c
+++ b/app/openvpn/src/openvpn/sig.c
@@ -279,9 +279,9 @@ print_status (const struct context *c, struct status_output *so)
status_printf (so, "TCP/UDP read bytes," counter_format, c->c2.link_read_bytes);
status_printf (so, "TCP/UDP write bytes," counter_format, c->c2.link_write_bytes);
status_printf (so, "Auth read bytes," counter_format, c->c2.link_read_bytes_auth);
-#ifdef ENABLE_LZO
- if (lzo_defined (&c->c2.lzo_compwork))
- lzo_print_stats (&c->c2.lzo_compwork, so);
+#ifdef USE_COMP
+ if (c->c2.comp_context)
+ comp_print_stats (c->c2.comp_context, so);
#endif
#ifdef PACKET_TRUNCATION_CHECK
status_printf (so, "TUN read truncations," counter_format, c->c2.n_trunc_tun_read);
diff --git a/app/openvpn/src/openvpn/snappy.c b/app/openvpn/src/openvpn/snappy.c
new file mode 100644
index 00000000..24440bae
--- /dev/null
+++ b/app/openvpn/src/openvpn/snappy.c
@@ -0,0 +1,189 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#elif defined(_MSC_VER)
+#include "config-msvc.h"
+#endif
+
+#include "syshead.h"
+
+#if defined(ENABLE_SNAPPY)
+
+#include "snappy-c.h"
+
+#include "comp.h"
+#include "error.h"
+#include "otime.h"
+
+#include "memdbg.h"
+
+/* Initial command byte to tell our peer if we compressed */
+#define SNAPPY_COMPRESS_BYTE 0x68
+
+static void
+snap_compress_init (struct compress_context *compctx)
+{
+ msg (D_INIT_MEDIUM, "Snappy compression initializing");
+ ASSERT(compctx->flags & COMP_F_SWAP);
+}
+
+static void
+snap_compress_uninit (struct compress_context *compctx)
+{
+}
+
+static void
+snap_compress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ snappy_status status;
+ bool compressed = false;
+
+ if (buf->len <= 0)
+ return;
+
+ /*
+ * In order to attempt compression, length must be at least COMPRESS_THRESHOLD.
+ */
+ if (buf->len >= COMPRESS_THRESHOLD)
+ {
+ const size_t ps = PAYLOAD_SIZE (frame);
+ size_t zlen = ps + COMP_EXTRA_BUFFER (ps);
+
+ ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
+ ASSERT (buf_safe (&work, zlen));
+
+ if (buf->len > ps)
+ {
+ dmsg (D_COMP_ERRORS, "Snappy compression buffer overflow");
+ buf->len = 0;
+ return;
+ }
+
+ status = snappy_compress((const char *)BPTR(buf), (size_t)BLEN(buf), (char *)BPTR(&work), &zlen);
+ if (status != SNAPPY_OK)
+ {
+ dmsg (D_COMP_ERRORS, "Snappy compression error: %d", status);
+ buf->len = 0;
+ return;
+ }
+
+ ASSERT (buf_safe (&work, zlen));
+ work.len = zlen;
+ compressed = true;
+
+ dmsg (D_COMP, "Snappy compress %d -> %d", buf->len, work.len);
+ compctx->pre_compress += buf->len;
+ compctx->post_compress += work.len;
+ }
+
+ /* did compression save us anything? */
+ {
+ uint8_t comp_head_byte = NO_COMPRESS_BYTE_SWAP;
+ if (compressed && work.len < buf->len)
+ {
+ *buf = work;
+ comp_head_byte = SNAPPY_COMPRESS_BYTE;
+ }
+
+ {
+ uint8_t *head = BPTR (buf);
+ uint8_t *tail = BEND (buf);
+ ASSERT (buf_safe (buf, 1));
+ ++buf->len;
+
+ /* move head byte of payload to tail */
+ *tail = *head;
+ *head = comp_head_byte;
+ }
+ }
+}
+
+static void
+snap_decompress (struct buffer *buf, struct buffer work,
+ struct compress_context *compctx,
+ const struct frame* frame)
+{
+ size_t zlen = EXPANDED_SIZE (frame);
+ snappy_status status;
+ uint8_t c; /* flag indicating whether or not our peer compressed */
+
+ if (buf->len <= 0)
+ return;
+
+ ASSERT (buf_init (&work, FRAME_HEADROOM (frame)));
+
+ /* do unframing/swap (assumes buf->len > 0) */
+ {
+ uint8_t *head = BPTR (buf);
+ c = *head;
+ --buf->len;
+ *head = *BEND (buf);
+ }
+
+ if (c == SNAPPY_COMPRESS_BYTE) /* packet was compressed */
+ {
+ ASSERT (buf_safe (&work, zlen));
+ status = snappy_uncompress((const char *)BPTR(buf), (size_t)BLEN(buf), (char *)BPTR(&work), &zlen);
+ if (status != SNAPPY_OK)
+ {
+ dmsg (D_COMP_ERRORS, "Snappy decompression error: %d", status);
+ buf->len = 0;
+ return;
+ }
+
+ ASSERT (buf_safe (&work, zlen));
+ work.len = zlen;
+
+ dmsg (D_COMP, "Snappy decompress %d -> %d", buf->len, work.len);
+ compctx->pre_decompress += buf->len;
+ compctx->post_decompress += work.len;
+
+ *buf = work;
+ }
+ else if (c == NO_COMPRESS_BYTE_SWAP) /* packet was not compressed */
+ {
+ ;
+ }
+ else
+ {
+ dmsg (D_COMP_ERRORS, "Bad Snappy decompression header byte: %d", c);
+ buf->len = 0;
+ }
+}
+
+const struct compress_alg snappy_alg = {
+ "snappy",
+ snap_compress_init,
+ snap_compress_uninit,
+ snap_compress,
+ snap_decompress
+};
+
+#else
+static void dummy(void) {}
+#endif /* ENABLE_SNAPPY */
diff --git a/app/openvpn/src/openvpn/snappy.h b/app/openvpn/src/openvpn/snappy.h
new file mode 100644
index 00000000..361a6317
--- /dev/null
+++ b/app/openvpn/src/openvpn/snappy.h
@@ -0,0 +1,39 @@
+/*
+ * OpenVPN -- An application to securely tunnel IP networks
+ * over a single UDP port, with support for SSL/TLS-based
+ * session authentication and key exchange,
+ * packet encryption, packet authentication, and
+ * packet compression.
+ *
+ * Copyright (C) 2002-2012 OpenVPN Technologies, Inc. <sales@openvpn.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (see the file COPYING included with this
+ * distribution); if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef OPENVPN_SNAPPY_H
+#define OPENVPN_SNAPPY_H
+
+#if defined(ENABLE_SNAPPY)
+
+#include "buffer.h"
+
+extern const struct compress_alg snappy_alg;
+
+struct snappy_workspace
+{
+};
+
+#endif /* ENABLE_SNAPPY */
+#endif
diff --git a/app/openvpn/src/openvpn/socket.c b/app/openvpn/src/openvpn/socket.c
index 31ff6d21..9e6bd10c 100644
--- a/app/openvpn/src/openvpn/socket.c
+++ b/app/openvpn/src/openvpn/socket.c
@@ -39,6 +39,7 @@
#include "manage.h"
#include "misc.h"
#include "manage.h"
+#include "openvpn.h"
#include "memdbg.h"
@@ -117,6 +118,178 @@ getaddr (unsigned int flags,
}
}
+static inline bool
+streqnull (const char* a, const char* b)
+{
+ if (a == NULL && b == NULL)
+ return true;
+ else if (a == NULL || b == NULL)
+ return false;
+ else
+ return streq (a, b);
+}
+
+/*
+ get_cached_dns_entry return 0 on success and -1
+ otherwise. (like getaddrinfo)
+ */
+static int
+get_cached_dns_entry (struct cached_dns_entry* dns_cache,
+ const char* hostname,
+ const char* servname,
+ int ai_family,
+ int resolve_flags,
+ struct addrinfo **ai)
+{
+ struct cached_dns_entry *ph;
+ int flags;
+
+ /* Only use flags that are relevant for the structure */
+ flags = resolve_flags & GETADDR_CACHE_MASK;
+
+ for (ph = dns_cache; ph ; ph = ph->next)
+ {
+ if (streqnull (ph->hostname, hostname) &&
+ streqnull (ph->servname, servname) &&
+ ph->ai_family == ai_family &&
+ ph->flags == flags)
+ {
+ *ai = ph->ai;
+ return 0;
+ }
+ }
+ return -1;
+}
+
+
+static int
+do_preresolve_host (struct context *c,
+ const char *hostname,
+ const char *servname,
+ const int af,
+ const int flags)
+{
+ struct addrinfo *ai;
+ int status;
+
+ if (get_cached_dns_entry(c->c1.dns_cache,
+ hostname,
+ servname,
+ af,
+ flags,
+ &ai) == 0 )
+ {
+ /* entry already cached, return success */
+ return 0;
+ }
+
+ status = openvpn_getaddrinfo (flags, hostname, servname,
+ c->options.resolve_retry_seconds, NULL,
+ af, &ai);
+ if (status == 0)
+ {
+ struct cached_dns_entry *ph;
+
+ ALLOC_OBJ_CLEAR_GC (ph, struct cached_dns_entry, &c->gc);
+ ph->ai = ai;
+ ph->hostname = hostname;
+ ph->servname = servname;
+ ph->flags = flags & GETADDR_CACHE_MASK;
+
+ if (!c->c1.dns_cache)
+ c->c1.dns_cache = ph;
+ else
+ {
+ struct cached_dns_entry *prev = c->c1.dns_cache;
+ while (prev->next)
+ prev = prev->next;
+ prev->next = ph;
+ }
+
+ gc_addspecial (ai, &gc_freeaddrinfo_callback, &c->gc);
+
+ }
+ return status;
+}
+
+void
+do_preresolve (struct context *c)
+{
+ int i;
+ struct connection_list *l = c->options.connection_list;
+ const unsigned int preresolve_flags = GETADDR_RESOLVE|
+ GETADDR_UPDATE_MANAGEMENT_STATE|
+ GETADDR_MENTION_RESOLVE_RETRY|
+ GETADDR_FATAL;
+
+
+ for (i = 0; i < l->len; ++i)
+ {
+ int status;
+ const char *remote;
+ int flags = preresolve_flags;
+
+ struct connection_entry* ce = c->options.connection_list->array[i];
+
+ if (proto_is_dgram(ce->proto))
+ flags |= GETADDR_DATAGRAM;
+
+ if (c->options.sockflags & SF_HOST_RANDOMIZE)
+ flags |= GETADDR_RANDOMIZE;
+
+ if (c->options.ip_remote_hint)
+ remote = c->options.ip_remote_hint;
+ else
+ remote = ce->remote;
+
+ /* HTTP remote hostname does not need to be resolved */
+ if (! ce->http_proxy_options)
+ {
+ status = do_preresolve_host (c, remote, ce->remote_port, ce->af, flags);
+ if (status != 0)
+ goto err;
+ }
+
+ /* Preresolve proxy */
+ if (ce->http_proxy_options)
+ {
+ status = do_preresolve_host (c,
+ ce->http_proxy_options->server,
+ ce->http_proxy_options->port,
+ ce->af,
+ preresolve_flags);
+
+ if (status != 0)
+ goto err;
+ }
+
+ if (ce->socks_proxy_server)
+ {
+ status = do_preresolve_host (c,
+ ce->socks_proxy_server,
+ ce->socks_proxy_port,
+ ce->af,
+ flags);
+ if (status != 0)
+ goto err;
+ }
+
+ if (ce->bind_local)
+ {
+ flags |= GETADDR_PASSIVE;
+ flags &= ~GETADDR_RANDOMIZE;
+ status = do_preresolve_host (c, ce->local, ce->local_port, ce->af, flags);
+ if (status != 0)
+ goto err;
+
+ }
+
+ }
+ return;
+
+ err:
+ throw_signal_soft (SIGHUP, "Preresolving failed");
+}
/*
* Translate IPv4/IPv6 addr or hostname into struct addrinfo
@@ -155,7 +328,7 @@ openvpn_getaddrinfo (unsigned int flags,
print_hostname = hostname;
else
print_hostname = "undefined";
-
+
if(servname)
print_servname = servname;
else
@@ -172,11 +345,10 @@ openvpn_getaddrinfo (unsigned int flags,
CLEAR(hints);
hints.ai_family = ai_family;
hints.ai_flags = AI_NUMERICHOST;
- hints.ai_socktype = SOCK_STREAM;
-
+
if(flags & GETADDR_PASSIVE)
hints.ai_flags |= AI_PASSIVE;
-
+
if(flags & GETADDR_DATAGRAM)
hints.ai_socktype = SOCK_DGRAM;
else
@@ -192,7 +364,7 @@ openvpn_getaddrinfo (unsigned int flags,
((resolve_retry_seconds + 4)/ fail_wait_interval);
const char *fmt;
int level = 0;
-
+
fmt = "RESOLVE: Cannot resolve host address: %s:%s (%s)";
if ((flags & GETADDR_MENTION_RESOLVE_RETRY)
&& !resolve_retry_seconds)
@@ -276,8 +448,8 @@ openvpn_getaddrinfo (unsigned int flags,
/* hostname resolve succeeded */
- /*
- * Do not chose an IP Addresse by random or change the order *
+ /*
+ * Do not choose an IP Addresse by random or change the order *
* of IP addresses, doing so will break RFC 3484 address selection *
*/
}
@@ -597,11 +769,14 @@ link_socket_update_buffer_sizes (struct link_socket *ls, int rcvbuf, int sndbuf)
*/
socket_descriptor_t
-create_socket_tcp (int af)
+create_socket_tcp (struct addrinfo* addrinfo)
{
socket_descriptor_t sd;
- if ((sd = socket (af, SOCK_STREAM, IPPROTO_TCP)) < 0)
+ ASSERT (addrinfo);
+ ASSERT (addrinfo->ai_socktype == SOCK_STREAM);
+
+ if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
msg (M_ERR, "Cannot create TCP socket");
#ifndef WIN32 /* using SO_REUSEADDR on Windows will cause bind to succeed on port conflicts! */
@@ -618,17 +793,20 @@ create_socket_tcp (int af)
}
static socket_descriptor_t
-create_socket_udp (const int af, const unsigned int flags)
+create_socket_udp (struct addrinfo* addrinfo, const unsigned int flags)
{
socket_descriptor_t sd;
- if ((sd = socket (af, SOCK_DGRAM, IPPROTO_UDP)) < 0)
+ ASSERT (addrinfo);
+ ASSERT (addrinfo->ai_socktype == SOCK_DGRAM);
+
+ if ((sd = socket (addrinfo->ai_family, addrinfo->ai_socktype, addrinfo->ai_protocol)) < 0)
msg (M_ERR, "UDP: Cannot create UDP/UDP6 socket");
#if ENABLE_IP_PKTINFO
else if (flags & SF_USE_IP_PKTINFO)
{
int pad = 1;
- if(af == AF_INET)
+ if(addrinfo->ai_family == AF_INET)
{
#ifdef IP_PKTINFO
if (setsockopt (sd, SOL_IP, IP_PKTINFO,
@@ -641,8 +819,8 @@ create_socket_udp (const int af, const unsigned int flags)
#else
#error ENABLE_IP_PKTINFO is set without IP_PKTINFO xor IP_RECVDSTADDR (fix syshead.h)
#endif
- }
- else if (af == AF_INET6 )
+ }
+ else if (addrinfo->ai_family == AF_INET6 )
{
#ifndef IPV6_RECVPKTINFO /* Some older Darwin platforms require this */
if (setsockopt (sd, IPPROTO_IPV6, IPV6_PKTINFO,
@@ -658,75 +836,91 @@ create_socket_udp (const int af, const unsigned int flags)
return sd;
}
-static void
-create_socket (struct link_socket *sock)
+static void bind_local (struct link_socket *sock, const sa_family_t ai_family)
{
- /* create socket, use information carried over from getaddrinfo */
- const int ai_proto = sock->info.lsa->actual.ai_protocol;
- const int ai_family = sock->info.lsa->actual.ai_family;
-
- ASSERT (sock->info.af == AF_UNSPEC || sock->info.af == ai_family);
+ /* bind to local address/port */
+ if (sock->bind_local)
+ {
+ if (sock->socks_proxy && sock->info.proto == PROTO_UDP)
+ socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local,
+ ai_family, "SOCKS", false);
+ else
+ socket_bind (sock->sd, sock->info.lsa->bind_local,
+ ai_family,
+ "TCP/UDP", sock->info.bind_ipv6_only);
+ }
+}
-
- if (ai_proto == IPPROTO_UDP)
+static void
+create_socket (struct link_socket* sock, struct addrinfo* addr)
+{
+ if (addr->ai_protocol == IPPROTO_UDP || addr->ai_socktype == SOCK_DGRAM)
{
- sock->sd = create_socket_udp (ai_family, sock->sockflags);
+ sock->sd = create_socket_udp (addr, sock->sockflags);
sock->sockflags |= SF_GETADDRINFO_DGRAM;
-#ifdef ENABLE_SOCKS
+ /* Assume that control socket and data socket to the socks proxy
+ * are using the same IP family */
if (sock->socks_proxy)
- sock->ctrl_sd = create_socket_tcp (ai_family);
-#endif
+ {
+ /* Construct a temporary addrinfo to create the socket,
+ * currently resolve two remote addresses is not supported,
+ * TODO: Rewrite the whole resolve_remote */
+ struct addrinfo addrinfo_tmp = *addr;
+ addrinfo_tmp.ai_socktype = SOCK_STREAM;
+ addrinfo_tmp.ai_protocol = IPPROTO_TCP;
+ sock->ctrl_sd = create_socket_tcp (&addrinfo_tmp);
+ }
}
- else if (ai_proto == IPPROTO_TCP)
+ else if (addr->ai_protocol == IPPROTO_TCP || addr->ai_socktype == SOCK_STREAM)
{
- sock->sd = create_socket_tcp (ai_family);
+ sock->sd = create_socket_tcp (addr);
}
else
{
ASSERT (0);
}
-
/* set socket buffers based on --sndbuf and --rcvbuf options */
socket_set_buffers (sock->sd, &sock->socket_buffer_sizes);
-
+
/* set socket to --mark packets with given value */
socket_set_mark (sock->sd, sock->mark);
-
+
+ bind_local (sock, addr->ai_family);
}
#ifdef TARGET_ANDROID
-static void protect_fd_nonlocal (int fd, struct sockaddr* addr)
+static void protect_fd_nonlocal (int fd, const struct sockaddr* addr)
{
- if (addr_local (addr)) {
- msg(M_DEBUG, "Address is local, not protecting socket fd %d", fd);
- return;
- }
-
- struct user_pass up;
- strcpy(up.username ,__func__);
- management->connection.fdtosend = fd;
- msg(M_DEBUG, "Protecting socket fd %d", fd);
- management_query_user_pass(management, &up , "PROTECTFD", GET_USER_PASS_NEED_OK,(void*) 0);
+ /* pass socket FD to management interface to pass on to VPNService API
+ * as "protected socket" (exempt from being routed into tunnel)
+ */
+ if (addr_local (addr)) {
+ msg(M_DEBUG, "Address is local, not protecting socket fd %d", fd);
+ return;
+ }
+ msg(M_DEBUG, "Protecting socket fd %d", fd);
+ management->connection.fdtosend = fd;
+ management_android_control (management, "PROTECTFD", __func__);
}
#endif
-
/*
* Functions used for establishing a TCP stream connection.
*/
static void
socket_do_listen (socket_descriptor_t sd,
- const struct sockaddr *local,
+ const struct addrinfo *local,
bool do_listen,
bool do_set_nonblock)
{
struct gc_arena gc = gc_new ();
if (do_listen)
{
+ ASSERT(local);
msg (M_INFO, "Listening for incoming TCP connection on %s",
- print_sockaddr (local, &gc));
+ print_sockaddr (local->ai_addr, &gc));
if (listen (sd, 1))
msg (M_ERR, "TCP: listen() failed");
}
@@ -819,7 +1013,7 @@ socket_listen_accept (socket_descriptor_t sd,
int new_sd = SOCKET_UNDEFINED;
CLEAR (*act);
- socket_do_listen (sd, local->ai_addr, do_listen, true);
+ socket_do_listen (sd, local, do_listen, true);
while (true)
{
@@ -854,7 +1048,7 @@ socket_listen_accept (socket_descriptor_t sd,
if (socket_defined (new_sd))
{
- struct addrinfo* ai;
+ struct addrinfo* ai = NULL;
if(remote_dynamic)
openvpn_getaddrinfo(0, remote_dynamic, NULL, 1, NULL,
remote_verify.addr.sa.sa_family, &ai);
@@ -891,7 +1085,8 @@ void
socket_bind (socket_descriptor_t sd,
struct addrinfo *local,
int ai_family,
- const char *prefix)
+ const char *prefix,
+ bool ipv6only)
{
struct gc_arena gc = gc_new ();
@@ -901,10 +1096,12 @@ socket_bind (socket_descriptor_t sd,
* For example if an address has multiple A records
* What is the correct way to deal with it?
*/
-
- ASSERT(local);
+
struct addrinfo* cur;
-
+
+ ASSERT(local);
+
+
/* find the first addrinfo with correct ai_family */
for (cur = local; cur; cur=cur->ai_next)
{
@@ -914,7 +1111,17 @@ socket_bind (socket_descriptor_t sd,
if (!cur)
msg (M_FATAL, "%s: Socket bind failed: Addr to bind has no %s record",
prefix, addr_family_name(ai_family));
-
+
+ if (ai_family == AF_INET6)
+ {
+ int v6only = ipv6only ? 1: 0; /* setsockopt must have an "int" */
+
+ msg (M_INFO, "setsockopt(IPV6_V6ONLY=%d)", v6only);
+ if (setsockopt(sd, IPPROTO_IPV6, IPV6_V6ONLY, &v6only, sizeof(v6only)))
+ {
+ msg (M_NONFATAL|M_ERRNO, "Setting IPV6_V6ONLY=%d failed", v6only);
+ }
+ }
if (bind (sd, cur->ai_addr, cur->ai_addrlen))
{
const int errnum = openvpn_errno ();
@@ -934,12 +1141,13 @@ openvpn_connect (socket_descriptor_t sd,
{
int status = 0;
+#ifdef TARGET_ANDROID
+ protect_fd_nonlocal(sd, remote);
+#endif
+
#ifdef CONNECT_NONBLOCK
set_nonblock (sd);
-
- protect_fd_nonlocal(sd, remote);
status = connect (sd, remote, af_addr_size(remote->sa_family));
-
if (status)
status = openvpn_errno ();
if (
@@ -1015,7 +1223,7 @@ void set_actual_address (struct link_socket_actual* actual, struct addrinfo* ai)
{
CLEAR (*actual);
ASSERT (ai);
-
+
if (ai->ai_family == AF_INET)
actual->dest.addr.in4 =
*((struct sockaddr_in*) ai->ai_addr);
@@ -1024,24 +1232,18 @@ void set_actual_address (struct link_socket_actual* actual, struct addrinfo* ai)
*((struct sockaddr_in6*) ai->ai_addr);
else
ASSERT(0);
-
- /* Copy addrinfo sock parameters for socket creating */
- actual->ai_family = ai->ai_family;
- actual->ai_protocol = ai->ai_protocol;
- actual->ai_socktype = ai->ai_socktype;
+
}
void
-socket_connect (socket_descriptor_t *sd,
- struct link_socket_addr *lsa,
+socket_connect (socket_descriptor_t* sd,
+ const struct sockaddr* dest,
const int connect_timeout,
struct signal_info* sig_info)
{
struct gc_arena gc = gc_new ();
- const struct sockaddr *dest = &lsa->actual.dest.addr.sa;
-
int status;
-
+
#ifdef CONNECT_NONBLOCK
msg (M_INFO, "Attempting to establish TCP connection with %s [nonblock]",
print_sockaddr (dest, &gc));
@@ -1049,14 +1251,14 @@ socket_connect (socket_descriptor_t *sd,
msg (M_INFO, "Attempting to establish TCP connection with %s",
print_sockaddr (dest, &gc));
#endif
-
+
#ifdef ENABLE_MANAGEMENT
if (management)
management_set_state (management,
- OPENVPN_STATE_TCP_CONNECT,
- NULL,
- (in_addr_t)0,
- (in_addr_t)0);
+ OPENVPN_STATE_TCP_CONNECT,
+ NULL,
+ (in_addr_t)0,
+ (in_addr_t)0);
#endif
/* Set the actual address */
@@ -1139,41 +1341,34 @@ resolve_bind_local (struct link_socket *sock, const sa_family_t af)
if (!sock->info.lsa->bind_local)
{
int flags = GETADDR_RESOLVE | GETADDR_WARN_ON_SIGNAL |
- GETADDR_FATAL | GETADDR_PASSIVE;
+ GETADDR_FATAL | GETADDR_PASSIVE;
int status;
-
+
if(proto_is_dgram(sock->info.proto))
- flags |= GETADDR_DATAGRAM;
-
+ flags |= GETADDR_DATAGRAM;
+
/* will return AF_{INET|INET6}from local_host */
- status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
- NULL, af, &sock->info.lsa->bind_local);
+ status = get_cached_dns_entry (sock->dns_cache,
+ sock->local_host,
+ sock->local_port,
+ af,
+ flags,
+ &sock->info.lsa->bind_local);
+
+ if (status)
+ status = openvpn_getaddrinfo(flags, sock->local_host, sock->local_port, 0,
+ NULL, af, &sock->info.lsa->bind_local);
+
if(status !=0) {
- msg (M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s",
- sock->local_host, sock->local_port,
- gai_strerror(status));
+ msg (M_FATAL, "getaddrinfo() failed for local \"%s:%s\": %s",
+ sock->local_host, sock->local_port,
+ gai_strerror(status));
}
}
gc_free (&gc);
}
-static void bind_local (struct link_socket *sock)
-{
- /* bind to local address/port */
- if (sock->bind_local)
- {
-#ifdef ENABLE_SOCKS
- if (sock->socks_proxy && sock->info.proto == PROTO_UDP)
- socket_bind (sock->ctrl_sd, sock->info.lsa->bind_local,
- sock->info.lsa->actual.ai_family, "SOCKS");
- else
-#endif
- socket_bind (sock->sd, sock->info.lsa->bind_local,
- sock->info.lsa->actual.ai_family, "TCP/UDP");
- }
-}
-
static void
resolve_remote (struct link_socket *sock,
int phase,
@@ -1182,103 +1377,104 @@ resolve_remote (struct link_socket *sock,
{
struct gc_arena gc = gc_new ();
- if (!sock->did_resolve_remote)
+ /* resolve remote address if undefined */
+ if (!sock->info.lsa->remote_list)
{
- /* resolve remote address if undefined */
- if (!sock->info.lsa->remote_list)
+ if (sock->remote_host)
{
- if (sock->remote_host)
+ unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
+ int retry = 0;
+ int status = -1;
+ struct addrinfo* ai;
+ if (proto_is_dgram(sock->info.proto))
+ flags |= GETADDR_DATAGRAM;
+
+ if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
{
- unsigned int flags = sf2gaf(GETADDR_RESOLVE|GETADDR_UPDATE_MANAGEMENT_STATE, sock->sockflags);
- int retry = 0;
- int status = -1;
-
- if (proto_is_dgram(sock->info.proto))
- flags |= GETADDR_DATAGRAM;
-
- if (sock->resolve_retry_seconds == RESOLV_RETRY_INFINITE)
+ if (phase == 2)
+ flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
+ retry = 0;
+ }
+ else if (phase == 1)
+ {
+ if (sock->resolve_retry_seconds)
{
- if (phase == 2)
- flags |= (GETADDR_TRY_ONCE | GETADDR_FATAL);
retry = 0;
}
- else if (phase == 1)
+ else
{
- if (sock->resolve_retry_seconds)
- {
- retry = 0;
- }
- else
- {
- flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
- retry = 0;
- }
+ flags |= (GETADDR_FATAL | GETADDR_MENTION_RESOLVE_RETRY);
+ retry = 0;
}
- else if (phase == 2)
+ }
+ else if (phase == 2)
+ {
+ if (sock->resolve_retry_seconds)
{
- if (sock->resolve_retry_seconds)
- {
- flags |= GETADDR_FATAL;
- retry = sock->resolve_retry_seconds;
- }
- else
- {
- ASSERT (0);
- }
+ flags |= GETADDR_FATAL;
+ retry = sock->resolve_retry_seconds;
}
else
{
ASSERT (0);
}
+ }
+ else
+ {
+ ASSERT (0);
+ }
- struct addrinfo* ai;
- status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port,
- retry, signal_received, sock->info.af, &ai);
- if(status == 0) {
- sock->info.lsa->remote_list = ai;
- sock->info.lsa->current_remote = ai;
-
- dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
- flags,
- phase,
- retry,
- signal_received ? *signal_received : -1,
- status);
- }
- if (signal_received)
- {
- if (*signal_received)
- goto done;
- }
+
+ status = get_cached_dns_entry (sock->dns_cache,
+ sock->remote_host,
+ sock->remote_port,
+ sock->info.af,
+ flags, &ai);
+ if (status)
+ status = openvpn_getaddrinfo (flags, sock->remote_host, sock->remote_port,
+ retry, signal_received, sock->info.af, &ai);
+
+ if(status == 0) {
+ sock->info.lsa->remote_list = ai;
+ sock->info.lsa->current_remote = ai;
+
+ dmsg (D_SOCKET_DEBUG, "RESOLVE_REMOTE flags=0x%04x phase=%d rrs=%d sig=%d status=%d",
+ flags,
+ phase,
+ retry,
+ signal_received ? *signal_received : -1,
+ status);
+ }
+ if (signal_received)
+ {
+ if (*signal_received)
+ goto done;
+ }
if (status!=0)
{
if (signal_received)
*signal_received = SIGUSR1;
goto done;
}
- }
}
+ }
- /* should we re-use previous active remote address? */
- if (link_socket_actual_defined (&sock->info.lsa->actual))
- {
- msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
- print_link_socket_actual (&sock->info.lsa->actual, &gc));
- if (remote_dynamic)
- *remote_dynamic = NULL;
- }
- /* else, quick hack to fix persistent-remote ....*/
+ /* should we re-use previous active remote address? */
+ if (link_socket_actual_defined (&sock->info.lsa->actual))
+ {
+ msg (M_INFO, "TCP/UDP: Preserving recently used remote address: %s",
+ print_link_socket_actual (&sock->info.lsa->actual, &gc));
+ if (remote_dynamic)
+ *remote_dynamic = NULL;
+ }
+ else
+ {
+ CLEAR (sock->info.lsa->actual);
+ if(sock->info.lsa->current_remote)
{
- CLEAR (sock->info.lsa->actual);
- if(sock->info.lsa->current_remote)
- {
- set_actual_address (&sock->info.lsa->actual,
- sock->info.lsa->current_remote);
- }
+ set_actual_address (&sock->info.lsa->actual,
+ sock->info.lsa->current_remote);
}
-
- /* remember that we finished */
- sock->did_resolve_remote = true;
}
done:
@@ -1294,61 +1490,24 @@ link_socket_new (void)
ALLOC_OBJ_CLEAR (sock, struct link_socket);
sock->sd = SOCKET_UNDEFINED;
-#ifdef ENABLE_SOCKS
sock->ctrl_sd = SOCKET_UNDEFINED;
-#endif
return sock;
}
void
-create_new_socket (struct link_socket* sock)
-{
- if (sock->bind_local) {
- resolve_bind_local (sock, sock->info.af);
- }
- resolve_remote (sock, 1, NULL, NULL);
- /*
- * In P2P or server mode we must create the socket even when resolving
- * the remote site fails/is not specified. */
-
- if (sock->info.af && sock->info.lsa->actual.ai_family==0 && sock->bind_local)
- {
- /* Copy sock parameters from bind addr */
- set_actual_address (&sock->info.lsa->actual, sock->info.lsa->bind_local);
- /* clear destination set by set_actual_address */
- CLEAR(sock->info.lsa->actual.dest);
- }
-
- /*
- * Create the socket early if socket should be bound
- */
- if (sock->bind_local && sock->info.lsa->actual.ai_family)
- {
- create_socket (sock);
-
- if (sock->bind_local)
- bind_local(sock);
- }
-}
-
-
-/* bind socket if necessary */
-void
link_socket_init_phase1 (struct link_socket *sock,
const char *local_host,
const char *local_port,
const char *remote_host,
const char *remote_port,
+ struct cached_dns_entry *dns_cache,
int proto,
- sa_family_t af,
+ sa_family_t af,
+ bool bind_ipv6_only,
int mode,
const struct link_socket *accept_from,
-#ifdef ENABLE_HTTP_PROXY
struct http_proxy_info *http_proxy,
-#endif
-#ifdef ENABLE_SOCKS
struct socks_proxy_info *socks_proxy,
-#endif
#ifdef ENABLE_DEBUG
int gremlin,
#endif
@@ -1372,15 +1531,9 @@ link_socket_init_phase1 (struct link_socket *sock,
sock->local_port = local_port;
sock->remote_host = remote_host;
sock->remote_port = remote_port;
-
-#ifdef ENABLE_HTTP_PROXY
+ sock->dns_cache = dns_cache;
sock->http_proxy = http_proxy;
-#endif
-
-#ifdef ENABLE_SOCKS
sock->socks_proxy = socks_proxy;
-#endif
-
sock->bind_local = bind_local;
sock->inetd = inetd;
sock->resolve_retry_seconds = resolve_retry_seconds;
@@ -1401,6 +1554,7 @@ link_socket_init_phase1 (struct link_socket *sock,
sock->info.af = af;
sock->info.remote_float = remote_float;
sock->info.lsa = lsa;
+ sock->info.bind_ipv6_only = bind_ipv6_only;
sock->info.ipchange_command = ipchange_command;
sock->info.plugins = plugins;
@@ -1412,10 +1566,9 @@ link_socket_init_phase1 (struct link_socket *sock,
ASSERT (!sock->inetd);
sock->sd = accept_from->sd;
}
-
+
if (false)
;
-#ifdef ENABLE_HTTP_PROXY
/* are we running in HTTP proxy mode? */
else if (sock->http_proxy)
{
@@ -1430,12 +1583,9 @@ link_socket_init_phase1 (struct link_socket *sock,
sock->proxy_dest_host = remote_host;
sock->proxy_dest_port = remote_port;
}
-#endif
-#ifdef ENABLE_SOCKS
/* or in Socks proxy mode? */
else if (sock->socks_proxy)
{
- ASSERT (sock->info.af == AF_INET);
ASSERT (!sock->inetd);
/* the proxy server */
@@ -1446,7 +1596,6 @@ link_socket_init_phase1 (struct link_socket *sock,
sock->proxy_dest_host = remote_host;
sock->proxy_dest_port = remote_port;
}
-#endif
else
{
sock->remote_host = remote_host;
@@ -1454,7 +1603,7 @@ link_socket_init_phase1 (struct link_socket *sock,
}
/* bind behavior for TCP server vs. client */
- if (sock->info.proto == PROTO_TCP_SERVER && sock->info.af==AF_INET)
+ if (sock->info.proto == PROTO_TCP_SERVER)
{
if (sock->mode == LS_MODE_TCP_ACCEPT_FROM)
sock->bind_local = false;
@@ -1471,13 +1620,16 @@ link_socket_init_phase1 (struct link_socket *sock,
}
else if (mode != LS_MODE_TCP_ACCEPT_FROM)
{
- create_new_socket (sock);
+ if (sock->bind_local) {
+ resolve_bind_local (sock, sock->info.af);
+ }
+ resolve_remote (sock, 1, NULL, NULL);
}
}
static
void phase2_inetd (struct link_socket* sock, const struct frame *frame,
- const char *remote_dynamic, volatile int *signal_received)
+ const char *remote_dynamic, volatile int *signal_received)
{
bool remote_changed = false;
@@ -1490,27 +1642,28 @@ void phase2_inetd (struct link_socket* sock, const struct frame *frame,
struct openvpn_sockaddr local_addr;
socklen_t addrlen = sizeof(local_addr);
if (getsockname (sock->sd, &local_addr.addr.sa, &addrlen) == 0) {
- sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family;
- dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)",
- proto2ascii(sock->info.proto, sock->info.af, false), local_addr.addr.sa.sa_family,
- sock->sd);
+ sock->info.lsa->actual.dest.addr.sa.sa_family = local_addr.addr.sa.sa_family;
+ dmsg (D_SOCKET_DEBUG, "inetd(%s): using sa_family=%d from getsockname(%d)",
+ proto2ascii(sock->info.proto, sock->info.af, false),
+ local_addr.addr.sa.sa_family, sock->sd);
} else
- msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET",
- proto2ascii(sock->info.proto, sock->info.af, false), sock->sd);
+ msg (M_WARN, "inetd(%s): getsockname(%d) failed, using AF_INET",
+ proto2ascii(sock->info.proto, sock->info.af, false), sock->sd);
}
#else
msg (M_WARN, "inetd(%s): this OS does not provide the getsockname() "
- "function, using AF_INET",
- proto2ascii(sock->info.proto, false));
+ "function, using AF_INET",
+ proto2ascii(sock->info.proto, false));
#endif
sock->sd =
socket_listen_accept (sock->sd,
- &sock->info.lsa->actual,
- remote_dynamic,
- sock->info.lsa->bind_local,
- false,
- sock->inetd == INETD_NOWAIT,
- signal_received);
+ &sock->info.lsa->actual,
+ remote_dynamic,
+ sock->info.lsa->bind_local,
+ false,
+ sock->inetd == INETD_NOWAIT,
+ signal_received);
+
}
ASSERT (!remote_changed);
}
@@ -1528,10 +1681,8 @@ phase2_set_socket_flags (struct link_socket* sock)
scripts don't have access to it */
set_cloexec (sock->sd);
-#ifdef ENABLE_SOCKS
if (socket_defined (sock->ctrl_sd))
set_cloexec (sock->ctrl_sd);
-#endif
/* set Path MTU discovery options on the socket */
set_mtu_discover_type (sock->sd, sock->mtu_discover_type);
@@ -1547,171 +1698,161 @@ static void
linksock_print_addr (struct link_socket *sock)
{
struct gc_arena gc = gc_new ();
+ const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO;
/* print local address */
- {
- const int msglevel = (sock->mode == LS_MODE_TCP_ACCEPT_FROM) ? D_INIT_MEDIUM : M_INFO;
-
- if (sock->inetd)
- msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true));
- else if (sock->bind_local)
- {
- /* Socket is always bound on the first matching address */
- struct addrinfo *cur;
- for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next)
- {
- if(cur->ai_family == sock->info.lsa->actual.ai_family)
- break;
- }
- ASSERT (cur);
- msg (msglevel, "%s link local (bound): %s",
- proto2ascii (sock->info.proto, sock->info.af, true),
- print_sockaddr(cur->ai_addr,&gc));
- }
- else
- msg (msglevel, "%s link local: (not bound)",
- proto2ascii (sock->info.proto, sock->info.af, true));
-
- /* print active remote address */
- msg (msglevel, "%s link remote: %s",
- proto2ascii (sock->info.proto, sock->info.af, true),
- print_link_socket_actual_ex (&sock->info.lsa->actual,
- ":",
- PS_SHOW_PORT_IF_DEFINED,
- &gc));
- }
+ if (sock->inetd)
+ msg (msglevel, "%s link local: [inetd]", proto2ascii (sock->info.proto, sock->info.af, true));
+ else if (sock->bind_local)
+ {
+ sa_family_t ai_family = sock->info.lsa->actual.dest.addr.sa.sa_family;
+ /* Socket is always bound on the first matching address,
+ * For bound sockets with no remote addr this is the element of
+ * the list */
+ struct addrinfo *cur;
+ for (cur = sock->info.lsa->bind_local; cur; cur=cur->ai_next)
+ {
+ if(!ai_family || ai_family == cur->ai_family)
+ break;
+ }
+ ASSERT (cur);
+ msg (msglevel, "%s link local (bound): %s",
+ proto2ascii (sock->info.proto, sock->info.af, true),
+ print_sockaddr(cur->ai_addr,&gc));
+ }
+ else
+ msg (msglevel, "%s link local: (not bound)",
+ proto2ascii (sock->info.proto, sock->info.af, true));
+
+ /* print active remote address */
+ msg (msglevel, "%s link remote: %s",
+ proto2ascii (sock->info.proto, sock->info.af, true),
+ print_link_socket_actual_ex (&sock->info.lsa->actual,
+ ":",
+ PS_SHOW_PORT_IF_DEFINED,
+ &gc));
gc_free(&gc);
}
static void
phase2_tcp_server (struct link_socket *sock, const char *remote_dynamic,
- volatile int *signal_received)
+ volatile int *signal_received)
{
switch (sock->mode)
{
case LS_MODE_DEFAULT:
sock->sd = socket_listen_accept (sock->sd,
- &sock->info.lsa->actual,
- remote_dynamic,
- sock->info.lsa->bind_local,
- true,
- false,
- signal_received);
+ &sock->info.lsa->actual,
+ remote_dynamic,
+ sock->info.lsa->bind_local,
+ true,
+ false,
+ signal_received);
break;
case LS_MODE_TCP_LISTEN:
socket_do_listen (sock->sd,
- sock->info.lsa->bind_local->ai_addr,
- true,
- false);
+ sock->info.lsa->bind_local,
+ true,
+ false);
break;
case LS_MODE_TCP_ACCEPT_FROM:
sock->sd = socket_do_accept (sock->sd,
- &sock->info.lsa->actual,
- false);
+ &sock->info.lsa->actual,
+ false);
if (!socket_defined (sock->sd))
- {
- *signal_received = SIGTERM;
- return;
- }
+ {
+ *signal_received = SIGTERM;
+ return;
+ }
tcp_connection_established (&sock->info.lsa->actual);
break;
default:
ASSERT (0);
}
-
}
static void
phase2_tcp_client (struct link_socket *sock, struct signal_info *sig_info)
{
-#ifdef GENERAL_PROXY_SUPPORT
- bool proxy_retry = false;
-#else
- const bool proxy_retry = false;
-#endif
- do {
- socket_connect (&sock->sd,
- sock->info.lsa,
- sock->connect_timeout,
- sig_info);
-
- if (sig_info->signal_received)
- return;
-
- if (false)
- ;
-#ifdef ENABLE_HTTP_PROXY
- else if (sock->http_proxy)
- {
- proxy_retry = establish_http_proxy_passthru (sock->http_proxy,
- sock->sd,
- sock->proxy_dest_host,
- sock->proxy_dest_port,
- &sock->stream_buf.residual,
- &sig_info->signal_received);
- }
-#endif
-#ifdef ENABLE_SOCKS
- else if (sock->socks_proxy)
- {
- establish_socks_proxy_passthru (sock->socks_proxy,
- sock->sd,
- sock->proxy_dest_host,
- sock->proxy_dest_port,
- &sig_info->signal_received);
- }
-#endif
- if (proxy_retry)
- {
- /* TODO (schwabe): This code assumes AF_INET for the proxy socket
- * when retrying a connection */
- openvpn_close_socket (sock->sd);
- sock->sd = create_socket_tcp (AF_INET);
- }
- } while (proxy_retry);
+ bool proxy_retry = false;
+ do {
+ socket_connect (&sock->sd,
+ sock->info.lsa->current_remote->ai_addr,
+ sock->connect_timeout,
+ sig_info);
+
+ if (sig_info->signal_received)
+ return;
+
+ if (false)
+ ;
+ else if (sock->http_proxy)
+ {
+ proxy_retry = establish_http_proxy_passthru (sock->http_proxy,
+ sock->sd,
+ sock->proxy_dest_host,
+ sock->proxy_dest_port,
+ &sock->stream_buf.residual,
+ &sig_info->signal_received);
+ }
+ else if (sock->socks_proxy)
+ {
+ establish_socks_proxy_passthru (sock->socks_proxy,
+ sock->sd,
+ sock->proxy_dest_host,
+ sock->proxy_dest_port,
+ &sig_info->signal_received);
+ }
+ if (proxy_retry)
+ {
+ openvpn_close_socket (sock->sd);
+ sock->sd = create_socket_tcp (sock->info.lsa->current_remote);
+ }
+
+ } while (proxy_retry);
}
-#ifdef ENABLE_SOCKS
static void
phase2_socks_client (struct link_socket *sock, struct signal_info *sig_info)
{
socket_connect (&sock->ctrl_sd,
- sock->info.lsa,
- sock->connect_timeout,
- sig_info);
-
+ sock->info.lsa->current_remote->ai_addr,
+ sock->connect_timeout,
+ sig_info);
+
if (sig_info->signal_received)
- return;
-
+ return;
+
establish_socks_proxy_udpassoc (sock->socks_proxy,
- sock->ctrl_sd,
- sock->sd,
- &sock->socks_relay.dest,
- &sig_info->signal_received);
-
+ sock->ctrl_sd,
+ sock->sd,
+ &sock->socks_relay.dest,
+ &sig_info->signal_received);
+
if (sig_info->signal_received)
- return;
-
+ return;
+
sock->remote_host = sock->proxy_dest_host;
sock->remote_port = sock->proxy_dest_port;
- sock->did_resolve_remote = false;
-
+
addr_zero_host(&sock->info.lsa->actual.dest);
if (sock->info.lsa->remote_list)
- freeaddrinfo(sock->info.lsa->remote_list);
-
+ {
+ freeaddrinfo(sock->info.lsa->remote_list);
+ sock->info.lsa->current_remote = NULL;
+ sock->info.lsa->remote_list = NULL;
+ }
+
resolve_remote (sock, 1, NULL, &sig_info->signal_received);
-
}
-#endif
/* finalize socket initialization */
void
link_socket_init_phase2 (struct link_socket *sock,
- const struct frame *frame,
- struct signal_info *sig_info)
+ const struct frame *frame,
+ struct signal_info *sig_info)
{
const char *remote_dynamic = NULL;
int sig_save = 0;
@@ -1740,69 +1881,77 @@ link_socket_init_phase2 (struct link_socket *sock,
{
phase2_inetd (sock, frame, remote_dynamic, &sig_info->signal_received);
if (sig_info && sig_info->signal_received)
- goto done;
+ goto done;
}
else
{
/* Second chance to resolv/create socket */
resolve_remote (sock, 2, &remote_dynamic, &sig_info->signal_received);
-
+
+ /* If a valid remote has been found, create the socket with its addrinfo */
+ if (sock->info.lsa->current_remote)
+ create_socket (sock, sock->info.lsa->current_remote);
+
/* If socket has not already been created create it now */
if (sock->sd == SOCKET_UNDEFINED)
- {
- if (sock->info.lsa->actual.ai_family)
- {
- create_socket (sock);
- }
- else
- {
- msg (M_WARN, "Could not determine IPv4/IPv6 protocol");
- sig_info->signal_received = SIGUSR1;
- goto done;
- }
-
- if (sock->bind_local)
- bind_local(sock);
- }
+ {
+ /* If we have no --remote and have still not figured out the
+ * protocol family to use we will use the first of the bind */
+
+ if (sock->bind_local && !sock->remote_host && sock->info.lsa->bind_local)
+ {
+ /* Warn if this is because neither v4 or v6 was specified
+ * and we should not connect a remote */
+ if (sock->info.af == AF_UNSPEC)
+ msg (M_WARN, "Could not determine IPv4/IPv6 protocol. Using %s",
+ addr_family_name(sock->info.lsa->bind_local->ai_family));
+
+ create_socket (sock, sock->info.lsa->bind_local);
+ }
+ }
+
+ /* Socket still undefined, give a warning and abort connection */
+ if (sock->sd == SOCKET_UNDEFINED)
+ {
+ msg (M_WARN, "Could not determine IPv4/IPv6 protocol");
+ sig_info->signal_received = SIGUSR1;
+ goto done;
+ }
-
if (sig_info && sig_info->signal_received)
- goto done;
+ goto done;
if (sock->info.proto == PROTO_TCP_SERVER)
- {
- phase2_tcp_server (sock, remote_dynamic,
- &sig_info->signal_received);
- }
+ {
+ phase2_tcp_server (sock, remote_dynamic,
+ &sig_info->signal_received);
+ }
else if (sock->info.proto == PROTO_TCP_CLIENT)
- {
- phase2_tcp_client (sock, sig_info);
-
- }
- else if (sock->info.proto == PROTO_UDP)
- {
-#ifdef ENABLE_SOCKS
- if (sock->info.proto == PROTO_UDP && sock->socks_proxy)
- {
- phase2_socks_client (sock, sig_info);
-#endif
- }
- protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa);
- }
+ {
+ phase2_tcp_client (sock, sig_info);
+ }
+ else if (sock->info.proto == PROTO_UDP && sock->socks_proxy)
+ {
+ phase2_socks_client (sock, sig_info);
+ }
+#ifdef TARGET_ANDROID
+ if (sock->sd != -1)
+ protect_fd_nonlocal (sock->sd, &sock->info.lsa->actual.dest.addr.sa);
+#endif
if (sig_info && sig_info->signal_received)
- goto done;
+ goto done;
}
phase2_set_socket_flags(sock);
linksock_print_addr(sock);
-
+
done:
if (sig_save && sig_info)
{
if (!sig_info->signal_received)
- sig_info->signal_received = sig_save;
+ sig_info->signal_received = sig_save;
}
}
@@ -1838,14 +1987,12 @@ link_socket_close (struct link_socket *sock)
#endif
}
-#ifdef ENABLE_SOCKS
if (socket_defined (sock->ctrl_sd))
{
if (openvpn_close_socket (sock->ctrl_sd))
msg (M_WARN | M_ERRNO, "TCP/UDP: Close Socket (ctrl_sd) failed");
sock->ctrl_sd = SOCKET_UNDEFINED;
}
-#endif
stream_buf_close (&sock->stream_buf);
free_buf (&sock->stream_buf_data);
@@ -2251,10 +2398,10 @@ print_sockaddr_ex (const struct sockaddr *sa,
{
if (separator)
buf_puts (&out, separator);
-
+
buf_puts (&out, servname);
}
-
+
return BSTR (&out);
}
@@ -2468,12 +2615,17 @@ struct proto_names {
/* Indexed by PROTO_x */
static const struct proto_names proto_names[] = {
{"proto-uninitialized", "proto-NONE", AF_UNSPEC, PROTO_NONE},
+ /* try IPv4 and IPv6 (client), bind dual-stack (server) */
{"udp", "UDP", AF_UNSPEC, PROTO_UDP},
- {"udp4", "UDPv4", AF_INET, PROTO_UDP},
- {"tcp-server", "TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER},
- {"tcp-client", "TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT},
+ {"tcp-server", "TCP_SERVER", AF_UNSPEC, PROTO_TCP_SERVER},
+ {"tcp-client", "TCP_CLIENT", AF_UNSPEC, PROTO_TCP_CLIENT},
{"tcp", "TCP", AF_UNSPEC, PROTO_TCP},
- {"tcp4", "TCPv4", AF_INET, PROTO_TCP},
+ /* force IPv4 */
+ {"udp4", "UDPv4", AF_INET, PROTO_UDP},
+ {"tcp4-server","TCPv4_SERVER", AF_INET, PROTO_TCP_SERVER},
+ {"tcp4-client","TCPv4_CLIENT", AF_INET, PROTO_TCP_CLIENT},
+ {"tcp4", "TCPv4", AF_INET, PROTO_TCP},
+ /* force IPv6 */
{"udp6" ,"UDPv6", AF_INET6, PROTO_UDP},
{"tcp6-server","TCPv6_SERVER", AF_INET6, PROTO_TCP_SERVER},
{"tcp6-client","TCPv6_CLIENT", AF_INET6, PROTO_TCP_CLIENT},
@@ -2535,7 +2687,7 @@ proto2ascii (int proto, sa_family_t af, bool display_form)
unsigned int i;
for (i = 0; i < SIZE (proto_names); ++i)
{
- if(proto_names[i].proto_af == af && proto_names[i].proto == proto)
+ if(proto_names[i].proto_af == af && proto_names[i].proto == proto)
{
if(display_form)
return proto_names[i].display_form;
@@ -2562,30 +2714,6 @@ proto2ascii_all (struct gc_arena *gc)
return BSTR (&out);
}
-int
-addr_guess_family(sa_family_t af, const char *name)
-{
- unsigned short ret;
- if (af)
- {
- return af; /* already stamped */
- }
- else
- {
- struct addrinfo hints , *ai;
- int err;
- CLEAR(hints);
- hints.ai_flags = AI_NUMERICHOST;
- err = getaddrinfo(name, NULL, &hints, &ai);
- if ( 0 == err )
- {
- ret=ai->ai_family;
- freeaddrinfo(ai);
- return ret;
- }
- }
- return AF_INET; /* default */
-}
const char *
addr_family_name (int af)
{
@@ -2615,13 +2743,16 @@ proto_remote (int proto, bool remote)
ASSERT (proto >= 0 && proto < PROTO_N);
if (proto == PROTO_UDP)
return "UDPv4";
-
- if ( (remote && proto == PROTO_TCP_CLIENT) || proto == PROTO_TCP_SERVER)
+
+ if ( (remote && proto == PROTO_TCP_CLIENT) ||
+ (!remote && proto == PROTO_TCP_SERVER))
return "TCPv4_SERVER";
- if ( (remote && proto == PROTO_TCP_SERVER) || proto == PROTO_TCP_CLIENT)
+ if ( (remote && proto == PROTO_TCP_SERVER) ||
+ (!remote && proto == PROTO_TCP_CLIENT))
return "TCPv4_CLIENT";
ASSERT (0);
+ return ""; /* Make the compiler happy */
}
/*
@@ -2757,7 +2888,12 @@ link_socket_read_udp_posix_recvmsg (struct link_socket *sock,
from->pi.in6.ipi6_ifindex = pkti6->ipi6_ifindex;
from->pi.in6.ipi6_addr = pkti6->ipi6_addr;
}
+ else if (cmsg != NULL)
+ {
+ msg(M_WARN, "CMSG received that cannot be parsed (cmsg_level=%d, cmsg_type=%d, cmsg=len=%d)", (int)cmsg->cmsg_level, (int)cmsg->cmsg_type, (int)cmsg->cmsg_len );
+ }
}
+
return fromlen;
}
#endif
@@ -2774,7 +2910,7 @@ link_socket_read_udp_posix (struct link_socket *sock,
ASSERT (buf_safe (buf, maxsize));
#if ENABLE_IP_PKTINFO
/* Both PROTO_UDPv4 and PROTO_UDPv6 */
- if (proto_is_udp(sock->info.proto) && sock->sockflags & SF_USE_IP_PKTINFO)
+ if (sock->info.proto == PROTO_UDP && sock->sockflags & SF_USE_IP_PKTINFO)
fromlen = link_socket_read_udp_posix_recvmsg (sock, buf, maxsize, from);
else
#endif
@@ -2818,24 +2954,24 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
struct iovec iov;
struct msghdr mesg;
struct cmsghdr *cmsg;
+ union openvpn_pktinfo opi;
iov.iov_base = BPTR (buf);
iov.iov_len = BLEN (buf);
mesg.msg_iov = &iov;
mesg.msg_iovlen = 1;
- switch (to->ai_family)
+ switch (to->dest.addr.sa.sa_family)
{
case AF_INET:
{
- struct openvpn_in4_pktinfo msgpi4;
mesg.msg_name = &to->dest.addr.sa;
mesg.msg_namelen = sizeof (struct sockaddr_in);
- mesg.msg_control = &msgpi4;
- mesg.msg_controllen = sizeof msgpi4;
+ mesg.msg_control = &opi;
mesg.msg_flags = 0;
+#ifdef HAVE_IN_PKTINFO
+ mesg.msg_controllen = sizeof (struct openvpn_in4_pktinfo);
cmsg = CMSG_FIRSTHDR (&mesg);
cmsg->cmsg_len = sizeof (struct openvpn_in4_pktinfo);
-#ifdef HAVE_IN_PKTINFO
cmsg->cmsg_level = SOL_IP;
cmsg->cmsg_type = IP_PKTINFO;
{
@@ -2846,6 +2982,10 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
pkti->ipi_addr.s_addr = 0;
}
#elif defined(IP_RECVDSTADDR)
+ ASSERT( CMSG_SPACE(sizeof (struct in_addr)) <= sizeof(opi) );
+ mesg.msg_controllen = CMSG_SPACE(sizeof (struct in_addr));
+ cmsg = CMSG_FIRSTHDR (&mesg);
+ cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr));
cmsg->cmsg_level = IPPROTO_IP;
cmsg->cmsg_type = IP_RECVDSTADDR;
*(struct in_addr *) CMSG_DATA (cmsg) = to->pi.in4;
@@ -2856,12 +2996,11 @@ link_socket_write_udp_posix_sendmsg (struct link_socket *sock,
}
case AF_INET6:
{
- struct openvpn_in6_pktinfo msgpi6;
struct in6_pktinfo *pkti6;
mesg.msg_name = &to->dest.addr.sa;
mesg.msg_namelen = sizeof (struct sockaddr_in6);
- mesg.msg_control = &msgpi6;
- mesg.msg_controllen = sizeof msgpi6;
+ mesg.msg_control = &opi;
+ mesg.msg_controllen = sizeof (struct openvpn_in6_pktinfo);
mesg.msg_flags = 0;
cmsg = CMSG_FIRSTHDR (&mesg);
cmsg->cmsg_len = sizeof (struct openvpn_in6_pktinfo);
@@ -2921,10 +3060,10 @@ socket_recv_queue (struct link_socket *sock, int maxsize)
if (proto_is_udp(sock->info.proto))
{
sock->reads.addr_defined = true;
- if (sock->info.proto == PROTO_UDPv6)
- sock->reads.addrlen = sizeof (sock->reads.addr6);
- else
+ if (sock->info.af == AF_INET)
sock->reads.addrlen = sizeof (sock->reads.addr);
+ else
+ sock->reads.addrlen = sizeof (sock->reads.addr6);
status = WSARecvFrom(
sock->sd,
wsabuf,
@@ -3020,7 +3159,7 @@ socket_send_queue (struct link_socket *sock, struct buffer *buf, const struct li
{
/* set destination address for UDP writes */
sock->writes.addr_defined = true;
- if (sock->info.proto == PROTO_UDPv6)
+ if (sock->info.af == AF_INET6)
{
sock->writes.addr6 = to->dest.addr.in6;
sock->writes.addrlen = sizeof (sock->writes.addr6);
diff --git a/app/openvpn/src/openvpn/socket.h b/app/openvpn/src/openvpn/socket.h
index 5b7a26a9..8e157c67 100644
--- a/app/openvpn/src/openvpn/socket.h
+++ b/app/openvpn/src/openvpn/socket.h
@@ -77,15 +77,21 @@ struct openvpn_sockaddr
} addr;
};
+/* struct to hold preresolved host names */
+struct cached_dns_entry {
+ const char *hostname;
+ const char *servname;
+ int ai_family;
+ int flags;
+ struct addrinfo *ai;
+ struct cached_dns_entry *next;
+};
+
/* actual address of remote, based on source address of received packets */
struct link_socket_actual
{
/*int dummy;*/ /* add offset to force a bug if dest not explicitly dereferenced */
- int ai_family; /* PF_xxx */
- int ai_socktype; /* SOCK_xxx */
- int ai_protocol; /* 0 or IPPROTO_xxx for IPv4 and IPv6 */
-
struct openvpn_sockaddr dest;
#if ENABLE_IP_PKTINFO
union {
@@ -104,7 +110,7 @@ struct link_socket_addr
{
struct addrinfo* bind_local;
struct addrinfo* remote_list; /* complete remote list */
- struct addrinfo* current_remote; /* remote used in the
+ struct addrinfo* current_remote; /* remote used in the
current connection attempt */
struct link_socket_actual actual; /* reply to this address */
};
@@ -118,6 +124,7 @@ struct link_socket_info
bool remote_float;
int proto; /* Protocol (PROTO_x defined below) */
sa_family_t af; /* Address family like AF_INET, AF_INET6 or AF_UNSPEC*/
+ bool bind_ipv6_only;
int mtu_changed; /* Set to true when mtu value is changed */
};
@@ -165,10 +172,7 @@ struct link_socket
struct link_socket_info info;
socket_descriptor_t sd;
-
-#ifdef ENABLE_SOCKS
socket_descriptor_t ctrl_sd; /* only used for UDP over Socks */
-#endif
#ifdef WIN32
struct overlapped_io reads;
@@ -187,6 +191,7 @@ struct link_socket
const char *remote_port;
const char *local_host;
const char *local_port;
+ struct cached_dns_entry *dns_cache;
bool bind_local;
# define INETD_NONE 0
@@ -207,8 +212,6 @@ struct link_socket
int mtu; /* OS discovered MTU, or 0 if unknown */
- bool did_resolve_remote;
-
# define SF_USE_IP_PKTINFO (1<<0)
# define SF_TCP_NODELAY (1<<1)
# define SF_PORT_SHARE (1<<2)
@@ -222,22 +225,16 @@ struct link_socket
struct buffer stream_buf_data;
bool stream_reset;
-#ifdef ENABLE_HTTP_PROXY
/* HTTP proxy */
struct http_proxy_info *http_proxy;
-#endif
-#ifdef ENABLE_SOCKS
/* Socks proxy */
struct socks_proxy_info *socks_proxy;
struct link_socket_actual socks_relay; /* Socks UDP relay address */
-#endif
-#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_SOCKS)
/* The OpenVPN server we will use the proxy to connect to */
const char *proxy_dest_host;
const char *proxy_dest_port;
-#endif
#if PASSTOS_CAPABILITY
/* used to get/set TOS. */
@@ -289,13 +286,16 @@ struct link_socket *link_socket_new (void);
void socket_bind (socket_descriptor_t sd,
struct addrinfo *local,
int af_family,
- const char *prefix);
+ const char *prefix,
+ bool ipv6only);
int openvpn_connect (socket_descriptor_t sd,
const struct sockaddr *remote,
int connect_timeout,
volatile int *signal_received);
+
+
/*
* Initialize link_socket object.
*/
@@ -306,16 +306,14 @@ link_socket_init_phase1 (struct link_socket *sock,
const char *local_port,
const char *remote_host,
const char *remote_port,
+ struct cached_dns_entry *dns_cache,
int proto,
- sa_family_t af,
+ sa_family_t af,
+ bool bind_ipv6_only,
int mode,
const struct link_socket *accept_from,
-#ifdef ENABLE_HTTP_PROXY
struct http_proxy_info *http_proxy,
-#endif
-#ifdef ENABLE_SOCKS
struct socks_proxy_info *socks_proxy,
-#endif
#ifdef ENABLE_DEBUG
int gremlin,
#endif
@@ -337,6 +335,8 @@ void link_socket_init_phase2 (struct link_socket *sock,
const struct frame *frame,
struct signal_info *sig_info);
+void do_preresolve(struct context *c);
+
void socket_adjust_frame_parameters (struct frame *frame, int proto);
void frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto);
@@ -456,7 +456,7 @@ bool ip_or_dns_addr_safe (const char *addr, const bool allow_fqdn);
bool mac_addr_safe (const char *mac_addr);
bool ipv6_addr_safe (const char *ipv6_text_addr);
-socket_descriptor_t create_socket_tcp (int af);
+socket_descriptor_t create_socket_tcp (struct addrinfo*);
socket_descriptor_t socket_do_accept (socket_descriptor_t sd,
struct link_socket_actual *act,
@@ -511,6 +511,8 @@ bool unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int *
#define GETADDR_PASSIVE (1<<10)
#define GETADDR_DATAGRAM (1<<11)
+#define GETADDR_CACHE_MASK (GETADDR_DATAGRAM|GETADDR_PASSIVE)
+
in_addr_t getaddr (unsigned int flags,
const char *hostname,
int resolve_retry_seconds,
@@ -600,14 +602,14 @@ static inline bool
addr_local (const struct sockaddr *addr)
{
if (!addr)
- return false;
+ return false;
switch (addr->sa_family) {
- case AF_INET:
- return ((const struct sockaddr_in*)addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
- case AF_INET6:
- return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6*)addr)->sin6_addr);
- default:
- return false;
+ case AF_INET:
+ return ((const struct sockaddr_in*)addr)->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
+ case AF_INET6:
+ return IN6_IS_ADDR_LOOPBACK(&((const struct sockaddr_in6*)addr)->sin6_addr);
+ default:
+ return false;
}
}
@@ -641,61 +643,78 @@ link_socket_actual_defined (const struct link_socket_actual *act)
static inline bool
addr_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockaddr *a2)
{
- switch(a1->addr.sa.sa_family) {
- case AF_INET:
- return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr;
- case AF_INET6:
- return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr);
- }
- ASSERT(0);
- return false;
+ switch(a1->addr.sa.sa_family) {
+ case AF_INET:
+ return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr;
+ case AF_INET6:
+ return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr);
+ }
+ ASSERT(0);
+ return false;
}
static inline bool
addrlist_match (const struct openvpn_sockaddr *a1, const struct addrinfo *addrlist)
{
const struct addrinfo *curele;
- for (curele = addrlist; curele; curele=curele->ai_next) {
-
- switch(a1->addr.sa.sa_family) {
- case AF_INET:
- if (a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr)
- return true;
- break;
- case AF_INET6:
- if (IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr))
- return true;
- break;
- default:
- ASSERT(0);
+ for (curele = addrlist; curele; curele=curele->ai_next)
+ {
+ switch(a1->addr.sa.sa_family)
+ {
+ case AF_INET:
+ if (a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr)
+ return true;
+ break;
+ case AF_INET6:
+ if (IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr))
+ return true;
+ break;
+ default:
+ ASSERT(0);
+ }
}
- }
return false;
}
+static inline in_addr_t
+addr_host (const struct openvpn_sockaddr *addr)
+{
+ /*
+ * "public" addr returned is checked against ifconfig for
+ * possible clash: non sense for now given
+ * that we do ifconfig only IPv4
+ */
+ if(addr->addr.sa.sa_family != AF_INET)
+ return 0;
+ return ntohl (addr->addr.in4.sin_addr.s_addr);
+}
+
+
static inline bool
addrlist_port_match (const struct openvpn_sockaddr *a1, const struct addrinfo *a2)
{
- const struct addrinfo *curele;
- for(curele=a2;curele;curele = curele->ai_next) {
- switch(a1->addr.sa.sa_family) {
- case AF_INET:
+ const struct addrinfo *curele;
+ for(curele=a2;curele;curele = curele->ai_next)
+ {
+ switch(a1->addr.sa.sa_family)
+ {
+ case AF_INET:
if (curele->ai_family == AF_INET
&& a1->addr.in4.sin_addr.s_addr == ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr
&& a1->addr.in4.sin_port == ((struct sockaddr_in*)curele->ai_addr)->sin_port)
return true;
break;
- case AF_INET6:
+ case AF_INET6:
if (curele->ai_family == AF_INET6
&& IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &((struct sockaddr_in6*) curele->ai_addr)->sin6_addr)
&& a1->addr.in6.sin6_port == ((struct sockaddr_in6*) curele->ai_addr)->sin6_port)
return true;
break;
- default:
+ default:
ASSERT(0);
}
}
- return false;
+ return false;
}
@@ -708,7 +727,7 @@ addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockadd
return a1->addr.in4.sin_addr.s_addr == a2->addr.in4.sin_addr.s_addr
&& a1->addr.in4.sin_port == a2->addr.in4.sin_port;
case AF_INET6:
- return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr)
+ return IN6_ARE_ADDR_EQUAL(&a1->addr.in6.sin6_addr, &a2->addr.in6.sin6_addr)
&& a1->addr.in6.sin6_port == a2->addr.in6.sin6_port;
}
ASSERT(0);
@@ -717,10 +736,10 @@ addr_port_match (const struct openvpn_sockaddr *a1, const struct openvpn_sockadd
static inline bool
addr_match_proto (const struct openvpn_sockaddr *a1,
- const struct openvpn_sockaddr *a2,
- const int proto)
+ const struct openvpn_sockaddr *a2,
+ const int proto)
{
- return link_socket_proto_connection_oriented (proto)
+ return link_socket_proto_connection_oriented (proto)
? addr_match (a1, a2)
: addr_port_match (a1, a2);
}
@@ -728,8 +747,8 @@ addr_match_proto (const struct openvpn_sockaddr *a1,
static inline bool
addrlist_match_proto (const struct openvpn_sockaddr *a1,
- struct addrinfo *addr_list,
- const int proto)
+ struct addrinfo *addr_list,
+ const int proto)
{
return link_socket_proto_connection_oriented (proto)
? addrlist_match (a1, addr_list)
@@ -839,7 +858,7 @@ link_socket_verify_incoming_addr (struct buffer *buf,
case AF_INET:
if (!link_socket_actual_defined (from_addr))
return false;
- if (info->remote_float || !info->lsa->remote_list)
+ if (info->remote_float || (!info->lsa->remote_list))
return true;
if (addrlist_match_proto (&from_addr->dest, info->lsa->remote_list, info->proto))
return true;
@@ -878,13 +897,15 @@ link_socket_set_outgoing_addr (const struct buffer *buf,
{
struct link_socket_addr *lsa = info->lsa;
if (
- /* new or changed address? */
- (!info->connection_established
- || !addr_match_proto (&act->dest, &lsa->actual.dest, info->proto))
- /* address undef or address == remote or --float */
- && (info->remote_float
- || !lsa->remote_list)
- || addrlist_match_proto (&act->dest, lsa->remote_list, info->proto)
+ /* new or changed address? */
+ (!info->connection_established
+ || !addr_match_proto (&act->dest, &lsa->actual.dest, info->proto)
+ )
+ &&
+ /* address undef or address == remote or --float */
+ (info->remote_float ||
+ (!lsa->remote_list || addrlist_match_proto (&act->dest, lsa->remote_list, info->proto))
+ )
)
{
link_socket_connection_initiated (buf, info, act, common_name, es);
@@ -1095,7 +1116,7 @@ static inline void
link_socket_set_tos (struct link_socket *ls)
{
if (ls && ls->ptos_defined)
- setsockopt (ls->sd, IPPROTO_IP, IP_TOS, &ls->ptos, sizeof (ls->ptos));
+ setsockopt (ls->sd, IPPROTO_IP, IP_TOS, (const void *)&ls->ptos, sizeof (ls->ptos));
}
#endif
diff --git a/app/openvpn/src/openvpn/socks.c b/app/openvpn/src/openvpn/socks.c
index 804c9836..72bdf550 100644
--- a/app/openvpn/src/openvpn/socks.c
+++ b/app/openvpn/src/openvpn/socks.c
@@ -38,8 +38,6 @@
#include "syshead.h"
-#ifdef ENABLE_SOCKS
-
#include "common.h"
#include "misc.h"
#include "win32.h"
@@ -189,10 +187,15 @@ socks_handshake (struct socks_proxy_info *p,
char buf[2];
int len = 0;
const int timeout_sec = 5;
+ ssize_t size;
+
+ /* VER = 5, NMETHODS = 1, METHODS = [0 (no auth)] */
+ char method_sel[3] = { 0x05, 0x01, 0x00 };
+ if (p->authfile[0])
+ method_sel[2] = 0x02; /* METHODS = [2 (plain login)] */
- /* VER = 5, NMETHODS = 2, METHODS = [0 (no auth), 2 (plain login)] */
- const ssize_t size = send (sd, "\x05\x02\x00\x02", 4, MSG_NOSIGNAL);
- if (size != 4)
+ size = send (sd, method_sel, sizeof (method_sel), MSG_NOSIGNAL);
+ if (size != sizeof (method_sel))
{
msg (D_LINK_ERRORS | M_ERRNO, "socks_handshake: TCP port write failed on send()");
return false;
@@ -252,6 +255,13 @@ socks_handshake (struct socks_proxy_info *p,
return false;
}
+ /* validate that the auth method returned is the one sent */
+ if (buf[1] != method_sel[2])
+ {
+ msg (D_LINK_ERRORS, "socks_handshake: Socks proxy returned unexpected auth");
+ return false;
+ }
+
/* select the appropriate authentication method */
switch (buf[1])
{
@@ -396,7 +406,7 @@ port_from_servname(const char* servname)
port = atoi(servname);
if(port >0 && port < 65536)
return port;
-
+
struct servent* service;
service = getservbyname(servname, NULL);
if(service)
@@ -436,7 +446,7 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p,
msg (D_LINK_ERRORS, "establish_socks_proxy_passthrough: Cannot convert %s to port number", servname);
goto error;
}
-
+
buf[5 + len] = (char) (port >> 8);
buf[5 + len + 1] = (char) (port & 0xff);
@@ -448,7 +458,7 @@ establish_socks_proxy_passthru (struct socks_proxy_info *p,
goto error;
}
}
-
+
/* receive reply from Socks proxy and discard */
if (!recv_socks_reply (sd, NULL, signal_received))
@@ -562,7 +572,3 @@ socks_process_outgoing_udp (struct buffer *buf,
return 10;
}
-
-#else
-static void dummy(void) {}
-#endif /* ENABLE_SOCKS */
diff --git a/app/openvpn/src/openvpn/socks.h b/app/openvpn/src/openvpn/socks.h
index 30b957d7..2475261f 100644
--- a/app/openvpn/src/openvpn/socks.h
+++ b/app/openvpn/src/openvpn/socks.h
@@ -30,8 +30,6 @@
#ifndef SOCKS_H
#define SOCKS_H
-#ifdef ENABLE_SOCKS
-
#include "buffer.h"
struct openvpn_sockaddr;
@@ -74,4 +72,3 @@ int socks_process_outgoing_udp (struct buffer *buf,
const struct link_socket_actual *to);
#endif
-#endif
diff --git a/app/openvpn/src/openvpn/ssl.c b/app/openvpn/src/openvpn/ssl.c
index 9f570b9d..95bbb277 100644
--- a/app/openvpn/src/openvpn/ssl.c
+++ b/app/openvpn/src/openvpn/ssl.c
@@ -7,10 +7,7 @@
*
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
* Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
- *
- * Additions for eurephia plugin done by:
- * David Sommerseth <dazo@users.sourceforge.net> Copyright (C) 2008-2009
- *
+ * Copyright (C) 2008-2013 David Sommerseth <dazo@users.sourceforge.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -38,7 +35,6 @@
* Both the TLS session and the data channel are multiplexed
* over the same TCP/UDP port.
*/
-
#ifdef HAVE_CONFIG_H
#include "config.h"
#elif defined(_MSC_VER)
@@ -51,7 +47,6 @@
#include "error.h"
#include "common.h"
-#include "integer.h"
#include "socket.h"
#include "misc.h"
#include "fdmisc.h"
@@ -60,8 +55,6 @@
#include "status.h"
#include "gremlin.h"
#include "pkcs11.h"
-#include "list.h"
-#include "base64.h"
#include "route.h"
#include "ssl.h"
@@ -113,6 +106,162 @@ show_tls_performance_stats(void)
#endif
+/**
+ * SSL/TLS Cipher suite name translation table
+ */
+static const tls_cipher_name_pair tls_cipher_name_translation_table[] = {
+ {"ADH-SEED-SHA", "TLS-DH-anon-WITH-SEED-CBC-SHA"},
+ {"AES128-GCM-SHA256", "TLS-RSA-WITH-AES-128-GCM-SHA256"},
+ {"AES128-SHA256", "TLS-RSA-WITH-AES-128-CBC-SHA256"},
+ {"AES128-SHA", "TLS-RSA-WITH-AES-128-CBC-SHA"},
+ {"AES256-GCM-SHA384", "TLS-RSA-WITH-AES-256-GCM-SHA384"},
+ {"AES256-SHA256", "TLS-RSA-WITH-AES-256-CBC-SHA256"},
+ {"AES256-SHA", "TLS-RSA-WITH-AES-256-CBC-SHA"},
+ {"CAMELLIA128-SHA256", "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA256"},
+ {"CAMELLIA128-SHA", "TLS-RSA-WITH-CAMELLIA-128-CBC-SHA"},
+ {"CAMELLIA256-SHA256", "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA256"},
+ {"CAMELLIA256-SHA", "TLS-RSA-WITH-CAMELLIA-256-CBC-SHA"},
+ {"DES-CBC3-SHA", "TLS-RSA-WITH-3DES-EDE-CBC-SHA"},
+ {"DES-CBC-SHA", "TLS-RSA-WITH-DES-CBC-SHA"},
+ {"DH-DSS-SEED-SHA", "TLS-DH-DSS-WITH-SEED-CBC-SHA"},
+ {"DHE-DSS-AES128-GCM-SHA256", "TLS-DHE-DSS-WITH-AES-128-GCM-SHA256"},
+ {"DHE-DSS-AES128-SHA256", "TLS-DHE-DSS-WITH-AES-128-CBC-SHA256"},
+ {"DHE-DSS-AES128-SHA", "TLS-DHE-DSS-WITH-AES-128-CBC-SHA"},
+ {"DHE-DSS-AES256-GCM-SHA384", "TLS-DHE-DSS-WITH-AES-256-GCM-SHA384"},
+ {"DHE-DSS-AES256-SHA256", "TLS-DHE-DSS-WITH-AES-256-CBC-SHA256"},
+ {"DHE-DSS-AES256-SHA", "TLS-DHE-DSS-WITH-AES-256-CBC-SHA"},
+ {"DHE-DSS-CAMELLIA128-SHA256", "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA256"},
+ {"DHE-DSS-CAMELLIA128-SHA", "TLS-DHE-DSS-WITH-CAMELLIA-128-CBC-SHA"},
+ {"DHE-DSS-CAMELLIA256-SHA256", "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA256"},
+ {"DHE-DSS-CAMELLIA256-SHA", "TLS-DHE-DSS-WITH-CAMELLIA-256-CBC-SHA"},
+ {"DHE-DSS-SEED-SHA", "TLS-DHE-DSS-WITH-SEED-CBC-SHA"},
+ {"DHE-RSA-AES128-GCM-SHA256", "TLS-DHE-RSA-WITH-AES-128-GCM-SHA256"},
+ {"DHE-RSA-AES128-SHA256", "TLS-DHE-RSA-WITH-AES-128-CBC-SHA256"},
+ {"DHE-RSA-AES128-SHA", "TLS-DHE-RSA-WITH-AES-128-CBC-SHA"},
+ {"DHE-RSA-AES256-GCM-SHA384", "TLS-DHE-RSA-WITH-AES-256-GCM-SHA384"},
+ {"DHE-RSA-AES256-SHA256", "TLS-DHE-RSA-WITH-AES-256-CBC-SHA256"},
+ {"DHE-RSA-AES256-SHA", "TLS-DHE-RSA-WITH-AES-256-CBC-SHA"},
+ {"DHE-RSA-CAMELLIA128-SHA256", "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA256"},
+ {"DHE-RSA-CAMELLIA128-SHA", "TLS-DHE-RSA-WITH-CAMELLIA-128-CBC-SHA"},
+ {"DHE-RSA-CAMELLIA256-SHA256", "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA256"},
+ {"DHE-RSA-CAMELLIA256-SHA", "TLS-DHE-RSA-WITH-CAMELLIA-256-CBC-SHA"},
+ {"DHE-RSA-SEED-SHA", "TLS-DHE-RSA-WITH-SEED-CBC-SHA"},
+ {"DH-RSA-SEED-SHA", "TLS-DH-RSA-WITH-SEED-CBC-SHA"},
+ {"ECDH-ECDSA-AES128-GCM-SHA256", "TLS-ECDH-ECDSA-WITH-AES-128-GCM-SHA256"},
+ {"ECDH-ECDSA-AES128-SHA256", "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA256"},
+ {"ECDH-ECDSA-AES128-SHA", "TLS-ECDH-ECDSA-WITH-AES-128-CBC-SHA"},
+ {"ECDH-ECDSA-AES256-GCM-SHA384", "TLS-ECDH-ECDSA-WITH-AES-256-GCM-SHA384"},
+ {"ECDH-ECDSA-AES256-SHA256", "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA256"},
+ {"ECDH-ECDSA-AES256-SHA384", "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA384"},
+ {"ECDH-ECDSA-AES256-SHA", "TLS-ECDH-ECDSA-WITH-AES-256-CBC-SHA"},
+ {"ECDH-ECDSA-CAMELLIA128-SHA256", "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-CBC-SHA256"},
+ {"ECDH-ECDSA-CAMELLIA128-SHA", "TLS-ECDH-ECDSA-WITH-CAMELLIA-128-CBC-SHA"},
+ {"ECDH-ECDSA-CAMELLIA256-SHA256", "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA256"},
+ {"ECDH-ECDSA-CAMELLIA256-SHA", "TLS-ECDH-ECDSA-WITH-CAMELLIA-256-CBC-SHA"},
+ {"ECDH-ECDSA-DES-CBC3-SHA", "TLS-ECDH-ECDSA-WITH-3DES-EDE-CBC-SHA"},
+ {"ECDH-ECDSA-DES-CBC-SHA", "TLS-ECDH-ECDSA-WITH-DES-CBC-SHA"},
+ {"ECDH-ECDSA-RC4-SHA", "TLS-ECDH-ECDSA-WITH-RC4-128-SHA"},
+ {"ECDHE-ECDSA-AES128-GCM-SHA256", "TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256"},
+ {"ECDHE-ECDSA-AES128-SHA256", "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA256"},
+ {"ECDHE-ECDSA-AES128-SHA384", "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA384"},
+ {"ECDHE-ECDSA-AES128-SHA", "TLS-ECDHE-ECDSA-WITH-AES-128-CBC-SHA"},
+ {"ECDHE-ECDSA-AES256-GCM-SHA384", "TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384"},
+ {"ECDHE-ECDSA-AES256-SHA256", "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA256"},
+ {"ECDHE-ECDSA-AES256-SHA384", "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA384"},
+ {"ECDHE-ECDSA-AES256-SHA", "TLS-ECDHE-ECDSA-WITH-AES-256-CBC-SHA"},
+ {"ECDHE-ECDSA-CAMELLIA128-SHA256", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA256"},
+ {"ECDHE-ECDSA-CAMELLIA128-SHA", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-128-CBC-SHA"},
+ {"ECDHE-ECDSA-CAMELLIA256-SHA256", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA256"},
+ {"ECDHE-ECDSA-CAMELLIA256-SHA", "TLS-ECDHE-ECDSA-WITH-CAMELLIA-256-CBC-SHA"},
+ {"ECDHE-ECDSA-DES-CBC3-SHA", "TLS-ECDHE-ECDSA-WITH-3DES-EDE-CBC-SHA"},
+ {"ECDHE-ECDSA-DES-CBC-SHA", "TLS-ECDHE-ECDSA-WITH-DES-CBC-SHA"},
+ {"ECDHE-ECDSA-RC4-SHA", "TLS-ECDHE-ECDSA-WITH-RC4-128-SHA"},
+ {"ECDHE-RSA-AES128-GCM-SHA256", "TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256"},
+ {"ECDHE-RSA-AES128-SHA256", "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA256"},
+ {"ECDHE-RSA-AES128-SHA384", "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA384"},
+ {"ECDHE-RSA-AES128-SHA", "TLS-ECDHE-RSA-WITH-AES-128-CBC-SHA"},
+ {"ECDHE-RSA-AES256-GCM-SHA384", "TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384"},
+ {"ECDHE-RSA-AES256-SHA256", "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA256"},
+ {"ECDHE-RSA-AES256-SHA384", "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA384"},
+ {"ECDHE-RSA-AES256-SHA", "TLS-ECDHE-RSA-WITH-AES-256-CBC-SHA"},
+ {"ECDHE-RSA-CAMELLIA128-SHA256", "TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA256"},
+ {"ECDHE-RSA-CAMELLIA128-SHA", "TLS-ECDHE-RSA-WITH-CAMELLIA-128-CBC-SHA"},
+ {"ECDHE-RSA-CAMELLIA256-SHA256", "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA256"},
+ {"ECDHE-RSA-CAMELLIA256-SHA", "TLS-ECDHE-RSA-WITH-CAMELLIA-256-CBC-SHA"},
+ {"ECDHE-RSA-DES-CBC3-SHA", "TLS-ECDHE-RSA-WITH-3DES-EDE-CBC-SHA"},
+ {"ECDHE-RSA-DES-CBC-SHA", "TLS-ECDHE-RSA-WITH-DES-CBC-SHA"},
+ {"ECDHE-RSA-RC4-SHA", "TLS-ECDHE-RSA-WITH-RC4-128-SHA"},
+ {"ECDH-RSA-AES128-GCM-SHA256", "TLS-ECDH-RSA-WITH-AES-128-GCM-SHA256"},
+ {"ECDH-RSA-AES128-SHA256", "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA256"},
+ {"ECDH-RSA-AES128-SHA384", "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA384"},
+ {"ECDH-RSA-AES128-SHA", "TLS-ECDH-RSA-WITH-AES-128-CBC-SHA"},
+ {"ECDH-RSA-AES256-GCM-SHA384", "TLS-ECDH-RSA-WITH-AES-256-GCM-SHA384"},
+ {"ECDH-RSA-AES256-SHA256", "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA256"},
+ {"ECDH-RSA-AES256-SHA384", "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA384"},
+ {"ECDH-RSA-AES256-SHA", "TLS-ECDH-RSA-WITH-AES-256-CBC-SHA"},
+ {"ECDH-RSA-CAMELLIA128-SHA256", "TLS-ECDH-RSA-WITH-CAMELLIA-128-CBC-SHA256"},
+ {"ECDH-RSA-CAMELLIA128-SHA", "TLS-ECDH-RSA-WITH-CAMELLIA-128-CBC-SHA"},
+ {"ECDH-RSA-CAMELLIA256-SHA256", "TLS-ECDH-RSA-WITH-CAMELLIA-256-CBC-SHA256"},
+ {"ECDH-RSA-CAMELLIA256-SHA", "TLS-ECDH-RSA-WITH-CAMELLIA-256-CBC-SHA"},
+ {"ECDH-RSA-DES-CBC3-SHA", "TLS-ECDH-RSA-WITH-3DES-EDE-CBC-SHA"},
+ {"ECDH-RSA-DES-CBC-SHA", "TLS-ECDH-RSA-WITH-DES-CBC-SHA"},
+ {"ECDH-RSA-RC4-SHA", "TLS-ECDH-RSA-WITH-RC4-128-SHA"},
+ {"EDH-DSS-DES-CBC3-SHA", "TLS-DHE-DSS-WITH-3DES-EDE-CBC-SHA"},
+ {"EDH-DSS-DES-CBC-SHA", "TLS-DHE-DSS-WITH-DES-CBC-SHA"},
+ {"EDH-RSA-DES-CBC3-SHA", "TLS-DHE-RSA-WITH-3DES-EDE-CBC-SHA"},
+ {"EDH-RSA-DES-CBC-SHA", "TLS-DHE-RSA-WITH-DES-CBC-SHA"},
+ {"EXP-DES-CBC-SHA", "TLS-RSA-EXPORT-WITH-DES40-CBC-SHA"},
+ {"EXP-EDH-DSS-DES-CBC-SHA", "TLS-DH-DSS-EXPORT-WITH-DES40-CBC-SHA"},
+ {"EXP-EDH-RSA-DES-CBC-SHA", "TLS-DH-RSA-EXPORT-WITH-DES40-CBC-SHA"},
+ {"EXP-RC2-CBC-MD5", "TLS-RSA-EXPORT-WITH-RC2-CBC-40-MD5"},
+ {"EXP-RC4-MD5", "TLS-RSA-EXPORT-WITH-RC4-40-MD5"},
+ {"NULL-MD5", "TLS-RSA-WITH-NULL-MD5"},
+ {"NULL-SHA256", "TLS-RSA-WITH-NULL-SHA256"},
+ {"NULL-SHA", "TLS-RSA-WITH-NULL-SHA"},
+ {"PSK-3DES-EDE-CBC-SHA", "TLS-PSK-WITH-3DES-EDE-CBC-SHA"},
+ {"PSK-AES128-CBC-SHA", "TLS-PSK-WITH-AES-128-CBC-SHA"},
+ {"PSK-AES256-CBC-SHA", "TLS-PSK-WITH-AES-256-CBC-SHA"},
+ {"PSK-RC4-SHA", "TLS-PSK-WITH-RC4-128-SHA"},
+ {"RC4-MD5", "TLS-RSA-WITH-RC4-128-MD5"},
+ {"RC4-SHA", "TLS-RSA-WITH-RC4-128-SHA"},
+ {"SEED-SHA", "TLS-RSA-WITH-SEED-CBC-SHA"},
+ {"SRP-DSS-3DES-EDE-CBC-SHA", "TLS-SRP-SHA-DSS-WITH-3DES-EDE-CBC-SHA"},
+ {"SRP-DSS-AES-128-CBC-SHA", "TLS-SRP-SHA-DSS-WITH-AES-128-CBC-SHA"},
+ {"SRP-DSS-AES-256-CBC-SHA", "TLS-SRP-SHA-DSS-WITH-AES-256-CBC-SHA"},
+ {"SRP-RSA-3DES-EDE-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-3DES-EDE-CBC-SHA"},
+ {"SRP-RSA-AES-128-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-AES-128-CBC-SHA"},
+ {"SRP-RSA-AES-256-CBC-SHA", "TLS-SRP-SHA-RSA-WITH-AES-256-CBC-SHA"},
+#ifdef ENABLE_CRYPTO_OPENSSL
+ {"DEFAULT", "DEFAULT"},
+ {"ALL", "ALL"},
+ {"HIGH", "HIGH"},
+ {"MEDIUM", "MEDIUM"},
+ {"LOW", "LOW"},
+ {"ECDH", "ECDH"},
+ {"ECDSA", "ECDSA"},
+ {"EDH", "EDH"},
+ {"EXP", "EXP"},
+ {"RSA", "RSA"},
+ {"SRP", "SRP"},
+#endif
+ {NULL, NULL}
+};
+
+const tls_cipher_name_pair *
+tls_get_cipher_name_pair (const char * cipher_name, size_t len) {
+ const tls_cipher_name_pair * pair = tls_cipher_name_translation_table;
+
+ while (pair->openssl_name != NULL) {
+ if ((strlen(pair->openssl_name) == len && 0 == memcmp (cipher_name, pair->openssl_name, len)) ||
+ (strlen(pair->iana_name) == len && 0 == memcmp (cipher_name, pair->iana_name, len))) {
+ return pair;
+ }
+ pair++;
+ }
+
+ // No entry found, return NULL
+ return NULL;
+}
/*
* Max number of bytes we will add
@@ -300,6 +449,27 @@ ssl_put_auth_challenge (const char *cr_str)
#endif
/*
+ * Parse a TLS version string, returning a TLS_VER_x constant.
+ * If version string is not recognized and extra == "or-highest",
+ * return tls_version_max().
+ */
+int
+tls_version_min_parse(const char *vstr, const char *extra)
+{
+ const int max_version = tls_version_max();
+ if (!strcmp(vstr, "1.0") && TLS_VER_1_0 <= max_version)
+ return TLS_VER_1_0;
+ else if (!strcmp(vstr, "1.1") && TLS_VER_1_1 <= max_version)
+ return TLS_VER_1_1;
+ else if (!strcmp(vstr, "1.2") && TLS_VER_1_2 <= max_version)
+ return TLS_VER_1_2;
+ else if (extra && !strcmp(extra, "or-highest"))
+ return max_version;
+ else
+ return TLS_VER_BAD;
+}
+
+/*
* Initialize SSL context.
* All files are in PEM format.
*/
@@ -348,12 +518,8 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
#ifdef MANAGMENT_EXTERNAL_KEY
else if ((options->management_flags & MF_EXTERNAL_KEY) && options->cert_file)
{
- openvpn_x509_cert_t *my_cert = NULL;
- tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline,
- &my_cert);
- tls_ctx_use_external_private_key(new_ctx, my_cert);
-
- tls_ctx_free_cert_file(my_cert);
+ tls_ctx_use_external_private_key(new_ctx, options->cert_file,
+ options->cert_file_inline);
}
#endif
else
@@ -361,7 +527,7 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
/* Load Certificate */
if (options->cert_file)
{
- tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline, NULL);
+ tls_ctx_load_cert_file(new_ctx, options->cert_file, options->cert_file_inline);
}
/* Load Private Key */
@@ -385,11 +551,12 @@ init_ssl (const struct options *options, struct tls_root_ctx *new_ctx)
tls_ctx_load_extra_certs(new_ctx, options->extra_certs_file, options->extra_certs_file_inline);
}
+ /* Once keys and cert are loaded, load ECDH parameters */
+ if (options->tls_server)
+ tls_ctx_load_ecdh_params(new_ctx, options->ecdh_curve);
+
/* Allowable ciphers */
- if (options->cipher_list)
- {
- tls_ctx_restrict_ciphers(new_ctx, options->cipher_list);
- }
+ tls_ctx_restrict_ciphers(new_ctx, options->cipher_list);
#ifdef ENABLE_CRYPTO_POLARSSL
/* Personalise the random by mixing in the certificate */
@@ -670,6 +837,25 @@ static inline void tls_session_set_self_referential_pointers (struct tls_session
session->tls_auth.packet_id = &session->tls_auth_pid;
}
+/**
+ * Returns whether or not the server should check for username/password
+ *
+ * @param session The current TLS session
+ *
+ * @return true if username and password verification is enabled,
+ * false if not.
+ */
+static inline bool
+tls_session_user_pass_enabled(struct tls_session *session)
+{
+ return (session->opt->auth_user_pass_verify_script
+ || plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
+#ifdef MANAGEMENT_DEF_AUTH
+ || management_enable_def_auth (management)
+#endif
+ );
+}
+
/** @addtogroup control_processor
* @{ */
@@ -959,6 +1145,8 @@ tls_multi_free (struct tls_multi *multi, bool clear)
#ifdef MANAGEMENT_DEF_AUTH
man_def_auth_set_client_reason(multi, NULL);
+#endif
+#if P2MP_SERVER
free (multi->peer_info);
#endif
@@ -1175,7 +1363,7 @@ tls1_P_hash(const md_kt_t *md_kt,
int olen)
{
struct gc_arena gc = gc_new ();
- int chunk,n;
+ int chunk;
hmac_ctx_t ctx;
hmac_ctx_t ctx_tmp;
uint8_t A1[MAX_HMAC_KEY_LENGTH];
@@ -1201,7 +1389,6 @@ tls1_P_hash(const md_kt_t *md_kt,
hmac_ctx_update(&ctx,seed,seed_len);
hmac_ctx_final(&ctx, A1);
- n=0;
for (;;)
{
hmac_ctx_reset(&ctx);
@@ -1585,7 +1772,6 @@ key_method_1_write (struct buffer *buf, struct tls_session *session)
{
struct key key;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
ASSERT (session->opt->key_method == 1);
ASSERT (buf_init (buf, 0));
@@ -1628,7 +1814,7 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
bool ret = false;
#ifdef ENABLE_PUSH_PEER_INFO
- if (session->opt->push_peer_info) /* write peer info */
+ if (session->opt->push_peer_info_detail > 0)
{
struct env_set *es = session->opt->es;
struct env_item *e;
@@ -1651,30 +1837,34 @@ push_peer_info(struct buffer *buf, struct tls_session *session)
#elif defined(TARGET_FREEBSD)
buf_printf (&out, "IV_PLAT=freebsd\n");
#elif defined(TARGET_ANDROID)
- buf_printf(&out, "IV_PLAT=android\n");
+ buf_printf (&out, "IV_PLAT=android\n");
#elif defined(WIN32)
buf_printf (&out, "IV_PLAT=win\n");
#endif
- /* push mac addr */
- {
- struct route_gateway_info rgi;
- get_default_gateway (&rgi);
- if (rgi.flags & RGI_HWADDR_DEFINED)
- buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (rgi.hwaddr, 6, 0, 1, ":", &gc));
- }
-
- /* push LZO status */
-#ifdef ENABLE_LZO_STUB
- buf_printf (&out, "IV_LZO_STUB=1\n");
+ /* push compression status */
+#ifdef USE_COMP
+ comp_generate_peer_info_string(&session->opt->comp_options, &out);
#endif
- /* push env vars that begin with UV_ */
+ if (session->opt->push_peer_info_detail >= 2)
+ {
+ /* push mac addr */
+ struct route_gateway_info rgi;
+ get_default_gateway (&rgi);
+ if (rgi.flags & RGI_HWADDR_DEFINED)
+ buf_printf (&out, "IV_HWADDR=%s\n", format_hex_ex (rgi.hwaddr, 6, 0, 1, ":", &gc));
+ buf_printf (&out, "IV_SSL=%s\n", get_ssl_library_version() );
+ }
+
+ /* push env vars that begin with UV_ and IV_GUI_VER */
for (e=es->list; e != NULL; e=e->next)
{
if (e->string)
{
- if (!strncmp(e->string, "UV_", 3) && buf_safe(&out, strlen(e->string)+1))
+ if (((strncmp(e->string, "UV_", 3)==0 && session->opt->push_peer_info_detail >= 2)
+ || (strncmp(e->string,"IV_GUI_VER=",sizeof("IV_GUI_VER=")-1)==0))
+ && buf_safe(&out, strlen(e->string)+1))
buf_printf (&out, "%s\n", e->string);
}
}
@@ -1699,7 +1889,6 @@ static bool
key_method_2_write (struct buffer *buf, struct tls_session *session)
{
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
ASSERT (session->opt->key_method == 2);
ASSERT (buf_init (buf, 0));
@@ -1783,7 +1972,6 @@ key_method_1_read (struct buffer *buf, struct tls_session *session)
int status;
struct key key;
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
ASSERT (session->opt->key_method == 1);
@@ -1842,13 +2030,13 @@ static bool
key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_session *session)
{
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
- struct key_state *ks_lame = &session->key[KS_LAME_DUCK]; /* retiring key */
int key_method_flags;
bool username_status, password_status;
struct gc_arena gc = gc_new ();
char *options;
+ struct user_pass *up;
/* allocate temporary objects */
ALLOC_ARRAY_CLEAR_GC (options, char, TLS_OPTIONS_LEN, &gc);
@@ -1884,15 +2072,25 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
ks->authenticated = false;
- if (verify_user_pass_enabled(session))
- {
- /* Perform username/password authentication */
- struct user_pass *up;
+ /* always extract username + password fields from buf, even if not
+ * authenticating for it, because otherwise we can't get at the
+ * peer_info data which follows behind
+ */
+ ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc);
+ username_status = read_string (buf, up->username, USER_PASS_LEN);
+ password_status = read_string (buf, up->password, USER_PASS_LEN);
- ALLOC_OBJ_CLEAR_GC (up, struct user_pass, &gc);
- username_status = read_string (buf, up->username, USER_PASS_LEN);
- password_status = read_string (buf, up->password, USER_PASS_LEN);
+#if P2MP_SERVER
+ /* get peer info from control channel */
+ free (multi->peer_info);
+ multi->peer_info = read_string_alloc (buf);
+ if ( multi->peer_info )
+ output_peer_info_env (session->opt->es, multi->peer_info);
+#endif
+ if (tls_session_user_pass_enabled(session))
+ {
+ /* Perform username/password authentication */
if (!username_status || !password_status)
{
CLEAR (*up);
@@ -1903,14 +2101,7 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
}
}
-#ifdef MANAGEMENT_DEF_AUTH
- /* get peer info from control channel */
- free (multi->peer_info);
- multi->peer_info = read_string_alloc (buf);
-#endif
-
verify_user_pass(up, multi, session);
- CLEAR (*up);
}
else
{
@@ -1924,6 +2115,9 @@ key_method_2_read (struct buffer *buf, struct tls_multi *multi, struct tls_sessi
ks->authenticated = true;
}
+ /* clear username and password from memory */
+ CLEAR (*up);
+
/* Perform final authentication checks */
if (ks->authenticated)
{
diff --git a/app/openvpn/src/openvpn/ssl.h b/app/openvpn/src/openvpn/ssl.h
index cd7cae2e..aaecff43 100644
--- a/app/openvpn/src/openvpn/ssl.h
+++ b/app/openvpn/src/openvpn/ssl.h
@@ -44,7 +44,6 @@
#include "plugin.h"
#include "ssl_common.h"
-#include "ssl_verify.h"
#include "ssl_backend.h"
/* Used in the TLS PRF function */
diff --git a/app/openvpn/src/openvpn/ssl_backend.h b/app/openvpn/src/openvpn/ssl_backend.h
index 203a4d26..bfd15496 100644
--- a/app/openvpn/src/openvpn/ssl_backend.h
+++ b/app/openvpn/src/openvpn/ssl_backend.h
@@ -36,12 +36,32 @@
#ifdef ENABLE_CRYPTO_OPENSSL
#include "ssl_openssl.h"
#include "ssl_verify_openssl.h"
+#define SSLAPI SSLAPI_OPENSSL
#endif
#ifdef ENABLE_CRYPTO_POLARSSL
#include "ssl_polarssl.h"
#include "ssl_verify_polarssl.h"
+#define SSLAPI SSLAPI_POLARSSL
#endif
+/* Ensure that SSLAPI got a sane value if SSL is disabled or unknown */
+#ifndef SSLAPI
+#define SSLAPI SSLAPI_NONE
+#endif
+
+/**
+ * prototype for struct tls_session from ssl_common.h
+ */
+struct tls_session;
+
+/**
+ * Get a tls_cipher_name_pair containing OpenSSL and IANA names for supplied TLS cipher name
+ *
+ * @param cipher_name Can be either OpenSSL or IANA cipher name
+ * @return tls_cipher_name_pair* if found, NULL otherwise
+ */
+typedef struct { const char *openssl_name; const char *iana_name; } tls_cipher_name_pair;
+const tls_cipher_name_pair *tls_get_cipher_name_pair (const char *cipher_name, size_t len);
/*
*
@@ -81,6 +101,29 @@ void tls_free_lib();
void tls_clear_error();
/**
+ * Parse a TLS version specifier
+ *
+ * @param vstr The TLS version string
+ * @param extra An optional extra parameter, may be NULL
+ *
+ * @return One of the TLS_VER_x constants or TLS_VER_BAD
+ * if a parse error should be flagged.
+ */
+#define TLS_VER_BAD -1
+#define TLS_VER_1_0 0 /* default */
+#define TLS_VER_1_1 1
+#define TLS_VER_1_2 2
+int tls_version_min_parse(const char *vstr, const char *extra);
+
+/**
+ * Return the maximum TLS version (as a TLS_VER_x constant)
+ * supported by current SSL implementation
+ *
+ * @return One of the TLS_VER_x constants (but not TLS_VER_BAD).
+ */
+int tls_version_max(void);
+
+/**
* Initialise a library-specific TLS context for a server.
*
* @param ctx TLS context to initialise
@@ -124,8 +167,9 @@ void tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags);
/**
* Restrict the list of ciphers that can be used within the TLS context.
*
- * @param ctx TLS context to restrict
- * @param ciphers String containing : delimited cipher names.
+ * @param ctx TLS context to restrict, must be valid.
+ * @param ciphers String containing : delimited cipher names, or NULL to use
+ * sane defaults.
*/
void tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers);
@@ -142,6 +186,16 @@ void tls_ctx_load_dh_params(struct tls_root_ctx *ctx, const char *dh_file,
const char *dh_file_inline);
/**
+ * Load Elliptic Curve Parameters, and load them into the library-specific
+ * TLS context.
+ *
+ * @param ctx TLS context to use
+ * @param curve_name The name of the elliptic curve to load.
+ */
+void tls_ctx_load_ecdh_params(struct tls_root_ctx *ctx, const char *curve_name
+ );
+
+/**
* Load PKCS #12 file for key, cert and (optionally) CA certs, and add to
* library-specific TLS context.
*
@@ -172,27 +226,13 @@ void tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert
* Load certificate file into the given TLS context. If the given certificate
* file contains a certificate chain, load the whole chain.
*
- * If the x509 parameter is not NULL, the certificate will be returned in it.
- *
* @param ctx TLS context to use
* @param cert_file The file name to load the certificate from, or
* "[[INLINE]]" in the case of inline files.
* @param cert_file_inline A string containing the certificate
- * @param x509 An optional certificate, if x509 is NULL,
- * do nothing, if x509 is not NULL, *x509 will be
- * allocated and filled with the loaded certificate.
- * *x509 must be NULL.
*/
void tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file,
- const char *cert_file_inline, openvpn_x509_cert_t **x509
- );
-
-/**
- * Free the given certificate
- *
- * @param x509 certificate to free
- */
-void tls_ctx_free_cert_file (openvpn_x509_cert_t *x509);
+ const char *cert_file_inline);
/**
* Load private key file into the given TLS context.
@@ -212,17 +252,19 @@ int tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
#ifdef MANAGMENT_EXTERNAL_KEY
/**
- * Tell the management interface to load the external private key matching
- * the given certificate.
+ * Tell the management interface to load the given certificate and the external
+ * private key matching the given certificate.
*
* @param ctx TLS context to use
- * @param cert The certificate file to load the private key for
+ * @param cert_file The file name to load the certificate from, or
* "[[INLINE]]" in the case of inline files.
+ * @param cert_file_inline A string containing the certificate
*
* @return 1 if an error occurred, 0 if parsing was
* successful.
*/
-int tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, openvpn_x509_cert_t *cert);
+int tls_ctx_use_external_private_key (struct tls_root_ctx *ctx,
+ const char *cert_file, const char *cert_file_inline);
#endif
@@ -282,7 +324,7 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx);
* @param session The session associated with the given key_state
*/
void key_state_ssl_init(struct key_state_ssl *ks_ssl,
- const struct tls_root_ctx *ssl_ctx, bool is_server, void *session);
+ const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session);
/**
* Free the SSL channel part of the given key state.
@@ -423,8 +465,15 @@ void print_details (struct key_state_ssl * ks_ssl, const char *prefix);
/*
* Show the TLS ciphers that are available for us to use in the OpenSSL
* library.
+ *
+ * @param - list of allowed TLS cipher, or NULL.
*/
-void show_available_tls_ciphers ();
+void show_available_tls_ciphers (const char *tls_ciphers);
+
+/*
+ * Show the available elliptic curves in the crypto library
+ */
+void show_available_curves (void);
/*
* The OpenSSL library has a notion of preference in TLS ciphers. Higher
@@ -432,4 +481,10 @@ void show_available_tls_ciphers ();
*/
void get_highest_preference_tls_cipher (char *buf, int size);
+/**
+ * return a pointer to a static memory area containing the
+ * name and version number of the SSL library in use
+ */
+const char * get_ssl_library_version(void);
+
#endif /* SSL_BACKEND_H_ */
diff --git a/app/openvpn/src/openvpn/ssl_common.h b/app/openvpn/src/openvpn/ssl_common.h
index cb259a96..04ba7892 100644
--- a/app/openvpn/src/openvpn/ssl_common.h
+++ b/app/openvpn/src/openvpn/ssl_common.h
@@ -233,7 +233,7 @@ struct tls_options
bool disable_occ;
#endif
#ifdef ENABLE_PUSH_PEER_INFO
- bool push_peer_info;
+ int push_peer_info_detail;
#endif
int transition_window;
int handshake_window;
@@ -245,7 +245,8 @@ struct tls_options
/* cert verification parms */
const char *verify_command;
const char *verify_export_cert;
- const char *verify_x509name;
+ int verify_x509_type;
+ const char *verify_x509_name;
const char *crl_file;
int ns_cert_type;
unsigned remote_cert_ku[MAX_PARMS];
@@ -284,12 +285,19 @@ struct tls_options
struct env_set *es;
const struct plugin_list *plugins;
- /* configuration file boolean options */
+ /* compression parms */
+#ifdef USE_COMP
+ struct compress_options comp_options;
+#endif
+
+ /* configuration file SSL-related boolean and low-permutation options */
# define SSLF_CLIENT_CERT_NOT_REQUIRED (1<<0)
# define SSLF_USERNAME_AS_COMMON_NAME (1<<1)
# define SSLF_AUTH_USER_PASS_OPTIONAL (1<<2)
# define SSLF_OPT_VERIFY (1<<4)
# define SSLF_CRL_VERIFY_DIR (1<<5)
+# define SSLF_TLS_VERSION_SHIFT 6
+# define SSLF_TLS_VERSION_MASK 0xF /* (uses bit positions 6 to 9) */
unsigned int ssl_flags;
#ifdef MANAGEMENT_DEF_AUTH
@@ -475,14 +483,16 @@ struct tls_multi
*/
char *client_reason;
+ /* Time of last call to tls_authentication_status */
+ time_t tas_last;
+#endif
+
+#if P2MP_SERVER
/*
* A multi-line string of general-purpose info received from peer
* over control channel.
*/
char *peer_info;
-
- /* Time of last call to tls_authentication_status */
- time_t tas_last;
#endif
/*
diff --git a/app/openvpn/src/openvpn/ssl_openssl.c b/app/openvpn/src/openvpn/ssl_openssl.c
index a727b605..c9d2d26d 100644
--- a/app/openvpn/src/openvpn/ssl_openssl.c
+++ b/app/openvpn/src/openvpn/ssl_openssl.c
@@ -56,6 +56,9 @@
#include <openssl/pkcs12.h>
#include <openssl/x509.h>
#include <openssl/crypto.h>
+#ifndef OPENSSL_NO_EC
+#include <openssl/ec.h>
+#endif
/*
* Allocate space in SSL objects in which to store a struct tls_session
@@ -93,33 +96,15 @@ tls_clear_error()
ERR_clear_error ();
}
-/*
- * OpenSSL callback to get a temporary RSA key, mostly
- * used for export ciphers.
- */
-static RSA *
-tmp_rsa_cb (SSL * s, int is_export, int keylength)
-{
- static RSA *rsa_tmp = NULL;
- if (rsa_tmp == NULL)
- {
- msg (D_HANDSHAKE, "Generating temp (%d bit) RSA key", keylength);
- rsa_tmp = RSA_generate_key (keylength, RSA_F4, NULL, NULL);
- }
- return (rsa_tmp);
-}
-
void
tls_ctx_server_new(struct tls_root_ctx *ctx)
{
ASSERT(NULL != ctx);
- ctx->ctx = SSL_CTX_new (TLSv1_server_method ());
+ ctx->ctx = SSL_CTX_new (SSLv23_server_method ());
if (ctx->ctx == NULL)
- msg (M_SSLERR, "SSL_CTX_new TLSv1_server_method");
-
- SSL_CTX_set_tmp_rsa_callback (ctx->ctx, tmp_rsa_cb);
+ msg (M_SSLERR, "SSL_CTX_new SSLv23_server_method");
}
void
@@ -127,10 +112,10 @@ tls_ctx_client_new(struct tls_root_ctx *ctx)
{
ASSERT(NULL != ctx);
- ctx->ctx = SSL_CTX_new (TLSv1_client_method ());
+ ctx->ctx = SSL_CTX_new (SSLv23_client_method ());
if (ctx->ctx == NULL)
- msg (M_SSLERR, "SSL_CTX_new TLSv1_client_method");
+ msg (M_SSLERR, "SSL_CTX_new SSLv23_client_method");
}
void
@@ -174,13 +159,49 @@ info_callback (INFO_CALLBACK_SSL_CONST SSL * s, int where, int ret)
}
}
+/*
+ * Return maximum TLS version supported by local OpenSSL library.
+ * Assume that presence of SSL_OP_NO_TLSvX macro indicates that
+ * TLSvX is supported.
+ */
+int
+tls_version_max(void)
+{
+#if defined(SSL_OP_NO_TLSv1_2)
+ return TLS_VER_1_2;
+#elif defined(SSL_OP_NO_TLSv1_1)
+ return TLS_VER_1_1;
+#else
+ return TLS_VER_1_0;
+#endif
+}
+
void
tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
{
ASSERT(NULL != ctx);
+ /* process SSL options including minimum TLS version we will accept from peer */
+ {
+ long sslopt = SSL_OP_SINGLE_DH_USE | SSL_OP_NO_TICKET | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+ const int tls_version_min = (ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK;
+ if (tls_version_min > TLS_VER_1_0)
+ sslopt |= SSL_OP_NO_TLSv1;
+#ifdef SSL_OP_NO_TLSv1_1
+ if (tls_version_min > TLS_VER_1_1)
+ sslopt |= SSL_OP_NO_TLSv1_1;
+#endif
+#ifdef SSL_OP_NO_TLSv1_2
+ if (tls_version_min > TLS_VER_1_2)
+ sslopt |= SSL_OP_NO_TLSv1_2;
+#endif
+ SSL_CTX_set_options (ctx->ctx, sslopt);
+ }
+
+#ifdef SSL_MODE_RELEASE_BUFFERS
+ SSL_CTX_set_mode (ctx->ctx, SSL_MODE_RELEASE_BUFFERS);
+#endif
SSL_CTX_set_session_cache_mode (ctx->ctx, SSL_SESS_CACHE_OFF);
- SSL_CTX_set_options (ctx->ctx, SSL_OP_SINGLE_DH_USE);
SSL_CTX_set_default_passwd_cb (ctx->ctx, pem_password_callback);
/* Require peer certificate verification */
@@ -202,10 +223,80 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
void
tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
{
+ if (ciphers == NULL)
+ {
+ /* Use sane default (disable export, and unsupported cipher modes) */
+ if(!SSL_CTX_set_cipher_list(ctx->ctx, "DEFAULT:!EXP:!PSK:!SRP"))
+ msg(M_SSLERR, "Failed to set default TLS cipher list.");
+ return;
+ }
+
+ /* Parse supplied cipher list and pass on to OpenSSL */
+ size_t begin_of_cipher, end_of_cipher;
+
+ const char *current_cipher;
+ size_t current_cipher_len;
+
+ const tls_cipher_name_pair *cipher_pair;
+
+ char openssl_ciphers[4096];
+ size_t openssl_ciphers_len = 0;
+ openssl_ciphers[0] = '\0';
+
ASSERT(NULL != ctx);
- if(!SSL_CTX_set_cipher_list(ctx->ctx, ciphers))
- msg(M_SSLERR, "Failed to set restricted TLS cipher list: %s", ciphers);
+ // Translate IANA cipher suite names to OpenSSL names
+ begin_of_cipher = end_of_cipher = 0;
+ for (; begin_of_cipher < strlen(ciphers); begin_of_cipher = end_of_cipher) {
+ end_of_cipher += strcspn(&ciphers[begin_of_cipher], ":");
+ cipher_pair = tls_get_cipher_name_pair(&ciphers[begin_of_cipher], end_of_cipher - begin_of_cipher);
+
+ if (NULL == cipher_pair)
+ {
+ // No translation found, use original
+ current_cipher = &ciphers[begin_of_cipher];
+ current_cipher_len = end_of_cipher - begin_of_cipher;
+
+ // Issue warning on missing translation
+ // %.*s format specifier expects length of type int, so guarantee
+ // that length is small enough and cast to int.
+ msg (M_WARN, "No valid translation found for TLS cipher '%.*s'",
+ constrain_int(current_cipher_len, 0, 256), current_cipher);
+ }
+ else
+ {
+ // Use OpenSSL name
+ current_cipher = cipher_pair->openssl_name;
+ current_cipher_len = strlen(current_cipher);
+
+ if (end_of_cipher - begin_of_cipher == current_cipher_len &&
+ 0 == memcmp (&ciphers[begin_of_cipher], cipher_pair->openssl_name, end_of_cipher - begin_of_cipher))
+ {
+ // Non-IANA name used, show warning
+ msg (M_WARN, "Deprecated TLS cipher name '%s', please use IANA name '%s'", cipher_pair->openssl_name, cipher_pair->iana_name);
+ }
+ }
+
+ // Make sure new cipher name fits in cipher string
+ if (((sizeof(openssl_ciphers)-1) - openssl_ciphers_len) < current_cipher_len) {
+ msg(M_SSLERR, "Failed to set restricted TLS cipher list, too long (>%d).", (int)sizeof(openssl_ciphers)-1);
+ }
+
+ // Concatenate cipher name to OpenSSL cipher string
+ memcpy(&openssl_ciphers[openssl_ciphers_len], current_cipher, current_cipher_len);
+ openssl_ciphers_len += current_cipher_len;
+ openssl_ciphers[openssl_ciphers_len] = ':';
+ openssl_ciphers_len++;
+
+ end_of_cipher++;
+ }
+
+ if (openssl_ciphers_len > 0)
+ openssl_ciphers[openssl_ciphers_len-1] = '\0';
+
+ // Set OpenSSL cipher list
+ if(!SSL_CTX_set_cipher_list(ctx->ctx, openssl_ciphers))
+ msg(M_SSLERR, "Failed to set restricted TLS cipher list: %s", openssl_ciphers);
}
void
@@ -244,6 +335,78 @@ tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file,
DH_free (dh);
}
+void
+tls_ctx_load_ecdh_params (struct tls_root_ctx *ctx, const char *curve_name
+ )
+{
+#ifndef OPENSSL_NO_EC
+ int nid = NID_undef;
+ EC_KEY *ecdh = NULL;
+ const char *sname = NULL;
+
+ /* Generate a new ECDH key for each SSL session (for non-ephemeral ECDH) */
+ SSL_CTX_set_options(ctx->ctx, SSL_OP_SINGLE_ECDH_USE);
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
+ /* OpenSSL 1.0.2 and newer can automatically handle ECDH parameter loading */
+ if (NULL == curve_name) {
+ SSL_CTX_set_ecdh_auto(ctx->ctx, 1);
+ return;
+ }
+#endif
+ /* For older OpenSSL, we'll have to do the parameter loading on our own */
+ if (curve_name != NULL)
+ {
+ /* Use user supplied curve if given */
+ msg (D_TLS_DEBUG, "Using user specified ECDH curve (%s)", curve_name);
+ nid = OBJ_sn2nid(curve_name);
+ }
+ else
+ {
+ /* Extract curve from key */
+ EC_KEY *eckey = NULL;
+ const EC_GROUP *ecgrp = NULL;
+ EVP_PKEY *pkey = NULL;
+
+ /* Little hack to get private key ref from SSL_CTX, yay OpenSSL... */
+ SSL ssl;
+ ssl.cert = ctx->ctx->cert;
+ pkey = SSL_get_privatekey(&ssl);
+
+ msg (D_TLS_DEBUG, "Extracting ECDH curve from private key");
+
+ if (pkey != NULL && (eckey = EVP_PKEY_get1_EC_KEY(pkey)) != NULL &&
+ (ecgrp = EC_KEY_get0_group(eckey)) != NULL)
+ nid = EC_GROUP_get_curve_name(ecgrp);
+ }
+
+ /* Translate NID back to name , just for kicks */
+ sname = OBJ_nid2sn(nid);
+ if (sname == NULL) sname = "(Unknown)";
+
+ /* Create new EC key and set as ECDH key */
+ if (NID_undef == nid || NULL == (ecdh = EC_KEY_new_by_curve_name(nid)))
+ {
+ /* Creating key failed, fall back on sane default */
+ ecdh = EC_KEY_new_by_curve_name(NID_secp384r1);
+ const char *source = (NULL == curve_name) ?
+ "extract curve from certificate" : "use supplied curve";
+ msg (D_TLS_DEBUG_LOW,
+ "Failed to %s (%s), using secp384r1 instead.", source, sname);
+ sname = OBJ_nid2sn(NID_secp384r1);
+ }
+
+ if (!SSL_CTX_set_tmp_ecdh(ctx->ctx, ecdh))
+ msg (M_SSLERR, "SSL_CTX_set_tmp_ecdh: cannot add curve");
+
+ msg (D_TLS_DEBUG_LOW, "ECDH curve %s added", sname);
+
+ EC_KEY_free(ecdh);
+#else
+ msg (M_DEBUG, "Your OpenSSL library was built without elliptic curve support."
+ " Skipping ECDH parameter loading.");
+#endif /* OPENSSL_NO_EC */
+}
+
int
tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
const char *pkcs12_file_inline,
@@ -318,16 +481,34 @@ tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
/* Set Certificate Verification chain */
if (load_ca_file)
{
+ /* Add CAs from PKCS12 to the cert store and mark them as trusted.
+ * They're also used to fill in the chain of intermediate certs as
+ * necessary.
+ */
if (ca && sk_X509_num(ca))
{
for (i = 0; i < sk_X509_num(ca); i++)
{
- if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i)))
+ if (!X509_STORE_add_cert(ctx->ctx->cert_store,sk_X509_value(ca, i)))
msg (M_SSLERR, "Cannot add certificate to certificate chain (X509_STORE_add_cert)");
if (!SSL_CTX_add_client_CA(ctx->ctx, sk_X509_value(ca, i)))
msg (M_SSLERR, "Cannot add certificate to client CA list (SSL_CTX_add_client_CA)");
}
}
+ } else {
+ /* If trusted CA certs were loaded from a PEM file, and we ignore the
+ * ones in PKCS12, do load PKCS12-provided certs to the client extra
+ * certs chain just in case they include intermediate CAs needed to
+ * prove my identity to the other end. This does not make them trusted.
+ */
+ if (ca && sk_X509_num(ca))
+ {
+ for (i = 0; i < sk_X509_num(ca); i++)
+ {
+ if (!SSL_CTX_add_extra_chain_cert(ctx->ctx,sk_X509_value(ca, i)))
+ msg (M_SSLERR, "Cannot add extra certificate to chain (SSL_CTX_add_extra_chain_cert)");
+ }
+ }
}
return 0;
}
@@ -361,9 +542,10 @@ tls_ctx_add_extra_certs (struct tls_root_ctx *ctx, BIO *bio)
}
}
-void
-tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file,
- const char *cert_file_inline, X509 **x509
+/* Like tls_ctx_load_cert, but returns a copy of the certificate in **X509 */
+static void
+tls_ctx_load_cert_file_and_copy (struct tls_root_ctx *ctx,
+ const char *cert_file, const char *cert_file_inline, X509 **x509
)
{
BIO *in = NULL;
@@ -418,6 +600,13 @@ end:
}
void
+tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file,
+ const char *cert_file_inline)
+{
+ tls_ctx_load_cert_file_and_copy (ctx, cert_file, cert_file_inline, NULL);
+}
+
+void
tls_ctx_free_cert_file (X509 *x509)
{
X509_free(x509);
@@ -428,7 +617,6 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
const char *priv_key_file_inline
)
{
- int status;
SSL_CTX *ssl_ctx = NULL;
BIO *in = NULL;
EVP_PKEY *pkey = NULL;
@@ -554,13 +742,18 @@ rsa_priv_enc(int flen, const unsigned char *from, unsigned char *to, RSA *rsa, i
}
int
-tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, X509 *cert)
+tls_ctx_use_external_private_key (struct tls_root_ctx *ctx,
+ const char *cert_file, const char *cert_file_inline)
{
RSA *rsa = NULL;
RSA *pub_rsa;
RSA_METHOD *rsa_meth;
+ X509 *cert = NULL;
ASSERT (NULL != ctx);
+
+ tls_ctx_load_cert_file_and_copy (ctx, cert_file, cert_file_inline, &cert);
+
ASSERT (NULL != cert);
/* allocate custom RSA method object */
@@ -597,10 +790,13 @@ tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, X509 *cert)
if (!SSL_CTX_use_RSAPrivateKey(ctx->ctx, rsa))
goto err;
+ X509_free(cert);
RSA_free(rsa); /* doesn't necessarily free, just decrements refcount */
return 1;
err:
+ if (cert)
+ X509_free(cert);
if (rsa)
RSA_free(rsa);
else
@@ -632,7 +828,7 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
X509_STORE *store = NULL;
X509_NAME *xn = NULL;
BIO *in = NULL;
- int i, added = 0;
+ int i, added = 0, prev = 0;
ASSERT(NULL != ctx);
@@ -659,6 +855,11 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
if (info->crl)
X509_STORE_add_crl (store, info->crl);
+ if (tls_server && !info->x509)
+ {
+ msg (M_SSLERR, "X509 name was missing in TLS mode");
+ }
+
if (info->x509)
{
X509_STORE_add_cert (store, info->x509);
@@ -688,6 +889,15 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
sk_X509_NAME_push (cert_names, xn);
}
}
+
+ if (tls_server) {
+ int cnum = sk_X509_NAME_num (cert_names);
+ if (cnum != (prev + 1)) {
+ msg (M_WARN, "Cannot load CA certificate file %s (entry %d did not validate)", np(ca_file), added);
+ }
+ prev = cnum;
+ }
+
}
sk_X509_INFO_pop_free (info_stack, X509_INFO_free);
}
@@ -695,8 +905,15 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
if (tls_server)
SSL_CTX_set_client_CA_list (ctx->ctx, cert_names);
- if (!added || (tls_server && sk_X509_NAME_num (cert_names) != added))
- msg (M_SSLERR, "Cannot load CA certificate file %s", np(ca_file));
+ if (!added)
+ msg (M_SSLERR, "Cannot load CA certificate file %s (no entries were read)", np(ca_file));
+
+ if (tls_server) {
+ int cnum = sk_X509_NAME_num (cert_names);
+ if (cnum != added)
+ msg (M_SSLERR, "Cannot load CA certificate file %s (only %d of %d entries were valid X509 names)", np(ca_file), cnum, added);
+ }
+
if (in)
BIO_free (in);
}
@@ -709,11 +926,7 @@ tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
msg(M_WARN, "WARNING: experimental option --capath %s", ca_path);
else
msg(M_SSLERR, "Cannot add lookup at --capath %s", ca_path);
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L
X509_STORE_set_flags (store, X509_V_FLAG_CRL_CHECK | X509_V_FLAG_CRL_CHECK_ALL);
-#else
- msg(M_WARN, "WARNING: this version of OpenSSL cannot handle CRL files in capath");
-#endif
}
}
@@ -953,7 +1166,7 @@ bio_read (BIO *bio, struct buffer *buf, int maxlen, const char *desc)
}
void
-key_state_ssl_init(struct key_state_ssl *ks_ssl, const struct tls_root_ctx *ssl_ctx, bool is_server, void *session)
+key_state_ssl_init(struct key_state_ssl *ks_ssl, const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session)
{
ASSERT(NULL != ssl_ctx);
ASSERT(ks_ssl);
@@ -1126,29 +1339,86 @@ print_details (struct key_state_ssl * ks_ssl, const char *prefix)
}
void
-show_available_tls_ciphers ()
+show_available_tls_ciphers (const char *cipher_list)
{
- SSL_CTX *ctx;
+ struct tls_root_ctx tls_ctx;
SSL *ssl;
const char *cipher_name;
+ const tls_cipher_name_pair *pair;
int priority = 0;
- ctx = SSL_CTX_new (TLSv1_method ());
- if (!ctx)
+ tls_ctx.ctx = SSL_CTX_new (SSLv23_method ());
+ if (!tls_ctx.ctx)
msg (M_SSLERR, "Cannot create SSL_CTX object");
- ssl = SSL_new (ctx);
+ ssl = SSL_new (tls_ctx.ctx);
if (!ssl)
msg (M_SSLERR, "Cannot create SSL object");
+ tls_ctx_restrict_ciphers(&tls_ctx, cipher_list);
+
printf ("Available TLS Ciphers,\n");
printf ("listed in order of preference:\n\n");
while ((cipher_name = SSL_get_cipher_list (ssl, priority++)))
- printf ("%s\n", cipher_name);
+ {
+ pair = tls_get_cipher_name_pair(cipher_name, strlen(cipher_name));
+
+ if (NULL == pair) {
+ // No translation found, print warning
+ printf ("%s (No IANA name known to OpenVPN, use OpenSSL name.)\n", cipher_name);
+ } else {
+ printf ("%s\n", pair->iana_name);
+ }
+
+ }
printf ("\n");
SSL_free (ssl);
- SSL_CTX_free (ctx);
+ SSL_CTX_free (tls_ctx.ctx);
+}
+
+/*
+ * Show the Elliptic curves that are available for us to use
+ * in the OpenSSL library.
+ */
+void
+show_available_curves()
+{
+#ifndef OPENSSL_NO_EC
+ EC_builtin_curve *curves = NULL;
+ size_t crv_len = 0;
+ size_t n = 0;
+
+ crv_len = EC_get_builtin_curves(NULL, 0);
+
+ curves = OPENSSL_malloc((int)(sizeof(EC_builtin_curve) * crv_len));
+
+ if (curves == NULL)
+ msg (M_SSLERR, "Cannot create EC_builtin_curve object");
+ else
+ {
+ if (EC_get_builtin_curves(curves, crv_len))
+ {
+ printf ("Available Elliptic curves:\n");
+ for (n = 0; n < crv_len; n++)
+ {
+ const char *sname;
+ sname = OBJ_nid2sn(curves[n].nid);
+ if (sname == NULL) sname = "";
+
+ printf("%s\n", sname);
+ }
+ }
+ else
+ {
+ msg (M_SSLERR, "Cannot get list of builtin curves");
+ }
+ OPENSSL_free(curves);
+ }
+#else
+ msg (M_WARN, "Your OpenSSL library was built without elliptic curve support. "
+ "No curves available.");
+#endif
}
void
@@ -1158,7 +1428,7 @@ get_highest_preference_tls_cipher (char *buf, int size)
SSL *ssl;
const char *cipher_name;
- ctx = SSL_CTX_new (TLSv1_method ());
+ ctx = SSL_CTX_new (SSLv23_method ());
if (!ctx)
msg (M_SSLERR, "Cannot create SSL_CTX object");
ssl = SSL_new (ctx);
@@ -1172,4 +1442,10 @@ get_highest_preference_tls_cipher (char *buf, int size)
SSL_CTX_free (ctx);
}
+const char *
+get_ssl_library_version(void)
+{
+ return SSLeay_version(SSLEAY_VERSION);
+}
+
#endif /* defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_OPENSSL) */
diff --git a/app/openvpn/src/openvpn/ssl_polarssl.c b/app/openvpn/src/openvpn/ssl_polarssl.c
index 12318b33..ddccf1d9 100644
--- a/app/openvpn/src/openvpn/ssl_polarssl.c
+++ b/app/openvpn/src/openvpn/ssl_polarssl.c
@@ -7,6 +7,7 @@
*
* Copyright (C) 2002-2010 OpenVPN Technologies, Inc. <sales@openvpn.net>
* Copyright (C) 2010 Fox Crypto B.V. <openvpn@fox-it.com>
+ * Copyright (C) 2006-2010, Brainspark B.V.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@@ -44,11 +45,12 @@
#include "manage.h"
#include "ssl_common.h"
-#include <polarssl/sha2.h>
#include <polarssl/havege.h>
#include "ssl_verify_polarssl.h"
+#include <polarssl/error.h>
#include <polarssl/pem.h>
+#include <polarssl/sha256.h>
void
tls_init_lib()
@@ -65,23 +67,6 @@ tls_clear_error()
{
}
-static int default_ciphersuites[] =
-{
- SSL_EDH_RSA_AES_256_SHA,
- SSL_EDH_RSA_CAMELLIA_256_SHA,
- SSL_EDH_RSA_AES_128_SHA,
- SSL_EDH_RSA_CAMELLIA_128_SHA,
- SSL_EDH_RSA_DES_168_SHA,
- SSL_RSA_AES_256_SHA,
- SSL_RSA_CAMELLIA_256_SHA,
- SSL_RSA_AES_128_SHA,
- SSL_RSA_CAMELLIA_128_SHA,
- SSL_RSA_DES_168_SHA,
- SSL_RSA_RC4_128_SHA,
- SSL_RSA_RC4_128_MD5,
- 0
-};
-
void
tls_ctx_server_new(struct tls_root_ctx *ctx)
{
@@ -89,10 +74,10 @@ tls_ctx_server_new(struct tls_root_ctx *ctx)
CLEAR(*ctx);
ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context);
- ALLOC_OBJ_CLEAR(ctx->priv_key, rsa_context);
+ ALLOC_OBJ_CLEAR(ctx->priv_key, pk_context);
- ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_cert);
- ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_cert);
+ ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt);
+ ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_crt);
ctx->endpoint = SSL_IS_SERVER;
@@ -106,10 +91,10 @@ tls_ctx_client_new(struct tls_root_ctx *ctx)
CLEAR(*ctx);
ALLOC_OBJ_CLEAR(ctx->dhm_ctx, dhm_context);
- ALLOC_OBJ_CLEAR(ctx->priv_key, rsa_context);
+ ALLOC_OBJ_CLEAR(ctx->priv_key, pk_context);
- ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_cert);
- ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_cert);
+ ALLOC_OBJ_CLEAR(ctx->ca_chain, x509_crt);
+ ALLOC_OBJ_CLEAR(ctx->crt_chain, x509_crt);
ctx->endpoint = SSL_IS_CLIENT;
ctx->initialised = true;
@@ -120,13 +105,13 @@ tls_ctx_free(struct tls_root_ctx *ctx)
{
if (ctx)
{
- rsa_free(ctx->priv_key);
+ pk_free(ctx->priv_key);
free(ctx->priv_key);
- x509_free(ctx->ca_chain);
+ x509_crt_free(ctx->ca_chain);
free(ctx->ca_chain);
- x509_free(ctx->crt_chain);
+ x509_crt_free(ctx->crt_chain);
free(ctx->crt_chain);
dhm_free(ctx->dhm_ctx);
@@ -138,6 +123,10 @@ tls_ctx_free(struct tls_root_ctx *ctx)
free(ctx->priv_key_pkcs11);
}
#endif
+#if defined(MANAGMENT_EXTERNAL_KEY)
+ if (ctx->external_key != NULL)
+ free(ctx->external_key);
+#endif
if (ctx->allowed_ciphers)
free(ctx->allowed_ciphers);
@@ -161,12 +150,36 @@ tls_ctx_set_options (struct tls_root_ctx *ctx, unsigned int ssl_flags)
{
}
+static const char *
+tls_translate_cipher_name (const char * cipher_name) {
+ const tls_cipher_name_pair * pair = tls_get_cipher_name_pair(cipher_name, strlen(cipher_name));
+
+ if (NULL == pair)
+ {
+ // No translation found, return original
+ return cipher_name;
+ }
+
+ if (0 != strcmp(cipher_name, pair->iana_name))
+ {
+ // Deprecated name found, notify user
+ msg(M_WARN, "Deprecated cipher suite name '%s', please use IANA name '%s'", pair->openssl_name, pair->iana_name);
+ }
+
+ return pair->iana_name;
+}
+
void
tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
{
char *tmp_ciphers, *tmp_ciphers_orig, *token;
int i, cipher_count;
- int ciphers_len = strlen (ciphers);
+ int ciphers_len;
+
+ if (NULL == ciphers)
+ return; /* Nothing to do */
+
+ ciphers_len = strlen (ciphers);
ASSERT (NULL != ctx);
ASSERT (0 != ciphers_len);
@@ -186,7 +199,8 @@ tls_ctx_restrict_ciphers(struct tls_root_ctx *ctx, const char *ciphers)
token = strtok (tmp_ciphers, ":");
while(token)
{
- ctx->allowed_ciphers[i] = ssl_get_ciphersuite_id (token);
+ ctx->allowed_ciphers[i] = ssl_get_ciphersuite_id (
+ tls_translate_cipher_name (token));
if (0 != ctx->allowed_ciphers[i])
i++;
token = strtok (NULL, ":");
@@ -201,12 +215,12 @@ tls_ctx_load_dh_params (struct tls_root_ctx *ctx, const char *dh_file,
{
if (!strcmp (dh_file, INLINE_FILE_TAG) && dh_file_inline)
{
- if (0 != x509parse_dhm(ctx->dhm_ctx, dh_file_inline, strlen(dh_file_inline)))
+ if (0 != dhm_parse_dhm(ctx->dhm_ctx, dh_file_inline, strlen(dh_file_inline)))
msg (M_FATAL, "Cannot read inline DH parameters");
}
else
{
- if (0 != x509parse_dhmfile(ctx->dhm_ctx, dh_file))
+ if (0 != dhm_parse_dhmfile(ctx->dhm_ctx, dh_file))
msg (M_FATAL, "Cannot read DH parameters from file %s", dh_file);
}
@@ -214,6 +228,15 @@ else
(counter_type) 8 * mpi_size(&ctx->dhm_ctx->P));
}
+void
+tls_ctx_load_ecdh_params (struct tls_root_ctx *ctx, const char *curve_name
+ )
+{
+ if (NULL != curve_name)
+ msg(M_WARN, "WARNING: PolarSSL builds do not support specifying an ECDH "
+ "curve, using default curves.");
+}
+
int
tls_ctx_load_pkcs12(struct tls_root_ctx *ctx, const char *pkcs12_file,
const char *pkcs12_file_inline,
@@ -234,37 +257,29 @@ tls_ctx_load_cryptoapi(struct tls_root_ctx *ctx, const char *cryptoapi_cert)
void
tls_ctx_load_cert_file (struct tls_root_ctx *ctx, const char *cert_file,
- const char *cert_file_inline,
- openvpn_x509_cert_t **x509
+ const char *cert_file_inline
)
{
ASSERT(NULL != ctx);
- if (NULL != x509)
- ASSERT(NULL == *x509);
if (!strcmp (cert_file, INLINE_FILE_TAG) && cert_file_inline)
{
- if (0 != x509parse_crt(ctx->crt_chain, cert_file_inline,
+ if (0 != x509_crt_parse(ctx->crt_chain, cert_file_inline,
strlen(cert_file_inline)))
msg (M_FATAL, "Cannot load inline certificate file");
}
else
{
- if (0 != x509parse_crtfile(ctx->crt_chain, cert_file))
- msg (M_FATAL, "Cannot load certificate file %s", cert_file);
- }
- if (x509)
- {
- *x509 = ctx->crt_chain;
+ int retval = x509_crt_parse_file(ctx->crt_chain, cert_file);
+ if (0 != retval)
+ {
+ char errstr[128];
+ polarssl_strerror(retval, errstr, sizeof(errstr));
+ msg (M_FATAL, "Cannot load certificate file %s (%s)", cert_file, errstr);
+ }
}
}
-void
-tls_ctx_free_cert_file (openvpn_x509_cert_t *x509)
-{
- x509_free(x509);
-}
-
int
tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
const char *priv_key_file_inline
@@ -275,26 +290,27 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
if (!strcmp (priv_key_file, INLINE_FILE_TAG) && priv_key_file_inline)
{
- status = x509parse_key(ctx->priv_key,
+ status = pk_parse_key(ctx->priv_key,
priv_key_file_inline, strlen(priv_key_file_inline),
NULL, 0);
+
if (POLARSSL_ERR_PEM_PASSWORD_REQUIRED == status)
{
char passbuf[512] = {0};
pem_password_callback(passbuf, 512, 0, NULL);
- status = x509parse_key(ctx->priv_key,
+ status = pk_parse_key(ctx->priv_key,
priv_key_file_inline, strlen(priv_key_file_inline),
- passbuf, strlen(passbuf));
+ (unsigned char *) passbuf, strlen(passbuf));
}
}
else
{
- status = x509parse_keyfile(ctx->priv_key, priv_key_file, NULL);
+ status = pk_parse_keyfile(ctx->priv_key, priv_key_file, NULL);
if (POLARSSL_ERR_PEM_PASSWORD_REQUIRED == status)
{
char passbuf[512] = {0};
pem_password_callback(passbuf, 512, 0, NULL);
- status = x509parse_keyfile(ctx->priv_key, priv_key_file, passbuf);
+ status = pk_parse_keyfile(ctx->priv_key, priv_key_file, passbuf);
}
}
if (0 != status)
@@ -319,13 +335,161 @@ tls_ctx_load_priv_file (struct tls_root_ctx *ctx, const char *priv_key_file,
#ifdef MANAGMENT_EXTERNAL_KEY
+
+struct external_context {
+ size_t signature_length;
+};
+
int
-tls_ctx_use_external_private_key (struct tls_root_ctx *ctx, openvpn_x509_cert_t *cert)
+tls_ctx_use_external_private_key (struct tls_root_ctx *ctx,
+ const char *cert_file, const char *cert_file_inline)
{
- msg(M_FATAL, "Use of management external keys not yet supported for PolarSSL.");
- return false;
+ ASSERT(NULL != ctx);
+
+ tls_ctx_load_cert_file(ctx, cert_file, cert_file_inline);
+
+ if (ctx->crt_chain == NULL)
+ return 0;
+
+ /* Most of the initialization happens in key_state_ssl_init() */
+ ALLOC_OBJ_CLEAR (ctx->external_key, struct external_context);
+ ctx->external_key->signature_length = pk_get_len(&ctx->crt_chain->pk);
+
+ return 1;
}
+/**
+ * external_pkcs1_sign implements a PolarSSL rsa_sign_func callback, that uses
+ * the management interface to request an RSA signature for the supplied hash.
+ *
+ * @param ctx_voidptr Management external key context.
+ * @param f_rng (Unused)
+ * @param p_rng (Unused)
+ * @param mode RSA mode (should be RSA_PRIVATE).
+ * @param md_alg Message digest ('hash') algorithm type.
+ * @param hashlen Length of hash (overridden by length specified by md_alg
+ * if md_alg != POLARSSL_MD_NONE).
+ * @param hash The digest ('hash') to sign. Should have a size
+ * matching the length of md_alg (if != POLARSSL_MD_NONE),
+ * or hashlen otherwise.
+ * @param sig Buffer that returns the signature. Should be at least of
+ * size ctx->signature_length.
+ *
+ * @return 0 on success, non-zero polarssl error code on failure.
+ */
+static inline int external_pkcs1_sign( void *ctx_voidptr,
+ int (*f_rng)(void *, unsigned char *, size_t), void *p_rng, int mode,
+ md_type_t md_alg, unsigned int hashlen, const unsigned char *hash,
+ unsigned char *sig )
+{
+ struct external_context * const ctx = ctx_voidptr;
+ char *in_b64 = NULL;
+ char *out_b64 = NULL;
+ int rv;
+ unsigned char *p = sig;
+ size_t asn_len = 0, oid_size = 0, sig_len = 0;
+ const char *oid = NULL;
+
+ if( NULL == ctx )
+ return POLARSSL_ERR_RSA_BAD_INPUT_DATA;
+
+ if( RSA_PRIVATE != mode )
+ return POLARSSL_ERR_RSA_BAD_INPUT_DATA;
+
+ /*
+ * Support a wide range of hashes. TLSv1.1 and before only need SIG_RSA_RAW,
+ * but TLSv1.2 needs the full suite of hashes.
+ *
+ * This code has been taken from PolarSSL pkcs11_sign(), under the GPLv2.0+.
+ */
+ if( md_alg != POLARSSL_MD_NONE )
+ {
+ const md_info_t *md_info = md_info_from_type( md_alg );
+ if( md_info == NULL )
+ return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+ if( oid_get_oid_by_md( md_alg, &oid, &oid_size ) != 0 )
+ return( POLARSSL_ERR_RSA_BAD_INPUT_DATA );
+
+ hashlen = md_get_size( md_info );
+ asn_len = 10 + oid_size;
+ }
+
+ sig_len = ctx->signature_length;
+ if ( (SIZE_MAX - hashlen) < asn_len || (hashlen + asn_len) > sig_len )
+ return POLARSSL_ERR_RSA_BAD_INPUT_DATA;
+
+ if( md_alg != POLARSSL_MD_NONE )
+ {
+ /*
+ * DigestInfo ::= SEQUENCE {
+ * digestAlgorithm DigestAlgorithmIdentifier,
+ * digest Digest }
+ *
+ * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+ *
+ * Digest ::= OCTET STRING
+ */
+ *p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED;
+ *p++ = (unsigned char) ( 0x08 + oid_size + hashlen );
+ *p++ = ASN1_SEQUENCE | ASN1_CONSTRUCTED;
+ *p++ = (unsigned char) ( 0x04 + oid_size );
+ *p++ = ASN1_OID;
+ *p++ = oid_size & 0xFF;
+ memcpy( p, oid, oid_size );
+ p += oid_size;
+ *p++ = ASN1_NULL;
+ *p++ = 0x00;
+ *p++ = ASN1_OCTET_STRING;
+ *p++ = hashlen;
+
+ /* Determine added ASN length */
+ asn_len = p - sig;
+ }
+
+ /* Copy the hash to be signed */
+ memcpy( p, hash, hashlen );
+
+ /* convert 'from' to base64 */
+ if (openvpn_base64_encode (sig, asn_len + hashlen, &in_b64) <= 0)
+ {
+ rv = POLARSSL_ERR_RSA_BAD_INPUT_DATA;
+ goto done;
+ }
+
+ /* call MI for signature */
+ if (management)
+ out_b64 = management_query_rsa_sig (management, in_b64);
+ if (!out_b64)
+ {
+ rv = POLARSSL_ERR_RSA_PRIVATE_FAILED;
+ goto done;
+ }
+
+ /* decode base64 signature to binary and verify length */
+ if ( openvpn_base64_decode (out_b64, sig, ctx->signature_length) !=
+ ctx->signature_length )
+ {
+ rv = POLARSSL_ERR_RSA_PRIVATE_FAILED;
+ goto done;
+ }
+
+ rv = 0;
+
+done:
+ if (in_b64)
+ free (in_b64);
+ if (out_b64)
+ free (out_b64);
+ return rv;
+}
+
+static inline size_t external_key_len(void *vctx)
+{
+ struct external_context * const ctx = vctx;
+
+ return ctx->signature_length;
+}
#endif
void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
@@ -338,14 +502,20 @@ void tls_ctx_load_ca (struct tls_root_ctx *ctx, const char *ca_file,
if (ca_file && !strcmp (ca_file, INLINE_FILE_TAG) && ca_file_inline)
{
- if (0 != x509parse_crt(ctx->ca_chain, ca_file_inline, strlen(ca_file_inline)))
+ if (0 != x509_crt_parse(ctx->ca_chain, (unsigned char *) ca_file_inline,
+ strlen(ca_file_inline)))
msg (M_FATAL, "Cannot load inline CA certificates");
}
else
{
/* Load CA file for verifying peer supplied certificate */
- if (0 != x509parse_crtfile(ctx->ca_chain, ca_file))
- msg (M_FATAL, "Cannot load CA certificate file %s", ca_file);
+ int retval = x509_crt_parse_file(ctx->ca_chain, ca_file);
+ if (0 != retval)
+ {
+ char errstr[128];
+ polarssl_strerror(retval, errstr, sizeof(errstr));
+ msg (M_FATAL, "Cannot load CA certificate file %s (%s)", ca_file, errstr);
+ }
}
}
@@ -358,13 +528,14 @@ tls_ctx_load_extra_certs (struct tls_root_ctx *ctx, const char *extra_certs_file
if (!strcmp (extra_certs_file, INLINE_FILE_TAG) && extra_certs_file_inline)
{
- if (0 != x509parse_crt(ctx->crt_chain, extra_certs_file_inline,
+ if (0 != x509_crt_parse(ctx->crt_chain,
+ (unsigned char *) extra_certs_file_inline,
strlen(extra_certs_file_inline)))
msg (M_FATAL, "Cannot load inline extra-certs file");
}
else
{
- if (0 != x509parse_crtfile(ctx->crt_chain, extra_certs_file))
+ if (0 != x509_crt_parse_file(ctx->crt_chain, extra_certs_file))
msg (M_FATAL, "Cannot load extra-certs file: %s", extra_certs_file);
}
}
@@ -482,14 +653,14 @@ static void my_debug( void *ctx, int level, const char *str )
void tls_ctx_personalise_random(struct tls_root_ctx *ctx)
{
static char old_sha256_hash[32] = {0};
- char sha256_hash[32] = {0};
+ unsigned char sha256_hash[32] = {0};
ctr_drbg_context *cd_ctx = rand_ctx_get();
if (NULL != ctx->crt_chain)
{
- x509_cert *cert = ctx->crt_chain;
+ x509_crt *cert = ctx->crt_chain;
- sha2(cert->tbs.p, cert->tbs.len, sha256_hash, false);
+ sha256(cert->tbs.p, cert->tbs.len, sha256_hash, false);
if ( 0 != memcmp(old_sha256_hash, sha256_hash, sizeof(sha256_hash)))
{
ctr_drbg_update(cd_ctx, sha256_hash, 32);
@@ -498,8 +669,20 @@ void tls_ctx_personalise_random(struct tls_root_ctx *ctx)
}
}
+int
+tls_version_max(void)
+{
+#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3)
+ return TLS_VER_1_2;
+#elif defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2)
+ return TLS_VER_1_1;
+#else
+ return TLS_VER_1_0;
+#endif
+}
+
void key_state_ssl_init(struct key_state_ssl *ks_ssl,
- const struct tls_root_ctx *ssl_ctx, bool is_server, void *session)
+ const struct tls_root_ctx *ssl_ctx, bool is_server, struct tls_session *session)
{
ASSERT(NULL != ssl_ctx);
ASSERT(ks_ssl);
@@ -514,36 +697,79 @@ void key_state_ssl_init(struct key_state_ssl *ks_ssl,
ssl_set_rng (ks_ssl->ctx, ctr_drbg_random, rand_ctx_get());
- ALLOC_OBJ_CLEAR (ks_ssl->ssn, ssl_session);
- ssl_set_session (ks_ssl->ctx, 0, 0, ks_ssl->ssn );
if (ssl_ctx->allowed_ciphers)
ssl_set_ciphersuites (ks_ssl->ctx, ssl_ctx->allowed_ciphers);
- else
- ssl_set_ciphersuites (ks_ssl->ctx, default_ciphersuites);
/* Initialise authentication information */
if (is_server)
ssl_set_dh_param_ctx (ks_ssl->ctx, ssl_ctx->dhm_ctx );
#if defined(ENABLE_PKCS11)
if (ssl_ctx->priv_key_pkcs11 != NULL)
- ssl_set_own_cert_pkcs11( ks_ssl->ctx, ssl_ctx->crt_chain,
- ssl_ctx->priv_key_pkcs11 );
+ ssl_set_own_cert_alt( ks_ssl->ctx, ssl_ctx->crt_chain,
+ ssl_ctx->priv_key_pkcs11, ssl_pkcs11_decrypt, ssl_pkcs11_sign,
+ ssl_pkcs11_key_len );
+ else
+#endif
+#if defined(MANAGMENT_EXTERNAL_KEY)
+ if (ssl_ctx->external_key != NULL)
+ ssl_set_own_cert_alt( ks_ssl->ctx, ssl_ctx->crt_chain,
+ ssl_ctx->external_key, NULL, external_pkcs1_sign,
+ external_key_len );
else
#endif
ssl_set_own_cert( ks_ssl->ctx, ssl_ctx->crt_chain, ssl_ctx->priv_key );
/* Initialise SSL verification */
- ssl_set_authmode (ks_ssl->ctx, SSL_VERIFY_REQUIRED);
- ssl_set_verify (ks_ssl->ctx, verify_callback, session);
+#if P2MP_SERVER
+ if (session->opt->ssl_flags & SSLF_CLIENT_CERT_NOT_REQUIRED)
+ {
+ msg (M_WARN, "WARNING: POTENTIALLY DANGEROUS OPTION "
+ "--client-cert-not-required may accept clients which do not present "
+ "a certificate");
+ }
+ else
+#endif
+ {
+ ssl_set_authmode (ks_ssl->ctx, SSL_VERIFY_REQUIRED);
+ ssl_set_verify (ks_ssl->ctx, verify_callback, session);
+ }
+
/* TODO: PolarSSL does not currently support sending the CA chain to the client */
ssl_set_ca_chain (ks_ssl->ctx, ssl_ctx->ca_chain, NULL, NULL );
+ /* Initialize minimum TLS version */
+ {
+ const int tls_version_min = (session->opt->ssl_flags >> SSLF_TLS_VERSION_SHIFT) & SSLF_TLS_VERSION_MASK;
+ int polar_major;
+ int polar_minor;
+ switch (tls_version_min)
+ {
+ case TLS_VER_1_0:
+ default:
+ polar_major = SSL_MAJOR_VERSION_3;
+ polar_minor = SSL_MINOR_VERSION_1;
+ break;
+#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_2)
+ case TLS_VER_1_1:
+ polar_major = SSL_MAJOR_VERSION_3;
+ polar_minor = SSL_MINOR_VERSION_2;
+ break;
+#endif
+#if defined(SSL_MAJOR_VERSION_3) && defined(SSL_MINOR_VERSION_3)
+ case TLS_VER_1_2:
+ polar_major = SSL_MAJOR_VERSION_3;
+ polar_minor = SSL_MINOR_VERSION_3;
+ break;
+#endif
+ }
+ ssl_set_min_version(ks_ssl->ctx, polar_major, polar_minor);
+ }
+
/* Initialise BIOs */
ALLOC_OBJ_CLEAR (ks_ssl->ct_in, endless_buffer);
ALLOC_OBJ_CLEAR (ks_ssl->ct_out, endless_buffer);
ssl_set_bio (ks_ssl->ctx, endless_buf_read, ks_ssl->ct_in,
endless_buf_write, ks_ssl->ct_out);
-
}
}
@@ -556,8 +782,6 @@ key_state_ssl_free(struct key_state_ssl *ks_ssl)
ssl_free(ks_ssl->ctx);
free(ks_ssl->ctx);
}
- if (ks_ssl->ssn)
- free(ks_ssl->ssn);
if (ks_ssl->ct_in) {
buf_free_entries(ks_ssl->ct_in);
free(ks_ssl->ct_in);
@@ -666,6 +890,7 @@ key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf,
{
int retval = 0;
int len = 0;
+ char error_message[1024];
perf_push (PERF_BIO_READ_CIPHERTEXT);
@@ -691,7 +916,8 @@ key_state_read_ciphertext (struct key_state_ssl *ks, struct buffer *buf,
perf_pop ();
if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval)
return 0;
- msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_plaintext error");
+ error_strerror(retval, error_message, sizeof(error_message));
+ msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_ciphertext error: %d %s", retval, error_message);
buf->len = 0;
return -1;
}
@@ -763,6 +989,7 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf,
{
int retval = 0;
int len = 0;
+ char error_message[1024];
perf_push (PERF_BIO_READ_PLAINTEXT);
@@ -787,7 +1014,8 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf,
{
if (POLARSSL_ERR_NET_WANT_WRITE == retval || POLARSSL_ERR_NET_WANT_READ == retval)
return 0;
- msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_plaintext error");
+ error_strerror(retval, error_message, sizeof(error_message));
+ msg (D_TLS_ERRORS, "TLS_ERROR: read tls_read_plaintext error: %d %s", retval, error_message);
buf->len = 0;
perf_pop ();
return -1;
@@ -818,7 +1046,7 @@ key_state_read_plaintext (struct key_state_ssl *ks, struct buffer *buf,
void
print_details (struct key_state_ssl * ks_ssl, const char *prefix)
{
- x509_cert *cert;
+ const x509_crt *cert;
char s1[256];
char s2[256];
@@ -828,20 +1056,27 @@ print_details (struct key_state_ssl * ks_ssl, const char *prefix)
ssl_get_version (ks_ssl->ctx),
ssl_get_ciphersuite(ks_ssl->ctx));
- cert = ks_ssl->ctx->peer_cert;
+ cert = ssl_get_peer_cert(ks_ssl->ctx);
if (cert != NULL)
{
- openvpn_snprintf (s2, sizeof (s2), ", " counter_format " bit RSA", (counter_type) cert->rsa.len * 8);
+ openvpn_snprintf (s2, sizeof (s2), ", %zu bit key", pk_get_size(&cert->pk));
}
msg (D_HANDSHAKE, "%s%s", s1, s2);
}
void
-show_available_tls_ciphers ()
+show_available_tls_ciphers (const char *cipher_list)
{
+ struct tls_root_ctx tls_ctx;
const int *ciphers = ssl_list_ciphersuites();
+ tls_ctx_server_new(&tls_ctx);
+ tls_ctx_restrict_ciphers(&tls_ctx, cipher_list);
+
+ if (tls_ctx.allowed_ciphers)
+ ciphers = tls_ctx.allowed_ciphers;
+
#ifndef ENABLE_SMALL
printf ("Available TLS Ciphers,\n");
printf ("listed in order of preference:\n\n");
@@ -853,6 +1088,25 @@ show_available_tls_ciphers ()
ciphers++;
}
printf ("\n");
+
+ tls_ctx_free(&tls_ctx);
+}
+
+void
+show_available_curves (void)
+{
+ const ecp_curve_info *pcurve = ecp_curve_list();
+
+ if (NULL == pcurve)
+ msg (M_FATAL, "Cannot retrieve curve list from PolarSSL");
+
+ /* Print curve list */
+ printf ("Available Elliptic curves, listed in order of preference:\n\n");
+ while (POLARSSL_ECP_DP_NONE != pcurve->grp_id)
+ {
+ printf("%s\n", pcurve->name);
+ pcurve++;
+ }
}
void
@@ -867,4 +1121,14 @@ get_highest_preference_tls_cipher (char *buf, int size)
strncpynt (buf, cipher_name, size);
}
+const char *
+get_ssl_library_version(void)
+{
+ static char polar_version[30];
+ unsigned int pv = version_get_number();
+ sprintf( polar_version, "PolarSSL %d.%d.%d",
+ (pv>>24)&0xff, (pv>>16)&0xff, (pv>>8)&0xff );
+ return polar_version;
+}
+
#endif /* defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_POLARSSL) */
diff --git a/app/openvpn/src/openvpn/ssl_polarssl.h b/app/openvpn/src/openvpn/ssl_polarssl.h
index 456573f5..b80a509e 100644
--- a/app/openvpn/src/openvpn/ssl_polarssl.h
+++ b/app/openvpn/src/openvpn/ssl_polarssl.h
@@ -30,7 +30,10 @@
#ifndef SSL_POLARSSL_H_
#define SSL_POLARSSL_H_
+#include "syshead.h"
+
#include <polarssl/ssl.h>
+#include <polarssl/x509_crt.h>
#if defined(ENABLE_PKCS11)
#include <polarssl/pkcs11.h>
@@ -62,18 +65,20 @@ struct tls_root_ctx {
int endpoint; /**< Whether or not this is a server or a client */
dhm_context *dhm_ctx; /**< Diffie-Helmann-Merkle context */
- x509_cert *crt_chain; /**< Local Certificate chain */
- x509_cert *ca_chain; /**< CA chain for remote verification */
- rsa_context *priv_key; /**< Local private key */
+ x509_crt *crt_chain; /**< Local Certificate chain */
+ x509_crt *ca_chain; /**< CA chain for remote verification */
+ pk_context *priv_key; /**< Local private key */
#if defined(ENABLE_PKCS11)
pkcs11_context *priv_key_pkcs11; /**< PKCS11 private key */
#endif
+#ifdef MANAGMENT_EXTERNAL_KEY
+ struct external_context *external_key; /**< Management external key */
+#endif
int * allowed_ciphers; /**< List of allowed ciphers for this connection */
};
struct key_state_ssl {
ssl_context *ctx;
- ssl_session *ssn;
endless_buffer *ct_in;
endless_buffer *ct_out;
};
diff --git a/app/openvpn/src/openvpn/ssl_verify.c b/app/openvpn/src/openvpn/ssl_verify.c
index cac46e98..2d10d155 100644
--- a/app/openvpn/src/openvpn/ssl_verify.c
+++ b/app/openvpn/src/openvpn/ssl_verify.c
@@ -337,8 +337,6 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert,
}
}
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L || ENABLE_CRYPTO_POLARSSL
-
/* verify certificate ku */
if (opt->remote_cert_ku[0] != 0)
{
@@ -367,18 +365,21 @@ verify_peer_cert(const struct tls_options *opt, openvpn_x509_cert_t *peer_cert,
}
}
-#endif /* OPENSSL_VERSION_NUMBER */
-
- /* verify X509 name or common name against --tls-remote */
- if (opt->verify_x509name && strlen (opt->verify_x509name) > 0)
+ /* verify X509 name or username against --verify-x509-[user]name */
+ if (opt->verify_x509_type != VERIFY_X509_NONE)
{
- if (strcmp (opt->verify_x509name, subject) == 0
- || strncmp (opt->verify_x509name, common_name, strlen (opt->verify_x509name)) == 0)
+ if ( (opt->verify_x509_type == VERIFY_X509_SUBJECT_DN
+ && strcmp (opt->verify_x509_name, subject) == 0)
+ || (opt->verify_x509_type == VERIFY_X509_SUBJECT_RDN
+ && strcmp (opt->verify_x509_name, common_name) == 0)
+ || (opt->verify_x509_type == VERIFY_X509_SUBJECT_RDN_PREFIX
+ && strncmp (opt->verify_x509_name, common_name,
+ strlen (opt->verify_x509_name)) == 0) )
msg (D_HANDSHAKE, "VERIFY X509NAME OK: %s", subject);
else
{
msg (D_HANDSHAKE, "VERIFY X509NAME ERROR: %s, must be %s",
- subject, opt->verify_x509name);
+ subject, opt->verify_x509_name);
return FAILURE; /* Reject connection */
}
}
@@ -420,7 +421,6 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert
setenv_str (es, envname, common_name);
#endif
-#ifdef ENABLE_EUREPHIA
/* export X509 cert SHA1 fingerprint */
{
unsigned char *sha1_hash = x509_get_sha1_hash(peer_cert, &gc);
@@ -429,13 +429,17 @@ verify_cert_set_env(struct env_set *es, openvpn_x509_cert_t *peer_cert, int cert
setenv_str (es, envname, format_hex_ex(sha1_hash, SHA_DIGEST_LENGTH, 0, 1,
":", &gc));
}
-#endif
/* export serial number as environmental variable */
- serial = x509_get_serial(peer_cert, &gc);
+ serial = backend_x509_get_serial(peer_cert, &gc);
openvpn_snprintf (envname, sizeof(envname), "tls_serial_%d", cert_depth);
setenv_str (es, envname, serial);
+ /* export serial number in hex as environmental variable */
+ serial = backend_x509_get_serial_hex(peer_cert, &gc);
+ openvpn_snprintf (envname, sizeof(envname), "tls_serial_hex_%d", cert_depth);
+ setenv_str (es, envname, serial);
+
gc_free(&gc);
}
@@ -559,7 +563,7 @@ verify_check_crl_dir(const char *crl_dir, openvpn_x509_cert_t *cert)
int fd = -1;
struct gc_arena gc = gc_new();
- char *serial = x509_get_serial(cert, &gc);
+ char *serial = backend_x509_get_serial(cert, &gc);
if (!openvpn_snprintf(fn, sizeof(fn), "%s%c%s", crl_dir, OS_SPECIFIC_DIRSEP, serial))
{
@@ -611,7 +615,7 @@ verify_cert(struct tls_session *session, openvpn_x509_cert_t *cert, int cert_dep
string_replace_leading (subject, '-', '_');
/* extract the username (default is CN) */
- if (SUCCESS != x509_get_username (common_name, TLS_USERNAME_LEN,
+ if (SUCCESS != backend_x509_get_username (common_name, TLS_USERNAME_LEN,
opt->x509_username_field, cert))
{
if (!cert_depth)
@@ -1022,7 +1026,9 @@ static int
verify_user_pass_plugin (struct tls_session *session, const struct user_pass *up, const char *raw_username)
{
int retval = OPENVPN_PLUGIN_FUNC_ERROR;
+#ifdef PLUGIN_DEF_AUTH
struct key_state *ks = &session->key[KS_PRIMARY]; /* primary key */
+#endif
/* Is username defined? */
if ((session->opt->ssl_flags & SSLF_AUTH_USER_PASS_OPTIONAL) || strlen (up->username))
diff --git a/app/openvpn/src/openvpn/ssl_verify.h b/app/openvpn/src/openvpn/ssl_verify.h
index 1d201523..84554f89 100644
--- a/app/openvpn/src/openvpn/ssl_verify.h
+++ b/app/openvpn/src/openvpn/ssl_verify.h
@@ -30,9 +30,10 @@
#ifndef SSL_VERIFY_H_
#define SSL_VERIFY_H_
+#if defined(ENABLE_CRYPTO) && defined(ENABLE_SSL)
+
#include "syshead.h"
#include "misc.h"
-#include "manage.h"
#include "ssl_common.h"
/* Include OpenSSL-specific code */
@@ -62,6 +63,12 @@ struct cert_hash_set {
struct cert_hash *ch[MAX_CERT_DEPTH]; /**< Array of certificate hashes */
};
+#define VERIFY_X509_NONE 0
+#define VERIFY_X509_SUBJECT_DN 1
+#define VERIFY_X509_SUBJECT_RDN 2
+#define VERIFY_X509_SUBJECT_RDN_PREFIX 3
+#define TLS_REMOTE_SUBJECT_DN 1 + 0x100
+#define TLS_REMOTE_SUBJECT_RDN_PREFIX 3 + 0x100
#define TLS_AUTHENTICATION_SUCCEEDED 0
#define TLS_AUTHENTICATION_FAILED 1
@@ -160,25 +167,6 @@ tls_common_name_hash (const struct tls_multi *multi, const char **cn, uint32_t *
#endif
/**
- * Returns whether or not the server should check for username/password
- *
- * @param session The current TLS session
- *
- * @return true if username and password verification is enabled,
- * false if not.
- *
- */
-static inline bool verify_user_pass_enabled(struct tls_session *session)
-{
- return (session->opt->auth_user_pass_verify_script
- || plugin_defined (session->opt->plugins, OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY)
-#ifdef MANAGEMENT_DEF_AUTH
- || management_enable_def_auth (management)
-#endif
- );
-}
-
-/**
* Verify the given username and password, using either an external script, a
* plugin, or the management interface.
*
@@ -248,5 +236,6 @@ tls_client_reason (struct tls_multi *multi)
#endif
}
-#endif /* SSL_VERIFY_H_ */
+#endif /* defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) */
+#endif /* SSL_VERIFY_H_ */
diff --git a/app/openvpn/src/openvpn/ssl_verify_backend.h b/app/openvpn/src/openvpn/ssl_verify_backend.h
index 1658cc02..4e9ad60f 100644
--- a/app/openvpn/src/openvpn/ssl_verify_backend.h
+++ b/app/openvpn/src/openvpn/ssl_verify_backend.h
@@ -109,20 +109,35 @@ unsigned char *x509_get_sha1_hash (openvpn_x509_cert_t *cert, struct gc_arena *g
*
* @return \c FAILURE, \c or SUCCESS
*/
-result_t x509_get_username (char *common_name, int cn_len,
+result_t backend_x509_get_username (char *common_name, int cn_len,
char * x509_username_field, openvpn_x509_cert_t *peer_cert);
/*
- * Return the certificate's serial number.
+ * Return the certificate's serial number in decimal string representation.
*
* The serial number is returned as a string, since it might be a bignum.
*
* @param cert Certificate to retrieve the serial number from.
* @param gc Garbage collection arena to use when allocating string.
*
- * @return The certificate's serial number.
+ * @return String representation of the certificate's serial number
+ * in decimal notation, or NULL on error.
*/
-char *x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc);
+char *backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc);
+
+/*
+ * Return the certificate's serial number in hex string representation.
+ *
+ * The serial number is returned as a string, since it might be a bignum.
+ *
+ * @param cert Certificate to retrieve the serial number from.
+ * @param gc Garbage collection arena to use when allocating string.
+ *
+ * @return String representation of the certificate's serial number
+ * in hex notation, or NULL on error.
+ */
+char *backend_x509_get_serial_hex (openvpn_x509_cert_t *cert,
+ struct gc_arena *gc);
/*
* Save X509 fields to environment, using the naming convention:
@@ -189,8 +204,6 @@ void x509_setenv_track (const struct x509_track *xt, struct env_set *es,
*/
result_t x509_verify_ns_cert_type(const openvpn_x509_cert_t *cert, const int usage);
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L || ENABLE_CRYPTO_POLARSSL
-
/*
* Verify X.509 key usage extension field.
*
@@ -219,8 +232,6 @@ result_t x509_verify_cert_ku (openvpn_x509_cert_t *x509, const unsigned * const
*/
result_t x509_verify_cert_eku (openvpn_x509_cert_t *x509, const char * const expected_oid);
-#endif
-
/*
* Store the given certificate in pem format in a temporary file in tmp_dir
*
diff --git a/app/openvpn/src/openvpn/ssl_verify_openssl.c b/app/openvpn/src/openvpn/ssl_verify_openssl.c
index 658f5f33..2482eaa4 100644
--- a/app/openvpn/src/openvpn/ssl_verify_openssl.c
+++ b/app/openvpn/src/openvpn/ssl_verify_openssl.c
@@ -37,9 +37,13 @@
#if defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_OPENSSL)
+#include "ssl_verify_openssl.h"
+
+#include "error.h"
+#include "ssl_openssl.h"
#include "ssl_verify.h"
#include "ssl_verify_backend.h"
-#include "ssl_openssl.h"
+
#include <openssl/x509v3.h>
#include <openssl/err.h>
@@ -202,7 +206,7 @@ extract_x509_field_ssl (X509_NAME *x509, const char *field_name, char *out,
}
result_t
-x509_get_username (char *common_name, int cn_len,
+backend_x509_get_username (char *common_name, int cn_len,
char * x509_username_field, X509 *peer_cert)
{
#ifdef ENABLE_X509ALTUSERNAME
@@ -220,7 +224,7 @@ x509_get_username (char *common_name, int cn_len,
}
char *
-x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc)
+backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc)
{
ASN1_INTEGER *asn1_i;
BIGNUM *bignum;
@@ -238,10 +242,18 @@ x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc)
return serial;
}
+char *
+backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, struct gc_arena *gc)
+{
+ const ASN1_INTEGER *asn1_i = X509_get_serialNumber(cert);
+
+ return format_hex_ex(asn1_i->data, asn1_i->length, 0, 1, ":", gc);
+}
+
unsigned char *
x509_get_sha1_hash (X509 *cert, struct gc_arena *gc)
{
- char *hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc);
+ unsigned char *hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc);
memcpy(hash, cert->sha1_hash, SHA_DIGEST_LENGTH);
return hash;
}
@@ -459,8 +471,6 @@ x509_verify_ns_cert_type(const openvpn_x509_cert_t *peer_cert, const int usage)
return FAILURE;
}
-#if OPENSSL_VERSION_NUMBER >= 0x00907000L
-
result_t
x509_verify_cert_ku (X509 *x509, const unsigned * const expected_ku,
int expected_len)
@@ -566,8 +576,6 @@ x509_write_pem(FILE *peercert_file, X509 *peercert)
return SUCCESS;
}
-#endif /* OPENSSL_VERSION_NUMBER */
-
/*
* check peer cert against CRL
*/
diff --git a/app/openvpn/src/openvpn/ssl_verify_polarssl.c b/app/openvpn/src/openvpn/ssl_verify_polarssl.c
index a32db8df..71d38a9d 100644
--- a/app/openvpn/src/openvpn/ssl_verify_polarssl.c
+++ b/app/openvpn/src/openvpn/ssl_verify_polarssl.c
@@ -38,17 +38,19 @@
#if defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_POLARSSL)
#include "ssl_verify.h"
+#include <polarssl/error.h>
+#include <polarssl/bignum.h>
+#include <polarssl/oid.h>
#include <polarssl/sha1.h>
#define MAX_SUBJECT_LENGTH 256
int
-verify_callback (void *session_obj, x509_cert *cert, int cert_depth,
- int preverify_ok)
+verify_callback (void *session_obj, x509_crt *cert, int cert_depth,
+ int *flags)
{
struct tls_session *session = (struct tls_session *) session_obj;
struct gc_arena gc = gc_new();
- int ret = 1;
ASSERT (cert);
ASSERT (session);
@@ -59,31 +61,29 @@ verify_callback (void *session_obj, x509_cert *cert, int cert_depth,
cert_hash_remember (session, cert_depth, x509_get_sha1_hash(cert, &gc));
/* did peer present cert which was signed by our root cert? */
- if (!preverify_ok)
+ if (*flags != 0)
{
char *subject = x509_get_subject(cert, &gc);
if (subject)
- msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, %s", cert_depth, subject);
+ msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, flags=%x, %s", cert_depth, *flags, subject);
else
- msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, could not extract X509 "
- "subject string from certificate", cert_depth);
+ msg (D_TLS_ERRORS, "VERIFY ERROR: depth=%d, flags=%x, could not extract X509 "
+ "subject string from certificate", *flags, cert_depth);
- goto cleanup;
+ /* Leave flags set to non-zero to indicate that the cert is not ok */
+ }
+ else if (SUCCESS != verify_cert(session, cert, cert_depth))
+ {
+ *flags |= BADCERT_OTHER;
}
- if (SUCCESS != verify_cert(session, cert, cert_depth))
- goto cleanup;
-
- ret = 0;
-
-cleanup:
gc_free(&gc);
/*
- * PolarSSL expects 1 on failure, 0 on success
+ * PolarSSL-1.2.0+ expects 0 on anything except fatal errors.
*/
- return ret;
+ return 0;
}
#ifdef ENABLE_X509ALTUSERNAME
@@ -91,8 +91,8 @@ cleanup:
#endif
result_t
-x509_get_username (char *cn, int cn_len,
- char *x509_username_field, x509_cert *cert)
+backend_x509_get_username (char *cn, int cn_len,
+ char *x509_username_field, x509_crt *cert)
{
x509_name *name;
@@ -103,7 +103,7 @@ x509_get_username (char *cn, int cn_len,
/* Find common name */
while( name != NULL )
{
- if( memcmp( name->oid.p, OID_CN, OID_SIZE(OID_CN) ) == 0)
+ if( memcmp( name->oid.p, OID_AT_CN, OID_SIZE(OID_AT_CN) ) == 0)
break;
name = name->next;
@@ -126,23 +126,59 @@ x509_get_username (char *cn, int cn_len,
}
char *
-x509_get_serial (x509_cert *cert, struct gc_arena *gc)
+backend_x509_get_serial (openvpn_x509_cert_t *cert, struct gc_arena *gc)
+{
+ char *buf = NULL;
+ size_t buflen = 0;
+ mpi serial_mpi = { 0 };
+ int retval = 0;
+
+ /* Transform asn1 integer serial into PolarSSL MPI */
+ mpi_init(&serial_mpi);
+ retval = mpi_read_binary(&serial_mpi, cert->serial.p, cert->serial.len);
+ if (retval < 0)
+ {
+ char errbuf[128];
+ polarssl_strerror(retval, errbuf, sizeof(errbuf));
+
+ msg(M_WARN, "Failed to retrieve serial from certificate: %s.", errbuf);
+ return NULL;
+ }
+
+ /* Determine decimal representation length, allocate buffer */
+ mpi_write_string(&serial_mpi, 10, buf, &buflen);
+ buf = gc_malloc(buflen, true, gc);
+
+ /* Write MPI serial as decimal string into buffer */
+ retval = mpi_write_string(&serial_mpi, 10, buf, &buflen);
+ if (retval < 0)
+ {
+ char errbuf[128];
+ polarssl_strerror(retval, errbuf, sizeof(errbuf));
+
+ msg(M_WARN, "Failed to write serial to string: %s.", errbuf);
+ return NULL;
+ }
+
+ return buf;
+}
+
+char *
+backend_x509_get_serial_hex (openvpn_x509_cert_t *cert, struct gc_arena *gc)
{
- int ret = 0;
- int i = 0;
char *buf = NULL;
size_t len = cert->serial.len * 3 + 1;
buf = gc_malloc(len, true, gc);
- if(x509parse_serial_gets(buf, len-1, &cert->serial) < 0)
+ if(x509_serial_gets(buf, len-1, &cert->serial) < 0)
buf = NULL;
return buf;
}
unsigned char *
-x509_get_sha1_hash (x509_cert *cert, struct gc_arena *gc)
+x509_get_sha1_hash (x509_crt *cert, struct gc_arena *gc)
{
unsigned char *sha1_hash = gc_malloc(SHA_DIGEST_LENGTH, false, gc);
sha1(cert->tbs.p, cert->tbs.len, sha1_hash);
@@ -150,14 +186,14 @@ x509_get_sha1_hash (x509_cert *cert, struct gc_arena *gc)
}
char *
-x509_get_subject(x509_cert *cert, struct gc_arena *gc)
+x509_get_subject(x509_crt *cert, struct gc_arena *gc)
{
char tmp_subject[MAX_SUBJECT_LENGTH] = {0};
char *subject = NULL;
int ret = 0;
- ret = x509parse_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject );
+ ret = x509_dn_gets( tmp_subject, MAX_SUBJECT_LENGTH-1, &cert->subject );
if (ret > 0)
{
/* Allocate the required space for the subject */
@@ -187,70 +223,28 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert)
while( name != NULL )
{
char name_expand[64+8];
+ const char *shortname;
- if( name->oid.len == 2 && memcmp( name->oid.p, OID_X520, 2 ) == 0 )
+ if( 0 == oid_get_attr_short_name(&name->oid, &shortname) )
{
- switch( name->oid.p[2] )
- {
- case X520_COMMON_NAME:
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_CN",
- cert_depth); break;
-
- case X520_COUNTRY:
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_C",
- cert_depth); break;
-
- case X520_LOCALITY:
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_L",
- cert_depth); break;
-
- case X520_STATE:
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_ST",
- cert_depth); break;
-
- case X520_ORGANIZATION:
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_O",
- cert_depth); break;
-
- case X520_ORG_UNIT:
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_OU",
- cert_depth); break;
-
- default:
- openvpn_snprintf (name_expand, sizeof(name_expand),
- "X509_%d_0x%02X", cert_depth, name->oid.p[2]);
- break;
- }
+ openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_%s",
+ cert_depth, shortname);
}
- else if( name->oid.len == 8 && memcmp( name->oid.p, OID_PKCS9, 8 ) == 0 )
- {
- switch( name->oid.p[8] )
- {
- case PKCS9_EMAIL:
- openvpn_snprintf (name_expand, sizeof(name_expand),
- "X509_%d_emailAddress", cert_depth); break;
-
- default:
- openvpn_snprintf (name_expand, sizeof(name_expand),
- "X509_%d_0x%02X", cert_depth, name->oid.p[8]);
- break;
- }
- }
- else
- {
- openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?",
- cert_depth);
- }
-
- for( i = 0; i < name->val.len; i++ )
+ else
+ {
+ openvpn_snprintf (name_expand, sizeof(name_expand), "X509_%d_\?\?",
+ cert_depth);
+ }
+
+ for( i = 0; i < name->val.len; i++ )
{
- if( i >= (int) sizeof( s ) - 1 )
- break;
+ if( i >= (int) sizeof( s ) - 1 )
+ break;
- c = name->val.p[i];
- if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
- s[i] = '?';
- else s[i] = c;
+ c = name->val.p[i];
+ if( c < 32 || c == 127 || ( c > 128 && c < 160 ) )
+ s[i] = '?';
+ else s[i] = c;
}
s[i] = '\0';
@@ -264,7 +258,7 @@ x509_setenv (struct env_set *es, int cert_depth, openvpn_x509_cert_t *cert)
}
result_t
-x509_verify_ns_cert_type(const x509_cert *cert, const int usage)
+x509_verify_ns_cert_type(const x509_crt *cert, const int usage)
{
if (usage == NS_CERT_CHECK_NONE)
return SUCCESS;
@@ -279,7 +273,7 @@ x509_verify_ns_cert_type(const x509_cert *cert, const int usage)
}
result_t
-x509_verify_cert_ku (x509_cert *cert, const unsigned * const expected_ku,
+x509_verify_cert_ku (x509_crt *cert, const unsigned * const expected_ku,
int expected_len)
{
result_t fFound = FAILURE;
@@ -312,7 +306,7 @@ x509_verify_cert_ku (x509_cert *cert, const unsigned * const expected_ku,
}
result_t
-x509_verify_cert_eku (x509_cert *cert, const char * const expected_oid)
+x509_verify_cert_eku (x509_crt *cert, const char * const expected_oid)
{
result_t fFound = FAILURE;
@@ -362,7 +356,7 @@ x509_verify_cert_eku (x509_cert *cert, const char * const expected_oid)
}
result_t
-x509_write_pem(FILE *peercert_file, x509_cert *peercert)
+x509_write_pem(FILE *peercert_file, x509_crt *peercert)
{
msg (M_WARN, "PolarSSL does not support writing peer certificate in PEM format");
return FAILURE;
@@ -372,12 +366,12 @@ x509_write_pem(FILE *peercert_file, x509_cert *peercert)
* check peer cert against CRL
*/
result_t
-x509_verify_crl(const char *crl_file, x509_cert *cert, const char *subject)
+x509_verify_crl(const char *crl_file, x509_crt *cert, const char *subject)
{
result_t retval = FAILURE;
x509_crl crl = {0};
- if (x509parse_crlfile(&crl, crl_file) != 0)
+ if (x509_crl_parse_file(&crl, crl_file) != 0)
{
msg (M_ERR, "CRL: cannot read CRL from file %s", crl_file);
goto end;
@@ -392,7 +386,7 @@ x509_verify_crl(const char *crl_file, x509_cert *cert, const char *subject)
goto end;
}
- if (0 != x509parse_revoked(cert, &crl))
+ if (0 != x509_crt_revoked(cert, &crl))
{
msg (D_HANDSHAKE, "CRL CHECK FAILED: %s is REVOKED", subject);
goto end;
diff --git a/app/openvpn/src/openvpn/ssl_verify_polarssl.h b/app/openvpn/src/openvpn/ssl_verify_polarssl.h
index fceee667..2076f2ef 100644
--- a/app/openvpn/src/openvpn/ssl_verify_polarssl.h
+++ b/app/openvpn/src/openvpn/ssl_verify_polarssl.h
@@ -31,13 +31,11 @@
#define SSL_VERIFY_POLARSSL_H_
#include "syshead.h"
-#include "misc.h"
-#include "manage.h"
-#include <polarssl/x509.h>
+#include <polarssl/x509_crt.h>
#ifndef __OPENVPN_X509_CERT_T_DECLARED
#define __OPENVPN_X509_CERT_T_DECLARED
-typedef x509_cert openvpn_x509_cert_t;
+typedef x509_crt openvpn_x509_cert_t;
#endif
/** @name Function for authenticating a new connection from a remote OpenVPN peer
@@ -55,27 +53,25 @@ typedef x509_cert openvpn_x509_cert_t;
* calls the PolarSSL library's \c ssl_set_verify_callback() function with \c
* verify_callback() as its callback argument.
*
- * It checks preverify_ok, and registers the certificate hash. If these steps
- * succeed, it calls the \c verify_cert() function, which performs
- * OpenVPN-specific verification.
+ * It checks *flags and registers the certificate hash. If these steps succeed,
+ * it calls the \c verify_cert() function, which performs OpenVPN-specific
+ * verification.
*
* @param session_obj - The OpenVPN \c tls_session associated with this object,
* as set during SSL session setup.
* @param cert - The certificate used by PolarSSL.
* @param cert_depth - The depth of the current certificate in the chain, with
* 0 being the actual certificate.
- * @param preverify_ok - Whether the remote OpenVPN peer's certificate
- * past verification. A value of 1 means it
- * verified successfully, 0 means it failed.
+ * @param flags - Whether the remote OpenVPN peer's certificate
+ * passed verification. A value of 0 means it
+ * verified successfully, any other value means it
+ * failed. \c verify_callback() is considered to have
+ * ok'ed this certificate if flags is 0 when it returns.
*
- * @return The return value indicates whether the supplied certificate is
- * allowed to set up a VPN tunnel. The following values can be
- * returned:
- * - \c 0: failure, this certificate is not allowed to connect.
- * - \c 1: success, this certificate is allowed to connect.
+ * @return The return value is 0 unless a fatal error occurred.
*/
-int verify_callback (void *session_obj, x509_cert *cert, int cert_depth,
- int preverify_ok);
+int verify_callback (void *session_obj, x509_crt *cert, int cert_depth,
+ int *flags);
/** @} name Function for authenticating a new connection from a remote OpenVPN peer */
diff --git a/app/openvpn/src/openvpn/status.c b/app/openvpn/src/openvpn/status.c
index 5f9ab9ee..b7ff4843 100644
--- a/app/openvpn/src/openvpn/status.c
+++ b/app/openvpn/src/openvpn/status.c
@@ -33,6 +33,7 @@
#include "status.h"
#include "perf.h"
#include "misc.h"
+#include "fdmisc.h"
#include "memdbg.h"
@@ -98,6 +99,7 @@ status_open (const char *filename,
if (so->fd >= 0)
{
so->filename = string_alloc (filename, NULL);
+ set_cloexec (so->fd);
/* allocate read buffer */
if (so->flags & STATUS_OUTPUT_READ)
diff --git a/app/openvpn/src/openvpn/syshead.h b/app/openvpn/src/openvpn/syshead.h
index 163d2bb2..771c4fc1 100644
--- a/app/openvpn/src/openvpn/syshead.h
+++ b/app/openvpn/src/openvpn/syshead.h
@@ -307,6 +307,10 @@
#include <netinet/ip.h>
#endif
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h>
+#endif
+
#ifdef HAVE_NET_IF_TUN_H
#include <net/if_tun.h>
#endif
@@ -422,6 +426,13 @@
#endif
/*
+ * Define type sa_family_t if it isn't defined in the socket headers
+ */
+#ifndef HAVE_SA_FAMILY_T
+typedef unsigned short sa_family_t;
+#endif
+
+/*
* Disable ESEC
*/
#if 0
@@ -535,7 +546,7 @@ socket_defined (const socket_descriptor_t sd)
/*
* Enable external private key
*/
-#if defined(ENABLE_MANAGEMENT) && defined(ENABLE_SSL) && !defined(ENABLE_CRYPTO_POLARSSL)
+#if defined(ENABLE_MANAGEMENT) && defined(ENABLE_SSL)
#define MANAGMENT_EXTERNAL_KEY
#endif
@@ -575,11 +586,6 @@ socket_defined (const socket_descriptor_t sd)
#endif
/*
- * Compile the struct buffer_list code
- */
-#define ENABLE_BUFFER_LIST
-
-/*
* Should we include OCC (options consistency check) code?
*/
#ifndef ENABLE_SMALL
@@ -589,7 +595,7 @@ socket_defined (const socket_descriptor_t sd)
/*
* Should we include NTLM proxy functionality
*/
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_HTTP_PROXY)
+#if defined(ENABLE_CRYPTO)
#define NTLM 1
#else
#define NTLM 0
@@ -598,20 +604,13 @@ socket_defined (const socket_descriptor_t sd)
/*
* Should we include proxy digest auth functionality
*/
-#if defined(ENABLE_CRYPTO) && defined(ENABLE_HTTP_PROXY)
+#if defined(ENABLE_CRYPTO)
#define PROXY_DIGEST_AUTH 1
#else
#define PROXY_DIGEST_AUTH 0
#endif
/*
- * Should we include code common to all proxy methods?
- */
-#if defined(ENABLE_HTTP_PROXY) || defined(ENABLE_SOCKS)
-#define GENERAL_PROXY_SUPPORT
-#endif
-
-/*
* Do we have CryptoAPI capability?
*/
#if defined(WIN32) && defined(ENABLE_CRYPTO) && defined(ENABLE_SSL) && defined(ENABLE_CRYPTO_OPENSSL)
@@ -650,15 +649,6 @@ socket_defined (const socket_descriptor_t sd)
#endif
/*
- * Should we include http proxy override functionality
- */
-#if defined(ENABLE_MANAGEMENT) && defined(ENABLE_HTTP_PROXY)
-#define HTTP_PROXY_OVERRIDE 1
-#else
-#define HTTP_PROXY_OVERRIDE 0
-#endif
-
-/*
* Reduce sensitivity to system clock instability
* and backtracks.
*/
@@ -704,9 +694,12 @@ socket_defined (const socket_descriptor_t sd)
#endif
/*
- * Do we support internal client-side NAT?
+ * Compression support
*/
-#define ENABLE_CLIENT_NAT
+#if defined(ENABLE_SNAPPY) || defined(ENABLE_LZO) || defined(ENABLE_LZ4) || \
+ defined(ENABLE_COMP_STUB)
+#define USE_COMP
+#endif
/*
* Enable --memstats option
diff --git a/app/openvpn/src/openvpn/tun.c b/app/openvpn/src/openvpn/tun.c
index a0754427..482f6402 100644
--- a/app/openvpn/src/openvpn/tun.c
+++ b/app/openvpn/src/openvpn/tun.c
@@ -74,6 +74,14 @@ static void solaris_error_close (struct tuntap *tt, const struct env_set *es, co
#include <stropts.h>
#endif
+#if defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H
+#include <sys/kern_control.h>
+#include <net/if_utun.h>
+#include <sys/sys_domain.h>
+#endif
+
+static void clear_tuntap (struct tuntap *tuntap);
+
bool
is_dev_type (const char *dev, const char *dev_type, const char *match_type)
{
@@ -299,16 +307,6 @@ warn_on_use_of_common_subnets (void)
}
/*
- * Complain if --dev tap and --ifconfig is used on an OS for which
- * we don't have a custom tap ifconfig template below.
- */
-static void
-no_tap_ifconfig ()
-{
- msg (M_FATAL, "Sorry but you cannot use --dev tap and --ifconfig together on this OS because I have not yet been programmed to understand the appropriate ifconfig syntax to use for TAP-style devices on this OS. Your best alternative is to use an --up script and do the ifconfig command manually.");
-}
-
-/*
* Return a string to be used for options compatibility check
* between peers.
*/
@@ -468,15 +466,15 @@ init_tun (const char *dev, /* --dev option */
*/
if (strict_warn)
{
- struct addrinfo *curele;
+ struct addrinfo *curele;
ifconfig_sanity_check (tt->type == DEV_TYPE_TUN, tt->remote_netmask, tt->topology);
/*
* If local_public or remote_public addresses are defined,
* make sure they do not clash with our virtual subnet.
*/
-
- for(curele=remote_public;curele;curele=curele->ai_next) {
+
+ for(curele=local_public;curele;curele=curele->ai_next) {
if(curele->ai_family == AF_INET)
check_addr_clash ("local",
tt->type,
@@ -485,14 +483,14 @@ init_tun (const char *dev, /* --dev option */
tt->remote_netmask);
}
- for(curele=remote_public;curele;curele=curele->ai_next) {
- if(curele->ai_family == AF_INET)
- check_addr_clash ("remote",
- tt->type,
- ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr,
- tt->local,
- tt->remote_netmask);
- }
+ for (curele=remote_public;curele;curele=curele->ai_next) {
+ if (curele->ai_family == AF_INET)
+ check_addr_clash ("remote",
+ tt->type,
+ ((struct sockaddr_in*)curele->ai_addr)->sin_addr.s_addr,
+ tt->local,
+ tt->remote_netmask);
+ }
if (tt->type == DEV_TYPE_TAP || (tt->type == DEV_TYPE_TUN && tt->topology == TOP_SUBNET))
check_subnet_conflict (tt->local, tt->remote_netmask, "TUN/TAP adapter");
@@ -781,39 +779,33 @@ do_ifconfig (struct tuntap *tt,
#endif /*ENABLE_IPROUTE*/
#elif defined(TARGET_ANDROID)
-
-
- if (do_ipv6) {
- struct user_pass up6;
- struct buffer out6 = alloc_buf_gc (64, &gc);
- buf_printf (&out6, "%s/%d", ifconfig_ipv6_local,tt->netbits_ipv6);
- strcpy(up6.username, buf_bptr(&out6));
- management_query_user_pass(management, &up6 , "IFCONFIG6", GET_USER_PASS_NEED_OK,(void*) 0);
- }
- struct user_pass up;
- struct buffer out = alloc_buf_gc (64, &gc);
- char* top;
- switch(tt->topology) {
- case TOP_NET30:
- top = "net30";
- break;
- case TOP_P2P:
- top="p2p";
- break;
- case TOP_SUBNET:
- top="subnet";
- break;
- default:
- top="undef";
- }
-
- buf_printf (&out, "%s %s %d %s", ifconfig_local, ifconfig_remote_netmask, tun_mtu,top);
- strcpy(up.username, buf_bptr(&out));
- management_query_user_pass(management, &up , "IFCONFIG", GET_USER_PASS_NEED_OK,(void*) 0);
+ if (do_ipv6) {
+ struct buffer out6 = alloc_buf_gc (64, &gc);
+ buf_printf (&out6, "%s/%d", ifconfig_ipv6_local,tt->netbits_ipv6);
+ management_android_control(management, "IFCONFIG6",buf_bptr(&out6));
+ }
+ struct buffer out = alloc_buf_gc (64, &gc);
+
+ char* top;
+ switch(tt->topology) {
+ case TOP_NET30:
+ top="net30";
+ break;
+ case TOP_P2P:
+ top="p2p";
+ break;
+ case TOP_SUBNET:
+ top="subnet";
+ break;
+ default:
+ top="undef";
+ }
+
+ buf_printf (&out, "%s %s %d %s", ifconfig_local, ifconfig_remote_netmask, tun_mtu, top);
+ management_android_control (management, "IFCONFIG", buf_bptr(&out));
-
#elif defined(TARGET_SOLARIS)
/* Solaris 2.6 (and 7?) cannot set all parameters in one go...
@@ -917,7 +909,7 @@ do_ifconfig (struct tuntap *tt,
if (!tun && tt->topology == TOP_SUBNET)
{
/* Add a network route for the local tun interface */
- struct route r;
+ struct route_ipv4 r;
CLEAR (r);
r.flags = RT_DEFINED | RT_METRIC_DEFINED;
r.network = tt->local & tt->remote_netmask;
@@ -1114,7 +1106,7 @@ do_ifconfig (struct tuntap *tt,
/* Add a network route for the local tun interface */
if (!tun && tt->topology == TOP_SUBNET)
{
- struct route r;
+ struct route_ipv4 r;
CLEAR (r);
r.flags = RT_DEFINED;
r.network = tt->local & tt->remote_netmask;
@@ -1180,7 +1172,7 @@ do_ifconfig (struct tuntap *tt,
/* Add a network route for the local tun interface */
if (!tun && tt->topology == TOP_SUBNET)
{
- struct route r;
+ struct route_ipv4 r;
CLEAR (r);
r.flags = RT_DEFINED;
r.network = tt->local & tt->remote_netmask;
@@ -1298,6 +1290,87 @@ open_null (struct tuntap *tt)
tt->actual_name = string_alloc ("null", NULL);
}
+
+#if defined (TARGET_OPENBSD) || (defined(TARGET_DARWIN) && HAVE_NET_IF_UTUN_H)
+
+/*
+ * OpenBSD and Mac OS X when using utun
+ * have a slightly incompatible TUN device from
+ * the rest of the world, in that it prepends a
+ * uint32 to the beginning of the IP header
+ * to designate the protocol (why not just
+ * look at the version field in the IP header to
+ * determine v4 or v6?).
+ *
+ * We strip off this field on reads and
+ * put it back on writes.
+ *
+ * I have not tested TAP devices on OpenBSD,
+ * but I have conditionalized the special
+ * TUN handling code described above to
+ * go away for TAP devices.
+ */
+
+#include <netinet/ip.h>
+#include <sys/uio.h>
+
+static inline int
+header_modify_read_write_return (int len)
+{
+ if (len > 0)
+ return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
+ else
+ return len;
+}
+
+int
+write_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+ struct ip *iph;
+
+ iph = (struct ip *) buf;
+
+ if (tt->ipv6 && iph->ip_v == 6)
+ type = htonl (AF_INET6);
+ else
+ type = htonl (AF_INET);
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (writev (tt->fd, iv, 2));
+ }
+ else
+ return write (tt->fd, buf, len);
+}
+
+int
+read_tun_header (struct tuntap* tt, uint8_t *buf, int len)
+{
+ if (tt->type == DEV_TYPE_TUN)
+ {
+ u_int32_t type;
+ struct iovec iv[2];
+
+ iv[0].iov_base = &type;
+ iv[0].iov_len = sizeof (type);
+ iv[1].iov_base = buf;
+ iv[1].iov_len = len;
+
+ return header_modify_read_write_return (readv (tt->fd, iv, 2));
+ }
+ else
+ return read (tt->fd, buf, len);
+}
+#endif
+
+
#ifndef WIN32
static void
open_tun_generic (const char *dev, const char *dev_type, const char *dev_node,
@@ -1422,33 +1495,52 @@ close_tun_generic (struct tuntap *tt)
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- int i;
- struct user_pass up;
- struct gc_arena gc = gc_new ();
-
- for (i = 0; i < tt->options.dns_len; ++i) {
- strcpy(up.username, print_in_addr_t(tt->options.dns[i], 0, &gc));
- management_query_user_pass(management, &up , "DNSSERVER", GET_USER_PASS_NEED_OK,(void*) 0);
- }
+#define ANDROID_TUNNAME "vpnservice-tun"
+ int i;
+ struct user_pass up;
+ struct gc_arena gc = gc_new ();
+ bool opentun;
+
+ int oldtunfd = tt->fd;
+
+ for (i = 0; i < tt->options.dns_len; ++i) {
+ management_android_control (management, "DNSSERVER",
+ print_in_addr_t(tt->options.dns[i], 0, &gc));
+ }
+
+ if(tt->options.domain)
+ management_android_control (management, "DNSDOMAIN", tt->options.domain);
+
+ int android_method = managment_android_persisttun_action (management);
- if(tt->options.domain) {
- strcpy(up.username , tt->options.domain);
- management_query_user_pass(management, &up , "DNSDOMAIN", GET_USER_PASS_NEED_OK,(void*) 0);
+ /* Android 4.4 workaround */
+ if (oldtunfd >=0 && android_method == ANDROID_OPEN_AFTER_CLOSE)
+ {
+ close(oldtunfd);
+ openvpn_sleep(2);
}
-
- strcpy(up.username , dev);
- management_query_user_pass(management, &up , "OPENTUN", GET_USER_PASS_NEED_OK,(void*) 0);
+ if (oldtunfd >=0 && android_method == ANDROID_KEEP_OLD_TUN) {
+ /* keep the old fd */
+ opentun = true;
+ } else {
+ opentun = management_android_control (management, "OPENTUN", dev);
+ /* Pick up the fd from management interface after calling the
+ * OPENTUN command */
tt->fd = management->connection.lastfdreceived;
management->connection.lastfdreceived=-1;
-
- if( (tt->fd < 0) || ! (strcmp("ok",up.password)==0)) {
- msg (M_ERR, "ERROR: Cannot open TUN");
- }
- /* Set the actual name to a dummy name to enable scripts */
- tt->actual_name = (char *) malloc(32);
- strncpy(tt->actual_name, "vpnservice-tun",32);
- gc_free (&gc);
+ }
+
+ if (oldtunfd>=0 && android_method == ANDROID_OPEN_BEFORE_CLOSE)
+ close(oldtunfd);
+
+ /* Set the actual name to a dummy name */
+ tt->actual_name = string_alloc (ANDROID_TUNNAME, NULL);
+
+ if ((tt->fd < 0) || !opentun)
+ msg (M_ERR, "ERROR: Cannot open TUN");
+
+ gc_free (&gc);
}
void
@@ -2076,23 +2168,6 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
#elif defined(TARGET_OPENBSD)
-/*
- * OpenBSD has a slightly incompatible TUN device from
- * the rest of the world, in that it prepends a
- * uint32 to the beginning of the IP header
- * to designate the protocol (why not just
- * look at the version field in the IP header to
- * determine v4 or v6?).
- *
- * We strip off this field on reads and
- * put it back on writes.
- *
- * I have not tested TAP devices on OpenBSD,
- * but I have conditionalized the special
- * TUN handling code described above to
- * go away for TAP devices.
- */
-
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
@@ -2159,59 +2234,16 @@ close_tun (struct tuntap* tt)
}
}
-static inline int
-openbsd_modify_read_write_return (int len)
-{
- if (len > 0)
- return len > sizeof (u_int32_t) ? len - sizeof (u_int32_t) : 0;
- else
- return len;
-}
-
int
-write_tun (struct tuntap* tt, uint8_t *buf, int len)
+write_tun(struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
- struct ip *iph;
-
- iph = (struct ip *) buf;
-
- if (tt->ipv6 && iph->ip_v == 6)
- type = htonl (AF_INET6);
- else
- type = htonl (AF_INET);
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (writev (tt->fd, iv, 2));
- }
- else
- return write (tt->fd, buf, len);
+ return write_tun_header (tt, buf, len);
}
int
-read_tun (struct tuntap* tt, uint8_t *buf, int len)
+read_tun (struct tuntap *tt, uint8_t *buf, int len)
{
- if (tt->type == DEV_TYPE_TUN)
- {
- u_int32_t type;
- struct iovec iv[2];
-
- iv[0].iov_base = &type;
- iv[0].iov_len = sizeof (type);
- iv[1].iov_base = buf;
- iv[1].iov_len = len;
-
- return openbsd_modify_read_write_return (readv (tt->fd, iv, 2));
- }
- else
- return read (tt->fd, buf, len);
+ return read_tun_header (tt, buf, len);
}
#elif defined(TARGET_NETBSD)
@@ -2571,10 +2603,177 @@ read_tun (struct tuntap* tt, uint8_t *buf, int len)
* pointing to lo0. Need to unconfigure... (observed on 10.5)
*/
+/*
+ * utun is the native Darwin tun driver present since at least 10.7
+ * Thanks goes to Jonathan Levin for providing an example how to utun
+ * (http://newosxbook.com/src.jl?tree=listings&file=17-15-utun.c)
+ */
+
+#ifdef HAVE_NET_IF_UTUN_H
+
+/* Helper functions that tries to open utun device
+ return -2 on early initialization failures (utun not supported
+ at all (old OS X) and -1 on initlization failure of utun
+ device (utun works but utunX is already used */
+static
+int utun_open_helper (struct ctl_info ctlInfo, int utunnum)
+{
+ struct sockaddr_ctl sc;
+ int fd;
+
+ fd = socket(PF_SYSTEM, SOCK_DGRAM, SYSPROTO_CONTROL);
+
+ if (fd < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "socket(SYSPROTO_CONTROL)",
+ strerror (errno));
+ return -2;
+ }
+
+ if (ioctl(fd, CTLIOCGINFO, &ctlInfo) == -1)
+ {
+ close (fd);
+ msg (M_INFO, "Opening utun (%s): %s", "ioctl(CTLIOCGINFO)",
+ strerror (errno));
+ return -2;
+ }
+
+
+ sc.sc_id = ctlInfo.ctl_id;
+ sc.sc_len = sizeof(sc);
+ sc.sc_family = AF_SYSTEM;
+ sc.ss_sysaddr = AF_SYS_CONTROL;
+
+ sc.sc_unit = utunnum+1;
+
+
+ /* If the connect is successful, a utun%d device will be created, where "%d"
+ * is (sc.sc_unit - 1) */
+
+ if (connect (fd, (struct sockaddr *)&sc, sizeof(sc)) < 0)
+ {
+ msg (M_INFO, "Opening utun (%s): %s", "connect(AF_SYS_CONTROL)",
+ strerror (errno));
+ close(fd);
+ return -1;
+ }
+
+ set_nonblock (fd);
+ set_cloexec (fd); /* don't pass fd to scripts */
+
+ return fd;
+}
+
+void
+open_darwin_utun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
+{
+ struct ctl_info ctlInfo;
+ int fd;
+ char utunname[20];
+ int utunnum =-1;
+ socklen_t utunname_len = sizeof(utunname);
+
+ /* dev_node is simply utun, do the normal dynamic utun
+ * otherwise try to parse the utun number */
+ if (dev_node && !strcmp ("utun", dev_node)==0)
+ {
+ if (!sscanf (dev_node, "utun%d", &utunnum)==1)
+ msg (M_FATAL, "Cannot parse 'dev-node %s' please use 'dev-node utunX'"
+ "to use a utun device number X", dev_node);
+ }
+
+
+
+ CLEAR (ctlInfo);
+ if (strlcpy(ctlInfo.ctl_name, UTUN_CONTROL_NAME, sizeof(ctlInfo.ctl_name)) >=
+ sizeof(ctlInfo.ctl_name))
+ {
+ msg (M_ERR, "Opening utun: UTUN_CONTROL_NAME too long");
+ }
+
+ /* try to open first available utun device if no specific utun is requested */
+ if (utunnum == -1)
+ {
+ for (utunnum=0; utunnum<255; utunnum++)
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ /* Break if the fd is valid,
+ * or if early initalization failed (-2) */
+ if (fd !=-1)
+ break;
+ }
+ }
+ else
+ {
+ fd = utun_open_helper (ctlInfo, utunnum);
+ }
+
+ /* opening an utun device failed */
+ tt->fd = fd;
+
+ if (fd < 0)
+ return;
+
+ /* Retrieve the assigned interface name. */
+ if (getsockopt (fd, SYSPROTO_CONTROL, UTUN_OPT_IFNAME, utunname, &utunname_len))
+ msg (M_ERR | M_ERRNO, "Error retrieving utun interface name");
+
+ tt->actual_name = string_alloc (utunname, NULL);
+
+ msg (M_INFO, "Opened utun device %s", utunname);
+ tt->is_utun = true;
+}
+
+#endif
+
void
open_tun (const char *dev, const char *dev_type, const char *dev_node, struct tuntap *tt)
{
- open_tun_generic (dev, dev_type, dev_node, true, true, tt);
+#ifdef HAVE_NET_IF_UTUN_H
+ /* If dev_node does not start start with utun assume regular tun/tap */
+ if ((!dev_node && tt->type==DEV_TYPE_TUN) ||
+ (dev_node && !strncmp (dev_node, "utun", 4)))
+ {
+
+ /* Check if user has specific dev_type tap and forced utun with
+ dev-node utun */
+ if (tt->type!=DEV_TYPE_TUN)
+ msg (M_FATAL, "Cannot use utun devices with --dev-type %s",
+ dev_type_string (dev, dev_type));
+
+ /* Try utun first and fall back to normal tun if utun fails
+ and dev_node is not specified */
+ open_darwin_utun(dev, dev_type, dev_node, tt);
+
+ if (!tt->is_utun)
+ {
+ if (!dev_node)
+ {
+ /* No explicit utun and utun failed, try the generic way) */
+ msg (M_INFO, "Failed to open utun device. Falling back to /dev/tun device");
+ open_tun_generic (dev, dev_type, NULL, true, true, tt);
+ }
+ else
+ {
+ /* Specific utun device or generic utun request with no tun
+ fall back failed, consider this a fatal failure */
+ msg (M_FATAL, "Cannot open utun device");
+ }
+ }
+ }
+ else
+#endif
+ {
+
+ /* Use plain dev-node tun to select /dev/tun style
+ * Unset dev_node variable prior to passing to open_tun_generic to
+ * let open_tun_generic pick the first available tun device */
+
+ if (dev_node && strcmp (dev_node, "tun")==0)
+ dev_node=NULL;
+
+ open_tun_generic (dev, dev_type, dev_node, true, true, tt);
+ }
}
void
@@ -2607,13 +2806,23 @@ close_tun (struct tuntap* tt)
int
write_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return write (tt->fd, buf, len);
+#ifdef HAVE_NET_IF_UTUN_H
+ if (tt->is_utun)
+ return write_tun_header (tt, buf, len);
+ else
+#endif
+ return write (tt->fd, buf, len);
}
int
read_tun (struct tuntap* tt, uint8_t *buf, int len)
{
- return read (tt->fd, buf, len);
+#ifdef HAVE_NET_IF_UTUN_H
+ if (tt->is_utun)
+ return read_tun_header (tt, buf, len);
+ else
+#endif
+ return read (tt->fd, buf, len);
}
#elif defined(WIN32)
@@ -2958,9 +3167,9 @@ get_panel_reg (struct gc_arena *gc)
char enum_name[256];
char connection_string[256];
HKEY connection_key;
- char name_data[256];
+ WCHAR name_data[256];
DWORD name_type;
- const char name_string[] = "Name";
+ const WCHAR name_string[] = L"Name";
len = sizeof (enum_name);
status = RegEnumKeyEx(
@@ -2994,12 +3203,12 @@ get_panel_reg (struct gc_arena *gc)
else
{
len = sizeof (name_data);
- status = RegQueryValueEx(
+ status = RegQueryValueExW(
connection_key,
name_string,
NULL,
&name_type,
- name_data,
+ (LPBYTE) name_data,
&len);
if (status != ERROR_SUCCESS || name_type != REG_SZ)
@@ -3007,10 +3216,15 @@ get_panel_reg (struct gc_arena *gc)
NETWORK_CONNECTIONS_KEY, connection_string, name_string);
else
{
+ int n;
+ LPSTR name;
struct panel_reg *reg;
ALLOC_OBJ_CLEAR_GC (reg, struct panel_reg, gc);
- reg->name = string_alloc (name_data, gc);
+ n = WideCharToMultiByte (CP_UTF8, 0, name_data, -1, NULL, 0, NULL, NULL);
+ name = gc_malloc (n, false, gc);
+ WideCharToMultiByte (CP_UTF8, 0, name_data, -1, name, n, NULL, NULL);
+ reg->name = name;
reg->guid = string_alloc (enum_name, gc);
/* link into return list */
@@ -3220,7 +3434,7 @@ static void
at_least_one_tap_win (const struct tap_reg *tap_reg)
{
if (!tap_reg)
- msg (M_FATAL, "There are no TAP-Windows adapters on this system. You should be able to create a TAP-Windows adapter by going to Start -> All Programs -> " PACKAGE_NAME " -> Add a new TAP-Windows virtual ethernet adapter.");
+ msg (M_FATAL, "There are no TAP-Windows adapters on this system. You should be able to create a TAP-Windows adapter by going to Start -> All Programs -> TAP-Windows -> Utilities -> Add a new TAP-Windows virtual ethernet adapter.");
}
/*
@@ -5091,10 +5305,14 @@ close_tun (struct tuntap *tt)
/* remove route pointing to interface */
delete_route_connected_v6_net(tt, NULL);
+ /* "store=active" is needed in Windows 8(.1) to delete the
+ * address we added (pointed out by Cedric Tabary).
+ */
+
/* netsh interface ipv6 delete address \"%s\" %s */
ifconfig_ipv6_local = print_in6_addr (tt->local_ipv6, 0, &gc);
argv_printf (&argv,
- "%s%sc interface ipv6 delete address %s %s",
+ "%s%sc interface ipv6 delete address %s %s store=active",
get_win_sys_path(),
NETSH_PATH_SUFFIX,
tt->actual_name,
diff --git a/app/openvpn/src/openvpn/tun.h b/app/openvpn/src/openvpn/tun.h
index e7d941ab..631b53c6 100644
--- a/app/openvpn/src/openvpn/tun.h
+++ b/app/openvpn/src/openvpn/tun.h
@@ -181,6 +181,9 @@ struct tuntap
int ip_fd;
#endif
+#ifdef HAVE_NET_IF_UTUN_H
+ bool is_utun;
+#endif
/* used for printing status info only */
unsigned int rwflags_debug;
@@ -203,8 +206,6 @@ tuntap_defined (const struct tuntap *tt)
* Function prototypes
*/
-static void clear_tuntap (struct tuntap *tuntap);
-
void open_tun (const char *dev, const char *dev_type, const char *dev_node,
struct tuntap *tt);
diff --git a/app/openvpn/src/openvpn/win32.c b/app/openvpn/src/openvpn/win32.c
index 2db96a8d..7c89a5a9 100644
--- a/app/openvpn/src/openvpn/win32.c
+++ b/app/openvpn/src/openvpn/win32.c
@@ -517,7 +517,7 @@ win32_signal_get (struct win32_signal *ws)
if (ret)
{
siginfo_static.signal_received = ret;
- siginfo_static.hard = true;
+ siginfo_static.source = SIG_SOURCE_HARD;
}
}
return ret;
@@ -870,6 +870,9 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
WCHAR *cl = wide_cmd_line (a, &gc);
WCHAR *cmd = wide_string (a->argv[0], &gc);
+ /* this allows console programs to run, and is ignored otherwise */
+ DWORD proc_flags = CREATE_NO_WINDOW;
+
CLEAR (start_info);
CLEAR (proc_info);
@@ -879,7 +882,7 @@ openvpn_execve (const struct argv *a, const struct env_set *es, const unsigned i
start_info.dwFlags = STARTF_USESHOWWINDOW;
start_info.wShowWindow = SW_HIDE;
- if (CreateProcessW (cmd, cl, NULL, NULL, FALSE, 0, env, NULL, &start_info, &proc_info))
+ if (CreateProcessW (cmd, cl, NULL, NULL, FALSE, proc_flags, env, NULL, &start_info, &proc_info))
{
DWORD exit_status = 0;
CloseHandle (proc_info.hThread);
@@ -993,19 +996,27 @@ set_win_sys_path_via_env (struct env_set *es)
const char *
win_get_tempdir()
{
- static char buf[MAX_PATH];
- char *tmpdir = buf;
+ static char tmpdir[MAX_PATH];
+ WCHAR wtmpdir[MAX_PATH];
- CLEAR(buf);
+ if (!GetTempPathW(_countof(wtmpdir), wtmpdir))
+ {
+ /* Warn if we can't find a valid temporary directory, which should
+ * be unlikely.
+ */
+ msg (M_WARN, "Could not find a suitable temporary directory."
+ " (GetTempPath() failed). Consider using --tmp-dir");
+ return NULL;
+ }
+
+ if (WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, NULL, 0, NULL, NULL) > sizeof (tmpdir))
+ {
+ msg (M_WARN, "Could not get temporary directory. Path is too long."
+ " Consider using --tmp-dir");
+ return NULL;
+ }
- if (!GetTempPath(sizeof(buf),buf)) {
- /* Warn if we can't find a valid temporary directory, which should
- * be unlikely.
- */
- msg (M_WARN, "Could not find a suitable temporary directory."
- " (GetTempPath() failed). Consider to use --tmp-dir");
- tmpdir = NULL;
- }
+ WideCharToMultiByte (CP_UTF8, 0, wtmpdir, -1, tmpdir, sizeof (tmpdir), NULL, NULL);
return tmpdir;
}
#endif
diff --git a/app/openvpn/src/plugins/auth-pam/Makefile.am b/app/openvpn/src/plugins/auth-pam/Makefile.am
index 701a7497..2aef311a 100644
--- a/app/openvpn/src/plugins/auth-pam/Makefile.am
+++ b/app/openvpn/src/plugins/auth-pam/Makefile.am
@@ -8,8 +8,9 @@ MAINTAINERCLEANFILES = \
$(srcdir)/Makefile.in
AM_CFLAGS = \
- -I$(top_srcdir)/include
- $(PLUGIN_AUTH_PAM_CFLAGS)
+ -I$(top_srcdir)/include \
+ $(PLUGIN_AUTH_PAM_CFLAGS) \
+ $(OPTIONAL_CRYPTO_CFLAGS)
if ENABLE_PLUGIN_AUTH_PAM
plugin_LTLIBRARIES = openvpn-plugin-auth-pam.la
diff --git a/app/openvpn/src/plugins/down-root/Makefile.am b/app/openvpn/src/plugins/down-root/Makefile.am
index 064aa30c..7ca5a4e1 100644
--- a/app/openvpn/src/plugins/down-root/Makefile.am
+++ b/app/openvpn/src/plugins/down-root/Makefile.am
@@ -8,7 +8,8 @@ MAINTAINERCLEANFILES = \
$(srcdir)/Makefile.in
AM_CFLAGS = \
- -I$(top_srcdir)/include
+ -I$(top_srcdir)/include \
+ $(OPTIONAL_CRYPTO_CFLAGS)
if ENABLE_PLUGIN_DOWN_ROOT
plugin_LTLIBRARIES = openvpn-plugin-down-root.la