quic_packet (quic v1.3.1)
View SourceQUIC packet encoding and decoding.
This module handles encoding and decoding of QUIC packets including: - Long header packets (Initial, Handshake, 0-RTT, Retry) - Short header packets (1-RTT)
Packet Header Format
Long Header:
+-+-+-+-+-+-+-+-+
|1|1|T T|X X X X|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Version (32) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| DCID Len (8) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Connection ID (0..160) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SCID Len (8) |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Source Connection ID (0..160) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+Short Header:
+-+-+-+-+-+-+-+-+
|0|1|S|R|R|K|P P|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Destination Connection ID (0..160) ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Summary
Functions
Decode a QUIC packet. DCIDLen is used for short header packets where DCID length is implicit. Returns {ok, Packet, Rest} or {error, Reason}.
Decode a packet number.
Extract the key phase bit from a short header first byte. The key phase bit is bit 2 of the first byte (after header protection removal). Returns 0 or 1.
Encode a long header packet. Type is one of: initial, handshake, zero_rtt, retry Returns the encoded packet header + payload. Note: For Initial packets, Token is required. Note: Packet number and payload should already be encrypted.
Encode a packet number.
Encode a QUIC Retry packet (RFC 9000 §17.2.5).
Encode a short header (1-RTT) packet with default key phase 0. DCIDLen is the expected DCID length (from connection state). Returns the encoded packet.
Encode a short header (1-RTT) packet with explicit key phase. KeyPhase is 0 or 1, indicating which set of keys was used for encryption. Returns the encoded packet.
Encode a Version Negotiation packet. RFC 9000 Section 17.2.1 - Version Negotiation Packet The server sends this when it receives a packet with an unsupported version. The DCID and SCID are copied from the received packet (swapped). Versions is a list of supported version numbers.
Calculate the minimum number of bytes needed for a packet number.
Types
-type packet() :: #quic_packet{type :: initial | handshake | zero_rtt | one_rtt | retry, version :: non_neg_integer() | undefined, dcid :: binary(), scid :: binary() | undefined, token :: binary() | undefined, pn :: non_neg_integer() | undefined, payload :: binary() | [term()]}.
-type packet_type() :: initial | handshake | zero_rtt | one_rtt | retry.
Functions
-spec decode(binary(), non_neg_integer()) -> {ok, packet(), binary()} | {error, term()}.
Decode a QUIC packet. DCIDLen is used for short header packets where DCID length is implicit. Returns {ok, Packet, Rest} or {error, Reason}.
-spec decode_pn(binary(), 1..4) -> {non_neg_integer(), binary()}.
Decode a packet number.
-spec decode_short_key_phase(non_neg_integer()) -> 0 | 1.
Extract the key phase bit from a short header first byte. The key phase bit is bit 2 of the first byte (after header protection removal). Returns 0 or 1.
-spec encode_long(packet_type(), non_neg_integer(), binary(), binary(), #{token => binary(), pn => non_neg_integer(), payload => binary()}) -> binary().
Encode a long header packet. Type is one of: initial, handshake, zero_rtt, retry Returns the encoded packet header + payload. Note: For Initial packets, Token is required. Note: Packet number and payload should already be encrypted.
-spec encode_pn(non_neg_integer(), 1..4) -> binary().
Encode a packet number.
-spec encode_retry(OriginalDCID, DCID, SCID, Token, Version) -> binary() when OriginalDCID :: binary(), DCID :: binary(), SCID :: binary(), Token :: binary(), Version :: non_neg_integer().
Encode a QUIC Retry packet (RFC 9000 §17.2.5).
OriginalDCID is the DCID from the Initial that triggered this Retry; it's mixed into the integrity tag per RFC 9001 §5.8 and is NOT part of the wire image. DCID is the client's SCID (the client expects us to address it by that), SCID is the fresh server-side connection ID the client must use as DCID on its retried Initial. Token is opaque; the server later validates its own HMAC over it when the client returns it in the next Initial. Returns the fully signed on-wire packet.
-spec encode_short(binary(), non_neg_integer(), binary(), boolean()) -> binary().
Encode a short header (1-RTT) packet with default key phase 0. DCIDLen is the expected DCID length (from connection state). Returns the encoded packet.
-spec encode_short(binary(), non_neg_integer(), binary(), boolean(), 0 | 1) -> binary().
Encode a short header (1-RTT) packet with explicit key phase. KeyPhase is 0 or 1, indicating which set of keys was used for encryption. Returns the encoded packet.
-spec encode_version_negotiation(binary(), binary(), [non_neg_integer()]) -> binary().
Encode a Version Negotiation packet. RFC 9000 Section 17.2.1 - Version Negotiation Packet The server sends this when it receives a packet with an unsupported version. The DCID and SCID are copied from the received packet (swapped). Versions is a list of supported version numbers.
-spec pn_length(non_neg_integer()) -> 1..4.
Calculate the minimum number of bytes needed for a packet number.