Skip to content

Commit 9300fc0

Browse files
committed
Capture TLS handshake bytes in metrics
Add txn log fields for the same HS metrics Requestor: Craig T.
1 parent e5cd67e commit 9300fc0

File tree

11 files changed

+220
-2
lines changed

11 files changed

+220
-2
lines changed

doc/admin-guide/logging/formatting.en.rst

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -426,6 +426,7 @@ Lengths and Sizes
426426
.. _cqcl:
427427
.. _cqhl:
428428
.. _cqql:
429+
.. _cqqtl:
429430
.. _csscl:
430431
.. _csshl:
431432
.. _cssql:
@@ -436,6 +437,7 @@ Lengths and Sizes
436437
.. _pscl:
437438
.. _pshl:
438439
.. _psql:
440+
.. _psqtl:
439441
.. _sscl:
440442
.. _sshl:
441443
.. _ssql:
@@ -451,6 +453,12 @@ cqcl Client Request Client request content length, in bytes.
451453
cqhl Client Request Client request header length, in bytes.
452454
cqql Client Request Client request header and content length combined,
453455
in bytes.
456+
cqqtl Client Request Same as cqql_, but for the first transaction on a
457+
TLS connection, also includes TLS handshake bytes
458+
received from the client. Since the TLS handshake
459+
only occurs once per connection, the handshake bytes
460+
are only attributed to the first transaction to
461+
prevent double-counting.
454462
csscl Cached Origin Response Content body length from cached origin response.
455463
csshl Cached Origin Response Header length from cached origin response.
456464
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.
466474
pshl Proxy Response Header length of the |TS| response to client.
467475
psql Proxy Response Content body and header length combined of the
468476
|TS| response to client.
477+
psqtl Proxy Response Same as psql_, but for the first transaction on a
478+
TLS connection, also includes TLS handshake bytes
479+
sent to the client. Since the TLS handshake only
480+
occurs once per connection, the handshake bytes are
481+
only attributed to the first transaction to prevent
482+
double-counting.
469483
sscl Origin Response Content body length of the origin server response
470484
to |TS|.
471485
sshl Origin Response Header length of the origin server response.
@@ -623,6 +637,9 @@ SSL / Encryption
623637
.. _cqssc:
624638
.. _cqssu:
625639
.. _cqssa:
640+
.. _cthbr:
641+
.. _cthbt:
642+
.. _cthb:
626643
.. _pqssl:
627644
.. _pscert:
628645

@@ -659,6 +676,17 @@ cqssg Client Request SSL Group used by |TS| to communicate with the client.
659676
OpenSSL 3.2 or later or a version of BoringSSL that
660677
supports querying group names.
661678
cqssa Client Request ALPN Protocol ID negotiated with the client.
679+
cthbr Client Request TLS handshake bytes received from the client. This is the
680+
number of bytes read from the client during the TLS
681+
handshake. Populated for all transactions on a TLS connection,
682+
including reused connections.
683+
cthbt Client Request TLS handshake bytes sent to the client. This is the number
684+
of bytes written to the client during the TLS handshake.
685+
Populated for all transactions on a TLS connection,
686+
including reused connections.
687+
cthb Client Request Total TLS handshake bytes (received + sent). This is the
688+
sum of cthbr_ and cthbt_. Populated for all transactions
689+
on a TLS connection, including reused connections.
662690
pqssl Proxy Request Indicates whether the connection from |TS| to the origin
663691
was over SSL or not.
664692
pqssr Proxy Request SSL session ticket reused status from |TS| to the origin;

include/iocore/net/NetVConnection.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,15 @@ class NetVConnection : public VConnection, public PluginUserArgs<TS_USER_ARGS_VC
322322
return 0;
323323
}
324324

325+
/** Capture handshake byte statistics. */
326+
virtual bool
327+
capture_handshake_bytes(uint64_t &bytes_in, uint64_t &bytes_out)
328+
{
329+
bytes_in = 0;
330+
bytes_out = 0;
331+
return false;
332+
}
333+
325334
/** Structure holding user options. */
326335
NetVCOptions options;
327336

