12#ifndef OPENVPN_CLIENT_CLIPROTO_H
13#define OPENVPN_CLIENT_CLIPROTO_H
35using namespace std::chrono_literals;
64#ifdef OPENVPN_DEBUG_CLIPROTO
65#define OPENVPN_LOG_CLIPROTO(x) OPENVPN_LOG(x)
67#define OPENVPN_LOG_CLIPROTO(x)
93 public RC<thread_unsafe_refcount>
118 ProfileParseLimits::MAX_PUSH_SIZE,
119 ProfileParseLimits::OPT_OVERHEAD,
120 ProfileParseLimits::TERM_OVERHEAD,
122 ProfileParseLimits::MAX_DIRECTIVE_SIZE)
142 Session(openvpn_io::io_context &io_context_arg,
165#ifdef OPENVPN_PACKET_LOG
166 packet_log.open(OPENVPN_PACKET_LOG, std::ios::binary);
168 OPENVPN_THROW(open_file_error,
"cannot open packet log for output: " << OPENVPN_PACKET_LOG);
174 info_hold.reset(
new std::vector<ClientEvent::Base::Ptr>());
269 void stop(
const bool call_terminate_callback)
381#ifdef OPENVPN_PACKET_LOG
382 log_packet(buf,
false);
421 catch (
const std::exception &e)
442#ifdef OPENVPN_PACKET_LOG
443 log_packet(buf,
true);
470 constexpr size_t MinTcpHeader = 20;
471 constexpr size_t MinIpHeader = 20;
472 size_t mss_no_tcp_ip_encap = c.
mss_fix + (MinTcpHeader + MinIpHeader);
474 if (df && c.
mss_fix > 0 && buf.
size() > mss_no_tcp_ip_encap)
500 catch (
const std::exception &e)
515 unsigned int &keepalive_timeout)
override
528 std::string server_host, server_port, server_proto, server_ip;
530 std::ostringstream
out;
531 out <<
'[' << server_host <<
"]:" << server_port <<
" (" << server_ip <<
") via " << server_proto;
558 catch (
const std::exception &e)
577 throw transport_exception(err_text);
593 throw proxy_exception(err_text);
598 std::string username;
613 const std::string &sess_id = o->
get(1, 256);
616 if (!username.empty())
618#ifdef OPENVPN_SHOW_SESSION_TOKEN
660 std::string::size_type reason_idx = 0;
661 auto endofflags =
msg.find(
']');
662 if (
msg.at(0) ==
'[' && endofflags != std::string::npos)
664 reason_idx = ++endofflags;
666 for (
const auto &flag :
flags)
670 std::istringstream f(flag);
675 OPENVPN_LOG(
"invalid AUTH_FAILED,TEMP flag: " << flag);
679 if (key ==
"backoff")
684 OPENVPN_LOG(
"invalid AUTH_FAILED,TEMP flag: " << flag);
686 temp_fail_backoff_ = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::seconds{timeout});
688 else if (key ==
"advance")
694 else if (value ==
"addr")
698 else if (value ==
"remote")
704 OPENVPN_LOG(
"unknown AUTH_FAILED,TEMP flag: " << flag);
709 OPENVPN_LOG(
"unknown AUTH_FAILED,TEMP flag: " << flag);
714 if (reason_idx >=
msg.size() ||
msg[reason_idx] !=
':')
718 return msg.substr(reason_idx + 1);
732 std::string log_reason;
735 if (
msg.length() >= 13)
744 bool password_defined =
false;
745 bool session_id_defined =
false;
756 if (session_id_defined)
758 bool reconnect =
false;
774 log_reason =
"SESSION_AUTH_FAILED";
781 log_reason =
"SESSION_EXPIRED";
789 log_reason =
"AUTH_FAILED";
799 throw authentication_failed();
809 std::string key_words;
811 unsigned int timeout = 0;
815 key_words =
msg.substr(strlen(
"AUTH_PENDING,"));
817 std::string timeout_str = opts.get_optional(
"timeout", 1, 20);
818 if (timeout_str !=
"")
822 timeout = clamp_to_typerange<unsigned int>(std::stoul(timeout_str));
826 catch (
const std::logic_error &)
828 OPENVPN_LOG(
"could not parse AUTH_PENDING timeout: " << timeout_str);
871 std::string info_msg;
874 info_msg =
msg.substr(std::string_view{
"INFO_PRE,"}.length());
876 info_msg =
msg.substr(std::string_view{
"INFO,"}.length());
914 auto opt_str =
msg.substr(strlen(
"PUSH_UPDATE,"));
938 const std::string
msg = ProtoContext::read_control_string<std::string>(*app_bp);
941 OPENVPN_LOG(
"Control channel message with invalid characters received, ignoring message");
971 else if (
msg ==
"RELAY")
1013 OPENVPN_LOG(
"App custom control message with unsupported protocol [" + proto +
"] received");
1026 if (msg_str.empty() ==
false)
1042 catch (std::exception &ex)
1044 OPENVPN_LOG(
"App custom control cert check exception: " << ex.what());
1068 catch (
const Option::RejectedException &e)
1113 throw tun_exception(
"not connected");
1190 ev->vpn_mtu = std::to_string(
tun->
vpn_mtu());
1194 ev->vpn_mtu =
"(default)";
1200 if (!client_ip.empty())
1203 catch (
const std::exception &e)
1205 OPENVPN_LOG(
"exception parsing client-ip: " << e.what());
1226 throw tun_exception(err_text);
1241#ifdef OPENVPN_DISABLE_AUTH_TOKEN
1270 const openvpn_io::error_code &e)
1301 const Time::Duration newdur = std::min(dur + Time::Duration::seconds(1),
1302 Time::Duration::seconds(3));
1308 catch (
const std::exception &e)
1322 self->send_push_request_callback(dur, error); });
1333 ClientEvent::Base::Ptr ev =
new ClientEvent::Warn(
"TLS: received certificate signed with MD5. Please inform your admin to upgrade to a stronger algorithm. Support for MD5 will be dropped in the near future");
1339 ClientEvent::Base::Ptr ev =
new ClientEvent::Warn(
"TLS: received certificate signed with SHA1. Please inform your admin to upgrade to a stronger algorithm. Support for SHA1 signatures will be dropped in the future");
1348 ClientEvent::Base::Ptr ev =
new ClientEvent::Warn(
"Proto: Using a 64-bit block cipher that is vulnerable to the SWEET32 attack. Please inform your admin to upgrade to a stronger algorithm. Support for 64-bit block cipher will be dropped in the future.");
1360 "settings that are not allowed and will result "
1361 "in a non-working connection. ");
1368 std::ostringstream
msg;
1370 ?
"Asymmetric compression enabled. Server may send compressed data."
1371 :
"Compression enabled.");
1372 msg <<
" This may be a potential security issue.";
1415 throw session_invalidated();
1420 catch (
const std::exception &e)
1442 self->housekeeping_callback(error); });
1473 { self->reset_inactive_timer(value); });
1478 { self->reset_inactive_timer(value); });
1483 catch (
const std::exception &e)
1485 OPENVPN_LOG(
"exception parsing inactive: " << e.what());
1492 inactive_timer.async_wait([self =
Ptr(
this)](
const openvpn_io::error_code &error)
1495 self->inactive_callback(error); });
1501 openvpn_io::post(
io_context, [self =
Ptr(
this), bytes_count]()
1505 self->inactivity_bytes += bytes_count;
1506 if (self->inactivity_bytes >= self->inactivity_minimum_bytes)
1509 self->inactivity_bytes = 0;
1510 self->schedule_inactive_timer();
1546 throw inactive_timer_expired();
1549 catch (
const std::exception &e)
1557 OptionList::IndexMap::const_iterator echo_opt = opt.
map().find(
"echo");
1558 if (echo_opt != opt.
map().end())
1560 for (OptionList::IndexList::const_iterator i = echo_opt->second.begin(); i != echo_opt->second.end(); ++i)
1562 const Option &o = opt[*i];
1564 const std::string &value = o.
get(1, 512);
1575 OPENVPN_LOG(
"Client exception in " << method_name <<
": " << e.what());
1579 throw client_exception(e.what());
1598 throw client_halt_restart(ch.
render());
1608 self->info_hold_callback(error); });
1626 catch (
const std::exception &exc)
1632#ifdef OPENVPN_PACKET_LOG
1633 void log_packet(
const Buffer &buf,
const bool out)
1637 std::uint16_t len = buf.
size() & 0x7FFF;
1640 packet_log.write((
const char *)&len,
sizeof(len));
1641 packet_log.write((
const char *)buf.
c_data(), buf.
size());
1700 std::unique_ptr<std::vector<ClientEvent::Base::Ptr>>
info_hold;
1710#ifdef OPENVPN_PACKET_LOG
1711 std::ofstream packet_log;
#define OPENVPN_ASYNC_HANDLER
bool receive_message(const std::string &msg)
std::pair< std::string, std::string > get_message()
std::size_t expires_at(const Time &t)
std::size_t expires_after(const Time::Duration &d)
size_t decode(void *data, size_t len, const std::string &str) const
bool password_defined() const
std::string get_password() const
bool password_needed() const
std::string auth_info() const
void set_need_user_interaction()
bool need_user_interaction() const
void set_session_id(const std::string &user, const std::string &sess_id)
std::string get_username() const
bool session_id_defined() const
void save_username_for_session_id()
std::string render() const
static bool match(const std::string &msg)
const std::string & reason() const
OPENVPN_EXCEPTION(transport_exception)
void recv_info(const std::string &msg, bool info_pre)
void stop_on_signal(const openvpn_io::error_code &error, int signal_number)
std::string parse_auth_failed_temp(const std::string &msg)
AccHandshaker certcheck_hs
void recv_custom_control_message(const std::string msg)
receive, validate, and dispatch ACC messages
void info_hold_callback(const openvpn_io::error_code &e)
std::unique_ptr< std::vector< ClientEvent::Base::Ptr > > info_hold
bool transport_is_openvpn_protocol() override
void control_recv(BufferPtr &&app_bp) override
AsioTimer info_hold_timer
void transport_recv(BufferAllocated &buf) override
void reset_inactive_timer(const count_t bytes_count)
void active(bool primary) override
Called when KeyContext transitions to ACTIVE state.
void recv_halt_restart(const std::string &msg)
static const std::string certcheckProto
openvpn_io::io_context & io_context
void housekeeping_callback(const openvpn_io::error_code &e)
void transport_wait() override
void start_acc_certcheck(SSLLib::SSLAPI::Config::Ptr config)
Start up the cert check handshake using the given certs and key.
TransportClient::Ptr transport
void schedule_push_request_callback(const Time::Duration &dur)
void recv_push_update(const std::string &msg)
Handles incoming PUSH_UPDATE message.
void control_net_send(const Buffer &net_buf) override
const std::string & fatal_reason() const
CoarseTime housekeeping_schedule
bool first_packet_received_
void tun_error(const Error::Type fatal_err, const std::string &err_text) override
TransportClientFactory::Ptr transport_factory_relay()
NotifyCallback * notify_callback
virtual void check_tls_warnings()
OptionList::Limits pushed_options_limit
void post_cc_msg(const std::string &msg)
unsigned int tcp_queue_limit
Session(openvpn_io::io_context &io_context_arg, const Config &config, NotifyCallback *notify_callback_arg)
std::string fatal_reason_
PushOptionsMerger::Ptr pushed_options_merger
RemoteList::Advance advance_type() const
void inactive_callback(const openvpn_io::error_code &e)
void transport_wait_proxy() override
void disable_keepalive(unsigned int &keepalive_ping, unsigned int &keepalive_timeout) override
void transport_factory_override(TransportClientFactory::Ptr factory)
void send_push_request_callback(const Time::Duration &dur, const openvpn_io::error_code &e)
OPENVPN_EXCEPTION(client_exception)
void tun_recv(BufferAllocated &buf) override
OptionList::FilterBase::Ptr pushed_options_filter
void tun_pre_tun_config() override
void check_proto_warnings()
void tun_event(ClientEvent::Base::Ptr ev) override
OPENVPN_SIMPLE_EXCEPTION(session_invalidated)
ClientEvent::Connected::Ptr connected_
AsioTimer housekeeping_timer
bool first_packet_received() const
ProtoContextCompressionOptions::Ptr proto_context_options
unsigned int inactivity_minimum_bytes
void transport_pre_resolve() override
OPENVPN_EXCEPTION(max_pushed_options_exceeded)
AsioTimer push_request_timer
void proxy_error(const Error::Type fatal_err, const std::string &err_text) override
void tun_set_disconnect()
OPENVPN_EXCEPTION(proxy_exception)
void recv_auth_failed(const std::string &msg)
SessionStats::Ptr cli_stats
void tun_connected() override
void stop(const bool call_terminate_callback)
void tun_pre_route_config() override
bool supports_proto_v3() override
std::uint64_t inactivity_bytes
void recv_auth_pending(const std::string &msg)
OptionListContinuation received_options
void do_acc_certcheck(const std::string &msg_str)
Handles the ACC certcheck TLS handshake data exchange.
void transport_error(const Error::Type fatal_err, const std::string &err_text) override
void client_auth(Buffer &buf) override
void transport_needs_send() override
std::chrono::milliseconds reconnect_delay() const
void recv_push_reply(const std::string &msg)
void validate_and_post_cc_msg(const std::string &msg)
void process_inactive(const OptionList &opt)
void set_housekeeping_timer()
void extract_auth_token(const OptionList &opt)
void transport_connecting() override
OPENVPN_EXCEPTION(tun_exception)
ClientEvent::Queue::Ptr cli_events
OPENVPN_SIMPLE_EXCEPTION(relay_event)
TunClientFactory::Ptr tun_factory
void send_explicit_exit_notify()
void schedule_inactive_timer()
bool transport_has_send_queue
void process_exception(const std::exception &e, const char *method_name)
ProtoContext proto_context
void process_echo(const OptionList &opt)
bool reached_connected_state() const
count_t inactive_last_sample
RemoteList::Advance temp_fail_advance_
std::string server_endpoint_render()
void post_app_control_message(const std::string proto, const std::string message)
void schedule_info_hold_callback()
OPENVPN_EXCEPTION(client_halt_restart)
OPENVPN_SIMPLE_EXCEPTION(inactive_timer_expired)
Time::Duration inactive_duration
bool is_keepalive_enabled() const override
void set_cc_handshake_config(SSLLib::SSLAPI::Config::Ptr cfg)
Set the cc handshake config object.
std::shared_ptr< SessionStats::inc_callback_t > in_tun_callback_
void notify_client_acc_protocols()
Error::Type fatal() const
std::chrono::milliseconds temp_fail_backoff_
OPENVPN_SIMPLE_EXCEPTION(authentication_failed)
std::shared_ptr< SessionStats::inc_callback_t > out_tun_callback_
TransportClientFactory::Ptr transport_factory
bool similar(const Time &t) const
void init(const Time::Duration &pre, const Time::Duration &post)
void reset(const Time &t)
static bool is_any_stub(const Type t)
const T * c_data() const
Returns a const pointer to the start of the buffer.
size_t size() const
Returns the size of the buffer in T objects.
void reset_size()
Resets the size of the buffer to zero.
bool code_defined() const
static std::string validate(const std::string &ipstr, const TITLE &title, const Version required_version)
void reset_completion()
Resets completion flag. Intended to use by PUSH_UPDATE.
void finalize(const PushOptionsMerger::Ptr merger)
void add(const OptionList &other, OptionList::FilterBase *filt, bool push_update=false)
std::string get_optional(const std::string &name, size_t index, const size_t max_len) const
const IndexMap & map() const
static OptionList parse_from_csv_static(const std::string &str, Limits *lim)
const Option * get_ptr(const std::string &name) const
void touch(bool lightly=false) const
const std::string & get(const size_t index, const size_t max_len) const
static void write_empty_string(Buffer &buf)
void build_connect_time_peer_info_string(TransportClient::Ptr transport)
AppControlMessageReceiver app_control_recv
void set_xmit_creds(const bool xmit_creds_arg)
AppControlMessageConfig app_control_config
void parse_custom_app_control(const OptionList &opt)
Time::Duration renegotiate
uint32_t get_tls_warnings() const
void send_explicit_exit_notify()
CryptoDCSettings & dc_settings()
void flush(const bool control_channel)
bool uses_bs64_cipher() const
PacketType packet_type(const Buffer &buf)
void data_encrypt(BufferAllocated &in_out)
bool is_keepalive_enabled() const
void process_push(const OptionList &opt, const ProtoContextCompressionOptions &pco)
static void write_auth_string(const S &str, Buffer &buf)
void set_protocol(const Protocol &p)
size_t align_adjust_hint() const
SessionStats & stat() const
std::string dump_packet(const Buffer &buf)
static void write_empty_string(Buffer &buf)
static void write_control_string(const S &str, Buffer &buf)
bool data_decrypt(const PacketType &type, BufferAllocated &in_out)
void disable_keepalive(unsigned int &keepalive_ping, unsigned int &keepalive_timeout)
Error::Type invalidation_reason() const
Time next_housekeeping() const
bool control_net_recv(const PacketType &type, BufferAllocated &&net_buf)
void reset(const ProtoSessionID cookie_psid=ProtoSessionID())
Resets ProtoContext *this to it's initial state.
void start(const ProtoSessionID cookie_psid=ProtoSessionID())
Initialize the state machine and start protocol negotiation.
const ProtoConfig & conf() const
static void generate_icmp_ptb(BufferAllocated &buf, std::uint16_t nexthop_mtu)
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
void swap(RCPtr &rhs) noexcept
swaps the contents of two RCPtr<T>
T * get() const noexcept
Returns the raw pointer to the object T, or nullptr.
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
virtual void error(const size_t type, const std::string *text=nullptr)
std::shared_ptr< inc_callback_t > set_inc_callback(Stats stat, inc_callback_t callback)
Sets a callback to be triggered upon increment of stats.
void update_last_packet_received(const Time &now)
count_t get_stat(const size_t type) const
void max(const TimeType &t)
#define OPENVPN_LOG_CLIPROTO(x)
#define OPENVPN_THROW(exc, stuff)
#define OPENVPN_LOG(args)
const char * name(const size_t type)
unsigned int version(const std::uint8_t version_len_prio)
bool is_valid_utf8(const STRING &str, const size_t max_len_flags=0)
OutT clamp_to_typerange(InT inVal)
Clamps the input value to the legal range for the output type.
auto join(const T &strings, const typename T::value_type &delim, const bool tail=false)
bool starts_with(const STRING &str, const std::string &prefix)
std::vector< T > split(const T &str, const typename T::value_type sep, const int maxsplit=-1)
std::string trim_left_copy(const std::string &str)
const Option * load_duration_parm(Time::Duration &dur, const std::string &name, const OptionList &opt, const unsigned int min_value, const bool x2, const bool allow_ms)
std::string render_options_sanitized(const OptionList &opt, const unsigned int render_flags)
bool parse_number(const char *str, T &retval, const bool nondigit_term=false)
defines a class that handles SSL/TLS handshaking
std::optional< std::string > MsgT
MsgT process_msg(const MsgT &msg)
Incrementally process the CLIENT HELLO / SERVER HELLO exchange.
void reset(SSLLib::SSLAPI::Config::Ptr cfg)
Re-init the handshaker.
bool supports_protocol(const std::string &protocol)
std::vector< std::string > supported_protocols
List of supported protocols.
std::vector< std::string > format_message(const std::string &protocol, const std::string &message)
Format a protocol string and a message into a properly packed series of message fragments.
virtual void client_proto_terminate()=0
virtual void client_proto_renegotiated()
virtual ~NotifyCallback()=default
virtual void client_proto_auth_pending_timeout(int timeout)
virtual void client_proto_connected()
unsigned int tcp_queue_limit
TunClientFactory::Ptr tun_factory
ClientEvent::Queue::Ptr cli_events
TransportClientFactory::Ptr transport_factory
OptionList::FilterBase::Ptr pushed_options_filter
PushOptionsBase::Ptr push_base
OptionList::Limits pushed_options_limit
ProtoContextCompressionOptions::Ptr proto_context_options
SessionStats::Ptr cli_stats
ProtoContext::ProtoConfig::Ptr proto_context_config
CompressionMode compression_mode
bool is_comp_asym() const
virtual TransportClient::Ptr new_transport_client_obj(openvpn_io::io_context &io_context, TransportClientParent *parent)=0
virtual void process_push(const OptionList &)
virtual void reset_align_adjust(const size_t align_adjust)=0
virtual void transport_start()=0
virtual bool transport_send_const(const Buffer &buf)=0
virtual size_t transport_send_queue_size()=0
virtual bool transport_has_send_queue()=0
virtual bool transport_send(BufferAllocated &buf)=0
virtual void server_endpoint_info(std::string &host, std::string &port, std::string &proto, std::string &ip_addr) const =0
virtual Protocol transport_protocol() const =0
virtual bool supports_proto_v3()=0
virtual TunClient::Ptr new_tun_client_obj(openvpn_io::io_context &io_context, TunClientParent &parent, TransportClient *transcli)=0
virtual std::string vpn_gw6() const
virtual std::string vpn_ip4() const =0
virtual std::string tun_name() const =0
virtual int vpn_mtu() const =0
virtual void adjust_mss(int mss)
virtual void apply_push_update(const OptionList &opt, TransportClient &cli)
Notifies tun client about received PUSH_UPDATE control channel message.
virtual void set_disconnect()=0
virtual void tun_start(const OptionList &, TransportClient &, CryptoDCSettings &)=0
virtual std::string vpn_gw4() const
virtual bool tun_send(BufferAllocated &buf)=0
virtual std::string vpn_ip6() const =0
static const char config[]
static std::stringstream out