Change:
causes all streams to immediately become closed; open streams can be assumed to be implicitly reset. <del> After sending a CONNECTION_CLOSE frame, endpoints immediately enter the closing state.  During the closing period, an endpoint that sends a CONNECTION_CLOSE frame SHOULD respond to any packet that it receives with another packet containing a CONNECTION_CLOSE frame.  To minimize the state that an endpoint maintains for a closing connection, endpoints MAY send the exact same packet.  However, endpoints SHOULD limit the number of packets they generate containing a CONNECTION_CLOSE frame.  For instance, an endpoint could </del> <ins> After sending a CONNECTION_CLOSE frame, an endpoint immediately enters the closing state. During the closing period, an endpoint that sends a CONNECTION_CLOSE frame SHOULD respond to any incoming packet that can be decrypted with another packet containing a CONNECTION_CLOSE frame.  Such an endpoint SHOULD limit the number of packets it generates containing a CONNECTION_CLOSE frame.  For instance, an endpoint could </ins> progressively increase the number of packets that it receives before sending additional packets or increase the time between packets. <ins> An endpoint is allowed to drop the packet protection keys when entering the closing period (draining) and send a packet containing a CONNECTION_CLOSE in response to any UDP datagram that is received. However, an endpoint without the packet protection keys cannot identify and discard invalid packets.  To avoid creating an unwitting amplification attack, such endpoints MUST reduce the frequency with which it sends packets containing a CONNECTION_CLOSE frame.  To minimize the state that an endpoint maintains for a closing connection, endpoints MAY send the exact same packet. </ins> Allowing retransmission of a closing packet contradicts other advice in this document that recommends the creation of new packet numbers for every packet.  Sending new packet numbers is primarily

Discussion:
The PR clarifies the following: An endpoint that drops the keys when entering closing state MUST back-off the frequency of CONNECTIONCLOSE packets that it sends. An endpoint that does not drop the keys stops sending CONNECTIONCLOSE packet once it receives a packet containing CONNECTION_CLOSE. The first point is what we have discussed in . The second point is an editorial clarification, which is explained far below in the original text
Is there a risk of amplification attacks if an attacker sends bad packets during handshake that triggers a connection close, possible to a spoofed address. Sorry, not really up to speed on handshake details, just want to make sure this isn't overlooked. I think it should be OK, since it would be below a factor 3.
Yes, amplification using CONNECTION_CLOSE is impossible because we require that - if you don't apply other rate limiting methods - the closing packet you send is smaller than the packet you receive. That is, the factor is <1 in that case. If you apply other rate limiting methods, then the 3x limit would apply, though it would be unlikely that you would ever have cause to hit that limit.
At the moment, the backoff is merely a recommendation. Quoting from : endpoints SHOULD limit the number of packets they generate containing a CONNECTIONCLOSE frame. However, there is a DoS attack vector unless we make this a MUST, as an attacker can create bounce of packets carrying CONNECTIONCLOSE frames between two servers. Consider the case where you have two servers (A, B) that use the original DCIDs supplied by the client as the server CIDs. The attacker sends the following two Initial packets: srcaddr=A, destaddr=B, srcCID=X, destCID=Y srcaddr=B, destaddr=A, srcCID=Y, destCID=X Both of the two packets would contain an invalid payload. Then, both server A and server B would enter the CLOSING state sending CONNECTION_CLOSE frame to the peer. While in the CLOSING state, the specification allows endpoints to respond to packets from peer without decrypting them. Therefore, this creates a ping-pong. To prevent this type of attack, I think we need to change "SHOULD limit" of the quoted text to "MUST limit". The alternative might be to forbid servers adopting the DCID given by the clients as their server CIDs.

In this case, I believe both sides are in the server role. Servers don't need to pad Initial packets and servers drop Initials less than 1200 bytes, so I believe the other 'Server' would drop the Initial CONNECTIONCLOSE and this would stop quickly. However, if an implementation padded all Initials, this could be a problem, so more clarity on Initial padding may be necessary? ie: Servers SHOULD NOT pad Initial packets containing only CONNECTIONCLOSE.
Oh I missed that point. Thank you for pointing it out. Though it is still possible to mount this attack by sending an invalid 0-RTT packet Consider the case where an attacker obtains a session ticket from both servers beforehand, and sends datagrams to the servers, each consisting of Initial and 0-RTT packets (of which 0-RTT packet contains an invalid frame). Then, assuming that both servers accept 0-RTT, they would send to each other a series of Initial, Handshake, and 1-RTT packets, of which the 1-RTT packet would contain an CONNECTION_CLOSE frame. So that would cause a ping-pong.
PS. Though I now realize that the maximum about of bytes that each server would ping-pong is limited to 3x the size of the datagram that the attacker sends. So it might be possible to call this a non-issue, though the number of UDP packets that the servers would send might be less concerning (it would be like 30 UDP packets, assuming that the packets containing CONNECTION_CLOSE would be around 100 bytes each).
Discussed in Cupertino. NAME to write up a PR that replaces SHOULD by MUST in this case.
Note that this is only MUST in the case where the server drops state and uses a canned packet.
I would suggest saying that impls MUST implement one of the two solutions: MUST NOT use the client's DCID as the SCID, or MUST do an exponential backoff if it does.
An alternative would be to simply require backoff always. Whether or not a canned packet is used. Not backing off seems like a live wire, and it might be better to neutralize it in general.
I think that a "SHOULD" is enough generally; the problem only exists because you are blindly sending packets without understanding the packet that triggers them.

In , I've gone with SHOULD limit when you retain packet protection keys (as you can stop sending packets once you receive CONNECTION_CLOSE) MUST limit when you drop packet protection keys (as you do not know when to stop) Re URL, while we can define a rule based on how endpoints use CIDs, I think I prefer having a rule based on how a stack is implemented (i.e. when you drop packet protection keys) rather than how a stack is configured (i.e. the way CIDs are used). IMO, the latter is harder to test and therefore fragile.