Skip to content
API Documentation
BastionGuard™
TlsIntercept Namespace Reference

Namespaces

namespace  detail

Functions

static void set_no_expiry (X509 *cert)
static void set_realistic_validity (X509 *cert)
static std::string extract_path_from_request (const std::string &raw)
static std::shared_ptr< asio::ssl::context > make_stealth_upstream_ctx (const std::string &host)
static std::string lower_ascii (std::string v)
static std::string trim_ascii (std::string v)
static std::string request_method_from_raw (const std::string &raw)
static std::string header_value_ci (const std::string &raw, const std::string &wanted)
static bool is_stateful_method (const std::string &method_l)
static bool is_speculative_request (const std::string &raw)
static bool should_passthrough_transaction (const std::string &raw)
static void send_speculative_no_content (asio::ssl::stream< tcp::socket > &tls)
static bool parse_content_length (const std::string &raw, std::size_t &out_len)
static bool is_chunked_request (const std::string &raw)
static bool read_more (asio::ssl::stream< tcp::socket > &tls, std::string &raw, std::size_t min_total, std::size_t max_total)
static bool read_complete_chunked (asio::ssl::stream< tcp::socket > &tls, std::string &raw, std::size_t body_start, std::size_t max_total)
static bool read_complete_http1_request (asio::ssl::stream< tcp::socket > &tls, std::string &raw)
static std::string force_connection_close (const std::string &raw)
static bool forward_transaction_https (asio::ssl::stream< tcp::socket > &client_tls, const std::string &host, std::string raw_request)
static void send_passthrough_failure (asio::ssl::stream< tcp::socket > &tls)
static void do_intercept (tcp::socket sock, const std::string &host, const std::string &type, std::function< void(const std::string &)> on_url_ready=nullptr)

Variables

static constexpr long CTX_CACHE_TTL_SEC = 30L * 24 * 3600

Function Documentation

◆ do_intercept()

void TlsIntercept::do_intercept ( tcp::socket sock,
const std::string & host,
const std::string & type,
std::function< void(const std::string &)> on_url_ready = nullptr )
inlinestatic

Definition at line 827 of file tls_intercept.hpp.

