Client does not abandon the connection attempt after Version Negotiation
Summary
RFC 9000 §6.2 requires a client that supports only this QUIC version to abandon the current connection attempt after receiving a Version Negotiation packet, unless it has already successfully processed another packet or the packet lists the version selected by the client. s2n-quic only advertises version 0x1, but its Version Negotiation receive path does not implement this rule. Runtime probing shows that the client keeps sending version 1 Initial packets and fails only by timeout.
Standard Requirement
A client that supports only this version of QUIC MUST abandon the
current connection attempt if it receives a Version Negotiation
packet, with the following two exceptions. A client MUST discard any
Version Negotiation packet if it has received and successfully
processed any other packet, including an earlier Version Negotiation
packet. A client MUST discard a Version Negotiation packet that
lists the QUIC version selected by the client.
The discussion of future versions in this section applies to implementations that support multiple versions. For a client that supports only the current version, Section 6.2 still requires MUST abandon.
Relevant Source Code
quic/s2n-quic-transport/src/endpoint/version.rs:26-28
const SUPPORTED_VERSIONS: &[u32] = &[
0x1, // Draft 34 / Version 1
];
The implementation declares support only for version 1.
quic/s2n-quic-transport/src/connection/connection_impl.rs:1925-1982
fn handle_version_negotiation_packet(
&mut self,
datagram: &DatagramInfo,
path_id: path::Id,
_packet: ProtectedVersionNegotiation,
packet_len: usize,
subscriber: &mut Config::EventSubscriber,
_packet_interceptor: &mut Config::PacketInterceptor,
) -> Result<(), ProcessingError> {
publisher.on_packet_received(...);
//# A client that supports only this version of QUIC MUST abandon the
//# current connection attempt if it receives a Version Negotiation
//# packet, with the following two exceptions.
...
//# A client MUST discard a Version Negotiation packet that
//# lists the QUIC version selected by the client.
if datagram.destination_connection_id_classification.is_initial() {
...
return Err(ProcessingError::Other);
}
Ok(())
}
This path retains a TODO for RFC 9000 Section 6.2. When the CID classification matches the normal path, it returns Ok(()) directly and does not implement abandon or discard logic.
Implementation Behavior
After receiving Version Negotiation, the code does not check:
- whether another packet has already been successfully processed;
- whether the Version Negotiation version list includes the version selected by the client;
- whether the current connection attempt must be terminated immediately.
Therefore the connection does not fail immediately; it remains active and retransmits Initial packets.
Runtime Evidence
- Command:
cargo run --quiet
Probe flow:
- receive the client's first Initial;
- send a valid Version Negotiation packet with echoed CIDs and a version list containing
0xface_b00c but not 0x00000001;
- observe whether the client aborts or keeps transmitting.
Observed output:
initial_version=0x00000001
followup_count=2
followup_1=len:1200 first_byte:206 type:Initial version:0x00000001
followup_2=len:1200 first_byte:204 type:Initial version:0x00000001
connect_outcome=attempt_timeout
connect_elapsed_ms=3004
After receiving Version Negotiation, the client sent two more version 1 Initial packets and eventually failed only by timeout. That is continued connection activity, not the immediate abandon required by RFC 9000 Section 6.2.
Impact
In a valid Version Negotiation scenario, the client does not terminate the connection attempt immediately. It continues retransmitting Initial packets and degrades into timeout failure, violating RFC 9000 Section 6.2.
Fix Direction
- Parse and validate the received
ProtectedVersionNegotiation.
- If another packet has already been successfully processed, or the selected version appears in the advertised list, discard the packet.
- Otherwise fail the connection attempt immediately and stop Initial retransmission.
Client does not abandon the connection attempt after Version Negotiation
Summary
RFC 9000 §6.2 requires a client that supports only this QUIC version to abandon the current connection attempt after receiving a Version Negotiation packet, unless it has already successfully processed another packet or the packet lists the version selected by the client.
s2n-quiconly advertises version0x1, but its Version Negotiation receive path does not implement this rule. Runtime probing shows that the client keeps sending version 1 Initial packets and fails only by timeout.Standard Requirement
The discussion of future versions in this section applies to implementations that support multiple versions. For a client that supports only the current version, Section 6.2 still requires
MUST abandon.Relevant Source Code
quic/s2n-quic-transport/src/endpoint/version.rs:26-28The implementation declares support only for version 1.
quic/s2n-quic-transport/src/connection/connection_impl.rs:1925-1982This path retains a TODO for RFC 9000 Section 6.2. When the CID classification matches the normal path, it returns
Ok(())directly and does not implement abandon or discard logic.Implementation Behavior
After receiving Version Negotiation, the code does not check:
Therefore the connection does not fail immediately; it remains active and retransmits Initial packets.
Runtime Evidence
cargo run --quietProbe flow:
0xface_b00cbut not0x00000001;Observed output:
After receiving Version Negotiation, the client sent two more version 1 Initial packets and eventually failed only by timeout. That is continued connection activity, not the immediate abandon required by RFC 9000 Section 6.2.
Impact
In a valid Version Negotiation scenario, the client does not terminate the connection attempt immediately. It continues retransmitting Initial packets and degrades into timeout failure, violating RFC 9000 Section 6.2.
Fix Direction
ProtectedVersionNegotiation.