include/proxy/http/HttpUserAgent.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,10 @@ struct ClientConnectionInfo {
5555
std::string security_group{"-"};
5656

5757
int alpn_id{SessionProtocolNameRegistry::INVALID};
58+
59+
// TLS handshake bytes (rx = received from client, tx = sent to client)
60+
uint64_t tls_handshake_bytes_rx{0};
61+
uint64_t tls_handshake_bytes_tx{0};
5862
};
5963

6064
class HttpUserAgent
@@ -97,6 +101,10 @@ class HttpUserAgent
97101

98102
int get_client_alpn_id() const;
99103

104+
uint64_t get_client_tls_handshake_bytes_rx() const;
105+
106+
uint64_t get_client_tls_handshake_bytes_tx() const;
107+
100108
private:
101109
HttpVCTableEntry *m_entry{nullptr};
102110
IOBufferReader *m_raw_buffer_reader{nullptr};
@@ -186,6 +194,7 @@ HttpUserAgent::set_txn(ProxyTransaction *txn, TransactionMilestones &milestones)
186194
milestones[TS_MILESTONE_TLS_HANDSHAKE_START] = tbs->get_tls_handshake_begin_time();
187195
milestones[TS_MILESTONE_TLS_HANDSHAKE_END] = tbs->get_tls_handshake_end_time();
188196
}
197+
netvc->capture_handshake_bytes(m_conn_info.tls_handshake_bytes_rx, m_conn_info.tls_handshake_bytes_tx);
189198
}
190199

191200
if (auto as = netvc->get_service<ALPNSupport>()) {
@@ -301,6 +310,18 @@ HttpUserAgent::get_client_alpn_id() const
301310
return m_conn_info.alpn_id;
302311
}
303312

313+
inline uint64_t
314+
HttpUserAgent::get_client_tls_handshake_bytes_rx() const
315+
{
316+
return m_conn_info.tls_handshake_bytes_rx;
317+
}
318+
319+
inline uint64_t
320+
HttpUserAgent::get_client_tls_handshake_bytes_tx() const
321+
{
322+
return m_conn_info.tls_handshake_bytes_tx;
323+
}
324+
304325
inline void
305326
HttpUserAgent::save_transaction_info()
306327
{

include/proxy/logging/LogAccess.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class LogAccess
142142
int marshal_client_req_protocol_version(char *); // STR
143143
int marshal_server_req_protocol_version(char *); // STR
144144
int marshal_client_req_squid_len(char *); // INT
145+
int marshal_client_req_squid_len_tls(char *); // INT
145146
int marshal_client_req_header_len(char *); // INT
146147
int marshal_client_req_content_len(char *); // INT
147148
int marshal_client_req_tcp_reused(char *); // INT
@@ -160,6 +161,9 @@ class LogAccess
160161
int marshal_client_req_uuid(char *); // STR
161162
int marshal_client_rx_error_code(char *); // STR
162163
int marshal_client_tx_error_code(char *); // STR
164+
int marshal_client_tls_handshake_bytes_rx(char *); // INT
165+
int marshal_client_tls_handshake_bytes_tx(char *); // INT
166+
int marshal_client_tls_handshake_bytes(char *); // INT
163167
int marshal_client_req_all_header_fields(char *); // STR
164168

165169
//
@@ -168,6 +172,7 @@ class LogAccess
168172
int marshal_proxy_resp_content_type(char *); // STR
169173
int marshal_proxy_resp_reason_phrase(char *); // STR
170174
int marshal_proxy_resp_squid_len(char *); // INT
175+
int marshal_proxy_resp_squid_len_tls(char *); // INT
171176
int marshal_proxy_resp_content_len(char *); // INT
172177
int marshal_proxy_resp_status_code(char *); // INT
173178
int marshal_status_plugin_entry(char *); // STR

src/iocore/net/P_SSLNetVConnection.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,8 @@ class SSLNetVConnection : public UnixNetVConnection,
309309
EThread *getThreadForTLSEvents() override;
310310
Ptr<ProxyMutex> getMutexForTLSEvents() override;
311311

312+
bool capture_handshake_bytes(uint64_t &bytes_in, uint64_t &bytes_out) override;
313+
312314
protected:
313315
// UnixNetVConnection
314316
bool _isReadyToTransferData() const override;
@@ -376,6 +378,10 @@ class SSLNetVConnection : public UnixNetVConnection,
376378
*/
377379
char *_getCoalescedHandShakeBuffer(int64_t total_chain_size);
378380

381+
// TLS handshake byte tracking (bytes read/written during handshake only)
382+
uint64_t _tls_handshake_bytes_in = 0;
383+
uint64_t _tls_handshake_bytes_out = 0;
384+
379385
enum SSLHandshakeStatus sslHandshakeStatus = SSLHandshakeStatus::SSL_HANDSHAKE_ONGOING;
380386
bool sslClientRenegotiationAbort = false;
381387
bool first_ssl_connect = true;

src/iocore/net/SSLNetVConnection.cc

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -978,10 +978,11 @@ SSLNetVConnection::clear()
978978
sslLastWriteTime = 0;
979979
sslTotalBytesSent = 0;
980980
sslClientRenegotiationAbort = false;
981+
_tls_handshake_bytes_in = 0;
982+
_tls_handshake_bytes_out = 0;
983+
hookOpRequested = SslVConnOp::SSL_HOOK_OP_DEFAULT;
981984

982-
hookOpRequested = SslVConnOp::SSL_HOOK_OP_DEFAULT;
983985
free_handshake_buffers();
984-
985986
super::clear();
986987
}
987988
void
@@ -2484,3 +2485,31 @@ SSLNetVConnection::_ssl_read_buffer(void *buf, int64_t nbytes, int64_t &nread)
24842485

