From 51eca5cbce8325f00d11e6808bc83302cd37c94c Mon Sep 17 00:00:00 2001 From: Frederic Lecaille Date: Fri, 17 Oct 2025 12:07:10 +0200 Subject: [PATCH] BUG/MINOR: quic: SSL counters not handled The SSL counters were not handled at all for QUIC connections. This patch implement ssl_sock_update_counters() extracting the code from ssl_sock.c and call this function where applicable both in TLS/TCP and QUIC parts. Must be backported as far as 2.8. --- include/haproxy/ssl_sock.h | 3 +++ src/quic_ssl.c | 19 +++++++++++++ src/ssl_sock.c | 55 +++++++++++++++++++++++--------------- 3 files changed, 55 insertions(+), 22 deletions(-) diff --git a/include/haproxy/ssl_sock.h b/include/haproxy/ssl_sock.h index d885a1ba0..4658ab9c6 100644 --- a/include/haproxy/ssl_sock.h +++ b/include/haproxy/ssl_sock.h @@ -86,6 +86,9 @@ int ssl_sock_get_remote_common_name(struct connection *conn, struct buffer *out); int ssl_sock_get_pkey_algo(struct connection *conn, struct buffer *out); unsigned int ssl_sock_get_verify_result(struct connection *conn); +void ssl_sock_update_counters(SSL *ssl, + struct ssl_counters *counters, + struct ssl_counters *counters_px, int backend); #if (defined SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB && TLS_TICKETS_NO > 0) int ssl_sock_update_tlskey_ref(struct tls_keys_ref *ref, struct buffer *tlskey); diff --git a/src/quic_ssl.c b/src/quic_ssl.c index 60e79a516..31220ff77 100644 --- a/src/quic_ssl.c +++ b/src/quic_ssl.c @@ -8,6 +8,7 @@ #include #include #include +#include #include DECLARE_TYPED_POOL(pool_head_quic_ssl_sock_ctx, "quic_ssl_sock_ctx", struct ssl_sock_ctx); @@ -853,12 +854,28 @@ static forceinline void qc_ssl_dump_errors(struct connection *conn) int qc_ssl_do_hanshake(struct quic_conn *qc, struct ssl_sock_ctx *ctx) { int ret, ssl_err, state; + struct ssl_counters *counters = NULL; + struct ssl_counters *counters_px = NULL; TRACE_ENTER(QUIC_EV_CONN_SSLDATA, qc); ret = 0; ssl_err = SSL_ERROR_NONE; state = qc->state; + + if (!qc_is_back(qc)) { + counters = EXTRA_COUNTERS_GET(qc->li->extra_counters, &ssl_stats_module); + counters_px = EXTRA_COUNTERS_GET(qc->li->bind_conf->frontend->extra_counters_fe, + &ssl_stats_module); + } + else if (ctx->conn) { + struct server *srv = __objt_server(ctx->conn->target); + + counters = EXTRA_COUNTERS_GET(srv->extra_counters, &ssl_stats_module); + counters_px = EXTRA_COUNTERS_GET(srv->proxy->extra_counters_be, + &ssl_stats_module); + } + if (state < QUIC_HS_ST_COMPLETE) { ssl_err = SSL_do_handshake(ctx->ssl); TRACE_PROTO("SSL_do_handshake() called", QUIC_EV_CONN_IO_CB, qc, NULL, NULL, ctx->ssl); @@ -928,6 +945,7 @@ int qc_ssl_do_hanshake(struct quic_conn *qc, struct ssl_sock_ctx *ctx) #ifndef HAVE_OPENSSL_QUIC TRACE_PROTO("SSL handshake OK", QUIC_EV_CONN_IO_CB, qc, &state); + ssl_sock_update_counters(ctx->ssl, counters, counters_px, qc_is_back(qc)); #else /* Hack to support O-RTT with the OpenSSL 3.5 QUIC API. * SSL_do_handshake() succeeds at the first call. Why? |-( @@ -946,6 +964,7 @@ int qc_ssl_do_hanshake(struct quic_conn *qc, struct ssl_sock_ctx *ctx) } else { TRACE_PROTO("SSL handshake OK", QUIC_EV_CONN_IO_CB, qc, &state); + ssl_sock_update_counters(ctx->ssl, counters, counters_px, qc_is_back(qc)); } } #endif diff --git a/src/ssl_sock.c b/src/ssl_sock.c index 8099f0d96..d64358641 100644 --- a/src/ssl_sock.c +++ b/src/ssl_sock.c @@ -5550,6 +5550,37 @@ err: return -1; } +/* Update counters and proxy counters of frontends or + * backends with as SSL connection object, depending on boolean + * value. + */ +void ssl_sock_update_counters(SSL *ssl, + struct ssl_counters *counters, + struct ssl_counters *counters_px, + int backend) +{ + if (!SSL_session_reused(ssl)) { + if (backend) { + update_freq_ctr(&global.ssl_be_keys_per_sec, 1); + if (global.ssl_be_keys_per_sec.curr_ctr > global.ssl_be_keys_max) + global.ssl_be_keys_max = global.ssl_be_keys_per_sec.curr_ctr; + } + else { + update_freq_ctr(&global.ssl_fe_keys_per_sec, 1); + if (global.ssl_fe_keys_per_sec.curr_ctr > global.ssl_fe_keys_max) + global.ssl_fe_keys_max = global.ssl_fe_keys_per_sec.curr_ctr; + } + + if (counters) { + HA_ATOMIC_INC(&counters->sess); + HA_ATOMIC_INC(&counters_px->sess); + } + } + else if (counters) { + HA_ATOMIC_INC(&counters->reused_sess); + HA_ATOMIC_INC(&counters_px->reused_sess); + } +} /* This is the callback which is used when an SSL handshake is pending. It * updates the FD status if it wants some polling before being called again. @@ -5564,7 +5595,7 @@ static int ssl_sock_handshake(struct connection *conn, unsigned int flag) struct ssl_counters *counters = NULL; struct ssl_counters *counters_px = NULL; struct listener *li; - struct server *srv; + struct server *srv = NULL; socklen_t lskerr; int skerr; @@ -5883,27 +5914,7 @@ reneg_ok: SSL_clear_mode(ctx->ssl, SSL_MODE_ASYNC); #endif /* Handshake succeeded */ - if (!SSL_session_reused(ctx->ssl)) { - if (objt_server(conn->target)) { - update_freq_ctr(&global.ssl_be_keys_per_sec, 1); - if (global.ssl_be_keys_per_sec.curr_ctr > global.ssl_be_keys_max) - global.ssl_be_keys_max = global.ssl_be_keys_per_sec.curr_ctr; - } - else { - update_freq_ctr(&global.ssl_fe_keys_per_sec, 1); - if (global.ssl_fe_keys_per_sec.curr_ctr > global.ssl_fe_keys_max) - global.ssl_fe_keys_max = global.ssl_fe_keys_per_sec.curr_ctr; - } - - if (counters) { - HA_ATOMIC_INC(&counters->sess); - HA_ATOMIC_INC(&counters_px->sess); - } - } - else if (counters) { - HA_ATOMIC_INC(&counters->reused_sess); - HA_ATOMIC_INC(&counters_px->reused_sess); - } + ssl_sock_update_counters(ctx->ssl, counters, counters_px, !!srv); TRACE_LEAVE(SSL_EV_CONN_HNDSHK, conn, ctx->ssl);