From 490373480d7625ff67f7a69ae7706cd77353a94e Mon Sep 17 00:00:00 2001 From: Stas Skokov <7090stas@gmail.com> Date: Sun, 18 Jan 2026 14:54:18 +1100 Subject: [PATCH] Add SNI whitelist and default proxy domain for probing protection --- deploy/docker/scripts/start-fptn.sh | 6 +- deploy/linux/deb/create-server-deb-package.sh | 17 ++++- docker-compose/.env.demo | 15 +++- docker-compose/docker-compose.yml | 2 + .../config/command_line_config.cpp | 40 ++++++++++- src/fptn-server/config/command_line_config.h | 4 ++ src/fptn-server/fptn-server.cpp | 19 ++++- src/fptn-server/web/listener/listener.cpp | 14 +++- src/fptn-server/web/listener/listener.h | 5 ++ src/fptn-server/web/server.cpp | 12 +++- src/fptn-server/web/server.h | 5 ++ src/fptn-server/web/session/session.cpp | 72 ++++++++++++++----- src/fptn-server/web/session/session.h | 6 ++ 13 files changed, 188 insertions(+), 29 deletions(-) diff --git a/deploy/docker/scripts/start-fptn.sh b/deploy/docker/scripts/start-fptn.sh index 0cdc8b2..52c6266 100644 --- a/deploy/docker/scripts/start-fptn.sh +++ b/deploy/docker/scripts/start-fptn.sh @@ -6,9 +6,11 @@ echo "[FPTN] Using network interface: $OUT_NETWORK_INTERFACE" exec /usr/local/bin/fptn-server \ --server-key=/etc/fptn/server.key \ --server-crt=/etc/fptn/server.crt \ - --out-network-interface="$OUT_NETWORK_INTERFACE" \ + --out-network-interface="${OUT_NETWORK_INTERFACE}" \ --server-port=443 \ - --enable-detect-probing="$ENABLE_DETECT_PROBING" \ + --enable-detect-probing="${ENABLE_DETECT_PROBING}" \ + --default-proxy-domain="${DEFAULT_PROXY_DOMAIN}" \ + --allowed-sni-list="${ALLOWED_SNI_LIST}" \ --tun-interface-name=fptn0 \ --disable-bittorrent="$DISABLE_BITTORRENT" \ --prometheus-access-key="$PROMETHEUS_SECRET_ACCESS_KEY" \ diff --git a/deploy/linux/deb/create-server-deb-package.sh b/deploy/linux/deb/create-server-deb-package.sh index 2cccdbe..9cbac39 100755 --- a/deploy/linux/deb/create-server-deb-package.sh +++ b/deploy/linux/deb/create-server-deb-package.sh @@ -48,7 +48,20 @@ TUN_INTERFACE_NAME=fptn0 # Enable detection of probing attempts (experimental; accepted values: true or false) ENABLE_DETECT_PROBING=false -# true or false +# Default domain where non-VPN client traffic will be redirected +# When someone scans your server (not using VPN), their connection will be forwarded to this domain instead +DEFAULT_PROXY_DOMAIN=cdnvideo.com + +# Comma-separated list of allowed website domains for non-VPN clients +# This acts like a "whitelist" of websites that scanning bots are allowed to reach +# Behavior logic: +# - List is empty (default): proxy all non-VPN traffic to DEFAULT_PROXY_DOMAIN +# - List is NOT empty: use as whitelist: +# - Client SNI in list -> proxy to client's SNI\ +# - Client SNI not in list -> proxy to --default-proxy-domain +ALLOWED_SNI_LIST= + +# Block BitTorrent traffic to prevent abuse (accepted values: true or false) DISABLE_BITTORRENT=true # Set the USE_REMOTE_SERVER_AUTH variable to true if you need to @@ -90,6 +103,8 @@ ExecStart=/usr/bin/$(basename "$SERVER_BIN") \ --out-network-interface=\${OUT_NETWORK_INTERFACE} \ --server-port=\${PORT} \ --enable-detect-probing=\${ENABLE_DETECT_PROBING} \ + --default-proxy-domain=\${DEFAULT_PROXY_DOMAIN} \ + --allowed-sni-list=\${ALLOWED_SNI_LIST} \ --tun-interface-name=\${TUN_INTERFACE_NAME} \ --disable-bittorrent=\${DISABLE_BITTORRENT} \ --prometheus-access-key=\${PROMETHEUS_SECRET_ACCESS_KEY} \ diff --git a/docker-compose/.env.demo b/docker-compose/.env.demo index 35a39c5..46e4a55 100644 --- a/docker-compose/.env.demo +++ b/docker-compose/.env.demo @@ -9,7 +9,20 @@ SERVER_EXTERNAL_IPS= # Enable detection of probing attempts (accepted values: true or false) ENABLE_DETECT_PROBING=true -# true or false +# Default domain where non-VPN client traffic will be redirected +# When someone scans your server (not using VPN), their connection will be forwarded to this domain instead +DEFAULT_PROXY_DOMAIN=cdnvideo.com + +# Comma-separated list of allowed website domains for non-VPN clients +# This acts like a "whitelist" of websites that scanning bots are allowed to reach +# Behavior logic: +# - List is empty (default): proxy all non-VPN traffic to DEFAULT_PROXY_DOMAIN +# - List is NOT empty: use as whitelist: +# - Client SNI in list -> proxy to client's SNI\ +# - Client SNI not in list -> proxy to --default-proxy-domain +ALLOWED_SNI_LIST= + +# Block BitTorrent traffic to prevent abuse (accepted values: true or false) DISABLE_BITTORRENT=true # Set the USE_REMOTE_SERVER_AUTH variable to true if you need to diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml index a78d2a4..10f67f6 100644 --- a/docker-compose/docker-compose.yml +++ b/docker-compose/docker-compose.yml @@ -30,6 +30,8 @@ services: - ./fptn-server-data:/etc/fptn environment: - ENABLE_DETECT_PROBING=${ENABLE_DETECT_PROBING} + - DEFAULT_PROXY_DOMAIN=${DEFAULT_PROXY_DOMAIN} + - ALLOWED_SNI_LIST=${ALLOWED_SNI_LIST} - DISABLE_BITTORRENT=${DISABLE_BITTORRENT} - PROMETHEUS_SECRET_ACCESS_KEY=${PROMETHEUS_SECRET_ACCESS_KEY} - USE_REMOTE_SERVER_AUTH=${USE_REMOTE_SERVER_AUTH} diff --git a/src/fptn-server/config/command_line_config.cpp b/src/fptn-server/config/command_line_config.cpp index f8f07df..eaa639d 100644 --- a/src/fptn-server/config/command_line_config.cpp +++ b/src/fptn-server/config/command_line_config.cpp @@ -9,9 +9,12 @@ Distributed under the MIT License (https://opensource.org/licenses/MIT) #include #include #include +#include #include // NOLINT(build/include_order) +#include "common/utils/utils.h" + namespace { bool ParseBoolean(std::string value) noexcept { try { @@ -105,11 +108,26 @@ CommandLineConfig::CommandLineConfig(int argc, char* argv[]) .help("Maximum number of active sessions allowed per VPN user") .default_value(3) .scan<'i', int>(); + // Probing args_.add_argument("--enable-detect-probing") .help( "Enable detection of non-FPTN clients or probing attempts during SSL " "handshake. ") .default_value("false"); + args_.add_argument("--default-proxy-domain") + .help("Default domain for proxying non-VPN clients.") + .default_value(FPTN_DEFAULT_SNI); + args_.add_argument("--allowed-sni-list") + .help( + "Comma-separated list of allowed SNI hostnames for non-VPN clients.\n" + "Behavior logic:\n" + " - List is empty (default): proxy all non-VPN traffic to " + "--default-proxy-domain\n" + " - List is NOT empty: use as whitelist:\n" + " - Client SNI in list -> proxy to client's SNI\n" + " - Client SNI not in list -> proxy to --default-proxy-domain") + .default_value(""); + // Prevent self-proxy args_.add_argument("--server-external-ips") .help( "Public IPv4 address of this VPN server. " @@ -204,12 +222,32 @@ bool CommandLineConfig::EnableDetectProbing() const { return ParseBoolean(args_.get("--enable-detect-probing")); } +[[nodiscard]] +std::string CommandLineConfig::DefaultProxyDomain() const { + auto default_domain = args_.get("--default-proxy-domain"); + if (default_domain.empty()) { + return FPTN_DEFAULT_SNI; + } + return default_domain; +} + +[[nodiscard]] +std::vector CommandLineConfig::AllowedSniList() const { + const auto allowed_sni = args_.get("--allowed-sni-list"); + if (!allowed_sni.empty()) { + return common::utils::SplitCommaSeparated( + allowed_sni + "," + DefaultProxyDomain()); + } + return {}; +} + std::size_t CommandLineConfig::MaxActiveSessionsPerUser() const { return static_cast( args_.get("--max-active-sessions-per-user")); } -[[nodiscard]] std::string CommandLineConfig::ServerExternalIPs() const { +[[nodiscard]] +std::string CommandLineConfig::ServerExternalIPs() const { return args_.get("--server-external-ips"); } diff --git a/src/fptn-server/config/command_line_config.h b/src/fptn-server/config/command_line_config.h index a1adfab..8d19c87 100644 --- a/src/fptn-server/config/command_line_config.h +++ b/src/fptn-server/config/command_line_config.h @@ -7,6 +7,7 @@ Distributed under the MIT License (https://opensource.org/licenses/MIT) #pragma once #include +#include #include // NOLINT(build/include_order) @@ -49,6 +50,9 @@ class CommandLineConfig { [[nodiscard]] bool EnableDetectProbing() const; + [[nodiscard]] std::string DefaultProxyDomain() const; + [[nodiscard]] std::vector AllowedSniList() const; + [[nodiscard]] std::size_t MaxActiveSessionsPerUser() const; [[nodiscard]] std::string ServerExternalIPs() const; diff --git a/src/fptn-server/fptn-server.cpp b/src/fptn-server/fptn-server.cpp index f9a77d4..fe8ad9f 100644 --- a/src/fptn-server/fptn-server.cpp +++ b/src/fptn-server/fptn-server.cpp @@ -10,6 +10,7 @@ Distributed under the MIT License (https://opensource.org/licenses/MIT) #include #include +#include // NOLINT(build/include_order) #include "common/jwt_token/token_manager.h" #include "common/logger/logger.h" @@ -105,8 +106,13 @@ int main(int argc, char* argv[]) { auto web_server = std::make_unique(config.ServerPort(), nat_table, user_manager, token_manager, prometheus, config.PrometheusAccessKey(), config.TunInterfaceIPv4(), - config.TunInterfaceIPv6(), config.EnableDetectProbing(), + config.TunInterfaceIPv6(), + /* probing */ + config.EnableDetectProbing(), config.DefaultProxyDomain(), + config.AllowedSniList(), + /* sessions */ config.MaxActiveSessionsPerUser(), + /* External IPs */ config.ServerExternalIPs()); /* init packet filter */ @@ -131,11 +137,19 @@ int main(int argc, char* argv[]) { "VPN NETWORK IPv6: {}\n" "VPN SERVER PORT: {}\n" "DETECT_PROBING: {}\n" + "DEFAULT_PROXY_DOMAIN: {}\n" + "ALLOWED_SNI_LIST: {}\n" "MAX_ACTIVE_SESSIONS_PER_USER: {}\n", - FPTN_VERSION, config.OutNetworkInterface(), + FPTN_VERSION, + // Network settings + config.OutNetworkInterface(), config.TunInterfaceNetworkIPv4Address().ToString(), config.TunInterfaceNetworkIPv6Address().ToString(), config.ServerPort(), + // Probing settings config.EnableDetectProbing() ? "YES" : "NO", + config.DefaultProxyDomain(), + fmt::format("[{}]", fmt::join(config.AllowedSniList(), ", ")), + // max session config.MaxActiveSessionsPerUser()); // Init vpn manager @@ -147,6 +161,7 @@ int main(int argc, char* argv[]) { manager.Start(); WaitForSignal(); manager.Stop(); + return EXIT_SUCCESS; } catch (const std::exception& ex) { SPDLOG_ERROR("An error occurred: {}. Exiting...", ex.what()); diff --git a/src/fptn-server/web/listener/listener.cpp b/src/fptn-server/web/listener/listener.cpp index 942f5e4..bef097a 100644 --- a/src/fptn-server/web/listener/listener.cpp +++ b/src/fptn-server/web/listener/listener.cpp @@ -9,6 +9,7 @@ Distributed under the MIT License (https://opensource.org/licenses/MIT) #include #include #include +#include #include #include @@ -24,6 +25,8 @@ using fptn::web::Listener; Listener::Listener(std::uint16_t port, bool enable_detect_probing, + std::string default_proxy_domain, + std::vector allowed_sni_list, boost::asio::io_context& ioc, fptn::common::jwt_token::TokenManagerSPtr token_manager, HandshakeCacheManagerSPtr handshake_cache_manager, @@ -33,6 +36,8 @@ Listener::Listener(std::uint16_t port, WebSocketCloseConnectionCallback ws_close_callback) : port_(port), enable_detect_probing_(enable_detect_probing), + default_proxy_domain_(std::move(default_proxy_domain)), + allowed_sni_list_(std::move(allowed_sni_list)), ioc_(ioc), ctx_(boost::asio::ssl::context::tlsv13_server), acceptor_(ioc_), @@ -81,9 +86,12 @@ boost::asio::awaitable Listener::Run() { co_await acceptor_.async_accept( socket, boost::asio::redirect_error(boost::asio::use_awaitable, ec)); if (!ec) { - auto session = std::make_shared(port_, enable_detect_probing_, - server_external_ips_, std::move(socket), ctx_, api_handles_, - handshake_cache_manager_, ws_open_callback_, + auto session = std::make_shared(port_, + // probing settings + enable_detect_probing_, default_proxy_domain_, allowed_sni_list_, + server_external_ips_, std::move(socket), ctx_, + // handlers + api_handles_, handshake_cache_manager_, ws_open_callback_, ws_new_ippacket_callback_, ws_close_callback_); // run coroutine boost::asio::co_spawn( diff --git a/src/fptn-server/web/listener/listener.h b/src/fptn-server/web/listener/listener.h index 5681884..97a8e32 100644 --- a/src/fptn-server/web/listener/listener.h +++ b/src/fptn-server/web/listener/listener.h @@ -9,6 +9,7 @@ Distributed under the MIT License (https://opensource.org/licenses/MIT) #include #include #include +#include #include #include @@ -27,6 +28,8 @@ class Listener final { public: explicit Listener(std::uint16_t port, bool enable_detect_probing, + std::string default_proxy_domain, + std::vector allowed_sni_list, boost::asio::io_context& ioc, fptn::common::jwt_token::TokenManagerSPtr token_manager, HandshakeCacheManagerSPtr handshake_cache_manager, @@ -44,6 +47,8 @@ class Listener final { protected: const std::uint16_t port_; const bool enable_detect_probing_; + const std::string default_proxy_domain_; + const std::vector allowed_sni_list_; boost::asio::io_context& ioc_; boost::asio::ssl::context ctx_; diff --git a/src/fptn-server/web/server.cpp b/src/fptn-server/web/server.cpp index 9da0ff7..da06424 100644 --- a/src/fptn-server/web/server.cpp +++ b/src/fptn-server/web/server.cpp @@ -11,6 +11,7 @@ Distributed under the MIT License (https://opensource.org/licenses/MIT) #include #include #include +#include #include // NOLINT(build/include_order) @@ -27,6 +28,8 @@ Server::Server(std::uint16_t port, fptn::common::network::IPv4Address dns_server_ipv4, fptn::common::network::IPv6Address dns_server_ipv6, bool enable_detect_probing, + std::string default_proxy_domain, + std::vector allowed_sni_list, std::size_t max_active_sessions_per_user, std::string server_external_ips, int thread_number) @@ -40,6 +43,8 @@ Server::Server(std::uint16_t port, dns_server_ipv4_(std::move(dns_server_ipv4)), dns_server_ipv6_(std::move(dns_server_ipv6)), enable_detect_probing_(enable_detect_probing), + default_proxy_domain_(std::move(default_proxy_domain)), + allowed_sni_list_(std::move(allowed_sni_list)), max_active_sessions_per_user_(max_active_sessions_per_user), server_external_ips_(std::move(server_external_ips)), thread_number_(std::max(1, thread_number)), @@ -56,8 +61,11 @@ Server::Server(std::uint16_t port, handshake_cache_manager_ = std::make_shared(ioc_); - listener_ = std::make_shared(port_, enable_detect_probing_, ioc_, - token_manager, handshake_cache_manager_, server_external_ips_, + listener_ = std::make_shared(port_, + // proxy settings + enable_detect_probing_, default_proxy_domain_, allowed_sni_list_, + // ioc + ioc_, token_manager, handshake_cache_manager_, server_external_ips_, // NOLINTNEXTLINE(modernize-avoid-bind) std::bind( &Server::HandleWsOpenConnection, this, _1, _2, _3, _4, _5, _6, _7), diff --git a/src/fptn-server/web/server.h b/src/fptn-server/web/server.h index abb0750..35665dd 100644 --- a/src/fptn-server/web/server.h +++ b/src/fptn-server/web/server.h @@ -39,6 +39,8 @@ class Server final { fptn::common::network::IPv4Address dns_server_ipv4, fptn::common::network::IPv6Address dns_server_ipv6, bool enable_detect_probing, + std::string default_proxy_domain, + std::vector allowed_sni_list, std::size_t max_active_sessions_per_user, std::string server_external_ips, int thread_number = 4); @@ -91,6 +93,9 @@ class Server final { const fptn::common::network::IPv4Address dns_server_ipv4_; const fptn::common::network::IPv6Address dns_server_ipv6_; const bool enable_detect_probing_; + const std::string default_proxy_domain_; + const std::vector allowed_sni_list_; + const std::size_t max_active_sessions_per_user_; const std::string server_external_ips_; const std::size_t thread_number_; diff --git a/src/fptn-server/web/session/session.cpp b/src/fptn-server/web/session/session.cpp index 23e84f6..23af569 100644 --- a/src/fptn-server/web/session/session.cpp +++ b/src/fptn-server/web/session/session.cpp @@ -77,6 +77,8 @@ namespace fptn::web { Session::Session(std::uint16_t port, bool enable_detect_probing, + std::string default_proxy_domain, + std::vector allowed_sni_list, std::string server_external_ips, boost::asio::ip::tcp::socket&& socket, boost::asio::ssl::context& ctx, @@ -87,6 +89,8 @@ Session::Session(std::uint16_t port, WebSocketCloseConnectionCallback ws_close_callback) : port_(port), enable_detect_probing_(enable_detect_probing), + default_proxy_domain_(std::move(default_proxy_domain)), + allowed_sni_list_(std::move(allowed_sni_list)), server_external_ips_(std::move(server_external_ips)), ws_(ssl_stream_type( obfuscator_socket_type(tcp_stream_type(std::move(socket))), ctx)), @@ -194,7 +198,7 @@ boost::asio::awaitable Session::Run() { // Prevent recursive proxy attempts for Reality Mode const auto self_proxy = co_await IsSniSelfProxyAttempt(result.sni); if (self_proxy) { - co_await HandleProxy(FPTN_DEFAULT_SNI, port_); + co_await HandleProxy(default_proxy_domain_, port_); Close(); co_return; } @@ -258,16 +262,18 @@ boost::asio::awaitable Session::DetectProbing() { boost::asio::socket_base::message_peek, boost::asio::use_awaitable); if (!bytes_read) { SPDLOG_ERROR("Peeked zero bytes from socket (client_id={})", client_id_); - co_return ProbingResult{ - .is_probing = true, .sni = FPTN_DEFAULT_SNI, .should_close = true}; + co_return ProbingResult{.is_probing = true, + .sni = default_proxy_domain_, + .should_close = true}; } // Check ssl if (!pcpp::SSLLayer::IsSSLMessage( 0, 0, buffer.data(), buffer.size(), true)) { SPDLOG_ERROR( "Not an SSL message, closing connection (client_id={})", client_id_); - co_return ProbingResult{ - .is_probing = true, .sni = FPTN_DEFAULT_SNI, .should_close = true}; + co_return ProbingResult{.is_probing = true, + .sni = default_proxy_domain_, + .should_close = true}; } // Create SslLayer pcpp::SSLLayer* ssl_layer = pcpp::SSLLayer::createSSLMessage( @@ -276,8 +282,9 @@ boost::asio::awaitable Session::DetectProbing() { SPDLOG_ERROR( "Failed to create SSL layer from handshake data (client_id={})", client_id_); - co_return ProbingResult{ - .is_probing = true, .sni = FPTN_DEFAULT_SNI, .should_close = true}; + co_return ProbingResult{.is_probing = true, + .sni = default_proxy_domain_, + .should_close = true}; } // Check handshake @@ -285,8 +292,9 @@ boost::asio::awaitable Session::DetectProbing() { const auto* handshake = dynamic_cast(ssl_layer); if (!handshake) { SPDLOG_ERROR("Failed to cast to SSLHandshakeLayer"); - co_return ProbingResult{ - .is_probing = true, .sni = FPTN_DEFAULT_SNI, .should_close = true}; + co_return ProbingResult{.is_probing = true, + .sni = default_proxy_domain_, + .should_close = true}; } // Get TTL-HELLO @@ -298,12 +306,13 @@ boost::asio::awaitable Session::DetectProbing() { "Failed to extract SSLClientHelloMessage from handshake " "(client_id={})", client_id_); - co_return ProbingResult{ - .is_probing = true, .sni = FPTN_DEFAULT_SNI, .should_close = true}; + co_return ProbingResult{.is_probing = true, + .sni = default_proxy_domain_, + .should_close = true}; } // Set SNI - std::string sni = FPTN_DEFAULT_SNI; + std::string sni = default_proxy_domain_; auto* sni_ext = // cppcheck-suppress nullPointerRedundantCheck hello->getExtensionOfType(); @@ -313,16 +322,30 @@ boost::asio::awaitable Session::DetectProbing() { sni = std::move(tls_sni); } } + // Validate allowed sni + if (!allowed_sni_list_.empty()) { + const bool sni_allowed = std::ranges::any_of( + allowed_sni_list_, [&sni](const std::string& allowed_sni) { + return sni == allowed_sni; + }); + if (!sni_allowed) { + sni = default_proxy_domain_; + SPDLOG_WARN( + "SNI '{}' not in allowed list, using default domain: {} " + "(client_id={})", + sni, default_proxy_domain_, client_id_); + } + } // Detect and prevent recursive proxying to the local server - if (sni != FPTN_DEFAULT_SNI) { + if (sni != default_proxy_domain_) { const bool is_recursive_attempt = co_await IsSniSelfProxyAttempt(sni); if (is_recursive_attempt) { SPDLOG_WARN( "Detected recursive proxy attempt! " "Client: {}, SNI: {}, Redirecting to default SNI: {}", - client_id_, sni, FPTN_DEFAULT_SNI); - sni = FPTN_DEFAULT_SNI; + client_id_, sni, default_proxy_domain_); + sni = default_proxy_domain_; } } @@ -366,7 +389,7 @@ boost::asio::awaitable Session::DetectProbing() { SPDLOG_ERROR("Unknown exception during probing (client_id={})", client_id_); } co_return ProbingResult{ - .is_probing = true, .sni = FPTN_DEFAULT_SNI, .should_close = true}; + .is_probing = true, .sni = default_proxy_domain_, .should_close = true}; } // NOLINTNEXTLINE(readability-convert-member-functions-to-static) @@ -462,7 +485,7 @@ boost::asio::awaitable Session::IsRealityHandshake() { } // Get SNI - std::string sni = FPTN_DEFAULT_SNI; + std::string sni = default_proxy_domain_; auto* sni_ext = // cppcheck-suppress nullPointerRedundantCheck hello->getExtensionOfType(); @@ -473,6 +496,21 @@ boost::asio::awaitable Session::IsRealityHandshake() { } } + // Validate allowed sni + if (!allowed_sni_list_.empty()) { + const bool sni_allowed = std::ranges::any_of( + allowed_sni_list_, [&sni](const std::string& allowed_sni) { + return sni == allowed_sni; + }); + if (!sni_allowed) { + sni = default_proxy_domain_; + SPDLOG_WARN( + "SNI '{}' not in allowed list, using default domain: {} " + "(client_id={})", + sni, default_proxy_domain_, client_id_); + } + } + // Check if this is a reality mode handshake by examining session ID constexpr std::size_t kSessionLen = 32; std::size_t session_len = std::min( diff --git a/src/fptn-server/web/session/session.h b/src/fptn-server/web/session/session.h index a9d75ad..6c6bf2f 100644 --- a/src/fptn-server/web/session/session.h +++ b/src/fptn-server/web/session/session.h @@ -9,6 +9,7 @@ Distributed under the MIT License (https://opensource.org/licenses/MIT) #include #include +#include #include #include @@ -36,6 +37,8 @@ class Session : public std::enable_shared_from_this { public: explicit Session(std::uint16_t port, bool enable_detect_probing, + std::string default_proxy_domain, + std::vector allowed_sni_list, std::string server_external_ips, boost::asio::ip::tcp::socket&& socket, boost::asio::ssl::context& ctx, @@ -97,6 +100,9 @@ class Session : public std::enable_shared_from_this { const std::uint16_t port_; const bool enable_detect_probing_; + const std::string default_proxy_domain_; + const std::vector allowed_sni_list_; + const std::string server_external_ips_; // TCP -> obfuscator -> SSL -> WebSocket