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 REGISTER_CLIENT_CID (Section 3.1.1) and REGISTER_TARGET_CID
(Section 3.1.2) 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. These capsule
types share a sequence number space which allows the proxy to limit the
number of registrations. The first registration (of either client CID or target CID)
has sequence number 0, and subsequent registrations increment the sequence number
by 1. Every registration capsule consumes a sequence number, including registrations
that are rejected and re-registrations of a previously registered connection ID.¶
The ACK_CLIENT_CID (Section 3.1.3) and ACK_TARGET_CID
(Section 3.1.4) 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. Note that
Virtual Connection IDs are always sent by the proxy in order to avoid possible loop attacks
Section 8.3.¶
The ACK_CLIENT_VCID (Section 3.1.5) 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 REJECT_CLIENT_CID and REJECT_TARGET_CID capsule types (Section 3.1.6)
are used to reject connection ID registrations. Each capsule includes
a reason code indicating the reason for the rejection. These capsules MUST only be sent
by the proxy. A proxy MUST NOT send a rejection capsule for a registration that it
has already acknowledged. If a client receives such a capsule, it MUST reset the
stream with H3_DATAGRAM_ERROR error code.¶
The CLOSE_CLIENT_CID and CLOSE_TARGET_CID capsule types (Section 3.1.7)
are used to close connection ID registrations. These capsules are only sent by the
client and MUST NOT be sent by proxies.¶
Clients send CLOSE_CLIENT_CID or CLOSE_TARGET_CID capsules to retire connection
IDs they no longer need, using the DEFAULT reason code. If a client cannot use the
proxy-chosen client VCID (e.g., due to conflict or insufficient length), it can
re-register the same client CID with an appropriate reason code to request a new
VCID.¶
The MAX_CONNECTION_IDS capsule type Section 3.1.8 MUST only be sent by the
proxy. It indicates to the client the cumulative number of connection ID registrations the client is allowed to request. This allows the proxy to limit the number of active
registrations. The initial maximum is 2, allowing the client to send 2 registrations,
one with sequence number 0 and another with sequence number 1. MAX_CONNECTION_IDS are
only sent to increase the limit. Since the initial limit is 2, a proxy MUST NOT
send a MAX_CONNECTION_IDS capsule with a value less than 3. Clients receiving a
MAX_CONNECTION_IDS capsule with a value less than 3 MUST reset the stream with
H3_DATAGRAM_ERROR error code.¶
When port sharing Section 2.3.2 is supported, the client MUST register
and receive acknowledgements for client and target CIDs before using them. Packets with
unknown connection IDs received by the proxy on a target-facing sockets that support
port sharing MUST be dropped. In order to avoid introducing an additional round trip
on setup, a REGISTER_CLIENT_CID capsule SHOULD be sent at the same time as the client's
first flight. If the proxy rejects the client CID, the proxy MUST drop all packets until
it has sent an ACK_CLIENT_CID capsule and the client MUST NOT send any packets until
receiving an ACK_CLIENT_CID. When port sharing is supported, a proxy SHOULD buffer a
reasonable number of incoming packets while waiting for the first REGISTER_CLIENT_CID
capsule.¶
Importantly, registering connection IDs does not introduce any delay in
communication between client and target unless port sharing is supported and
there is an unlikely client CID collision. The client and target can always
communicate over the tunnel without having to wait for registrations to be
acknowledged. Forwarded mode requires CID/VCID mappings be communicated and
acknowledged, and, as a consequence, cannot be leveraged without a round
trip. This is particularly pronounced when chaining proxies because
registration happens sequentially. While waiting for forwarded mode to become
enabled, clients SHOULD communicate over tunneled mode to avoid end-to-end
delays.¶
For QUIC-aware proxying without forwarded mode, the steps are as follows:¶
-
The client sends the REGISTER_CLIENT_CID capsule once it selects a
CID that it will use for receiving packets from a target.¶
-
The proxy sends the ACK_CLIENT_CID capsule to acknowledge that CID,
with no associated client VCID; alternatively, the proxy can send the
REJECT_CLIENT_CID if it detects a conflict with another CID.¶
-
The proxy sends the MAX_CONNECTION_IDS capsule to allow additional
registration of new connection IDs via future REGISTER_CLIENT_CID and
REGISTER_TARGET_CID capsules.¶
-
Whenever a client stops using a particular CID, the client
sends a CLOSE_CLIENT_CID. The client can also initiate new
REGISTER_CLIENT_CID exchanges at any time.¶
For QUIC-aware proxying with forwarded mode, the steps are as follows:¶
-
The client sends the REGISTER_CLIENT_CID capsule once it selects a
CID that it will use for receiving packets from a target.¶
-
The proxy sends the ACK_CLIENT_CID capsule to acknowledge that CID,
with a client VCID; alternatively, the proxy can send the
REJECT_CLIENT_CID if it detects a conflict with another CID.¶
-
The client sends the ACK_CLIENT_VCID capsule to acknowledge the
client VCID, which allows forwarded packets for that VCID to be used.¶
-
The client sends the REGISTER_TARGET_CID capsule as soon as it learns
the target CID on the client-to-target connection.¶
-
The proxy sends the ACK_TARGET_CID capsule to acknowledge that CID,
with a target VCID; alternatively, the proxy can send the
REJECT_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.¶
-
The proxy sends the MAX_CONNECTION_IDS capsule to allow additional
registration of new connection IDs via future REGISTER_CLIENT_CID and
REGISTER_TARGET_CID capsules.¶
-
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 client sends a REGISTER_CLIENT_CID capsule before it advertises a new
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. Note that re-registrations
consume sequence numbers like any other registration. The client may solicit a new
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.¶
If the client receives a VCID it cannot use, it may re-register the same
client CID with a reason code indicating why the previous VCID was unusable.
The proxy SHOULD use this information to select a more suitable VCID. If the
reason is TOO_SHORT, the proxy MUST either select a longer VCID or close the registration. If the reason is
CONFLICT, the proxy MUST select a different VCID.¶
Connection ID registrations are subject to a proxy-advertised limit. Each registration
has a corresponding sequence number. The client MUST NOT send a registration
capsule with a sequence number greater than what the proxy advertises via the
MAX_CONNECTION_IDS capsule. The initial MAX_CONNECTION_IDS value is 1, allowing both
sequence numbers 0 and 1 for a total of two registrations without receiving a
MAX_CONNECTION_IDS capsule from the proxy.¶
Clients that cannot register new connection IDs within a reasonable time due to
the MAX_CONNECTION_IDS limit SHOULD abort the proxied connection by resetting the HTTP
stream with error code NO_ERROR. This may happen, for example, if the target server
sends a NEW_CONNECTION_ID frame with Sequence Number and Retire Prior To equal to the
same value.¶
Clients can cease receiving with forwarded mode over an existing tunnel while
retaining the same client-to-target connection by creating a new tunnel with
"Proxy-QUIC-Forwarding" set to "?0" and migrating the client-to-target connection.¶
To initiate QUIC-aware proxying, the client sends a REGISTER_CLIENT_CID
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 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 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 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 CIDs.
A proxy detects a conflict when it is not able to create a unique mapping
using the client CID (Section 3.3.1). It can reject registrations that
would cause a conflict by replying with a REJECT_CLIENT_CID capsule with the
CONFLICT reason code. Proxies may also reject registrations for short CIDs
using the TOO_SHORT reason code. In order to avoid rejections, clients SHOULD
select 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 reason was CONFLICT, the client MUST select a new Connection ID
before sending a new registration 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. If the rejection reason was TOO_SHORT, the client
MUST select a longer Connection ID before retrying.¶
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 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 CID once an
ACK_CLIENT_CID capsule is received that contains the echoed connection ID.¶
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.¶
The proxy MUST reply to each REGISTER_CLIENT_CID capsule with either
an ACK_CLIENT_CID or REJECT_CLIENT_CID capsule containing the
Connection ID that was in the registration capsule. Capsules MUST be responded
to in the order in which they are received.¶
Similarly, the proxy MUST reply to each REGISTER_TARGET_CID capsule with
either an ACK_TARGET_CID or REJECT_TARGET_CID capsule containing the
Connection ID that was in the registration capsule.¶
When a proxy receives a REGISTER_CLIENT_CID with a non-zero reason code,
it indicates the client is requesting a new VCID because the previous one
was unusable. The proxy SHOULD attempt to address the issue indicated by
the reason code when selecting the new VCID.¶
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 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 the client did not send a value of "?1" for the
"Proxy-QUIC-Port-Sharing" header, port reuse is not permitted and the proxy MUST allocate
a new UDP 4-tuple.¶
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 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.¶
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 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 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 proxy-to-target 4-tuple that match the
client CID can be sent to the client after the proxy has replaced
the CID with the client VCID and executed the negotiated transform (Section 4.3). 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
proxy MAY tunnel these packets in HTTP Datagram frames instead. If the mapping
would create a conflict, the proxy responds with a REJECT_CLIENT_CID capsule
with the CONFLICT reason code.¶
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 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 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-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-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 and executing the
negotiated transform.¶
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 target VCIDs.
Packets sent by the client that are forwarded SHOULD be
considered as activity for restarting QUIC's Idle Timeout [QUIC].¶
In order to permit the client to change client-to-target connection IDs, the proxy
SHOULD send MAX_CONNECTION_IDS capsules allowing the client additional connection ID
registrations.¶
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 registration using a REJECT_CLIENT_CID
or REJECT_TARGET_CID capsule with the CONFLICT reason code.¶
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
registrations for very short Connection IDs using the TOO_SHORT reason code.¶
For any registration capsule for which the proxy has sent an acknowledgement, the
mapping lasts until the client sends a close capsule or either side of the
HTTP stream closes.¶
A client that no longer wants a given Connection ID to be forwarded by the
proxy sends a CLOSE_CLIENT_CID or CLOSE_TARGET_CID capsule with the DEFAULT
reason code.¶
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 proxy-to-target 4-tuple once all UDP proxying requests mapped to
that 4-tuple have been removed.¶