diff --git a/httplib.h b/httplib.h index 703c171..371db9a 100644 --- a/httplib.h +++ b/httplib.h @@ -10429,6 +10429,13 @@ inline void ClientImpl::set_error_logger(ErrorLogger error_logger) { #ifdef CPPHTTPLIB_OPENSSL_SUPPORT namespace detail { +inline bool is_ip_address(const std::string &host) { + struct in_addr addr4; + struct in6_addr addr6; + return inet_pton(AF_INET, host.c_str(), &addr4) == 1 || + inet_pton(AF_INET6, host.c_str(), &addr6) == 1; +} + template inline SSL *ssl_new(socket_t sock, SSL_CTX *ctx, std::mutex &ctx_mutex, U SSL_connect_or_accept, V setup) { @@ -11087,14 +11094,18 @@ inline bool SSLClient::initialize_ssl(Socket &socket, Error &error) { return true; }, [&](SSL *ssl2) { + // Set SNI only if host is not IP address + if (!detail::is_ip_address(host_)) { #if defined(OPENSSL_IS_BORINGSSL) - SSL_set_tlsext_host_name(ssl2, host_.c_str()); + SSL_set_tlsext_host_name(ssl2, host_.c_str()); #else - // NOTE: Direct call instead of using the OpenSSL macro to suppress - // -Wold-style-cast warning - SSL_ctrl(ssl2, SSL_CTRL_SET_TLSEXT_HOSTNAME, TLSEXT_NAMETYPE_host_name, - static_cast(const_cast(host_.c_str()))); + // NOTE: Direct call instead of using the OpenSSL macro to suppress + // -Wold-style-cast warning + SSL_ctrl(ssl2, SSL_CTRL_SET_TLSEXT_HOSTNAME, + TLSEXT_NAMETYPE_host_name, + static_cast(const_cast(host_.c_str()))); #endif + } return true; }); diff --git a/test/test.cc b/test/test.cc index 867b093..23dd0fb 100644 --- a/test/test.cc +++ b/test/test.cc @@ -7366,6 +7366,48 @@ TEST(KeepAliveTest, SSLClientReconnectionPost) { ASSERT_TRUE(result); EXPECT_EQ(200, result->status); } + +TEST(SNI_AutoDetectionTest, SNI_Logic) { + { + SSLServer svr(SERVER_CERT_FILE, SERVER_PRIVATE_KEY_FILE); + ASSERT_TRUE(svr.is_valid()); + + svr.Get("/sni", [&](const Request &req, Response &res) { + std::string expected; + if (req.ssl) { + if (const char *sni = + SSL_get_servername(req.ssl, TLSEXT_NAMETYPE_host_name)) { + expected = sni; + } + } + EXPECT_EQ(expected, req.get_param_value("expected")); + res.set_content("ok", "text/plain"); + }); + + auto listen_thread = std::thread([&svr] { svr.listen(HOST, PORT); }); + auto se = detail::scope_exit([&] { + svr.stop(); + listen_thread.join(); + ASSERT_FALSE(svr.is_running()); + }); + + svr.wait_until_ready(); + + { + SSLClient cli("localhost", PORT); + cli.enable_server_certificate_verification(false); + auto res = cli.Get("/sni?expected=localhost"); + ASSERT_TRUE(res); + } + + { + SSLClient cli("::1", PORT); + cli.enable_server_certificate_verification(false); + auto res = cli.Get("/sni?expected="); + ASSERT_TRUE(res); + } + } +} #endif TEST(ClientProblemDetectionTest, ContentProvider) {