Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
51e58b6
Preparing for v2.0.0 branch merge
cuonglm Oct 9, 2025
31517ce
all: unify code to handle static DNS file path
cuonglm May 5, 2025
5641aab
all: unify handling user home directory logic
cuonglm May 5, 2025
fc527db
all: eliminate usage of global ProxyLogger
cuonglm Apr 3, 2025
b9b9cfc
cmd/cli: avoid accessing mainLog when possible
cuonglm Jun 17, 2025
64632fa
cmd/cli: use resolvconffile lib for parsing
cuonglm Jun 17, 2025
f0cb810
all: move nameserver resolution to public API
cuonglm Jun 18, 2025
c736f4c
test: improve DNS resolver tests reliability and thread safety
cuonglm Jun 18, 2025
7a2277b
refactor: move client info handling to desktop-specific files
cuonglm Jun 18, 2025
d5cb327
docs: improve test resolv.conf handling documentation
cuonglm Jun 18, 2025
59ece45
refactor: improve network interface validation
cuonglm Jun 19, 2025
a16b25a
refactor: move getDNS type to os_linux.go
cuonglm Jun 19, 2025
b18cd7e
refactor(dns): improve DNS proxy code structure and readability
cuonglm Jun 19, 2025
0ef02bc
internal/router: support Merlin Guest Network Pro VLAN
cuonglm Jun 30, 2025
b2a54db
internal/router: support Ubios 4.3+
cuonglm Jul 8, 2025
2e63624
Removing router platforms support
cuonglm Jun 30, 2025
f7fb555
Removing Windows Server support
cuonglm Jul 3, 2025
41282d0
refactor: break down proxy method into smaller focused functions
cuonglm Jul 7, 2025
05d183c
Correct debug logging in DNS-over-HTTP transport
cuonglm Jul 7, 2025
84d4491
refactor: split selfUpgradeCheck into version check and upgrade execu…
cuonglm Jul 14, 2025
a67aea8
cmd/cli: ignore empty positional argument for start command
cuonglm Jul 15, 2025
65a300a
refactor: extract empty string filtering to reusable function
cuonglm Jul 15, 2025
35e2a20
Refactor handleRecovery method and improve tests
cuonglm Jul 16, 2025
2996a16
Fix tautological condition in findWorkingInterface
cuonglm Jul 16, 2025
ddbb0f0
refactor: migrate from zerolog to zap logging library
cuonglm Jul 21, 2025
ec85b16
fix: improve listener configuration and error logging
cuonglm Jul 22, 2025
69b192c
feat: add custom NOTICE log level between INFO and WARN
cuonglm Jul 22, 2025
b5f101f
feat: add interfaces and types for command refactoring
cuonglm Jul 28, 2025
fc8268b
feat: create commands_log.go and add LogCommand
cuonglm Jul 28, 2025
6e10bba
feat: create commands_service.go and add ServiceCommand
cuonglm Jul 28, 2025
0a1d6fa
feat: create commands_upgrade.go and add UpgradeCommand with complete…
cuonglm Jul 28, 2025
0ab51cd
feat: create commands_clients.go and add ClientsCommand with complete…
cuonglm Jul 28, 2025
59fe941
feat: create commands_interfaces.go and add InterfacesCommand
cuonglm Jul 28, 2025
5b8ed3a
feat: port complete alias command logic from original implementation
cuonglm Jul 28, 2025
d4df2e7
refactor: remove old initLogCmd and integrate new log command structure
cuonglm Jul 28, 2025
13b15e6
refactor: consolidate service commands into modular structure with co…
cuonglm Jul 28, 2025
af93865
cleanup: remove unused service command functions from commands.go
cuonglm Jul 29, 2025
42ea5f7
refactor: move initRunCmd to dedicated commands_run.go file
cuonglm Jul 29, 2025
13de41d
refactor: rename service_manager.go and remove unused CommandRunner i…
cuonglm Jul 29, 2025
9f65626
fix: complete porting of initUninstallCmd logic to ServiceCommand.Uni…
cuonglm Jul 29, 2025
a22f057
refactor: split ServiceCommand methods into dedicated files
cuonglm Jul 29, 2025
ca505f1
refactor: fix createStartCommands to follow single responsibility pri…
cuonglm Jul 29, 2025
37523fd
fix: register uninstall command before interfaces command
cuonglm Jul 29, 2025
5f0b9a2
refactor: improve ServiceManager initialization with cleaner API
cuonglm Jul 30, 2025
af05cb2
refactor: replace direct newService calls with ServiceCommand pattern
cuonglm Jul 30, 2025
a2f8313
refactor: pass rootCmd as parameter to Init*Cmd functions
cuonglm Jul 30, 2025
6971d39
fix: reorder service command additions for consistency
cuonglm Jul 30, 2025
ea98a59
fix: add missing flags to uninstall command
cuonglm Jul 30, 2025
954395f
fix: restore missing logic from refactoring
cuonglm Jul 30, 2025
1ff5d1f
test: add comprehensive CLI command tests
cuonglm Jul 31, 2025
0cd873a
refactor: move network monitoring to separate goroutine
cuonglm Aug 1, 2025
7cda5d7
fix: correct Windows API constants to fix domain join detection
cuonglm Aug 1, 2025
8b605da
refactor: convert rootCmd from global to local variable
cuonglm Aug 5, 2025
d88c860
Add explanatory comments for variable overwrites and code flow decisions
cuonglm Aug 6, 2025
4792183
Add comprehensive documentation to CLI components and core functionality
cuonglm Aug 7, 2025
2c98b2c
refactor(prog): move network monitoring outside listener loop
cuonglm Aug 11, 2025
a72ff1e
fix: ensure upstream health checks can handle large DNS responses
cuonglm Aug 15, 2025
3412d1f
start mobile library with provision id and custom hostname.
Ginder-Singh Aug 20, 2025
5d87bd0
feat: enhance logging in service commands with consistent logger usage
cuonglm Sep 3, 2025
a084c87
fix: use background context for DNS listeners to survive reloads
cuonglm Sep 3, 2025
b7202f8
feat: enhance DNS proxy logging with comprehensive flow tracking
cuonglm Sep 4, 2025
d87a0a6
feat: enhance configuration and network management logging
cuonglm Sep 4, 2025
3bcad10
feat: enhance CLI commands and service management logging
cuonglm Sep 4, 2025
eb8c5bc
feat: enhance internal components and utilities logging
cuonglm Sep 4, 2025
54f58cc
feat: capitalize all log messages for better readability
cuonglm Sep 4, 2025
f6be1ab
docs: add known issues documentation for Darwin 15.5 upgrade issue
cuonglm Sep 5, 2025
59b9824
feat: enhance log reading with ANSI color stripping and comprehensive…
cuonglm Sep 8, 2025
a04babb
Upgrade quic-go to v0.54.0
cuonglm Sep 9, 2025
56f8113
refactor: replace Unix socket log communication with HTTP-based system
cuonglm Sep 12, 2025
ed826f7
Change download url for v2
cuonglm Sep 23, 2025
f7c124d
feat: add --rfc1918 flag for explicit LAN client support
cuonglm Sep 24, 2025
fb807d7
refactor: consolidate network interface detection logic
cuonglm Oct 1, 2025
ef7432d
Fix staticcheck linter
cuonglm Oct 9, 2025
3afdaef
refactor: extract rule matching logic into internal/rulematcher package
cuonglm Sep 16, 2025
adc0e1a
feat: add configurable rule matching engine
cuonglm Sep 16, 2025
4c838f6
feat: add configurable rule matching with improved code structure
cuonglm Sep 16, 2025
92f32ba
refactor: remove unused StopOnFirstMatch field from MatchingConfig
cuonglm Sep 16, 2025
d42a78c
docs: add comprehensive package documentation for rulematcher
cuonglm Sep 22, 2025
c13a3c3
cmd/cli: ensure error message ends with newline
cuonglm Oct 3, 2025
90eddb8
cmd/cli: workaround TB.TemdDir path too long for Unix socket path
cuonglm Oct 9, 2025
36d4192
Upgrade quic-go to v0.56.0
cuonglm Nov 11, 2025
f9d0263
.github/workflows: upgrade staticcheck-action to v1.4.0
cuonglm Nov 12, 2025
7006e96
docs: add v2.0.0 breaking changes documentation
cuonglm Oct 2, 2025
34fef77
Upgrade quic-go to v0.57.0
cuonglm Dec 16, 2025
d0e66b8
.github/workflows: temporary use actions/setup-go
cuonglm Dec 17, 2025
2e53fa4
docs: add documentation for runtime internal logging
cuonglm Dec 16, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,12 @@ jobs:
- uses: actions/checkout@v3
with:
fetch-depth: 1
- uses: WillAbides/setup-go-faster@v1.8.0
- uses: actions/setup-go@v6
with:
go-version: ${{ matrix.go }}
- run: "go test -race ./..."
- uses: dominikh/staticcheck-action@v1.3.1
- uses: dominikh/staticcheck-action@v1.4.0
with:
version: "2025.1"
version: "2025.1.1"
install-go: false
cache-key: ${{ matrix.go }}
39 changes: 9 additions & 30 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ A highly configurable DNS forwarding proxy with support for:
- 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
- Integrations with common router vendors and firmware
- LAN client discovery via DHCP, mDNS, ARP, NDP, hosts file parsing
- Prometheus metrics exporter

