<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE rfc [
  <!ENTITY nbsp    "&#160;">
  <!ENTITY zwsp   "&#8203;">
  <!ENTITY nbhy   "&#8209;">
  <!ENTITY wj     "&#8288;">
]>

<!-- generated by https://github.com/cabo/kramdown-rfc version 1.6.29 (Ruby 3.1.4) -->

<rfc xmlns:xi="http://www.w3.org/2001/XInclude" ipr="trust200902" docName="draft-ietf-masque-connect-ip-13" number="9484" submissionType="IETF" category="std" consensus="true" updates="9298" obsoletes="" xml:lang="en" tocInclude="true" sortRefs="true" symRefs="true" version="3">

  <!-- xml2rfc v2v3 conversion 3.17.1 -->
  <front>
    <title>Proxying IP in HTTP</title>
    <seriesInfo name="RFC" value="9484"/>
    <author initials="T." surname="Pauly" fullname="Tommy Pauly" role="editor">
      <organization>Apple Inc.</organization>
      <address>
        <email>tpauly@apple.com</email>
      </address>
    </author>
    <author initials="D." surname="Schinazi" fullname="David Schinazi">
      <organization>Google LLC</organization>
      <address>
        <postal>
          <street>1600 Amphitheatre Parkway</street>
          <city>Mountain View</city>
          <region>CA</region>
          <code>94043</code>
          <country>United States of America</country>
        </postal>
        <email>dschinazi.ietf@gmail.com</email>
      </address>
    </author>
    <author initials="A." surname="Chernyakhovsky" fullname="Alex Chernyakhovsky">
      <organization>Google LLC</organization>
      <address>
        <email>achernya@google.com</email>
      </address>
    </author>
    <author initials="M." surname="Kühlewind" fullname="Mirja Kühlewind">
      <organization>Ericsson</organization>
      <address>
        <email>mirja.kuehlewind@ericsson.com</email>
      </address>
    </author>
    <author initials="M." surname="Westerlund" fullname="Magnus Westerlund">
      <organization>Ericsson</organization>
      <address>
        <email>magnus.westerlund@ericsson.com</email>
      </address>
    </author>
    <date year="2023" month="October"/>
    <area>tsv</area>
    <workgroup>masque</workgroup>
    <keyword>quic</keyword>
    <keyword>http</keyword>
    <keyword>datagram</keyword>
    <keyword>VPN</keyword>
    <keyword>proxy</keyword>
    <keyword>tunnels</keyword>
    <keyword>quic in udp in IP in quic</keyword>
    <keyword>turtles all the way down</keyword>
    <keyword>masque</keyword>
    <keyword>http-ng</keyword>
    <abstract>
      <t>This document describes how to proxy IP packets in HTTP. This protocol is
similar to UDP proxying in HTTP but allows transmitting arbitrary IP packets.
More specifically, this document defines a protocol that allows an HTTP client
to create an IP tunnel through an HTTP server that acts as an IP proxy. This
document updates RFC 9298.</t>
    </abstract>
  </front>
  <middle>
    <section anchor="introduction">
      <name>Introduction</name>
      <t>HTTP provides the CONNECT method (see <xref section="9.3.6" sectionFormat="of" target="RFC9110"/>) for
creating a TCP <xref target="RFC9293"/> tunnel to a destination and a similar mechanism
for UDP <xref target="RFC9298"/>. However, these mechanisms cannot tunnel other
IP protocols <xref target="IANA-PN"/> nor convey fields of the IP header.</t>
      <t>This document describes a protocol for tunnelling IP through an HTTP server
acting as an IP-specific proxy over HTTP. This can be used for various use
cases, such as remote access VPN, site-to-site VPN, secure point-to-point
communication, or general-purpose packet tunnelling.</t>
      <t>IP proxying operates similarly to UDP proxying <xref target="RFC9298"/>,
whereby the proxy itself is identified with an absolute URL, optionally
containing the traffic's destination. Clients generate these URLs using a URI
Template <xref target="RFC6570"/>, as described in <xref target="client-config"/>.</t>
      <t>This protocol supports all existing versions of HTTP by using HTTP Datagrams
<xref target="RFC9297"/>. When using HTTP/2 <xref target="RFC9113"/> or HTTP/3 <xref target="RFC9114"/>, it uses
HTTP Extended CONNECT, as described in <xref target="RFC8441"/> and
<xref target="RFC9220"/>. When using HTTP/1.x <xref target="RFC9112"/>, it uses HTTP Upgrade, as
      defined in <xref section="7.8" sectionFormat="of" target="RFC9110"/>.</t>
     
      <t>This document updates <xref target="RFC9298"/> to change the "masque" well-known URI;
see <xref target="iana-uri"/>.</t>
    </section>
    <section anchor="conventions-and-definitions">
      <name>Conventions and Definitions</name>
        <t>
    The key words "<bcp14>MUST</bcp14>", "<bcp14>MUST NOT</bcp14>", "<bcp14>REQUIRED</bcp14>", "<bcp14>SHALL</bcp14>", "<bcp14>SHALL
    NOT</bcp14>", "<bcp14>SHOULD</bcp14>", "<bcp14>SHOULD NOT</bcp14>", "<bcp14>RECOMMENDED</bcp14>", "<bcp14>NOT RECOMMENDED</bcp14>",
    "<bcp14>MAY</bcp14>", and "<bcp14>OPTIONAL</bcp14>" in this document are to be interpreted as
    described in BCP&nbsp;14 <xref target="RFC2119"/> <xref target="RFC8174"/> 
    when, and only when, they appear in all capitals, as shown here.
        </t>
      <t>In this document, we use the term "IP proxy" to refer to the HTTP server that
responds to the IP proxying request. The term "client" is used in the HTTP
sense; the client constructs the IP proxying request. If there are HTTP
intermediaries (as defined in <xref section="3.7" sectionFormat="of" target="RFC9110"/>) between the client and
the IP proxy, those are referred to as "intermediaries" in this document. The
term "IP proxying endpoints" refers to both the client and the IP proxy.</t>
      <t>This document uses terminology from <xref target="RFC9000"/>. Where this document
defines protocol types, the definition format uses the notation from <xref section="1.3" sectionFormat="of" target="RFC9000"/>. This specification uses the variable-length integer encoding
from <xref section="16" sectionFormat="of" target="RFC9000"/>. Variable-length integer values do not
need to be encoded in the minimum number of bytes necessary.</t>
      <t>Note that, when the HTTP version in use does not support multiplexing streams
(such as HTTP/1.1), any reference to "stream" in this document represents the
entire connection.</t>
    </section>
    <section anchor="client-config">
      <name>Configuration of Clients</name>
      <t>Clients are configured to use IP proxying over HTTP via a URI Template
<xref target="RFC6570"/>. The URI Template <bcp14>MAY</bcp14> contain two variables: "target" and
"ipproto"; see <xref target="scope"/>. The optionality of the variables needs to be
considered when defining the template so that the variable is either
self-identifying or possible to exclude in the syntax.</t>
      <t>Examples are shown below:</t>
      <figure anchor="fig-template-examples">
        <name>URI Template Examples</name>
        <artwork><![CDATA[
https://example.org/.well-known/masque/ip/{target}/{ipproto}/
https://proxy.example.org:4443/masque/ip?t={target}&i={ipproto}
https://proxy.example.org:4443/masque/ip{?target,ipproto}
https://masque.example.org/?user=bob
]]></artwork>
      </figure>
      <t>The following requirements apply to the URI Template:</t>
      <ul spacing="normal">
        <li>The URI Template <bcp14>MUST</bcp14> be a level 3 template or lower.</li>
        <li>The URI Template <bcp14>MUST</bcp14> be in absolute form and <bcp14>MUST</bcp14> include non-empty scheme,
authority, and path components.</li>
        <li>The path component of the URI Template <bcp14>MUST</bcp14> start with a slash "/".</li>
        <li>All template variables <bcp14>MUST</bcp14> be within the path or query components of the URI.</li>
        <li>The URI Template <bcp14>MAY</bcp14> contain the two variables "target" and "ipproto" and <bcp14>MAY</bcp14>
contain other variables. If the "target" or "ipproto" variables are included,
their values <bcp14>MUST NOT</bcp14> be empty. Clients can instead use "*" to indicate
wildcard or no-preference values; see <xref target="scope"/>.</li>
        <li>The URI Template <bcp14>MUST NOT</bcp14> contain any non-ASCII Unicode characters and <bcp14>MUST</bcp14>
only contain ASCII characters in the range 0x21-0x7E inclusive (note that
percent-encoding is allowed; see <xref target="RFC3986" section="2.1" sectionFormat="of" />).</li>
        <li>The URI Template <bcp14>MUST NOT</bcp14> use Reserved Expansion ("+" operator), Fragment
Expansion ("#" operator), Label Expansion with Dot-Prefix, Path Segment
Expansion with Slash-Prefix, nor Path-Style Parameter Expansion with
Semicolon-Prefix.</li>
      </ul>
      <t>Clients <bcp14>SHOULD</bcp14> validate the requirements above; however, clients <bcp14>MAY</bcp14> use a
general-purpose URI Template implementation that lacks this specific
validation. If a client detects that any of the requirements above are not met
by a URI Template, the client <bcp14>MUST</bcp14> reject its configuration and abort the
request without sending it to the IP proxy.</t>
      <t>As with UDP proxying, some client configurations for IP proxies will only allow
the user to configure the proxy host and proxy port. Clients with such
limitations <bcp14>MAY</bcp14> attempt to access IP proxying capabilities using the default
template, which is defined as:
"https://$PROXY_HOST:$PROXY_PORT/.well-known/masque/ip/{target}/{ipproto}/",
where $PROXY_HOST and $PROXY_PORT are the configured host and port of the IP
proxy, respectively. IP proxy deployments <bcp14>SHOULD</bcp14> offer service at this location
if they need to interoperate with such clients.</t>
    </section>
    <section anchor="tunnelling-ip-over-http">
      <name>Tunnelling IP over HTTP</name>
      <t>To allow negotiation of a tunnel for IP over HTTP, this document defines the
"connect-ip" HTTP upgrade token. The resulting IP tunnels use the Capsule
Protocol (see <xref section="3.2" sectionFormat="of" target="RFC9297"/>) with HTTP Datagrams in the format
defined in <xref target="payload-format"/>.</t>
      <t>To initiate an IP tunnel associated with a single HTTP stream, a client issues
a request containing the "connect-ip" upgrade token.</t>
      <t>When sending its IP proxying request, the client <bcp14>SHALL</bcp14> perform URI Template
expansion to determine the path and query of its request; see <xref target="client-config"/>.</t>
      <t>By virtue of the definition of the Capsule Protocol (see <xref section="3.2" sectionFormat="of" target="RFC9297"/>), IP proxying requests do not carry any message content.
Similarly, successful IP proxying responses also do not carry any message
content.</t>
      <t>IP proxying over HTTP <bcp14>MUST</bcp14> be operated over TLS or QUIC encryption, or another
equivalent encryption protocol, to provide confidentiality, integrity, and
authentication.</t>
      <section anchor="ip-proxy-handling">
        <name>IP Proxy Handling</name>
        <t>Upon receiving an IP proxying request:</t>
        <ul spacing="normal">
          <li>If the recipient is configured to use another HTTP server, it will act as an
intermediary by forwarding the request to the other HTTP server. Note that
such intermediaries may need to re-encode the request if they forward it
using a version of HTTP that is different from the one used to receive it,
as the request encoding differs by version (see below).</li>
          <li>Otherwise, the recipient will act as an IP proxy. The IP proxy can choose to
