diff --git a/NEWS b/NEWS index af792aed78..c7781d3629 100644 --- a/NEWS +++ b/NEWS @@ -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 --------------------- diff --git a/scripts/base/protocols/quic/main.zeek b/scripts/base/protocols/quic/main.zeek index 284107b26a..36e23871ae 100644 --- a/scripts/base/protocols/quic/main.zeek +++ b/scripts/base/protocols/quic/main.zeek @@ -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) { diff --git a/scripts/base/protocols/quic/spicy-events.zeek b/scripts/base/protocols/quic/spicy-events.zeek index 914c0d2f16..bcca73aa47 100644 --- a/scripts/base/protocols/quic/spicy-events.zeek +++ b/scripts/base/protocols/quic/spicy-events.zeek @@ -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); diff --git a/src/analyzer/protocol/quic/QUIC.evt b/src/analyzer/protocol/quic/QUIC.evt index 0dd6fa73fe..7c5435050e 100644 --- a/src/analyzer/protocol/quic/QUIC.evt +++ b/src/analyzer/protocol/quic/QUIC.evt @@ -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); diff --git a/src/analyzer/protocol/quic/QUIC.spicy b/src/analyzer/protocol/quic/QUIC.spicy index 835cfb342c..3205782180 100644 --- a/src/analyzer/protocol/quic/QUIC.spicy +++ b/src/analyzer/protocol/quic/QUIC.spicy @@ -6,6 +6,8 @@ module QUIC; import spicy; import zeek; +global max_discarded_packet_events: optional; + # 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(context.total_decrypted) > 0 && (*max_discarded_packet_events == 0 || cast(context.total_discarded) <= *max_discarded_packet_events)) { + self.raise_discarded_packet = True; + self.total_decrypted = context.total_decrypted; + } + } } }; }; diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.39264-rand/quic.log b/testing/btest/Baseline/scripts.base.protocols.quic.39264-rand/quic.log index 10648c9e82..50395c88ae 100644 --- a/testing/btest/Baseline/scripts.base.protocols.quic.39264-rand/quic.log +++ b/testing/btest/Baseline/scripts.base.protocols.quic.39264-rand/quic.log @@ -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 diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.curl-http3/quic.log b/testing/btest/Baseline/scripts.base.protocols.quic.curl-http3/quic.log index 9a2bc00efd..6d05cd3fb0 100644 --- a/testing/btest/Baseline/scripts.base.protocols.quic.curl-http3/quic.log +++ b/testing/btest/Baseline/scripts.base.protocols.quic.curl-http3/quic.log @@ -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 diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.discarded-packet/quic.log.cut b/testing/btest/Baseline/scripts.base.protocols.quic.discarded-packet/quic.log.cut new file mode 100644 index 0000000000..d774d46ee9 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.discarded-packet/quic.log.cut @@ -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 diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.discarded-packet/quic.log.default-discarded-packets b/testing/btest/Baseline/scripts.base.protocols.quic.discarded-packet/quic.log.default-discarded-packets new file mode 100644 index 0000000000..e1ca9f5e2a --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.discarded-packet/quic.log.default-discarded-packets @@ -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 diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.discarded-packet/quic.log.no-discarded-packets b/testing/btest/Baseline/scripts.base.protocols.quic.discarded-packet/quic.log.no-discarded-packets new file mode 100644 index 0000000000..d774d46ee9 --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.discarded-packet/quic.log.no-discarded-packets @@ -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 diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.discarded-packet/quic.log.one-discarded-packet b/testing/btest/Baseline/scripts.base.protocols.quic.discarded-packet/quic.log.one-discarded-packet new file mode 100644 index 0000000000..02c35124bf --- /dev/null +++ b/testing/btest/Baseline/scripts.base.protocols.quic.discarded-packet/quic.log.one-discarded-packet @@ -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 diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.firefox/quic.log b/testing/btest/Baseline/scripts.base.protocols.quic.firefox/quic.log index c009ab178e..c11c608163 100644 --- a/testing/btest/Baseline/scripts.base.protocols.quic.firefox/quic.log +++ b/testing/btest/Baseline/scripts.base.protocols.quic.firefox/quic.log @@ -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 diff --git a/testing/btest/Baseline/scripts.base.protocols.quic.max-history-length/quic.log.cut b/testing/btest/Baseline/scripts.base.protocols.quic.max-history-length/quic.log.cut index 2d63056136..f99c845268 100644 --- a/testing/btest/Baseline/scripts.base.protocols.quic.max-history-length/quic.log.cut +++ b/testing/btest/Baseline/scripts.base.protocols.quic.max-history-length/quic.log.cut @@ -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 diff --git a/testing/btest/scripts/base/protocols/quic/discarded-packet.zeek b/testing/btest/scripts/base/protocols/quic/discarded-packet.zeek new file mode 100644 index 0000000000..bad809757f --- /dev/null +++ b/testing/btest/scripts/base/protocols/quic/discarded-packet.zeek @@ -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 diff --git a/testing/external/commit-hash.zeek-testing b/testing/external/commit-hash.zeek-testing index f88d37e597..4dd8867bea 100644 --- a/testing/external/commit-hash.zeek-testing +++ b/testing/external/commit-hash.zeek-testing @@ -1 +1 @@ -31094f4840d0abc8fdf7f810e281851bd057931b +0aecb0467324a7db7758f54a677e61b4b0532b60