§12.1
Chapter 12 · MASQUE: Proxying UDP and IP over HTTP/3

§12.1What MASQUE Is: Proxying Inside HTTP/3

RFC 9298RFC 9484RFC 9297

Learning objective. Understand what MASQUE is (a way to tunnel arbitrary UDP and IP traffic inside an ordinary HTTP/3 connection), why it exists, the three RFCs that define it, and why HTTP/3's QUIC transport is the right substrate for it.

Proxying, and why HTTP needed more of it #

A proxy is a server that forwards traffic on a client's behalf. HTTP has had one form of this for decades: the CONNECT method opens a TCP tunnel through a proxy. It is how a browser reaches an HTTPS site through a corporate or privacy proxy, the proxy blindly relaying encrypted TCP bytes it cannot read. But CONNECT only tunnels TCP. It cannot carry UDP (which matters now that QUIC, WebRTC, and DNS all run over UDP) and it cannot carry raw IP packets, which is what a VPN needs.

MASQUE fills that gap. The name is the IETF working group's (Multiplexed Application Substrate over QUIC Encryption), and the work produced a small family of HTTP extensions that tunnel modern traffic through an HTTP proxy:

  • CONNECT-UDP ([RFC 9298]): tunnel UDP datagrams, so a client can reach a UDP service (or run a whole QUIC connection) through the proxy.
  • CONNECT-IP ([RFC 9484]): tunnel full IP packets, i.e. a VPN built entirely out of HTTP.
  • HTTP Datagrams and the Capsule Protocol ([RFC 9297]): the shared foundation both build on, covered in §12.2.

The unifying idea: carry inner packets as data inside an encrypted HTTP/3 connection to the proxy, which unwraps them and forwards them to their real destination. To anyone between the client and the proxy, it looks like ordinary HTTPS traffic.

Target serverMASQUE proxyClientone HTTP/3 connection · SETTINGSenable Extended CONNECT + HTTP/3Datagramsinner packets now flow as HTTPDatagrams tied to that streamthe proxy forwards opaque payloads · the whole tunnel rides insideencrypted HTTP/3request stream — ExtendedCONNECT (:protocol =connect-udp) to target:443open a UDP socket to the target2xx — tunnel established on thisrequest streamHTTP Datagram — [ inner UDPpayload ]forward as a real UDP packetUDP replyHTTP Datagram — [ inner UDPpayload ]
Fig. 12.1-1MASQUE in one picture. Over a single HTTP/3 connection, the client sends an Extended CONNECT request (here connect-udp) that opens a tunnel to a target on one request stream. The proxy opens a real UDP socket to the target; inner UDP payloads then flow both ways as HTTP Datagrams tied to that stream, which the proxy forwards as real UDP packets. The whole tunnel rides inside encrypted HTTP/3.RFC 9298 §3; RFC 9297 §1

How the tunnel is built #

Trace Figure 12.1-1. The client already has a normal HTTP/3 connection to the proxy, whose SETTINGS have enabled two features (§12.2, §12.3). To open a tunnel it sends an Extended CONNECT request: a CONNECT whose :protocol pseudo-header names the tunnel type (connect-udp) and whose path names the target (§12.3). The proxy opens a real UDP socket to that target and answers 2xx, and the tunnel is live on that one request stream.

From then on, each inner packet travels as an HTTP Datagram associated with that request stream (§12.2): the client wraps a UDP payload, the proxy unwraps it and sends it as a genuine UDP packet to the target, and replies come back the same way. The proxy never inspects the payload (it forwards opaque bytes), and the entire exchange is encrypted inside the outer HTTP/3 connection.

Because tunnels are just request streams, one HTTP/3 connection can carry many tunnels at once: several connect-udp tunnels to different targets, or a mix of CONNECT-UDP, CONNECT-IP, and ordinary HTTP requests, each on its own stream, multiplexed by the transport you already know (Chapter 4). That structure is the thing to hold in your head:

each tunnel is ONE request stream — many multiplex over a single HTTP/3 connection (one handshake) Client one HTTP/3 connection to the proxy stream 0 · connect-udp → media 203.0.113.5:443 stream 4 · connect-udp → DNS 192.0.2.6:53 stream 8 · connect-ip → VPN (all IP) stream 12 · GET /page an ordinary request — not a tunnel tunnels and normal requests share the same connection, each on its own stream Proxy unwraps media srv DNS srv internet origin In HTTP/2 and HTTP/3 a CONNECT tunnel lives on a single stream (RFC 9114 §4.4), so opening a tunnel does NOT consume the connection — the client keeps reusing it for more tunnels and ordinary requests, paying just one handshake for all of them.
Fig. 12.1-2A tunnel is one request stream, and many share one connection. Over a single HTTP/3 connection to the proxy, stream 0 is a connect-udp tunnel to a media server, stream 4 a connect-udp tunnel to a DNS server, stream 8 a connect-ip VPN, and stream 12 an ordinary GET — each on its own stream. Opening a tunnel does not consume the connection (as it would in HTTP/1.1); the client keeps reusing it, paying one handshake for all of them, while the proxy unwraps each tunnel and forwards it to its target.RFC 9114 §4.4

