# Modules

## `authsignal` – Automatic Authenticated DNSSEC Bootstrapping records

This module is able to synthesize records for automatic DNSSEC bootstrapping (RFC 9615).

Records are synthesized only if the query can't be satisfied from the zone.

Synthesized records also need to be signed. Typically, this can be done using the onlinesign module, as shown below.

### Example

#### Automatic forward records

    mod-onlinesign:
      - id: authsignal
        nsec-bitmap: [CDS, CDNSKEY]

    zone:
      - domain: example.net
        dnssec-signing: on
      - domain: _signal.ns1.example.com
        module: [mod-authsignal, mod-onlinesign/authsignal]

Result:

    $ kdig CDS _dsboot.example.net._signal.ns1.example.com.
    ...
    ;; QUESTION SECTION:
    ;; _dsboot.example.net._signal.ns1.example.com.      IN      CDS

    ;; ANSWER SECTION:
    _dsboot.example.net._signal.ns1.example.com. 0       IN      CDS     45504 13 2 2F2D518FD9DBB2B1403F51398A9931F2832B89F0F85C146B130D383FC23584FA

## `cookies` — DNS Cookies

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 two statistics counters:

- `presence` – The number of queries containing the COOKIE option.

- `dropped` – The number of dropped queries due to the slip limit.

### Example

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 with defaults

Module configuration may be supplied if necessary.

    mod-cookies:
      - id: custom
        badcookie-slip: 3  # The server replies only to every third query with a wrong cookie
        secret: 0xdeadbeefdeadbeefdeadbeefdeadbeef  # Explicit Server Secret

    template:
      - id: default
        global-module: mod-cookies/custom  # Enable DNS Cookies globally with custom settings

### Module reference

    mod-cookies:
      - id: STR
        secret-lifetime: TIME
        badcookie-slip: INT
        secret: STR | HEXSTR ...

#### id

A module identifier.

#### secret-lifetime

This option configures in seconds how often the Server Secret is regenerated. The maximum allowed value is 36 days (RFC 7873 Section 7.1).

Default: `26h` (26 hours)

#### badcookie-slip

This option configures how often the server responds to queries containing an invalid cookie by sending them the correct cookie.

- The value 1 means that the server responds to every query.

- The value 2 means that the server responds to every second query with an invalid cookie, the rest of the queries is dropped.

- The value N > 2 means that the server responds to every Nth query with an invalid cookie, the rest of the queries is dropped.

Default: `1`

#### secret

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.

It's possible to specify a second Server Secret, which is used for the fallback when the cookie verification with the first Server Secret fails (secret rollover).

Default: not set

## `dnserr` — DNS Error Reporting

The module implements RFC 9567 and can be used either to indicate support for DNS error reporting or as a monitoring agent.

### Example

Use this configuration to tell resolvers that if they encounter an error with example.com, they should send a report to channel.example.

    mod-dnserr:
      - id: report
        report-channel: channel.example

    zone:
      - domain: example.com
        module: mod-dnserr/report

Use this configuration on the server responsible for channel.example to capture incoming error reports. The zone name is considered as the report channel name. Unique reports are cached to prevent log flooding.

    mod-dnserr:
      - id: agent
        agent: on

    zone:
      - domain: channel.example
        module: mod-dnserr/agent

### Module reference

    mod-dnserr:
      - id: STR
        report-channel: DNAME
        agent: BOOL
        cache-size: INT
        cache-lifetime: TIME

#### id

A module identifier.

#### report-channel

Enables the announcement of DNS error reporting to the specified channel.

Default: not set

#### agent

Enables monitoring agent mode. Received reports are logged to the server log.

Default: not set

#### cache-size

Size of the cache that stores unique reports to be logged.

Default: 1000

#### cache-lifetime

Lifetime of the log cache in seconds.

Default: 10

## `dnsproxy` – Tiny DNS proxy

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 locally unsatisfied queries are forwarded. I.e. a tiny DNS proxy. There are several uses of this feature:

