Play with Extra DNStap field
In this blog post, we will explore how to include additional metadata in your DNStap logs, such as security flags, resolver IP addresses, and more. The DNStap protocol offers an extra field specifically designed for this purpose.
// Extra data for this payload.
// This field can be used for adding an arbitrary byte-string annotation to
// the payload. No encoding or interpretation is applied or enforced.
optional bytes extra = 3;
Let’s begin by exploring how to implement this feature in CoreDNS.
CoreDNS
Support for the extra field was introduced in CoreDNS starting from v1.11.1. Below is an example of how to add the upstream IP (either 8.8.8.8 or 9.9.9.9) to the extra field.
First, create the coredns.conf file. This configuration sets up your CoreDNS instance to:
- Listen on port 53 for DNS queries.
- Enable metadata collection.
- Send dnstapto the remote collector 10.0.0.100 on port 6000 with full logging.
- Specify the identity as “coredns” for dnstap data.
- Include upstream addresses in extra field
- Cache DNS responses.
- Forward DNS queries to both 8.8.8.8 and 9.9.9.9 as upstream resolvers.
.:53 {
metadata
dnstap tcp://10.0.0.100:6000 full {
identity coredns
extra {/forward/upstream}
}
cache
forward . 8.8.8.8 9.9.9.9
}
Next, start CoreDNS using the Docker image:
sudo docker run -d -p 8053:53/tcp -p 8053:53/udp --name=coredns -v $PWD/coredns.conf:/config.conf coredns/coredns:1.11.1 -conf /config.conf
To retrieve DNS logs with support for the extra field, you can utilize the DNS-collector
Create the dnscollector.conf file. This configuration sets up DNS collector (dnscollector) to listen on port tcp 6000 for incoming dnstap data and send it to the console logger in a specified text format that includes the timestamp, identity, operation, query IP, extra field, query name (qname), and response code (rcode).
multiplexer:
collectors:
- name: tap
dnstap:
listen-ip: 0.0.0.0
listen-port: 6000
loggers:
- name: console
stdout:
mode: text
text-format: "timestamp-rfc3339ns identity operation queryip extra qname rcode"
routes:
- from: [ tap ]
to: [ console ]
Now, start the DNS-collector using the Docker image:
sudo docker run -d -p 6000:6000/tcp --name=dnscollector -v $PWD/dnscollector.conf:/config.conf dmachard/go-dnscollector:v0.36.0 -config /config.conf
Execute the dig command to perform a DNS resolution using your CoreDNS instance:
dig @127.0.0.1 -p 8053 www.twitter.com
To view the DNScollector logs and observe the extra field, use the following command:
sudo docker logs dnscollector
You should see logs similar to the following, with the extra field equal to 8.8.8.8:53 and 9.9.9.9:53:
023-09-20T18:08:17.912209255Z coredns1 FORWARDER_QUERY 172.17.0.1 8.8.8.8:53 www.google.com NOERROR
2023-09-20T18:08:17.943256625Z coredns1 FORWARDER_RESPONSE 172.17.0.1 8.8.8.8:53 www.google.com NOERROR
2023-09-20T18:08:17.943348497Z coredns1 CLIENT_RESPONSE 172.17.0.1 8.8.8.8:53 www.google.com NOERROR
2023-09-20T18:08:51.271234557Z coredns1 CLIENT_QUERY 172.17.0.1 - www.twitter.com NOERROR
2023-09-20T18:08:51.271290121Z coredns1 FORWARDER_QUERY 172.17.0.1 9.9.9.9:53 www.twitter.com NOERROR
2023-09-20T18:08:51.294051653Z coredns1 FORWARDER_RESPONSE 172.17.0.1 9.9.9.9:53 www.twitter.com NOERROR
2023-09-20T18:08:51.294120571Z coredns1 CLIENT_RESPONSE 172.17.0.1 9.9.9.9:53 www.twitter.com NOERROR
DNSdist
Next, continue into DNSdist, a tool that offers greater flexibility in adding custom information to the extra field in dnstap messages. Before getting started, within your working directory, generate certificates and a private key for use with the DNS over HTTPS (DoH) service:
openssl rand -base64 48 > passphrase.txt
openssl genrsa -aes128 -passout file:passphrase.txt -out server.key 2048
openssl req -new -passin file:passphrase.txt -key server.key -out server.csr -subj "/C=FR/O=krkr/OU=Domain Control Validated/CN=*.test.dev"
openssl rsa -in server.key -passin file:passphrase.txt -out doh.key
openssl x509 -req -days 36500 -in server.csr -signkey doh.key -out doh.crt
Now, create the config_dnsdist.conf
file with the following Lua configuration.
This DNSdist configuration listen on DoH service with backends load balancing (google, cloudflare, quad9)
The lua functions (alterDnstapQuery, alterDnstapResponse, alterDnstapCachedResponse) are used to customize the extra field in dnstap messages.
addDOHLocal("0.0.0.0:443", "/etc/dnsdist/doh.crt", "/etc/dnsdist/doh.key", "/dns-query", {keepIncomingHeaders=true})
setACL({'0.0.0.0/0'})
newServer({address = "1.1.1.1", pool="poolA"})
newServer({address = "9.9.9.9", pool="poolB"})
newServer({address = "8.8.8.8", pool="poolB"})
function alterDnstapQuery(dq, tap)
local ua = ""
for key,value in pairs(dq:getHTTPHeaders()) do
if key == 'user-agent' then
ua = value
break
end
end
tap:setExtra(ua)
end
function alterDnstapResponse(dr, tap)
tap:setExtra(dr.pool)
end
function alterDnstapCachedResponse(dr, tap)
tap:setExtra("cached")
end
-- init dnstap remote collector
rl = newFrameStreamTcpLogger("192.168.1.17:6000")
-- rules for queries
addAction(AllRule(), DnstapLogAction("dnsdist1", rl, alterDnstapQuery))
addAction(ProbaRule(0.5), PoolAction("poolA"))
addAction(AllRule(), PoolAction("poolB"))
-- rules for replies
addResponseAction(AllRule(), DnstapLogResponseAction("dnsdist1", rl, alterDnstapResponse))
To start DNSdist using a Docker image, use the following command:
sudo docker run -d -p 8443:443/tcp -p 8083:8080 --name=dnsdist -v $PWD/:/etc/dnsdist/:ro powerdns/dnsdist-18:1.8.1
To test the DNSdist configuration, you can install and use the q client. Then, perform a DoH resolution using your DNSdist server with the following command:
./q www.google.fr A @https://127.0.0.1:8443 --tls-no-verify
To view the DNScollector logs and observe the extra field, use the following command:
sudo docker logs dnscollector
You should see logs similar to the following, which include the “User-Agent” of the HTTP client or the “pool” used:
2023-09-20T20:20:39.423635597Z dnsdist1 CLIENT_RESPONSE 172.17.0.1 poolA www.google.fr NOERROR
2023-09-20T20:20:42.883887269Z dnsdist1 CLIENT_QUERY 172.17.0.1 Go-http-client/1.1 www.google.fr NOERROR
2023-09-20T20:20:42.899695506Z dnsdist1 CLIENT_RESPONSE 172.17.0.1 poolA www.google.fr NOERROR
2023-09-20T20:20:43.241895751Z dnsdist1 CLIENT_QUERY 172.17.0.1 Go-http-client/1.1 www.google.fr NOERROR
2023-09-20T20:20:43.254621667Z dnsdist1 CLIENT_RESPONSE 172.17.0.1 poolA www.google.fr NOERROR
2023-09-20T20:20:43.611780251Z dnsdist1 CLIENT_QUERY 172.17.0.1 Go-http-client/1.1 www.google.fr NOERROR
2023-09-20T20:20:43.628321105Z dnsdist1 CLIENT_RESPONSE 172.17.0.1 poolB www.google.fr NOERROR