Original text:
<del> The CONNECT-UDP HTTP Method </del>  draft-ietf-masque-connect-udp-latest Abstract <del> This document describes the CONNECT-UDP HTTP method.  CONNECT-UDP is similar to the HTTP CONNECT method, but it uses UDP instead of TCP. </del>  1. <del> This document describes the CONNECT-UDP HTTP method.  CONNECT-UDP is similar to the HTTP CONNECT method (see section 4.3.6 of RFC7231), but it uses UDP UDP instead of TCP TCP. </del>  1.1. as shown here. In this document, we use the term "proxy" to refer to the HTTP server <del> that opens the UDP socket and responds to the CONNECT-UDP request. If there are HTTP intermediaries (as defined in Section 2.3 of RFC7230) between the client and the proxy, those are referred to as </del>  "intermediaries" in this document.  2. <del> The CONNECT-UDP method is defined for all versions of HTTP.  UDP payloads are sent using HTTP Datagrams HTTP-DGRAM.  Note that, when the HTTP version in use does not support multiplexing streams (such as HTTP/1.1), then any reference to "stream" in this document is meant to represent the entire connection. </del>  3. <del> The CONNECT-UDP method requests that the recipient establish a tunnel over a single HTTP stream to the destination origin server identified by the request-target and, if successful, thereafter restrict its behavior to blind forwarding of packets, in both directions, until the tunnel is closed.  Tunnels are commonly used to create an end-to- end virtual connection, which can then be secured using QUIC QUIC or another protocol running over UDP. </del>  <del> The request-target of a CONNECT-UDP request is a URI RFC3986 which uses the "masque" scheme and an immutable path of "/".  For example: </del>  <del> When using HTTP/2 H2 or later, CONNECT-UDP requests use HTTP pseudo- headers with the following requirements: </del>  <del> The ":method" pseudo-header field is set to "CONNECT-UDP". </del>  <del> The ":scheme" pseudo-header field is set to "masque". </del>  <del> The ":path" pseudo-header field is set to "/". </del>  <del> The ":authority" pseudo-header field contains the host and port to connect to (similar to the authority-form of the request-target of CONNECT requests; see RFC7230, Section 5.3). </del>  <del> A CONNECT-UDP request that does not conform to these restrictions is malformed (see H2, Section 8.1.2.6). </del>  <del> The recipient proxy establishes a tunnel by directly opening a UDP socket to the request-target.  Any 2xx (Successful) response indicates that the proxy has opened a socket to the request-target and is willing to proxy UDP payloads.  Any response other than a successful response indicates that the tunnel has not yet been formed. </del>  <del> A proxy MUST NOT send any Transfer-Encoding or Content-Length header fields in a 2xx (Successful) response to CONNECT-UDP.  A client MUST treat a response to CONNECT-UDP containing any Content-Length or Transfer-Encoding header fields as malformed. </del>  <del> A payload within a CONNECT-UDP request message has no defined semantics; a CONNECT-UDP request with a non-empty payload is malformed. </del>  <del> Responses to the CONNECT-UDP method are not cacheable. </del>  4. UDP packets are encoded using HTTP Datagrams HTTP-DGRAM.  The payload of a UDP packet (referred to as "data octets" in UDP) is sent unmodified in the "HTTP Datagram Payload" field of an HTTP Datagram. <del> In order to use HTTP Datagrams, the CONNECT-UDP client will first decide whether or not to use HTTP Datagram Contexts and then register its context ID (or lack thereof) using the corresponding registration capsule, see HTTP-DGRAM. Since HTTP Datagrams require prior negotiation (for example, in HTTP/3 it is necessary to both send and receive the H3_DATAGRAM SETTINGS Parameter), clients MUST NOT send any HTTP Datagrams until they have established support on a given connection. The proxy that is creating the UDP socket to the destination responds to the CONNECT-UDP request with a 2xx (Successful) response. </del>  Clients MAY optimistically start sending proxied UDP packets before <del> receiving the response to its CONNECT-UDP request, noting however </del>  that those may not be processed by the proxy if it responds to the <del> CONNECT-UDP request with a failure, or if the datagrams arrive before the CONNECT-UDP request. </del>  <del> Extensions to CONNECT-UDP MAY leverage the "Context Extensions" field of registration capsules in order to negotiate different semantics or encoding for UDP payloads. </del>  5. <del> Unlike TCP, UDP is connection-less.  The proxy that opens the UDP socket has no way of knowing whether the destination is reachable. Therefore it needs to respond to the CONNECT-UDP request without waiting for a TCP SYN-ACK. Proxies can use connected UDP sockets if their operating system supports them, as that allows the proxy to rely on the kernel to only send it UDP packets that match the correct 5-tuple.  If the proxy uses a non-connected socket, it MUST validate the IP source address and UDP source port on received packets to ensure they match the client's CONNECT-UDP request.  Packets that do not match MUST be discarded by the proxy. The lifetime of the socket is tied to the CONNECT-UDP stream.  The proxy MUST keep the socket open while the CONNECT-UDP stream is open. Proxies MAY choose to close sockets due to a period of inactivity, but they MUST close the CONNECT-UDP stream before closing the socket. If a proxy is notified by its operating system that its socket is no longer usable, it MUST close the CONNECT-UDP stream. 6. </del> Proxies SHOULD strive to avoid increasing burstiness of UDP traffic: they SHOULD NOT queue packets in order to increase batching. control unless it has an out-of-band way of knowing with absolute certainty that the inner traffic is congestion-controlled. <del> If a client or proxy with a connection containing a CONNECT-UDP stream disables congestion control, it MUST NOT signal ECN support on that connection.  That is, it MUST mark all IP headers with the Not- ECT codepoint.  It MAY continue to report ECN feedback via ACK_ECN frames, as the peer may not have disabled congestion control. </del>  When the protocol running over UDP that is being proxied uses loss recovery (e.g., QUIC), and the underlying HTTP connection runs over independently retransmit the same data.  To avoid this, HTTP/3 datagrams SHOULD be used. <del> 6.1. </del>  <del> CONNECT-UDP does not create an IP-in-IP tunnel, so the guidance in </del>  RFC6040 about transferring ECN marks between inner and outer IP <del> headers does not apply.  There is no inner IP header in CONNECT-UDP </del>  tunnels. <del> Note that CONNECT-UDP clients do not have the ability in this </del>  specification to control the ECN codepoints on UDP packets the proxy sends to the server, nor can proxies communicate the markings of each UDP packet from server to proxy. <del> A CONNECT-UDP proxy MUST ignore ECN bits in the IP header of UDP packets received from the server, and MUST set the ECN bits to Not- ECT on UDP packets it sends to the server.  These do not relate to the ECN markings of packets sent between client and proxy in any way. </del>  <del> 7. </del>  There are significant risks in allowing arbitrary clients to establish a tunnel to arbitrary servers, as that could allow bad actors to send traffic and have it attributed to the proxy.  Proxies <del> that support CONNECT-UDP SHOULD restrict its use to authenticated </del>  users. Because the CONNECT method creates a TCP connection to the target, the target has to indicate its willingness to accept TCP connections by responding with a TCP SYN-ACK before the proxy can send it <del> application data.  UDP doesn't have this property, so a CONNECT-UDP proxy could send more data to an unwilling target than a CONNECT proxy.  However, in practice denial of service attacks target open TCP ports so the TCP SYN-ACK does not offer much protection in real scenarios.  Proxies MUST NOT introspect the contents of UDP payloads as that would lead to ossification of UDP-based protocols by proxies. </del>  <del> 8. </del>  <del> 8.1. </del>  <del> This document will request IANA to register "CONNECT-UDP" in the HTTP Method Registry (IETF review) maintained at <<https://www.iana.org/assignments/http-methods>>. </del>  <del> 8.2. </del>  <del> This document will request IANA to register the URI scheme "masque". </del>  <del> The syntax definition below uses Augmented Backus-Naur Form (ABNF) RFC5234.  The definitions of "host" and "port" are adopted from RFC3986.  The syntax of a MASQUE URI is: </del>  <del> The "host" and "port" component MUST NOT be empty, and the "port" component MUST NOT be 0. </del> 