831{
832 std::cerr << "[tls-intercept] intercepting " << host << "\n";
833
834 auto ssl_ctx = detail::get_or_create_ctx(host);
835 if (!ssl_ctx) {
836 std::cerr << "[tls-intercept] ctx setup failed for " << host << "\n";
837 boost::system::error_code ignore;
838 sock.close(ignore);
839 return;
840 }
841
842 try {
843 asio::ssl::stream<tcp::socket> tls(std::move(sock), *ssl_ctx);
844
845 boost::system::error_code hs_ec;
846 tls.handshake(asio::ssl::stream_base::server, hs_ec);
847 if (hs_ec) {
848 std::cerr << "[tls-intercept] handshake failed for " << host
849 << ": " << hs_ec.message() << "\n";
850 boost::system::error_code ignore;
851 tls.lowest_layer().close(ignore);
852 return;
853 }
854
855 std::cerr << "[tls-intercept] handshake ok for " << host << "\n";
856
857 asio::streambuf rbuf;
858 boost::system::error_code read_ec;
859 asio::read_until(tls, rbuf, "\r\n\r\n", read_ec);
860 if (read_ec) {
861 std::cerr << "[tls-intercept] request header read failed for " << host
862 << ": " << read_ec.message() << "\n";
863 boost::system::error_code ignore;
864 tls.lowest_layer().close(ignore);
865 return;
866 }
867
868 const std::string raw{
869 asio::buffers_begin(rbuf.data()),
870 asio::buffers_end(rbuf.data())
871 };
872
873 // Le richieste speculative non devono neppure raggiungere il sito:
874 // non aprono CEF e non consumano una challenge/controllo anti-abuso.
875 // La navigazione reale successiva (con user activation) verra' gestita
876 // normalmente.
877 if (is_speculative_request(raw)) {
878 const std::string method = request_method_from_raw(raw);
879 const std::string dest = lower_ascii(header_value_ci(raw, "sec-fetch-dest"));
880 std::cerr << "[tls-intercept] speculative request suppressed: host=" << host
881 << " method=" << method << " dest=" << dest << "\n";
883
884 boost::system::error_code sd_ec;
885 tls.shutdown(sd_ec);
886 boost::system::error_code ignore;
887 tls.lowest_layer().close(ignore);
888 return;
889 }
890
892 const std::string method = request_method_from_raw(raw);
893 const std::string dest = lower_ascii(header_value_ci(raw, "sec-fetch-dest"));
894 const std::string mode = lower_ascii(header_value_ci(raw, "sec-fetch-mode"));
895 const std::string user = trim_ascii(header_value_ci(raw, "sec-fetch-user"));
896 std::cerr << "[tls-intercept] passthrough (subresource/stateful/automatic): host=" << host
897 << " method=" << method
898 << " dest=" << dest
899 << " mode=" << mode
900 << " user=" << (user.empty() ? "<none>" : user)
901 << "\n";
902 if (!forward_transaction_https(tls, host, raw))
904
905 boost::system::error_code sd_ec;
906 tls.shutdown(sd_ec);
907 boost::system::error_code ignore;
908 tls.lowest_layer().close(ignore);
909 return;
910 }
911
912 // Solo una vera navigazione top-level GET/HEAD viene trasformata in
913 // apertura SecureBrowser. Il callback NON viene chiamato per iframe,
914 // fetch/XHR o POST, quindi nessuna sessione/gate fittizia viene creata.
915 if (on_url_ready) {
916 const std::string path = extract_path_from_request(raw);
917 const std::string full_url = "https://" + host + path;
918 std::cerr << "[tls-intercept] top-level secure URL: " << full_url << "\n";
919 on_url_ready(full_url);
920 }
921
922 const std::string resp = detail::make_tls_response(host, type);
923 boost::system::error_code write_ec;
924 asio::write(tls, asio::buffer(resp), write_ec);
925
926 if (write_ec)
927 std::cerr << "[tls-intercept] write error for " << host
928 << ": " << write_ec.message() << "\n";
929 else
930 std::cerr << "[tls-intercept] page served for " << host << "\n";
931
932 boost::system::error_code sd_ec;
933 tls.shutdown(sd_ec);
934 boost::system::error_code ignore;
935 tls.lowest_layer().close(ignore);
936
937 } catch (const std::exception& e) {
938 std::cerr << "[tls-intercept] exception for " << host
939 << ": " << e.what() << "\n";
940 boost::system::error_code ignore;
941 sock.close(ignore);
942 }
943}
static std::shared_ptr< asio::ssl::context > get_or_create_ctx(const std::string &host)
static std::string make_tls_response(const std::string &host, const std::string &type)
static void send_speculative_no_content(asio::ssl::stream< tcp::socket > &tls)
static std::string request_method_from_raw(const std::string &raw)
static std::string lower_ascii(std::string v)
static bool is_speculative_request(const std::string &raw)
static std::string extract_path_from_request(const std::string &raw)
static void send_passthrough_failure(asio::ssl::stream< tcp::socket > &tls)
static std::string trim_ascii(std::string v)
static std::string header_value_ci(const std::string &raw, const std::string &wanted)
static bool should_passthrough_transaction(const std::string &raw)
static bool forward_transaction_https(asio::ssl::stream< tcp::socket > &client_tls, const std::string &host, std::string raw_request)

References do_intercept(), extract_path_from_request(), forward_transaction_https(), TlsIntercept::detail::get_or_create_ctx(), header_value_ci(), is_speculative_request(), lower_ascii(), TlsIntercept::detail::make_tls_response(), request_method_from_raw(), send_passthrough_failure(), send_speculative_no_content(), should_passthrough_transaction(), and trim_ascii().

Referenced by do_intercept().

◆ extract_path_from_request()

std::string TlsIntercept::extract_path_from_request ( const std::string & raw)
inlinestatic

Definition at line 389 of file tls_intercept.hpp.

