Skip to content

Client does not abandon the connection attempt after Version Negotiation #3264

Description

@LiD0209

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:

  1. receive the client's first Initial;
  2. send a valid Version Negotiation packet with echoed CIDs and a version list containing 0xface_b00c but not 0x00000001;
  3. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions