mirror of
https://github.com/deneraraujo/OpenVPNAdapter.git
synced 2026-02-11 00:00:08 +08:00
3e002c8 remove unused Jenkinsfile 16b1055 [OVPN3-140] Update company names in copyrights 6caca2c [OVPN3-140] Relicense back to AGPLv3 4f9ae74 cliproto: react to tls_warnings 546547b Proto: export tls_warnings attribute from SSL session 7cbaa26 SSLAPI: add tls_warning attribute 7ed93a3 clievent: add Warn event class 7a71ba1 win: get 'arch' param value from environment 61bb21b win: make parameter optional 15d66c4 [OVPN3-141] win: disable WPO 97d9c28 [OU-15] mbedtls: remove duplicated code 95aec32 [OU-15] mbedtls: refactor X509Cert to allow reuse der2pem 946753e [OVPN3-135] Win: remove unneeded default route d7f8c47 nrpt: create separate policy per dns suffix 577b5ca cli.cpp: fix typ0 in define fc8f89d [OVPN3-129] android: ensure all SWIG files are archived and saved e143bc0 [OVPN3-129] android: improve build system in order to perform full build 06d23ec [OVPN3-129] build-system: let scripts download dependencies 76bb99c fix usage of to_string() in Android 44c183a time: mute type conversion warnings for UWP client 7d7490c transport: enable socket protect call for UWP 1c003ac transport: pass protocol type to external factory c0de92c transport: add stop_requeueing method e2c60c8 android: build core library with MD5 support 3928069 [OVPN3-119] mbedTLS: create INSECURE profile including MD5 4f99310 remove function accidentally duplicated by last merge b91d841 self-test: add missing includes 19e33c4 [OA-14] mbedTLS: relax x509 date/time format check f3cf645 [OVPN3-116] disable SSL_CBC_RECORD_SPLITTING fca9ed2 [OVPN3-105] ParseClientConfig: avoid crash when not all key material is provided 7299fef [OC-42] Android: specify API level on command line d3da3df android: build client lib for x86 (for emulator) 8e501c5 Update version for mbedTLS and lz4 e57676e ParseClientConfig: export config to json format 9aa715f ParseClientConfig: export configuration to ovpn file format 1eab4cb ParseClientConfig: add helper constructor 71a59e4 ParseClientConfig: store the entire ovpn profile e0bb85a Transport: convert from transport protocol to config string 2fe56c3 Compress: convert from ctx type to config string 174ee25 OpenSSL: implement stub methods for new private_key_type/length() SSLAPIs 3d57708 mbedTLS: implement private_key_type/length() API a3210f0 SSLAPI: add private_key_type/length() getter methods 8ffe888 OpenSSL: implement stub methods for new extract_* SSLAPIs 16e9160 mbedTLS: implement extended API for key material extraction fe3d519 SSLAPI: extend API with methods to extract key material 2b4c850 Debugging: added header and build flag for valgrind run-time extensions. b948cde ManClientInstance::Factory: added virtual stop() method. 121e975 client API: added portOverride 106981c JSON: allow alternative JSON library implementations f206ae2 logging: added logdatetime.hpp which prepends date/time to log lines 49e933d Time: added to_double, delta_float, and delta_str methods 569b1da daemon.hpp: added class WritePid for managing pid files 63e9e04 ClientProto: reset CoarseTime object when AsioTimer is canceled f64b501 Cleanup: allow functor to be passed by value. ebe2560 RunContext: add configurable exit via EXIT_IN env var for debugging 1fbff4f tls-crypt: revised server-side validate_initial_packet() methods to use a BufferAllocated rather than a Buffer. 0090c51 SSLConst: added new ssl_flags() method which filters out non-ssl flags from given argument. 8379b0a CryptoDCInstance: added new RekeyType PRIMARY_SECONDARY_SWAP and use it in ProtoContext::promote_secondary_to_primary() since it more accurately reflects the underlying implementation. 18f45c2 ManClientInstance::Send: added AuthStatus::Type parameter to disconnect_user() method. 4bba803 Listen::List: added expand_ports() method. 5122e7d Listen::List: in port_offset(), set n_threads to 0 since number-of-threads data for port_offset items isn't really relevant. 4e11a6c StaticKey: added render_to_base64() and init_from_rng() methods. 190ece9 CryptoAlgs: added mode() method. 76e65cf CryptoAlgs: added AEAD_NONCE_TAIL_SIZE constant (set to 8 bytes) to represent the size in bytes of AEAD "nonce tail" normally taken from the HMAC key material. 2738718 compress: added method_to_string() method, i.e. the inverse of parse_method(). 7b47f99 compress: since parse_method() performs a linear search on method, reorder so that more frequently used methods appear at the top of the list. b428f74 library: added integer is_pow2() and log2() methods based on efficient __builtin_ffs and __builtin_clz intrinsics. 4926011 Android: adapt toolchain scripts to new SDK and move to API 26 ad4e995 mbedTLS: use mbedtls API to initialize cert object 908c611 transport: use socket_protect to communicate socket handle on UWP 92a6216 build win: read certain params from env 8166ea8 common: define uwp platform macro 0186bf6 common: report platform name as "uwp" 3f291b0 netconf: disable getting hwaddr for UWP 6365d26 transport: external factory 2ffa0c9 transport: synchronous DNS lookup 2c09c7c cliconnect.hpp: support for AsioWork always on 4f5a04d rand.hpp: allow external entropy source b19c5da time.hpp: use GetTickCount64 on Vista and newer 712ccfc android: export DEP_DIR via vars files only if not already defined 1b5a784 asio: make sure to switch to DEP_DIR before building 4302651 changes to support android building 6f56b2b Merge pull request #21 from OpenVPN/make_test_proto_deterministic 3a5ef2b travis-ci: make testing binary deterministic b76882d mbedtls: fix typ0 in exception message 40065a6 avoid "uninitialized variable warning" f33e7c2 [OVPN3-5] tls-crypt: add tls-crypt support in proto.hpp test unit 74c5f4f [OVPN3-5] tls-crypt: introduce tls-crypt support 389353c proto.cpp: uninit process at the end of the execution 56a831f [OVPN3-5] crypto/ssl: add support for AES-256-CTR 7cbf539 [OVPN3-5] build script: allow user to specify its own mbedTLS folder and LDFLAGS 8ae2a3f Integrate Google Test framework 68ae101 Add swig build to jenkins pipeline d496311 ovpncli.hpp: inline LogInfo constructor for clarity 96e0d89 Revert "Merged in OVPN3-21-prepend-log-record-with-unique- (pull request #7)" 7db95cc Make build fail on compilation errors 860129a TunBuilderCapture: make (to|from)_json methods public 2486494 random: added helper class Rand2 containing a crypto and non-crypto RNG 04175c2 appversion.hpp: Stringize VERSION -> MY_VERSION 81cb887 build script: added DPROF=1 flag a3dd47f timestr.hpp: moved milliseconds_since_epoch() to time/epoch.hpp 59b9492 sslchoose.hpp: added SSL_LIB_NAME 8fcb797 ProtoContext::KeyContext::raw_recv() : fix state transition e49e993 ProtoContext: comment edit 1d941aa VPNServerNetblock::Netblock refactor 7190495 Server-side renamings to break up long class names using namespaces. 3f74ec1 Listen::List: minor changes 79c789b RandomAPI: comment edit 5b5af36 Added SSLConst::SERVER_TO_SERVER flag fe00df4 OpenSSLContext::Config::set_rng: call assert_crypto() 3ae0076 In sslchoose.hpp, move OPENVPN_LOG_SSL macro to new file ssllog.hpp 1502cf6 URL::Parse: made is_valid_uri_char() standalone and moved to validate_uri.hpp 2dcb189 Added HTTP::Status::SwitchingProtocols constant 2f57024 HTTP::HeaderList: added get_value_trim_lower() method bee94d2 HTTP::HeaderList: get_value() and get_value_trim() should return std::string instead of const std::string 5debab1 Frame::Context: #define OPENVPN_NO_IO to allow building without i/o layer faf8f8f StaticKey: added parse_from_base64() method d11f250 HashString: added final_base64() method c373bf8 CompressContext: use C++11 member initialization and remove explicit attribute on constructor bd75cd7 RCPtr: added operator==() and operator!=() methods 7be33c5 PThreadBarrier: fixed incorrect comment 6f5f77b Link: use move semantics 17a5d89 inotify.hpp: no longer used 8ce39fc added render_hex() and render_hex_sep() methods that accept void* data ddc8e8a Function: use std::forward 76ee587 write_binary_atomic(): added tmpdir (temporary directory) parameter f366d55 base64: encode() now accepts void* data 462fe90 BufferType: added read(), write(), and prepend() variants that accept void* data 9ad1be4 IP::RouteType: added host_bits() method 3ebc8c7 IPv[46]::Addr::to_sockaddr() now accepts optional port number ce0977b Support Cityhash. fdbb0b9 IP::Addr: added validate_prefix_len() 25146d8 IP::Addr::from_ipv[4|6](): use move semantics a264f99 Merge pull request #20 from OpenVPN/fix_travis_ci_coverity 966e212 travis: don't mess up the SSL libs for wget/curl 2b8f09d Merge pull request #19 from OpenVPN/antonio/travis-ci-to-coverity 127cbb0 travis.yml: send build to Coverity SCAN when building master 2bca49b Merge pull request #15 from OpenVPN/antonio/travis-ci a5ce566 add basic support for Travis CI f9b14e9 macOS: add basic logging support 2b9188d Remotelist: pass meaningful port value to resolve::async_resolve() 4ebdbd0 Merged in OVPN3-38-improve-jenkins-pipeline-script (pull request #8) 832cf7f Report build status to Bitbucket 62423c9 Merged in OVPN3-21-prepend-log-record-with-unique- (pull request #7) cce2455 Prepend log string with unique reference. f26b08b Merged in OVPN3-25-pipeline-build (pull request #4) dc5ff1f Add OpenSSL version building. c77e1d6 Add pipeline script for multiplatform build. 4fab9b0 Merged in OVPN3-18-vs-project (pull request #2) 8eb0d6c Add Visual Studio project info to README 67c4989 Visual Studio 2015 solution and project files 52bfcd3 Merged in OVPN3-17 (pull request #1) 5f648ce Document Windows build process 3213c48 Support for local build settings b3ec01b Support for gpl version of mbedtls 903abc8 Support for zipballs 4029579 AsioPolySock: support bind to local address. 1e85566 Use openvpn::strerror_str() instead of std::strerror(). 3ba37fc OpenVPN 3 client: added OPENVPN_OVPNCLI_ASYNC_SETUP flag. git-subtree-dir: OpenVPN Adapter/Vendors/openvpn git-subtree-split: 3e002c83ce2e9f9f40ddcee750d3cfa664238abe
1124 lines
30 KiB
C++
1124 lines
30 KiB
C++
// OpenVPN -- An application to securely tunnel IP networks
|
|
// over a single port, with support for SSL/TLS-based
|
|
// session authentication and key exchange,
|
|
// packet encryption, packet authentication, and
|
|
// packet compression.
|
|
//
|
|
// Copyright (C) 2012-2017 OpenVPN Inc.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Affero General Public License Version 3
|
|
// 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 Affero General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Affero General Public License
|
|
// along with this program in the COPYING file.
|
|
// If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
// Unit test for OpenVPN Protocol implementation (class ProtoContext)
|
|
|
|
#include <iostream>
|
|
#include <string>
|
|
#include <sstream>
|
|
#include <deque>
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
#include <limits>
|
|
#include <thread>
|
|
|
|
#include <openvpn/common/platform.hpp>
|
|
|
|
#ifdef OPENVPN_PLATFORM_WIN
|
|
#include "protowin.h"
|
|
#endif
|
|
|
|
#define OPENVPN_DEBUG
|
|
#define OPENVPN_ENABLE_ASSERT
|
|
|
|
#if !defined(USE_TLS_AUTH) && !defined(USE_TLS_CRYPT)
|
|
//#define USE_TLS_AUTH
|
|
#define USE_TLS_CRYPT
|
|
#endif
|
|
|
|
#define OPENVPN_INSTRUMENTATION
|
|
|
|
// Data limits for Blowfish and other 64-bit block-size ciphers
|
|
#ifndef BF
|
|
#define BF 0
|
|
#endif
|
|
#define OPENVPN_BS64_DATA_LIMIT 50000
|
|
#if BF == 1
|
|
#define PROTO_CIPHER "BF-CBC"
|
|
#define TLS_VER_MIN TLSVersion::UNDEF
|
|
#define HANDSHAKE_WINDOW 60
|
|
#define BECOME_PRIMARY_CLIENT 5
|
|
#define BECOME_PRIMARY_SERVER 5
|
|
#define TLS_TIMEOUT_CLIENT 1000
|
|
#define TLS_TIMEOUT_SERVER 1000
|
|
#define FEEDBACK 0
|
|
#elif BF == 2
|
|
#define PROTO_CIPHER "BF-CBC"
|
|
#define TLS_VER_MIN TLSVersion::UNDEF
|
|
#define HANDSHAKE_WINDOW 10
|
|
#define BECOME_PRIMARY_CLIENT 10
|
|
#define BECOME_PRIMARY_SERVER 10
|
|
#define TLS_TIMEOUT_CLIENT 2000
|
|
#define TLS_TIMEOUT_SERVER 1000
|
|
#define FEEDBACK 0
|
|
#elif BF == 3
|
|
#define PROTO_CIPHER "BF-CBC"
|
|
#define TLS_VER_MIN TLSVersion::UNDEF
|
|
#define HANDSHAKE_WINDOW 60
|
|
#define BECOME_PRIMARY_CLIENT 60
|
|
#define BECOME_PRIMARY_SERVER 10
|
|
#define TLS_TIMEOUT_CLIENT 2000
|
|
#define TLS_TIMEOUT_SERVER 1000
|
|
#define FEEDBACK 0
|
|
#elif BF != 0
|
|
#error unknown BF value
|
|
#endif
|
|
|
|
// TLS timeout
|
|
#ifndef TLS_TIMEOUT_CLIENT
|
|
#define TLS_TIMEOUT_CLIENT 2000
|
|
#endif
|
|
#ifndef TLS_TIMEOUT_SERVER
|
|
#define TLS_TIMEOUT_SERVER 2000
|
|
#endif
|
|
|
|
// NoisyWire
|
|
#ifndef NOERR
|
|
#define SIMULATE_OOO
|
|
#define SIMULATE_DROPPED
|
|
#define SIMULATE_CORRUPTED
|
|
#endif
|
|
|
|
// how many virtual seconds between SSL renegotiations
|
|
#ifndef RENEG
|
|
#define RENEG 900
|
|
#endif
|
|
|
|
// feedback
|
|
#ifndef FEEDBACK
|
|
#define FEEDBACK 1
|
|
#else
|
|
#define FEEDBACK 0
|
|
#endif
|
|
|
|
// number of threads to use for test
|
|
#ifndef N_THREADS
|
|
#define N_THREADS 1
|
|
#endif
|
|
|
|
// number of iterations
|
|
#ifndef ITER
|
|
#define ITER 1000000
|
|
#endif
|
|
|
|
// number of high-level session iterations
|
|
#ifndef SITER
|
|
#define SITER 1
|
|
#endif
|
|
|
|
// abort if we reach this limit
|
|
//#define DROUGHT_LIMIT 100000
|
|
|
|
#if !defined(VERBOSE) && !defined(QUIET) && ITER <= 10000
|
|
#define VERBOSE
|
|
#endif
|
|
|
|
#ifdef VERBOSE
|
|
#define OPENVPN_DEBUG_PROTO 2
|
|
#define OPENVPN_LOG_SSL(x) OPENVPN_LOG(x)
|
|
#else
|
|
#define OPENVPN_LOG_SSL(x) // disable
|
|
#endif
|
|
|
|
#define STRINGIZE1(x) #x
|
|
#define STRINGIZE(x) STRINGIZE1(x)
|
|
|
|
// setup cipher
|
|
#ifndef PROTO_CIPHER
|
|
#ifdef PROTOv2
|
|
#define PROTO_CIPHER "AES-256-GCM"
|
|
#define TLS_VER_MIN TLSVersion::V1_2
|
|
#else
|
|
#define PROTO_CIPHER "AES-128-CBC"
|
|
#define TLS_VER_MIN TLSVersion::UNDEF
|
|
#endif
|
|
#endif
|
|
|
|
// setup digest
|
|
#ifndef PROTO_DIGEST
|
|
#define PROTO_DIGEST "SHA1"
|
|
#endif
|
|
|
|
// setup compressor
|
|
#ifdef PROTOv2
|
|
#ifdef HAVE_LZ4
|
|
#define COMP_METH CompressContext::LZ4v2
|
|
#else
|
|
#define COMP_METH CompressContext::COMP_STUBv2
|
|
#endif
|
|
#else
|
|
#define COMP_METH CompressContext::LZO_STUB
|
|
#endif
|
|
|
|
#include <openvpn/log/logsimple.hpp>
|
|
|
|
#include <openvpn/common/exception.hpp>
|
|
#include <openvpn/common/file.hpp>
|
|
#include <openvpn/common/count.hpp>
|
|
#include <openvpn/time/time.hpp>
|
|
#include <openvpn/random/mtrandapi.hpp>
|
|
#include <openvpn/frame/frame.hpp>
|
|
#include <openvpn/ssl/proto.hpp>
|
|
#include <openvpn/init/initprocess.hpp>
|
|
|
|
#include <openvpn/crypto/cryptodcsel.hpp>
|
|
|
|
#if defined(USE_MBEDTLS_APPLE_HYBRID)
|
|
#define USE_MBEDTLS
|
|
#endif
|
|
|
|
#if !(defined(USE_OPENSSL) || defined(USE_MBEDTLS) || defined(USE_APPLE_SSL))
|
|
#error Must define one or more of USE_OPENSSL, USE_MBEDTLS, USE_APPLE_SSL.
|
|
#endif
|
|
|
|
#if defined(USE_OPENSSL) && (defined(USE_MBEDTLS) || defined(USE_APPLE_SSL))
|
|
#undef USE_OPENSSL
|
|
#define USE_OPENSSL_SERVER
|
|
#elif !defined(USE_OPENSSL) && defined(USE_MBEDTLS)
|
|
#define USE_MBEDTLS_SERVER
|
|
#elif defined(USE_OPENSSL) && !defined(USE_MBEDTLS)
|
|
#define USE_OPENSSL_SERVER
|
|
#else
|
|
#error no server setup
|
|
#endif
|
|
|
|
#if defined(USE_OPENSSL) || defined(USE_OPENSSL_SERVER)
|
|
#include <openvpn/openssl/util/init.hpp>
|
|
|
|
#include <openvpn/openssl/crypto/api.hpp>
|
|
#include <openvpn/openssl/ssl/sslctx.hpp>
|
|
#include <openvpn/openssl/util/rand.hpp>
|
|
|
|
#endif
|
|
|
|
#if defined(USE_APPLE_SSL) || defined(USE_MBEDTLS_APPLE_HYBRID)
|
|
#include <openvpn/applecrypto/crypto/api.hpp>
|
|
#include <openvpn/applecrypto/ssl/sslctx.hpp>
|
|
#include <openvpn/applecrypto/util/rand.hpp>
|
|
#endif
|
|
|
|
#if defined(USE_MBEDTLS) || defined(USE_MBEDTLS_SERVER)
|
|
#include <openvpn/mbedtls/crypto/api.hpp>
|
|
#include <openvpn/mbedtls/ssl/sslctx.hpp>
|
|
#include <openvpn/mbedtls/util/rand.hpp>
|
|
#include <mbedtls/debug.h>
|
|
#endif
|
|
|
|
#include <openvpn/crypto/selftest.hpp>
|
|
|
|
using namespace openvpn;
|
|
|
|
// server Crypto/SSL/Rand implementation
|
|
#if defined(USE_MBEDTLS_SERVER)
|
|
typedef MbedTLSCryptoAPI ServerCryptoAPI;
|
|
typedef MbedTLSContext ServerSSLAPI;
|
|
typedef MbedTLSRandom ServerRandomAPI;
|
|
#elif defined(USE_OPENSSL_SERVER)
|
|
typedef OpenSSLCryptoAPI ServerCryptoAPI;
|
|
typedef OpenSSLContext ServerSSLAPI;
|
|
typedef OpenSSLRandom ServerRandomAPI;
|
|
#else
|
|
#error No server SSL implementation defined
|
|
#endif
|
|
|
|
// client SSL implementation can be OpenSSL, Apple SSL, or MbedTLS
|
|
#if defined(USE_MBEDTLS)
|
|
#if defined(USE_MBEDTLS_APPLE_HYBRID)
|
|
typedef AppleCryptoAPI ClientCryptoAPI;
|
|
#else
|
|
typedef MbedTLSCryptoAPI ClientCryptoAPI;
|
|
#endif
|
|
typedef MbedTLSContext ClientSSLAPI;
|
|
typedef MbedTLSRandom ClientRandomAPI;
|
|
#elif defined(USE_APPLE_SSL)
|
|
typedef AppleCryptoAPI ClientCryptoAPI;
|
|
typedef AppleSSLContext ClientSSLAPI;
|
|
typedef AppleRandom ClientRandomAPI;
|
|
#elif defined(USE_OPENSSL)
|
|
typedef OpenSSLCryptoAPI ClientCryptoAPI;
|
|
typedef OpenSSLContext ClientSSLAPI;
|
|
typedef OpenSSLRandom ClientRandomAPI;
|
|
#else
|
|
#error No client SSL implementation defined
|
|
#endif
|
|
|
|
const char message[] =
|
|
"Message _->_ 0000000000 It was a bright cold day in April, and the clocks\n"
|
|
"were striking thirteen. Winston Smith, his chin nuzzled\n"
|
|
"into his breast in an effort to escape the vile wind,\n"
|
|
"slipped quickly through the glass doors of Victory\n"
|
|
"Mansions, though not quickly enough to prevent a\n"
|
|
"swirl of gritty dust from entering along with him.\n"
|
|
#ifdef LARGE_MESSAGE
|
|
"It was a bright cold day in April, and the clocks\n"
|
|
"were striking thirteen. Winston Smith, his chin nuzzled\n"
|
|
"into his breast in an effort to escape the vile wind,\n"
|
|
"slipped quickly through the glass doors of Victory\n"
|
|
"Mansions, though not quickly enough to prevent a\n"
|
|
"swirl of gritty dust from entering along with him.\n"
|
|
"It was a bright cold day in April, and the clocks\n"
|
|
"were striking thirteen. Winston Smith, his chin nuzzled\n"
|
|
"into his breast in an effort to escape the vile wind,\n"
|
|
"slipped quickly through the glass doors of Victory\n"
|
|
"Mansions, though not quickly enough to prevent a\n"
|
|
"swirl of gritty dust from entering along with him.\n"
|
|
"It was a bright cold day in April, and the clocks\n"
|
|
"were striking thirteen. Winston Smith, his chin nuzzled\n"
|
|
"into his breast in an effort to escape the vile wind,\n"
|
|
"slipped quickly through the glass doors of Victory\n"
|
|
"Mansions, though not quickly enough to prevent a\n"
|
|
"swirl of gritty dust from entering along with him.\n"
|
|
"It was a bright cold day in April, and the clocks\n"
|
|
"were striking thirteen. Winston Smith, his chin nuzzled\n"
|
|
"into his breast in an effort to escape the vile wind,\n"
|
|
"slipped quickly through the glass doors of Victory\n"
|
|
"Mansions, though not quickly enough to prevent a\n"
|
|
"swirl of gritty dust from entering along with him.\n"
|
|
#endif
|
|
;
|
|
|
|
// A "Drought" measures the maximum period of time between
|
|
// any two successive events. Used to measure worst-case
|
|
// packet loss.
|
|
class DroughtMeasure
|
|
{
|
|
public:
|
|
OPENVPN_SIMPLE_EXCEPTION(drought_limit_exceeded);
|
|
|
|
DroughtMeasure(const std::string& name_arg, TimePtr now_arg)
|
|
: now(now_arg), name(name_arg)
|
|
{
|
|
}
|
|
|
|
void event()
|
|
{
|
|
if (last_event.defined())
|
|
{
|
|
Time::Duration since_last = *now - last_event;
|
|
if (since_last > drought)
|
|
{
|
|
drought = since_last;
|
|
#if defined(VERBOSE) || defined(DROUGHT_LIMIT)
|
|
{
|
|
const unsigned int r = drought.raw();
|
|
#if defined(VERBOSE)
|
|
std::cout << "*** Drought " << name << " has reached " << r << std::endl;
|
|
#endif
|
|
#ifdef DROUGHT_LIMIT
|
|
if (r > DROUGHT_LIMIT)
|
|
throw drought_limit_exceeded();
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
last_event = *now;
|
|
}
|
|
|
|
Time::Duration operator()() const { return drought; }
|
|
|
|
private:
|
|
TimePtr now;
|
|
Time last_event;
|
|
Time::Duration drought;
|
|
std::string name;
|
|
};
|
|
|
|
// test the OpenVPN protocol implementation in ProtoContext
|
|
class TestProto : public ProtoContext
|
|
{
|
|
typedef ProtoContext Base;
|
|
|
|
using Base::now;
|
|
using Base::mode;
|
|
using Base::is_server;
|
|
|
|
public:
|
|
using Base::flush;
|
|
|
|
typedef Base::PacketType PacketType;
|
|
|
|
OPENVPN_EXCEPTION(session_invalidated);
|
|
|
|
TestProto(const Base::Config::Ptr& config,
|
|
const SessionStats::Ptr& stats)
|
|
: Base(config, stats),
|
|
control_drought("control", config->now),
|
|
data_drought("data", config->now),
|
|
frame(config->frame)
|
|
{
|
|
// zero progress value
|
|
std::memset(progress_, 0, 11);
|
|
}
|
|
|
|
void reset()
|
|
{
|
|
net_out.clear();
|
|
Base::reset();
|
|
}
|
|
|
|
void initial_app_send(const char *msg)
|
|
{
|
|
Base::start();
|
|
const size_t msglen = std::strlen(msg) + 1;
|
|
BufferAllocated app_buf((unsigned char *)msg, msglen, 0);
|
|
copy_progress(app_buf);
|
|
control_send(std::move(app_buf));
|
|
flush(true);
|
|
}
|
|
|
|
void app_send_templ_init(const char *msg)
|
|
{
|
|
Base::start();
|
|
const size_t msglen = std::strlen(msg) + 1;
|
|
templ.reset(new BufferAllocated((unsigned char *)msg, msglen, 0));
|
|
flush(true);
|
|
}
|
|
|
|
void app_send_templ()
|
|
{
|
|
#if !FEEDBACK
|
|
if (bool(iteration++ & 1) == is_server())
|
|
{
|
|
modmsg(templ);
|
|
BufferAllocated app_buf(*templ);
|
|
control_send(std::move(app_buf));
|
|
flush(true);
|
|
++n_control_send_;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool do_housekeeping()
|
|
{
|
|
if (now() >= Base::next_housekeeping())
|
|
{
|
|
Base::housekeeping();
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
void control_send(BufferPtr&& app_bp)
|
|
{
|
|
app_bytes_ += app_bp->size();
|
|
Base::control_send(std::move(app_bp));
|
|
}
|
|
|
|
void control_send(BufferAllocated&& app_buf)
|
|
{
|
|
app_bytes_ += app_buf.size();
|
|
Base::control_send(std::move(app_buf));
|
|
}
|
|
|
|
BufferPtr data_encrypt_string(const char *str)
|
|
{
|
|
BufferPtr bp = new BufferAllocated();
|
|
frame->prepare(Frame::READ_LINK_UDP, *bp);
|
|
bp->write((unsigned char *)str, std::strlen(str));
|
|
data_encrypt(*bp);
|
|
return bp;
|
|
}
|
|
|
|
void data_encrypt(BufferAllocated& in_out)
|
|
{
|
|
Base::data_encrypt(in_out);
|
|
}
|
|
|
|
void data_decrypt(const PacketType& type, BufferAllocated& in_out)
|
|
{
|
|
Base::data_decrypt(type, in_out);
|
|
if (in_out.size())
|
|
{
|
|
data_bytes_ += in_out.size();
|
|
data_drought.event();
|
|
}
|
|
}
|
|
|
|
size_t net_bytes() const { return net_bytes_; }
|
|
size_t app_bytes() const { return app_bytes_; }
|
|
size_t data_bytes() const { return data_bytes_; }
|
|
size_t n_control_recv() const { return n_control_recv_; }
|
|
size_t n_control_send() const { return n_control_send_; }
|
|
|
|
const char *progress() const { return progress_; }
|
|
|
|
void finalize()
|
|
{
|
|
data_drought.event();
|
|
control_drought.event();
|
|
}
|
|
|
|
void check_invalidated()
|
|
{
|
|
if (Base::invalidated())
|
|
throw session_invalidated(Error::name(Base::invalidation_reason()));
|
|
}
|
|
|
|
std::deque<BufferPtr> net_out;
|
|
|
|
DroughtMeasure control_drought;
|
|
DroughtMeasure data_drought;
|
|
|
|
private:
|
|
virtual void control_net_send(const Buffer& net_buf)
|
|
{
|
|
net_bytes_ += net_buf.size();
|
|
net_out.push_back(BufferPtr(new BufferAllocated(net_buf, 0)));
|
|
}
|
|
|
|
virtual void control_recv(BufferPtr&& app_bp)
|
|
{
|
|
BufferPtr work;
|
|
work.swap(app_bp);
|
|
if (work->size() >= 23)
|
|
std::memcpy(progress_, work->data()+13, 10);
|
|
|
|
#ifdef VERBOSE
|
|
{
|
|
const ssize_t trunc = 64;
|
|
const std::string show((char *)work->data(), trunc);
|
|
std::cout << now().raw() << " " << mode().str() << " " << show << std::endl;
|
|
}
|
|
#endif
|
|
#if FEEDBACK
|
|
modmsg(work);
|
|
control_send(std::move(work));
|
|
#endif
|
|
control_drought.event();
|
|
++n_control_recv_;
|
|
}
|
|
|
|
void copy_progress(Buffer& buf)
|
|
{
|
|
if (progress_[0]) // make sure progress was initialized
|
|
std::memcpy(buf.data()+13, progress_, 10);
|
|
}
|
|
|
|
void modmsg(BufferPtr& buf)
|
|
{
|
|
char *msg = (char *) buf->data();
|
|
if (is_server())
|
|
{
|
|
msg[8] = 'S';
|
|
msg[11] = 'C';
|
|
}
|
|
else
|
|
{
|
|
msg[8] = 'C';
|
|
msg[11] = 'S';
|
|
}
|
|
|
|
// increment embedded number
|
|
for (int i = 22; i >= 13; i--)
|
|
{
|
|
if (msg[i] != '9')
|
|
{
|
|
msg[i]++;
|
|
break;
|
|
}
|
|
else
|
|
msg[i] = '0';
|
|
}
|
|
}
|
|
|
|
Frame::Ptr frame;
|
|
size_t app_bytes_ = 0;
|
|
size_t net_bytes_ = 0;
|
|
size_t data_bytes_ = 0;
|
|
size_t n_control_send_ = 0;
|
|
size_t n_control_recv_ = 0;
|
|
BufferPtr templ;
|
|
size_t iteration = 0;
|
|
char progress_[11];
|
|
};
|
|
|
|
class TestProtoClient : public TestProto
|
|
{
|
|
typedef TestProto Base;
|
|
public:
|
|
TestProtoClient(const Base::Config::Ptr& config,
|
|
const SessionStats::Ptr& stats)
|
|
: Base(config, stats)
|
|
{
|
|
}
|
|
|
|
private:
|
|
virtual void client_auth(Buffer& buf)
|
|
{
|
|
const std::string username("foo");
|
|
const std::string password("bar");
|
|
Base::write_auth_string(username, buf);
|
|
Base::write_auth_string(password, buf);
|
|
}
|
|
};
|
|
|
|
class TestProtoServer : public TestProto
|
|
{
|
|
typedef TestProto Base;
|
|
public:
|
|
OPENVPN_SIMPLE_EXCEPTION(auth_failed);
|
|
|
|
TestProtoServer(const Base::Config::Ptr& config,
|
|
const SessionStats::Ptr& stats)
|
|
: Base(config, stats)
|
|
{
|
|
}
|
|
|
|
private:
|
|
virtual void server_auth(const std::string& username,
|
|
const SafeString& password,
|
|
const std::string& peer_info,
|
|
const AuthCert::Ptr& auth_cert)
|
|
{
|
|
#ifdef VERBOSE
|
|
std::cout << "**** AUTHENTICATE " << username << '/' << password << " PEER INFO:" << std::endl;
|
|
std::cout << peer_info;
|
|
#endif
|
|
if (username != "foo" || password != "bar")
|
|
throw auth_failed();
|
|
}
|
|
};
|
|
|
|
// Simulate a noisy transmission channel where packets can be dropped,
|
|
// reordered, or corrupted.
|
|
class NoisyWire
|
|
{
|
|
public:
|
|
NoisyWire(const std::string title_arg,
|
|
TimePtr now_arg,
|
|
RandomAPI& rand_arg,
|
|
const unsigned int reorder_prob_arg,
|
|
const unsigned int drop_prob_arg,
|
|
const unsigned int corrupt_prob_arg)
|
|
: title(title_arg),
|
|
now(now_arg),
|
|
random(rand_arg),
|
|
reorder_prob(reorder_prob_arg),
|
|
drop_prob(drop_prob_arg),
|
|
corrupt_prob(corrupt_prob_arg)
|
|
{
|
|
}
|
|
|
|
template <typename T1, typename T2>
|
|
void xfer(T1& a, T2& b)
|
|
{
|
|
// check for errors
|
|
a.check_invalidated();
|
|
b.check_invalidated();
|
|
|
|
// need to retransmit?
|
|
if (a.do_housekeeping())
|
|
{
|
|
#ifdef VERBOSE
|
|
std::cout << now->raw() << " " << title << " Housekeeping" << std::endl;
|
|
#endif
|
|
}
|
|
|
|
// queue a control channel packet
|
|
a.app_send_templ();
|
|
|
|
// queue a data channel packet
|
|
if (a.data_channel_ready())
|
|
{
|
|
BufferPtr bp = a.data_encrypt_string("Waiting for godot A... Waiting for godot B... Waiting for godot C... Waiting for godot D... Waiting for godot E... Waiting for godot F... Waiting for godot G... Waiting for godot H... Waiting for godot I... Waiting for godot J...");
|
|
wire.push_back(bp);
|
|
}
|
|
|
|
// transfer network packets from A -> wire
|
|
while (!a.net_out.empty())
|
|
{
|
|
BufferPtr bp = a.net_out.front();
|
|
#ifdef VERBOSE
|
|
std::cout << now->raw() << " " << title << " " << a.dump_packet(*bp) << std::endl;
|
|
#endif
|
|
a.net_out.pop_front();
|
|
wire.push_back(bp);
|
|
}
|
|
|
|
// transfer network packets from wire -> B
|
|
while (true)
|
|
{
|
|
BufferPtr bp = recv();
|
|
if (!bp)
|
|
break;
|
|
typename T2::PacketType pt = b.packet_type(*bp);
|
|
if (pt.is_control())
|
|
{
|
|
#ifdef VERBOSE
|
|
if (!b.control_net_validate(pt, *bp)) // not strictly necessary since control_net_recv will also validate
|
|
std::cout << now->raw() << " " << title << " CONTROL PACKET VALIDATION FAILED" << std::endl;
|
|
#endif
|
|
b.control_net_recv(pt, std::move(bp));
|
|
}
|
|
else if (pt.is_data())
|
|
{
|
|
try {
|
|
b.data_decrypt(pt, *bp);
|
|
#ifdef VERBOSE
|
|
if (bp->size())
|
|
{
|
|
const std::string show((char *)bp->data(), std::min(bp->size(), size_t(40)));
|
|
std::cout << now->raw() << " " << title << " DATA CHANNEL DECRYPT: " << show << std::endl;
|
|
}
|
|
#endif
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
#ifdef VERBOSE
|
|
std::cout << now->raw() << " " << title << " Exception on data channel decrypt: " << e.what() << std::endl;
|
|
#endif
|
|
}
|
|
}
|
|
else
|
|
{
|
|
#ifdef VERBOSE
|
|
std::cout << now->raw() << " " << title << " KEY_STATE_ERROR" << std::endl;
|
|
#endif
|
|
b.stat().error(Error::KEY_STATE_ERROR);
|
|
}
|
|
}
|
|
b.flush(true);
|
|
}
|
|
|
|
private:
|
|
BufferPtr recv()
|
|
{
|
|
#ifdef SIMULATE_OOO
|
|
// simulate packets being received out of order
|
|
if (wire.size() >= 2 && !rand(reorder_prob))
|
|
{
|
|
const size_t i = random.randrange(wire.size() - 1) + 1;
|
|
#ifdef VERBOSE
|
|
std::cout << now->raw() << " " << title << " Simulating packet reordering " << i << " -> 0" << std::endl;
|
|
#endif
|
|
std::swap(wire[0], wire[i]);
|
|
}
|
|
#endif
|
|
|
|
if (wire.size())
|
|
{
|
|
BufferPtr bp = wire.front();
|
|
wire.pop_front();
|
|
|
|
#ifdef VERBOSE
|
|
std::cout << now->raw() << " " << title << " Received packet, size=" << bp->size() << std::endl;
|
|
#endif
|
|
|
|
#ifdef SIMULATE_DROPPED
|
|
// simulate dropped packet
|
|
if (!rand(drop_prob))
|
|
{
|
|
#ifdef VERBOSE
|
|
std::cout << now->raw() << " " << title << " Simulating a dropped packet" << std::endl;
|
|
#endif
|
|
return BufferPtr();
|
|
}
|
|
#endif
|
|
|
|
#ifdef SIMULATE_CORRUPTED
|
|
// simulate corrupted packet
|
|
if (bp->size() && !rand(corrupt_prob))
|
|
{
|
|
#ifdef VERBOSE
|
|
std::cout << now->raw() << " " << title << " Simulating a corrupted packet" << std::endl;
|
|
#endif
|
|
const size_t pos = random.randrange(bp->size());
|
|
const unsigned char value = random.randrange(256);
|
|
(*bp)[pos] = value;
|
|
}
|
|
#endif
|
|
return bp;
|
|
}
|
|
|
|
return BufferPtr();
|
|
}
|
|
|
|
unsigned int rand(const unsigned int prob)
|
|
{
|
|
if (prob)
|
|
return random.randrange(prob);
|
|
else
|
|
return 1;
|
|
}
|
|
|
|
std::string title;
|
|
TimePtr now;
|
|
RandomAPI& random;
|
|
unsigned int reorder_prob;
|
|
unsigned int drop_prob;
|
|
unsigned int corrupt_prob;
|
|
std::deque<BufferPtr> wire;
|
|
};
|
|
|
|
class MySessionStats : public SessionStats
|
|
{
|
|
public:
|
|
typedef RCPtr<MySessionStats> Ptr;
|
|
|
|
MySessionStats()
|
|
{
|
|
std::memset(errors, 0, sizeof(errors));
|
|
}
|
|
|
|
virtual void error(const size_t err_type, const std::string* text=nullptr)
|
|
{
|
|
if (err_type < Error::N_ERRORS)
|
|
++errors[err_type];
|
|
}
|
|
|
|
count_t get_error_count(const Error::Type type) const
|
|
{
|
|
if (type < Error::N_ERRORS)
|
|
return errors[type];
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
void show_error_counts() const
|
|
{
|
|
for (size_t i = 0; i < Error::N_ERRORS; ++i)
|
|
{
|
|
count_t c = errors[i];
|
|
if (c)
|
|
std::cerr << Error::name(i) << " : " << c << std::endl;
|
|
}
|
|
}
|
|
|
|
private:
|
|
count_t errors[Error::N_ERRORS];
|
|
};
|
|
|
|
// execute the unit test in one thread
|
|
int test(const int thread_num)
|
|
{
|
|
try {
|
|
// frame
|
|
Frame::Ptr frame(new Frame(Frame::Context(128, 256, 128, 0, 16, 0)));
|
|
|
|
// RNG
|
|
ClientRandomAPI::Ptr rng_cli(new ClientRandomAPI(false));
|
|
ClientRandomAPI::Ptr prng_cli(new ClientRandomAPI(true));
|
|
ServerRandomAPI::Ptr rng_serv(new ServerRandomAPI(false));
|
|
ServerRandomAPI::Ptr prng_serv(new ServerRandomAPI(true));
|
|
MTRand rng_noncrypto;
|
|
|
|
// init simulated time
|
|
Time time;
|
|
const Time::Duration time_step = Time::Duration::binary_ms(100);
|
|
|
|
// client config files
|
|
const std::string ca_crt = read_text("ca.crt");
|
|
const std::string client_crt = read_text("client.crt");
|
|
const std::string client_key = read_text("client.key");
|
|
const std::string server_crt = read_text("server.crt");
|
|
const std::string server_key = read_text("server.key");
|
|
const std::string dh_pem = read_text("dh.pem");
|
|
const std::string tls_auth_key = read_text("tls-auth.key");
|
|
|
|
// client config
|
|
ClientSSLAPI::Config::Ptr cc(new ClientSSLAPI::Config());
|
|
cc->set_mode(Mode(Mode::CLIENT));
|
|
cc->set_frame(frame);
|
|
#ifdef FORCE_AES_CBC
|
|
cc->set_force_aes_cbc_ciphersuites(true);
|
|
#endif
|
|
#ifdef USE_APPLE_SSL
|
|
cc->load_identity("etest");
|
|
#else
|
|
cc->load_ca(ca_crt, true);
|
|
cc->load_cert(client_crt);
|
|
cc->load_private_key(client_key);
|
|
#endif
|
|
cc->set_tls_version_min(TLS_VER_MIN);
|
|
#ifdef VERBOSE
|
|
cc->set_debug_level(1);
|
|
#endif
|
|
cc->set_rng(rng_cli);
|
|
|
|
// stats
|
|
MySessionStats::Ptr cli_stats(new MySessionStats);
|
|
MySessionStats::Ptr serv_stats(new MySessionStats);
|
|
|
|
// client ProtoContext config
|
|
typedef ProtoContext ClientProtoContext;
|
|
ClientProtoContext::Config::Ptr cp(new ClientProtoContext::Config);
|
|
cp->ssl_factory = cc->new_factory();
|
|
cp->dc.set_factory(new CryptoDCSelect<ClientCryptoAPI>(frame, cli_stats, prng_cli));
|
|
cp->tlsprf_factory.reset(new CryptoTLSPRFFactory<ClientCryptoAPI>());
|
|
cp->frame = frame;
|
|
cp->now = &time;
|
|
cp->rng = rng_cli;
|
|
cp->prng = prng_cli;
|
|
cp->protocol = Protocol(Protocol::UDPv4);
|
|
cp->layer = Layer(Layer::OSI_LAYER_3);
|
|
#ifdef PROTOv2
|
|
cp->enable_op32 = true;
|
|
cp->remote_peer_id = 100;
|
|
#endif
|
|
cp->comp_ctx = CompressContext(COMP_METH, false);
|
|
cp->dc.set_cipher(CryptoAlgs::lookup(PROTO_CIPHER));
|
|
cp->dc.set_digest(CryptoAlgs::lookup(PROTO_DIGEST));
|
|
#ifdef USE_TLS_AUTH
|
|
cp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ClientCryptoAPI>());
|
|
cp->tls_key.parse(tls_auth_key);
|
|
cp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
|
|
cp->key_direction = 0;
|
|
#endif
|
|
#ifdef USE_TLS_CRYPT
|
|
cp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ClientCryptoAPI>());
|
|
cp->tls_key.parse(tls_auth_key);
|
|
cp->set_tls_crypt_algs(CryptoAlgs::lookup("SHA256"), CryptoAlgs::lookup("AES-256-CTR"));
|
|
#endif
|
|
cp->reliable_window = 4;
|
|
cp->max_ack_list = 4;
|
|
cp->pid_mode = PacketIDReceive::UDP_MODE;
|
|
#if defined(HANDSHAKE_WINDOW)
|
|
cp->handshake_window = Time::Duration::seconds(HANDSHAKE_WINDOW);
|
|
#elif SITER > 1
|
|
cp->handshake_window = Time::Duration::seconds(30);
|
|
#else
|
|
cp->handshake_window = Time::Duration::seconds(18); // will cause a small number of handshake failures
|
|
#endif
|
|
#ifdef BECOME_PRIMARY_CLIENT
|
|
cp->become_primary = Time::Duration::seconds(BECOME_PRIMARY_CLIENT);
|
|
#else
|
|
cp->become_primary = cp->handshake_window;
|
|
#endif
|
|
cp->tls_timeout = Time::Duration::milliseconds(TLS_TIMEOUT_CLIENT);
|
|
#if defined(CLIENT_NO_RENEG)
|
|
cp->renegotiate = Time::Duration::infinite();
|
|
#else
|
|
cp->renegotiate = Time::Duration::seconds(RENEG);
|
|
#endif
|
|
cp->expire = cp->renegotiate + cp->renegotiate;
|
|
cp->keepalive_ping = Time::Duration::seconds(5);
|
|
cp->keepalive_timeout = Time::Duration::seconds(60);
|
|
|
|
#ifdef VERBOSE
|
|
std::cout << "CLIENT OPTIONS: " << cp->options_string() << std::endl;
|
|
std::cout << "CLIENT PEER INFO:" << std::endl;
|
|
std::cout << cp->peer_info_string();
|
|
#endif
|
|
|
|
// server config
|
|
ClientSSLAPI::Config::Ptr sc(new ClientSSLAPI::Config());
|
|
sc->set_mode(Mode(Mode::SERVER));
|
|
sc->set_frame(frame);
|
|
sc->load_ca(ca_crt, true);
|
|
sc->load_cert(server_crt);
|
|
sc->load_private_key(server_key);
|
|
sc->load_dh(dh_pem);
|
|
sc->set_tls_version_min(TLS_VER_MIN);
|
|
sc->set_rng(rng_serv);
|
|
#ifdef VERBOSE
|
|
sc->set_debug_level(1);
|
|
#endif
|
|
|
|
// server ProtoContext config
|
|
typedef ProtoContext ServerProtoContext;
|
|
ServerProtoContext::Config::Ptr sp(new ServerProtoContext::Config);
|
|
sp->ssl_factory = sc->new_factory();
|
|
sp->dc.set_factory(new CryptoDCSelect<ServerCryptoAPI>(frame, serv_stats, prng_serv));
|
|
sp->tlsprf_factory.reset(new CryptoTLSPRFFactory<ServerCryptoAPI>());
|
|
sp->frame = frame;
|
|
sp->now = &time;
|
|
sp->rng = rng_serv;
|
|
sp->prng = prng_serv;
|
|
sp->protocol = Protocol(Protocol::UDPv4);
|
|
sp->layer = Layer(Layer::OSI_LAYER_3);
|
|
#ifdef PROTOv2
|
|
sp->enable_op32 = true;
|
|
sp->remote_peer_id = 101;
|
|
#endif
|
|
sp->comp_ctx = CompressContext(COMP_METH, false);
|
|
sp->dc.set_cipher(CryptoAlgs::lookup(PROTO_CIPHER));
|
|
sp->dc.set_digest(CryptoAlgs::lookup(PROTO_DIGEST));
|
|
#ifdef USE_TLS_AUTH
|
|
sp->tls_auth_factory.reset(new CryptoOvpnHMACFactory<ServerCryptoAPI>());
|
|
sp->tls_key.parse(tls_auth_key);
|
|
sp->set_tls_auth_digest(CryptoAlgs::lookup(PROTO_DIGEST));
|
|
sp->key_direction = 1;
|
|
#endif
|
|
#ifdef USE_TLS_CRYPT
|
|
sp->tls_crypt_factory.reset(new CryptoTLSCryptFactory<ServerCryptoAPI>());
|
|
sp->tls_key.parse(tls_auth_key);
|
|
sp->set_tls_crypt_algs(CryptoAlgs::lookup("SHA256"), CryptoAlgs::lookup("AES-256-CTR"));
|
|
#endif
|
|
sp->reliable_window = 4;
|
|
sp->max_ack_list = 4;
|
|
sp->pid_mode = PacketIDReceive::UDP_MODE;
|
|
#if defined(HANDSHAKE_WINDOW)
|
|
sp->handshake_window = Time::Duration::seconds(HANDSHAKE_WINDOW);
|
|
#elif SITER > 1
|
|
sp->handshake_window = Time::Duration::seconds(30);
|
|
#else
|
|
sp->handshake_window = Time::Duration::seconds(17) + Time::Duration::binary_ms(512);
|
|
#endif
|
|
#ifdef BECOME_PRIMARY_SERVER
|
|
sp->become_primary = Time::Duration::seconds(BECOME_PRIMARY_SERVER);
|
|
#else
|
|
sp->become_primary = sp->handshake_window;
|
|
#endif
|
|
sp->tls_timeout = Time::Duration::milliseconds(TLS_TIMEOUT_SERVER);
|
|
#if defined(SERVER_NO_RENEG)
|
|
sp->renegotiate = Time::Duration::infinite();
|
|
#else
|
|
// NOTE: if we don't add sp->handshake_window, both client and server reneg-sec (RENEG)
|
|
// will be equal and will therefore occasionally collide. Such collisions can sometimes
|
|
// produce this OpenSSL error:
|
|
// OpenSSLContext::SSL::read_cleartext: BIO_read failed, cap=400 status=-1: error:140E0197:SSL routines:SSL_shutdown:shutdown while in init
|
|
// The issue was introduced by this patch in OpenSSL:
|
|
// https://github.com/openssl/openssl/commit/64193c8218540499984cd63cda41f3cd491f3f59
|
|
sp->renegotiate = Time::Duration::seconds(RENEG) + sp->handshake_window;
|
|
#endif
|
|
sp->expire = sp->renegotiate + sp->renegotiate;
|
|
sp->keepalive_ping = Time::Duration::seconds(5);
|
|
sp->keepalive_timeout = Time::Duration::seconds(60);
|
|
|
|
#ifdef VERBOSE
|
|
std::cout << "SERVER OPTIONS: " << sp->options_string() << std::endl;
|
|
std::cout << "SERVER PEER INFO:" << std::endl;
|
|
std::cout << sp->peer_info_string();
|
|
#endif
|
|
|
|
TestProtoClient cli_proto(cp, cli_stats);
|
|
TestProtoServer serv_proto(sp, serv_stats);
|
|
|
|
for (int i = 0; i < SITER; ++i)
|
|
{
|
|
#ifdef VERBOSE
|
|
std::cout << "***** SITER " << i << std::endl;
|
|
#endif
|
|
cli_proto.reset();
|
|
serv_proto.reset();
|
|
|
|
NoisyWire client_to_server("Client -> Server", &time, rng_noncrypto, 8, 16, 32); // last value: 32
|
|
NoisyWire server_to_client("Server -> Client", &time, rng_noncrypto, 8, 16, 32); // last value: 32
|
|
|
|
int j = -1;
|
|
try {
|
|
#if FEEDBACK
|
|
// start feedback loop
|
|
cli_proto.initial_app_send(message);
|
|
serv_proto.start();
|
|
#else
|
|
cli_proto.app_send_templ_init(message);
|
|
serv_proto.app_send_templ_init(message);
|
|
#endif
|
|
|
|
// message loop
|
|
for (j = 0; j < ITER; ++j)
|
|
{
|
|
client_to_server.xfer(cli_proto, serv_proto);
|
|
server_to_client.xfer(serv_proto, cli_proto);
|
|
time += time_step;
|
|
}
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
std::cerr << "Exception[" << i << '/' << j << "]: " << e.what() << std::endl;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
cli_proto.finalize();
|
|
serv_proto.finalize();
|
|
|
|
const size_t ab = cli_proto.app_bytes() + serv_proto.app_bytes();
|
|
const size_t nb = cli_proto.net_bytes() + serv_proto.net_bytes();
|
|
const size_t db = cli_proto.data_bytes() + serv_proto.data_bytes();
|
|
|
|
std::cerr << "*** app bytes=" << ab
|
|
<< " net_bytes=" << nb
|
|
<< " data_bytes=" << db
|
|
<< " prog=" << cli_proto.progress() << '/' << serv_proto.progress()
|
|
#if !FEEDBACK
|
|
<< " CTRL=" << cli_proto.n_control_recv() << '/' << cli_proto.n_control_send() << '/' << serv_proto.n_control_recv() << '/' << serv_proto.n_control_send()
|
|
#endif
|
|
<< " D=" << cli_proto.control_drought().raw() << '/' << cli_proto.data_drought().raw() << '/' << serv_proto.control_drought().raw() << '/' << serv_proto.data_drought().raw()
|
|
<< " N=" << cli_proto.negotiations() << '/' << serv_proto.negotiations()
|
|
<< " SH=" << cli_proto.slowest_handshake().raw() << '/' << serv_proto.slowest_handshake().raw()
|
|
<< " HE=" << cli_stats->get_error_count(Error::HANDSHAKE_TIMEOUT) << '/' << serv_stats->get_error_count(Error::HANDSHAKE_TIMEOUT)
|
|
<< std::endl;
|
|
|
|
#ifdef STATS
|
|
std::cerr << "-------- CLIENT STATS --------" << std::endl;
|
|
cli_stats->show_error_counts();
|
|
std::cerr << "-------- SERVER STATS --------" << std::endl;
|
|
serv_stats->show_error_counts();
|
|
#endif
|
|
#ifdef OPENVPN_MAX_DATALIMIT_BYTES
|
|
std::cerr << "------------------------------" << std::endl;
|
|
std::cerr << "MAX_DATALIMIT_BYTES=" << DataLimit::max_bytes() << std::endl;
|
|
#endif
|
|
}
|
|
catch (const std::exception& e)
|
|
{
|
|
std::cerr << "Exception: " << e.what() << std::endl;
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int main(int argc, char* argv[])
|
|
{
|
|
int ret = 0;
|
|
// process-wide initialization
|
|
InitProcess::init();
|
|
|
|
// set global MbedTLS debug level
|
|
#if defined(USE_MBEDTLS)
|
|
mbedtls_debug_set_threshold(1);
|
|
#endif
|
|
|
|
if (argc >= 2 && !strcmp(argv[1], "test"))
|
|
{
|
|
const std::string out = SelfTest::crypto_self_test();
|
|
OPENVPN_LOG(out);
|
|
goto out;
|
|
}
|
|
|
|
#if N_THREADS >= 2
|
|
std::thread* threads[N_THREADS];
|
|
int i;
|
|
for (i = 0; i < N_THREADS; ++i)
|
|
{
|
|
threads[i] = new std::thread([i]() {
|
|
test(i);
|
|
});
|
|
}
|
|
for (i = 0; i < N_THREADS; ++i)
|
|
{
|
|
threads[i]->join();
|
|
delete threads[i];
|
|
}
|
|
#else
|
|
ret = test(1);
|
|
#endif
|
|
|
|
out:
|
|
InitProcess::uninit();
|
|
|
|
return ret;
|
|
}
|