Support 0-RTT for DoQ
According to RFC 9250,
Using 0-RTT for DoQ has many compelling advantages. Clients can
establish connections and send queries without incurring a connection
delay. Servers can thus negotiate low values of the connection
timers, which reduces the total number of connections that they need
to manage. They can do that because the clients that use 0-RTT will
not incur latency penalties if new connections are required for a
query.
dnsproxy, unfortunately, has not yet supported 0-RTT for DoQ, but nevertheless its dependent QUIC implementation has already supported 0-RTT.
https://github.com/AdguardTeam/dnsproxy/blob/7f5cafa118a59337a3d8d7dc2faade89f91b114d/upstream/upstream_quic.go#L225
The dnsproxy uses DialAddrContext instead of DialAddrEarlyContext.
Last but not least, AdGuard DoQ does not support 0-RTT, either.
Besides DialAddrEarlyContext, ClientSessionCache and TokenStore should be also set up. Even in absence of 0-RTT support, the handshake time could be reduced from 2 RTT to 1 RTT.
This was added in https://github.com/AdguardTeam/dnsproxy/pull/268
Yep, should be closed, thank you!
I wonder whether there is a public DoQ server to test this feature.
quic://dns.adguard.com, but it may not work since the traffic in a single location may be load-balanced between multiple servers that do not share tokens cache.
Alternatively, try running two instances of dnsproxy, one as a DoQ server with a self-signed cert, the other one with --insecure option.
Also, I haven't extensively tested 0-RTT support, quic-go does not expose enough information about the handshake (or I haven't found it).
The TLS early_data extension in the NewSessionTicket message is defined to convey (in the max_early_data_size parameter) the amount of TLS 0-RTT data the server is willing to accept. Therefore, unlike dns.google and cloudflare-dns.com, dns.adguard.com does not seem to support 0-RTT.
echo GET / | openssl s_client -connect dns.adguard.com:443
Max Early Data: 0
echo GET / | openssl s_client -connect dns.google:443
Max Early Data: 14336
echo GET / | openssl s_client -connect cloudflare-dns.com:443
Max Early Data: 14336
As far as I know, logging of quic-go could be enabled by https://github.com/lucas-clemente/quic-go/wiki/Logging, thereby providing information surrounding handshake.
Well, bad news is that crypto/tls does not support early data extension on the server-side: https://go.dev/src/crypto/tls/handshake_server_tls13.go
143 if hs.clientHello.earlyData {
144 // See RFC 8446, Section 4.2.10 for the complicated behavior required
145 // here. The scenario is that a different server at our address offered
146 // to accept early data in the past, which we can't handle. For now, all
147 // 0-RTT enabled session tickets need to expire before a Go server can
148 // replace a server or join a pool. That's the same requirement that
149 // applies to mixing or replacing with any TLS 1.2 server.
150 c.sendAlert(alertUnsupportedExtension)
151 return errors.New("tls: client sent unexpected early data")
152 }
Therefore neither dnsproxy nor AdGuard DNS support it (both written in golang).
After reading the comment I am now not sure if I quoted the right part of the code. Will do a more extensive search when I am at the laptop, doing this from mobile is not too convenient:)
edit: reading further confirms that 0rtt is not supported :(
So TLS 1.3 implemented by golang does not support early data, while the quic-go supports 0-RTT on both client side and server side, which is shown by https://interop.seemann.io/
@msoxzw thanks for checking it!
In this case it's not correct to examine standard TLS here.
Let's reopen this until I fully verify that everything works as it should.