- A substitute public-facing server in front of the real one

- Local zones (poor man's "views"), rest is forwarded to the public-facing server

- Using the fallback to forward queries to a resolver

- etc.

Note

The module does not alter the query/response as the resolver would, and the original transport protocol (UDP or TCP) is kept as well.

### Example

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 a client queries anything in the `local.zone` (which must exist), it will receive a local response. All other requests (to unknown zones) will be forwarded to the specified server (`10.0.1.1` in this case).

### Module reference

    mod-dnsproxy:
      - id: STR
        remote: remote_id
        timeout: INT
        address: ADDR[/INT] | ADDR-ADDR | STR ...
        fallback: BOOL
        tcp-fastopen: BOOL
        catch-nxdomain: BOOL

#### id

A module identifier.

#### remote

A reference to a remote server where the queries are forwarded to.

Required

Note

If the remote has more addresses configured, other addresses are used sequentially as fallback. In this case, for the N-th address the N-th via address is taken if configured.

#### timeout

A remote response timeout in milliseconds.

Default: `500` (milliseconds)

#### address

An ordered list of IP addresses, absolute UNIX socket paths, network subnets, or network ranges. If the query's source address does not fall into any of the configured ranges, the query isn't forwarded.

Default: not set

#### fallback

If enabled, locally 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`

#### tcp-fastopen

If enabled, TCP Fast Open is used when forwarding TCP queries.

Default: `off`

#### catch-nxdomain

If enabled, locally unsatisfied queries leading to NXDOMAIN are forwarded. This option is only relevant in the fallback mode.

Default: `off`

## `dnstap` – Dnstap traffic logging

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.

### Example

The configuration comprises only a sink path parameter, which can be either a file, a UNIX socket, or a TCP address:

    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.

Note

Dnstap log files can also be created or read using kdig.

### Module reference

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
        responses-with-queries: BOOL

#### id

A module identifier.

#### sink

A sink path, which can be either a file, a UNIX socket when prefixed with `unix:`, or a TCP address@port when prefixed with `tcp:`. The file may be specified as an absolute path or a path relative to the knotd startup directory.

Required

Warning

File is overwritten on server startup or reload.

#### identity

A DNS server identity. Set empty value to disable.

Default: FQDN hostname

#### version

A DNS server version. Set empty value to disable.

Default: server version

#### log-queries

If enabled, query messages will be logged.

Default: `on`

#### log-responses

If enabled, response messages will be logged.

Default: `on`

#### responses-with-queries

If enabled, dnstap `AUTH_RESPONSE` messages will also include the original query message as well as the response message sent by the server.

Default: `off`

## `geoip` — Geography-based responses

This module offers response tailoring based on client's subnet, geographic location, or a statistical weight. 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.

### DNSSEC support

There are several ways to enable DNSSEC signing of tailored responses.

#### Full zone signing

If automatic DNSSEC signing is enabled, the whole zone is signed by the server and all alternative RRsets, which are responded by the module, are pre-signed 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

DNSSEC keys for computing record signatures MUST exist in the KASP database or be generated before the module is launched, otherwise the module fails to compute the signatures and does not load.

#### Module signing

If automatic DNSSEC signing is disabled, it's possible to combine externally pre-signed zone with module pre-signing of the alternative RRsets when the module is loaded. In this mode, only ZSK has to be present in the KASP database. Also in this mode every RRset configured in the module should have a default RRset of the same type contained in the zone.

Example:

    policy:
      - id: presigned_zone
        manual: on
        unsafe-operation: no-check-keyset

    mod-geoip:
      - id: geo_dnssec
        ...
        dnssec: on
        policy: presigned_zone

    zone:
      - domain: example.com.
        module: mod-geoip/geo_dnssec

#### Online signing

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.

### Example

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

### Configuration file

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|weight: value1
        RR-Type1: RDATA
        RR-Type2: RDATA
        ...
      - geo|net|weight: value2
        RR-Type1: RDATA
      ...
    domain-name2:
    ...

### Module configuration examples

This section contains some examples for the module's config-file.

#### Using subnets

    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"
    ...

Clients from the specified subnets will receive the responses defined in the module config. Others will receive the default records defined in the zone (if any).

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\""

#### Using geographic locations

    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.
    ...

Clients from the specified geographic locations will receive the responses defined in the module config. Others will receive the default records defined in the zone (if any). See geodb-key for the syntax and semantics of the location definitions.

#### Using weighted records

    foo.example.com:
      - weight: 1
        CNAME: canary.foo.example.com.
      - weight: 10
        CNAME: prod1.foo.example.com.
      - weight: 10
        CNAME: prod2.foo.example.com.
    ...

Each response is generated through a random pick where each defined record has a likelihood of its weight over the sum of all weights for the requested name to. Records defined in the zone itself (if any) will never be served.

Result:

    $ for i in $(seq 1 100); do kdig @192.168.1.242 CNAME foo.example.com +short; done | sort | uniq -c
       3 canary.foo.example.com.foo.example.com.
      52 prod1.foo.example.net.foo.example.com.
      45 prod2.foo.example.net.foo.example.com.

### Module reference

    mod-geoip:
      - id: STR
        config-file: STR
        ttl: TIME
        mode: geodb | subnet | weighted
        dnssec: BOOL
        policy: policy_id
        geodb-file: STR
        geodb-key: STR ...

#### id

A module identifier.

#### config-file

A path to the response configuration file as described above. A non-absolute path is relative to the knotd startup directory.

Required

#### ttl

The time to live of Resource Records returned by the module, in seconds.

Default: `60`

#### mode

The mode of operation of the module.

Possible values:

- `subnet` – Responses are tailored according to subnets.

- `geodb` – Responses are tailored according to geographic data retrieved from the configured database.

- `weighted` – Responses are tailored according to a statistical weight.

Default: `subnet`

#### dnssec

If explicitly enabled, the module signs positive responses based on the module policy (policy). If explicitly disabled, positive responses from the module are not signed even if the zone is pre-signed or signed by the server (dnssec-signing).

Warning

This configuration must be used carefully. Otherwise the zone responses can be bogus. DNSKEY rotation isn't supported. So manual mode is highly recommended.

Default: current value of dnssec-signing with dnssec-policy

#### policy

A reference to DNSSEC signing policy which is used if dnssec is enabled.

Default: an imaginary policy with all default values

#### geodb-file

A path to a .mmdb file containing the GeoIP database. A non-absolute path is relative to the knotd startup directory.

Required if mode is set to geodb

#### geodb-key

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:

- continent/code

- country/iso_code

- (id)country/geoname_id

- city/names/en

- (id)city/geoname_id

- isp

- ...

The exact keys available depend on the database being used. To get the full list of keys available, you can e.g. do a sample lookup on your database with the mmdblookup tool.

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.

## `noudp` — No UDP response

The module sends empty truncated reply to a query over UDP. Replies over TCP are not affected.

### Example

To enable this module for all configured zones and every UDP reply:

    template:
      - id: default
        global-module: mod-noudp

Or with specified UDP allow rate:

    mod-noudp:
      - id: sometimes
        udp-allow-rate: 1000  # Don't truncate every 1000th UDP reply

    template:
      - id: default
        module: mod-noudp/sometimes

### Module reference

    mod-noudp:
     - id: STR
       udp-allow-rate: INT
       udp-truncate-rate: INT

Note

Both udp-allow-rate and udp-truncate-rate cannot be specified together.

#### udp-allow-rate

Specifies frequency of UDP replies that are not truncated. A non-zero value means that every Nth UDP reply is not truncated.

Note

The rate value is associated with one UDP worker. If more UDP workers are configured, the specified value may not be obvious to clients.

Default: not set

#### udp-truncate-rate

Specifies frequency of UDP replies that are truncated (opposite of udp-allow-rate). A non-zero value means that every Nth UDP reply is truncated.

Note

The rate value is associated with one UDP worker. If more UDP workers are configured, the specified value may not be obvious to clients.

Default: `1`

## `onlinesign` — Online DNSSEC signing

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:

- The NSEC records are constructed as Minimally Covering NSEC Records (RFC 7129 Appendix A). Therefore the generated domain names cover the complete domain name space in the zone's authority.

- NXDOMAIN responses are promoted to NODATA responses. The module proves that the query type does not exist rather than that the domain name does not exist.

- Domain names matching a wildcard are expanded. The module pretends and proves that the domain name exists rather than proving a presence of the wildcard.

Records synthesized by the module:

- DNSKEY record is synthesized in the zone apex and includes public key material for the active signing key.

- NSEC records are synthesized as needed.

- RRSIG records are synthesized for authoritative content of the zone.

- CDNSKEY and CDS records are generated as usual to publish valid Secure Entry Point.

Limitations:

- Due to limited interaction between the server and the module, after any change to KASP DB (including knotc zone-ksk-submitted command) or when a scheduled DNSSEC event shall be processed (e.g. transition to next DNSKEY rollover state) the server must be reloaded or queried to the zone (with the DO bit set) to apply the change or to trigger the event. For optimal operation, the recommended query frequency is at least ones per second for each zone configured.

- The NSEC records may differ for one domain name if queried for different types. This is an implementation shortcoming as the dynamic modules cooperate loosely. Possible synthesis of a type by other module cannot be predicted. This dissimilarity should not affect response validation, even with validators performing aggressive negative caching (RFC 8198).

- The module isn't compatible with the Offline KSK mode yet.

Recommendations:

- Configure the module with an explicit signing policy which has the rrsig-lifetime value in the order of hours.

- Note that single-type-signing should be set explicitly to avoid fallback to backward-compatible default.

### Example

- 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
          ksk-size: 2048
          rrsig-lifetime: 25h
          rrsig-refresh: 20h

      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]

### Module reference

    mod-onlinesign:
      - id: STR
        policy: policy_id
        nsec-bitmap: STR ...

#### id

A module identifier.

#### policy

A reference to DNSSEC signing policy. A special default value can be used for the default policy setting.

Default: an imaginary policy with all default values

#### nsec-bitmap

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]`

## `probe` — DNS traffic probe

The module allows the server to send simplified information about regular DNS traffic through UNIX sockets. The exported information consists of data blocks where each data block (datagram) describes one query/response pair. The response part can be empty. The receiver can be an arbitrary program using libknot interface (C or Python). In case of high traffic, more channels (sockets) can be configured to allow parallel processing.

Tip

A simple probe client in Python.

### Example

Default module configuration:

    template:
      - id: default
        global-module: mod-probe

Per zone probe with 8 channels and maximum 1M logs per second limit:

    mod-probe:
      - id: custom
        path: /tmp/knot-probe
        channels: 8
        max-rate: 1000000

    zone:
      - domain: example.com.
        module: mod-probe/custom

### Module reference

    mod-probe:
      - id: STR
        path: STR
        channels: INT
        max-rate: INT

#### id

A module identifier.

#### path

A directory path where the UNIX sockets are located. A non-absolute path is relative to the knotd startup directory.

Note

It's recommended to use a directory with the execute permission restricted to the intended probe consumer process owner only.

Default: rundir

#### channels

Number of channels (UNIX sockets) the traffic is distributed to. In case of high DNS traffic which is beeing processed by many UDP/XDP/TCP workers, using more channels reduces the module overhead.

Default: `1`

#### max-rate

Maximum number of queries/replies per second the probe is allowed to transfer. If the limit is exceeded, the over-limit traffic is ignored. Zero value means no limit.

Default: `100000` (one hundred thousand)

## `queryacl` — Limit queries by remote address or target interface

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.

### Example

    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

### Module reference

    mod-queryacl:
      - id: STR
        address: ADDR[/INT] | ADDR-ADDR | STR ...
        interface: ADDR[/INT] | ADDR-ADDR | STR ...

#### id

A module identifier.

#### address

An ordered list of IP addresses, absolute UNIX socket paths, network subnets, or network ranges. If the query's address does not fall into any of the configured ranges, NOTAUTH rcode is returned.

Default: not set

#### interface

An ordered list of IP addresses, absolute UNIX socket paths, network subnets, or network ranges. If the interface does not fall into any of the configured ranges, NOTAUTH rcode is returned. Note that every interface used has to be configured in listen.

Note

Don't use values 0.0.0.0 and ::0. These values are redundant and don't work as expected.

Default: not set

## `rrl` — Response rate limiting

Response rate limiting (RRL) is a method to combat DNS reflection amplification attacks. These attacks rely on the fact that the 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 to flood a victim with a large number of unsolicited DNS responses. RRL lowers the amplification factor of these attacks by sending some responses as truncated or by dropping them altogether.

This module can also help protect the server from excessive utilization by limiting incoming packets (including handshakes) based on consumed time. If a packet is time rate limited, it's dropped. This function works with all supported non-UDP transport protocols (TCP, TLS, and QUIC) and cannot be configured per zone.

Note

This module introduces three statistics counters:

- `slipped` – The number of slipped UDP responses.

- `dropped` – The number of dropped UDP responses due to the rate limit.

- `dropped-time` – The number of dropped non-UDP packets due to the time rate limit.

Note

If the Cookies module is active and configured before this module, RRL is not applied to UDP responses with a valid DNS cookie.

Note

The time limiting applies even to handshakes of incoming authorized requests (e.g. NOTIFY, AXFR). In such cases, setting whitelist or reusing already established connections (e.g. remote-pool-timeout on the remote server) can mitigate this issue.

### Example

You can enable RRL by setting the module globally

    template:
      - id: default
        global-module: mod-rrl  # Default module configuration

or per zone

    mod-rrl:
      - id: custom
        rate-limit: 200

    zone:
      - domain: example.com
        module: mod-rrl/custom  # Custom module configuration

### Module reference

    mod-rrl:
      - id: STR
        rate-limit: INT
        instant-limit: INT
        slip: INT
        time-rate-limit: INT
        time-instant-limit: INT
        table-size: INT
        whitelist: ADDR[/INT] | ADDR-ADDR | STR ...
        log-period: INT
        dry-run: BOOL

#### id

A module identifier.

#### rate-limit

Maximal allowed number of UDP queries per second from a single IPv6 or IPv4 address.

Rate limiting is performed for the whole address and several chosen prefixes. The limits of prefixes are constant multiples of rate-limit.

The specific prefixes and multipliers, which might be adjusted in the future, are for IPv6 /128: 1, /64: 2, /56: 3, /48: 4, /32: 64; for IPv4 /32: 1, /24: 32, /20: 256, /18: 768.

With each host/network, a counter of unrestricted responses is associated; if the counter would exceed its capacity, it is not incremented and the response is restricted. Counters use exponential decay for lowering their values, i.e. they are lowered by a constant fraction of their value each millisecond. The specified rate limit is reached, when the number of queries is the same every millisecond; sending many queries once a second or even a larger timespan leads to a more strict limiting.

Set to 0 to disable the rate limiting.

Default: `50`

#### instant-limit

Maximal allowed number of queries at a single point in time from a single IPv6 or IPv4 address. The limits for prefixes use the same multipliers as for rate-limit.

This limit is reached when many queries come from a new host/network, or after a longer time of inactivity.

The instant-limit sets the actual capacity of each counter of responses, and together with the rate-limit they set the fraction by which the counter is periodically lowered. The instant-limit may be at least rate-limit / 1000, at which point the counters are zeroed each millisecond.

Default: `125`

#### slip

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).