24852486
return ssl_error;
24862487
}
2488+
2489+
bool
2490+
SSLNetVConnection::capture_handshake_bytes(uint64_t &bytes_in, uint64_t &bytes_out)
2491+
{
2492+
if (_tls_handshake_bytes_in > 0 || _tls_handshake_bytes_out > 0) {
2493+
bytes_in = _tls_handshake_bytes_in;
2494+
bytes_out = _tls_handshake_bytes_out;
2495+
2496+
return false;
2497+
}
2498+
2499+
// If no SSL object, nothing to capture
2500+
if (this->ssl == nullptr) {
2501+
bytes_in = 0;
2502+
bytes_out = 0;
2503+
2504+
return false;
2505+
}
2506+
2507+
// Capture bytes from BIO statistics
2508+
BIO *rbio = SSL_get_rbio(this->ssl);
2509+
BIO *wbio = SSL_get_wbio(this->ssl);
2510+
2511+
bytes_in = _tls_handshake_bytes_in = rbio ? BIO_number_read(rbio) : 0;
2512+
bytes_out = _tls_handshake_bytes_out = wbio ? BIO_number_written(wbio) : 0;
2513+
2514+
return true;
2515+
}

src/iocore/net/SSLStats.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -280,6 +280,8 @@ SSLInitializeStatistics()
280280
ssl_rsb.user_agent_version_too_high = Metrics::Counter::createPtr("proxy.process.ssl.user_agent_version_too_high");
281281
ssl_rsb.user_agent_version_too_low = Metrics::Counter::createPtr("proxy.process.ssl.user_agent_version_too_low");
282282
ssl_rsb.user_agent_wrong_version = Metrics::Counter::createPtr("proxy.process.ssl.user_agent_wrong_version");
283+
ssl_rsb.tls_handshake_bytes_in_total = Metrics::Counter::createPtr("proxy.process.ssl.total_handshake_bytes_read_in");
284+
ssl_rsb.tls_handshake_bytes_out_total = Metrics::Counter::createPtr("proxy.process.ssl.total_handshake_bytes_write_in");
283285

284286
#if defined(OPENSSL_IS_BORINGSSL)
285287
size_t n = SSL_get_all_cipher_names(nullptr, 0);

