ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Vector dnstap Source 深度实战:从 BIND 采集 DNSTAP DNS 查询日志的完整配置与解析机制

2026/9/13 20:12:29 拓冰建站 浏览量
Vector dnstap Source 深度实战:从 BIND 采集 DNSTAP DNS 查询日志的完整配置与解析机制 Vector dnstap Source 深度实战从 BIND 采集 DNSTAP DNS 查询日志的完整配置与解析机制【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector本篇指南以 Vector 的dnstapsource 组件为核心讲解如何配置 TCP/Unix Socket 两种监听模式从支持 DNSTAP 协议的 DNS 服务器以 BIND 为例采集 DNS 查询与动态更新日志覆盖全部配置参数、输出事件字段结构、可运行的实操示例并深入到 src/sources/dnstap/mod.rs 的帧处理与解析实现。读完你可以独立完成 DNS 服务器与 Vector 的对接理解rawData解析链路和内部遥测事件的含义。组件定位与核心属性dnstapsource 用于从 dnstap。它监听一条 socket 连接接收 DNS 服务器如 BIND发出的 DNSTAP 帧Protobuf 编码将其解析为结构化的日志事件向下游输出。组件元数据定义在 website/cue/reference/components/sources/dnstap.cue关键属性如下属性值说明组件类型source数据入口交付语义deliverybest_effort尽力而为不保证每条事件都送达确认机制acknowledgementsfalse不支持端到端确认源码中can_acknowledge()返回false部署角色daemon作为守护进程运行开发状态beta仍处于 beta 阶段有状态false无状态组件输出数据logs输出日志事件不支持 multiline由于不支持确认且是尽力交付生产环境建议将其用于可容忍少量丢失的 DNS 可观测性场景查询分析、异常检测等而非强一致性场景。配置结构总览配置结构由 src/sources/dnstap/mod.rs 中的DnstapConfig定义顶层公共参数之外通过mode字段serde tag在Tcp(TcpConfig)与Unix(UnixConfig)两个变体之间切换。TcpConfig与UnixConfig分别定义在 src/sources/dnstap/tcp.rs 和 src/sources/dnstap/unix.rs。参数说明数据类型、默认值、适用条件、示例值由 website/cue/reference/components/sources/generated/dnstap.cue 生成。公共参数tcp / unix 两种模式通用参数类型必填默认值说明modestring (tcp|unix)是unix 平台默认 unix非 unix 平台默认 tcp0.0.0.0:9000使用的 dnstap socket 类型max_frame_lengthuint字节否102400100 KiB见default_max_frame_length()源接受的最大 DNSTAP 帧长度超过的帧直接丢弃host_keystring否全局log_schema.host_key覆盖写入对端地址的日志字段名值为 socket 地址本身raw_data_onlybool否false是否跳过 DNSTAP 帧的解析/解码。为true时原始帧数据以 base64 字符串写入事件的rawData字段multithreadedbool否false是否并发处理 DNSTAP 帧max_frame_handling_tasksuint否1000源码中unwrap_or(1000)可并发处理的最大帧数lowercase_hostnamesbool否false是否将所有接收到的 DNSTAP 主机名统一转为小写保证一致性TCP 模式mode tcp适用于跨主机接收 DNSTAP 数据DNS 服务器通过网络连接到 Vector。参数类型必填默认值说明addressstring是-监听地址必须包含端口支持systemd{#N}使用 systemd socket activation 传递的第 N 个 socket。示例0.0.0.0:9000、systemd、systemd#3port_keystring否port覆盖写入对端端口的日志字段名值形如9000设为可抑制该字段permit_originstring[]否-允许的源 IP 网段白名单CIDR 表示。示例192.168.0.0/16、127.0.0.1/32、::1/128receive_buffer_bytesuint字节否-每条连接使用的接收缓冲区大小max_connection_duration_secsuint秒否-单条连接最长保持时间超时的连接会被关闭有助于对长连接做负载均衡connection_limituint连接数否-任意时刻允许的最大 TCP 连接数keepalive对象否-TCP keepalive 设置TcpKeepaliveConfigshutdown_timeout_secsuint秒否30关闭阶段强制关闭连接前的超时时间tls对象否关闭TlsSourceConfig开启 TLS 并支持从客户端证书中提取元数据TCP 模式的一个关键细节来自 src/sources/dnstap/tcp.rs当tls配置中指定了client_metadata_key时DnstapFrameHandler::insert_tls_client_metadata会把客户端证书的subject写入事件的tls_client_metadata字段键名可自定义用于审计“哪个客户端连接在发送 DNSTAP 数据”。同时每个接收到的帧会触发SocketEventsReceived内部事件mode tcp用于字节计数遥测。permit_origin在实现中映射为IpAllowlistConfig最终转换为VecIpNet网段表不匹配的源地址连接会被拒绝。Unix Socket 模式mode unix适用于 Vector 与 DNS 服务器部署在同一台机器的最常见场景。DNS 服务器把 DNSTAP 数据写入 Vector 创建的 server UDS。参数类型必填默认值说明socket_pathstring是/run/bind/dnstap.sock源码UnixConfig::default()读取 DNSTAP 数据的 socket 文件绝对路径源首次启动时若不存在会自动创建socket_file_modeuint否由umask决定socket 文件的权限位。支持任意数字格式最直观的是八进制如0o777、0o754、508即0o774socket_receive_buffer_sizeuint字节否-接收缓冲区大小。注意需要相应调整系统级最大 socket 接收缓冲区Linux 的/proc/sys/net/core/rmem_max才能生效socket_send_buffer_sizeuint字节否-发送缓冲区大小。注意需要相应调整/proc/sys/net/core/wmem_max关于 UDS 的工作机制源自 dnstap.cue 的 how_it_works 章节启动时dnstap源在指定路径创建新的 server UDS若该路径上的 UDS 已存在被占用Vector 会先自动删除再创建。UDS 默认权限取决于当前umask。为了让本机 BIND 能够向 UDS 写数据需通过socket_file_mode显式设置权限例如[sources.my_dnstap_source] type dnstap mode unix socket_file_mode 0o774 # 其他配置使用远端 BIND 服务器UDS 只能创建在本地机器但可以配合 SSH 端口/通道转发把本地 UDS 转发到远端 BIND 所在主机让远端 BIND 写入“本地”socket。确保两端 Unix socket 权限设置正确。调整 UDS 缓冲区在高负载场景下可平滑处理 DNS 流量尖峰将socket_receive_buffer_size/socket_send_buffer_size调到例如 10 MiB[sources.my_dnstap_source] type dnstap mode unix socket_receive_buffer_size 10_485_760 socket_send_buffer_size 10_485_760 # 其他配置事件输出字段结构解析成功后每个 DNSTAP 帧输出为一个日志事件。字段定义在 dnstap.cue 的 output 章节并对应 src/sources/dnstap/mod.rs 中DnstapConfig::schema_definition引用的DnstapEventSchema来自 lib/vector-vrl/dnstap-parser 的 schema 模块。顶层字段字段类型必填说明dataTypestring否DNSTAP 事件数据类型目前仅定义Message载荷为 dnstap messagedataTypeIduint是数据类型数字 ID如1messageTypestring否DNSTAP 消息类型仅dataType Message时有意义枚举见下表messageTypeIduint是消息类型数字 ID如6timeuint是DNS 消息发送/接收时间为距 UNIX 纪元的timePrecision时间单位数timePrecisionstring是time的时间精度s/ms/us/nstimestampstring是与time相同时刻ISO 8601 UTC 字符串如2021-04-09T15:08:32.767098ZserverIdstring否DNS 服务器标识如ns1.example.comserverVersionstring否DNS 服务器版本如BIND 9.16.8extraInfostring否事件的附加数据任意字节注解的 base64 形式socketFamilystring是INETIPv4或INET6IPv6决定如何解释地址字段socketProtocolstring是UDP或TCP决定如何解释端口字段sourceAddress/sourcePortstring / uint是 / 否消息发起方的网络地址 / 传输端口responseAddress/responsePortstring / uint是 / 否消息响应方的网络地址 / 传输端口errorstring否解析 dnstap 数据失败时的错误信息rawDatastring否解析失败或开启raw_data_only时出现的原始 DNSTAP 二进制数据 base64requestDataobject否DNS 查询/更新的请求消息数据子结构见下responseDataobject否DNS 查询/更新的响应消息数据子结构见下messageType 枚举14 种视角组合枚举值语义以谁为视角AuthQuery/AuthResponse权威服务器收到解析器的查询 / 权威服务器发回响应ResolverQuery/ResolverResponse解析器发往权威服务器的查询通常清 RD 位/ 解析器收到的响应ClientQuery/ClientResponseDNS 服务器视角客户端发来递归期望的查询 / 服务器回给客户端的响应通常置 RA 位ForwarderQuery/ForwarderResponse下游服务器发往上游递归服务器的查询 / 上游回给下游的响应StubQuery/StubResponse桩解析器视角的查询 / 响应ToolQuery/ToolResponseDNS 工具视角的查询 / 响应UpdateQuery/UpdateResponse权威服务器视角收到的动态更新 / 发出的更新响应requestData / responseData 子结构公共字段time、timePrecision、fullRcode4 位 header rcode 8 位 opt extendedRcode 之和、rcodeName文本化响应码、rawData仅解析失败时出现base64。rcodeName枚举覆盖 DNS 标准响应码NoError、FormErr、ServFail、NXDomain、NotImp、Refused、YXDomain、YXRRSet、NXRRSet、NotAuth、NotZone以及 EDNS 扩展码BADVERS、BADSIG、BADKEY、BADTIME、BADMODE、BADNAME、BADALG、BADTRUNC、BADCOOKIE。requestData特有子段header、question、additional、optEDNS 伪段含do、ednsVersion、extendedRcode、options、udpPayloadSize、zone/prerequisite/updateDNS 动态更新三段见 RFC 2136。responseData特有子段header、question、answers、authority、additional、opt、zone。其中opt还包含ede数组扩展 DNS 错误含infoCode、purpose、extraText见 RFC 8914。资源记录条目字段示例class、domainName、rData、recordType、recordTypeId、ttl。实操示例一采集常规 DNS 查询与响应前置条件来自 website/cue/reference/services/dnstap_data.cue 的设置说明参考 ISC 官方 KB 文章 “Using DNSTAP with BIND” 配置 BIND使其把 DNSTAP 数据写入 Vector 将创建的 Unix socket确保该 socket 对 DNS 服务器进程可写例如 BIND 对 socket 有rw权限可用socket_file_mode 508即0o774实现BIND 与 Vector 两端配置的 Unix socket 路径一致。Vector 配置[sources.my_dnstap_source] type dnstap mode unix socket_path /run/bind/dnstap.sock socket_file_mode 508 max_frame_length 102400 max_frame_handling_tasks 10000在 BIND 上执行一条本地查询nslookup host.example.com localhost源将输出两个事件。查询事件节选{ dataType: Message, dataTypeId: 1, messageType: ClientQuery, messageTypeId: 5, requestData: { fullRcode: 0, header: { aa: false, ad: false, anCount: 0, arCount: 0, cd: false, id: 49653, nsCount: 0, opcode: 0, qdCount: 1, qr: 0, ra: false, rcode: 0, rd: true, tc: false }, question: [ { class: IN, domainName: host.example.com., questionType: A, questionTypeId: 1 } ], rcodeName: NoError, time: 1614781642516276825, timePrecision: ns }, responseAddress: 127.0.0.1, responsePort: 0, serverId: ns1.example.com, serverVersion: BIND 9.16.8, socketFamily: INET, socketProtocol: UDP, sourceAddress: 127.0.0.1, sourcePort: 52398, time: 1614781642516276825, timePrecision: ns }响应事件节选{ dataType: Message, dataTypeId: 1, messageType: ClientResponse, messageTypeId: 6, responseData: { answers: [ { class: IN, domainName: host.example.com., rData: 192.0.2.100, recordType: A, recordTypeId: 1, ttl: 3600 } ], authority: [ { class: IN, domainName: example.com., rData: ns1.example.com., recordType: NS, recordTypeId: 2, ttl: 86400 } ], fullRcode: 0, header: { aa: true, anCount: 1, nsCount: 1, qdCount: 1, qr: 1, ra: true, rd: true, id: 49653, rcode: 0 }, question: [ { class: IN, domainName: host.example.com., questionType: A, questionTypeId: 1 } ], rcodeName: NoError, time: 1614781642516276825, timePrecision: ns }, responseAddress: 127.0.0.1, responsePort: 0, serverId: ns1.example.com, serverVersion: BIND 9.16.8, socketFamily: INET, socketProtocol: UDP, sourceAddress: 127.0.0.1, sourcePort: 52398, time: 1614781642516276825, timePrecision: ns }注意事项BIND 需托管example.com区域且区域内含host.example.com主机记录BIND 与 Vector 的 Unix socket 路径必须一致BIND 对 socket 需有rw权限。实操示例二采集 DNS 动态更新Dynamic Update若 DNS 流量较大可把 UDS 缓冲区调大注意同步调整系统级rmem_max/wmem_max[sources.my_dnstap_source] type dnstap mode unix socket_path /run/bind/dnstap.sock socket_file_mode 508 socket_receive_buffer_size 10485760 socket_send_buffer_size 10485760对允许动态更新的权威 BIND 发送一条更新nsupdate EOF server localhost update add h1.example.com 3600 a 192.0.2.110 send EOF源输出UpdateQuerymessageTypeId: 13与UpdateResponsemessageTypeId: 14两个事件。UpdateQuery的requestData包含opcode: 5、upCount: 1、zoCount: 1的更新 headerzone段zName: example.com.、zType: SOA以及update段domainName: h1.example.com.、rData: 192.0.2.110、ttl: 3600UpdateResponse的responseData中qr: 1表示这是一条响应。注意事项与示例一相同另需example.com区域允许动态更新。源码级实现解析帧处理主流程mod.rsDnstapConfig::buildsrc/sources/dnstap/mod.rs按mode分发TCP 走build_framestream_tcp_source附带MaybeTlsSettingsUnix 走build_framestream_unix_source均来自 src/sources/util 的 framestream 工具。核心帧处理逻辑集中在CommonFrameHandlercontent_type固定为protobuf:dnstap.Dnstapframestream 层据此做 protobuf 拆帧handle_event中先发出BytesReceived协议标记为 protobuf内部事件做字节计数再写入host由host_key控制等元数据若raw_data_only为true整帧 base64 编码后写入rawData字段不做任何解码否则调用DnstapParser::parse来自 lib/vector-vrl/dnstap-parser并把DnsParserOptions { lowercase_hostnames }传入以支持统一小写主机名解析失败时发出DnstapParseError内部事件并丢弃该帧返回None不会生成部分事件最后按日志命名空间legacy / vector写入ingest_timestamp与source_type dnstap等标准源元数据。解析失败的可观测性解析错误事件定义在 src/internal_events/dnstap.rs以error_type PARSER_FAILED、stage PROCESSING记录日志并递增component_errors_total计数器。监控该计数器即可发现上游数据格式问题。配合事件中的error与rawData字段解析失败时保留原始 base64 数据可以事后离线重放排查。集成测试的验证方式mod.rs末尾的integration_tests模块需dnstap-integration-testsfeature演示了端到端验证方式在 Docker 中运行 BIND通过rndc dnstap -reopen让 BIND 重新打开 DNSTAP socket路径如dnstap.sock2再用nslookup/nsupdate触发真实查询与更新最终断言输出事件中同时存在ClientQuery/ClientResponse或UpdateQuery/UpdateResponse/AuthQuery/AuthResponse以及requestData.question[0].domainName、responseData.answers[0].rData等字段值正确。raw_data_only变体则断言所有事件都携带rawData字段。这套流程可以直接作为你自部署时的验收脚本参考。相关能力VRL 侧的 parse_dnstap 函数仓库中 lib/vector-vrl/dnstap-parser/src/vrl_functions/parse_dnstap.rs 基于同一dnstap-parser库提供了 VRL 函数parse_dnstap生成文档见 docs/generated/parse_dnstap.json。若你在 source 层使用raw_data_only true只落地原始 base64 数据也可以后续在remap变换里用该函数按需解码实现“先采集、后解析”的弹性方案。使用注意事项小结该组件交付语义为 best effort、不支持端到端确认can_acknowledge() false且开发状态为 beta升级 Vector 版本时应关注其行为变化mode tcp时address必须带端口跨机器部署建议配合permit_origin限制来源网段高连接数场景用connection_limit与max_connection_duration_secs控制长连接max_frame_length过小会静默丢弃大帧DNS over TCP 的大报文场景下需要评估并调大Unix 模式的socket_file_mode、socket_receive/send_buffer_size与系统 umask、/proc/sys/net/core/{rmem,wmem}_max存在联动关系调大缓冲区前请先确认系统上限事件字段完整 schema 与枚举说明以 website/cue/reference/components/sources/dnstap.cue 和 generated/dnstap.cue 为准下游管道编写 VRL 查询时可据此构造精确的字段路径。【免费下载链接】vectorA high-performance observability data pipeline.项目地址: https://gitcode.com/GitHub_Trending/vect/vector创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考