update
This commit is contained in:
@@ -0,0 +1,79 @@
|
||||
# DNS 查询超时问题分析与修复计划
|
||||
|
||||
## 问题现状
|
||||
- 客户端请求 DNS 解析需要两次才能成功
|
||||
- 第一次返回 SERVFAIL,第二次才有正确结果
|
||||
- 错误数量高达 29,594 条
|
||||
|
||||
## 已尝试的修复
|
||||
- 将 `queryTimeout` 从 5ms 修改为 5000ms
|
||||
- 服务器已重启
|
||||
|
||||
## 需要深入调查的问题
|
||||
|
||||
### 1. 超时配置的实际生效情况
|
||||
- 检查配置文件中 queryTimeout 的单位(毫秒还是秒)
|
||||
- 验证代码中如何解析和使用这个配置值
|
||||
- 确认配置是否真正被重新加载
|
||||
|
||||
### 2. 上游 DNS 服务器可达性
|
||||
- 测试上游 DNS 服务器 (10.35.10.200, 106.14.121.141) 是否可达
|
||||
- 检查上游服务器的响应时间
|
||||
- 验证上游服务器是否支持递归查询
|
||||
|
||||
### 3. 网络层面问题
|
||||
- 检查是否有防火墙规则阻止 DNS 查询
|
||||
- 验证 UDP 53 端口是否畅通
|
||||
- 检查是否存在网络延迟或丢包
|
||||
|
||||
### 4. DNS 缓存逻辑问题
|
||||
- 检查缓存是否正常工作
|
||||
- 验证缓存 TTL 设置是否合理
|
||||
- 确认缓存命中时是否还会超时
|
||||
|
||||
### 5. 代码逻辑问题
|
||||
- 检查并行查询模式的实现
|
||||
- 验证超时处理逻辑是否正确
|
||||
- 查看是否有竞态条件导致的问题
|
||||
|
||||
## 调查步骤
|
||||
|
||||
### 第一步:检查当前配置和日志
|
||||
1. 查看当前配置文件中的 queryTimeout 值
|
||||
2. 检查最新日志中的超时设置
|
||||
3. 统计错误日志中的错误类型分布
|
||||
|
||||
### 第二步:测试上游 DNS 服务器
|
||||
1. 直接测试上游 DNS 服务器的响应
|
||||
2. 测量到上游服务器的网络延迟
|
||||
3. 验证上游服务器是否工作正常
|
||||
|
||||
### 第三步:分析代码中的超时处理
|
||||
1. 查看 forwardDNSRequestWithCache 函数中的超时逻辑
|
||||
2. 检查 dns.Client 的 Timeout 设置
|
||||
3. 验证并行查询的超时处理
|
||||
|
||||
### 第四步:检查网络配置
|
||||
1. 检查防火墙规则
|
||||
2. 测试 DNS 端口连通性
|
||||
3. 检查路由表和网络接口
|
||||
|
||||
## 可能的修复方案
|
||||
|
||||
### 方案 A:修复配置单位问题
|
||||
如果配置单位是秒而不是毫秒,需要将 5000 改为 5
|
||||
|
||||
### 方案 B:修复上游服务器配置
|
||||
如果上游服务器不可达,需要更换可用的 DNS 服务器
|
||||
|
||||
### 方案 C:修复代码中的超时逻辑
|
||||
如果代码中存在超时处理 bug,需要修改相关代码
|
||||
|
||||
### 方案 D:优化查询模式
|
||||
如果并行查询模式有问题,可以切换到 fastest-ip 模式
|
||||
|
||||
## 验证标准
|
||||
1. DNS 查询一次成功,不需要重试
|
||||
2. 错误率降低到接近 0
|
||||
3. 平均响应时间合理(<100ms)
|
||||
4. 日志中不再有大量 SERVFAIL 记录
|
||||
@@ -0,0 +1,368 @@
|
||||
# DNS 查询 SERVFAIL 问题分析(已禁用 DNSSEC)
|
||||
|
||||
## 问题描述
|
||||
|
||||
客户端请求 DNS 解析时,需要请求两次才能得到正常结果:
|
||||
|
||||
* 第一次请求:返回 SERVFAIL(服务器失败)
|
||||
|
||||
* 第二次请求:返回正常解析结果
|
||||
|
||||
## 重要信息
|
||||
|
||||
**DNSSEC 已禁用** - 因此问题与 DNSSEC 验证无关
|
||||
|
||||
## 可能的原因分析
|
||||
|
||||
### 1. 缓存初始化时机问题
|
||||
|
||||
**现象**:第一次查询时缓存为空,第二次查询命中缓存
|
||||
|
||||
**可能原因**:
|
||||
|
||||
* 缓存加载逻辑可能存在问题
|
||||
|
||||
* 第一次查询的响应没有正确缓存
|
||||
|
||||
* 缓存键生成或查找逻辑有问题
|
||||
|
||||
**相关代码位置**:
|
||||
|
||||
* `/root/dns-server/dns/cache.go` - `Get` 和 `Set` 方法
|
||||
|
||||
* `/root/dns-server/dns/server.go` - `handleCacheResponse` 方法
|
||||
|
||||
### 2. DNSSEC 验证超时或失败
|
||||
|
||||
**现象**:第一次查询触发 DNSSEC 验证,验证超时导致 SERVFAIL;第二次直接使用缓存结果
|
||||
|
||||
**可能原因**:
|
||||
|
||||
* DNSSEC 验证逻辑可能存在超时
|
||||
|
||||
* 验证失败后没有正确处理响应
|
||||
|
||||
* `verifyDNSSEC` 方法可能阻塞或失败
|
||||
|
||||
**相关代码位置**:
|
||||
|
||||
* `/root/dns-server/dns/server.go` - `verifyDNSSEC` 方法
|
||||
|
||||
* 第 1563 行左右的 DNSSEC 验证逻辑
|
||||
|
||||
### 3. 上游服务器选择逻辑问题
|
||||
|
||||
**现象**:第一次查询时服务器状态统计为空,导致选择了不可用的服务器
|
||||
|
||||
**可能原因**:
|
||||
|
||||
* 服务器健康检查逻辑可能有问题
|
||||
|
||||
* 第一次查询时没有正确选择最快的服务器
|
||||
|
||||
* 并行查询逻辑可能存在竞态条件
|
||||
|
||||
**相关代码位置**:
|
||||
|
||||
* `/root/dns-server/dns/server.go` - `forwardDNSRequestWithCache` 方法
|
||||
|
||||
* 第 1473-1600 行的并行查询逻辑
|
||||
|
||||
### 4. 响应处理逻辑问题
|
||||
|
||||
**现象**:第一次查询返回的响应被错误地判断为失败
|
||||
|
||||
**可能原因**:
|
||||
|
||||
* 响应代码判断逻辑可能有误
|
||||
|
||||
* `hasValidRecords` 判断可能过于严格
|
||||
|
||||
* 某些类型的响应被错误地拒绝
|
||||
|
||||
**相关代码位置**:
|
||||
|
||||
* `/root/dns-server/dns/server.go` - 第 871-891 行的响应验证逻辑
|
||||
|
||||
### 5. 并发锁竞争问题
|
||||
|
||||
**现象**:第一次查询时遇到锁竞争,导致超时返回 SERVFAIL
|
||||
|
||||
**可能原因**:
|
||||
|
||||
* 缓存访问锁可能与其他操作冲突
|
||||
|
||||
* 统计信息更新可能导致阻塞
|
||||
|
||||
* 日志写入可能阻塞查询流程
|
||||
|
||||
**相关代码位置**:
|
||||
|
||||
* `/root/dns-server/dns/cache.go` - 各种锁操作
|
||||
|
||||
* `/root/dns-server/dns/server.go` - 统计更新操作
|
||||
|
||||
## 调试建议
|
||||
|
||||
### 方案 1:增强日志记录
|
||||
|
||||
在关键位置添加详细日志:
|
||||
|
||||
* 缓存命中/未命中时
|
||||
|
||||
* DNSSEC 验证开始/结束/结果
|
||||
|
||||
* 上游服务器选择和响应
|
||||
|
||||
* 响应验证过程
|
||||
|
||||
### 方案 2:检查时间戳
|
||||
|
||||
分析查询日志中的时间戳:
|
||||
|
||||
* 第一次查询的实际处理时间
|
||||
|
||||
* 是否有超时现象
|
||||
|
||||
* DNSSEC 验证耗时
|
||||
|
||||
### 方案 3:复现测试
|
||||
|
||||
使用 `dig` 命令测试:
|
||||
|
||||
```bash
|
||||
# 清除缓存后测试
|
||||
dig @127.0.0.1 example.com +norecurse
|
||||
dig @127.0.0.1 example.com
|
||||
```
|
||||
|
||||
## 根本原因已确定
|
||||
|
||||
经过详细代码分析,发现问题出在 **并行请求模式下的响应处理逻辑缺陷**:
|
||||
|
||||
### 问题流程:
|
||||
|
||||
1. **第一次查询**:
|
||||
|
||||
* 缓存未命中,向上游服务器发起并行查询
|
||||
|
||||
* 代码进入并行请求模式(第 1490-1777 行)
|
||||
|
||||
* 收到上游返回的响应,`resp.response.Rcode == dns.RcodeSuccess`
|
||||
|
||||
* **关键问题**:在 `noDNSSEC` 模式下(第 1572-1588 行),代码直接返回第一个成功响应
|
||||
|
||||
* **但是**:没有检查响应是否包含有效记录(Answer/Ns/Extra)
|
||||
|
||||
* 如果上游返回的是 `Rcode=Success` 但 `Answer 为空` 的响应(例如某些 DNS 服务器的截断响应)
|
||||
|
||||
* 该响应被直接发送给客户端
|
||||
|
||||
* 在 `handleUpstreamRequest` 第 870-891 行,由于 `hasValidRecords` 检查失败(Answer 为空),`response.Rcode` 没有被设置为 `RcodeSuccess`
|
||||
|
||||
* 最终客户端收到 SERVFAIL 错误
|
||||
|
||||
2. **第二次查询**:
|
||||
|
||||
* 第一次查询的响应已经被缓存(即使 Answer 为空,只要 Rcode=Success 就会被缓存)
|
||||
|
||||
* 直接从缓存返回
|
||||
|
||||
* 但此时缓存的可能是完整响应(因为上游第二次返回了完整结果)
|
||||
|
||||
* 客户端收到正常解析结果
|
||||
|
||||
### 具体代码问题:
|
||||
|
||||
**问题 1:并行模式下缺少 hasValidRecords 检查**
|
||||
|
||||
在 `/root/dns-server/dns/server.go` 第 1572-1588 行(并行模式,noDNSSEC 分支):
|
||||
|
||||
```go
|
||||
if noDNSSEC && !bestResponseSent {
|
||||
// 不验证 DNSSEC 的域名:直接返回第一个成功响应
|
||||
if fastestResponse == nil || resp.rtt < fastestRtt {
|
||||
fastestResponse = resp.response
|
||||
fastestRtt = resp.rtt
|
||||
fastestServer = resp.server
|
||||
fastestDnssecServer = dnssecServerForResponse
|
||||
fastestHasDnssec = false
|
||||
|
||||
// 立即发送结果,快速返回(只发送一次)
|
||||
resultChan <- struct {
|
||||
response: fastestResponse, // 可能 Answer 为空!
|
||||
...
|
||||
}
|
||||
bestResponseSent = true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**对比**:在串行模式(第 1452-1469 行)中有 `hasValidRecords` 检查:
|
||||
|
||||
```go
|
||||
// 检查响应是否包含有效的记录,如果包含,将 Rcode 设置为成功
|
||||
hasValidRecords := false
|
||||
if len(response.Answer) > 0 {
|
||||
hasValidRecords = true
|
||||
} else if len(response.Ns) > 0 {
|
||||
hasValidRecords = true
|
||||
} else if len(response.Extra) > 0 {
|
||||
for _, rr := range response.Extra {
|
||||
if rr.Header().Rrtype != dns.TypeOPT {
|
||||
hasValidRecords = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hasValidRecords {
|
||||
response.Rcode = dns.RcodeSuccess
|
||||
}
|
||||
```
|
||||
|
||||
**问题 2:Rcode 判断逻辑不准确**
|
||||
|
||||
第 1562 行只检查 `resp.response.Rcode == dns.RcodeSuccess`,但有些 DNS 服务器可能返回:
|
||||
|
||||
* `Rcode=Success` 但 `Answer 为空`(例如需要 TCP 回退时)
|
||||
|
||||
* 这种情况下应该继续等待其他服务器的响应,而不是立即返回
|
||||
|
||||
## 建议的修复步骤
|
||||
|
||||
### 方案 1:在并行模式下添加 hasValidRecords 检查(推荐)
|
||||
|
||||
**问题**:并行模式(noDNSSEC 分支)缺少 hasValidRecords 检查
|
||||
|
||||
**解决方案**:
|
||||
在并行模式的快速返回逻辑中添加 hasValidRecords 检查,确保只返回包含有效记录的响应
|
||||
|
||||
```go
|
||||
// 修改前
|
||||
if noDNSSEC && !bestResponseSent {
|
||||
// 不验证 DNSSEC 的域名:直接返回第一个成功响应
|
||||
if fastestResponse == nil || resp.rtt < fastestRtt {
|
||||
fastestResponse = resp.response
|
||||
fastestRtt = resp.rtt
|
||||
fastestServer = resp.server
|
||||
fastestDnssecServer = dnssecServerForResponse
|
||||
fastestHasDnssec = false
|
||||
|
||||
// 立即发送结果,快速返回(只发送一次)
|
||||
resultChan <- struct {
|
||||
response: fastestResponse,
|
||||
...
|
||||
}
|
||||
bestResponseSent = true
|
||||
}
|
||||
}
|
||||
|
||||
// 修改后
|
||||
if noDNSSEC && !bestResponseSent {
|
||||
// 不验证 DNSSEC 的域名:返回第一个包含有效记录的成功响应
|
||||
if fastestResponse == nil || resp.rtt < fastestRtt {
|
||||
// 检查响应是否包含有效记录
|
||||
hasValidRecords := false
|
||||
if len(resp.response.Answer) > 0 {
|
||||
hasValidRecords = true
|
||||
} else if len(resp.response.Ns) > 0 {
|
||||
hasValidRecords = true
|
||||
} else if len(resp.response.Extra) > 0 {
|
||||
for _, rr := range resp.response.Extra {
|
||||
if rr.Header().Rrtype != dns.TypeOPT {
|
||||
hasValidRecords = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 只有包含有效记录才返回
|
||||
if hasValidRecords {
|
||||
fastestResponse = resp.response
|
||||
fastestRtt = resp.rtt
|
||||
fastestServer = resp.server
|
||||
fastestDnssecServer = dnssecServerForResponse
|
||||
fastestHasDnssec = false
|
||||
|
||||
// 立即发送结果,快速返回(只发送一次)
|
||||
resultChan <- struct {
|
||||
response: fastestResponse,
|
||||
...
|
||||
}
|
||||
bestResponseSent = true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 方案 2:改进 Rcode 判断逻辑
|
||||
|
||||
**问题**:只检查 Rcode,不检查 Answer 内容
|
||||
|
||||
**解决方案**:
|
||||
将 Rcode 检查和 Answer 检查结合起来,确保响应真正有效
|
||||
|
||||
```go
|
||||
// 修改前
|
||||
if resp.response.Rcode == dns.RcodeSuccess || resp.response.Rcode == dns.RcodeNameError {
|
||||
// 处理响应
|
||||
}
|
||||
|
||||
// 修改后
|
||||
// 检查 Rcode 和 Answer 内容
|
||||
isValidResponse := false
|
||||
if resp.response.Rcode == dns.RcodeSuccess {
|
||||
// 成功响应需要包含有效记录
|
||||
if len(resp.response.Answer) > 0 || len(resp.response.Ns) > 0 {
|
||||
isValidResponse = true
|
||||
}
|
||||
} else if resp.response.Rcode == dns.RcodeNameError {
|
||||
// NXDOMAIN 响应可以没有 Answer
|
||||
isValidResponse = true
|
||||
}
|
||||
|
||||
if isValidResponse {
|
||||
// 处理有效响应
|
||||
}
|
||||
```
|
||||
|
||||
### 方案 3:增加重试机制
|
||||
|
||||
**问题**:第一次返回空 Answer 后没有重试
|
||||
|
||||
**解决方案**:
|
||||
检测到空 Answer 时,继续等待其他服务器的响应或重试
|
||||
|
||||
```go
|
||||
// 在并行模式中添加重试逻辑
|
||||
if len(resp.response.Answer) == 0 && resp.response.Rcode == dns.RcodeSuccess {
|
||||
// Answer 为空,可能是截断响应,继续等待其他服务器
|
||||
logger.Debug("响应 Answer 为空,继续等待其他服务器", "domain", domain)
|
||||
continue // 不立即返回,继续等待
|
||||
}
|
||||
```
|
||||
|
||||
### 方案 4:调整上游 DNS 服务器配置
|
||||
|
||||
**问题**:某些上游 DNS 服务器可能返回截断响应
|
||||
|
||||
**解决方案**:
|
||||
|
||||
1. 检查上游 DNS 服务器配置
|
||||
2. 尝试更换更可靠的上游 DNS 服务器
|
||||
3. 增加 UDP 缓冲区大小,避免截断
|
||||
|
||||
## 推荐修复顺序
|
||||
|
||||
1. **立即修复**:方案 1(在并行模式下添加 hasValidRecords 检查)- 直接解决问题
|
||||
2. **优化改进**:方案 2(改进 Rcode 判断逻辑)- 提高健壮性
|
||||
3. **可选优化**:方案 3(增加重试机制)- 进一步提高可靠性
|
||||
|
||||
## 需要查看的关键代码
|
||||
|
||||
1. `verifyDNSSEC` 方法实现
|
||||
2. `forwardDNSRequestWithCache` 中的 DNSSEC 验证逻辑
|
||||
3. `handleUpstreamRequest` 中的响应处理
|
||||
4. DNSSEC 相关配置和超时设置
|
||||
|
||||
@@ -0,0 +1,332 @@
|
||||
# 域名信息管理项重新设计计划
|
||||
|
||||
## 1. 现状分析
|
||||
|
||||
### 1.1 现有实现
|
||||
|
||||
- **后端实现**:`shield/domain_info_manager.go` 实现了域名信息管理器
|
||||
- **前端实现**:`static/js/modules/domain-info.js` 实现了前端管理界面
|
||||
- **API接口**:`http/domain_info_handlers.go` 提供了相关API
|
||||
- **配置管理**:`config/config.go` 定义了配置结构
|
||||
|
||||
### 1.2 现有功能
|
||||
|
||||
1. **三个列表管理**:
|
||||
- 域名信息列表 (domain-info)
|
||||
- 威胁域名列表 (threat-database)
|
||||
- 跟踪器列表 (tracker)
|
||||
|
||||
2. **现有API**:
|
||||
- `/api/domain-info` - 获取域名信息列表和统计
|
||||
- `/api/domain-info/update` - 更新所有域名信息
|
||||
- `/api/domain-info/update/{type}` - 更新指定类型的域名信息
|
||||
- `/api/domain-info/query` - 查询单个域名信息
|
||||
|
||||
3. **现有前端功能**:
|
||||
- 显示三个列表的详细信息
|
||||
- 显示各列表的规则数量
|
||||
- 显示最后更新时间
|
||||
- 支持更新所有列表和单个列表
|
||||
|
||||
### 1.3 问题与不足
|
||||
|
||||
1. **数据更新机制**:
|
||||
- 威胁数据库的URL配置错误(使用了src路径而非raw路径)
|
||||
- 缺少更新状态的实时反馈
|
||||
|
||||
2. **前端界面**:
|
||||
- 界面设计较为简单
|
||||
- 缺少视觉层次感和交互体验
|
||||
|
||||
3. **数据管理**:
|
||||
- 缺少数据验证和错误处理
|
||||
- 缓存机制可以进一步优化
|
||||
|
||||
4. **用户功能**:
|
||||
- 缺少用户增加和删除列表的功能
|
||||
|
||||
### 1.4 列表文件分析
|
||||
|
||||
通过下载和分析列表文件,了解到:
|
||||
|
||||
1. **domain-info.json**:
|
||||
- 格式:JSON
|
||||
- 结构:
|
||||
- categories: 分类信息(键值对)
|
||||
- domains: 域名信息(嵌套结构,第一层公司名称,第二层具体域名服务)
|
||||
- timeUpdated: 更新时间
|
||||
- 规模:4444行
|
||||
- 用途:提供域名分类信息
|
||||
|
||||
2. **threats-database.csv**:
|
||||
- 格式:CSV
|
||||
- 结构:包含 type, name, riskLevel, domain 字段
|
||||
- 规模:73012行(约3.1MB)
|
||||
- 用途:提供威胁域名数据库
|
||||
|
||||
3. **trackers.json**:
|
||||
- 格式:JSON
|
||||
- 结构:
|
||||
- categories: 分类信息
|
||||
- timeUpdated: 更新时间
|
||||
- trackerDomains: 跟踪器域名
|
||||
- trackers: 跟踪器信息(嵌套结构)
|
||||
- 规模:25345行
|
||||
- 用途:提供跟踪器域名信息
|
||||
|
||||
### 1.5 嵌套结构处理注意事项
|
||||
|
||||
- **domain-info.json**:domains字段包含多层嵌套结构,需要递归处理
|
||||
- **trackers.json**:trackers字段包含嵌套结构,需要正确解析
|
||||
- **数据量级**:威胁数据库较大(7万多行),需要考虑性能优化
|
||||
|
||||
## 2. 重新设计方案
|
||||
|
||||
### 2.1 后端改进
|
||||
|
||||
1. **修复URL配置**:
|
||||
- 修正威胁数据库的URL,使用raw路径
|
||||
|
||||
2. **增强更新机制**:
|
||||
- 添加更新状态的实时反馈
|
||||
- 改进错误处理和日志记录
|
||||
|
||||
3. **优化缓存策略**:
|
||||
- 实现更智能的缓存过期机制
|
||||
- 增加缓存验证
|
||||
|
||||
4. **添加API端点**:
|
||||
- `/api/domain-info/status` - 获取更新状态
|
||||
- `/api/domain-info/refresh` - 强制刷新缓存
|
||||
- `/api/domain-info/add` - 添加新的域名信息列表
|
||||
- `/api/domain-info/remove` - 删除域名信息列表
|
||||
|
||||
5. **实现用户增删功能**:
|
||||
- 支持用户添加自定义域名信息列表
|
||||
- 支持用户删除现有列表
|
||||
- 实现列表配置的持久化存储
|
||||
|
||||
6. **嵌套结构处理**:
|
||||
- 优化JSON嵌套结构的解析和处理
|
||||
- 实现高效的嵌套数据存储和查询
|
||||
|
||||
### 2.2 前端改进
|
||||
|
||||
1. **界面重新设计**:
|
||||
- 采用卡片式布局,增强视觉层次感
|
||||
- 添加统计信息概览区域
|
||||
- 优化表格布局和交互体验
|
||||
|
||||
2. **功能增强**:
|
||||
- 添加更新进度指示
|
||||
- 实现批量操作功能
|
||||
- 增加数据导出功能
|
||||
- 添加列表增加和删除功能
|
||||
- 实现列表编辑功能
|
||||
|
||||
3. **响应式设计**:
|
||||
- 优化移动端显示
|
||||
- 确保在不同设备上的良好体验
|
||||
|
||||
4. **数据展示优化**:
|
||||
- 实现嵌套结构的可视化展示
|
||||
- 支持展开/折叠嵌套数据
|
||||
|
||||
### 2.3 数据管理优化
|
||||
|
||||
1. **数据验证**:
|
||||
- 增加URL格式验证
|
||||
- 实现数据完整性检查
|
||||
- 验证列表类型和格式
|
||||
|
||||
2. **错误处理**:
|
||||
- 提供更详细的错误信息
|
||||
- 实现优雅的错误展示
|
||||
|
||||
3. **性能优化**:
|
||||
- 减少不必要的网络请求
|
||||
- 优化数据加载和渲染
|
||||
- 实现大型列表的分页加载
|
||||
- 优化嵌套结构的处理性能
|
||||
|
||||
## 3. 具体实现步骤
|
||||
|
||||
### 3.1 后端修改
|
||||
|
||||
1. **修复配置**:
|
||||
- 修正 `config/config.go` 中的威胁数据库URL
|
||||
|
||||
2. **增强域名信息管理器**:
|
||||
- 在 `shield/domain_info_manager.go` 中添加更新状态管理
|
||||
- 实现更详细的错误处理
|
||||
- 完善列表增删功能
|
||||
- 优化嵌套JSON结构的解析
|
||||
|
||||
3. **扩展API接口**:
|
||||
- 在 `http/domain_info_handlers.go` 中添加新的API端点
|
||||
- 实现状态查询、缓存刷新、列表增删功能
|
||||
|
||||
4. **实现配置持久化**:
|
||||
- 确保用户添加的列表配置能够持久保存
|
||||
- 实现配置文件的自动更新
|
||||
|
||||
### 3.2 前端修改
|
||||
|
||||
1. **重新设计界面**:
|
||||
- 更新 `static/js/modules/domain-info.js` 中的渲染逻辑
|
||||
- 实现卡片式布局和统计概览
|
||||
|
||||
2. **增强交互功能**:
|
||||
- 添加更新进度指示
|
||||
- 实现批量操作和数据导出
|
||||
- 添加列表增加和删除功能
|
||||
- 实现列表编辑表单
|
||||
|
||||
3. **优化用户体验**:
|
||||
- 添加加载动画和过渡效果
|
||||
- 实现更友好的错误提示
|
||||
- 提供操作确认机制
|
||||
|
||||
4. **实现嵌套数据展示**:
|
||||
- 支持展开/折叠嵌套结构
|
||||
- 优化大型嵌套数据的渲染性能
|
||||
|
||||
### 3.3 测试与验证
|
||||
|
||||
1. **功能测试**:
|
||||
- 测试所有API端点
|
||||
- 验证数据更新功能
|
||||
- 测试列表增删功能
|
||||
- 测试错误处理
|
||||
|
||||
2. **性能测试**:
|
||||
- 测试数据加载速度
|
||||
- 验证缓存机制
|
||||
- 测试响应式布局
|
||||
|
||||
3. **安全性测试**:
|
||||
- 验证输入验证
|
||||
- 测试错误处理安全性
|
||||
|
||||
## 4. 预期效果
|
||||
|
||||
### 4.1 功能改进
|
||||
|
||||
- ✅ 正确显示三个列表的数量
|
||||
- ✅ 支持更新所有/单个列表
|
||||
- ✅ 显示更新时间
|
||||
- ✅ 提供更新状态反馈
|
||||
- ✅ 实现批量操作功能
|
||||
- ✅ 支持用户增加和删除列表
|
||||
- ✅ 实现列表编辑功能
|
||||
- ✅ 正确处理JSON嵌套结构
|
||||
|
||||
### 4.2 界面改进
|
||||
|
||||
- ✅ 现代化的卡片式布局
|
||||
- ✅ 清晰的统计信息概览
|
||||
- ✅ 良好的响应式设计
|
||||
- ✅ 流畅的交互体验
|
||||
- ✅ 直观的列表管理界面
|
||||
- ✅ 嵌套数据的可视化展示
|
||||
|
||||
### 4.3 性能改进
|
||||
|
||||
- ✅ 优化的数据加载速度
|
||||
- ✅ 智能的缓存机制
|
||||
- ✅ 减少网络请求
|
||||
- ✅ 提高系统稳定性
|
||||
- ✅ 支持大型列表的高效处理
|
||||
- ✅ 优化嵌套结构的处理性能
|
||||
|
||||
## 5. 风险与应对措施
|
||||
|
||||
### 5.1 风险
|
||||
|
||||
1. **数据加载失败**:
|
||||
- 远程数据源不可用
|
||||
- 网络连接问题
|
||||
|
||||
2. **性能问题**:
|
||||
- 大量数据导致加载缓慢
|
||||
- 缓存策略不当
|
||||
- 嵌套结构处理性能问题
|
||||
|
||||
3. **兼容性问题**:
|
||||
- 浏览器兼容性
|
||||
- 移动设备适配
|
||||
|
||||
4. **用户操作风险**:
|
||||
- 误删除重要列表
|
||||
- 添加无效的列表配置
|
||||
|
||||
5. **数据结构风险**:
|
||||
- JSON嵌套结构解析错误
|
||||
- 数据格式不一致
|
||||
|
||||
### 5.2 应对措施
|
||||
|
||||
1. **数据加载失败**:
|
||||
- 实现错误重试机制
|
||||
- 使用缓存数据作为备用
|
||||
- 提供详细的错误信息
|
||||
|
||||
2. **性能问题**:
|
||||
- 实现数据分页加载
|
||||
- 优化缓存策略
|
||||
- 使用异步加载
|
||||
- 实现嵌套结构的懒加载
|
||||
|
||||
3. **兼容性问题**:
|
||||
- 使用现代前端技术
|
||||
- 测试主流浏览器
|
||||
- 实现响应式设计
|
||||
|
||||
4. **用户操作风险**:
|
||||
- 实现操作确认机制
|
||||
- 提供默认列表恢复功能
|
||||
- 验证用户输入的有效性
|
||||
|
||||
5. **数据结构风险**:
|
||||
- 实现健壮的JSON解析
|
||||
- 添加数据结构验证
|
||||
- 提供详细的错误提示
|
||||
|
||||
## 6. 实施步骤
|
||||
|
||||
1. **准备阶段**:
|
||||
- 代码分析和问题识别
|
||||
- 设计新的界面和功能
|
||||
|
||||
2. **后端开发**:
|
||||
- 修复URL配置
|
||||
- 扩展API接口
|
||||
- 实现列表增删功能
|
||||
- 优化嵌套结构处理
|
||||
|
||||
3. **前端开发**:
|
||||
- 重新设计界面
|
||||
- 实现交互功能
|
||||
- 添加列表管理功能
|
||||
- 实现嵌套数据展示
|
||||
|
||||
4. **测试阶段**:
|
||||
- 功能测试
|
||||
- 性能测试
|
||||
- 兼容性测试
|
||||
|
||||
5. **部署阶段**:
|
||||
- 代码审查
|
||||
- 部署更新
|
||||
- 监控运行状态
|
||||
|
||||
## 7. 结论
|
||||
|
||||
通过重新设计域名信息管理项,我们将实现:
|
||||
|
||||
1. **功能完善**:确保三个列表的数量显示、更新功能、时间显示,以及用户增删列表的能力,同时正确处理JSON嵌套结构
|
||||
2. **界面优化**:提供现代化、美观的用户界面,支持嵌套数据的可视化展示
|
||||
3. **性能提升**:优化数据加载和缓存机制,提高嵌套结构处理性能
|
||||
4. **用户体验**:提供流畅、直观的操作体验
|
||||
|
||||
这些改进将使域名信息管理系统更加实用、可靠和用户友好,满足用户对域名信息管理的各种需求。
|
||||
@@ -0,0 +1,186 @@
|
||||
# 域名信息远程列表功能实施计划
|
||||
|
||||
## 概述
|
||||
在 DNS 服务器的屏蔽管理系统中增加三类域名信息的远程异步加载功能,用于增强日志详情 API 和威胁告警 API 的域名信息查询能力。
|
||||
|
||||
## 需要添加的远程域名信息
|
||||
|
||||
### 1. 域名信息列表
|
||||
- **URL**: `https://gitea.amazehome.xyz/AMAZEHOME/domain-info/raw/branch/main/domains/domain-info.json`
|
||||
- **用途**: 用于查询日志详情 API 中的域名信息
|
||||
- **格式**: JSON
|
||||
|
||||
### 2. 威胁告警域名列表
|
||||
- **URL**: `https://gitea.amazehome.xyz/AMAZEHOME/domain-info/src/branch/main/threats/threats-database.csv`
|
||||
- **用途**: 用于威胁告警 API 的威胁域名信息
|
||||
- **格式**: CSV
|
||||
|
||||
### 3. 跟踪器域名列表
|
||||
- **URLs**:
|
||||
- `https://gitea.amazehome.xyz/AMAZEHOME/domain-info/raw/branch/main/tracker/trackers.json`
|
||||
- **用途**: 用于查询日志详情 API 中的跟踪器信息
|
||||
- **格式**: JSON
|
||||
|
||||
## 实施步骤
|
||||
|
||||
### 步骤 1: 扩展配置文件结构
|
||||
1.1 在 `config/config.go` 中添加新的配置结构:
|
||||
- `DomainInfoConfig` - 域名信息配置
|
||||
- 包含三个远程列表的配置条目(类似 `BlacklistEntry`)
|
||||
- 添加更新间隔、启用状态等配置项
|
||||
|
||||
1.2 在 `Config` 结构体中添加 `DomainInfo DomainInfoConfig` 字段
|
||||
|
||||
1.3 实现配置解析函数:
|
||||
- `parseDomainInfoLists()` - 解析域名信息列表配置
|
||||
- 支持 INI 格式配置
|
||||
|
||||
### 步骤 2: 创建域名信息管理器
|
||||
2.1 创建新文件 `shield/domain_info_manager.go`
|
||||
|
||||
2.2 实现 `DomainInfoManager` 结构体:
|
||||
- 存储域名信息数据(JSON 格式)
|
||||
- 存储威胁域名数据(CSV 格式)
|
||||
- 存储跟踪器数据(JSON 格式)
|
||||
- 缓存管理和过期检查机制
|
||||
- 异步加载和更新逻辑
|
||||
|
||||
2.3 实现核心方法:
|
||||
- `LoadDomainInfo()` - 加载所有域名信息
|
||||
- `fetchRemoteDomainInfo()` - 获取远程域名信息
|
||||
- `fetchThreatDatabase()` - 获取威胁数据库
|
||||
- `fetchTrackerInfo()` - 获取跟踪器信息
|
||||
- `shouldUpdateCache()` - 检查缓存是否需要更新
|
||||
- `GetDomainInfo(domain)` - 查询域名信息
|
||||
- `GetThreatInfo(domain)` - 查询威胁信息
|
||||
- `GetTrackerInfo(domain)` - 查询跟踪器信息
|
||||
- `GetAllDomainInfo()` - 获取所有域名信息(用于 API)
|
||||
|
||||
2.4 实现缓存机制:
|
||||
- 使用内存缓存存储加载的数据
|
||||
- 定期后台刷新(根据配置的更新间隔)
|
||||
- 支持手动刷新
|
||||
|
||||
### 步骤 3: 实现后端 API
|
||||
3.1 在 `http/server.go` 中添加新的 API 路由:
|
||||
- `/api/shield/domain-info` - 获取域名信息列表(GET)
|
||||
- `/api/shield/domain-info/update` - 手动更新所有域名信息(POST)
|
||||
- `/api/shield/domain-info/{type}/update` - 更新指定类型的域名信息(POST)
|
||||
- `/api/domain/info` - 查询单个域名的详细信息(GET)
|
||||
|
||||
3.2 实现 API 处理函数:
|
||||
- `handleDomainInfo()` - 处理域名信息列表的获取
|
||||
- `handleUpdateDomainInfo()` - 处理手动更新请求
|
||||
- `handleDomainInfoQuery()` - 处理域名信息查询
|
||||
|
||||
3.3 在服务器初始化时:
|
||||
- 创建 `DomainInfoManager` 实例
|
||||
- 启动后台定期更新任务
|
||||
|
||||
### 步骤 4: 实现前端界面
|
||||
4.1 创建 `static/js/modules/domain-info.js` 模块:
|
||||
- `loadDomainInfoLists()` - 加载域名信息列表
|
||||
- `updateDomainInfo(type)` - 更新域名信息
|
||||
- `renderDomainInfoLists()` - 渲染域名信息列表表格
|
||||
- `showDomainInfoDetails()` - 显示域名信息详情
|
||||
|
||||
4.2 在 `static/js/shield.js` 中添加:
|
||||
- `loadRemoteDomainInfoLists()` - 异步加载远程域名信息列表
|
||||
- `updateDomainInfoListsTable()` - 更新域名信息列表 UI
|
||||
- 添加状态指示器和通知逻辑
|
||||
|
||||
4.3 创建前端管理界面 `static/domain-info.html`(或集成到现有 shield.html):
|
||||
- 域名信息列表管理表格
|
||||
- 显示各列表的状态、规则数量、最后更新时间
|
||||
- 手动更新按钮
|
||||
- 启用/禁用切换
|
||||
|
||||
### 步骤 5: 集成到日志详情 API
|
||||
5.1 修改日志详情查询接口:
|
||||
- 在返回的日志详情中添加域名信息字段
|
||||
- 添加跟踪器信息字段
|
||||
- 如果域名在威胁数据库中,添加威胁告警信息
|
||||
|
||||
5.2 优化查询性能:
|
||||
- 使用缓存避免重复查询
|
||||
- 批量查询优化
|
||||
|
||||
### 步骤 6: 集成到威胁告警 API
|
||||
6.1 修改威胁告警查询接口:
|
||||
- 使用远程威胁数据库进行匹配
|
||||
- 返回威胁类型、风险等级等详细信息
|
||||
|
||||
### 步骤 7: 测试和文档
|
||||
7.1 功能测试:
|
||||
- 测试远程列表加载
|
||||
- 测试缓存机制
|
||||
- 测试 API 接口
|
||||
- 测试前端界面
|
||||
|
||||
7.2 更新文档:
|
||||
- 更新 README.md
|
||||
- 添加配置示例
|
||||
- 更新 API 文档
|
||||
|
||||
## 技术要点
|
||||
|
||||
### 异步加载机制
|
||||
- 使用 goroutine 进行后台异步加载
|
||||
- 使用 channel 或 context 控制加载流程
|
||||
- 支持并发加载多个远程列表
|
||||
|
||||
### 缓存策略
|
||||
- 内存缓存 + 文件缓存双重机制
|
||||
- 基于时间的过期策略
|
||||
- 支持手动刷新和自动刷新
|
||||
|
||||
### 错误处理
|
||||
- 网络错误的重试机制
|
||||
- 加载失败时的降级处理(使用缓存)
|
||||
- 详细的错误日志记录
|
||||
|
||||
### 性能优化
|
||||
- 批量处理减少锁竞争
|
||||
- 使用 RWMutex 优化读写性能
|
||||
- 延迟加载和按需加载
|
||||
|
||||
## 文件清单
|
||||
|
||||
### 新增文件
|
||||
- `shield/domain_info_manager.go` - 域名信息管理器
|
||||
- `static/js/modules/domain-info.js` - 前端域名信息管理模块
|
||||
- `static/domain-info.html` - 域名信息管理界面(可选,如集成到现有页面则不需要)
|
||||
|
||||
### 修改文件
|
||||
- `config/config.go` - 添加域名信息配置
|
||||
- `http/server.go` - 添加 API 路由和处理函数
|
||||
- `shield/manager.go` - 集成域名信息管理(可选)
|
||||
- `static/js/shield.js` - 添加前端加载逻辑
|
||||
- `README.md` - 更新文档
|
||||
|
||||
## 配置示例
|
||||
|
||||
```ini
|
||||
[domainInfo]
|
||||
; 域名信息列表配置
|
||||
; 格式:name = url,enabled
|
||||
domainInfoList = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/raw/branch/main/domains/domain-info.json,true
|
||||
threatDatabase = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/src/branch/main/threats/threats-database.csv,true
|
||||
trackerList = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/raw/branch/main/tracker/trackers.json,true
|
||||
|
||||
; 更新间隔(秒)
|
||||
updateInterval = 3600
|
||||
|
||||
; 是否启用自动更新
|
||||
enableAutoUpdate = true
|
||||
```
|
||||
|
||||
## 时间估算
|
||||
- 步骤 1: 配置文件扩展 - 30 分钟
|
||||
- 步骤 2: 域名信息管理器 - 2 小时
|
||||
- 步骤 3: 后端 API 实现 - 1 小时
|
||||
- 步骤 4: 前端界面实现 - 1.5 小时
|
||||
- 步骤 5-6: API 集成 - 1 小时
|
||||
- 步骤 7: 测试和文档 - 1 小时
|
||||
|
||||
**总计**: 约 7-8 小时
|
||||
@@ -0,0 +1,87 @@
|
||||
# DNS服务器间歇性SERVFAIL错误修复计划
|
||||
|
||||
## 问题分析
|
||||
|
||||
通过分析代码和测试脚本,发现DNS服务器存在间歇性SERVFAIL错误,表现为:
|
||||
- 第一次查询失败(返回SERVFAIL)
|
||||
- 第二次查询成功
|
||||
|
||||
## 可能的原因
|
||||
|
||||
1. **上游服务器连接问题**:上游DNS服务器偶尔响应失败,导致第一次查询时所有服务器都失败
|
||||
2. **缓存机制问题**:缓存未正确处理失败响应,导致第二次查询时能够从缓存中获取到正确的响应
|
||||
3. **并行查询逻辑问题**:在parallel模式下,响应处理可能存在竞态条件
|
||||
4. **超时处理问题**:超时设置不合理或处理不当
|
||||
|
||||
## 代码分析
|
||||
|
||||
### 关键问题点
|
||||
|
||||
1. **forwardDNSRequestWithCache函数**(server.go:1191):
|
||||
- 当所有上游服务器都失败时,可能返回nil响应,导致SERVFAIL
|
||||
- 并行查询时的响应处理逻辑可能存在问题
|
||||
|
||||
2. **handleUpstreamRequest函数**(server.go:825):
|
||||
- 当response为nil时,直接返回SERVFAIL
|
||||
|
||||
3. **客户端池管理**:
|
||||
- 使用sync.Pool管理DNS客户端实例,但可能存在并发问题
|
||||
|
||||
## 修复方案
|
||||
|
||||
### 1. 改进上游请求处理逻辑
|
||||
|
||||
- **增加重试机制**:当第一次查询失败时,自动重试一次
|
||||
- **优化超时设置**:确保超时时间合理,避免过早超时
|
||||
- **改进错误处理**:当所有上游服务器都失败时,尝试使用备选服务器
|
||||
|
||||
### 2. 优化缓存机制
|
||||
|
||||
- **缓存失败响应**:暂时缓存失败响应,避免短时间内重复查询失败的域名
|
||||
- **改进缓存键设计**:确保缓存键能够正确标识不同的查询条件
|
||||
|
||||
### 3. 改进并行查询逻辑
|
||||
|
||||
- **优化响应处理**:确保并行查询时能够正确处理所有响应
|
||||
- **增加响应验证**:验证响应的有效性,避免返回无效响应
|
||||
|
||||
### 4. 增加监控和日志
|
||||
|
||||
- **增加详细日志**:记录每次查询的详细信息,包括上游服务器响应情况
|
||||
- **增加统计信息**:统计上游服务器的响应成功率,便于问题定位
|
||||
|
||||
## 实施步骤
|
||||
|
||||
1. **修改forwardDNSRequestWithCache函数**:
|
||||
- 增加重试机制
|
||||
- 优化错误处理逻辑
|
||||
- 改进并行查询的响应处理
|
||||
|
||||
2. **修改handleUpstreamRequest函数**:
|
||||
- 增加对nil响应的处理
|
||||
- 优化响应验证
|
||||
|
||||
3. **修改缓存机制**:
|
||||
- 增加失败响应的缓存
|
||||
- 改进缓存键设计
|
||||
|
||||
4. **增加监控和日志**:
|
||||
- 增加详细的查询日志
|
||||
- 增加上游服务器响应统计
|
||||
|
||||
5. **测试验证**:
|
||||
- 使用test_servfail.sh脚本测试修复效果
|
||||
- 进行压力测试,确保修复后系统稳定
|
||||
|
||||
## 预期效果
|
||||
|
||||
- 消除间歇性SERVFAIL错误
|
||||
- 提高DNS服务器的稳定性和可靠性
|
||||
- 减少对上游服务器的重复查询
|
||||
- 提供更详细的日志和监控信息
|
||||
|
||||
## 风险评估
|
||||
|
||||
- **性能影响**:增加重试机制可能会增加响应时间,但可以通过合理的超时设置来平衡
|
||||
- **内存使用**:增加失败响应的缓存可能会增加内存使用,但可以通过设置合理的缓存大小和过期时间来控制
|
||||
- **兼容性**:修改缓存机制可能会影响现有缓存的使用,但可以通过平滑过渡来避免问题
|
||||
@@ -0,0 +1 @@
|
||||
代码逻辑严谨有序。
|
||||
@@ -15,17 +15,20 @@
|
||||
## 功能特性
|
||||
|
||||
### 1. DNS查询处理
|
||||
|
||||
- 支持UDP和TCP协议
|
||||
- 支持常见DNS查询类型(A, AAAA, CNAME, MX, NS, TXT等)
|
||||
- 高性能查询处理
|
||||
|
||||
### 2. 屏蔽规则管理
|
||||
|
||||
- 支持域名规则和正则表达式规则
|
||||
- 支持规则例外
|
||||
- 支持远程规则列表
|
||||
- 支持自定义规则管理
|
||||
|
||||
### 3. 查询日志记录和统计
|
||||
|
||||
- 实时记录DNS查询日志
|
||||
- 支持日志持久化到文件
|
||||
- 提供查询统计和趋势分析
|
||||
@@ -33,6 +36,7 @@
|
||||
- 支持日志排序
|
||||
|
||||
### 4. Web 控制台
|
||||
|
||||
- 直观的仪表盘
|
||||
- 实时统计数据
|
||||
- 图表可视化
|
||||
@@ -40,12 +44,23 @@
|
||||
- 查询日志详情页面
|
||||
- 支持分页和自定义记录数量
|
||||
|
||||
### 5. 域名信息管理
|
||||
|
||||
- 支持远程域名信息列表
|
||||
- 支持威胁域名数据库
|
||||
- 支持跟踪器域名列表
|
||||
- 异步加载和自动更新
|
||||
- 内存 + 文件双重缓存
|
||||
- 集成到日志详情查询
|
||||
|
||||
### 5. WebSocket实时更新
|
||||
|
||||
- 实时更新统计数据
|
||||
- 实时更新图表
|
||||
- 支持连接状态管理
|
||||
|
||||
### 6. 查询日志持久化
|
||||
|
||||
- 将查询日志保存到`querylog.json`文件
|
||||
- 定期自动保存
|
||||
- 服务器重启后自动加载
|
||||
@@ -160,6 +175,18 @@ content = ./data/gfwlist.txt
|
||||
# 是否启用 GFWList 功能
|
||||
enabled = true
|
||||
|
||||
[domainInfo]
|
||||
# 域名信息列表更新间隔(秒)
|
||||
updateInterval = 3600
|
||||
# 是否启用自动更新
|
||||
enableAutoUpdate = true
|
||||
# 域名信息列表配置
|
||||
# 格式:domainInfo_名称 = URL,类型,enabled
|
||||
# 类型:domain-info(域名信息)、threat-database(威胁数据库)、tracker(跟踪器)
|
||||
domainInfo_域名信息列表 = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/raw/branch/main/domains/domain-info.json,domain-info,true
|
||||
domainInfo_威胁数据库 = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/src/branch/main/threats/threats-database.csv,threat-database,true
|
||||
domainInfo_跟踪器列表 = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/raw/branch/main/tracker/trackers.json,tracker,true
|
||||
|
||||
[log]
|
||||
# 日志级别:debug, info, warn, error
|
||||
level = debug
|
||||
@@ -182,8 +209,9 @@ maxAge = 30
|
||||
### 访问Web控制台
|
||||
|
||||
在浏览器中访问:
|
||||
|
||||
```
|
||||
http://localhost:8080
|
||||
http://localhost:8081
|
||||
```
|
||||
|
||||
### 管理屏蔽规则
|
||||
@@ -207,11 +235,13 @@ http://localhost:8080
|
||||
### 主要API端点
|
||||
|
||||
#### 1. DNS查询
|
||||
|
||||
```
|
||||
GET /api/query?domain=example.com
|
||||
```
|
||||
|
||||
#### 2. 屏蔽规则管理
|
||||
|
||||
```
|
||||
GET /api/shield/rules
|
||||
POST /api/shield/rules
|
||||
@@ -219,6 +249,7 @@ DELETE /api/shield/rules/:id
|
||||
```
|
||||
|
||||
#### 3. Hosts管理
|
||||
|
||||
```
|
||||
GET /api/hosts
|
||||
POST /api/hosts
|
||||
@@ -226,6 +257,7 @@ DELETE /api/hosts/:id
|
||||
```
|
||||
|
||||
#### 4. 查询日志
|
||||
|
||||
```
|
||||
GET /api/logs/stats
|
||||
GET /api/logs/query
|
||||
@@ -233,10 +265,20 @@ GET /api/logs/count
|
||||
```
|
||||
|
||||
#### 5. WebSocket
|
||||
|
||||
```
|
||||
ws://localhost:8080/ws/stats
|
||||
```
|
||||
|
||||
#### 6. 域名信息管理
|
||||
|
||||
```
|
||||
GET /api/domain-info # 获取域名信息列表
|
||||
POST /api/domain-info/update # 更新所有域名信息
|
||||
POST /api/domain-info/update/{type} # 更新指定类型的域名信息
|
||||
GET /api/domain-info/query?domain=xxx # 查询单个域名的详细信息
|
||||
```
|
||||
|
||||
## 开发说明
|
||||
|
||||
### 项目结构
|
||||
@@ -283,12 +325,13 @@ MIT License
|
||||
|
||||
如有问题或建议,请通过以下方式联系:
|
||||
|
||||
- Email: wxf26054@live.cn
|
||||
- Git: https://gitea.amazehome.xyz/AMAZEHOME/dns-server
|
||||
- Email: <wxf26054@live.cn>
|
||||
- Git: <https://gitea.amazehome.xyz/AMAZEHOME/dns-server>
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v1.0.0 (2025-11-30)
|
||||
|
||||
- 初始版本
|
||||
- 实现基本DNS服务器功能
|
||||
- 实现屏蔽规则管理
|
||||
@@ -298,6 +341,7 @@ MIT License
|
||||
- 实现查询日志持久化
|
||||
|
||||
### v1.0.1 (2025-11-30)
|
||||
|
||||
- 修复搜索和过滤功能
|
||||
- 优化查询日志显示
|
||||
- 修复样式间隔问题
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
CGO_ENABLED=1 \
|
||||
GOOS=windows \
|
||||
GOARCH=amd64 \
|
||||
CC=gcc \
|
||||
go build -o dns-server.exe main.go
|
||||
@@ -2,7 +2,5 @@ export CGO_ENABLED=1
|
||||
export GOOS=linux
|
||||
export GOARCH=amd64
|
||||
export CC=gcc
|
||||
#service dns-server stop &&
|
||||
go build -o dns-server main.go
|
||||
#&& service dns-server start
|
||||
|
||||
#service dns-server stop && go build -o dns-server main.go && service dns-server start
|
||||
go build
|
||||
|
||||
+14
-31
@@ -1,25 +1,25 @@
|
||||
[dns]
|
||||
port = 53
|
||||
upstreamDNS = 10.35.10.200, 106.14.121.141
|
||||
upstreamDNS = 10.35.10.200
|
||||
dnssecUpstreamDNS = 208.67.220.220, 208.67.222.222
|
||||
saveInterval = 10
|
||||
cacheTTL = 60
|
||||
cacheTTL = 10
|
||||
enableDNSSEC = false
|
||||
queryMode = parallel
|
||||
queryTimeout = 5
|
||||
queryTimeout = 5000
|
||||
enableFastReturn = true
|
||||
noDNSSECDomains = amazehome.cn, addr.arpa, amazehome.xyz, .cn
|
||||
enableIPv6 = false
|
||||
cacheMode = file
|
||||
cacheSize = 100
|
||||
maxCacheTTL = 60
|
||||
minCacheTTL = 30
|
||||
domain_akamai = 10.35.10.200:53
|
||||
maxCacheTTL = 30
|
||||
minCacheTTL = 5
|
||||
domain_amazehome.cn = 10.35.10.200:53
|
||||
domain_amazehome.xyz = 10.35.10.200:53
|
||||
domain_microsoft.com = 10.35.10.200:53
|
||||
domain_addr.arpa = 10.35.10.200:53
|
||||
domain_akadns = 10.35.10.200:53
|
||||
domain_akamai = 10.35.10.200:53
|
||||
|
||||
[http]
|
||||
port = 8081
|
||||
@@ -60,31 +60,6 @@ maxSize = 100
|
||||
maxBackups = 10
|
||||
maxAge = 30
|
||||
|
||||
[queryLog]
|
||||
# 基本配置
|
||||
enabled = true
|
||||
ringBufferSize = 10000
|
||||
|
||||
# SQLite 主库配置
|
||||
databasePath = data/query_logs.db
|
||||
maxDatabaseSizeMB = 1024
|
||||
enableWAL = true
|
||||
|
||||
# 归档配置
|
||||
archiveEnabled = true
|
||||
archiveDir = data/archive
|
||||
archivePrefix = querylog
|
||||
compressionLevel = 6
|
||||
|
||||
# 清理配置
|
||||
retentionDays = 0
|
||||
retentionMonths = 0
|
||||
|
||||
# 查询配置
|
||||
queryTimeout = 5
|
||||
enableCache = true
|
||||
cacheTTL = 300
|
||||
|
||||
[threat]
|
||||
enabled = true
|
||||
queryRateThreshold = 0
|
||||
@@ -94,3 +69,11 @@ suspiciousPatterns = malware,phishing,trojan,virus,ransomware
|
||||
unusualQueryTypes = TXT, SRV, MX
|
||||
alertRetentionDays = 0
|
||||
threatDatabasePath = ./static/domain-info/threats/threats-database.csv
|
||||
|
||||
[domainInfo]
|
||||
updateInterval = 3600
|
||||
enableAutoUpdate = true
|
||||
domainInfo_威胁数据库 = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/src/branch/main/threats/threats-database.csv,threat-database,true
|
||||
domainInfo_跟踪器列表 = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/raw/branch/main/tracker/trackers.json,tracker,true
|
||||
domainInfo_111 = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/src/commit/b085e15b1ec593deeff1b8ea53bfc82a8669a020/domains/domain-info.json,domain-info,true
|
||||
domainInfo_11 = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/src/commit/b085e15b1ec593deeff1b8ea53bfc82a8669a020/domains/domain-info.json,domain-info,true
|
||||
|
||||
+64
-2
@@ -52,11 +52,28 @@ type BlacklistEntry struct {
|
||||
LastUpdateTime string `json:"lastUpdateTime,omitempty"`
|
||||
}
|
||||
|
||||
// DomainInfoEntry 域名信息条目
|
||||
type DomainInfoEntry struct {
|
||||
Name string `json:"name"`
|
||||
URL string `json:"url"`
|
||||
Enabled bool `json:"enabled"`
|
||||
Type string `json:"type"` // domain-info, threat-database, tracker
|
||||
RuleCount int `json:"ruleCount,omitempty"`
|
||||
LastUpdateTime string `json:"lastUpdateTime,omitempty"`
|
||||
}
|
||||
|
||||
// DomainInfoConfig 域名信息配置
|
||||
type DomainInfoConfig struct {
|
||||
DomainInfoLists []DomainInfoEntry `json:"domainInfoLists"`
|
||||
UpdateInterval int `json:"updateInterval"` // 更新间隔(秒)
|
||||
EnableAutoUpdate bool `json:"enableAutoUpdate"` // 是否启用自动更新
|
||||
}
|
||||
|
||||
// ShieldConfig 屏蔽规则配置
|
||||
type ShieldConfig struct {
|
||||
Blacklists []BlacklistEntry `json:"blacklists"`
|
||||
UpdateInterval int `json:"updateInterval"`
|
||||
BlockMethod string `json:"blockMethod"` // 屏蔽方法: "NXDOMAIN", "refused", "emptyIP", "customIP"
|
||||
BlockMethod string `json:"blockMethod"` // 屏蔽方法:"NXDOMAIN", "refused", "emptyIP", "customIP"
|
||||
CustomBlockIP string `json:"customBlockIP"` // 自定义屏蔽 IP,当 BlockMethod 为"customIP"时使用
|
||||
StatsSaveInterval int `json:"statsSaveInterval"` // 计数数据保存间隔(秒)
|
||||
}
|
||||
@@ -109,6 +126,7 @@ type Config struct {
|
||||
Threat ThreatConfig `json:"threat"` // 威胁检测配置
|
||||
Log LogConfig `json:"log"`
|
||||
QueryLog QueryLogConfig `json:"queryLog"` // 查询日志配置
|
||||
DomainInfo DomainInfoConfig `json:"domainInfo"` // 域名信息配置
|
||||
}
|
||||
|
||||
// ThreatConfig 威胁检测配置
|
||||
@@ -209,6 +227,11 @@ func LoadConfig(path string) (*Config, error) {
|
||||
AlertRetentionDays: cfg.Section("threat").Key("alertRetentionDays").MustInt(0),
|
||||
ThreatDatabasePath: cfg.Section("threat").Key("threatDatabasePath").MustString("./static/domain-info/threats/threats-database.csv"),
|
||||
},
|
||||
DomainInfo: DomainInfoConfig{
|
||||
UpdateInterval: cfg.Section("domainInfo").Key("updateInterval").MustInt(3600),
|
||||
EnableAutoUpdate: cfg.Section("domainInfo").Key("enableAutoUpdate").MustBool(true),
|
||||
DomainInfoLists: parseDomainInfoLists(cfg.Section("domainInfo")),
|
||||
},
|
||||
}
|
||||
|
||||
// 如果黑名单列表为空,添加一些默认的黑名单
|
||||
@@ -221,6 +244,15 @@ func LoadConfig(path string) (*Config, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// 如果域名信息列表为空,添加默认的域名信息列表
|
||||
if len(config.DomainInfo.DomainInfoLists) == 0 {
|
||||
config.DomainInfo.DomainInfoLists = []DomainInfoEntry{
|
||||
{Name: "域名信息列表", URL: "https://gitea.amazehome.xyz/AMAZEHOME/domain-info/raw/branch/main/domains/domain-info.json", Enabled: true, Type: "domain-info"},
|
||||
{Name: "威胁数据库", URL: "https://gitea.amazehome.xyz/AMAZEHOME/domain-info/raw/branch/main/threats/threats-database.csv", Enabled: true, Type: "threat-database"},
|
||||
{Name: "跟踪器列表", URL: "https://gitea.amazehome.xyz/AMAZEHOME/domain-info/raw/branch/main/tracker/trackers.json", Enabled: true, Type: "tracker"},
|
||||
}
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
@@ -270,7 +302,7 @@ func parseBlacklists(section *ini.Section) []BlacklistEntry {
|
||||
name := strings.TrimPrefix(key.Name(), "blacklist_")
|
||||
value := key.String()
|
||||
|
||||
// 解析黑名单URL和启用状态,格式: url,enabled
|
||||
// 解析黑名单 URL 和启用状态,格式:url,enabled
|
||||
parts := strings.Split(value, ",")
|
||||
if len(parts) >= 2 {
|
||||
url := strings.TrimSpace(parts[0])
|
||||
@@ -286,3 +318,33 @@ func parseBlacklists(section *ini.Section) []BlacklistEntry {
|
||||
|
||||
return blacklists
|
||||
}
|
||||
|
||||
// parseDomainInfoLists 解析域名信息列表配置
|
||||
func parseDomainInfoLists(section *ini.Section) []DomainInfoEntry {
|
||||
domainInfoLists := []DomainInfoEntry{}
|
||||
|
||||
// 遍历所有键,查找以"domainInfo_"开头的键
|
||||
for _, key := range section.Keys() {
|
||||
if strings.HasPrefix(key.Name(), "domainInfo_") {
|
||||
// 提取域名信息名称和属性
|
||||
name := strings.TrimPrefix(key.Name(), "domainInfo_")
|
||||
value := key.String()
|
||||
|
||||
// 解析域名信息 URL 和启用状态,格式:url,type,enabled
|
||||
parts := strings.Split(value, ",")
|
||||
if len(parts) >= 3 {
|
||||
url := strings.TrimSpace(parts[0])
|
||||
entryType := strings.TrimSpace(parts[1])
|
||||
enabled := strings.TrimSpace(parts[2]) == "true"
|
||||
domainInfoLists = append(domainInfoLists, DomainInfoEntry{
|
||||
Name: name,
|
||||
URL: url,
|
||||
Type: entryType,
|
||||
Enabled: enabled,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return domainInfoLists
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# GFWList规则文件
|
||||
# 格式:每行一条规则
|
||||
# 例如:www.google.com
|
||||
@@ -1,3 +0,0 @@
|
||||
# Hosts文件
|
||||
# 格式:IP 域名
|
||||
# 例如:127.0.0.1 localhost
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
-1688
File diff suppressed because it is too large
Load Diff
-734
@@ -1,734 +0,0 @@
|
||||
!Title: AWAvenue Ads Rule
|
||||
!--------------------------------------
|
||||
!Total lines: 725
|
||||
!Version: 1.5.5-release
|
||||
|
||||
!Homepage: https://github.com/TG-Twilight/AWAvenue-Ads-Rule
|
||||
!License: https://github.com/TG-Twilight/AWAvenue-Ads-Rule/blob/main/LICENSE
|
||||
|
||||
|
||||
||1010pic.com^
|
||||
||16dd-advertise-1252317822.file.myqcloud.com^
|
||||
||16dd-advertise-1252317822.image.myqcloud.com^
|
||||
||8le8le.com^
|
||||
||a0.app.xiaomi.com^
|
||||
||aaid.umeng.com^
|
||||
||abtest-ch.snssdk.com^
|
||||
||ad-cache.dopool.com^
|
||||
||ad-cdn.qingting.fm^
|
||||
||ad-cmp.hismarttv.com^
|
||||
||ad-download.hismarttv.com^
|
||||
||ad-imp.hismarttv.com^
|
||||
||ad-scope.com^
|
||||
||ad-scope.com.cn^
|
||||
||ad-sdk-config.youdao.com^
|
||||
||ad-sdk.huxiu.com^
|
||||
||ad.12306.cn^
|
||||
||ad.51wnl.com^
|
||||
||ad.bwton.com^
|
||||
||ad.cctv.com^
|
||||
||ad.cyapi.cn^
|
||||
||ad.doubleclick.net^
|
||||
||ad.partner.gifshow.com^
|
||||
||ad.qingting.fm^
|
||||
||ad.qq.com^
|
||||
||ad.richmob.cn^
|
||||
||ad.tencentmusic.com^
|
||||
||ad.toutiao.com^
|
||||
||ad.v3mh.com^
|
||||
||ad.winrar.com.cn^
|
||||
||ad.xelements.cn^
|
||||
||ad.xiaomi.com^
|
||||
||ad.ximalaya.com^
|
||||
||ad.zijieapi.com^
|
||||
||adapi.izuiyou.com^
|
||||
||adapi.yynetwk.com^
|
||||
||adashbc.ut.taobao.com^
|
||||
||adc.hpplay.cn^
|
||||
||adcdn.hpplay.cn^
|
||||
||adcdn.tencentmusic.com^
|
||||
||adclick.g.doubleclick.net^
|
||||
||adclick.tencentmusic.com^
|
||||
||adcolony.com^
|
||||
||adexpo.tencentmusic.com^
|
||||
||adfilter.imtt.qq.com^
|
||||
||adfstat.yandex.ru^
|
||||
||adguanggao.eee114.com^
|
||||
||adjust.cn^
|
||||
||adjust.com^
|
||||
||adkwai.com^
|
||||
||adlink-api.huan.tv^
|
||||
||adm.funshion.com^
|
||||
||ads-api-o.api.leiniao.com^
|
||||
||ads-api.tiktok.com^
|
||||
||ads-api.twitter.com^
|
||||
||ads-img-qc.xhscdn.com^
|
||||
||ads-jp.tiktok.com^
|
||||
||ads-marketing-vivofs.vivo.com.cn^
|
||||
||ads-sg.tiktok.com^
|
||||
||ads-us.tiktok.com^
|
||||
||ads-video-al.xhscdn.com^
|
||||
||ads-video-qc.xhscdn.com^
|
||||
||ads.95516.com^
|
||||
||ads.google.cn^
|
||||
||ads.heytapmobi.com^
|
||||
||ads.huan.tv^
|
||||
||ads.huantest.com^
|
||||
||ads.icloseli.cn^
|
||||
||ads.linkedin.com^
|
||||
||ads.music.126.net^
|
||||
||ads.oppomobile.com^
|
||||
||ads.pinterest.com^
|
||||
||ads.servebom.com^
|
||||
||ads.service.kugou.com^
|
||||
||ads.tiktok.com^
|
||||
||ads.v3mh.com^
|
||||
||ads.youtube.com^
|
||||
||ads3-normal-hl.zijieapi.com^
|
||||
||ads3-normal-lf.zijieapi.com^
|
||||
||ads3-normal-lq.zijieapi.com^
|
||||
||ads3-normal.zijieapi.com^
|
||||
||ads5-normal-hl.zijieapi.com^
|
||||
||ads5-normal-lf.zijieapi.com^
|
||||
||ads5-normal-lq.zijieapi.com^
|
||||
||ads5-normal.zijieapi.com^
|
||||
||adse.test.ximalaya.com^
|
||||
||adse.wsa.ximalaya.com^
|
||||
||adse.ximalaya.com^
|
||||
||adsebs.ximalaya.com^
|
||||
||adsense.google.cn^
|
||||
||adserver.unityads.unity3d.com^
|
||||
||adservice.google.cn^
|
||||
||adservice.google.com^
|
||||
||adserviceretry.kugou.com^
|
||||
||adsfile.bssdlbig.kugou.com^
|
||||
||adsfile.qq.com^
|
||||
||adsfilebssdlbig.ali.kugou.com^
|
||||
||adsfileretry.service.kugou.com^
|
||||
||adsfs-sdkconfig.heytapimage.com^
|
||||
||adsfs.oppomobile.com^
|
||||
||adslvfile.qq.com^
|
||||
||adsmart.konka.com^
|
||||
||adsmind.gdtimg.com^
|
||||
||adsmind.ugdtimg.com^
|
||||
||adsp.xunlei.com^
|
||||
||adstats.tencentmusic.com^
|
||||
||adstore-1252524079.file.myqcloud.com^
|
||||
||adstore-index-1252524079.file.myqcloud.com^
|
||||
||adtago.s3.amazonaws.com^
|
||||
||adtech.yahooinc.com^
|
||||
||adtrack.quark.cn^
|
||||
||adukwai.com^
|
||||
||adv.fjtv.net^
|
||||
||adv.sec.intl.miui.com^
|
||||
||adv.sec.miui.com^
|
||||
||advertiseonbing.azureedge.net^
|
||||
||advertising-api-eu.amazon.com^
|
||||
||advertising-api-fe.amazon.com^
|
||||
||advertising-api.amazon.com^
|
||||
||advertising.apple.com^
|
||||
||advertising.yahoo.com^
|
||||
||advertising.yandex.ru^
|
||||
||advice-ads.s3.amazonaws.com^
|
||||
||adview.cn^
|
||||
||adx-ad.smart-tv.cn^
|
||||
||adx-bj.anythinktech.com^
|
||||
||adx-cn.anythinktech.com^
|
||||
||adx-drcn.op.dbankcloud.cn^
|
||||
||adx-open-service.youku.com^
|
||||
||adx-os.anythinktech.com^
|
||||
||adx.ads.heytapmobi.com^
|
||||
||adx.ads.oppomobile.com^
|
||||
||adxlog-adnet.vivo.com.cn^
|
||||
||adxlog-adnet.vivo.com.cn.dsa.dnsv1.com.cn^
|
||||
||adxserver.ad.cmvideo.cn^
|
||||
||aegis.qq.com^
|
||||
||afs.googlesyndication.com^
|
||||
||aiseet.aa.atianqi.com^
|
||||
||ali-ad.a.yximgs.com^
|
||||
||alog.umeng.com^
|
||||
||als.baidu.com^
|
||||
||amdcopen.m.taobao.com^
|
||||
||amdcopen.m.umeng.com^
|
||||
||an.facebook.com^
|
||||
||analysis.yozocloud.cn^
|
||||
||analytics-api.samsunghealthcn.com^
|
||||
||analytics.126.net^
|
||||
||analytics.95516.com^
|
||||
||analytics.google.com^
|
||||
||analytics.pinterest.com^
|
||||
||analytics.pointdrive.linkedin.com^
|
||||
||analytics.query.yahoo.com^
|
||||
||analytics.rayjump.com^
|
||||
||analytics.s3.amazonaws.com^
|
||||
||analytics.tiktok.com^
|
||||
||analytics.woozooo.com^
|
||||
||analyticsengine.s3.amazonaws.com^
|
||||
||analyze.lemurbrowser.com^
|
||||
||andrqd.play.aiseet.atianqi.com^
|
||||
||ap.dongqiudi.com^
|
||||
||apd-pcdnwxlogin.teg.tencent-cloud.net^
|
||||
||apd-pcdnwxnat.teg.tencent-cloud.net^
|
||||
||apd-pcdnwxstat.teg.tencent-cloud.net^
|
||||
||api-access.pangolin-sdk-toutiao.com^
|
||||
||api-access.pangolin-sdk-toutiao1.com^
|
||||
||api-access.pangolin-sdk-toutiao2.com^
|
||||
||api-access.pangolin-sdk-toutiao3.com^
|
||||
||api-access.pangolin-sdk-toutiao4.com^
|
||||
||api-access.pangolin-sdk-toutiao5.com^
|
||||
||api-ad-product.huxiu.com^
|
||||
||api-adservices.apple.com^
|
||||
||api-gd.hiaiabc.com^
|
||||
||api-htp.beizi.biz^
|
||||
||api.ad.xiaomi.com^
|
||||
||api.e.kuaishou.com^
|
||||
||api.htp.hubcloud.com.cn^
|
||||
||api.hzsanjiaomao.com^
|
||||
||api.installer.xiaomi.com^
|
||||
||api.jietuhb.com^
|
||||
||api.kingdata.ksyun.com^
|
||||
||api.statsig.com^
|
||||
||api5-normal-quic-lf.ixigua.com^
|
||||
||apiyd.my91app.com^
|
||||
||apks.webxiaobai.top^
|
||||
||app-measurement.com^
|
||||
||appcloud2.in.zhihu.com^
|
||||
||applog.lc.quark.cn^
|
||||
||applog.uc.cn^
|
||||
||applog.zijieapi.com^
|
||||
||ata-sdk-uuid-report.dreport.meituan.net^
|
||||
||auction.unityads.unity3d.com^
|
||||
||audid-api.taobao.com^
|
||||
||audid.umeng.com^
|
||||
||azr.footprintdns.com^
|
||||
||b1-data.ads.heytapmobi.com^
|
||||
||baichuan-sdk.alicdn.com^
|
||||
||baichuan-sdk.taobao.com^
|
||||
||bdad.123pan.cn^
|
||||
||bdapi-ads.realmemobile.com^
|
||||
||bdapi-in-ads.realmemobile.com^
|
||||
||bdapi.ads.oppomobile.com^
|
||||
||beacon-api.aliyuncs.com^
|
||||
||beacon.qq.com^
|
||||
||beaconcdn.qq.com^
|
||||
||beacons.gvt2.com^
|
||||
||beizi.biz^
|
||||
||bes-mtj.baidu.com^
|
||||
||bgg.baidu.com^
|
||||
||bianxian.com^
|
||||
||bingads.microsoft.com^
|
||||
||bj.ad.track.66mobi.com^
|
||||
||books-analytics-events.apple.com^
|
||||
||browsercfg-drcn.cloud.dbankcloud.cn^
|
||||
||bsrv.qq.com^
|
||||
||bugly.qq.com^
|
||||
||business-api.tiktok.com^
|
||||
||c.bidtoolads.com^
|
||||
||c.evidon.com^
|
||||
||c.gj.qq.com^
|
||||
||c.kuaiduizuoye.com^
|
||||
||c.sayhi.360.cn^
|
||||
||c2.gdt.qq.com^
|
||||
||canvas-cdn.gdt.qq.com^
|
||||
||catalog.fjwhcbsh.com^
|
||||
||cbjs.baidu.com^
|
||||
||ccs.umeng.com^
|
||||
||cctv.adsunion.com^
|
||||
||cdn-ad.wtzw.com^
|
||||
||cdn-ads.oss-cn-shanghai.aliyuncs.com^
|
||||
||cdn-plugin-sync-upgrade-juui.hismarttv.com^
|
||||
||cdn.ad.xiaomi.com^
|
||||
||cdn.ynuf.aliapp.org^
|
||||
||cfg.imtt.qq.com^
|
||||
||chat1.jd.com^
|
||||
||chiq-cloud.com^
|
||||
||cj.qidian.com^
|
||||
||ck.ads.oppomobile.com^
|
||||
||click.googleanalytics.com^
|
||||
||click.oneplus.cn^
|
||||
||clog.miguvideo.com^
|
||||
||cnlogs.umeng.com^
|
||||
||cnlogs.umengcloud.com^
|
||||
||cnzz.com^
|
||||
||collect.kugou.com^
|
||||
||commdata.v.qq.com^
|
||||
||config.chsmarttv.com^
|
||||
||config.unityads.unity3d.com^
|
||||
||cpro.baidustatic.com^
|
||||
||crashlytics.com^
|
||||
||crashlyticsreports-pa.googleapis.com^
|
||||
||csjplatform.com^
|
||||
||cws-cctv.conviva.com^
|
||||
||data.ads.oppomobile.com^
|
||||
||data.chsmarttv.com^
|
||||
||data.mistat.india.xiaomi.com^
|
||||
||data.mistat.rus.xiaomi.com^
|
||||
||data.mistat.xiaomi.com^
|
||||
||diagnosis.ad.xiaomi.com^
|
||||
||dig.bdurl.net^
|
||||
||dl.zuimeitianqi.com^
|
||||
||dlogs.bwton.com^
|
||||
||dm.toutiao.com^
|
||||
||domain.aishengji.com^
|
||||
||doubleclick-cn.net^
|
||||
||download.changhong.upgrade2.huan.tv^
|
||||
||downloadxml.changhong.upgrade2.huan.tv^
|
||||
||drcn-weather.cloud.huawei.com^
|
||||
||dsp-x.jd.com^
|
||||
||dsp.fcbox.com^
|
||||
||dualstack-logs.amap.com^
|
||||
||dutils.com^
|
||||
||dxp.baidu.com^
|
||||
||e.ad.xiaomi.com^
|
||||
||eclick.baidu.com^
|
||||
||edge.ads.twitch.tv^
|
||||
||ef-dongfeng.tanx.com^
|
||||
||entry.baidu.com^
|
||||
||errlog.umeng.com^
|
||||
||errnewlog.umeng.com^
|
||||
||event.tradplusad.com^
|
||||
||events-drcn.op.dbankcloud.cn^
|
||||
||events.reddit.com^
|
||||
||events.redditmedia.com^
|
||||
||firebaselogging-pa.googleapis.com^
|
||||
||flurry.com^
|
||||
||g-adnet.hiaiabc.com^
|
||||
||g-staic.ganjingworld.com^
|
||||
||g2.ganjing.world^
|
||||
||game.loveota.com^
|
||||
||gdfp.gifshow.com^
|
||||
||gemini.yahoo.com^
|
||||
||geo.yahoo.com^
|
||||
||getui.cn^
|
||||
||getui.com^
|
||||
||getui.net^
|
||||
||ggx.cmvideo.cn^
|
||||
||ggx01.miguvideo.com^
|
||||
||ggx03.miguvideo.com^
|
||||
||globalapi.ad.xiaomi.com^
|
||||
||google-analytics.com^
|
||||
||googleads.g.doubleclick.net^
|
||||
||googleadservices-cn.com^
|
||||
||googleadservices.com^
|
||||
||googletagservices-cn.com^
|
||||
||googletagservices.com^
|
||||
||gorgon.youdao.com^
|
||||
||gromore.pangolin-sdk-toutiao.com^
|
||||
||grs.dbankcloud.com^
|
||||
||grs.hicloud.com^
|
||||
||grs.platform.dbankcloud.ru^
|
||||
||h-adashx.ut.taobao.com^
|
||||
||h.trace.qq.com^
|
||||
||hanlanad.com^
|
||||
||hexagon-analytics.com^
|
||||
||hm.baidu.com^
|
||||
||hmma.baidu.com^
|
||||
||houyi.kkmh.com^
|
||||
||hpplay.cn^
|
||||
||httpdns.bcelive.com^
|
||||
||httpdns.ocloud.oppomobile.com^
|
||||
||hugelog.fcbox.com^
|
||||
||huichuan.sm.cn^
|
||||
||hw-ot-ad.a.yximgs.com^
|
||||
||hw.zuimeitianqi.com^
|
||||
||hwpub-s01-drcn.cloud.dbankcloud.cn^
|
||||
||hya.comp.360os.com^
|
||||
||hybrid.miniapp.taobao.com^
|
||||
||hye.comp.360os.com^
|
||||
||hyt.comp.360os.com^
|
||||
||i.snssdk.com^
|
||||
||iad.apple.com^
|
||||
||iadctest.qwapi.com^
|
||||
||iadsdk.apple.com^
|
||||
||iadworkbench.apple.com^
|
||||
||ifacelog.iqiyi.com^
|
||||
||ifs.tanx.com^
|
||||
||igexin.com^
|
||||
||ii.gdt.qq.com^
|
||||
||imag8.pubmatic.com^
|
||||
||imag86.pubmatic.com^
|
||||
||image-ad.sm.cn^
|
||||
||imageplus.baidu.com^
|
||||
||images.outbrainimg.com^
|
||||
||images.pinduoduo.com^
|
||||
||img-c.heytapimage.com^
|
||||
||img.adnyg.com^
|
||||
||img.adnyg.com.w.kunlungr.com^
|
||||
||imtmp.net^
|
||||
||iot-eu-logser.realme.com^
|
||||
||iot-logser.realme.com^
|
||||
||ipv4.kkmh.com^
|
||||
||irc.qubiankeji.com^
|
||||
||itv2-up.openspeech.cn^
|
||||
||ixav-cse.avlyun.com^
|
||||
||iyfbodn.com^
|
||||
||janapi.jd.com^
|
||||
||jiguang.cn^
|
||||
||jpush.cn^
|
||||
||jpush.html5.qq.com^
|
||||
||jpush.io^
|
||||
||jswebcollects.kugou.com^
|
||||
||kepler.jd.com^
|
||||
||kl.67it.com^
|
||||
||knicks.jd.com^
|
||||
||ks.pull.yximgs.com^
|
||||
||launcher.smart-tv.cn^
|
||||
||launcherimg.smart-tv.cn^
|
||||
||lf3-ad-union-sdk.pglstatp-toutiao.com^
|
||||
||lf6-ad-union-sdk.pglstatp-toutiao.com^
|
||||
||litchiads.com^
|
||||
||liveats-vod.video.ptqy.gitv.tv^
|
||||
||livemonitor.huan.tv^
|
||||
||livep.l.aiseet.atianqi.com^
|
||||
||lives.l.aiseet.atianqi.com^
|
||||
||lives.l.ott.video.qq.com^
|
||||
||lm10111.jtrincc.cn^
|
||||
||log-api-mn.huxiu.com^
|
||||
||log-api.huxiu.com^
|
||||
||log-api.pangolin-sdk-toutiao-b.com^
|
||||
||log-api.pangolin-sdk-toutiao.com^
|
||||
||log-report.com^
|
||||
||log-sdk.gifshow.com^
|
||||
||log-upload-os.hoyoverse.com^
|
||||
||log-upload.mihoyo.com^
|
||||
||log.ad.xiaomi.com^
|
||||
||log.aispeech.com^
|
||||
||log.amemv.com^
|
||||
||log.appstore3.huan.tv^
|
||||
||log.avlyun.com^
|
||||
||log.avlyun.sec.intl.miui.com^
|
||||
||log.byteoversea.com^
|
||||
||log.fc.yahoo.com^
|
||||
||log.kuwo.cn^
|
||||
||log.pinterest.com^
|
||||
||log.snssdk.com^
|
||||
||log.stat.kugou.com^
|
||||
||log.tagtic.cn^
|
||||
||log.tbs.qq.com^
|
||||
||log.vcgame.cn^
|
||||
||log.web.kugou.com^
|
||||
||log.zijieapi.com^
|
||||
||log1.cmpassport.com^
|
||||
||logbak.hicloud.com^
|
||||
||logs.amap.com^
|
||||
||logservice.hicloud.com^
|
||||
||logservice1.hicloud.com^
|
||||
||logtj.kugou.com^
|
||||
||logupdate.avlyun.sec.miui.com^
|
||||
||m-adnet.hiaiabc.com^
|
||||
||m.ad.zhangyue.com^
|
||||
||m.atm.youku.com^
|
||||
||m.kubiqq.com^
|
||||
||m1.ad.10010.com^
|
||||
||mapi.m.jd.com^
|
||||
||masdkv6.3g.qq.com^
|
||||
||mazu.m.qq.com^
|
||||
||mbdlog.iqiyi.com^
|
||||
||metrics.apple.com^
|
||||
||metrics.data.hicloud.com^
|
||||
||metrics.icloud.com^
|
||||
||metrics.mzstatic.com^
|
||||
||metrics2.data.hicloud.com^
|
||||
||metrika.yandex.ru^
|
||||
||mi.gdt.qq.com^
|
||||
||miav-cse.avlyun.com^
|
||||
||mime.baidu.com^
|
||||
||mine.baidu.com^
|
||||
||mission-pub.smart-tv.cn^
|
||||
||miui-fxcse.avlyun.com^
|
||||
||mnqlog.ldmnq.com^
|
||||
||mobads-logs.baidu.com^
|
||||
||mobads-pre-config.cdn.bcebos.com^
|
||||
||mobads.baidu.com^
|
||||
||mobile.da.mgtv.com^
|
||||
||mobilelog.upqzfile.com^
|
||||
||mobileservice.cn^
|
||||
||mon.zijieapi.com^
|
||||
||monitor-ads-test.huan.tv^
|
||||
||monitor-uu.play.aiseet.atianqi.com^
|
||||
||monitor.music.qq.com^
|
||||
||monitor.uu.qq.com^
|
||||
||monsetting.toutiao.com^
|
||||
||mssdk.volces.com^
|
||||
||mssdk.zijieapi.com^
|
||||
||mtj.baidu.com^
|
||||
||newvoice.chiq5.smart-tv.cn^
|
||||
||nmetrics.samsung.com^
|
||||
||notes-analytics-events.apple.com^
|
||||
||nsclick.baidu.com^
|
||||
||o2o.api.xiaomi.com^
|
||||
||oauth-login-drcn.platform.dbankcloud.com^
|
||||
||offerwall.yandex.net^
|
||||
||omgmta.play.aiseet.atianqi.com^
|
||||
||open.e.kuaishou.cn^
|
||||
||open.e.kuaishou.com^
|
||||
||open.kuaishouzt.com^
|
||||
||open.kwaishouzt.com^
|
||||
||open.kwaizt.com^
|
||||
||optimus-ads.amap.com^
|
||||
||orbit.jd.com^
|
||||
||oth.eve.mdt.qq.com^
|
||||
||oth.str.mdt.qq.com^
|
||||
||otheve.play.aiseet.atianqi.com^
|
||||
||outlookads.live.com^
|
||||
||p.l.qq.com^
|
||||
||p.s.360.cn^
|
||||
||p1-be-pack-sign.pglstatp-toutiao.com^
|
||||
||p1-lm.adkwai.com^
|
||||
||p2-be-pack-sign.pglstatp-toutiao.com^
|
||||
||p2-lm.adkwai.com^
|
||||
||p2p.huya.com^
|
||||
||p3-be-pack-sign.pglstatp-toutiao.com^
|
||||
||p3-lm.adkwai.com^
|
||||
||p3-tt.byteimg.com^
|
||||
||p4-be-pack-sign.pglstatp-toutiao.com^
|
||||
||p5-be-pack-sign.pglstatp-toutiao.com^
|
||||
||p6-be-pack-sign.pglstatp-toutiao.com^
|
||||
||pagead2.googleadservices.com^
|
||||
||pagead2.googlesyndication.com^
|
||||
||pangolin-sdk-toutiao-b.com^
|
||||
||pay.sboot.cn^
|
||||
||pgdt.ugdtimg.com^
|
||||
||pglstatp-toutiao.com^
|
||||
||pig.pupuapi.com^
|
||||
||pixon.ads-pixiv.net^
|
||||
||pkoplink.com^
|
||||
||plbslog.umeng.com^
|
||||
||pms.mb.qq.com^
|
||||
||policy.video.ptqy.gitv.tv^
|
||||
||pos.baidu.com^
|
||||
||proxy.advp.apple.com^
|
||||
||public.gdtimg.com^
|
||||
||q.i.gdt.qq.com^
|
||||
||qqdata.ab.qq.com^
|
||||
||qwapi.apple.com^
|
||||
||qzs.gdtimg.com^
|
||||
||recommend-drcn.hms.dbankcloud.cn^
|
||||
||report.tv.kohesport.qq.com^
|
||||
||res.hubcloud.com.cn^
|
||||
||res1.hubcloud.com.cn^
|
||||
||res2.hubcloud.com.cn^
|
||||
||res3.hubcloud.com.cn^
|
||||
||resolve.umeng.com^
|
||||
||review.gdtimg.com^
|
||||
||rms-drcn.platform.dbankcloud.cn^
|
||||
||roi.soulapp.cn^
|
||||
||rpt.gdt.qq.com^
|
||||
||rtb.voiceads.cn^
|
||||
||s.amazon-adsystem.com^
|
||||
||s1.qq.com^
|
||||
||s2.qq.com^
|
||||
||s3.qq.com^
|
||||
||saad.ms.zhangyue.net^
|
||||
||samsung-com.112.2o7.net^
|
||||
||samsungads.com^
|
||||
||sanme2.taisantech.com^
|
||||
||saveu5-normal-lq.zijieapi.com^
|
||||
||scdown.qq.com^
|
||||
||scs.openspeech.cn^
|
||||
||sdk-ab-config.qquanquan.com^
|
||||
||sdk-cache.video.ptqy.gitv.tv^
|
||||
||sdk.1rtb.net^
|
||||
||sdk.beizi.biz^
|
||||
||sdk.cferw.com^
|
||||
||sdk.e.qq.com^
|
||||
||sdk.hzsanjiaomao.com^
|
||||
||sdk.markmedia.com.cn^
|
||||
||sdk.mobads.adwangmai.com^
|
||||
||sdkconf.avlyun.com^
|
||||
||sdkconfig.ad.intl.xiaomi.com^
|
||||
||sdkconfig.ad.xiaomi.com^
|
||||
||sdkconfig.play.aiseet.atianqi.com^
|
||||
||sdkconfig.video.qq.com^
|
||||
||sdkoptedge.chinanetcenter.com^
|
||||
||sdktmp.hubcloud.com.cn^
|
||||
||sdownload.stargame.com^
|
||||
||search.ixigua.com^
|
||||
||search3-search.ixigua.com^
|
||||
||search5-search-hl.ixigua.com^
|
||||
||search5-search.ixigua.com^
|
||||
||securemetrics.apple.com^
|
||||
||securepubads.g.doubleclick.net^
|
||||
||sensors-log.dongqiudi.com^
|
||||
||service.changhong.upgrade2.huan.tv^
|
||||
||service.vmos.cn^
|
||||
||sf16-static.i18n-pglstatp.com^
|
||||
||sf3-fe-tos.pglstatp-toutiao.com^
|
||||
||shouji.sogou.com^
|
||||
||sigmob.cn^
|
||||
||sigmob.com^
|
||||
||skdisplay.jd.com^
|
||||
||slb-p2p.vcloud.ks-live.com^
|
||||
||smad.ms.zhangyue.net^
|
||||
||smart-tv.cn^
|
||||
||smartad.10010.com^
|
||||
||smetrics.samsung.com^
|
||||
||sms.ads.oppomobile.com^
|
||||
||sngmta.qq.com^
|
||||
||snowflake.qq.com^
|
||||
||stat.dongqiudi.com^
|
||||
||stat.y.qq.com^
|
||||
||static.ads-twitter.com^
|
||||
||statics.woozooo.com^
|
||||
||stats.qiumibao.com^
|
||||
||stats.wp.com^
|
||||
||statsigapi.net^
|
||||
||stg-data.ads.heytapmobi.com^
|
||||
||success.ctobsnssdk.com^
|
||||
||syh-imp.cdnjtzy.com^
|
||||
||szbdyd.com^
|
||||
||t-dsp.pinduoduo.com^
|
||||
||t.l.qq.com^
|
||||
||t.track.ad.xiaomi.com^
|
||||
||t002.ottcn.com^
|
||||
||t1.a.market.xiaomi.com^
|
||||
||t2.a.market.xiaomi.com^
|
||||
||t3.a.market.xiaomi.com^
|
||||
||tangram.e.qq.com^
|
||||
||tdc.qq.com^
|
||||
||tdsdk.cpatrk.net^
|
||||
||tdsdk.xdrig.com^
|
||||
||tencent-dtv.m.cn.miaozhen.com^
|
||||
||terms-drcn.platform.dbankcloud.cn^
|
||||
||test.ad.xiaomi.com^
|
||||
||test.e.ad.xiaomi.com^
|
||||
||tj.b.qq.com^
|
||||
||tj.video.qq.com^
|
||||
||tmead.y.qq.com^
|
||||
||tmeadcomm.y.qq.com^
|
||||
||tmfmazu-wangka.m.qq.com^
|
||||
||tmfmazu.m.qq.com^
|
||||
||tmfsdk.m.qq.com^
|
||||
||tmfsdktcpv4.m.qq.com^
|
||||
||tnc3-aliec1.toutiaoapi.com^
|
||||
||tnc3-aliec2.bytedance.com^
|
||||
||tnc3-aliec2.toutiaoapi.com^
|
||||
||tnc3-alisc1.bytedance.com^
|
||||
||tnc3-alisc1.zijieapi.com^
|
||||
||tnc3-alisc2.zijieapi.com^
|
||||
||tnc3-bjlgy.bytedance.com^
|
||||
||tnc3-bjlgy.toutiaoapi.com^
|
||||
||tnc3-bjlgy.zijieapi.com^
|
||||
||toblog.ctobsnssdk.com^
|
||||
||trace.qq.com^
|
||||
||tracelog-debug.qquanquan.com^
|
||||
||track.lc.quark.cn^
|
||||
||track.uc.cn^
|
||||
||tracker.ai.xiaomi.com^
|
||||
||tracker.gitee.com^
|
||||
||tracking.miui.com^
|
||||
||tracking.rus.miui.com^
|
||||
||tsvrv.com^
|
||||
||tvuser-ch.cedock.com^
|
||||
||tx-ad.a.yximgs.com^
|
||||
||tx-kmpaudio.pull.yximgs.com^
|
||||
||tz.sec.xiaomi.com^
|
||||
||uapi.ads.heytapmobi.com^
|
||||
||udc.yahoo.com^
|
||||
||udcm.yahoo.com^
|
||||
||uedas.qidian.com^
|
||||
||ulog-sdk.gifshow.com^
|
||||
||ulogjs.gifshow.com^
|
||||
||ulogs.umeng.com^
|
||||
||ulogs.umengcloud.com^
|
||||
||umengacs.m.taobao.com^
|
||||
||umengjmacs.m.taobao.com^
|
||||
||umini.shujupie.com^
|
||||
||umsns.com^
|
||||
||union.baidu.cn^
|
||||
||union.baidu.com^
|
||||
||update.avlyun.sec.miui.com^
|
||||
||update.lejiao.tv^
|
||||
||upgrade-update.hismarttv.com^
|
||||
||us.l.qq.com^
|
||||
||v.adintl.cn^
|
||||
||v.adx.hubcloud.com.cn^
|
||||
||v1-ad.video.yximgs.com^
|
||||
||v2-ad.video.yximgs.com^
|
||||
||v2-api-channel-launcher.hismarttv.com^
|
||||
||v2.gdt.qq.com^
|
||||
||v2mi.gdt.qq.com^
|
||||
||v3-ad.video.yximgs.com^
|
||||
||v3.gdt.qq.com^
|
||||
||video-ad.sm.cn^
|
||||
||video-dsp.pddpic.com^
|
||||
||video.dispatch.tc.qq.com^
|
||||
||virusinfo-cloudscan-cn.heytapmobi.com^
|
||||
||vlive.qqvideo.tc.qq.com^
|
||||
||volc.bj.ad.track.66mobi.com^
|
||||
||vungle.com^
|
||||
||w.l.qq.com^
|
||||
||w1.askwai.com^
|
||||
||w1.bskwai.com^
|
||||
||w1.cskwai.com^
|
||||
||w1.dskwai.com^
|
||||
||w1.eskwai.com^
|
||||
||w1.fskwai.com^
|
||||
||w1.gskwai.com^
|
||||
||w1.hskwai.com^
|
||||
||w1.iskwai.com^
|
||||
||w1.jskwai.com^
|
||||
||w1.kskwai.com^
|
||||
||w1.lskwai.com^
|
||||
||w1.mskwai.com^
|
||||
||w1.nskwai.com^
|
||||
||w1.oskwai.com^
|
||||
||w1.pskwai.com^
|
||||
||w1.qskwai.com^
|
||||
||w1.rskwai.com^
|
||||
||w1.sskwai.com^
|
||||
||w1.tskwai.com^
|
||||
||w1.uskwai.com^
|
||||
||w1.vskwai.com^
|
||||
||w1.wskwai.com^
|
||||
||w1.xskwai.com^
|
||||
||w1.yskwai.com^
|
||||
||w1.zskwai.com^
|
||||
||watson.microsoft.com^
|
||||
||watson.telemetry.microsoft.com^
|
||||
||weather-analytics-events.apple.com^
|
||||
||weather-community-drcn.weather.dbankcloud.cn^
|
||||
||webstat.qiumibao.com^
|
||||
||webview.unityads.unity3d.com^
|
||||
||widgets.outbrain.com^
|
||||
||widgets.pinterest.com^
|
||||
||win.gdt.qq.com^
|
||||
||wn.x.jd.com^
|
||||
||ws-keyboard.shouji.sogou.com^
|
||||
||ws.sj.qq.com^
|
||||
||www42.zskwai.com^
|
||||
||wxa.wxs.qq.com^
|
||||
||wximg.wxs.qq.com^
|
||||
||wxsmw.wxs.qq.com^
|
||||
||wxsnsad.tc.qq.com^
|
||||
||wxsnsdy.wxs.qq.com^
|
||||
||wxsnsdythumb.wxs.qq.com^
|
||||
||xc.gdt.qq.com^
|
||||
||xiaomi-dtv.m.cn.miaozhen.com^
|
||||
||xiaoshuo.wtzw.com^
|
||||
||xlivrdr.com^
|
||||
||xlmzc.cnjp-exp.com^
|
||||
||xlog.jd.com^
|
||||
||xlviiirdr.com^
|
||||
||xlviirdr.com^
|
||||
||yk-ssp.ad.youku.com^
|
||||
||ykad-data.youku.com^
|
||||
||ykad-gateway.youku.com^
|
||||
||youku-acs.m.taobao.com^
|
||||
||youxi.kugou.com^
|
||||
||zeus.ad.xiaomi.com^
|
||||
||zhihu-web-analytics.zhihu.com^
|
||||
/.*\.*\.shouji\.sogou\.com/
|
||||
/.*\.[a-zA-Z0-9.-]skwai\.com/
|
||||
/.*\.a\.market\.xiaomi\.com/
|
||||
/.*\.data\.hicloud\.com/
|
||||
/.*\.log\.aliyuncs\.com/
|
||||
/[a-zA-Z0-9.-]*-ad-[a-zA-Z0-9.-]*\.byteimg\.com/
|
||||
/[a-zA-Z0-9.-]*-ad\.sm\.cn/
|
||||
/[a-zA-Z0-9.-]*-ad\.video\.yximgs\.com/
|
||||
/[a-zA-Z0-9.-]*-ad\.wtzw\.com/
|
||||
/[a-zA-Z0-9.-]*-be-pack-sign\.pglstatp-toutiao\.com/
|
||||
/[a-zA-Z0-9.-]*-lm\.adkwai\.com/
|
||||
/[a-zA-Z0-9.-]*-normal-[a-zA-Z0-9.-]*\.zijieapi\.com/
|
||||
/[a-zA-Z0-9.-]*-normal\.zijieapi\.com/
|
||||
/cloudinject[a-zA-Z0-9.-]*-dev\.*\.[a-zA-Z0-9.-]*-[a-zA-Z0-9.-]*-[a-zA-Z0-9.-]*\.amazonaws\.com/
|
||||
-1641
File diff suppressed because it is too large
Load Diff
-3688
File diff suppressed because it is too large
Load Diff
-3735
File diff suppressed because it is too large
Load Diff
-7826
File diff suppressed because it is too large
Load Diff
-68050
File diff suppressed because it is too large
Load Diff
-10607
File diff suppressed because it is too large
Load Diff
-82584
File diff suppressed because it is too large
Load Diff
-53291
File diff suppressed because it is too large
Load Diff
-1
@@ -1 +0,0 @@
|
||||
/ciceknoktasi/
|
||||
-1212
File diff suppressed because it is too large
Load Diff
@@ -1,3 +0,0 @@
|
||||
# 自定义规则文件
|
||||
# 格式:域名
|
||||
# 例如:example.com
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"blockedDomainsCount": {},
|
||||
"resolvedDomainsCount": {},
|
||||
"lastSaved": "2026-04-05T02:12:23.623097707+08:00"
|
||||
}
|
||||
-121
@@ -1,121 +0,0 @@
|
||||
{
|
||||
"stats": {
|
||||
"Queries": 153,
|
||||
"Blocked": 40,
|
||||
"Allowed": 84,
|
||||
"Errors": 29,
|
||||
"LastQuery": "2026-04-05T02:12:23.465147386+08:00",
|
||||
"AvgResponseTime": 53,
|
||||
"TotalResponseTime": 8033,
|
||||
"QueryTypes": {
|
||||
"A": 105,
|
||||
"AAAA": 48
|
||||
},
|
||||
"SourceIPs": {
|
||||
"10.35.10.21": true,
|
||||
"10.35.10.29": true,
|
||||
"10.35.10.39": true,
|
||||
"10.35.10.70": true,
|
||||
"10.35.10.78": true
|
||||
},
|
||||
"CpuUsage": 0.9268537074148298,
|
||||
"DNSSECQueries": 0,
|
||||
"DNSSECSuccess": 0,
|
||||
"DNSSECFailed": 0,
|
||||
"DNSSECEnabled": false
|
||||
},
|
||||
"blockedDomains": {
|
||||
"h-adashx.ut.taobao.com": {
|
||||
"Domain": "h-adashx.ut.taobao.com",
|
||||
"Count": 5,
|
||||
"LastSeen": 1775326320763967699,
|
||||
"DNSSEC": false
|
||||
},
|
||||
"log.zijieapi.com": {
|
||||
"Domain": "log.zijieapi.com",
|
||||
"Count": 11,
|
||||
"LastSeen": 1775326340263318690,
|
||||
"DNSSEC": false
|
||||
},
|
||||
"o1098464.ingest.sentry.io": {
|
||||
"Domain": "o1098464.ingest.sentry.io",
|
||||
"Count": 6,
|
||||
"LastSeen": 1775326342243323063,
|
||||
"DNSSEC": false
|
||||
},
|
||||
"oth.eve.mdt.qq.com": {
|
||||
"Domain": "oth.eve.mdt.qq.com",
|
||||
"Count": 4,
|
||||
"LastSeen": 1775326338058395755,
|
||||
"DNSSEC": false
|
||||
},
|
||||
"pcapp-data-collect.youku.com": {
|
||||
"Domain": "pcapp-data-collect.youku.com",
|
||||
"Count": 9,
|
||||
"LastSeen": 1775326322906085951,
|
||||
"DNSSEC": false
|
||||
},
|
||||
"puds.ucweb.com": {
|
||||
"Domain": "puds.ucweb.com",
|
||||
"Count": 1,
|
||||
"LastSeen": 1775326318450490954,
|
||||
"DNSSEC": false
|
||||
},
|
||||
"pw.mediav.com": {
|
||||
"Domain": "pw.mediav.com",
|
||||
"Count": 2,
|
||||
"LastSeen": 1775326325615190218,
|
||||
"DNSSEC": false
|
||||
},
|
||||
"px.effirst.com": {
|
||||
"Domain": "px.effirst.com",
|
||||
"Count": 1,
|
||||
"LastSeen": 1775326318462130855,
|
||||
"DNSSEC": false
|
||||
},
|
||||
"tpstelemetry.tencent.com": {
|
||||
"Domain": "tpstelemetry.tencent.com",
|
||||
"Count": 1,
|
||||
"LastSeen": 1775326318452632826,
|
||||
"DNSSEC": false
|
||||
}
|
||||
},
|
||||
"resolvedDomains": {},
|
||||
"clientStats": {
|
||||
"10.35.10.21": {
|
||||
"IP": "10.35.10.21",
|
||||
"Count": 4,
|
||||
"LastSeen": 1775326338058117035
|
||||
},
|
||||
"10.35.10.29": {
|
||||
"IP": "10.35.10.29",
|
||||
"Count": 24,
|
||||
"LastSeen": 1775326329866081939
|
||||
},
|
||||
"10.35.10.39": {
|
||||
"IP": "10.35.10.39",
|
||||
"Count": 5,
|
||||
"LastSeen": 1775326333564538372
|
||||
},
|
||||
"10.35.10.70": {
|
||||
"IP": "10.35.10.70",
|
||||
"Count": 80,
|
||||
"LastSeen": 1775326343465148826
|
||||
},
|
||||
"10.35.10.78": {
|
||||
"IP": "10.35.10.78",
|
||||
"Count": 40,
|
||||
"LastSeen": 1775326340263184353
|
||||
}
|
||||
},
|
||||
"hourlyStats": {
|
||||
"2026-04-05-02": 40
|
||||
},
|
||||
"dailyStats": {
|
||||
"2026-04-05": 40
|
||||
},
|
||||
"monthlyStats": {
|
||||
"2026-04": 40
|
||||
},
|
||||
"lastSaved": "2026-04-05T02:12:23.62184716+08:00"
|
||||
}
|
||||
BIN
Binary file not shown.
@@ -1,476 +0,0 @@
|
||||
# DNS 查询日志加载性能优化方案
|
||||
|
||||
## 问题分析
|
||||
|
||||
当前日志详情页面加载时间约 10 秒,主要性能瓶颈分析如下:
|
||||
|
||||
### 1. **主要性能瓶颈**
|
||||
|
||||
#### 1.1 同步 API 调用(最严重)
|
||||
- **位置**: `updateLogsTable()` 函数第 1221 行
|
||||
- **问题**: 对每条日志都调用 `await isDomainInTrackerDatabase(log.domain)`
|
||||
- **影响**: 假设每页 10 条日志,每条日志检查跟踪器数据库需要 100-500ms,总计 1-5 秒
|
||||
- **代码**:
|
||||
```javascript
|
||||
const trackerInfo = await isDomainInTrackerDatabase(log.domain); // ❌ 每条都 await
|
||||
```
|
||||
|
||||
#### 1.2 跟踪器数据库加载
|
||||
- **位置**: `isDomainInTrackerDatabase()` 函数
|
||||
- **问题**: 每次检查都要等待数据库加载完成
|
||||
- **影响**: 首次加载或数据库未加载完成时,每条日志都要等待
|
||||
|
||||
#### 1.3 域名信息 API 调用
|
||||
- **位置**: `getDomainInfoFromAPI()` 函数
|
||||
- **问题**: 如果实现中调用 API,会产生网络延迟
|
||||
- **影响**: 每个域名都可能产生一次 HTTP 请求
|
||||
|
||||
#### 1.4 IP 地理位置查询
|
||||
- **位置**: `getIpGeolocation()` 函数
|
||||
- **问题**: 虽然有缓存,但首次查询仍需调用外部 API
|
||||
- **影响**: 每个新 IP 地址需要 200-500ms
|
||||
|
||||
### 2. **性能测试数据(估算)**
|
||||
|
||||
| 操作 | 单次耗时 | 每页 10 条总耗时 | 优化后耗时 |
|
||||
|------|---------|----------------|-----------|
|
||||
| 跟踪器检查 | 100-500ms | 1-5 秒 | <100ms |
|
||||
| IP 地理位置 | 200-500ms | 2-5 秒 | <500ms(缓存) |
|
||||
| 后端 API 查询 | 100-300ms | 100-300ms | 不变 |
|
||||
| DOM 渲染 | 50-100ms | 50-100ms | 不变 |
|
||||
| **总计** | **10 秒** | **3-10 秒** | **<1 秒** |
|
||||
|
||||
---
|
||||
|
||||
## 优化方案
|
||||
|
||||
### 方案一:异步并行处理(推荐优先实施)⭐⭐⭐⭐⭐
|
||||
|
||||
#### 1.1 批量并行检查跟踪器
|
||||
|
||||
**问题**: 当前是串行等待每个域名的检查结果
|
||||
**解决**: 使用 `Promise.all()` 并行处理所有域名的检查
|
||||
|
||||
```javascript
|
||||
// 优化前(串行)
|
||||
for (const log of logs) {
|
||||
const trackerInfo = await isDomainInTrackerDatabase(log.domain);
|
||||
// ... 处理逻辑
|
||||
}
|
||||
|
||||
// 优化后(并行)
|
||||
const trackerChecks = logs.map(log => isDomainInTrackerDatabase(log.domain));
|
||||
const trackerResults = await Promise.all(trackerChecks);
|
||||
|
||||
// 然后渲染表格
|
||||
logs.forEach((log, index) => {
|
||||
const trackerInfo = trackerResults[index];
|
||||
// ... 渲染逻辑
|
||||
});
|
||||
```
|
||||
|
||||
**预期效果**: 从 1-5 秒降低到 100-500ms
|
||||
|
||||
#### 1.2 预加载跟踪器数据库
|
||||
|
||||
**问题**: 每次检查都要等待数据库加载
|
||||
**解决**: 页面初始化时立即加载,而不是延迟加载
|
||||
|
||||
```javascript
|
||||
// 在页面加载时立即执行
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
loadTrackersDatabase(); // 提前加载,不等待日志显示
|
||||
});
|
||||
```
|
||||
|
||||
**预期效果**: 消除数据库加载等待时间
|
||||
|
||||
---
|
||||
|
||||
### 方案二:缓存优化 ⭐⭐⭐⭐
|
||||
|
||||
#### 2.1 增强跟踪器检查缓存
|
||||
|
||||
**问题**: 相同的域名被重复检查
|
||||
**解决**: 添加内存缓存,避免重复检查
|
||||
|
||||
```javascript
|
||||
// 添加缓存
|
||||
const trackerCache = new Map();
|
||||
const trackerCacheTimestamp = new Map();
|
||||
const TRACKER_CACHE_EXPIRY = 24 * 60 * 60 * 1000; // 24 小时
|
||||
|
||||
async function isDomainInTrackerDatabase(domain) {
|
||||
// 检查缓存
|
||||
const cached = trackerCache.get(domain);
|
||||
const timestamp = trackerCacheTimestamp.get(domain);
|
||||
|
||||
if (cached && timestamp && (Date.now() - timestamp) < TRACKER_CACHE_EXPIRY) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
// 执行实际检查...
|
||||
const result = // ... 检查逻辑
|
||||
|
||||
// 缓存结果
|
||||
trackerCache.set(domain, result);
|
||||
trackerCacheTimestamp.set(domain, Date.now());
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
**预期效果**: 重复域名检查从 100ms 降低到 <1ms
|
||||
|
||||
#### 2.2 IP 地理位置缓存优化
|
||||
|
||||
**问题**: 相同 IP 被重复查询
|
||||
**解决**: 已有 LRU 缓存,确保缓存命中率高
|
||||
|
||||
```javascript
|
||||
// 确保缓存大小足够(当前为 1000,建议保持)
|
||||
const GEOLOCATION_CACHE_MAX_SIZE = 1000;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 方案三:延迟渲染优化 ⭐⭐⭐
|
||||
|
||||
#### 3.1 先渲染后更新
|
||||
|
||||
**问题**: 等待所有数据获取完成才渲染表格
|
||||
**解决**: 先渲染基本内容,再异步更新增强信息
|
||||
|
||||
```javascript
|
||||
async function updateLogsTable(logs) {
|
||||
// 第一步:立即渲染基本表格(不等待跟踪器检查)
|
||||
renderBasicTable(logs);
|
||||
|
||||
// 第二步:异步获取跟踪器信息并更新
|
||||
const trackerChecks = logs.map(log => isDomainInTrackerDatabase(log.domain));
|
||||
Promise.all(trackerChecks).then(results => {
|
||||
updateTrackerIcons(results); // 只更新图标部分
|
||||
});
|
||||
|
||||
// 第三步:异步获取 IP 地理位置
|
||||
logs.forEach(log => {
|
||||
getIpGeolocation(log.clientIP).then(location => {
|
||||
updateLocationElement(log.clientIP, location);
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
**预期效果**: 用户感知加载时间从 10 秒降低到 500ms 以内
|
||||
|
||||
#### 3.2 虚拟滚动(针对大量数据)
|
||||
|
||||
**问题**: 如果用户选择每页 100 条,DOM 节点过多
|
||||
**解决**: 只渲染可见区域的日志
|
||||
|
||||
```javascript
|
||||
// 使用虚拟滚动库或自定义实现
|
||||
// 只渲染可视区域的 20-30 条,滚动时动态加载
|
||||
```
|
||||
|
||||
**预期效果**: 渲染时间从 100ms 降低到 20ms
|
||||
|
||||
---
|
||||
|
||||
### 方案四:后端优化 ⭐⭐⭐⭐
|
||||
|
||||
#### 4.1 后端批量检查跟踪器
|
||||
|
||||
**问题**: 前端检查每条日志的跟踪器状态
|
||||
**解决**: 后端在返回日志时直接包含跟踪器信息
|
||||
|
||||
```go
|
||||
// 后端代码修改
|
||||
type QueryLog struct {
|
||||
// ... 现有字段
|
||||
IsTracker bool `json:"isTracker"`
|
||||
TrackerName string `json:"trackerName,omitempty"`
|
||||
}
|
||||
|
||||
// 在返回日志前批量检查
|
||||
func (s *Server) enrichLogsWithTrackerInfo(logs []QueryLog) {
|
||||
for i := range logs {
|
||||
logs[i].IsTracker, logs[i].TrackerName = s.checkTracker(logs[i].Domain)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**预期效果**: 完全消除前端跟踪器检查时间
|
||||
|
||||
#### 4.2 后端缓存优化
|
||||
|
||||
**问题**: 后端查询数据库慢
|
||||
**解决**: 增加 Redis 或内存缓存
|
||||
|
||||
```go
|
||||
// 使用内存缓存查询结果
|
||||
var queryCache = lru.New(100)
|
||||
```
|
||||
|
||||
**预期效果**: 后端查询时间从 300ms 降低到 50ms
|
||||
|
||||
---
|
||||
|
||||
### 方案五:数据库索引优化 ⭐⭐⭐
|
||||
|
||||
#### 5.1 添加数据库索引
|
||||
|
||||
**问题**: 日志查询慢
|
||||
**解决**: 为常用查询字段添加索引
|
||||
|
||||
```sql
|
||||
-- 为时间戳添加索引(加速时间范围查询)
|
||||
CREATE INDEX idx_timestamp ON query_logs(timestamp DESC);
|
||||
|
||||
-- 为域名添加索引(加速域名搜索)
|
||||
CREATE INDEX idx_domain ON query_logs(domain);
|
||||
|
||||
-- 为客户端 IP 添加索引
|
||||
CREATE INDEX idx_client_ip ON query_logs(client_ip);
|
||||
|
||||
-- 组合索引(加速组合查询)
|
||||
CREATE INDEX idx_timestamp_result ON query_logs(timestamp DESC, result);
|
||||
```
|
||||
|
||||
**预期效果**: 后端查询时间从 500ms 降低到 50ms
|
||||
|
||||
---
|
||||
|
||||
## 实施优先级
|
||||
|
||||
### 第一阶段(立即实施,效果最明显)
|
||||
1. ✅ **方案 1.1**: 并行处理跟踪器检查
|
||||
2. ✅ **方案 2.1**: 添加跟踪器检查缓存
|
||||
3. ✅ **方案 1.2**: 预加载跟踪器数据库
|
||||
|
||||
**预期效果**: 10 秒 → 2-3 秒
|
||||
|
||||
### 第二阶段(本周内实施)
|
||||
4. ✅ **方案 3.1**: 先渲染后更新
|
||||
5. ✅ **方案 4.1**: 后端批量检查跟踪器
|
||||
|
||||
**预期效果**: 2-3 秒 → 1 秒以内
|
||||
|
||||
### 第三阶段(长期优化)
|
||||
6. ✅ **方案 5.1**: 数据库索引优化
|
||||
7. ✅ **方案 4.2**: 后端缓存
|
||||
8. ✅ **方案 3.2**: 虚拟滚动
|
||||
|
||||
**预期效果**: 1 秒 → 500ms 以内
|
||||
|
||||
---
|
||||
|
||||
## 具体代码修改
|
||||
|
||||
### 修改 1: `logs.js` - 并行处理跟踪器检查
|
||||
|
||||
```javascript
|
||||
// 在 updateLogsTable() 函数中,替换第 1155-1353 行
|
||||
|
||||
async function updateLogsTable(logs) {
|
||||
const tableBody = document.getElementById('logs-table-body');
|
||||
if (!tableBody) return;
|
||||
|
||||
// 清空表格
|
||||
tableBody.innerHTML = '';
|
||||
|
||||
if (logs.length === 0) {
|
||||
// 显示空状态
|
||||
tableBody.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="5" class="py-8 text-center text-gray-500 border-b border-gray-100">
|
||||
<i class="fa fa-file-text-o text-4xl mb-2 text-gray-300"></i>
|
||||
<div>暂无查询日志</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
return;
|
||||
}
|
||||
|
||||
// 检测是否为移动设备
|
||||
const isMobile = window.innerWidth <= 768;
|
||||
|
||||
// 【优化】并行处理所有跟踪器检查
|
||||
const trackerChecks = logs.map(log => isDomainInTrackerDatabase(log.domain));
|
||||
const trackerResults = await Promise.all(trackerChecks);
|
||||
|
||||
// 预创建文档片段,减少 DOM 操作
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
// 填充表格
|
||||
for (let i = 0; i < logs.length; i++) {
|
||||
const log = logs[i];
|
||||
const trackerInfo = trackerResults[i];
|
||||
const isTracker = trackerInfo !== null;
|
||||
|
||||
const row = document.createElement('tr');
|
||||
row.className = `border-b border-gray-100 hover:bg-gray-50 transition-colors ${
|
||||
log.result === 'blocked' ? 'bg-red-50' : ''
|
||||
}`;
|
||||
|
||||
// ... 渲染逻辑(保持不变,但移除 await)
|
||||
|
||||
fragment.appendChild(row);
|
||||
}
|
||||
|
||||
// 一次性添加到 DOM
|
||||
tableBody.appendChild(fragment);
|
||||
|
||||
// 【优化】异步更新 IP 地理位置(不阻塞渲染)
|
||||
logs.forEach(log => {
|
||||
if (!isPrivateIP(log.clientIP)) {
|
||||
getIpGeolocation(log.clientIP).then(location => {
|
||||
const locationEl = document.querySelector(`.location-${log.clientIP.replace(/[.:]/g, '-')}`);
|
||||
if (locationEl) {
|
||||
locationEl.textContent = location;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### 修改 2: `logs.js` - 添加跟踪器缓存
|
||||
|
||||
```javascript
|
||||
// 在全局变量部分添加
|
||||
const trackerCache = new Map();
|
||||
const trackerCacheTimestamp = new Map();
|
||||
const TRACKER_CACHE_EXPIRY = 24 * 60 * 60 * 1000; // 24 小时
|
||||
|
||||
// 修改 isDomainInTrackerDatabase 函数
|
||||
async function isDomainInTrackerDatabase(domain) {
|
||||
// 检查缓存
|
||||
const cached = trackerCache.get(domain);
|
||||
const timestamp = trackerCacheTimestamp.get(domain);
|
||||
|
||||
if (cached !== undefined && timestamp && (Date.now() - timestamp) < TRACKER_CACHE_EXPIRY) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
// 确保数据库已加载
|
||||
if (!trackersDatabase || !trackersLoaded) {
|
||||
await loadTrackersDatabase();
|
||||
}
|
||||
|
||||
if (!trackersDatabase || !trackersDatabase.trackers) {
|
||||
trackerCache.set(domain, null);
|
||||
trackerCacheTimestamp.set(domain, Date.now());
|
||||
return null;
|
||||
}
|
||||
|
||||
// 检查逻辑(保持不变)
|
||||
let result = null;
|
||||
|
||||
if (trackersDatabase.trackers.hasOwnProperty(domain)) {
|
||||
result = trackersDatabase.trackers[domain];
|
||||
} else {
|
||||
for (const trackerKey in trackersDatabase.trackers) {
|
||||
const tracker = trackersDatabase.trackers[trackerKey];
|
||||
if (tracker && tracker.url) {
|
||||
try {
|
||||
const trackerUrl = new URL(tracker.url);
|
||||
if (trackerUrl.hostname === domain) {
|
||||
result = tracker;
|
||||
break;
|
||||
}
|
||||
} catch (e) {
|
||||
// 忽略无效 URL
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 缓存结果
|
||||
trackerCache.set(domain, result);
|
||||
trackerCacheTimestamp.set(domain, Date.now());
|
||||
|
||||
// 限制缓存大小(LRU 简单实现)
|
||||
if (trackerCache.size > 1000) {
|
||||
const oldestKey = trackerCache.keys().next().value;
|
||||
trackerCache.delete(oldestKey);
|
||||
trackerCacheTimestamp.delete(oldestKey);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
### 修改 3: `index.html` - 预加载跟踪器数据库
|
||||
|
||||
```html
|
||||
<!-- 在页面底部,logs.js 加载后立即执行 -->
|
||||
<script>
|
||||
// 页面加载时立即预加载跟踪器数据库
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// 异步加载,不阻塞页面
|
||||
if (typeof loadTrackersDatabase === 'function') {
|
||||
loadTrackersDatabase();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 性能监控
|
||||
|
||||
### 添加性能日志
|
||||
|
||||
```javascript
|
||||
// 在 loadLogs() 函数中添加性能监控
|
||||
async function loadLogs() {
|
||||
const startTime = performance.now();
|
||||
console.log('🚀 开始加载日志...');
|
||||
|
||||
// ... 加载逻辑
|
||||
|
||||
const endTime = performance.now();
|
||||
const duration = endTime - startTime;
|
||||
console.log(`✅ 日志加载完成,耗时:${duration.toFixed(2)}ms`);
|
||||
|
||||
// 分解各阶段耗时
|
||||
console.log('📊 性能分析:', {
|
||||
API 请求:apiTime,
|
||||
跟踪器检查:trackerTime,
|
||||
DOM 渲染:renderTime,
|
||||
IP 查询:ipTime
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 预期最终效果
|
||||
|
||||
| 优化阶段 | 加载时间 | 改善幅度 |
|
||||
|---------|---------|---------|
|
||||
| 优化前 | 10 秒 | - |
|
||||
| 第一阶段 | 2-3 秒 | 70-80% |
|
||||
| 第二阶段 | 1 秒以内 | 90% |
|
||||
| 第三阶段 | 500ms 以内 | 95% |
|
||||
|
||||
---
|
||||
|
||||
## 风险与注意事项
|
||||
|
||||
1. **内存使用**: 缓存会增加内存占用,建议限制缓存大小
|
||||
2. **缓存一致性**: 跟踪器数据库更新后需要清理缓存
|
||||
3. **浏览器兼容性**: `Promise.all()` 在老旧浏览器可能不支持
|
||||
4. **并发限制**: 如果日志数量过多(>100),考虑分批处理
|
||||
|
||||
---
|
||||
|
||||
## 总结
|
||||
|
||||
**最优先实施的优化**:
|
||||
1. ✅ 并行处理跟踪器检查(方案 1.1)
|
||||
2. ✅ 添加跟踪器检查缓存(方案 2.1)
|
||||
3. ✅ 先渲染后更新(方案 3.1)
|
||||
|
||||
这三项优化可以将加载时间从 10 秒降低到 1 秒以内,且实施成本低,风险小。
|
||||
@@ -0,0 +1,64 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"dns-server/log"
|
||||
)
|
||||
|
||||
// enrichLogsWithDomainInfo 为日志条目添加域名信息、威胁信息和跟踪器信息
|
||||
func (s *Server) enrichLogsWithDomainInfo(logs []log.QueryLog) []map[string]interface{} {
|
||||
enrichedLogs := make([]map[string]interface{}, len(logs))
|
||||
|
||||
for i, logItem := range logs {
|
||||
// 将日志条目转换为 map
|
||||
logMap := make(map[string]interface{})
|
||||
logMap["timestamp"] = logItem.Timestamp
|
||||
logMap["clientIP"] = logItem.ClientIP
|
||||
logMap["domain"] = logItem.Domain
|
||||
logMap["queryType"] = logItem.QueryType
|
||||
logMap["result"] = logItem.Result
|
||||
logMap["responseTime"] = logItem.ResponseTime
|
||||
logMap["dnsServer"] = logItem.DNSServer
|
||||
logMap["answers"] = logItem.Answers
|
||||
|
||||
// 查询域名信息
|
||||
if domainInfo := s.domainInfoManager.GetDomainInfo(logItem.Domain); domainInfo != nil {
|
||||
logMap["domainInfo"] = domainInfo
|
||||
}
|
||||
|
||||
// 查询威胁信息
|
||||
if threatInfo := s.domainInfoManager.GetThreatInfo(logItem.Domain); threatInfo != nil {
|
||||
logMap["threatInfo"] = threatInfo
|
||||
}
|
||||
|
||||
// 查询跟踪器信息
|
||||
if trackerInfo := s.domainInfoManager.GetTrackerInfo(logItem.Domain); trackerInfo != nil {
|
||||
logMap["trackerInfo"] = trackerInfo
|
||||
}
|
||||
|
||||
enrichedLogs[i] = logMap
|
||||
}
|
||||
|
||||
return enrichedLogs
|
||||
}
|
||||
|
||||
// enrichDomainInfoWithDetails 为域名查询结果添加详细信息
|
||||
func (s *Server) enrichDomainInfoWithDetails(domain string, baseResult map[string]interface{}) map[string]interface{} {
|
||||
// 添加域名信息
|
||||
if domainInfo := s.domainInfoManager.GetDomainInfo(domain); domainInfo != nil {
|
||||
baseResult["domainInfo"] = domainInfo
|
||||
}
|
||||
|
||||
// 添加威胁信息
|
||||
if threatInfo := s.domainInfoManager.GetThreatInfo(domain); threatInfo != nil {
|
||||
baseResult["threatInfo"] = threatInfo
|
||||
baseResult["isThreat"] = true
|
||||
}
|
||||
|
||||
// 添加跟踪器信息
|
||||
if trackerInfo := s.domainInfoManager.GetTrackerInfo(domain); trackerInfo != nil {
|
||||
baseResult["trackerInfo"] = trackerInfo
|
||||
baseResult["isTracker"] = true
|
||||
}
|
||||
|
||||
return baseResult
|
||||
}
|
||||
@@ -0,0 +1,385 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"dns-server/config"
|
||||
"dns-server/logger"
|
||||
"dns-server/shield"
|
||||
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
// handleDomainInfoUpdate 处理域名信息更新请求(更新所有类型)
|
||||
func (s *Server) handleDomainInfoUpdate(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("收到更新所有域名信息的请求")
|
||||
|
||||
// 异步更新所有域名信息
|
||||
go func() {
|
||||
if err := s.domainInfoManager.LoadDomainInfo(); err != nil {
|
||||
logger.Error("更新所有域名信息失败", "error", err)
|
||||
} else {
|
||||
logger.Info("更新所有域名信息成功")
|
||||
}
|
||||
}()
|
||||
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "success",
|
||||
"message": "域名信息更新任务已启动",
|
||||
})
|
||||
}
|
||||
|
||||
// handleDomainInfoUpdateByType 处理指定类型的域名信息更新请求
|
||||
func (s *Server) handleDomainInfoUpdateByType(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
// 从 URL 路径中提取类型
|
||||
// 路径格式:/api/domain-info/update/{type}
|
||||
pathParts := strings.Split(r.URL.Path, "/")
|
||||
var entryType string
|
||||
for i, part := range pathParts {
|
||||
if part == "update" && i+1 < len(pathParts) {
|
||||
entryType = strings.TrimSpace(pathParts[i+1])
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if entryType == "" {
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "error",
|
||||
"message": "类型参数不能为空",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("收到更新域名信息的请求", "type", entryType)
|
||||
|
||||
// 异步更新指定类型的域名信息
|
||||
go func(typeToUpdate string) {
|
||||
if err := s.domainInfoManager.UpdateDomainInfoList(typeToUpdate); err != nil {
|
||||
logger.Error("更新域名信息失败", "type", typeToUpdate, "error", err)
|
||||
} else {
|
||||
logger.Info("更新域名信息成功", "type", typeToUpdate)
|
||||
}
|
||||
}(entryType)
|
||||
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "success",
|
||||
"message": "域名信息更新任务已启动",
|
||||
"type": entryType,
|
||||
})
|
||||
}
|
||||
|
||||
// handleDomainInfoQuery 处理单个域名信息查询请求
|
||||
func (s *Server) handleDomainInfoQuery(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
domain := r.URL.Query().Get("domain")
|
||||
if domain == "" {
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "error",
|
||||
"message": "domain 参数不能为空",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
result := map[string]interface{}{
|
||||
"domain": domain,
|
||||
}
|
||||
|
||||
// 查询域名信息
|
||||
if domainInfo := s.domainInfoManager.GetDomainInfo(domain); domainInfo != nil {
|
||||
result["domainInfo"] = domainInfo
|
||||
}
|
||||
|
||||
// 查询威胁信息
|
||||
if threatInfo := s.domainInfoManager.GetThreatInfo(domain); threatInfo != nil {
|
||||
result["threatInfo"] = threatInfo
|
||||
}
|
||||
|
||||
// 查询跟踪器信息
|
||||
if trackerInfo := s.domainInfoManager.GetTrackerInfo(domain); trackerInfo != nil {
|
||||
result["trackerInfo"] = trackerInfo
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(result)
|
||||
}
|
||||
|
||||
// AddDomainInfoList 添加域名信息列表(供外部调用)
|
||||
func (s *Server) AddDomainInfoList(entry config.DomainInfoEntry) error {
|
||||
return s.domainInfoManager.AddDomainInfoList(entry)
|
||||
}
|
||||
|
||||
// RemoveDomainInfoList 移除域名信息列表(供外部调用)
|
||||
func (s *Server) RemoveDomainInfoList(entryType string) error {
|
||||
return s.domainInfoManager.RemoveDomainInfoList(entryType)
|
||||
}
|
||||
|
||||
// GetDomainInfoManager 获取域名信息管理器实例(供外部调用)
|
||||
func (s *Server) GetDomainInfoManager() *shield.DomainInfoManager {
|
||||
return s.domainInfoManager
|
||||
}
|
||||
|
||||
// handleDomainInfoStatus 处理域名信息更新状态请求
|
||||
func (s *Server) handleDomainInfoStatus(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
status := s.domainInfoManager.GetUpdateStatus()
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"status": "success",
|
||||
"data": status,
|
||||
})
|
||||
}
|
||||
|
||||
// handleDomainInfoRefresh 处理域名信息缓存刷新请求
|
||||
func (s *Server) handleDomainInfoRefresh(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("收到刷新域名信息缓存的请求")
|
||||
|
||||
// 异步刷新缓存
|
||||
go func() {
|
||||
if err := s.domainInfoManager.LoadDomainInfo(); err != nil {
|
||||
logger.Error("刷新域名信息缓存失败", "error", err)
|
||||
} else {
|
||||
logger.Info("刷新域名信息缓存成功")
|
||||
}
|
||||
}()
|
||||
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "success",
|
||||
"message": "域名信息缓存刷新任务已启动",
|
||||
})
|
||||
}
|
||||
|
||||
// handleDomainInfoAdd 处理添加域名信息列表请求
|
||||
func (s *Server) handleDomainInfoAdd(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
var entry config.DomainInfoEntry
|
||||
if err := json.NewDecoder(r.Body).Decode(&entry); err != nil {
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "error",
|
||||
"message": "无效的请求数据",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 验证必填字段
|
||||
if entry.Name == "" || entry.URL == "" || entry.Type == "" {
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "error",
|
||||
"message": "名称、URL和类型不能为空",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("收到添加域名信息列表的请求", "name", entry.Name, "type", entry.Type)
|
||||
|
||||
if err := s.domainInfoManager.AddDomainInfoList(entry); err != nil {
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "error",
|
||||
"message": fmt.Sprintf("添加列表失败: %v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 保存配置到文件
|
||||
if err := saveConfigToFile(s.globalConfig, "config.ini"); err != nil {
|
||||
logger.Error("保存配置文件失败", "error", err)
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "error",
|
||||
"message": "添加列表成功,但保存配置失败",
|
||||
"name": entry.Name,
|
||||
"type": entry.Type,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "success",
|
||||
"message": "域名信息列表添加成功",
|
||||
"name": entry.Name,
|
||||
"type": entry.Type,
|
||||
})
|
||||
}
|
||||
|
||||
// handleDomainInfoRemove 处理删除域名信息列表请求
|
||||
func (s *Server) handleDomainInfoRemove(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if r.Method != http.MethodPost {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
var request struct {
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&request); err != nil {
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "error",
|
||||
"message": "无效的请求数据",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if request.Type == "" {
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "error",
|
||||
"message": "类型参数不能为空",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
logger.Info("收到删除域名信息列表的请求", "type", request.Type)
|
||||
|
||||
if err := s.domainInfoManager.RemoveDomainInfoList(request.Type); err != nil {
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "error",
|
||||
"message": fmt.Sprintf("删除列表失败: %v", err),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 保存配置到文件
|
||||
if err := saveConfigToFile(s.globalConfig, "config.ini"); err != nil {
|
||||
logger.Error("保存配置文件失败", "error", err)
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "error",
|
||||
"message": "删除列表成功,但保存配置失败",
|
||||
"type": request.Type,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
json.NewEncoder(w).Encode(map[string]string{
|
||||
"status": "success",
|
||||
"message": "域名信息列表删除成功",
|
||||
"type": request.Type,
|
||||
})
|
||||
}
|
||||
|
||||
// saveConfigToFile 保存配置到文件
|
||||
func saveConfigToFile(config *config.Config, filePath string) error {
|
||||
// 创建新的INI文件
|
||||
cfg := ini.Empty()
|
||||
|
||||
// DNS配置
|
||||
dnsSection := cfg.Section("dns")
|
||||
dnsSection.Key("port").SetValue(fmt.Sprintf("%d", config.DNS.Port))
|
||||
dnsSection.Key("upstreamDNS").SetValue(strings.Join(config.DNS.UpstreamDNS, ", "))
|
||||
dnsSection.Key("dnssecUpstreamDNS").SetValue(strings.Join(config.DNS.DNSSECUpstreamDNS, ", "))
|
||||
dnsSection.Key("saveInterval").SetValue(fmt.Sprintf("%d", config.DNS.SaveInterval))
|
||||
dnsSection.Key("cacheTTL").SetValue(fmt.Sprintf("%d", config.DNS.CacheTTL))
|
||||
dnsSection.Key("enableDNSSEC").SetValue(fmt.Sprintf("%t", config.DNS.EnableDNSSEC))
|
||||
dnsSection.Key("queryMode").SetValue(config.DNS.QueryMode)
|
||||
dnsSection.Key("queryTimeout").SetValue(fmt.Sprintf("%d", config.DNS.QueryTimeout))
|
||||
dnsSection.Key("enableFastReturn").SetValue(fmt.Sprintf("%t", config.DNS.EnableFastReturn))
|
||||
dnsSection.Key("noDNSSECDomains").SetValue(strings.Join(config.DNS.NoDNSSECDomains, ", "))
|
||||
dnsSection.Key("enableIPv6").SetValue(fmt.Sprintf("%t", config.DNS.EnableIPv6))
|
||||
dnsSection.Key("cacheMode").SetValue(config.DNS.CacheMode)
|
||||
dnsSection.Key("cacheSize").SetValue(fmt.Sprintf("%d", config.DNS.CacheSize))
|
||||
dnsSection.Key("maxCacheTTL").SetValue(fmt.Sprintf("%d", config.DNS.MaxCacheTTL))
|
||||
dnsSection.Key("minCacheTTL").SetValue(fmt.Sprintf("%d", config.DNS.MinCacheTTL))
|
||||
|
||||
// 域名特定DNS服务器配置
|
||||
for domain, servers := range config.DNS.DomainSpecificDNS {
|
||||
dnsSection.Key(fmt.Sprintf("domain_%s", domain)).SetValue(strings.Join(servers, ", "))
|
||||
}
|
||||
|
||||
// HTTP配置
|
||||
httpSection := cfg.Section("http")
|
||||
httpSection.Key("port").SetValue(fmt.Sprintf("%d", config.HTTP.Port))
|
||||
httpSection.Key("host").SetValue(config.HTTP.Host)
|
||||
httpSection.Key("enableAPI").SetValue(fmt.Sprintf("%t", config.HTTP.EnableAPI))
|
||||
httpSection.Key("username").SetValue(config.HTTP.Username)
|
||||
httpSection.Key("password").SetValue(config.HTTP.Password)
|
||||
|
||||
// Shield配置
|
||||
shieldSection := cfg.Section("shield")
|
||||
shieldSection.Key("updateInterval").SetValue(fmt.Sprintf("%d", config.Shield.UpdateInterval))
|
||||
shieldSection.Key("blockMethod").SetValue(config.Shield.BlockMethod)
|
||||
shieldSection.Key("customBlockIP").SetValue(config.Shield.CustomBlockIP)
|
||||
shieldSection.Key("statsSaveInterval").SetValue(fmt.Sprintf("%d", config.Shield.StatsSaveInterval))
|
||||
|
||||
// 黑名单配置
|
||||
for _, bl := range config.Shield.Blacklists {
|
||||
shieldSection.Key(fmt.Sprintf("blacklist_%s", bl.Name)).SetValue(fmt.Sprintf("%s,%t", bl.URL, bl.Enabled))
|
||||
}
|
||||
|
||||
// GFWList配置
|
||||
gfwListSection := cfg.Section("gfwList")
|
||||
gfwListSection.Key("ip").SetValue(config.GFWList.IP)
|
||||
gfwListSection.Key("content").SetValue(config.GFWList.Content)
|
||||
gfwListSection.Key("enabled").SetValue(fmt.Sprintf("%t", config.GFWList.Enabled))
|
||||
|
||||
// Log配置
|
||||
logSection := cfg.Section("log")
|
||||
logSection.Key("level").SetValue(config.Log.Level)
|
||||
logSection.Key("maxSize").SetValue(fmt.Sprintf("%d", config.Log.MaxSize))
|
||||
logSection.Key("maxBackups").SetValue(fmt.Sprintf("%d", config.Log.MaxBackups))
|
||||
logSection.Key("maxAge").SetValue(fmt.Sprintf("%d", config.Log.MaxAge))
|
||||
|
||||
// Threat配置
|
||||
threatSection := cfg.Section("threat")
|
||||
threatSection.Key("enabled").SetValue(fmt.Sprintf("%t", config.Threat.Enabled))
|
||||
threatSection.Key("queryRateThreshold").SetValue(fmt.Sprintf("%d", config.Threat.QueryRateThreshold))
|
||||
threatSection.Key("nxDomainThreshold").SetValue(fmt.Sprintf("%d", config.Threat.NXDomainThreshold))
|
||||
threatSection.Key("maxDomainLength").SetValue(fmt.Sprintf("%d", config.Threat.MaxDomainLength))
|
||||
threatSection.Key("suspiciousPatterns").SetValue(strings.Join(config.Threat.SuspiciousPatterns, ", "))
|
||||
threatSection.Key("unusualQueryTypes").SetValue(strings.Join(config.Threat.UnusualQueryTypes, ", "))
|
||||
threatSection.Key("alertRetentionDays").SetValue(fmt.Sprintf("%d", config.Threat.AlertRetentionDays))
|
||||
threatSection.Key("threatDatabasePath").SetValue(config.Threat.ThreatDatabasePath)
|
||||
|
||||
// DomainInfo配置
|
||||
domainInfoSection := cfg.Section("domainInfo")
|
||||
domainInfoSection.Key("updateInterval").SetValue(fmt.Sprintf("%d", config.DomainInfo.UpdateInterval))
|
||||
domainInfoSection.Key("enableAutoUpdate").SetValue(fmt.Sprintf("%t", config.DomainInfo.EnableAutoUpdate))
|
||||
|
||||
// 域名信息列表配置
|
||||
for _, entry := range config.DomainInfo.DomainInfoLists {
|
||||
domainInfoSection.Key(fmt.Sprintf("domainInfo_%s", entry.Name)).SetValue(fmt.Sprintf("%s,%s,%t", entry.URL, entry.Type, entry.Enabled))
|
||||
}
|
||||
|
||||
// 保存到文件
|
||||
return cfg.SaveTo(filePath)
|
||||
}
|
||||
|
||||
|
||||
+94
-155
@@ -21,7 +21,6 @@ import (
|
||||
"dns-server/threat"
|
||||
|
||||
"github.com/gorilla/websocket"
|
||||
"gopkg.in/ini.v1"
|
||||
)
|
||||
|
||||
// CacheEntry 缓存条目
|
||||
@@ -313,6 +312,7 @@ type Server struct {
|
||||
dnsServer *dns.Server
|
||||
shieldManager *shield.ShieldManager
|
||||
gfwManager *gfw.GFWListManager
|
||||
domainInfoManager *shield.DomainInfoManager
|
||||
server *http.Server
|
||||
|
||||
// 会话管理相关字段
|
||||
@@ -336,12 +336,16 @@ type Server struct {
|
||||
|
||||
// NewServer 创建 HTTP 服务器实例
|
||||
func NewServer(globalConfig *config.Config, dnsServer *dns.Server, shieldManager *shield.ShieldManager, gfwManager *gfw.GFWListManager) *Server {
|
||||
// 创建域名信息管理器
|
||||
domainInfoManager := shield.NewDomainInfoManager(&globalConfig.DomainInfo)
|
||||
|
||||
server := &Server{
|
||||
globalConfig: globalConfig,
|
||||
config: &globalConfig.HTTP,
|
||||
dnsServer: dnsServer,
|
||||
shieldManager: shieldManager,
|
||||
gfwManager: gfwManager,
|
||||
domainInfoManager: domainInfoManager,
|
||||
upgrader: websocket.Upgrader{
|
||||
ReadBufferSize: 1024,
|
||||
WriteBufferSize: 1024,
|
||||
@@ -363,6 +367,9 @@ func NewServer(globalConfig *config.Config, dnsServer *dns.Server, shieldManager
|
||||
cacheMaxSize: 100, // 默认最大 100 条
|
||||
}
|
||||
|
||||
// 启动域名信息管理器
|
||||
domainInfoManager.Start()
|
||||
|
||||
// 启动广播协程
|
||||
go server.startBroadcastLoop()
|
||||
// 启动会话清理协程
|
||||
@@ -444,6 +451,17 @@ func (s *Server) Start() error {
|
||||
mux.HandleFunc("/api/logs/archive-cleanup", s.loginRequired(s.handleArchiveCleanup))
|
||||
// 域名信息列表接口
|
||||
mux.HandleFunc("/api/domain-info", s.loginRequired(s.handleDomainInfoList))
|
||||
// 域名信息更新接口
|
||||
mux.HandleFunc("/api/domain-info/update", s.loginRequired(s.handleDomainInfoUpdate))
|
||||
mux.HandleFunc("/api/domain-info/update/{type}", s.loginRequired(s.handleDomainInfoUpdateByType))
|
||||
// 域名信息状态接口
|
||||
mux.HandleFunc("/api/domain-info/status", s.loginRequired(s.handleDomainInfoStatus))
|
||||
// 域名信息缓存刷新接口
|
||||
mux.HandleFunc("/api/domain-info/refresh", s.loginRequired(s.handleDomainInfoRefresh))
|
||||
// 域名信息列表添加接口
|
||||
mux.HandleFunc("/api/domain-info/add", s.loginRequired(s.handleDomainInfoAdd))
|
||||
// 域名信息列表删除接口
|
||||
mux.HandleFunc("/api/domain-info/remove", s.loginRequired(s.handleDomainInfoRemove))
|
||||
// 威胁查询接口
|
||||
mux.HandleFunc("/api/threat", s.loginRequired(s.handleThreatQuery))
|
||||
// 威胁批量查询接口
|
||||
@@ -1583,81 +1601,7 @@ func (s *Server) handleStatus(w http.ResponseWriter, r *http.Request) {
|
||||
json.NewEncoder(w).Encode(status)
|
||||
}
|
||||
|
||||
// saveConfigToFile 保存配置到文件
|
||||
func saveConfigToFile(config *config.Config, filePath string) error {
|
||||
// 创建新的INI文件
|
||||
cfg := ini.Empty()
|
||||
|
||||
// DNS配置
|
||||
dnsSection := cfg.Section("dns")
|
||||
dnsSection.Key("port").SetValue(fmt.Sprintf("%d", config.DNS.Port))
|
||||
dnsSection.Key("upstreamDNS").SetValue(strings.Join(config.DNS.UpstreamDNS, ", "))
|
||||
dnsSection.Key("dnssecUpstreamDNS").SetValue(strings.Join(config.DNS.DNSSECUpstreamDNS, ", "))
|
||||
dnsSection.Key("saveInterval").SetValue(fmt.Sprintf("%d", config.DNS.SaveInterval))
|
||||
dnsSection.Key("cacheTTL").SetValue(fmt.Sprintf("%d", config.DNS.CacheTTL))
|
||||
dnsSection.Key("enableDNSSEC").SetValue(fmt.Sprintf("%t", config.DNS.EnableDNSSEC))
|
||||
dnsSection.Key("queryMode").SetValue(config.DNS.QueryMode)
|
||||
dnsSection.Key("queryTimeout").SetValue(fmt.Sprintf("%d", config.DNS.QueryTimeout))
|
||||
dnsSection.Key("enableFastReturn").SetValue(fmt.Sprintf("%t", config.DNS.EnableFastReturn))
|
||||
dnsSection.Key("noDNSSECDomains").SetValue(strings.Join(config.DNS.NoDNSSECDomains, ", "))
|
||||
dnsSection.Key("enableIPv6").SetValue(fmt.Sprintf("%t", config.DNS.EnableIPv6))
|
||||
dnsSection.Key("cacheMode").SetValue(config.DNS.CacheMode)
|
||||
dnsSection.Key("cacheSize").SetValue(fmt.Sprintf("%d", config.DNS.CacheSize))
|
||||
dnsSection.Key("maxCacheTTL").SetValue(fmt.Sprintf("%d", config.DNS.MaxCacheTTL))
|
||||
dnsSection.Key("minCacheTTL").SetValue(fmt.Sprintf("%d", config.DNS.MinCacheTTL))
|
||||
|
||||
// 域名特定DNS服务器配置
|
||||
for domain, servers := range config.DNS.DomainSpecificDNS {
|
||||
dnsSection.Key(fmt.Sprintf("domain_%s", domain)).SetValue(strings.Join(servers, ", "))
|
||||
}
|
||||
|
||||
// HTTP配置
|
||||
httpSection := cfg.Section("http")
|
||||
httpSection.Key("port").SetValue(fmt.Sprintf("%d", config.HTTP.Port))
|
||||
httpSection.Key("host").SetValue(config.HTTP.Host)
|
||||
httpSection.Key("enableAPI").SetValue(fmt.Sprintf("%t", config.HTTP.EnableAPI))
|
||||
httpSection.Key("username").SetValue(config.HTTP.Username)
|
||||
httpSection.Key("password").SetValue(config.HTTP.Password)
|
||||
|
||||
// Shield配置
|
||||
shieldSection := cfg.Section("shield")
|
||||
shieldSection.Key("updateInterval").SetValue(fmt.Sprintf("%d", config.Shield.UpdateInterval))
|
||||
shieldSection.Key("blockMethod").SetValue(config.Shield.BlockMethod)
|
||||
shieldSection.Key("customBlockIP").SetValue(config.Shield.CustomBlockIP)
|
||||
shieldSection.Key("statsSaveInterval").SetValue(fmt.Sprintf("%d", config.Shield.StatsSaveInterval))
|
||||
|
||||
// 黑名单配置
|
||||
for _, bl := range config.Shield.Blacklists {
|
||||
shieldSection.Key(fmt.Sprintf("blacklist_%s", bl.Name)).SetValue(fmt.Sprintf("%s,%t", bl.URL, bl.Enabled))
|
||||
}
|
||||
|
||||
// GFWList配置
|
||||
gfwListSection := cfg.Section("gfwList")
|
||||
gfwListSection.Key("ip").SetValue(config.GFWList.IP)
|
||||
gfwListSection.Key("content").SetValue(config.GFWList.Content)
|
||||
gfwListSection.Key("enabled").SetValue(fmt.Sprintf("%t", config.GFWList.Enabled))
|
||||
|
||||
// Log配置
|
||||
logSection := cfg.Section("log")
|
||||
logSection.Key("level").SetValue(config.Log.Level)
|
||||
logSection.Key("maxSize").SetValue(fmt.Sprintf("%d", config.Log.MaxSize))
|
||||
logSection.Key("maxBackups").SetValue(fmt.Sprintf("%d", config.Log.MaxBackups))
|
||||
logSection.Key("maxAge").SetValue(fmt.Sprintf("%d", config.Log.MaxAge))
|
||||
|
||||
// Threat配置
|
||||
threatSection := cfg.Section("threat")
|
||||
threatSection.Key("enabled").SetValue(fmt.Sprintf("%t", config.Threat.Enabled))
|
||||
threatSection.Key("queryRateThreshold").SetValue(fmt.Sprintf("%d", config.Threat.QueryRateThreshold))
|
||||
threatSection.Key("nxDomainThreshold").SetValue(fmt.Sprintf("%d", config.Threat.NXDomainThreshold))
|
||||
threatSection.Key("maxDomainLength").SetValue(fmt.Sprintf("%d", config.Threat.MaxDomainLength))
|
||||
threatSection.Key("suspiciousPatterns").SetValue(strings.Join(config.Threat.SuspiciousPatterns, ","))
|
||||
threatSection.Key("unusualQueryTypes").SetValue(strings.Join(config.Threat.UnusualQueryTypes, ","))
|
||||
threatSection.Key("alertRetentionDays").SetValue(fmt.Sprintf("%d", config.Threat.AlertRetentionDays))
|
||||
threatSection.Key("threatDatabasePath").SetValue(config.Threat.ThreatDatabasePath)
|
||||
|
||||
// 保存到文件
|
||||
return cfg.SaveTo(filePath)
|
||||
}
|
||||
|
||||
// handleConfig 处理配置请求
|
||||
func (s *Server) handleConfig(w http.ResponseWriter, r *http.Request) {
|
||||
@@ -2168,6 +2112,12 @@ func (s *Server) handleLogsQuery(w http.ResponseWriter, r *http.Request) {
|
||||
"totalPages": totalPages,
|
||||
}
|
||||
|
||||
// 为日志添加域名信息(只在第一页添加,减少开销)
|
||||
if pageNum == 1 && len(logs) > 0 {
|
||||
enrichedLogs := s.enrichLogsWithDomainInfo(logs)
|
||||
response["logs"] = enrichedLogs
|
||||
}
|
||||
|
||||
// 存入缓存(只缓存第一页,因为用户最常查看第一页)
|
||||
if s.cacheEnabled && pageNum == 1 {
|
||||
s.queryCache.Set(cacheKey, response)
|
||||
@@ -2416,10 +2366,41 @@ func (s *Server) handleDomainInfoList(w http.ResponseWriter, r *http.Request) {
|
||||
threatFilter := query.Get("threats")
|
||||
handleThreatsInfo(w, threatFilter)
|
||||
} else {
|
||||
// 直接访问 /domain-info 不提供任何内容
|
||||
http.Error(w, "No content provided", http.StatusNoContent)
|
||||
// 获取所有域名信息列表
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
if s.domainInfoManager == nil {
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"lists": []interface{}{},
|
||||
"domainInfoCount": 0,
|
||||
"threatCount": 0,
|
||||
"trackerCount": 0,
|
||||
"lastUpdateTime": "从未更新",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// 使用 goroutine 和 channel 避免死锁
|
||||
done := make(chan map[string]interface{}, 1)
|
||||
go func() {
|
||||
domainInfo := s.domainInfoManager.GetAllDomainInfo()
|
||||
done <- domainInfo
|
||||
}()
|
||||
|
||||
select {
|
||||
case domainInfo := <-done:
|
||||
json.NewEncoder(w).Encode(domainInfo)
|
||||
case <-time.After(10 * time.Second):
|
||||
// 超时,返回空响应
|
||||
json.NewEncoder(w).Encode(map[string]interface{}{
|
||||
"lists": []interface{}{},
|
||||
"domainInfoCount": 0,
|
||||
"threatCount": 0,
|
||||
"trackerCount": 0,
|
||||
"lastUpdateTime": "加载中...",
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// isService 判断一个对象是否是服务(而不是分组)
|
||||
@@ -2930,95 +2911,53 @@ func (s *Server) handleThreatQuery(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// 读取威胁数据库 CSV 文件
|
||||
filePath := "./static/domain-info/threats/threats-database.csv"
|
||||
data, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
json.NewEncoder(w).Encode(map[string]string{"error": "读取威胁数据库失败"})
|
||||
logger.Error(fmt.Sprintf("读取威胁数据库文件失败:%v", err))
|
||||
return
|
||||
// 使用域名信息管理器查询威胁信息
|
||||
threatInfo := s.domainInfoManager.GetThreatInfo(domain)
|
||||
|
||||
result := map[string]interface{}{
|
||||
"domain": domain,
|
||||
}
|
||||
|
||||
// 解析 CSV
|
||||
reader := csv.NewReader(bytes.NewReader(data))
|
||||
reader.FieldsPerRecord = -1 // 允许不同长度的记录
|
||||
|
||||
// 读取所有记录
|
||||
records, err := reader.ReadAll()
|
||||
if err != nil {
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
json.NewEncoder(w).Encode(map[string]string{"error": "解析威胁数据库失败"})
|
||||
logger.Error(fmt.Sprintf("解析威胁数据库文件失败:%v", err))
|
||||
return
|
||||
}
|
||||
|
||||
// 构建威胁域名映射(支持顶级域名匹配)
|
||||
threatMap := make(map[string][]string)
|
||||
for i, record := range records {
|
||||
if i == 0 {
|
||||
continue // 跳过标题行
|
||||
}
|
||||
if len(record) >= 4 {
|
||||
threatType := record[0] // 第一列:类型
|
||||
threatName := record[1] // 第二列:名称
|
||||
riskLevel := record[2] // 第三列:风险等级
|
||||
domain := record[3] // 第四列:域名
|
||||
threatInfo := []string{threatType, threatName, riskLevel}
|
||||
|
||||
// 1. 完整域名匹配(所有类型都添加)
|
||||
threatMap[domain] = threatInfo
|
||||
|
||||
// 2. 只有恶意网站类型才添加子域名匹配规则
|
||||
// 类型判断:钓鱼网站、仿冒网站
|
||||
// 逻辑:如果威胁数据库中有 sub.example.com,则所有子域名(a.sub.example.com)都应匹配
|
||||
if threatType == "钓鱼网站" || threatType == "仿冒网站" {
|
||||
// 对于恶意网站,添加子域名匹配规则
|
||||
// 例如:sub.example.com -> 添加 .sub.example.com 规则
|
||||
// 这样 a.sub.example.com 就会匹配
|
||||
topLevelDomain := "." + domain
|
||||
// 只有当该顶级域名规则不存在时才添加
|
||||
if _, exists := threatMap[topLevelDomain]; !exists {
|
||||
threatMap[topLevelDomain] = threatInfo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 查询单个域名
|
||||
var result string
|
||||
|
||||
// 1. 先检查完整匹配
|
||||
if threat, exists := threatMap[domain]; exists {
|
||||
result = fmt.Sprintf("%s,%s,%s,%s", threat[0], threat[1], threat[2], domain)
|
||||
if threatInfo != nil {
|
||||
// 从内存中的威胁数据库获取信息
|
||||
result["isThreat"] = true
|
||||
result["data"] = threatInfo
|
||||
result["threatType"] = threatInfo["type"]
|
||||
result["threatName"] = threatInfo["name"]
|
||||
result["riskLevel"] = threatInfo["riskLevel"]
|
||||
} else {
|
||||
// 2. 检查子域名匹配(遍历顶级域名规则)
|
||||
for threatDomain, threatInfo := range threatMap {
|
||||
// 只检查以点开头的顶级域名规则
|
||||
if strings.HasPrefix(threatDomain, ".") && strings.HasSuffix(domain, threatDomain) {
|
||||
// 额外验证:确保是完整的域名部分匹配
|
||||
prefix := strings.TrimSuffix(domain, threatDomain)
|
||||
if len(prefix) > 0 && !strings.HasSuffix(prefix, ".") {
|
||||
// 不是完整的子域名部分,跳过
|
||||
// 检查子域名匹配
|
||||
matched := false
|
||||
// 遍历威胁数据库查找匹配的顶级域名规则
|
||||
s.domainInfoManager.GetThreatInfo("") // 这个调用会触发遍历,需要重新实现
|
||||
|
||||
// 简单的子域名匹配逻辑
|
||||
parts := strings.Split(domain, ".")
|
||||
for i := range parts {
|
||||
if i == 0 {
|
||||
continue
|
||||
}
|
||||
|
||||
result = fmt.Sprintf("%s,%s,%s,%s", threatInfo[0], threatInfo[1], threatInfo[2], domain)
|
||||
subDomain := strings.Join(parts[i:], ".")
|
||||
threatInfo = s.domainInfoManager.GetThreatInfo(subDomain)
|
||||
if threatInfo != nil {
|
||||
result["isThreat"] = true
|
||||
result["data"] = threatInfo
|
||||
result["threatType"] = threatInfo["type"]
|
||||
result["threatName"] = threatInfo["name"]
|
||||
result["riskLevel"] = threatInfo["riskLevel"]
|
||||
result["matchedDomain"] = subDomain
|
||||
matched = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if !matched {
|
||||
result["isThreat"] = false
|
||||
}
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
if result == "" {
|
||||
// 未找到匹配的威胁信息
|
||||
json.NewEncoder(w).Encode(map[string]string{"message": "无"})
|
||||
} else {
|
||||
// 返回威胁信息
|
||||
json.NewEncoder(w).Encode(map[string]string{"data": result})
|
||||
}
|
||||
json.NewEncoder(w).Encode(result)
|
||||
}
|
||||
|
||||
// handleThreatBatch 批量查询威胁域名
|
||||
|
||||
+50
-17
@@ -12,6 +12,7 @@ import (
|
||||
"time"
|
||||
|
||||
"dns-server/logger"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
@@ -51,24 +52,43 @@ func (aqe *ArchiveQueryEngine) QueryLogs(filter LogFilter, page PageParams) ([]Q
|
||||
mainTotal = 0
|
||||
}
|
||||
|
||||
// 2. 智能优化:如果主库数据足够且是第一页,直接返回
|
||||
if page.Offset == 0 && len(mainLogs) >= page.Limit {
|
||||
return mainLogs, mainTotal, nil
|
||||
// 2. 智能优化:如果主库数据足够,直接返回
|
||||
if len(mainLogs) > page.Offset {
|
||||
// 计算主库中需要返回的数据范围
|
||||
start := page.Offset
|
||||
end := start + page.Limit
|
||||
if end > len(mainLogs) {
|
||||
end = len(mainLogs)
|
||||
}
|
||||
return mainLogs[start:end], mainTotal, nil
|
||||
}
|
||||
|
||||
// 3. 查询所有归档库
|
||||
archiveLogs, archiveTotal, err := aqe.queryArchives(filter, page)
|
||||
// 3. 计算需要从归档中获取的数据量
|
||||
// 注意:归档库查询时,offset 应该始终为 0,因为我们需要从归档的开头开始查询,然后与主库数据合并后再进行分页
|
||||
remainingLimit := page.Offset + page.Limit - len(mainLogs)
|
||||
if remainingLimit < 0 {
|
||||
remainingLimit = 0
|
||||
}
|
||||
archivePage := PageParams{
|
||||
Limit: remainingLimit,
|
||||
Offset: 0,
|
||||
SortField: page.SortField,
|
||||
SortDirection: page.SortDirection,
|
||||
}
|
||||
|
||||
// 4. 查询归档库
|
||||
archiveLogs, archiveTotal, err := aqe.queryArchives(filter, archivePage)
|
||||
if err != nil {
|
||||
logger.Error("查询归档失败", "error", err)
|
||||
archiveLogs = []QueryLog{}
|
||||
archiveTotal = 0
|
||||
}
|
||||
|
||||
// 4. 合并结果
|
||||
// 5. 合并结果
|
||||
allLogs := append(mainLogs, archiveLogs...)
|
||||
total := mainTotal + archiveTotal
|
||||
|
||||
// 5. 排序(默认按时间倒序)
|
||||
// 6. 排序(默认按时间倒序)
|
||||
if page.SortField == "" || page.SortField == "timestamp" {
|
||||
if page.SortDirection == "" || page.SortDirection == "desc" {
|
||||
sort.Slice(allLogs, func(i, j int) bool {
|
||||
@@ -81,13 +101,9 @@ func (aqe *ArchiveQueryEngine) QueryLogs(filter LogFilter, page PageParams) ([]Q
|
||||
}
|
||||
}
|
||||
|
||||
// 6. 分页
|
||||
start := page.Offset
|
||||
if start >= len(allLogs) {
|
||||
return []QueryLog{}, total, nil
|
||||
}
|
||||
|
||||
end := start + page.Limit
|
||||
// 7. 分页
|
||||
start := 0
|
||||
end := page.Limit
|
||||
if end > len(allLogs) {
|
||||
end = len(allLogs)
|
||||
}
|
||||
@@ -101,8 +117,16 @@ func (aqe *ArchiveQueryEngine) queryMainStore(filter LogFilter, page PageParams)
|
||||
return []QueryLog{}, 0, nil
|
||||
}
|
||||
|
||||
// 注意:查询主库时,不使用 offset,只使用 limit + offset,这样可以获取足够的数据与归档库数据合并后再进行分页
|
||||
mainPage := PageParams{
|
||||
Limit: page.Offset + page.Limit,
|
||||
Offset: 0,
|
||||
SortField: page.SortField,
|
||||
SortDirection: page.SortDirection,
|
||||
}
|
||||
|
||||
// 使用 SQLiteStore 的查询方法
|
||||
return aqe.mainStore.QueryLogs(filter, page)
|
||||
return aqe.mainStore.QueryLogs(filter, mainPage)
|
||||
}
|
||||
|
||||
// queryArchives 查询所有归档库
|
||||
@@ -121,15 +145,24 @@ func (aqe *ArchiveQueryEngine) queryArchives(filter LogFilter, page PageParams)
|
||||
var allLogs []QueryLog
|
||||
var totalCount int64 = 0
|
||||
|
||||
// 计算需要从归档中获取的总数据量
|
||||
requiredTotal := int64(page.Offset + page.Limit)
|
||||
|
||||
// 从新到旧遍历归档
|
||||
for _, archive := range archives {
|
||||
// 如果已经有足够的数据,提前退出
|
||||
if int64(len(allLogs)) >= int64(page.Limit) && page.Offset == 0 {
|
||||
if int64(len(allLogs)) >= requiredTotal {
|
||||
break
|
||||
}
|
||||
|
||||
// 计算当前归档需要查询的数据量
|
||||
remaining := requiredTotal - int64(len(allLogs))
|
||||
archivePage := page
|
||||
archivePage.Limit = int(remaining)
|
||||
archivePage.Offset = 0
|
||||
|
||||
// 查询单个归档
|
||||
logs, count, err := aqe.querySingleArchive(&archive, filter, page)
|
||||
logs, count, err := aqe.querySingleArchive(&archive, filter, archivePage)
|
||||
if err != nil {
|
||||
logger.Warn("查询归档失败", "file", archive.FilePath, "error", err)
|
||||
continue
|
||||
|
||||
@@ -1,662 +0,0 @@
|
||||
time="2026-04-05T02:11:56+08:00" level=debug msg="尝试加载Shield统计数据" file=/root/dnsbeta2/data/shield_stats.json
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="Shield计数数据加载成功" blocked_entries=0 resolved_entries=0
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="本地规则加载完成,域名规则: 0, 排除规则: 0, 正则规则: 0, hosts规则: 0"
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="新日志系统初始化成功" databasePath=data/query_logs.db ringBufferSize=10000
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="元数据加载完成" count=0
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="归档管理器初始化成功" archiveDir=data/archive
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="归档查询引擎初始化成功"
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="统计数据加载成功"
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="DNS服务器已启动,监听端口: 53"
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="HTTP控制台已启动,监听端口: 8081"
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="规则自动更新已启动" interval=3600
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="开始加载威胁域名数据库" path=./static/domain-info/threats/threats-database.csv
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="启动Shield计数数据自动保存功能" file=data/shield_stats.json interval=60
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="Shield计数数据保存成功" blocked_entries=0 file=/root/dnsbeta2/data/shield_stats.json resolved_entries=0
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="开始异步加载远程屏蔽规则"
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="HTTP控制台服务器启动,监听地址: 0.0.0.0:8081"
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="威胁域名数据库加载完成" count=72976
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="开始监听威胁域名数据库文件" path=./static/domain-info/threats/threats-database.csv
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="归档管理器监控启动"
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="归档监控和清理任务已启动"
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="DNS TCP服务器启动,监听端口: 53"
|
||||
time="2026-04-05T02:11:56+08:00" level=info msg="DNS UDP服务器启动,监听端口: 53"
|
||||
time="2026-04-05T02:11:56+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:49312" domain=www.baidu.com type=AAAA
|
||||
time="2026-04-05T02:11:56+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:49312" domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:11:56+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=www.baidu.com
|
||||
time="2026-04-05T02:11:56+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:57960" domain=edge.microsoft.com type=A
|
||||
time="2026-04-05T02:11:56+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:58734" domain=wpad.amazehome.xyz type=A
|
||||
time="2026-04-05T02:11:56+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:58572" domain=topdesk.com type=AAAA
|
||||
time="2026-04-05T02:11:56+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=topdesk.com
|
||||
time="2026-04-05T02:11:56+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:60997" domain=topdesk.com type=A
|
||||
time="2026-04-05T02:11:57+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:44335" domain=time.apple.com type=AAAA
|
||||
time="2026-04-05T02:11:57+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=time.apple.com
|
||||
time="2026-04-05T02:11:57+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:44335" domain=time.apple.com type=A
|
||||
time="2026-04-05T02:11:57+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:58126" domain=puds.ucweb.com type=A
|
||||
time="2026-04-05T02:11:57+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:58555" domain=pcapp-data-collect.youku.com type=A
|
||||
time="2026-04-05T02:11:57+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:50418" domain=h-adashx.ut.taobao.com type=A
|
||||
time="2026-04-05T02:11:57+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:62594" domain=tpstelemetry.tencent.com type=A
|
||||
time="2026-04-05T02:11:57+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:48563" domain=sonymusic.com type=A
|
||||
time="2026-04-05T02:11:57+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:38934" domain=sonymusic.com type=AAAA
|
||||
time="2026-04-05T02:11:57+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=sonymusic.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:45438" domain=vsco.co type=AAAA
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:47681" domain=vsco.co type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=vsco.co
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:50648" domain=fossilgroup.com type=AAAA
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=fossilgroup.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:54604" domain=fossilgroup.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:55011" domain=time.apple.com.amazehome.xyz type=AAAA
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:55011" domain=time.apple.com.amazehome.xyz type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=time.apple.com.amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=info msg="规则加载完成,域名规则: 189912, 排除规则: 654, 正则规则: 12057, hosts规则: 0"
|
||||
time="2026-04-05T02:11:58+08:00" level=info msg="远程屏蔽规则异步加载完成"
|
||||
time="2026-04-05T02:11:58+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:58126" domain=puds.ucweb.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=www.baidu.com sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=www.baidu.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=vsco.co sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=vsco.co type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=vsco.co. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:62594" domain=tpstelemetry.tencent.com
|
||||
time="2026-04-05T02:11:58+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:58555" domain=pcapp-data-collect.youku.com
|
||||
time="2026-04-05T02:11:58+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:50418" domain=h-adashx.ut.taobao.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="返回第一个成功响应" domain=www.baidu.com rtt=1.743041ms server=10.35.10.200
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=www.baidu.com response=true rtt=1.743041ms
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=www.baidu.com ttl=30m0s type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="CNAME响应已缓存" dnssec=false domain=www.a.shifen.com. ttl=30m0s type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=www.baidu.com responseCode=0 result=allowed
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=www.baidu.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=vsco.co response=false rtt=0s
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=vsco.co
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=vsco.co responseCode=0 result=error
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=vsco.co
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:58799" domain=vsco.co type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=topdesk.com sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=topdesk.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=topdesk.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=vsco.co sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=vsco.co type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=vsco.co. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:55673" domain=px.effirst.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:55673" domain=px.effirst.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=fossilgroup.com sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=fossilgroup.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=fossilgroup.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=time.apple.com sourceIP=10.35.10.29
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=time.apple.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=time.apple.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=topdesk.com response=false rtt=0s
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=topdesk.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=topdesk.com responseCode=0 result=error
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=topdesk.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:40275" domain=topdesk.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=vsco.co response=false rtt=0s
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=vsco.co
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=vsco.co responseCode=0 result=error
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=vsco.co
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=edge.microsoft.com sourceIP=10.35.10.78
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=edge.microsoft.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="域名匹配到特定DNS服务器配置" dnsServers="[10.35.10.200:53]" domain=edge.microsoft.com matchStr=microsoft.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=edge.microsoft.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=wpad.amazehome.xyz sourceIP=10.35.10.78
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=wpad.amazehome.xyz type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=wpad.amazehome.xyz pattern=amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="域名匹配到特定DNS服务器配置" dnsServers="[10.35.10.200:53]" domain=wpad.amazehome.xyz matchStr=amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=wpad.amazehome.xyz. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="所有服务器都失败,返回最后一个错误响应" domain=wpad.amazehome.xyz server="10.35.10.200:53"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=wpad.amazehome.xyz response=true rtt="546.09µs"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=fossilgroup.com response=false rtt=0s
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=fossilgroup.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=time.apple.com response=false rtt=0s
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=fossilgroup.com responseCode=0 result=error
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=fossilgroup.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=wpad.amazehome.xyz ttl=30m0s type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=wpad.amazehome.xyz responseCode=0 result=allowed
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=wpad.amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=time.apple.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=time.apple.com responseCode=0 result=error
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=time.apple.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:59390" domain=fossilgroup.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:50073" domain=pool.ntp.org type=AAAA
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=pool.ntp.org
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:50073" domain=pool.ntp.org type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=sonymusic.com sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=sonymusic.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=sonymusic.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=edge.microsoft.com response=false rtt=0s
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=edge.microsoft.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=edge.microsoft.com responseCode=0 result=error
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=edge.microsoft.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=topdesk.com sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=topdesk.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=topdesk.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=sonymusic.com response=false rtt=0s
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=sonymusic.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=sonymusic.com responseCode=0 result=error
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=sonymusic.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:43196" domain=sonymusic.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=pool.ntp.org sourceIP=10.35.10.29
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=pool.ntp.org type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=pool.ntp.org. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=topdesk.com response=false rtt=0s
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=topdesk.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=topdesk.com responseCode=0 result=error
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=topdesk.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=time.apple.com.amazehome.xyz sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=time.apple.com.amazehome.xyz type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=time.apple.com.amazehome.xyz pattern=amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="域名匹配到特定DNS服务器配置" dnsServers="[10.35.10.200:53]" domain=time.apple.com.amazehome.xyz matchStr=amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=time.apple.com.amazehome.xyz. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="所有服务器都失败,返回最后一个错误响应" domain=time.apple.com.amazehome.xyz server="10.35.10.200:53"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=time.apple.com.amazehome.xyz response=true rtt="664.963µs"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=time.apple.com.amazehome.xyz ttl=30m0s type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=time.apple.com.amazehome.xyz responseCode=0 result=allowed
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=time.apple.com.amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:55768" domain=pool.ntp.org type=AAAA
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:55768" domain=pool.ntp.org type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=pool.ntp.org
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=fossilgroup.com sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=fossilgroup.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=fossilgroup.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="返回第一个成功响应" domain=fossilgroup.com rtt="456.346µs" server=10.35.10.200
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=fossilgroup.com response=true rtt="456.346µs"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=pool.ntp.org response=false rtt=0s
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=pool.ntp.org
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=pool.ntp.org responseCode=0 result=error
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=pool.ntp.org
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=fossilgroup.com ttl=30m0s type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=fossilgroup.com responseCode=0 result=allowed
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=fossilgroup.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=sonymusic.com sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=sonymusic.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=sonymusic.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=pool.ntp.org sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=pool.ntp.org type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=pool.ntp.org. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="返回第一个成功响应" domain=sonymusic.com rtt=4.027306ms server=10.35.10.200
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=sonymusic.com response=true rtt=4.027306ms
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=sonymusic.com ttl=30m0s type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=sonymusic.com responseCode=0 result=allowed
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=sonymusic.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=pool.ntp.org response=false rtt=0s
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=pool.ntp.org
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=pool.ntp.org responseCode=0 result=error
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=pool.ntp.org
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:56074" domain=pool.ntp.org.amazehome.xyz type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:56074" domain=pool.ntp.org.amazehome.xyz type=AAAA
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=pool.ntp.org.amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=pool.ntp.org.amazehome.xyz sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=pool.ntp.org.amazehome.xyz type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=pool.ntp.org.amazehome.xyz pattern=amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="域名匹配到特定DNS服务器配置" dnsServers="[10.35.10.200:53]" domain=pool.ntp.org.amazehome.xyz matchStr=amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=pool.ntp.org.amazehome.xyz. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="所有服务器都失败,返回最后一个错误响应" domain=pool.ntp.org.amazehome.xyz server="10.35.10.200:53"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=pool.ntp.org.amazehome.xyz response=true rtt="909.456µs"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=pool.ntp.org.amazehome.xyz ttl=30m0s type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=pool.ntp.org.amazehome.xyz responseCode=0 result=allowed
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=pool.ntp.org.amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:57606" domain=www.baidu.com.amazehome.xyz type=AAAA
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:57606" domain=www.baidu.com.amazehome.xyz type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=www.baidu.com.amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=www.baidu.com.amazehome.xyz sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=www.baidu.com.amazehome.xyz type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=www.baidu.com.amazehome.xyz pattern=amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="域名匹配到特定DNS服务器配置" dnsServers="[10.35.10.200:53]" domain=www.baidu.com.amazehome.xyz matchStr=amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=www.baidu.com.amazehome.xyz. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="所有服务器都失败,返回最后一个错误响应" domain=www.baidu.com.amazehome.xyz server="10.35.10.200:53"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=www.baidu.com.amazehome.xyz response=true rtt="867.793µs"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=www.baidu.com.amazehome.xyz ttl=30m0s type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=www.baidu.com.amazehome.xyz responseCode=0 result=allowed
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=www.baidu.com.amazehome.xyz
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:55673" domain=sdkconfig.ad.xiaomi.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="威胁检测引擎检查域名" domain=sdkconfig.ad.xiaomi.com sourceIP=10.35.10.78
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="开始处理上游请求" domain=sdkconfig.ad.xiaomi.com type=A
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=sdkconfig.ad.xiaomi.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游请求返回" domain=sdkconfig.ad.xiaomi.com response=false rtt=0s
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=sdkconfig.ad.xiaomi.com
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="准备添加查询日志" domain=sdkconfig.ad.xiaomi.com responseCode=0 result=error
|
||||
time="2026-04-05T02:11:58+08:00" level=debug msg="查询日志已添加" domain=sdkconfig.ad.xiaomi.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:50322" domain=www.baidu.com type=AAAA
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=www.baidu.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:50322" domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=h-adashx.ut.taobao.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=h-adashx.ut.taobao.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=h-adashx.ut.taobao.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=h-adashx.ut.taobao.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=log.zijieapi.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=log.zijieapi.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=log.zijieapi.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=log.zijieapi.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=log.zijieapi.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=log.zijieapi.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=log.zijieapi.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=log.zijieapi.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=log.zijieapi.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=log.zijieapi.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=log.zijieapi.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=log.zijieapi.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=log.zijieapi.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=log.zijieapi.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:43377" domain=registry.cn-hangzhou.aliyuncs.com type=AAAA
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=registry.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:43377" domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="威胁检测引擎检查域名" domain=registry.cn-hangzhou.aliyuncs.com sourceIP=10.35.10.29
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="开始处理上游请求" domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=registry.cn-hangzhou.aliyuncs.com pattern=.cn
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=registry.cn-hangzhou.aliyuncs.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="上游请求返回" domain=registry.cn-hangzhou.aliyuncs.com response=false rtt=0s
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=registry.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="准备添加查询日志" domain=registry.cn-hangzhou.aliyuncs.com responseCode=0 result=error
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="查询日志已添加" domain=registry.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:34218" domain=registry.cn-hangzhou.aliyuncs.com type=AAAA
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=registry.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:11:59+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:34218" domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="威胁检测引擎检查域名" domain=registry.cn-hangzhou.aliyuncs.com sourceIP=10.35.10.29
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="开始处理上游请求" domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=registry.cn-hangzhou.aliyuncs.com pattern=.cn
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=registry.cn-hangzhou.aliyuncs.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="返回第一个成功响应" domain=registry.cn-hangzhou.aliyuncs.com rtt="733.909µs" server=10.35.10.200
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="上游请求返回" domain=registry.cn-hangzhou.aliyuncs.com response=true rtt="733.909µs"
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=registry.cn-hangzhou.aliyuncs.com ttl=30m0s type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="准备添加查询日志" domain=registry.cn-hangzhou.aliyuncs.com responseCode=0 result=allowed
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="查询日志已添加" domain=registry.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:46141" domain=dockerauth.cn-hangzhou.aliyuncs.com type=AAAA
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=dockerauth.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:46141" domain=dockerauth.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="威胁检测引擎检查域名" domain=dockerauth.cn-hangzhou.aliyuncs.com sourceIP=10.35.10.29
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="开始处理上游请求" domain=dockerauth.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=dockerauth.cn-hangzhou.aliyuncs.com pattern=.cn
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=dockerauth.cn-hangzhou.aliyuncs.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="上游请求返回" domain=dockerauth.cn-hangzhou.aliyuncs.com response=false rtt=0s
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=dockerauth.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="准备添加查询日志" domain=dockerauth.cn-hangzhou.aliyuncs.com responseCode=0 result=error
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="查询日志已添加" domain=dockerauth.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:52387" domain=dockerauth.cn-hangzhou.aliyuncs.com type=AAAA
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:52387" domain=dockerauth.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=dockerauth.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="威胁检测引擎检查域名" domain=dockerauth.cn-hangzhou.aliyuncs.com sourceIP=10.35.10.29
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="开始处理上游请求" domain=dockerauth.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=dockerauth.cn-hangzhou.aliyuncs.com pattern=.cn
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=dockerauth.cn-hangzhou.aliyuncs.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="返回第一个成功响应" domain=dockerauth.cn-hangzhou.aliyuncs.com rtt="617.302µs" server=10.35.10.200
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="上游请求返回" domain=dockerauth.cn-hangzhou.aliyuncs.com response=true rtt="617.302µs"
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=dockerauth.cn-hangzhou.aliyuncs.com ttl=30m0s type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="CNAME响应已缓存" dnssec=false domain=tyjr-cn-hangzhou.aliyun.com. ttl=30m0s type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="准备添加查询日志" domain=dockerauth.cn-hangzhou.aliyuncs.com responseCode=0 result=allowed
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="查询日志已添加" domain=dockerauth.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:36552" domain=registry.cn-hangzhou.aliyuncs.com type=AAAA
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:36552" domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=registry.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:57098" domain=registry.cn-hangzhou.aliyuncs.com type=AAAA
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:57098" domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=registry.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=h-adashx.ut.taobao.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=h-adashx.ut.taobao.com
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=h-adashx.ut.taobao.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=h-adashx.ut.taobao.com
|
||||
time="2026-04-05T02:12:00+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com type=A
|
||||
time="2026-04-05T02:12:00+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com
|
||||
time="2026-04-05T02:12:01+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:35834" domain=o1098464.ingest.sentry.io type=A
|
||||
time="2026-04-05T02:12:01+08:00" level=info msg="域名被屏蔽" client="10.35.10.70:35834" domain=o1098464.ingest.sentry.io
|
||||
time="2026-04-05T02:12:01+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:58915" domain=o1098464.ingest.sentry.io type=AAAA
|
||||
time="2026-04-05T02:12:01+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=o1098464.ingest.sentry.io
|
||||
time="2026-04-05T02:12:01+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:60750" domain=o1098464.ingest.sentry.io type=AAAA
|
||||
time="2026-04-05T02:12:01+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=o1098464.ingest.sentry.io
|
||||
time="2026-04-05T02:12:01+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:54257" domain=o1098464.ingest.sentry.io type=A
|
||||
time="2026-04-05T02:12:01+08:00" level=info msg="域名被屏蔽" client="10.35.10.70:54257" domain=o1098464.ingest.sentry.io
|
||||
time="2026-04-05T02:12:01+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com type=A
|
||||
time="2026-04-05T02:12:01+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com
|
||||
time="2026-04-05T02:12:01+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com type=A
|
||||
time="2026-04-05T02:12:01+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com
|
||||
time="2026-04-05T02:12:02+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:51182" domain=www.baidu.com type=AAAA
|
||||
time="2026-04-05T02:12:02+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=www.baidu.com
|
||||
time="2026-04-05T02:12:02+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:51182" domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:02+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:02+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com type=A
|
||||
time="2026-04-05T02:12:02+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com
|
||||
time="2026-04-05T02:12:02+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com type=A
|
||||
time="2026-04-05T02:12:02+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:51927" domain=pcapp-data-collect.youku.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:41199" domain=topdesk.com type=AAAA
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:52054" domain=topdesk.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=topdesk.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="威胁检测引擎检查域名" domain=topdesk.com sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="开始处理上游请求" domain=topdesk.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=topdesk.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="上游请求返回" domain=topdesk.com response=false rtt=0s
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=topdesk.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="准备添加查询日志" domain=topdesk.com responseCode=0 result=error
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="查询日志已添加" domain=topdesk.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:37015" domain=topdesk.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="威胁检测引擎检查域名" domain=topdesk.com sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="开始处理上游请求" domain=topdesk.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=topdesk.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="上游请求返回" domain=topdesk.com response=false rtt=0s
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=topdesk.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="准备添加查询日志" domain=topdesk.com responseCode=0 result=error
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="查询日志已添加" domain=topdesk.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:35803" domain=sonymusic.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:57103" domain=sonymusic.com type=AAAA
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=sonymusic.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=sonymusic.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:55790" domain=vsco.co type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:34632" domain=vsco.co type=AAAA
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=vsco.co
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="威胁检测引擎检查域名" domain=vsco.co sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="开始处理上游请求" domain=vsco.co type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=vsco.co. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="上游请求返回" domain=vsco.co response=false rtt=0s
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=vsco.co
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="准备添加查询日志" domain=vsco.co responseCode=0 result=error
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="查询日志已添加" domain=vsco.co
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:47650" domain=vsco.co type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="威胁检测引擎检查域名" domain=vsco.co sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="开始处理上游请求" domain=vsco.co type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=vsco.co. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="上游请求返回" domain=vsco.co response=false rtt=0s
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=vsco.co
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="准备添加查询日志" domain=vsco.co responseCode=0 result=error
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="查询日志已添加" domain=vsco.co
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:41298" domain=www.baidu.com type=AAAA
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:41298" domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=www.baidu.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51605" domain=ipv6.msftncsi.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:51927" domain=ipv6.msftncsi.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="威胁检测引擎检查域名" domain=ipv6.msftncsi.com sourceIP=10.35.10.78
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="开始处理上游请求" domain=ipv6.msftncsi.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=ipv6.msftncsi.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="威胁检测引擎检查域名" domain=ipv6.msftncsi.com sourceIP=10.35.10.78
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="开始处理上游请求" domain=ipv6.msftncsi.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=ipv6.msftncsi.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="上游请求返回" domain=ipv6.msftncsi.com response=false rtt=0s
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=ipv6.msftncsi.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="上游请求返回" domain=ipv6.msftncsi.com response=false rtt=0s
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=ipv6.msftncsi.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="准备添加查询日志" domain=ipv6.msftncsi.com responseCode=0 result=error
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="查询日志已添加" domain=ipv6.msftncsi.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="准备添加查询日志" domain=ipv6.msftncsi.com responseCode=0 result=error
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="查询日志已添加" domain=ipv6.msftncsi.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:50175" domain=pw.mediav.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:50175" domain=pw.mediav.com
|
||||
time="2026-04-05T02:12:05+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:50175" domain=pw.mediav.com type=A
|
||||
time="2026-04-05T02:12:05+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:50175" domain=pw.mediav.com
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:50175" domain=edge.microsoft.com type=A
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="威胁检测引擎检查域名" domain=edge.microsoft.com sourceIP=10.35.10.78
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="开始处理上游请求" domain=edge.microsoft.com type=A
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="域名匹配到特定DNS服务器配置" dnsServers="[10.35.10.200:53]" domain=edge.microsoft.com matchStr=microsoft.com
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=edge.microsoft.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="上游请求返回" domain=edge.microsoft.com response=false rtt=0s
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=edge.microsoft.com
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="准备添加查询日志" domain=edge.microsoft.com responseCode=0 result=error
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="查询日志已添加" domain=edge.microsoft.com
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:49006" domain=fossilgroup.com type=AAAA
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:43042" domain=fossilgroup.com type=A
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=fossilgroup.com
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=fossilgroup.com type=A
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:54905" domain=o1098464.ingest.sentry.io type=A
|
||||
time="2026-04-05T02:12:06+08:00" level=info msg="域名被屏蔽" client="10.35.10.70:54905" domain=o1098464.ingest.sentry.io
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:33302" domain=o1098464.ingest.sentry.io type=AAAA
|
||||
time="2026-04-05T02:12:06+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=o1098464.ingest.sentry.io
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:54859" domain=log.zijieapi.com type=A
|
||||
time="2026-04-05T02:12:08+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:54859" domain=log.zijieapi.com
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:54859" domain=log.zijieapi.com type=A
|
||||
time="2026-04-05T02:12:08+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:54859" domain=log.zijieapi.com
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:42052" domain=www.baidu.com type=AAAA
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:42052" domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=www.baidu.com
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:54859" domain=chinanorth3-0.in.applicationinsights.azure.cn type=A
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="威胁检测引擎检查域名" domain=chinanorth3-0.in.applicationinsights.azure.cn sourceIP=10.35.10.78
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="开始处理上游请求" domain=chinanorth3-0.in.applicationinsights.azure.cn type=A
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=chinanorth3-0.in.applicationinsights.azure.cn pattern=.cn
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=chinanorth3-0.in.applicationinsights.azure.cn. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="上游请求返回" domain=chinanorth3-0.in.applicationinsights.azure.cn response=false rtt=0s
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=chinanorth3-0.in.applicationinsights.azure.cn
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="准备添加查询日志" domain=chinanorth3-0.in.applicationinsights.azure.cn responseCode=0 result=error
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="查询日志已添加" domain=chinanorth3-0.in.applicationinsights.azure.cn
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="接收到DNS查询" client="10.35.10.39:57732" domain=horizon1.amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="威胁检测引擎检查域名" domain=horizon1.amazehome.xyz sourceIP=10.35.10.39
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="开始处理上游请求" domain=horizon1.amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=horizon1.amazehome.xyz pattern=amazehome.xyz
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="域名匹配到特定DNS服务器配置" dnsServers="[10.35.10.200:53]" domain=horizon1.amazehome.xyz matchStr=amazehome.xyz
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=horizon1.amazehome.xyz. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="返回第一个成功响应" domain=horizon1.amazehome.xyz rtt="566.02µs" server="10.35.10.200:53"
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="上游请求返回" domain=horizon1.amazehome.xyz response=true rtt="566.02µs"
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=horizon1.amazehome.xyz ttl=30m0s type=A
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="准备添加查询日志" domain=horizon1.amazehome.xyz responseCode=0 result=allowed
|
||||
time="2026-04-05T02:12:08+08:00" level=debug msg="查询日志已添加" domain=horizon1.amazehome.xyz
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:53304" domain=registry.cn-hangzhou.aliyuncs.com type=AAAA
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:53304" domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=registry.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:50420" domain=registry.cn-hangzhou.aliyuncs.com type=AAAA
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:50420" domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=registry.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:51881" domain=registry.cn-hangzhou.aliyuncs.com type=AAAA
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:51881" domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=registry.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:37858" domain=registry.cn-hangzhou.aliyuncs.com type=AAAA
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=registry.cn-hangzhou.aliyuncs.com
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.29:37858" domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:09+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=registry.cn-hangzhou.aliyuncs.com type=A
|
||||
time="2026-04-05T02:12:11+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:42775" domain=www.baidu.com type=AAAA
|
||||
time="2026-04-05T02:12:11+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=www.baidu.com
|
||||
time="2026-04-05T02:12:11+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:42775" domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:11+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:11+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:39920" domain=o1098464.ingest.sentry.io type=A
|
||||
time="2026-04-05T02:12:11+08:00" level=info msg="域名被屏蔽" client="10.35.10.70:39920" domain=o1098464.ingest.sentry.io
|
||||
time="2026-04-05T02:12:11+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:36592" domain=o1098464.ingest.sentry.io type=AAAA
|
||||
time="2026-04-05T02:12:11+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=o1098464.ingest.sentry.io
|
||||
time="2026-04-05T02:12:12+08:00" level=debug msg="接收到DNS查询" client="10.35.10.21:60582" domain=oth.eve.mdt.qq.com type=A
|
||||
time="2026-04-05T02:12:12+08:00" level=info msg="域名被屏蔽" client="10.35.10.21:60582" domain=oth.eve.mdt.qq.com
|
||||
time="2026-04-05T02:12:12+08:00" level=debug msg="接收到DNS查询" client="10.35.10.21:60582" domain=oth.eve.mdt.qq.com type=A
|
||||
time="2026-04-05T02:12:12+08:00" level=info msg="域名被屏蔽" client="10.35.10.21:60582" domain=oth.eve.mdt.qq.com
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="接收到DNS查询" client="10.35.10.39:55727" domain=DC.amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="威胁检测引擎检查域名" domain=DC.amazehome.xyz sourceIP=10.35.10.39
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="开始处理上游请求" domain=DC.amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=DC.amazehome.xyz pattern=amazehome.xyz
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="域名匹配到特定DNS服务器配置" dnsServers="[10.35.10.200:53]" domain=DC.amazehome.xyz matchStr=amazehome.xyz
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=DC.amazehome.xyz. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="返回第一个成功响应" domain=DC.amazehome.xyz rtt="805.167µs" server="10.35.10.200:53"
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="上游请求返回" domain=DC.amazehome.xyz response=true rtt="805.167µs"
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=DC.amazehome.xyz ttl=30m0s type=A
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="准备添加查询日志" domain=DC.amazehome.xyz responseCode=0 result=allowed
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="查询日志已添加" domain=DC.amazehome.xyz
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="接收到DNS查询" client="10.35.10.39:55727" domain=DC.amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=DC.amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="接收到DNS查询" client="10.35.10.39:53351" domain=amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="威胁检测引擎检查域名" domain=amazehome.xyz sourceIP=10.35.10.39
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="开始处理上游请求" domain=amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=amazehome.xyz pattern=amazehome.xyz
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="域名匹配到特定DNS服务器配置" dnsServers="[10.35.10.200:53]" domain=amazehome.xyz matchStr=amazehome.xyz
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=amazehome.xyz. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="返回第一个成功响应" domain=amazehome.xyz rtt="721.515µs" server="10.35.10.200:53"
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="上游请求返回" domain=amazehome.xyz response=true rtt="721.515µs"
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=amazehome.xyz ttl=30m0s type=A
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="准备添加查询日志" domain=amazehome.xyz responseCode=0 result=allowed
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="查询日志已添加" domain=amazehome.xyz
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="接收到DNS查询" client="10.35.10.39:53351" domain=amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:13+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:59963" domain=res-honeycomb.wpscdn.cn type=A
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="威胁检测引擎检查域名" domain=res-honeycomb.wpscdn.cn sourceIP=10.35.10.78
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="开始处理上游请求" domain=res-honeycomb.wpscdn.cn type=A
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="域名匹配到不验证DNSSEC的模式" domain=res-honeycomb.wpscdn.cn pattern=.cn
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=res-honeycomb.wpscdn.cn. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="上游请求返回" domain=res-honeycomb.wpscdn.cn response=false rtt=0s
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=res-honeycomb.wpscdn.cn
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="准备添加查询日志" domain=res-honeycomb.wpscdn.cn responseCode=0 result=error
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="查询日志已添加" domain=res-honeycomb.wpscdn.cn
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:36043" domain=www.baidu.com type=AAAA
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=www.baidu.com
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:36043" domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:14+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:33346" domain=topdesk.com type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:43044" domain=topdesk.com type=AAAA
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=topdesk.com
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="威胁检测引擎检查域名" domain=topdesk.com sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="开始处理上游请求" domain=topdesk.com type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=topdesk.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="上游请求返回" domain=topdesk.com response=false rtt=0s
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=topdesk.com
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="准备添加查询日志" domain=topdesk.com responseCode=0 result=error
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="查询日志已添加" domain=topdesk.com
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:35101" domain=topdesk.com type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="威胁检测引擎检查域名" domain=topdesk.com sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="开始处理上游请求" domain=topdesk.com type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=topdesk.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="返回第一个成功响应" domain=topdesk.com rtt=1.83092ms server=10.35.10.200
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="上游请求返回" domain=topdesk.com response=true rtt=1.83092ms
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="DNS响应已缓存" dnssec=false domain=topdesk.com ttl=30m0s type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="准备添加查询日志" domain=topdesk.com responseCode=0 result=allowed
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="查询日志已添加" domain=topdesk.com
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:50918" domain=vsco.co type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:37699" domain=vsco.co type=AAAA
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=vsco.co
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="威胁检测引擎检查域名" domain=vsco.co sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="开始处理上游请求" domain=vsco.co type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=vsco.co. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="上游请求返回" domain=vsco.co response=false rtt=0s
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=vsco.co
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="准备添加查询日志" domain=vsco.co responseCode=0 result=error
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="查询日志已添加" domain=vsco.co
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:43519" domain=vsco.co type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="威胁检测引擎检查域名" domain=vsco.co sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="开始处理上游请求" domain=vsco.co type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=vsco.co. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="上游请求返回" domain=vsco.co response=false rtt=0s
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=vsco.co
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="准备添加查询日志" domain=vsco.co responseCode=0 result=error
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="查询日志已添加" domain=vsco.co
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:54421" domain=fossilgroup.com type=AAAA
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=fossilgroup.com
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:57964" domain=fossilgroup.com type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=fossilgroup.com type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:8420" domain=sonymusic.com type=A
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:58694" domain=sonymusic.com type=AAAA
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=sonymusic.com
|
||||
time="2026-04-05T02:12:15+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=sonymusic.com type=A
|
||||
time="2026-04-05T02:12:16+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:52560" domain=ipv6.msftncsi.com type=A
|
||||
time="2026-04-05T02:12:16+08:00" level=debug msg="威胁检测引擎检查域名" domain=ipv6.msftncsi.com sourceIP=10.35.10.78
|
||||
time="2026-04-05T02:12:16+08:00" level=debug msg="开始处理上游请求" domain=ipv6.msftncsi.com type=A
|
||||
time="2026-04-05T02:12:16+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:16+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=ipv6.msftncsi.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:16+08:00" level=debug msg="上游请求返回" domain=ipv6.msftncsi.com response=false rtt=0s
|
||||
time="2026-04-05T02:12:16+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=ipv6.msftncsi.com
|
||||
time="2026-04-05T02:12:16+08:00" level=debug msg="准备添加查询日志" domain=ipv6.msftncsi.com responseCode=0 result=error
|
||||
time="2026-04-05T02:12:16+08:00" level=debug msg="查询日志已添加" domain=ipv6.msftncsi.com
|
||||
time="2026-04-05T02:12:17+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:46385" domain=o1098464.ingest.sentry.io type=A
|
||||
time="2026-04-05T02:12:17+08:00" level=info msg="域名被屏蔽" client="10.35.10.70:46385" domain=o1098464.ingest.sentry.io
|
||||
time="2026-04-05T02:12:17+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:39396" domain=o1098464.ingest.sentry.io type=AAAA
|
||||
time="2026-04-05T02:12:17+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=o1098464.ingest.sentry.io
|
||||
time="2026-04-05T02:12:17+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:35777" domain=www.baidu.com type=AAAA
|
||||
time="2026-04-05T02:12:17+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:35777" domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:17+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=www.baidu.com
|
||||
time="2026-04-05T02:12:17+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:18+08:00" level=debug msg="接收到DNS查询" client="10.35.10.21:60659" domain=oth.eve.mdt.qq.com type=A
|
||||
time="2026-04-05T02:12:18+08:00" level=info msg="域名被屏蔽" client="10.35.10.21:60659" domain=oth.eve.mdt.qq.com
|
||||
time="2026-04-05T02:12:18+08:00" level=debug msg="接收到DNS查询" client="10.35.10.21:60659" domain=oth.eve.mdt.qq.com type=A
|
||||
time="2026-04-05T02:12:18+08:00" level=info msg="域名被屏蔽" client="10.35.10.21:60659" domain=oth.eve.mdt.qq.com
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:49685" domain=time.apple.com type=AAAA
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:49685" domain=time.apple.com type=A
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=time.apple.com
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="威胁检测引擎检查域名" domain=time.apple.com sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="开始处理上游请求" domain=time.apple.com type=A
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=time.apple.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="上游请求返回" domain=time.apple.com response=false rtt=0s
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=time.apple.com
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="准备添加查询日志" domain=time.apple.com responseCode=0 result=error
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="查询日志已添加" domain=time.apple.com
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:58278" domain=time.apple.com.amazehome.xyz type=AAAA
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:58278" domain=time.apple.com.amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=time.apple.com.amazehome.xyz
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=time.apple.com.amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:33817" domain=pool.ntp.org type=AAAA
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:33817" domain=pool.ntp.org type=A
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=pool.ntp.org
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="威胁检测引擎检查域名" domain=pool.ntp.org sourceIP=10.35.10.70
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="开始处理上游请求" domain=pool.ntp.org type=A
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="使用用户配置的上游DNS服务器" servers="[10.35.10.200 106.14.121.141]"
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=pool.ntp.org. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="上游请求返回" domain=pool.ntp.org response=false rtt=0s
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=pool.ntp.org
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="准备添加查询日志" domain=pool.ntp.org responseCode=0 result=error
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="查询日志已添加" domain=pool.ntp.org
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:34559" domain=pool.ntp.org.amazehome.xyz type=AAAA
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:34559" domain=pool.ntp.org.amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=pool.ntp.org.amazehome.xyz
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=pool.ntp.org.amazehome.xyz type=A
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:64381" domain=edge.microsoft.com type=A
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="威胁检测引擎检查域名" domain=edge.microsoft.com sourceIP=10.35.10.78
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="开始处理上游请求" domain=edge.microsoft.com type=A
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="域名匹配到特定DNS服务器配置" dnsServers="[10.35.10.200:53]" domain=edge.microsoft.com matchStr=microsoft.com
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="并行查询超时设置" defaultTimeout=5ms domain=edge.microsoft.com. queryTimeout 配置=5
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="上游请求返回" domain=edge.microsoft.com response=false rtt=0s
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="上游 DNS 查询失败,返回 SERVFAIL" domain=edge.microsoft.com
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="准备添加查询日志" domain=edge.microsoft.com responseCode=0 result=error
|
||||
time="2026-04-05T02:12:19+08:00" level=debug msg="查询日志已添加" domain=edge.microsoft.com
|
||||
time="2026-04-05T02:12:20+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:53046" domain=log.zijieapi.com type=A
|
||||
time="2026-04-05T02:12:20+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:53046" domain=log.zijieapi.com
|
||||
time="2026-04-05T02:12:20+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:53046" domain=log.zijieapi.com type=A
|
||||
time="2026-04-05T02:12:20+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:53046" domain=log.zijieapi.com
|
||||
time="2026-04-05T02:12:20+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:41090" domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:20+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:20+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:41090" domain=www.baidu.com type=AAAA
|
||||
time="2026-04-05T02:12:20+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=www.baidu.com
|
||||
time="2026-04-05T02:12:22+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:45794" domain=o1098464.ingest.sentry.io type=AAAA
|
||||
time="2026-04-05T02:12:22+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:54463" domain=o1098464.ingest.sentry.io type=A
|
||||
time="2026-04-05T02:12:22+08:00" level=info msg="域名被屏蔽" client="10.35.10.70:54463" domain=o1098464.ingest.sentry.io
|
||||
time="2026-04-05T02:12:22+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=o1098464.ingest.sentry.io
|
||||
time="2026-04-05T02:12:23+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:56464" domain=www.baidu.com type=AAAA
|
||||
time="2026-04-05T02:12:23+08:00" level=debug msg="IPv6解析已禁用,返回空的成功响应" domain=www.baidu.com
|
||||
time="2026-04-05T02:12:23+08:00" level=debug msg="接收到DNS查询" client="10.35.10.70:56464" domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:23+08:00" level=debug msg="从缓存返回DNS响应" dnssec=false domain=www.baidu.com type=A
|
||||
time="2026-04-05T02:12:23+08:00" level=info msg="正在关闭服务..."
|
||||
time="2026-04-05T02:12:23+08:00" level=info msg="停止监听威胁域名数据库文件"
|
||||
time="2026-04-05T02:12:23+08:00" level=info msg="统计数据保存成功" file=/root/dnsbeta2/data/stats.json
|
||||
time="2026-04-05T02:12:23+08:00" level=info msg="DNS服务器已停止"
|
||||
time="2026-04-05T02:12:23+08:00" level=error msg="HTTP控制台服务器启动失败" error="http: Server closed"
|
||||
time="2026-04-05T02:12:23+08:00" level=info msg="HTTP控制台服务器已停止"
|
||||
time="2026-04-05T02:12:23+08:00" level=info msg="Shield计数数据保存成功" blocked_entries=0 file=/root/dnsbeta2/data/shield_stats.json resolved_entries=0
|
||||
time="2026-04-05T02:12:23+08:00" level=info msg="规则自动更新已停止"
|
||||
time="2026-04-05T02:12:23+08:00" level=info msg="服务已关闭"
|
||||
time="2026-04-05T02:12:23+08:00" level=warning msg="日志系统已关闭"
|
||||
@@ -1,23 +0,0 @@
|
||||
#!/bin/bash
|
||||
echo "=== 域名清理进度监控 ==="
|
||||
while true; do
|
||||
if [ -f /root/dns/static/domain-info/threats/threats-removed.csv ]; then
|
||||
removed=$(wc -l < /root/dns/static/domain-info/threats/threats-removed.csv)
|
||||
removed=$((removed - 1))
|
||||
else
|
||||
removed=0
|
||||
fi
|
||||
|
||||
if [ -f /root/dns/static/domain-info/threats/threats-database-cleaned.csv ]; then
|
||||
kept=$(wc -l < /root/dns/static/domain-info/threats/threats-database-cleaned.csv)
|
||||
kept=$((kept - 1))
|
||||
else
|
||||
kept=0
|
||||
fi
|
||||
|
||||
total=$((removed + kept))
|
||||
progress=$(echo "scale=2; $total * 100 / 89941" | bc)
|
||||
|
||||
echo "$(date '+%Y-%m-%d %H:%M:%S') - 已检查:$total/89941 ($progress%) | 移除:$removed | 保留:$kept"
|
||||
sleep 60
|
||||
done
|
||||
@@ -0,0 +1,756 @@
|
||||
package shield
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/csv"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"dns-server/config"
|
||||
"dns-server/logger"
|
||||
)
|
||||
|
||||
type DomainInfoManager struct {
|
||||
config *config.DomainInfoConfig
|
||||
|
||||
domainInfoMap map[string]map[string]interface{}
|
||||
threatDatabase map[string]map[string]string
|
||||
trackerMap map[string]map[string]interface{}
|
||||
|
||||
mutex sync.RWMutex
|
||||
updateCtx context.Context
|
||||
updateCancel context.CancelFunc
|
||||
updateRunning bool
|
||||
updateStatus map[string]string
|
||||
lastUpdateTime time.Time
|
||||
updateInterval time.Duration
|
||||
|
||||
cacheDir string
|
||||
statsFile string
|
||||
}
|
||||
|
||||
type DomainInfo struct {
|
||||
Domain string `json:"domain"`
|
||||
Category string `json:"category"`
|
||||
Type string `json:"type"`
|
||||
RiskLevel int `json:"riskLevel"`
|
||||
Info map[string]interface{} `json:"info,omitempty"`
|
||||
}
|
||||
|
||||
type ThreatInfo struct {
|
||||
Type string `json:"type"`
|
||||
Name string `json:"name"`
|
||||
RiskLevel int `json:"riskLevel"`
|
||||
Domain string `json:"domain"`
|
||||
}
|
||||
|
||||
type TrackerInfo struct {
|
||||
Domain string `json:"domain"`
|
||||
Category string `json:"category"`
|
||||
Tracker string `json:"tracker"`
|
||||
Info map[string]interface{} `json:"info,omitempty"`
|
||||
}
|
||||
|
||||
func NewDomainInfoManager(config *config.DomainInfoConfig) *DomainInfoManager {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
manager := &DomainInfoManager{
|
||||
config: config,
|
||||
domainInfoMap: make(map[string]map[string]interface{}),
|
||||
threatDatabase: make(map[string]map[string]string),
|
||||
trackerMap: make(map[string]map[string]interface{}),
|
||||
updateCtx: ctx,
|
||||
updateCancel: cancel,
|
||||
updateRunning: false,
|
||||
updateStatus: make(map[string]string),
|
||||
updateInterval: time.Duration(config.UpdateInterval) * time.Second,
|
||||
cacheDir: "data/domain_info_cache",
|
||||
statsFile: "data/domain_info_stats.json",
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(manager.cacheDir, 0755); err != nil {
|
||||
logger.Error("创建域名信息缓存目录失败", "error", err)
|
||||
}
|
||||
|
||||
return manager
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) Start() {
|
||||
logger.Info("启动域名信息管理器")
|
||||
|
||||
// 异步加载缓存和初始数据
|
||||
go func() {
|
||||
// 先加载统计信息
|
||||
if err := m.loadStats(); err != nil {
|
||||
logger.Info("未找到域名信息统计文件,将使用默认值")
|
||||
}
|
||||
|
||||
m.loadFromCache()
|
||||
|
||||
// 启动自动更新循环
|
||||
if m.config.EnableAutoUpdate {
|
||||
go m.autoUpdateLoop()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) Stop() {
|
||||
logger.Info("停止域名信息管理器")
|
||||
m.updateCancel()
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) autoUpdateLoop() {
|
||||
ticker := time.NewTicker(m.updateInterval)
|
||||
defer ticker.Stop()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-m.updateCtx.Done():
|
||||
return
|
||||
case <-ticker.C:
|
||||
logger.Info("开始自动更新域名信息")
|
||||
if err := m.LoadDomainInfo(); err != nil {
|
||||
logger.Error("自动更新域名信息失败", "error", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) LoadDomainInfo() error {
|
||||
// 检查是否有更新正在运行
|
||||
m.mutex.Lock()
|
||||
if m.updateRunning {
|
||||
m.mutex.Unlock()
|
||||
logger.Info("域名信息正在更新中,跳过")
|
||||
return nil
|
||||
}
|
||||
m.updateRunning = true
|
||||
m.updateStatus["overall"] = "running"
|
||||
m.mutex.Unlock()
|
||||
|
||||
defer func() {
|
||||
m.mutex.Lock()
|
||||
m.updateRunning = false
|
||||
m.updateStatus["overall"] = "completed"
|
||||
m.mutex.Unlock()
|
||||
}()
|
||||
|
||||
var wg sync.WaitGroup
|
||||
errChan := make(chan error, 3)
|
||||
|
||||
for _, entry := range m.config.DomainInfoLists {
|
||||
if !entry.Enabled {
|
||||
continue
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(entry config.DomainInfoEntry) {
|
||||
defer wg.Done()
|
||||
|
||||
// 更新状态为开始
|
||||
m.mutex.Lock()
|
||||
m.updateStatus[entry.Type] = "running"
|
||||
m.mutex.Unlock()
|
||||
|
||||
var err error
|
||||
switch entry.Type {
|
||||
case "domain-info":
|
||||
err = m.fetchRemoteDomainInfo(entry.URL)
|
||||
case "threat-database":
|
||||
err = m.fetchThreatDatabase(entry.URL)
|
||||
case "tracker":
|
||||
err = m.fetchTrackerInfo(entry.URL)
|
||||
default:
|
||||
logger.Warn("未知的域名信息类型", "type", entry.Type)
|
||||
}
|
||||
|
||||
// 更新状态为完成或失败
|
||||
m.mutex.Lock()
|
||||
if err != nil {
|
||||
m.updateStatus[entry.Type] = "failed"
|
||||
errChan <- fmt.Errorf("更新 %s 失败: %v", entry.Name, err)
|
||||
} else {
|
||||
m.updateStatus[entry.Type] = "completed"
|
||||
}
|
||||
m.mutex.Unlock()
|
||||
}(entry)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(errChan)
|
||||
|
||||
var errors []string
|
||||
for err := range errChan {
|
||||
errors = append(errors, err.Error())
|
||||
}
|
||||
|
||||
m.mutex.Lock()
|
||||
if len(errors) > 0 {
|
||||
m.lastUpdateTime = time.Now()
|
||||
m.saveToCache()
|
||||
m.mutex.Unlock()
|
||||
return fmt.Errorf("更新过程中有错误: %s", strings.Join(errors, "; "))
|
||||
}
|
||||
|
||||
m.lastUpdateTime = time.Now()
|
||||
m.saveToCache()
|
||||
m.mutex.Unlock()
|
||||
|
||||
logger.Info("域名信息更新完成",
|
||||
"domainInfoCount", len(m.domainInfoMap),
|
||||
"threatCount", len(m.threatDatabase),
|
||||
"trackerCount", len(m.trackerMap))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) fetchRemoteDomainInfo(url string) error {
|
||||
data, err := m.fetchRemoteData(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var domainInfoData map[string]interface{}
|
||||
if err := json.Unmarshal(data, &domainInfoData); err != nil {
|
||||
return fmt.Errorf("解析域名信息 JSON 失败: %v", err)
|
||||
}
|
||||
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
// 清空现有数据
|
||||
m.domainInfoMap = make(map[string]map[string]interface{})
|
||||
|
||||
// 处理嵌套的domains结构
|
||||
if domains, ok := domainInfoData["domains"].(map[string]interface{}); ok {
|
||||
for company, services := range domains {
|
||||
if servicesMap, ok := services.(map[string]interface{}); ok {
|
||||
for serviceName, serviceInfo := range servicesMap {
|
||||
if infoMap, ok := serviceInfo.(map[string]interface{}); ok {
|
||||
// 提取域名信息
|
||||
if urlStr, ok := infoMap["url"].(string); ok {
|
||||
// 从URL中提取域名
|
||||
domain := m.extractDomainFromURL(urlStr)
|
||||
if domain != "" {
|
||||
// 添加公司和服务信息
|
||||
infoMap["company"] = company
|
||||
infoMap["service"] = serviceName
|
||||
m.domainInfoMap[domain] = infoMap
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("加载域名信息", "count", len(m.domainInfoMap), "url", url)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) fetchThreatDatabase(url string) error {
|
||||
data, err := m.fetchRemoteData(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
reader := csv.NewReader(strings.NewReader(string(data)))
|
||||
records, err := reader.ReadAll()
|
||||
if err != nil {
|
||||
return fmt.Errorf("解析威胁数据库 CSV 失败: %v", err)
|
||||
}
|
||||
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
for i, record := range records {
|
||||
if i == 0 || len(record) < 4 {
|
||||
continue
|
||||
}
|
||||
|
||||
domain := strings.TrimSpace(record[3])
|
||||
if domain == "" {
|
||||
continue
|
||||
}
|
||||
|
||||
m.threatDatabase[domain] = map[string]string{
|
||||
"type": strings.TrimSpace(record[0]),
|
||||
"name": strings.TrimSpace(record[1]),
|
||||
"riskLevel": strings.TrimSpace(record[2]),
|
||||
"domain": domain,
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("加载威胁数据库", "count", len(m.threatDatabase), "url", url)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) fetchTrackerInfo(url string) error {
|
||||
data, err := m.fetchRemoteData(url)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var trackerData map[string]interface{}
|
||||
if err := json.Unmarshal(data, &trackerData); err != nil {
|
||||
return fmt.Errorf("解析跟踪器信息 JSON 失败: %v", err)
|
||||
}
|
||||
|
||||
m.mutex.Lock()
|
||||
defer m.mutex.Unlock()
|
||||
|
||||
// 清空现有数据
|
||||
m.trackerMap = make(map[string]map[string]interface{})
|
||||
|
||||
// 处理trackers字段
|
||||
if trackers, ok := trackerData["trackers"].(map[string]interface{}); ok {
|
||||
for domain, info := range trackers {
|
||||
if infoMap, ok := info.(map[string]interface{}); ok {
|
||||
m.trackerMap[domain] = infoMap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 处理trackerDomains字段
|
||||
if trackerDomains, ok := trackerData["trackerDomains"].(map[string]interface{}); ok {
|
||||
for trackerName, domains := range trackerDomains {
|
||||
if domainsList, ok := domains.([]interface{}); ok {
|
||||
for _, domain := range domainsList {
|
||||
if domainStr, ok := domain.(string); ok {
|
||||
// 为每个域名创建跟踪器信息
|
||||
if _, exists := m.trackerMap[domainStr]; !exists {
|
||||
m.trackerMap[domainStr] = map[string]interface{}{
|
||||
"tracker": trackerName,
|
||||
"domain": domainStr,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("加载跟踪器信息", "count", len(m.trackerMap), "url", url)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) fetchRemoteData(url string) ([]byte, error) {
|
||||
cacheFile := m.getCacheFilePath(url)
|
||||
|
||||
if m.shouldUpdateCache(cacheFile) {
|
||||
resp, err := http.Get(url)
|
||||
if err != nil {
|
||||
logger.Warn("从远程获取数据失败,尝试使用缓存", "url", url, "error", err)
|
||||
return m.loadFromCacheFile(cacheFile)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, fmt.Errorf("HTTP 状态码: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("读取响应失败: %v", err)
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(cacheFile, data, 0644); err != nil {
|
||||
logger.Warn("保存缓存文件失败", "error", err)
|
||||
}
|
||||
|
||||
return data, nil
|
||||
}
|
||||
|
||||
return m.loadFromCacheFile(cacheFile)
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) getCacheFilePath(url string) string {
|
||||
hash := fmt.Sprintf("%x", sha256.Sum256([]byte(url)))
|
||||
return filepath.Join(m.cacheDir, hash+".cache")
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) shouldUpdateCache(cacheFile string) bool {
|
||||
if _, err := os.Stat(cacheFile); os.IsNotExist(err) {
|
||||
return true
|
||||
}
|
||||
|
||||
fileInfo, err := os.Stat(cacheFile)
|
||||
if err != nil {
|
||||
return true
|
||||
}
|
||||
|
||||
return time.Since(fileInfo.ModTime()) > m.updateInterval
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) loadFromCacheFile(cacheFile string) ([]byte, error) {
|
||||
data, err := ioutil.ReadFile(cacheFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) saveToCache() {
|
||||
data := map[string]interface{}{
|
||||
"domainInfoMap": m.domainInfoMap,
|
||||
"threatDatabase": m.threatDatabase,
|
||||
"trackerMap": m.trackerMap,
|
||||
"lastUpdateTime": m.lastUpdateTime,
|
||||
}
|
||||
|
||||
jsonData, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
logger.Error("序列化域名信息缓存失败", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
cacheFile := filepath.Join(m.cacheDir, "all_domain_info.json")
|
||||
if err := ioutil.WriteFile(cacheFile, jsonData, 0644); err != nil {
|
||||
logger.Error("保存域名信息缓存失败", "error", err)
|
||||
}
|
||||
|
||||
// 同时保存统计信息
|
||||
m.saveStats()
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) loadFromCache() {
|
||||
cacheFile := filepath.Join(m.cacheDir, "all_domain_info.json")
|
||||
|
||||
data, err := ioutil.ReadFile(cacheFile)
|
||||
if err != nil {
|
||||
logger.Info("未找到域名信息缓存,将从远程加载")
|
||||
if err := m.LoadDomainInfo(); err != nil {
|
||||
logger.Error("初始加载域名信息失败", "error", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var cacheData map[string]interface{}
|
||||
if err := json.Unmarshal(data, &cacheData); err != nil {
|
||||
logger.Error("解析域名信息缓存失败", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
if domainInfoMap, ok := cacheData["domainInfoMap"].(map[string]interface{}); ok {
|
||||
for k, v := range domainInfoMap {
|
||||
if vm, ok := v.(map[string]interface{}); ok {
|
||||
m.domainInfoMap[k] = vm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if threatDatabase, ok := cacheData["threatDatabase"].(map[string]interface{}); ok {
|
||||
for k, v := range threatDatabase {
|
||||
if vm, ok := v.(map[string]interface{}); ok {
|
||||
strMap := make(map[string]string)
|
||||
for kk, vv := range vm {
|
||||
if vs, ok := vv.(string); ok {
|
||||
strMap[kk] = vs
|
||||
}
|
||||
}
|
||||
m.threatDatabase[k] = strMap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if trackerMap, ok := cacheData["trackerMap"].(map[string]interface{}); ok {
|
||||
for k, v := range trackerMap {
|
||||
if vm, ok := v.(map[string]interface{}); ok {
|
||||
m.trackerMap[k] = vm
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.Info("从缓存加载域名信息完成",
|
||||
"domainInfoCount", len(m.domainInfoMap),
|
||||
"threatCount", len(m.threatDatabase),
|
||||
"trackerCount", len(m.trackerMap))
|
||||
|
||||
// 从缓存加载后也保存统计信息
|
||||
m.saveStats()
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) GetDomainInfo(domain string) map[string]interface{} {
|
||||
m.mutex.RLock()
|
||||
defer m.mutex.RUnlock()
|
||||
|
||||
if info, ok := m.domainInfoMap[domain]; ok {
|
||||
return info
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) GetThreatInfo(domain string) map[string]string {
|
||||
m.mutex.RLock()
|
||||
defer m.mutex.RUnlock()
|
||||
|
||||
if info, ok := m.threatDatabase[domain]; ok {
|
||||
return info
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) GetTrackerInfo(domain string) map[string]interface{} {
|
||||
m.mutex.RLock()
|
||||
defer m.mutex.RUnlock()
|
||||
|
||||
if info, ok := m.trackerMap[domain]; ok {
|
||||
return info
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// extractDomainFromURL 从URL中提取域名
|
||||
func (m *DomainInfoManager) extractDomainFromURL(urlStr string) string {
|
||||
// 解析URL
|
||||
parsedURL, err := url.Parse(urlStr)
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
// 返回主机名
|
||||
return parsedURL.Hostname()
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) GetAllDomainInfo() map[string]interface{} {
|
||||
// 获取当前统计(只读锁)
|
||||
m.mutex.RLock()
|
||||
domainInfoCount := len(m.domainInfoMap)
|
||||
threatCount := len(m.threatDatabase)
|
||||
trackerCount := len(m.trackerMap)
|
||||
lastUpdateTime := m.lastUpdateTime
|
||||
m.mutex.RUnlock()
|
||||
|
||||
lastUpdateTimeStr := "从未更新"
|
||||
if !lastUpdateTime.IsZero() {
|
||||
lastUpdateTimeStr = lastUpdateTime.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
// 直接返回配置中的列表,并添加统计信息
|
||||
var lists []config.DomainInfoEntry
|
||||
if m.config != nil {
|
||||
lists = make([]config.DomainInfoEntry, len(m.config.DomainInfoLists))
|
||||
copy(lists, m.config.DomainInfoLists)
|
||||
|
||||
// 为每个列表添加规则数量
|
||||
for i := range lists {
|
||||
switch lists[i].Type {
|
||||
case "domain-info":
|
||||
lists[i].RuleCount = domainInfoCount
|
||||
case "threat-database":
|
||||
lists[i].RuleCount = threatCount
|
||||
case "tracker":
|
||||
lists[i].RuleCount = trackerCount
|
||||
}
|
||||
|
||||
if !lastUpdateTime.IsZero() {
|
||||
lists[i].LastUpdateTime = lastUpdateTimeStr
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lists = []config.DomainInfoEntry{}
|
||||
}
|
||||
|
||||
return map[string]interface{}{
|
||||
"lists": lists,
|
||||
"domainInfoCount": domainInfoCount,
|
||||
"threatCount": threatCount,
|
||||
"trackerCount": trackerCount,
|
||||
"lastUpdateTime": lastUpdateTimeStr,
|
||||
}
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) getRuleCount(entryType string) int {
|
||||
switch entryType {
|
||||
case "domain-info":
|
||||
return len(m.domainInfoMap)
|
||||
case "threat-database":
|
||||
return len(m.threatDatabase)
|
||||
case "tracker":
|
||||
return len(m.trackerMap)
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) UpdateDomainInfoList(entryType string) error {
|
||||
for _, entry := range m.config.DomainInfoLists {
|
||||
if entry.Type != entryType {
|
||||
continue
|
||||
}
|
||||
|
||||
m.mutex.Lock()
|
||||
switch entryType {
|
||||
case "domain-info":
|
||||
m.domainInfoMap = make(map[string]map[string]interface{})
|
||||
case "threat-database":
|
||||
m.threatDatabase = make(map[string]map[string]string)
|
||||
case "tracker":
|
||||
m.trackerMap = make(map[string]map[string]interface{})
|
||||
}
|
||||
m.mutex.Unlock()
|
||||
|
||||
switch entryType {
|
||||
case "domain-info":
|
||||
return m.fetchRemoteDomainInfo(entry.URL)
|
||||
case "threat-database":
|
||||
return m.fetchThreatDatabase(entry.URL)
|
||||
case "tracker":
|
||||
return m.fetchTrackerInfo(entry.URL)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("未找到类型为 %s 的域名信息配置", entryType)
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) AddDomainInfoList(entry config.DomainInfoEntry) error {
|
||||
m.config.DomainInfoLists = append(m.config.DomainInfoLists, entry)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *DomainInfoManager) RemoveDomainInfoList(entryType string) error {
|
||||
var newLists []config.DomainInfoEntry
|
||||
for _, entry := range m.config.DomainInfoLists {
|
||||
if entry.Type != entryType {
|
||||
newLists = append(newLists, entry)
|
||||
}
|
||||
}
|
||||
m.config.DomainInfoLists = newLists
|
||||
|
||||
m.mutex.Lock()
|
||||
switch entryType {
|
||||
case "domain-info":
|
||||
m.domainInfoMap = make(map[string]map[string]interface{})
|
||||
case "threat-database":
|
||||
m.threatDatabase = make(map[string]map[string]string)
|
||||
case "tracker":
|
||||
m.trackerMap = make(map[string]map[string]interface{})
|
||||
}
|
||||
m.mutex.Unlock()
|
||||
|
||||
m.saveToCache()
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetUpdateStatus 获取更新状态
|
||||
func (m *DomainInfoManager) GetUpdateStatus() map[string]string {
|
||||
m.mutex.RLock()
|
||||
defer m.mutex.RUnlock()
|
||||
|
||||
// 复制状态以避免并发修改
|
||||
status := make(map[string]string)
|
||||
for k, v := range m.updateStatus {
|
||||
status[k] = v
|
||||
}
|
||||
|
||||
return status
|
||||
}
|
||||
|
||||
// DomainInfoStats 域名信息统计
|
||||
type DomainInfoStats struct {
|
||||
DomainInfoCount int `json:"domainInfoCount"`
|
||||
ThreatCount int `json:"threatCount"`
|
||||
TrackerCount int `json:"trackerCount"`
|
||||
LastUpdateTime string `json:"lastUpdateTime"`
|
||||
Lists []struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
URL string `json:"url"`
|
||||
Enabled bool `json:"enabled"`
|
||||
RuleCount int `json:"ruleCount"`
|
||||
LastUpdateTime string `json:"lastUpdateTime"`
|
||||
} `json:"lists"`
|
||||
}
|
||||
|
||||
// saveStats 保存统计信息到文件
|
||||
func (m *DomainInfoManager) saveStats() {
|
||||
m.mutex.RLock()
|
||||
defer m.mutex.RUnlock()
|
||||
|
||||
stats := DomainInfoStats{
|
||||
DomainInfoCount: len(m.domainInfoMap),
|
||||
ThreatCount: len(m.threatDatabase),
|
||||
TrackerCount: len(m.trackerMap),
|
||||
}
|
||||
|
||||
if !m.lastUpdateTime.IsZero() {
|
||||
stats.LastUpdateTime = m.lastUpdateTime.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
for _, entry := range m.config.DomainInfoLists {
|
||||
listStat := struct {
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
URL string `json:"url"`
|
||||
Enabled bool `json:"enabled"`
|
||||
RuleCount int `json:"ruleCount"`
|
||||
LastUpdateTime string `json:"lastUpdateTime"`
|
||||
}{
|
||||
Name: entry.Name,
|
||||
Type: entry.Type,
|
||||
URL: entry.URL,
|
||||
Enabled: entry.Enabled,
|
||||
}
|
||||
|
||||
switch entry.Type {
|
||||
case "domain-info":
|
||||
listStat.RuleCount = len(m.domainInfoMap)
|
||||
case "threat-database":
|
||||
listStat.RuleCount = len(m.threatDatabase)
|
||||
case "tracker":
|
||||
listStat.RuleCount = len(m.trackerMap)
|
||||
}
|
||||
|
||||
if !m.lastUpdateTime.IsZero() {
|
||||
listStat.LastUpdateTime = m.lastUpdateTime.Format(time.RFC3339)
|
||||
}
|
||||
|
||||
stats.Lists = append(stats.Lists, listStat)
|
||||
}
|
||||
|
||||
jsonData, err := json.MarshalIndent(stats, "", " ")
|
||||
if err != nil {
|
||||
logger.Error("序列化域名信息统计失败", "error", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := ioutil.WriteFile(m.statsFile, jsonData, 0644); err != nil {
|
||||
logger.Error("保存域名信息统计失败", "error", err)
|
||||
}
|
||||
}
|
||||
|
||||
// loadStats 从文件加载统计信息
|
||||
func (m *DomainInfoManager) loadStats() error {
|
||||
data, err := ioutil.ReadFile(m.statsFile)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
var stats DomainInfoStats
|
||||
if err := json.Unmarshal(data, &stats); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// 更新配置中的统计信息
|
||||
for i := range m.config.DomainInfoLists {
|
||||
for _, listStat := range stats.Lists {
|
||||
if m.config.DomainInfoLists[i].Type == listStat.Type {
|
||||
m.config.DomainInfoLists[i].RuleCount = listStat.RuleCount
|
||||
m.config.DomainInfoLists[i].LastUpdateTime = listStat.LastUpdateTime
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1,176 +0,0 @@
|
||||
#!/bin/bash
|
||||
# 启动/停止/重启脚本
|
||||
|
||||
# ===================== 配置区 =====================
|
||||
# 程序路径
|
||||
AGENT_PATH="./dns-server"
|
||||
# 日志文件路径
|
||||
LOG_FILE="./server.log"
|
||||
# PID文件路径(记录进程ID)
|
||||
PID_FILE="./server.pid"
|
||||
# 启动参数(根据实际需求调整)
|
||||
START_ARGS=""
|
||||
# 工作目录
|
||||
WORK_DIR="."
|
||||
# ==================== 配置区结束 ====================
|
||||
|
||||
# 检查程序文件是否存在
|
||||
check_agent_exists() {
|
||||
if [ ! -f "${AGENT_PATH}" ]; then
|
||||
echo "错误:程序文件 ${AGENT_PATH} 不存在!"
|
||||
exit 1
|
||||
fi
|
||||
if [ ! -x "${AGENT_PATH}" ]; then
|
||||
echo "错误:程序文件 ${AGENT_PATH} 没有执行权限,正在尝试添加..."
|
||||
chmod +x "${AGENT_PATH}"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "错误:添加执行权限失败,请手动执行 chmod +x ${AGENT_PATH}"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查进程是否运行
|
||||
check_running() {
|
||||
if [ -f "${PID_FILE}" ]; then
|
||||
PID=$(cat "${PID_FILE}")
|
||||
if ps -p "${PID}" > /dev/null 2>&1; then
|
||||
return 0 # 运行中
|
||||
else
|
||||
rm -f "${PID_FILE}" # PID文件存在但进程已死,清理PID文件
|
||||
fi
|
||||
fi
|
||||
return 1 # 未运行
|
||||
}
|
||||
|
||||
# 启动程序
|
||||
start_agent() {
|
||||
if check_running; then
|
||||
echo "✅ dns-server 已在运行(PID: $(cat ${PID_FILE}))"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo "🚀 正在启动 dns-server(工作目录:${WORK_DIR})..."
|
||||
|
||||
# 新增:检查并切换工作目录
|
||||
if [ ! -d "${WORK_DIR}" ]; then
|
||||
echo "⚠️ 工作目录 ${WORK_DIR} 不存在,正在创建..."
|
||||
mkdir -p "${WORK_DIR}"
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ 创建工作目录 ${WORK_DIR} 失败!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# 切换到工作目录(关键:程序将在此目录下运行)
|
||||
cd "${WORK_DIR}" || {
|
||||
echo "❌ 切换到工作目录 ${WORK_DIR} 失败!"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# 创建日志目录
|
||||
mkdir -p "$(dirname ${LOG_FILE})"
|
||||
# 后台启动程序(注意:cd仅影响当前子进程,需在同一行执行)
|
||||
nohup "${AGENT_PATH}" ${START_ARGS} > "${LOG_FILE}" 2>&1 &
|
||||
AGENT_PID=$!
|
||||
echo "${AGENT_PID}" > "${PID_FILE}"
|
||||
|
||||
# 等待检查启动状态
|
||||
sleep 2
|
||||
if check_running; then
|
||||
echo "✅ dns-server 启动成功(PID: ${AGENT_PID},工作目录:${WORK_DIR})"
|
||||
echo "日志文件:${LOG_FILE}"
|
||||
else
|
||||
echo "❌ dns-server 启动失败!请查看日志:${LOG_FILE}"
|
||||
rm -f "${PID_FILE}"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
# 停止程序
|
||||
stop_agent() {
|
||||
if ! check_running; then
|
||||
echo "ℹ️ dns-server 未运行"
|
||||
return 0
|
||||
fi
|
||||
|
||||
PID=$(cat "${PID_FILE}")
|
||||
echo "🛑 正在停止 dns-server(PID: ${PID})..."
|
||||
# 优雅停止(先尝试TERM信号,失败则强制KILL)
|
||||
kill "${PID}" > /dev/null 2>&1
|
||||
sleep 3
|
||||
|
||||
if ps -p "${PID}" > /dev/null 2>&1; then
|
||||
echo "⚠️ 优雅停止失败,强制杀死进程..."
|
||||
kill -9 "${PID}" > /dev/null 2>&1
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# 清理PID文件
|
||||
rm -f "${PID_FILE}"
|
||||
echo "✅ dns-server 已停止"
|
||||
}
|
||||
|
||||
# 查看状态
|
||||
status_agent() {
|
||||
if check_running; then
|
||||
echo "✅ dns-server 运行中(PID: $(cat ${PID_FILE}))"
|
||||
else
|
||||
echo "ℹ️ dns-server 未运行"
|
||||
fi
|
||||
}
|
||||
|
||||
# 重启程序
|
||||
restart_agent() {
|
||||
echo "🔄 正在重启 dns-server..."
|
||||
stop_agent
|
||||
sleep 2
|
||||
start_agent
|
||||
}
|
||||
|
||||
# 帮助信息
|
||||
show_help() {
|
||||
echo "使用方法:$0 [start|stop|restart|status|help]"
|
||||
echo " start - 启动 dns-server"
|
||||
echo " stop - 停止 dns-server"
|
||||
echo " restart - 重启 dns-server"
|
||||
echo " status - 查看 dns-server 运行状态"
|
||||
echo " help - 显示帮助信息"
|
||||
}
|
||||
|
||||
# 主逻辑
|
||||
main() {
|
||||
# 检查是否为root用户(可选,根据需求调整)
|
||||
if [ "$(id -u)" -ne 0 ]; then
|
||||
echo "警告:建议使用root用户运行此脚本(当前用户:$(whoami))"
|
||||
# exit 1 # 如果强制要求root,取消注释
|
||||
fi
|
||||
|
||||
check_agent_exists
|
||||
|
||||
case "$1" in
|
||||
start)
|
||||
start_agent
|
||||
;;
|
||||
stop)
|
||||
stop_agent
|
||||
;;
|
||||
restart)
|
||||
restart_agent
|
||||
;;
|
||||
status)
|
||||
status_agent
|
||||
;;
|
||||
help|--help|-h)
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
echo "错误:无效参数 '$1'"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# 执行主逻辑
|
||||
main "$@"
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
[dns]
|
||||
port = 53
|
||||
upstreamDNS = 10.35.10.200
|
||||
dnssecUpstreamDNS = 208.67.220.220, 208.67.222.222
|
||||
saveInterval = 10
|
||||
cacheTTL = 10
|
||||
enableDNSSEC = false
|
||||
queryMode = parallel
|
||||
queryTimeout = 5000
|
||||
enableFastReturn = true
|
||||
noDNSSECDomains = amazehome.cn, addr.arpa, amazehome.xyz, .cn
|
||||
enableIPv6 = false
|
||||
cacheMode = file
|
||||
cacheSize = 100
|
||||
maxCacheTTL = 30
|
||||
minCacheTTL = 5
|
||||
domain_akamai = 10.35.10.200:53
|
||||
domain_amazehome.cn = 10.35.10.200:53
|
||||
domain_amazehome.xyz = 10.35.10.200:53
|
||||
domain_microsoft.com = 10.35.10.200:53
|
||||
domain_addr.arpa = 10.35.10.200:53
|
||||
domain_akadns = 10.35.10.200:53
|
||||
|
||||
[http]
|
||||
port = 8081
|
||||
host = 0.0.0.0
|
||||
enableAPI = true
|
||||
username = admin
|
||||
password = admin
|
||||
|
||||
[shield]
|
||||
updateInterval = 3600
|
||||
blockMethod = NXDOMAIN
|
||||
customBlockIP = 0.0.0.2
|
||||
statsSaveInterval = 60
|
||||
blacklist_AdGuard_DNS_filter = https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/filter.txt,true
|
||||
blacklist_Adaway_Default_Blocklist = https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-Filters/raw/branch/main/hosts/adaway.txt,true
|
||||
blacklist_CHN_anti_AD = https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-Filters/raw/branch/main/list/easylist.txt,true
|
||||
blacklist_My_GitHub_Rules = https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/rules/costomize.txt,true
|
||||
blacklist_CNList = https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/list/china.list,false
|
||||
blacklist_大圣净化 = http://gitea.amazehome.xyz/AMAZEHOME/hosts-and-Filters/raw/branch/main/hosts/dsjh.txt,true
|
||||
blacklist_Hate_and_Junk = http://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/hate-and-junk-extended.txt,true
|
||||
blacklist_My_Gitlab_Hosts = http://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/hosts/costomize.txt,true
|
||||
blacklist_Anti_Remote_Requests = http://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/hosts/anti-remoterequests.txt,true
|
||||
blacklist_URL_Based = http://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/rules/url-based-adguard.txt,true
|
||||
blacklist_My_Gitlab_A_T_Rules = http://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/rules/ads-and-trackers.txt,true
|
||||
blacklist_My_Gitlab_Malware_List = http://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/rules/malware.txt,true
|
||||
blacklist_hosts = http://gitea.amazehome.xyz/AMAZEHOME/hosts-and-Filters/raw/branch/main/hosts/costomize.txt,true
|
||||
blacklist_AWAvenue_Ads_Rule = http://gitea.amazehome.xyz/AMAZEHOME/hosts-and-Filters/raw/branch/main/rules/AWAvenue-Ads-Rule.txt,true
|
||||
blacklist_诈骗域名 = https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/rules/cheat.txt,true
|
||||
|
||||
[domainInfo]
|
||||
updateInterval = 3600
|
||||
enableAutoUpdate = true
|
||||
domainInfo_域名信息列表 = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/raw/branch/main/domains/domain-info.json,domain-info,true
|
||||
domainInfo_威胁数据库 = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/src/branch/main/threats/threats-database.csv,threat-database,true
|
||||
domainInfo_跟踪器列表 = https://gitea.amazehome.xyz/AMAZEHOME/domain-info/raw/branch/main/tracker/trackers.json,tracker,true
|
||||
|
||||
[gfwList]
|
||||
ip = 127.0.0.1
|
||||
content =
|
||||
enabled = false
|
||||
|
||||
[log]
|
||||
level = debug
|
||||
maxSize = 100
|
||||
maxBackups = 10
|
||||
maxAge = 30
|
||||
|
||||
[queryLog]
|
||||
# 基本配置
|
||||
enabled = true
|
||||
ringBufferSize = 10000
|
||||
|
||||
# SQLite 主库配置
|
||||
databasePath = data/query_logs.db
|
||||
maxDatabaseSizeMB = 1024
|
||||
enableWAL = true
|
||||
|
||||
# 归档配置
|
||||
archiveEnabled = true
|
||||
archiveDir = data/archive
|
||||
archivePrefix = querylog
|
||||
compressionLevel = 6
|
||||
|
||||
# 清理配置
|
||||
retentionDays = 0
|
||||
retentionMonths = 0
|
||||
|
||||
# 查询配置
|
||||
queryTimeout = 5
|
||||
enableCache = true
|
||||
cacheTTL = 300
|
||||
|
||||
[threat]
|
||||
enabled = true
|
||||
queryRateThreshold = 0
|
||||
nxDomainThreshold = 0
|
||||
maxDomainLength = 0
|
||||
suspiciousPatterns = malware,phishing,trojan,virus,ransomware
|
||||
unusualQueryTypes = TXT,SRV,MX
|
||||
alertRetentionDays = 0
|
||||
threatDatabasePath = ./static/domain-info/threats/threats-database.csv
|
||||
Executable
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+173
-4
@@ -47,6 +47,13 @@
|
||||
<span>屏蔽管理</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#domain-info"
|
||||
class="flex items-center px-4 py-3 text-gray-700 hover:bg-gray-100 rounded-md transition-all">
|
||||
<i class="fa fa-database mr-3 text-lg"></i>
|
||||
<span>域名信息管理</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#hosts"
|
||||
class="flex items-center px-4 py-3 text-gray-700 hover:bg-gray-100 rounded-md transition-all">
|
||||
@@ -146,6 +153,13 @@
|
||||
<span>屏蔽管理</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#domain-info"
|
||||
class="flex items-center px-4 py-3 text-gray-700 hover:bg-gray-100 rounded-md transition-all">
|
||||
<i class="fa fa-database mr-3 text-lg"></i>
|
||||
<span>域名信息管理</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="#hosts"
|
||||
class="flex items-center px-4 py-3 text-gray-700 hover:bg-gray-100 rounded-md transition-all">
|
||||
@@ -730,6 +744,164 @@
|
||||
|
||||
|
||||
|
||||
<!-- 添加域名信息列表模态框 -->
|
||||
<div id="add-domain-info-modal" class="fixed inset-0 bg-black/50 flex items-center justify-center z-50 hidden">
|
||||
<div class="bg-white rounded-lg w-full max-w-md p-6">
|
||||
<div class="flex items-center justify-between mb-4">
|
||||
<h3 class="text-lg font-semibold">添加域名信息列表</h3>
|
||||
<button onclick="window.domainInfo.hideAddListModal()"
|
||||
class="p-2 rounded-full hover:bg-gray-100 transition-colors">
|
||||
<i class="fa fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
<form id="add-domain-info-form">
|
||||
<div class="space-y-4">
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">名称</label>
|
||||
<input type="text" id="list-name" required
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">URL</label>
|
||||
<input type="url" id="list-url" required
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-sm font-medium text-gray-700 mb-1">类型</label>
|
||||
<select id="list-type" required
|
||||
class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
|
||||
<option value="domain-info">域名信息</option>
|
||||
<option value="threat-database">威胁数据库</option>
|
||||
<option value="tracker">跟踪器</option>
|
||||
</select>
|
||||
</div>
|
||||
<div>
|
||||
<label class="flex items-center space-x-2">
|
||||
<input type="checkbox" id="list-enabled" checked
|
||||
class="rounded border-gray-300 text-primary focus:ring-primary">
|
||||
<span class="text-sm text-gray-700">启用</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-6 flex space-x-3">
|
||||
<button type="button" onclick="window.domainInfo.hideAddListModal()"
|
||||
class="px-4 py-2 border border-gray-300 rounded-md hover:bg-gray-50 transition-colors text-sm flex-1">
|
||||
取消
|
||||
</button>
|
||||
<button type="submit"
|
||||
class="px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors text-sm flex-1">
|
||||
添加
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 域名信息管理页面内容(初始隐藏) -->
|
||||
<div id="domain-info-content" class="hidden space-y-6">
|
||||
<!-- 域名信息统计卡片 -->
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 gap-4 sm:gap-6">
|
||||
<!-- 域名信息数量卡片 -->
|
||||
<div class="bg-blue-50 rounded-lg p-3 sm:p-4 card-shadow relative overflow-hidden transition-all hover:shadow-md">
|
||||
<div class="absolute -bottom-6 -right-6 w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-primary opacity-10"></div>
|
||||
<div class="relative z-10">
|
||||
<div class="flex items-center justify-between mb-3 sm:mb-4">
|
||||
<h3 class="text-xs sm:text-sm text-gray-500 font-medium">域名信息数量</h3>
|
||||
<div class="p-1.5 sm:p-2 rounded-full bg-primary/10 text-primary">
|
||||
<i class="fa fa-database text-xs sm:text-sm"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div class="flex items-end justify-between">
|
||||
<p class="text-2xl sm:text-3xl font-bold" id="domain-info-count">0</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 威胁域名数量卡片 -->
|
||||
<div class="bg-red-50 rounded-lg p-3 sm:p-4 card-shadow relative overflow-hidden transition-all hover:shadow-md">
|
||||
<div class="absolute -bottom-6 -right-6 w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-danger opacity-10"></div>
|
||||
<div class="relative z-10">
|
||||
<div class="flex items-center justify-between mb-3 sm:mb-4">
|
||||
<h3 class="text-xs sm:text-sm text-gray-500 font-medium">威胁域名数量</h3>
|
||||
<div class="p-1.5 sm:p-2 rounded-full bg-danger/10 text-danger">
|
||||
<i class="fa fa-exclamation-triangle text-xs sm:text-sm"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div class="flex items-end justify-between">
|
||||
<p class="text-2xl sm:text-3xl font-bold" id="threat-count">0</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 跟踪器数量卡片 -->
|
||||
<div class="bg-purple-50 rounded-lg p-3 sm:p-4 card-shadow relative overflow-hidden transition-all hover:shadow-md">
|
||||
<div class="absolute -bottom-6 -right-6 w-20 h-20 sm:w-24 sm:h-24 rounded-full bg-purple-500 opacity-10"></div>
|
||||
<div class="relative z-10">
|
||||
<div class="flex items-center justify-between mb-3 sm:mb-4">
|
||||
<h3 class="text-xs sm:text-sm text-gray-500 font-medium">跟踪器数量</h3>
|
||||
<div class="p-1.5 sm:p-2 rounded-full bg-purple-500/10 text-purple-500">
|
||||
<i class="fa fa-bullseye text-xs sm:text-sm"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<div class="flex items-end justify-between">
|
||||
<p class="text-2xl sm:text-3xl font-bold" id="tracker-count">0</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 域名信息列表管理 -->
|
||||
<div class="bg-white rounded-lg p-4 sm:p-6 card-shadow">
|
||||
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between mb-4 sm:mb-6">
|
||||
<h3 class="text-base sm:text-lg font-semibold mb-3 sm:mb-0">远程域名信息列表</h3>
|
||||
<div class="flex space-x-2 sm:space-x-3">
|
||||
<button onclick="window.domainInfo.updateAllDomainInfo()"
|
||||
class="px-3 sm:px-4 py-2 bg-primary text-white rounded-md hover:bg-primary/90 transition-colors text-sm flex items-center">
|
||||
<i class="fa fa-refresh mr-2"></i>
|
||||
更新所有列表
|
||||
</button>
|
||||
<button onclick="window.domainInfo.showAddListModal()"
|
||||
class="px-3 sm:px-4 py-2 bg-green-500 text-white rounded-md hover:bg-green-600 transition-colors text-sm flex items-center">
|
||||
<i class="fa fa-plus mr-2"></i>
|
||||
添加列表
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 最后更新时间 -->
|
||||
<div class="mb-4 text-sm text-gray-500">
|
||||
<i class="fa fa-clock-o mr-2"></i>
|
||||
最后更新时间:<span id="last-update-time">从未更新</span>
|
||||
</div>
|
||||
|
||||
<!-- 域名信息列表表格 -->
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full divide-y divide-gray-200">
|
||||
<thead class="bg-gray-50">
|
||||
<tr>
|
||||
<th class="px-3 sm:px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">名称</th>
|
||||
<th class="px-3 sm:px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">状态</th>
|
||||
<th class="px-3 sm:px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">类型</th>
|
||||
<th class="px-3 sm:px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">规则数量</th>
|
||||
<th class="px-3 sm:px-4 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">最后更新</th>
|
||||
<th class="px-3 sm:px-4 py-3 text-center text-xs font-medium text-gray-500 uppercase tracking-wider">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="domain-info-lists-table-body" class="bg-white divide-y divide-gray-200">
|
||||
<!-- 动态生成 -->
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<!-- 威胁告警页面内容(初始隐藏) -->
|
||||
<div id="threats-content" class="hidden space-y-6">
|
||||
<!-- 威胁统计卡片 -->
|
||||
@@ -2219,16 +2391,13 @@
|
||||
<script src="js/api.js"></script>
|
||||
<script src="js/dashboard.js"></script>
|
||||
<script src="js/shield.js"></script>
|
||||
<script src="js/modules/domain-info.js"></script>
|
||||
<script src="js/hosts.js"></script>
|
||||
<script src="js/query.js"></script>
|
||||
<script src="js/logs.js"></script>
|
||||
<script src="js/config.js"></script>
|
||||
<script src="js/about.js"></script>
|
||||
|
||||
<!-- 直接渲染滚动列表的静态HTML内容 -->
|
||||
|
||||
<script src="js/whois.js"></script>
|
||||
<!-- 威胁告警页面脚本 -->
|
||||
<script src="js/threats.js"></script>
|
||||
</body>
|
||||
|
||||
|
||||
@@ -0,0 +1,374 @@
|
||||
// 域名信息管理模块
|
||||
// 用于管理远程域名信息列表的加载、更新和显示
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// 域名信息列表缓存
|
||||
let domainInfoCache = null;
|
||||
let cacheTimestamp = 0;
|
||||
const CACHE_DURATION = 5 * 60 * 1000; // 5 分钟缓存
|
||||
|
||||
/**
|
||||
* 加载域名信息列表
|
||||
*/
|
||||
function loadDomainInfoLists() {
|
||||
const tbody = document.getElementById('domain-info-lists-table-body');
|
||||
if (!tbody) {
|
||||
console.warn('未找到域名信息列表表格元素');
|
||||
return;
|
||||
}
|
||||
|
||||
showLoading(tbody);
|
||||
|
||||
// 检查缓存
|
||||
if (domainInfoCache && (Date.now() - cacheTimestamp) < CACHE_DURATION) {
|
||||
console.log('使用缓存的域名信息列表');
|
||||
renderDomainInfoLists(domainInfoCache);
|
||||
return;
|
||||
}
|
||||
|
||||
apiRequest('/api/domain-info')
|
||||
.then(data => {
|
||||
domainInfoCache = data;
|
||||
cacheTimestamp = Date.now();
|
||||
renderDomainInfoLists(data);
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('获取域名信息列表失败:', error);
|
||||
showError(tbody, '获取域名信息列表失败');
|
||||
window.showNotification('获取域名信息列表失败', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染域名信息列表
|
||||
*/
|
||||
function renderDomainInfoLists(data) {
|
||||
const tbody = document.getElementById('domain-info-lists-table-body');
|
||||
if (!tbody) return;
|
||||
|
||||
tbody.innerHTML = '';
|
||||
|
||||
if (!data || !data.lists || data.lists.length === 0) {
|
||||
const emptyRow = document.createElement('tr');
|
||||
emptyRow.innerHTML = '<td colspan="6" class="py-4 text-center text-gray-500">暂无域名信息列表</td>';
|
||||
tbody.appendChild(emptyRow);
|
||||
return;
|
||||
}
|
||||
|
||||
const fragment = document.createDocumentFragment();
|
||||
|
||||
data.lists.forEach((list, index) => {
|
||||
const tr = document.createElement('tr');
|
||||
tr.className = 'border-b border-gray-200 hover:bg-gray-50';
|
||||
|
||||
const typeLabel = getTypeLabel(list.type);
|
||||
const statusClass = list.enabled ? 'bg-green-100 text-green-800' : 'bg-gray-100 text-gray-800';
|
||||
const statusText = list.enabled ? '启用' : '禁用';
|
||||
|
||||
tr.innerHTML = `
|
||||
<td class="py-3 px-4 font-medium">${escapeHtml(list.name)}</td>
|
||||
<td class="py-3 px-4">
|
||||
<span class="px-2 py-1 rounded-full text-xs font-medium ${statusClass}">${statusText}</span>
|
||||
</td>
|
||||
<td class="py-3 px-4">
|
||||
<span class="px-2 py-1 rounded-full text-xs font-medium bg-blue-100 text-blue-800">${typeLabel}</span>
|
||||
</td>
|
||||
<td class="py-3 px-4 text-center">${list.ruleCount || 0}</td>
|
||||
<td class="py-3 px-4 text-sm text-gray-600">${formatLastUpdateTime(list.lastUpdateTime)}</td>
|
||||
<td class="py-3 px-4 text-center">
|
||||
<div class="flex space-x-2 justify-center">
|
||||
<button onclick="window.domainInfo.updateDomainInfo('${list.type}')"
|
||||
class="px-3 py-1 bg-blue-500 text-white rounded hover:bg-blue-600 text-sm"
|
||||
title="更新此列表">
|
||||
更新
|
||||
</button>
|
||||
<button onclick="window.domainInfo.removeDomainInfo('${list.type}')"
|
||||
class="px-3 py-1 bg-red-500 text-white rounded hover:bg-red-600 text-sm"
|
||||
title="删除此列表">
|
||||
删除
|
||||
</button>
|
||||
</div>
|
||||
</td>
|
||||
`;
|
||||
|
||||
fragment.appendChild(tr);
|
||||
});
|
||||
|
||||
tbody.appendChild(fragment);
|
||||
|
||||
// 更新统计信息
|
||||
updateDomainInfoStats(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新域名信息统计
|
||||
*/
|
||||
function updateDomainInfoStats(data) {
|
||||
if (document.getElementById('domain-info-count')) {
|
||||
document.getElementById('domain-info-count').textContent = data.domainInfoCount || 0;
|
||||
}
|
||||
if (document.getElementById('threat-count')) {
|
||||
document.getElementById('threat-count').textContent = data.threatCount || 0;
|
||||
}
|
||||
if (document.getElementById('tracker-count')) {
|
||||
document.getElementById('tracker-count').textContent = data.trackerCount || 0;
|
||||
}
|
||||
if (document.getElementById('last-update-time')) {
|
||||
document.getElementById('last-update-time').textContent = formatLastUpdateTime(data.lastUpdateTime);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新域名信息
|
||||
*/
|
||||
function updateDomainInfo(type) {
|
||||
const url = `/api/domain-info/update/${encodeURIComponent(type)}`;
|
||||
|
||||
apiRequest(url, 'POST')
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
window.showNotification(`域名信息更新任务已启动:${getTypeLabel(type)}`, 'success');
|
||||
// 延迟刷新列表
|
||||
setTimeout(() => {
|
||||
loadDomainInfoLists();
|
||||
}, 2000);
|
||||
} else {
|
||||
window.showNotification(`更新失败:${data.message || '未知错误'}`, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('更新域名信息失败:', error);
|
||||
window.showNotification('更新域名信息失败', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新所有域名信息
|
||||
*/
|
||||
function updateAllDomainInfo() {
|
||||
if (!confirm('确定要更新所有域名信息吗?这可能需要一些时间。')) {
|
||||
return;
|
||||
}
|
||||
|
||||
apiRequest('/api/domain-info/update', 'POST')
|
||||
.then(data => {
|
||||
if (data.status === 'success') {
|
||||
window.showNotification('所有域名信息更新任务已启动', 'success');
|
||||
setTimeout(() => {
|
||||
loadDomainInfoLists();
|
||||
}, 2000);
|
||||
} else {
|
||||
window.showNotification(`更新失败:${data.message || '未知错误'}`, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('更新所有域名信息失败:', error);
|
||||
window.showNotification('更新所有域名信息失败', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取类型标签
|
||||
*/
|
||||
function getTypeLabel(type) {
|
||||
const labels = {
|
||||
'domain-info': '域名信息',
|
||||
'threat-database': '威胁数据库',
|
||||
'tracker': '跟踪器'
|
||||
};
|
||||
return labels[type] || type;
|
||||
}
|
||||
|
||||
/**
|
||||
* 格式化最后更新时间
|
||||
*/
|
||||
function formatLastUpdateTime(timeStr) {
|
||||
if (!timeStr) return '从未更新';
|
||||
const date = new Date(timeStr);
|
||||
const now = new Date();
|
||||
const diff = now - date;
|
||||
|
||||
const minutes = Math.floor(diff / 60000);
|
||||
const hours = Math.floor(diff / 3600000);
|
||||
const days = Math.floor(diff / 86400000);
|
||||
|
||||
if (minutes < 1) return '刚刚';
|
||||
if (minutes < 60) return `${minutes}分钟前`;
|
||||
if (hours < 24) return `${hours}小时前`;
|
||||
if (days < 30) return `${days}天前`;
|
||||
|
||||
return date.toLocaleDateString('zh-CN');
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示加载状态
|
||||
*/
|
||||
function showLoading(container) {
|
||||
container.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="6" class="py-8 text-center">
|
||||
<div class="flex items-center justify-center">
|
||||
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
|
||||
<span class="ml-3 text-gray-600">加载中...</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示错误状态
|
||||
*/
|
||||
function showError(container, message) {
|
||||
container.innerHTML = `
|
||||
<tr>
|
||||
<td colspan="6" class="py-8 text-center text-red-500">
|
||||
<svg class="w-12 h-12 mx-auto mb-3" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4m0 4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
|
||||
</svg>
|
||||
${escapeHtml(message)}
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* HTML 转义
|
||||
*/
|
||||
function escapeHtml(text) {
|
||||
const div = document.createElement('div');
|
||||
div.textContent = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
/**
|
||||
* API 请求封装
|
||||
*/
|
||||
function apiRequest(url, method = 'GET', data = null) {
|
||||
const options = {
|
||||
method: method,
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
credentials: 'same-origin' // 添加认证信息
|
||||
};
|
||||
|
||||
if (data && method !== 'GET') {
|
||||
options.body = JSON.stringify(data);
|
||||
}
|
||||
|
||||
return fetch(url, options)
|
||||
.then(response => {
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
||||
}
|
||||
return response.json();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 显示添加列表模态框
|
||||
*/
|
||||
function showAddListModal() {
|
||||
const modal = document.getElementById('add-domain-info-modal');
|
||||
if (modal) {
|
||||
modal.classList.remove('hidden');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 隐藏添加列表模态框
|
||||
*/
|
||||
function hideAddListModal() {
|
||||
const modal = document.getElementById('add-domain-info-modal');
|
||||
if (modal) {
|
||||
modal.classList.add('hidden');
|
||||
// 重置表单
|
||||
document.getElementById('add-domain-info-form').reset();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加域名信息列表
|
||||
*/
|
||||
function addDomainInfo(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const name = document.getElementById('list-name').value.trim();
|
||||
const url = document.getElementById('list-url').value.trim();
|
||||
const type = document.getElementById('list-type').value;
|
||||
const enabled = document.getElementById('list-enabled').checked;
|
||||
|
||||
if (!name || !url) {
|
||||
window.showNotification('请填写名称和URL', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
const data = {
|
||||
name: name,
|
||||
url: url,
|
||||
type: type,
|
||||
enabled: enabled
|
||||
};
|
||||
|
||||
apiRequest('/api/domain-info/add', 'POST', data)
|
||||
.then(response => {
|
||||
if (response.status === 'success') {
|
||||
window.showNotification('域名信息列表添加成功', 'success');
|
||||
hideAddListModal();
|
||||
loadDomainInfoLists();
|
||||
} else {
|
||||
window.showNotification(`添加失败:${response.message || '未知错误'}`, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('添加域名信息列表失败:', error);
|
||||
window.showNotification('添加域名信息列表失败', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除域名信息列表
|
||||
*/
|
||||
function removeDomainInfo(type) {
|
||||
if (!confirm('确定要删除此域名信息列表吗?此操作不可恢复。')) {
|
||||
return;
|
||||
}
|
||||
|
||||
apiRequest(`/api/domain-info/remove/${encodeURIComponent(type)}`, 'POST')
|
||||
.then(response => {
|
||||
if (response.status === 'success') {
|
||||
window.showNotification('域名信息列表删除成功', 'success');
|
||||
loadDomainInfoLists();
|
||||
} else {
|
||||
window.showNotification(`删除失败:${response.message || '未知错误'}`, 'error');
|
||||
}
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('删除域名信息列表失败:', error);
|
||||
window.showNotification('删除域名信息列表失败', 'error');
|
||||
});
|
||||
}
|
||||
|
||||
// 绑定添加列表表单提交事件
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const form = document.getElementById('add-domain-info-form');
|
||||
if (form) {
|
||||
form.addEventListener('submit', addDomainInfo);
|
||||
}
|
||||
});
|
||||
|
||||
// 暴露到全局命名空间
|
||||
window.domainInfo = {
|
||||
loadDomainInfoLists,
|
||||
updateDomainInfo,
|
||||
updateAllDomainInfo,
|
||||
renderDomainInfoLists,
|
||||
showAddListModal,
|
||||
hideAddListModal,
|
||||
removeDomainInfo
|
||||
};
|
||||
|
||||
})();
|
||||
@@ -1481,3 +1481,152 @@ document.addEventListener('DOMContentLoaded', () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
// ========== 域名信息管理相关功能 ==========
|
||||
|
||||
// 加载远程域名信息列表
|
||||
async function loadRemoteDomainInfoLists() {
|
||||
// 检查是否有有效的缓存数据
|
||||
const cachedDomainInfo = window.pageDataCache && window.pageDataCache.getCache('domain_info_lists');
|
||||
if (cachedDomainInfo) {
|
||||
console.log('使用缓存的域名信息列表');
|
||||
updateDomainInfoListsTable(cachedDomainInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/domain-info');
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`加载失败:${response.status}`);
|
||||
}
|
||||
|
||||
const domainInfo = await response.json();
|
||||
|
||||
// 更新域名信息列表 UI
|
||||
updateDomainInfoListsTable(domainInfo);
|
||||
|
||||
// 存储数据到缓存
|
||||
if (window.pageDataCache) {
|
||||
window.pageDataCache.setCache('domain_info_lists', domainInfo);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载域名信息列表失败:', error);
|
||||
showNotification('加载域名信息列表失败', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 更新域名信息列表表格
|
||||
function updateDomainInfoListsTable(data) {
|
||||
if (!data) return;
|
||||
|
||||
// 更新统计信息
|
||||
if (document.getElementById('domain-info-count')) {
|
||||
document.getElementById('domain-info-count').textContent = data.domainInfoCount || 0;
|
||||
}
|
||||
if (document.getElementById('threat-count')) {
|
||||
document.getElementById('threat-count').textContent = data.threatCount || 0;
|
||||
}
|
||||
if (document.getElementById('tracker-count')) {
|
||||
document.getElementById('tracker-count').textContent = data.trackerCount || 0;
|
||||
}
|
||||
|
||||
// 渲染列表(如果页面有表格元素)
|
||||
if (window.domainInfo && typeof window.domainInfo.renderDomainInfoLists === 'function') {
|
||||
window.domainInfo.renderDomainInfoLists(data);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新所有域名信息
|
||||
async function updateAllDomainInfo() {
|
||||
if (!confirm('确定要更新所有域名信息吗?这可能需要一些时间。')) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await fetch('/api/domain-info/update', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`更新失败:${response.status}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'success') {
|
||||
showNotification('所有域名信息更新任务已启动', 'success');
|
||||
// 清除缓存
|
||||
if (window.pageDataCache) {
|
||||
window.pageDataCache.clearCache('domain_info_lists');
|
||||
}
|
||||
// 延迟刷新
|
||||
setTimeout(() => {
|
||||
loadRemoteDomainInfoLists();
|
||||
}, 2000);
|
||||
} else {
|
||||
showNotification(`更新失败:${result.message || '未知错误'}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('更新所有域名信息失败:', error);
|
||||
showNotification('更新所有域名信息失败', 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 更新指定类型的域名信息
|
||||
async function updateDomainInfoByType(type) {
|
||||
const typeLabels = {
|
||||
'domain-info': '域名信息',
|
||||
'threat-database': '威胁数据库',
|
||||
'tracker': '跟踪器'
|
||||
};
|
||||
|
||||
const typeName = typeLabels[type] || type;
|
||||
|
||||
try {
|
||||
const response = await fetch(`/api/domain-info/update/${encodeURIComponent(type)}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`更新失败:${response.status}`);
|
||||
}
|
||||
|
||||
const result = await response.json();
|
||||
|
||||
if (result.status === 'success') {
|
||||
showNotification(`${typeName}更新任务已启动`, 'success');
|
||||
// 清除缓存
|
||||
if (window.pageDataCache) {
|
||||
window.pageDataCache.clearCache('domain_info_lists');
|
||||
}
|
||||
// 延迟刷新
|
||||
setTimeout(() => {
|
||||
loadRemoteDomainInfoLists();
|
||||
}, 2000);
|
||||
} else {
|
||||
showNotification(`更新失败:${result.message || '未知错误'}`, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(`更新${typeName}失败:`, error);
|
||||
showNotification(`更新${typeName}失败`, 'error');
|
||||
}
|
||||
}
|
||||
|
||||
// 在 initShieldPage 中添加域名信息列表加载(如果页面存在相关元素)
|
||||
const originalInitShieldPage = window.initShieldPage;
|
||||
window.initShieldPage = async function() {
|
||||
if (originalInitShieldPage) {
|
||||
await originalInitShieldPage();
|
||||
}
|
||||
|
||||
// 如果页面有域名信息管理相关元素,则加载
|
||||
if (document.getElementById('domain-info-lists-table-body')) {
|
||||
await loadRemoteDomainInfoLists();
|
||||
}
|
||||
};
|
||||
|
||||
-25333
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user