# ctrld ![Test](https://github.com/Control-D-Inc/ctrld/actions/workflows/ci.yml/badge.svg) [![Go Reference](https://pkg.go.dev/badge/github.com/Control-D-Inc/ctrld.svg)](https://pkg.go.dev/github.com/Control-D-Inc/ctrld) [![Go Report Card](https://goreportcard.com/badge/github.com/Control-D-Inc/ctrld)](https://goreportcard.com/report/github.com/Control-D-Inc/ctrld) ![ctrld splash image](/docs/ctrldsplash.png) A highly configurable DNS forwarding proxy with support for: - Multiple listeners for incoming queries - Multiple upstreams with fallbacks - Multiple network policy driven DNS query steering (via network cidr, MAC address or FQDN) - Policy driven domain based "split horizon" DNS with wildcard support - LAN client discovery via DHCP, mDNS, ARP, NDP, hosts file parsing - Prometheus metrics exporter ## TLDR Proxy legacy DNS traffic to secure DNS upstreams in highly configurable ways. All DNS protocols are supported, including: - `UDP 53` - `DNS-over-HTTPS` - `DNS-over-TLS` - `DNS-over-HTTP/3` (DOH3) - `DNS-over-QUIC` # Use Cases 1. Use secure DNS protocols on networks and devices that don't natively support them (legacy OSes, TVs, smart toasters). 2. Create source IP based DNS routing policies with variable secure DNS upstreams. Subnet 1 (admin) uses upstream resolver A, while Subnet 2 (employee) uses upstream resolver B. 3. Create destination IP based DNS routing policies with variable secure DNS upstreams. Listener 1 uses upstream resolver C, while Listener 2 uses upstream resolver D. 4. Create domain level "split horizon" DNS routing policies to send internal domains (*.company.int) to a local DNS server, while everything else goes to another upstream. ## OS Support - Windows Desktop (386, amd64, arm) - MacOS (amd64, arm64) - Linux (386, amd64, arm, mips) - FreeBSD (386, amd64, arm) # Install There are several ways to download and install `ctrld`. ## Quick Install The simplest way to download and install `ctrld` is to use the following installer command on any UNIX-like platform: ```shell sh -c 'sh -c "$(curl -sL https://api.controld.com/dl?version=2)"' ``` Windows user and prefer Powershell (who doesn't)? No problem, execute this command instead in administrative PowerShell: ```shell (Invoke-WebRequest -Uri 'https://api.controld.com/dl/ps1?version=2' -UseBasicParsing).Content | Set-Content "$env:TEMPctrld_install.ps1"; Invoke-Expression "& '$env:TEMPctrld_install.ps1'" ``` Or you can pull and run a Docker container from [Docker Hub](https://hub.docker.com/r/controldns/ctrld) ```shell docker run -d --name=ctrld -p 127.0.0.1:53:53/tcp -p 127.0.0.1:53:53/udp controldns/ctrld:latest ``` ## Download Manually Alternatively, if you know what you're doing you can download pre-compiled binaries from the [Releases](https://github.com/Control-D-Inc/ctrld/releases) section for the appropriate platform. ## Build Lastly, you can build `ctrld` from source which requires `go1.23+`: ```shell go build ./cmd/ctrld ``` or ```shell go install github.com/Control-D-Inc/ctrld/cmd/ctrld@latest ``` or ```shell docker build -t controldns/ctrld . -f docker/Dockerfile ``` # Usage The cli is self documenting, so feel free to run `--help` on any sub-command to get specific usages. ## Arguments ``` __ .__ .___ _____/ |________| | __| _/ _/ ___\ __\_ __ \ | / __ | \ \___| | | | \/ |__/ /_/ | \___ >__| |__| |____/\____ | \/ dns forwarding proxy \/ Usage: ctrld [command] Available Commands: run Run the DNS proxy server start Quick start service and configure DNS on interface stop Quick stop service and remove DNS from interface restart Restart the ctrld service reload Reload the ctrld service status Show status of the ctrld service uninstall Stop and uninstall the ctrld service service Manage ctrld service clients Manage clients upgrade Upgrading ctrld to latest version log Manage runtime debug logs Flags: -h, --help help for ctrld -s, --silent do not write any log output -v, --verbose count verbose log output, "-v" basic logging, "-vv" debug logging --version version for ctrld Use "ctrld [command] --help" for more information about a command. ``` ## Basic Run Mode This is the most basic way to run `ctrld`, in foreground mode. Unless you already have a config file, a default one will be generated. ### Command Windows (Admin Shell) ```shell ctrld.exe run ``` Linux or Macos ```shell sudo ctrld run ``` You can then run a test query using a DNS client, for example, `dig`: ``` $ dig verify.controld.com @127.0.0.1 +short api.controld.com. 147.185.34.1 ``` If `verify.controld.com` resolves, you're successfully using the default Control D upstream. From here, you can start editing the config file that was generated. To enforce a new config, restart the server. ## Service Mode This mode will run the application as a background system service on any Windows, MacOS, Linux or FreeBSD distribution. This will create a generic `ctrld.toml` file in the **C:\ControlD** directory (on Windows) or `/etc/controld/` (almost everywhere else), start the system service, and **configure the listener on all physical network interface**. Service will start on OS boot. ### Command Windows (Admin Shell) ```shell ctrld.exe start ``` Linux or Macos ``` sudo ctrld start ``` If `ctrld` is not in your system path (you installed it manually), you will need to run the above commands from the directory where you installed `ctrld`. In order to stop the service, and restore your DNS to original state, simply run `ctrld stop`. If you wish to stop and uninstall the service permanently, run `ctrld uninstall`. ## Unmanaged Service Mode This mode functions similarly to the "Service Mode" above except it will simply start a system service and the config defined listeners, but **will not make any changes to any network interfaces**. You can then set the `ctrld` listener(s) IP on the desired network interfaces manually. ### Command Windows (Admin Shell) ```shell ctrld.exe service start ``` Linux or Macos ```shell sudo ctrld service start ``` # Configuration `ctrld` can be configured in variety of different ways, which include: API, local config file or via cli launch args. ## API Based Auto Configuration Application can be started with a specific Control D resolver config, instead of the default one. Simply supply your Resolver ID with a `--cd` flag, when using the `start` (service) mode. This mode is used when the 1 liner installer command from the Control D onboarding guide is executed. The following command will use your own personal Control D Device resolver, and start the application in service mode. Your resolver ID is displayed on the "Show Resolvers" screen for the relevant Control D Endpoint. Windows (Admin Shell) ```shell ctrld.exe start --cd abcd1234 ``` Linux or Macos ```shell sudo ctrld start --cd abcd1234 ``` Once you run the above command, the following things will happen: - You resolver configuration will be fetched from the API, and config file templated with the resolver data - Application will start as a service, and keep running (even after reboot) until you run the `stop` or `uninstall` sub-commands - All physical network interface will be updated to use the listener started by the service - All DNS queries will be sent to the listener ## Manual Configuration `ctrld` is entirely config driven and can be configured in many different ways, please see [Configuration Docs](docs/config.md). ### Example ```toml [listener] [listener.0] ip = '0.0.0.0' port = 53 [network] [network.0] cidrs = ["0.0.0.0/0"] name = "Network 0" [upstream] [upstream.0] bootstrap_ip = "76.76.2.11" endpoint = "https://freedns.controld.com/p1" name = "Control D - Anti-Malware" timeout = 5000 type = "doh" ``` The above basic config will: - Start listener on 0.0.0.0:53 - Accept queries from any source address - Send all queries to `https://freedns.controld.com/p1` using DoH protocol ## CLI Args If you're unable to use a config file, `ctrld` can be be supplied with basic configuration via launch arguments, in [Ephemeral Mode](docs/ephemeral_mode.md). ### Example ``` ctrld run --listen=127.0.0.1:53 --primary_upstream=https://freedns.controld.com/p2 --secondary_upstream=10.0.10.1:53 --domains=*.company.int,very-secure.local --log /path/to/log.log ``` The above will start a foreground process and: - Listen on `127.0.0.1:53` for DNS queries - Forward all queries to `https://freedns.controld.com/p2` using DoH protocol, while... - Excluding `*.company.int` and `very-secure.local` matching queries, that are forwarded to `10.0.10.1:53` - Write a debug log to `/path/to/log.log` ## DNS Intercept Mode When running `ctrld` alongside VPN software, DNS conflicts can cause intermittent failures, bypassed filtering, or configuration loops. DNS Intercept Mode prevents these issues by transparently capturing all DNS traffic on the system and routing it through `ctrld`, without modifying network adapter DNS settings. ### When to Use Enable DNS Intercept Mode if you: - Use corporate VPN software (F5, Cisco AnyConnect, Palo Alto GlobalProtect, Zscaler) - Run overlay networks like Tailscale or WireGuard - Experience random DNS failures when VPN connects/disconnects - See gaps in your Control D analytics when VPN is active - Have endpoint security software that also manages DNS ### Command Windows (Admin Shell) ```shell ctrld.exe start --intercept-mode dns --cd RESOLVER_ID_HERE ``` macOS ```shell sudo ctrld start --intercept-mode dns --cd RESOLVER_ID_HERE ``` `--intercept-mode dns` automatically detects VPN internal domains and routes them to the VPN's DNS server, while Control D handles everything else. To disable intercept mode on a service that already has it enabled: Windows (Admin Shell) ```shell ctrld.exe start --intercept-mode off ``` macOS ```shell sudo ctrld start --intercept-mode off ``` This removes the intercept rules and reverts to standard interface-based DNS configuration. ### Platform Support | Platform | Supported | Mechanism | |----------|-----------|-----------| | Windows | ✅ | NRPT (Name Resolution Policy Table) | | macOS | ✅ | pf (packet filter) redirect | | Linux | ❌ | Not currently supported | ### Features - **VPN split routing** — VPN-specific domains are automatically detected and forwarded to the VPN's DNS server - **Captive portal recovery** — Wi-Fi login pages (hotels, airports, coffee shops) work automatically - **No network adapter changes** — DNS settings stay untouched, eliminating conflicts entirely - **Automatic port 53 conflict resolution** — if another process (e.g., `mDNSResponder` on macOS) is already using port 53, `ctrld` automatically listens on a different port. OS-level packet interception redirects all DNS traffic to `ctrld` transparently, so no manual configuration is needed. This only applies to intercept mode. ### Tested VPN Software - F5 BIG-IP APM - Cisco AnyConnect - Palo Alto GlobalProtect - Tailscale (including Exit Nodes) - Windscribe - WireGuard For more details, see the [DNS Intercept Mode documentation](https://docs.controld.com/docs/dns-intercept). ## Contributing See [Contribution Guideline](./docs/contributing.md)