Files
ctrld/docs/config.md
2023-01-20 21:37:24 +07:00

9.8 KiB

Configuration File

The config file allows for advanced configuration of the ctrld utility to cover a vast array of use cases.

  1. Source IP based DNS routing policies
  2. Destination IP based DNS routing policies
  3. Split horizon DNS

Config Location

ctrld uses TOML format for its configuration file. Default configuration file is config.toml found in following order:

  • $HOME/.ctrld
  • Current directory

The user can choose to override default value using command line --config or -c:

ctrld run --config /path/to/myconfig.toml

If no configuration files found, a default ctrld.toml file will be created in the current directory.

In pre v1.1.0, config.toml file was used, so for compatibility, ctrld will still read config.toml if it's existed.

Example Config

[service]
    log_level = "info"
    log_path = ""
    cache_enable = true
    cache_size = 4096

[network.0]
    cidrs = ["0.0.0.0/0"]
    name = "Everyone"

[network.1]
    cidrs = ["10.10.10.0/24"]
    name = "Admins"

[upstream.0]
    bootstrap_ip = "76.76.2.11"
    endpoint = "https://freedns.controld.com/p1"
    name = "Control D - Anti-Malware"
    timeout = 5000
    type = "doh"

[upstream.1]
    bootstrap_ip = "76.76.2.11"
    endpoint = "p2.freedns.controld.com"
    name = "Control D - No Ads"
    timeout = 5000
    type = "doq"

[upstream.2]
    bootstrap_ip = "76.76.2.22"
    endpoint = "private.dns.controld.com"
    name = "Control D - Private"
    timeout = 5000
    type = "dot"

[listener.0]
    ip = "127.0.0.1"
    port = 53

[listener.0.policy]
    name = "My Policy"
    networks = [
        {"network.0" = ["upstream.1"]},
    ]
    rules = [
        {"*.local" = ["upstream.1"]},
        {"test.com" = ["upstream.2", "upstream.1"]},
    ]

[listener.1]
    ip = "127.0.0.69"
    port = 53
    restricted = true

See below for details on each configuration block.

Service

The [service] section controls general behaviors.

[service]
    log_level = "debug"
    log_path = "log.txt"

log_level

Logging level you wish to enable.

  • Type: string
  • Required: no
  • Valid values: debug, info, warn, error, fatal, panic
  • Default: info

log_path

Relative or absolute path of the log file.

  • Type: string
  • Required: no

cache_enable

When cache_enable = true, all resolved DNS query responses will be cached for duration of the upstream record TTLs.

  • Type: boolean
  • Required: no

cache_size

The number of cached records, must be a positive integer. Tweaking this value with care depends on your available RAM. A minimum value 4096 should be enough for most use cases.

An invalid cache_size value will disable the cache, regardless of cache_enable value.

  • Type: int
  • Required: no

cache_ttl_override

When cache_ttl_override is set to a positive value (in seconds), TTLs are overridden to this value and cached for this long.

  • Type: int
  • Required: no

cache_serve_stale

When cache_serve_stale = true, in cases of upstream failures (upstreams not reachable), ctrld will keep serving stale cached records (regardless of their TTLs) until upstream comes online.

The above config will look like this at query time.

2022-11-14T22:18:53.808 INF Setting bootstrap IP for upstream.0 bootstrap_ip=76.76.2.11
2022-11-14T22:18:53.808 INF Starting DNS server on listener.0: 127.0.0.1:53
2022-11-14T22:18:56.381 DBG [9fd5d3] 127.0.0.1:53978 -> listener.0: 127.0.0.1:53: received query: verify.controld.com
2022-11-14T22:18:56.381 INF [9fd5d3] no policy, no network, no rule -> [upstream.0]
2022-11-14T22:18:56.381 DBG [9fd5d3] sending query to upstream.0: Control D - DOH Free
2022-11-14T22:18:56.381 DBG [9fd5d3] debug dial context freedns.controld.com:443 - tcp - 76.76.2.0
2022-11-14T22:18:56.381 DBG [9fd5d3] sending doh request to: 76.76.2.11:443
2022-11-14T22:18:56.420 DBG [9fd5d3] received response of 118 bytes in 39.662597ms

Upstream

The [upstream] section specifies the DNS upstream servers that ctrld will forward DNS requests to.

[upstream.0]
  bootstrap_ip = ""
  endpoint = "https://freedns.controld.com/p1"
  name = "Control D - DOH"
  timeout = 5000
  type = "doh"
  
[upstream.1]
  bootstrap_ip = ""
  endpoint = "https://freedns.controld.com/p1"
  name = "Control D - DOH3"
  timeout = 5000
  type = "doh3"
  
