Hi all,

In another thread, I was asked whether I thought I had gotten a complete
list of issues, and I said it is hard to know when one is done realizing
all the things one hasn't realized yet. Particularly in the process of
implementing things. That seems to have been correct. Here's another topic
for the list. :-)

So, Section 7 says the ACK contains:
> A list of the records containing handshake messages in the current flight
which the endpoint has received and either processed or buffered, in
numerically increasing order.
https://www.rfc-editor.org/rfc/rfc9147.html#name-ack-message

First, it is ambiguous what "numerically increasing order" means when there
are two integers in a packet number, not one. But, more importantly, I'm
not sure this matches what implementations do. I haven't tested carefully,
so I may be wrong about this, but at a glance, I don't think either NSS or
wolfSSL's DTLS 1.3 implementations (are there any other DTLS 1.3
implementations yet) do this?

Keep in mind that appending records to the list as you receive them will
*not* result in numerical order because packets may be reordered. If no one
is following this rule anyway, perhaps we should just remove it?

In particular, it seems a natural implementation will result in receive
order, not numerical order. Implementations should bound their ACK buffers
to avoid DoS, and are expected to preferentially ACK more recent records:

> Implementations MAY acknowledge the records corresponding to each
transmission of each flight or simply acknowledge the most recent one. In
general, implementations SHOULD ACK as many received packets as can fit
into the ACK record, as this provides the most complete information and
thus reduces the chance of spurious retransmission; if space is limited,
implementations SHOULD favor including records which have not yet been
acknowledged.

Given that, the natural implementation is some kind of bounded MRU queue of
records, where old ones fall off the end. (I'm planning to use a ring
buffer for our implementation.) To get numerical order, you'd need to
re-sort when sending an ACK. That is not hard, but it's unclear to me
what's the point.

Next, the spec's guidance on when to clear the ACK buffer seems odd to me.
Section 7 also says:

> During the handshake, ACKs only cover the current outstanding flight
(this is possible because DTLS is generally a lock-step protocol). In
particular, receiving a message from a handshake flight implicitly
acknowledges all messages from the previous flight(s). Accordingly, an ACK
from the server would not cover both the ClientHello and the client's
Certificate message, because the ClientHello and client Certificate are in
different flights. Implementations can accomplish this by clearing their
ACK list upon receiving the start of the next flight.

The claim that clearing this ACK list accomplishes this is not true, for
several reasons:

First, there's nothing stopping you from receiving a (redundant) portion of
the previous flight while you're receiving the new one. You'll notice all
the sequence numbers are old and ignore them when processing, but that
still keeps the record eligible for an ACK. Moreover, it's still important
ACK to old fragments. When the old fragment is in the *current* flight, the
peer may have lost an earlier ACK and not realize they can stop
retransmitting. It's only old fragments in *previous* flights that are
unnecessary to ACK, but the specification does not suggest to distinguish
them. (Distinguishing them would require extra state in the record layer to
store a low watermark for the flight, and that seems a waste. There's no
real harm in adding that record to the ACK buffer.)

Next, packets can be reordered. You might receive not the start of the next
flight, but the middle of the next flight. In general, any DTLS record
layer rule keyed on the start of a flight is suspect because of packet
reordering. But actually I'm not sure if the spirit of this rule is correct
at all.

If the peer sent flight N-1, you sent N, and now you're in the middle of
receiving flight N+1, you can stop ACKing flight N-1 as soon as you start
*sending* N. You don't need to wait to receive N+1. *Every* fragment of N
implicitly ACKs all of N-1, so as soon as you're ready to send any part of
N, you may as well send that instead of ACKing individual records because
then you also make progress in the connection. The spec instead says to
wait until receiving part of N+1, which seems later than needed and may not
even exist.

(Neither version achieves the stated goal in the spec. The stated goal
seems to require tracking extra state.)

With all that said, it seems odd to be clearing the ACK buffer at all. I've
gathered the reason to ACK by record number instead of message ranges (and
thus require the implementation keep around some state) was so that RTT
measurements could work despite retransmits. Is that right? But if the
happy path doesn't ACK most records in the first place, you won't actually
get an estimate out of it.

David
_______________________________________________
TLS mailing list -- tls@ietf.org
To unsubscribe send an email to tls-le...@ietf.org

Reply via email to