mirror of
https://github.com/OpenVPN/openvpn3.git
synced 2024-09-20 04:02:15 +02:00
ProtoContext object can now be reused via reset() method.
Fixed rare bug where client receives auth, goes ACTIVE, but the ACK response back to the server is dropped causing the server to receive post-ACTIVE app messages from the client while it's still stuck in the S_WAIT_AUTH_ACK state.
This commit is contained in:
parent
6260957c37
commit
fb163b65f4
@ -977,6 +977,7 @@ namespace openvpn {
|
||||
send_auth();
|
||||
state = S_WAIT_AUTH_ACK;
|
||||
break;
|
||||
case S_WAIT_AUTH_ACK: // rare case where client receives auth, goes ACTIVE, but the ACK response is dropped
|
||||
case ACTIVE:
|
||||
proto.app_recv(key_id_, to_app_buf);
|
||||
break;
|
||||
@ -1032,6 +1033,7 @@ namespace openvpn {
|
||||
write_auth_string(peer_info, *buf);
|
||||
}
|
||||
Base::app_send(buf);
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
void recv_auth(BufferAllocated& buf)
|
||||
@ -1059,6 +1061,7 @@ namespace openvpn {
|
||||
{
|
||||
Base::app_send(app_pre_write_queue.front());
|
||||
app_pre_write_queue.pop_front();
|
||||
dirty = true;
|
||||
}
|
||||
reached_active_time_ = *now;
|
||||
proto.slowest_handshake_.max(reached_active_time_ - construct_time);
|
||||
@ -1370,9 +1373,7 @@ namespace openvpn {
|
||||
const ProtoStats::Ptr& stats_arg) // error stats
|
||||
: config(config_arg),
|
||||
stats(stats_arg),
|
||||
hmac_size(0),
|
||||
use_tls_auth(false),
|
||||
upcoming_key_id(0),
|
||||
server_(config_arg->ssl_ctx->mode() == SSLConfig::SERVER),
|
||||
n_key_ids(0),
|
||||
now_(config_arg->now),
|
||||
keepalive_ping(config_arg->keepalive_ping),
|
||||
@ -1380,9 +1381,6 @@ namespace openvpn {
|
||||
{
|
||||
const Config& c = *config;
|
||||
|
||||
// determine client/server status
|
||||
server_ = (c.ssl_ctx->mode() == SSLConfig::SERVER);
|
||||
|
||||
// tls-auth setup
|
||||
if (c.tls_auth_key.defined())
|
||||
{
|
||||
@ -1390,7 +1388,29 @@ namespace openvpn {
|
||||
|
||||
// get HMAC size from Digest object
|
||||
hmac_size = c.tls_auth_digest.size();
|
||||
}
|
||||
else
|
||||
{
|
||||
use_tls_auth = false;
|
||||
hmac_size = 0;
|
||||
}
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
const Config& c = *config;
|
||||
|
||||
// clear key contexts
|
||||
primary.reset();
|
||||
secondary.reset();
|
||||
|
||||
// start with key ID 0
|
||||
upcoming_key_id = 0;
|
||||
|
||||
// tls-auth initialization
|
||||
if (use_tls_auth)
|
||||
{
|
||||
// init tls_auth hmac
|
||||
const unsigned int key_dir = server_ ? OpenVPNStaticKey::NORMAL : OpenVPNStaticKey::INVERSE;
|
||||
ta_hmac_send.init(c.tls_auth_digest, c.tls_auth_key.slice(OpenVPNStaticKey::HMAC | OpenVPNStaticKey::ENCRYPT | key_dir));
|
||||
@ -1408,8 +1428,9 @@ namespace openvpn {
|
||||
|
||||
// initialize proto session ID
|
||||
psid_self.randomize(*c.prng);
|
||||
psid_peer.reset();
|
||||
|
||||
// initialize primary key context
|
||||
// initialize key contexts
|
||||
primary.reset(new KeyContext(*this, !server_));
|
||||
|
||||
// initialize keepalive timers
|
||||
@ -1755,6 +1776,7 @@ namespace openvpn {
|
||||
switch (ev)
|
||||
{
|
||||
case KeyContext::KEV_ACTIVE:
|
||||
OPENVPN_LOG_PROTO("*** SESSION_ACTIVE");
|
||||
active();
|
||||
break;
|
||||
case KeyContext::KEV_RENEGOTIATE:
|
||||
|
@ -18,8 +18,13 @@ namespace openvpn {
|
||||
};
|
||||
|
||||
ProtoSessionID()
|
||||
: defined_(false)
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
defined_ = false;
|
||||
std::memset(id_, 0, SIZE);
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,8 @@ if [ -z "$1" ]; then
|
||||
echo " STRIP=1 -- strip binary"
|
||||
echo " LTO=1 -- build with LTO"
|
||||
echo " GPROF=1 -- build for gprof profiling"
|
||||
echo " PGEN=1 -- generate data for profile-guided optimization"
|
||||
echo " PUSE=1 -- use data from previous run of PGEN=1 build"
|
||||
echo " OSSL=1 -- include OpenSSL on Mac"
|
||||
echo " SSL_BOTH=1 -- include OpenSSL and Apple SSL on Mac"
|
||||
echo " NOTHREADS=1 -- disable threads"
|
||||
@ -17,6 +19,9 @@ fi
|
||||
# remove previous build
|
||||
rm -f $1
|
||||
|
||||
# build flags
|
||||
FLAGS=""
|
||||
|
||||
# special Mac settings
|
||||
if [ "$PLATFORM" = "mac" ]; then
|
||||
# On Mac, only link with OpenSSL if OSSL is defined.
|
||||
@ -41,21 +46,27 @@ fi
|
||||
# boost link libraries
|
||||
BOOST_LIBS="-lboost_system"
|
||||
if [ "$NOTHREADS" = "1" ]; then
|
||||
THREAD_FLAGS="-DBOOST_DISABLE_THREADS"
|
||||
FLAGS="$FLAGS -DBOOST_DISABLE_THREADS"
|
||||
else
|
||||
BOOST_LIBS="$BOOST_LIBS -lboost_thread"
|
||||
THREAD_FLAGS="-pthread"
|
||||
FLAGS="$FLAGS -pthread"
|
||||
fi
|
||||
|
||||
# profile-guided optimization
|
||||
if [ "$PGEN" = "1" ]; then
|
||||
FLAGS="$FLAGS -fprofile-generate"
|
||||
elif [ "$PUSE" = "1" ]; then
|
||||
FLAGS="$FLAGS -fprofile-use"
|
||||
fi
|
||||
|
||||
if [ "$DEBUG" = "1" ]; then
|
||||
# debug build
|
||||
CMD="g++ -Wall -g $THREAD_FLAGS $GCC_EXTRA -I$BOOST -I$OVPN3 -L$BOOST/stage/lib $1.cpp -o $1 $BOOST_LIBS $CRYPTO_LIBS"
|
||||
CMD="g++ -Wall -g $FLAGS $GCC_EXTRA -I$BOOST -I$OVPN3 -L$BOOST/stage/lib $1.cpp -o $1 $BOOST_LIBS $CRYPTO_LIBS"
|
||||
else
|
||||
# release build
|
||||
FLAGS=""
|
||||
[ "$LTO" = "1" ] && FLAGS="$FLAGS -flto=4 -Wl,--no-as-needed"
|
||||
[ "$GPROF" = "1" ] && FLAGS="$FLAGS -pg"
|
||||
CMD="g++ -Wall -O3 -fwhole-program $FLAGS $THREAD_FLAGS $GCC_EXTRA -I$BOOST -I$OVPN3 -L$BOOST/stage/lib $1.cpp -o $1 $BOOST_LIBS $CRYPTO_LIBS"
|
||||
CMD="g++ -Wall -O3 -fwhole-program $FLAGS $GCC_EXTRA -I$BOOST -I$OVPN3 -L$BOOST/stage/lib $1.cpp -o $1 $BOOST_LIBS $CRYPTO_LIBS"
|
||||
fi
|
||||
|
||||
# execute CMD
|
||||
|
@ -21,6 +21,14 @@
|
||||
#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) && ITER <= 10000
|
||||
#define VERBOSE
|
||||
#endif
|
||||
@ -91,8 +99,10 @@ const char message[] =
|
||||
class DroughtMeasure
|
||||
{
|
||||
public:
|
||||
DroughtMeasure(TimePtr now_arg)
|
||||
: now(now_arg)
|
||||
OPENVPN_SIMPLE_EXCEPTION(drought_limit_exceeded);
|
||||
|
||||
DroughtMeasure(const std::string& name_arg, TimePtr now_arg)
|
||||
: now(now_arg), name(name_arg)
|
||||
{
|
||||
}
|
||||
|
||||
@ -102,7 +112,21 @@ public:
|
||||
{
|
||||
Time::Duration since_last = *now - last_event;
|
||||
if (since_last > drought)
|
||||
drought = since_last;
|
||||
{
|
||||
drought = since_last;
|
||||
#if defined(VERBOSE) || defined(DROUGHT_LIMIT)
|
||||
{
|
||||
const unsigned int r = drought.raw();
|
||||
#ifdef 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;
|
||||
}
|
||||
@ -113,6 +137,7 @@ private:
|
||||
TimePtr now;
|
||||
Time last_event;
|
||||
Time::Duration drought;
|
||||
std::string name;
|
||||
};
|
||||
|
||||
// test the OpenVPN protocol implementation in ProtoContext
|
||||
@ -121,7 +146,6 @@ class TestProto : public ProtoContext<SSL_CONTEXT>
|
||||
{
|
||||
typedef ProtoContext<SSL_CONTEXT> Base;
|
||||
|
||||
using Base::start;
|
||||
using Base::now;
|
||||
using Base::server;
|
||||
|
||||
@ -133,8 +157,8 @@ public:
|
||||
TestProto(const typename Base::Config::Ptr& config,
|
||||
const ProtoStats::Ptr& stats)
|
||||
: Base(config, stats),
|
||||
control_drought(config->now),
|
||||
data_drought(config->now),
|
||||
control_drought("control", config->now),
|
||||
data_drought("data", config->now),
|
||||
frame(config->frame),
|
||||
app_bytes_(0),
|
||||
net_bytes_(0),
|
||||
@ -144,6 +168,23 @@ public:
|
||||
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);
|
||||
BufferAllocated app_buf((unsigned char *)msg, msglen, 0);
|
||||
copy_progress(app_buf);
|
||||
control_send(app_buf);
|
||||
flush(true);
|
||||
}
|
||||
|
||||
bool do_housekeeping()
|
||||
{
|
||||
if (now() >= Base::next_housekeeping())
|
||||
@ -191,16 +232,6 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void initial_app_send(const char *msg)
|
||||
{
|
||||
start();
|
||||
|
||||
const size_t msglen = std::strlen(msg);
|
||||
BufferAllocated app_buf((unsigned char *)msg, msglen, 0);
|
||||
control_send(app_buf);
|
||||
flush(true);
|
||||
}
|
||||
|
||||
size_t net_bytes() const { return net_bytes_; }
|
||||
size_t app_bytes() const { return app_bytes_; }
|
||||
size_t data_bytes() const { return data_bytes_; }
|
||||
@ -244,6 +275,12 @@ private:
|
||||
control_drought.event();
|
||||
}
|
||||
|
||||
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();
|
||||
@ -551,7 +588,11 @@ void test(const int thread_num)
|
||||
cp->pid_seq_backtrack = 64;
|
||||
cp->pid_time_backtrack = 30;
|
||||
cp->pid_debug_level = PacketIDReceive::DEBUG_QUIET;
|
||||
#if 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
|
||||
cp->become_primary = Time::Duration::seconds(30);
|
||||
cp->renegotiate = Time::Duration::seconds(95);
|
||||
cp->expire = Time::Duration::seconds(150);
|
||||
@ -599,7 +640,11 @@ void test(const int thread_num)
|
||||
sp->pid_seq_backtrack = 64;
|
||||
sp->pid_time_backtrack = 30;
|
||||
sp->pid_debug_level = PacketIDReceive::DEBUG_QUIET;
|
||||
#if SITER > 1
|
||||
sp->handshake_window = Time::Duration::seconds(30);
|
||||
#else
|
||||
sp->handshake_window = Time::Duration::seconds(17) + Time::Duration::binary_ms(512);
|
||||
#endif
|
||||
sp->become_primary = Time::Duration::seconds(30);
|
||||
sp->renegotiate = Time::Duration::seconds(90);
|
||||
sp->expire = Time::Duration::seconds(150);
|
||||
@ -617,18 +662,29 @@ void test(const int thread_num)
|
||||
|
||||
TestProtoClient<ClientSSLContext> cli_proto(cp, cli_stats);
|
||||
TestProtoServer<OpenSSLContext> serv_proto(sp, serv_stats);
|
||||
NoisyWire client_to_server("Client -> Server", &time, rand, 8, 16, 32); // last value: 32
|
||||
NoisyWire server_to_client("Server -> Client", &time, rand, 8, 16, 32); // last value: 32
|
||||
|
||||
// start feedback loop
|
||||
cli_proto.initial_app_send(message);
|
||||
|
||||
// message loop
|
||||
for (int j = 0; j < ITER; ++j)
|
||||
for (int i = 0; i < SITER; ++i)
|
||||
{
|
||||
client_to_server.xfer(cli_proto, serv_proto);
|
||||
server_to_client.xfer(serv_proto, cli_proto);
|
||||
time += time_step;
|
||||
#ifdef VERBOSE
|
||||
std::cout << "***** SITER " << i << std::endl;
|
||||
#endif
|
||||
cli_proto.reset();
|
||||
serv_proto.reset();
|
||||
|
||||
NoisyWire client_to_server("Client -> Server", &time, rand, 8, 16, 32); // last value: 32
|
||||
NoisyWire server_to_client("Server -> Client", &time, rand, 8, 16, 32); // last value: 32
|
||||
|
||||
// start feedback loop
|
||||
cli_proto.initial_app_send(message);
|
||||
serv_proto.start();
|
||||
|
||||
// message loop
|
||||
for (int j = 0; j < ITER; ++j)
|
||||
{
|
||||
client_to_server.xfer(cli_proto, serv_proto);
|
||||
server_to_client.xfer(serv_proto, cli_proto);
|
||||
time += time_step;
|
||||
}
|
||||
}
|
||||
|
||||
cli_proto.finalize();
|
||||
|
@ -1,6 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
./proto &
|
||||
./proto &
|
||||
./proto &
|
||||
./proto &
|
||||
./proto >log1 &
|
||||
./proto >log2 &
|
||||
./proto >log3 &
|
||||
./proto >log4 &
|
||||
wait
|
||||
for f in log1 log2 log3 log4 ; do
|
||||
echo "*************" $f
|
||||
tail -5 $f
|
||||
done
|
||||
|
Loading…
Reference in New Issue
Block a user