Why HTTP CONNECT Can’t Proxy Every Protocol

HTTP CONNECT, as described in our previous post on proxying TCP-based applications, is a solid solution for TCP traffic. It enables proxying of protocols like DNS-over-HTTPS and generic HTTPS. However, its utility stops at the boundary of TCP. Applications that run over UDP, such as HTTP/3, which itself is built on QUIC, require a different approach entirely.

To proxy a UDP-based protocol like HTTP/3, two things are needed. First, a method to encapsulate UDP payloads between the client and the proxy, which the proxy can then decapsulate and forward as a real UDP datagram to the target server. Second, a mechanism to instruct the proxy to establish a UDP association with a target so it knows where to route the decapsulated data.

Encapsulating Unreliable Datagrams

The fundamental difference lies in the transport. TCP provides a reliable, ordered byte stream, while UDP offers unreliable, independent messages called datagrams. Many applications, like low-latency media streaming, embrace this unreliability for performance; it’s often preferable for a live teleconference to receive the most recent audio and video rather than wait for retransmitted stale data.

QUIC is designed to run over this kind of unreliable UDP substrate, providing its own security, loss detection, and congestion control. If lower layers start duplicating these features, they can cause harmful interference. QUIC’s congestion control algorithms rely on signals like loss, timing, and pacing. Tunneling that perturbs these signals can create a feedback loop, making the algorithms overly conservative and reducing end-to-end throughput.

While one could theoretically use a reliable QUIC stream to carry an encapsulated UDP payload, the reliability of the stream works against the goals of the application. This is where QUIC’s unreliable datagram extension comes in. It introduces the DATAGRAM frame, a message type that is, by design, not retransmitted if lost. This extension has several key properties for proxying:

  • DATAGRAM frames are individual messages, not a continuous stream.
  • They lack a multiplexing identifier, unlike QUIC’s stream IDs.
  • Like all QUIC frames, a DATAGRAM frame must fit entirely within a single QUIC packet.
  • They are subject to congestion control.
  • Receivers acknowledge them, but senders do not retransmit them upon loss.

This extension has been supported in Cloudflare’s quiche library since October 2020. With reliable streams and unreliable datagrams available in QUIC, the responsibility moves to the application layer to define how to use them for proxying. This is the problem the MASQUE Working Group is solving.

MASQUE and Extended CONNECT for UDP

The MASQUE Working Group, formed in June 2020, has been designing the standards for this. Their work on UDP tunneling comprises two specifications: one for using QUIC datagrams with HTTP/3, and another defining a new HTTP request type to initiate a UDP socket to a target.

This builds upon the concept of extended CONNECT, which was initially introduced for HTTP/2 in RFC 8441 and has since been ported to HTTP/3. Extended CONNECT allows a client to use a :protocol pseudo-header to indicate the request’s intent. While first used for WebSockets, it’s repurposed for UDP.

:method = CONNECT
:protocol = connect-udp
:scheme = https
:path = /target.example.com/443/
:authority = proxy.example.com

The client sends an extended CONNECT request to the proxy, specifying the target server in the :path. If the proxy successfully opens a UDP socket, it responds with a 2xx status code. From that point, the client and proxy can exchange QUIC DATAGRAM frames containing the payload, while the proxy and target exchange standard UDP datagrams.

Components involved in UDP tunneling. From left-to-right: Client, Proxy, Server.

The Size Problem: Anatomy of Encapsulation

UDP tunneling introduces a significant constraint related to message size and the path MTU (Maximum Transmission Unit). The path MTU is the maximum packet size every network element on a path can handle; a common practical limit on the Internet is 1,500 bytes. All protocol overhead—from UDP and QUIC headers up to the application layer—subtracts from this theoretical maximum.

HTTP/3 normally uses its own framing (HEADERS, DATA, etc.), but QUIC DATAGRAM frames bypass this. The payload is placed directly into the frame, which consists of two parts. The first is the variable-length Quarter Stream ID field, an encoded identifier that supports multiple, independent datagram flows by binding each to an HTTP request stream ID. Since stream IDs in QUIC use two bits to denote the stream type, and request streams are always client-initiated and bidirectional, dividing by four saves space. The second field is the payload itself.

A UDP datagram, containing a QUIC packet, which contains a DATAGRAM frame.

Because QUIC requires that fragmentation is disabled, a QUIC packet must fit within a UDP datagram, and a DATAGRAM frame must fit within a QUIC packet. This chain of constraints limits the maximum payload size. The size of the UDP datagram is set by the path MTU, from which we must subtract the overhead of the UDP and QUIC headers and the DATAGRAM frame header.

When a message is too large for the tunnel, a sender has only two options: discard it or fragment it. Neither is ideal. A client initiating the tunnel can calculate the correct size to avoid this. However, a target server, which is often unaware that the client is behind a proxy, may send a datagram that’s too big for the proxy to encapsulate. This is a common issue for many proxy protocols. In practice, a conservative payload limit of 1,200 to 1,300 bytes can be effective given a 1,500-byte path MTU, once QUIC overhead is considered.

This size issue is critical when tunneling QUIC itself. RFC 9000 states that clients initiating new QUIC connections must send UDP datagrams of at least 1,200 bytes. If a proxy cannot support that size, QUIC will not function within the tunnel.

Composing Tunnels and Nested Proxying

One of the more powerful aspects of these building blocks is the ability to combine them into complex architectures. Nested tunnels through multiple proxies can be used to minimize the connection metadata visible to any single proxy. In such a setup, a client might manage at least three logical connections:

  1. A QUIC connection between the Client and Proxy 1.
  2. A QUIC connection between the Client and Proxy 2, which runs inside a CONNECT tunnel on the first connection.
  3. An end-to-end byte stream to the Server, which runs inside a CONNECT tunnel on the second connection.

In this architecture, a physical TCP connection only exists between Proxy 2 and the Server. Additional logical connections can be created within the existing pair of QUIC connections.

Components involved in a nested tunneling setup. From left-to-right: Client, Proxy 1, Proxy 2 and Server.

From UDP to IP Tunneling

UDP and TCP proxying covers many use cases like TLS, QUIC, HTTP, and DNS, but it still doesn’t support IP protocols such as ICMP or IPsec Encapsulating Security Payload (ESP). To address this, the MASQUE Working Group is defining requirements for IP tunneling and has adopted a new specification for IP proxying over HTTP.

A fair question is why use a full HTTP/3 stack when a simpler tunnel protocol might suffice. The answer depends on the ecosystem. CONNECT-based IP proxies leverage TLS and the well-established WebPKI for secure channels and authentication. By contrast, a protocol like WireGuard uses a simpler cryptographic handshake and defers authentication to the application. While both approaches have similar framing overhead on the wire, they serve different purposes, have distinct implementation complexities, and assume different deployment environments.

For an ecosystem already deeply invested in TLS and WebPKI, CONNECT-based solutions are likely to become the standard for IP tunnels in the future.

Current State and Future Work

The IETF-chartered MASQUE Working Group is developing HTTP-based solutions for UDP and IP tunneling to complement the existing CONNECT method. Using HTTP semantics offers features such as request methods, response status codes, and headers for authentication and status reporting. Building on HTTP/3 allows tunneling to utilize QUIC’s security and native datagram support. The design remains flexible, allowing for support of older HTTP versions to broaden potential deployment scenarios.

While the specifications are still being refined, multiple implementations exist and have shown interoperability at IETF hackathons. This running code informs further development. Though details will continue to evolve, the overarching approach is expected to remain consistent.