From 9300fc0948372f47c985f7c739a2670672785a43 Mon Sep 17 00:00:00 2001 From: Leif Hedstrom Date: Mon, 15 Dec 2025 12:09:05 -0700 Subject: [PATCH 1/2] Capture TLS handshake bytes in metrics Add txn log fields for the same HS metrics Requestor: Craig T. --- doc/admin-guide/logging/formatting.en.rst | 28 +++++++++ include/iocore/net/NetVConnection.h | 9 +++ include/proxy/http/HttpUserAgent.h | 21 +++++++ include/proxy/logging/LogAccess.h | 5 ++ src/iocore/net/P_SSLNetVConnection.h | 6 ++ src/iocore/net/SSLNetVConnection.cc | 33 +++++++++- src/iocore/net/SSLStats.cc | 2 + src/iocore/net/SSLStats.h | 2 + src/iocore/net/SSLUtils.cc | 10 +++ src/proxy/logging/Log.cc | 30 +++++++++ src/proxy/logging/LogAccess.cc | 76 +++++++++++++++++++++++ 11 files changed, 220 insertions(+), 2 deletions(-) diff --git a/doc/admin-guide/logging/formatting.en.rst b/doc/admin-guide/logging/formatting.en.rst index 3df372979fb..27dcae11dde 100644 --- a/doc/admin-guide/logging/formatting.en.rst +++ b/doc/admin-guide/logging/formatting.en.rst @@ -426,6 +426,7 @@ Lengths and Sizes .. _cqcl: .. _cqhl: .. _cqql: +.. _cqqtl: .. _csscl: .. _csshl: .. _cssql: @@ -436,6 +437,7 @@ Lengths and Sizes .. _pscl: .. _pshl: .. _psql: +.. _psqtl: .. _sscl: .. _sshl: .. _ssql: @@ -451,6 +453,12 @@ cqcl Client Request Client request content length, in bytes. cqhl Client Request Client request header length, in bytes. cqql Client Request Client request header and content length combined, in bytes. +cqqtl Client Request Same as cqql_, but for the first transaction on a + TLS connection, also includes TLS handshake bytes + received from the client. Since the TLS handshake + only occurs once per connection, the handshake bytes + are only attributed to the first transaction to + prevent double-counting. csscl Cached Origin Response Content body length from cached origin response. csshl Cached Origin Response Header length from cached origin response. cssql Cached Origin Response Content and header length from cached origin @@ -466,6 +474,12 @@ pscl Proxy Response Content body length of the |TS| proxy response. pshl Proxy Response Header length of the |TS| response to client. psql Proxy Response Content body and header length combined of the |TS| response to client. +psqtl Proxy Response Same as psql_, but for the first transaction on a + TLS connection, also includes TLS handshake bytes + sent to the client. Since the TLS handshake only + occurs once per connection, the handshake bytes are + only attributed to the first transaction to prevent + double-counting. sscl Origin Response Content body length of the origin server response to |TS|. sshl Origin Response Header length of the origin server response. @@ -623,6 +637,9 @@ SSL / Encryption .. _cqssc: .. _cqssu: .. _cqssa: +.. _cthbr: +.. _cthbt: +.. _cthb: .. _pqssl: .. _pscert: @@ -659,6 +676,17 @@ cqssg Client Request SSL Group used by |TS| to communicate with the client. OpenSSL 3.2 or later or a version of BoringSSL that supports querying group names. cqssa Client Request ALPN Protocol ID negotiated with the client. +cthbr Client Request TLS handshake bytes received from the client. This is the + number of bytes read from the client during the TLS + handshake. Populated for all transactions on a TLS connection, + including reused connections. +cthbt Client Request TLS handshake bytes sent to the client. This is the number + of bytes written to the client during the TLS handshake. + Populated for all transactions on a TLS connection, + including reused connections. +cthb Client Request Total TLS handshake bytes (received + sent). This is the + sum of cthbr_ and cthbt_. Populated for all transactions + on a TLS connection, including reused connections. pqssl Proxy Request Indicates whether the connection from |TS| to the origin was over SSL or not. pqssr Proxy Request SSL session ticket reused status from |TS| to the origin; diff --git a/include/iocore/net/NetVConnection.h b/include/iocore/net/NetVConnection.h index 9f3178fa75f..1f23b038c43 100644 --- a/include/iocore/net/NetVConnection.h +++ b/include/iocore/net/NetVConnection.h @@ -322,6 +322,15 @@ class NetVConnection : public VConnection, public PluginUserArgsget_tls_handshake_begin_time(); milestones[TS_MILESTONE_TLS_HANDSHAKE_END] = tbs->get_tls_handshake_end_time(); } + netvc->capture_handshake_bytes(m_conn_info.tls_handshake_bytes_rx, m_conn_info.tls_handshake_bytes_tx); } if (auto as = netvc->get_service()) { @@ -301,6 +310,18 @@ HttpUserAgent::get_client_alpn_id() const return m_conn_info.alpn_id; } +inline uint64_t +HttpUserAgent::get_client_tls_handshake_bytes_rx() const +{ + return m_conn_info.tls_handshake_bytes_rx; +} + +inline uint64_t +HttpUserAgent::get_client_tls_handshake_bytes_tx() const +{ + return m_conn_info.tls_handshake_bytes_tx; +} + inline void HttpUserAgent::save_transaction_info() { diff --git a/include/proxy/logging/LogAccess.h b/include/proxy/logging/LogAccess.h index b71c91ae883..11bb886c616 100644 --- a/include/proxy/logging/LogAccess.h +++ b/include/proxy/logging/LogAccess.h @@ -142,6 +142,7 @@ class LogAccess int marshal_client_req_protocol_version(char *); // STR int marshal_server_req_protocol_version(char *); // STR int marshal_client_req_squid_len(char *); // INT + int marshal_client_req_squid_len_tls(char *); // INT int marshal_client_req_header_len(char *); // INT int marshal_client_req_content_len(char *); // INT int marshal_client_req_tcp_reused(char *); // INT @@ -160,6 +161,9 @@ class LogAccess int marshal_client_req_uuid(char *); // STR int marshal_client_rx_error_code(char *); // STR int marshal_client_tx_error_code(char *); // STR + int marshal_client_tls_handshake_bytes_rx(char *); // INT + int marshal_client_tls_handshake_bytes_tx(char *); // INT + int marshal_client_tls_handshake_bytes(char *); // INT int marshal_client_req_all_header_fields(char *); // STR // @@ -168,6 +172,7 @@ class LogAccess int marshal_proxy_resp_content_type(char *); // STR int marshal_proxy_resp_reason_phrase(char *); // STR int marshal_proxy_resp_squid_len(char *); // INT + int marshal_proxy_resp_squid_len_tls(char *); // INT int marshal_proxy_resp_content_len(char *); // INT int marshal_proxy_resp_status_code(char *); // INT int marshal_status_plugin_entry(char *); // STR diff --git a/src/iocore/net/P_SSLNetVConnection.h b/src/iocore/net/P_SSLNetVConnection.h index fdc52726e49..a0ca420d32c 100644 --- a/src/iocore/net/P_SSLNetVConnection.h +++ b/src/iocore/net/P_SSLNetVConnection.h @@ -309,6 +309,8 @@ class SSLNetVConnection : public UnixNetVConnection, EThread *getThreadForTLSEvents() override; Ptr getMutexForTLSEvents() override; + bool capture_handshake_bytes(uint64_t &bytes_in, uint64_t &bytes_out) override; + protected: // UnixNetVConnection bool _isReadyToTransferData() const override; @@ -376,6 +378,10 @@ class SSLNetVConnection : public UnixNetVConnection, */ char *_getCoalescedHandShakeBuffer(int64_t total_chain_size); + // TLS handshake byte tracking (bytes read/written during handshake only) + uint64_t _tls_handshake_bytes_in = 0; + uint64_t _tls_handshake_bytes_out = 0; + enum SSLHandshakeStatus sslHandshakeStatus = SSLHandshakeStatus::SSL_HANDSHAKE_ONGOING; bool sslClientRenegotiationAbort = false; bool first_ssl_connect = true; diff --git a/src/iocore/net/SSLNetVConnection.cc b/src/iocore/net/SSLNetVConnection.cc index 787936fb76c..5f65ce25f4e 100644 --- a/src/iocore/net/SSLNetVConnection.cc +++ b/src/iocore/net/SSLNetVConnection.cc @@ -978,10 +978,11 @@ SSLNetVConnection::clear() sslLastWriteTime = 0; sslTotalBytesSent = 0; sslClientRenegotiationAbort = false; + _tls_handshake_bytes_in = 0; + _tls_handshake_bytes_out = 0; + hookOpRequested = SslVConnOp::SSL_HOOK_OP_DEFAULT; - hookOpRequested = SslVConnOp::SSL_HOOK_OP_DEFAULT; free_handshake_buffers(); - super::clear(); } void @@ -2484,3 +2485,31 @@ SSLNetVConnection::_ssl_read_buffer(void *buf, int64_t nbytes, int64_t &nread) return ssl_error; } + +bool +SSLNetVConnection::capture_handshake_bytes(uint64_t &bytes_in, uint64_t &bytes_out) +{ + if (_tls_handshake_bytes_in > 0 || _tls_handshake_bytes_out > 0) { + bytes_in = _tls_handshake_bytes_in; + bytes_out = _tls_handshake_bytes_out; + + return false; + } + + // If no SSL object, nothing to capture + if (this->ssl == nullptr) { + bytes_in = 0; + bytes_out = 0; + + return false; + } + + // Capture bytes from BIO statistics + BIO *rbio = SSL_get_rbio(this->ssl); + BIO *wbio = SSL_get_wbio(this->ssl); + + bytes_in = _tls_handshake_bytes_in = rbio ? BIO_number_read(rbio) : 0; + bytes_out = _tls_handshake_bytes_out = wbio ? BIO_number_written(wbio) : 0; + + return true; +} diff --git a/src/iocore/net/SSLStats.cc b/src/iocore/net/SSLStats.cc index fdec94b1e46..41326356c1b 100644 --- a/src/iocore/net/SSLStats.cc +++ b/src/iocore/net/SSLStats.cc @@ -280,6 +280,8 @@ SSLInitializeStatistics() ssl_rsb.user_agent_version_too_high = Metrics::Counter::createPtr("proxy.process.ssl.user_agent_version_too_high"); ssl_rsb.user_agent_version_too_low = Metrics::Counter::createPtr("proxy.process.ssl.user_agent_version_too_low"); ssl_rsb.user_agent_wrong_version = Metrics::Counter::createPtr("proxy.process.ssl.user_agent_wrong_version"); + ssl_rsb.tls_handshake_bytes_in_total = Metrics::Counter::createPtr("proxy.process.ssl.total_handshake_bytes_read_in"); + ssl_rsb.tls_handshake_bytes_out_total = Metrics::Counter::createPtr("proxy.process.ssl.total_handshake_bytes_write_in"); #if defined(OPENSSL_IS_BORINGSSL) size_t n = SSL_get_all_cipher_names(nullptr, 0); diff --git a/src/iocore/net/SSLStats.h b/src/iocore/net/SSLStats.h index 82b84445302..cd0ec4bd811 100644 --- a/src/iocore/net/SSLStats.h +++ b/src/iocore/net/SSLStats.h @@ -99,6 +99,8 @@ struct SSLStatsBlock { Metrics::Counter::AtomicType *user_agent_version_too_high = nullptr; Metrics::Counter::AtomicType *user_agent_version_too_low = nullptr; Metrics::Counter::AtomicType *user_agent_wrong_version = nullptr; + Metrics::Counter::AtomicType *tls_handshake_bytes_in_total = nullptr; + Metrics::Counter::AtomicType *tls_handshake_bytes_out_total = nullptr; // Note: The following user_agent_session_* metrics are implemented as Gauge types // even though they semantically represent cumulative counters. This is because diff --git a/src/iocore/net/SSLUtils.cc b/src/iocore/net/SSLUtils.cc index 0b7bc982ad4..dcdb8e44604 100644 --- a/src/iocore/net/SSLUtils.cc +++ b/src/iocore/net/SSLUtils.cc @@ -1078,6 +1078,16 @@ ssl_callback_info(const SSL *ssl, int where, int ret) } Metrics::Counter::increment(it->second); } + + // Capture TLS handshake byte statistics + if (netvc && netvc->get_context() == NET_VCONNECTION_IN) { + uint64_t bytes_in = 0, bytes_out = 0; + + if (netvc->capture_handshake_bytes(bytes_in, bytes_out)) { + Metrics::Counter::increment(ssl_rsb.tls_handshake_bytes_in_total, bytes_in); + Metrics::Counter::increment(ssl_rsb.tls_handshake_bytes_out_total, bytes_out); + } + } } } diff --git a/src/proxy/logging/Log.cc b/src/proxy/logging/Log.cc index ca56f27c5ac..51b5c87718e 100644 --- a/src/proxy/logging/Log.cc +++ b/src/proxy/logging/Log.cc @@ -485,6 +485,12 @@ Log::init_fields() global_field_list.add(field, false); field_symbol_hash.emplace("cqql", field); + // Client request squid length plus TLS handshake bytes received for TLS connections + field = new LogField("client_req_squid_len_tls", "cqqtl", LogField::sINT, &LogAccess::marshal_client_req_squid_len_tls, + &LogAccess::unmarshal_int_to_str); + global_field_list.add(field, false); + field_symbol_hash.emplace("cqqtl", field); + field = new LogField("cache_lookup_url_canonical", "cluc", LogField::STRING, &LogAccess::marshal_cache_lookup_url_canon, &LogAccess::unmarshal_str); global_field_list.add(field, false); @@ -574,6 +580,24 @@ Log::init_fields() global_field_list.add(field, false); field_symbol_hash.emplace("cqssa", field); + // TLS handshake bytes - bytes received from client during TLS handshake + field = new LogField("client_tls_handshake_bytes_rx", "cthbr", LogField::sINT, &LogAccess::marshal_client_tls_handshake_bytes_rx, + &LogAccess::unmarshal_int_to_str); + global_field_list.add(field, false); + field_symbol_hash.emplace("cthbr", field); + + // TLS handshake bytes - bytes sent to client during TLS handshake + field = new LogField("client_tls_handshake_bytes_tx", "cthbt", LogField::sINT, &LogAccess::marshal_client_tls_handshake_bytes_tx, + &LogAccess::unmarshal_int_to_str); + global_field_list.add(field, false); + field_symbol_hash.emplace("cthbt", field); + + // TLS handshake bytes - total (rx + tx) during TLS handshake + field = new LogField("client_tls_handshake_bytes", "cthb", LogField::sINT, &LogAccess::marshal_client_tls_handshake_bytes, + &LogAccess::unmarshal_int_to_str); + global_field_list.add(field, false); + field_symbol_hash.emplace("cthb", field); + Ptr finish_status_map = make_ptr(new LogFieldAliasTable); finish_status_map->init(N_LOG_FINISH_CODE_TYPES, LOG_FINISH_FIN, "FIN", LOG_FINISH_INTR, "INTR", LOG_FINISH_TIMEOUT, "TIMEOUT"); @@ -623,6 +647,12 @@ Log::init_fields() global_field_list.add(field, false); field_symbol_hash.emplace("psql", field); + // Squid length plus TLS handshake bytes sent for TLS connections + field = new LogField("proxy_resp_squid_len_tls", "psqtl", LogField::sINT, &LogAccess::marshal_proxy_resp_squid_len_tls, + &LogAccess::unmarshal_int_to_str); + global_field_list.add(field, false); + field_symbol_hash.emplace("psqtl", field); + field = new LogField("proxy_resp_content_len", "pscl", LogField::sINT, &LogAccess::marshal_proxy_resp_content_len, &LogAccess::unmarshal_int_to_str); global_field_list.add(field, false); diff --git a/src/proxy/logging/LogAccess.cc b/src/proxy/logging/LogAccess.cc index 50991eada35..2543b7099be 100644 --- a/src/proxy/logging/LogAccess.cc +++ b/src/proxy/logging/LogAccess.cc @@ -2096,6 +2096,27 @@ LogAccess::marshal_client_req_squid_len(char *buf) return INK_MIN_ALIGN; } +/*------------------------------------------------------------------------- + Client request squid length plus TLS handshake bytes received for TLS connections. + -------------------------------------------------------------------------*/ +int +LogAccess::marshal_client_req_squid_len_tls(char *buf) +{ + if (buf) { + int64_t val = 0; + + if (m_client_request) { + val = m_client_request->length_get() + m_http_sm->client_request_body_bytes; + } + + if (!m_http_sm->get_user_agent().get_client_tcp_reused()) { + val += m_http_sm->get_user_agent().get_client_tls_handshake_bytes_rx(); + } + marshal_int(buf, val); + } + return INK_MIN_ALIGN; +} + /*------------------------------------------------------------------------- -------------------------------------------------------------------------*/ @@ -2320,6 +2341,44 @@ LogAccess::marshal_client_security_alpn(char *buf) return round_len; } +/*------------------------------------------------------------------------- + TLS Handshake Bytes - Bytes received from client during TLS handshake + -------------------------------------------------------------------------*/ +int +LogAccess::marshal_client_tls_handshake_bytes_rx(char *buf) +{ + if (buf) { + marshal_int(buf, m_http_sm->get_user_agent().get_client_tls_handshake_bytes_rx()); + } + return INK_MIN_ALIGN; +} + +/*------------------------------------------------------------------------- + TLS Handshake Bytes - Bytes sent to client during TLS handshake + -------------------------------------------------------------------------*/ +int +LogAccess::marshal_client_tls_handshake_bytes_tx(char *buf) +{ + if (buf) { + marshal_int(buf, m_http_sm->get_user_agent().get_client_tls_handshake_bytes_tx()); + } + return INK_MIN_ALIGN; +} + +/*------------------------------------------------------------------------- + TLS Handshake Bytes - Total bytes (rx + tx) during TLS handshake + -------------------------------------------------------------------------*/ +int +LogAccess::marshal_client_tls_handshake_bytes(char *buf) +{ + if (buf) { + uint64_t total = m_http_sm->get_user_agent().get_client_tls_handshake_bytes_rx() + + m_http_sm->get_user_agent().get_client_tls_handshake_bytes_tx(); + marshal_int(buf, static_cast(total)); + } + return INK_MIN_ALIGN; +} + /*------------------------------------------------------------------------- -------------------------------------------------------------------------*/ @@ -2360,6 +2419,23 @@ LogAccess::marshal_proxy_resp_squid_len(char *buf) return INK_MIN_ALIGN; } +/*------------------------------------------------------------------------- + Squid length plus TLS handshake bytes sent for TLS connections. + -------------------------------------------------------------------------*/ +int +LogAccess::marshal_proxy_resp_squid_len_tls(char *buf) +{ + if (buf) { + int64_t val = m_http_sm->client_response_hdr_bytes + m_http_sm->client_response_body_bytes; + + if (!m_http_sm->get_user_agent().get_client_tcp_reused()) { + val += m_http_sm->get_user_agent().get_client_tls_handshake_bytes_tx(); + } + marshal_int(buf, val); + } + return INK_MIN_ALIGN; +} + /*------------------------------------------------------------------------- -------------------------------------------------------------------------*/ From b6515d932fea7d2f7e1951c6c403342f63f252a6 Mon Sep 17 00:00:00 2001 From: Leif Hedstrom Date: Tue, 16 Dec 2025 12:53:02 -0700 Subject: [PATCH 2/2] Move things out of the NetVC, subtract early data --- doc/admin-guide/logging/formatting.en.rst | 12 +++------ include/iocore/net/NetVConnection.h | 9 ------- include/iocore/net/TLSBasicSupport.h | 4 +++ include/proxy/http/HttpUserAgent.h | 16 +++++++++++- src/iocore/net/P_SSLNetVConnection.h | 6 ----- src/iocore/net/SSLNetVConnection.cc | 30 ----------------------- src/iocore/net/SSLUtils.cc | 4 +-- src/iocore/net/TLSBasicSupport.cc | 30 +++++++++++++++++++++++ src/proxy/logging/LogAccess.cc | 12 ++++++++- 9 files changed, 66 insertions(+), 57 deletions(-) diff --git a/doc/admin-guide/logging/formatting.en.rst b/doc/admin-guide/logging/formatting.en.rst index 27dcae11dde..4b34d823e7e 100644 --- a/doc/admin-guide/logging/formatting.en.rst +++ b/doc/admin-guide/logging/formatting.en.rst @@ -455,10 +455,8 @@ cqql Client Request Client request header and content length combined, in bytes. cqqtl Client Request Same as cqql_, but for the first transaction on a TLS connection, also includes TLS handshake bytes - received from the client. Since the TLS handshake - only occurs once per connection, the handshake bytes - are only attributed to the first transaction to - prevent double-counting. + received from the client. Note that this metrics + may not always be 100% accurate. csscl Cached Origin Response Content body length from cached origin response. csshl Cached Origin Response Header length from cached origin response. cssql Cached Origin Response Content and header length from cached origin @@ -476,10 +474,8 @@ psql Proxy Response Content body and header length combined of the |TS| response to client. psqtl Proxy Response Same as psql_, but for the first transaction on a TLS connection, also includes TLS handshake bytes - sent to the client. Since the TLS handshake only - occurs once per connection, the handshake bytes are - only attributed to the first transaction to prevent - double-counting. + sent to the client. Note that this metric may not + always be 100% accurate. sscl Origin Response Content body length of the origin server response to |TS|. sshl Origin Response Header length of the origin server response. diff --git a/include/iocore/net/NetVConnection.h b/include/iocore/net/NetVConnection.h index 1f23b038c43..9f3178fa75f 100644 --- a/include/iocore/net/NetVConnection.h +++ b/include/iocore/net/NetVConnection.h @@ -322,15 +322,6 @@ class NetVConnection : public VConnection, public PluginUserArgsget_tls_handshake_begin_time(); milestones[TS_MILESTONE_TLS_HANDSHAKE_END] = tbs->get_tls_handshake_end_time(); } - netvc->capture_handshake_bytes(m_conn_info.tls_handshake_bytes_rx, m_conn_info.tls_handshake_bytes_tx); + tbs->get_tls_handshake_bytes(m_conn_info.tls_handshake_bytes_rx, m_conn_info.tls_handshake_bytes_tx); + } + + if (auto eds = netvc->get_service()) { + m_conn_info.tls_early_data_len = eds->get_early_data_len(); } if (auto as = netvc->get_service()) { @@ -322,6 +330,12 @@ HttpUserAgent::get_client_tls_handshake_bytes_tx() const return m_conn_info.tls_handshake_bytes_tx; } +inline size_t +HttpUserAgent::get_client_tls_early_data_len() const +{ + return m_conn_info.tls_early_data_len; +} + inline void HttpUserAgent::save_transaction_info() { diff --git a/src/iocore/net/P_SSLNetVConnection.h b/src/iocore/net/P_SSLNetVConnection.h index a0ca420d32c..fdc52726e49 100644 --- a/src/iocore/net/P_SSLNetVConnection.h +++ b/src/iocore/net/P_SSLNetVConnection.h @@ -309,8 +309,6 @@ class SSLNetVConnection : public UnixNetVConnection, EThread *getThreadForTLSEvents() override; Ptr getMutexForTLSEvents() override; - bool capture_handshake_bytes(uint64_t &bytes_in, uint64_t &bytes_out) override; - protected: // UnixNetVConnection bool _isReadyToTransferData() const override; @@ -378,10 +376,6 @@ class SSLNetVConnection : public UnixNetVConnection, */ char *_getCoalescedHandShakeBuffer(int64_t total_chain_size); - // TLS handshake byte tracking (bytes read/written during handshake only) - uint64_t _tls_handshake_bytes_in = 0; - uint64_t _tls_handshake_bytes_out = 0; - enum SSLHandshakeStatus sslHandshakeStatus = SSLHandshakeStatus::SSL_HANDSHAKE_ONGOING; bool sslClientRenegotiationAbort = false; bool first_ssl_connect = true; diff --git a/src/iocore/net/SSLNetVConnection.cc b/src/iocore/net/SSLNetVConnection.cc index 5f65ce25f4e..3119543b17b 100644 --- a/src/iocore/net/SSLNetVConnection.cc +++ b/src/iocore/net/SSLNetVConnection.cc @@ -978,8 +978,6 @@ SSLNetVConnection::clear() sslLastWriteTime = 0; sslTotalBytesSent = 0; sslClientRenegotiationAbort = false; - _tls_handshake_bytes_in = 0; - _tls_handshake_bytes_out = 0; hookOpRequested = SslVConnOp::SSL_HOOK_OP_DEFAULT; free_handshake_buffers(); @@ -2485,31 +2483,3 @@ SSLNetVConnection::_ssl_read_buffer(void *buf, int64_t nbytes, int64_t &nread) return ssl_error; } - -bool -SSLNetVConnection::capture_handshake_bytes(uint64_t &bytes_in, uint64_t &bytes_out) -{ - if (_tls_handshake_bytes_in > 0 || _tls_handshake_bytes_out > 0) { - bytes_in = _tls_handshake_bytes_in; - bytes_out = _tls_handshake_bytes_out; - - return false; - } - - // If no SSL object, nothing to capture - if (this->ssl == nullptr) { - bytes_in = 0; - bytes_out = 0; - - return false; - } - - // Capture bytes from BIO statistics - BIO *rbio = SSL_get_rbio(this->ssl); - BIO *wbio = SSL_get_wbio(this->ssl); - - bytes_in = _tls_handshake_bytes_in = rbio ? BIO_number_read(rbio) : 0; - bytes_out = _tls_handshake_bytes_out = wbio ? BIO_number_written(wbio) : 0; - - return true; -} diff --git a/src/iocore/net/SSLUtils.cc b/src/iocore/net/SSLUtils.cc index dcdb8e44604..c27a1830aa6 100644 --- a/src/iocore/net/SSLUtils.cc +++ b/src/iocore/net/SSLUtils.cc @@ -1079,11 +1079,11 @@ ssl_callback_info(const SSL *ssl, int where, int ret) Metrics::Counter::increment(it->second); } - // Capture TLS handshake byte statistics if (netvc && netvc->get_context() == NET_VCONNECTION_IN) { uint64_t bytes_in = 0, bytes_out = 0; + auto tbs = TLSBasicSupport::getInstance(const_cast(ssl)); - if (netvc->capture_handshake_bytes(bytes_in, bytes_out)) { + if (tbs && tbs->get_tls_handshake_bytes(bytes_in, bytes_out)) { Metrics::Counter::increment(ssl_rsb.tls_handshake_bytes_in_total, bytes_in); Metrics::Counter::increment(ssl_rsb.tls_handshake_bytes_out_total, bytes_out); } diff --git a/src/iocore/net/TLSBasicSupport.cc b/src/iocore/net/TLSBasicSupport.cc index 7510aeb4281..98374ad504f 100644 --- a/src/iocore/net/TLSBasicSupport.cc +++ b/src/iocore/net/TLSBasicSupport.cc @@ -72,6 +72,36 @@ TLSBasicSupport::clear() { this->_tls_handshake_begin_time = 0; this->_tls_handshake_end_time = 0; + this->_tls_handshake_bytes_in = 0; + this->_tls_handshake_bytes_out = 0; +} + +bool +TLSBasicSupport::get_tls_handshake_bytes(uint64_t &bytes_in, uint64_t &bytes_out) +{ + if (_tls_handshake_bytes_in > 0 || _tls_handshake_bytes_out > 0) { + bytes_in = _tls_handshake_bytes_in; + bytes_out = _tls_handshake_bytes_out; + return false; + } + + SSL *ssl = this->_get_ssl_object(); + if (ssl == nullptr) { + bytes_in = 0; + bytes_out = 0; + return false; + } + + BIO *rbio = SSL_get_rbio(ssl); + BIO *wbio = SSL_get_wbio(ssl); + + uint64_t bio_in = rbio ? BIO_number_read(rbio) : 0; + uint64_t bio_out = wbio ? BIO_number_written(wbio) : 0; + + bytes_in = _tls_handshake_bytes_in = bio_in; + bytes_out = _tls_handshake_bytes_out = bio_out; + + return true; } TLSHandle diff --git a/src/proxy/logging/LogAccess.cc b/src/proxy/logging/LogAccess.cc index 2543b7099be..ef432cf9cb0 100644 --- a/src/proxy/logging/LogAccess.cc +++ b/src/proxy/logging/LogAccess.cc @@ -2098,6 +2098,9 @@ LogAccess::marshal_client_req_squid_len(char *buf) /*------------------------------------------------------------------------- Client request squid length plus TLS handshake bytes received for TLS connections. + For TLS 1.3 early data (0-RTT), we subtract the early data length from the + handshake bytes to avoid double-counting since the early data bytes are + already included in client_request_body_bytes. -------------------------------------------------------------------------*/ int LogAccess::marshal_client_req_squid_len_tls(char *buf) @@ -2110,7 +2113,14 @@ LogAccess::marshal_client_req_squid_len_tls(char *buf) } if (!m_http_sm->get_user_agent().get_client_tcp_reused()) { - val += m_http_sm->get_user_agent().get_client_tls_handshake_bytes_rx(); + uint64_t handshake_rx = m_http_sm->get_user_agent().get_client_tls_handshake_bytes_rx(); + size_t early_data_len = m_http_sm->get_user_agent().get_client_tls_early_data_len(); + + if (early_data_len > 0 && handshake_rx > early_data_len) { + handshake_rx -= early_data_len; + } + + val += handshake_rx; } marshal_int(buf, val); }