Expand All @@ -26,35 +25,17 @@ All DNS protocols are supported, including:
- `DNS-over-QUIC`

# Use Cases
1. Use secure DNS protocols on networks and devices that don't natively support them (legacy routers, legacy OSes, TVs, smart toasters).
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.
5. Deploy on a router and create LAN client specific DNS routing policies from a web GUI (When using ControlD.com).


## OS Support
- Windows (386, amd64, arm)
- Windows Server (386, amd64)
- Windows Desktop (386, amd64, arm)
- MacOS (amd64, arm64)
- Linux (386, amd64, arm, mips)
- FreeBSD (386, amd64, arm)
- Common routers (See below)


### Supported Routers
You can run `ctrld` on any supported router. The list of supported routers and firmware includes:
- Asus Merlin
- DD-WRT
- Firewalla
- FreshTomato
- GL.iNet
- OpenWRT
- pfSense / OPNsense
- Synology
- Ubiquiti (UniFi, EdgeOS)

`ctrld` will attempt to interface with dnsmasq (or Windows Server) whenever possible and set itself as the upstream, while running on port 5354. On FreeBSD based OSes, `ctrld` will terminate dnsmasq and unbound in order to be able to listen on port 53 directly.

# Install
There are several ways to download and install `ctrld`.
Expand All @@ -63,12 +44,12 @@ There are several ways to download and install `ctrld`.
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)"'
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' -UseBasicParsing).Content | Set-Content "$env:TEMPctrld_install.ps1"; Invoke-Expression "& '$env:TEMPctrld_install.ps1'"
(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)
Expand All @@ -80,7 +61,7 @@ docker run -d --name=ctrld -p 127.0.0.1:53:53/tcp -p 127.0.0.1:53:53/udp control
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.21+`:
Lastly, you can build `ctrld` from source which requires `go1.23+`:

```shell
go build ./cmd/ctrld
Expand Down Expand Up @@ -130,7 +111,7 @@ Available Commands:
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 level logging
-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.
Expand Down Expand Up @@ -161,9 +142,7 @@ You can then run a test query using a DNS client, for example, `dig`:
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, FreeBSD distribution or supported router. 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.