reject the IP proxying request. Otherwise, it extracts the optional "target"
and "ipproto" variables from the URI it has reconstructed from the request
headers, decodes their percent-encoding, and establishes an IP tunnel.</li>
        </ul>
        <t>IP proxies <bcp14>MUST</bcp14> validate whether the decoded "target" and "ipproto" variables
meet the requirements in <xref target="scope"/>. If they do not, the IP proxy <bcp14>MUST</bcp14> treat the
request as malformed; see <xref section="8.1.1" sectionFormat="of" target="RFC9113"/> and <xref section="4.1.2" sectionFormat="of" target="RFC9114"/>.
If the "target" variable is a DNS name, the IP proxy <bcp14>MUST</bcp14> perform DNS
resolution (to obtain the corresponding IPv4 and/or IPv6 addresses via A and/or
AAAA records) before replying to the HTTP request. If errors occur during this
process, the IP proxy <bcp14>MUST</bcp14> reject the request and <bcp14>SHOULD</bcp14> send details using an
appropriate Proxy-Status header field <xref target="RFC9209"/>. For example,
if DNS resolution returns an error, the proxy can use the <tt>dns_error</tt> proxy
error type from <xref section="2.3.2" sectionFormat="of" target="RFC9209"/>.</t>
        <t>The lifetime of the IP forwarding tunnel is tied to the IP proxying request
stream. The IP proxy <bcp14>MUST</bcp14> maintain all IP address and route assignments
associated with the IP forwarding tunnel while the request stream is open. IP
proxies <bcp14>MAY</bcp14> choose to tear down the tunnel due to a period of inactivity, but
they <bcp14>MUST</bcp14> close the request stream when doing so.</t>
        <t>A successful IP proxying response (as defined in Sections <xref format="counter" target="resp1"/> and <xref format="counter" target="resp23"/>)
indicates that the IP proxy has established an IP tunnel and is willing to
proxy IP payloads. Any response other than a successful IP proxying response indicates that
the request has failed; thus, the client <bcp14>MUST</bcp14> abort the request.</t>
        <t>Along with a successful IP proxying response, the IP proxy can send capsules to assign
addresses and advertise routes to the client (<xref target="capsules"/>). The client can
also assign addresses and advertise routes to the IP proxy for
network-to-network routing.</t>
      </section>
      <section anchor="req1">
        <name>HTTP/1.1 Request</name>
        <t>When using HTTP/1.1 <xref target="RFC9112"/>, an IP proxying request will meet the following
requirements:</t>
        <ul spacing="normal">
          <li>The method <bcp14>SHALL</bcp14> be "GET".</li>
          <li>The request <bcp14>SHALL</bcp14> include a single Host header field containing the host
and optional port of the IP proxy.</li>
          <li>The request <bcp14>SHALL</bcp14> include a Connection header field with value "Upgrade"
(note that this requirement is case-insensitive, as per <xref section="7.6.1" sectionFormat="of" target="RFC9110"/>).</li>
          <li>The request <bcp14>SHALL</bcp14> include an Upgrade header field with value "connect-ip".</li>
        </ul>
        <t>An IP proxying request that does not conform to these restrictions is
malformed. The recipient of such a malformed request <bcp14>MUST</bcp14> respond with an error
and <bcp14>SHOULD</bcp14> use the 400 (Bad Request) status code.</t>
        <t>For example, if the client is configured with URI Template
"https://example.org/.well-known/masque/ip/{target}/{ipproto}/" and wishes to
open an IP forwarding tunnel with no target or protocol limitations, it could
send the following request:</t>
        <figure anchor="fig-req-h1">
          <name>Example HTTP/1.1 Request</name>
          <sourcecode type="http-message"><![CDATA[
GET https://example.org/.well-known/masque/ip/*/*/ HTTP/1.1
Host: example.org
Connection: Upgrade
Upgrade: connect-ip
Capsule-Protocol: ?1
]]></sourcecode>
        </figure>
      </section>
      <section anchor="resp1">
        <name>HTTP/1.1 Response</name>
        <t>The server indicates a successful IP proxying response by replying with the following
requirements:</t>
        <ul spacing="normal">
          <li>The HTTP status code on the response <bcp14>SHALL</bcp14> be 101 (Switching Protocols).</li>
          <li>The response <bcp14>SHALL</bcp14> include a Connection header field with value "Upgrade"
(note that this requirement is case-insensitive, as per <xref section="7.6.1" sectionFormat="of" target="RFC9110"/>).</li>  
          <li>The response <bcp14>SHALL</bcp14> include a single Upgrade header field with value
"connect-ip".</li>
          <li>The response <bcp14>SHALL</bcp14> meet the requirements of HTTP responses that start the
Capsule Protocol; see <xref section="3.2" sectionFormat="of" target="RFC9297"/>.</li>
        </ul>
        <t>If any of these requirements are not met, the client <bcp14>MUST</bcp14> treat this proxying
attempt as failed and close the connection.</t>
        <t>For example, the server could respond with:</t>
        <figure anchor="fig-resp-h1">
          <name>Example HTTP/1.1 Response</name>
          <sourcecode type="http-message"><![CDATA[
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: connect-ip
Capsule-Protocol: ?1
]]></sourcecode>
        </figure>
      </section>
      <section anchor="req23">
        <name>HTTP/2 and HTTP/3 Requests</name>
        <t>When using HTTP/2 <xref target="RFC9113"/> or HTTP/3 <xref target="RFC9114"/>, IP proxying requests use HTTP
Extended CONNECT. This requires that servers send an HTTP Setting, as specified
in <xref target="RFC8441"/> and <xref target="RFC9220"/>, and that requests use HTTP
pseudo-header fields with the following requirements:</t>
        <ul spacing="normal">
          <li>The :method pseudo-header field <bcp14>SHALL</bcp14> be "CONNECT".</li>
          <li>The :protocol pseudo-header field <bcp14>SHALL</bcp14> be "connect-ip".</li>
          <li>The :authority pseudo-header field <bcp14>SHALL</bcp14> contain the authority of the IP
proxy.</li>
          <li>The :path and :scheme pseudo-header fields <bcp14>SHALL NOT</bcp14> be empty. Their values
<bcp14>SHALL</bcp14> contain the scheme and path from the URI Template after the URI
Template expansion process has been completed; see <xref target="client-config"/>.
Variables in the URI Template can determine the scope of the request, such as
requesting full-tunnel IP packet forwarding, or a specific proxied flow; see
<xref target="scope"/>.</li>
        </ul>
        <t>An IP proxying request that does not conform to these restrictions is
malformed; see <xref section="8.1.1" sectionFormat="of" target="RFC9113"/> and <xref section="4.1.2" sectionFormat="of" target="RFC9114"/>.</t>
        <t>For example, if the client is configured with URI Template
"https://example.org/.well-known/masque/ip/{target}/{ipproto}/" and wishes to
open an IP forwarding tunnel with no target or protocol limitations, it could
send the following request:</t>
        <figure anchor="fig-req-h2">
          <name>Example HTTP/2 or HTTP/3 Request</name>
          <sourcecode type="http-message"><![CDATA[
HEADERS
:method = CONNECT
:protocol = connect-ip
:scheme = https
:path = /.well-known/masque/ip/*/*/
:authority = example.org
capsule-protocol = ?1
]]></sourcecode>
        </figure>
      </section>
      <section anchor="resp23">
        <name>HTTP/2 and HTTP/3 Responses</name>
        <t>The server indicates a successful IP proxying response by replying with the following
requirements:</t>
        <ul spacing="normal">
          <li>The HTTP status code on the response <bcp14>SHALL</bcp14> be in the 2xx (Successful) range.</li>
          <li>The response <bcp14>SHALL</bcp14> meet the requirements of HTTP responses that start the
Capsule Protocol; see <xref section="3.2" sectionFormat="of" target="RFC9297"/>.</li>
        </ul>
        <t>If any of these requirements are not met, the client <bcp14>MUST</bcp14> treat this proxying
attempt as failed and abort the request. As an example, any status code in the
3xx range will be treated as a failure and cause the client to abort the
request.</t>
        <t>For example, the server could respond with:</t>
        <figure anchor="fig-resp-h2">
          <name>Example HTTP/2 or HTTP/3 Response</name>
          <sourcecode type="http-message"><![CDATA[
HEADERS
:status = 200
capsule-protocol = ?1
]]></sourcecode>
        </figure>
      </section>
      <section anchor="scope">
        <name>Limiting Request Scope</name>
        <t>Unlike UDP proxying requests, which require specifying a target host, IP
proxying requests can allow endpoints to send arbitrary IP packets to any host.
The client can choose to restrict a given request to a specific IP prefix or IP
protocol by adding parameters to its request. When the IP proxy knows that a
request is scoped to a target prefix or protocol, it can leverage this
information to optimize its resource allocation; for example, the IP proxy can
assign the same public IP address to two IP proxying requests that are scoped
to different prefixes and/or different protocols.</t>
        <t>The scope of the request is indicated by the client to the IP proxy via the
"target" and "ipproto" variables of the URI Template; see <xref target="client-config"/>.
Both the "target" and "ipproto" variables are optional; if they are not
included, they are considered to carry the wildcard value "*".</t>
        <dl spacing="normal" newline="true">
          <dt>target:</dt>
          <dd>
            <t>The variable "target" contains a hostname or IP prefix of a specific host to
which the client wants to proxy packets. If the "target" variable is not
specified or its value is "*", the client is requesting to communicate with
any allowable host. "target" supports using DNS names, IPv6 prefixes, and IPv4
prefixes. Note that IPv6 scoped addressing zone identifiers <xref target="RFC6874"/> are
not supported. If the target is an IP prefix (IP address optionally followed by
a percent-encoded slash followed by the prefix length in bits), the request
will only support a single IP version. If the target is a hostname, the IP
proxy is expected to perform DNS resolution to determine which route(s) to
advertise to the client. The IP proxy <bcp14>SHOULD</bcp14> send a ROUTE_ADVERTISEMENT capsule
that includes routes for all addresses that were resolved for the requested
hostname, that are accessible to the IP proxy, and belong to an address family
for which the IP proxy also sends an Assigned Address.</t>
          </dd>
          <dt>ipproto:</dt>
          <dd>
            <t>The variable "ipproto" contains an Internet Protocol Number; see the defined list in the
"Assigned Internet Protocol Numbers" IANA registry <xref target="IANA-PN"/>. If present, it
specifies that a client only wants to proxy a specific IP protocol for this
request. If the value is "*", or the variable is not included, the client is
requesting to use any IP protocol. The IP protocol indicated in the "ipproto"
variable represents an allowable next header value carried in IP headers that
are directly sent in HTTP Datagrams (the outermost IP headers). ICMP traffic
is always allowed, regardless of the value of this field.</t>
          </dd>
        </dl>
        <t>Using the terms IPv6address, IPv4address, and reg-name from <xref target="RFC3986"/>, the
"target" and "ipproto" variables <bcp14>MUST</bcp14> adhere to the format in
<xref target="target-format"/>, using notation from <xref target="RFC5234"/>. Additionally:</t>
        <ul spacing="normal">
          <li>If "target" contains an IPv6 literal or prefix, the colons (":") <bcp14>MUST</bcp14> be
percent-encoded. For example, if the target host is "2001:db8::42", it will
be encoded in the URI as "2001%3Adb8%3A%3A42".</li>
          <li>If present, the IP prefix length in "target" <bcp14>SHALL</bcp14> be preceded by a
percent-encoded slash ("/"): "%2F". The IP prefix length <bcp14>MUST</bcp14> represent a
decimal integer between 0 and the length of the IP address in bits, inclusive.</li>
          <li>If "target" contains an IP prefix and the prefix length is strictly less than
