Noureddine RAMDI / ctrld: bridging legacy DNS to secure modern protocols with policy-driven routing in Go

Created Mon, 04 May 2026 10:23:01 +0000 Modified Sat, 23 May 2026 20:41:27 +0000

Control-D-Inc/ctrld

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.


→ GitHub Repo: Control-D-Inc/ctrld ⭐ 819 · Go