mirror of
https://github.com/OpenVPN/openvpn3.git
synced 2024-09-20 20:13:05 +02:00
Added "remote" option list handling.
Added ClientProtoTerminateCallback abstraction to ClientProto. Added ClientProto::Config for configuration parameters, rather than passing parameters individually to ClientProto constructor.
This commit is contained in:
parent
e7a5d9f55b
commit
f9ae757e1a
@ -2,7 +2,8 @@
|
||||
#define OPENVPN_CLIENT_CLIPROTO_H
|
||||
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/cstdint.hpp> // for boost::uint...
|
||||
#include <boost/algorithm/string.hpp> // for boost::algorithm::starts_with
|
||||
|
||||
#include <openvpn/tun/client/tunbase.hpp>
|
||||
#include <openvpn/transport/client/transbase.hpp>
|
||||
@ -21,7 +22,10 @@
|
||||
|
||||
namespace openvpn {
|
||||
|
||||
// OpenVPN client
|
||||
struct ClientProtoTerminateCallback {
|
||||
virtual void client_proto_terminate() = 0;
|
||||
};
|
||||
|
||||
template <typename SSL_CONTEXT>
|
||||
class ClientProto : public ProtoContext<SSL_CONTEXT>, TransportClientParent, TunClientParent
|
||||
{
|
||||
@ -32,6 +36,7 @@ namespace openvpn {
|
||||
|
||||
public:
|
||||
typedef boost::intrusive_ptr<ClientProto> Ptr;
|
||||
typedef typename Base::Config ProtoConfig;
|
||||
|
||||
OPENVPN_EXCEPTION(client_exception);
|
||||
OPENVPN_EXCEPTION(tun_exception);
|
||||
@ -39,28 +44,32 @@ namespace openvpn {
|
||||
OPENVPN_SIMPLE_EXCEPTION(session_invalidated);
|
||||
OPENVPN_SIMPLE_EXCEPTION(auth_failed);
|
||||
|
||||
struct Config {
|
||||
typename Base::Config::Ptr proto_context_config;
|
||||
TransportClientFactory::Ptr transport_factory;
|
||||
TunClientFactory::Ptr tun_factory;
|
||||
SessionStats::Ptr cli_stats;
|
||||
ClientEvent::Queue::Ptr cli_events;
|
||||
std::string username;
|
||||
std::string password;
|
||||
};
|
||||
|
||||
ClientProto(boost::asio::io_service& io_service_arg,
|
||||
const typename Base::Config::Ptr& config,
|
||||
const TransportClientFactory::Ptr& transport_factory_arg,
|
||||
const TunClientFactory::Ptr& tun_factory_arg,
|
||||
const SessionStats::Ptr& stats_arg,
|
||||
const ClientEvent::Queue::Ptr& cli_events_arg,
|
||||
const bool client_throw_arg,
|
||||
const std::string& username_arg,
|
||||
const std::string& password_arg)
|
||||
: Base(config, stats_arg),
|
||||
const Config& config,
|
||||
ClientProtoTerminateCallback* terminate_callback_arg)
|
||||
: Base(config.proto_context_config, config.cli_stats),
|
||||
io_service(io_service_arg),
|
||||
transport_factory(transport_factory_arg),
|
||||
tun_factory(tun_factory_arg),
|
||||
client_throw(client_throw_arg),
|
||||
transport_factory(config.transport_factory),
|
||||
tun_factory(config.tun_factory),
|
||||
terminate_callback(terminate_callback_arg),
|
||||
housekeeping_timer(io_service_arg),
|
||||
push_request_timer(io_service_arg),
|
||||
stopped(false),
|
||||
username(username_arg),
|
||||
password(password_arg),
|
||||
first_packet_received(false),
|
||||
username(config.username),
|
||||
password(config.password),
|
||||
first_packet_received_(false),
|
||||
sent_push_request(false),
|
||||
cli_events(cli_events_arg)
|
||||
cli_events(config.cli_events)
|
||||
{
|
||||
#ifdef OPENVPN_PACKET_LOG
|
||||
packet_log.open(OPENVPN_PACKET_LOG, std::ios::binary);
|
||||
@ -83,6 +92,8 @@ namespace openvpn {
|
||||
}
|
||||
#endif
|
||||
|
||||
bool first_packet_received() const { return first_packet_received_; }
|
||||
|
||||
void start()
|
||||
{
|
||||
// coarse wakeup range
|
||||
@ -95,26 +106,28 @@ namespace openvpn {
|
||||
|
||||
void stop_on_signal(const boost::system::error_code& error, int signal_number)
|
||||
{
|
||||
stop();
|
||||
stop(true);
|
||||
}
|
||||
|
||||
void stop()
|
||||
void stop(const bool call_terminate_callback)
|
||||
{
|
||||
if (!stopped)
|
||||
{
|
||||
stopped = true;
|
||||
housekeeping_timer.cancel();
|
||||
push_request_timer.cancel();
|
||||
if (tun)
|
||||
tun->stop();
|
||||
if (transport)
|
||||
transport->stop();
|
||||
stopped = true;
|
||||
if (terminate_callback && call_terminate_callback)
|
||||
terminate_callback->client_proto_terminate();
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~ClientProto()
|
||||
{
|
||||
stop();
|
||||
stop(false);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -128,11 +141,11 @@ namespace openvpn {
|
||||
Base::update_now();
|
||||
|
||||
// log connecting event (only on first packet received)
|
||||
if (!first_packet_received)
|
||||
if (!first_packet_received_)
|
||||
{
|
||||
ClientEvent::Base::Ptr ev = new ClientEvent::Connecting();
|
||||
cli_events->add_event(ev);
|
||||
first_packet_received = true;
|
||||
first_packet_received_ = true;
|
||||
}
|
||||
|
||||
// get packet type
|
||||
@ -241,13 +254,13 @@ namespace openvpn {
|
||||
|
||||
virtual void transport_error(const std::exception& err)
|
||||
{
|
||||
if (client_throw)
|
||||
throw transport_exception(err.what());
|
||||
else
|
||||
if (terminate_callback)
|
||||
{
|
||||
OPENVPN_LOG("Transport Error: " << err.what());
|
||||
stop();
|
||||
stop(true);
|
||||
}
|
||||
else
|
||||
throw transport_exception(err.what());
|
||||
}
|
||||
|
||||
void extract_auth_token(const OptionList& opt)
|
||||
@ -300,13 +313,13 @@ namespace openvpn {
|
||||
else if (boost::starts_with(msg, "AUTH_FAILED"))
|
||||
{
|
||||
Base::stat().error(Error::AUTH_FAIL);
|
||||
if (client_throw)
|
||||
throw auth_failed();
|
||||
else
|
||||
if (terminate_callback)
|
||||
{
|
||||
OPENVPN_LOG("AUTH_FAILED");
|
||||
stop();
|
||||
stop(true);
|
||||
}
|
||||
else
|
||||
throw auth_failed();
|
||||
}
|
||||
}
|
||||
|
||||
@ -336,13 +349,13 @@ namespace openvpn {
|
||||
|
||||
virtual void tun_error(const std::exception& err)
|
||||
{
|
||||
if (client_throw)
|
||||
throw tun_exception(err.what());
|
||||
else
|
||||
if (terminate_callback)
|
||||
{
|
||||
OPENVPN_LOG("TUN Error: " << err.what());
|
||||
stop();
|
||||
stop(true);
|
||||
}
|
||||
else
|
||||
throw tun_exception(err.what());
|
||||
}
|
||||
|
||||
// proto base class calls here to get auth credentials
|
||||
@ -405,13 +418,13 @@ namespace openvpn {
|
||||
Base::housekeeping();
|
||||
if (Base::invalidated())
|
||||
{
|
||||
if (client_throw)
|
||||
throw session_invalidated();
|
||||
else
|
||||
if (terminate_callback)
|
||||
{
|
||||
OPENVPN_LOG("Session invalidated");
|
||||
stop();
|
||||
stop(true);
|
||||
}
|
||||
else
|
||||
throw session_invalidated();
|
||||
}
|
||||
set_housekeeping_timer();
|
||||
}
|
||||
@ -443,13 +456,13 @@ namespace openvpn {
|
||||
|
||||
void process_exception(std::exception& e)
|
||||
{
|
||||
if (client_throw)
|
||||
throw client_exception(e.what());
|
||||
else
|
||||
if (terminate_callback)
|
||||
{
|
||||
OPENVPN_LOG("Client exception: " << e.what());
|
||||
stop();
|
||||
stop(true);
|
||||
}
|
||||
else
|
||||
throw client_exception(e.what());
|
||||
}
|
||||
|
||||
boost::asio::io_service& io_service;
|
||||
@ -460,7 +473,7 @@ namespace openvpn {
|
||||
TunClientFactory::Ptr tun_factory;
|
||||
TunClient::Ptr tun;
|
||||
|
||||
bool client_throw;
|
||||
ClientProtoTerminateCallback* terminate_callback;
|
||||
|
||||
CoarseTime housekeeping_schedule;
|
||||
AsioTimer housekeeping_timer;
|
||||
@ -472,7 +485,7 @@ namespace openvpn {
|
||||
std::string username;
|
||||
std::string password;
|
||||
|
||||
bool first_packet_received;
|
||||
bool first_packet_received_;
|
||||
bool sent_push_request;
|
||||
ClientEvent::Queue::Ptr cli_events;
|
||||
|
||||
|
@ -187,7 +187,7 @@ namespace openvpn {
|
||||
|
||||
const Option& get_first(const std::string& name) const
|
||||
{
|
||||
OptionList::IndexMap::const_iterator e = map_.find(name);
|
||||
IndexMap::const_iterator e = map_.find(name);
|
||||
if (e != map_.end() && !e->second.empty())
|
||||
return (*this)[e->second[0]];
|
||||
else
|
||||
@ -196,7 +196,7 @@ namespace openvpn {
|
||||
|
||||
const Option* get_ptr(const std::string& name) const
|
||||
{
|
||||
OptionList::IndexMap::const_iterator e = map_.find(name);
|
||||
IndexMap::const_iterator e = map_.find(name);
|
||||
if (e != map_.end() && !e->second.empty())
|
||||
{
|
||||
if (e->second.size() == 1)
|
||||
@ -217,6 +217,24 @@ namespace openvpn {
|
||||
OPENVPN_THROW(option_error, "option '" << name << "' not found");
|
||||
}
|
||||
|
||||
const IndexList& get_index(const std::string& name) const
|
||||
{
|
||||
IndexMap::const_iterator e = map_.find(name);
|
||||
if (e != map_.end() && !e->second.empty())
|
||||
return e->second;
|
||||
else
|
||||
OPENVPN_THROW(option_error, "option '" << name << "' not found");
|
||||
}
|
||||
|
||||
const IndexList* get_index_ptr(const std::string& name) const
|
||||
{
|
||||
IndexMap::const_iterator e = map_.find(name);
|
||||
if (e != map_.end() && !e->second.empty())
|
||||
return &e->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool exists(const std::string& name) const
|
||||
{
|
||||
const Option* o = get_ptr(name);
|
||||
|
70
openvpn/options/remotelist.hpp
Normal file
70
openvpn/options/remotelist.hpp
Normal file
@ -0,0 +1,70 @@
|
||||
#ifndef OPENVPN_OPTIONS_REMOTELIST_H
|
||||
#define OPENVPN_OPTIONS_REMOTELIST_H
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/common/options.hpp>
|
||||
#include <openvpn/common/rc.hpp>
|
||||
#include <openvpn/transport/protocol.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
|
||||
class RemoteList : public RC<thread_unsafe_refcount>
|
||||
{
|
||||
public:
|
||||
typedef boost::intrusive_ptr<RemoteList> Ptr;
|
||||
|
||||
struct Item
|
||||
{
|
||||
std::string server_host;
|
||||
std::string server_port;
|
||||
Protocol transport_protocol;
|
||||
};
|
||||
|
||||
RemoteList(const OptionList& opt)
|
||||
{
|
||||
const OptionList::IndexList& rem = opt.get_index("remote");
|
||||
for (OptionList::IndexList::const_iterator i = rem.begin(); i != rem.end(); i++)
|
||||
{
|
||||
Item e;
|
||||
const Option& o = opt[*i];
|
||||
e.server_host = o.get(1);
|
||||
e.server_port = o.get(2);
|
||||
e.transport_protocol = Protocol::parse(o.get(3));
|
||||
list.push_back(e);
|
||||
}
|
||||
}
|
||||
|
||||
// used to cycle through Item list
|
||||
const Item& modulo_ref(const size_t i) { return list[i % list.size()]; }
|
||||
|
||||
size_t size() const { return list.size(); }
|
||||
const Item& operator[](const size_t i) { return list[i]; }
|
||||
|
||||
#ifdef OPENVPN_DEBUG
|
||||
std::string debug_render() const
|
||||
{
|
||||
std::ostringstream out;
|
||||
for (size_t i = 0; i < list.size(); ++i)
|
||||
{
|
||||
const Item& e = list[i];
|
||||
out << '[' << i
|
||||
<< "] host=" << e.server_host
|
||||
<< " port=" << e.server_port
|
||||
<< " proto=" << e.transport_protocol.str()
|
||||
<< std::endl;
|
||||
}
|
||||
return out.str();
|
||||
}
|
||||
#endif
|
||||
|
||||
private:
|
||||
std::vector<Item> list;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -29,6 +29,7 @@
|
||||
#include <openvpn/transport/protocol.hpp>
|
||||
#include <openvpn/tun/layer.hpp>
|
||||
#include <openvpn/compress/compress.hpp>
|
||||
#include <openvpn/options/remotelist.hpp>
|
||||
|
||||
#ifdef OPENVPN_DEBUG_PROTO
|
||||
#define OPENVPN_LOG_PROTO(x) OPENVPN_LOG(x)
|
||||
@ -163,6 +164,7 @@ namespace openvpn {
|
||||
OPENVPN_SIMPLE_EXCEPTION(peer_psid_undef);
|
||||
OPENVPN_SIMPLE_EXCEPTION(bad_auth_prefix);
|
||||
OPENVPN_EXCEPTION(process_server_push_error);
|
||||
OPENVPN_EXCEPTION_INHERIT(option_error, proto_option_error);
|
||||
|
||||
static unsigned int mtu()
|
||||
{
|
||||
@ -249,24 +251,8 @@ namespace openvpn {
|
||||
keepalive_ping = Time::Duration::seconds(8);
|
||||
keepalive_timeout = Time::Duration::seconds(40);
|
||||
comp_ctx = CompressContext(CompressContext::NONE);
|
||||
|
||||
// tcp/udp
|
||||
{
|
||||
const Option& o = opt.get_first("remote");
|
||||
const std::string& proto = o.get(3);
|
||||
if (proto == "udp")
|
||||
{
|
||||
protocol = Protocol(Protocol::UDPv4);
|
||||
protocol = Protocol();
|
||||
pid_mode = PacketIDReceive::UDP_MODE;
|
||||
}
|
||||
else if (proto == "tcp")
|
||||
{
|
||||
protocol = Protocol(Protocol::TCPv4);
|
||||
pid_mode = PacketIDReceive::TCP_MODE;
|
||||
}
|
||||
else
|
||||
throw option_error("bad protocol");
|
||||
}
|
||||
|
||||
// layer
|
||||
{
|
||||
@ -276,7 +262,7 @@ namespace openvpn {
|
||||
else if (dev_type == "tap")
|
||||
layer = Layer(Layer::OSI_LAYER_2);
|
||||
else
|
||||
throw option_error("bad dev-type");
|
||||
throw proto_option_error("bad dev-type");
|
||||
}
|
||||
|
||||
// cipher
|
||||
@ -318,7 +304,7 @@ namespace openvpn {
|
||||
const std::string meth_name = (*o)[1];
|
||||
CompressContext::Type meth = CompressContext::parse_method(meth_name);
|
||||
if (meth == CompressContext::NONE)
|
||||
OPENVPN_THROW(option_error, "Unknown compressor: '" << meth_name << '\'');
|
||||
OPENVPN_THROW(proto_option_error, "Unknown compressor: '" << meth_name << '\'');
|
||||
comp_ctx = CompressContext(meth);
|
||||
}
|
||||
else
|
||||
@ -335,6 +321,7 @@ namespace openvpn {
|
||||
}
|
||||
}
|
||||
|
||||
// load options string pushed by server
|
||||
void process_push(const OptionList& opt)
|
||||
{
|
||||
// cipher
|
||||
@ -402,6 +389,24 @@ namespace openvpn {
|
||||
}
|
||||
}
|
||||
|
||||
void remote_adjust(const RemoteList::Item& rli)
|
||||
{
|
||||
// adjust options for new transport protocol
|
||||
protocol = rli.transport_protocol;
|
||||
if (protocol.is_udp())
|
||||
pid_mode = PacketIDReceive::UDP_MODE;
|
||||
else if (protocol.is_tcp())
|
||||
pid_mode = PacketIDReceive::TCP_MODE;
|
||||
else
|
||||
throw proto_option_error("transport protocol undefined");
|
||||
}
|
||||
|
||||
void validate_complete() const
|
||||
{
|
||||
if (!protocol.defined())
|
||||
throw proto_option_error("transport protocol undefined");
|
||||
}
|
||||
|
||||
// generate a string summarizing options that will be
|
||||
// transmitted to peer for options consistency check
|
||||
std::string options_string() const
|
||||
@ -1605,6 +1610,9 @@ namespace openvpn {
|
||||
{
|
||||
const Config& c = *config;
|
||||
|
||||
// validate options
|
||||
c.validate_complete();
|
||||
|
||||
// by default, fast_transition is turned off
|
||||
fast_transition = false;
|
||||
|
||||
|
@ -1,7 +1,13 @@
|
||||
#ifndef OPENVPN_TRANSPORT_PROTOCOL_H
|
||||
#define OPENVPN_TRANSPORT_PROTOCOL_H
|
||||
|
||||
#include <string>
|
||||
|
||||
#include <boost/cstdint.hpp> // for boost::uint32_t, etc.
|
||||
#include <boost/algorithm/string.hpp> // for boost::algorithm::to_lower
|
||||
|
||||
#include <openvpn/common/exception.hpp>
|
||||
#include <openvpn/common/options.hpp>
|
||||
|
||||
namespace openvpn {
|
||||
class Protocol
|
||||
@ -19,6 +25,8 @@ namespace openvpn {
|
||||
explicit Protocol(const Type t) : type_(t) {}
|
||||
Type operator()() const { return type_; }
|
||||
|
||||
bool defined() const { return type_ != NONE; }
|
||||
|
||||
bool is_udp() const { return type_ == UDPv4 || type_ == UDPv6; }
|
||||
bool is_tcp() const { return type_ == TCPv4 || type_ == TCPv6; }
|
||||
|
||||
@ -29,6 +37,35 @@ namespace openvpn {
|
||||
return is_tcp() ? sizeof(boost::uint16_t) : 0;
|
||||
}
|
||||
|
||||
static Protocol parse(const std::string& str)
|
||||
{
|
||||
Protocol ret;
|
||||
std::string s = str;
|
||||
boost::algorithm::to_lower(s);
|
||||
if (s.length() >= 3)
|
||||
{
|
||||
const std::string s1 = s.substr(0, 3);
|
||||
const std::string s2 = s.substr(3);
|
||||
if (s2 == "" || s2 == "4" || s2 == "v4")
|
||||
{
|
||||
if (s1 == "udp")
|
||||
ret.type_ = UDPv4;
|
||||
else if (s1 == "tcp")
|
||||
ret.type_ = TCPv4;
|
||||
}
|
||||
else if (s2 == "6" || s2 == "v6")
|
||||
{
|
||||
if (s1 == "udp")
|
||||
ret.type_ = UDPv6;
|
||||
else if (s1 == "tcp")
|
||||
ret.type_ = TCPv6;
|
||||
}
|
||||
}
|
||||
if (ret.type_ == NONE)
|
||||
OPENVPN_THROW(option_error, "error parsing protocol: " << s);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *str() const
|
||||
{
|
||||
switch (type_)
|
||||
|
Loading…
Reference in New Issue
Block a user