2011-12-11 09:28:55 +01:00
|
|
|
#include <iostream>
|
|
|
|
#include <string>
|
|
|
|
#include <sstream>
|
|
|
|
#include <deque>
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cstring>
|
|
|
|
#include <limits>
|
|
|
|
|
2011-12-13 12:13:27 +01:00
|
|
|
// Unit test for OpenVPN protocol
|
|
|
|
|
2011-12-14 12:34:33 +01:00
|
|
|
#define OPENVPN_DEBUG
|
2011-12-13 05:46:56 +01:00
|
|
|
#define USE_TLS_AUTH
|
2011-12-11 09:28:55 +01:00
|
|
|
|
2011-12-13 12:13:27 +01:00
|
|
|
// number of threads to use for test
|
2011-12-13 05:46:56 +01:00
|
|
|
#ifndef N_THREADS
|
|
|
|
#define N_THREADS 1
|
|
|
|
#endif
|
|
|
|
|
2011-12-13 12:13:27 +01:00
|
|
|
// number of iterations
|
2011-12-13 05:46:56 +01:00
|
|
|
#ifndef ITER
|
|
|
|
#define ITER 1000000
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if !defined(VERBOSE) && ITER <= 10000
|
|
|
|
#define VERBOSE
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <openvpn/common/thread.hpp>
|
2011-12-11 09:28:55 +01:00
|
|
|
#include <openvpn/common/exception.hpp>
|
|
|
|
#include <openvpn/common/file.hpp>
|
|
|
|
#include <openvpn/time/time.hpp>
|
|
|
|
#include <openvpn/random/rand.hpp>
|
|
|
|
#include <openvpn/frame/frame.hpp>
|
|
|
|
#include <openvpn/ssl/proto.hpp>
|
|
|
|
|
|
|
|
#include <openvpn/openssl/ssl/sslctx.hpp>
|
|
|
|
#include <openvpn/openssl/util/init.hpp>
|
2011-12-13 05:46:56 +01:00
|
|
|
|
2011-12-11 09:28:55 +01:00
|
|
|
#ifdef USE_APPLE_SSL
|
|
|
|
#include <openvpn/applecrypto/ssl/sslctx.hpp>
|
|
|
|
#endif
|
|
|
|
|
2011-12-13 05:46:56 +01:00
|
|
|
#if OPENVPN_MULTITHREAD
|
|
|
|
#include <boost/bind.hpp>
|
2011-12-11 09:28:55 +01:00
|
|
|
#endif
|
|
|
|
|
2011-12-13 05:46:56 +01:00
|
|
|
using namespace openvpn;
|
2011-12-11 09:28:55 +01:00
|
|
|
|
|
|
|
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
|
|
|
|
;
|
|
|
|
|
2011-12-13 12:13:27 +01:00
|
|
|
// A "Drought" measures the maximum period of time between
|
|
|
|
// any two successive events. Used to measure worst-case
|
|
|
|
// packet loss.
|
2011-12-13 05:46:56 +01:00
|
|
|
class DroughtMeasure
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DroughtMeasure(TimePtr now_arg)
|
|
|
|
: now(now_arg)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void event()
|
|
|
|
{
|
|
|
|
if (last_event.defined())
|
|
|
|
{
|
|
|
|
Time::Duration since_last = *now - last_event;
|
|
|
|
if (since_last > drought)
|
|
|
|
drought = since_last;
|
|
|
|
}
|
|
|
|
last_event = *now;
|
|
|
|
}
|
|
|
|
|
|
|
|
Time::Duration operator()() const { return drought; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
TimePtr now;
|
|
|
|
Time last_event;
|
|
|
|
Time::Duration drought;
|
|
|
|
};
|
|
|
|
|
2011-12-13 12:13:27 +01:00
|
|
|
// test the OpenVPN protocol implementation in ProtoContext
|
2011-12-11 09:28:55 +01:00
|
|
|
template <typename SSL_CONTEXT>
|
|
|
|
class TestProto : public ProtoContext<SSL_CONTEXT>
|
|
|
|
{
|
|
|
|
typedef ProtoContext<SSL_CONTEXT> Base;
|
|
|
|
|
|
|
|
using Base::start;
|
|
|
|
using Base::now;
|
|
|
|
using Base::server;
|
|
|
|
|
|
|
|
public:
|
|
|
|
using Base::flush;
|
|
|
|
|
|
|
|
typedef typename Base::PacketType PacketType;
|
|
|
|
|
|
|
|
TestProto(const typename Base::Config::Ptr& config,
|
|
|
|
const ProtoStats::Ptr& stats)
|
|
|
|
: Base(config, stats),
|
2011-12-13 05:46:56 +01:00
|
|
|
control_drought(config->now),
|
|
|
|
data_drought(config->now),
|
2011-12-11 09:28:55 +01:00
|
|
|
frame(config->frame),
|
|
|
|
app_bytes_(0),
|
|
|
|
net_bytes_(0),
|
|
|
|
data_bytes_(0)
|
|
|
|
{
|
|
|
|
// zero progress value
|
|
|
|
std::memset(progress_, 0, 11);
|
|
|
|
}
|
|
|
|
|
|
|
|
void control_send(BufferPtr& app_bp)
|
|
|
|
{
|
|
|
|
app_bytes_ += app_bp->size();
|
|
|
|
Base::control_send(app_bp);
|
|
|
|
}
|
|
|
|
|
|
|
|
void control_send(BufferAllocated& app_buf)
|
|
|
|
{
|
|
|
|
app_bytes_ += app_buf.size();
|
|
|
|
Base::control_send(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);
|
2011-12-13 05:46:56 +01:00
|
|
|
if (in_out.size())
|
2011-12-14 12:34:33 +01:00
|
|
|
{
|
|
|
|
data_bytes_ += in_out.size();
|
|
|
|
data_drought.event();
|
|
|
|
}
|
2011-12-11 09:28:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
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);
|
2011-12-13 05:46:56 +01:00
|
|
|
flush(true);
|
2011-12-11 09:28:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t net_bytes() const { return net_bytes_; }
|
|
|
|
size_t app_bytes() const { return app_bytes_; }
|
|
|
|
size_t data_bytes() const { return data_bytes_; }
|
|
|
|
|
|
|
|
const char *progress() const { return progress_; }
|
|
|
|
|
2011-12-13 05:46:56 +01:00
|
|
|
void finalize()
|
|
|
|
{
|
|
|
|
data_drought.event();
|
|
|
|
control_drought.event();
|
|
|
|
}
|
|
|
|
|
2011-12-11 09:28:55 +01:00
|
|
|
std::deque<BufferPtr> net_out;
|
|
|
|
|
2011-12-13 05:46:56 +01:00
|
|
|
DroughtMeasure control_drought;
|
|
|
|
DroughtMeasure data_drought;
|
|
|
|
|
2011-12-11 09:28:55 +01:00
|
|
|
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() << " " << (server() ? "SERVER" : "CLIENT") << " " << show << std::endl;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
modmsg(work);
|
|
|
|
control_send(work);
|
2011-12-13 05:46:56 +01:00
|
|
|
control_drought.event();
|
2011-12-11 09:28:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void modmsg(BufferPtr& buf)
|
|
|
|
{
|
|
|
|
char *msg = (char *) buf->data();
|
|
|
|
if (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_;
|
|
|
|
size_t net_bytes_;
|
|
|
|
size_t data_bytes_;
|
|
|
|
char progress_[11];
|
|
|
|
};
|
|
|
|
|
2011-12-14 17:20:07 +01:00
|
|
|
template <typename SSL_CONTEXT>
|
|
|
|
class TestProtoClient : public TestProto<SSL_CONTEXT>
|
|
|
|
{
|
|
|
|
typedef TestProto<SSL_CONTEXT> Base;
|
|
|
|
public:
|
|
|
|
TestProtoClient(const typename Base::Config::Ptr& config,
|
|
|
|
const ProtoStats::Ptr& stats)
|
|
|
|
: Base(config, stats)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
virtual void client_auth(Buffer& buf)
|
|
|
|
{
|
|
|
|
const std::string username("foo");
|
|
|
|
const std::string password("bar");
|
|
|
|
Base::write_string(username, buf);
|
|
|
|
Base::write_string(password, buf);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
template <typename SSL_CONTEXT>
|
|
|
|
class TestProtoServer : public TestProto<SSL_CONTEXT>
|
|
|
|
{
|
|
|
|
typedef TestProto<SSL_CONTEXT> Base;
|
|
|
|
public:
|
|
|
|
OPENVPN_SIMPLE_EXCEPTION(auth_failed);
|
|
|
|
|
|
|
|
TestProtoServer(const typename Base::Config::Ptr& config,
|
|
|
|
const ProtoStats::Ptr& stats)
|
|
|
|
: Base(config, stats)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
virtual void server_auth(Buffer& buf, const std::string& peer_info)
|
|
|
|
{
|
|
|
|
const std::string username = Base::template read_string<std::string>(buf);
|
|
|
|
const std::string password = Base::template read_string<std::string>(buf);
|
|
|
|
|
|
|
|
#ifdef VERBOSE
|
|
|
|
std::cout << "**** AUTHENTICATE " << username << '/' << password << " PEER INFO:" << std::endl;
|
|
|
|
std::cout << peer_info;
|
|
|
|
#endif
|
|
|
|
if (username != "foo" || password != "bar")
|
|
|
|
throw auth_failed();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2011-12-13 12:13:27 +01:00
|
|
|
// Simulate a noisy transmission channel where packets can be dropped,
|
|
|
|
// reordered, or corrupted.
|
2011-12-11 09:28:55 +01:00
|
|
|
class NoisyWire
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NoisyWire(const std::string title_arg,
|
|
|
|
TimePtr now_arg,
|
|
|
|
RandomIntBase& 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)
|
|
|
|
{
|
|
|
|
// need to retransmit?
|
|
|
|
if (*now >= a.next_retransmit())
|
|
|
|
{
|
|
|
|
#ifdef VERBOSE
|
|
|
|
std::cout << now->raw() << " " << title << " Retransmitting" << std::endl;
|
|
|
|
#endif
|
|
|
|
a.retransmit();
|
2011-12-13 05:46:56 +01:00
|
|
|
a.flush(true);
|
2011-12-11 09:28:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// queue a data channel packet
|
|
|
|
if (a.data_channel_ready())
|
|
|
|
{
|
|
|
|
BufferPtr bp = a.data_encrypt_string("Waiting for godot...");
|
|
|
|
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())
|
2011-12-13 05:46:56 +01:00
|
|
|
{
|
|
|
|
#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, bp);
|
|
|
|
}
|
2011-12-11 09:28:55 +01:00
|
|
|
else if (pt.is_data())
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
b.data_decrypt(pt, *bp);
|
|
|
|
#ifdef VERBOSE
|
|
|
|
if (bp->size())
|
|
|
|
{
|
|
|
|
const std::string show((char *)bp->data(), bp->size());
|
2011-12-13 05:46:56 +01:00
|
|
|
std::cout << now->raw() << " " << title << " DATA CHANNEL DECRYPT: " << show << std::endl;
|
2011-12-11 09:28:55 +01:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
#ifdef VERBOSE
|
|
|
|
std::cout << now->raw() << " " << title << " Exception on data channel decrypt: " << e.what() << std::endl;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-13 05:46:56 +01:00
|
|
|
b.flush(true);
|
2011-12-11 09:28:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
BufferPtr recv()
|
|
|
|
{
|
|
|
|
// 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]);
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
|
// simulate dropped packet
|
|
|
|
if (!rand(drop_prob))
|
|
|
|
{
|
|
|
|
#ifdef VERBOSE
|
|
|
|
std::cout << now->raw() << " " << title << " Simulating a dropped packet" << std::endl;
|
|
|
|
#endif
|
|
|
|
return BufferPtr();
|
|
|
|
}
|
|
|
|
|
|
|
|
// simulate corrupted packet
|
2011-12-13 05:46:56 +01:00
|
|
|
if (bp->size() && !rand(corrupt_prob))
|
2011-12-11 09:28:55 +01:00
|
|
|
{
|
|
|
|
#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;
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
RandomIntBase& random;
|
|
|
|
unsigned int reorder_prob;
|
|
|
|
unsigned int drop_prob;
|
|
|
|
unsigned int corrupt_prob;
|
|
|
|
std::deque<BufferPtr> wire;
|
|
|
|
};
|
|
|
|
|
2011-12-13 12:13:27 +01:00
|
|
|
// execute the unit test in one thread
|
2011-12-13 05:46:56 +01:00
|
|
|
void test(const int thread_num)
|
2011-12-11 09:28:55 +01:00
|
|
|
{
|
|
|
|
try {
|
|
|
|
// frame
|
|
|
|
Frame::Ptr frame(new Frame(Frame::Context(128, 256, 128, 0, 16, 0)));
|
|
|
|
|
|
|
|
// RNG
|
|
|
|
RandomInt rand;
|
|
|
|
PRNG::Ptr prng(new PRNG("sha1", 16));
|
|
|
|
|
|
|
|
// init simulated time
|
|
|
|
Time time;
|
|
|
|
const Time::Duration time_step = Time::Duration::binary_ms(100);
|
|
|
|
|
|
|
|
// client config files
|
|
|
|
const std::string ca1_crt = read_text("ca1.crt");
|
|
|
|
const std::string ca2_crt = read_text("ca2.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
|
|
|
|
SSLConfig cc;
|
|
|
|
#ifdef USE_APPLE_SSL
|
|
|
|
typedef AppleSSLContext ClientSSLContext;
|
|
|
|
cc.identity = "etest";
|
|
|
|
#else
|
|
|
|
typedef OpenSSLContext ClientSSLContext;
|
|
|
|
cc.ca = ca1_crt + ca2_crt;
|
|
|
|
cc.cert = client_crt;
|
|
|
|
cc.pkey = client_key;
|
|
|
|
#endif
|
|
|
|
cc.mode = SSLConfig::CLIENT;
|
|
|
|
#ifdef VERBOSE
|
|
|
|
cc.flags = SSLConfig::DEBUG;
|
|
|
|
#endif
|
|
|
|
cc.frame = frame;
|
|
|
|
|
|
|
|
// client stats
|
|
|
|
ProtoStats::Ptr cli_stats(new ProtoStats);
|
|
|
|
|
|
|
|
// client ProtoContext config
|
|
|
|
typedef ProtoContext<ClientSSLContext> ClientProtoContext;
|
|
|
|
ClientProtoContext::Config::Ptr cp(new ClientProtoContext::Config);
|
|
|
|
cp->ssl_ctx.reset(new ClientSSLContext(cc));
|
|
|
|
cp->frame = frame;
|
|
|
|
cp->now = &time;
|
|
|
|
cp->prng = prng;
|
2011-12-14 12:34:33 +01:00
|
|
|
cp->protocol = Protocol(Protocol::UDPv4);
|
|
|
|
cp->layer = Layer(Layer::OSI_LAYER_3);
|
|
|
|
cp->comp_ctx = CompressContext(CompressContext::LZO_STUB);
|
|
|
|
cp->cipher = Cipher("AES-256-CBC");
|
2011-12-11 09:28:55 +01:00
|
|
|
cp->digest = Digest("SHA1");
|
2011-12-13 05:46:56 +01:00
|
|
|
#ifdef USE_TLS_AUTH
|
2011-12-11 09:28:55 +01:00
|
|
|
cp->tls_auth_key.parse(tls_auth_key);
|
|
|
|
cp->tls_auth_digest = Digest("sha1");
|
2011-12-13 05:46:56 +01:00
|
|
|
#endif
|
2011-12-11 09:28:55 +01:00
|
|
|
cp->reliable_window = 4;
|
|
|
|
cp->max_ack_list = 4;
|
|
|
|
cp->pid_mode = PacketIDReceive::UDP_MODE;
|
|
|
|
cp->pid_seq_backtrack = 64;
|
|
|
|
cp->pid_time_backtrack = 30;
|
|
|
|
cp->pid_debug_level = PacketIDReceive::DEBUG_QUIET;
|
2011-12-13 05:46:56 +01:00
|
|
|
cp->handshake_window = Time::Duration::seconds(30);
|
|
|
|
cp->become_primary = Time::Duration::seconds(30);
|
|
|
|
cp->renegotiate = Time::Duration::seconds(95);
|
|
|
|
cp->expire = Time::Duration::seconds(150);
|
2011-12-11 09:28:55 +01:00
|
|
|
|
2011-12-14 12:34:33 +01:00
|
|
|
#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
|
|
|
|
|
2011-12-11 09:28:55 +01:00
|
|
|
// server config
|
|
|
|
SSLConfig sc;
|
|
|
|
typedef OpenSSLContext ServerSSLContext;
|
|
|
|
sc.mode = SSLConfig::SERVER;
|
|
|
|
#ifdef VERBOSE
|
|
|
|
sc.flags = SSLConfig::DEBUG;
|
|
|
|
#endif
|
|
|
|
sc.ca = ca1_crt + ca2_crt;
|
|
|
|
sc.cert = server_crt;
|
|
|
|
sc.pkey = server_key;
|
|
|
|
sc.dh = dh_pem;
|
|
|
|
sc.frame = frame;
|
|
|
|
|
|
|
|
// server ProtoContext config
|
|
|
|
typedef ProtoContext<ServerSSLContext> ServerProtoContext;
|
|
|
|
ServerProtoContext::Config::Ptr sp(new ServerProtoContext::Config);
|
|
|
|
sp->ssl_ctx.reset(new ServerSSLContext(sc));
|
|
|
|
sp->frame = frame;
|
|
|
|
sp->now = &time;
|
|
|
|
sp->prng = prng;
|
2011-12-14 12:34:33 +01:00
|
|
|
sp->protocol = Protocol(Protocol::UDPv4);
|
|
|
|
sp->layer = Layer(Layer::OSI_LAYER_3);
|
|
|
|
sp->comp_ctx = CompressContext(CompressContext::LZO_STUB);
|
|
|
|
sp->cipher = Cipher("AES-256-CBC");
|
2011-12-11 09:28:55 +01:00
|
|
|
sp->digest = Digest("SHA1");
|
2011-12-13 05:46:56 +01:00
|
|
|
#ifdef USE_TLS_AUTH
|
2011-12-11 09:28:55 +01:00
|
|
|
sp->tls_auth_key.parse(tls_auth_key);
|
|
|
|
sp->tls_auth_digest = Digest("sha1");
|
2011-12-13 05:46:56 +01:00
|
|
|
#endif
|
2011-12-11 09:28:55 +01:00
|
|
|
sp->reliable_window = 4;
|
|
|
|
sp->max_ack_list = 4;
|
|
|
|
sp->pid_mode = PacketIDReceive::UDP_MODE;
|
|
|
|
sp->pid_seq_backtrack = 64;
|
|
|
|
sp->pid_time_backtrack = 30;
|
|
|
|
sp->pid_debug_level = PacketIDReceive::DEBUG_QUIET;
|
2011-12-13 05:46:56 +01:00
|
|
|
sp->handshake_window = Time::Duration::seconds(30); // 30
|
|
|
|
sp->become_primary = Time::Duration::seconds(30); // 60
|
|
|
|
sp->renegotiate = Time::Duration::seconds(90); // 90
|
|
|
|
sp->expire = Time::Duration::seconds(150); // 150
|
2011-12-11 09:28:55 +01:00
|
|
|
|
2011-12-14 12:34:33 +01:00
|
|
|
#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
|
|
|
|
|
2011-12-11 09:28:55 +01:00
|
|
|
// server stats
|
|
|
|
ProtoStats::Ptr serv_stats(new ProtoStats);
|
|
|
|
|
2011-12-14 17:20:07 +01:00
|
|
|
TestProtoClient<ClientSSLContext> cli_proto(cp, cli_stats);
|
|
|
|
TestProtoServer<OpenSSLContext> serv_proto(sp, serv_stats);
|
2011-12-13 05:46:56 +01:00
|
|
|
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
|
2011-12-11 09:28:55 +01:00
|
|
|
|
|
|
|
// start feedback loop
|
|
|
|
cli_proto.initial_app_send(message);
|
|
|
|
|
|
|
|
// 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;
|
|
|
|
}
|
|
|
|
|
2011-12-13 05:46:56 +01:00
|
|
|
cli_proto.finalize();
|
|
|
|
serv_proto.finalize();
|
|
|
|
|
2011-12-11 09:28:55 +01:00
|
|
|
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();
|
|
|
|
|
2011-12-13 05:46:56 +01:00
|
|
|
std::cout << "*** app bytes=" << ab
|
|
|
|
<< " net_bytes=" << nb
|
|
|
|
<< " data_bytes=" << db
|
|
|
|
<< " prog=" << cli_proto.progress() << '/' << serv_proto.progress()
|
|
|
|
<< " 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()
|
|
|
|
<< " F=" << cli_proto.negotiation_fails() << '/' << serv_proto.negotiation_fails()
|
|
|
|
<< std::endl;
|
2011-12-11 09:28:55 +01:00
|
|
|
}
|
|
|
|
catch (std::exception& e)
|
|
|
|
{
|
|
|
|
std::cerr << "Exception: " << e.what() << std::endl;
|
|
|
|
}
|
2011-12-13 05:46:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
int main(int /*argc*/, char* /*argv*/[])
|
|
|
|
{
|
|
|
|
Time::reset_base();
|
|
|
|
openssl_init ossl_init;
|
|
|
|
|
|
|
|
#if N_THREADS >= 2 && OPENVPN_MULTITHREAD
|
|
|
|
boost::thread* threads[N_THREADS];
|
|
|
|
size_t i;
|
|
|
|
for (i = 0; i < N_THREADS; ++i)
|
|
|
|
{
|
|
|
|
threads[i] = new boost::thread(boost::bind(&test, i));
|
|
|
|
}
|
|
|
|
for (i = 0; i < N_THREADS; ++i)
|
|
|
|
{
|
|
|
|
threads[i]->join();
|
|
|
|
delete threads[i];
|
|
|
|
}
|
|
|
|
#else
|
|
|
|
test(1);
|
|
|
|
#endif
|
2011-12-11 09:28:55 +01:00
|
|
|
return 0;
|
|
|
|
}
|