Reviewer comments:
As discussed on the list, there appears to be agreement to replace a custom method with extended CONNECT.
Some potential bikesheds/comments from (which generally looks good): 1) For HTTP/1.1, should the method be "GET" or "CONNECT"? WebSockets uses GET -- are there any uses of "Extended CONNECT" that use CONNECT rather than GET? 2) Should the default URI template have a /.well-known prefix? For example, "/.well-known/masque/udp/{targethost}/{targetport}/" ? 3) Should the upgrade token be "connect-udp" or "masque-udp" ?
Great questions, but let's keep one issue per topic, I've opened , , and to track these individual points.
With the switch to use Extended CONNECT in for UDP, it seems logical to shift TCP to also use the same model. Two approaches would either be for a new draft (draft-ietf-masque-connect-tcp?), or to generalize the connect-udp draft since there is lots in-common given how things are now factored.
I was thinking about that when I wrote the PR and I agree
I'd worry accommodating TCP is scope creep for this draft. H2 and H3 CONNECT already support TCP. Extended CONNECT might be nicer but then we'd probably want text to explain why endpoints might choose one or another. That seems better suited to some other document to me right now. edit: I also think the HTTP WG could probably own that work
I'm realizing my "I agree" wasn't very specific, I meant: I agree that we should do the same for TCP. I didn't have a strong opinion for this draft vs a new draft, but based on URL I think a separate draft might be best
Yeah, this should probably be a separate draft, but defining connect-tcp would be nice to make things more parallel.
Closing this issue since we'll want to do this in a separate draft
draft 03 states indicates that the proxy has opened a socket to the request-target and is willing to proxy UDP payloads. Any response other than a successful response indicates that the tunnel has not yet been formed. the use of "not yet" seems a little hand waving. What's the intent of the statement, I think it would help to be more specific. We could presume that a non-final 1xx response could indicate that the tunnel is possibly yet to be created. Whereas a 4xx could mean that the client erred and that no tunnel is ever going to be created.
This text was lifted from the but I'm sure we can be even more clear. Can you propose some text?
touché Semantics still says it, so it must mean something URL But both the H2 and H3 definitions don't really do any handwaving and just say URL [RFC0793] to the server identified in the ":authority" pseudo- header field. Once this connection is successfully established, the proxy sends a HEADERS frame containing a 2xx series status code to the client, as defined in Section 15.3 of [SEMANTICS]. Since CONNECT-UDP is trying to cover all 3 known major versions, it has to be careful. If I had to write a PR, I might try to combine the most up to date Semantics text with H2/H3, and in the process drop this "not yet been fully formed" clause. However, maybe I'm missing something that HTTP WG aficionados will tell be is really important.
So I think it's pretty clear that 2xx means "yes send me your UDP" and 4xx/5xx means "nope don't send your UDP". I think the points that might need clarification are: are 1xx responses allowed? if 1xx is allowed, how does the client react? are 3xx allowed? if 3xx is allowed, how does the client react?
This was fixed by , closing.
So the URI scheme registration rules (URL) have a number of things to consider. Thus, at a minimal the definition needs its own section where that is properly covered. My experience is that the template and definition needs its own sections to make it easy to define clearly and know where things reside. I would also note that issue depending on the semantics is for masque scheme and how it relates to the proxied protocol it might make sense to split this scheme out into its own document even if it will be a short one.
Or, better yet, we don't define any scheme, and just use https for the CONNECT-UDP requests!
requires that CONNECT requests omit the pseudo-header: Why does this draft need to define a URI scheme and then include that in ? There are already two different definitions for URI scheme. Both seem - at least on face value - fairly sensible, but they both come with considerable baggage. The question I'd like to ask is whether this protocol even needs a URI scheme at all. My first inclination is very much that it does not.
I added the scheme because I thought it was required (and ), but maybe it isn't. Unfortunately, CONNECT-UDP is distinct from CONNECT, so it cannot benefit from the exception that CONNECT has. This is pretty explicit in : This means that, unlike CONNECT, CONNECT-UDP needs a URI reference. However, according to : So, if we go the route of I think we can legally say that CONNECT-UDP request targets are of the form and require the and pseudo-headers to not be sent. This would allow us to use URIs without schemes for CONNECT-UDP. Can someone who's more of an HTTP guru comment on this please? NAME NAME NAME
It's an intriguing approach, but I'm not sure it works. SEMANTICS 4.1 says: I don't see anywhere in SEMANTICS it specifies that a method's target URI can't be relative. However, for HTTP/1.1 at least: does not permit the use of relative URIs. Since support for this method is negotiated in SETTINGS for HTTP/2 and HTTP/3, it's possible for it to depart from the general requirements for which pseudo-headers to send and specify something that looks more like CONNECT (omit and , for example). However, I'm not convinced that can be generalized. NAME and NAME thoughts?
NAME support for CONNECT-UDP is not gated by a SETTINGS parameter. Only the datagram mode in h3 has a setting.
Ah, then it would need to include and pseudo-headers; I'm not sure off-hand if it's valid for those to be empty.
I think that I would prefer a setting. It's probably true that this doesn't require special handling, but there are intermediaries that do crazy things like buffer request bodies. A setting would avoid any potential for misunderstanding. It makes this unusable in HTTP/1.1, but I might see that as more of a feature than a bug.
I would strongly prefer to avoid a setting, as it breaks the use-case.
I tend to think that defining a URI scheme (perhaps not ) is the path of least resistance here, and I don't see any immediate harm in doing so. As a thought experiment, consider how the Web would work if CONNECT had a URI scheme; that would give a distinct way to convey proxy configuration, for example. Based on the above I also think we need to clarify in Semantics that a target-uri is always absolute, even if it is transmitted as a relative uri.
For your obfuscation goals, the client needs to initiate any feature detection and do so after or in parallel with authentication. So you're right, probably that precludes a setting unless you're using client certs to authenticate (which would itself be visible on a probe, though not clear evidence of Masque). Then I agree with NAME that your path of least resistance is to mint a scheme for a UDP connection. The fact that has been used to describe other services available over UDP is regrettable, since those services actually intended to convey certain protocol endpoints. In this instance, you are literally describing a UDP connection with no protocol-specific properties; I'd consider asking NAME if he'd be willing to have the provisional registration (which ) replaced by a permanent one that simply designates as describing a UDP endpoint without conveying application-layer protocol expectations.
Thinking about this some more, could we use the "https" scheme? I really like NAME to use a URI for proxy configuration, as that could allow future extensibility. and the "https" scheme there already maps TCP to the CONNECT method. I think it would make sense to have that also map UDP to CONNECT-UDP. And with that mindset, having the scheme sent over the wire as "https" seems natural, and bypasses the need to define a new URI scheme. Thoughts?
Can you explain a bit more please David? I'm vaguely familiar with Chrome's URI format of proxy configuration. I note that the link you provide also defines THR "quic" scheme. And I presume that it would be nice to ditch that some something more consistent. IIRC it is possible for a proxy identified by "http" or "https" schemes to offer H3 as an Alt-Svc. And then it's upon the client to decide how to tunnel requests through such a proxy that might be capable of talking CONNECT and CONNECT-UDP. If this is too far off tangent (because of discovery) , we don't need to explore it here.
NAME I totally agree with you, Chrome's "quic" scheme is historical and I think it should now be deprecated in favor of "https" (and rely on Alt-Svc to use h3). But yes this is somewhat of a tangent that we may want to discuss offline. I was simply trying to make the case that there was some sort of precedent to consider proxying using CONNECT as "https". Back to the scheme discussion, since the scheme carries no useful information on CONNECT-UDP requests, I'm proposing to simply use "https".
That all works for me. It doesn't adhere to any sort of architectural purity, but CONNECT has no hope of achieving that; hoping to include some notion of purity along other design constraints would only make things worse. I like the idea that you can just use "https" and work out the rest using the protocol negotiation tools we have (Alt-Svc, HTTPS, settings).
I think some discussion in this thread, but likely not fully what the intended semantics of the URI scheme should be. I think there are two basic ones that I can think of and the first one is: A) Use a MASQUE proxy to send packets to "target address" However, I would think that outside of the MASQUE protocol a more useful URI semantics would be: B) Use this MASQUE proxy to send traffic to this target address. I also think we have to take a step back and ask ourselves if MASQUE URI scheme implies UDP or it it should use parameters to encode which protocol that should be proxied over the MASQUE proxy? The other aspect in this country I think the A) semantics in the -03 connect-udp draft is that is it doesn't discuss the identity of the proxy. For the security aspect the MASQUE client need to know the identity of the proxy so that it can verify the initial H/3 connection to the MASQUE proxy.
Can we simply recommend using as the scheme, but allow clients to specify a different scheme if appropriate?
After discussion at the meeting, my understanding is that the target resource CONNECT-UDP might be an origin that speaks CONNECT-UDP, or it might be a 'raw' UDP endpoint. In the former case, a HTTPS schemed target URI makes sense; in the latter, something new is necessary (e.g., , if we can make that interoperable).
given that the authority component of an URI would not need to be aware of CONNECT-UDP, I am not sure that this reasoning for works for me. IOW, it implies that a new scheme is good. I think that is doubly burned already, unfortunately.
NAME if we required a new scheme for every new method introduced, we'd have some problems. Why is that necessary?
I wasn't arguing for anything in particular, just looking for you (or someone) to address the problem somehow.
Given that we don't care about the scheme for now, and want to make sure people ignore it on receipt, how about we do https:// by default, but say that clients SHOULD grease the scheme?
FWIW, I tend to think that we should omit scheme, path, and use SETTINGS for HTTP/2 and HTTP/3. As NAME points out, we have to make sure that servers unaware of CONNECT-UDP do not mishandle CONNECT-UDP requests. For HTTP/2 and /3, we can go with either using sending SETTINGS or send set to something else than or as well as sending a fake . But in HTTP/1, there's no way of sending a scheme, therefore, we'd have to use a connect-style request line (i.e. `CONNECT-UDP host:port HTTP/1.1). Otherwise, servers unaware of the method would handle it as an ordinary request. The latter point means that there's practical advantage in following the style of CONNECT method. Then, why not use a SETTINGS on H2 and H3 to minimize the difference between H1 and H2/H3?
It's actually legal to send a fully-qualified URI in HTTP/1.1; that's just not the common case when you're talking to an origin server. I don't think it's a problem to be considering a full URI for CONNECT-UDP in HTTP/1.1. Of course, if we know there's a lack of support for that form, that's a different issue.
NAME That's a good point. Regarding the concern that you point out, I'm not sure if that would actually be an issue because a request in absolute-URI form will be considered malformed and rejected by a server that only supports HTTP/1.0-style requests. However, there's the other failure mode, and that is servers ignoring the scheme. IIUC, most origin servers do not have the incentive to consult and reject requests based on the scheme. When I send to some host, I do see 200 responses, from servers hosted by large IaaS operators / multiple CDNsnote 1. When sending to those servers, I do see 4xx errors. Therefore, if we are to care about how existing HTTP/1.1 servers would respond to masque, I think that using the form of is going to provide us better results. note 1: I'd take part of the blame, because h2o simply drops the scheme when receiving an HTTP/1.1 request. I'm glad that we are not alone!
The more I'm thinking about this, the more I'm leaning towards the simplest solution: no SETTING, and simply use a scheme of . That works perfectly for everything we need, and carries the least complexity.
NAME I'm not sure if we'd be fine with the failure mode associated to that approach? HTTP servers (or applications) often buffer the entire request, before they start processing it. Even the method is being checked after all the request body is being received. When a client connects to such a server, sending a CONNECT-UDP request with an https URI, the server will hang forever, as the client never closes the request stream. Eventually, a timeout would kick in, but I do not think it's preferable to keep the client waiting until a timeout? Am I missing something, or is it the case that you are fine with relying on a timeout?
NAME thanks for clarifying - that's a good argument for a SETTING (at least in the server-to-client direction). However, I really dislike the idea that every new HTTP method needs its own SETTING... But apart from switching to extended CONNECT I'm not seeing a lot of alternate solutions.
None of this makes any sense. If you can't send a valid request, then this protocol does not belong anywhere near an HTTP stream. Figure out how to send a valid request or build your own protocol.
NAME how do you define a valid request? The issue here is that a CONNECT (or CONNECT-UDP) request is valid as far as our understanding of the HTTP specs, but that doesn't mean that servers handle them correctly - the important difference is that these requests are not followed by a FIN on the stream, and some servers don't handle that well, even if it's valid.
I have never met a server that didn't handle an HTTP request "well", for its own definition of well. A server that doesn't know the method will use the standard parsing algorithm and respond at the end of the header section with a 405 or 501, depending on taste. If you want that to be faster, send fewer header fields. This is not a concern in practice. There is no option to send host:port with CONNECT-UDP. That is not HTTP. Stop bringing it up. Obviously, sending a GET request to a server is not the same as sending CONNECT-UDP to a server. The two have entirely different backwards-compatibility algorithms. Likewise, sending an absolute URI within a CONNECT-UDP request works just fine for every server chain that might be expected to support such a request, and the response is going to be 501, 405, or 400 for those that don't. If you find a deployed server that evidences any other form of behavior, send the developers a bug report. The IETF is not the place to work around every possible fool's implementation of bad parsing. By the time you finish writing the spec, there will be at least three more ways to fail to implement that spec correctly. Focus instead on making it work for servers that implement HTTP correctly.
No HTTP requests are followed by a FIN on the stream. FIN is part of TCP. Clients do not half-close their sockets in HTTP/1.1 -- the end of a request is indicated by either the end of the header section or by the end of the request Content-Length's amount of data, and the server doesn't read past that until it looks for the next request (on a persistent connection). A server sends FIN after closing their end of the TCP connection. For HTTP/2 and HTTP/3, both requests and response occur within protocol frames. A FIN only occurs when the underlying connection breaks.
NAME my comment about the FIN was specific to HTTP/2+. With those versions, the client sends a FIN on the request stream when it is done sending the body (or the headers when there is no body) for non-CONNECT requests. Some servers have unfortunately come to expect that of all request types, leading to timeouts for CONNECT.
NAME I get your argument that sending CONNECT-style host:port is an act of breaking HTTP. Though, I would argue that if we are to stay within HTTP, we have to use a hop-by-hop opt-in mechanism for CONNECT-UDP, because it breaks existing assumption within HTTP that servers can wait for a complete request before processing it. To that end, I tend to believe that we have to do the following: For HTTP/2 and /3, use SETTINGS, like we did in RFC 8441. If we need support for HTTP/1.1, use upgrade, like we did in RFC 6455, RFC 7540. NAME We do not have to add a new SETTING parameter for every new type of tunnel. Assuming that we are fine with using SETTINGS, I tend to wonder if we could reuse RFC 8441. With that opt-in UDP tunnels can be created by using a CONNECT request (rather than a new method), with a scheme used for identifying that the payload is UDP datagrams?
There is no such assumption in HTTP. The request is complete when the header section is complete.
IOW, if a server doesn't start processing a request message as soon as the header section is complete, it cannot correctly implement Expect and it probably doesn't support request content delimited by Transfer-Encoding or Content-Length. HTTP is designed for infinite length content streams, so there are no cases where we assume a recipient will wait until the end of the message body before starting to process the request. There would be no distinction between that and a denial-of-service vulnerability.
NAME Sorry my phrasing was incorrect. What I meant to say was that HTTP does not assume servers to start sending a final response before receiving end of the stream . EDIT. After initially posting this comment, I realized that for HTTP/1.1, lack of CL or TE indicates that the end of request headers is the end of the request. But for HTTP/2 and HTTP/3, the method being CONNECT is the only indicator that changes where the request ends, isn't it?
FWIW, if all you need is something that is a valid URI (and the content does not matter), a URN might work perfectly well: urn:ietf:rfc:xxxx (see URL). (I think Ted Hardie mentioned this in the IETF meeting chat)
NAME mentioned elsewhere that a locator that identifies the server providing the connect tunnel would be much better than the current design, which effectively puts the target host as an authority. I'm not yet sure what I think of that, but it's an interesting thought worth considering.
Here is the example from NAME :
That specific example makes my RFC 8820 sense itch, but it's an OK illustration of the idea.
NAME do you have an alternate encoding that would appease your itch?
With the https scheme, we might be able to use a URI template (which might lead to that exact example if people so chose). Or we could define a new scheme...
NAME pointed out that draft-pauly-dprive-oblivious-doh does something similar. It may make sense to have some consistency. Maybe: (perhaps adjusting the path somehow, or using a URI template?)
I like the idea of keeping the https scheme and using the path to convey the target
No need to abuse .well-known when we can use a URI template.
URL in something using curly brackets...?
URL
So something like ?
That would be an easy way of doing it. Or .
But that would be an invalid path.
Would it be invalid after RFC 6570 substitution?
After substitution is of course ok. So where do you want to put the template?
The template goes the same place you might put a URL. Right now, that is configuration.
Ah, I thought you wanted to put it into the ":path" pseudo header.
Closely related to this is whether: 1) Use a method per protocol (CONNECT-UDP, CONNECT-IP, etc) 2) Use a new common method (eg, CONNECTX) with protocol in either a pseudoheader or path component 3) Use Extended CONNECT with a ":protocol" psuedoheader Given all of the baggage with CONNECT, I'd lean towards (2)
(This issue probably wants a more general name covering the set of interrelated topics here.)
NAME As said at the meeting, to avoid intermediaries unaware of masque waiting for FIN before doing anything, I think it would be a good idea to make this an opt-in. For that, we need to use an ALPN, SETTING, or something that it being exchanged prior to the HTTP requests. The problem with option 1 is that we'd need to introduce a new negotiation scheme for every protocol. Option 2 is better in that respect because we need to introduce one negotiation scheme, and reuse it for different protocols. But I'm not sure if hawing a new negotiation scheme is necessary, when option (3), i.e., the Extended CONNECT method, already provides us the necessary negotiation scheme with the ":protocol" psuedo header acting as a way of specifying the protocol.
Extended CONNECT does have the advantage of targeting a resource. The challenge then is in how the target (for UDP, that would be a hostname or IP plus a port) is encoded into that target URI. We have URI templates that have been successfully used elsewhere, so that might work. Webtransport can just use an arbitrary target URI. The main complaint I have is that :protocol is terrible. HTTP Upgrade Tokens aren't ALPN, but that's almost what we want here: a unified protocol identification system. Of course, as a tunneled protocol, ALPN isn't right either, so maybe we can just reclaim upgrade tokens for this tunneling stuff.
Yeah, I share the temptation to use ALPN. Though, talking specifically about masque, I'm not sure if it's an application protocol. Rather, it is a combination of an encapsulated datagram protocol and a way of specifying the remote address. Let's say we want to use SRTP on top of a HTTP tunnel with support for datagrams. In such case, SRTP would be the ALPN, and we'd need another identifier for specifying that the transport carries datagrams, rather than a bidirectional stream. Based on that, I am inclined to say that ":protocol" might be a better fit for masque, and separately, we could discuss adding a non-pseudo header field for specifying ALPN. PS. And the other benefit of using Upgrade Tokens is that we can support HTTP/1.1 as well (though I'm not entirely sure if we want to officially support HTTP/1.1).
I keep forgetting that I wrote RFC 7639. Still, I agree on all counts. ALPN has a purpose, but it isn't quite right here. Update tokens are a little weird, but I think that they are actually perfect. We just need to reclaim them for use.
One thing I do find appealing about using Upgrade Tokens is that it means that HTTP/1.1 support becomes easy: we just use Upgrade and keep the target in the path like in h2 and h3. And conceptually an upgrade is what we're doing: we're replacing the DATA stream with a new protocol that uses capsules/stream chunks. That's not too dissimilar to WebSocket. Following up on today's question on what should be used for scheme and authority for CONNECT-UDP, I am thinking we may want to reconsider the overall approach for scheme, authority, and path for CONNECT-UDP and any other new CONNECT- methods. We may even wish to consider defining a new CONNECT-TCP method for QUIC. As a service operator, the CONNECT method has problematic semantics that don't work well for providing a multi-tenant service. It is defined (in H2 at least) to have no scheme and no path, and its authority is the same name as the hostname of the connect target. This makes it problematic: there's effectively no Host header in the sense that all other HTTP requests have a Host header (or H2 :authority) that will match the TLS ServerName. Given that many HTTP servers apply policy on an Origin basis (scheme+authority+port) this policy isn't applicable to CONNECT in a meaningful way. ie, what you generally want to apply configuration / authentication / policy on is the server Host name, not on the target name. We clearly can't change the CONNECT semantics here, but we should avoid introducing another new weird case that varies from HTTP semantics and which makes providing a multi-tenant service hard. What I'd propose for CONNECT-UDP is: We keep :scheme as "https" We keep :authority as the Host header / TLS ServerName for the connection to the proxy We encode the target in :path So as an example: :method = CONNECT-UDP :authority = masque-URL :path = URL :scheme = https (There are a few different ways to encode :path) We may wish to consider defining a parallel CONNECT-TCP in MASQUE that provides similar semantics to CONNECT but which uses this structure, that will be much more conducive to running services. Best, Erik

Revised text:
 <ins> UDP Proxying Support for HTTP </ins> draft-ietf-masque-connect-udp-latest Abstract  <ins> This document describes how to proxy UDP over HTTP.  Similar to how the CONNECT method allows proxying TCP over HTTP, this document defines a new mechanism to proxy UDP.  It is built using HTTP Extended CONNECT. </ins> 1.  <ins> This document describes how to proxy UDP over HTTP.  Similar to how the CONNECT method (see Section 9.3.6 of SEMANTICS) allows proxying TCP TCP over HTTP, this document defines a new mechanism to proxy UDP UDP. UDP Proxying supports all versions of HTTP and uses HTTP Datagrams HTTP-DGRAM.  When using HTTP/2 or HTTP/3, UDP proxying uses HTTP Extended CONNECT as described in EXT-CONNECT2 and EXT-CONNECT3.  When using HTTP/1.x, UDP proxying uses HTTP Upgrade as defined in Section 7.8 of SEMANTICS. </ins> 1.1. as shown here. In this document, we use the term "proxy" to refer to the HTTP server  <ins> that opens the UDP socket and responds to the UDP proxying request. If there are HTTP intermediaries (as defined in Section 3.7 of SEMANTICS) between the client and the proxy, those are referred to as </ins> "intermediaries" in this document. <ins> 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. </ins> 2.  <ins> Clients are configured to use UDP Proxying over HTTP via an URI Template TEMPLATE.  The URI template MUST contain exactly two variables: "target_host" and "target_port".  Examples are shown below: Since the original HTTP CONNECT method allowed conveying the target host and port but not the scheme, proxy authority, path, nor query, there exist proxy configuration interfaces that only allow the user to configure the proxy host and the proxy port.  Client implementations of this specification that are constrained by such limitations MUST use the default template which is defined as: "https://{proxy_host}:{proxy_port}/{target_host}/{target_port}/" where "proxy_host" and "proxy_port" are the configured host and port of the proxy respectively.  Proxy deployments SHOULD use the default template to facilitate interoperability with such clients. </ins> 3.  <ins> This document defines the "masque-udp" HTTP Upgrade Token. "masque- udp" uses the Capsule Protocol as defined in HTTP-DGRAM. A "masque-udp" request requests that the recipient establish a tunnel over a single HTTP stream to the destination target server identified by the "target_host" and "target_port" variables of the URI template (see client-config).  If the request is successful, the proxy commits to converting received HTTP Datagrams into UDP packets and vice versa until the tunnel is closed.  Tunnels are commonly used to create an end-to-end virtual connection, which can then be secured using QUIC QUIC or another protocol running over UDP. When sending its UDP proxying request, the client SHALL perform URI template expansion to determine the path and query of its request. target_host supports using DNS names, IPv6 literals and IPv4 literals.  Note that this URI template expansion requires using pct- encoding, so for example if the target_host is "2001:db8::42", it will be encoded in the URI as "2001%3Adb8%3A%3A42". A payload within a UDP proxying request message has no defined semantics; a UDP proxying request with a non-empty payload is malformed. </ins>  <ins> Responses to UDP proxying requests are not cacheable. </ins>  <ins> 3.1. </ins>  <ins> Upon receiving a UDP proxying request, the recipient proxy extracts the "target_host" and "target_port" variables from the URI it has reconstructed from the request headers, and establishes a tunnel by directly opening a UDP socket to the requested target. </ins>  <ins> Unlike TCP, UDP is connection-less.  The proxy that opens the UDP socket has no way of knowing whether the destination is reachable. Therefore it needs to respond to the request without waiting for a packet from the target.  However, if the target_host is a DNS name, the proxy MUST perform DNS resolution before replying to the HTTP request.  If DNS resolution fails, the proxy MUST fail the request and SHOULD send details using the Proxy-Status header PROXY-STATUS. </ins>  <ins> Proxies can use connected UDP sockets if their operating system supports them, as that allows the proxy to rely on the kernel to only send it UDP packets that match the correct 5-tuple.  If the proxy uses a non-connected socket, it MUST validate the IP source address and UDP source port on received packets to ensure they match the client's request.  Packets that do not match MUST be discarded by the proxy. </ins>  <ins> The lifetime of the socket is tied to the request stream.  The proxy MUST keep the socket open while the request stream is open.  Proxies MAY choose to close sockets due to a period of inactivity, but they MUST close the request stream before closing the socket.  If a proxy is notified by its operating system that its socket is no longer usable, it MUST close the request stream. </ins>  <ins> A successful response (as defined in resp1 and resp23) indicates that the proxy has opened a socket to the requested target and is willing to proxy UDP payloads.  Any response other than a successful response indicates that the request has failed, and the client MUST therefore abort the request. </ins>  <ins> 3.2. </ins>  <ins> When using HTTP/1.1, a UDP proxying request will meet the following requirements: </ins>  <ins> the method SHALL be "CONNECT". the request-target SHALL use absolute-form (see Section 3.2.2 of MESSAGING). the request SHALL include a single Host header containing the origin of the proxy. the request SHALL include a single "Connection" header with value "Upgrade". the request SHALL include a single "Upgrade" header with value "masque-udp". For example, if the client is configured with URI template "https://proxy.example.org/{target_host}/{target_port}/" and wishes to open a UDP proxying tunnel to target 192.0.2.42:443, it could send the following request: 3.3. The proxy SHALL indicate a successful response by replying with the following requirements: the HTTP status code on the response SHALL be 101 (Switching Protocols). the reponse SHALL include a single "Connection" header with value "Upgrade". the response SHALL include a single "Upgrade" header with value "masque-udp". the response SHALL NOT include any Transfer-Encoding or Content- Length header fields. If any of these requirements are not met, the client MUST treat this proxying attempt as failed and abort the connection. For example, the proxy could respond with: 3.4. When using HTTP/2 H2 or HTTP/3 H3, UDP proxying requests use HTTP pseudo-headers with the following requirements: </ins>  <ins> The ":method" pseudo-header field SHALL be "CONNECT". The ":protocol" pseudo-header field SHALL be "masque-udp". The ":authority" pseudo-header field SHALL contain the authority of the 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. A UDP proxying request that does not conform to these restrictions is malformed (see Section 8.1.2.6 of H2). For example, if the client is configured with URI template "https://proxy.example.org/{target_host}/{target_port}/" and wishes to open a UDP proxying tunnel to target 192.0.2.42:443, it could send the following request: 3.5. The proxy SHALL indicate a successful response by replying with any 2xx (Successful) HTTP status code, without any Transfer-Encoding or Content-Length header fields. If any of these requirements are not met, the client MUST treat this proxying attempt as failed and abort the connection. For example, the proxy could respond with: </ins> 4. UDP packets are encoded using HTTP Datagrams HTTP-DGRAM.  The payload of a UDP packet (referred to as "data octets" in UDP) is sent unmodified in the "HTTP Datagram Payload" field of an HTTP Datagram.  <ins> In order to use HTTP Datagrams, the client will first decide whether or not to use HTTP Datagram Contexts and then register its context ID (or lack thereof) using the corresponding registration capsule, see HTTP-DGRAM. </ins> Clients MAY optimistically start sending proxied UDP packets before  <ins> receiving the response to its UDP proxying request, noting however </ins> that those may not be processed by the proxy if it responds to the  <ins> request with a failure, or if the datagrams are received by the proxy before the request. </ins>  <ins> Extensions to this mechanism MAY leverage the "Context Extensions" field of registration capsules in order to negotiate different semantics or encoding for UDP payloads. </ins> 5.  Proxies SHOULD strive to avoid increasing burstiness of UDP traffic: they SHOULD NOT queue packets in order to increase batching. control unless it has an out-of-band way of knowing with absolute certainty that the inner traffic is congestion-controlled.  <ins> If a client or proxy with a connection containing a UDP proxying request stream disables congestion control, it MUST NOT signal ECN support on that connection.  That is, it MUST mark all IP headers with the Not-ECT codepoint.  It MAY continue to report ECN feedback via ACK_ECN frames, as the peer may not have disabled congestion control. </ins> When the protocol running over UDP that is being proxied uses loss recovery (e.g., QUIC), and the underlying HTTP connection runs over independently retransmit the same data.  To avoid this, HTTP/3 datagrams SHOULD be used.  <ins> 5.1. </ins>  <ins> UDP proxying does not create an IP-in-IP tunnel, so the guidance in </ins> RFC6040 about transferring ECN marks between inner and outer IP  <ins> headers does not apply.  There is no inner IP header in UDP proxying </ins> tunnels.  <ins> Note that UDP proxying clients do not have the ability in this </ins> specification to control the ECN codepoints on UDP packets the proxy sends to the server, nor can proxies communicate the markings of each UDP packet from server to proxy.  <ins> A UDP proxy MUST ignore ECN bits in the IP header of UDP packets received from the server, and MUST set the ECN bits to Not-ECT on UDP packets it sends to the server.  These do not relate to the ECN markings of packets sent between client and proxy in any way. </ins>  <ins> 6. </ins> There are significant risks in allowing arbitrary clients to establish a tunnel to arbitrary servers, as that could allow bad actors to send traffic and have it attributed to the proxy.  Proxies  <ins> that support UDP proxying SHOULD restrict its use to authenticated </ins> users. Because the CONNECT method creates a TCP connection to the target, the target has to indicate its willingness to accept TCP connections by responding with a TCP SYN-ACK before the proxy can send it  <ins> application data.  UDP doesn't have this property, so a UDP proxy could send more data to an unwilling target than a CONNECT proxy. However, in practice denial of service attacks target open TCP ports so the TCP SYN-ACK does not offer much protection in real scenarios. Proxies MUST NOT introspect the contents of UDP payloads as that would lead to ossification of UDP-based protocols by proxies. </ins>  <ins> 7. </ins>  <ins> 7.1. </ins>  <ins> This document will request IANA to register "masque-udp" in the HTTP Upgrade Token Registry maintained at <<https://www.iana.org/assignments/http-upgrade-tokens>>. </ins>  <ins> masque-udp </ins>  <ins> Proxying of UDP Payloads. </ins>  <ins> None. </ins>  <ins> This document. </ins>