Technitium DNS Server 的 Query Logs (SQL Server) App:将 DNS 查询日志写入 Microsoft SQL Server 的完整实战指南
网络后端【免费下载链接】DnsServerTechnitium DNS Server项目地址https://gitcode.com/GitHub_Trending/dn/DnsServer点击查看免费下载本指南围绕 Technitium DNS Server 仓库中的QueryLogsSqlServerAppQuery Logs (SQL Server) DNS App展开它是一套将 DNS 服务器收到的所有查询请求与响应异步持久化到 Microsoft SQL Server 数据库的查询日志记录应用。读完本文你将掌握该 App 的架构设计有界队列 批量写入 定时清理、全部配置项与完整dnsApp.config示例、自动建库建表与索引的底层实现、数据库字段的数值编码规则以及基于IDnsQueryLogs接口的多维过滤查询能力可以直接在真实 SQL Server 环境中落地部署并排查问题。应用定位与适用场景QueryLogsSqlServerApp是 Technitium DNS Server 的官方 DNS App 之一仓库中对应的注册信息位于 Apps/apps2.json名称 Query Logs (SQL Server)。它的核心功能是把 DNS 服务器处理的每一次查询请求和对应响应写入 SQL Server 数据库并且这些日志可以直接通过 DNS Server 的 Web 控制台查询浏览——这正是IDnsQueryLogs接口的用途。典型的适用场景包括需要一个集中式、可长期保留的 DNS 查询审计库供安全分析、故障排查或合规留存已有 SQL Server 基础设施希望把 DNS 日志纳入现有数据库运维体系备份、监控、权限管理需要按客户端 IP、协议、响应类型、RCODE、QNAME、QTYPE 等条件灵活检索历史查询记录。值得说明的是该 App 与 Technitium DNS Server 内置的查询日志功能相互独立启用本 App 后所有 DNS 查询会同时写入 SQL Server可在 Web 控制台的日志查询界面中浏览这些记录而不会影响服务器内置日志。功能概览与扩展点根据 Apps/QueryLogsSqlServerApp/README.md该 App 提供三大核心能力异步日志写入Async logging日志条目先写入一个有界的内存队列再由后台线程批量落库写入路径不阻塞 DNS 请求处理自动清理Cleanup support按保留天数maxLogDays或最大记录数maxLogRecords定期清理过期数据持久化存储Retained schema通过databaseName SQL Server 连接字符串组合实现数据库与表结构的自动初始化。在扩展点层面它同时实现了三个接口定义于 DnsServerCore.ApplicationCommon 目录接口定义文件作用IDnsApplicationIDnsApplication.cs应用生命周期入口DNS Server 在加载或更新配置时调用InitializeAsync(IDnsServer, config)IDnsQueryLoggerIDnsQueryLogger.cs请求处理并返回响应后由服务器调用InsertLogAsync(...)记录日志IDnsQueryLogsIDnsQueryLogs.cs供 DNS Server 的 Query Logs HTTP API 调用QueryLogsAsync(...)实现分页、过滤查询在 Apps/QueryLogsSqlServerApp/App.cs 中类声明为public sealed class App : IDnsApplication, IDnsQueryLogger, IDnsQueryLogs正是这三个接口的组合实现因此它既是日志写入方也是日志查询数据源。快速部署先决条件与安装在 Web 控制台安装并启用该 App 之前需要先满足以下前提条件说明同样见于 Apps/apps2.json 的官方描述在 SQL Server 中创建专用数据库用户为该用户启用dbcreator服务器角色Server Role。原因是 App 首次启用时会自动执行CREATE DATABASE、CREATE TABLE以及索引创建语句普通db_owner权限不足以完成建库操作确认网络可达从运行 Technitium DNS Server 的主机能够访问 SQL Server 实例示例连接串使用tcp:192.168.10.101,1433即 1433 默认端口连接串建议带上TrustServerCertificatetrue自签名/测试证书场景并按需配置Encrypt。之后在 DNS Server 的 Apps 页面安装Query Logs (SQL Server)App编辑其配置把enableLogging设为true并保存。App 会自动完成建库、建表和索引初始化随后立即开始记录查询日志——无需手工执行任何 SQL 脚本。配置详解与完整示例配置存放在 Apps/QueryLogsSqlServerApp/dnsApp.config仓库自带如下示例{ enableLogging: false, maxQueueSize: 1000000, maxLogDays: 0, maxLogRecords: 0, databaseName: DnsQueryLogs, connectionString: Data Sourcetcp:192.168.10.101,1433; User IDusername; Passwordpassword; TrustServerCertificatetrue; }各配置项的含义、类型与默认值如下表源自 README.md 的 Configuration 一节Property类型默认值说明enableLoggingbooleanfalse是否启用查询日志记录。设为false时队列被停止不再写入数据库maxQueueSizenumber1000000内存队列中允许的最大日志条目数达到上限后新条目会被丢弃DropWrite 策略maxLogDaysnumber0按保留天数清理0表示禁用基于天数的清理maxLogRecordsnumber0按保留记录数清理0表示禁用基于记录数的清理databaseNamestringDnsQueryLogs存储日志所用的数据库名connectionStringstring(必填)SQL Server 连接字符串不得包含选择数据库的 Initial Catalog库名由databaseName单独提供配置解析逻辑位于 App.cs 的InitializeAsync方法代码通过jsonConfig.GetPropertyValue(...)依次读取各键并对connectionString做了三项强校验为空时直接抛出异常提示必须在connectionString参数中指定有效连接串禁止包含Initial Catalog——若检测到会抛错并要求改用databaseName参数避免库名出现两处定义的不一致若连接串末尾没有分号会自动补上;为后续拼接Initial Catalog{databaseName};做准备。连接串写法建议连接串负责与 SQL Server 实例建连但不选择具体数据库。实际运行时App 会在其内部拼接Initial Catalog{databaseName};得到完整连接串见 App.cs 与 App.cs。例如示例配置最终等效于Data Sourcetcp:192.168.10.101,1433; Initial CatalogDnsQueryLogs; User IDusername; Passwordpassword; TrustServerCertificatetrue;运行时行为有界队列 批量写入 定时清理README 将运行时行为概括为三步结合源码可以完整还原其实现细节。1. 有界 Channel 缓冲查询每条 DNS 查询在服务器处理完成并返回响应后通过InsertLogAsync被包装成LogEntry结构体包含时间戳、请求、客户端端点、协议、响应见 App.cs 与 App.cs随后TryWrite进一个System.Threading.Channels的有界通道。通道通过StartNewChannel创建App.cs关键配置为BoundedChannelOptions options new BoundedChannelOptions(maxQueueSize); options.SingleWriter true; options.SingleReader true; options.FullMode BoundedChannelFullMode.DropWrite;FullMode DropWrite意味着当队列积压到maxQueueSize上限时新日志条目会被直接丢弃而不是阻塞 DNS 处理线程这保证了日志功能不会反向拖垮查询性能代价是高并发瞬时峰值下可能丢日志README 的 Risks 一节明确提示了这一点。2. 后台消费者线程批量落库StartNewChannel同时启动一个名为QueryLogsSqlServer类名的后台线程作为消费者它循环WaitToReadAsync攒够一批后调用BulkInsertLogsAsync批量插入App.cs。批量写入有几个值得注意的工程细节App.cs批次大小固定为 190 条常量BULK_INSERT_COUNT 190的注释说明SQL Server 单条 SQL 最多支持 2100 个参数每条日志占 11 个参数server、timestamp、client_ip、protocol、response_type、response_rtt、rcode、qname、qtype、qclass、answer190 × 11 2090正好压线单条多值 INSERT 语句用StringBuilder拼出INSERT INTO dns_logs (...) VALUES (...),(...)...每条记录对应一组server{i}之类的带下标参数参数类型显式声明timestamp为SqlDbType.DateTime、protocol/response_type/rcode为TinyInt、response_rtt为Real、qtype为Int、qclass为SmallInt、文本列使用VarCharanswer 字段的归一化处理无应答时若截断Truncation写[TRUNCATED]否则写NULL应答超过 2 条且发生区域传送Zone Transfer时写[ZONE TRANSFER]正常情况则拼接为TYPE RDATA, TYPE RDATA, ...的文本且截断到 4000 字符以内与表定义的answer VARCHAR(4000)对齐写库失败不重试但延迟捕获异常后写服务器日志并Task.Delay(BULK_INSERT_ERROR_DELAY)10 秒随后循环继续尝试下一批。3. 定时清理旧记录构造函数中注册了一个TimerApp.cs行为受两个配置控制初始间隔 5 秒CLEAN_UP_TIMER_INITIAL_INTERVAL 5000之后周期 15 分钟CLEAN_UP_TIMER_PERIODIC_INTERVAL 15 * 60 * 1000仅当maxLogRecords 0或maxLogDays 0时才会启动定时器见 App.cs按记录数清理先SELECT Count(*) FROM dns_logs统计总量超出部分用DELETE FROM dns_logs WHERE dlid IN (SELECT TOP n dlid FROM dns_logs ORDER BY dlid)分批删除每批BULK_REMOVE_COUNT 10000条按天数清理用WHERE timestamp timestamptimestamp DateTime.UtcNow.AddDays(-maxLogDays)统计并分批删除同样按dlid升序取最旧记录。数据库 Schema 与字段数值编码自动建库建表ApplyConfig中的建库逻辑App.cs会在enableLogging为 true 时执行先用不指定库的连接串连接 SQL Server 实例IF NOT EXISTS(SELECT * FROM sys.databases WHERE name {databaseName}) CREATE DATABASE {databaseName}自动建库切到该库后IF NOT EXISTS(...) CREATE TABLE dns_logs (...)自动建表随后通过一系列IF NOT EXISTS判断幂等地创建 10 个索引index_server、index_timestamp、index_client_ip、index_protocol、index_response_type、index_rcode、index_qname、index_qtype、index_qclass、index_timestamp_client_ip、index_timestamp_qname、index_client_qname、index_query、index_all其中index_all覆盖 server、timestamp、client_ip、protocol、response_type、rcode、qname、qtype、qclass 全列。dns_logs表结构如下与 App.cs 一致列名类型约束/说明dlidBIGINT IDENTITY(1,1)主键自增servervarchar(255)写入日志的 DNS 服务器域名timestampDATETIME非空请求时间UTCclient_ipVARCHAR(39)非空客户端 IP39 字符足以容纳 IPv6 文本protocolTINYINT非空传输协议编码response_typeTINYINT非空响应类型编码response_rttREAL可空仅递归响应记录往返时延rcodeTINYINT非空DNS 响应码qnameVARCHAR(255)查询域名小写qtypeINT查询类型qclassSMALLINT查询类别answerVARCHAR(4000)应答文本可空Schema 脚本还内置了兼容性处理例如若已存在index_qtype/index_query/index_all索引但qtype列类型不是INT会先DROP INDEX再ALTER COLUMN qtype INT以应对早期版本遗留的表结构。Protocol 字段传输协议README 给出了完整的数值映射表写入时paramProtocol.Value (byte)log.ProtocolApp.cs值协议说明0UDP标准 DNS-over-UDP1TCP标准 DNS-over-TCP2TLSDNS-over-TLSRFC 78583HTTPSDNS-over-HTTPSRFC 84845QUICDNS-over-QUICRFC 9250253UdpProxy基于 UDP 的 PROXY Protocol254TcpProxy基于 TCP 的 PROXY ProtocolResponse Type 字段响应类型响应类型枚举DnsServerResponseType定义于 IDnsQueryLogger.cs与 README 的数值表完全对应值响应类型说明1Authoritative由 DNS 服务器自身生成的权威响应2Recursive递归查询上游后收到的响应3Cached由 DNS 服务器缓存生成的响应4Blocked服务器为拦截请求生成的响应5UpstreamBlocked上游返回的拦截响应6UpstreamBlockedCached缓存中包含上游拦截响应的响应7Dropped服务器返回null响应表示请求被丢弃写入逻辑位于 App.cs若log.Response.Tag为空则视为Recursive否则按Tag强转枚举最终以byte落库。response_rtt 与 RCODEresponse_rtt往返时延仅在响应类型为Recursive且响应元数据中存在RoundTripTime时写入否则写入DBNullApp.cs。rcode为(byte)log.Response.RCODE即标准 DNS 响应码NOERROR0、NXDOMAIN3、SERVFAIL2 等。日志查询接口能力与过滤维度IDnsQueryLogs.QueryLogsAsync定义见 IDnsQueryLogs.cs由 DNS Server 的 Query Logs HTTP API 在 Web 控制台展示日志时调用。实现位于 App.cs其能力包括分页pageNumber0 自动修正为 1-1表示最后一页entriesPerPage配合ORDER BY dlid与OFFSET ... FETCH NEXT ... ROWS ONLY实现排序descendingOrder决定按dlid倒序还是正序同时通过rowNumber计算每行在总数据集中的真实行号多维过滤start/end时间范围、clientIpAddress、protocol、responseType、rcode、qname、qtype、qclass均可选过滤条件动态拼进WHERE子句通配符支持当qname含*时转为 SQLLIKE查询*替换为%否则做精确匹配App.cs固定隔离条件查询始终附带server {_dnsServer.ServerDomain}确保多服务器写入同一数据库时每个服务器只看到自己的日志返回结构封装为DnsLogPage含PageNumber、TotalPages、TotalEntries、Entries条目为DnsLogEntry含行号、时间戳、客户端 IP、协议、响应类型、RTT、RCODE、问题记录、应答文本两者均定义于 IDnsQueryLogs.cs。查询时qname会先ToLowerInvariant()归一化与写入路径中query.Name.ToLowerInvariant()App.cs保持一致避免大小写不一致导致过滤失效。容错与初始化重试InitializeAsync对数据库连接做了专门的容错设计App.cs首次启动_isStartupInit true时初始化被放到线程池异步执行最多重试 20 次、每次间隔 30 秒MAX_RETRIES 20、RETRY_DELAY 30000仅当捕获 SQL 错误号258SqlException.Number 258即登录超时/无法连接时才进入重试循环并在服务器日志中输出“请检查 App 配置与数据库服务器在线状态”的提示其他 SQL 错误或普通异常则记录日志后直接结束初始化**通过 API 更新配置非首次**时则同步执行ApplyConfig()失败会立即暴露给调用方。这意味着在服务器启动早期、SQL Server 尚未就绪的情况下App 会保持重试而不是崩溃退出但若数据库长期不可达日志写入BulkInsertLogsAsync会持续报错并每 10 秒延迟重试表现为日志缺失需要运维介入。风险与运维注意事项README 的 Risks / operational notes 一节明确提出三条结合源码可进一步确认队列溢出会丢日志DropWrite策略下超过maxQueueSize的新日志被静默丢弃。高并发场景应根据查询速率合理调大maxQueueSize并监控内存占用队列上限即内存上限的近似值数据库连接问题会中断日志写库失败不重试同一批数据而是延迟 10 秒后继续连接长期不可用意味着这段时间的查询日志全部缺失高流量部署需关注写延迟批量写入的吞吐取决于 SQL Server 的写入性能建议为dns_logs所在的磁盘/文件组做性能规划并关注BulkInsertLogsAsync的耗时与response_rtt数值的合理性。此外Dispose时App.cs会先关闭日志开关、释放清理定时器、TryComplete()队列并等待消费者线程退出保证进程/App 卸载时队列中已积压的条目尽量被消费完成。故障排查清单README 的 Troubleshooting 一节给出方向结合实现可形成可执行的排查路径确认数据库可达与凭据有效在 DNS 服务器所在主机用sqlcmd或 SSMS 测试示例连接串去掉Initial Catalog后能否建连注意 SQL 错误 258 表示登录超时需检查网络、端口 1433 与防火墙核对连接串与databaseName确认connectionString中没有Initial Catalog否则 App 会直接拒绝加载配置确认数据库用户具备dbcreator服务器角色否则首次建库会失败查看服务器日志中的 SQL 客户端错误BulkInsertLogsAsync、清理定时器与初始化路径都会通过_dnsServer.WriteLog(ex)输出异常错误号 258、207无效列名、262无权限等都能直接定位问题验证数据落库在 SQL Server 中执行SELECT TOP 100 * FROM DnsQueryLogs.dbo.dns_logs ORDER BY dlid DESC;确认协议/响应类型字段数值与上文编码表一致server列等于当前服务器域名若日志缺失但 App 状态正常优先检查是否触发DropWrite队列积压或写库延迟重试网络抖动必要时临时调大maxQueueSize并观察服务器日志。从源码结构可以获得的延伸视角从仓库目录结构看Query Logs 系列 App 遵循同一套接口与设计模式除 SQL Server 版本外仓库还包含 QueryLogsSqliteApp、QueryLogsMySqlApp、QueryLogsPostgreSqlApp 等对应不同数据库的实现它们都实现了IDnsApplication/IDnsQueryLogger/IDnsQueryLogs并采用“有界队列 批量插入 定时清理”的相似架构例如 SQLite 版同样定义BULK_INSERT_COUNT、BULK_INSERT_ERROR_DELAY与清理定时器。这种统一抽象意味着无论后端是何种数据库DNS Server 的日志写入与 Web 控制台查询体验保持一致为在多数据库环境间迁移日志存储提供了便利。相关仓库资源App 源码与实现Apps/QueryLogsSqlServerApp/App.cs配置文件示例Apps/QueryLogsSqlServerApp/dnsApp.configApp 说明文档Apps/QueryLogsSqlServerApp/README.md项目文件依赖Microsoft.Data.SqlClient7.1.0目标框架 net10.0Apps/QueryLogsSqlServerApp/QueryLogsSqlServerApp.csproj应用注册信息含官方安装说明Apps/apps2.json接口定义IDnsApplication.cs、IDnsQueryLogger.cs、IDnsQueryLogs.cs赞分享网络后端【免费下载链接】DnsServerTechnitium DNS Server项目地址https://gitcode.com/GitHub_Trending/dn/DnsServer点击查看免费下载相关推荐如何快速识别DNS查询模式Technitium DNS Server日志分析终极指南如何快速识别DNS查询模式Technitium DNS Server日志分析终极指南 Technitium DNS Server是一款功能强大的DNS服务器软网络后端Technitium DNS Server DNS Block ListDNSBLApp 实战指南基于 RFC 5782 的 IP 与域名黑名单查询Technitium DNS Server DNS Block ListDNSBLApp 实战指南基于 RFC 5782 的 IP 与域名黑名单查询 DN网络后端Technitium DNS Server 的 DNS Rebinding Protection App原理、配置与排障完全指南Technitium DNS Server 的 DNS Rebinding Protection App原理、配置与排障完全指南 导读 本文以 Technit网络后端上一篇Skill Seekers 集成指南模板实战为任意 AI 工具构建标准化的技能集成内容体系下一篇OpenSRE Agent Harness 架构解析agent_harness 包的职责、端口与运行循环创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →