Subject: [quicwg/base-drafts] Padding overhead in DNS over QUIC scenarios (#3523)

From: Christian Huitema <[email-masked]>
Date: Fri, 13 Mar 2020 21:58:16 -0700

I am looking at DNS over QUIC scenarios. A common case would be a resumed session in which the client sends the short DNS query as 0-RTT data, and the server then sends the response after the session is confirmed. Assuming a service delay larger than 1-RTT, I expect to see something like:

1- Client initial + 0-RTT (DNS query), 1232 bytes, including 669 bytes of padding
2- Server Initial + handshake + 1-RTT (Crypto ticket, 2x new connection ID), 606 bytes
3- Handshake (finished) + 1 RTT (2x new connection ID) 222 bytes
4- Server 1RTT(handshake done) 55 bytes
5-Client 1-RTT(ACK) 55 bytes
6- Server 1-RTT (DNS response) 85 bytes

That's 2170 bytes total, of which 31% are the initial padding -- which is also 44% of the client's traffic. That's quite a bit of overhead. The question is, is that strictly necessary? 

Suppose for example that the server also provisions a "NEW TOKEN", maybe 40 bytes long. The server can verify the token when receiving the first packet, and validate the IP address. At that point, the concerns about DDOS are mostly mitigated. We could remove the 669 bytes of padding, at the cost of an initial token (1 byte length, 40 bytes data) and a NEW TOKEN frame (1 byte type, 1 byte length, 40 bytes data), i.e. a gain of 486 bytes. The client would send a total of 923 bytes instead of 1503, the total exchange would use 1584 bytes instead of 2170.

What do you think? Would it be OK to relax the "pad to 1200" rule when the Initial carries a valid token? Should we make that part of the main spec, or treat that as an extension?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523

---

From: Kazuho Oku <[email-masked]>
Date: Fri, 13 Mar 2020 22:18:29 -0700

I'm tempted to argue that this proposal should be considered as an extension, if we are to consider it.

Amount of data that a server might be willing to send before it confirms the client's address depends on if the server is resuming the TLS handshake. It is my understanding that the reason we require clients to pad Initial up to 1200 bytes is to provide server enough room to send the certificate chain before the client's address is confirmed. That room is unnecessary when the handshake is resumed.

However, it is questionable if a TLS server sending a session ticket is committed to getting the handshake being resumed. As an example, each server behind an anycast address might be issuing session tickets that can be only handled by the server that generated the ticket. This is fine, because resumption is considered as an "optimization."

I think we should stick to the design principle of TLS that resumption is an optimization that sometimes work, but not always guaranteed to be.

Allowing clients to send a small-sized Initial when attempting resumption goes against that principle.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599013462

---

From: MikkelFJ <[email-masked]>
Date: Sat, 14 Mar 2020 01:28:21 -0700

Initially I would say that 0-RTT would not need padding because the token is validated. However, if the server cannot trivially defend against cloned tokens it is a different matter. Multiple clients can sit behind the same NAT in an attack so the IP address need not even change. The token can also be stolen by observation on a compromised LAN.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599027876

---

From: Kazuho Oku <[email-masked]>
Date: Sat, 14 Mar 2020 01:35:19 -0700

@mikkelfj To add one point, use of 0-RTT is driven by session ticket, which is orthogonal to the use of a NEW_TOKEN token.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599028498

---

From: Kazuho Oku <[email-masked]>
Date: Sat, 14 Mar 2020 01:44:25 -0700

Regarding solution, I think it might be a good idea to have a way of reducing the size of first client-sent Initial to 400 bytes, possibly by letting the server advertise that using a TP.

The reason for choosing 400 bytes is that 3x of 400 is 1200 bytes - this gives the server enough room for sending a Retry packet, or a datagram consisting of Initial and Handshake packet. When the server decides to do a full handshake, waiting for the response to either of the two would allow the server to validate the connection.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599029182

---

From: Christian Huitema <[email-masked]>
Date: Sat, 14 Mar 2020 07:52:03 -0700

@mikkelfj Yes, servers should have ways to ban token reuse. There is already a recommendation that "A client SHOULD NOT reuse a NEW_TOKEN token for different connection attempts." I think we should add text saying that "A server that detects NEW_TOKEN reuse MAY immediately close (Section 10.3) the connection with an INVALID_TOKEN error."

It would be even better if the NEW_TOKEN frame carried an expected DCID parameter. This would make handling of new tokens by server very similar to handling of retry token: refuse or drop if the incoming DCID does not match the value tied to the token. It would also make reuse detection very easy, because connections attempts from the same address and to the same DCID could be routed to the same connection context. Only one connection would be accepted for the duration of the draining delay, which would greatly limit the possibility of abuse.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599073854

---

From: Christian Huitema <[email-masked]>
Date: Sat, 14 Mar 2020 07:53:59 -0700

@kazuho the 400 bytes suggestion is interesting. In the DNS scenario, the "resume" initial and the 0-RTT packet use 500 to 600 bytes.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599074198

---

From: ianswett <[email-masked]>
Date: Sat, 14 Mar 2020 10:40:15 -0700

I can also imagine an application specifying a smaller minimum packet size.  That removes the dependency upon the resumption case and remembering the new transport param.

But if that argument holds, then the transport doc should have a smaller limit(400 would be an absolute minimum as Kazuho points out, but I think something closer the the minimum v4 packet size of 576 bytes makes sense, so maybe 512?), and applications like HTTP/3 can specify a higher limit(ie: 1200).

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599106952

---

From: Christian Huitema <[email-masked]>
Date: Sat, 14 Mar 2020 11:14:21 -0700

If we are happy with the factor 3 amplification limit, the practical minimum is "one third of the server's first flight". If we go below that, then the server flight has to be split over several RTT, which is bad for latency. I wonder what the flight's minimum is. Can we rely on certificate compression? How big is the signature? What of post-quantum, or hybrid techniques?

I was initially focusing on the "token-authenticated" case, because that's less exposed to DDOS than the general case. It is also a good fit for the DNS scenarios, with intermittent connections to a small number of big servers. But a global solution would be even better.

Something like, the initial packet can be as small as 512 bytes, but the server can never send more than 3 times that before validating the connection. And clarifying what validating means in the "new token" scenario.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599113691

---

From: Christian Huitema <[email-masked]>
Date: Sat, 14 Mar 2020 11:16:06 -0700

Of course, there is also an interaction with PMTU discovery. If the client sends a 1200 bytes packet and it is accepted, it knows that the path can carry such packets...

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599114042

---

From: ianswett <[email-masked]>
Date: Sat, 14 Mar 2020 11:28:11 -0700

Agreed about PMTU.  A smaller packet size would only truly be a win if it was expected larger payloads were rare enough that this would not significantly increase the packet count.  In the case of DNS, particularly from client to server, that seems plausible to me.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599116471

---

From: Christian Huitema <[email-masked]>
Date: Sat, 14 Mar 2020 11:52:13 -0700

For PMTU my DNS over QUIC example shows an initial datagram of 600 bytes, including the 0-RTT packet. It could be larger with larger tokens, or if the 0-RTT packet included several DNS queries on several streams. Of course the client could send the 0-RTT requests in non-coalesced packets, but that's not always desirable.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599120786

---

From: Christian Huitema <[email-masked]>
Date: Sat, 14 Mar 2020 12:02:05 -0700

This scenario is not a great fit for the extension mechanism. Extensions are normally negotiated using transport parameters. We could see an exchange such as:

* Client: set "minimal_initial_packet_size = 512"
* Server: set "minimal_initial_packet_size = 768"

After which the client would remember the minimal initial packet size for this application as the maximum of the client proposed value and the server proposed value, or 1200 if either the client or the server do not set the parameter. The client could then remember that value with the session ticket, and use it for resumed connections.

But the client would not be able to use this for the first exchange with the server -- that's the limit of our extension mechanism. If we want shorter first packets in general, the alternate minimal initial has to be part of the application specification.

On the other hand, even an application specification is a bit problematic if the server multiplexes several applications and demuxes on the ALPN. The server will only be able to verify that the size is OK after obtaining the ALPN, which means after processing the Initial packet. With the current spec, the server can reject packets too short before doing any processing.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599121809

---

From: martinduke <[email-masked]>
Date: Sun, 15 Mar 2020 14:44:59 -0700

What would happen if the token turned out to be expired? What would be the server response to a smaller Initial?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599268923

---

From: Kazuho Oku <[email-masked]>
Date: Sun, 15 Mar 2020 14:58:06 -0700

@martinduke It would be the same.

Assuming that the `minimal_initial_packet_size` used for client-sent packets are going to be at least 400 bytes, a server would always have room to send one full-size packet. Therefore, the server can send a Retry, or start immediately with sending the TLS handshake messages. The only difference is that when the server does the latter, it's initial send window will be 1 MTU rather than 3 MTU.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-599270190

---

From: Martin Thomson <[email-masked]>
Date: Tue, 17 Mar 2020 16:02:35 -0700

This seems like a prime candidate for extension, particularly since this isn't really in scope for version 1.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-600341728

---

From: Jana Iyengar <[email-masked]>
Date: Tue, 17 Mar 2020 16:02:36 -0700

This should be considered a v2/extension issue. In part because this isn't a debilitating issue for DNS, and it's not even clear that this is a performance issue for DNS (which is not the primary application for v1).

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-600341727

---

From: Nick Banks <[email-masked]>
Date: Tue, 17 Mar 2020 16:10:03 -0700

FYI, for MsQuic it would be difficult to make kind of decision based on an extension (TP). This logic happens statelessly, without processing the payload of the packet. If we had to change the logic to possibly always accept the packet far enough into the recv pipeline to look for a TP, that would be a really big change. What if the TP isn't in the first packet of the client initial (multi-client-initial)? Now the attacker can send an even smaller packet to make me (the server) hold state, while I wait for a TP that might not come to decide if that first packet was big enough?

Making a new version would be the only reasonable solution, IMO.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-600343706

---

From: Christian Huitema <[email-masked]>
Date: Tue, 17 Mar 2020 17:06:07 -0700

I don't like the idea of creating a version of Quic especially for DNS over Quic, because of the privacy implications. Of course it could be negotiated and remembered, but then it looks like painting the packets with a big target for various kinds of firewall filtering. But then using shorter initials also paints a big target.

I also don't advocate holding V1 at the gate to solve that. I like the suggestion to allow shorter initial packets and to limit the number of bytes that the server sends. But i get that we may want to wait for V2 for that.

For now, I will concentrate on other optimizations, such as limiting the packet overhead. That can be done with implementation guidance.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-600358797

---

From: ekr <[email-masked]>
Date: Thu, 19 Mar 2020 08:17:20 -0700

Won't DoQ need a different ALPN?

On Tue, Mar 17, 2020 at 5:06 PM Christian Huitema <[email-masked]>
wrote:

> I don't like the idea of creating a version of Quic especially for DNS
> over Quic, because of the privacy implications. Of course it could be
> negotiated and remembered, but then it looks like painting the packets with
> a big target for various kinds of firewall filtering. But then using
> shorter initials also paints a big target.
>
> I also don't advocate holding V1 at the gate to solve that. I like the
> suggestion to allow shorter initial packets and to limit the number of
> bytes that the server sends. But i get that we may want to wait for V2 for
> that.
>
> For now, I will concentrate on other optimizations, such as limiting the
> packet overhead. That can be done with implementation guidance.
>
> —
> Reply to this email directly, view it on GitHub
> <https://github.com/quicwg/base-drafts/issues/3523#issuecomment-600358797>,
> or unsubscribe
> <https://github.com/notifications/unsubscribe-auth/AAIPLILMF4HC5TKEY45LWGDRIAF6TANCNFSM4LIG6WCQ>
> .
>

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-601237238

---

From: Christian Huitema <[email-masked]>
Date: Thu, 19 Mar 2020 11:29:59 -0700

Yes, DNS over QUIC uses its own ALPN.  The draft specifies "doq". (The "sticking out" issue is hopefully solved with ESNI/ECHO.) But in the QUIC stack, the test for Initial packet length is performed before parsing the content of the Client Hello. Short Initial packets are just discarded before processing.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-601343746

---

From: Lucas Pardue <[email-masked]>
Date: Mon, 30 Mar 2020 09:23:29 -0700

My read of the discussion on this issue is that there may be some pain but that it can be overcome without design changes to quicv1.

> I also don't advocate holding V1 at the gate to solve that. I like the suggestion to allow shorter initial packets and to limit the number of bytes that the server sends. But i get that we may want…

As the issue creator, and given what you said in the quoted paragraph, would you be satisfied if the issue were marked `quicv2` label and closed?

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-606100943

---

From: Christian Huitema <[email-masked]>
Date: Mon, 30 Mar 2020 10:28:26 -0700

@LPardue moving to V2 seems fair, yes. 

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-606135042

---

From: Lucas Pardue <[email-masked]>
Date: Tue, 31 Mar 2020 10:13:29 -0700

Thanks.

In that case I'm closing this issue and labelling it as quicv2. 

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#issuecomment-606758568

---

From: Lucas Pardue <[email-masked]>
Date: Tue, 31 Mar 2020 10:13:29 -0700

Closed #3523.

-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/quicwg/base-drafts/issues/3523#event-3184330589