Files
ctrld/docs/intercept-mode-default.md
T
Cuong Manh Le bf7c264464 cli: default to dns intercept mode for new desktop installations
When no intercept mode is selected by flag or config, a new
installation on macOS or a Windows desktop edition now uses "dns".
Windows Server, iOS and other platforms keep interface DNS mode unless
intercept is selected explicitly, and so does a config that cannot run
in intercept mode.

Existing Standard installations are not switched on upgrade. ctrld
start marks the services it installs fresh, and the service applies
the default below service.intercept_mode against the config it
fetches, so a service with neither a mode nor the marker predates the
default and keeps interface DNS mode, whichever path upgrades it; the
macOS package also pins such a service to "off" explicitly. An
explicit "off" stays final and is persisted.
2026-10-20 17:23:47 +07:00

7.0 KiB

Intercept Mode Default

On the supported desktop platforms, macOS and Windows desktop (workstation) editions, a new ctrld installation runs in DNS intercept mode (dns) unless you select a mode explicitly. Everywhere else, Windows Server included, it keeps interface DNS mode, which sets ctrld's listener as the DNS server of the network interfaces. An existing installation keeps the mode it had: upgrading never switches a Standard (interface DNS) install to intercept mode. See Upgrades.

Windows Server is excluded on purpose. A server, and a domain controller running its own DNS server in particular, is not switched to intercept mode by default. Intercept mode still works there when selected explicitly.

This applies to a service that ctrld start installs and to ctrld run in the foreground alike. See DNS Intercept Mode for what intercept mode does.

Precedence

The effective mode is the first of these that is set:

  1. --intercept-mode on the command line, or in the service's arguments.
  2. service.intercept_mode in the configuration the service runs with: ctrld.toml, a --base64_config, or a Control D custom configuration.
  3. The default: dns on macOS and Windows desktop editions; interface DNS mode elsewhere, Windows Server included. An installed service that predates the default is the exception, see Upgrades.

off is a selection like dns and hard, not an absence of one. At either explicit level it stops the lookup and selects interface DNS mode, including over a persisted intercept_mode = "dns".

--intercept-mode service.intercept_mode macOS / Windows desktop Windows Server Linux and others
unset unset dns (default)² interface DNS mode interface DNS mode
unset dns / hard that mode that mode that mode¹
unset off interface DNS mode interface DNS mode interface DNS mode
dns / hard any that mode that mode that mode¹
off any interface DNS mode interface DNS mode interface DNS mode

² For a fresh install or a foreground run. An installed service that predates the default keeps interface DNS mode, see Upgrades.

¹ Intercept mode is not supported outside Windows and macOS, so an explicit dns or hard there fails to start intercept, as before. An unset mode never tries: those platforms do not log an intercept-start failure just because the default changed.

Desktop versus server follows ctrld.IsDesktopPlatform, which ctrld already uses elsewhere: on Windows it is the workstation product type (VER_NT_WORKSTATION), so Windows Server and domain controllers are not desktop platforms. iOS is not a desktop platform here either, although it builds ctrld's macOS code: it has no pf to intercept with.

The default also keeps interface DNS mode for a configuration that cannot run in intercept mode. On macOS that is any os or untyped upstream: pf would redirect ctrld's own port-53 queries to it back to ctrld. Such a configuration worked in interface DNS mode and keeps doing so; the service log says why the default was not used. Selecting dns or hard explicitly for it still fails to start intercept, as before.

The service decides the default itself, on every start, against the configuration it runs with. In Control D mode (--cd) that is the resolver's configuration it fetches, so an os upstream or an intercept_mode in a custom configuration counts, including one added after installation.

Opting out

Use interface DNS mode explicitly:

# Windows (Admin Shell)
ctrld.exe start --intercept-mode off --cd RESOLVER_ID_HERE

# macOS
sudo ctrld start --intercept-mode off --cd RESOLVER_ID_HERE

On an installed service, ctrld start --intercept-mode off with no other arguments switches the existing service to interface DNS mode, keeping its other arguments.

The selection is stored in two places, so it survives restarts and upgrades:

  • in the service's arguments, as --intercept-mode off;
  • in ctrld.toml, as intercept_mode = "off".

Earlier builds cleared intercept_mode when switching to off. That no longer works as an opt-out: an unset value now means the platform default, so switching to off writes off. Older builds read off the same way, so a downgrade keeps interface DNS mode too.

Upgrades

Only a fresh installation gets the dns default. An existing Standard (interface DNS) installation stays in Standard mode across upgrades, whichever path upgrades it.

To tell the two apart, ctrld start marks the services it installs, in the service's arguments, when no mode is selected:

  • A fresh install records --intercept-mode-default=true, an internal flag. It ranks lowest: the service applies the default only if neither --intercept-mode nor service.intercept_mode selects a mode, against the configuration it fetched.
  • A reinstall over an existing service keeps what that service recorded, its mode or the marker. If it recorded neither, it was installed in Standard mode before this default, and the reinstall records --intercept-mode off, unless service.intercept_mode selects a mode.
  • Platforms without the dns default record nothing, as before.

Older ctrld builds ignore flags they do not know in the service's arguments, so the marker is safe if a device is downgraded.

An installed service with neither a mode nor the marker therefore predates the default. It keeps interface DNS mode when the new binary runs it, and the service log says why. That covers upgrades that rewrite nothing, such as ctrld upgrade run by an older binary, which swaps the binary and restarts the service with its existing arguments. A foreground ctrld run with no mode selected uses the default.

The macOS package pins such a service explicitly when it upgrades it with a profile that has no InterceptMode: it runs ctrld start --intercept-mode off, the same as for a standard profile. See macOS MDM Package.

To move an existing Standard installation to intercept mode, select it explicitly with ctrld start --intercept-mode dns.

The Control D installer and dashboard should generate --intercept-mode off for a device where Standard mode is chosen, so a fresh install never gets intercept mode against that choice.

Where the mode is reported

  • ctrld start output: DNS intercept mode active ... once the service runs in intercept mode, followed, when the default selected it, by how to switch to interface DNS mode. A reinstall over a Standard install prints Existing service selects no intercept mode; keeping interface DNS mode (--intercept-mode off).
  • The service log, at startup: Intercept mode enabled via config when the configuration set the mode, Intercept mode "dns" is the default on this platform; ... when the default applied, or Intercept mode default not applied; using interface DNS mode with the reason, for a service that predates the default or a configuration that cannot run in intercept mode.
  • The log header field intercept_mode, which reads off for interface DNS mode.