Subject: [core] Ben Campbell's Discuss on draft-ietf-core-coap-tcp-tls-08: (with DISCUSS and COMMENT)

From: Ben Campbell <[email-masked]>
Date: Thu, 11 May 2017 08:14:33 -0700

Ben Campbell has entered the following ballot position for
draft-ietf-core-coap-tcp-tls-08: Discuss

When responding, please keep the subject line intact and reply to all
email addresses included in the To and CC lines. (Feel free to cut this
introductory paragraph, however.)

Please refer to https://www.ietf.org/iesg/statement/discuss-criteria.html
for more information about IESG DISCUSS and COMMENT positions.

The document, along with other ballot positions, can be found here:
https://datatracker.ietf.org/doc/draft-ietf-core-coap-tcp-tls/

----------------------------------------------------------------------
DISCUSS:
----------------------------------------------------------------------

1) [removed, please see update in comments]

2) It seems problematic to encode the transport choice in the URI
scheme.
 Section 7 says "They are hosted
in distinct namespaces because each URI scheme implies a distinct
origin
server." IIUC, this means any given resource can only be reached over a
specific transport. That seems to break the idea of cross-transport
proxies
as discussed in section 7.

It also does not seem to fit with a primary motivation for this draft.
That
is, one might want to use TCP because of local NAT/FW issues. But if
there is
a resource with a "coap" scheme, I cannot switch to TCP when I'm behind
a
problematic middlebox, and have an expectation of reaching the same
resource.

----------------------------------------------------------------------
COMMENT:
----------------------------------------------------------------------

Update: I removed point 1 from my discuss. But I do still think it would
be useful to add a paragraph about how COAP reliability features are only
hop-by-hop.

Subtantive:

3.2: I agree with Adam that this length scheme seems very complex for
the
return

3.3: Since the initiator can start sending messages before receiving a
CSM
from the responder, how long should the initiator wait for a CSM before
bailing?

3.4: Can you offer any guidance about how often to send keep-alives? I
note
that these keepalives are not necessarily bi-directional. Aren't there
some
NAT/FW cases where bi-directional traffic is needed to keep bindings
from
timing out?

This and other places explicitly mention that in-flight messages may be
lost
when the transport is closed or reset. This creates uncertainty about
whether
such messages have been processed or not. Is that really okay?

4: After the discussion resulting from Mark's Art-Art review, I expected
to
see more emphasis about WebSocket being intended for browser-based
clients.
There's a couple of in-passing mentions of browser-clients buried in
the
text; I would have expected something more up front.

4.2: Is it really worth making the framing code behave differently for
WebSocket than for TCP?

5.3: Do I understand correctly that once an option is established, it
cannot
be removed unless replaced? (Short of tearing down the connection and
starting over, anyway.)

7.2: The text mentions 443 as a default port, but really seems to make
5684
the default. If 443 is really a default, then this needs  discussion
about
why and why it's okay to squat on HTTPS.

The text about whether ALPN is required is confusing. Why not just
require
ALPN and move one, rather than special casing it by port choice? (There
seems
to be some circular logic about requiring 5685 to support clients that
don't
do ALPN, then saying clients MUST do ALPN unless they are using port
5685.)

7.3: I agree with Adam's DISCUSS comment. And even if people decide that
the
well-known bit can be specified in CORE, I think it does future users of
a
well-known URIs for ws a disservice to make them dig through this spec
to
find the update to 6455.  It would be better to pull that into a
separate
draft. That's also a material addition post IETF last call, so we should
consider
repeating the LC.

10.2: Is the registration policy "analogous to" that of [RFC7252] S12.2,
or
"identical to" it. If the answer is not "identical", then the policy
should be detailed here.

Editorial:

Figures 7 and 8: "Payload (if any)" - Can we assume that if one uses
either
extended length format, one has a payload?

3.3: Is the guidance about what errors to return if you don't implement
a
server any different here than for UDP?

4.3 and 4.4 seem to primarily repeat details that are the same for WS as
for
TCP, even though the introduction to the WS part says that it won't do
that
:-)

5.3: "One CSM MUST be sent by both endpoints...": s/both/each

