Clarify correct behavior on unrecognized circIDs and/or DESTROY.
Tor and Arti behave differently when they receive a relay cell with an unrecognized circuit ID.
In short: Tor and the spec ignore such relay cells. (See
command.c.) The relevant parts of tor-spec say:
After a DESTROY cell has been processed, an OR ignores all data or destroy cells for the corresponding circuit. [...] When a node receives a RELAY or RELAY_EARLY cell, it checks the cell's circID and determines whether it has a corresponding circuit along that connection. If not, the node drops the cell.
But to a first approximation*: Arti treats the cell as a channel error, and closes the channel.
*: Arti has special handling for the case where the circuit used to be present, but we sent a DESTROY cell. In that case, in-flight traffic still might be arriving, so Arti discards the traffic, but counts it against a maximum number of permitted cells (currently 3000). It also treats these circuit IDs as unusable for new circuits unless a DESTROY cell is received on them. Perhaps there will someday be a timeout here too. (Or perhaps we can treat the next party's ackowledgement of any subsequently sent traffic on the channel as acknowledging all previously sent destroys?)
Arti's behavior is stricter, which is maybe better. Should Tor behave similarly?
Note that if the guard is behaving correctly, once it receives the client's DESTROY, it will not relay any more traffic to the client along that circuit. So at least this isn't a way to do an active traffic flooding attack against the client.
If we decide we want to prefer Arti's behavior, here is some possible wording:
+5.4.1. After a circuit is destroyed + + After sending a DESTROY cell from one direction along a circuit, an + implementation MUST NOT send any more cells on that circuit. It must + be prepared to _receive_ traffic on that circuit, however, until the + destroy cell has propagated to the other end of the circuit, and all + previously queued cells from that end of the circuit had been + delivered. + + Therefore, after receiving a DESTROY cell, the party that received it + may assume that the DESTROY cell's sender will not send any more + traffic on that circuit, and may forget that the circuit once + existed. Any further traffic received with that same circuit ID on + that connection is in error (unless a new circuit is created with the + same ID.) + + However, after _sending_ a DESTROY cell, the sending party cannot + assume that it will receive no more traffic for that circuit ID. It + must instead reserve that circuit ID as "recently in use" on the + connection until one of the following occurs: + - It receives a DESTROY cell on that circuit ID. (This is not + guaranteed to happen.) + - The connection is closed. + - N seconds have elapsed