the length of the IP address in bits, the lower bits of the IP address that
are not covered by the prefix length <bcp14>MUST</bcp14> all be set to 0.</li>
          <li>"ipproto" <bcp14>MUST</bcp14> represent a decimal integer between 0 and 255 inclusive or
the wildcard value "*".</li>
        </ul>
        <figure anchor="target-format">
          <name>URI Template Variable Format</name>
          <sourcecode type="abnf"><![CDATA[
target = IPv6prefix / IPv4prefix / reg-name / "*"
IPv6prefix = IPv6address ["%2F" 1*3DIGIT]
IPv4prefix = IPv4address ["%2F" 1*2DIGIT]
ipproto = 1*3DIGIT / "*"
]]></sourcecode>
        </figure>
        <t>IP proxies <bcp14>MAY</bcp14> perform access control using the scoping information provided by
the client, i.e., if the client is not authorized to access any of the destinations
included in the scope, then the IP proxy can immediately reject the request.</t>
      </section>
      <section anchor="capsules">
        <name>Capsules</name>
        <t>This document defines multiple new capsule types that allow endpoints to
exchange IP configuration information. Both endpoints <bcp14>MAY</bcp14> send any number of
these new capsules.</t>
        <section anchor="addressassign-capsule">
          <name>ADDRESS_ASSIGN Capsule</name>
          <t>The ADDRESS_ASSIGN capsule (capsule type 0x01) allows an endpoint to assign its peer a list of IP addresses or
prefixes. Every capsule contains the full list of IP
prefixes currently assigned to the receiver. Any of these addresses can be used
as the source address on IP packets originated by the receiver of this capsule.</t>
          <figure anchor="addr-assign-format">
            <name>ADDRESS_ASSIGN Capsule Format</name>
            <artwork><![CDATA[
ADDRESS_ASSIGN Capsule {
  Type (i) = 0x01,
  Length (i),
  Assigned Address (..) ...,
}
]]></artwork>
          </figure>
          <t>The ADDRESS_ASSIGN capsule contains a sequence of zero or more Assigned
Addresses.</t>
          <figure anchor="assigned-addr-format">
            <name>Assigned Address Format</name>
            <artwork><![CDATA[
Assigned Address {
  Request ID (i),
  IP Version (8),
  IP Address (32..128),
  IP Prefix Length (8),
}
]]></artwork>
          </figure>
          <t>Each Assigned Address contains the following fields:</t>
          <dl spacing="normal" newline="true">
            <dt>Request ID:</dt>
            <dd>
              <t>Request identifier, encoded as a variable-length integer. If this address
assignment is in response to an Address Request (see <xref target="addr_req"/>), then this
field <bcp14>SHALL</bcp14> contain the value of the corresponding field in the request.
Otherwise, this field <bcp14>SHALL</bcp14> be zero.</t>
            </dd>
            <dt>IP Version:</dt>
            <dd>
              <t>IP Version of this address assignment, encoded as an unsigned 8-bit integer. It
<bcp14>MUST</bcp14> be either 4 or 6.</t>
            </dd>
            <dt>IP Address:</dt>
            <dd>
              <t>Assigned IP address. If the IP Version field has value 4, the IP Address
field <bcp14>SHALL</bcp14> have a length of 32 bits. If the IP Version field has value 6, the
IP Address field <bcp14>SHALL</bcp14> have a length of 128 bits.</t>
            </dd>
            <dt>IP Prefix Length:</dt>
            <dd>
              <t>The number of bits in the IP address that are used to define the prefix that
is being assigned, encoded as an unsigned 8-bit integer. This <bcp14>MUST</bcp14> be less than
or equal to the length of the IP Address field in bits. If the prefix length
is equal to the length of the IP address, the receiver of this capsule is
allowed to send packets from a single source address. If the prefix length is
less than the length of the IP address, the receiver of this capsule is allowed
to send packets from any source address that falls within the prefix. If the
prefix length is strictly less than the length of the IP address in bits, the
lower bits of the IP Address field that are not covered by the prefix length
<bcp14>MUST</bcp14> all be set to 0.</t>
            </dd>
          </dl>
          <t>If any of the capsule fields are malformed upon reception, the receiver of the
capsule <bcp14>MUST</bcp14> follow the error-handling procedure defined in <xref section="3.3" sectionFormat="of" target="RFC9297"/>.</t>
          <t>If an ADDRESS_ASSIGN capsule does not contain an address that was previously
transmitted in another ADDRESS_ASSIGN capsule, it indicates that the address
has been removed. An ADDRESS_ASSIGN capsule can also be empty, indicating that
all addresses have been removed.</t>
          <t>In some deployments of IP proxying in HTTP, an endpoint needs to be assigned an
address by its peer before it knows what source address to set on its own
packets. For example, in the remote access VPN case (<xref target="example-remote"/>), the
client cannot send IP packets until it knows what address to use.
In these
deployments, the endpoint that is expecting an address assignment <bcp14>MUST</bcp14> send an
ADDRESS_REQUEST capsule. This isn't required if the endpoint does not need any
address assignment, for example, when it is configured out-of-band with static
addresses.</t>
          <t>While ADDRESS_ASSIGN capsules are commonly sent in response to ADDRESS_REQUEST
capsules, endpoints <bcp14>MAY</bcp14> send ADDRESS_ASSIGN capsules unprompted.</t>
        </section>
        <section anchor="addr_req">
          <name>ADDRESS_REQUEST Capsule</name>
          <t>The ADDRESS_REQUEST capsule (capsule type 0x02) allows an endpoint to request assignment of IP addresses from its peer.
The capsule allows the endpoint to optionally indicate a preference for which
address it would get assigned.</t>
          <figure anchor="addr-req-format">
            <name>ADDRESS_REQUEST Capsule Format</name>
            <artwork><![CDATA[
ADDRESS_REQUEST Capsule {
  Type (i) = 0x02,
  Length (i),
  Requested Address (..) ...,
}
]]></artwork>
          </figure>
          <t>The ADDRESS_REQUEST capsule contains a sequence of one or more Requested
Addresses.</t>
          <figure anchor="requested-addr-format">
            <name>Requested Address Format</name>
            <artwork><![CDATA[
Requested Address {
  Request ID (i),
  IP Version (8),
  IP Address (32..128),
  IP Prefix Length (8),
}
]]></artwork>
          </figure>
          <t>Each Requested Address contains the following fields:</t>
          <dl spacing="normal" newline="true">
            <dt>Request ID:</dt>
            <dd>
              <t>Request identifier, encoded as a variable-length integer. This is the
identifier of this specific address request. Each request from a given endpoint
carries a different identifier. Request IDs <bcp14>MUST NOT</bcp14> be reused by an endpoint
and <bcp14>MUST NOT</bcp14> be zero.</t>
            </dd>
            <dt>IP Version:</dt>
            <dd>
              <t>IP Version of this address request, encoded as an unsigned 8-bit integer. It
<bcp14>MUST</bcp14> be either 4 or 6.</t>
            </dd>
            <dt>IP Address:</dt>
            <dd>
              <t>Requested IP address. If the IP Version field has value 4, the IP Address
field <bcp14>SHALL</bcp14> have a length of 32 bits. If the IP Version field has value 6, the
IP Address field <bcp14>SHALL</bcp14> have a length of 128 bits.</t>
            </dd>
            <dt>IP Prefix Length:</dt>
            <dd>
              <t>Length of the IP Prefix requested in bits, encoded as an unsigned 8-bit
integer. It <bcp14>MUST</bcp14> be less than or equal to the length of the IP Address field in
bits. If the prefix length is strictly less than the length of the IP address
in bits, the lower bits of the IP Address field that are not covered by the
prefix length <bcp14>MUST</bcp14> all be set to 0.</t>
            </dd>
          </dl>
          <t>If the IP address is all-zero (0.0.0.0 or ::), this indicates that the sender
is requesting an address of that address family but does not have a preference
for a specific address. In that scenario, the prefix length still indicates the
sender's preference for the prefix length it is requesting.</t>
          <t>If any of the capsule fields are malformed upon reception, the receiver of the
capsule <bcp14>MUST</bcp14> follow the error-handling procedure defined in <xref section="3.3" sectionFormat="of" target="RFC9297"/>.</t> 
          <t>Upon receiving the ADDRESS_REQUEST capsule, an endpoint <bcp14>SHOULD</bcp14> assign one or
more IP addresses to its peer and then respond with an ADDRESS_ASSIGN capsule
to inform the peer of the assignment. For each Requested Address, the receiver
of the ADDRESS_REQUEST capsule <bcp14>SHALL</bcp14> respond with an Assigned Address with a
matching Request ID. If the requested address was assigned, the IP Address and
IP Prefix Length fields in the Assigned Address response <bcp14>SHALL</bcp14> be set to the
assigned values. If the requested address was not assigned, the IP address
<bcp14>SHALL</bcp14> be all-zero, and the IP Prefix Length <bcp14>SHALL</bcp14> be the maximum length
(0.0.0.0/32 or ::/128) to indicate that no address was assigned. These address
rejections <bcp14>SHOULD NOT</bcp14> be included in subsequent ADDRESS_ASSIGN capsules. Note
that other Assigned Address entries that do not correspond to any Request ID
can also be contained in the same ADDRESS_ASSIGN response.</t>
          <t>If an endpoint receives an ADDRESS_REQUEST capsule that contains zero Requested
Addresses, it <bcp14>MUST</bcp14> abort the IP proxying request stream.</t>
          <t>Note that the ordering of Requested Addresses does not carry any semantics.
Similarly, the Request ID is only meant as a unique identifier; it does not
convey any priority or importance.</t>
        </section>
        <section anchor="route-adv">
          <name>ROUTE_ADVERTISEMENT Capsule</name>
          <t>The ROUTE_ADVERTISEMENT capsule (capsule type 0x03) allows an endpoint to communicate to its peer that it is willing
to route traffic to a set of IP address ranges. This indicates that the sender
has an existing route to each address range and notifies its peer that, if the
receiver of the ROUTE_ADVERTISEMENT capsule sends IP packets for one of these
ranges in HTTP Datagrams, the sender of the capsule will forward them along its
preexisting route. Any address that is in one of the address ranges can be
used as the destination address on IP packets originated by the receiver of
this capsule.</t>
          <figure anchor="route-adv-format">
            <name>ROUTE_ADVERTISEMENT Capsule Format</name>
            <artwork><![CDATA[
ROUTE_ADVERTISEMENT Capsule {
  Type (i) = 0x03,
  Length (i),
  IP Address Range (..) ...,
}
]]></artwork>
          </figure>
          <t>The ROUTE_ADVERTISEMENT capsule contains a sequence of zero or more IP Address
Ranges.</t>
          <figure anchor="addr-range-format">
            <name>IP Address Range Format</name>
            <artwork><![CDATA[
IP Address Range {
  IP Version (8),
  Start IP Address (32..128),
  End IP Address (32..128),
  IP Protocol (8),
}
]]></artwork>
          </figure>
          <t>Each IP Address Range contains the following fields:</t>
          <dl spacing="normal" newline="true">
            <dt>IP Version:</dt>
            <dd>
              <t>IP Version of this range, encoded as an unsigned 8-bit integer. It <bcp14>MUST</bcp14> be
either 4 or 6.</t>
            </dd>
            <dt>Start IP Address and End IP Address:</dt>
            <dd>
              <t>Inclusive start and end IP address of the advertised range. If the IP Version
field has value 4, these fields <bcp14>SHALL</bcp14> have a length of 32 bits. If the IP
Version field has value 6, these fields <bcp14>SHALL</bcp14> have a length of 128 bits. The
Start IP Address <bcp14>MUST</bcp14> be less than or equal to the End IP Address.</t>
            </dd>
            <dt>IP Protocol:</dt>
            <dd>
              <t>The Internet Protocol Number for traffic that can be sent to this range,