7.6: The "updates" in this section are confusing. I understand this to
mean
that the procedures for TCP and WS are identical to those for UDP except
for
the mentioned steps. But the language of the form of "This step from
[RFC7252] is updated to:" makes it sound like this intends to actually
change
the language in 7252 to this new language. If the latter, then that
effectively removes UDP support from 7252 as updated.

This could easily be fixed by changing that to something to the effect
of
"When using TCP, this step changes to ..."

Appendix A: Why is this an appendix? Updates to a standards track RFC
seem to
warrant a more prominent position in the draft.

---

From: Adam Roach <[email-masked]>
Date: Thu, 11 May 2017 16:32:35 -0500

On 5/11/17 10:14, Ben Campbell wrote:
> 2) It seems problematic to encode the transport choice in the URI scheme.
>
> Section 7 says "They are hosted in distinct namespaces because each URI scheme implies a distinct origin server." IIUC, this means any given resource can only be reached over a specific transport. That seems to break the idea of cross-transport proxies as discussed in section 7.
>
> It also does not seem to fit with a primary motivation for this draft. That is, one might want to use TCP because of local NAT/FW issues. But if there is a resource with a "coap" scheme, I cannot switch to TCP when I'm behind a problematic middlebox, and have an expectation of reaching the same resource.

I've been turning this over in my mind, and I think there are two 
problems here. The fundamental problem is that this document is encoding 
all kinds of protocol options into the URI scheme, which is an 
architecturally worrisome precedent for *all* URI-using protocols, 
current and future (by which I mean to say I don't think it's in CORE's 
unilateral purview to decide this is okay). This problem is compounded 
for CoAP in particular by treating the resource spaces associated with 
each scheme as distinct.

I don't know whether the second issue is intentional or just a 
misunderstanding about whether it is allowable to have different schemes 
share a resource space (it is; cf. [1]), but I think we can come up with 
a solution to the first problem that allows the second to become moot.

Looking to what we've done elsewhere in the IETF: considering the 
present moment, recent past, and near future, we effectively have six 
protocols in the wild for securely retrieving hypermedia across the 
Internet: HTTP 1.x, SPDY1, SPDY2, SPDY3, H2, and QUIC. Note that these 
protocols vary in syntax, semantics, and even transport-layer protocols. 
The URI schemes for these six different protocols are https, https, 
https, https, https, and https, respectively.

I think that's a good model. One pleasant advantage of this model is 
that it completely eliminates the resource space issue I describe above.

Concretely, then, I propose that the URI schemes in this document be 
assigned as follows:

For CoAP over TCP: coap

For CoAP over TLS over TCP: coaps

For CoAP over WS: coap

For CoAP over WSS: coaps

We then make UDP support mandatory to implement [2]. Now, let's talk 
about TCP. I'm leaving WebSockets out of this description for a moment, 
for reasons that I will explain later.

The general process for accessing a CoAP resource would be: try to 
contact the remote node over UDP using a Confirmable message. After some 
reasonable timespan (I would propose just prior to the third 
transmission [second retransmission] of a message), if no ACK had been 
received, those nodes that support TCP would try to initiate a TCP 
connection (same host, same port, different transport) in parallel with 
the third UDP transmission. If the TCP connection succeeds, abandon the 
UDP attempts and start the transaction over on the TCP connection [3].

Two additionally proposed minor details on this scheme that I think 
increase its appeal:

 1. Nodes SHOULD cache, on a per-authority basis, whether UDP failed
    (but TCP worked) in the past; and, if such a failure was observed
    within a reasonable timeframe (hours or maybe days), use TCP instead
    of UDP for subsequent contact. This cache would be flushed whenever
    an IP address or routing table change is observed.

 2. Nodes SHOULD allow configuration, both globally and on a
    per-authority basis, to skip the UDP attempt, so as to optimize
    connection times when UDP is administratively known to be nonviable
    or otherwise undesirable.

Turning now to WebSockets. As far as I can tell, the use of WebSockets 
is intended for a radically different deployment architecture than TCP 
-- it looks very much like TCP is meant to accommodate one or both of 
the parties being a constrained node, while WebSockets clearly is not: 
there is no way it makes sense for a constrained device to implement 
CoAP over WebSockets over HTTP on the conceit that it's simpler than 
using HTTP. So, this means that CoAP/WebSockets is intended to run only 
between two high-powered network hosts.

