Proxying UDP in HTTP
updated by
Extracted elements (28)
Context IDs are split into even (client-allocated) and odd (proxy-allocated) namespaces to avoid the need for synchronization between endpoints when allocating new Context IDs.
HTTP/1.1 uses the GET method rather than CONNECT in order to mimic the design of the WebSocket Protocol. This allows the protocol to fit naturally into HTTP/1.1 upgrade semantics.
UDP proxying SHOULD be performed over HTTP/3 to allow the use of QUIC DATAGRAM frames, avoiding double loss recovery that occurs when UDP-over-TCP proxying causes both the inner and outer protocol to independently retransmit the same data.
Unlike HTTP CONNECT for TCP, the UDP proxy target is identified using an absolute URL derived from a URI Template rather than a host:port pair, because the scheme, path, and query are needed to identify the proxy endpoint and provide extensibility.
When a UDP payload from the target is too large to fit in a QUIC DATAGRAM frame, the UDP proxy SHOULD NOT send it in a DATAGRAM capsule because doing so defeats the end-to-end unreliability that DPLPMTUD depends on. Instead, the proxy SHOULD drop the payload and send an ICMP Packet Too Big message.
Clients constrained to proxy host:port configuration MAY use the default template 'https://$PROXY_HOST:$PROXY_PORT/.well-known/masque/udp/{target_host}/{target_port}/'. UDP proxy deployments SHOULD offer service at this location to interoperate with such clients.
A UDP proxy MUST ignore ECN bits in the IP header of UDP packets received from the target, and MUST set the ECN bits to Not-ECT on UDP packets it sends to the target. These are decoupled from the ECN markings of the client-to-proxy HTTP connection.
Context IDs MUST NOT be re-allocated within a given HTTP request namespace, but MAY be allocated in any order. The even/odd allocation restriction applies only at allocation time; once allocated, any endpoint may use the Context ID.
Endpoints MUST NOT send HTTP Datagrams with a UDP Proxying Payload longer than 65527 bytes using Context ID zero (UDP header limit). A receiver of such an oversized datagram MUST abort the corresponding stream.
For HTTP/1.1, a UDP proxying request SHALL use the GET method, include Connection: Upgrade, and include Upgrade: connect-udp. A malformed request MUST be answered with an error; the 400 (Bad Request) status code SHOULD be used.
For HTTP/1.1, the UDP proxy SHALL indicate success with status 101 (Switching Protocols), Connection: Upgrade, Upgrade: connect-udp, and the Capsule Protocol requirements. If any requirement is not met, the client MUST treat the attempt as failed and abort the connection.
For HTTP/2 and HTTP/3, a successful response SHALL have a status code in the 2xx range and SHALL meet Capsule Protocol requirements. If not, the client MUST treat the attempt as failed and abort the request.
For HTTP/2 and HTTP/3, UDP proxying requests use HTTP Extended CONNECT with :method = CONNECT, :protocol = connect-udp, and non-empty :path and :scheme set to the URI Template expansion result. Non-conforming requests are malformed.
If a client detects that any URI Template requirements are not met, the client MUST reject its configuration and abort the request without sending it to the UDP proxy.
If 'target_host' is a DNS name, the UDP proxy MUST perform DNS resolution before replying to the HTTP request. If errors occur, the UDP proxy MUST reject the request and SHOULD send details using an appropriate Proxy-Status header field.
If the UDP proxy uses a non-connected socket, it MUST validate the IP source address and UDP source port on received packets to ensure they match the client's request. Packets that do not match MUST be discarded.
Receivers that buffer datagrams pending request or Context ID registration SHOULD apply buffering limits (by count or cumulative size per stream, context, or connection) to reduce the risk of resource exhaustion.
The UDP proxy MUST keep the socket open while the request stream is open. If the socket becomes unusable (e.g., ICMP Destination Unreachable), it MUST close the request stream. Proxies that close sockets due to inactivity MUST also close the request stream and SHOULD NOT use an inactivity timeout lower than two minutes.
The underlying HTTP connection MUST NOT disable congestion control unless it has an out-of-band way of knowing with certainty that the inner traffic is congestion-controlled. If congestion control is disabled, ECN support MUST NOT be signaled and all IP headers MUST be marked Not-ECT.
The URI Template used to configure a UDP proxy MUST be a level 3 template or lower, in absolute form with non-empty scheme, authority, and path components, and MUST contain the variables 'target_host' and 'target_port'. It MUST NOT contain non-ASCII characters outside 0x21-0x7E, and MUST NOT use reserved or fragment expansion operators.
UDP proxies MUST NOT introduce fragmentation at the IP layer when forwarding HTTP Datagrams to a UDP socket. In IPv4, the Don't Fragment (DF) bit MUST be set, if possible, to prevent path fragmentation.
Context Identifiers are 62-bit integers (0 to 2^62-1) encoded as QUIC variable-length integers. Context ID 0 is reserved for UDP payloads. Non-zero even values are client-allocated; odd values are proxy-allocated. Context IDs are scoped to a single HTTP request namespace.
IANA registered the 'connect-udp' HTTP Upgrade Token in the 'HTTP Upgrade Tokens' registry. Value: connect-udp; Description: Proxying of UDP Payloads; Expected Version Tokens: None.
IANA registered the 'masque' Well-Known URI in the 'Well-Known URIs' registry (permanent status), covering all resources under the path prefix '/.well-known/masque/udp/'.
Allowing arbitrary clients to tunnel to arbitrary targets risks traffic attribution to the UDP proxy. HTTP servers supporting UDP proxying ought to restrict its use to authenticated users.
Proxied UDP traffic arrives at the target with the UDP proxy's source IP address. Software performing access control based on source IP (e.g., allowing unauthenticated configuration from 127.0.0.1) could be exploited. UDP proxies should disallow requests to localhost, link-local, multicast, and broadcast addresses.
UDP proxies can be misused for DoS amplification. Unlike TCP CONNECT proxies, which stop forwarding once the TCP path is flooded (no SYN-ACK), UDP proxies have no shared state with the target and may continue sending traffic indefinitely. Packet-count limits provide only limited mitigation.
The UDP Proxying HTTP Datagram Payload contains a Context ID field (QUIC variable-length integer, 1-8 bytes) followed by a UDP Proxying Payload field of variable length. When Context ID is 0, the payload is the unmodified UDP packet payload.