DNSCrypt / doh-server

Fast, mature, secure DoH and ODoH server proxy written in Rust. Previously known as doh-proxy and rust-doh.
MIT License
762 stars 63 forks source link

Support Oblivious Proxy function in ODoH #64

Open junkurihara opened 3 years ago

junkurihara commented 3 years ago

Hello!

Much like encrypted-dns-server having both target resolver and relay functions, I have added the Oblivious Proxy function of ODoH in doh-server. I am not sure if this is a right direction of DNSCrypt community, but I believe it is useful. I am very happy If you like this extension and review it.

The relaying logic exactly follows the current Cloudflare's implementation in Golang. (https://github.com/cloudflare/odoh-server-go)

Note: In the IETF-draft (ver.6, Mar. 2021), single endpoint (e.g., /dns-query) works as both oblivious target and proxy, and only requests with appropriate uri queries are forwarded to oblivious target. But in the current Cloudflare's implementation, each of proxy and target has a distinct endpoint. Only requests to the proxy-specific endpoint (e.g., /proxy) are always handled as ones forwarded upstream, and the endpoint of /dns-query does not forward incoming requests.

jedisct1 commented 3 years ago

Great work!

This can be useful for testing. However, it should be disabled by default and we should make it clear that it is only for testing and should never be used in production.

Relaying is the tricky part of ODoH.

First, for performance reasons, establishing a new connection for each query would be really bad. So, we need to maintain a pool of connections to upstream resolvers, and reconnect on error. The reconnection logic by itself cannot be too naive, as we'll have to rate limits that targets will enforce.

Next, the security requirements of running an ODoH relay are not clearly defined yet. An ODoH relay is essentially an open HTTP proxy, which is very open to abuse. It can be used to access internal resources, anonymously scan remote systems and more. Besides enforcing dynamic rate limits everywhere, it has to guess whether the relaying action is safe or not. Current deployments either use hard-coded whitelists, or are completely insecure. A possible approach is to keep a dynamic set of targets that actually appear to be ODoH servers, by having the relay act as a client when a new target is requested, and check that a test ODoH query gets a valid response. This, however, opens yet another attack vector, where the relay can now be abused for amplification. Once again, additional rate limits can help, but then we hit a problem with services such as NextDNS that use customer-specific URLs.

Since this project is used to run actual servers, I'd rather add relaying code once it's actually safe to use, not just for testing.

The relaying aspect of ODoH is still quite an open problem. Both from a specification and implementation perspective.

https://github.com/jedisct1/odoh-relay is going to be open sourced soon, and is a testbed to start evaluating the security considerations of an ODoH relay that can be deployed. The specification is also likely to see some changes in that area. Cloudflare and another CDN expressed their interest in collaborating on this, which is great.

So, no need to rush. Maybe this code is still good to have in doh-server but is must be optional and explicitly documented as "only for testing".

junkurihara commented 3 years ago

Hi Frank! Thank you so much for your comments!

I totally agree to both of first and second considerations.

For the first concern on the performance, in my code one asynchronous proxy instance is recycled to avoid the performance degradation when serving lots of queries, and this may be enough for small projects (like a local proxy?). But I agree that as your comment, it should not be enough for large production environment, and more tricks should be required.

For the security concern, yes, that's right as well. As in your comment, I suspect that ODoH relay could cause DoS attacks. So I think too that the whitelist or rate limits are realistic (but insufficient) approach. Currently in my idea, some authentication or authorization may be useful to protect resource at the target. For instance, only authorized proxies can get connected to the target like the context of resource authorization on Web. Also then another authorization is needed between a client and a proxy, independently from the target, to protect the resource of proxies. Anyways, I totally agree that there are rooms for more discussion and consideration.

https://github.com/jedisct1/odoh-relay

Cool! I am really looking forward to it! When it is open, I will deploy it!

As conclusion, I am no problem and really agree that this is not merged, or is optional as "only for testing" (then not be included in default feature?).

Best, Jun

junkurihara commented 3 years ago

Hello! I just made the oblivious proxy feature non-default and explicitly mentioned it as 'non-default' and 'for testing purposes only'.