- Setting the value to 0 will cause that all rate-limited responses will be dropped. The outbound bandwidth and packet rate will be strictly capped by the rate-limit option. All legitimate requestors affected by the limit will face denial of service and will observe excessive timeouts. Therefore this setting is not recommended.

- Setting the value to 1 will cause that all rate-limited responses will be sent as truncated. The amplification factor of the attack will be reduced, but the outbound data bandwidth won't be lower than the incoming bandwidth. Also the outbound packet rate will be the same as without RRL.

- Setting the value to 2 will cause that approximately half of the rate-limited responses will be dropped, the other half will be sent as truncated. With this configuration, both outbound bandwidth and packet rate will be lower than the inbound. On the other hand, the dropped responses enlarge the time window for possible cache poisoning attack on the resolver.

- Setting the value to anything larger than 2 will keep on decreasing the outgoing rate-limited bandwidth, packet rate, and chances to notify legitimate requestors to reconnect using TCP. These attributes are inversely proportional to the configured value. Setting the value high is not advisable.

Default: `1`

#### time-rate-limit

This limit works similarly to rate-limit but considers the time consumed (in microseconds) by the remote over non-UDP transport protocols.

Set to 0 to disable the time limiting.

Default: `5000` (microseconds)

#### time-instant-limit

This limit works similarly to instant-limit but considers the time consumed (in microseconds) by the remote over non-UDP transport protocols.