(I'd like to take a quick pause to say that these radically different 
use cases suggest that it would be a Really Good Idea to split 
CoAP/WebSockets out into its own document that builds on top of the 
CoAP/TCP document.)

Okay, so let's try to back out an architecture of *why* you have two 
non-contrained hosts using CoAP over WebSockets. Clearly, one of them is 
a browser, or you'd just use straight-up CoAP, right? In fact, the 
WebSockets client has to be the browser here. Further, if this is simply 
a browser sending and receiving data to and from a server, there are 
already a host of well-defined and broadly-deployed web technologies 
that they could use instead of CoAP.

That means that the the only sensible conclusion is that the server is 
one of: (a) a proxy for constrained device(s) that the browser wants to 
contact, (b) a proxy for non-constrained device(s) that speak only CoAP 
(presumably so constrained devices can also connect to it), or (c) both. 
In all three cases, the proxy needs to have its own mapping that 
converts from resources at its own authority to the corresponding 
resources on the authority/ies for which is is serving as a proxy. This 
is important, and we'll come back to it later.

As far as I can tell, that is the *only* context in which one might use 
CoAP/WebSockets. I mean, if there's some other architecture that makes 
sense here, I'd like to hear about it, but I think the logic above is 
pretty sound.

In that context, then: a CoAP node implemented inside a web browser that 
gets ahold of a coap: or coaps: URI can do precisely one thing: use 
WebSockets to connect to the authority, using the CoAP/WebSockets 
semantics defined in this document. It can't try UDP or TCP, because 
these affordances aren't available from a web execution context. So if 
the authority in the URL doesn't support CoAP/WebSockets, the client is 
done.

Now, what about other, non-browser nodes that happen to get ahold of 
these URIs? Well, now we're back to the fact that we made UDP MTI: these 
same servers are listening for normal CoAP over UDP (and maybe TCP, if 
they want to). So, remember how we said that this thing is necessarily a 
proxy fronting other resources, and it has its own mapping from its 
local resources to remote ones? That's what makes the whole UDP and TCP 
thing work: it just needs to act like the same proxy for CoAP/UDP and 
CoAP/TCP as it does for CoAP/WS.

/a

_____

[1] RFC section 4.1: "SIP and SIPS URIs that are identical except for 
the scheme itself (e.g., sip:[email-masked] and 
sips:[email-masked]) refer to the same resource."

[2] This is, I think, architecturally consistent with what's already 
been done. In fact, this may already be the case; I can't quickly find 
language covering this.

[3] The operation on the TCP connection would need to use the same 
Message ID as the UDP attempts did, to ensure idempotency -- it's 
possible that one or more of the transmitted UDP packets did make it to 
the remote node, but the ACKs did not arrive back at the originator. 
This does necessitate un-removing the Message ID field from TCP, but I 
think that's a Good Thing anyway.

---

From: Ben Campbell <[email-masked]>
Date: Thu, 11 May 2017 17:15:55 -0500

> On May 11, 2017, at 4:32 PM, Adam Roach <[email-masked]> wrote:
> 
> I've been turning this over in my mind, and I think there are two problems here. The fundamental problem is that this document is encoding all kinds of protocol options into the URI scheme, which is an architecturally worrisome precedent for *all* URI-using protocols, current and future (by which I mean to say I don't think it's in CORE's unilateral purview to decide this is okay). This problem is compounded for CoAP in particular by treating the resource spaces associated with each scheme as distinct.
> 
> I don't know whether the second issue is intentional or just a misunderstanding about whether it is allowable to have different schemes share a resource space (it is; cf. [1]), but I think we can come up with a solution to the first problem that allows the second to become moot.
> 
> Looking to what we've done elsewhere in the IETF: considering the present moment, recent past, and near future, we effectively have six protocols in the wild for securely retrieving hypermedia across the Internet: HTTP 1.x, SPDY1, SPDY2, SPDY3, H2, and QUIC. Note that these protocols vary in syntax, semantics, and even transport-layer protocols. The URI schemes for these six different protocols are https, https, https, https, https, and https, respectively.
> 
> I think that's a good model. One pleasant advantage of this model is that it completely eliminates the resource space issue I describe above
> 
> 
> Concretely, then, I propose that the URI schemes in this document be assigned as follows:
> 
> For CoAP over TCP: coap
> 

