2016-03-15 22:42:13 +01:00
|
|
|
//
|
2017-03-18 20:03:00 +01:00
|
|
|
// omi.hpp
|
|
|
|
// OpenVPN
|
2016-03-15 22:42:13 +01:00
|
|
|
//
|
2017-03-18 20:14:09 +01:00
|
|
|
// Copyright (C) 2012-2017 OpenVPN Technologies, Inc.
|
2017-03-18 20:03:00 +01:00
|
|
|
// All rights reserved.
|
2016-03-15 22:42:13 +01:00
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef OPENVPN_OMI_OMI_H
|
|
|
|
#define OPENVPN_OMI_OMI_H
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
#include <sstream>
|
|
|
|
#include <vector>
|
|
|
|
#include <deque>
|
|
|
|
#include <memory>
|
|
|
|
#include <utility>
|
2016-03-28 09:04:34 +02:00
|
|
|
#include <algorithm>
|
2016-03-15 22:42:13 +01:00
|
|
|
|
2016-05-06 00:11:53 +02:00
|
|
|
#include <openvpn/common/size.hpp>
|
2016-03-15 22:42:13 +01:00
|
|
|
#include <openvpn/common/platform.hpp>
|
|
|
|
#include <openvpn/common/exception.hpp>
|
|
|
|
#include <openvpn/common/rc.hpp>
|
|
|
|
#include <openvpn/common/string.hpp>
|
2016-03-28 09:04:34 +02:00
|
|
|
#include <openvpn/common/number.hpp>
|
|
|
|
#include <openvpn/common/hostport.hpp>
|
2016-03-15 22:42:13 +01:00
|
|
|
#include <openvpn/common/options.hpp>
|
|
|
|
#include <openvpn/buffer/bufstr.hpp>
|
2016-03-28 22:52:18 +02:00
|
|
|
#include <openvpn/time/timestr.hpp>
|
2019-08-30 09:39:29 +02:00
|
|
|
#include <openvpn/time/asiotimersafe.hpp>
|
2018-07-07 20:27:24 +02:00
|
|
|
#include <openvpn/asio/asiowork.hpp>
|
2016-03-15 22:42:13 +01:00
|
|
|
|
|
|
|
// include acceptors for different protocols
|
|
|
|
#include <openvpn/acceptor/base.hpp>
|
|
|
|
#include <openvpn/acceptor/tcp.hpp>
|
|
|
|
#ifdef ASIO_HAS_LOCAL_SOCKETS
|
|
|
|
#include <openvpn/acceptor/unix.hpp>
|
|
|
|
#endif
|
|
|
|
|
2016-03-28 22:52:18 +02:00
|
|
|
#if defined(OPENVPN_PLATFORM_WIN)
|
|
|
|
#include <openvpn/win/logutil.hpp>
|
|
|
|
#else
|
|
|
|
#include <openvpn/common/redir.hpp>
|
|
|
|
#endif
|
|
|
|
|
2016-03-15 22:42:13 +01:00
|
|
|
namespace openvpn {
|
|
|
|
class OMICore : public Acceptor::ListenerBase
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
OPENVPN_EXCEPTION(omi_error);
|
|
|
|
|
2016-05-06 00:11:53 +02:00
|
|
|
struct LogFn
|
|
|
|
{
|
|
|
|
LogFn(const OptionList& opt)
|
|
|
|
{
|
|
|
|
fn = opt.get_optional("log", 1, 256);
|
|
|
|
if (fn.empty())
|
|
|
|
{
|
|
|
|
fn = opt.get_optional("log-append", 1, 256);
|
|
|
|
append = true;
|
|
|
|
}
|
|
|
|
errors_to_stderr = opt.exists("errors-to-stderr");
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string fn;
|
|
|
|
bool append = false;
|
|
|
|
bool errors_to_stderr = false;
|
|
|
|
};
|
|
|
|
|
2016-03-28 09:04:34 +02:00
|
|
|
void stop()
|
|
|
|
{
|
|
|
|
if (stop_called)
|
|
|
|
return;
|
|
|
|
stop_called = true;
|
|
|
|
|
2018-07-07 20:27:24 +02:00
|
|
|
asio_work.reset();
|
|
|
|
|
2016-03-28 09:04:34 +02:00
|
|
|
// close acceptor
|
|
|
|
if (acceptor)
|
|
|
|
acceptor->close();
|
|
|
|
|
|
|
|
// Call derived class stop method and close OMI socket,
|
|
|
|
// but if omi_stop() returns true, wait for content_out
|
|
|
|
// to be flushed to OMI socket before closing it.
|
|
|
|
if (!omi_stop() || content_out.empty())
|
2016-03-30 08:17:10 +02:00
|
|
|
stop_omi_client(false, 250);
|
2016-03-28 09:04:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected:
|
|
|
|
struct Command
|
|
|
|
{
|
2016-03-15 22:42:13 +01:00
|
|
|
Option option;
|
|
|
|
std::vector<std::string> extra;
|
|
|
|
bool valid_utf8 = false;
|
|
|
|
|
|
|
|
std::string to_string() const
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
os << option.render(Option::RENDER_BRACKET);
|
|
|
|
if (!valid_utf8)
|
|
|
|
os << " >>>!UTF8";
|
|
|
|
os << '\n';
|
|
|
|
for (auto &line : extra)
|
|
|
|
os << line << '\n';
|
|
|
|
return os.str();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2016-03-28 09:04:34 +02:00
|
|
|
class History
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
History(const std::string& type_arg,
|
|
|
|
const size_t max_size_arg)
|
|
|
|
: type(type_arg),
|
|
|
|
max_size(max_size_arg)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_cmd(const Option& o) const
|
|
|
|
{
|
|
|
|
return o.get_optional(0, 0) == type;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string process_cmd(const Option& o)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
const std::string arg1 = o.get(1, 16);
|
|
|
|
if (arg1 == "on")
|
|
|
|
{
|
|
|
|
const std::string arg2 = o.get_optional(2, 16);
|
|
|
|
real_time = true;
|
|
|
|
std::string ret = real_time_status();
|
|
|
|
if (arg2 == "all")
|
|
|
|
ret += show(hist.size());
|
|
|
|
else if (!arg2.empty())
|
|
|
|
return error();
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
else if (arg1 == "all")
|
|
|
|
{
|
|
|
|
return show(hist.size());
|
|
|
|
}
|
|
|
|
else if (arg1 == "off")
|
|
|
|
{
|
|
|
|
real_time = false;
|
|
|
|
return real_time_status();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
unsigned int n;
|
|
|
|
if (parse_number(arg1, n))
|
|
|
|
return show(n);
|
|
|
|
else
|
|
|
|
return error();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const option_error&)
|
|
|
|
{
|
|
|
|
return error();
|
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
return "ERROR: " + type + " processing error: " + e.what() + "\r\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string notify(const std::string& msg)
|
|
|
|
{
|
|
|
|
hist.push_front(msg);
|
|
|
|
while (hist.size() > max_size)
|
|
|
|
hist.pop_back();
|
|
|
|
if (real_time)
|
|
|
|
return notify_prefix() + msg;
|
|
|
|
else
|
|
|
|
return std::string();
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::string show(size_t n) const
|
|
|
|
{
|
|
|
|
std::string ret = "";
|
|
|
|
n = std::min(n, hist.size());
|
|
|
|
for (size_t i = 0; i < n; ++i)
|
|
|
|
ret += hist[n - i - 1];
|
|
|
|
ret += "END\r\n";
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string notify_prefix() const
|
|
|
|
{
|
|
|
|
return ">" + string::to_upper_copy(type) + ":";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string real_time_status() const
|
|
|
|
{
|
|
|
|
std::string ret = "SUCCESS: real-time " + type + " notification set to ";
|
|
|
|
if (real_time)
|
|
|
|
ret += "ON";
|
|
|
|
else
|
|
|
|
ret += "OFF";
|
|
|
|
ret += "\r\n";
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string error() const
|
|
|
|
{
|
|
|
|
return "ERROR: " + type + " parameter must be 'on' or 'off' or some number n or 'all'\r\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string type;
|
|
|
|
size_t max_size;
|
|
|
|
bool real_time = false;
|
|
|
|
std::deque<std::string> hist;
|
|
|
|
};
|
|
|
|
|
2017-03-30 23:38:32 +02:00
|
|
|
OMICore(openvpn_io::io_context& io_context_arg)
|
2016-03-15 22:42:13 +01:00
|
|
|
: io_context(io_context_arg),
|
2016-03-30 08:17:10 +02:00
|
|
|
stop_timer(io_context_arg)
|
2016-03-15 22:42:13 +01:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2016-05-06 00:11:53 +02:00
|
|
|
void log_setup(const LogFn& log)
|
2016-03-15 22:42:13 +01:00
|
|
|
{
|
2016-05-06 00:11:53 +02:00
|
|
|
if (!log.fn.empty())
|
2016-03-28 09:04:34 +02:00
|
|
|
{
|
2016-05-06 00:11:53 +02:00
|
|
|
#if defined(OPENVPN_PLATFORM_WIN)
|
|
|
|
log_handle = Win::LogUtil::create_file(log.fn, "", log.append);
|
|
|
|
#else
|
|
|
|
RedirectStd redir("",
|
|
|
|
log.fn,
|
|
|
|
log.append ? RedirectStd::FLAGS_APPEND : RedirectStd::FLAGS_OVERWRITE,
|
|
|
|
RedirectStd::MODE_ALL,
|
|
|
|
false);
|
|
|
|
redir.redirect();
|
|
|
|
#endif
|
2016-03-28 09:04:34 +02:00
|
|
|
}
|
2016-05-06 00:11:53 +02:00
|
|
|
errors_to_stderr = log.errors_to_stderr;
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
|
2016-05-06 00:11:53 +02:00
|
|
|
static std::string get_config(const OptionList& opt)
|
2016-03-15 22:42:13 +01:00
|
|
|
{
|
|
|
|
// get config file
|
|
|
|
const std::string config_fn = opt.get("config", 1, 256);
|
|
|
|
return read_config(config_fn);
|
|
|
|
}
|
|
|
|
|
2016-05-06 00:11:53 +02:00
|
|
|
void start(const OptionList& opt)
|
2016-03-15 22:42:13 +01:00
|
|
|
{
|
|
|
|
const Option& o = opt.get("management");
|
|
|
|
const std::string addr = o.get(1, 256);
|
|
|
|
const std::string port = o.get(2, 16);
|
2016-03-28 09:04:34 +02:00
|
|
|
|
|
|
|
hold_flag = opt.exists("management-hold");
|
|
|
|
|
2016-05-06 00:11:53 +02:00
|
|
|
// management-queue-limit low_water high_water
|
|
|
|
{
|
|
|
|
const Option* o = opt.get_ptr("management-queue-limit");
|
|
|
|
if (o)
|
|
|
|
{
|
|
|
|
const size_t low_water = o->get_num<size_t>(1, 0, 0, 1000000);
|
|
|
|
const size_t high_water = o->get_num<size_t>(2, 0, 0, 1000000);
|
|
|
|
content_out_throttle.reset(new BufferThrottle(low_water, high_water));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-28 09:04:34 +02:00
|
|
|
// management-client-user root
|
|
|
|
{
|
|
|
|
const Option* o = opt.get_ptr("management-client-user");
|
|
|
|
if (o)
|
|
|
|
{
|
|
|
|
if (o->get(1, 64) == "root")
|
|
|
|
management_client_root = true;
|
|
|
|
else
|
|
|
|
throw Exception("only --management-client-user root supported");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-03-15 22:42:13 +01:00
|
|
|
if (opt.exists("management-client"))
|
|
|
|
{
|
|
|
|
if (port == "unix")
|
|
|
|
{
|
2016-05-06 00:11:53 +02:00
|
|
|
OPENVPN_LOG("OMI Connecting to " << addr << " [unix]");
|
2016-03-15 22:42:13 +01:00
|
|
|
connect_unix(addr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-05-06 00:11:53 +02:00
|
|
|
OPENVPN_LOG("OMI Connecting to [" << addr << "]:" << port << " [tcp]");
|
2016-03-15 22:42:13 +01:00
|
|
|
connect_tcp(addr, port);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (port == "unix")
|
|
|
|
{
|
2016-05-06 00:11:53 +02:00
|
|
|
OPENVPN_LOG("OMI Listening on " << addr << " [unix]");
|
2016-03-15 22:42:13 +01:00
|
|
|
listen_unix(addr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-05-06 00:11:53 +02:00
|
|
|
OPENVPN_LOG("OMI Listening on [" << addr << "]:" << port << " [tcp]");
|
2016-03-15 22:42:13 +01:00
|
|
|
listen_tcp(addr, port);
|
|
|
|
}
|
|
|
|
}
|
2018-07-07 20:27:24 +02:00
|
|
|
|
|
|
|
// don't exit Asio event loop until AsioWork object is deleted
|
|
|
|
asio_work.reset(new AsioWork(io_context));
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
|
2016-05-06 00:11:53 +02:00
|
|
|
void start_connection_if_not_hold()
|
|
|
|
{
|
|
|
|
if (!hold_flag)
|
|
|
|
omi_start_connection();
|
|
|
|
}
|
|
|
|
|
2016-03-15 22:42:13 +01:00
|
|
|
void send(BufferPtr buf)
|
|
|
|
{
|
2016-03-28 09:04:34 +02:00
|
|
|
if (!is_sock_open())
|
2016-03-15 22:42:13 +01:00
|
|
|
return;
|
|
|
|
content_out.push_back(std::move(buf));
|
2016-05-06 00:11:53 +02:00
|
|
|
if (content_out_throttle)
|
|
|
|
content_out_throttle->size_change(content_out.size());
|
2016-03-15 22:42:13 +01:00
|
|
|
if (content_out.size() == 1) // send operation not currently active?
|
|
|
|
queue_send();
|
|
|
|
}
|
|
|
|
|
|
|
|
void send(const std::string& str)
|
|
|
|
{
|
2016-03-28 09:04:34 +02:00
|
|
|
if (!str.empty())
|
|
|
|
send(buf_from_string(str));
|
|
|
|
}
|
|
|
|
|
2016-05-06 00:11:53 +02:00
|
|
|
bool send_ready() const
|
|
|
|
{
|
|
|
|
if (content_out_throttle)
|
|
|
|
return content_out_throttle->ready();
|
|
|
|
else
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2018-07-07 20:27:24 +02:00
|
|
|
void async_done()
|
|
|
|
{
|
|
|
|
process_recv();
|
|
|
|
}
|
|
|
|
|
2016-03-28 22:52:18 +02:00
|
|
|
void log_full(const std::string& text) // logs to OMI buffer and log file
|
|
|
|
{
|
|
|
|
const time_t now = ::time(NULL);
|
|
|
|
const std::string textcrlf = string::unix2dos(text, true);
|
|
|
|
log_line(openvpn::to_string(now) + ",," + textcrlf);
|
|
|
|
#if defined(OPENVPN_PLATFORM_WIN)
|
|
|
|
if (log_handle.defined())
|
|
|
|
Win::LogUtil::log(log_handle(), date_time(now) + ' ' + textcrlf);
|
|
|
|
else
|
|
|
|
#endif
|
|
|
|
std::cout << date_time(now) << ' ' << text << std::flush;
|
|
|
|
}
|
|
|
|
|
2016-05-06 00:11:53 +02:00
|
|
|
void log_timestamp(const time_t timestamp, const std::string& text) // logs to OMI buffer only
|
|
|
|
{
|
|
|
|
const std::string textcrlf = string::unix2dos(text, true);
|
|
|
|
log_line(openvpn::to_string(timestamp) + ",," + textcrlf);
|
|
|
|
}
|
|
|
|
|
2016-03-28 22:52:18 +02:00
|
|
|
void log_line(const std::string& line) // logs to OMI buffer only
|
2016-03-28 09:04:34 +02:00
|
|
|
{
|
|
|
|
if (!stop_called)
|
|
|
|
send(hist_log.notify(line));
|
|
|
|
}
|
|
|
|
|
|
|
|
void state_line(const std::string& line)
|
|
|
|
{
|
|
|
|
if (!stop_called)
|
|
|
|
send(hist_state.notify(line));
|
|
|
|
}
|
|
|
|
|
|
|
|
void echo_line(const std::string& line)
|
|
|
|
{
|
|
|
|
if (!stop_called)
|
|
|
|
send(hist_echo.notify(line));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool is_errors_to_stderr() const
|
|
|
|
{
|
|
|
|
return errors_to_stderr;
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
|
2016-03-28 09:04:34 +02:00
|
|
|
bool is_stopping() const
|
|
|
|
{
|
|
|
|
return stop_called;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned int get_bytecount() const
|
|
|
|
{
|
|
|
|
return bytecount;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual bool omi_command_is_multiline(const std::string& arg0, const Option& option) = 0;
|
2018-07-07 20:27:24 +02:00
|
|
|
virtual bool omi_command_in(const std::string& arg0, const Command& cmd) = 0;
|
2016-03-28 09:04:34 +02:00
|
|
|
virtual void omi_start_connection() = 0;
|
2016-03-15 22:42:13 +01:00
|
|
|
virtual void omi_done(const bool eof) = 0;
|
2016-03-28 09:04:34 +02:00
|
|
|
virtual void omi_sigterm() = 0;
|
|
|
|
virtual bool omi_stop() = 0;
|
2016-03-15 22:42:13 +01:00
|
|
|
|
2016-05-06 00:11:53 +02:00
|
|
|
virtual bool omi_is_sighup_implemented()
|
|
|
|
{
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void omi_sighup()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-03-30 23:38:32 +02:00
|
|
|
openvpn_io::io_context& io_context;
|
2016-03-15 22:42:13 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
typedef RCPtr<OMICore> Ptr;
|
|
|
|
|
2016-05-06 00:11:53 +02:00
|
|
|
class BufferThrottle
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
BufferThrottle(const size_t low_water_arg,
|
|
|
|
const size_t high_water_arg)
|
|
|
|
: low_water(low_water_arg),
|
|
|
|
high_water(high_water_arg)
|
|
|
|
{
|
|
|
|
if (low_water > high_water)
|
|
|
|
throw Exception("bad management-queue-limit values");
|
|
|
|
}
|
|
|
|
|
|
|
|
void size_change(const size_t size)
|
|
|
|
{
|
|
|
|
if (ready_)
|
|
|
|
{
|
|
|
|
if (size > high_water)
|
|
|
|
ready_ = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (size <= low_water)
|
|
|
|
ready_ = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ready() const
|
|
|
|
{
|
|
|
|
return ready_;
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const size_t low_water;
|
|
|
|
const size_t high_water;
|
|
|
|
volatile bool ready_ = true;
|
|
|
|
};
|
|
|
|
|
2018-07-07 20:27:24 +02:00
|
|
|
bool command_in(std::unique_ptr<Command> cmd)
|
2016-03-28 09:04:34 +02:00
|
|
|
{
|
|
|
|
try {
|
|
|
|
const std::string arg0 = cmd->option.get_optional(0, 64);
|
|
|
|
if (arg0.empty())
|
2018-07-07 20:27:24 +02:00
|
|
|
return false;
|
2016-03-28 09:04:34 +02:00
|
|
|
if (!cmd->valid_utf8)
|
|
|
|
throw Exception("invalid UTF8");
|
|
|
|
switch (arg0[0])
|
|
|
|
{
|
|
|
|
case 'b':
|
|
|
|
{
|
|
|
|
if (arg0 == "bytecount")
|
|
|
|
{
|
|
|
|
process_bytecount_cmd(cmd->option);
|
2018-07-07 20:27:24 +02:00
|
|
|
return false;
|
2016-03-28 09:04:34 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'e':
|
|
|
|
{
|
|
|
|
if (hist_echo.is_cmd(cmd->option))
|
|
|
|
{
|
|
|
|
send(hist_echo.process_cmd(cmd->option));
|
2018-07-07 20:27:24 +02:00
|
|
|
return false;
|
2016-03-28 09:04:34 +02:00
|
|
|
}
|
|
|
|
if (arg0 == "exit")
|
|
|
|
{
|
|
|
|
conditional_stop(true);
|
2018-07-07 20:27:24 +02:00
|
|
|
return false;
|
2016-03-28 09:04:34 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'h':
|
|
|
|
{
|
|
|
|
if (is_hold_cmd(cmd->option))
|
|
|
|
{
|
|
|
|
bool release = false;
|
|
|
|
send(hold_cmd(cmd->option, release));
|
|
|
|
if (release)
|
|
|
|
hold_release();
|
2018-07-07 20:27:24 +02:00
|
|
|
return false;
|
2016-03-28 09:04:34 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'l':
|
|
|
|
{
|
|
|
|
if (hist_log.is_cmd(cmd->option))
|
|
|
|
{
|
|
|
|
send(hist_log.process_cmd(cmd->option));
|
2018-07-07 20:27:24 +02:00
|
|
|
return false;
|
2016-03-28 09:04:34 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'q':
|
|
|
|
{
|
|
|
|
if (arg0 == "quit")
|
|
|
|
{
|
|
|
|
conditional_stop(true);
|
2018-07-07 20:27:24 +02:00
|
|
|
return false;
|
2016-03-28 09:04:34 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 's':
|
|
|
|
{
|
|
|
|
if (hist_state.is_cmd(cmd->option))
|
|
|
|
{
|
|
|
|
send(hist_state.process_cmd(cmd->option));
|
2018-07-07 20:27:24 +02:00
|
|
|
return false;
|
2016-03-28 09:04:34 +02:00
|
|
|
}
|
|
|
|
if (arg0 == "signal")
|
|
|
|
{
|
|
|
|
process_signal_cmd(cmd->option);
|
2018-07-07 20:27:24 +02:00
|
|
|
return false;
|
2016-03-28 09:04:34 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-07-07 20:27:24 +02:00
|
|
|
return omi_command_in(arg0, *cmd);
|
2016-03-28 09:04:34 +02:00
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
|
|
|
std::string err_ref = "option";
|
|
|
|
if (cmd)
|
|
|
|
err_ref = cmd->option.err_ref();
|
|
|
|
send("ERROR: error processing " + err_ref + " : " + e.what() + "\r\n");
|
|
|
|
}
|
2018-07-07 20:27:24 +02:00
|
|
|
return false;
|
2016-03-28 09:04:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
bool is_hold_cmd(const Option& o) const
|
|
|
|
{
|
|
|
|
return o.get_optional(0, 0) == "hold";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string hold_cmd(const Option& o, bool& release)
|
|
|
|
{
|
|
|
|
try {
|
|
|
|
const std::string arg1 = o.get_optional(1, 16);
|
|
|
|
if (arg1.empty())
|
|
|
|
{
|
|
|
|
if (hold_flag)
|
|
|
|
return "SUCCESS: hold=1\r\n";
|
|
|
|
else
|
|
|
|
return "SUCCESS: hold=0\r\n";
|
|
|
|
}
|
|
|
|
else if (arg1 == "on")
|
|
|
|
{
|
|
|
|
hold_flag = true;
|
|
|
|
return "SUCCESS: hold flag set to ON\r\n";
|
|
|
|
}
|
|
|
|
else if (arg1 == "off")
|
|
|
|
{
|
|
|
|
hold_flag = false;
|
|
|
|
return "SUCCESS: hold flag set to OFF\r\n";
|
|
|
|
}
|
|
|
|
else if (arg1 == "release")
|
|
|
|
{
|
|
|
|
release = true;
|
|
|
|
return "SUCCESS: hold release succeeded\r\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const option_error&)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
return "ERROR: bad hold command parameter\r\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
void hold_cycle()
|
|
|
|
{
|
|
|
|
hold_wait = true;
|
|
|
|
if (hold_flag)
|
|
|
|
send(">HOLD:Waiting for hold release\r\n");
|
|
|
|
else
|
|
|
|
hold_release();
|
|
|
|
}
|
|
|
|
|
|
|
|
void hold_release()
|
|
|
|
{
|
|
|
|
if (hold_wait)
|
|
|
|
{
|
|
|
|
hold_wait = false;
|
|
|
|
omi_start_connection();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void process_bytecount_cmd(const Option& o)
|
|
|
|
{
|
|
|
|
bytecount = o.get_num<decltype(bytecount)>(1, 0, 0, 86400);
|
|
|
|
send("SUCCESS: bytecount interval changed\r\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void process_signal_cmd(const Option& o)
|
|
|
|
{
|
|
|
|
const std::string type = o.get(1, 16);
|
|
|
|
if (type == "SIGTERM")
|
|
|
|
{
|
|
|
|
send("SUCCESS: signal SIGTERM thrown\r\n");
|
|
|
|
omi_sigterm();
|
|
|
|
}
|
2016-05-06 00:11:53 +02:00
|
|
|
else if (type == "SIGHUP" && omi_is_sighup_implemented())
|
2016-03-28 09:04:34 +02:00
|
|
|
{
|
|
|
|
send("SUCCESS: signal SIGHUP thrown\r\n");
|
|
|
|
omi_sighup();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
send("ERROR: signal not supported\r\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool command_is_multiline(const Option& o)
|
|
|
|
{
|
|
|
|
const std::string arg0 = o.get_optional(0, 64);
|
|
|
|
if (arg0.empty())
|
|
|
|
return false;
|
|
|
|
return omi_command_is_multiline(arg0, o);
|
|
|
|
}
|
|
|
|
|
2016-03-15 22:42:13 +01:00
|
|
|
bool is_sock_open() const
|
|
|
|
{
|
|
|
|
return socket && socket->is_open();
|
|
|
|
}
|
|
|
|
|
2016-03-28 09:04:34 +02:00
|
|
|
void conditional_stop(const bool eof)
|
|
|
|
{
|
|
|
|
if (acceptor || stop_called)
|
2016-03-30 08:17:10 +02:00
|
|
|
stop_omi_client(eof, 250);
|
2016-03-28 09:04:34 +02:00
|
|
|
else
|
|
|
|
stop(); // if running in management-client mode, do a full stop
|
|
|
|
}
|
|
|
|
|
2016-03-30 08:17:10 +02:00
|
|
|
void stop_omi_client(const bool eof, const unsigned int milliseconds)
|
|
|
|
{
|
2017-04-12 22:07:02 +02:00
|
|
|
stop_timer.expires_after(Time::Duration::milliseconds(milliseconds));
|
2017-03-30 23:38:32 +02:00
|
|
|
stop_timer.async_wait([self=Ptr(this), eof](const openvpn_io::error_code& error)
|
2016-03-30 08:17:10 +02:00
|
|
|
{
|
|
|
|
if (!error)
|
|
|
|
self->stop_omi_client(eof);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2016-03-28 09:04:34 +02:00
|
|
|
void stop_omi_client(const bool eof)
|
2016-03-15 22:42:13 +01:00
|
|
|
{
|
2016-03-30 08:17:10 +02:00
|
|
|
stop_timer.cancel();
|
2016-03-28 09:04:34 +02:00
|
|
|
const bool is_open = is_sock_open();
|
|
|
|
if (is_open)
|
2016-03-15 22:42:13 +01:00
|
|
|
socket->close();
|
|
|
|
content_out.clear();
|
2016-05-06 00:11:53 +02:00
|
|
|
if (content_out_throttle)
|
|
|
|
content_out_throttle->size_change(content_out.size());
|
2016-03-15 22:42:13 +01:00
|
|
|
in_partial.clear();
|
2016-03-28 09:04:34 +02:00
|
|
|
if (is_open)
|
|
|
|
omi_done(eof);
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void send_title_message()
|
|
|
|
{
|
2016-03-28 09:04:34 +02:00
|
|
|
send(">INFO:OpenVPN Management Interface Version 1 -- type 'help' for more info\r\n");
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
|
2018-07-07 20:27:24 +02:00
|
|
|
bool process_in_line() // process incoming line in in_partial
|
2016-03-15 22:42:13 +01:00
|
|
|
{
|
2018-07-07 20:27:24 +02:00
|
|
|
bool ret = false;
|
2016-03-15 22:42:13 +01:00
|
|
|
const bool utf8 = Unicode::is_valid_utf8(in_partial);
|
|
|
|
string::trim_crlf(in_partial);
|
|
|
|
if (multiline)
|
|
|
|
{
|
|
|
|
if (!command)
|
|
|
|
throw omi_error("process_in_line: internal error");
|
|
|
|
if (in_partial == "END")
|
|
|
|
{
|
2018-07-07 20:27:24 +02:00
|
|
|
ret = command_in(std::move(command));
|
2016-03-15 22:42:13 +01:00
|
|
|
command.reset();
|
|
|
|
multiline = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!utf8)
|
|
|
|
command->valid_utf8 = false;
|
|
|
|
command->extra.push_back(std::move(in_partial));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
command.reset(new Command);
|
|
|
|
command->option = OptionList::parse_option_from_line(in_partial, nullptr);
|
|
|
|
command->valid_utf8 = utf8;
|
2016-03-28 09:04:34 +02:00
|
|
|
multiline = command_is_multiline(command->option);
|
2016-03-15 22:42:13 +01:00
|
|
|
if (!multiline)
|
|
|
|
{
|
2018-07-07 20:27:24 +02:00
|
|
|
ret = command_in(std::move(command));
|
2016-03-15 22:42:13 +01:00
|
|
|
command.reset();
|
|
|
|
}
|
|
|
|
}
|
2018-07-07 20:27:24 +02:00
|
|
|
return ret;
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
static std::string read_config(const std::string& fn)
|
|
|
|
{
|
|
|
|
if (fn == "stdin")
|
|
|
|
return read_stdin();
|
|
|
|
else
|
|
|
|
return read_text_utf8(fn);
|
|
|
|
}
|
|
|
|
|
|
|
|
void listen_tcp(const std::string& addr, const std::string& port)
|
|
|
|
{
|
|
|
|
// init TCP acceptor
|
|
|
|
Acceptor::TCP::Ptr a(new Acceptor::TCP(io_context));
|
|
|
|
|
|
|
|
// parse address/port of local endpoint
|
|
|
|
const IP::Addr ip_addr = IP::Addr::from_string(addr);
|
|
|
|
a->local_endpoint.address(ip_addr.to_asio());
|
2016-03-28 09:04:34 +02:00
|
|
|
a->local_endpoint.port(HostPort::parse_port(port, "OMI TCP listen"));
|
2016-03-15 22:42:13 +01:00
|
|
|
|
|
|
|
// open socket
|
|
|
|
a->acceptor.open(a->local_endpoint.protocol());
|
|
|
|
|
|
|
|
// set options
|
2019-08-30 10:03:06 +02:00
|
|
|
a->set_socket_options(0);
|
2016-03-15 22:42:13 +01:00
|
|
|
|
|
|
|
// bind to local address
|
|
|
|
a->acceptor.bind(a->local_endpoint);
|
|
|
|
|
|
|
|
// listen for incoming client connections
|
|
|
|
a->acceptor.listen();
|
|
|
|
|
|
|
|
// save acceptor
|
|
|
|
acceptor = a;
|
|
|
|
|
|
|
|
// dispatch accepts to handle_except()
|
|
|
|
queue_accept();
|
|
|
|
}
|
|
|
|
|
|
|
|
void listen_unix(const std::string& socket_path)
|
|
|
|
{
|
|
|
|
#ifdef ASIO_HAS_LOCAL_SOCKETS
|
|
|
|
// init unix socket acceptor
|
|
|
|
Acceptor::Unix::Ptr a(new Acceptor::Unix(io_context));
|
|
|
|
|
|
|
|
// set endpoint
|
|
|
|
a->pre_listen(socket_path);
|
|
|
|
a->local_endpoint.path(socket_path);
|
|
|
|
|
|
|
|
// open socket
|
|
|
|
a->acceptor.open(a->local_endpoint.protocol());
|
|
|
|
|
|
|
|
// bind to local address
|
|
|
|
a->acceptor.bind(a->local_endpoint);
|
|
|
|
|
|
|
|
// set socket permissions in filesystem
|
|
|
|
a->set_socket_permissions(socket_path, 0777);
|
|
|
|
|
|
|
|
// listen for incoming client connections
|
|
|
|
a->acceptor.listen();
|
|
|
|
|
|
|
|
// save acceptor
|
|
|
|
acceptor = a;
|
|
|
|
|
|
|
|
// dispatch accepts to handle_except()
|
|
|
|
queue_accept();
|
|
|
|
#else
|
|
|
|
throw Exception("unix sockets not supported on this platform");
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void queue_accept()
|
|
|
|
{
|
2016-03-28 09:04:34 +02:00
|
|
|
if (acceptor)
|
|
|
|
acceptor->async_accept(this, 0, io_context);
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
|
2016-03-28 09:04:34 +02:00
|
|
|
void verify_sock_peer(AsioPolySock::Base& sock)
|
|
|
|
{
|
|
|
|
#ifdef ASIO_HAS_LOCAL_SOCKETS
|
|
|
|
SockOpt::Creds cr;
|
|
|
|
if (management_client_root && sock.peercreds(cr))
|
|
|
|
{
|
|
|
|
if (!cr.root_uid())
|
|
|
|
throw Exception("peer must be root");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// despite its name, this method handles both accept and connect events
|
2017-03-30 23:38:32 +02:00
|
|
|
virtual void handle_accept(AsioPolySock::Base::Ptr sock, const openvpn_io::error_code& error) override
|
2016-03-15 22:42:13 +01:00
|
|
|
{
|
2016-03-28 09:04:34 +02:00
|
|
|
if (stop_called)
|
2016-03-15 22:42:13 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
try {
|
|
|
|
if (error)
|
2016-03-28 09:04:34 +02:00
|
|
|
throw Exception("accept/connect failed: " + error.message());
|
2016-03-15 22:42:13 +01:00
|
|
|
if (is_sock_open())
|
|
|
|
throw Exception("client already connected");
|
|
|
|
|
2016-03-28 09:04:34 +02:00
|
|
|
verify_sock_peer(*sock);
|
|
|
|
|
2016-03-15 22:42:13 +01:00
|
|
|
sock->non_blocking(true);
|
|
|
|
sock->set_cloexec();
|
|
|
|
socket = std::move(sock);
|
|
|
|
|
|
|
|
send_title_message();
|
|
|
|
queue_recv();
|
2016-03-28 09:04:34 +02:00
|
|
|
hold_cycle();
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
2016-03-28 09:04:34 +02:00
|
|
|
const std::string msg = "exception in accept/connect handler: " + std::string(e.what()) + '\n';
|
|
|
|
if (errors_to_stderr)
|
|
|
|
std::cerr << msg << std::flush;
|
|
|
|
OPENVPN_LOG_STRING(msg);
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
queue_accept();
|
|
|
|
}
|
|
|
|
|
|
|
|
void connect_tcp(const std::string& addr, const std::string& port)
|
|
|
|
{
|
2017-03-30 23:38:32 +02:00
|
|
|
openvpn_io::ip::tcp::endpoint ep(IP::Addr::from_string(addr).to_asio(),
|
2016-03-28 09:04:34 +02:00
|
|
|
HostPort::parse_port(port, "OMI TCP connect"));
|
|
|
|
AsioPolySock::TCP* s = new AsioPolySock::TCP(io_context, 0);
|
|
|
|
AsioPolySock::Base::Ptr sock(s);
|
|
|
|
s->socket.async_connect(ep,
|
2018-05-12 05:40:57 +02:00
|
|
|
[self=Ptr(this), sock](const openvpn_io::error_code& error) mutable
|
2016-03-28 09:04:34 +02:00
|
|
|
{
|
|
|
|
// this is a connect, but we reuse the accept method
|
2018-05-12 05:40:57 +02:00
|
|
|
self->handle_accept(std::move(sock), error);
|
2016-03-28 09:04:34 +02:00
|
|
|
});
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void connect_unix(const std::string& socket_path)
|
|
|
|
{
|
2016-03-28 09:04:34 +02:00
|
|
|
#ifdef ASIO_HAS_LOCAL_SOCKETS
|
2017-03-30 23:38:32 +02:00
|
|
|
openvpn_io::local::stream_protocol::endpoint ep(socket_path);
|
2016-03-28 09:04:34 +02:00
|
|
|
AsioPolySock::Unix* s = new AsioPolySock::Unix(io_context, 0);
|
|
|
|
AsioPolySock::Base::Ptr sock(s);
|
|
|
|
s->socket.async_connect(ep,
|
2018-05-12 05:40:57 +02:00
|
|
|
[self=Ptr(this), sock](const openvpn_io::error_code& error) mutable
|
2016-03-28 09:04:34 +02:00
|
|
|
{
|
|
|
|
// this is a connect, but we reuse the accept method
|
2018-05-12 05:40:57 +02:00
|
|
|
self->handle_accept(std::move(sock), error);
|
2016-03-28 09:04:34 +02:00
|
|
|
});
|
|
|
|
#else
|
|
|
|
throw Exception("unix sockets not supported on this platform");
|
|
|
|
#endif
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void queue_recv()
|
|
|
|
{
|
2018-07-07 20:27:24 +02:00
|
|
|
if (!is_sock_open() || recv_queued)
|
2016-03-15 22:42:13 +01:00
|
|
|
return;
|
|
|
|
BufferPtr buf(new BufferAllocated(256, 0));
|
2017-02-27 21:39:02 +01:00
|
|
|
socket->async_receive(buf->mutable_buffer_clamp(),
|
2017-03-30 23:38:32 +02:00
|
|
|
[self=Ptr(this), sock=socket, buf](const openvpn_io::error_code& error, const size_t bytes_recvd)
|
2016-03-15 22:42:13 +01:00
|
|
|
{
|
2018-07-07 20:27:24 +02:00
|
|
|
self->handle_recv(error, bytes_recvd, std::move(buf), sock.get());
|
2016-03-15 22:42:13 +01:00
|
|
|
});
|
2018-07-07 20:27:24 +02:00
|
|
|
recv_queued = true;
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
|
2017-03-30 23:38:32 +02:00
|
|
|
void handle_recv(const openvpn_io::error_code& error, const size_t bytes_recvd,
|
2018-07-07 20:27:24 +02:00
|
|
|
BufferPtr buf, const AsioPolySock::Base* queued_socket)
|
2016-03-15 22:42:13 +01:00
|
|
|
{
|
2018-07-07 20:27:24 +02:00
|
|
|
recv_queued = false;
|
2016-03-28 09:04:34 +02:00
|
|
|
if (!is_sock_open() || socket.get() != queued_socket)
|
2016-03-15 22:42:13 +01:00
|
|
|
return;
|
|
|
|
if (error)
|
|
|
|
{
|
2017-03-30 23:38:32 +02:00
|
|
|
const bool eof = (error == openvpn_io::error::eof);
|
2016-03-15 22:42:13 +01:00
|
|
|
if (!eof)
|
|
|
|
OPENVPN_LOG("client socket recv error: " << error.message());
|
2016-03-28 09:04:34 +02:00
|
|
|
conditional_stop(eof);
|
2016-03-15 22:42:13 +01:00
|
|
|
return;
|
|
|
|
}
|
2018-07-07 20:27:24 +02:00
|
|
|
buf->set_size(bytes_recvd);
|
|
|
|
in_buf = std::move(buf);
|
|
|
|
process_recv();
|
|
|
|
}
|
2016-03-15 22:42:13 +01:00
|
|
|
|
2018-07-07 20:27:24 +02:00
|
|
|
void process_recv()
|
|
|
|
{
|
|
|
|
while (in_buf->size())
|
2016-03-15 22:42:13 +01:00
|
|
|
{
|
2018-07-07 20:27:24 +02:00
|
|
|
const char c = (char)in_buf->pop_front();
|
2016-03-15 22:42:13 +01:00
|
|
|
in_partial += c;
|
|
|
|
if (c == '\n')
|
|
|
|
{
|
2018-07-07 20:27:24 +02:00
|
|
|
bool defer = false;
|
2016-03-15 22:42:13 +01:00
|
|
|
try {
|
2018-07-07 20:27:24 +02:00
|
|
|
defer = process_in_line();
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
catch (const std::exception& e)
|
|
|
|
{
|
2016-03-28 09:04:34 +02:00
|
|
|
send("ERROR: in OMI command: " + std::string(e.what()) + "\r\n");
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
in_partial.clear();
|
2018-07-07 20:27:24 +02:00
|
|
|
if (defer)
|
|
|
|
return;
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
queue_recv();
|
|
|
|
}
|
|
|
|
|
|
|
|
void queue_send()
|
|
|
|
{
|
2016-03-28 09:04:34 +02:00
|
|
|
if (!is_sock_open())
|
2016-03-15 22:42:13 +01:00
|
|
|
return;
|
|
|
|
BufferAllocated& buf = *content_out.front();
|
2017-02-27 21:39:02 +01:00
|
|
|
socket->async_send(buf.const_buffer_clamp(),
|
2017-03-30 23:38:32 +02:00
|
|
|
[self=Ptr(this), sock=socket](const openvpn_io::error_code& error, const size_t bytes_sent)
|
2016-03-15 22:42:13 +01:00
|
|
|
{
|
|
|
|
self->handle_send(error, bytes_sent, sock.get());
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2017-03-30 23:38:32 +02:00
|
|
|
void handle_send(const openvpn_io::error_code& error, const size_t bytes_sent,
|
2016-03-15 22:42:13 +01:00
|
|
|
const AsioPolySock::Base* queued_socket)
|
|
|
|
{
|
2016-03-28 09:04:34 +02:00
|
|
|
if (!is_sock_open() || socket.get() != queued_socket)
|
2016-03-15 22:42:13 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (error)
|
|
|
|
{
|
|
|
|
OPENVPN_LOG("client socket send error: " << error.message());
|
2016-03-28 09:04:34 +02:00
|
|
|
conditional_stop(false);
|
2016-03-15 22:42:13 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
BufferPtr buf = content_out.front();
|
|
|
|
if (bytes_sent == buf->size())
|
2016-05-06 00:11:53 +02:00
|
|
|
{
|
|
|
|
content_out.pop_front();
|
|
|
|
if (content_out_throttle)
|
|
|
|
content_out_throttle->size_change(content_out.size());
|
|
|
|
}
|
2016-03-15 22:42:13 +01:00
|
|
|
else if (bytes_sent < buf->size())
|
|
|
|
buf->advance(bytes_sent);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
OPENVPN_LOG("client socket unexpected send size: " << bytes_sent << '/' << buf->size());
|
2016-03-28 09:04:34 +02:00
|
|
|
conditional_stop(false);
|
2016-03-15 22:42:13 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!content_out.empty())
|
|
|
|
queue_send();
|
2016-03-28 09:04:34 +02:00
|
|
|
else if (stop_called)
|
|
|
|
conditional_stop(false);
|
2016-03-15 22:42:13 +01:00
|
|
|
}
|
|
|
|
|
2016-03-28 09:04:34 +02:00
|
|
|
// I/O
|
2016-03-15 22:42:13 +01:00
|
|
|
Acceptor::Base::Ptr acceptor;
|
|
|
|
AsioPolySock::Base::Ptr socket;
|
2018-07-07 20:27:24 +02:00
|
|
|
std::unique_ptr<AsioWork> asio_work;
|
2016-03-15 22:42:13 +01:00
|
|
|
std::deque<BufferPtr> content_out;
|
|
|
|
std::string in_partial;
|
|
|
|
std::unique_ptr<Command> command;
|
2018-07-07 20:27:24 +02:00
|
|
|
BufferPtr in_buf;
|
2016-03-28 09:04:34 +02:00
|
|
|
bool management_client_root = false;
|
2016-03-15 22:42:13 +01:00
|
|
|
bool multiline = false;
|
2016-03-28 09:04:34 +02:00
|
|
|
bool errors_to_stderr = false;
|
2018-07-07 20:27:24 +02:00
|
|
|
bool recv_queued = false;
|
2016-03-28 09:04:34 +02:00
|
|
|
|
|
|
|
// stopping
|
2016-05-06 00:11:53 +02:00
|
|
|
volatile bool stop_called = false;
|
2019-08-30 09:39:29 +02:00
|
|
|
AsioTimerSafe stop_timer;
|
2016-03-28 09:04:34 +02:00
|
|
|
|
|
|
|
// hold
|
|
|
|
bool hold_wait = false;
|
|
|
|
bool hold_flag = false;
|
|
|
|
|
|
|
|
// bandwidth stats
|
|
|
|
unsigned int bytecount = 0;
|
|
|
|
|
|
|
|
// histories
|
|
|
|
History hist_log {"log", 100};
|
|
|
|
History hist_state {"state", 100};
|
|
|
|
History hist_echo {"echo", 100};
|
2016-03-28 22:52:18 +02:00
|
|
|
|
2016-05-06 00:11:53 +02:00
|
|
|
// throttling
|
|
|
|
std::unique_ptr<BufferThrottle> content_out_throttle;
|
|
|
|
|
2016-03-28 22:52:18 +02:00
|
|
|
#if defined(OPENVPN_PLATFORM_WIN)
|
|
|
|
Win::ScopedHANDLE log_handle;
|
|
|
|
#endif
|
2016-03-15 22:42:13 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|