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
Section 3.2 of [
HTTP-DGRAM]) with HTTP Datagrams in the format defined in
Section 6.
To initiate an IP tunnel associated with a single HTTP stream, a client issues a request containing the "connect-ip" upgrade token.
When sending its IP proxying request, the client
SHALL perform URI Template expansion to determine the path and query of its request; see
Section 3.
By virtue of the definition of the Capsule Protocol (see
Section 3.2 of [
HTTP-DGRAM]), IP proxying requests do not carry any message content. Similarly, successful IP proxying responses also do not carry any message content.
IP proxying over HTTP
MUST be operated over TLS or QUIC encryption, or another equivalent encryption protocol, to provide confidentiality, integrity, and authentication.
Upon receiving an IP proxying request:
-
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).
-
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.
IP proxies
MUST validate whether the decoded "target" and "ipproto" variables meet the requirements in
Section 4.6. If they do not, the IP proxy
MUST treat the request as malformed; see
Section 8.1.1 of [
HTTP/2] and
Section 4.1.2 of [
HTTP/3]. If the "target" variable is a DNS name, the IP proxy
MUST 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
MUST reject the request and
SHOULD send details using an appropriate Proxy-Status header field [
PROXY-STATUS]. For example, if DNS resolution returns an error, the proxy can use the
dns_error proxy error type from
Section 2.3.2 of [
PROXY-STATUS].
The lifetime of the IP forwarding tunnel is tied to the IP proxying request stream. The IP proxy
MUST maintain all IP address and route assignments associated with the IP forwarding tunnel while the request stream is open. IP proxies
MAY choose to tear down the tunnel due to a period of inactivity, but they
MUST close the request stream when doing so.
A successful IP proxying response (as defined in Sections [
4.3] and [
4.5]) 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
MUST abort the request.
Along with a successful IP proxying response, the IP proxy can send capsules to assign addresses and advertise routes to the client (
Section 4.7). The client can also assign addresses and advertise routes to the IP proxy for network-to-network routing.
When using HTTP/1.1 [
HTTP/1.1], an IP proxying request will meet the following requirements:
-
The method SHALL be "GET".
-
The request SHALL include a single Host header field containing the host and optional port of the IP proxy.
-
The request SHALL include a Connection header field with value "Upgrade" (note that this requirement is case-insensitive, as per Section 7.6.1 of [HTTP]).
-
The request SHALL include an Upgrade header field with value "connect-ip".
An IP proxying request that does not conform to these restrictions is malformed. The recipient of such a malformed request
MUST respond with an error and
SHOULD use the 400 (Bad Request) status code.
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:
GET https://example.org/.well-known/masque/ip/*/*/ HTTP/1.1
Host: example.org
Connection: Upgrade
Upgrade: connect-ip
Capsule-Protocol: ?1
The server indicates a successful IP proxying response by replying with the following requirements:
-
The HTTP status code on the response SHALL be 101 (Switching Protocols).
-
The response SHALL include a Connection header field with value "Upgrade" (note that this requirement is case-insensitive, as per Section 7.6.1 of [HTTP]).
-
The response SHALL include a single Upgrade header field with value "connect-ip".
-
The response SHALL meet the requirements of HTTP responses that start the Capsule Protocol; see Section 3.2 of [HTTP-DGRAM].
If any of these requirements are not met, the client
MUST treat this proxying attempt as failed and close the connection.
For example, the server could respond with:
HTTP/1.1 101 Switching Protocols
Connection: Upgrade
Upgrade: connect-ip
Capsule-Protocol: ?1
When using HTTP/2 [
HTTP/2] or HTTP/3 [
HTTP/3], IP proxying requests use HTTP Extended CONNECT. This requires that servers send an HTTP Setting, as specified in [
EXT-CONNECT2] and [
EXT-CONNECT3], and that requests use HTTP pseudo-header fields with the following requirements:
-
The :method pseudo-header field SHALL be "CONNECT".
-
The :protocol pseudo-header field SHALL be "connect-ip".
-
The :authority pseudo-header field SHALL contain the authority of the IP proxy.
-
The :path and :scheme pseudo-header fields SHALL NOT be empty. Their values SHALL contain the scheme and path from the URI Template after the URI Template expansion process has been completed; see Section 3. 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 Section 4.6.
An IP proxying request that does not conform to these restrictions is malformed; see
Section 8.1.1 of [
HTTP/2] and
Section 4.1.2 of [
HTTP/3].
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:
HEADERS
:method = CONNECT
:protocol = connect-ip
:scheme = https
:path = /.well-known/masque/ip/*/*/
:authority = example.org
capsule-protocol = ?1
The server indicates a successful IP proxying response by replying with the following requirements:
-
The HTTP status code on the response SHALL be in the 2xx (Successful) range.
-
The response SHALL meet the requirements of HTTP responses that start the Capsule Protocol; see Section 3.2 of [HTTP-DGRAM].
If any of these requirements are not met, the client
MUST 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.
For example, the server could respond with:
HEADERS
:status = 200
capsule-protocol = ?1
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.
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
Section 3. Both the "target" and "ipproto" variables are optional; if they are not included, they are considered to carry the wildcard value "*".
-
target:
-
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 [IPv6-ZONE-ID] 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 SHOULD 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.
-
ipproto:
-
The variable "ipproto" contains an Internet Protocol Number; see the defined list in the "Assigned Internet Protocol Numbers" IANA registry [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.
Using the terms IPv6address, IPv4address, and reg-name from [
URI], the "target" and "ipproto" variables
MUST adhere to the format in
Figure 6, using notation from [
ABNF]. Additionally:
-
If "target" contains an IPv6 literal or prefix, the colons (":") MUST 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".
-
If present, the IP prefix length in "target" SHALL be preceded by a percent-encoded slash ("/"): "%2F". The IP prefix length MUST represent a decimal integer between 0 and the length of the IP address in bits, inclusive.
-
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 MUST all be set to 0.
-
"ipproto" MUST represent a decimal integer between 0 and 255 inclusive or the wildcard value "*".
target = IPv6prefix / IPv4prefix / reg-name / "*"
IPv6prefix = IPv6address ["%2F" 1*3DIGIT]
IPv4prefix = IPv4address ["%2F" 1*2DIGIT]
ipproto = 1*3DIGIT / "*"
IP proxies
MAY 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.
This document defines multiple new capsule types that allow endpoints to exchange IP configuration information. Both endpoints
MAY send any number of these new capsules.
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.
ADDRESS_ASSIGN Capsule {
Type (i) = 0x01,
Length (i),
Assigned Address (..) ...,
}
The ADDRESS_ASSIGN capsule contains a sequence of zero or more Assigned Addresses.
Assigned Address {
Request ID (i),
IP Version (8),
IP Address (32..128),
IP Prefix Length (8),
}
Each Assigned Address contains the following fields:
-
Request ID:
-
Request identifier, encoded as a variable-length integer. If this address assignment is in response to an Address Request (see Section 4.7.2), then this field SHALL contain the value of the corresponding field in the request. Otherwise, this field SHALL be zero.
-
IP Version:
-
IP Version of this address assignment, encoded as an unsigned 8-bit integer. It MUST be either 4 or 6.
-
IP Address:
-
Assigned IP address. If the IP Version field has value 4, the IP Address field SHALL have a length of 32 bits. If the IP Version field has value 6, the IP Address field SHALL have a length of 128 bits.
-
IP Prefix Length:
-
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 MUST 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 MUST all be set to 0.
If any of the capsule fields are malformed upon reception, the receiver of the capsule
MUST follow the error-handling procedure defined in
Section 3.3 of [
HTTP-DGRAM].
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.
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 (
Section 8.1), the client cannot send IP packets until it knows what address to use. In these deployments, the endpoint that is expecting an address assignment
MUST 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.
While ADDRESS_ASSIGN capsules are commonly sent in response to ADDRESS_REQUEST capsules, endpoints
MAY send ADDRESS_ASSIGN capsules unprompted.
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.
ADDRESS_REQUEST Capsule {
Type (i) = 0x02,
Length (i),
Requested Address (..) ...,
}
The ADDRESS_REQUEST capsule contains a sequence of one or more Requested Addresses.
Requested Address {
Request ID (i),
IP Version (8),
IP Address (32..128),
IP Prefix Length (8),
}
Each Requested Address contains the following fields:
-
Request ID:
-
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 MUST NOT be reused by an endpoint and MUST NOT be zero.
-
IP Version:
-
IP Version of this address request, encoded as an unsigned 8-bit integer. It MUST be either 4 or 6.
-
IP Address:
-
Requested IP address. If the IP Version field has value 4, the IP Address field SHALL have a length of 32 bits. If the IP Version field has value 6, the IP Address field SHALL have a length of 128 bits.
-
IP Prefix Length:
-
Length of the IP Prefix requested in bits, encoded as an unsigned 8-bit integer. It MUST 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 MUST all be set to 0.
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.
If any of the capsule fields are malformed upon reception, the receiver of the capsule
MUST follow the error-handling procedure defined in
Section 3.3 of [
HTTP-DGRAM].
Upon receiving the ADDRESS_REQUEST capsule, an endpoint
SHOULD 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
SHALL 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
SHALL be set to the assigned values. If the requested address was not assigned, the IP address
SHALL be all-zero, and the IP Prefix Length
SHALL be the maximum length (0.0.0.0/32 or ::/128) to indicate that no address was assigned. These address rejections
SHOULD NOT 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.
If an endpoint receives an ADDRESS_REQUEST capsule that contains zero Requested Addresses, it
MUST abort the IP proxying request stream.
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.
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.
ROUTE_ADVERTISEMENT Capsule {
Type (i) = 0x03,
Length (i),
IP Address Range (..) ...,
}
The ROUTE_ADVERTISEMENT capsule contains a sequence of zero or more IP Address Ranges.
IP Address Range {
IP Version (8),
Start IP Address (32..128),
End IP Address (32..128),
IP Protocol (8),
}
Each IP Address Range contains the following fields:
-
IP Version:
-
IP Version of this range, encoded as an unsigned 8-bit integer. It MUST be either 4 or 6.
-
Start IP Address and End IP Address:
-
Inclusive start and end IP address of the advertised range. If the IP Version field has value 4, these fields SHALL have a length of 32 bits. If the IP Version field has value 6, these fields SHALL have a length of 128 bits. The Start IP Address MUST be less than or equal to the End IP Address.
-
IP Protocol:
-
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.
If any of the capsule fields are malformed upon reception, the receiver of the capsule
MUST follow the error-handling procedure defined in
Section 3.3 of [
HTTP-DGRAM].
Upon receiving the ROUTE_ADVERTISEMENT capsule, an endpoint
MAY 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.
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.
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
MUST follow these requirements:
-
The IP Version of A MUST be less than or equal to the IP Version of B.
-
If the IP Version of A and B are equal, the IP Protocol of A MUST be less than or equal to the IP Protocol of B.
-
If the IP Version and IP Protocol of A and B are both equal, the End IP Address of A MUST be strictly less than the Start IP Address of B.
If an endpoint receives a ROUTE_ADVERTISEMENT capsule that does not meet these requirements, it
MUST abort the IP proxying request stream.
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
MUST NOT send a ROUTE_ADVERTISEMENT capsule with routes that overlap in such a way. Validating this requirement is
OPTIONAL, but if an endpoint detects the violation, it
MUST abort the IP proxying request stream.
Both request scoping (see
Section 4.6) and the ROUTE_ADVERTISEMENT capsule (see
Section 4.7.3) use Internet Protocol Numbers. These numbers represent both upper layers (as defined in
Section 2 of [
IPv6], with examples that include TCP and UDP) and IPv6 extension headers (as defined in
Section 4 of [
IPv6], with examples that include Fragment and Options headers). IP proxies
MAY 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
MUST 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 (
Section 4.3 of [
IPv6]).