encoded as an unsigned 8-bit integer. If the value is 0, all protocols are
allowed. If the value is not 0, it represents an allowable next header value
carried in IP headers that are sent directly in HTTP Datagrams (the outermost
IP headers). ICMP traffic is always allowed, regardless of the value of this
field.</t>
            </dd>
          </dl>
          <t>If any of the capsule fields are malformed upon reception, the receiver of the
capsule <bcp14>MUST</bcp14> follow the error-handling procedure defined in <xref section="3.3" sectionFormat="of" target="RFC9297"/>.</t>
          <t>Upon receiving the ROUTE_ADVERTISEMENT capsule, an endpoint <bcp14>MAY</bcp14> update its
local state regarding what its peer is willing to route (subject to local
policy), such as by installing entries in a routing table.</t>
          <t>Each ROUTE_ADVERTISEMENT contains the full list of address ranges. If multiple
ROUTE_ADVERTISEMENT capsules are sent in one direction, each
ROUTE_ADVERTISEMENT capsule supersedes prior ones. In other words, if a given
address range was present in a prior capsule but the most recently received
ROUTE_ADVERTISEMENT capsule does not contain it, the receiver will consider
that range withdrawn.</t>
          <t>If multiple ranges using the same IP protocol were to overlap, some routing
table implementations might reject them. To prevent overlap, the ranges are
ordered; this places the burden on the sender and makes verification by the
receiver much simpler. If an IP Address Range A precedes an IP Address Range B
in the same ROUTE_ADVERTISEMENT capsule, they <bcp14>MUST</bcp14> follow these requirements:</t>
          <ul spacing="normal">
            <li>The IP Version of A <bcp14>MUST</bcp14> be less than or equal to the IP Version of B.</li>
            <li>If the IP Version of A and B are equal, the IP Protocol of A <bcp14>MUST</bcp14> be less
than or equal to the IP Protocol of B.</li>
            <li>If the IP Version and IP Protocol of A and B are both equal, the End IP
Address of A <bcp14>MUST</bcp14> be strictly less than the Start IP Address of B.</li>
          </ul>
          <t>If an endpoint receives a ROUTE_ADVERTISEMENT capsule that does not meet these
requirements, it <bcp14>MUST</bcp14> abort the IP proxying request stream.</t>
          <t>Since setting the IP protocol to zero indicates all protocols are allowed, the
requirements above make it possible for two routes to overlap when one has its IP
protocol set to zero and the other has it set to non-zero. Endpoints <bcp14>MUST NOT</bcp14> send a
ROUTE_ADVERTISEMENT capsule with routes that overlap in such a way. Validating
this requirement is <bcp14>OPTIONAL</bcp14>, but if an endpoint detects the violation, it <bcp14>MUST</bcp14>
abort the IP proxying request stream.</t>
        </section>
      </section>
      <section anchor="ipv6-extension-headers">
        <name>IPv6 Extension Headers</name>
        <t>Both request scoping (see <xref target="scope"/>) and the ROUTE_ADVERTISEMENT capsule (see
<xref target="route-adv"/>) use Internet Protocol Numbers. These numbers represent both upper
layers (as defined in <xref section="2" sectionFormat="of" target="RFC8200"/>, with examples that include TCP and
UDP) and IPv6 extension headers (as defined in <xref section="4" sectionFormat="of" target="RFC8200"/>, with examples
that include Fragment and Options headers). IP proxies <bcp14>MAY</bcp14> reject requests to scope
to protocol numbers that are used for extension headers. Upon receiving
packets, implementations that support scoping or routing by Internet Protocol Number
<bcp14>MUST</bcp14> walk the chain of extensions to find the outermost non-extension Internet Protocol
Number to match against the scoping rule. Note that the ROUTE_ADVERTISEMENT
capsule uses Internet Protocol Number 0 to indicate that all protocols are allowed;
it does not restrict the route to the IPv6 Hop-by-Hop Options header
(<xref section="4.3" sectionFormat="of" target="RFC8200"/>).</t>
      </section>
    </section>
    <section anchor="context-identifiers">
      <name>Context Identifiers</name>
      <t>The mechanism for proxying IP in HTTP defined in this document allows future
extensions to exchange HTTP Datagrams that carry different semantics from IP
payloads. Some of these extensions can augment IP payloads with additional data
or compress IP header fields, while others can exchange data that is completely
separate from IP payloads. In order to accomplish this, all HTTP Datagrams
associated with IP proxying request streams start with a Context ID field; see
<xref target="payload-format"/>.</t>
      <t>Context IDs are 62-bit integers (0 to 2<sup>62</sup>-1). Context IDs are
encoded as variable-length integers; see <xref section="16" sectionFormat="of" target="RFC9000"/>. The Context ID
value of 0 is reserved for IP payloads, while non-zero values are dynamically
allocated. Non-zero even-numbered Context IDs are client-allocated, and
odd-numbered Context IDs are proxy-allocated. The Context ID namespace is tied
to a given HTTP request; it is possible for a Context ID with the same numeric
value to be simultaneously allocated in distinct requests, potentially with
different semantics. Context IDs <bcp14>MUST NOT</bcp14> be re-allocated within a given HTTP
request but <bcp14>MAY</bcp14> be allocated in any order. The Context ID allocation
restrictions to the use of even-numbered and odd-numbered Context IDs exist in
order to avoid the need for synchronization between endpoints. However, once a
Context ID has been allocated, those restrictions do not apply to the use of
the Context ID; it can be used by either the client or the IP proxy,
independent of which endpoint initially allocated it.</t>
      <t>Registration is the action by which an endpoint informs its peer of the
semantics and format of a given Context ID. This document does not define how
registration occurs. Future extensions <bcp14>MAY</bcp14> use HTTP header fields or capsules
to register Context IDs. Depending on the method being used, it is possible for
datagrams to be received with Context IDs that have not yet been registered.
For instance, this can be due to reordering of the packet containing the
datagram and the packet containing the registration message during transmission.</t>
    </section>
    <section anchor="payload-format">
      <name>HTTP Datagram Payload Format</name>
      <t>When associated with IP proxying request streams, the HTTP Datagram Payload
field of HTTP Datagrams (see <xref target="RFC9297"/>) has the format defined in
<xref target="dgram-format"/>. Note that, when HTTP Datagrams are encoded using QUIC DATAGRAM
frames, the Context ID field defined below directly follows the Quarter Stream
ID field that is at the start of the QUIC DATAGRAM frame payload:</t>
      <figure anchor="dgram-format">
        <name>IP Proxying HTTP Datagram Format</name>
        <artwork><![CDATA[
IP Proxying HTTP Datagram Payload {
  Context ID (i),
  Payload (..),
}
]]></artwork>
      </figure>
      <t>The IP Proxying HTTP Datagram Payload contains the following fields:</t>
      <dl spacing="normal" newline="true">
        <dt>Context ID:</dt>
        <dd>
          <t>A variable-length integer that contains the value of the Context ID. If an
HTTP/3 datagram that carries an unknown Context ID is received, the receiver
<bcp14>SHALL</bcp14> either drop that datagram silently or buffer it temporarily (on the order
of a round trip) while awaiting the registration of the corresponding Context
ID.</t>
        </dd>
        <dt>Payload:</dt>
        <dd>
          <t>The payload of the datagram, whose semantics depend on value of the previous
field. Note that this field can be empty.</t>
        </dd>
      </dl>
      <t>IP packets are encoded using HTTP Datagrams with the Context ID set to zero.
When the Context ID is set to zero, the Payload field contains a full IP packet
(from the IP Version field until the last byte of the IP payload).</t>
    </section>
    <section anchor="ip-packet-handling">
      <name>IP Packet Handling</name>
      <t>This document defines a tunneling mechanism that is conceptually an IP link.
However, because links are attached to IP routers, implementations might need
to handle some of the responsibilities of IP routers if they do not delegate
them to another implementation, such as a kernel.</t>
      <section anchor="link-operation">
        <name>Link Operation</name>
        <t>The IP forwarding tunnels described in this document are not fully featured
"interfaces" in the IPv6 addressing architecture sense <xref target="RFC4291"/>.
In particular, they do not necessarily have IPv6 link-local addresses.
Additionally, IPv6 stateless autoconfiguration or router advertisement messages
are not used in such interfaces, and neither is neighbor discovery.</t>
        <t>When using HTTP/2 or HTTP/3, a client <bcp14>MAY</bcp14> optimistically start sending proxied IP packets before receiving
the response to its IP proxying request, noting however that those may not be
processed by the IP proxy if it responds to the request with a failure or if
the datagrams are received by the IP proxy before the request. Since receiving
addresses and routes is required in order to know that a packet can be sent
through the tunnel, such optimistic packets might be dropped by the IP proxy if
it chooses to provide different addressing or routing information than what the
client assumed.</t>
        <t>Note that it is possible for multiple proxied IP packets to be encapsulated in
the same outer packet, for example, because a QUIC packet can carry more than one QUIC
DATAGRAM frame. It is also possible for a proxied IP packet to span multiple
outer packets, because a DATAGRAM capsule can be split across multiple QUIC or
TCP packets.</t>
      </section>
      <section anchor="routing-operation">
        <name>Routing Operation</name>
        <t>The requirements in this section are a repetition of requirements that apply to
IP routers in general and might not apply to implementations of IP proxying
that rely on external software for routing.</t>
        <t>When an endpoint receives an HTTP Datagram containing an IP packet, it will
parse the packet's IP header, perform any local policy checks (e.g., source
address validation), check their routing table to pick an outbound interface,
and then send the IP packet on that interface or pass it to a local
application. The endpoint can also choose to drop any received packets instead
of forwarding them. If a received IP packet fails any correctness or policy
checks, that is a forwarding error, not a protocol violation, as far as IP
proxying is concerned; see <xref target="error-signal"/>. IP proxying endpoints <bcp14>MAY</bcp14>
implement additional filtering policies on the IP packets they forward.</t>
        <t>In the other direction, when an endpoint receives an IP packet, it checks to see
if the packet matches the routes mapped for an IP tunnel and performs the same
forwarding checks as above before transmitting the packet over HTTP Datagrams.</t>
        <t>When IP proxying endpoints forward IP packets between different links, they
will decrement the IP Hop Count (or TTL) upon encapsulation but not upon
decapsulation. In other words, the Hop Count is decremented right before an IP
packet is transmitted in an HTTP Datagram. This prevents infinite loops in the
presence of routing loops and matches the choices in IPsec <xref target="RFC4301"/>.
This does not apply to IP packets generated by the IP proxying endpoint itself.</t>
        <t>Implementers need to ensure that they do not forward any link-local traffic
beyond the IP proxying interface that it was received on. IP proxying endpoints
also need to properly reply to packets destined to link-local multicast
addresses.</t>
<t>IPv6 requires that every link have an MTU of at least 1280 bytes <xref target="RFC8200"/>.
Since IP proxying in HTTP conveys IP packets in HTTP Datagrams and those can in
turn be sent in QUIC DATAGRAM frames that cannot be fragmented
<xref target="RFC9221"/>, the MTU of an IP tunnel can be limited by the MTU of the
QUIC connection that IP proxying is operating over. This can lead to situations
where the IPv6 minimum link MTU is violated. IP proxying endpoints that operate
as routers and support IPv6 <bcp14>MUST</bcp14> ensure that the IP tunnel link MTU is at least
1280 bytes (i.e., that they can send HTTP Datagrams with payloads of at least 1280
bytes). This can be accomplished using various techniques:</t>
        <ul spacing="normal">
          <li>If both IP proxying endpoints know for certain that HTTP intermediaries are
not in use, the endpoints can pad the QUIC INITIAL packets of the outer
QUIC connection that IP proxying is running over. (Assuming QUIC version 1 is
in use, the overhead is 1 byte for the type, 20 bytes for the maximal connection ID length, 4
bytes for the maximal packet number length, 1 byte for the DATAGRAM frame type, 8 bytes
for the maximal Quarter Stream ID, 1 byte for the zero Context ID, and 16 bytes for
the Authenticated Encryption with Associated Data (AEAD) authentication tag, for a total of 51 bytes of overhead, which
corresponds to padding QUIC INITIAL packets to 1331 bytes or more.)</li>
          <li>IP proxying endpoints can also send ICMPv6 echo requests with 1232 bytes of
data to ascertain the link MTU and tear down the tunnel if they do not
receive a response. Unless endpoints have an out-of-band means of
guaranteeing that the previous techniques are sufficient, they <bcp14>MUST</bcp14> use this
method. If an endpoint does not know an IPv6 address of its peer, it can send
the ICMPv6 echo request to the link-local all nodes multicast address
(ff02::1).</li>
        </ul>
        <t>If an endpoint is using QUIC DATAGRAM frames to convey IPv6 packets and it
detects that the QUIC MTU is too low to allow sending 1280 bytes, it <bcp14>MUST</bcp14> abort
the IP proxying request stream.</t>
        <section anchor="error-signal">
          <name>Error Signalling</name>
          <t>Since IP proxying endpoints often forward IP packets onwards to other network
interfaces, they need to handle errors in the forwarding process. For example,
forwarding can fail if the endpoint does not have a route for the destination
address, if it is configured to reject a destination prefix by policy, or if
the MTU of the outgoing link is lower than the size of the packet to be
forwarded. In such scenarios, IP proxying endpoints <bcp14>SHOULD</bcp14> use ICMP
<xref target="RFC0792"/> <xref target="RFC4443"/> to signal the forwarding error to its
peer by generating ICMP packets and sending them using HTTP Datagrams.</t>
          <t>Endpoints are free to select the most appropriate ICMP errors to send. Some
examples that are relevant for IP proxying include the following:</t>
          <ul spacing="normal">
            <li>For invalid source addresses, send Destination Unreachable (<xref section="3.1" sectionFormat="of" target="RFC4443"/>) with code 5, "Source address failed ingress/egress policy".</li>
            <li>For unroutable destination addresses, send Destination Unreachable (<xref section="3.1" sectionFormat="of" target="RFC4443"/>) with code 0, "No route to destination", or code 1,
"Communication with destination administratively prohibited".</li>
            <li>For packets that cannot fit within the MTU of the outgoing link, send Packet
Too Big (<xref section="3.2" sectionFormat="of" target="RFC4443"/>).</li>
          </ul> 
          <t>In order to receive these errors, endpoints need to be prepared to receive ICMP
packets. If an endpoint does not send ROUTE_ADVERTISEMENT capsules, such as a
client opening an IP flow through an IP proxy, it <bcp14>SHOULD</bcp14> process proxied ICMP
packets from its peer in order to receive these errors. Note that ICMP messages
can originate from a source address different from that of the IP proxying
peer and also from outside the target if scoping is in use (see <xref target="scope"/>).</t>
        </section>
      </section>
    </section>
    <section anchor="examples">
      <name>Examples</name>
      <t>IP proxying in HTTP enables many different use cases that can benefit from IP
packet proxying and tunnelling. These examples are provided to help illustrate
some of the ways in which IP proxying in HTTP can be used.</t>
      <section anchor="example-remote">
        <name>Remote Access VPN</name>
        <t>The following example shows a point-to-network VPN setup, where a client
receives a set of local addresses and can send to any remote host through the
IP proxy. Such VPN setups can be either full-tunnel or split-tunnel.</t>
        <figure anchor="diagram-tunnel">
          <name>VPN Tunnel Setup</name>
          <artset>
            <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1"  viewBox="0 0 768 128" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px">
                <path d="M 8,32 L 8,96" fill="none" stroke="black"/>
                <path d="M 80,32 L 80,96" fill="none" stroke="black"/>
                <path d="M 248,32 L 248,96" fill="none" stroke="black"/>
                <path d="M 320,32 L 320,96" fill="none" stroke="black"/>
                <path d="M 416,32 L 416,96" fill="none" stroke="black"/>
                <path d="M 8,32 L 80,32" fill="none" stroke="black"/>
                <path d="M 248,32 L 320,32" fill="none" stroke="black"/>
                <path d="M 416,32 L 448,32" fill="none" stroke="black"/>
                <path d="M 80,48 L 248,48" fill="none" stroke="black"/>
                <path d="M 192,64 L 216,64" fill="none" stroke="black"/>
                <path d="M 320,64 L 448,64" fill="none" stroke="black"/>
                <path d="M 80,80 L 248,80" fill="none" stroke="black"/>
                <path d="M 8,96 L 80,96" fill="none" stroke="black"/>
                <path d="M 248,96 L 320,96" fill="none" stroke="black"/>
                <path d="M 416,96 L 448,96" fill="none" stroke="black"/>
                <polygon class="arrowhead" points="456,96 444,90.4 444,101.6" fill="black" transform="rotate(0,448,96)"/>
                <polygon class="arrowhead" points="456,64 444,58.4 444,69.6" fill="black" transform="rotate(0,448,64)"/>
                <polygon class="arrowhead" points="456,32 444,26.4 444,37.6" fill="black" transform="rotate(0,448,32)"/>
                <polygon class="arrowhead" points="224,64 212,58.4 212,69.6" fill="black" transform="rotate(0,216,64)"/>
                <polygon class="arrowhead" points="200,64 188,58.4 188,69.6" fill="black" transform="rotate(180,192,64)"/>
                <g class="text">
                  <text x="100" y="36">IP</text>
                  <text x="120" y="36">A</text>
                  <text x="212" y="36">IP</text>
                  <text x="232" y="36">B</text>
                  <text x="468" y="36">IP</text>
                  <text x="488" y="36">D</text>
                  <text x="284" y="52">IP</text>
                  <text x="340" y="52">IP</text>
                  <text x="360" y="52">C</text>
                  <text x="44" y="68">Client</text>
                  <text x="100" y="68">IP</text>
                  <text x="140" y="68">Subnet</text>
                  <text x="176" y="68">C</text>
                  <text x="232" y="68">?</text>
                  <text x="288" y="68">Proxy</text>
                  <text x="468" y="68">IP</text>
                  <text x="488" y="68">E</text>
                  <text x="468" y="100">IP</text>
                  <text x="496" y="100">...</text>
                </g>
              </svg>
            </artwork>
            <artwork type="ascii-art"><![CDATA[
+--------+ IP A          IP B +--------+           +---> IP D
|        +--------------------+   IP   | IP C      |
| Client | IP Subnet C <--> ? |  Proxy +-----------+---> IP E
|        +--------------------+        |           |
+--------+                    +--------+           +---> IP ...

]]></artwork>
          </artset>
        </figure>
        <t>In this case, the client does not specify any scope in its request. The IP
proxy assigns the client an IPv4 address (192.0.2.11) and a full-tunnel route
of all IPv4 addresses (0.0.0.0/0). The client can then send to any IPv4 host
using its assigned address as its source address.</t>
        <figure anchor="fig-full-tunnel">
          <name>VPN Full-Tunnel Example</name>
          <artwork><![CDATA[
[[ From Client ]]             [[ From IP Proxy ]]

SETTINGS
  H3_DATAGRAM = 1

                              SETTINGS
                                ENABLE_CONNECT_PROTOCOL = 1
                                H3_DATAGRAM = 1

STREAM(44): HEADERS
:method = CONNECT
:protocol = connect-ip
:scheme = https
:path = /vpn
:authority = proxy.example.com
capsule-protocol = ?1

                              STREAM(44): HEADERS
                              :status = 200
                              capsule-protocol = ?1

STREAM(44): DATA
Capsule Type = ADDRESS_REQUEST
(Request ID = 1
 IP Version = 4
 IP Address = 0.0.0.0
 IP Prefix Length = 32)

                              STREAM(44): DATA
                              Capsule Type = ADDRESS_ASSIGN
                              (Request ID = 1
                               IP Version = 4
                               IP Address = 192.0.2.11
                               IP Prefix Length = 32)

                              STREAM(44): DATA
                              Capsule Type = ROUTE_ADVERTISEMENT
                              (IP Version = 4
                               Start IP Address = 0.0.0.0
                               End IP Address = 255.255.255.255
                               IP Protocol = 0) // Any

DATAGRAM
Quarter Stream ID = 11
Context ID = 0
Payload = Encapsulated IP Packet

                              DATAGRAM
                              Quarter Stream ID = 11
                              Context ID = 0
                              Payload = Encapsulated IP Packet
]]></artwork>
        </figure>
        <t>A setup for a split-tunnel VPN (the case where the client can only access a
specific set of private subnets) is quite similar. In this case, the advertised
route is restricted to 192.0.2.0/24, rather than 0.0.0.0/0.</t>
        <figure anchor="fig-split-tunnel">
          <name>VPN Split-Tunnel Example</name>
          <artwork><![CDATA[
[[ From Client ]]             [[ From IP Proxy ]]

                              STREAM(44): DATA
                              Capsule Type = ADDRESS_ASSIGN
                              (Request ID = 0
                               IP Version = 4
                               IP Address = 192.0.2.42
                               IP Prefix Length = 32)

                              STREAM(44): DATA
                              Capsule Type = ROUTE_ADVERTISEMENT
                              (IP Version = 4
                               Start IP Address = 192.0.2.0
                               End IP Address = 192.0.2.41
                               IP Protocol = 0) // Any
                              (IP Version = 4
                               Start IP Address = 192.0.2.43
                               End IP Address = 192.0.2.255
                               IP Protocol = 0) // Any
]]></artwork>
        </figure>
      </section>
      <section anchor="site-to-site-vpn">
        <name>Site-to-Site VPN</name>
        <t>The following example shows how to connect a branch office network to a