Default: `5000` (microseconds)

#### table-size

Maximal number of stored hosts/networks with their counters. The data structure tries to store only the most frequent sources, so it is safe to set it according to the expected maximal number of limited ones.

Use 1.4 * maximum_qps / rate-limit, where maximum_qps is the number of queries which can be handled by the server per second. There is at most maximum_qps / rate-limit limited hosts; larger networks have higher limits and so require only a fraction of the value (handled by the 1.4 multiplier). The value will be rounded up to the nearest power of two.

The same table size is used for both counting-based and time-based limiting; the maximum number of time-limited hosts is expected to be lower, so it's not typically needed to be considered. There is at most 1 000 000 * #cpus / time-rate-limit of them.

The memory occupied by one table structure is 8 * table-size B.

Default: `524288`

#### whitelist

An ordered list of IP addresses, absolute UNIX socket paths, network subnets, or network ranges to exempt from rate limiting. Empty list means that no incoming connection will be white-listed.

Default: not set

#### log-period

Minimal time in milliseconds between two log messages, or zero to disable logging.

If a response is limited, the address and the prefix on which it was blocked is logged and logging is disabled for the log-period milliseconds. As long as limiting is needed, one source is logged each period and sources with more blocked queries have greater probability to be chosen.

The approach is used by counting-based and time-based limiting separately, so you can expect one message per log-period from each of them.

