Skip to content
nxplain-shPublic

About

Self-hosted, security-hardened DNS filtering resolver in Rust: blocks ads and trackers, serves DoH, DoT and DoQ, resolves with DNSSEC, clusters with Raft and a floating IP, and sandboxes itself with Landlock and seccomp.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

goethite

A self-hosted, clustered, security-hardened DNS filtering resolver written in Rust.

goethite puts security, performance and high availability first, and covers the everyday features of a network-wide DNS filter: caching and forwarding, encrypted DNS, per-client groups and schedules, AdGuard/uBlock filter syntax, CNAME uncloaking, and a replicated cluster with a floating IP and zero-downtime upgrades. It is named after the iron-oxide mineral that is a main component of rust.

Quick start (development)

Requires Rust via rustup. The pinned toolchain (1.99.0) installs automatically from rust-toolchain.toml.

cargo run -- run --config config/goethite.example.toml

In another terminal:

dig @127.0.0.1 -p 15353 goethite.test        # -> 127.0.0.53, answered by goethite itself
dig @127.0.0.1 -p 15353 example.com          # -> forwarded to Quad9 over DNS over TLS
dig @127.0.0.1 -p 15353 example.com +tcp     # same, client side over TCP
dig @127.0.0.1 -p 15353 doubleclick.net      # -> 0.0.0.0, blocked by the example rules

The example config forwards to Quad9 over DNS over TLS. Upstreams are configured in [[upstream]] tables (udp, tcp, tls or https) and at least one is required, or [recursion] enabled = true resolves every name from the root servers down; see config/goethite.example.toml.

Development binds to 127.0.0.1:15353, so no root is needed (port 5353 is avoided because multicast DNS already uses it on most desktops). Logs go to stderr and are controlled by RUST_LOG (default info; malformed packets are logged at debug):

RUST_LOG=debug cargo run -- run --config config/goethite.example.toml

Ctrl-C or SIGTERM shuts the server down gracefully. goethite check-config --config <path> checks a config file and its filter lists without starting the server.

While it runs, cargo run -- tui opens the terminal UI, and the REST API answers on http://127.0.0.1:8053/api/v1 (see the API docs). The web UI is at http://127.0.0.1:8053/ once it is built (Node.js 22.19+; CI and release builds use the version in web/.node-version):

cd web && npm ci --ignore-scripts && npm run build

Repository layout

Path Purpose
crates/goethite-proto DNS wire format; wraps hickory-proto behind our own trait and types
crates/goethite-filter Rule parsing (hosts, domain lists, AdGuard syntax) and FST/Bloom compiler
crates/goethite-resolver Cache, forwarding, recursion with DNSSEC validation
crates/goethite-server Listeners: UDP, TCP, DoT, DoH, DoQ; the Oblivious DoH target
crates/goethite-cluster Raft for the config (openraft), the witness, and VRRP
crates/goethite-api REST API (/api/v1) with OpenAPI
crates/goethite-store Embedded storage for query log, stats and config
crates/goethite-tui Terminal UI that talks to the API
crates/goethite-migrate Plans a migration from Pi-hole or AdGuard Home (goethite migrate)
crates/goethite The binary: CLI, wiring, signal handling
xtask/ Repository automation: cargo xtask ci runs the checks CI runs
web/ Web UI (Vite+, React, TanStack Router), embedded into the binary
site/ Project website and docs (TanStack Start), deployed to GitHub Pages
fuzz/ cargo-fuzz targets
tests/chaos/ Chaos tests: two nodes, a witness and a client in network namespaces
tests/packages/ Installs the .deb and .rpm on each supported distribution
deploy/ Systemd units, server config, Helm chart, package and container image definitions
config/ The example configuration
docs/ Threat model, security review, branching and releases, ADRs, backlog

Benchmarks and how to record them are in bench/. The layout follows the standard Rust project layout; ADR 0025 records where goethite deviates from it.

Documentation

Independent implementation

goethite is its own code, written from scratch. Nothing in it is copied from Pi-hole, AdGuard Home, NextDNS, Numa or any other DNS filter, translated from another language, or used as a template. What it does comes from the DNS RFCs, the published formats of the filter lists it reads (hosts files, domain lists, AdGuard-style rules) and its own design, which the ADRs record.

Other projects were studied, never copied, in three places, all linked so anyone can check them:

  • Competitor features records what the other projects do, citing their documentation and source, so goethite can decide what to build. It lists features, not code.
  • Observability research records how other DNS servers and OpenTelemetry handle metrics, logs and traces, citing their documentation and source. It lists choices, not code.
  • goethite migrate reads Pi-hole's and AdGuard Home's web APIs, so the shape of their answers was checked against their source, for interoperability only (ADR 0030).

No third-party data is compiled into goethite either: filter lists and AdGuard's blocked-services catalog (GPL-3.0) are downloaded at runtime from their publishers, under their own licenses (ADR 0019, ADR 0022). The libraries goethite builds on, such as hickory-proto, are declared dependencies whose licenses cargo deny checks. Contributions are held to the same rule: send only code you wrote yourself.

License

goethite is free software under the GNU Affero General Public License, version 3 only (AGPL-3.0-only). You may run, study, change and share it. If you distribute it, or run a changed version that others use over a network (for a DNS server, every client that queries it), you must offer them its source under the same license.

Releases up to and including v0.5.0 were published under MIT OR Apache-2.0 and keep that license. ADR 0033 explains the change.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in goethite by you, as defined in the Apache-2.0 license, is licensed under the Apache License, Version 2.0, without any additional terms or conditions. goethite ships it under the AGPL-3.0-only with the rest of the code. Because Apache-2.0 is permissive, the maintainers can also offer goethite, your contribution included, under other terms, such as a hosted service or a commercial license.

About

Self-hosted, security-hardened DNS filtering resolver in Rust: blocks ads and trackers, serves DoH, DoT and DoQ, resolves with DNSSEC, clusters with Raft and a floating IP, and sandboxes itself with Landlock and seccomp.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages