From 28654f3c9bfc1386b4e57e0f1577053dfc78f21e Mon Sep 17 00:00:00 2001 From: Christopher Faulet Date: Fri, 5 Dec 2025 11:04:21 +0100 Subject: [PATCH] MINOR: connection/ssl: Store the SNI hash value in the connection itself When a SNI is set on a new connection, its hash is now saved in the connection itself. To do so, a dedicated field was added into the connection strucutre, called sni_hash. For now, this value is only used when the TLS session is cached. --- include/haproxy/connection-t.h | 1 + src/backend.c | 5 ++++- src/connection.c | 1 + src/ssl_sock.c | 8 +++----- src/tcpcheck.c | 14 +++++++++++--- 5 files changed, 20 insertions(+), 9 deletions(-) diff --git a/include/haproxy/connection-t.h b/include/haproxy/connection-t.h index a603966e5..b727c3a56 100644 --- a/include/haproxy/connection-t.h +++ b/include/haproxy/connection-t.h @@ -660,6 +660,7 @@ struct connection { struct buffer name; /* Only used for passive reverse. Used as SNI when connection added to server idle pool. */ } reverse; + uint64_t sni_hash; /* Hash of the SNI. Used to cache the TLS session and try to reuse it. set to 0 is there is no SNI */ uint32_t term_evts_log; /* Termination events log: first 4 events reported from fd, handshake or xprt */ uint32_t mark; /* set network mark, if CO_FL_OPT_MARK is set */ uint8_t tos; /* set ip tos, if CO_FL_OPT_TOS is set */ diff --git a/src/backend.c b/src/backend.c index 0170547b2..d84a5f524 100644 --- a/src/backend.c +++ b/src/backend.c @@ -2162,8 +2162,11 @@ int connect_server(struct stream *s) sni_smp = sample_fetch_as_type(s->be, s->sess, s, SMP_OPT_DIR_REQ | SMP_OPT_FINAL, srv->ssl_ctx.sni, SMP_T_STR); - if (smp_make_safe(sni_smp)) + if (smp_make_safe(sni_smp)) { + srv_conn->sni_hash = ssl_sock_sni_hash(ist2(b_orig(&sni_smp->data.u.str), + b_data(&sni_smp->data.u.str))); ssl_sock_set_servername(srv_conn, sni_smp->data.u.str.area); + } } #endif /* USE_OPENSSL */ diff --git a/src/connection.c b/src/connection.c index ed3764df5..445991421 100644 --- a/src/connection.c +++ b/src/connection.c @@ -520,6 +520,7 @@ void conn_init(struct connection *conn, void *target) conn->xprt = NULL; conn->reverse.target = NULL; conn->reverse.name = BUF_NULL; + conn->sni_hash = 0; } /* Initialize members used for backend connections. diff --git a/src/ssl_sock.c b/src/ssl_sock.c index d3eabacda..880bb2bd9 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -4202,7 +4202,6 @@ static int ssl_sess_new_srv_cb(SSL *ssl, SSL_SESSION *sess) int len; unsigned char *ptr; const char *sni; - uint64_t sni_hash; #ifdef USE_QUIC struct quic_conn *qc = SSL_get_ex_data(ssl, ssl_qc_app_data_index); #endif @@ -4247,11 +4246,10 @@ static int ssl_sess_new_srv_cb(SSL *ssl, SSL_SESSION *sess) else if (s->ssl_ctx.reused_sess[tid].ptr && !old_tid) HA_ATOMIC_CAS(&s->ssl_ctx.last_ssl_sess_tid, &old_tid, tid + 1); - sni_hash = (sni ? ssl_sock_sni_hash(ist(sni)) : 0); - if (s->ssl_ctx.reused_sess[tid].sni_hash != sni_hash) { - /* if the new sni hash isn' t the same as the old one */ - s->ssl_ctx.reused_sess[tid].sni_hash = sni_hash; + if (s->ssl_ctx.reused_sess[tid].sni_hash != conn->sni_hash) { + /* if the new sni hash or isn' t the same as the old one */ ha_free(&s->ssl_ctx.reused_sess[tid].sni); + s->ssl_ctx.reused_sess[tid].sni_hash = conn->sni_hash; if (sni) s->ssl_ctx.reused_sess[tid].sni = strdup(sni); } diff --git a/src/tcpcheck.c b/src/tcpcheck.c index 815a84099..d0fd31cfe 100644 --- a/src/tcpcheck.c +++ b/src/tcpcheck.c @@ -1280,6 +1280,9 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec struct buffer *auto_sni = NULL; int status, port; int check_type; +#ifdef USE_OPENSSL + struct ist sni = IST_NULL; +#endif TRACE_ENTER(CHK_EV_TCPCHK_CONN, check); @@ -1504,11 +1507,16 @@ enum tcpcheck_eval_ret tcpcheck_eval_connect(struct check *check, struct tcpchec #ifdef USE_OPENSSL if (conn_is_ssl(conn)) { if (connect->sni) - ssl_sock_set_servername(conn, connect->sni); + sni = ist(connect->sni); else if ((connect->options & TCPCHK_OPT_DEFAULT_CONNECT) && s && s->check.sni) - ssl_sock_set_servername(conn, s->check.sni); + sni = ist(s->check.sni); else if (auto_sni) - ssl_sock_set_servername(conn, b_orig(auto_sni)); + sni = ist2(b_orig(auto_sni), b_data(auto_sni)); + + if (isttest(sni)) { + conn->sni_hash = ssl_sock_sni_hash(sni); + ssl_sock_set_servername(conn, istptr(sni)); + } if (connect->alpn) ssl_sock_set_alpn(conn, (unsigned char *)connect->alpn, connect->alpn_len);