-
Notifications
You must be signed in to change notification settings - Fork 25
Example Configurations
The best way to learn something is to see an example. This page provides a few example ctrld
configurations for different use cases. You can copy/paste these and use them as a starting point.
You can find your existing configuration file in the following locations, depending on your platform:
-
/etc/controld/
- on most platforms -
/data/controld/
- on some Ubiqiti devices -
/jffs/controld/
- on DD-WRT, Asus merlin, FreshTomato
If you used the default 1 liner installer to get ctrld
on your device, or used the --cd RESOLVER_ID
flag to start the service, you will see the following line at the top of the config file on disk:
# AUTO-GENERATED VIA CD FLAG - DO NOT MODIFY
In this mode, the config is automatically re-rendered every time the service starts, so your changes will be overwritten. In order to use ctrld
in local config mode, execute the following commands:
-
ctrld stop
- this will stop the service -
ctrld start --config=/path/to/ctrld.toml
- this will start the service in "local config mode" which enforces the config on disk
Now you can make changes to it, and execute ctrld restart
command to enforce your changes.
If you wish to route DNS queries yourself, without any magic on the part of ctrld
you can start it in pure service mode, where ctrld
will register as a system service and start the necessary listeners, but make no changes to your DNS configuration (resolv.conf files, or interface with dnsmasq). You can then reference the listeners yourself part of your advanced setup.
-
ctrld service start --cd=RESOLVER_ID
- starts ctrld service in cd mode but makes no DNS routing changes -
ctrld service start --config=/path/to/ctrld.toml
- starts ctrld service in local config mode but makes no DNS routing changes
Since v1.3.8, if ctrld
has been already installed, running ctrld start
or ctrld service start
will start the existing ctrld
service instead of installing new one. That means ctrld
service will be started with last service configuration.
Example:
$ ctrld start --cd=RESOLVER_ID -vv
$ ctrld stop
$ ctrld start # service will be run with --cd=RESOLVER_ID and -vv flags.
Passing any new arguments/flags to ctrld start
will result in old behavior.
The simplest possible configuration looks like this. The following config does the following:
- Spawn a single DNS listener on
0.0.0.0
(all interfaces) and port53
- Send all DNS queries to the matching
upstream
(listener.0
->upstream.0
) which uses DNS-over-HTTPS
[listener]
[listener.0]
ip = '0.0.0.0'
port = 53
[upstream]
[upstream.0]
type = 'doh'
endpoint = 'https://freedns.controld.com/p2'
timeout = 5000
Let's get a bit fancier, and specify multiple upstreams and route requests via network
policy. The following config does the following:
- Spawn a single DNS listener on
0.0.0.0
(all interfaces) and port5354
- Define 2 networks with 2 different subnets:
192.168.1.0/24
and192.168.100.0/24
- Define 2 upstreams with different levels of blocking
- Using a network policy map
192.168.1.0/24
toupstream.0
and192.168.100.0/24
toupstream.1
. This means that requests originating from each subnet will be sent to a different upstream DNS resolver = A DNS query from a device with MAC address 14:54:4a:8e:08:2d from any subnet would be sent to upstream.1 (since MAC rules match 2nd). - If a request doesn't match the defined networks, it will use the default
upstream.0
. To override this behavior and REFUSE queries from undefined networks, use restricted resolver config param.
[listener]
[listener.0]
ip = '0.0.0.0'
port = 5354
[listener.0.policy]
name = 'Home Policy'
networks = [
{ 'network.0' = ['upstream.0']},
{ 'network.1' = ['upstream.1']}
]
macs = [
{"14:54:4a:8e:08:2d" = ["upstream.1"]}
]
[network]
[network.0]
name = 'Adults'
cidrs = ['192.168.1.0/24']
[network.1]
name = 'Children'
cidrs = ['192.168.100.0/24']
[upstream]
[upstream.0]
name = 'Control D - No Ads'
type = 'doh'
endpoint = 'https://freedns.controld.com/p2'
timeout = 5000
[upstream.1]
name = 'Control D - Family Friendly'
type = 'doh'
endpoint = 'https://freedns.controld.com/family'
timeout = 5000
If you wish to use your own local DNS resolver for your own custom domains, and send everything else to a remote upstream, you can do that too. The following config will do the following:
- Spawn a single DNS listener on
10.0.0.1
and port5354
- Define 2 networks with 3 different subnets:
10.0.0.0/24
+10.0.1.0/24
(network.0
) and10.0.99.0/24
(network.1
) - Define 3 upstreams with 3 different endpoints, one of them being a local DNS resolver running on
10.0.0.1:1234
- Using a network policy map
network.0
(10.0.0.0/24
,10.0.1.0/24
) toupstream.0
, andnetwork.1
(10.0.99.0/24
) toupstream.1
- Using a rules policy map DNS queries for
*.domain.local
(wildcard) andsecret.cheese
(specific) toupstream.2
which runs locally on10.0.0.1:1234
. This supersedesnetwork
policy rules.
[listener]
[listener.0]
ip = '10.0.0.1'
port = 5354
[listener.0.policy]
name = 'My Policy'
networks = [
{'network.0' = ['upstream.0']},
{'network.1' = ['upstream.1']}
]
rules = [
{ '*.domain.local' = ['upstream.2']},
{ 'secret.cheese' = ['upstream.2']}
]
[network]
[network.0]
name = 'Main Subnets'
cidrs = ['10.0.0.0/24', '10.0.1.0/24']
[network.1]
name = 'Personal Subnet'
cidrs = ['10.0.99.0/24']
[upstream]
[upstream.0]
name = 'Unfiltered Resolver'
type = 'doh'
endpoint = 'https://freedns.controld.com/p0'
timeout = 5000
[upstream.1]
name = 'My Control D Resolver'
type = 'doh3'
endpoint = 'https://dns.controld.com/abcd1234'
timeout = 5000
[upstream.2]
name = 'Custom Resolver'
type = 'legacy'
endpoint = '10.0.0.1:1234'
timeout = 5000
So far all examples used a single listener, which is likely what you want in 99% of cases. But you're the 1% that needs more. Well, we got you covered here as well. The following example config will do the following:
- Spawn 2 different DNS listeners on 2 different IPs (
127.0.0.1:5555
and127.0.0.2:5555
) - Define 2 upstreams with different DNS endpoints
- DNS traffic received on
listener.0
usesupstream.0
, while DNS traffic onlistener.1
usesupstream.1
(this is default behavior unless you have an overriding policy)
[listener]
[listener.0]
ip = '127.0.0.1'
port = 5555
[listener.1]
ip = '127.0.0.2'
port = 5555
[upstream]
[upstream.0]
type = 'doh'
endpoint = 'https://freedns.controld.com/p2'
timeout = 5000
[upstream.1]
type = 'legacy'
endpoint = '1.1.1.1'
timeout = 5000
You can now use network and rule policies in conjunction with the above to define highly complex behaviors using multiple listeners. Use the earlier example for a single listener, as it works the same. Just be sure to attach the policy to the correct listener.