Subject: Is CONNECT hop-by-hop?

From: Alex Rousskov <[email-masked]>
Date: Fri, 19 Apr 2019 14:20:30 -0600

Hello,

    Imagine two chained proxies. When a child proxy receives a CONNECT
request, and must go through the parent proxy, is the child supposed to
forward the end-to-end CONNECT headers (e.g., User-Agent and X-Foo)?

Different specs seem to imply different answers:

1. RFC 7231 section 4.3.6 and draft-ietf-httpbis-semantics say that the
child should be "forwarding the CONNECT request to the next inbound
proxy". So the answer to my question may be "yes" because, by default,
message "forwarding" implies forwarding end-to-end headers.

2. Mozilla documentation[1] says that CONNECT is a "hop-by-hop method".
While that phrasing may be using non-standard terminology, the implied
answer to my question is "no" because hop-by-hop things are not
forwarded by default.

3. RFC 7540 section 8.3 seems to prohibit chaining CONNECT tunnels
because it says that the CONNECT recipient `establishes a TCP connection
to the server identified in the ":authority" pseudo-header field`. If
"TCP connection" here is interpreted literally, then establishing that
TCP connection from the child proxy to an origin server is impossible
when there is a parent proxy involved. The answer to my question is,
hence, "undefined behavior".

[1] https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/CONNECT

The correct answer probably depends on whether the CONNECT is a
hop-by-hop mechanism. Mozilla got it right if the CONNECT request is
meant specifically for the proxy at the next hop. HTTP/1 got it right if
CONNECT is meant for all proxies in the chain.

Should a compliant HTTP proxy forward regular end-to-end CONNECT headers
to the next proxy?

Thank you,

Alex.
P.S. I understand that the proxy may decide to send some of the received
CONNECT headers it knows about even if the compliant behavior is "hop by
hop". Such purposeful relaying/replicating does not violate the
hop-by-hop principle, of course. The question is essentially about the
end-to-end CONNECT headers that the proxy does not want to treat specially.

---

From: Lucas Pardue <[email-masked]>
Date: Fri, 19 Apr 2019 23:06:18 +0100

Hi Alex,

This is an interesting thread. You raise some questions that I had not
thought of. It seems like a good time to tighten up language.

I think that the "open a TCP connection" view is the most accurate thing
here. And so the final hop, from last proxy to origin will never have a way
to express such "end-to-end" headers. Proxies, in the role of client, that
are configured to use a proxy would use their own user agent and
authentication.

I'd considered the chaining case in HTTP/2 but just taken for granted that
a proxy that has it's own *HTTP proxy* configured would attempt to use it
when opening TCP connections to the indicated authority. This seems like a
reasonable assumption to make for HTTP proxies. I'm sure there might be
other ways a proxy might choose to tunnel, like SOCKS, but that is down to
local configuration.

Note that HTTP/3 also defines CONNECT to behave like RFC 7540. This raises
some challenges for tunnelling HTTP/3, which is one of the driving use
cases in the HiNT I-D [1].

Cheers
Lucas

[1]
https://datatracker.ietf.org/doc/draft-pardue-httpbis-http-network-tunnelling/

---

From: Alex Rousskov <[email-masked]>
Date: Fri, 19 Apr 2019 17:42:42 -0600

On 4/19/19 4:06 PM, Lucas Pardue wrote:

> here. And so the final hop, from last proxy to origin will never have a
> way to express such "end-to-end" headers.

CONNECT ends at proxies, so, in this context, "end-to-end" (*if* it is
going to be confirmed as the right model) would mean
client-to-the-last-proxy, not client-to-origin. The second "end" is the
last proxy in the chain here, not the origin server. Thus, "end-to-end"
semantics can be considered valid/applicable.

> Proxies, in the role of
> client, that are configured to use a proxy would use their own user
> agent and authentication. 

Please note that HTTP authentication is a red herring in this context --
Proxy-Authenticate is already documented as a hop-by-hop mechanism.
Nothing we discuss here will change that.

> I'd considered the chaining case in HTTP/2 but just taken for granted
> that a proxy that has it's own *HTTP proxy* configured would attempt to
> use it when opening TCP connections to the indicated authority.

AFAICT, HTTP/2 specs prohibit such use (possibly accidentally). I agree
that such prohibition seems unnatural -- most people would probably
"take for granted" that chained tunnels are allowed and should be supported.

> Note that HTTP/3 also defines CONNECT to behave like RFC 7540.

Yes, both HTTP/2 and HTTP/3 give "undefined behavior" answers.

> This
> raises some challenges for tunnelling HTTP/3, which is one of the
> driving use cases in the HiNT I-D [1].
> [1] https://datatracker.ietf.org/doc/draft-pardue-httpbis-http-network-tunnelling/

Hopefully, if there is consensus regarding CONNECT forwarding on this
mailing list, then draft-ietf-httpbis-semantics, HTTP/3 [errata], and
your draft can express it.

