This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
RouteDNS is a composable DNS stub resolver, proxy and router written in Go. It builds processing pipelines from four component types (listeners, resolvers, groups/modifiers, routers) configured via TOML files.
# Build
go build -o cmd/desync/ ./cmd/routedns
# Run all tests
go test ./...
# Run a single test
go test -run TestCacheLookupAndExpiry ./...
# Run tests in a specific package
go test ./dnssec/
# Run with race detector
go test -race ./...
# Run the binary
routedns config.tomlThere is no Makefile or linter configuration. CI uses GitHub Actions with CodeQL analysis only.
Every component in the pipeline implements the Resolver interface (resolver.go):
type Resolver interface {
Resolve(*dns.Msg, ClientInfo) (*dns.Msg, error)
fmt.Stringer
}This single interface is implemented by clients, groups, modifiers, and routers alike, enabling arbitrary composition.
Listeners (receive DNS queries over UDP/TCP/DoT/DoH/DoQ/DTLS/ODoH)
↓
Routers (route based on query name, type, source IP, time, etc.)
↓
Groups/Modifiers (cache, blocklist, load-balance, transform)
↓
Resolvers/Clients (forward to upstream DNS servers)
- Listeners (
Listenerinterface inlistener.go): Entry points that accept DNS queries. Each protocol has its own file (e.g.,dohlistener.go,dotlistener.go,doqlistener.go). - Clients/Resolvers: Forward queries upstream. Each protocol is in its own file (
dnsclient.gofor UDP/TCP,dotclient.go,dohclient.go,doqclient.go,dtlsclient.go,odohclient.go). - Groups/Modifiers (~30 types): Wrap one or more resolvers to add behavior — caching (
cache.go), blocklists (blocklist-v2.go), load-balancing (round-robin.go,failrotate.go,fastest.go), rate limiting (rate-limiter.go), query/response modification, etc. - Routers (
router.go): Conditional routing based on query properties (name regex, type, source IP, time of day, etc.). Routes evaluated in order; first match wins.
TOML-based configuration defined in cmd/routedns/config.go. Four top-level sections: [listeners], [resolvers], [groups], [routers]. Component instantiation in cmd/routedns/resolver.go uses a DAG (github.com/heimdalr/dag) to resolve dependencies bottom-up, preventing circular references.
Multiple config files can be provided as arguments and are merged.
- Go package name:
rdns(import asgithub.com/folbricht/routedns) - Composition via Resolver interface: Groups/modifiers wrap inner resolvers, creating decorator chains
- Options structs: Constructors take
*XxxOptionsstructs (e.g.,CacheOptions,DNSClientOptions) - Metrics: Components export metrics via
expvarusing the patternroutedns.<base>.<id>.<metric> - Graceful shutdown:
onClosefunctions registered globally, triggered on SIGTERM/SIGINT - Blocklist databases:
BlocklistDBinterface with implementations for domains, regex, hosts, CIDR, GeoIP, ASN, MAC formats
Tests use a TestResolver mock (returns the query as-is or a configured response). Test files live alongside source files. Some tests require network access (DoH/DoT/DoQ client tests connect to real servers).