Default: `30000` (milliseconds)

#### dry-run

If enabled, the module doesn't alter any response. Only query classification is performed with possible statistics counter incrementation.

Default: `off`

## `stats` — Query statistics

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.

### Example

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

### Module reference

    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

#### id

A module identifier.

#### request-protocol

If enabled, all incoming requests are counted by the network protocol:

- udp4 - UDP over IPv4

- tcp4 - TCP over IPv4

- quic4 - QUIC over IPv4

- tls4 - TLS over IPv4

- udp6 - UDP over IPv6

- tcp6 - TCP over IPv6

- quic6 - QUIC over IPv6

- tls6 - TLS over IPv6

- udp4-xdp - UDP over IPv4 through XDP

- tcp4-xdp - TCP over IPv4 through XDP

- quic4-xdp - QUIC over IPv4 through XDP

- udp6-xdp - UDP over IPv6 through XDP

- tcp6-xdp - TCP over IPv6 through XDP

- quic6-xdp - QUIC over IPv6 through XDP

Default: `on`

#### server-operation

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:

- query - Normal query operation

- update - Dynamic update operation

- notify - NOTIFY request operation

- axfr - Full zone transfer operation

- ixfr - Incremental zone transfer operation

- invalid - Invalid server operation

Default: `on`

#### request-bytes

