#dns #doh

app rust-doh-proxy

Rust DNS over HTTPS proxy application

28 releases

✓ Uses Rust 2018 edition

new 0.4.9 May 16, 2020
0.4.8 May 9, 2020
0.4.6 Apr 23, 2020
0.4.2 Mar 28, 2020
0.1.10 Jan 17, 2020

#88 in Network programming

Download history 50/week @ 2020-01-24 47/week @ 2020-01-31 31/week @ 2020-02-07 118/week @ 2020-02-14 65/week @ 2020-02-21 117/week @ 2020-02-28 53/week @ 2020-03-06 49/week @ 2020-03-13 61/week @ 2020-03-20 36/week @ 2020-03-27 37/week @ 2020-04-03 150/week @ 2020-04-10 42/week @ 2020-04-17 37/week @ 2020-04-24 15/week @ 2020-05-01 13/week @ 2020-05-08

261 downloads per month

MIT and maybe MPL-2.0



Simple and super useful DNS over HTTPS proxy server. Mostly an exercise to learn more async/await in Rust, but stable enough that I'm using this as the only DNS server on my home network.

In short this app listens on normal/legacy DNS UDP and TCP sockets on the local network. It proxies to an upstream DNS over HTTPS server and caches the results. Also supports simple forward and reverse host/IP mappings to allow authorative lookups on a local domain.

Tech Stack:

  • tokio Asnyc I/O runtime for rust. Using this directly to do async file I/O, TCP and UDP sockets, timers, and timeouts.
  • trust-dns-proto a nice library for marshalling and umarshalling binary DNS messages to Rust DTOs. Ignoring the warning that this library should not be used directly. :)
  • RFC8484 DNS over HTTPS protocol for upstream requests.
  • reqwest HTTP client. This does HTTP2, is based on hyper (which is based on tokio), and supports async/await.
  • lru LRU cache.

How do I run this?

After building with cargo, you can run the app as follows. Since this is using env_logger need to set RUST_LOG variable to get log output:

RUST_LOG=info ./target/debug/rust-doh-proxy ./config/config.json

If all is well you will see these logs that the app is listening on

[INFO  rust_doh_proxy::doh::udpserver] listening on udp
[INFO  rust_doh_proxy::doh::tcpserver] listening on tcp

Then you can use dig for example to make a DNS query to the app:

dig -p 10053 @ google.com

Normally DNS uses a privileged port 53. In this example this app is using unprivileged port 10053 to run as a normal user. The listen address and port are configurable in the configuration json file.

To use this app as a DNS server that serves requests on port 53, I use nftables on linux with a redirect rule to redirect incoming requests on port 53 to port 10053.


See config directory for examples.


See systemd directory for an example user unit file.

Cross compile

Using cross to compile for x86_64 Linux on MacOS:

cross build --target x86_64-unknown-linux-gnu --release


~284K SLoC