folbricht / routedns

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

Enabling 0-RTT for QUIC/H3 clients #387

Closed LeonardWalter closed 1 month ago

LeonardWalter commented 1 month 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 1 month 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 1 month ago

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

LeonardWalter commented 1 month 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 1 month 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 1 month 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 1 month 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 1 month ago

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

LeonardWalter commented 1 month 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 1 month ago

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