The picture matters because it overturns the classic mental model of a proxy tunnel. With HTTP/1.1 CONNECT, opening a tunnel converts the whole connection into that one tunnel; you get a fresh connection and handshake per tunnel ([RFC 9114 §4.4], and §12.2). Here, a tunnel is just one request stream, so a client opens one connection to the proxy and runs everything over it: dozens of tunnels to different targets, side by side with normal requests. That is the efficiency a privacy relay or VPN client needs, and it is why the datagram machinery of §12.2 has to label each datagram with which tunnel it belongs to.

What it's for #

Three use cases drive MASQUE, and they explain its design:

  • Privacy / relay proxies. A client sends its real traffic through a proxy so the destination sees the proxy's address, not the client's — the basis of relay services that decouple who you are from what you access. CONNECT-UDP lets such a relay carry QUIC and other UDP traffic, which classic CONNECT could not.
  • VPNs over HTTP. CONNECT-IP tunnels raw IP packets, so a full VPN can be built that looks indistinguishable from HTTPS on the wire, valuable where classic VPN protocols are blocked (§12.4).
  • Connectivity in restrictive networks. Because the tunnel is ordinary-looking HTTP/3 to port 443, it traverses networks that permit only web traffic.

Why HTTP/3 is the right substrate #

MASQUE works over any HTTP version, but it is best over HTTP/3, for a reason rooted in Chapter 9. Tunneled packets (a QUIC handshake, a video stream) are usually themselves loss-tolerant or already reliable, and wrapping them in a reliable outer stream causes a well-known pathology: the outer layer retransmits packets the inner layer would have handled, and the two recovery loops fight (the "reliability-over-reliability" meltdown). HTTP/3 avoids it by carrying HTTP Datagrams over QUIC's unreliable DATAGRAM frames ([RFC 9221], §9.3). A lost inner packet is simply lost, exactly as it would be on a real UDP path, and the inner protocol recovers as it normally would. Over HTTP/1.1 or HTTP/2 (TCP), MASQUE can only fall back to the reliable Capsule Protocol (§12.2), which reintroduces that outer reliability. The unreliable path is the whole reason HTTP/3 is MASQUE's natural home.

Worked example: QUIC inside QUIC #

The sharpest illustration is a client running a QUIC connection to a website through a MASQUE proxy. The client opens an HTTP/3 connection to the proxy and sends a connect-udp request targeting the website's host:443. Its real QUIC packets to the website are then sent as HTTP Datagrams into that tunnel; the proxy forwards each as a UDP packet to the website, and the website's QUIC packets return the same way. There are now two nested QUIC connections: the outer one (client↔proxy) protecting the tunnel, and the inner one (client↔website) that the proxy cannot read. The website sees the proxy's address; the network sees only HTTPS to the proxy. This is exactly how modern relay proxies carry QUIC, and it works cleanly only because the outer connection carries the inner packets unreliably, avoiding nested retransmission.

Note

"MASQUE" is the working-group and umbrella name, not a single protocol you turn on. Concretely you implement one or more of three RFCs: the HTTP Datagram / Capsule foundation (RFC 9297), CONNECT-UDP (RFC 9298), and CONNECT-IP (RFC 9484), plus the Extended CONNECT mechanism (RFC 9220 for HTTP/3) they all depend on. The rest of this chapter builds them up in that order: the datagram foundation first, then UDP proxying, then IP proxying, then a byte-level worked example.

In practice

editorial Reach for MASQUE when you need to carry non-HTTP traffic through an HTTP endpoint, most often UDP/QUIC through a privacy relay or IP through an HTTP-based VPN, rather than as a general-purpose proxy for plain web requests (ordinary HTTP forward proxying already handles those). The single biggest deployment decision is the outer HTTP version: use HTTP/3 so tunneled packets ride QUIC DATAGRAM frames unreliably and you avoid nested retransmission; treat the HTTP/2/TCP capsule fallback as a compatibility path for networks that block UDP, not the primary mode, and measure its added latency before relying on it.

Takeaways #

MASQUE is a family of HTTP extensions — CONNECT-UDP (RFC 9298) and CONNECT-IP (RFC 9484), on the HTTP Datagram / Capsule foundation (RFC 9297) — that tunnel UDP and IP traffic inside an encrypted HTTP/3 connection to a proxy, which unwraps and forwards them. Each tunnel is one request stream, so many multiplex over one connection, and the design shines over HTTP/3 because QUIC's unreliable datagrams carry inner packets without a second reliability layer. The foundation both proxying protocols stand on (HTTP Datagrams and the Capsule Protocol) is §12.2.