389 {
390 // Cerca la prima riga (fino a \r\n o \n)
391 const auto eol = raw.find('\n');
392 const std::string line = (eol != std::string::npos)
393 ? raw.substr(0, eol) : raw;
394
395
396 const auto s1 = line.find(' ');
397 if (s1 == std::string::npos) return "/";
398 const auto s2 = line.find(' ', s1 + 1);
399 const std::string path = (s2 != std::string::npos)
400 ? line.substr(s1 + 1, s2 - s1 - 1)
401 : line.substr(s1 + 1);
402
403 if (!path.empty() && path.back() == '\r')
404 return path.substr(0, path.size() - 1);
405
406 return path.empty() ? "/" : path;
407}

References extract_path_from_request().

Referenced by do_intercept(), and extract_path_from_request().

◆ force_connection_close()

std::string TlsIntercept::force_connection_close ( const std::string & raw)
inlinestatic

Definition at line 716 of file tls_intercept.hpp.

716 {
717 const auto hdr_end = raw.find("\r\n\r\n");
718 if (hdr_end == std::string::npos) return raw;
719
720 const std::string headers = raw.substr(0, hdr_end);
721 const std::string body = raw.substr(hdr_end + 4);
722 std::istringstream in(headers);
723 std::ostringstream out;
724 std::string line;
725 bool first = true;
726 while (std::getline(in, line)) {
727 if (!line.empty() && line.back() == '\r') line.pop_back();
728 if (first) {
729 out << line << "\r\n";
730 first = false;
731 continue;
732 }
733 const auto colon = line.find(':');
734 const std::string name = colon == std::string::npos
735 ? std::string{} : lower_ascii(trim_ascii(line.substr(0, colon)));
736 if (name == "connection" || name == "proxy-connection" || name == "keep-alive")
737 continue;
738 out << line << "\r\n";
739 }
740 out << "Connection: close\r\n\r\n";
741 out << body;
742 return out.str();
743}

References force_connection_close(), lower_ascii(), and trim_ascii().

Referenced by force_connection_close(), and forward_transaction_https().

◆ forward_transaction_https()

bool TlsIntercept::forward_transaction_https ( asio::ssl::stream< tcp::socket > & client_tls,
const std::string & host,
std::string raw_request )
inlinestatic

Definition at line 745 of file tls_intercept.hpp.

