On this page

UDP and QUIC Transport Layer

UDP is essentially just "IP with port numbers." QUIC wraps a complete reliable transport layer on top of UDP: 0-RTT handshake, head-of-line blocking-free stream multiplexing, connection migration—QUIC gets it right in one go, whereas TCP took 30 years to learn these lessons.

Overview

UDP is the simplest transport layer protocol—an 8-byte header, connectionless, no retransmission, no flow control. Its "rudimentary" nature is actually an advantage: DNS queries (one round-trip), real-time audio/video (dropping a few frames doesn't affect experience), and VPNs (WireGuard) all choose UDP. QUIC implements a complete modern transport layer on top of UDP, merging TCP's flow control/congestion control and TLS 1.3 encryption into a single protocol, solving TCP's head-of-line blocking and connection migration issues. HTTP/3 runs on QUIC.

UDP

UDP Header (fixed 8 bytes):

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|          Source Port          |       Destination Port        |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|            Length             |           Checksum            |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Length: Total length of UDP header + payload (minimum 8 = header only, maximum 65535)
Checksum: Optional for IPv4 (0=no checksum), mandatory for IPv6 — covers pseudo-header (src/dst IP +
          protocol + length) + UDP header + payload

UDP does nothing beyond "port + length + optional checksum"—no connection, no retransmission, no flow control, no congestion control. If the application layer needs reliability, it must implement it itself. QUIC is precisely a case of "the application layer implementing the transport layer."

QUIC Transport Layer

QUIC is not "UDP + reliability wrapper"—it is a brand-new transport layer implemented on top of UDP, merging TCP's flow control/congestion control and TLS's encryption/authentication into one protocol.

QUIC Packet Structure

QUIC Long Header (Initial/Handshake/0-RTT packets):

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|1|   Type  |     Version (32 bits)                             |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| DCID Len  |  Destination Connection ID (0-20 bytes)          ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| SCID Len  |  Source Connection ID (0-20 bytes)               ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

QUIC Short Header (1-RTT data packets):

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|0|1|S|R|R|R|        Destination Connection ID (...)           ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

Header Form (bit 0): 1=Long, 0=Short
Fixed Bit (bit 1): Always 1 — used for version negotiation detection (middleboxes cannot set this bit)
Spin Bit (bit 2 in Short): Flips once per RTT — observers can measure RTT
Reserved Bits: 0, if middleboxes modify these bits → GREASE detection → connection close

QUIC Connection: Connection ID

TCP connection = 5-tuple (src_ip, dst_ip, src_port, dst_port). IP changes → connection drops.

QUIC connection = Destination Connection ID + Source Connection ID. Endpoints can change Connection IDs at any time (via NEW_CONNECTION_ID frame) → IP/port become fully variable.

Connection Migration:

QUIC Connection Migration: Connection ID Unchanged, Connection Persists Despite IP Change Client · WiFi IP 192.168.1.x · QUIC flow uses CID_A → CID_B to identify connection Switch to 4G (Network Switch) Client · 4G IP 10.10.10.x · Sends PATH_CHALLENGE (new IP, same CID_A → CID_B) Server Response PATH_RESPONSE Verify new path is reachable → Migration confirmed Connection seamlessly migrated! The application layer sees no interruption— QUIC connections are identified by Connection ID (not IP/port), so switching networks does not drop the connection.

Stream Multiplexing

A single QUIC connection has multiple streams:

Stream ID (62-bit, variable-length encoding):
  Bit 0: 0=client-initiated, 1=server-initiated
  Bit 1: 0=bidi, 1=unidirectional
  Bits 2-61: stream number (0, 1, 4, 8, 12, ... — client starts at 0, server at 1,
             bidi-only: even client, odd server)

Each stream is independent:
  - Has independent flow control (MAX_STREAM_DATA / STREAM_DATA_BLOCKED)
  - Packet loss on Stream 1 → only blocks data for Stream 1, Stream 3 continues delivery
  - Solves TCP head-of-line blocking: In TCP, all streams' bytes are in the same byte stream → one loss blocks everything

Connection-level flow control: MAX_DATA / DATA_BLOCKED — limits total reception across all streams

0-RTT

First Connection:
  1-RTT: ClientHello → ServerHello → EncryptedExtensions → Finished → (data)

Subsequent Connections (PSK mode):
  Client: Caches the previous session ticket (containing PSK + transport parameters + server address)
  0-RTT: ClientHello + PSK + early data — starts sending data before receiving ServerHello
  Server: Verifies PSK → accepts early data → processes directly

0-RTT Security Risk — Replay:
  Attacker replays 0-RTT packets → server processes duplicates → duplicate side effects (e.g., double charge)

QUIC Mitigation:
  - Application layer: Only idempotent operations (GET, HEAD, OPTIONS) are allowed in 0-RTT
  - Transport layer: Server can send REJECTED frame → client must retransmit 0-RTT data
  - AEAD limits: The same key cannot be used for too many 0-RTT packets → limits replay window

QUIC Loss Detection

QUIC's loss detection is more precise than TCP's:

TCP: 3 duplicate ACKs → retransmit (but for SACK, distinguishes reordering vs loss)

QUIC: 
  - Each packet has an independent packet number (monotonically increasing, even retransmissions get new numbers)
  - Receiver ACK frame: max received + missing ranges → precisely knows which packets are lost
  - Loss detection:
    1. Time threshold: Exceeds kTimeThreshold (9/8) × latest RTT → packet loss
    2. Packet threshold: Exceeds kPacketThreshold (3) larger packets acknowledged → packet loss

QUIC Applications

HTTP/3: QUIC's largest user (RFC 9114)
DNS/DoQ: DNS over QUIC (RFC 9250) — 0-RTT query
SMB over QUIC: Windows Server 2022
RDP over QUIC: Remote desktop resistant to packet loss

References

  • RFC: 768, 8999-9002, 9000 Appendix A (design rationale), 9250
  • Implementations: quiche (Cloudflare), lsquic (LiteSpeed), quinn (Rust), ngtcp2 (C)
  • LWN: "QUIC and HTTP/3"

Keywords: UDP, QUIC, connection migration, 0-RTT, stream multiplexing, head-of-line blocking, spin bit, GREASE