DNS Cookies (RFC 7873) is a lightweight security mechanism against denial-of-service and amplification attacks. The server keeps a secret value (the Server Secret), which is used to generate a cookie, which is sent to the client in the OPT RR. The server then verifies the authenticity of the client by the presence of a correct cookie. Both the server and the client have to support DNS Cookies, otherwise they are not used.
Note
This module introduces a statistics counter: the number of queries containing the COOKIE option.
Warning
For effective module operation the RRL module must also be enabled.
It is recommended to enable DNS Cookies globally, not per zone. The module may be used without any further configuration.
template:
- id: default
global-module: mod-cookies # Enable DNS Cookies globally
Module configuration may be supplied if necessary.
mod-cookies:
- id: default
secret-lifetime: 30h # The Server Secret is regenerated every 30 hours
badcookie-slip: 3 # The server replies only to every third query with a wrong cookie
template:
- id: default
global-module: mod-cookies/default # Enable DNS Cookies globally
The value of the Server Secret may also be managed manually using the secret option. In this case the server does not automatically regenerate the Server Secret.
mod-cookies:
- id: default
secret: 0xdeadbeefdeadbeefdeadbeefdeadbeef
mod-cookies:
- id: STR
secret-lifetime: TIME
badcookie-slip: INT
secret: STR|HEXSTR
A module identifier.
This option configures how often the Server Secret is regenerated. The maximum allowed value is 36 days (RFC 7873).
Default: 26 hours
This option configures how often the server responds to queries containing an invalid cookie by sending them the correct cookie.
Default: 1
Use this option to set the Server Secret manually. If this option is used, the Server Secret remains the same until changed manually and the secret-lifetime option is ignored. The size of the Server Secret currently MUST BE 16 bytes, or 32 hexadecimal characters.
Default: not set
The module forwards all queries, or all specific zone queries if configured per zone, to the indicated server for resolution. If configured in the fallback mode, only localy unsatisfied queries are forwarded. I.e. a tiny DNS proxy. There are several uses of this feature:
Note
The module does not alter the query/response as the resolver would, and the original transport protocol is kept as well.
The configuration is straightforward and just a single remote server is required:
remote:
- id: hidden
address: 10.0.1.1
mod-dnsproxy:
- id: default
remote: hidden
fallback: on
template:
- id: default
global-module: mod-dnsproxy/default
zone:
- domain: local.zone
When clients query for anything in the local.zone, they will be responded to locally. The rest of the requests will be forwarded to the specified server (10.0.1.1 in this case).
mod-dnsproxy:
- id: STR
remote: remote_id
timeout: INT
fallback: BOOL
catch-nxdomain: BOOL
A module identifier.
If enabled, localy unsatisfied queries leading to REFUSED (no zone) are forwarded. If disabled, all queries are directly forwarded without any local attempts to resolve them.
Default: on
If enabled, localy unsatisfied queries leading to NXDOMAIN are forwarded. This option is only relevant in the fallback mode.
Default: off
A module for query and response logging based on the dnstap library. You can capture either all or zone-specific queries and responses; usually you want to do the former.
The configuration comprises only a sink path parameter, which can be either a file or a UNIX socket:
mod-dnstap:
- id: capture_all
sink: /tmp/capture.tap
template:
- id: default
global-module: mod-dnstap/capture_all
Note
To be able to use a Unix socket you need an external program to create it. Knot DNS connects to it as a client using the libfstrm library. It operates exactly like syslog. See here for more details.
Note
Dnstap log files can also be created or read using kdig.
For all queries logging, use this module in the default template. For zone-specific logging, use this module in the proper zone configuration.
mod-dnstap:
- id: STR
sink: STR
identity: STR
version: STR
log-queries: BOOL
log-responses: BOOL
A module identifier.
A sink path, which can be either a file or a UNIX socket when prefixed with unix:.
Required
Warning
File is overwritten on server startup or reload.
This module offers response tailoring based on client’s subnet or geographic location. It supports GeoIP databases in the MaxMind DB format, such as GeoIP2 or the free version GeoLite2.
The module can be enabled only per zone.
Note
If EDNS Client Subnet support is enabled and if a query contains this option, the module takes advantage of this information to provide a more accurate response.
There are two ways to enable DNSSEC signing of tailored responses. If automatic DNSSEC signing is enabled, record signatures are precomputed when the module is loaded. This has a speed benefit, however note that every RRset configured in the module should have a default RRset of the same type contained in the zone, so that the NSEC(3) chain can be built correctly. Also, it is STRONGLY RECOMMENDED to use manual key management in this setting, as the corresponding zone has to be reloaded when the signing key changes and to have better control over key synchronization to all instances of the server.
Note
If the GeoIP module is used with automatic DNSSEC signing, the keys for computing record signatures MUST exist or be generated before the server is launched, otherwise the module fails to compute the signatures and does not load.
Alternatively, the geoip module may be combined with the onlinesign module and the tailored responses can be signed on the fly. This approach is much more computationally demanding for the server.
Note
If the GeoIP module is used with online signing, it is recommended to set the nsec-bitmap option of the onlinesign module to contain all Resource Record types potentially generated by the module.
An example configuration.:
mod-geoip:
- id: default
config-file: /path/to/geo.conf
ttl: 20
mode: geodb
geodb-file: /path/to/GeoLite2-City.mmdb
geodb-key: [ country/iso_code, city/names/en ]
zone:
- domain: example.com.
module: mod-geoip/default
Every instance of the module requires an additional config-file in which the desired responses to queries from various locations are configured. This file has the following simple format:
domain-name1:
- geo|net: location1
RR-Type1: RDATA
RR-Type2: RDATA
...
- geo|net: location2
RR-Type1: RDATA
...
domain-name2:
...
foo.example.com:
- net: 10.0.0.0/24
A: [ 192.168.1.1, 192.168.1.2 ]
AAAA: [ 2001:DB8::1, 2001:DB8::2 ]
TXT: "subnet\ 10.0.0.0/24"
...
bar.example.com:
- net: 2001:DB8::/32
A: 192.168.1.3
AAAA: 2001:DB8::3
TXT: "subnet\ 2001:DB8::/32"
...
Note
If a space or a quotation mark is a part of record data, such a character must be prefixed with a backslash. The following notations are equivalent:
Multi-word\ string
"Multi-word\ string"
"\"Multi-word string\""
foo.example.com:
- geo: "CZ;Prague"
CNAME: cz.foo.example.com
- geo: "US;Las Vegas"
CNAME: vegas.foo.example.net
- geo: "US;*"
CNAME: us.foo.example.net
...
mod-geoip:
- id: STR
config-file: STR
ttl: TIME
mode: geodb | subnet
geodb-file: STR
geodb-key: STR ...
A module identifier.
The mode of operation of the module.
Possible values:
Default: subnet
Full path to a .mmdb file containing the GeoIP database.
Reqired if mode is set to geodb
Multi-valued item, can be specified up to 8 times. Each geodb-key specifies a path to a key in a node in the supplied GeoIP database. The module currently supports two types of values: string or 32-bit unsigned int. In the latter case, the key has to be prefixed with (id). Common choices of keys include:
In the zone’s config file for the module the values of the keys are entered in the same order as the keys in the module’s configuration, separated by a semicolon. Enter the value “*” if the key is allowed to have any value.
The module sends empty truncated response to any UDP query. TCP queries are not affected.
To enable this module globally, you need to add something like the following to the configuration file:
template:
- id: default
global-module: mod-noudp
Note
This module is not configurable.
The module provides online DNSSEC signing. Instead of pre-computing the zone signatures when the zone is loaded into the server or instead of loading an externally signed zone, the signatures are computed on-the-fly during answering.
The main purpose of the module is to enable authenticated responses with zones which use other dynamic module (e.g., automatic reverse record synthesis) because these zones cannot be pre-signed. However, it can be also used as a simple signing solution for zones with low traffic and also as a protection against zone content enumeration (zone walking).
In order to minimize the number of computed signatures per query, the module produces a bit different responses from the responses that would be sent if the zone was pre-signed. Still, the responses should be perfectly valid for a DNSSEC validating resolver.
Differences from statically signed zones:
Records synthesized by the module:
Known issues:
Limitations:
Recommendations:
Enable the module in the zone configuration with the default signing policy:
zone:
- domain: example.com
module: mod-onlinesign
Or with an explicit signing policy:
policy:
- id: rsa
algorithm: RSASHA256
zsk-size: 2048
rrsig-lifetime: 25h
mod-onlinesign:
- id: explicit
policy: rsa
zone:
- domain: example.com
module: mod-onlinesign/explicit
Or use manual policy in an analogous manner, see Manual key management.
Make sure the zone is not signed and also that the automatic signing is disabled. All is set, you are good to go. Reload (or start) the server:
$ knotc reload
The following example stacks the online signing with reverse record synthesis module:
mod-synthrecord:
- id: lan-forward
type: forward
prefix: ip-
ttl: 1200
network: 192.168.100.0/24
zone:
- domain: corp.example.net
module: [mod-synthrecord/lan-forward, mod-onlinesign]
mod-onlinesign:
- id: STR
policy: STR
nsec-bitmap: STR ...
A module identifier.
A reference to DNSSEC signing policy. A special default value can be used for the default policy setting.
A list of Resource Record types included in an NSEC bitmap generated by the module. This option should reflect zone contents or synthesized responses by modules, such as synthrecord and GeoIP.
Default: [A, AAAA]
This module provides a simple way to whitelist incoming queries according to the query’s source address or target interface. It can be used e.g. to create a restricted-access subzone with delegations from the corresponding public zone. The module may be enabled both globally and per-zone.
Note
The module limits only regular queries. Notify, transfer and update are handled by ACL.
mod-queryacl:
- id: default
address: [192.0.2.73-192.0.2.90, 203.0.113.0/24]
interface: 198.51.100
zone:
- domain: example.com
module: mod-queryacl/default
mod-queryacl:
- id: STR
address: ADDR[/INT] | ADDR-ADDR ...
interface: ADDR[/INT] | ADDR-ADDR ...
A module identifier.
A list of allowed ranges and/or subnets for query’s source address. If the query’s address does not fall into any of the configured ranges, NOTAUTH rcode is returned.
Response rate limiting (RRL) is a method to combat DNS reflection amplification attacks. These attacks rely on the fact that source address of a UDP query can be forged, and without a worldwide deployment of BCP38, such a forgery cannot be prevented. An attacker can use a DNS server (or multiple servers) as an amplification source and can flood a victim with a large number of unsolicited DNS responses. The RRL lowers the amplification factor of these attacks by sending some of the responses as truncated or by dropping them altogether.
Note
The module introduces two statistics counters. The number of slipped and dropped responses.
Note
If the Cookies module is active, RRL is not applied for responses with a valid DNS cookie.
You can enable RRL by setting the module globally or per zone.
mod-rrl:
- id: default
rate-limit: 200 # Allow 200 resp/s for each flow
slip: 2 # Every other response slips
template:
- id: default
global-module: mod-rrl/default # Enable RRL globally
mod-rrl:
- id: STR
rate-limit: INT
slip: INT
table-size: INT
whitelist: ADDR[/INT] | ADDR-ADDR ...
A module identifier.
Rate limiting is based on the token bucket scheme. A rate basically represents a number of tokens available each second. Each response is processed and classified (based on several discriminators, e.g. source netblock, query type, zone name, rcode, etc.). Classified responses are then hashed and assigned to a bucket containing number of available tokens, timestamp and metadata. When available tokens are exhausted, response is dropped or sent as truncated (see slip). Number of available tokens is recalculated each second.
Required
Size of the hash table in a number of buckets. The larger the hash table, the lesser the probability of a hash collision, but at the expense of additional memory costs. Each bucket is estimated roughly to 32 bytes. The size should be selected as a reasonably large prime due to better hash function distribution properties. Hash table is internally chained and works well up to a fill rate of 90 %, general rule of thumb is to select a prime near 1.2 * maximum_qps.
Default: 393241
As attacks using DNS/UDP are usually based on a forged source address, an attacker could deny services to the victim’s netblock if all responses would be completely blocked. The idea behind SLIP mechanism is to send each Nth response as truncated, thus allowing client to reconnect via TCP for at least some degree of service. It is worth noting, that some responses can’t be truncated (e.g. SERVFAIL).
Default: 1
A list of IP addresses, network subnets, or network ranges to exempt from rate limiting. Empty list means that no incoming connection will be white-listed.
Default: not set
The module extends server statistics with incoming DNS request and corresponding response counters, such as used network protocol, total number of responded bytes, etc (see module reference for full list of supported counters). This module should be configured as the last module.
Note
Server initiated communication (outgoing NOTIFY, incoming *XFR,...) is not counted by this module.
Note
Leading 16-bit message size over TCP is not considered.
Common statistics with default module configuration:
template:
- id: default
global-module: mod-stats
Per zone statistics with explicit module configuration:
mod-stats:
- id: custom
edns-presence: on
query-type: on
template:
- id: default
module: mod-stats/custom
mod-stats:
- id: STR
request-protocol: BOOL
server-operation: BOOL
request-bytes: BOOL
response-bytes: BOOL
edns-presence: BOOL
flag-presence: BOOL
response-code: BOOL
request-edns-option: BOOL
response-edns-option: BOOL
reply-nodata: BOOL
query-type: BOOL
query-size: BOOL
reply-size: BOOL
A module identifier.
If enabled, all incoming requests are counted by the network protocol:
Default: on
If enabled, all incoming requests are counted by the server operation. The server operation is based on message header OpCode and message query (meta) type:
Default: on
If enabled, all incoming request bytes are counted by the server operation:
Default: on
If enabled, outgoing response bytes are counted by the server operation:
Warning
Dynamic update response bytes are not counted by this module.
Default: on
If enabled, EDNS pseudo section presence is counted by the message direction:
Default: off
If enabled, some message header flags are counted:
Default: off
If enabled, outgoing response code is counted:
Note
In the case of multi-message zone transfer response, just one counter is incremented.
Warning
Dynamic update response code is not counted by this module.
Default: on
If enabled, EDNS options in requests are counted by their code:
Default: off
If enabled, EDNS options in responses are counted by their code. See request-edns-option.
Default: off
If enabled, NODATA pseudo RCODE (RFC 2308) is counted by the query type:
Default: off
If enabled, normal query type is counted:
Note
Not all assigned meta types (IXFR, AXFR,...) have their own counters, because such types are not processed as normal query.
Default: off
If enabled, normal query message size distribution is counted by the size range in bytes:
Default: off
If enabled, normal reply message size distribution is counted by the size range in bytes:
Default: off
This module is able to synthesize either forward or reverse records for a given prefix and subnet.
Records are synthesized only if the query can’t be satisfied from the zone. Both IPv4 and IPv6 are supported.
mod-synthrecord:
- id: test1
type: forward
prefix: dynamic-
ttl: 400
network: 2620:0:b61::/52
zone:
- domain: test.
file: test.zone # Must exist
module: mod-synthrecord/test1
Result:
$ kdig AAAA dynamic-2620-0000-0b61-0100-0000-0000-0000-0001.test.
...
;; QUESTION SECTION:
;; dynamic-2620-0000-0b61-0100-0000-0000-0000-0001.test. IN AAAA
;; ANSWER SECTION:
dynamic-2620-0000-0b61-0100-0000-0000-0000-0001.test. 400 IN AAAA 2620:0:b61:100::1
You can also have CNAME aliases to the dynamic records, which are going to be further resolved:
$ kdig AAAA alias.test.
...
;; QUESTION SECTION:
;; alias.test. IN AAAA
;; ANSWER SECTION:
alias.test. 3600 IN CNAME dynamic-2620-0000-0b61-0100-0000-0000-0000-0002.test.
dynamic-2620-0000-0b61-0100-0000-0000-0000-0002.test. 400 IN AAAA 2620:0:b61:100::2
mod-synthrecord:
- id: test2
type: reverse
prefix: dynamic-
origin: test
ttl: 400
network: 2620:0:b61::/52
zone:
- domain: 1.6.b.0.0.0.0.0.0.2.6.2.ip6.arpa.
file: 1.6.b.0.0.0.0.0.0.2.6.2.ip6.arpa.zone # Must exist
module: mod-synthrecord/test2
Result:
$ kdig -x 2620:0:b61::1
...
;; QUESTION SECTION:
;; 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.6.b.0.0.0.0.0.0.2.6.2.ip6.arpa. IN PTR
;; ANSWER SECTION:
1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.6.b.0.0.0.0.0.0.2.6.2.ip6.arpa. 400 IN PTR
dynamic-2620-0000-0b61-0000-0000-0000-0000-0001.test.
mod-synthrecord:
- id: STR
type: forward | reverse
prefix: STR
origin: DNAME
ttl: INT
network: ADDR[/INT] | ADDR-ADDR ...
A module identifier.
The type of generated records.
Possible values:
Required
A record owner prefix.
Note
The value doesn’t allow dots, address parts in the synthetic names are separated with a dash.
Default: empty
The module synthesizes an A or AAAA record containing the query source IP address, at the apex of the zone being served. It makes sure to allow Knot DNS to generate cacheable negative responses, and to allow fallback to extra records defined in the underlying zone file. The TTL of the synthesized record is copied from the TTL of the SOA record in the zone file.
Because a DNS query for type A or AAAA has nothing to do with whether the query occurs over IPv4 or IPv6, this module requires a special zone configuration to support both address families. For A queries, the underlying zone must have a set of nameservers that only have IPv4 addresses, and for AAAA queries, the underlying zone must have a set of nameservers that only have IPv6 addresses.
To enable this module, you need to add something like the following to the Knot DNS configuration file:
zone:
- domain: whoami.domain.example
file: "/path/to/whoami.domain.example"
module: mod-whoami
zone:
- domain: whoami6.domain.example
file: "/path/to/whoami6.domain.example"
module: mod-whoami
The whoami.domain.example zone file example:
$TTL 1 @ SOA ( whoami.domain.example. ; MNAME hostmaster.domain.example. ; RNAME 2016051300 ; SERIAL 86400 ; REFRESH 86400 ; RETRY 86400 ; EXPIRE 1 ; MINIMUM ) $TTL 86400 @ NS ns1.whoami.domain.example. @ NS ns2.whoami.domain.example. @ NS ns3.whoami.domain.example. @ NS ns4.whoami.domain.example. ns1 A 198.51.100.53 ns2 A 192.0.2.53 ns3 A 203.0.113.53 ns4 A 198.19.123.53
The whoami6.domain.example zone file example:
$TTL 1 @ SOA ( whoami6.domain.example. ; MNAME hostmaster.domain.example. ; RNAME 2016051300 ; SERIAL 86400 ; REFRESH 86400 ; RETRY 86400 ; EXPIRE 1 ; MINIMUM ) $TTL 86400 @ NS ns1.whoami6.domain.example. @ NS ns2.whoami6.domain.example. @ NS ns3.whoami6.domain.example. @ NS ns4.whoami6.domain.example. ns1 AAAA 2001:db8:100::53 ns2 AAAA 2001:db8:200::53 ns3 AAAA 2001:db8:300::53 ns4 AAAA 2001:db8:400::53
The parent domain would then delegate whoami.domain.example to ns[1-4].whoami.domain.example and whoami6.domain.example to ns[1-4].whoami6.domain.example, and include the corresponding A-only or AAAA-only glue records.
Note
This module is not configurable.