Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/net/uvcpp_tcp_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3269,6 +3269,20 @@ void uvcpp_tcp_client::apply_tls_hostname() {
// 从没承诺过的校验(名字对不上的对端从此连不上),`NONE` 则什么都不会发生 ——
// 两种都是"悄悄改掉既有行为"。本档位的定义就是"校验对端 **+ 主机名**",所以
// 钉与不钉**只**看这一个档位。
// SNI is not optional: every modern virtual host needs it, and without it the
// server either aborts the handshake or serves an unrelated default certificate.
//
// RFC 6066 §3 restricts `server_name` to DNS host names: an IP literal must not
// be sent. Some servers reject the extension outright, and none can route on it.
struct sockaddr_in sni_addr4;
struct sockaddr_in6 sni_addr6;
const bool is_ip_literal =
uv_ip4_addr(tls_host_want_.c_str(), 0, &sni_addr4) == 0 ||
uv_ip6_addr(tls_host_want_.c_str(), 0, &sni_addr6) == 0;
if (!is_ip_literal) {
tls_ssl_->set_server_name(tls_host_want_.c_str(), tls_host_want_.size());
}

uvcpp_ssl_context* ctx = tls_ssl_->context();
if (ctx == nullptr || ctx->verify_mode() != tls_verify_mode::PEER_STRICT) return;

Expand Down
9 changes: 9 additions & 0 deletions src/ssl/uvcpp_ssl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -189,6 +189,15 @@ bool uvcpp_ssl::set_alpn_protos(const std::vector<std::string>& protos) {
return true;
}

bool uvcpp_ssl::set_server_name(const char* host, size_t len) {
if (!ssl_ || host == nullptr || len == 0) return false;
if (SSL_set_tlsext_host_name(ssl_, std::string(host, len).c_str()) != 1) {
clear_error();
return false;
}
return true;
}

bool uvcpp_ssl::set_verify_hostname(const char* host, size_t len) {
if (!ssl_ || host == nullptr || len == 0) return false;
X509_VERIFY_PARAM* param = SSL_get0_param(ssl_);
Expand Down
3 changes: 3 additions & 0 deletions src/ssl/uvcpp_ssl.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,9 @@ class UVCPP_API uvcpp_ssl {
*/
bool set_verify_hostname(const char* host, size_t len);

/** @brief Set the TLS SNI server name (must be called before the handshake). */
bool set_server_name(const char* host, size_t len);

/**
* @brief 本连接所属的上下文;没有返回 nullptr。
*
Expand Down
10 changes: 10 additions & 0 deletions src/web/uvcpp_http_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,16 @@ int uvcpp_http_client::do_ssl_handshake(int fd) {
// h2 的 TLS 层必须走内存 BIO(`uvcpp_tcp_client` 那条),两者不能混。
// 写出来之后,将来往 ctx 上加了客户端 ALPN 也不会意外把这条路径带进 h2。
ssl_->set_alpn_protos({"http/1.1"});
// 与 `uvcpp_tcp_client::apply_tls_hostname()` 同一条规则:SNI 只带 DNS 名,
// IP 字面量(RFC 6066 §3)不发。证书校验仍然按 `host_` 走下面那条。
struct sockaddr_in sni_addr4;
struct sockaddr_in6 sni_addr6;
const bool is_ip_literal =
uv_ip4_addr(host_.c_str(), 0, &sni_addr4) == 0 ||
uv_ip6_addr(host_.c_str(), 0, &sni_addr6) == 0;
if (!is_ip_literal) {
ssl_->set_server_name(host_.c_str(), host_.size());
}

// 主机名校验**必须在这里单独接一次**。这条路是 `*_wait` 系列专用的:它自己
// `new uvcpp_ssl(ssl_ctx_, fd)`,**根本不经过 `uvcpp_tcp_client::connect()`**,
Expand Down
Loading