folbricht / routedns

DNS stub resolver, proxy and router with support for DoT, DoH, DoQ, and DTLS
BSD 3-Clause "New" or "Revised" License
476 stars 63 forks source link

Enabling 0-RTT for QUIC/H3 clients #387

Closed LeonardWalter closed 6 months ago

LeonardWalter commented 6 months ago

Updated the DoQ and DoH QUIC client to enable 0-RTT based on the guide from: https://quic-go.net/docs/http3/client/#using-0-rtt

LeonardWalter commented 6 months ago

I updated the DoQ client to use DialEarly. The implementation looks a bit weird but others (SSH3 for example) are also using net.ListenUDP(netString, nil) for this purpose. In my testbed with adguard's dnsproxy DoQ server, I can observe 0-RTT packets with DoQ.

mattkeenan commented 6 months ago

@LeonardWalter you mentioned in your commit message that there was a bug in the previous doqclient code; what was the bug?

LeonardWalter commented 6 months ago

The problem was what Frank mentioned with the updConn not being closed in my earlier commit (4d4f1a1) If the query failed due to timeout or if the server rejects the query, the udpConn would remain open for some time causing new queries to fail. This could have been avoided if I added a simple if statement that closes the udpconn again after a failed request. As the change to DialEarly was not needed, opening the UdpConn was also redundant. So I just reverted it.

mattkeenan commented 6 months ago

@LeonardWalter to be clear it wasn't a criticism of the commit, i wasn't sure i understood it correctly; apologies. also, so i understand correctly, dohclient.go will do the correct thing for http2 / TCP?

LeonardWalter commented 6 months ago

@mattkeenan It is good that you mention this. The changes don't affect DoH much, but introducing the session cache (tlsConfig.ClientSessionCache = tls.NewLRUClientSessionCache(100)) does change the behavior. Session resumption should also be used for HTTP/2, but I have not tested it.

I looked at the DoH RFC

TLS-based implementations often achieve better handshake performance through the use of some form of session resumption mechanism, such as Section 2.2 of [RFC8446]. Session resumption creates trivial mechanisms for a server to correlate TLS connections together.

AFAIK there are countermeasures to this in TLS1.3 but don't quote me on this I am no expert. Other DoH implementations also it. From the DNS over QUIC RFC but this also counts for DoH when using session resumption/pre shared keys

Session resumption and 0-RTT data transmission create privacy risks detailed in Sections 7.1 and 7.2. The following recommendations are meant to reduce the privacy risks while enjoying the performance benefits of 0-RTT data, subject to the restrictions specified in Section 4.5.

Clients SHOULD use resumption tickets only once, as specified in Appendix C.4 of [RFC8446]. By default, clients SHOULD NOT use session resumption if the client's connectivity has changed.

LeonardWalter commented 6 months ago

Also, I really don't like how I disable 0-RTT for DoQ

if opt.Use0RTT { tlsConfig.ClientSessionCache = tls.NewLRUClientSessionCache(100) } Session caching should not be disabled, instead there should be some other way to handle this.

folbricht commented 6 months ago

Let's keep the session cache enabled in all cases. It's a good thing to have regardless of config.

LeonardWalter commented 6 months ago

Do you know of a flag or something to disable 0-RTT. I know Allow0RTT is only used for the server side. So far I haven't discovered a good way to toggle 0-RTT on and off

folbricht commented 6 months ago

Server side? Is it needed? Seems fine to support it in all cases