747 {
748 if (!read_complete_http1_request(client_tls, raw_request)) {
749 std::cerr << "[tls-intercept] transaction request incomplete/too large for "
750 << host << "\n";
751 return false;
752 }
753
754 raw_request = force_connection_close(raw_request);
755
756 try {
757 asio::io_context io;
758 tcp::resolver resolver(io);
759 auto endpoints = resolver.resolve(host, "443");
760 tcp::socket upstream_socket(io);
761 asio::connect(upstream_socket, endpoints);
762
763 auto upstream_ctx = make_stealth_upstream_ctx(host);
764 asio::ssl::stream<tcp::socket> upstream(std::move(upstream_socket), *upstream_ctx);
765
766 SSL* ssl = upstream.native_handle();
767 if (SSL_set_tlsext_host_name(ssl, host.c_str()) != 1) {
768 std::cerr << "[tls-intercept] SNI setup failed for " << host << "\n";
769 return false;
770 }
771 X509_VERIFY_PARAM* param = SSL_get0_param(ssl);
772 X509_VERIFY_PARAM_set_hostflags(param, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
773 if (X509_VERIFY_PARAM_set1_host(param, host.c_str(), 0) != 1) {
774 std::cerr << "[tls-intercept] hostname verification setup failed for "
775 << host << "\n";
776 return false;
777 }
778
779 upstream.set_verify_mode(asio::ssl::verify_peer);
780 upstream.handshake(asio::ssl::stream_base::client);
781
782 asio::write(upstream, asio::buffer(raw_request));
783
784 std::array<char, 64 * 1024> buf{};
785 for (;;) {
786 boost::system::error_code rec;
787 const std::size_t n = upstream.read_some(asio::buffer(buf), rec);
788 if (n) {
789 boost::system::error_code wec;
790 asio::write(client_tls, asio::buffer(buf.data(), n), wec);
791 if (wec) return false;
792 }
793 if (rec) {
794 if (rec != asio::error::eof &&
795 rec != asio::ssl::error::stream_truncated) {
796 std::cerr << "[tls-intercept] upstream read failed for " << host
797 << ": " << rec.message() << "\n";
798 }
799 break;
800 }
801 }
802
803 boost::system::error_code sd_ec;
804 upstream.shutdown(sd_ec);
805 return true;
806 } catch (const std::exception& e) {
807 std::cerr << "[tls-intercept] transaction passthrough failed for " << host
808 << ": " << e.what() << "\n";
809 return false;
810 }
811}
static std::shared_ptr< asio::ssl::context > make_stealth_upstream_ctx(const std::string &host)
static bool read_complete_http1_request(asio::ssl::stream< tcp::socket > &tls, std::string &raw)
static std::string force_connection_close(const std::string &raw)

References force_connection_close(), forward_transaction_https(), make_stealth_upstream_ctx(), and read_complete_http1_request().

Referenced by do_intercept(), and forward_transaction_https().

◆ header_value_ci()

std::string TlsIntercept::header_value_ci ( const std::string & raw,
const std::string & wanted )
inlinestatic

Definition at line 497 of file tls_intercept.hpp.

498 {
499 const std::string wanted_l = lower_ascii(wanted);
500 const auto first_eol = raw.find("\r\n");
501 if (first_eol == std::string::npos) return {};
502 std::size_t pos = first_eol + 2;
503
504 while (pos < raw.size()) {
505 const auto eol = raw.find("\r\n", pos);
506 if (eol == std::string::npos || eol == pos) break;
507 const auto colon = raw.find(':', pos);
508 if (colon != std::string::npos && colon < eol) {
509 std::string name = lower_ascii(raw.substr(pos, colon - pos));
510 if (name == wanted_l)
511 return trim_ascii(raw.substr(colon + 1, eol - colon - 1));
512 }
513 pos = eol + 2;
514 }
515 return {};
516}

References header_value_ci(), lower_ascii(), and trim_ascii().

Referenced by do_intercept(), header_value_ci(), is_chunked_request(), is_speculative_request(), parse_content_length(), and should_passthrough_transaction().

◆ is_chunked_request()

bool TlsIntercept::is_chunked_request ( const std::string & raw)
inlinestatic

Definition at line 619 of file tls_intercept.hpp.

619 {
620 const std::string te = lower_ascii(header_value_ci(raw, "transfer-encoding"));
621 return te.find("chunked") != std::string::npos;
622}

References header_value_ci(), is_chunked_request(), and lower_ascii().

Referenced by is_chunked_request(), and read_complete_http1_request().

◆ is_speculative_request()

bool TlsIntercept::is_speculative_request ( const std::string & raw)
inlinestatic

Definition at line 526 of file tls_intercept.hpp.

526 {
527 const std::string purpose = lower_ascii(header_value_ci(raw, "purpose"));
528 const std::string sec_purpose = lower_ascii(header_value_ci(raw, "sec-purpose"));
529 return purpose.find("prefetch") != std::string::npos ||
530 sec_purpose.find("prefetch") != std::string::npos ||
531 purpose.find("prerender") != std::string::npos ||
532 sec_purpose.find("prerender") != std::string::npos;
533}

References header_value_ci(), is_speculative_request(), and lower_ascii().

Referenced by do_intercept(), is_speculative_request(), and should_passthrough_transaction().

◆ is_stateful_method()

bool TlsIntercept::is_stateful_method ( const std::string & method_l)
inlinestatic

Definition at line 518 of file tls_intercept.hpp.

518 {
519 return !(method_l == "get" || method_l == "head" || method_l == "options");
520}

References is_stateful_method().

Referenced by is_stateful_method(), and should_passthrough_transaction().

◆ lower_ascii()

std::string TlsIntercept::lower_ascii ( std::string v)
inlinestatic

Definition at line 475 of file tls_intercept.hpp.

475 {
476 std::transform(v.begin(), v.end(), v.begin(),
477 [](unsigned char c) { return static_cast<char>(std::tolower(c)); });
478 return v;
479}

References lower_ascii().

Referenced by do_intercept(), force_connection_close(), header_value_ci(), is_chunked_request(), is_speculative_request(), lower_ascii(), request_method_from_raw(), and should_passthrough_transaction().

◆ make_stealth_upstream_ctx()

std::shared_ptr< asio::ssl::context > TlsIntercept::make_stealth_upstream_ctx ( const std::string & host)
inlinestatic

Definition at line 410 of file tls_intercept.hpp.

411{
412 auto ctx = std::make_shared<asio::ssl::context>(asio::ssl::context::tls_client);
413 SSL_CTX* native = ctx->native_handle();
414
415 // Disabilita protocolli obsoleti e opzioni che non usa Chrome
416 SSL_CTX_set_options(native,
417 SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
418 SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1 |
419 SSL_OP_NO_COMPRESSION);
420
421 SSL_CTX_set_min_proto_version(native, TLS1_2_VERSION);
422
423 SSL_CTX_set_cipher_list(native,
424 "TLS_AES_128_GCM_SHA256:"
425 "TLS_AES_256_GCM_SHA384:"
426 "TLS_CHACHA20_POLY1305_SHA256:"
427 "ECDHE-ECDSA-AES128-GCM-SHA256:"
428 "ECDHE-RSA-AES128-GCM-SHA256:"
429 "ECDHE-ECDSA-AES256-GCM-SHA384:"
430 "ECDHE-RSA-AES256-GCM-SHA384:"
431 "ECDHE-ECDSA-CHACHA20-POLY1305:"
432 "ECDHE-RSA-CHACHA20-POLY1305:"
433 "ECDHE-RSA-AES128-SHA:"
434 "ECDHE-RSA-AES256-SHA:"
435 "AES128-GCM-SHA256:"
436 "AES256-GCM-SHA384:"
437 "AES128-SHA:"
438 "AES256-SHA");
439
440#ifdef TLS1_3_VERSION
441 SSL_CTX_set_ciphersuites(native,
442 "TLS_AES_128_GCM_SHA256:"
443 "TLS_AES_256_GCM_SHA384:"
444 "TLS_CHACHA20_POLY1305_SHA256");
445#endif
446 // Il proxy trasparente sotto usa HTTP/1.1 byte-for-byte. Non negoziare
447 // h2 upstream: inviare una request HTTP/1.1 su una connessione ALPN h2
448 // corromperebbe il flusso.
449 static const unsigned char alpn[] = "\x08http/1.1";
450 SSL_CTX_set_alpn_protos(native, alpn, sizeof(alpn) - 1);
451 SSL_CTX_set_default_verify_paths(native);
452 SSL_CTX_set_verify(native, SSL_VERIFY_PEER, nullptr);
453 (void)host;
454
455 return ctx;
456}

References make_stealth_upstream_ctx().

Referenced by forward_transaction_https(), and make_stealth_upstream_ctx().

◆ parse_content_length()

bool TlsIntercept::parse_content_length ( const std::string & raw,
std::size_t & out_len )
inlinestatic

Definition at line 604 of file tls_intercept.hpp.

605 {
606 const std::string v = trim_ascii(header_value_ci(raw, "content-length"));
607 if (v.empty()) return false;
608 errno = 0;
609 char* end = nullptr;
610 const unsigned long long n = std::strtoull(v.c_str(), &end, 10);
611 if (errno != 0 || end == v.c_str() || (end && *end != '\0') ||
612 n > std::numeric_limits<std::size_t>::max()) {
613 return false;
614 }
615 out_len = static_cast<std::size_t>(n);
616 return true;
617}

References header_value_ci(), parse_content_length(), and trim_ascii().

Referenced by parse_content_length(), and read_complete_http1_request().

◆ read_complete_chunked()

bool TlsIntercept::read_complete_chunked ( asio::ssl::stream< tcp::socket > & tls,
std::string & raw,
std::size_t body_start,
std::size_t max_total )
inlinestatic

Definition at line 640 of file tls_intercept.hpp.

643 {
644 std::size_t cur = body_start;
645 std::array<char, 16 * 1024> buf{};
646
647 auto ensure_line = [&](std::size_t from, std::size_t& eol) -> bool {
648 for (;;) {
649 eol = raw.find("\r\n", from);
650 if (eol != std::string::npos) return true;
651 if (raw.size() >= max_total) return false;
652 boost::system::error_code ec;
653 const std::size_t room = std::min<std::size_t>(buf.size(), max_total - raw.size());
654 const std::size_t n = tls.read_some(asio::buffer(buf.data(), room), ec);
655 if (n) raw.append(buf.data(), n);
656 if (ec) return false;
657 }
658 };
659
660 for (;;) {
661 std::size_t eol = 0;
662 if (!ensure_line(cur, eol)) return false;
663 std::string size_line = raw.substr(cur, eol - cur);
664 const auto semi = size_line.find(';');
665 if (semi != std::string::npos) size_line.erase(semi);
666 size_line = trim_ascii(size_line);
667 if (size_line.empty()) return false;
668
669 errno = 0;
670 char* end = nullptr;
671 const unsigned long long chunk = std::strtoull(size_line.c_str(), &end, 16);
672 if (errno != 0 || end == size_line.c_str() || (end && *end != '\0') ||
673 chunk > max_total) {
674 return false;
675 }
676
677 cur = eol + 2;
678 if (chunk == 0) {
679 // Trailer section: zero o piu' header, terminati da una riga vuota.
680 for (;;) {
681 if (!ensure_line(cur, eol)) return false;
682 if (eol == cur) return true;
683 cur = eol + 2;
684 }
685 }
686
687 const std::size_t need = cur + static_cast<std::size_t>(chunk) + 2;
688 if (need < cur || need > max_total) return false;
689 if (!read_more(tls, raw, need, max_total)) return false;
690 if (raw.compare(cur + static_cast<std::size_t>(chunk), 2, "\r\n") != 0)
691 return false;
692 cur = need;
693 }
694}
static bool read_more(asio::ssl::stream< tcp::socket > &tls, std::string &raw, std::size_t min_total, std::size_t max_total)

References read_complete_chunked(), read_more(), and trim_ascii().

Referenced by read_complete_chunked(), and read_complete_http1_request().

◆ read_complete_http1_request()

bool TlsIntercept::read_complete_http1_request ( asio::ssl::stream< tcp::socket > & tls,
std::string & raw )
inlinestatic

Definition at line 696 of file tls_intercept.hpp.

697 {
698 static constexpr std::size_t MAX_REQUEST = 32u * 1024u * 1024u;
699 const auto hdr_end_pos = raw.find("\r\n\r\n");
700 if (hdr_end_pos == std::string::npos) return false;
701 const std::size_t body_start = hdr_end_pos + 4;
702
703 std::size_t content_len = 0;
704 if (parse_content_length(raw, content_len)) {
705 if (content_len > MAX_REQUEST || body_start > MAX_REQUEST - content_len)
706 return false;
707 return read_more(tls, raw, body_start + content_len, MAX_REQUEST);
708 }
709
710 if (is_chunked_request(raw))
711 return read_complete_chunked(tls, raw, body_start, MAX_REQUEST);
712
713 return true;
714}
static bool is_chunked_request(const std::string &raw)
static bool parse_content_length(const std::string &raw, std::size_t &out_len)
static bool read_complete_chunked(asio::ssl::stream< tcp::socket > &tls, std::string &raw, std::size_t body_start, std::size_t max_total)

References is_chunked_request(), parse_content_length(), read_complete_chunked(), read_complete_http1_request(), and read_more().

Referenced by forward_transaction_https(), and read_complete_http1_request().

◆ read_more()

bool TlsIntercept::read_more ( asio::ssl::stream< tcp::socket > & tls,
std::string & raw,
std::size_t min_total,
std::size_t max_total )
inlinestatic

Definition at line 624 of file tls_intercept.hpp.

627 {
628 std::array<char, 16 * 1024> buf{};
629 while (raw.size() < min_total) {
630 if (raw.size() >= max_total) return false;
631 boost::system::error_code ec;
632 const std::size_t room = std::min<std::size_t>(buf.size(), max_total - raw.size());
633 const std::size_t n = tls.read_some(asio::buffer(buf.data(), room), ec);
634 if (n) raw.append(buf.data(), n);
635 if (ec) return false;
636 }
637 return true;
638}

References read_more().

Referenced by read_complete_chunked(), read_complete_http1_request(), and read_more().

◆ request_method_from_raw()

std::string TlsIntercept::request_method_from_raw ( const std::string & raw)
inlinestatic

Definition at line 489 of file tls_intercept.hpp.

489 {
490 const auto eol = raw.find("\r\n");
491 const std::string line = raw.substr(0, eol);
492 const auto sp = line.find(' ');
493 if (sp == std::string::npos) return {};
494 return lower_ascii(line.substr(0, sp));
495}

References lower_ascii(), and request_method_from_raw().

Referenced by do_intercept(), request_method_from_raw(), and should_passthrough_transaction().

◆ send_passthrough_failure()

void TlsIntercept::send_passthrough_failure ( asio::ssl::stream< tcp::socket > & tls)
inlinestatic

Definition at line 813 of file tls_intercept.hpp.

813 {
814 static constexpr char body[] = "BastionGuard: upstream secure transaction failed\n";
815 std::ostringstream oss;
816 oss << "HTTP/1.1 502 Bad Gateway\r\n"
817 << "Content-Type: text/plain; charset=UTF-8\r\n"
818 << "Content-Length: " << (sizeof(body) - 1) << "\r\n"
819 << "Cache-Control: no-store\r\n"
820 << "Connection: close\r\n\r\n"
821 << body;
822 const std::string resp = oss.str();
823 boost::system::error_code ec;
824 asio::write(tls, asio::buffer(resp), ec);
825}

References send_passthrough_failure().

Referenced by do_intercept(), and send_passthrough_failure().

◆ send_speculative_no_content()

void TlsIntercept::send_speculative_no_content ( asio::ssl::stream< tcp::socket > & tls)
inlinestatic

Definition at line 590 of file tls_intercept.hpp.

590 {
591 static const char kResponse[] =
592 "HTTP/1.1 204 No Content\r\n"
593 "Cache-Control: no-store\r\n"
594 "Content-Length: 0\r\n"
595 "Connection: close\r\n"
596 "\r\n";
597 boost::system::error_code ec;
598 asio::write(tls, asio::buffer(kResponse, sizeof(kResponse) - 1), ec);
599 if (ec)
600 std::cerr << "[tls-intercept] speculative response write failed: "
601 << ec.message() << "\n";
602}

References send_speculative_no_content().

Referenced by do_intercept(), and send_speculative_no_content().

◆ set_no_expiry()

void TlsIntercept::set_no_expiry ( X509 * cert)
inlinestatic

Definition at line 65 of file tls_intercept.hpp.

65 {
66 ASN1_TIME* not_after = X509_getm_notAfter(cert);
67 ASN1_GENERALIZEDTIME_set_string(not_after, "99991231235959Z");
68}

References set_no_expiry().

Referenced by TlsIntercept::detail::generate_ca(), and set_no_expiry().

◆ set_realistic_validity()

void TlsIntercept::set_realistic_validity ( X509 * cert)
inlinestatic

Definition at line 70 of file tls_intercept.hpp.

70 {
71 X509_gmtime_adj(X509_getm_notBefore(cert), -43200L);
72 X509_gmtime_adj(X509_getm_notAfter(cert), 397L * 24 * 3600);
73}

References set_realistic_validity().

Referenced by TlsIntercept::detail::make_ssl_ctx_for_host(), and set_realistic_validity().

◆ should_passthrough_transaction()

bool TlsIntercept::should_passthrough_transaction ( const std::string & raw)
inlinestatic

Definition at line 535 of file tls_intercept.hpp.

535 {
536 const std::string method = request_method_from_raw(raw);
537 if (method.empty()) return false; // fail verso il comportamento storico
538
539 // Mai trasformare una POST/PUT/PATCH/DELETE in una GET dentro un altro
540 // browser: perderemmo i dati della transazione.
541 if (is_stateful_method(method)) return true;
542
543 const std::string dest = lower_ascii(header_value_ci(raw, "sec-fetch-dest"));
544 if (dest == "iframe" || dest == "frame" || dest == "embed" ||
545 dest == "object" || dest == "empty" || dest == "script" ||
546 dest == "style" || dest == "image" || dest == "font" ||
547 dest == "audio" || dest == "video" || dest == "track" ||
548 dest == "worker" || dest == "sharedworker" ||
549 dest == "serviceworker" || dest == "manifest") {
550 return true;
551 }
552
553 const std::string mode = lower_ascii(header_value_ci(raw, "sec-fetch-mode"));
554 if (mode == "cors" || mode == "no-cors" || mode == "same-origin" ||
555 mode == "websocket") {
556 return true;
557 }
558
559 // Difesa in profondita': nel path normale queste richieste vengono
560 // soppresse prima di arrivare qui. Se la funzione viene riusata altrove,
561 // restano comunque non eleggibili per l'apertura CEF.
562 if (is_speculative_request(raw))
563 return true;
564
565 // Una vera apertura automatica del Secure Browser deve corrispondere a
566 // una navigazione top-level iniziata dall'utente. I browser moderni
567 // aggiungono `Sec-Fetch-User: ?1` solo quando la navigazione deriva da
568 // user activation (click, invio esplicito, barra indirizzi, bookmark).
569 //
570 // Se Fetch Metadata e' presente ma Sec-Fetch-User manca, si tratta di una
571 // navigazione automatica (redirect/script/meta refresh/autosubmit GET):
572 // non generiamo una seconda sessione CEF. La richiesta resta nel contesto
573 // del browser che l'ha originata e mantiene cookie/sessione/redirect chain.
574 //
575 // Compatibilita': se Fetch Metadata manca completamente, manteniamo il
576 // comportamento storico e lasciamo che la navigazione apra CEF. Questo
577 // evita di rompere client/browser che non implementano Sec-Fetch-*.
578 const bool has_fetch_metadata = !dest.empty() || !mode.empty();
579 if (has_fetch_metadata && dest == "document" && mode == "navigate") {
580 const std::string user = trim_ascii(header_value_ci(raw, "sec-fetch-user"));
581 if (user != "?1")
582 return true;
583 }
584
585 // document+navigate+Sec-Fetch-User:?1, oppure header Fetch Metadata
586 // completamente assenti: conserva il comportamento top-level esistente.
587 return false;
588}
static bool is_stateful_method(const std::string &method_l)

References header_value_ci(), is_speculative_request(), is_stateful_method(), lower_ascii(), request_method_from_raw(), should_passthrough_transaction(), and trim_ascii().

Referenced by do_intercept(), and should_passthrough_transaction().

◆ trim_ascii()

std::string TlsIntercept::trim_ascii ( std::string v)
inlinestatic

Definition at line 481 of file tls_intercept.hpp.

481 {
482 while (!v.empty() && std::isspace(static_cast<unsigned char>(v.front())))
483 v.erase(v.begin());
484 while (!v.empty() && std::isspace(static_cast<unsigned char>(v.back())))
485 v.pop_back();
486 return v;
487}

References trim_ascii().

Referenced by do_intercept(), force_connection_close(), header_value_ci(), parse_content_length(), read_complete_chunked(), should_passthrough_transaction(), and trim_ascii().

Variable Documentation

◆ CTX_CACHE_TTL_SEC

long TlsIntercept::CTX_CACHE_TTL_SEC = 30L * 24 * 3600
staticconstexpr

Definition at line 63 of file tls_intercept.hpp.

Referenced by TlsIntercept::detail::get_or_create_ctx().