corporate network such that all machines on those networks can communicate. In
this example, the IP proxying client is attached to the branch office network
192.0.2.0/24, and the IP proxy is attached to the corporate network
203.0.113.0/24. There are legacy clients on the branch office network that only
allow maintenance requests from machines on their subnet, so the IP proxy is
provisioned with an IP address from that subnet.</t>
        <figure anchor="diagram-s2s">
          <name>Site-to-Site VPN Example</name>
          <artset>
            <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 700 128" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px">
                <path d="M 112,32 L 112,96" fill="none" stroke="black"/>
                <path d="M 144,32 L 144,96" fill="none" stroke="black"/>
                <path d="M 216,32 L 216,96" fill="none" stroke="black"/>
                <path d="M 328,32 L 328,96" fill="none" stroke="black"/>
                <path d="M 392,32 L 392,96" fill="none" stroke="black"/>
                <path d="M 424,32 L 424,96" fill="none" stroke="black"/>
                <path d="M 88,32 L 112,32" fill="none" stroke="black"/>
                <path d="M 144,32 L 216,32" fill="none" stroke="black"/>
                <path d="M 328,32 L 392,32" fill="none" stroke="black"/>
                <path d="M 424,32 L 456,32" fill="none" stroke="black"/>
                <path d="M 216,48 L 328,48" fill="none" stroke="black"/>
                <path d="M 88,64 L 144,64" fill="none" stroke="black"/>
                <path d="M 392,64 L 456,64" fill="none" stroke="black"/>
                <path d="M 216,80 L 328,80" fill="none" stroke="black"/>
                <path d="M 88,96 L 112,96" fill="none" stroke="black"/>
                <path d="M 144,96 L 216,96" fill="none" stroke="black"/>
                <path d="M 328,96 L 392,96" fill="none" stroke="black"/>
                <path d="M 424,96 L 456,96" fill="none" stroke="black"/>
                <polygon class="arrowhead" points="464,96 452,90.4 452,101.6" fill="black" transform="rotate(0,456,96)"/>
                <polygon class="arrowhead" points="464,64 452,58.4 452,69.6" fill="black" transform="rotate(0,456,64)"/>
                <polygon class="arrowhead" points="464,32 452,26.4 452,37.6" fill="black" transform="rotate(0,456,32)"/>
                <polygon class="arrowhead" points="96,96 84,90.4 84,101.6" fill="black" transform="rotate(180,88,96)"/>
                <polygon class="arrowhead" points="96,64 84,58.4 84,69.6" fill="black" transform="rotate(180,88,64)"/>
                <polygon class="arrowhead" points="96,32 84,26.4 84,37.6" fill="black" transform="rotate(180,88,32)"/>
                <g class="text">
                  <text x="40" y="36">192.0.2.1</text>
                  <text x="512" y="36">203.0.113.9</text>
                  <text x="356" y="52">IP</text>
                  <text x="40" y="68">192.0.2.2</text>
                  <text x="180" y="68">Client</text>
                  <text x="236" y="68">IP</text>
                  <text x="284" y="68">Proxying</text>
                  <text x="360" y="68">Proxy</text>
                  <text x="512" y="68">203.0.113.8</text>
                  <text x="40" y="100">192.0.2.3</text>
                  <text x="512" y="100">203.0.113.7</text>
                </g>
              </svg>
            </artwork>
            <artwork type="ascii-art"><![CDATA[
192.0.2.1 <--+   +--------+             +-------+   +---> 203.0.113.9
             |   |        +-------------+  IP   |   |
192.0.2.2 <--+---+ Client | IP Proxying | Proxy +---+---> 203.0.113.8
             |   |        +-------------+       |   |
192.0.2.3 <--+   +--------+             +-------+   +---> 203.0.113.7

]]></artwork>
          </artset>
        </figure>
        <t>In this case, the client does not specify any scope in its request. The IP
proxy assigns the client an IPv4 address (203.0.113.100) and a split-tunnel
route to the corporate network (203.0.113.0/24). The client assigns the IP
proxy an IPv4 address (192.0.2.200) and a split-tunnel route to the branch
office network (192.0.2.0/24). This allows hosts on both networks to
communicate with each other and allows the IP proxy to perform maintenance on
legacy hosts in the branch office. Note that IP proxying endpoints will
decrement the IP Hop Count (or TTL) when encapsulating forwarded packets, so
protocols that require that field be set to 255 will not function.</t>
        <figure anchor="fig-s2s">
          <name>Site-to-Site VPN Capsule Example</name>
          <artwork><![CDATA[
[[ From Client ]]             [[ From IP Proxy ]]

SETTINGS
  H3_DATAGRAM = 1

                              SETTINGS
                                ENABLE_CONNECT_PROTOCOL = 1
                                H3_DATAGRAM = 1

STREAM(44): HEADERS
:method = CONNECT
:protocol = connect-ip
:scheme = https
:path = /corp
:authority = proxy.example.com
capsule-protocol = ?1

                              STREAM(44): HEADERS
                              :status = 200
                              capsule-protocol = ?1

STREAM(44): DATA
Capsule Type = ADDRESS_ASSIGN
(Request ID = 0
IP Version = 4
IP Address = 192.0.2.200
IP Prefix Length = 32)

STREAM(44): DATA
Capsule Type = ROUTE_ADVERTISEMENT
(IP Version = 4
Start IP Address = 192.0.2.0
End IP Address = 192.0.2.255
IP Protocol = 0) // Any

                              STREAM(44): DATA
                              Capsule Type = ADDRESS_ASSIGN
                              (Request ID = 0
                               IP Version = 4
                               IP Address = 203.0.113.100
                               IP Prefix Length = 32)

                              STREAM(44): DATA
                              Capsule Type = ROUTE_ADVERTISEMENT
                              (IP Version = 4
                               Start IP Address = 203.0.113.0
                               End IP Address = 203.0.113.255
                               IP Protocol = 0) // Any

DATAGRAM
Quarter Stream ID = 11
Context ID = 0
Payload = Encapsulated IP Packet

                              DATAGRAM
                              Quarter Stream ID = 11
                              Context ID = 0
                              Payload = Encapsulated IP Packet
]]></artwork>
        </figure>
      </section>
      <section anchor="ip-flow-forwarding">
        <name>IP Flow Forwarding</name>
        <t>The following example shows an IP flow forwarding setup, where a client
requests to establish a forwarding tunnel to target.example.com using the Stream Control Transmission Protocol (SCTP) (IP
protocol 132) and receives a single local address and remote address it can
use for transmitting packets. A similar approach could be used for any other IP
protocol that isn't easily proxied with existing HTTP methods, such as ICMP,
Encapsulating Security Payload (ESP), etc.</t>
        <figure anchor="diagram-flow">
          <name>Proxied Flow Setup</name>
          <artset>
            <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1"  viewBox="0 0 660 128" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px">
                <path d="M 8,32 L 8,96" fill="none" stroke="black"/>
                <path d="M 80,32 L 80,96" fill="none" stroke="black"/>
                <path d="M 240,32 L 240,96" fill="none" stroke="black"/>
                <path d="M 312,32 L 312,96" fill="none" stroke="black"/>
                <path d="M 8,32 L 80,32" fill="none" stroke="black"/>
                <path d="M 240,32 L 312,32" fill="none" stroke="black"/>
                <path d="M 80,48 L 240,48" fill="none" stroke="black"/>
                <path d="M 160,64 L 184,64" fill="none" stroke="black"/>
                <path d="M 312,64 L 392,64" fill="none" stroke="black"/>
                <path d="M 80,80 L 240,80" fill="none" stroke="black"/>
                <path d="M 8,96 L 80,96" fill="none" stroke="black"/>
                <path d="M 240,96 L 312,96" fill="none" stroke="black"/>
                <polygon class="arrowhead" points="400,64 388,58.4 388,69.6" fill="black" transform="rotate(0,392,64)"/>
                <polygon class="arrowhead" points="192,64 180,58.4 180,69.6" fill="black" transform="rotate(0,184,64)"/>
                <polygon class="arrowhead" points="168,64 156,58.4 156,69.6" fill="black" transform="rotate(180,160,64)"/>
                <g class="text">
                  <text x="100" y="36">IP</text>
                  <text x="120" y="36">A</text>
                  <text x="204" y="36">IP</text>
                  <text x="224" y="36">B</text>
                  <text x="276" y="52">IP</text>
                  <text x="332" y="52">IP</text>
                  <text x="352" y="52">C</text>
                  <text x="44" y="68">Client</text>
                  <text x="124" y="68">IP</text>
                  <text x="144" y="68">C</text>
                  <text x="200" y="68">D</text>
                  <text x="280" y="68">Proxy</text>
                  <text x="412" y="68">IP</text>
                  <text x="432" y="68">D</text>
                </g>
              </svg>
            </artwork>
            <artwork type="ascii-art"><![CDATA[
+--------+ IP A         IP B +--------+
|        +-------------------+   IP   | IP C
| Client |    IP C <--> D    |  Proxy +---------> IP D
|        +-------------------+        |
+--------+                   +--------+

]]></artwork>
          </artset>
        </figure>
        <t>In this case, the client specifies both a target hostname and an Internet Protocol
Number in the scope of its request, indicating that it only needs to
communicate with a single host. The IP proxy is able to perform DNS resolution
on behalf of the client and allocate a specific outbound socket for the client
instead of allocating an entire IP address to the client. In this regard, the
request is similar to a regular CONNECT proxy request.</t>
        <t>The IP proxy assigns a single IPv6 address to the client (2001:db8:1234::a) and
a route to a single IPv6 host (2001:db8:3456::b) scoped to SCTP. The client
can send and receive SCTP IP packets to the remote host.</t>
        <figure anchor="fig-flow">
          <name>Proxied SCTP Flow Example</name>
          <artwork><![CDATA[
[[ From Client ]]             [[ From IP Proxy ]]

SETTINGS
  H3_DATAGRAM = 1

                              SETTINGS
                                ENABLE_CONNECT_PROTOCOL = 1
                                H3_DATAGRAM = 1

STREAM(44): HEADERS
:method = CONNECT
:protocol = connect-ip
:scheme = https
:path = /proxy?target=target.example.com&ipproto=132
:authority = proxy.example.com
capsule-protocol = ?1

                              STREAM(44): HEADERS
                              :status = 200
                              capsule-protocol = ?1

                              STREAM(44): DATA
                              Capsule Type = ADDRESS_ASSIGN
                              (Request ID = 0
                               IP Version = 6
                               IP Address = 2001:db8:1234::a
                               IP Prefix Length = 128)

                              STREAM(44): DATA
                              Capsule Type = ROUTE_ADVERTISEMENT
                              (IP Version = 6
                               Start IP Address = 2001:db8:3456::b
                               End IP Address = 2001:db8:3456::b
                               IP Protocol = 132)

DATAGRAM
Quarter Stream ID = 11
Context ID = 0
Payload = Encapsulated SCTP/IP Packet

                              DATAGRAM
                              Quarter Stream ID = 11
                              Context ID = 0
                              Payload = Encapsulated SCTP/IP Packet
]]></artwork>
        </figure>
      </section>
      <section anchor="proxied-connection-racing">
        <name>Proxied Connection Racing</name>
        <t>The following example shows a setup where a client is proxying UDP packets
