diff options
| author | Parménides GV <parmegv@sdf.org> | 2014-06-13 13:24:13 +0200 | 
|---|---|---|
| committer | Parménides GV <parmegv@sdf.org> | 2014-06-13 13:24:13 +0200 | 
| commit | 69b10487fcd63dfe1e94fa97c9f3fd9b035646b4 (patch) | |
| tree | d4960893a4444634d404c7fbe4fa3e8778d30179 /app/openvpn/src | |
| parent | 9f6cfff38ae87922adc022300e1e2fd1c0d4c3e4 (diff) | |
| parent | e45929e220fe49e30235a1d4d36c1a413547f8bf (diff) | |
Merge branch 'develop'
Diffstat (limited to 'app/openvpn/src')
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 | 