When Control D upstreams are used on a router type device, `ctrld` will [relay your network topology](https://docs.controld.com/docs/device-clients) to Control D (LAN IPs, MAC addresses, and hostnames), and you will be able to see your LAN devices in the web panel, view analytics and apply unique profiles to them.
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

Expand Down Expand Up @@ -200,7 +179,7 @@ Linux or Macos
`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. In this mode, the application will automatically choose a non-conflicting IP and/or port and configure itself as the upstream to whatever process is running on port 53 (like dnsmasq or Windows DNS Server). This mode is used when the 1 liner installer command from the Control D onboarding guide is executed.
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.

Expand All @@ -217,7 +196,7 @@ 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 or dnsmasq upstream will be switched to `ctrld`
- 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
Expand Down
4 changes: 0 additions & 4 deletions client_info_darwin.go

This file was deleted.

6 changes: 0 additions & 6 deletions client_info_others.go

This file was deleted.

18 changes: 0 additions & 18 deletions client_info_windows.go

This file was deleted.

5 changes: 0 additions & 5 deletions cmd/cli/ad_others.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,3 @@ import (

// addExtraSplitDnsRule adds split DNS rule if present.
func addExtraSplitDnsRule(_ *ctrld.Config) bool { return false }

// getActiveDirectoryDomain returns AD domain name of this computer.
func getActiveDirectoryDomain() (string, error) {
return "", nil
}
8 changes: 4 additions & 4 deletions cmd/cli/ad_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ import (
func addExtraSplitDnsRule(cfg *ctrld.Config) bool {
domain, err := getActiveDirectoryDomain()
if err != nil {
mainLog.Load().Debug().Msgf("unable to get active directory domain: %v", err)
mainLog.Load().Debug().Msgf("Unable to get active directory domain: %v", err)
return false
}
if domain == "" {
mainLog.Load().Debug().Msg("no active directory domain found")
mainLog.Load().Debug().Msg("No active directory domain found")
return false
}
// Network rules are lowercase during toml config marshaling,
Expand All @@ -40,11 +40,11 @@ func addSplitDnsRule(cfg *ctrld.Config, domain string) bool {
}
for _, rule := range lc.Policy.Rules {
if _, ok := rule[domain]; ok {
mainLog.Load().Debug().Msgf("split-rule %q already existed for listener.%s", domain, n)
mainLog.Load().Debug().Msgf("Split-rule %q already existed for listener.%s", domain, n)
return false
}
}
mainLog.Load().Debug().Msgf("adding split-rule %q for listener.%s", domain, n)
mainLog.Load().Debug().Msgf("Adding split-rule %q for listener.%s", domain, n)
lc.Policy.Rules = append(lc.Policy.Rules, ctrld.Rule{domain: []string{}})
}
return true
Expand Down
Loading