I agree this appears to be the right model. I also recall Carsten mentioning elsewhere that the WG had made an earlier architectural decision to encode transport in the URLs. If that’s really the case, I’d be interested in hearing the reasoning behind it. I am skeptical that said reasoning would still hold in light of the architectural problems with doing so that have been identified .

> 
> 
> We then make UDP support mandatory to implement [2]. Now, let's talk about TCP. I'm leaving WebSockets out of this description for a moment, for reasons that I will explain later.
> The general process for accessing a CoAP resource would be: try to contact the remote node over UDP using a Confirmable message. After some reasonable timespan (I would propose just prior to the third transmission [second retransmission] of a message), if no ACK had been received, those nodes that support TCP would try to initiate a TCP connection (same host, same port, different transport) in parallel with the third UDP transmission. If the TCP connection succeeds, abandon the UDP attempts and start the transaction over on the TCP connection [3].
> 
> Two additionally proposed minor details on this scheme that I think increase its appeal: 
> 	• Nodes SHOULD cache, on a per-authority basis, whether UDP failed (but TCP worked) in the past; and, if such a failure was observed within a reasonable timeframe (hours or maybe days), use TCP instead of UDP for subsequent contact. This cache would be flushed whenever an IP address or routing table change is observed.
> 
> 	• Nodes SHOULD allow configuration, both globally and on a per-authority basis, to skip the UDP attempt, so as to optimize connection times when UDP is administratively known to be nonviable or otherwise undesirable.

While this probably falls under your second bullet, I would include the possibility of an out-of-band mechanism to determine which transport the server supports/prefers. For example, DNS. In particular, Carsten mentioned draft-silverajan-core-coap-protocol-negotiation, which I understand might eventually offer such a mechanism.

> 
> Turning now to WebSockets. As far as I can tell, the use of WebSockets is intended for a radically different deployment architecture than TCP -- it looks very much like TCP is meant to accommodate one or both of the parties being a constrained node, while WebSockets clearly is not: there is no way it makes sense for a constrained device to implement CoAP over WebSockets over HTTP on the conceit that it's simpler than using HTTP. So, this means that CoAP/WebSockets is intended to run only between two high-powered network hosts.
> (I'd like to take a quick pause to say that these radically different use cases suggest that it would be a Really Good Idea to split CoAP/WebSockets out into its own document that builds on top of the CoAP/TCP document.)
> 
> Okay, so let's try to back out an architecture of *why* you have two non-contrained hosts using CoAP over WebSockets. Clearly, one of them is a browser, or you'd just use straight-up CoAP, right? In fact, the WebSockets client has to be the browser here. Further, if this is simply a browser sending and receiving data to and from a server, there are already a host of well-defined and broadly-deployed web technologies that they could use instead of CoAP.
> 
> That means that the the only sensible conclusion is that the server is one of: (a) a proxy for constrained device(s) that the browser wants to contact, (b) a proxy for non-constrained device(s) that speak only CoAP (presumably so constrained devices can also connect to it), or (c) both. In all three cases, the proxy needs to have its own mapping that converts from resources at its own authority to the corresponding resources on the authority/ies for which is is serving as a proxy. This is important, and we'll come back to it later.
> As far as I can tell, that is the *only* context in which one might use CoAP/WebSockets. I mean, if there's some other architecture that makes sense here, I'd like to hear about it, but I think the logic above is pretty sound.
> 
> In that context, then: a CoAP node implemented inside a web browser that gets ahold of a coap: or coaps: URI can do precisely one thing: use WebSockets to connect to the authority, using the CoAP/WebSockets semantics defined in this document. It can't try UDP or TCP, because these affordances aren't available from a web execution context. So if the authority in the URL doesn't support CoAP/WebSockets, the client is done.
> Now, what about other, non-browser nodes that happen to get ahold of these URIs? Well, now we're back to the fact that we made UDP MTI: these same servers are listening for normal CoAP over UDP (and maybe TCP, if they want to). So, remember how we said that this thing is necessarily a proxy fronting other resources, and it has its own mapping from its local resources to remote ones? That's what makes the whole UDP and TCP thing work: it just needs to act like the same proxy for CoAP/UDP and CoAP/TCP as it does for CoAP/WS.
> /a
> _____
> 
> [1] RFC section 4.1: "SIP and SIPS URIs that are identical except for the scheme itself (e.g., sip:[email-masked] and sips:[email-masked]) refer to the same resource."
> 
> [2] This is, I think, architecturally consistent with what's already been done. In fact, this may already be the case; I can't quickly find language covering this.
> 
> [3] The operation on the TCP connection would need to use the same Message ID as the UDP attempts did, to ensure idempotency -- it's possible that one or more of the transmitted UDP packets did make it to the remote node, but the ACKs did not arrive back at the originator. This does necessitate un-removing the Message ID field from TCP, but I think that's a Good Thing anyway.
>

---

From: Carsten Bormann <[email-masked]>
Date: Fri, 12 May 2017 11:48:05 +0200

Hi Adam,

thank you for this design sketch.

I fully support your quest to find a solution that avoids resource siloing.

I’ll call the approach of trying out several transports at once “happy bearing balls” for now :-)
(We don’t have eyeballs in the IoT :-)

