QUIC: Introduce discarded_packet() event

And include its occurrence into the history as X. The event raising is
configurable with a new const redef QUIC::max_discarded_packet_events.
This commit is contained in:
Arne Welzel 2025-10-08 17:25:41 +02:00
parent 9345a8c84e
commit 586b7b94cb
15 changed files with 96 additions and 8 deletions

5
NEWS
View file

@ -64,6 +64,11 @@ New Functionality
- The DNS analyzer now returns the set of parameters for SVCB data. It previously handled
SVCB packets, but omitted the parameters while parsing.
- The QUIC analyzer now raises QUIC::discarded_packet() when a packet with fixed_bit
set to 0 is encountered. Such an occurrence is included in the QUIC history as ``X``.
This functionality can be controlled with ``QUIC::max_discarded_packet_events``,
setting this variable to -1 disabled the ``QUIC::discarded_packet`` event.
Changed Functionality
---------------------

View file

@ -59,6 +59,7 @@ export {
## C CONNECTION_CLOSE packet
## S SSL Client/Server Hello
## U Unfamiliar QUIC version
## X Discarded packet after successful decryption of INITIAL packets.
## ====== ====================================================
history: string &log &default="";
@ -77,6 +78,10 @@ export {
## The maximum length of the history field.
option max_history_length = 100;
## Maximum number of QUIC::discarded packet() events to generate.
## Set to 0 for unlimited, -1 for disabled.
const max_discarded_packet_events: int = 100 &redef;
}
redef record connection += {
@ -164,6 +169,18 @@ event QUIC::retry_packet(c: connection, is_orig: bool, version: count, dcid: str
delete c$quic;
}
event QUIC::discarded_packet(c: connection, is_orig: bool, total_decrypted: count)
{
if ( ! c?$quic )
{
# This should not happen.
Reporter::conn_weird("QUIC_spurious_discarded_packet", c);
return;
}
add_to_history(c, is_orig, "Xdiscarded");
}
# If we couldn't handle a version, log it as a single record.
event QUIC::unhandled_version(c: connection, is_orig: bool, version: count, dcid: string, scid: string)
{

View file

@ -94,3 +94,15 @@ global QUIC::connection_close_frame: event(c: connection, is_orig: bool, version
##
## scid: The Source Connection ID field.
global QUIC::unhandled_version: event(c: connection, is_orig: bool, version: count, dcid: string, scid: string);
## Generated when a QUIC packet with fixed_bit 0 is encountered.
##
## This event is only generated if some INITIAL QUIC packets were successfully
## decrypted previously.
##
## c: The connection.
##
## is_orig: True if the packet is from the the connection's originator.
##
## total_decrypted: The number of QUIC packets successfully decrypted previously.
global QUIC::discarded_packet: event(c: connection, is_orig: bool, total_decrypted: count);

View file

@ -22,3 +22,5 @@ on QUIC::ConnectionClosePayload -> event QUIC::connection_close_frame($conn, $is
self.error_code.result_, self.reason_phrase);
on QUIC::UnhandledVersion -> event QUIC::unhandled_version($conn, $is_orig, self.header.version, self.header.dest_conn_id, self.header.src_conn_id);
on QUIC::Packet if ( self.raise_discarded_packet ) -> event QUIC::discarded_packet($conn, $is_orig, self.total_decrypted);

View file

@ -6,6 +6,8 @@ module QUIC;
import spicy;
import zeek;
global max_discarded_packet_events: optional<int64>;
# The interface to the C++ code that handles the decryption of the INITIAL packet payload using well-known keys
public function decrypt_crypto_payload(version: uint32, data: bytes, connection_id: bytes, encrypted_offset: uint64, payload_offset: uint64, from_client: bool): bytes &cxxname="QUIC_decrypt_crypto_payload";
@ -125,6 +127,9 @@ type Context = struct {
server_sink: sink&;
ssl_handle: zeek::ProtocolHandle &optional;
total_decrypted: uint64;
total_discarded: uint64;
};
##############
@ -483,6 +488,8 @@ type Packet = unit(from_client: bool, context: Context&) {
var crypto: CryptoSinkUnit&;
var crypto_sink: sink&;
var raise_discarded_packet: bool = False;
var total_decrypted: uint64;
# Attach an SSL analyzer to this connection once.
on %init {
@ -606,6 +613,9 @@ type Packet = unit(from_client: bool, context: Context&) {
# We were able to decrypt the INITIAL packet. Confirm QUIC!
spicy::accept_input();
# Keep track of the packets decrypted, too.
++context.total_decrypted;
}
# If this packet has a SHORT header, consume until &eod, there's nothing
@ -618,9 +628,20 @@ type Packet = unit(from_client: bool, context: Context&) {
}
False -> {
# Consume the packet if fixed_bit is not 1. Basically discard it.
#
# # TODO: Raise QUIC::discarded_packet() when this happens.
: skip bytes &eod;
: skip bytes &eod {
++context.total_discarded;
# Initialize the global if it hasn't been initialized yet.
if (!max_discarded_packet_events)
max_discarded_packet_events = zeek::as_int(zeek::get_value("QUIC::max_discarded_packet_events"));
# If enabled and we haven't raised too many events yet, set
# a flag such that in .evt QUIC::discarded_packet() is raised.
if (cast<int64>(context.total_decrypted) > 0 && (*max_discarded_packet_events == 0 || cast<int64>(context.total_discarded) <= *max_discarded_packet_events)) {
self.raise_discarded_packet = True;
self.total_decrypted = context.total_decrypted;
}
}
}
};
};

View file

@ -7,5 +7,5 @@
#open XXXX-XX-XX-XX-XX-XX
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version client_initial_dcid client_scid server_scid server_name client_protocol history
#types time string addr port addr port string string string string string string string
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 765b:b77b:dad1:7e73:56f9:5a0f:52a3:f4f 39264 725f:1f71:525f:a3b:525f:3673:525f:3673 443 1 ceef7990f5bb4071 1e6dc7 eeef7990f5bb4071 tr6.snapchat.com h3 IIISZiiiiishIH
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 765b:b77b:dad1:7e73:56f9:5a0f:52a3:f4f 39264 725f:1f71:525f:a3b:525f:3673:525f:3673 443 1 ceef7990f5bb4071 1e6dc7 eeef7990f5bb4071 tr6.snapchat.com h3 IXIXISZXiiiiishIH
#close XXXX-XX-XX-XX-XX-XX

View file

@ -7,5 +7,5 @@
#open XXXX-XX-XX-XX-XX-XX
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version client_initial_dcid client_scid server_scid server_name client_protocol history
#types time string addr port addr port string string string string string string string
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.17.0.2 34347 64.233.166.94 443 1 815d62c70884f4b51e8ccadd5beed372 e5ec6b26584229be98a164349ae910351c40d10b c15d62c70884f4b5 www.google.de h3 ISishIHhHhhH
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 172.17.0.2 34347 64.233.166.94 443 1 815d62c70884f4b51e8ccadd5beed372 e5ec6b26584229be98a164349ae910351c40d10b c15d62c70884f4b5 www.google.de h3 ISXishIHXhHhhH
#close XXXX-XX-XX-XX-XX-XX

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
ts uid history
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 IIISZiiiiishIH

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
ts uid history
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 IXIXISZXiiiiishIH

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
ts uid history
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 IIISZiiiiishIH

View file

@ -0,0 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
ts uid history
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 IXIISZiiiiishIH

View file

@ -7,5 +7,5 @@
#open XXXX-XX-XX-XX-XX-XX
#fields ts uid id.orig_h id.orig_p id.resp_h id.resp_p version client_initial_dcid client_scid server_scid server_name client_protocol history
#types time string addr port addr port string string string string string string string
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 82.239.54.117 44174 250.58.23.113 443 1 c5a5015ae8f479784a 34696c 01275b138ee6aca8a6276b132ae6b3547cf7773f blog.cloudflare.com h3 ISiishIhhhHHhHH
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 82.239.54.117 44174 250.58.23.113 443 1 c5a5015ae8f479784a 34696c 01275b138ee6aca8a6276b132ae6b3547cf7773f blog.cloudflare.com h3 ISXixisxhIXhhhHHhHH
#close XXXX-XX-XX-XX-XX-XX

View file

@ -1,3 +1,3 @@
### BTest baseline data generated by btest-diff. Do not edit. Use "btest -U/-u" to update. Requires BTest >= 0.63.
ts uid history
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ISi
XXXXXXXXXX.XXXXXX CHhAvVGS1DHFjwGM9 ISX

View file

@ -0,0 +1,19 @@
# @TEST-DOC: Test the QUIC::max_discarded_packet_events setting and its.
# @TEST-REQUIRES: ${SCRIPTS}/have-spicy
# @TEST-EXEC: zeek -r $TRACES/quic/quic-39264-rand.pcap base/protocols/quic QUIC::max_discarded_packet_events=-1
# @TEST-EXEC: test ! -f analyzer.log || cat analyzer.log >&2
# @TEST-EXEC: zeek-cut -m ts uid history service_name < quic.log > quic.log.no-discarded-packets
# @TEST-EXEC: zeek -r $TRACES/quic/quic-39264-rand.pcap base/protocols/quic QUIC::max_discarded_packet_events=1
# @TEST-EXEC: test ! -f analyzer.log || cat analyzer.log >&2
# @TEST-EXEC: zeek-cut -m ts uid history service_name < quic.log > quic.log.one-discarded-packet
# @TEST-EXEC: zeek -r $TRACES/quic/quic-39264-rand.pcap base/protocols/quic
# @TEST-EXEC: test ! -f analyzer.log || cat analyzer.log >&2
# @TEST-EXEC: zeek-cut -m ts uid history service_name < quic.log > quic.log.default-discarded-packets
# @TEST-EXEC: btest-diff quic.log.no-discarded-packets
# @TEST-EXEC: btest-diff quic.log.one-discarded-packet
# @TEST-EXEC: btest-diff quic.log.default-discarded-packets

View file

@ -1 +1 @@
31094f4840d0abc8fdf7f810e281851bd057931b
0aecb0467324a7db7758f54a677e61b4b0532b60