-
Notifications
You must be signed in to change notification settings - Fork 205
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Immediately close with INVALID_TOKEN #3107
Conversation
If the Retry token is known to be invalid by the server, then the server can close the connection with INVALID_TOKEN instead of waiting for a timeout.
You need to update the "Transport Error Codes" section too. |
Thanks @nibanks I did that in a subsequent update. Refresh and tell me if it looks correct. |
@ianswett you're missing the section that gives some text to each error code |
draft-ietf-quic-transport.md
Outdated
@@ -1641,6 +1641,14 @@ of connection establishment. By giving the client a different connection ID to | |||
use, a server can cause the connection to be routed to a server instance with | |||
more resources available for new connections. | |||
|
|||
If a server receives a client Initial with a unverifiable Retry token, | |||
it knows the client will not accept another Retry token. It can either | |||
proceed with the handshake without verifying the token or immediately close |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think that we should allow the server to continue. Why not make the INVALID_TOKEN mandatory?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are to make this a mandatory requirement, under the assumption that the servers would act like that, should we also suggest that a server should issue tokens in a way that a Retry token and a NEW_TOKEN token are distinguishable from each other?
Unless we recommend servers building a token in that way, I do not think making this a MUST has benefits.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we assume that servers only require Retries when they’re under attack, they might not bother checking the validity of a token when they’re not under attack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A token SHOULD be constructed in a way that allows the server to distinguish it from tokens that are sent in Retry packets as they are carried in the same field.
We could strengthen that to MUST if you like. It probably should be anyway.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The server could decide it's not under heavy load and proceed with the handshake, even if the token doesn't constitute address validation. ie: The token could expire on a shorter timeline than the session ticket/etc, so 0-RTT could succeed, but address validation would fail.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm persuaded by Marten's comment here (which I missed at first, I think because we commented at almost the same time).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think the requirement to make them distinguishable should be a MUST. Otherwise, a change of token generation method could make an old NEW_TOKEN token appear to be an invalid Retry token.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Depending how the server distinguishes them, a change of method / confusion about what server you're sending it to could make you appear to be presenting a Retry token instead of a regular token. This error code enables the client to recover and retry quickly, but there's no language about what the client should do when it receives the code.
draft-ietf-quic-transport.md
Outdated
@@ -1641,6 +1641,14 @@ of connection establishment. By giving the client a different connection ID to | |||
use, a server can cause the connection to be routed to a server instance with | |||
more resources available for new connections. | |||
|
|||
If a server receives a client Initial with a unverifiable Retry token, | |||
it knows the client will not accept another Retry token. It can either | |||
proceed with the handshake without verifying the token or immediately close |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I still think the requirement to make them distinguishable should be a MUST. Otherwise, a change of token generation method could make an old NEW_TOKEN token appear to be an invalid Retry token.
@MikeBishop do you have a suggestion about what the client should do? Clearly it could start a new connection, but it would't want to do that an unlimited number of times, and it may depend upon whether a TCP fallback is available. Given that, it wasn't clear I should recommend something. And I agree making them distinguishable should be a MUST, as stated in #3128 |
I think that the best thing we can say is "the connection attempt failed". The first version of the PR strongly suggested that making another connection attempt was the right thing to do, but that gets into lots of difficult questions about identifying why. Given that this is an error that only happens if a Retry is spoofed, then I think that all we can say is: |
draft-ietf-quic-transport.md
Outdated
@@ -1641,6 +1641,13 @@ of connection establishment. By giving the client a different connection ID to | |||
use, a server can cause the connection to be routed to a server instance with | |||
more resources available for new connections. | |||
|
|||
If a server receives a client Initial with an invalid Retry token, | |||
it knows the client will not accept another Retry token. It can either |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand this sentence. How would the server know this for sure?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a keen observation (I think).
There is a chance where a Retry token is considered invalid due to packet becoming corrupt while being transmitted. A server can only say for sure that "the client will not accept another Retry token" unless either of the following conditions are met:
- The token is accompanied by a checksum (or an integrity protection). The checksum is correct, but the contents of the Retry token is invalid.
- The server successfully unprotects the Initial.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The client could also connect to an unexpected endpoint or the token could have expired.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me retract my comment above. We do not need to care about the packet becoming corrupt on the wire, because the prerequisite for responding with a CONNECTION_CLOSE is that the Initial that has been received can be unprotected.
To avoid confusion, maybe change "If a server receives a client Initial with an invalid Retry token" to "If a server receives a client Initial that can be unprotected but contains an invalid Retry token"?
The client could also connect to an unexpected endpoint or the token could have expired.
I'd say that that's a failure in the server deployment. We do not discuss how that should be handled.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd say that that's a failure in the server deployment. We do not discuss how that should be handled.
Since Retry is processed before handshake, why can't it just be the client sending to the wrong IP address?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
#3128 requires being able to distinguish between the two types of tokens. I updated the text with Kazuho's suggestion about being able to unprotect the Initial.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. I have one editorial suggestion.
draft-ietf-quic-transport.md
Outdated
@@ -1641,6 +1641,13 @@ of connection establishment. By giving the client a different connection ID to | |||
use, a server can cause the connection to be routed to a server instance with | |||
more resources available for new connections. | |||
|
|||
If a server receives a client Initial with an invalid Retry token, | |||
it knows the client will not accept another Retry token. It can either |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let me retract my comment above. We do not need to care about the packet becoming corrupt on the wire, because the prerequisite for responding with a CONNECTION_CLOSE is that the Initial that has been received can be unprotected.
To avoid confusion, maybe change "If a server receives a client Initial with an invalid Retry token" to "If a server receives a client Initial that can be unprotected but contains an invalid Retry token"?
The client could also connect to an unexpected endpoint or the token could have expired.
I'd say that that's a failure in the server deployment. We do not discuss how that should be handled.
About being able to unprotect the Initial packet
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the changes, @kazuho's text suggestion answers my question. I have a couple more comments.
draft-ietf-quic-transport.md
Outdated
It can either proceed with the handshake without verifying the token or | ||
immediately close ({{immediate-close}}) the connection with a connection | ||
error of INVALID_TOKEN to cause the handshake to fail quickly instead of | ||
waiting for the client to timeout. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This suggests 2 options at the server, when there are 3: it can simply drop the packet and let the client time out. You may want to call out all three options.
Suggestion: "If a server receives a client Initial that can be unprotected but contains an invalid Retry token, it knows the client will not accept another Retry token. The server can drop such a packet and allow the client to time out to detect loss of this connection, but that is a significant latency penalty to the client. If possible, the server SHOULD either immediately close the connection with an INVALID_TOKEN error or proceed with the handshake without verifying the token."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree that listing all the three options would be an improvement.
At the same time, I have a concern regarding the suggestion of doing either an immediate close or proceeding the handshake. Those two options both require the server to retain state that cannot be delayed by providing a Retry to token to the client.
I think it we might want to downgrade the SHOULD to MAY, or, suggest that a server can send a CONNECTION_CLOSE frame (with INVALID_TOKEN) without retaining state.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be possible to detect an invalid token without per-connection state, right?
That said, I realized that I don't think we should recommend that a server that might be getting DoSsed SHOULD send out another packet in response. How about "A server that is able to maintain enough state MAY either ..."
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
By saying state, I mean the closing and the draining state that gets built and retained once you invoke {immediate-close}. We should not recommend such behavior as it would create a DoS vector. But if it is not going to be a SHOULD but instead “can” or MAY, I think we can be less precise and therefor the text we have now is fine.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added a sentence about not creating any state in this case. PTAL.
Co-Authored-By: Jana Iyengar <jri.ietf@gmail.com>
Co-Authored-By: Jana Iyengar <jri.ietf@gmail.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found some of the wording to be awkward. I'm not sure that my formulation is better, but you can integrate as you like.
Co-Authored-By: Martin Thomson <mt@lowentropy.net>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rereading the changes, I have the following editorial suggestion.
server chooses not to proceed with the handshake, it SHOULD immediately close | ||
({{immediate-close}}) the connection with an INVALID_TOKEN error. Note that a | ||
server has not established any state for the connection at this point and so | ||
does not enter the closing period. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to change the last two sentences to something like: If a server chooses not to proceed with the handshake, it SHOULD immediately send a CONNECTION_CLOSE frame with an INVALID_TOKEN error without creating any state. As the server does not establish any state for the connection, it does not enter the closing period ({{immediate-close}}).
Current text is confusing as the normative text suggests following the rule in {{immediate-close}}, then argues as if it is a fact that a server would not be retaining any state, even though what we want to do here is to recommend the server to send CONNECTION_CLOSE in a stateless manner.
@@ -1641,6 +1641,17 @@ of connection establishment. By giving the client a different connection ID to | |||
use, a server can cause the connection to be routed to a server instance with | |||
more resources available for new connections. | |||
|
|||
If a server receives a client Initial that can be unprotected but contains an | |||
invalid Retry token, it knows the client will not accept another Retry token. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This only applies if the token is a Retry token (and not a NEW_TOKEN token).
When the client uses a NEW_TOKEN token, it would exchange this token for the Retry token when it receives a Retry packet, wouldn't it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that the text explicitly says "Retry token", so I don't see how this is a problem.
If the Retry token is known to be invalid by the server, then the server can close the connection with INVALID_TOKEN instead of waiting for a timeout.
Came out of discussion of Issue #3014
Fixes #3168
Related to #3127