I’m still a bit nauseous from all that probing and caching (and negative caching).  It sounds like a big deployment headache, and a way to add indeterminism and inexplicable delays into something that could have been very simple.  Having a transport *hint* in the URI still sounds like a way to reduce this when the determination can already be made at the server side ([1]).

In the IoT space we typically have information from configuration and from places such as the Resource Directory that could enhance a URI with information about the best transport type to use for it (DNS is not always in use, by the way).  Baking this into the way transports are selected goes further down the road that a URI is not by itself all you need to make the request, but to a certain extent that has always been the case by including a DNS name (which may be one reason why DNS is not as much in use with CoAP).

> [3] The operation on the TCP connection would need to use the same Message ID as the UDP attempts did, to ensure idempotency -- it's possible that one or more of the transmitted UDP packets did mak…

How is a server supposed to find out two messages that reach it over different transports are actually the same?
Sure, including message-IDs would be one thing (which are otherwise of no use in TCP).
But what about two clients happening to use the same message-ID?  The server would need to associate the copies of the request it got to the same client.  This would require that the client uses matching ephemeral ports for UDP and TCP, and I don’t know how to get this through NATs (which are one of the big use cases we are addressing).

So I would like to de-emphasize the happy bearing balls for non-idempotent requests — there is usually something that a client wants to do with a server anyway before getting to those.

In summary: I like being able to do happy bearing balls.  I’d also like to be able to not use it, based on transport hints.

Grüße, Carsten

[1] It seems you have those transport hints in SIP.  But SIP doesn’t have to deal with URI resolution based on base URIs, so it has more freedom in putting parameters into the URI.  The reason our transport information is in the scheme is that we couldn’t find a better place.  I would love to hear there is.

---

From: Adam Roach <[email-masked]>
Date: Fri, 12 May 2017 09:57:27 -0500

> I fully support your quest to find a solution that avoids resource siloing.

To be clear, while that's a goal here, it's far from the primary goal. 
The high-order bit in my book is correctly dealing with what URI schemes 
actually mean, since that has implications well beyond CoAP.

> I’m still a bit nauseous from all that probing and caching (and negative caching).

The caching is an optimization with obvious trade-offs, and I'm more 
than happy to leave it to implementations as to whether they think it's 
something they need.

>    It sounds like a big deployment headache, and a way to add indeterminism and inexplicable delays into something that could have been very simple.

As you correctly point out above, there are no eyeballs involved. I 
doubt that Things care about the occasional 15-second delay. In any 
case, the configuration I propose is intended to shortcut these delays 
if NATs are known to be a problem a priori.

>    Having a transport *hint* in the URI still sounds like a way to reduce this when the determination can already be made at the server side ([1]).
>

I really don't follow this paragraph.

> So I would like to de-emphasize the happy bearing balls for non-idempotent requests — there is usually something that a client wants to do with a server anyway before getting to those.

It sounds like we can come up with something here, then -- perhaps 
UDP&TCP clients would be required to make first contact using a request 
that is inherently idempotent. (I mean, I have some other ideas about 
how we could perform deduplication, but I'm sure you'd find them 
distasteful for constrained implementations.)

> In summary: I like being able to do happy bearing balls.  I’d also like to be able to not use it, based on transport hints.

I'm fine with that in principle, but your transport hints can't be part 
of your URI scheme. That's just not what schemes mean.

/a