Alex.

---

From: Willy Tarreau <[email-masked]>
Date: Sat, 20 Apr 2019 07:53:49 +0200

Hi Alex,

> Should a compliant HTTP proxy forward regular end-to-end CONNECT headers

I have a different view on this. In my opinion CONNECT is indeed hop by
hop, but if it ends on proxy which itself is configured to use another
forward proxy instead of connecting directly to the net, then this second
proxy will likely emit another CONNECT request to that proxy. Of course
both requests might end up being the same, but if you look at authentication
headers, the ones from the first request are there to authenticate on the
first proxy. The second proxy might need a hard-coded authentication in
order to pass through the second proxy, and will likely use its own auth
headers, unless it is configured to pass credentials verbatim.

I find that it's easier to see it as a demand by the client to establish
a clear data path to the TCP endpoint mentioned in the authority. The
client doesn't care how intermediaries split the work, if they use other
CONNECT between them, if one relies on SOCKS, or even use RFC1149, provided
the last element in the chain reaches this endpoint.

Regards,
Willy

---

From: Amos Jeffries <[email-masked]>
Date: Sat, 20 Apr 2019 18:51:53 +1200

> forward the end-to-end CONNECT headers (e.g., User-Agent and X-Foo)?
...
> Should a compliant HTTP proxy forward regular end-to-end CONNECT headers

I think this is incorrectly mixing two independent principles here.

The method hop-by-hop (or not) refers to the HTTP-message. Which can be
just the request-line or status-line values. That is the minimal
HTTP-message per RFC7230 section 3.

RFC 7230 section 3.2.1 is what you/we need to be using as the definitive
default forward/remove guidance on "regular" headers. Except where the
headers own more-specific definition overrides that with a requirement
about forwarding or removal.

This section 3.2.1 requirements do not rely on the hop-by-hop (or not)
nature of CONNECT, but on whether there is any next-hop HTTP-message to
relay the relevant end-to-end headers on.

So IMO the issue is not whether CONNECT is hop-by-hop, but whether the
intermediary is mapping the CONNECT to TCP directly or to another
HTTP-message. If it is to another HTTP-message (eg CONNECT to a peer)
the end-to-end headers still apply to that (non-)payload sent to the
next-hop, the hop-by-hop headers do not.

Amos

---

From: Andy Green <[email-masked]>
Date: Sat, 20 Apr 2019 08:06:21 +0100

> next-hop, the hop-by-hop headers do not.

Reading from the perspective of "how does RFC8441 'CONNECT upgrade'" fit 
into this, that sounds right.

When using CONNECT to upgrade an h2 stream to another protocol, it's 
definitely not hop-by-hop since it's informing the endpoint, and anyone 
inbetween that might care, that it wants to change the stream protocol 
in an arbitrary way... an intermediary cannot eat and conceal from 
downstream nodes say a change from http to ws, they are too different.

What Willy says sounds right too... downstream intermediaries may not 
participate in the same auth scheme as the proxy the peer initially 
connects to.

Is it enough to say that CONNECT is end-to-end except if an intermediary 
assertively recognizes hop-to-hop related headers aimed at itself it 
should snip?

-Andy

---

From: "Poul-Henning Kamp" <[email-masked]>
Date: Sat, 20 Apr 2019 07:09:12 +0000

--------
In message <[email-masked]>, Amos Jeffries 

>next-hop, the hop-by-hop headers do not.

My understanding:

Client sends CONNECT to proxy1

Proxy1 interprets this as "Please open TCP connection to ____"

If Proxy1 is configured to always use Proxy2, the only way Proxy1
can serve this request, is by sending a CONNECT to proxy2.

If my understanding is correct, then CONNECT is hop-by-hop, but
depending on the proxy configuration, CONNECTs may be chained until
some proxy in the chain is allowed/can do the direct TCP connection.

-- 
Poul-Henning Kamp       | UNIX since Zilog Zeus 3.20
[email-masked]         | TCP/IP since RFC 956
FreeBSD committer       | BSD since 4.3-tahoe    
Never attribute to malice what can adequately be explained by incompetence.

---

From: Alex Rousskov <[email-masked]>
Date: Sun, 21 Apr 2019 10:09:40 -0600

On 4/19/19 2:20 PM, Alex Rousskov wrote:
>> When a child proxy receives a CONNECT

I regret using a short and catchy subject line! My misleading subject
derailed the discussion away from the actual question (quoted above)
into the muddy waters of lesser terminology battles. Sorry.

AFAICT after distilling the responses, the consensus so far is "yes, the
child proxy should forward end-to-end CONNECT headers (e.g., User-Agent
and X-Foo) in the CONNECT request it sends to the parent proxy".

If you think that the child proxy should _not_ forward end-to-end
CONNECT headers such as User-Agent and X-Foo, please say so.

Thank you,

Alex.