through an IP proxy in order to control connection establishment racing through
an IP proxy, as defined in Happy Eyeballs <xref target="RFC8305"/>. This example is a
variant of the proxied flow but highlights how IP-level proxying can enable
new capabilities, even for TCP and UDP.</t>
        <figure anchor="diagram-racing">
          <name>Proxied Connection Racing Setup</name>
          <artset>
            <artwork type="svg"><svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 708 144" class="diagram" text-anchor="middle" font-family="monospace" font-size="13px">
                <path d="M 8,32 L 8,112" fill="none" stroke="black"/>
                <path d="M 80,32 L 80,112" fill="none" stroke="black"/>
                <path d="M 240,32 L 240,112" fill="none" stroke="black"/>
                <path d="M 312,32 L 312,112" fill="none" stroke="black"/>
                <path d="M 8,32 L 80,32" fill="none" stroke="black"/>
                <path d="M 240,32 L 312,32" fill="none" stroke="black"/>
                <path d="M 80,48 L 240,48" fill="none" stroke="black"/>
                <path d="M 320,48 L 424,48" fill="none" stroke="black"/>
                <path d="M 144,64 L 168,64" fill="none" stroke="black"/>
                <path d="M 144,80 L 168,80" fill="none" stroke="black"/>
                <path d="M 80,96 L 240,96" fill="none" stroke="black"/>
                <path d="M 320,96 L 424,96" fill="none" stroke="black"/>
                <path d="M 8,112 L 80,112" fill="none" stroke="black"/>
                <path d="M 240,112 L 312,112" fill="none" stroke="black"/>
                <polygon class="arrowhead" points="432,96 420,90.4 420,101.6" fill="black" transform="rotate(0,424,96)"/>
                <polygon class="arrowhead" points="432,48 420,42.4 420,53.6" fill="black" transform="rotate(0,424,48)"/>
                <polygon class="arrowhead" points="328,96 316,90.4 316,101.6" fill="black" transform="rotate(180,320,96)"/>
                <polygon class="arrowhead" points="328,48 316,42.4 316,53.6" fill="black" transform="rotate(180,320,48)"/>
                <polygon class="arrowhead" points="176,80 164,74.4 164,85.6" fill="black" transform="rotate(0,168,80)"/>
                <polygon class="arrowhead" points="176,64 164,58.4 164,69.6" fill="black" transform="rotate(0,168,64)"/>
                <polygon class="arrowhead" points="152,80 140,74.4 140,85.6" fill="black" transform="rotate(180,144,80)"/>
                <polygon class="arrowhead" points="152,64 140,58.4 140,69.6" fill="black" transform="rotate(180,144,64)"/>
                <g class="text">
                  <text x="100" y="36">IP</text>
                  <text x="120" y="36">A</text>
                  <text x="204" y="36">IP</text>
                  <text x="224" y="36">B</text>
                  <text x="332" y="36">IP</text>
                  <text x="352" y="36">C</text>
                  <text x="444" y="52">IP</text>
                  <text x="464" y="52">E</text>
                  <text x="44" y="68">Client</text>
                  <text x="108" y="68">IP</text>
                  <text x="128" y="68">C</text>
                  <text x="184" y="68">E</text>
                  <text x="276" y="68">IP</text>
                  <text x="128" y="84">D</text>
                  <text x="184" y="84">F</text>
                  <text x="280" y="84">Proxy</text>
                  <text x="444" y="100">IP</text>
                  <text x="464" y="100">F</text>
                  <text x="332" y="116">IP</text>
                  <text x="352" y="116">D</text>
                </g>
              </svg>
            </artwork>
            <artwork type="ascii-art"><![CDATA[
+--------+ IP A         IP B +--------+ IP C
|        +-------------------+        |<------------> IP E
| Client |  IP C <--> E      |   IP   |
|        |     D <--> F      |  Proxy |
|        +-------------------+        |<------------> IP F
+--------+                   +--------+ IP D

]]></artwork>
          </artset>
        </figure>
        <t>As with proxied flows, the client specifies both a target hostname and an Internet
Protocol Number in the scope of its request. When the IP proxy performs DNS
resolution on behalf of the client, it can send the various remote address
options to the client as separate routes. It can also ensure that the client
has both IPv4 and IPv6 addresses assigned.</t>
        <t>The IP proxy assigns both an IPv4 address (192.0.2.3) and an IPv6
address (2001:db8:1234::a) to the client, as well as an IPv4 route
(198.51.100.2) and an IPv6 route (2001:db8:3456::b), which represent the
resolved addresses of the target hostname, scoped to UDP. The client can send
and receive UDP IP packets to either one of the IP proxy addresses to enable
Happy Eyeballs through the IP proxy.</t>
        <figure anchor="fig-listen">
          <name>Proxied Connection Racing Example</name>
          <artwork><![CDATA[
[[ From Client ]]             [[ From IP Proxy ]]

SETTINGS
  H3_DATAGRAM = 1

                              SETTINGS
                                ENABLE_CONNECT_PROTOCOL = 1
                                H3_DATAGRAM = 1

STREAM(44): HEADERS
:method = CONNECT
:protocol = connect-ip
:scheme = https
:path = /proxy?target=target.example.com&ipproto=17
:authority = proxy.example.com
capsule-protocol = ?1

                              STREAM(44): HEADERS
                              :status = 200
                              capsule-protocol = ?1

                              STREAM(44): DATA
                              Capsule Type = ADDRESS_ASSIGN
                              (Request ID = 0
                               IP Version = 4
                               IP Address = 192.0.2.3
                               IP Prefix Length = 32),
                              (Request ID = 0
                               IP Version = 6
                               IP Address = 2001:db8::1234:1234
                               IP Prefix Length = 128)

                              STREAM(44): DATA
                              Capsule Type = ROUTE_ADVERTISEMENT
                              (IP Version = 4
                               Start IP Address = 198.51.100.2
                               End IP Address = 198.51.100.2
                               IP Protocol = 17),
                              (IP Version = 6
                               Start IP Address = 2001:db8:3456::b
                               End IP Address = 2001:db8:3456::b
                               IP Protocol = 17)
...

DATAGRAM
Quarter Stream ID = 11
Context ID = 0
Payload = Encapsulated IPv6 Packet

DATAGRAM
Quarter Stream ID = 11
Context ID = 0
Payload = Encapsulated IPv4 Packet

]]></artwork>
        </figure>
      </section>
    </section>
    <section anchor="extensibility-considerations">
      <name>Extensibility Considerations</name>
      <t>Extensions to IP proxying in HTTP can define behavior changes to this
mechanism. Such extensions <bcp14>SHOULD</bcp14> define new capsule types to exchange
configuration information if needed.  
It is <bcp14>RECOMMENDED</bcp14> for extensions that
modify addressing to specify that their extension capsules be sent before the
ADDRESS_ASSIGN capsule and that they do not take effect until the
ADDRESS_ASSIGN capsule is parsed. This allows modifications to address
assignment to operate atomically. Similarly, extensions that modify routing
<bcp14>SHOULD</bcp14> behave similarly with regard to the ROUTE_ADVERTISEMENT capsule.</t>
    </section>
    <section anchor="performance-considerations">
      <name>Performance Considerations</name>
      <t>Bursty traffic can often lead to temporally correlated packet losses; in turn,
this can lead to suboptimal responses from congestion controllers in protocols
running inside the tunnel. To avoid this, IP proxying endpoints <bcp14>SHOULD</bcp14> strive
to avoid increasing burstiness of IP traffic; they <bcp14>SHOULD NOT</bcp14> queue packets in
order to increase batching beyond the minimal amount required to take advantage
of hardware offloads.</t>
      <t>When the protocol running inside the tunnel uses congestion control (e.g.,
<xref target="RFC9293"/> or <xref target="RFC9000"/>), the proxied traffic will incur at least two nested
congestion controllers. When tunneled packets are sent using QUIC DATAGRAM
frames, the outer HTTP connection <bcp14>MAY</bcp14> disable congestion control for those
packets that contain only QUIC DATAGRAM frames encapsulating IP packets.
Implementers will benefit from reading the guidance in <xref section="3.1.11" sectionFormat="of" target="RFC8085"/>.</t>
      <t>When the protocol running inside the tunnel uses loss recovery (e.g., <xref target="RFC9293"/>
or <xref target="RFC9000"/>) and the outer HTTP connection runs over TCP, the proxied traffic
will incur at least two nested loss recovery mechanisms. This can reduce
performance, as both can sometimes independently retransmit the same data. To
avoid this, IP proxying <bcp14>SHOULD</bcp14> be performed over HTTP/3 to allow leveraging the
QUIC DATAGRAM frame.</t>
      <section anchor="mtu-considerations">
        <name>MTU Considerations</name>
        <t>When using HTTP/3 with the QUIC Datagram extension <xref target="RFC9221"/>, IP packets are
transmitted in QUIC DATAGRAM frames. Since these frames cannot be fragmented,
they can only carry packets up to a given length determined by the QUIC
connection configuration and the Path MTU (PMTU). If an endpoint is using QUIC
DATAGRAM frames and it attempts to route an IP packet through the tunnel that
will not fit inside a QUIC DATAGRAM frame, the IP proxy <bcp14>SHOULD NOT</bcp14> send the IP
packet in a DATAGRAM capsule, as that defeats the end-to-end unreliability
characteristic that methods such as Datagram Packetization Layer PMTU Discovery
(DPLPMTUD) depend on <xref target="RFC8899"/>. In this scenario, the endpoint
<bcp14>SHOULD</bcp14> drop the IP packet and send an ICMP Packet Too Big message to the sender
of the dropped packet; see <xref section="3.2" sectionFormat="of" target="RFC4443"/>.</t>
      </section>
      <section anchor="ecn-considerations">
        <name>ECN Considerations</name>  
        <t>If an IP proxying endpoint with a connection containing an IP proxying request
stream disables congestion control, it cannot signal Explicit Congestion
Notification (ECN) <xref target="RFC3168"/> support on that outer connection. That is,
the QUIC sender <bcp14>MUST</bcp14> mark all IP headers with the Not ECN-Capable Transport (Not-ECT) codepoint for QUIC
packets that are outside of congestion control. The endpoint can still report
ECN feedback via QUIC ACK_ECN frames or the TCP ECN-Echo (ECE) bit, as the peer might not
have disabled congestion control.</t>
        <t>Conversely, if congestion control is not disabled on the outer congestion, the
guidance in <xref target="RFC6040"/> about transferring ECN marks between inner
and outer IP headers does not apply because the outer connection will react
correctly to congestion notifications if it uses ECN. The inner traffic can
also use ECN, independently of whether it is in use on the outer connection.</t>
      </section>
      <section anchor="dscp-considerations">
        <name>Differentiated Services Considerations</name>
        <t>Tunneled IP packets can have Differentiated Services Code Points (DSCPs)
<xref target="RFC2474"/> set in the traffic class IP header field to request a
particular per-hop behavior. If an IP proxying endpoint is configured as part
of a Differentiated Services domain, it <bcp14>MAY</bcp14> implement traffic differentiation
based on these markings. However, the use of HTTP can limit the possibilities
for differentiated treatment of the tunneled IP packets on the path between the
IP proxying endpoints.</t>
        <t>When an HTTP connection is congestion-controlled, marking packets with
different DSCPs can lead to reordering between them, and that can in turn lead
the underlying transport connection's congestion controller to perform poorly.
If tunneled packets are subject to congestion control by the outer connection,
they need to avoid carrying DSCP markings that are not equivalent in forwarding
behavior to prevent this situation. In this scenario, the IP proxying endpoint
<bcp14>MUST NOT</bcp14> copy the DSCP field from the inner IP header to the outer IP header of
the packet carrying this packet. Instead, an application would need to use
separate connections to the proxy, one for each DSCP. Note that this document
does not define a way for requests to scope to particular DSCP values; such
support is left to future extensions.</t>
        <t>If tunneled packets use QUIC datagrams and are not subject to congestion
control by the outer connection, the IP proxying endpoints <bcp14>MAY</bcp14> translate the
DSCP field value from the tunneled traffic to the outer IP header. IP proxying
endpoints <bcp14>MUST NOT</bcp14> coalesce multiple inner packets into the same outer packet
unless they have the same DSCP marking or an equivalent traffic class. Note
that the ability to translate DSCP values is dependent on the tunnel ingress
and egress belonging to the same Differentiated Service domain or not.</t>
      </section>
    </section>
    <section anchor="security-considerations">
      <name>Security Considerations</name>
      <t>There are significant risks in allowing arbitrary clients to establish a tunnel
that permits sending to arbitrary hosts, regardless of whether tunnels are
scoped to specific hosts or not. Bad actors could abuse this capability to send
traffic and have it attributed to the IP proxy. HTTP servers that support IP
proxying <bcp14>SHOULD</bcp14> restrict its use to authenticated users. Depending on the
deployment, possible authentication mechanisms include mutual TLS between IP
proxying endpoints, HTTP-based authentication via the HTTP Authorization header
<xref target="RFC9110"/>, or even bearer tokens. Proxies can enforce policies for authenticated
users to further constrain client behavior or deal with possible abuse. For
example, proxies can rate limit individual clients that send an excessively
large amount of traffic through the proxy. As another example, proxies can
restrict address (prefix) assignment to clients based on certain client
attributes, such as geographic location.</t>
      <t>Address assignment can have privacy implications for endpoints. For example, if
