dnstap

源代码

dnstap 可启用向 dnstap 进行日志记录。

说明

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 记录发送到上游的消息。