21#include <unordered_map>
50#ifdef VPN_BINDING_PROFILES
54#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
55#include <openvpn/kovpn/sock_mark.hpp>
62#if defined(OPENVPN_PLATFORM_WIN)
65#ifdef ASIO_HAS_LOCAL_SOCKETS
69#ifndef OPENVPN_HTTP_SERV_RC
70#define OPENVPN_HTTP_SERV_RC RC<thread_unsafe_refcount>
104 static const char *error_names[] = {
115 "E_PIPELINE_OVERFLOW",
120 static_assert(
N_ERRORS ==
array_size(error_names),
"HTTP error names array inconsistency");
122 return error_names[status];
133#if defined(OPENVPN_PLATFORM_WIN)
134 std::string sddl_string;
136#ifdef ASIO_HAS_LOCAL_SOCKETS
137 mode_t unix_mode = 0;
208 socket(std::move(socket_arg)),
237 return sock->remote_ip_port(addr,
port);
268 return sock->is_local();
275#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
276 return is_alt_routing_;
286 sock(std::move(ci.socket)),
357 return sock->remote_endpoint_str();
359 catch (
const std::exception &)
362 return "[unknown endpoint]";
375#ifdef ASIO_HAS_LOCAL_SOCKETS
378 AsioPolySock::Unix *uds =
dynamic_cast<AsioPolySock::Unix *
>(
sock.
get());
380 return uds->socket.native_handle();
406 os <<
"Server: " <<
parent->
config->http_server_id <<
"\r\n";
410 os <<
"WWW-Authenticate: Basic realm=\"" <<
content_info.basic_realm <<
"\"\r\n";
414 os <<
"Content-Length: " <<
content_info.length <<
"\r\n";
416 os <<
"Transfer-Encoding: chunked\r\n";
420 os <<
"Content-Encoding: " <<
content_info.content_encoding <<
"\r\n";
422 os <<
"Cache-Control: no-cache, no-store, must-revalidate\r\n";
424 os <<
"Connection: keep-alive\r\n";
426 os <<
"Connection: close\r\n";
432 os <<
"HTTP/1.1 101 Switching Protocols\r\n";
466 link->set_raw_mode(
true);
474#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
475 case Acceptor::Item::AltRouting:
476 is_alt_routing_ =
true;
496 void stop(
const bool remove_self_from_map,
const bool shutdown)
513 if (remove_self_from_map)
531 self->timeout_callback(error); });
589 catch (
const std::exception &e)
605 catch (
const std::exception &e)
621 catch (
const std::exception &e)
670 return link->send(buf);
675 return link->send_queue_empty();
679 const bool parent_handoff)
698 error_handler(errcode, std::string(
"HTTPCore Asio ") + func_name +
": " + error.message());
708 const bool shutdown =
http_stop(errcode, err);
710 stop(
true, shutdown);
750 virtual bool http_stop(
const int status,
const std::string &description)
768#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
769 bool is_alt_routing_ =
false;
776 template <
typename L>
779 const L &listen_item_or_list,
797 switch (listen_item.proto())
805 switch (listen_item.ssl)
812 throw http_server_exception(
"listen item has 'ssl' qualifier, but no SSL configuration");
817#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
818 case Listen::Item::AltRouting:
819 ssl_mode = Acceptor::Item::AltRouting;
830#ifdef VPN_BINDING_PROFILES
833 const IP::Addr ip_addr(listen_item.addr, listen_item.directive);
835 a->local_endpoint.address(ip_addr.
to_asio());
839 a->acceptor.open(a->local_endpoint.protocol());
842 a->set_socket_options(
config->sockopt_flags);
845#ifdef OPENVPN_DEBUG_ACCEPT
846 OPENVPN_LOG(
"ACCEPTOR BIND " << a->local_endpoint);
848 a->acceptor.bind(a->local_endpoint);
851 a->acceptor.listen(
config->tcp_backlog);
854 acceptors.emplace_back(std::move(a), ssl_mode);
860#if defined(OPENVPN_PLATFORM_WIN)
863 OPENVPN_LOG(
"HTTP Listen: " << listen_item.to_string());
876#ifdef ASIO_HAS_LOCAL_SOCKETS
879 OPENVPN_LOG(
"HTTP Listen: " << listen_item.to_string());
884 a->pre_listen(listen_item.addr);
885 a->local_endpoint.path(listen_item.addr);
888 a->acceptor.open(a->local_endpoint.protocol());
891 a->acceptor.bind(a->local_endpoint);
894 a->set_socket_permissions(listen_item.addr,
config->unix_mode);
897 a->acceptor.listen();
908 throw http_server_exception(
"listen on unknown protocol");
926 c.second->stop(
false,
false);
934 template <
typename CLIENT_INSTANCE,
typename FUNC>
938 func(*
static_cast<CLIENT_INSTANCE *
>(c.second.get()));
942 typedef std::unordered_map<client_t, Client::Ptr>
ClientMap;
951 if (
config->tcp_throttle_max_connections_per_period)
990 if (self->halt || error)
992 self->throttle_timer_callback(); });
1014 const size_t acceptor_index = sock->index();
1022#ifdef OPENVPN_DEBUG_ACCEPT
1023 OPENVPN_LOG(
"ACCEPT from " << sock->remote_endpoint_str());
1026 sock->non_blocking(
true);
1027 sock->set_cloexec();
1028 sock->tcp_nodelay();
1031 throw http_server_exception(
"max clients exceeded");
1033 throw http_server_exception(
"client socket rejected");
1035#ifdef OPENVPN_POLYSOCK_SUPPORTS_ALT_ROUTING
1036 if (ssl_mode == Acceptor::Item::AltRouting)
1038 const KovpnSockMark ksm(sock->native_handle());
1039 if (!ksm.is_internal())
1040 throw http_server_exception(
"non alt-routing socket: " + ksm.to_string());
1049 cli->start(ssl_mode);
1052 throw http_server_exception(
"accept failed: " + error.message());
1054 catch (
const std::exception &e)
1056 OPENVPN_LOG(
"exception in handle_accept: " << e.what());
1080 ClientMap::const_iterator e =
clients.find(client_id);
1090#ifdef VPN_BINDING_PROFILES
std::size_t expires_at(const Time &t)
void async_wait(F &&func)
bool similar(const Time &t) const
void init(const Time::Duration &pre, const Time::Duration &post)
void reset(const Time &t)
bool empty() const
Returns true if the buffer is empty.
openvpn_io::ip::address to_asio() const
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
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.
virtual const AuthCert::Ptr & auth_cert() const =0
LinkCommon< Protocol, ReadHandler, RAW_MODE_ONLY > Base
const HTTP::HeaderList & headers() const
void tcp_in(BufferAllocated &b)
void set_async_out(const bool async_out_arg)
CONTENT_INFO content_info
const REQUEST_REPLY::State & request_reply() const
Initializer(openvpn_io::io_context &io_context_arg, Listener *parent_arg, AsioPolySock::Base::Ptr &&socket_arg, const client_t client_id_arg)
openvpn_io::io_context & io_context
AsioPolySock::Base::Ptr socket
std::string remote_endpoint_str() const
std::deque< BufferAllocated > pipeline
virtual void http_content_in(BufferAllocated &buf)
BufferPtr base_http_content_out()
virtual bool http_stop(const int status, const std::string &description)
void base_http_done_handler(BufferAllocated &residual, const bool parent_handoff)
void generate_reply_headers_http(std::ostream &os)
virtual void http_destroy()
bool is_alt_routing() const
bool base_http_headers_received()
virtual void tcp_intercept(BufferAllocated &b)
void asio_error_handler(int errcode, const char *func_name, const openvpn_io::error_code &error)
void generate_reply_headers(ContentInfo ci)
IP::Addr remote_ip() const
virtual bool http_out_eof()
TCPTransport::TCPLink< AsioProtocol, Client *, false > LinkImpl
AsioPolySock::Base::Ptr sock
virtual BufferPtr http_content_out()
virtual void http_request_received()
void base_http_content_out_needed()
client_t get_client_id() const
void tcp_write_queue_needs_send()
virtual bool http_headers_received()
void start(const Acceptor::Item::SSLMode ssl_mode)
Listener * get_parent() const
bool base_link_send(BufferAllocated &buf)
bool tcp_read_handler(BufferAllocated &b)
void timeout_callback(const openvpn_io::error_code &e)
bool remote_ip_port(IP::Addr &addr, unsigned int &port) const
void handle_exception(const char *func_name, const std::exception &e)
void external_stop(const std::string &description)
void stop(const bool remove_self_from_map, const bool shutdown)
virtual void http_content_out_needed()
AsioTimerSafe timeout_timer
void cancel_general_timeout()
void base_http_content_in(BufferAllocated &buf)
void abort(const std::string &description, const int status=Status::E_ABORTED)
void error_handler(const int errcode, const std::string &err)
CoarseTime timeout_coarse
Time::Duration timeout_duration
bool base_send_queue_empty()
void tcp_error_handler(const char *error)
virtual void http_pipeline_peek(BufferAllocated &buf)
const HTTP::Request & request() const
void generate_reply_headers_websocket(std::ostream &os)
void base_error_handler(const int errcode, const std::string &err)
AuthCert::Ptr auth_cert() const
openvpn_io::io_context & io_context
virtual void http_headers_sent(const Buffer &buf)
void restart(const bool initial)
void generate_custom_reply_headers(BufferPtr &&buf)
void add_to_pipeline(BufferAllocated &buf)
void remove_client(Client::Ptr cli)
virtual bool allow_client(AsioPolySock::Base &sock)
void throttle_timer_callback()
void walk(FUNC func) const
std::deque< size_t > throttle_acceptor_indices
AsioTimerSafe throttle_timer
void handle_accept(AsioPolySock::Base::Ptr sock, const openvpn_io::error_code &error) override
void throttle_reset(const Time &now, const bool debit_one)
std::unordered_map< client_t, Client::Ptr > ClientMap
void remove_client_id(const client_t client_id)
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)
WS::HTTPBase< Client, Config, Status, HTTP::RequestType, ContentInfo, content_len_t, OPENVPN_HTTP_SERV_RC > Base
void throttle_timer_wait()
void queue_accept(const size_t acceptor_index)
Client::Factory::Ptr client_factory
void queue_accept_throttled(const size_t acceptor_index, const bool debit_one)
static IP::Addr server_local_addr(const LISTEN_ITEM &listen_item, const GatewayType gw_type)
#define OPENVPN_EXCEPTION(C)
#define OPENVPN_HTTP_SERV_RC
#define OPENVPN_LOG(args)
const char * to_string(const int status)
unsigned short parse_port(const std::string &port, const std::string &title)
std::int64_t content_len_t
constexpr std::size_t array_size(T(&)[N])
std::string date_time_rfc822()
RCPtr< BufferAllocatedRc > BufferPtr
@ GROW
if enabled, buffer will grow (otherwise buffer_full exception will be thrown)
unsigned int tcp_throttle_max_connections_per_period
SSLFactoryAPI::Ptr ssl_factory
unsigned int max_header_bytes
std::string http_server_id
content_len_t max_content_bytes
unsigned int send_queue_max_size
unsigned int free_list_max_size
unsigned int general_timeout
Time::Duration tcp_throttle_period
unsigned int sockopt_flags
unsigned int pipeline_max_size
unsigned int msg_overhead_bytes
std::vector< std::string > extra_headers
std::string http_status_str
WebSocket::Server::PerRequest::Ptr websocket
static constexpr content_len_t CHUNKED
std::string content_encoding
AsioPolySock::Base socket
virtual Client::Ptr new_client(Initializer &ci)=0
static std::string error_str(const size_t status)