DNS forwarding proxies are a staple in network infrastructure, but bridging legacy DNS clients that use UDP port 53 to secure modern DNS protocols is not trivial. ctrld tackles this challenge by acting as a multi-protocol DNS proxy written in Go that forwards DNS queries from traditional UDP 53 endpoints to secure upstreams like DoH, DoT, DoH3, and DoQ. What sets ctrld apart is its policy-driven query steering based on client IP, MAC address, or domain names, along with LAN client discovery mechanisms that integrate well with common router platforms.
ctrld: a multi-protocol DNS forwarding proxy with policy steering
ctrld is designed as a DNS forwarding proxy that listens on the legacy UDP 53 port and forwards DNS queries to secure, privacy-preserving DNS protocols upstream. These include DNS over HTTPS (DoH), DNS over TLS (DoT), DNS over HTTP/3 (DoH3), and DNS over QUIC (DoQ). The goal is to provide a seamless bridge for clients that do not support these modern protocols directly.
Written in Go, ctrld supports running on various platforms including Windows, macOS, Linux, FreeBSD, and embedded router platforms like OpenWRT, pfSense, and DD-WRT. It can run as a foreground process or as a system service, making it flexible for different deployment scenarios.
The proxy supports advanced DNS routing features such as split-horizon DNS, where queries can be routed differently based on client location or network segment. It also supports wildcard domain routing, where DNS queries matching certain patterns can be forwarded to different upstreams.
Configuration is flexible and can be done via TOML config files, CLI arguments, or an API-based auto-configuration mechanism. ctrld exposes Prometheus metrics for observability and monitoring, which is useful in production environments.
technical strengths: multi-protocol support, policy-driven routing, and LAN client discovery
What distinguishes ctrld is its comprehensive support for multiple secure DNS protocols and its policy-driven forwarding capabilities. The proxy can dynamically steer queries based on network CIDR blocks, client MAC addresses, or fully qualified domain names (FQDNs). This fine-grained control allows network administrators to enforce different DNS policies per client or group of clients.
The integration with common router firmware platforms is another strong point. ctrld performs LAN client discovery using DHCP leases, multicast DNS (mDNS), Address Resolution Protocol (ARP), and Neighbor Discovery Protocol (NDP). This means it can maintain an up-to-date view of clients on the local network without manual configuration.
Under the hood, the code is organized for concurrency and performance typical of Go network applications. While the repo does not explicitly publish benchmarks, its design choices align with efficient DNS proxying: non-blocking IO, context cancellation, and minimal external dependencies.
A tradeoff to note is the complexity introduced by supporting multiple DNS transport protocols and policy layers. This can increase the codebase size and configuration complexity. However, ctrld balances this by providing clear TOML configuration examples and CLI tooling, making it accessible without sacrificing flexibility.
From a code quality perspective, the project is actively maintained with clean modular design. It uses idiomatic Go patterns and includes integration points for metrics and API access, making it suitable for production use in diverse environments.
quick start with ctrld
Getting ctrld up and running is straightforward, with multiple installation options tailored to different platforms. Here are the commands provided by the project for quick installation:
# Quick install on UNIX-like platforms
sh -c 'sh -c "$(curl -sL https://api.controld.com/dl)"'
For Windows users preferring PowerShell, the installer command is:
(Invoke-WebRequest -Uri 'https://api.controld.com/dl/ps1' -UseBasicParsing).Content | Set-Content "$env:TEMPctrld_install.ps1"; Invoke-Expression "& '$env:TEMPctrld_install.ps1'"
Alternatively, you can run ctrld via Docker:
docker run -d --name=ctrld -p 127.0.0.1:53:53/tcp -p 127.0.0.1:53:53/udp controldns/ctrld:latest
If you prefer building from source and have Go 1.21+ installed:
go build ./cmd/ctrld
or
go install github.com/Control-D-Inc/ctrld/cmd/ctrld@latest
or build the Docker image yourself:
docker build -t controldns/ctrld . -f docker/Dockerfile
Once installed, configuring ctrld involves editing the TOML config files to define upstreams, routing policies, and client discovery settings. The README and documentation provide examples that cover common use cases.
verdict: a solid choice for secure DNS forwarding with complex routing needs
ctrld stands out as a practical, multi-protocol DNS forwarding proxy that bridges the gap between legacy DNS clients and modern secure DNS upstreams. Its policy-driven routing capabilities and LAN client discovery features make it well suited for environments where fine-grained DNS control and client awareness are required.
While the configuration and feature set introduce some complexity, the project balances this with clear documentation and flexible installation options. It’s particularly relevant for network engineers managing home or small business routers, or anyone looking to upgrade their DNS infrastructure without abandoning legacy clients.
The project is mature enough for production use, though users should be aware that the multi-protocol support and policy layers mean the system has a broader attack surface and operational complexity compared to simpler DNS forwarders. Proper monitoring, via the exposed Prometheus metrics, and careful configuration are recommended.
Overall, ctrld is worth understanding if you’re dealing with DNS security or need advanced DNS routing policies in a multi-platform environment.
Related Articles
- frp: a fast, extensible reverse proxy evolving towards cloud-native architecture — frp is a Go-based reverse proxy enabling NAT traversal with TCP/UDP/HTTP support and P2P mode. Its upcoming V2 rethinks
- Traefik: dynamic reverse proxy and load balancer for microservices — Traefik is a Go-based reverse proxy and load balancer that automatically configures routes by integrating with orchestra
- etcd: a robust distributed key-value store built on Go and Raft — etcd is a distributed key-value store in Go that uses the Raft consensus algorithm for high availability and consistency
- Caddy: a dynamic, extensible Go web server focused on automatic HTTPS and modularity — Caddy is an extensible Go web server with automatic HTTPS, dynamic API-driven config, and modular architecture, designed
- witr: tracing the full causality chain of running processes in Go — witr is a Go CLI that traces the full causality chain of any running process, replacing fragmented commands with a singl
→ GitHub Repo: Control-D-Inc/ctrld ⭐ 819 · Go