a proxy partitions its address space by the number of authenticated clients and
then assigns distinct address ranges to each client, target hosts could use
this information to determine when IP packets correspond to the same client.
Avoiding such tracking vectors may be important for certain proxy deployments.
Proxies <bcp14>SHOULD</bcp14> avoid persistent per-client address (prefix) assignment when
possible.</t>
      <t>Falsifying IP source addresses in sent traffic has been common for denial-of-service 
attacks. Implementations of this mechanism need to ensure that they do
not facilitate such attacks. In particular, there are scenarios where an
endpoint knows that its peer is only allowed to send IP packets from a given
prefix. For example, that can happen through out-of-band configuration
information or when allowed prefixes are shared via ADDRESS_ASSIGN capsules.
In such scenarios, endpoints <bcp14>MUST</bcp14> follow the recommendations from
<xref target="RFC2827"/> to prevent source address spoofing.</t>
      <t>Limiting request scope (see <xref target="scope"/>) allows two clients to share one of the
proxy's external IP addresses if their requests are scoped to different Internet
Protocol Numbers. If the proxy receives an ICMP packet destined for that
external IP address, it has the option to forward it back to the clients.
However, some of these ICMP packets carry part of the original IP packet that
triggered the ICMP response. Forwarding such packets can accidentally divulge
information about one client's traffic to another client. To avoid this,
proxies that forward ICMP on shared external IP addresses <bcp14>MUST</bcp14> inspect the
invoking packet included in the ICMP packet and only forward the ICMP packet to
the client whose scoping matches the invoking packet.</t>
      <t>Implementers will benefit from reading the guidance in
<xref target="RFC6169"/>. Since there are known risks with some IPv6
extension headers (e.g., <xref target="RFC5095"/>), implementers need to follow
the latest guidance regarding handling of IPv6 extension headers.</t>
      <t>Transferring DSCP markings from inner to outer packets (see
<xref target="dscp-considerations"/>) exposes end-to-end flow level information to an
on-path observer between the IP proxying endpoints. This can potentially expose
a single end-to-end flow. Because of this, such use of DSCPs in
privacy-sensitive contexts is <bcp14>NOT RECOMMENDED</bcp14>.</t>
      <t>Opportunistic sending of IP packets (see <xref target="link-operation"/>) is not allowed
in HTTP/1.x because a server could reject the HTTP Upgrade and
attempt to parse the IP packets as a subsequent HTTP request,
allowing request smuggling attacks; see <xref target="I-D.schwartz-httpbis-optimistic-upgrade"/>.  In particular,
an intermediary that re-encodes a request from HTTP/2 or 3 to
HTTP/1.1 <bcp14>MUST NOT</bcp14> forward any received capsules until it has parsed a
successful IP proxying response.
      </t>
    </section>
    <section anchor="iana-considerations">
      <name>IANA Considerations</name>
      <section anchor="http-upgrade-token">
        <name>HTTP Upgrade Token Registration</name>
        <t>IANA has registered "connect-ip" in the "HTTP Upgrade
Tokens" registry maintained at
<eref target="https://www.iana.org/assignments/http-upgrade-tokens" brackets="angle"/>.</t>

<dl spacing="compact" newline="false">
           <dt>Value:</dt>
          <dd>
            <t>connect-ip</t>
          </dd>
          <dt>Description:</dt>
          <dd>
            <t>Proxying of IP Payloads</t>
          </dd>
          <dt>Expected Version Tokens:</dt>
          <dd>
            <t>None</t>
          </dd>
          <dt>References:</dt>
          <dd>
            <t>RFC 9484</t>
          </dd>
        </dl>
      </section>
      <section anchor="iana-suffix">
        <name>MASQUE URI Suffixes Registry Creation</name>
        <t>IANA has created the "MASQUE URI Suffixes" registry 
maintained at <eref target="https://www.iana.org/assignments/masque" brackets="angle"/>. The registration policy is Expert Review; see <xref section="4.5" sectionFormat="of" target="RFC8126"/>. This new registry governs the path segment that
immediately follows "masque" in paths that start with "/.well-known/masque/";
see <eref target="https://www.iana.org/assignments/well-known-uris" brackets="angle"/> for the registration
of "masque" in the "Well-Known URIs" registry.</t>

<t>This new registry contains three
columns:</t>
        <dl spacing="compact" newline="false">
          <dt>Path Segment:</dt>
          <dd>
            <t>An ASCII string containing only characters allowed in tokens; see
<xref section="5.6.2" sectionFormat="of" target="RFC9110"/>. Entries in this registry <bcp14>MUST</bcp14> all have distinct
entries in this column.</t>
          </dd>
          <dt>Description:</dt>
          <dd>
            <t>A description of the entry.</t>
          </dd>
          <dt>Reference:</dt>
          <dd>
            <t>An optional reference defining the use of the entry.</t>
          </dd>
        </dl>
        <t>The registry's initial entries are as follows:</t>
        <table anchor="iana-suffixes-table">
          <name>MASQUE URI Suffixes Registry</name>
          <thead>
            <tr>
              <th align="left">Path Segment</th>
              <th align="left">Description</th>
              <th align="left">Reference</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="left">udp</td>
              <td align="left">UDP Proxying</td>
              <td align="left">RFC 9298</td>
            </tr>
            <tr>
              <td align="left">ip</td>
              <td align="left">IP Proxying</td>
              <td align="left">RFC 9484</td>
            </tr>
          </tbody>
        </table>
        <t>Designated experts for this registry are advised that they should approve all
requests as long as the expert believes that both (1) the requested Path
Segment will not conflict with existing or expected future IETF work and (2)
the use case is relevant to proxying.</t>
      </section>
      <section anchor="iana-uri">
        <name>Updates to masque Well-Known URI Registration</name>
        <t>IANA has updated the entry for the "masque"
URI suffix in the "Well-Known URIs" registry maintained at
<eref target="https://www.iana.org/assignments/well-known-uris" brackets="angle"/>.</t>
        <t>IANA has updated the "Reference" field to include this
document and has replaced the "Related Information" field with
"For sub-suffix allocations, see the registry at <eref target="https://www.iana.org/assignments/masque" brackets="angle"/>.".</t>

      </section>
      <section anchor="iana-types">
        <name>HTTP Capsule Types Registrations</name>
        <t>IANA has added the following values to the "HTTP Capsule
Types" registry maintained at
<eref target="https://www.iana.org/assignments/masque" brackets="angle"/>.</t>

       <table anchor="iana-capsules-table">
          <name>New Capsules</name>
          <thead>
            <tr>
              <th align="left">Value</th>
              <th align="left">Capsule Type</th>
            </tr>
          </thead>
          <tbody>
            <tr>
              <td align="left">0x01</td>
              <td align="left">ADDRESS_ASSIGN</td>
            </tr>
            <tr>
              <td align="left">0x02</td>
              <td align="left">ADDRESS_REQUEST</td>
            </tr>
            <tr>
              <td align="left">0x03</td>
              <td align="left">ROUTE_ADVERTISEMENT</td>
            </tr>
          </tbody>
        </table>

        <t>All of these new entries use the following values for these fields:</t>
        <dl spacing="compact" newline="false">
        <dt>Status:</dt>
          <dd>
            <t>permanent</t>
          </dd>
          <dt>Reference:</dt>
          <dd>
            <t>RFC 9484</t>
          </dd>
          <dt>Change Controller:</dt>
          <dd>
            <t>IETF</t>
          </dd>
          <dt>Contact:</dt>
          <dd>
            <t>masque@ietf.org</t>
          </dd>
          <dt>Notes:</dt>
          <dd>
            <t>None</t>
          </dd>
        </dl>

      </section>
    </section>
  </middle>
  <back>

    <displayreference target="RFC9112" to="HTTP/1.1"/>
    <displayreference target="RFC9113" to="HTTP/2"/>
    <displayreference target="RFC9114" to="HTTP/3"/>
    <displayreference target="RFC9110" to="HTTP"/>
    <displayreference target="RFC9293" to="TCP"/>
    <displayreference target="RFC6570" to="TEMPLATE"/>
    <displayreference target="RFC9297" to="HTTP-DGRAM"/>
    <displayreference target="RFC8441" to="EXT-CONNECT2"/>
    <displayreference target="RFC9220" to="EXT-CONNECT3"/>
    <displayreference target="RFC9000" to="QUIC"/>
    <displayreference target="RFC3986" to="URI"/>
    <displayreference target="RFC9209" to="PROXY-STATUS"/>
    <displayreference target="RFC5234" to="ABNF"/>
    <displayreference target="RFC8200" to="IPv6"/>
    <displayreference target="RFC9221" to="DGRAM"/>
    <displayreference target="RFC0792" to="ICMP"/>
    <displayreference target="RFC4443" to="ICMPv6"/>
    <displayreference target="RFC3168" to="ECN"/>
    <displayreference target="RFC2474" to="DSCP"/>
    <displayreference target="RFC2827" to="BCP38"/>
    <displayreference target="RFC8126" to="IANA-POLICY"/>
    <displayreference target="RFC9298" to="CONNECT-UDP"/>
    <displayreference target="RFC4291" to="IPv6-ADDR"/>
    <displayreference target="RFC4301" to="IPSEC"/>
    <displayreference target="RFC8305" to="HEv2"/>
    <displayreference target="RFC8085" to="UDP-USAGE"/>
    <displayreference target="RFC8899" to="DPLPMTUD"/>
    <displayreference target="RFC6040" to="ECN-TUNNEL"/>
    <displayreference target="RFC6169" to="TUNNEL-SECURITY"/>
    <displayreference target="RFC5095" to="ROUTING-HDR"/>
    <displayreference target="I-D.ietf-masque-ip-proxy-reqs" to="PROXY-REQS"/>
    <displayreference target="RFC6874" to="IPv6-ZONE-ID"/>
    <displayreference target="I-D.schwartz-httpbis-optimistic-upgrade" to="OPTIMISTIC"/>
    <references>
      <name>References</name>
      <references>
        <name>Normative References</name>

<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9112.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9113.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9114.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9110.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9293.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6570.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9297.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8441.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9220.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2119.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8174.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9000.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3986.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9209.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6874.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5234.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8200.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9221.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.0792.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4443.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.3168.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2474.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.2827.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8126.xml"/>

      </references>
      <references>
        <name>Informative References</name>
        <reference anchor="IANA-PN" target="https://www.iana.org/assignments/protocol-numbers">
          <front>
            <title>Protocol Numbers</title>
            <author>
              <organization>IANA</organization>
            </author>
          </front>
        </reference>


<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.9298.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4291.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.4301.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8305.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8085.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.8899.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6040.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.6169.xml"/>
<xi:include href="https://bib.ietf.org/public/rfc/bibxml/reference.RFC.5095.xml"/>
<xi:include href="https://datatracker.ietf.org/doc/bibxml3/reference.I-D.ietf-masque-ip-proxy-reqs.xml"/>
<xi:include href="https://datatracker.ietf.org/doc/bibxml3/reference.I-D.schwartz-httpbis-optimistic-upgrade.xml"/>

      </references>
    </references>
    <section numbered="false" anchor="acknowledgments">
      <name>Acknowledgments</name>
      <t>The design of this method was inspired by discussions in the MASQUE Working
Group around <xref target="I-D.ietf-masque-ip-proxy-reqs"/>. The authors would
like to thank participants in those discussions for their feedback.
Additionally, <contact fullname="Mike Bishop"/>, <contact fullname="Lucas Pardue"/>, and <contact fullname="Alejandro Sedeño"/>
provided valuable feedback on the document.</t>
      <t>Most of the text on client configuration is based on the corresponding text in
<xref target="RFC9298"/>.</t>
    </section>
  </back>
</rfc>
