RFC 9312
Manageability of the QUIC Transport Protocol
Manageability of the QUIC Transport Protocol ๐ฆ
- Series: Request for Comments: 9312, from the Internet Engineering Task Force (IETF) ๐
- Authors: M. Kรผhlewind (Ericsson) and B. Trammell (Google Switzerland GmbH) ๐
- Category: Informational ๐
- ISSN: 2070-1721 โจ
- Date: September 2022 ๐ธ
- Obsoletes / updates: the title block doesn't list any RFC this one obsoletes or updates ๐
Abstract โจ
Okay bestie, this doc is about how manageable QUIC is, and it zooms in on what QUIC's design and wire image mean for network ops that touch QUIC traffic ๐ฅ It's basically a "user's manual" for the wire image, so network operators and equipment vendors who rely on transport-aware network functions know what they're working with ๐
Status of This Memo ๐
Not a standards track spec, just published for info purposes, so no cap, it's informational ๐ง
This is an IETF product ๐ It represents the consensus of the IETF community, got public review, and was approved for publication by the Internet Engineering Steering Group (IESG). Not every IESG-approved doc is a candidate for any level of Internet Standard, so check Section 2 of RFC 7841 for that ๐ซถ
For the current status, any errata, and how to send feedback, head to https://www.rfc-editor.org/info/rfc9312 ๐ฆ
Copyright Notice ๐
Copyright (c) 2022 IETF Trust and the persons identified as the document authors. All rights reserved. โจ
This doc is subject to BCP 78 and the IETF Trust's Legal Provisions Relating to IETF Documents (https://trustee.ietf.org/license-info) as they're in effect on the publication date. Please read these carefully, because they spell out your rights and restrictions for this document ๐ Code Components pulled out of this document must include Revised BSD License text as described in Section 4.e of the Trust Legal Provisions, and they come without warranty, as the Revised BSD License describes ๐
Table of Contents ๐๏ธ
1. Introduction
2. Features of the QUIC Wire Image
2.1. QUIC Packet Header Structure
2.2. Coalesced Packets
2.3. Use of Port Numbers
2.4. The QUIC Handshake
2.5. Integrity Protection of the Wire Image
2.6. Connection ID and Rebinding
2.7. Packet Numbers
2.8. Version Negotiation and Greasing
3. Network-Visible Information about QUIC Flows
3.1. Identifying QUIC Traffic
3.1.1. Identifying Negotiated Version
3.1.2. First Packet Identification for Garbage Rejection
3.2. Connection Confirmation
3.3. Distinguishing Acknowledgment Traffic
3.4. Server Name Indication (SNI)
3.4.1. Extracting Server Name Indication (SNI) Information
3.5. Flow Association
3.6. Flow Teardown
3.7. Flow Symmetry Measurement
3.8. Round-Trip Time (RTT) Measurement
3.8.1. Measuring Initial RTT
3.8.2. Using the Spin Bit for Passive RTT Measurement
4. Specific Network Management Tasks
4.1. Passive Network Performance Measurement and Troubleshooting
4.2. Stateful Treatment of QUIC Traffic
4.3. Address Rewriting to Ensure Routing Stability
4.4. Server Cooperation with Load Balancers
4.5. Filtering Behavior
4.6. UDP Blocking, Throttling, and NAT Binding
4.7. DDoS Detection and Mitigation
4.8. Quality of Service Handling and ECMP Routing
4.9. Handling ICMP Messages
4.10. Guiding Path MTU
5. IANA Considerations
6. Security Considerations
7. References
7.1. Normative References
7.2. Informative References
Acknowledgments
Contributors
Authors' Addresses
1. Introduction ๐
Okay so QUIC [QUIC-TRANSPORT] is a brand-new transport protocol that rides inside UDP ๐ฆ It uses TLS [QUIC-TLS] to encrypt all the payload data and most of the control info, which is so iconic ๐ญ QUIC version 1 was mainly designed as a transport for HTTP, and the resulting protocol is known as HTTP/3 [QUIC-HTTP] ๐
This doc gives guidance for network operations that manage QUIC traffic ๐ซถ It covers how to read and use the info QUIC exposes to the network, the requirements and assumptions QUIC's design has around how the network treats it, and how common network management practices get affected by QUIC ๐
QUIC is an end-to-end transport protocol, so nothing in the protocol header is meant to be changed by the network ๐ That's enforced by integrity protection of the wire image [WIRE-IMAGE]. Since most transport-layer control signaling is encrypted, the network can see way less than it could with TCP ๐
Integrity protection is also a win for troubleshooting at the endpoints, because no node on the path can modify transport-layer info ๐ BUT it also means that in-network operations which depend on modifying data (for examples, see [RFC9065]) aren't possible without cooperation from a QUIC endpoint ๐ญ That cooperation might be possible if you add a proxy that authenticates as an endpoint. Proxy operations are not in scope for this doc ๐ง
Network management is not one-size-fits-all, babe. Practices that are necessary or even mandatory inside enterprise networks with certain compliance requirements would be impermissible on networks without those requirements ๐ So just because a practice shows up in this document doesn't mean it's being recommended. For each practice, the doc describes what is and isn't possible with QUIC as defined ๐ธ
This doc only looks at network management practices that observe traffic on the wire ๐ So swapping observation-based troubleshooting for active measurement techniques is out of scope. A broader take on network management for encrypted transports is in [RFC9065] ๐
QUIC-specific terminology used here is defined in [QUIC-TRANSPORT] ๐
2. Features of the QUIC Wire Image ๐
This section is all about the parts of QUIC that affect how devices forwarding QUIC packets get designed and run ๐ฅ So it's mainly looking at the unencrypted part of QUIC's wire image [WIRE-IMAGE], meaning the info in each QUIC packet's header, plus how that info changes over time โจ QUIC is a versioned protocol, so the header's wire image can change from version to version ๐ฆ The field that identifies the QUIC version in some packets, and the format of the Version Negotiation packet, are both inspectable and invariant [QUIC-INVARIANTS] ๐
This doc addresses version 1 of QUIC, whose wire image is fully defined in [QUIC-TRANSPORT] and [QUIC-TLS] ๐ Features of the wire image described here may change in future versions, except where they're specified as an invariant [QUIC-INVARIANTS]. So don't use them to identify QUIC as a protocol or to guess how future versions of QUIC will behave ๐ โโ๏ธโจ
2.1. QUIC Packet Header Structure โจ
okay so QUIC packets can rock either a long header or a short header ๐. The very first bit is the Header Form bit, and it tells you which kind of header you're looking at ๐. Its purpose stays the same across every QUIC version, which is so iconic of it ๐ .
The long header is the one that spills more tea ๐ซ. It carries a version number, plus Source and Destination Connection IDs, which is how packets get matched up with a QUIC connection ๐ฆ. The definition and location of these fields in the long header are invariant for future versions of QUIC, but future versions might add extra fields to the long header anyway [QUIC-INVARIANTS] ๐ง.
In version 1 of QUIC, the long header shows up during connection establishment. It's used to transmit CRYPTO handshake data, perform version negotiation, perform retry, and send 0-RTT data ๐ธ.
Short headers take over after connection establishment in version 1 of QUIC ๐. They only expose an optional Destination Connection ID and the initial flags byte, which includes the spin bit for RTT measurement โญ.
The following information is exposed in QUIC packet headers in all versions of QUIC (as specified in [QUIC-INVARIANTS]) ๐ซถ:
- version number: The version number is present in the long header and tells you which version was used for that packet. During Version Negotiation (see Section 17.2.1 of [QUIC-TRANSPORT] and Section 2.8), the Version field has a special value (
0x00000000) that marks the packet as a Version Negotiation packet ๐. QUIC version 1 uses version0x00000001. Operators should expect to observe packets with other version numbers because of various Internet experiments, future standards, and greasing [RFC7801] ๐งช. An IANA registry holds the values of all standardized versions of QUIC, and it may contain some proprietary versions (see Section 22.2 of [QUIC-TRANSPORT]). Still, other versions of QUIC can be expected to be seen on the Internet at any given time ๐. - Source and Destination Connection ID: Short and long headers both carry a Destination Connection ID, which is a variable-length field ๐. If the Destination Connection ID is not zero length, it can be used to identify the connection a QUIC packet belongs to, for load balancing and NAT rebinding purposes. See Sections 4.4 and 2.6 for more on that ๐ฅ. Long packet headers also carry a Source Connection ID. This one only shows up on long headers, and it tells you which Destination Connection ID the other endpoint should use when it sends packets ๐. On long header packets, the lengths of the connection IDs are also present. On short header packets, the length of the Destination Connection ID is implicit, because it's already known from earlier long header packets ๐ง.
In version 1 of QUIC, the following extra info is exposed:
- "Fixed Bit": In version 1 of QUIC, the second-most-significant bit of the first octet is set to 1, unless the packet is a Version Negotiation packet or an extension is used that changes how this bit is used ๐ฆ. When it's set to 1, it lets endpoints easily demultiplex with other UDP-encapsulated protocols ๐. Even though this bit is fixed in the version 1 specification, endpoints might use an extension that varies the bit [QUIC-GREASE]. So observers cannot reliably use it as an identifier for QUIC ๐.
- latency spin bit: The third-most-significant bit of the first octet in the short header for version 1 ๐ซ. Endpoints set the spin bit so that tracking its edge transitions can be used to passively observe end-to-end RTT. See Section 3.8.2 for further details โฑ๏ธ.
- header type: The long header has a 2-bit packet type field after the Header Form and Fixed Bits ๐. Header types correspond to stages of the handshake. See Section 17.2 of [QUIC-TRANSPORT] for details ๐.
- length: The length of the rest of the QUIC packet after the Length field, which only exists on long headers ๐. This field is what lets coalesced packets work during the handshake (see Section 2.2) ๐งฉ.
- token: Initial packets may contain a token. It's a variable-length opaque value that the client can optionally send to the server, and it's used for validating the client's address ๐. Retry packets also contain a token, which the client can use in an Initial packet on a later connection attempt ๐. In both cases, the length of the token is explicit โจ.
Retry (Section 17.2.5 of [QUIC-TRANSPORT]) and Version Negotiation (Section 17.2.1 of [QUIC-TRANSPORT]) packets are not encrypted ๐. Retry packets are integrity protected ๐ก๏ธ. Transport parameters are used to authenticate the contents of Retry packets later in the handshake ๐ค. For other kinds of packets, version 1 of QUIC cryptographically protects other information in the packet headers ๐:
- Packet Number: All packets except Version Negotiation and Retry packets have an associated packet number. Here's the twist though: this packet number is encrypted, so on-path observers can't use it ๐ซฃ. The offset of the packet number can be decoded in long headers, while in short headers it's implicit (it depends on the Destination Connection ID length) ๐งฎ. The length of the packet number is cryptographically protected too ๐ .
- Key Phase: The Key Phase bit (present in short headers) specifies which keys were used to encrypt the packet, so key rotation can happen ๐. The Key Phase bit is cryptographically protected ๐.
2.2. Coalesced Packets
Multiple QUIC packets can be coalesced into a single UDP datagram ๐ฆ. The datagram carries one or more long header packets, followed by zero or one short header packets ๐ง. When packets are coalesced, the Length fields in the long headers are what separate the QUIC packets. See Section 12.2 of [QUIC-TRANSPORT] ๐ช. The Length field is variable-length, and its position in the header also shifts depending on the lengths of the Source and Destination Connection IDs. See Section 17.2 of [QUIC-TRANSPORT] for that ๐ธ.
2.3. Use of Port Numbers
Applications that have a mapping for both TCP and QUIC are expected to use the same port number for both services ๐. That said, as for all other IETF transports [RFC7605], there's no guarantee that a specific application will use a given registered port, or that a given port carries traffic for the matching registered service ๐. This is especially true when application layer information is encrypted ๐. For example, [QUIC-HTTP] specifies the use of the HTTP Alternative Services mechanism [RFC7838] to discover HTTP/3 services on other ports ๐ฆ.
Further, because QUIC has a connection ID, it's also possible to maintain multiple QUIC connections over one 5-tuple (protocol, source and destination IP address, and source and destination port) ๐. However, if the connection ID is zero length, all packets of the 5-tuple likely belong to the same QUIC connection ๐.
2.4. The QUIC Handshake ๐ค
okay so every new QUIC connection starts with a handshake you can literally spot on the wire (peep Section 3.1 for the deets ๐), and it leaks some info that anyone can passively observe ๐ซฃ
before we get into the nitty gritty, we're gonna look at the general communication pattern you can see in the UDP datagrams carrying the QUIC handshake. then we'll zoom in on each datagram one by one ๐
the QUIC handshake can usually be recognized on the wire by its four flights of datagrams: "Client Initial", "Server Initial", "Client Completion", and "Server Completion" ๐ (see Figure 1 below ๐ฆ)
Client Server
| |
+----Client Initial----------------------->|
+----(zero or more 0-RTT)----------------->|
| |
|<-----------------------Server Initial----+
|<--------(1-RTT encrypted data starts)----+
| |
+----Client Completion-------------------->|
+----(1-RTT encrypted data starts)-------->|
| |
|<--------------------Server Completion----+
| |
Figure 1: General Communication Pattern Visible in the QUIC Handshake
so the handshake kicks off when the client sends one or more datagrams containing Initial packets (see Figure 2 for the full breakdown ๐). that triggers the Server Initial response (see Figure 3 ๐), which usually has three kinds of packets: Initial packet(s) carrying the start of the server's side of the TLS handshake, Handshake packet(s) carrying the rest of the server's part of the TLS handshake, and 1-RTT packet(s), if there are any ๐ธ
the client can send 0-RTT data as soon as it has sent its ClientHello, and the server can send 1-RTT data as soon as it has sent its ServerHello. that's the speed. ๐๏ธ๐จ
the Client Completion flight has at least one Handshake packet and could also include an Initial packet โจ and during the handshake, QUIC packets from different contexts can get coalesced (see Section 2.2) so fewer UDP datagrams get sent. efficiency is the goal bestie ๐
handshake packets can show up out of order without messing up the handshake, as long as the reordering doesn't come with huge delays that trigger a spurious Probe Timeout (Section 6.2 of [QUIC-RECOVERY]) ๐ if packets get lost or reordered, the packets from the same flight might not show up close together in time. the order of the flights still stays the same though, because each flight depends on the peer's previous flight ๐ง
datagrams carrying an Initial packet (Client Initial, Server Initial, and some Client Completion ones) have at least 1200 octets of UDP payload ๐ this protects against amplification attacks and checks that the network path can handle the minimum QUIC IP packet size (see Section 14 of [QUIC-TRANSPORT]) ๐ก๏ธ it's done by adding PADDING frames inside the Initial packet, coalescing other packets with the Initial packet, or leaving unused payload in the UDP packet after the Initial packet. and a network path has to be able to forward packets at least this big for QUIC to work at all ๐
the content of Initial packets is encrypted with Initial Secrets, which come from a per-version constant and the client's Destination Connection ID ๐ so any on-path device that knows the per-version constant can see that content, and that's how it's treated in this illustration. the content of QUIC Handshake packets is encrypted using keys set up during the initial handshake exchange, so it's not visible ๐
Initial, Handshake, and 1-RTT packets all belong to different cryptographic and transport contexts ๐ the Client Completion (Figure 4) and Server Completion (Figure 5) flights wrap up the Initial and Handshake contexts by sending final acknowledgments and CRYPTO frames ๐
+----------------------------------------------------------+
| UDP header (source and destination UDP ports) |
+----------------------------------------------------------+
| QUIC long header (type = Initial, Version, DCID, SCID) (Length)
+----------------------------------------------------------+ |
| QUIC CRYPTO frame header | |
+----------------------------------------------------------+ |
| | TLS ClientHello (incl. TLS SNI) | | |
+----------------------------------------------------------+ |
| QUIC PADDING frames | |
+----------------------------------------------------------+<-+
Figure 2: Example Client Initial Datagram Without 0-RTT
a Client Initial packet exposes the Version, Source, and Destination Connection IDs without encryption ๐ the payload of the Initial packet is protected using the Initial secret. the complete TLS ClientHello, including any TLS Server Name Indication (SNI) that's present, gets sent in one or more CRYPTO frames across one or more QUIC Initial packets ๐ซถ
+------------------------------------------------------------+
| UDP header (source and destination UDP ports) |
+------------------------------------------------------------+
| QUIC long header (type = Initial, Version, DCID, SCID) (Length)
+------------------------------------------------------------+ |
| QUIC CRYPTO frame header | |
+------------------------------------------------------------+ |
| TLS ServerHello | |
+------------------------------------------------------------+ |
| QUIC ACK frame (acknowledging client hello) | |
+------------------------------------------------------------+<-+
| QUIC long header (type = Handshake, Version, DCID, SCID) (Length)
+------------------------------------------------------------+ |
| encrypted payload (presumably CRYPTO frames) | |
+------------------------------------------------------------+<-+
| QUIC short header |
+------------------------------------------------------------+
| 1-RTT encrypted payload |
+------------------------------------------------------------+
Figure 3: Coalesced Server Initial Datagram Pattern
the Server Initial datagram also exposes the version number and the Source and Destination Connection IDs in the clear ๐ the payload of the Initial packet is protected using the Initial secret.
+------------------------------------------------------------+
| UDP header (source and destination UDP ports) |
+------------------------------------------------------------+
| QUIC long header (type = Initial, Version, DCID, SCID) (Length)
+------------------------------------------------------------+ |
| QUIC ACK frame (acknowledging Server Initial) | |
+------------------------------------------------------------+<-+
| QUIC long header (type = Handshake, Version, DCID, SCID) (Length)
+------------------------------------------------------------+ |
| encrypted payload (presumably CRYPTO/ACK frames) | |
+------------------------------------------------------------+<-+
| QUIC short header |
+------------------------------------------------------------+
| 1-RTT encrypted payload |
+------------------------------------------------------------+
Figure 4: Coalesced Client Completion Datagram Pattern
the Client Completion flight doesn't expose any extra info ๐คซ however, the Destination Connection ID is server-selected, so it usually isn't the same ID that was sent in the Client Initial ๐ Client Completion flights contain 1-RTT packets that signal the handshake has completed on the client (see Section 3.2), and they're used for three-way handshake RTT estimation as in Section 3.8 โญ
+------------------------------------------------------------+
| UDP header (source and destination UDP ports) |
+------------------------------------------------------------+
| QUIC long header (type = Handshake, Version, DCID, SCID) (Length)
+------------------------------------------------------------+ |
| encrypted payload (presumably ACK frame) | |
+------------------------------------------------------------+<-+
| QUIC short header |
+------------------------------------------------------------+
| 1-RTT encrypted payload |
+------------------------------------------------------------+
Figure 5: Coalesced Server Completion Datagram Pattern
similar to Client Completion, Server Completion doesn't expose any additional info. watching it only tells you that the handshake has completed ๐ฅน
when the client uses 0-RTT data, the Client Initial flight can also include one or more 0-RTT packets, as shown in Figure 6 ๐งโโ๏ธ
+----------------------------------------------------------+
| UDP header (source and destination UDP ports) |
+----------------------------------------------------------+
| QUIC long header (type = Initial, Version, DCID, SCID) (Length)
+----------------------------------------------------------+ |
| QUIC CRYPTO frame header | |
+----------------------------------------------------------+ |
| TLS ClientHello (incl. TLS SNI) | |
+----------------------------------------------------------+<-+
| QUIC long header (type = 0-RTT, Version, DCID, SCID) (Length)
+----------------------------------------------------------+ |
| 0-RTT encrypted payload | |
+----------------------------------------------------------+<-+
Figure 6: Coalesced 0-RTT Client Initial Datagram
when a 0-RTT packet is coalesced with an Initial packet, the datagram gets padded to 1200 bytes ๐ additional datagrams containing only 0-RTT packets with long headers can be sent after the client Initial packet, and they carry more 0-RTT data ๐ธ the amount of 0-RTT protected data that can go out in the first flight is limited by the initial congestion window, which is typically around 10 packets (see Section 7.2 of [QUIC-RECOVERY]) ๐ฆ
2.5. Integrity Protection of the Wire Image ๐
as soon as the cryptographic context is established, all the info in the QUIC header, including the exposed stuff, is integrity protected ๐ก๏ธ and any info that was exposed in packets sent before the cryptographic context was established gets validated during the cryptographic handshake ๐ so devices on path can't alter any information or bits in QUIC packets. any alteration would make the integrity check fail, and the receiver would discard the packet ๐
some parts of Initial packets could be altered by removing and reapplying the authenticated encryption, without an immediate discard at the receiver ๐ but the cryptographic handshake validates most fields, so any changes to those fields will cause a connection establishment failure later on ๐ซ
2.6. Connection ID and Rebinding ๐ฆ
okay so the connection ID is giving independent identity ๐ซถ it lets QUIC packets get linked together without caring about the 5-tuple at all. that's what makes rebinding possible after one endpoint (usually the client) has an address change. in-network devices can also use it to make sure related 5-tuple flows get balanced together (see Section 4.4) โจ
the client and server each pick a connection ID during the handshake ๐ a server might ask the client to use a certain connection ID, while the client might choose a zero-length value. connection IDs can change during the connection's lifetime too, and the new one is delivered inside encrypted frames (see Section 5.1 of [QUIC-TRANSPORT]). so seeing a new connection ID does not necessarily mean you're looking at a new connection ๐
[QUIC-LB] has the algorithms for encoding the server mapping inside a connection ID, so it can be shared with selected on-path devices like load balancers ๐ but server mappings should only be exposed to selected entities, bestie. uncontrolled exposure would let someone link multiple IP addresses to the same host if the server also supports migration, and that opens an attack vector on specific servers or pools ๐ญ the best way to hide an encoding is to look random to every other observer, and encryption is the most rigorous way to get there ๐ so trying to infer anything from specific parts of a connection ID is unlikely to be useful ๐
2.7. Packet Numbers ๐ธ
the Packet Number field is always there in the QUIC packet header in version 1, but it's always encrypted ๐ the key for packet number protection on Initial packets (the ones sent before cryptographic context is established) is specific to the QUIC version. packet number protection on later packets uses secrets derived from the end-to-end cryptographic context. so packet numbers are not part of the wire image that on-path observers can see ๐
2.8. Version Negotiation and Greasing ๐ง
Version Negotiation packets are how the server says "hey, that version you asked for isn't supported" (see Section 6 of [QUIC-TRANSPORT]) ๐ they aren't intrinsically protected, but future QUIC versions could use later encrypted messages to verify they're authentic. so if anyone changes this list, it will be detected, and that may cause the endpoints to terminate the connection attempt โญ
also, the list of versions in a Version Negotiation packet may contain reserved versions. this mechanism exists to avoid ossification in how the selection mechanism gets implemented ๐ a client may also send an Initial packet with a reserved version number to trigger version negotiation. in the Version Negotiation packet, the connection IDs from the client's Initial packet get reflected back to provide proof of return-routability. so changing that info will also make the connection fail ๐ซฃ
QUIC is expected to evolve rapidly, so new versions (both experimental and IETF standard ones) will show up on the Internet more often than with other commonly deployed Internet and transport-layer protocols ๐ฅ that means using the Version field to recognize traffic behaves differently than it does with those protocols. using one particular version number to spot valid QUIC traffic will persistently miss a fraction of QUIC flows and completely fail in the near future ๐ relying on the Version field for admission control is also likely to cause unintended failure modes. admitting QUIC traffic regardless of version avoids all of these failure modes, avoids unnecessary deployment delays, and supports continuous version-based evolution โจ
3. Network-Visible Information about QUIC Flows ๐
this section is all about the different observations and inferences a passive observer in the network can make about QUIC flows, based on the wire image from Section 2 ๐ฆ unless noted, we assume a bidirectional observer (one that sees packets in both directions, in the order they're carried on the wire), but usually without any keying information.
3.1. Identifying QUIC Traffic ๐ต๏ธโโ๏ธ
the QUIC wire image is not specifically designed to stand out from other UDP traffic to a passive observer. some QUIC applications may be heuristically identifiable on a per-application basis, but there's no general method for telling QUIC apart from otherwise unclassifiable UDP traffic on a given link. so any unrecognized UDP traffic may be QUIC traffic ๐ซถ
at the time of writing, two application bindings for QUIC have been published or adopted by the IETF: HTTP/3 [QUIC-HTTP] and DNS over Dedicated QUIC Connections [RFC9250] โจ both are known to have active Internet deployments, so assuming all QUIC traffic is HTTP/3 is not valid, bestie ๐ โโ๏ธ HTTP/3 uses UDP port 443 by convention, but various methods can be used to specify alternate port numbers. other apps (like Microsoft's SMB over QUIC) also use UDP port 443 by default ๐ so simple assumptions about whether a flow is using QUIC (or which app might be using it) based only on a UDP port number may not hold. see Section 5 of [RFC7605] ๐
the second-most-significant bit (0x40) of the first octet is set to 1 in most QUIC packets of the current version (see Section 2.1 and Section 17 of [QUIC-TRANSPORT]), but this way of recognizing QUIC traffic is not reliable ๐ฌ first, it only gives you one bit of info, and it's prone to collisions with UDP-based protocols other than those considered in [RFC7983]. second, this part of the wire image is not invariant [QUIC-INVARIANTS] and may change in future versions of the protocol, or even get negotiated during the handshake via an extension [QUIC-GREASE] ๐ญ
the transport parameters in the client's Initial packet are observable by the network, but the network can't modify them without causing a connection failure ๐ซ and the server's reply can't be observed, so observers can't know which parameters are actually in use ๐
3.1.1. Identifying Negotiated Version ๐
an in-network observer who assumes a set of packets belongs to a QUIC flow might infer the version number in use by watching the handshake ๐ if the version number in an Initial packet of the server response later shows up in a packet from the client, then both endpoints have accepted that version to be used for the rest of the connection (see Section 2 of [QUIC-VERSION-NEGOTIATION]) ๐
the negotiated version can't be identified for flows where the handshake isn't observed, such as in the case of connection migration ๐ญ however, it might be possible to associate a flow with a flow whose version has been identified. see Section 3.5 ๐งฉ
3.1.2. First Packet Identification for Garbage Rejection ๐๏ธ
a related question is whether the first packet of a given flow, on a port known to be associated with QUIC, is actually a valid QUIC packet. this helps with in-network filtering of garbage UDP packets (reflection attacks, random backscatter, etc.) ๐ก๏ธ heuristics based on the first byte of the packet (the packet type) could separate valid from invalid first packet types, but deploying such heuristics is not recommended, because bits in the first byte may have different meanings in future versions of the protocol ๐ โโ๏ธ
3.2. Connection Confirmation ๐
this document focuses on QUIC version 1, and this Connection Confirmation section only applies to packets that belong to QUIC version 1 flows ๐ for on-path observation, it assumes those packets have been identified as such by observing a version number exchange, as described above.
connection establishment uses Initial and Handshake packets containing a TLS handshake, plus Retry packets that don't contain parts of the handshake ๐ค so connection establishment can be detected with heuristics similar to the ones used to detect TLS over TCP. a client starting a connection may also send data in 0-RTT packets directly after the Initial packet containing the TLS ClientHello โฉ since packets can be reordered or lost in the network, 0-RTT packets could show up before the Initial packet ๐
note that in this version of QUIC, clients send Initial packets before servers do, servers send Handshake packets before clients do, and only clients send Initial packets with tokens ๐ญ that means an endpoint can be identified as a client or server by an on-path observer. an attempted connection after Retry can be detected by correlating the contents of the Retry packet with the Token and the Destination Connection ID fields of the new Initial packet ๐ต๏ธโโ๏ธโจ
3.3. Distinguishing Acknowledgment Traffic ๐ซง
some deployed in-network functions tell apart packets that carry only acknowledgment (ACK-only) information from packets carrying upper-layer data, in order to try to boost performance. for example, they might queue ACKs differently or manipulate ACK signaling [RFC3449] ๐ฆ this is possible in TCP, but QUIC doesn't support it, since acknowledgment signaling is carried inside QUIC's encrypted payload and ACK manipulation is impossible ๐
specifically, heuristics that try to tell ACK-only packets from payload-carrying packets based on packet size are likely to fail ๐ต they're not recommended as a way to construe the internals of QUIC's operation, because those mechanisms can change, e.g., due to the use of extensions ๐ช๏ธ
3.4. Server Name Indication (SNI) ๐ท๏ธ
the client's TLS ClientHello may contain a Server Name Indication (SNI) extension [RFC6066], which is how the client reveals the name of the server it intends to connect to, so the server can present a certificate based on that name ๐ชช if it's present, SNI information is available to unidirectional observers on the client-to-server path if it.
the TLS ClientHello may also contain an Application-Layer Protocol Negotiation (ALPN) extension [RFC7301], which is how the client exposes the names of the application-layer protocols it supports ๐๏ธ an observer can deduce that one of those protocols will be used if the connection continues.
work is currently underway in the TLS working group to encrypt the contents of the ClientHello in TLS 1.3 [TLS-ECH] ๐ this would make SNI-based application identification impossible by on-path observation for QUIC and other protocols that use TLS ๐๐
3.4.1. Extracting Server Name Indication (SNI) Information โจ
okay so if the ClientHello isn't encrypted, you can still grab the SNI ๐ by working out the Initial secret, using it to decrypt the packet payload, and then parsing the QUIC CRYPTO frames that carry the TLS ClientHello. ๐
bestie, the Initial secret and the layout of the Initial packet are both version specific, so the very first move is always to read the version number. That's the second through fifth bytes of the long header ๐ฆ Only long header packets carry a version number, so you also have to check that the first bit of the QUIC packet is set to 1, which tells you it's a long header. ๐
Quick heads up ๐ Proprietary QUIC versions that got deployed before standardization might not set that first bit to 1 in a long header packet. BUT it's expected that these versions will slowly disappear over time, so they don't need any special consideration or handling. ๐ธ
Once you've identified QUIC version 1, you check the packet type is Initial by making sure the third and fourth bits of the header are both 0 ๐ Then you pull out the Destination Connection ID. The Initial secret gets calculated using the version-specific Initial salt, as described in Section 5.2 of [QUIC-TLS]. The length of the connection ID sits in the 6th byte of the header, followed by the connection ID itself. ๐ง
Heads up, bestie: later Initial packets might carry a Destination Connection ID that's different from the one used to generate the Initial secret. So decrypting those with the procedure above might fail, unless the observer has kept hold of the Initial secret. ๐
To find where the header ends and the payload starts, you need the Packet Number Length, the Source Connection ID Length, and the Token Length. The Packet Number Length comes from the seventh and eighth bits of the header, as described in Section 17.2 of [QUIC-TRANSPORT], but it's protected the way Section 5.4 of [QUIC-TLS] describes. The Source Connection ID Length is in the byte right after the Destination Connection ID. And the Token Length, which comes after the Source Connection ID, is a variable-length integer, as specified in Section 16 of [QUIC-TRANSPORT]. ๐
After decryption, you can parse the client's Initial packets to find the CRYPTO frames holding the TLS ClientHello. That can then be parsed much like TLS over TCP connections. ๐ Now, there can be several CRYPTO frames spread across one or more Initial packets, and they might show up out of order, so you have to reassemble the CRYPTO stream by parsing offsets and lengths. The client's Initial packets can also hold other frames, so you check the first bytes of each frame to figure out its type and whether you can skip past it. The length of a frame depends on its type; see Section 18 of [QUIC-TRANSPORT]. For example, PADDING frames (each one is a single zero byte) can show up before, after, or between CRYPTO frames. โจ
Extensions can define extra frame types too ๐ If you hit an unknown frame type, you can't know how long that frame is, so you can't skip over it, and parsing fails. Big yikes, but that's just how it goes. ๐ญ
3.5. Flow Association ๐ฆ
The QUIC connection ID (see Section 2.6) is designed so a coordinating on-path device, like a load balancer, can associate two flows when one of the endpoints changes address. ๐ซถ That change can happen because of NAT rebinding or address migration.
The connection ID must change when an endpoint changes address on purpose, and connection ID negotiation is encrypted. So a passive observer can't use the connection ID to link intended address changes together. ๐
When one endpoint's address changes by accident, like with NAT rebinding, an on-path observer may be able to use the connection ID to match the flow on the new address with the flow on the old one. ๐งฉ
A network function that tries to use the connection ID to associate flows has to be robust to this technique failing. ๐ The connection ID may change several times over a connection's lifetime, so packets with the same 5-tuple but different connection IDs might or might not belong to the same connection. Likewise, packets with the same connection ID but different 5-tuples might not belong to the same connection either. ๐ธ
Connection IDs should be treated as opaque. Check Section 4.4 for the caveats about connection ID selection at servers. ๐
3.6. Flow Teardown ๐
QUIC doesn't expose the end of a connection, bestie. The only sign an on-path device gets that a flow has ended is that packets stop showing up. ๐ป So stateful devices on path, like NATs and firewalls, have to use idle timeouts to decide when to drop state for QUIC flows. See Section 4.2. โณ
3.7. Flow Symmetry Measurement ๐ช
QUIC openly shows which side is the client and which is the server during the handshake. ๐ค On top of that, you can infer a flow's symmetry (whether it's mainly client-to-server, mainly server-to-client, or roughly bidirectional, which feeds into basic traffic classification) by measuring the data rate in each direction. ๐
Here's a fun wrinkle: QUIC packets that carry only control frames (like ACK-only packets) may be padded. ๐ซง Padding is optional, but it can hide connection roles or flow symmetry info. Sneaky, right? ๐
3.8. Round-Trip Time (RTT) Measurement โฑ๏ธ
The round-trip time (RTT) of QUIC flows can be inferred by observing once per flow during the handshake, using passive TCP measurement. To do that, you parse the QUIC packet header and recognize the handshake, as shown in Section 2.4. ๐ซ You can also infer RTT during the flow's lifetime if the endpoints use the spin bit facility, which is described below and in Section 17.3.1 of [QUIC-TRANSPORT]. And RTT measurement is available to unidirectional observers whenever the spin bit is enabled. ๐
3.8.1. Measuring Initial RTT ๐ธ
Usually, the delay between the client's Initial packet (the one with the TLS ClientHello) and the server's Initial packet (the one with the TLS ServerHello) is the RTT component on the path between the observer and the server. ๐ฅ๏ธ The delay between the server's first Handshake packet and the Handshake packet the client sends back is the RTT component on the path between the observer and the client. ๐ฑ The client might send 0-RTT packets after its Initial packet when it's re-establishing a connection, but you can ignore those for RTT measurement. ๐ โโ๏ธ
Handshake RTT can be measured by adding the client-to-observer and observer-to-server RTT components together. This measurement always includes all the transport and application layer delay at both endpoints. ๐ง
3.8.2. Using the Spin Bit for Passive RTT Measurement ๐
The spin bit gives you a version-specific way to measure per-flow RTT from observation points on the network path, for the whole life of a connection. ๐ Check Section 17.4 of [QUIC-TRANSPORT] for how the spin bit is defined in Version 1 of QUIC. Endpoints can choose whether to take part in spin bit signaling, which is optional. The bit's location is fixed in this version of QUIC, but an endpoint can decide on its own not to "spin" the bit. ๐โโ๏ธ
Devices on path can only use the spin bit for RTT measurement when both endpoints enable it. Some endpoints turn it off by default, and others only turn it off in certain deployment scenarios, like servers and clients where the RTT would reveal a VPN or proxy. ๐ต๏ธโโ๏ธ To keep these connections from being identifiable through spin bit usage, all endpoints randomly disable "spinning" for at least one eighth of connections, even if it's on by default. โจ An endpoint that isn't taking part in spin bit signaling for a connection can use a fixed spin value for the whole connection, or it can set the bit randomly on every packet it sends. ๐ฒ
When it's in use, the latency spin bit changes value once per RTT, in each direction, any time both endpoints are sending packets continuously. ๐ An on-path observer can measure the time difference between edges (changes from 1 to 0 or from 0 to 1) in the spin bit signal in a single direction to get one sample of end-to-end RTT. This mechanism follows the principles of protocol measurability laid out in [IPIM]. ๐
Heads up, this measurement (just like passive RTT measurement for TCP) includes all transport protocol delay, like delayed sending of acknowledgments, and/or application layer delay, like waiting for a response to be generated. ๐ข So it gives devices on path a good instantaneous estimate of the RTT the application actually experiences. ๐
Application-limited and flow-control-limited senders, though, can have application and transport layer delay that's way bigger than the network RTT. ๐ฌ For example, if a sender only sends small bits of application traffic now and then, and the gap between them is longer than the RTT, spin bit measurements tell you about the application's period rather than the network RTT. ๐
The spin bit logic at each endpoint only considers samples from packets that advance the largest packet number, so signal generation itself holds up against reordering. ๐ก๏ธ Reordering can still cause trouble at an observer, though. It can cause spurious edge detection, which leads to inaccurate (lower) RTT estimates, if reordering happens across a spin bit flip in the stream. ๐ช๏ธ
Simple heuristics based on the observed data rate per flow, or on changes in the RTT series, can reject bad RTT samples caused by lost or reordered edges in the spin signal, as well as application or flow control limitation. For example, QoF [TMA-QOF] rejects component RTTs that are significantly higher than the RTTs over the flow's history. ๐งน These heuristics may use the handshake RTT as an initial RTT estimate for a given flow. Usually, such heuristics would also detect if the spin is either constant or randomly set for a connection. ๐ต๏ธ
An on-path observer that can see traffic in both directions (from client to server and from server to client) can also use the spin bit to measure "upstream" and "downstream" component RTT. The upstream component is the part of the end-to-end RTT attributable to the path between the observer and the server, and the downstream component is the part attributable to the path between the observer and the client. ๐บ๏ธ To get these, the observer measures the delay between a spin edge seen in the upstream direction and one seen in the downstream direction, and vice versa. ๐
Raw RTT samples from these techniques can be processed in different ways to produce useful network performance metrics. A simple linear smoothing or moving minimum filter can be applied to the stream of RTT samples to get a steadier estimate of the application-experienced RTT. ๐ RTT samples measured from the spin bit can also be used to build RTT distribution information. That includes minimum RTT, which approximates network RTT over longer time windows, and RTT variance, which approximates one-way packet delay variance as seen by an application endpoint. ๐
4. Specific Network Management Tasks ๐ ๏ธ
In this section, we look at specific network management and measurement techniques and how QUIC's design affects them. ๐ โจ
4.1. Passive Network Performance Measurement and Troubleshooting
okay so passive RTT measurement is totally possible by just watching QUIC traffic, see Section 3.8 ๐ฆ no passive loss measurement though, not with the current wire image ๐ญ there's limited visibility into upstream congestion too, if you look at Congestion Experienced (CE) markings in the IP header [RFC3168] on ECN-enabled QUIC traffic ๐ธ
on-path devices can also measure RTT, loss, and other perf metrics when the info rides in an extra network-layer packet header ๐ (Section 6 of [RFC9065] covers Operations, Administration, and Management (OAM) information, iykyk). the bestie perk here is that the same observation and analysis tools can be used across multiple transport protocols โจ the catch? these techniques are often limited to measurements within one or multiple cooperating domains ๐
4.2. Stateful Treatment of QUIC Traffic
okay the bestie tea โ stateful treatment of QUIC traffic (like at a firewall or NAT middlebox) is possible through QUIC traffic and version identification (Section 3.1) and by watching the handshake for connection confirmation (Section 3.2) ๐ฅ but since there's no visible end-of-flow signal (Section 3.6), that state has to be purged either through timers or least-recently-used eviction, depending on what the application needs ๐
ngl QUIC has no clear network-visible end-of-flow signal, so it totally does need timer-based state removal ๐ญ but the handshake does confirm that both ends agreed to a valid bidirectional transmission ๐ซถ once the handshake completes, timers SHOULD be set long enough to also allow for short idle time during a valid transmission ๐
[RFC4787] REQUIRES a network state timeout of not less than 2 minutes for most UDP traffic ๐ however, in practice, a QUIC endpoint can see lower timeouts, in the range of 30 to 60 seconds [QUIC-TIMEOUT] ๐
meanwhile [RFC5382] RECOMMENDS a state timeout of more than 2 hours for TCP, since TCP is connection-oriented with well-defined closure semantics ๐ง even though QUIC was explicitly designed to tolerate NAT rebindings, decreasing the NAT timeout is NOT RECOMMENDED, because it may hurt application performance or push endpoints to send very frequent keep-alive packets ๐
so yeah, a state timeout of at least two minutes is RECOMMENDED for QUIC traffic ๐ even when lower state timeouts are used for other UDP traffic ๐
if state gets removed too early, incoming packets could get black-holed after a short idle period ๐ญ to notice this, a timer at the client has to expire before a re-establishment can happen (if at all), which means unnecessarily long delays in a connection that was otherwise working fine ๐ฅฒ
and furthermore, not every endpoint uses routing architectures where connections survive a port or address change ๐ even when the client revives the connection, a NAT rebinding can cause a routing mismatch, so the packet isn't even delivered to the server that might support address migration ๐ฆ for these reasons, the limits in [RFC4787] matter a LOT for avoiding black-holed packets (and so avoiding interrupting the flow of data to the client), especially where devices can tell QUIC traffic apart from other UDP payloads โจ
the QUIC header OPTIONALLY contains a connection ID, which could add extra entropy beyond the 5-tuple ๐ธ the handshake needs to be observed to know whether the connection ID is present and how long it is ๐ but connection IDs may be renegotiated after the handshake, and that renegotiation isn't visible to the path ๐ญ so using the connection ID as a flow key field for stateful treatment of flows is NOT RECOMMENDED, because connection ID changes cause undetectable and unrecoverable loss of state in the middle of a connection ๐ especially for functions that need state to make a forwarding decision: that's NOT viable, since it breaks connectivity, or at minimum causes long timeout-based delays before the endpoints notice and the connection can maybe be re-established ๐ซ
connection ID use is specifically discouraged for NAT applications ๐ซ if a NAT hits an operational limit, it is RECOMMENDED to rather drop the initial packets of a flow (see also Section 4.5) ๐ which potentially triggers TCP fallback ๐ using the connection ID to multiplex multiple connections on the same IP address/port pair is not a viable solution, since it risks connectivity breakage if the connection ID changes ๐
4.3. Address Rewriting to Ensure Routing Stability
QUIC's migration capability makes it possible for a connection to survive client address changes โจ but this does NOT work if the routers or switches in the server infrastructure route using the address-port 4-tuple ๐ญ if infrastructure routes on addresses only, NAT rebinding or address migration will send packets to the wrong server ๐ [QUIC-LB] describes a way to address this problem by coordinating the selection and use of connection IDs between load balancers and servers ๐ง
applying address translation at a middlebox to keep a stable address-port mapping for flows based on connection ID might seem like a solution ๐ but hiding the change of IP address or port hides important, security-relevant info from QUIC endpoints, and that would facilitate amplification attacks (see Section 8 of [QUIC-TRANSPORT]) ๐จ a NAT function that hides peer address changes stops the other end from detecting and mitigating attacks, since the endpoint can't verify connectivity to the new address using QUIC PATH_CHALLENGE and PATH_RESPONSE frames ๐
also, a change of IP address or port is an input signal to other internal QUIC mechanisms ๐ when a path change is detected, path-dependent variables like congestion control parameters get reset, which protects the new path from overload ๐
4.4. Server Cooperation with Load Balancers
in networking setups that include load balancers, the connection ID can be used as a way for the server to signal the desired treatment of a flow to the load balancers ๐ guidance on assigning connection IDs is given in [QUIC-APPLICABILITY] โจ and [QUIC-LB] describes a system for coordinating selection and use of connection IDs between load balancers and servers ๐ซถ
4.5. Filtering Behavior
[RFC4787] describes possible packet-filtering behaviors that relate to NATs but are often used in other scenarios where packet filtering is wanted ๐ฆ the guidance there holds, but a particularly unwise behavior lets a handful of UDP packets through and then decides whether or not to filter later packets in the same connection ๐ค QUIC applications are ENCOURAGED to fall back to TCP if early packets don't arrive at their destination [QUIC-APPLICABILITY], since QUIC is based on UDP and there are known blocks of UDP traffic (see Section 4.6) ๐ admitting a few packets lets the QUIC endpoint figure out that the path accepts QUIC ๐ธ but sudden drops afterwards mean slow and costly timeouts before the connection gets abandoned ๐
4.6. UDP Blocking, Throttling, and NAT Binding
okay this one is a whole saga ๐ญ today UDP is the most prevalent DDoS vector, since it's easy for compromised non-admin applications to flood large UDP packets (with TCP, the attacker gets throttled by the congestion controller) or to craft reflection and amplification attacks ๐ฅ so some networks block UDP traffic ๐ซ with more QUIC deployed, there's also an increased need to allow UDP on the ports QUIC uses ๐ but if UDP is generally enabled on those ports, UDP flood attacks may use the same ports too ๐ one response is to throttle UDP on the network, allocating a fixed portion of capacity to UDP and blocking datagrams over that cap ๐ง since the share of QUIC compared to TCP is also expected to grow over time, using such a limit is NOT RECOMMENDED; if it's done, limits might need to be adapted dynamically ๐
if UDP is supposed to be throttled, it is RECOMMENDED to block individual QUIC flows entirely rather than dropping packets indiscriminately ๐ when the handshake is blocked, QUIC-capable applications MAY fall back to TCP ๐ however, blocking a random fraction of QUIC packets across 4-tuples lets many QUIC handshakes complete, which prevents TCP fallback, but those connections suffer severe packet loss (see also Section 4.5) ๐ญ therefore, UDP throttling SHOULD be realized by per-flow policing as opposed to per-packet policing ๐ note that this per-flow policing SHOULD be stateless to avoid problems with stateful treatment of QUIC flows (see Section 4.2), for example by blocking a portion of the space of values of a hash function over the addresses and ports in the UDP datagram ๐ซถ QUIC endpoints are often able to survive address changes, e.g., by NAT rebindings, but blocking a portion of traffic based on 5-tuple hashing increases the risk of black-holing an active connection when the address changes ๐
note that some source ports are assumed to be reflection attack vectors by some servers; see Section 8.1 of [QUIC-APPLICABILITY] ๐จ as a result, NAT binding to these source ports can get that traffic blocked ๐ธ
4.7. DDoS Detection and Mitigation โจ
okay so this is the bit where the network gets to be a little bouncer ๐ On-path observation of the transport headers of packets can be used for all kinds of security stuff. Like, DoS and DDoS attacks, whether they're hitting the infrastructure or a single endpoint, can be detected and mitigated by characterizing anomalous traffic ๐จ. It also helps with security audits (like checking that cipher suites are being complied with), client and application fingerprinting for inventory ๐๏ธ, and alerts for network intrusion detection and other next-gen firewall stuff ๐ฅ.
Current DDoS detection and mitigation practice mostly goes like this: incoming traffic gets sorted (by packets, flows, or some other aggregate) into "good" (productive) and "bad" (DDoS) buckets ๐ซง, and then the two get treated differently so only the good stuff gets forwarded. This usually happens in a separate, specialized mitigation environment that all the traffic runs through. A generalized architecture for separating those concerns is described in [DOTS-ARCH] ๐.
Efficient classification is the whole game here ๐ฏ. Limited first packet garbage detection (as in Section 3.1.2) and stateful tracking of QUIC traffic (as mentioned in Section 4.2 above) may be useful during classification ๐ฆ.
Now, here's the tricky part ๐ญ. Using a connection ID to support connection migration makes 5-tuple-based filtering insufficient for detecting active flows, and it means DDoS defense systems need to maintain more state if they want to support migration of QUIC flows ๐ง . For the common case of NAT rebinding, where the client's address changes without the client's intent or knowledge, DDoS defense systems can notice the client's endpoint address changed by linking flows based on the server's connection IDs ๐. BUT, QUIC's linkability resistance means a deliberate connection migration always comes with a change in the connection ID ๐. So in that case, the connection ID can't be used to tell valid, active traffic apart from brand-new attack traffic. Not me being dramatic about it ๐.
Endpoints can also directly support security functions like DoS classification and mitigation ๐. They can cooperate with an in-network device, for example by sharing information about connection IDs ๐ซถ.
Another possible method is an on-path network device that relies on pattern inferences in the traffic, plus heuristics or machine learning, instead of processing the observed header information ๐ง.
Honestly though, it's questionable whether connection migrations need to be supported during a DDoS attack ๐ค. Unintended migration without a connection ID change is much easier to support, and it might be acceptable to not support migrations of active QUIC connections that aren't visible to the network functions doing the DDoS detection ๐ธ. As soon as the client detects connection blocking, it may be able to rely on the 0-RTT data mechanism provided by QUIC โก. When clients migrate to a new path, they SHOULD be prepared for the migration to fail and attempt to reconnect quickly ๐โโ๏ธ.
Beyond in-network DDoS protection, TCP SYN cookies [RFC4987] are a well-established way of mitigating some kinds of TCP DDoS attacks ๐ช. QUIC Retry packets are the functional analogue to SYN cookies: they force clients to prove possession of their IP address before the server commits any state ๐. There are safeguards in QUIC against unsolicited injection of these packets by intermediaries who don't have consent from the end server ๐ก๏ธ. See [QUIC-RETRY] for the standard ways intermediaries can send Retry packets on behalf of consenting servers ๐.
4.8. Quality of Service Handling and ECMP Routing ๐
So the expectation is that any QoS handling in the network (for example based on Diffserv Code Points (DSCPs) [RFC2475]) and Equal-Cost Multi-Path (ECMP) routing gets applied on a per-flow basis, not per-packet ๐. That means all the packets in the same active QUIC connection get uniform treatment. Main character energy for consistency ๐ .
Using ECMP to spread packets from a single flow across multiple network paths, or doing any other nonuniform treatment of packets that belong to the same connection, could cause variations in order, delivery rate, and drop rate ๐ฌ. Feedback about loss or delay for each packet is used as input to the congestion controller, so those variations could hurt performance pretty badly ๐. Depending on the loss recovery mechanism implemented, QUIC may be more tolerant of packet reordering than typical TCP traffic (see Section 2.7) ๐. But the network can't know which recovery mechanism a flow uses, so reordering tolerance should be treated as unknown ๐คทโโ๏ธ.
Also, the 5-tuple of a QUIC connection can change due to migration ๐ฆ. When that happens, the path sees different flows and may treat them differently, since congestion control is usually reset on migration (see also Section 3.5) ๐.
4.9. Handling ICMP Messages ๐จ
Datagram Packetization Layer PMTU Discovery (DPLPMTUD) can be used by QUIC to probe for the supported PMTU ๐. DPLPMTUD optionally uses ICMP messages (for example, IPv6 Packet Too Big (PTB) messages) ๐ฌ. Given the known attacks that involve ICMP messages, DPLPMTUD in QUIC was designed to safely use ICMP feedback but not rely on it (see Section 14.2.1 of [QUIC-TRANSPORT]) ๐ก๏ธ.
Networks are RECOMMENDED to forward these ICMP messages and keep as much of the original packet as possible, without exceeding the minimum MTU for the IP version when generating ICMP messages, as recommended in [RFC1812] and [RFC4443] ๐.
4.10. Guiding Path MTU ๐ฃ๏ธ
Some network segments support 1500-byte packets, but they can only do that by fragmenting at a lower layer before crossing a segment with a smaller MTU, then reassembling inside that segment ๐งฉ. This is permissible even when the IP layer is IPv6, or IPv4 with the Don't Fragment (DF) bit set, because the fragmentation happens below the IP layer ๐. However, this process adds compute and memory costs, which can become a bottleneck that limits network capacity ๐ฉ. In networks like that, there's a desire to influence most senders to use smaller packets so they don't exceed the limited reassembly capacity ๐ญ.
For TCP, Maximum Segment Size (MSS) clamping (Section 3.2 of [RFC4459]) is often used to change the sender's TCP maximum segment size, but QUIC needs a different approach ๐โโ๏ธ. Section 14 of [QUIC-TRANSPORT] advises senders to probe larger sizes using DPLPMTUD [DPLPMTUD] or Path Maximum Transmission Unit Discovery (PMTUD) [RFC1191] [RFC8201] ๐. This mechanism encourages senders to approach the maximum packet size, which could then cause fragmentation within a network segment they might not even know about ๐ฑ.
If path performance is limited when forwarding larger packets, an on-path device SHOULD support a maximum packet size for a specific transport flow, and then consistently drop all packets that exceed the configured size when the inner IPv4 packet has DF set or IPv6 is used ๐ซ.
Networks with configurations that would lead to fragmentation of large packets within a network segment SHOULD drop such packets rather than fragmenting them ๐ โโ๏ธ. Network operators who plan to implement a more selective policy may start by focusing on QUIC ๐ฏ.
QUIC flows can't always be easily told apart from other UDP traffic, but we assume at least some portion of QUIC traffic can be identified (see Section 3.1) ๐. For networks supporting QUIC, it is RECOMMENDED that a path drops any packet larger than the fragmentation size ๐. When a QUIC endpoint uses DPLPMTUD, it will use a QUIC probe packet to discover the PMTU, and if that probe is lost, it won't impact the flow of QUIC data ๐ท.
IPv4 routers generate an ICMP message when a packet is dropped because the link MTU was exceeded ๐ค. [RFC8504] specifies how an IPv6 node generates an ICMPv6 PTB in this case ๐งพ. PMTUD relies on an endpoint receiving those PTB messages [RFC8201], whereas DPLPMTUD does not rely on them, but can still optionally use them to improve performance (Section 4.6 of [DPLPMTUD]) ๐.
A network can't know in advance which discovery method a QUIC endpoint is using, so it SHOULD send a PTB message in addition to dropping an oversized packet ๐. A generated PTB message SHOULD comply with the validation requirements of Section 14.2.1 of [QUIC-TRANSPORT], otherwise it will be ignored for PMTU discovery โ ๏ธ. This gives the endpoint a signal to stop the packet size from growing too large, which can completely avoid network segment fragmentation for that flow ๐ฅฐ.
Endpoints can cache PMTU information in the IP-layer cache ๐๏ธ. This short-term consistency between the PMTU for flows can help stop an endpoint from using a PMTU that's inefficient ๐ . The IP cache can also influence the PMTU value of other IP flows that use the same path [RFC8201] [DPLPMTUD], including IP packets carrying protocols other than QUIC ๐. How an IP path is represented is implementation specific [RFC8201] ๐ค.
5. IANA Considerations ๐ธ
This document has no actions for IANA ๐.
6. Security Considerations ๐
QUIC is an encrypted and authenticated transport ๐. That means once the cryptographic handshake is complete, QUIC endpoints discard most packets that aren't authenticated, which greatly limits an attacker's ability to interfere with existing connections ๐.
However, some information is still observable, since supporting manageability of QUIC traffic inherently involves trade-offs with the confidentiality of QUIC's control information ๐. This entire document is therefore security-relevant ๐จ.
More security considerations for QUIC are discussed in [QUIC-TRANSPORT] and [QUIC-TLS], which generally consider active or passive attackers in the network, as well as attacks on specific QUIC mechanisms ๐.
Version Negotiation packets don't contain any mechanism to prevent version downgrade attacks ๐ค. However, future versions of QUIC that use Version Negotiation packets are REQUIRED to define a mechanism that is robust against version downgrade attacks ๐ช. So a network node SHOULD NOT attempt to affect version selection, because a version downgrade may result in connection failure ๐ โโ๏ธ.
7. References ๐
7.1. Normative References ๐
[QUIC-TLS] Thomson, M., Ed. and S. Turner, Ed., "Using TLS to Secure QUIC", RFC 9001, DOI 10.17487/RFC9001, May 2021, <https://www.rfc-editor.org/info/rfc9001>.
[QUIC-TRANSPORT] Iyengar, J., Ed. and M. Thomson, Ed., "QUIC: A UDP-Based Multiplexed and Secure Transport", RFC 9000, DOI 10.17487/RFC9000, May 2021, <https://www.rfc-editor.org/info/rfc9000>.
7.2. Informative References ๐
Okay bestie, these are the "extra reading" refs, the ones the doc points to for background instead of requirements ๐ค๐ They're all listed in alphabetical order, same as always.
[DOTS-ARCH]
Mortensen, A., Ed., Reddy.K, T., Ed., Andreasen, F.,
Teague, N., and R. Compton, "DDoS Open Threat Signaling
(DOTS) Architecture", RFC 8811, DOI 10.17487/RFC8811,
August 2020, <https://www.rfc-editor.org/info/rfc8811>.
[DPLPMTUD] Fairhurst, G., Jones, T., Tรผxen, M., Rรผngeler, I., and T.
Vรถlker, "Packetization Layer Path MTU Discovery for
Datagram Transports", RFC 8899, DOI 10.17487/RFC8899,
September 2020, <https://www.rfc-editor.org/info/rfc8899>.
[IPIM] Allman, M., Beverly, R., and B. Trammell, "Principles for
Measurability in Protocol Design", 9 December 2016,
<https://arxiv.org/abs/1612.02902>.
[QUIC-APPLICABILITY]
Kรผhlewind, M. and B. Trammell, "Applicability of the QUIC
Transport Protocol", RFC 9308, DOI 10.17487/RFC9308,
September 2022, <https://www.rfc-editor.org/info/rfc9308>.
[QUIC-GREASE]
Thomson, M., "Greasing the QUIC Bit", RFC 9287,
DOI 10.17487/RFC9287, August 2022,
<https://www.rfc-editor.org/info/rfc9287>.
[QUIC-HTTP]
Bishop, M., Ed., "HTTP/3", RFC 9114, DOI 10.17487/RFC9114,
June 2022, <https://www.rfc-editor.org/info/rfc9114>.
[QUIC-INVARIANTS]
Thomson, M., "Version-Independent Properties of QUIC",
RFC 8999, DOI 10.17487/RFC8999, May 2021,
<https://www.rfc-editor.org/info/rfc8999>.
[QUIC-LB] Duke, M., Banks, N., and C. Huitema, "QUIC-LB: Generating
Routable QUIC Connection IDs", Work in Progress, Internet-
Draft, draft-ietf-quic-load-balancers-14, 11 July 2022,
<https://datatracker.ietf.org/doc/html/draft-ietf-quic-
load-balancers-14>.
[QUIC-RECOVERY]
Iyengar, J., Ed. and I. Swett, Ed., "QUIC Loss Detection
and Congestion Control", RFC 9002, DOI 10.17487/RFC9002,
May 2021, <https://www.rfc-editor.org/info/rfc9002>.
[QUIC-RETRY]
Duke, M. and N. Banks, "QUIC Retry Offload", Work in
Progress, Internet-Draft, draft-ietf-quic-retry-offload-
00, 25 May 2022, <https://datatracker.ietf.org/doc/html/
draft-ietf-quic-retry-offload-00>.
[QUIC-TIMEOUT]
Roskind, J., "QUIC", IETF-88 TSV Area Presentation, 7
November 2013,
<https://www.ietf.org/proceedings/88/slides/slides-88-
tsvarea-10.pdf>.
[QUIC-VERSION-NEGOTIATION]
Schinazi, D. and E. Rescorla, "Compatible Version
Negotiation for QUIC", Work in Progress, Internet-Draft,
draft-ietf-quic-version-negotiation-10, 27 September 2022,
<https://datatracker.ietf.org/doc/html/draft-ietf-quic-
version-negotiation-10>.
[RFC1191] Mogul, J. and S. Deering, "Path MTU discovery", RFC 1191,
DOI 10.17487/RFC1191, November 1990,
<https://www.rfc-editor.org/info/rfc1191>.
[RFC1812] Baker, F., Ed., "Requirements for IP Version 4 Routers",
RFC 1812, DOI 10.17487/RFC1812, June 1995,
<https://www.rfc-editor.org/info/rfc1812>.
[RFC2475] Blake, S., Black, D., Carlson, M., Davies, E., Wang, Z.,
and W. Weiss, "An Architecture for Differentiated
Services", RFC 2475, DOI 10.17487/RFC2475, December 1998,
<https://www.rfc-editor.org/info/rfc2475>.
[RFC3168] Ramakrishnan, K., Floyd, S., and D. Black, "The Addition
of Explicit Congestion Notification (ECN) to IP",
RFC 3168, DOI 10.17487/RFC3168, September 2001,
<https://www.rfc-editor.org/info/rfc3168>.
[RFC3449] Balakrishnan, H., Padmanabhan, V., Fairhurst, G., and M.
Sooriyabandara, "TCP Performance Implications of Network
Path Asymmetry", BCP 69, RFC 3449, DOI 10.17487/RFC3449,
December 2002, <https://www.rfc-editor.org/info/rfc3449>.
[RFC4443] Conta, A., Deering, S., and M. Gupta, Ed., "Internet
Control Message Protocol (ICMPv6) for the Internet
Protocol Version 6 (IPv6) Specification", STD 89,
RFC 4443, DOI 10.17487/RFC4443, March 2006,
<https://www.rfc-editor.org/info/rfc4443>.
[RFC4459] Savola, P., "MTU and Fragmentation Issues with In-the-
Network Tunneling", RFC 4459, DOI 10.17487/RFC4459, April
2006, <https://www.rfc-editor.org/info/rfc4459>.
[RFC4787] Audet, F., Ed. and C. Jennings, "Network Address
Translation (NAT) Behavioral Requirements for Unicast
UDP", BCP 127, RFC 4787, DOI 10.17487/RFC4787, January
2007, <https://www.rfc-editor.org/info/rfc4787>.
[RFC4987] Eddy, W., "TCP SYN Flooding Attacks and Common
Mitigations", RFC 4987, DOI 10.17487/RFC4987, August 2007,
<https://www.rfc-editor.org/info/rfc4987>.
[RFC5382] Guha, S., Ed., Biswas, K., Ford, B., Sivakumar, S., and P.
Srisuresh, "NAT Behavioral Requirements for TCP", BCP 142,
RFC 5382, DOI 10.17487/RFC5382, October 2008,
<https://www.rfc-editor.org/info/rfc5382>.
[RFC6066] Eastlake 3rd, D., "Transport Layer Security (TLS)
Extensions: Extension Definitions", RFC 6066,
DOI 10.17487/RFC6066, January 2011,
<https://www.rfc-editor.org/info/rfc6066>.
[RFC7301] Friedl, S., Popov, A., Langley, A., and E. Stephan,
"Transport Layer Security (TLS) Application-Layer Protocol
Negotiation Extension", RFC 7301, DOI 10.17487/RFC7301,
July 2014, <https://www.rfc-editor.org/info/rfc7301>.
[RFC7605] Touch, J., "Recommendations on Using Assigned Transport
Port Numbers", BCP 165, RFC 7605, DOI 10.17487/RFC7605,
August 2015, <https://www.rfc-editor.org/info/rfc7605>.
[RFC7801] Dolmatov, V., Ed., "GOST R 34.12-2015: Block Cipher
"Kuznyechik"", RFC 7801, DOI 10.17487/RFC7801, March 2016,
<https://www.rfc-editor.org/info/rfc7801>.
[RFC7838] Nottingham, M., McManus, P., and J. Reschke, "HTTP
Alternative Services", RFC 7838, DOI 10.17487/RFC7838,
April 2016, <https://www.rfc-editor.org/info/rfc7838>.
[RFC7983] Petit-Huguenin, M. and G. Salgueiro, "Multiplexing Scheme
Updates for Secure Real-time Transport Protocol (SRTP)
Extension for Datagram Transport Layer Security (DTLS)",
RFC 7983, DOI 10.17487/RFC7983, September 2016,
<https://www.rfc-editor.org/info/rfc7983>.
[RFC8201] McCann, J., Deering, S., Mogul, J., and R. Hinden, Ed.,
"Path MTU Discovery for IP version 6", STD 87, RFC 8201,
DOI 10.17487/RFC8201, July 2017,
<https://www.rfc-editor.org/info/rfc8201>.
[RFC8504] Chown, T., Loughney, J., and T. Winters, "IPv6 Node
Requirements", BCP 220, RFC 8504, DOI 10.17487/RFC8504,
January 2019, <https://www.rfc-editor.org/info/rfc8504>.
[RFC9065] Fairhurst, G. and C. Perkins, "Considerations around
Transport Header Confidentiality, Network Operations, and
the Evolution of Internet Transport Protocols", RFC 9065,
DOI 10.17487/RFC9065, July 2021,
<https://www.rfc-editor.org/info/rfc9065>.
[RFC9250] Huitema, C., Dickinson, S., and A. Mankin, "DNS over
Dedicated QUIC Connections", RFC 9250,
DOI 10.17487/RFC9250, May 2022,
<https://www.rfc-editor.org/info/rfc9250>.
[TLS-ECH] Rescorla, E., Oku, K., Sullivan, N., and C. A. Wood, "TLS
Encrypted Client Hello", Work in Progress, Internet-Draft,
draft-ietf-tls-esni-14, 13 February 2022,
<https://datatracker.ietf.org/doc/html/draft-ietf-tls-
esni-14>.
[TMA-QOF] Trammell, B., Gugelmann, D., and N. Brownlee, "Inline Data
Integrity Signals for Passive Measurement", Traffic
Measurement and Analysis, TMA 2014, Lecture Notes in
Computer Science, vol. 8406, pp. 15-25,
DOI 10.1007/978-3-642-54999-1_2, April 2014,
<https://link.springer.com/
chapter/10.1007/978-3-642-54999-1_2>.
[WIRE-IMAGE]
Trammell, B. and M. Kuehlewind, "The Wire Image of a
Network Protocol", RFC 8546, DOI 10.17487/RFC8546, April
2019, <https://www.rfc-editor.org/info/rfc8546>.
Acknowledgments ๐ซถ
Huge shoutout to the last call reviewers Elwyn Davies, Barry Leiba, Al Morton, and Peter Saint-Andre ๐ You absolutely carried this doc ๐
Money talk, because it matters ๐ This work was partially supported by the European Commission under Horizon 2020 grant agreement no. 688421, the Measurement and Architecture for a Middleboxed Internet (MAMI) project ๐ It was also supported by the Swiss State Secretariat for Education, Research, and Innovation under contract no. 15.0268 ๐ง Support like this does not mean the funders endorse the content, so no blaming them for my hot takes lol ๐
Contributors โจ
The following people have contributed significant text to and/or feedback on this document ๐ They're all iconic:
- Chris Box
- Dan Druta
- David Schinazi
- Gorry Fairhurst
- Ian Swett
- Igor Lubashev
- Jana Iyengar
- Jared Mauch
- Lars Eggert
- Lucas Purdue
- Marcus Ihlar
- Mark Nottingham
- Martin Duke
- Martin Thomson
- Matt Joras
- Mike Bishop
- Nick Banks
- Thomas Fossati
- Sean Turner
Authors' Addresses ๐
Here's where you can find the authors, if you want to slide into their inbox ๐ฆ Mirja Kรผhlewind is at Ericsson, and Brian Trammell is at Google Switzerland GmbH ๐
Mirja Kรผhlewind
Ericsson
Email: mirja.kuehlewind@ericsson.com
Brian Trammell
Google Switzerland GmbH
Gustav-Gull-Platz 1
CH-8004 Zurich
Switzerland
Email: ietf@trammell.ch
๐ฆ where this page comes from
- ietf: rfc9312 2022-09
- ๐ girlified by claude-haiku-5-5 on : a language model's rewrite of the original, under its terms