# dnstap-utils A collection of [dnstap] utilities implemented using the Rust programming language. [dnstap]: https://dnstap.info/ ## `dnstap-replay` `dnstap-replay` is a dnstap collection server which receives dnstap messages from one or more DNS nameservers and replays them against a target nameserver. The responses from the target nameserver are compared against the originally logged response messages and any ***mismatches*** or other errors are made available in dnstap format via an HTTP endpoint for later analysis. ### `dnstap-replay`: dnstap message requirements `dnstap-replay` was designed for testing authoritative nameservers. The only type of dnstap log payload that `dnstap-replay` supports is the `Message/AUTH_RESPONSE` type. Any other dnstap log payload types will be silently ignored by `dnstap-replay`. The following fields are ***required*** to be set in the dnstap log payload: * `query_address` * `query_port` * `query_message` * `response_message` Typically, dnstap `Message/*_RESPONSE` log payloads do not include both the `query_message` and `response_message` fields on the assumption that the query message will be logged separately by a `Message/*_QUERY` log payload. However, this presents a problem for the replay-and-comparison phase in `dnstap-replay` because it is not entirely trivial to derive the original DNS query message given only the DNS response message. In some cases it may be impossible to recover the original query, for instance if the query is not a validly formatted DNS message. For the Knot DNS server, [support was added in version 3.1.4] to add a configuration option `responses-with-queries` to the `dnstap` module that logs ***both*** query and response messages together in the `Message/AUTH_RESPONSE` log payload type. The `mod-dnstap` configuration stanza in `knot.conf` would need to look like the following to produce dnstap output with the fields needed by `dnstap-replay`: ``` mod-dnstap: - id: "default" sink: "[...]" log-queries: off log-responses: on responses-with-queries: on ``` [support was added in version 3.1.4]: https://gitlab.nic.cz/knot/knot-dns/-/issues/764 ### `dnstap-replay`: PROXY support in target nameserver `dnstap-replay` was originally designed for testing nameservers that may have source IP address dependent behavior or configuration. When a dnstap-originated DNS query message is replayed by `dnstap-replay`, the target nameserver sees the source IP address of the machine running `dnstap-replay` on the UDP packets containing the replayed query messages. This may elicit varying DNS response message content from the target nameserver. In order to avoid this problem, `dnstap-replay` can use the haproxy [PROXY] protocol to prepend the original source address and source port as logged in the `query_address` and `query_port` dnstap message fields to the outgoing DNS query message sent to the target nameserver. This requires support in the target nameserver. Currently, at least [dnsdist], [PowerDNS Authoritative Nameserver], [PowerDNS Recursor], and [Knot DNS] have support for the PROXY header. To enable this functionality in `dnstap-replay`, add the `--proxy` option to the command-line parameters. Support for PROXYv2 as a connection target was added in Knot DNS version 3.2.2, which adds a configuration option [`proxy_allowlist`] that lists the IP addresses that are allowed to initiate queries with the PROXYv2 header. It is enabled by placing the option in the `server` configuration stanza, for instance: ``` server: […] proxy-allowlist: 127.0.0.0/8 ``` [PROXY]: https://www.haproxy.org/download/2.5/doc/proxy-protocol.txt [dnsdist]: https://blog.powerdns.com/2021/05/11/dnsdist-1-6-0-released/ [PowerDNS Authoritative Nameserver]: https://github.com/PowerDNS/pdns/pull/10660 [PowerDNS Recursor]: https://github.com/PowerDNS/pdns/pull/8874 [Knot DNS]: https://gitlab.nic.cz/knot/knot-dns/-/merge_requests/1468 [`proxy_allowlist`]: https://www.knot-dns.cz/docs/3.2/html/reference.html?highlight=proxy#proxy-allowlist ### `dnstap-replay`: HTTP server `dnstap-replay` includes a built-in HTTP server to export [Prometheus metrics] which are available at the `/metrics` HTTP endpoint. When `dnstap-replay` sends a DNS query to the target nameserver and the response from the target nameserver does not exactly match the originally logged response message, a log message containing the mismatched response message is generated and buffered in memory and can be retrieved from the `/errors` HTTP endpoint. This endpoint drains the error buffer and provides the output in Frame Streams format containing dnstap payloads. The dnstap log messages exported via the `/errors` endpoint are the originally logged dnstap messages received by `dnstap-replay`, with the [dnstap `extra` field] populated with a serialized version of the error encountered by `dnstap-replay`. This preserves the original DNS response message as well as the DNS response message sent by the target nameserver, which allows for byte-for-byte analysis of the mismatch. A separate `/timeouts` endpoint is available which can be used to retrieve dnstap log messages that resulted in timeouts when re-querying the target nameserver. The format used is the same as the `/errors` endpoint. [Prometheus metrics]: https://github.com/fastly/dnstap-utils/blob/main/src/bin/dnstap-replay/metrics.rs [dnstap `extra` field]: https://github.com/dnstap/dnstap.pb/blob/9bafb5b59dacc48a6ff6a839e419e540f1201c42/dnstap.proto#L37-L40 ### `dnstap-replay`: Command-line example `dnstap-replay` requires the `--dns`, `--http`, and `--unix` arguments to be provided. The `--dns` argument specifies the IP address and port of the target nameserver which will receive replayed DNS queries. The `--http` argument specifies the IP address and port for the built-in HTTP server. The `--unix` argument specifies the filesystem path to bind the dnstap Unix socket to. Additionally, there are command-line options `--channel-capacity` and `--channel-error-capacity` which allow tuning of internal buffer sizes. For example, the following command-line invocation will listen on the filesystem path `/run/dnstap.sock` for incoming dnstap connections from the DNS server(s) that will send dnstap log data and on the TCP socket 127.0.0.1:53080 for incoming HTTP connections. Replayed DNS queries will be sent to the target nameserver which should be configured to listen on 127.0.0.1:53053. ``` $ dnstap-replay --dns 127.0.0.1:53053 --http 127.0.0.1:53080 --unix /run/dnstap.sock ``` The Prometheus metrics endpoint can be accessed at `http://127.0.0.1:53080/metrics`. The Frame Streams "errors" endpoint can be accessed at `http://127.0.0.1:53080/errors`. The Frame Streams "timeouts" endpoint can be accessad at `http://127.0.0.1:53080/timeouts`. ## `dnstap-dump` `dnstap-dump` is a utility which dumps a Frame Streams formatted dnstap file to YAML. The output format is very similar to the format generated by the [`dnstap-ldns`] utility. It has support for decoding the `extra` field in dnstap error payloads produced by `dnstap-replay`, and it also dumps DNS wire messages in hex-encoded wire format as well as in dig-style output. [`dnstap-ldns`]: https://github.com/dnstap/dnstap-ldns ## `fmt-dns-message` `fmt-dns-message` is a utility which converts a hex-encoded wire format DNS message to dig-style output using the [NLnet Labs `domain` crate]. [NLnet Labs `domain` crate]: https://github.com/NLnetLabs/domain ## License `dnstap-utils` is distributed under the terms of the [Apache-2.0] license. See the [LICENSE] and [NOTICE] files for details. [Apache-2.0]: https://www.apache.org/licenses/LICENSE-2.0 [LICENSE]: https://github.com/fastly/dnstap-utils/blob/main/LICENSE [NOTICE]: https://github.com/fastly/dnstap-utils/blob/main/NOTICE