src/iocore/net/SSLStats.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ struct SSLStatsBlock {
9999
Metrics::Counter::AtomicType *user_agent_version_too_high = nullptr;
100100
Metrics::Counter::AtomicType *user_agent_version_too_low = nullptr;
101101
Metrics::Counter::AtomicType *user_agent_wrong_version = nullptr;
102+
Metrics::Counter::AtomicType *tls_handshake_bytes_in_total = nullptr;
103+
Metrics::Counter::AtomicType *tls_handshake_bytes_out_total = nullptr;
102104

103105
// Note: The following user_agent_session_* metrics are implemented as Gauge types
104106
// even though they semantically represent cumulative counters. This is because

src/iocore/net/SSLUtils.cc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1078,6 +1078,16 @@ ssl_callback_info(const SSL *ssl, int where, int ret)
10781078
}
10791079
Metrics::Counter::increment(it->second);
10801080
}
1081+
1082+
// Capture TLS handshake byte statistics
1083+
if (netvc && netvc->get_context() == NET_VCONNECTION_IN) {
1084+
uint64_t bytes_in = 0, bytes_out = 0;
1085+
1086+
if (netvc->capture_handshake_bytes(bytes_in, bytes_out)) {
1087+
Metrics::Counter::increment(ssl_rsb.tls_handshake_bytes_in_total, bytes_in);
1088+
Metrics::Counter::increment(ssl_rsb.tls_handshake_bytes_out_total, bytes_out);
1089+
}
1090+
}
10811091
}
10821092
}
10831093

src/proxy/logging/Log.cc

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -485,6 +485,12 @@ Log::init_fields()
485485
global_field_list.add(field, false);
486486
field_symbol_hash.emplace("cqql", field);
487487

488+
// Client request squid length plus TLS handshake bytes received for TLS connections
489+
field = new LogField("client_req_squid_len_tls", "cqqtl", LogField::sINT, &LogAccess::marshal_client_req_squid_len_tls,
490+
&LogAccess::unmarshal_int_to_str);
491+
global_field_list.add(field, false);
492+
field_symbol_hash.emplace("cqqtl", field);
493+
488494
field = new LogField("cache_lookup_url_canonical", "cluc", LogField::STRING, &LogAccess::marshal_cache_lookup_url_canon,
489495
&LogAccess::unmarshal_str);
490496
global_field_list.add(field, false);
@@ -574,6 +580,24 @@ Log::init_fields()
574580
global_field_list.add(field, false);
575581
field_symbol_hash.emplace("cqssa", field);
576582

583+
// TLS handshake bytes - bytes received from client during TLS handshake
584+
field = new LogField("client_tls_handshake_bytes_rx", "cthbr", LogField::sINT, &LogAccess::marshal_client_tls_handshake_bytes_rx,
585+
&LogAccess::unmarshal_int_to_str);
586+
global_field_list.add(field, false);
587+
field_symbol_hash.emplace("cthbr", field);
588+
589+
// TLS handshake bytes - bytes sent to client during TLS handshake
590+
field = new LogField("client_tls_handshake_bytes_tx", "cthbt", LogField::sINT, &LogAccess::marshal_client_tls_handshake_bytes_tx,
591+
&LogAccess::unmarshal_int_to_str);
592+
global_field_list.add(field, false);
593+
field_symbol_hash.emplace("cthbt", field);
594+
595+
// TLS handshake bytes - total (rx + tx) during TLS handshake
596+
field = new LogField("client_tls_handshake_bytes", "cthb", LogField::sINT, &LogAccess::marshal_client_tls_handshake_bytes,
597+
&LogAccess::unmarshal_int_to_str);
598+
global_field_list.add(field, false);
599+
field_symbol_hash.emplace("cthb", field);
600+
577601
Ptr<LogFieldAliasTable> finish_status_map = make_ptr(new LogFieldAliasTable);
578602
finish_status_map->init(N_LOG_FINISH_CODE_TYPES, LOG_FINISH_FIN, "FIN", LOG_FINISH_INTR, "INTR", LOG_FINISH_TIMEOUT, "TIMEOUT");
579603

@@ -623,6 +647,12 @@ Log::init_fields()
623647
global_field_list.add(field, false);
624648
field_symbol_hash.emplace("psql", field);
625649

650+
// Squid length plus TLS handshake bytes sent for TLS connections
651+
field = new LogField("proxy_resp_squid_len_tls", "psqtl", LogField::sINT, &LogAccess::marshal_proxy_resp_squid_len_tls,
652+
&LogAccess::unmarshal_int_to_str);
653+
global_field_list.add(field, false);
654+
field_symbol_hash.emplace("psqtl", field);
655+
626656
field = new LogField("proxy_resp_content_len", "pscl", LogField::sINT, &LogAccess::marshal_proxy_resp_content_len,
627657
&LogAccess::unmarshal_int_to_str);
628658
global_field_list.add(field, false);

0 commit comments

Comments
 (0)