diff --git a/draft-ietf-masque-quic-proxy.md b/draft-ietf-masque-quic-proxy.md index 1dd2461..825b9c9 100644 --- a/draft-ietf-masque-quic-proxy.md +++ b/draft-ietf-masque-quic-proxy.md @@ -141,7 +141,7 @@ communication than if no proxy was used. Forwarded mode does not prevent correlation of packets on the link between client and proxy and the link between proxy and target by an entity that can observe both links. The precise risks depend on the negotiated transform -({{packet-transforms}}). See {{security}} for further discussion. +({{transforms}}). See {{security}} for further discussion. Both clients and proxies can unilaterally choose to disable forwarded mode for any client-to-target connection. @@ -168,268 +168,362 @@ This document uses the following terms: - Client: the client of all QUIC connections discussed in this document. - Proxy: the endpoint that responds to the UDP proxying request. - Target: the server that a client is accessing via a proxy. -- Client <-> Proxy HTTP stream: a single HTTP stream established from -the client to the proxy. -- Socket: a UDP 4-tuple (local IP address, local UDP port, remote IP address, -remote UDP port). In some implementations, this is referred to as a "connected" -socket. -- Client-facing socket: the socket used to communicate between the client and +- Client-to-proxy 4-tuple: the UDP 4-tuple (client IP address, client UDP port, +proxy IP address, proxy UDP port) used to communicate between the client and the proxy. -- Target-facing socket: the socket used to communicate between the proxy and +- Proxy-to-target 4-tuple: the UDP 4-tuple (proxy IP address, proxy UDP port, +target IP address, target UDP port) used to communicate between the proxy and the target. -- Client Connection ID: a QUIC Connection ID that is chosen by the client, and +- Client Connection ID (CID): a QUIC Connection ID that is chosen by the client, and is used in the Destination Connection ID field of packets from the target to the client. -- Target Connection ID: a QUIC Connection ID that is chosen by the target, and +- Target Connection ID (CID): a QUIC Connection ID that is chosen by the target, and is used in the Destination Connection ID field of packets from the client to the target. -- Virtual Client Connection ID: a fake QUIC Connection ID that is chosen by the -proxy that the proxy MUST use when sending QUIC packets in forwarded mode. -- Virtual Target Connection ID: a fake QUIC Connection ID that is chosen by the -proxy that the client MUST use when sending QUIC packets in forwarded mode. +- Virtual Connection ID (VCID): a fake QUIC Connection ID chosen by the proxy +that is used on the client-to-proxy 4-tuple in forwarded mode. +- Client VCID: a VCID used by the proxy to send forwarded packets from the target +to the client. +- Target VCID: a VCID used by the client to send forwarded packets to the target +via the proxy. - Packet Transform: the procedure used to modify packets before they enter the client-proxy link. -## Virtual Connection IDs +# Protocol Overview + +QUIC-aware proxying involves a client, a proxy, and a target. Although +multiple proxies can be chained together in sequence (which is +a main motivation for enabling forwarded mode), each subsequent proxy +is just treated as a target by the preceding proxy. + +~~~ aasvg + +--------+ +-----------+ +--------+ + | | | | | | + | Client +--------------+ Proxy +--------------+ Target | + | | | | | | + +--------+ +-----------+ +--------+ + + <----------- Client-to-target connection -----------> + + + <-- Client-to-proxy --> <-- Proxy-to-target --> + 4-tuple 4-tuple +~~~ +{: #overview-diagram title="Diagram of roles in QUIC-aware proxying"} + +All QUIC-aware proxying relies on the proxy learning information about +QUIC connection IDs on the client-to-target QUIC connection ({{cid-awareness}}). + +Forwarded mode adds the concept of Virtual Connection IDs that are assigned +by the proxy to use to identify packets on the client-to-proxy 4-tuple ({{vcids}}). + +Negotation of modes and assignment of connection IDs is described in {{negotiation}}. + +## Connection ID Awareness {#cid-awareness} + +For a proxy to be aware of proxied QUIC connection IDs, it needs to know and +correlate three values: + +1. The HTTP stream used to proxy a client-to-target QUIC connection +1. The client-chosen connection ID on the client-to-target QUIC connection, +or the "client CID" +1. The target-chosen connection ID on the client-to-target QUIC connection, +or the "target CID" + +For example, consider a proxy using HTTP/3 that has two clients (A and B) connected +simultaneously, each client coming from a different IP address and port. +Each client makes a request to proxy a UDP flow to "target.example.net" on +port 443. If the proxy knows that client A's connection to the target +has negotiated a client CID `AAAA0000` and a target CID `0000AAAA`, and client B's +connection to the target has negotiated a client CID `BBBB0000` and a target CID +`0000BBBB`, then the proxy would be able to use the same proxy-to-target 4-tuple +for both connections, because it can route packets from the target to the +correct client based on CID `AAAA0000` or `BBBB0000`. + +~~~ aasvg + <---------- Client A-to-target connection ----------> + AAAA0000 0000AAAA + +--------+ +-----------+ + | Client +--------------+ + + | A | | | + +--------+ | | +--------+ + | | Shared | | + | Proxy +--------------+ Target | + | | 4-tuple | | + +--------+ | | +--------+ + | Client | | | + | B +--------------+ | + +--------+ +-----------+ + BBBB0000 0000BBBB + <---------- Client B-to-target connection ----------> +~~~ +{: #sharing-tuple-diagram title="Example of sharing a proxy-to-target 4-tuple"} + +In order to share a proxy-to-target 4-tuple between multiple proxied connections, +the proxy MUST guarantee that the client CIDs do not conflict. See {{conflicts}} +for more discussion of handlng CID conflicts. + +## Virtual Connection IDs {#vcids} + +Virtual Connection IDs (VCIDs) are QUIC Connection IDs used on the link between a +client and proxy that do not belong to the QUIC connection between the client +and proxy, but instead are aliases for particular client-to-target connections. +VCIDs are only used in forwarded mode. They are established using HTTP capsules +{{!HTTP-CAPSULES=RFC9297}} as described in {{cid-capsules}}. + +For example, consider a proxy using HTTP/3 that has a single client connected +to it. The client-to-proxy QUIC connection has `CCCC0000` as the client CID +and `0000CCCC` as the proxy CID. The client has connected to a single target +through the proxy, and the client-to-target QUIC connection has `CCCC1111` +as the client CID and `1111CCCC` as the target CID. In order to use +forwarded mode, the proxy assigns VCIDs to use on the client-to-proxy link +to represent the client-to-target connection. In this case, the VCIDs could +be `CCCC2222` for the client's VCID and `2222CCCC` for the proxy's VCID that +it uses to forward to the target. + +~~~ aasvg + +--------+ +-----------+ +--------+ + | | | | | | + | Client +--------------+ Proxy +--------------+ Target | + | | | | | | + +--------+ +-----------+ +--------+ + + CCCC0000 0000CCCC + <-- Client-to-proxy --> + connection + + CCCC1111 1111CCCC + <----------- Client-to-target connection -----------> + + CCCC2222 (CCCC1111) 2222CCCC (1111CCCC) + <-- Client-to-proxy --> + VCIDs +~~~ +{: #vcid-diagram title="Diagram of VCIDs in forwarded mode"} + +In order for a proxy to correctly route packets using VCIDs from +client-to-target and target-to-client, the proxy MUST guarantee that +the mappings between VCIDs, CIDs, and 4-tuples are unique. Specifically, +in order to route packets sent by the client, the proxy needs to be able +to observe the VCID and the client-to-proxy 4-tuple, and map them +to a specific target CID and proxy-to-target 4-tuple. In order to route +packets sent by a target, the proxy needs to be able to observe the client +CID and the proxy-to-target 4-tuple, and map them to a specific VCID +and client-to-proxy 4-tuple. Since proxies choose the VCID values, they +can ensure that the VCIDs are distinguishable. Servers receiving QUIC packets can employ load balancing strategies such as those described in {{?QUIC-LB=I-D.ietf-quic-load-balancers}} -that encode routing information in -the connection ID. When operating in forwarded mode, clients send QUIC packets -destined for the Target directly to the Proxy. Since these packets are generated -using the Target Connection ID, load balancers would not be able to route packets -to the correct Proxy if the packets were sent with the Target Connection ID. -The Virtual Target Connection ID is a connection ID chosen -by the Proxy that the Client uses when sending forwarded mode packets. The Proxy -replaces the Virtual Target Connection ID with the Target Connection ID prior to -forwarding the packet to the Target. +that encode routing information in the connection ID. When operating in +forwarded mode, clients send QUIC packets destined for the target directly +to the proxy. Since these packets are generated using the target CID, +load balancers may not have the necessary information to route packets to the correct proxy. The target VCID +is a VCID chosen by the proxy that the client uses when sending +forwarded mode packets. The proxy replaces the target VCID +with the target CID prior to forwarding the packet to the target. Similarly, QUIC requires that connection IDs aren't reused over multiple network -paths to avoid linkability. The Virtual Client Connection ID is a connection ID -chosen by the Proxy that the Proxy uses when sending forwarded mode packets. -The Proxy replaces the Client Connection ID with the Virtual Client Connection -ID prior to forwarding the packet to the Client. Clients take advantage of this +paths to avoid linkability. The client VCID is a connection ID +chosen by the proxy that the proxy uses when sending forwarded mode packets. +The proxy replaces the client CID with the client VCID prior to +forwarding the packet to the client. Clients take advantage of this to avoid linkability when migrating a client to proxy network path. The Virtual -Client Connection ID allows the connection ID bytes to change on the wire +client CID allows the connection ID bytes to change on the wire without requiring the connection IDs on the client to target connection change. To reduce the likelihood of connection ID conflicts, the proxy SHOULD choose a -Virtual Client Connection ID that is at least as long as the Client Connection -ID. Similarly, clients multiplexing connections on the same UDP socket SHOULD -choose a Client Connection ID that's sufficiently long to reduce the likelihood -of a conflict with the proxy-chosen Virtual Client Connection ID. The Virtual -Client Connection ID MUST either be constructed such that it is unpredictable to -the client or to guarantee no conflicts among all proxies sharing an IP address -and port. See {{security}} for more discussion on Virtual Client Connection ID +client VCID that is at least as long as the original client CID. Similarly, +clients multiplexing connections on the same UDP 4-tuple SHOULD +choose a client CID that's sufficiently long to reduce the likelihood +of a conflict with the proxy-chosen client VCID. The client VCID MUST either be +constructed such that it is unpredictable to the client or to guarantee no +conflicts among all proxies sharing an IP address +and port. See {{security}} for more discussion on client VCID construction. Clients and Proxies not implementing forwarded mode do not need to consider -Virtual Connection IDs since all Client<->Target datagrams will be encapsulated -within the Client<->Proxy connection. - -# Required Proxy State {#mappings} - -In the methods defined in this document, the proxy is aware of the QUIC -Connection IDs being used by proxied connections, along with the sockets -used to communicate with the client and the target. Tracking Connection IDs in -this way allows the proxy to reuse target-facing sockets for multiple -connections and support the forwarded mode of proxying. - -QUIC packets can be either tunnelled within an HTTP proxy connection using -HTTP Datagram frames {{!HTTP-DGRAM=RFC9297}}, or be forwarded -directly alongside an HTTP/3 proxy connection on the same set of IP addresses and UDP -ports. The use of forwarded mode requires the consent of both the client and the -proxy. - -In order to correctly route QUIC packets in both tunnelled and forwarded modes, -the proxy needs to maintain mappings between several items. There are three -required unidirectional mappings, described below. +VCIDs since all client-to-target datagrams will be encapsulated +within the client-to-proxy connection. -## Stream Mapping +## Negotiating Modes and Connection IDs {#negotiation} -Each client <-> proxy HTTP stream MUST be mapped to a single target-facing socket. +In order to support QUIC-aware proxying, both clients and proxies need +to support capsules {{HTTP-CAPSULES}}, which is indicated by including +the "Capsule-Protocol" header field in requests and responses. If this header +field is not included, none of the functionality in this document can be used. ~~~ -(Client <-> Proxy HTTP Stream) => Target-facing socket + capsule-protocol = ?1 ~~~ -Multiple streams can map to the same target-facing socket, but a -single stream cannot be mapped to multiple target-facing sockets. -Each stream MUST also be associated with a single Packet Transform. +To support forwarded mode, both clients and proxies need to include +the "Proxy-QUIC-Forwarding" header field, as defined in {{forwarding-header}}. +This indicates support for forwarded mode, and allows negotiation of +packet transforms to apply when forwarding ({{transforms}}), along +with any parameters for specific transforms. Clients or proxies that +don't support forwarded mode will not include this header field. -This mapping guarantees that any HTTP Datagram using a stream sent -from the client to the proxy in tunnelled mode can be sent to the correct -target. +~~~ + proxy-quic-forwarding = ?1; accept-transform=scramble,identity; \ + scramble-key=:abc...789=: +~~~ -## Virtual Target Connection ID Mapping +After negotiating support with header fields, clients and proxies use +the capsules defined in {{cid-capsules}} to communicate information +about CIDs and VCIDs. -Each pair of Virtual Target Connection ID and client-facing socket MUST map to a -single target-facing socket and Target Connection ID. +For QUIC-aware proxying without forwarded mode, the steps are as follows: -~~~ -(Client-facing socket + Virtual Target Connection ID) - => (Target-facing socket + Target Connection ID) -~~~ +1. The client sends the `REGISTER_CLIENT_CID` capsule once it selects a +CID that it will use for receiving packets from a target. -Multiple pairs of Connection IDs and client-facing sockets can map to the -same target-facing socket. +1. The proxy sends the `ACK_CLIENT_CID` capsule to acknowledge that CID, +with no associated client VCID; alternatively, the proxy can send the +`CLOSE_CLIENT_CID` if it detects a conflict with another CID. -This mapping guarantees that any QUIC packet containing the Virtual Target -Connection ID sent from the client to the proxy in forwarded mode can be sent to -the correct target with the correct Target Connection ID. Thus, a proxy that -does not allow forwarded mode does not need to maintain this mapping. +1. The client sends the `REGISTER_TARGET_CID` capsule as soon as it learns +the target CID on the client-to-target connection. -## Client Connection ID Mappings +1. The proxy sends the `ACK_TARGET_CID` capsule to acknowledge that CID, +with no associated target VCID; alternatively, the proxy can send the +`CLOSE_TARGET_CID` if it detects a conflict with another CID. -Each pair of Client Connection ID and target-facing socket MUST map to a single -stream on a single client <-> proxy HTTP stream. Additionally, when supporting -forwarded mode, the pair of Client Connection ID and target-facing socket MUST -map to a single client-facing socket and Virtual Client Connection ID. +1. Whenever a client or target stops uses a particular CID, the client +sends a `CLOSE_CLIENT_CID` or `CLOSE_TARGET_CID` capsule. The client +can also initiate new `REGISTER_CLIENT_CID` or `REGISTER_TARGET_CID` +exchanges at any time. -~~~ -(Target-facing socket + Client Connection ID) => (Client <-> Proxy HTTP Stream) -(Target-facing socket + Client Connection ID) - => (Client-facing socket + Virtual Client Connection ID) -~~~ +For QUIC-aware proxying with forwarded mode, the steps are as follows: -Multiple pairs of Connection IDs and target-facing sockets can map to the same -HTTP stream or client-facing socket. +1. The client sends the `REGISTER_CLIENT_CID` capsule once it selects a +CID that it will use for receiving packets from a target. -These mappings guarantee that any QUIC packet sent from a target to the proxy -can be sent to the correct client, in either tunnelled or forwarded mode. Note -that this mapping becomes trivial if the proxy always opens a new target-facing -socket for every client request with a unique stream. The mapping is -critical for any case where target-facing sockets are shared or reused. +1. The proxy sends the `ACK_CLIENT_CID` capsule to acknowledge that CID, +with a client VCID; alternatively, the proxy can send the +`CLOSE_CLIENT_CID` if it detects a conflict with another CID. -## Detecting Connection ID Conflicts {#conflicts} +1. The client sends the `ACK_CLIENT_VCID` capsule to acknowledge the +client VCID, which allows forwarded packets for that VCID to be used. -In order to be able to route packets correctly in both tunnelled and forwarded -mode, proxies check for conflicts before creating a new mapping. If a conflict -is detected, the proxy will reject the client's request, as described in -{{proxy-behavior}}. +1. The client sends the `REGISTER_TARGET_CID` capsule as soon as it learns +the target CID on the client-to-target connection. -Two sockets conflict if and only if all members of the 4-tuple (local IP -address, local UDP port, remote IP address, and remote UDP port) are identical. +1. The proxy sends the `ACK_TARGET_CID` capsule to acknowledge that CID, +with a target VCID; alternatively, the proxy can send the +`CLOSE_TARGET_CID` if it detects a conflict with another CID. Once +the client receives the target VCID, it can start sending forwarded +packets using the target VCID. -Two Connection IDs conflict if and only if one Connection ID is equal to or a -prefix of another. For example, a zero-length Connection ID conflicts with all -connection IDs. This definition of a conflict originates from the fact that -QUIC short headers do not carry the length of the Destination Connection ID -field, and therefore if two short headers with different Destination Connection -IDs are received on a shared socket, one being a prefix of the other prevents -the receiver from identifying which mapping this corresponds to. +1. Whenever a client or target stops uses a particular CID, the client +sends a `CLOSE_CLIENT_CID` or `CLOSE_TARGET_CID` capsule. The client +can also initiate new `REGISTER_CLIENT_CID` or `REGISTER_TARGET_CID` +exchanges at any time. -The proxy treats two mappings as being in conflict when a conflict is detected -for all elements on the left side of the mapping diagrams above. +# Proxy-QUIC-Forwarding Header {#forwarding-header} -Since very short Connection IDs are more likely to lead to conflicts, -particularly zero-length Connection IDs, a proxy MAY choose to reject all -requests for very short Connection IDs as conflicts, in anticipation of future -conflicts. +A client initiates UDP proxying via a CONNECT request as defined +in {{CONNECT-UDP}}. Within its request, it includes the "Proxy-QUIC-Forwarding" +header to indicate whether or not the request should support forwarding. +If this header is not included, the client MUST NOT send any connection ID +capsules. -## Stateless Resets for Forwarded Mode QUIC Packets +"Proxy-QUIC-Forwarding" is an Item Structured Header {{!RFC8941}}. Its +value MUST be a Boolean. -While the lifecycle of forwarding rules are bound to the lifecycle of the -client<->proxy HTTP stream, a peer may not be aware that the stream has -terminated. If the above mappings are lost or removed without the peer's -knowledge, they may send forwarded mode packets even though the Client -or Proxy no longer has state for that connection. To allow the Client or -Proxy to reset the client<->target connection in the absence of the mappings -above, a stateless reset token corresponding to the Virtual Connection ID -can be provided. +If the client wants to enable QUIC packet forwarding for this request, it sets +the value to "?1". If it doesn't want to enable forwarding, but instead only +provide information about QUIC Connection IDs for the purpose of allowing +the proxy to share a proxy-to-target 4-tuple, it sets the value to "?0". -Consider a proxy that initiates closure of a client<->proxy QUIC connection. -If the client is temporarily unresponsive or unreachable, the proxy might have -considered the connection closed and removed all connection state (including -the stream mappings used for forwarding). If the client never learned about the closure, it -might send forwarded mode packets to the proxy, assuming the stream mappings -and client<->proxy connection are still intact. The proxy will receive these -forwarded mode packets, but won't have any state corresponding to the -destination connection ID in the packet. If the proxy has provided a stateless -reset token for the Virtual Target Connection ID, it can send a stateless reset -packet to quickly notify the client that the client<->target connection is -broken. +The client MUST add an "accept-transform" parameter whose value is an +`sf-string` containing the supported packet transforms ({{transforms}}) +in order of descending preference, separated by commas. If the proxy receives a +"Proxy-QUIC-Forwarding" header without the "accept-transform" parameters, it +MUST ignore the header and respond as if the client had not sent the +"Proxy-QUIC-Forwarding" header. -## Stateless Resets from the Target +If the proxy supports QUIC-aware proxying, it will include the +"Proxy-QUIC-Forwarding" header in successful HTTP responses. The value +indicates whether or not the proxy supports forwarding. If the client does +not receive this header in responses, the client SHALL assume that the proxy +does not support this extension. -Reuse of target-facing sockets is only possible because QUIC connection IDs -allow distinguishing packets for multiple QUIC connections received with the -same 5-tuple. One exception to this is Stateless Reset packets, in which the -connection ID is not used, but rather populated with unpredictable bits followed -by a Stateless Reset token, to make it indistinguishable from a regular packet -with a short header. In order for the proxy to correctly recognize Stateless -Reset packets, the client SHOULD share the Stateless Reset token for each -registered Target Connection ID. When the proxy receives a Stateless Reset packet, -it can send the packet to the client as a tunnelled datagram. Although Stateless Reset packets -look like short header packets, they are not technically short header packets and do not contain -negotiated connection IDs, and thus are not eligible for forwarded mode. +The proxy MUST include a "transform" parameter whose value is an `sf-string` +indicating the selected transform. If the proxy does not recognize or accept +any of the transforms offered by the client, it MUST omit this parameter and +set the header field value to "?0", or omit the header entirely. -# Connection ID Capsule Types +# Connection ID Capsules {#cid-capsules} -Proxy awareness of QUIC Connection IDs relies on using capsules ({{HTTP-DGRAM}}) -to signal the addition and removal of Client and Target Connection IDs. +Connection ID awareness relies on using capsules {{HTTP-CAPSULES}} to +signal addition and removal of Connection IDs. Clients send capsules +to let proxies know when Connection IDs on the client-to-target +QUIC connection are changing. Proxies send capsules to acknowledge or +reject these Connection IDs, and in forwarded mode to let clients know +about Virtual Connection IDs to use on the client-to-proxy link. Note that these capsules do not register contexts. QUIC packets are encoded using HTTP Datagrams with the context ID set to zero as defined in {{CONNECT-UDP}}. -The capsules used for QUIC-aware proxying allow a client to register connection -IDs with the proxy, and for the client and proxy to acknowledge or reject the -connection ID mappings. - -The REGISTER_CLIENT_CID and REGISTER_TARGET_CID capsule types (see -{{iana-capsule-types}} for the capsule type values) allow a client to inform -the proxy about a new Client Connection ID or a new Target Connection ID, +The REGISTER_CLIENT_CID ({{capsule-reg-client}}) and REGISTER_TARGET_CID +({{capsule-reg-target}}) capsule types allow a client to inform +the proxy about a new client CID or a new target CID, respectively. These capsule types MUST only be sent by a client. -The ACK_CLIENT_CID and ACK_TARGET_CID capsule types (see {{iana-capsule-types}} -for the capsule type values) are sent by the proxy to the client to indicate -that a mapping was successfully created for a registered connection ID as well -as provide the Virtual Connection IDs that may be used in forwarded mode. -These capsule types MUST only be sent by a proxy. - -The ACK_CLIENT_VCID capsule type MUST only be sent by the client and only when -forwarding mode is enabled. It is sent by the client to the proxy in response to -an ACK_CLIENT_CID capsule to indicate that the client is ready to receive -forwarded mode packets with the specified virtual connection ID. The proxy MUST -NOT send forwarded mode packets to the client prior to receiving this +The ACK_CLIENT_CID ({{capsule-ack-client}}) and ACK_TARGET_CID +({{capsule-ack-target}}) capsule types are sent by the proxy to the client +to indicate that a mapping was successfully created for a registered +connection ID as well as optionally provide the Virtual Connection IDs that can be +used in forwarded mode. These capsule types MUST only be sent by a proxy. + +The ACK_CLIENT_VCID ({{capsule-ack-virtual}}) capsule type MUST only be sent +by the client and only when forwarded mode is enabled. It is sent by the client +to the proxy in response to an ACK_CLIENT_CID capsule to indicate that the client +is ready to receive forwarded mode packets with the specified virtual connection ID. +The proxy MUST NOT send forwarded mode packets to the client prior to receiving this acknowledgement. This capsule also contains a Stateless Reset Token the client may respond with when receiving forwarded mode packets with the specified virtual connection ID. -The CLOSE_CLIENT_CID and CLOSE_TARGET_CID capsule types (see -{{iana-capsule-types}} for the capsule type values) allow either a client -or a proxy to remove a mapping for a connection ID. These capsule types -MAY be sent by either a client or the proxy. If a proxy sends a +The CLOSE_CLIENT_CID and CLOSE_TARGET_CID capsule types ({{capsule-close}}) +allow either a client or a proxy to remove a mapping for a connection ID. +These capsule types MAY be sent by either a client or the proxy. If a proxy sends a CLOSE_CLIENT_CID without having sent an ACK_CLIENT_CID, or if a proxy sends a CLOSE_TARGET_CID without having sent an ACK_TARGET_CID, it is rejecting a Connection ID registration. Similarly, if a client sends CLOSE_CLIENT_CID without having sent an ACK_CLIENT_VCID capsule, the client is -either rejecting the proxy-chosen Virtual Client Connection ID or no longer +either rejecting the proxy-chosen client VCID or no longer needs the connection ID registered. -REGISTER_CLIENT_CID, CLOSE_CLIENT_CID, and CLOSE_TARGET_CID capsule types are -formatted as follows: +## REGISTER_CLIENT_CID {#capsule-reg-client} + +The REGISTER_CLIENT_CID capsule has type `0xffe500` and is sent by the client. +It contains a single connection ID that is the client-provided connection +on the client-to-target QUIC connection. ~~~ -Connection ID Capsule { - Type (i) = 0xffe500, 0xffe505, 0xffe506 +Register CID Capsule { + Type (i) = 0xffe500 Length (i), Connection ID (0..2040), } ~~~ -{: #fig-capsule-cid title="Connection ID Capsule Format"} +{: #fig-capsule-register-client-cid title="Register CID Capsule Format"} Connection ID: -: A connection ID being registered or closed, which is between 0 and 255 bytes in +: A connection ID being registered, which is between 0 and 255 bytes in length. The length of the connection ID is implied by the length of the capsule. Note that in QUICv1, the length of the Connection ID is limited to 20 bytes, but QUIC invariants allow up to 255 bytes. -The REGISTER_TARGET_CID capsule includes the target-provided connection ID -and Stateless Reset Token. +## REGISTER_TARGET_CID {#capsule-reg-target} + +The REGISTER_TARGET_CID capsule has type `0xffe501` and is sent by the client. +It includes the target-provided connection ID on the client-to-target QUIC +connection, and the corresponding Stateless Reset Token. ~~~ -Register Target Connection ID Capsule { +Register Target CID Capsule { Type (i) = 0xffe501 Length (i), Connection ID Length (i) @@ -438,7 +532,7 @@ Register Target Connection ID Capsule { Stateless Reset Token (..), } ~~~ -{: #fig-capsule-register-target-cid title="Register Target Connection ID Capsule Format"} +{: #fig-capsule-register-target-cid title="Register Target CID Capsule Format"} Connection ID Length : The length of the connection ID being registered, which is between 0 and @@ -447,7 +541,7 @@ bytes, but QUIC invariants allow up to 255 bytes. Connection ID : A connection ID being registered whose length is equal to Connection ID -Length. This is the real Target Connection ID. +Length. This is the real target CID. Stateless Reset Token Length : The length of the target-provided Stateless Reset Token. @@ -456,22 +550,23 @@ Stateless Reset Token : The target-provided Stateless Reset token allowing the proxy to correctly recognize Stateless Reset packets to be tunnelled to the client. -The ACK_TARGET_CID capsule type includes a Virtual Connection ID and Stateless -Reset Token. +## ACK_CLIENT_CID {#capsule-ack-client} + +The ACK_CLIENT_CID capsule has type `0xffe502` and is sent by the proxy in +response to a REGISTER_CLIENT_CID capsule. It optionally assigns a Virtual +Connection ID when forwarded mode is supported. ~~~ -Acknowledge Target Connection ID Capsule { - Type (i) = 0xffe504 +Acknowledge Client CID Capsule { + Type (i) = 0xffe502 Length (i) Connection ID Length (i) Connection ID (0..2040), Virtual Connection ID Length (i) Virtual Connection ID (0..2040), - Stateless Reset Token Length (i), - Stateless Reset Token (..), } ~~~ -{: #fig-capsule-ack-target-cid title="Acknowledge Target Connection ID Capsule Format"} +{: #fig-capsule-ack-client-cid title="Acknowledge Client CID Capsule Format"} Connection ID Length : The length of the connection ID being acknowledged, which @@ -480,44 +575,41 @@ is limited to 20 bytes, but QUIC invariants allow up to 255 bytes. Connection ID : A connection ID being acknowledged whose length is equal to -Connection ID Length. This is the real Target Connection ID. +Connection ID Length. This is the real Cilent Connection ID. Virtual Connection ID Length -: The length of the virtual target connection ID being provided. This MUST be a -valid connection ID length for the QUIC version used in the client<->proxy QUIC +: The length of the client VCID being provided. This MUST be a +valid connection ID length for the QUIC version used in the client-to-proxy QUIC connection. When forwarded mode is not negotiated, the length MUST be zero. The Virtual Connection ID Length and Connection ID Length SHOULD be equal -when possible to avoid the need to resize packets during replacement. +when possible to avoid the need to resize packets during replacement. The +client VCID Length SHOULD be at least as large as the +Connection ID to reduce the likelihood of connection ID conflicts. Virtual Connection ID -: The proxy-chosen connection ID that the client MUST use when sending in -forwarding mode. The proxy rewrites forwarded mode packets to contain the -correct Target Connection ID prior to sending them. - -Stateless Reset Token Length -: The length of the Stateless Reset Token sent by the proxy in response to -forwarded mode packets in order to reset the Client<->Target QUIC connection. -When forwarded mode is not negotiated, the length MUST be zero. Proxies choosing -not to support stateless resets MAY set the length to zero. Clients receiving a -zero-length stateless reset token MUST ignore it. +: The proxy-chosen connection ID that the proxy MUST use when sending in +forwarded mode. The proxy rewrites forwarded mode packets to contain the +correct client VCID prior to sending them to the client. -Stateless Reset Token -: A Stateless Reset Token allowing reset of the Client<->Target connection in -response to Client->Target forwarded mode packets. +## ACK_TARGET_CID {#capsule-ack-target} -The ACK_CLIENT_CID capsule type includes a Virtual Connection ID. +The ACK_TARGET_CID capsule has type `0xffe504` and is sent by the proxy in +response to a REGISTER_TARGET_CID capsule. It optionally assigns a Virtual +Connection ID and Stateless Reset Token if forwarded mode is enabled. ~~~ -Acknowledge Client Connection ID Capsule { - Type (i) = 0xffe502 +Acknowledge Target CID Capsule { + Type (i) = 0xffe504 Length (i) Connection ID Length (i) Connection ID (0..2040), Virtual Connection ID Length (i) Virtual Connection ID (0..2040), + Stateless Reset Token Length (i), + Stateless Reset Token (..), } ~~~ -{: #fig-capsule-ack-client-cid title="Acknowledge Client Connection ID Capsule Format"} +{: #fig-capsule-ack-target-cid title="Acknowledge Target CID Capsule Format"} Connection ID Length : The length of the connection ID being acknowledged, which @@ -526,26 +618,38 @@ is limited to 20 bytes, but QUIC invariants allow up to 255 bytes. Connection ID : A connection ID being acknowledged whose length is equal to -Connection ID Length. This is the real Cilent Connection ID. +Connection ID Length. This is the real target CID. Virtual Connection ID Length -: The length of the virtual client connection ID being provided. This MUST be a -valid connection ID length for the QUIC version used in the client<->proxy QUIC +: The length of the target VCID being provided. This MUST be a +valid connection ID length for the QUIC version used in the client-to-proxy QUIC connection. When forwarded mode is not negotiated, the length MUST be zero. The Virtual Connection ID Length and Connection ID Length SHOULD be equal -when possible to avoid the need to resize packets during replacement. The -Virtual Client Connection ID Length SHOULD be at least as large as the -Connection ID to reduce the likelihood of connection ID conflicts. +when possible to avoid the need to resize packets during replacement. Virtual Connection ID -: The proxy-chosen connection ID that the proxy MUST use when sending in -forwarding mode. The proxy rewrites forwarded mode packets to contain the -correct Virtual Client Connection ID prior to sending them to the client. +: The proxy-chosen connection ID that the client MUST use when sending in +forwarded mode. The proxy rewrites forwarded mode packets to contain the +correct target CID prior to sending them. + +Stateless Reset Token Length +: The length of the Stateless Reset Token sent by the proxy in response to +forwarded mode packets in order to reset the client-to-target QUIC connection. +When forwarded mode is not negotiated, the length MUST be zero. Proxies choosing +not to support stateless resets MAY set the length to zero. Clients receiving a +zero-length stateless reset token MUST ignore it. + +Stateless Reset Token +: A Stateless Reset Token allowing reset of the client-to-target connection in +response to client-to-target forwarded mode packets. + +## ACK_CLIENT_VCID {#capsule-ack-virtual} -The ACK_CLIENT_VCID capsule type includes a Stateless Reset Token. +The ACK_CLIENT_VCID capsule type has type `0xffe503` and is sent by the client in +response to an ACK_TARGET_CID capsule that contains a virtual connection ID. ~~~ -Acknowledge Virtual Client Connection ID Capsule { +Acknowledge Client VCID Capsule { Type (i) = 0xffe503 Length (i) Connection ID Length (i) @@ -556,7 +660,7 @@ Acknowledge Virtual Client Connection ID Capsule { Stateless Reset Token (..), } ~~~ -{: #fig-capsule-ack-virtual-client-cid title="Acknowledge Virtual Client Connection ID Capsule Format"} +{: #fig-capsule-ack-virtual-client-cid title="Acknowledge Client VCID Capsule Format"} Connection ID Length : The length of the connection ID being acknowledged, which @@ -568,7 +672,7 @@ Connection ID Connection ID Length. This is the real Cilent Connection ID. Virtual Connection ID Length -: The length of the virtual client connection ID being acknowledged. +: The length of the client VCID being acknowledged. Virtual Connection ID : The proxy-chosen virtual connection ID being acknowledged whose length is @@ -576,195 +680,129 @@ equal to Virtual Connection ID Length. Stateless Reset Token Length : The length of the Stateless Reset Token that may be sent by the client in -response to forwarded mode packets to reset the Client<->Target connection. +response to forwarded mode packets to reset the client-to-target connection. Clients choosing not to support stateless resets MAY set the length to zero. Proxies receiving a zero-length stateless reset token MUST ignore it. Stateless Reset Token -: A Stateless Reset Token allowing reset of the Target->Client forwarding rule -in response to Target->Client forwarded mode packets. +: A Stateless Reset Token allowing reset of the target-to-client forwarding rule +in response to target-to-client forwarded mode packets. +## CLOSE_CLIENT_CID and CLOSE_TARGET_CID {#capsule-close} -# Client Behavior {#client-behavior} +CLOSE_CLIENT_CID and CLOSE_TARGET_CID capsule types have types `0xffe505` and +`0xffe506`, respectively, and include a single connection ID to close. They +can be sent by either clients or proxies. -A client initiates UDP proxying via a CONNECT request as defined -in {{CONNECT-UDP}}. Within its request, it includes the "Proxy-QUIC-Forwarding" -header to indicate whether or not the request should support forwarding. -If this header is not included, the client MUST NOT send any connection ID -capsules. +~~~ +Close CID Capsule { + Type (i) = 0xffe505, 0xffe506 + Length (i), + Connection ID (0..2040), +} +~~~ +{: #fig-capsule-close-cid title="Close CID Capsule Format"} -"Proxy-QUIC-Forwarding" is an Item Structured Header {{!RFC8941}}. Its -value MUST be a Boolean. +Connection ID: +: A connection ID being closed, which is between 0 and 255 bytes in +length. The length of the connection ID is implied by the length of the +capsule. Note that in QUICv1, the length of the Connection ID is limited +to 20 bytes, but QUIC invariants allow up to 255 bytes. -If the client wants to enable QUIC packet forwarding for this request, it sets -the value to "?1". If it doesn't want to enable forwarding, but instead only -provide information about QUIC Connection IDs for the purpose of allowing -the proxy to share a target-facing socket, it sets the value to "?0". +## Detecting Conflicts {#conflicts} -The client MUST add an "accept-transform" parameter whose value is an -`sf-string` containing the supported packet transforms ({{packet-transforms}}) -in order of descending preference, separated by commas. If the proxy receives a -"Proxy-QUIC-Forwarding" header without the "accept-transform" parameters, it -MUST ignore the header and respond as if the client had not sent the -"Proxy-QUIC-Forwarding" header. +In order to be able to route packets correctly in both tunnelled and forwarded +mode, proxies check for conflicts before creating a new CID mapping. If a conflict +is detected, the proxy will reject the client's request using a CLOSE_CLIENT_CID +or CLOSE_TARGET_CID capsule. -If the proxy supports QUIC-aware proxying, it will include the -"Proxy-QUIC-Forwarding" header in successful HTTP responses. The value -indicates whether or not the proxy supports forwarding. If the client does -not receive this header in responses, the client SHALL assume that the proxy -does not support this extension. +Two 4-tuples conflict if and only if all members of the 4-tuple (local IP +address, local UDP port, remote IP address, and remote UDP port) are identical. + +Two Connection IDs conflict if and only if one Connection ID is equal to or a +prefix of another. For example, a zero-length Connection ID conflicts with all +connection IDs. This definition of a conflict originates from the fact that +QUIC short headers do not carry the length of the Destination Connection ID +field, and therefore if two short headers with different Destination Connection +IDs are received on a shared 4-tuple, one being a prefix of the other prevents +the receiver from identifying which mapping this corresponds to. + +The proxy treats two mappings as being in conflict when a conflict is detected +for all elements on the left side of the mapping diagrams above. + +Since very short Connection IDs are more likely to lead to conflicts, +particularly zero-length Connection IDs, a proxy MAY choose to reject all +requests for very short Connection IDs as conflicts, in anticipation of future +conflicts. + +## Client Considerations The client sends a REGISTER_CLIENT_CID capsule whenever it advertises a new -Client Connection ID to the target, and a REGISTER_TARGET_CID capsule when -it has received a new Target Connection ID for the target. In order to change +client CID to the target, and a REGISTER_TARGET_CID capsule when +it has received a new target CID for the target. In order to change the connection ID bytes on the wire, a client can solicit new virtual connection IDs by re-registering the same connection IDs. The client may solicit a new -Virtual Target Connection ID by sending a REGISTER_TARGET_CID capsule with a -previously registered Target Connection ID. Similarly, the client may solicit a -new Virtual Client Connection ID by sending a REGISTER_CLIENT_CID with a -previously registered Client Connection ID. The client MUST acknowledge the new -Virtual Client Connection ID with an ACK_CLIENT_VCID capsule or close the +target VCID by sending a REGISTER_TARGET_CID capsule with a +previously registered target CID. Similarly, the client may solicit a +new client VCID by sending a REGISTER_CLIENT_CID with a +previously registered client CID. The client MUST acknowledge the new +client VCID with an ACK_CLIENT_VCID capsule or close the registration. The proxy MUST NOT send in forwarded mode until ACK_CLIENT_VCID has been received. Clients are responsible for changing Virtual Connection IDs when the HTTP stream's network path changes to avoid linkability across network paths. Note that initial REGISTER_CLIENT_CID capsules MAY be sent prior to receiving an HTTP response from the proxy. -## New Proxied Connection Setup +### New Proxied Connection Setup To initiate QUIC-aware proxying, the client sends a REGISTER_CLIENT_CID -capsule containing the initial Client Connection ID that the client has +capsule containing the initial client CID that the client has advertised to the target. If the mapping is created successfully, the client will receive a -ACK_CLIENT_CID capsule that contains the same Client Connection ID that was -requested as well as a Virtual Client Connection ID that the client MUST use -when sending forwarding mode packets, assuming forwarding mode is supported. +ACK_CLIENT_CID capsule that contains the same client CID that was +requested as well as a client VCID that the client MUST use +when sending forwarded mode packets, assuming forwarded mode is supported. -If forwarding mode is supported, the client MUST respond with an +If forwarded mode is supported, the client MUST respond with an ACK_CLIENT_VCID to signal to the proxy that it may start sending forwarded mode -packets. If forwarding mode is not supported, an ACK_CLIENT_VCID capsule MUST +packets. If forwarded mode is not supported, an ACK_CLIENT_VCID capsule MUST NOT be sent. Since clients are always aware whether or not they are using a QUIC proxy, -clients are expected to cooperate with proxies in selecting Client Connection -IDs. A proxy detects a conflict when it is not able to create a unique mapping -using the Client Connection ID ({{conflicts}}). It can reject requests that +clients are expected to cooperate with proxies in selecting client CIDs. +A proxy detects a conflict when it is not able to create a unique mapping +using the client CID ({{conflicts}}). It can reject requests that would cause a conflict and indicate this to the client by replying with a CLOSE_CLIENT_CID capsule. In order to avoid conflicts, clients SHOULD select -Client Connection IDs of at least 8 bytes in length with unpredictable values. -A client also SHOULD NOT select a Client Connection ID that matches the ID used +client CIDs of at least 8 bytes in length with unpredictable values. +A client also SHOULD NOT select a client CID that matches the ID used for the QUIC connection to the proxy, as this inherently creates a conflict. -If the rejection indicated a conflict due to the Client Connection ID, the +If the rejection indicated a conflict due to the client CID, the client MUST select a new Connection ID before sending a new request, and generate a new packet. For example, if a client is sending a QUIC Initial packet and chooses a Connection ID that conflicts with an existing mapping to the same target server, it will need to generate a new QUIC Initial. -## Adding New Client Connection IDs +### Adding New Client Connection IDs Since QUIC connection IDs are chosen by the receiver, an endpoint needs to communicate its chosen connection IDs to its peer before the peer can start using them. In QUICv1, this is performed using the NEW_CONNECTION_ID frame. -Prior to informing the target of a new chosen client connection ID, the client -MUST send a REGISTER_CLIENT_CID capsule to the proxy containing the new Client -Connection ID. +Prior to informing the target of a new chosen client CID, the client +MUST send a REGISTER_CLIENT_CID capsule to the proxy containing the new client +CID. -The client should only inform the target of the new Client Connection ID once an +The client should only inform the target of the new client CID once an ACK_CLIENT_CID capsule is received that contains the echoed connection ID. -If forwarding mode is enabled, the client MUST reply to the ACK_CLIENT_CID with +If forwarded mode is enabled, the client MUST reply to the ACK_CLIENT_CID with an ACK_CLIENT_VCID capsule with the real and virtual connection IDs along with an optional Stateless Reset Token. -## Sending With Forwarded Mode - -Support for forwarded mode is determined by the "Proxy-QUIC-Forwarding" header, -see {{proxy-behavior}}. - -Once the client has learned the target server's Connection ID, such as in the -response to a QUIC Initial packet, it can send a REGISTER_TARGET_CID capsule -containing the Target Connection ID to request the ability to forward packets. - -The client MUST wait for an ACK_TARGET_CID capsule that contains the echoed -connection ID and Virtual Target Connection ID before using forwarded mode. - -Prior to receiving the proxy server response, the client MUST send short header -packets tunnelled in HTTP Datagram frames. The client MAY also choose to tunnel -some short header packets even after receiving the successful response. - -If the Target Connection ID registration is rejected, for example with a -CLOSE_TARGET_CID capsule, it MUST NOT forward packets to the requested Target -Connection ID, but only use tunnelled mode. The request might also be rejected -if the proxy does not support forwarded mode or has it disabled by policy. - -QUIC long header packets MUST NOT be forwarded. These packets can only be -tunnelled within HTTP Datagram frames to avoid exposing unnecessary connection -metadata. - -When forwarding, the client sends a QUIC packet with the Virtual Target -Connection ID in the QUIC short header, using the same socket between client and -proxy that was used for the main QUIC connection between client and proxy. - -When forwarding, the proxy sends a QUIC packet with the Virtual Client Target -Connection ID in the QUIC short header, using the same socket between client -and proxy that was used for the main QUIC connection between client and proxy. - -Prior to sending a forwarded mode packet, the sender MUST replace the Connection -ID with the Virtual Connection ID. If the Virtual Connection ID is larger than -the Connection ID, the sender MUST extend the length of the packet by the -difference between the two lengths, to include the entire Virtual Connection ID. -If the Virtual Connection ID is smaller than the Connection ID, the sender MUST -shrink the length of the packet by the difference between the two lengths. - -Clients and proxies supporting forwarded mode MUST be able to handle Virtual -Connection IDs of different lengths than the corresponding Connection IDs. - -## Receiving With Forwarded Mode - -If the client has indicated support for forwarded mode with the "Proxy-QUIC-Forwarding" -header, the proxy MAY use forwarded mode for any Client Connection ID for which -it has a valid mapping. - -Once a client has sent an ACK_CLIENT_VCID capsule to the proxy, it MUST be -prepared to receive forwarded short header packets on the socket between itself -and the proxy for the specified Virtual Client Connection ID. - -The client uses the Destination Connection ID field of the received packet to -determine if the packet was originated by the proxy, or merely forwarded from -the target. The client replaces the Virtual Client Connection ID with the real -Client Connection ID before processing the packet further. - -## Connection Maintenance in Forwarded Mode - -When a client and proxy are using forwarded mode, it is possible that there can be -long periods of time in which no ack-eliciting packets (see {{Section 2 of !QUIC-RETRANSMISSION=RFC9002}}) are exchanged -between the client and proxy. If these periods extend beyond the effective idle -timeout for the client-to-proxy QUIC connection (see {{Section 10.1 of QUIC}}), -the QUIC connection might be closed by the proxy if the proxy does not use -forwarded packets as an explicit liveness signal. To avoid this, clients SHOULD -send keepalive packets to the proxy before the idle timeouts would be reached, -which can be done using a PING frame or another ack-eliciting frame as described -in {{Section 10.1.1 of QUIC}}. - -# Proxy Behavior {#proxy-behavior} - -Upon receipt of a CONNECT request that includes the "Proxy-QUIC-Forwarding" -header, the proxy indicates to the client that it supports QUIC-aware proxying -by including a "Proxy-QUIC-Forwarding" header in a successful response. -If it supports QUIC packet proxying in forwarded mode, it sets the value to "?1"; otherwise, -it sets it to "?0". - -The proxy MUST include a "transform" parameter whose value is an `sf-string` -indicating the selected transform. If the proxy does not recognize or accept -any of the transforms offered by the client, it MUST omit this parameter and -set the header field value to "?0", or omit the header entirely. - -Upon receipt of a REGISTER_CLIENT_CID or REGISTER_TARGET_CID capsule, -the proxy validates the registration and tries to establish the appropriate -mappings as described in {{mappings}}. +## Proxy Considerations The proxy MUST reply to each REGISTER_CLIENT_CID capsule with either an ACK_CLIENT_CID or CLOSE_CLIENT_CID capsule containing the @@ -774,37 +812,37 @@ Similarly, the proxy MUST reply to each REGISTER_TARGET_CID capsule with either an ACK_TARGET_CID or CLOSE_TARGET_CID capsule containing the Connection ID that was in the registration capsule. -The proxy then determines the target-facing socket to associate with the +The proxy then determines the proxy-to-target 4-tuple to associate with the client's request. This will generally involve performing a DNS lookup for -the target hostname in the CONNECT request, or finding an existing target-facing -socket to the authority. The target-facing socket might already be open due to a -previous request from this client, or another. If the socket is not already -created, the proxy creates a new one. Proxies can choose to reuse target-facing -sockets across multiple UDP proxying requests, or have a unique target-facing socket +the target hostname in the CONNECT request, or finding an existing proxy-to-target +4-tuple to the authority. The proxy-to-target 4-tuple might already be open due to a +previous request from this client, or another. If the 4-tuple is not already +created, the proxy creates a new one. Proxies can choose to reuse proxy-to-target +4-tuples across multiple UDP proxying requests, or have a unique proxy-to-target 4-tuple for every UDP proxying request. -If a proxy reuses target-facing sockets, it SHOULD store which authorities +If a proxy reuses proxy-to-target 4-tuples, it SHOULD store which authorities (which could be a domain name or IP address literal) are being accessed over a -particular target-facing socket so it can avoid performing a new DNS query and +particular proxy-to-target 4-tuple so it can avoid performing a new DNS query and potentially choosing a different target server IP address which could map to a different target server. -Target-facing sockets MUST NOT be reused across QUIC and non-QUIC UDP proxy +Proxy-to-target 4-tuples MUST NOT be reused across QUIC and non-QUIC UDP proxy requests, since it might not be possible to correctly demultiplex or direct -the traffic. Any packets received on a target-facing socket used for proxying -QUIC that does not correspond to a known Connection ID MUST be dropped. +the traffic. Any packets received on a proxy-to-target 4-tuple used for proxying +QUIC that does not correspond to a known CID MUST be dropped. When the proxy recieves a REGISTER_CLIENT_CID capsule, it is receiving a -request to be able to route traffic matching the Client Connection ID back to -the client using. If the pair of this Client Connection ID and the selected -target-facing socket does not create a conflict, the proxy creates the mapping -and responds with an ACK_CLIENT_CID capsule. If forwarding mode is enabled, the -capsule contains a proxy-chosen Virtual Client Connection ID. If forwarding mode +request to be able to route traffic matching the client CID back to +the client using. If the pair of this client CID and the selected +proxy-to-target 4-tuple does not create a conflict, the proxy creates the mapping +and responds with an ACK_CLIENT_CID capsule. If forwarded mode is enabled, the +capsule contains a proxy-chosen client VCID. If forwarded mode is enabled, and after receiving an ACK_CLIENT_VCID capsule from the client, any -packets received by the proxy from the target-facing socket that match the -Client Connection ID can to be sent to the client after the proxy has replaced -the Connection ID with the Virtual Client Connection ID. If forwarding mode is -not supported, the proxy MUST NOT send a Virtual Client Connection ID by setting +packets received by the proxy from the proxy-to-target 4-tuple that match the +client CID can to be sent to the client after the proxy has replaced +the CID with the client VCID. If forwarded mode is +not supported, the proxy MUST NOT send a client VCID by setting the length to zero. The proxy MUST use tunnelled mode (HTTP Datagram frames) for any long header packets. The proxy SHOULD forward directly to the client for any matching short header packets if forwarding is supported by the client, but the @@ -813,27 +851,26 @@ would create a conflict, the proxy responds with a CLOSE_CLIENT_CID capsule. When the proxy recieves a REGISTER_TARGET_CID capsule, it is receiving a request to allow the client to forward packets to the target. The proxy -generates a Virtual Target Connection ID for the client to use when sending +generates a target VCID for the client to use when sending packets in forwarded mode. If forwarded mode is not supported, the proxy MUST -NOT send a Virtual Target Connection ID by setting the length to zero. If -forwarded mode is supported, the proxy MUST use a Virtual Target Connection ID +NOT send a target VCID by setting the length to zero. If +forwarded mode is supported, the proxy MUST use a target VCID that does not introduce a conflict with any other Connection ID on the -client-facing socket. The proxy creates the mapping and responds with an +client-to-proxy 4-tuple. The proxy creates the mapping and responds with an ACK_TARGET_CID capsule. Once the successful response is sent, the proxy will -forward any short header packets received on the client-facing socket that use -the Virtual Target Connection ID using the correct target-facing socket after -first rewriting the Virtual Target Connection ID to be the correct Target -Connection ID. +forward any short header packets received on the client-to-proxy 4-tuple that use +the target VCID using the correct proxy-to-target 4-tuple after +first rewriting the target VCID to be the correct target CID. -Proxies MUST choose unpredictable Virtual Target and Client Connection IDs to +Proxies MUST choose unpredictable client and target VCIDs to avoid forwarding loop attacks. The proxy MUST only forward non-tunnelled packets from the client that are QUIC -short header packets (based on the Header Form bit) and have mapped Virtual Target -Connection IDs. Packets sent by the client that are forwarded SHOULD be +short header packets (based on the Header Form bit) and have mapped target VCIDs. +Packets sent by the client that are forwarded SHOULD be considered as activity for restarting QUIC's Idle Timeout {{QUIC}}. -## Removing Mapping State +### Closing Proxy State For any registration capsule for which the proxy has sent an acknowledgement, any mappings last until either endpoint sends a close capsule or the either side of the @@ -845,52 +882,78 @@ proxy sends a CLOSE_CLIENT_CID or CLOSE_TARGET_CID capsule. If a client's connection to the proxy is terminated for any reason, all mappings associated with all requests are removed. -A proxy can close its target-facing socket once all UDP proxying requests mapped to -that socket have been removed. +A proxy can close its proxy-to-target 4-tuple once all UDP proxying requests mapped to +that 4-tuple have been removed. -## Handling Connection Migration +# Using Forwarded Mode -If a proxy supports QUIC connection migration, it needs to ensure that a migration -event does not end up sending too many tunnelled or proxied packets on a new -path prior to path validation. +All packets sent in forwarded mode use a transform in which CIDs are switched +into VCIDs, and the contents of packets are either left the same, or modified +({{transforms}}). -Specifically, the proxy MUST limit the number of packets that it will proxy -to an unvalidated client address to the size of an initial congestion window. -Proxies additionally SHOULD pace the rate at which packets are sent over a new -path to avoid creating unintentional congestion on the new path. +Forwarded mode also raises special considerations for handling connection +maintenance ({{maintenance}}), connection migration ({{migration}}), +ECN markings ({{ecn}}), and stateless resets ({{resets}}). -When operating in forwarded mode, the proxy reconfigures or removes forwarding -rules as the network path between the client and proxy changes. In the event of -passive migration, the proxy automatically reconfigures forwarding rules to use -the latest active and validated network path for the HTTP stream. In the event of -active migration, the proxy removes forwarding rules in order to not send -packets with the same connection ID bytes over multiple network paths. After -initiating active migration, clients are no longer able to send forwarded mode -packets since the proxy will have removed forwarding rules. Clients can proceed with -tunnelled mode or can request new forwarding rules via REGISTER_CLIENT_CID and -REGISTER_TARGET_CID capsules. Each of the acknowledging capsules will contain new -virtual connection IDs to prevent packets with the same connection ID bytes being -used over multiple network paths. Note that the Client Connection ID and Target -Connection ID can stay the same while the Virtual Target Connection ID and -Virtual Client Connection ID change. +## Sending With Forwarded Mode -## Handling ECN Marking +Support for forwarded mode is determined by the "Proxy-QUIC-Forwarding" header, +see {{forwarding-header}}. -Explicit Congestion Notification marking {{!ECN=RFC3168}} uses two bits in the IP -header to signal congestion from a network to endpoints. When using forwarded mode, -the proxy replaces IP headers for packets exchanged between the client and target; -these headers can include ECN markings. Proxies SHOULD preserve ECN markings on -forwarded packets in both directions, to allow ECN to function end-to-end. If the proxy does not -preserve ECN markings, it MUST set ECN marks to zero on the IP headers it generates. +Once the client has learned the target server's Connection ID, such as in the +response to a QUIC Initial packet, it can send a REGISTER_TARGET_CID capsule +containing the target CID to request the ability to forward packets. -Forwarded mode does not create an IP-in-IP tunnel, so the guidance in -{{?ECN-TUNNEL=RFC6040}} about transferring ECN markings between inner and outer IP -headers does not apply. +The client MUST wait for an ACK_TARGET_CID capsule that contains the echoed +connection ID and target VCID before using forwarded mode. -A proxy MAY additionally add ECN markings to signal congestion being experienced -on the proxy itself. +Prior to receiving the proxy server response, the client MUST send short header +packets tunnelled in HTTP Datagram frames. The client MAY also choose to tunnel +some short header packets even after receiving the successful response. -# Packet Transforms +If the target CID registration is rejected, for example with a +CLOSE_TARGET_CID capsule, it MUST NOT forward packets to the requested target CID, +but only use tunnelled mode. The request might also be rejected +if the proxy does not support forwarded mode or has it disabled by policy. + +QUIC long header packets MUST NOT be forwarded. These packets can only be +tunnelled within HTTP Datagram frames to avoid exposing unnecessary connection +metadata. + +When forwarding, the client sends a QUIC packet with the target VCID +in the QUIC short header, using the same 4-tuple between client and +proxy that was used for the main QUIC connection between client and proxy. + +When forwarding, the proxy sends a QUIC packet with the client VCID +in the QUIC short header, using the same 4-tuple between client +and proxy that was used for the main QUIC connection between client and proxy. + +Prior to sending a forwarded mode packet, the sender MUST replace the Connection +ID with the Virtual Connection ID. If the Virtual Connection ID is larger than +the Connection ID, the sender MUST extend the length of the packet by the +difference between the two lengths, to include the entire Virtual Connection ID. +If the Virtual Connection ID is smaller than the Connection ID, the sender MUST +shrink the length of the packet by the difference between the two lengths. + +Clients and proxies supporting forwarded mode MUST be able to handle Virtual +Connection IDs of different lengths than the corresponding Connection IDs. + +## Receiving With Forwarded Mode + +If the client has indicated support for forwarded mode with the "Proxy-QUIC-Forwarding" +header, the proxy MAY use forwarded mode for any client CID for which +it has a valid mapping. + +Once a client has sent an ACK_CLIENT_VCID capsule to the proxy, it MUST be +prepared to receive forwarded short header packets on the 4-tuple between itself +and the proxy for the specified client VCID. + +The client uses the Destination Connection ID field of the received packet to +determine if the packet was originated by the proxy, or merely forwarded from +the target. The client replaces the client VCID with the real +client CID before processing the packet further. + +## Packet Transforms {#transforms} A packet transform is the procedure applied to encode packets as they are sent on the link between the client and proxy, along with the inverse decode step applied @@ -912,10 +975,10 @@ More complex transform behaviors could have internal state, but no such transfor are presented here. Packet transforms are identified by an IANA-registered name, and negotiated in -the HTTP headers (see {{client-behavior}}). This document defines two initial +the HTTP headers (see {{forwarding-header}}). This document defines two initial transforms: the `identity` transform and the `scramble` transform. -## The identify transform {#identity-transform} +### The identify transform {#identity-transform} The `identity` transform does not modify the packet in any way. When this transform is in use, a global passive adversary can trivially correlate pairs of packets @@ -929,7 +992,7 @@ by both the client and the proxy. Implementations MAY choose to not implement or support the `identity` transform, depending on the use cases and privacy requirements of the deployment. -## The scramble transform {#scramble-transform} +### The scramble transform {#scramble-transform} The `scramble` transform implements length-preserving unauthenticated re-encryption of QUIC packets while preserving the QUIC invariants. When @@ -946,9 +1009,9 @@ to use the reserved value "scramble" {{iana-transforms}}. The `scramble` transform is initialized using a 32-byte random symmetric key. When offering or selecting this transform, the client and server each generate the key that they will use to encrypt scrambled packets and MUST add it to the -Proxy-QUIC-Transform header in an `sf-binary` parameter named "scramble-key". +"Proxy-QUIC-Transform" header in an `sf-binary` parameter named "scramble-key". If either side receives a `scramble` transform without the "scramble-key" parameter, -forwarding mode MUST be disabled. +forwarded mode MUST be disabled. This transform relies on the AES-128 block cipher, which is represented by the syntax `AES-ECB(key, plaintext_block)` as in {{?RFC9001}}. The corresponding @@ -995,12 +1058,103 @@ packets that are too short or repeat the values at this location. When using the `scramble` transform, clients MUST NOT offer any configuration that could cause the client or target to violate this requirement. -# Example +## Connection Maintenance in Forwarded Mode {#maintenance} + +When a client and proxy are using forwarded mode, it is possible that there can be +long periods of time in which no ack-eliciting packets +(see {{Section 2 of !QUIC-RETRANSMISSION=RFC9002}}) are exchanged +between the client and proxy. If these periods extend beyond the effective idle +timeout for the client-to-proxy QUIC connection (see {{Section 10.1 of QUIC}}), +the QUIC connection might be closed by the proxy if the proxy does not use +forwarded packets as an explicit liveness signal. To avoid this, clients SHOULD +send keepalive packets to the proxy before the idle timeouts would be reached, +which can be done using a PING frame or another ack-eliciting frame as described +in {{Section 10.1.1 of QUIC}}. + +## Handling Connection Migration {#migration} + +If a proxy supports QUIC connection migration, it needs to ensure that a migration +event does not end up sending too many tunnelled or forwarded packets on a new +path prior to path validation. + +Specifically, the proxy MUST limit the number of packets that it will proxy +to an unvalidated client address to the size of an initial congestion window. +Proxies additionally SHOULD pace the rate at which packets are sent over a new +path to avoid creating unintentional congestion on the new path. + +When operating in forwarded mode, the proxy reconfigures or removes forwarding +rules as the network path between the client and proxy changes. In the event of +passive migration, the proxy automatically reconfigures forwarding rules to use +the latest active and validated network path for the HTTP stream. In the event of +active migration, the proxy removes forwarding rules in order to not send +packets with the same connection ID bytes over multiple network paths. After +initiating active migration, clients are no longer able to send forwarded mode +packets since the proxy will have removed forwarding rules. Clients can proceed with +tunnelled mode or can request new forwarding rules via REGISTER_CLIENT_CID and +REGISTER_TARGET_CID capsules. Each of the acknowledging capsules will contain new +virtual connection IDs to prevent packets with the same connection ID bytes being +used over multiple network paths. Note that the client CID and target CID +can stay the same while the target VCID and client VCID change. + +## Handling ECN Marking {#ecn} + +Explicit Congestion Notification marking {{!ECN=RFC3168}} uses two bits in the IP +header to signal congestion from a network to endpoints. When using forwarded mode, +the proxy replaces IP headers for packets exchanged between the client and target; +these headers can include ECN markings. Proxies SHOULD preserve ECN markings on +forwarded packets in both directions, to allow ECN to function end-to-end. If the proxy does not +preserve ECN markings, it MUST set ECN marks to zero on the IP headers it generates. + +Forwarded mode does not create an IP-in-IP tunnel, so the guidance in +{{?ECN-TUNNEL=RFC6040}} about transferring ECN markings between inner and outer IP +headers does not apply. + +A proxy MAY additionally add ECN markings to signal congestion being experienced +on the proxy itself. + +## Stateless Resets for Forwarded Mode QUIC Packets {#resets} + +While the lifecycle of forwarding rules are bound to the lifecycle of the +client-to-proxy HTTP stream, a peer may not be aware that the stream has +terminated. If the above mappings are lost or removed without the peer's +knowledge, they may send forwarded mode packets even though the client +or proxy no longer has state for that connection. To allow the client or +proxy to reset the client-to-target connection in the absence of the mappings +above, a stateless reset token corresponding to the Virtual Connection ID +can be provided. + +Consider a proxy that initiates closure of a client-to-proxy QUIC connection. +If the client is temporarily unresponsive or unreachable, the proxy might have +considered the connection closed and removed all connection state (including +the stream mappings used for forwarding). If the client never learned about the closure, it +might send forwarded mode packets to the proxy, assuming the stream mappings +and client-to-proxy connection are still intact. The proxy will receive these +forwarded mode packets, but won't have any state corresponding to the +destination connection ID in the packet. If the proxy has provided a stateless +reset token for the target VCID, it can send a stateless reset +packet to quickly notify the client that the client-to-target connection is +broken. + +### Stateless Resets from the Target + +Reuse of proxy-to-target 4-tuples is only possible because QUIC connection IDs +allow distinguishing packets for multiple QUIC connections received with the +same 5-tuple. One exception to this is Stateless Reset packets, in which the +connection ID is not used, but rather populated with unpredictable bits followed +by a Stateless Reset token, to make it indistinguishable from a regular packet +with a short header. In order for the proxy to correctly recognize Stateless +Reset packets, the client SHOULD share the Stateless Reset token for each +registered target CID. When the proxy receives a Stateless Reset packet, +it can send the packet to the client as a tunnelled datagram. Although Stateless Reset packets +look like short header packets, they are not technically short header packets and do not contain +negotiated connection IDs, and thus are not eligible for forwarded mode. + +# Example Exchange Consider a client that is establishing a new QUIC connection through the proxy. In this example, the client prefers the `scramble` transform, but also offers the `identity` -transform. It has selected a Client Connection ID of 0x31323334. In order to inform a proxy -of the new QUIC Client Connection ID, the client also sends a +transform. It has selected a client CID of `0x31323334`. In order to inform a proxy +of the new QUIC client CID, the client also sends a REGISTER_CLIENT_CID capsule. The client will also send the initial QUIC packet with the Long Header form in @@ -1042,10 +1196,10 @@ DATAGRAM --------> Virtual CID = 0x62646668 ~~~ -The proxy has acknowledged the Client Connection ID and provided a Virtual -Client Connection ID. Even if there were Short Header packets to send, the proxy +The proxy has acknowledged the client CID and provided a client VCID. +Even if there were Short Header packets to send, the proxy cannot send forwarded mode packets because the client hasn't acknowledged the -Virtual Client Connection ID. +client VCID. ~~~ STREAM(44): DATA --------> @@ -1055,7 +1209,7 @@ STREAM(44): DATA --------> Stateless Reset Token = Token ~~~ -The client acknowledges the Virtual Client Connection ID. The proxy still +The client acknowledges the client VCID. The proxy still doesn't have any Short Header Packets to send, but, if it did, it would be able to send with forwarded mode. @@ -1082,10 +1236,10 @@ DATAGRAM --------> ~~~ The client may receive forwarded mode packets from the proxy with a Virtual -Client Connection ID of 0x62646668 which it will replace with the real Client -Connection ID of 0x31323334. All forwarded mode packets sent by the proxy -will have been modified to contain the Virtual Client Connection ID instead -of the Client Connection ID, and processed by the negotiated "scramble" +client CID of 0x62646668 which it will replace with the real client CID +of 0x31323334. All forwarded mode packets sent by the proxy +will have been modified to contain the client VCID instead +of the client CID, and processed by the negotiated "scramble" packet transform. However, in the unlikely event that a forwarded packet arrives before the proxy's HTTP response, the client will not know which transform the proxy selected. In this case, the client will have to ignore @@ -1104,10 +1258,10 @@ STREAM(44): DATA --------> <-------- STREAM(44): DATA Capsule Type = ACK_TARGET_CID Connection ID = 0x61626364 - Virtual Target Connection ID = 0x123412341234 + Virtual Connection ID = 0x123412341234 Stateless Reset Token = Token -/* Client -> Target QUIC short header packets may use forwarding mode */ +/* Client -> Target QUIC short header packets may use forwarded mode */ UDP Datagram --------> Payload = Forwarded QUIC SH packet @@ -1120,7 +1274,7 @@ packets with a Destination Connection ID of 0x123412341234 directly to the proxy Connection ID 0x61626364 prior to being forwarded directly to the target. In the reverse direction, Short Header packets from the target with a Destination Connection ID of 0x31323334 are modified to replace the Destination Connection -ID with the Virtual Client Connection ID of 0x62646668 and forwarded directly to +ID with the client VCID of 0x62646668 and forwarded directly to the client. # Packet Size Considerations @@ -1203,9 +1357,9 @@ would forward the packets. In this way, forwarded mode is less vulnerable to flow recognition based on corrupting a portion of packets in a burst. Chaining of proxies using forwarded mode introduces the risk of forwarding loop -attacks. Preventing Virtual Client Connection ID conflicts across proxies +attacks. Preventing client VCID conflicts across proxies sharing an IP address and port mitigates one such forwarding loop attack. -Conflicts can be avoided by partitioning the Virtual Client Connection ID space +Conflicts can be avoided by partitioning the client VCID space across proxies, using sufficiently long and random values, or by other means. [comment1]: # OPEN ISSUE: Figure out how clients and proxies could interact to @@ -1231,7 +1385,7 @@ Protocol (HTTP) Field Name Registry" <[](https://www.iana.org/assignments/http-f ## Proxy QUIC Forwarding Parameter Names This document establishes a new registry, "Proxy QUIC Forwarding Parameter Names", -for parameter names to use with the `Proxy-QUIC-Forwarding` header field, +for parameter names to use with the "Proxy-QUIC-Forwarding" header field, in <[](https://www.iana.org/assignments/masque/masque.xhtml)>. Registrations in this registry are assigned using the Specification Required policy (Section 4.6 of [IANA-POLICY]). @@ -1240,9 +1394,9 @@ Specification Required policy (Section 4.6 of [IANA-POLICY]). +-----------------------+-------------------------------------+---------------+--------------------------------+ | Parameter Name | Description | Reference | Notes | +-----------------------+-------------------------------------+---------------+--------------------------------+ - | accept-transform | contains supported transforms | This document | Section {{client-behavior}} | + | accept-transform | contains supported transforms | This document | Section {{forwarding-header}} | +-----------------------+-------------------------------------+---------------+--------------------------------+ - | transform | indicates selected transforms | This document | Section {{proxy-behavior}} | + | transform | indicates selected transforms | This document | Section {{forwarding-header}} | +-----------------------+-------------------------------------+---------------+--------------------------------+ | scramble-key | contains key for scramble transform | This document | Section {{scramble-transform}} | +-----------------------+-------------------------------------+---------------+--------------------------------+ @@ -1270,7 +1424,7 @@ Specification Required policy (Section 4.6 of [IANA-POLICY]). ## Capsule Types {#iana-capsule-types} This document registers six new values in the "HTTP Capsule Types" -registry established by {{HTTP-DGRAM}}. Note that the codepoints below +registry established by {{HTTP-CAPSULES}}. Note that the codepoints below will be replaced with lower values before publication. | Capule Type | Value | Specification |