[upstream.2]
  bootstrap_ip = ""
  endpoint = "p1.freedns.controld.com"
  name = "Controld D - DOT"
  timeout = 5000
  type = "dot"
  
[upstream.3]
  bootstrap_ip = ""
  endpoint = "p1.freedns.controld.com"
  name = "Controld D - DOT"
  timeout = 5000
  type = "doq"
  
[upstream.4]
  bootstrap_ip = ""
  endpoint = "76.76.2.2"
  name = "Control D - Ad Blocking"
  timeout = 5000
  type = "legacy"

bootstrap_ip

IP address of upstream DNS server when hostname or URL is used. This exists to prevent the bootstrapping cycle problem. For example, if the Endpoint is set to https://freedns.controld.com/p1, ctrld needs to know the ip address of freedns.controld.com to be able to do communication. To do that, ctrld may need to use OS resolver, which may or may not be set.

If bootstrap_ip is empty, ctrld will resolve this itself using its own bootstrap DNS, normal users should not care about bootstrap_ip and just leave it empty.

  • type: ip address string
  • required: no

endpoint

IP address, hostname or URL of upstream DNS. Used together with Type of the endpoint.

  • Type: string
  • Required: yes

Default ports are implied for each protocol, but can be overriden. ie. p1.freedns.controld.com:1024

name

Human-readable name of the upstream.

  • Type: string
  • Required: no

timeout

Timeout in milliseconds before request failsover to the next upstream (if defined).

Value 0 means no timeout.

  • Type: number
  • required: no

type

The protocol that ctrld will use to send DNS requests to upstream.

  • Type: string
  • required: yes
  • Valid values: doh, doh3, dot, doq, legacy, os

Network

The [network] section defines networks from which DNS queries can originate from. These are used in policies. You can define multiple networks, and each one can have multiple cidrs.

[network.0]
  cidrs = ["0.0.0.0/0"]
  name = "Any Network"
  
[network.1]
  cidrs = ["192.168.1.0/24"]
  name = "Home Wifi "

name

Name of the network.

  • Type: string
  • Required: no

cidrs

Specifies the network addresses that the listener will accept requests from. You will see more details in the listener policy section.

  • Type: array of network CIDR string
  • Required: no

listener

The [listener] section specifies the ip and port of the local DNS server. You can have multiple listeners, and attached policies.

[listener.0]
  ip = "127.0.0.1"
  port = 53
  
[listener.1]
  ip = "10.10.10.1"
  port = 53
  restricted = true

ip

IP address that serves the incoming requests.

  • Type: string
  • Required: yes

port

Port number that the listener will listen on for incoming requests.

  • Type: number
  • Required: yes

restricted

If set to true makes the listener REFUSE DNS queries from all source IP addresses that are not explicitly defined in the policy using a network.

  • Type: bool
  • Required: no

policy

Allows ctrld to set policy rules to determine which upstreams the requests will be forwarded to. If no policy is defined or the requests do not match any policy rules, it will be forwarded to corresponding upstream of the listener. For example, the request to listener.0 will be forwarded to upstream.0.

The policy rule syntax is a simple toml inline table with exactly one key/value pair per rule. key is either the network or a domain. Value is the list of the upstreams. For example:

[listener.0.policy]
name = "My Policy"

networks = [
    {"network.0" = ["upstream.1"]},
]

rules = [
    {"*.local" = ["upstream.1"]},
    {"test.com" = ["upstream.2", "upstream.1"]},
]

Above policy will:

  • Forward requests on listener.0 from network.0 to upstream.1.
  • Forward requests on listener.0 for .local suffixed domains to upstream.1.
  • Forward requests on listener.0 for test.com to upstream.2. If timeout is reached, retry on upstream.1.
  • All other requests on listener.0 that do not match above conditions will be forwarded to upstream.0.

An empty upstream would not route the request to any defined upstreams, and use the OS default resolver.

[listener.0.policy]
name = "OS Resolver"

rules = [
    {"*.local" = []},
]

name

name is the name for the policy.

  • Type: string
  • Required: no

networks:

networks is the list of network rules of the policy.

  • type: array of networks

rules:

rules is the list of domain rules within the policy. Domain can be either FQDN or wildcard domain.

  • type: array of rule

failover_rcodes

For non success response, failover_rcodes allows the request to be forwarded to next upstream, if the response RCODE matches any value defined in failover_rcodes. For example:

[listener.0.policy]
name = "My Policy"
failover_rcodes = ["NXDOMAIN", "SERVFAIL"]
networks = [
	{"network.0" = ["upstream.0", "upstream.1"]},
]

If upstream.0 returns a NXDOMAIN response, the request will be forwarded to upstream.1 instead of returning immediately to the client.

See all available DNS Rcodes value here.