If enabled, all incoming request bytes are counted by the server operation:

- query - Normal query bytes

- update - Dynamic update bytes

- other - Other request bytes

Default: `on`

#### response-bytes

If enabled, outgoing response bytes are counted by the server operation:

- reply - Normal response bytes

- transfer - Zone transfer bytes

- other - Other response bytes

Warning

Dynamic update response bytes are not counted by this module.

Default: `on`

#### edns-presence

If enabled, EDNS pseudo section presence is counted by the message direction:

- request - EDNS present in request

- response - EDNS present in response

Default: `off`

#### flag-presence

If enabled, some message header flags are counted:

- TC - Truncated Answer in response

- DO - DNSSEC OK in request

Default: `off`

#### response-code

If enabled, outgoing response code is counted:

- NOERROR

- ...

- NOTZONE

- BADVERS

- ...

- BADCOOKIE

- other - All other codes

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`

#### request-edns-option

If enabled, EDNS options in requests are counted by their code:

- CODE0

- ...

- EDNS-KEY-TAG (CODE14)

- other - All other codes

Default: `off`

#### response-edns-option

If enabled, EDNS options in responses are counted by their code. See request-edns-option.

Default: `off`

#### reply-nodata

If enabled, NODATA pseudo RCODE (RFC 2308 Section 2.2) is counted by the query type:

- A

- AAAA

- other - All other types

Default: `off`

#### query-type

If enabled, normal query type is counted:

- A (TYPE1)

- ...

- TYPE65

- SPF (TYPE99)

- ...

- TYPE110

- ANY (TYPE255)

- ...

- TYPE260

- other - All other types

Note

Not all assigned meta types (IXFR, AXFR,...) have their own counters, because such types are not processed as normal query.

Default: `off`

#### query-size

If enabled, normal query message size distribution is counted by the size range in bytes:

- 0-15

- 16-31

- ...

- 272-287

- 288-65535

Default: `off`

#### reply-size

If enabled, normal reply message size distribution is counted by the size range in bytes:

- 0-15

- 16-31

- ...

- 4080-4095

- 4096-65535

Default: `off`

## `synthrecord` – Automatic forward/reverse records

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.

### Example

#### Automatic forward records

    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-0-b61-100--1.test.
    ...
    ;; QUESTION SECTION:
    ;; dynamic-2620-0-b61-100--1.test. IN AAAA

    ;; ANSWER SECTION:
    dynamic-2620-0-b61-100--1.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-0-b61-100--2.test.
    dynamic-2620-0-b61-100--2.test. 400 IN AAAA 2620:0:b61:100::2

#### Automatic reverse records

    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-0-b61--1.test.

### Module reference

    mod-synthrecord:
      - id: STR
        type: forward | reverse
        prefix: STR
        origin: DNAME
        ttl: INT
        network: ADDR[/INT] | ADDR-ADDR ...
        reverse-short: BOOL

#### id

A module identifier.

#### type

The type of generated records.

Possible values:

- `forward` – Forward records

- `reverse` – Reverse records

Required

#### prefix

A record owner prefix.

Note

The value doesn’t allow dots, address parts in the synthetic names are separated with a dash.

Default: empty

#### origin

A zone origin (only valid for the reverse type).

Required

#### ttl

Time to live of the generated records.

Default: `3600`

#### network

An ordered list of IP addresses, network subnets or network ranges the query must match.

Required

#### reverse-short

If enabled, a shortened IPv6 address can be used for reverse record rdata synthesis.

Default: `on`

## `whoami` — Whoami response

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.

### Example

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.