说明
dnstap 是一种灵活的、结构化的二进制日志格式,适用于 DNS 软件;请参阅 https://dnstap.info。通过此插件,您可以让 CoreDNS 输出 dnstap 日志。
每条消息都将在出现后立即发送到套接字,dnstap 插件具有 10000 条消息缓冲区,超过此数量的 dnstap 消息将会被丢弃(此情况会记录下来)。
语法
dnstap SOCKET [full] {
[identity IDENTITY]
[version VERSION]
[extra EXTRA]
[skipverify]
}
- SOCKET 是提供给 dnstap 命令行工具的套接字(路径)。
full
用于包含原始格式的 DNS 消息。- IDENTITY 用于覆盖服务器标识。默认为主机名。
- VERSION 用于覆盖版本字段。默认为 CoreDNS 版本。
- EXTRA 用于定义 dnstap 有效负载中的“extra”字段,此处提供 metadata 替换。
skipverify
用于在连接时跳过 TLS 验证。默认为安全设置
示例
将有关客户端请求和响应的信息记录到 /tmp/dnstap.sock。
dnstap /tmp/dnstap.sock
将有关客户端请求和响应的信息(包括原始格式的 DNS 消息)记录到 /tmp/dnstap.sock。
dnstap unix:///tmp/dnstap.sock full
记录到远程端点。
dnstap tcp://127.0.0.1:6000 full
按 FQDN 记录到远程端点。
dnstap tcp://example.com:6000 full
记录到套接字,同时覆盖默认标识和版本。
dnstap /tmp/dnstap.sock {
identity my-dns-server1
version MyDNSServer-1.2.3
}
记录到套接字,自定义 dnstap 有效负载中的“extra”字段。您可以在 extra 字段中使用其他插件提供的元数据。
forward . 8.8.8.8
metadata
dnstap /tmp/dnstap.sock {
extra "upstream: {/forward/upstream}"
}
记录到远程 TLS 端点。
dnstap tls://127.0.0.1:6000 full {
skipverify
}
您可以多次使用dnstap 来定义多个记录。以下操作将记录有关客户端请求和响应的信息(包括原始格式的 DNS 消息)到 /tmp/dnstap.sock,且还将客户端请求和响应(不含原始格式的 DNS 消息)发送到远程 FQDN。
dnstap /tmp/dnstap.sock full
dnstap tcp://example.com:6000
命令行工具
Dnstap 具有一个命令行工具,可用于检查日志记录。可以在 Github 上找到此工具:https://github.com/dnstap/golang-dnstap。该工具是使用 Go 语言编写的。
以下命令侦听指定的套接字并将消息解码为 stdout。
$ dnstap -u /tmp/dnstap.sock
以下命令侦听指定的套接字并将消息有效负载保存到二进制 dnstap 格式的日志文件。
$ dnstap -u /tmp/dnstap.sock -w /tmp/test.dnstap
在端口 6000 上侦听 dnstap 消息。
$ dnstap -l 127.0.0.1:6000
在插件中使用 Dnstap
在设置功能中收集并存储在配置中加载的所有 dnstap 插件列表
x := &ExamplePlugin{}
c.OnStartup(func() error {
if taph := dnsserver.GetConfig(c).Handler("dnstap"); taph != nil {
for tapPlugin, ok := taph.(*dnstap.Dnstap); ok; tapPlugin, ok = tapPlugin.Next.(*dnstap.Dnstap) {
x.tapPlugins = append(x.tapPlugins, tapPlugin)
}
}
return nil
})
然后在插件中
import (
"github.com/coredns/coredns/plugin/dnstap/msg"
"github.com/coredns/coredns/request"
tap "github.com/dnstap/golang-dnstap"
)
func (x ExamplePlugin) ServeDNS(ctx context.Context, w dns.ResponseWriter, r *dns.Msg) (int, error) {
for _, tapPlugin := range x.tapPlugins {
q := new(msg.Msg)
msg.SetQueryTime(q, time.Now())
msg.SetQueryAddress(q, w.RemoteAddr())
if tapPlugin.IncludeRawMessage {
buf, _ := r.Pack() // r has been seen packed/unpacked before, this should not fail
q.QueryMessage = buf
}
msg.SetType(q, tap.Message_CLIENT_QUERY)
// if no metadata interpretation is needed, just send the message
tapPlugin.TapMessage(q)
// OR: to interpret the metadata in "extra" field, give more context info
tapPlugin.TapMessageWithMetadata(ctx, q, request.Request{W: w, Req: query})
}
// ...
}
另请参见
网站 dnstap.info 上提供了有关 dnstap 协议的信息。forward 插件的 dnstap.go
使用 dnstap 记录发送到上游的消息。