# The Story — Why This Project Exists ## The Problem In countries with internet censorship (Iran, China, Russia, and others), DNS is one of the first things controlled. ISPs intercept plain DNS queries (UDP/TCP port 53) and: - Return fake IP addresses for blocked domains - Log every domain you look up - Inject ads or redirect to government portals ```mermaid sequenceDiagram participant User participant ISP as ISP DNS participant Real as Real Server User->>ISP: youtube.com? ISP-->>User: 1.2.3.4 (FAKE IP) User->>Real: HTTPS to 1.2.3.4 Real-->>User: ❌ Connection failed / redirected ``` DNS-over-HTTPS (DoH) and DNS-over-TLS (DoT) solve this by encrypting DNS queries, making them invisible to the ISP's DNS layer. ## What Already Exists This is not a new problem. Mature tools already solve local DNS → DoH forwarding: | Tool | What it does | Maintained by | |---|---|---| | `cloudflared` | Local DNS → DoH proxy (`cloudflared proxy-dns`) | Cloudflare | | `dnscrypt-proxy` | DoH + DoT + anonymized relays, blocklists | Frank Denis | | `stubby` | Local DNS → DoT proxy | getdns team | | `systemd-resolved` | Built into systemd, supports DoT | systemd team | | `AdGuard Home` | DNS proxy + DoH/DoT + web UI + blocklists | AdGuard | For simple "local DNS → DoH" forwarding, **`cloudflared proxy-dns` does exactly what this project does in one command:** ```bash cloudflared proxy-dns --port 5353 --upstream https://cloudflare-dns.com/dns-query ``` ## The Real Obstacle The harder problem — and the one most relevant to censored regions — is that **upstream DoH/DoT endpoints themselves get blocked:** | Technique | What gets blocked | How | |---|---|---| | SNI inspection | `cloudflare-dns.com`, `dns.google` | TLS ClientHello reveals the domain | | IP blocklist | Known resolver IPs (1.1.1.1, 8.8.8.8) | Direct IP blocking | | TLS fingerprinting | DoH/DoT traffic patterns | JA3/JA4 fingerprint analysis | | Deep packet inspection | HTTPS traffic to known DNS resolvers | Pattern matching on domain + path | A local forwarder that sends `POST https://cloudflare-dns.com/dns-query` will work in most of the world, but **will likely fail in Iran** because the connection to Cloudflare itself is blocked. ```mermaid sequenceDiagram participant Client participant FW as Firewall / DPI participant CF as Cloudflare DoH Client->>FW: POST https://cloudflare-dns.com/dns-query FW->>FW: Inspect SNI: cloudflare-dns.com FW-->>Client: ❌ BLOCKED (connection reset) ``` ## What Actually Works in Censored Environments Tools that solve the **upstream blocking** problem: 1. **Warp / WireGuard** — tunnel all traffic (including DNS) through an encrypted VPN. The ISP sees WireGuard traffic but can't inspect it. 2. **GoodbyeDPI / zapret** — packet manipulation to evade DPI without a VPN. Modifies TCP flags, splits packets, fakes SNI. 3. **dnscrypt-proxy with anonymized relays** — DNS queries go through intermediate relays. The resolver never sees your IP, and the ISP never sees the resolver's IP. 4. **Tor** — route DNS through Tor exit nodes. Slow but highly resistant. 5. **Encrypted Client Hello (ECH)** — hides the SNI field in TLS handshakes. Still emerging; not widely supported. ## So Is This Project Necessary? **Honestly: no, not for its current functionality.** If the goal is "use encrypted DNS from Linux in a censored region," install `cloudflared` or `dnscrypt-proxy` + a Warp/WireGuard tunnel. These are battle-tested, maintained by teams, and packaged in every distro. ## Where This Project Becomes Useful This project becomes **genuinely valuable** if it evolves beyond a basic forwarder. Directions that matter: ### 1. Upstream obfuscation (the real differentiator) Route upstream DoH traffic through a proxy (SOCKS5, HTTP CONNECT, or WireGuard tunnel) instead of direct HTTPS. This bypasses SNI and IP blocking: ```mermaid flowchart LR client["DNS Client"] -- "UDP/TCP" --> forwarder["doh-forwarder"] forwarder -- "SOCKS5/CONNECT" --> proxy["Proxy Server"] proxy -- "HTTPS" --> doh["DoH Resolver"] doh -- "DNS response" --> proxy proxy -- "DNS response" --> forwarder forwarder -- "DNS response" --> client ``` No existing lightweight Rust tool does this well. `dnscrypt-proxy` has anonymized relays but no SOCKS5 support for DoH. ### 2. Pluggable transport layer Support multiple upstream transports: - **Direct DoH** (current — works in free internet) - **DoH over SOCKS5** (works behind blocks) - **DoH over WireGuard tunnel** (works behind aggressive DPI) - **DNS-over-TLS** (for resolvers that support it) The user picks the transport based on their environment. ### 3. Smart upstream selection Don't just round-robin — **probe** upstreams for latency and availability. Auto-switch when a resolver becomes unreachable. This matters when resolvers get blocked intermittently. ### 4. Built-in blocklist support Ad-blocking and malware-blocking at the DNS level. `dnscrypt-proxy` and `AdGuard Home` do this, but a lightweight Rust binary with this built-in is appealing for embedded/resource-constrained systems. ### 5. Learning Even if you never deploy it, building this teaches: - DNS wire format (RFC 1035) - DoH protocol (RFC 8484) - Rust async (Tokio, Axum) - Network programming - Error handling patterns That alone justifies the project. ## Summary | Question | Answer | |---|---| | Does this solve local DNS → DoH? | Yes, but `cloudflared` already does this | | Does this bypass censorship? | No — upstream DoH endpoints get blocked | | Is the project pointless? | No — it's a foundation for something better | | What makes it worth building? | SOCKS5/proxy upstream support, pluggable transports, learning | The project is a **starting point**, not a finished solution. The first 80% (local DNS → DoH forwarding) is solved by existing tools. The last 20% (bypassing upstream blocking) is where this project can differentiate.