27#define HTTP_SERVER_VERSION OPENVPN_STRINGIZE(VERSION)
29#define HTTP_SERVER_VERSION "0.1.1"
33#define OVPNAGENT_NAME_STRING OPENVPN_STRINGIZE(OVPNAGENT_NAME)
35#define OVPNAGENT_NAME_STRING "ovpnagent"
63 <<
" built on " __DATE__
" " __TIME__
75 void error(
const size_t err_type,
const std::string *text =
nullptr)
override
82 std::ostringstream
os;
83 os <<
"OpenVPN Agent Stats" << std::endl;
90 ThreadCommon(
const char *unix_sock,
const char *user,
const char *group)
108 ll.push_back(std::move(li));
160 OPENVPN_LOG(
"Setting up watchdog for pid " << pid <<
" exit notification");
169 fcntl(
fds[1], F_SETFL, O_NONBLOCK);
174 OPENVPN_LOG(
"kqueue() failed: " << strerror(errno));
180 struct kevent chlist[2];
181 EV_SET(&chlist[0], pid, EVFILT_PROC, EV_ADD | EV_RECEIPT, NOTE_EXIT, 0, NULL);
182 EV_SET(&chlist[1],
fds[0], EVFILT_READ, EV_ADD, 0, 0, NULL);
183 if (kevent(
kq, chlist, 2, NULL, 0, NULL) == -1)
185 OPENVPN_LOG(
"kevent() failed: " << strerror(errno));
199 th = std::thread([self =
Ptr(
this), pid]()
201 struct kevent evlist[2];
202 int nev = kevent(self->kq, 0, 0, evlist, 2, NULL);
205 OPENVPN_LOG(
"kevent() failed: " << strerror(errno));
206 self->close_pipe_fds();
210 for (
int i = 0; i < nev; ++ i)
212 if (evlist[i].filter == EVFILT_PROC)
214 openvpn_io::post(self->io_context, [self, pid]() {
215 OPENVPN_LOG(
"Process " << pid <<
" has exited, destroy tun");
216 std::ostringstream os;
217 self->parent->destroy_tun(os);
222 self->client_pid = -1;
223 self->close_pipe_fds(); });
229 write(
fds[1],
"x", 1);
302 std::ostringstream
os;
347 ci.
type =
"application/json";
356 std::ostringstream
os;
361 OPENVPN_LOG(
"HTTP request received from " <<
sock->remote_endpoint_str() <<
'\n'
375 if (!root.isObject())
376 throw Exception(
"json parse error: top level json object is not a dictionary");
378 if (req.
uri ==
"/tun-setup")
399 Json::Value jout(Json::objectValue);
401 jout[
"config"] =
config.to_json();
404 else if (req.
uri ==
"/add-bypass-route")
414 Json::Value jout(Json::objectValue);
418 else if (req.
method ==
"GET" && req.
uri ==
"/tun-destroy")
424 Json::Value jout(Json::objectValue);
433 ci.
type =
"text/plain";
438 catch (
const std::exception &e)
443 ci.
type =
"text/plain";
478 if (buf.
size() == 1 && buf.
front() ==
't')
480 const int fd = unix_fd();
491 bool http_stop(
const int status,
const std::string &description)
override
504 std::ostringstream
os;
590void work(openvpn_io::io_context &io_context,
593 const unsigned int unit)
629 const unsigned int unit)
632 openvpn_io::io_context io_context(1);
638 work(io_context, tc, runctx, unit);
640 catch (
const std::exception &e)
642 OPENVPN_LOG(
"Worker thread exception: " << e.what());
648 const bool log_append,
654 daemonize(log_fn,
nullptr, log_append, 0);
666 runctx->set_stats_obj(tc.
stats);
670 const unsigned int thread_num = 0;
671 std::thread *thread =
new std::thread([&tc, &runctx]()
673 runctx->set_thread(thread_num, thread);
692int main(
int argc,
char *argv[])
694 static const struct option longopts[] = {
695 {
"help", no_argument,
nullptr,
'h'},
696 {
"append", no_argument,
nullptr,
'a'},
697 {
"daemon", required_argument,
nullptr,
'd'},
698 {
"pidfile", required_argument,
nullptr,
'p'},
699 {
"user", required_argument,
nullptr,
'u'},
700 {
"group", required_argument,
nullptr,
'g'},
701 {
nullptr, 0,
nullptr, 0}};
706 const char *logfile =
nullptr;
707 const char *pidfile =
nullptr;
708 const char *user =
nullptr;
709 const char *group =
nullptr;
715#if defined(USE_MBEDTLS) && defined(OPENVPN_SSL_DEBUG)
716 debug_set_threshold(OPENVPN_SSL_DEBUG);
725 while ((ch = getopt_long(argc, argv,
"had:p:u:g:", longopts,
nullptr)) != -1)
753 catch (
const usage &)
756 std::cout <<
"usage: ovpnagent [options]" << std::endl;
757 std::cout <<
" --daemon <file>, -d : daemonize, log to file" << std::endl;
758 std::cout <<
" --append, -a : append to log file" << std::endl;
759 std::cout <<
" --pidfile <file>, -p : write pid to file" << std::endl;
760 std::cout <<
" --user <user>, -u : set UID to user" << std::endl;
761 std::cout <<
" --group <group>, -g : set group" << std::endl;
764 catch (
const std::exception &e)
766 std::cout <<
"Main thread exception: " << e.what() << std::endl;
WS::Server::Listener::Client::Ptr new_client(WS::Server::Listener::Client::Initializer &ci) override
RCPtr< MyClientFactory > Ptr
void http_content_in(BufferAllocated &buf) override
bool http_stop(const int status, const std::string &description) override
void generate_reply(const Json::Value &jout)
MyClientInstance(WS::Server::Listener::Client::Initializer &ci)
bool http_out_eof() override
void http_request_received() override
BufferPtr http_content_out() override
virtual ~MyClientInstance()=default
void http_pipeline_peek(BufferAllocated &buf) override
RCPtr< MyClientInstance > Ptr
WatchdogThread(MyListener *parent_arg, openvpn_io::io_context &io_context_arg)
openvpn_io::io_context & io_context
RCPtr< WatchdogThread > Ptr
bool allow_client(AsioPolySock::Base &sock) override
void set_watchdog(pid_t pid)
ActionList remove_cmds_bypass_hosts
WatchdogThread::Ptr watchdog
void destroy_tun(std::ostream &os)
void add_bypass_route(const std::string &host, bool ipv6)
MyListener(openvpn_io::io_context &io_context, const WS::Server::Config::Ptr &config, const Listen::List &listen_list, const WS::Server::Listener::Client::Factory::Ptr &client_factory)
ScopedFD establish_tun(const TunBuilderCapture &tbc, TunBuilderSetup::Config *config, Stop *stop, std::ostream &os)
void error(const size_t err_type, const std::string *text=nullptr) override
RCPtr< MySessionStats > Ptr
RCPtr< ServerThread > Ptr
ServerThread(openvpn_io::io_context &io_context_arg, ThreadCommon &tc)
openvpn_io::io_context & io_context
void thread_safe_stop() override
virtual std::unordered_set< std::string > execute(std::ostream &os)
Executes a sequence of actions and returns marks of failed actions.
bool defined() const
Returns true if the buffer is not empty.
T front() const
Returns the first element of the buffer.
size_t size() const
Returns the size of the buffer in T objects.
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.
static Ptr Create(ArgsT &&...args)
Creates a new instance of RcEnable with the given arguments.
void set_server(const unsigned int unit, ServerThread *serv)
void clear_server(const unsigned int unit)
const Log::Context::Wrapper & log_wrapper()
void reset(const int fd_arg)
void validate() const
Validates the configuration of the tunnel.
static TunBuilderCapture::Ptr from_json(const Json::Value &root)
Creates a TunBuilderCapture instance from a JSON representation.
bool add_bypass_route(const std::string &address, bool ipv6, std::ostream &os)
void generate_reply_headers(ContentInfo ci)
AsioPolySock::Base::Ptr sock
Listener * get_parent() const
void external_stop(const std::string &description)
const HTTP::Request & request() const
openvpn_io::io_context & io_context
Listener(openvpn_io::io_context &io_context_arg, const Config::Ptr &config_arg, const L &listen_item_or_list, const Client::Factory::Ptr &client_factory_arg)
Client::Factory::Ptr client_factory
static void xmit_fd(const int sock_fd, const int payload_fd, const std::string &message, const int timeout_ms)
static void worker_thread()
#define OPENVPN_SIMPLE_EXCEPTION(C)
#define OPENVPN_THROW_EXCEPTION(stuff)
#define OPENVPN_LOG_NTNL(args)
#define OPENVPN_LOG(args)
int main(int argc, char *argv[])
void work(openvpn_io::io_context &io_context, ThreadCommon &tc, MyRunContext &runctx, const unsigned int unit)
RunContext< ServerThreadBase, MySessionStats > MyRunContext
int ovpnagent(const char *sock_fn, const char *log_fn, const bool log_append, const char *pid_fn, const char *user, const char *group)
#define HTTP_SERVER_VERSION
#define OVPNAGENT_NAME_STRING
const char * name(const size_t type)
bool get_bool(const Json::Value &root, const NAME &name, const TITLE &title)
const Json::Value & get_dict(const Json::Value &root, const NAME &name, const bool optional, const TITLE &title)
int get_int_optional(const Json::Value &root, const NAME &name, const int default_value, const TITLE &title)
Json::Value parse(const std::string &str, const TITLE &title)
std::string get_string(const Json::Value &root, const NAME &name, const TITLE &title)
std::string remove_blanks(const std::string &str)
int strcasecmp(const char *s1, const char *s2)
Frame::Ptr frame_init_simple(const size_t payload)
void event_loop_wait_barrier(THREAD_COMMON &tc, const unsigned int seconds=WAIT_BARRIER_TIMEOUT)
void write_pid(const std::string &fn)
BufferPtr buf_from_string(const std::string &str)
ThreadCommon(const char *unix_sock, const char *user, const char *group)
MySessionStats::Ptr stats
PThreadBarrier event_loop_bar
const SetUserGroup user_group
void show_unused_options() const
static Listen::List build_listen_list(const char *unix_sock)
const Listen::List listen_list
std::string to_string() const
std::string to_string() const
Scoped RAII for the global_log pointer.
void from_json(const Json::Value &root, const std::string &title) override
static std::string error_str(const size_t status)
const TunBuilderCapture::Ptr tbc(new TunBuilderCapture)
static const char config[]