增加数据持久化功能

This commit is contained in:
Alex Yang
2025-11-23 19:07:59 +08:00
parent 63a95f7463
commit f5911af449
8 changed files with 519 additions and 16 deletions

View File

@@ -5,11 +5,13 @@ import (
"io/ioutil" "io/ioutil"
) )
// DNSConfig DNS服务器配置 // DNSConfig DNS配置
type DNSConfig struct { type DNSConfig struct {
Port int `json:"port"` Port int `json:"port"`
UpstreamDNS []string `json:"upstreamDNS"` UpstreamDNS []string `json:"upstreamDNS"`
Timeout int `json:"timeout"` Timeout int `json:"timeout"`
StatsFile string `json:"statsFile"` // 统计数据持久化文件
SaveInterval int `json:"saveInterval"` // 数据保存间隔(秒)
} }
// HTTPConfig HTTP控制台配置 // HTTPConfig HTTP控制台配置
@@ -21,12 +23,14 @@ type HTTPConfig struct {
// ShieldConfig 屏蔽规则配置 // ShieldConfig 屏蔽规则配置
type ShieldConfig struct { type ShieldConfig struct {
LocalRulesFile string `json:"localRulesFile"` LocalRulesFile string `json:"localRulesFile"`
RemoteRules []string `json:"remoteRules"` RemoteRules []string `json:"remoteRules"`
UpdateInterval int `json:"updateInterval"` UpdateInterval int `json:"updateInterval"`
HostsFile string `json:"hostsFile"` HostsFile string `json:"hostsFile"`
BlockMethod string `json:"blockMethod"` // 屏蔽方法: "NXDOMAIN", "refused", "emptyIP", "customIP" BlockMethod string `json:"blockMethod"` // 屏蔽方法: "NXDOMAIN", "refused", "emptyIP", "customIP"
CustomBlockIP string `json:"customBlockIP"` // 自定义屏蔽IP当BlockMethod为"customIP"时使用 CustomBlockIP string `json:"customBlockIP"` // 自定义屏蔽IP当BlockMethod为"customIP"时使用
StatsFile string `json:"statsFile"` // 计数数据持久化文件
StatsSaveInterval int `json:"statsSaveInterval"` // 计数数据保存间隔(秒)
} }
// LogConfig 日志配置 // LogConfig 日志配置
@@ -64,7 +68,13 @@ func LoadConfig(path string) (*Config, error) {
config.DNS.Port = 53 config.DNS.Port = 53
} }
if len(config.DNS.UpstreamDNS) == 0 { if len(config.DNS.UpstreamDNS) == 0 {
config.DNS.UpstreamDNS = []string{"8.8.8.8:53", "1.1.1.1:53"} config.DNS.UpstreamDNS = []string{"223.5.5.5:53", "223.6.6.6:53"}
}
if config.DNS.StatsFile == "" {
config.DNS.StatsFile = "./data/stats.json" // 默认统计数据文件路径
}
if config.DNS.SaveInterval == 0 {
config.DNS.SaveInterval = 300 // 默认5分钟保存一次
} }
if config.HTTP.Port == 0 { if config.HTTP.Port == 0 {
config.HTTP.Port = 8080 config.HTTP.Port = 8080
@@ -78,6 +88,12 @@ func LoadConfig(path string) (*Config, error) {
if config.Shield.BlockMethod == "" { if config.Shield.BlockMethod == "" {
config.Shield.BlockMethod = "NXDOMAIN" // 默认屏蔽方法为NXDOMAIN config.Shield.BlockMethod = "NXDOMAIN" // 默认屏蔽方法为NXDOMAIN
} }
if config.Shield.StatsFile == "" {
config.Shield.StatsFile = "./data/shield_stats.json" // 默认Shield统计数据文件路径
}
if config.Shield.StatsSaveInterval == 0 {
config.Shield.StatsSaveInterval = 300 // 默认5分钟保存一次
}
if config.Log.Level == "" { if config.Log.Level == "" {
config.Log.Level = "info" config.Log.Level = "info"
} }

0
data/shield_stats.json Normal file
View File

42
data/stats.json Normal file
View File

@@ -0,0 +1,42 @@
{
"stats": {
"Queries": 33,
"Blocked": 24,
"Allowed": 19,
"Errors": 2,
"LastQuery": "2025-11-23T19:06:10.694259822+08:00"
},
"blockedDomains": {
"ad.qq.com": {
"Domain": "ad.qq.com",
"Count": 6,
"LastSeen": "2025-11-23T19:06:10.694532789+08:00"
},
"ad.qq.com.amazehome.xyz": {
"Domain": "ad.qq.com.amazehome.xyz",
"Count": 6,
"LastSeen": "2025-11-23T19:06:10.691565251+08:00"
}
},
"resolvedDomains": {
"ad.qq.com": {
"Domain": "ad.qq.com",
"Count": 10,
"LastSeen": "2025-11-23T19:05:54.429002187+08:00"
},
"ad.qq.com.amazehome.xyz": {
"Domain": "ad.qq.com.amazehome.xyz",
"Count": 8,
"LastSeen": "2025-11-23T19:05:54.356216418+08:00"
},
"apd-pcdnwxstat.teg.tencent-cloud.net": {
"Domain": "apd-pcdnwxstat.teg.tencent-cloud.net",
"Count": 1,
"LastSeen": "2025-11-23T19:05:56.842653777+08:00"
}
},
"hourlyStats": {
"2025-11-23-19": 12
},
"lastSaved": "2025-11-23T19:06:21.194988376+08:00"
}

Binary file not shown.

View File

@@ -230,3 +230,152 @@ time="2025-11-23T18:30:48+08:00" level=debug msg="接收到DNS查询" client="10
time="2025-11-23T18:30:48+08:00" level=error msg="DNS查询失败" domain=ads.qq.com time="2025-11-23T18:30:48+08:00" level=error msg="DNS查询失败" domain=ads.qq.com
time="2025-11-23T18:31:49+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:8360" domain=self.events.data.microsoft.com type=65 time="2025-11-23T18:31:49+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:8360" domain=self.events.data.microsoft.com type=65
time="2025-11-23T18:31:49+08:00" level=debug msg="DNS查询成功" domain=self.events.data.microsoft.com rtt=14.34768ms server="223.5.5.5:53" time="2025-11-23T18:31:49+08:00" level=debug msg="DNS查询成功" domain=self.events.data.microsoft.com rtt=14.34768ms server="223.5.5.5:53"
time="2025-11-23T18:35:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:34681" domain=apd-pcdnwxstat.teg.tencent-cloud.net type=1
time="2025-11-23T18:35:09+08:00" level=debug msg="DNS查询成功" domain=apd-pcdnwxstat.teg.tencent-cloud.net rtt=5.914665ms server="223.5.5.5:53"
time="2025-11-23T18:37:26+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:8652" domain=apd-pcdnwxstat.teg.tencent-cloud.net type=1
time="2025-11-23T18:37:26+08:00" level=debug msg="DNS查询成功" domain=apd-pcdnwxstat.teg.tencent-cloud.net rtt=5.903025ms server="223.5.5.5:53"
time="2025-11-23T18:39:07+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:15083" domain=metrics1-drcn.dt.dbankcloud.cn type=1
time="2025-11-23T18:39:07+08:00" level=debug msg="DNS查询成功" domain=metrics1-drcn.dt.dbankcloud.cn rtt=5.213232ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:61317" domain=appdl-1-drcn.dbankcdn.com type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:4656" domain=appdl-drcn.dbankcdn.com type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=appdl-1-drcn.dbankcdn.com rtt=4.647968ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=appdl-drcn.dbankcdn.com rtt=4.474298ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:47439" domain=appoptimize-drcn.dbankcdn.cn type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:50747" domain=appimg-drcn.dbankcdn.com type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=appoptimize-drcn.dbankcdn.cn rtt=4.028323ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=appimg-drcn.dbankcdn.com rtt=4.806171ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:58085" domain=store-drcn.hispace.dbankcloud.com type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=store-drcn.hispace.dbankcloud.com rtt=4.298717ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:65072" domain=contentcenter-drcn.dbankcdn.cn type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:9115" domain=api-drcn.theme.dbankcloud.cn type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=contentcenter-drcn.dbankcdn.cn rtt=5.394543ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=api-drcn.theme.dbankcloud.cn rtt=5.24299ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:58544" domain=magazine-drcn.theme.dbankcloud.cn type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:22253" domain=magazine-drcn.theme.dbankcloud.cn type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=magazine-drcn.theme.dbankcloud.cn rtt=5.682249ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=magazine-drcn.theme.dbankcloud.cn rtt=5.599705ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:32221" domain=agpicnsp-drcn.dbankcdn.com type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:3445" domain=appimg.dbankcdn.com type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=agpicnsp-drcn.dbankcdn.com rtt=5.96018ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=appimg.dbankcdn.com rtt=13.633739ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:16444" domain=f00b1b869deb32d2ad60ba514bb876ea.b.hon.cc.cdnhwc8.com type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=f00b1b869deb32d2ad60ba514bb876ea.b.hon.cc.cdnhwc8.com rtt=15.020117ms server="223.5.5.5:53"
time="2025-11-23T18:39:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:43083" domain=appdl-2-drcn.dbankcdn.com type=1
time="2025-11-23T18:39:09+08:00" level=debug msg="DNS查询成功" domain=appdl-2-drcn.dbankcdn.com rtt=4.087138ms server="223.5.5.5:53"
time="2025-11-23T18:39:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:41949" domain=grs.dbankcloud.com type=1
time="2025-11-23T18:39:10+08:00" level=debug msg="DNS查询成功" domain=grs.dbankcloud.com rtt=6.434814ms server="223.5.5.5:53"
time="2025-11-23T18:39:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:18043" domain=sdkserver.op.hicloud.com type=1
time="2025-11-23T18:39:10+08:00" level=debug msg="DNS查询成功" domain=sdkserver.op.hicloud.com rtt=6.663746ms server="223.5.5.5:53"
time="2025-11-23T18:39:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:27296" domain=events.op.hicloud.com type=1
time="2025-11-23T18:39:10+08:00" level=debug msg="DNS查询成功" domain=events.op.hicloud.com rtt=4.076785ms server="223.5.5.5:53"
time="2025-11-23T18:39:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:20705" domain=acd.op.hicloud.com type=1
time="2025-11-23T18:39:10+08:00" level=debug msg="DNS查询成功" domain=acd.op.hicloud.com rtt=5.188271ms server="223.5.5.5:53"
time="2025-11-23T18:39:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:11580" domain=api.cloud.huawei.com type=1
time="2025-11-23T18:39:11+08:00" level=debug msg="DNS查询成功" domain=api.cloud.huawei.com rtt=5.414894ms server="223.5.5.5:53"
time="2025-11-23T18:39:11+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:16274" domain=sdkserver-drcn.op.dbankcloud.cn type=1
time="2025-11-23T18:39:11+08:00" level=debug msg="DNS查询成功" domain=sdkserver-drcn.op.dbankcloud.cn rtt=5.745651ms server="223.5.5.5:53"
time="2025-11-23T18:39:12+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:54852" domain=tsms-drcn.security.dbankcloud.cn type=1
time="2025-11-23T18:39:12+08:00" level=debug msg="DNS查询成功" domain=tsms-drcn.security.dbankcloud.cn rtt=5.889368ms server="223.5.5.5:53"
time="2025-11-23T18:39:18+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:56128" domain=store-drcn.hispace.dbankcloud.com type=1
time="2025-11-23T18:39:18+08:00" level=debug msg="DNS查询成功" domain=store-drcn.hispace.dbankcloud.com rtt=5.222492ms server="223.5.5.5:53"
time="2025-11-23T18:41:22+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:6990" domain=dldir1v6.qq.com type=1
time="2025-11-23T18:41:22+08:00" level=debug msg="DNS查询成功" domain=dldir1v6.qq.com rtt=5.968557ms server="223.5.5.5:53"
time="2025-11-23T18:48:02+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:20065" domain=dns.weixin.qq.com.cn type=1
time="2025-11-23T18:48:02+08:00" level=debug msg="DNS查询成功" domain=dns.weixin.qq.com.cn rtt=5.24456ms server="223.5.5.5:53"
time="2025-11-23T18:52:01+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:2060" domain=apd-pcdnwxlogin.teg.tencent-cloud.net type=1
time="2025-11-23T18:52:01+08:00" level=debug msg="DNS查询成功" domain=apd-pcdnwxlogin.teg.tencent-cloud.net rtt=6.190907ms server="223.5.5.5:53"
time="2025-11-23T18:55:03+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:12293" domain=apd-pcdnwxnat.teg.tencent-cloud.net type=1
time="2025-11-23T18:55:03+08:00" level=debug msg="DNS查询成功" domain=apd-pcdnwxnat.teg.tencent-cloud.net rtt=5.919306ms server="223.5.5.5:53"
time="2025-11-23T18:55:34+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:27926" domain=aeventlog.beacon.qq.com type=1
time="2025-11-23T18:55:34+08:00" level=debug msg="DNS查询成功" domain=aeventlog.beacon.qq.com rtt=6.692955ms server="223.5.5.5:53"
time="2025-11-23T18:57:28+08:00" level=info msg="正在关闭服务..."
time="2025-11-23T18:57:28+08:00" level=info msg="DNS服务器已停止"
time="2025-11-23T18:57:28+08:00" level=error msg="HTTP控制台服务器启动失败" error="http: Server closed"
time="2025-11-23T18:57:28+08:00" level=info msg="HTTP控制台服务器已停止"
time="2025-11-23T18:57:28+08:00" level=info msg="所有服务已关闭"
time="2025-11-23T18:57:28+08:00" level=warning msg="日志系统已关闭"
time="2025-11-23T19:05:40+08:00" level=error msg="获取远程规则失败" error="远程服务器返回错误状态码: 404" url="https://example.com/rules.txt"
time="2025-11-23T19:05:40+08:00" level=info msg="规则加载完成,域名规则: 2, 排除规则: 0, 正则规则: 2, hosts规则: 3"
time="2025-11-23T19:05:40+08:00" level=info msg="DNS服务器已启动监听端口: 53"
time="2025-11-23T19:05:40+08:00" level=info msg="HTTP控制台已启动监听端口: 8080"
time="2025-11-23T19:05:40+08:00" level=info msg="HTTP控制台服务器启动监听地址: 0.0.0.0:8080"
time="2025-11-23T19:05:40+08:00" level=info msg="DNS TCP服务器启动监听端口: 53"
time="2025-11-23T19:05:40+08:00" level=info msg="规则自动更新已启动" interval=3600
time="2025-11-23T19:05:40+08:00" level=info msg="启动Shield计数数据自动保存功能" file=./data/shield_stats.json interval=300
time="2025-11-23T19:05:40+08:00" level=info msg="DNS UDP服务器启动监听端口: 53"
time="2025-11-23T19:05:40+08:00" level=info msg="Shield计数数据保存成功"
time="2025-11-23T19:05:51+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:63504" domain=ad.qq.com.amazehome.xyz type=1
time="2025-11-23T19:05:52+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com.amazehome.xyz rtt=68.496416ms server="223.5.5.5:53"
time="2025-11-23T19:05:52+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:63505" domain=ad.qq.com.amazehome.xyz type=28
time="2025-11-23T19:05:52+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com.amazehome.xyz rtt=22.855544ms server="223.5.5.5:53"
time="2025-11-23T19:05:52+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:63506" domain=ad.qq.com type=1
time="2025-11-23T19:05:52+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com rtt=23.728363ms server="223.5.5.5:53"
time="2025-11-23T19:05:52+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:62552" domain=ad.qq.com type=28
time="2025-11-23T19:05:52+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com rtt=27.123116ms server="223.5.5.5:53"
time="2025-11-23T19:05:52+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:62553" domain=ad.qq.com.amazehome.xyz type=1
time="2025-11-23T19:05:52+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com.amazehome.xyz rtt=5.560802ms server="223.5.5.5:53"
time="2025-11-23T19:05:52+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:62554" domain=ad.qq.com.amazehome.xyz type=28
time="2025-11-23T19:05:52+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com.amazehome.xyz rtt=4.628616ms server="223.6.6.6:53"
time="2025-11-23T19:05:52+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:62555" domain=ad.qq.com type=1
time="2025-11-23T19:05:52+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com rtt=32.441875ms server="223.5.5.5:53"
time="2025-11-23T19:05:52+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:62556" domain=ad.qq.com type=28
time="2025-11-23T19:05:52+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com rtt=16.630593ms server="223.5.5.5:53"
time="2025-11-23T19:05:53+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:62557" domain=ad.qq.com.amazehome.xyz type=1
time="2025-11-23T19:05:53+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com.amazehome.xyz rtt=37.27035ms server="223.5.5.5:53"
time="2025-11-23T19:05:53+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:62558" domain=ad.qq.com.amazehome.xyz type=28
time="2025-11-23T19:05:53+08:00" level=error msg="DNS查询失败" domain=ad.qq.com.amazehome.xyz
time="2025-11-23T19:05:53+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:62559" domain=ad.qq.com type=1
time="2025-11-23T19:05:53+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com rtt=14.2654ms server="223.5.5.5:53"
time="2025-11-23T19:05:53+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:62560" domain=ad.qq.com type=28
time="2025-11-23T19:05:53+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com rtt=6.551795ms server="223.5.5.5:53"
time="2025-11-23T19:05:53+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:52135" domain=ad.qq.com.amazehome.xyz type=1
time="2025-11-23T19:05:53+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com.amazehome.xyz rtt=31.31022ms server="223.5.5.5:53"
time="2025-11-23T19:05:53+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:52136" domain=ad.qq.com.amazehome.xyz type=28
time="2025-11-23T19:05:53+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com.amazehome.xyz rtt=30.611352ms server="223.5.5.5:53"
time="2025-11-23T19:05:53+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:52137" domain=ad.qq.com type=1
time="2025-11-23T19:05:53+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com rtt=43.032729ms server="223.5.5.5:53"
time="2025-11-23T19:05:53+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:52138" domain=ad.qq.com type=28
time="2025-11-23T19:05:53+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com rtt=27.754923ms server="223.5.5.5:53"
time="2025-11-23T19:05:54+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:52139" domain=ad.qq.com.amazehome.xyz type=1
time="2025-11-23T19:05:54+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com.amazehome.xyz rtt=5.00309ms server="223.5.5.5:53"
time="2025-11-23T19:05:54+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:52140" domain=ad.qq.com.amazehome.xyz type=28
time="2025-11-23T19:05:54+08:00" level=error msg="DNS查询失败" domain=ad.qq.com.amazehome.xyz
time="2025-11-23T19:05:54+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:52141" domain=ad.qq.com type=1
time="2025-11-23T19:05:54+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com rtt=18.018889ms server="223.5.5.5:53"
time="2025-11-23T19:05:54+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:52142" domain=ad.qq.com type=28
time="2025-11-23T19:05:54+08:00" level=debug msg="DNS查询成功" domain=ad.qq.com rtt=32.759047ms server="223.5.5.5:53"
time="2025-11-23T19:05:56+08:00" level=debug msg="接收到DNS查询" client="10.35.10.11:32332" domain=apd-pcdnwxstat.teg.tencent-cloud.net type=1
time="2025-11-23T19:05:56+08:00" level=debug msg="DNS查询成功" domain=apd-pcdnwxstat.teg.tencent-cloud.net rtt=6.574939ms server="223.5.5.5:53"
time="2025-11-23T19:06:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:49579" domain=ad.qq.com.amazehome.xyz type=1
time="2025-11-23T19:06:09+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:49579" domain=ad.qq.com.amazehome.xyz
time="2025-11-23T19:06:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:49580" domain=ad.qq.com.amazehome.xyz type=28
time="2025-11-23T19:06:09+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:49580" domain=ad.qq.com.amazehome.xyz
time="2025-11-23T19:06:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:49581" domain=ad.qq.com type=1
time="2025-11-23T19:06:09+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:49581" domain=ad.qq.com
time="2025-11-23T19:06:09+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:49582" domain=ad.qq.com type=28
time="2025-11-23T19:06:09+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:49582" domain=ad.qq.com
time="2025-11-23T19:06:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:49583" domain=ad.qq.com.amazehome.xyz type=1
time="2025-11-23T19:06:10+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:49583" domain=ad.qq.com.amazehome.xyz
time="2025-11-23T19:06:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:49584" domain=ad.qq.com.amazehome.xyz type=28
time="2025-11-23T19:06:10+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:49584" domain=ad.qq.com.amazehome.xyz
time="2025-11-23T19:06:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:49585" domain=ad.qq.com type=1
time="2025-11-23T19:06:10+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:49585" domain=ad.qq.com
time="2025-11-23T19:06:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:49586" domain=ad.qq.com type=28
time="2025-11-23T19:06:10+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:49586" domain=ad.qq.com
time="2025-11-23T19:06:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:64329" domain=ad.qq.com.amazehome.xyz type=1
time="2025-11-23T19:06:10+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:64329" domain=ad.qq.com.amazehome.xyz
time="2025-11-23T19:06:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:64330" domain=ad.qq.com.amazehome.xyz type=28
time="2025-11-23T19:06:10+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:64330" domain=ad.qq.com.amazehome.xyz
time="2025-11-23T19:06:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:64331" domain=ad.qq.com type=1
time="2025-11-23T19:06:10+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:64331" domain=ad.qq.com
time="2025-11-23T19:06:10+08:00" level=debug msg="接收到DNS查询" client="10.35.10.78:64332" domain=ad.qq.com type=28
time="2025-11-23T19:06:10+08:00" level=info msg="域名被屏蔽" client="10.35.10.78:64332" domain=ad.qq.com
time="2025-11-23T19:06:21+08:00" level=info msg="正在关闭服务..."
time="2025-11-23T19:06:21+08:00" level=info msg="统计数据保存成功"
time="2025-11-23T19:06:21+08:00" level=info msg="DNS服务器已停止"
time="2025-11-23T19:06:21+08:00" level=error msg="HTTP控制台服务器启动失败" error="http: Server closed"
time="2025-11-23T19:06:21+08:00" level=info msg="HTTP控制台服务器已停止"
time="2025-11-23T19:06:21+08:00" level=info msg="Shield计数数据保存成功"
time="2025-11-23T19:06:21+08:00" level=info msg="规则自动更新已停止"
time="2025-11-23T19:06:21+08:00" level=info msg="所有服务已关闭"
time="2025-11-23T19:06:21+08:00" level=warning msg="日志系统已关闭"

View File

@@ -2,8 +2,12 @@ package dns
import ( import (
"context" "context"
"encoding/json"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"os"
"path/filepath"
"sort" "sort"
"sync" "sync"
"time" "time"
@@ -23,6 +27,15 @@ type BlockedDomain struct {
LastSeen time.Time LastSeen time.Time
} }
// StatsData 用于持久化的统计数据结构
type StatsData struct {
Stats *Stats `json:"stats"`
BlockedDomains map[string]*BlockedDomain `json:"blockedDomains"`
ResolvedDomains map[string]*BlockedDomain `json:"resolvedDomains"`
HourlyStats map[string]int64 `json:"hourlyStats"`
LastSaved time.Time `json:"lastSaved"`
}
// Server DNS服务器 // Server DNS服务器
type Server struct { type Server struct {
config *config.DNSConfig config *config.DNSConfig
@@ -40,6 +53,8 @@ type Server struct {
resolvedDomains map[string]*BlockedDomain // 用于记录解析的域名 resolvedDomains map[string]*BlockedDomain // 用于记录解析的域名
hourlyStatsMutex sync.RWMutex hourlyStatsMutex sync.RWMutex
hourlyStats map[string]int64 // 按小时统计屏蔽数量 hourlyStats map[string]int64 // 按小时统计屏蔽数量
saveTicker *time.Ticker // 用于定时保存数据
saveDone chan struct{} // 用于通知保存协程停止
} }
// Stats DNS服务器统计信息 // Stats DNS服务器统计信息
@@ -54,7 +69,7 @@ type Stats struct {
// NewServer 创建DNS服务器实例 // NewServer 创建DNS服务器实例
func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shieldManager *shield.ShieldManager) *Server { func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shieldManager *shield.ShieldManager) *Server {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
return &Server{ server := &Server{
config: config, config: config,
shieldConfig: shieldConfig, shieldConfig: shieldConfig,
shieldManager: shieldManager, shieldManager: shieldManager,
@@ -73,7 +88,14 @@ func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shie
blockedDomains: make(map[string]*BlockedDomain), blockedDomains: make(map[string]*BlockedDomain),
resolvedDomains: make(map[string]*BlockedDomain), resolvedDomains: make(map[string]*BlockedDomain),
hourlyStats: make(map[string]int64), hourlyStats: make(map[string]int64),
saveDone: make(chan struct{}),
} }
// 加载已保存的统计数据
server.loadStatsData()
return server
} }
// Start 启动DNS服务器 // Start 启动DNS服务器
@@ -116,10 +138,17 @@ func (s *Server) Start() error {
// Stop 停止DNS服务器 // Stop 停止DNS服务器
func (s *Server) Stop() { func (s *Server) Stop() {
// 发送停止信号给保存协程
close(s.saveDone)
// 最后保存一次数据
s.saveStatsData()
// 停止服务器
s.cancel()
if s.server != nil { if s.server != nil {
s.server.Shutdown() s.server.Shutdown()
} }
s.cancel()
logger.Info("DNS服务器已停止") logger.Info("DNS服务器已停止")
} }
@@ -452,3 +481,135 @@ func (s *Server) GetHourlyStats() map[string]int64 {
} }
return result return result
} }
// loadStatsData 从文件加载统计数据
func (s *Server) loadStatsData() {
if s.config.StatsFile == "" {
return
}
// 检查文件是否存在
data, err := ioutil.ReadFile(s.config.StatsFile)
if err != nil {
if !os.IsNotExist(err) {
logger.Error("读取统计数据文件失败", "error", err)
}
return
}
var statsData StatsData
err = json.Unmarshal(data, &statsData)
if err != nil {
logger.Error("解析统计数据失败", "error", err)
return
}
// 恢复统计数据
s.statsMutex.Lock()
if statsData.Stats != nil {
s.stats = statsData.Stats
}
s.statsMutex.Unlock()
s.blockedDomainsMutex.Lock()
if statsData.BlockedDomains != nil {
s.blockedDomains = statsData.BlockedDomains
}
s.blockedDomainsMutex.Unlock()
s.resolvedDomainsMutex.Lock()
if statsData.ResolvedDomains != nil {
s.resolvedDomains = statsData.ResolvedDomains
}
s.resolvedDomainsMutex.Unlock()
s.hourlyStatsMutex.Lock()
if statsData.HourlyStats != nil {
s.hourlyStats = statsData.HourlyStats
}
s.hourlyStatsMutex.Unlock()
logger.Info("统计数据加载成功")
}
// saveStatsData 保存统计数据到文件
func (s *Server) saveStatsData() {
if s.config.StatsFile == "" {
return
}
// 创建数据目录
statsDir := filepath.Dir(s.config.StatsFile)
err := os.MkdirAll(statsDir, 0755)
if err != nil {
logger.Error("创建统计数据目录失败", "error", err)
return
}
// 收集所有统计数据
statsData := &StatsData{
Stats: s.GetStats(),
LastSaved: time.Now(),
}
// 复制域名数据
s.blockedDomainsMutex.RLock()
statsData.BlockedDomains = make(map[string]*BlockedDomain)
for k, v := range s.blockedDomains {
statsData.BlockedDomains[k] = v
}
s.blockedDomainsMutex.RUnlock()
s.resolvedDomainsMutex.RLock()
statsData.ResolvedDomains = make(map[string]*BlockedDomain)
for k, v := range s.resolvedDomains {
statsData.ResolvedDomains[k] = v
}
s.resolvedDomainsMutex.RUnlock()
s.hourlyStatsMutex.RLock()
statsData.HourlyStats = make(map[string]int64)
for k, v := range s.hourlyStats {
statsData.HourlyStats[k] = v
}
s.hourlyStatsMutex.RUnlock()
// 序列化数据
jsonData, err := json.MarshalIndent(statsData, "", " ")
if err != nil {
logger.Error("序列化统计数据失败", "error", err)
return
}
// 写入文件
err = ioutil.WriteFile(s.config.StatsFile, jsonData, 0644)
if err != nil {
logger.Error("保存统计数据到文件失败", "error", err)
return
}
logger.Info("统计数据保存成功")
}
// startAutoSave 启动自动保存功能
func (s *Server) startAutoSave() {
if s.config.StatsFile == "" || s.config.SaveInterval <= 0 {
return
}
// 设置定时器
s.saveTicker = time.NewTicker(time.Duration(s.config.SaveInterval) * time.Second)
defer s.saveTicker.Stop()
logger.Info("启动统计数据自动保存功能", "interval", s.config.SaveInterval, "file", s.config.StatsFile)
// 定期保存数据
for {
select {
case <-s.saveTicker.C:
s.saveStatsData()
case <-s.saveDone:
return
}
}
}

View File

@@ -1,3 +1,5 @@
||hm.baidu.com ||hm.baidu.com
||baidu.com
/.*tracking.*/ /.*tracking.*/
/adjust.net/ /adjust.net/
/ad./

View File

@@ -3,10 +3,12 @@ package shield
import ( import (
"bufio" "bufio"
"context" "context"
"encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os" "os"
"path/filepath"
"regexp" "regexp"
"sort" "sort"
"strings" "strings"
@@ -23,6 +25,13 @@ type regexRule struct {
original string original string
} }
// ShieldStatsData 用于持久化的Shield统计数据
type ShieldStatsData struct {
BlockedDomainsCount map[string]int `json:"blockedDomainsCount"`
ResolvedDomainsCount map[string]int `json:"resolvedDomainsCount"`
LastSaved time.Time `json:"lastSaved"`
}
// ShieldManager 屏蔽管理器 // ShieldManager 屏蔽管理器
type ShieldManager struct { type ShieldManager struct {
config *config.ShieldConfig config *config.ShieldConfig
@@ -42,7 +51,7 @@ type ShieldManager struct {
// NewShieldManager 创建屏蔽管理器实例 // NewShieldManager 创建屏蔽管理器实例
func NewShieldManager(config *config.ShieldConfig) *ShieldManager { func NewShieldManager(config *config.ShieldConfig) *ShieldManager {
ctx, cancel := context.WithCancel(context.Background()) ctx, cancel := context.WithCancel(context.Background())
return &ShieldManager{ manager := &ShieldManager{
config: config, config: config,
domainRules: make(map[string]bool), domainRules: make(map[string]bool),
domainExceptions: make(map[string]bool), domainExceptions: make(map[string]bool),
@@ -54,6 +63,11 @@ func NewShieldManager(config *config.ShieldConfig) *ShieldManager {
updateCtx: ctx, updateCtx: ctx,
updateCancel: cancel, updateCancel: cancel,
} }
// 加载已保存的计数数据
manager.loadStatsData()
return manager
} }
// LoadRules 加载屏蔽规则 // LoadRules 加载屏蔽规则
@@ -651,6 +665,9 @@ func (m *ShieldManager) StartAutoUpdate() {
ticker := time.NewTicker(time.Duration(m.config.UpdateInterval) * time.Second) ticker := time.NewTicker(time.Duration(m.config.UpdateInterval) * time.Second)
defer ticker.Stop() defer ticker.Stop()
// 启动自动保存计数数据
go m.startAutoSaveStats()
for { for {
select { select {
case <-ticker.C: case <-ticker.C:
@@ -661,16 +678,27 @@ func (m *ShieldManager) StartAutoUpdate() {
logger.Info("自动更新规则成功") logger.Info("自动更新规则成功")
} }
case <-m.updateCtx.Done(): case <-m.updateCtx.Done():
// 保存计数数据
m.saveStatsData()
m.updateRunning = false m.updateRunning = false
return return
} }
} }
}() }()
logger.Info("规则自动更新已启动", "interval", m.config.UpdateInterval)
// 如果是首次启动,先保存一次数据确保目录存在
go m.saveStatsData()
} }
// StopAutoUpdate 停止自动更新 // StopAutoUpdate 停止自动更新
func (m *ShieldManager) StopAutoUpdate() { func (m *ShieldManager) StopAutoUpdate() {
m.updateRunning = false
m.updateCancel() m.updateCancel()
// 保存计数数据
m.saveStatsData()
logger.Info("规则自动更新已停止")
} }
// saveRulesToFile 保存规则到文件 // saveRulesToFile 保存规则到文件
@@ -781,7 +809,112 @@ func (m *ShieldManager) GetStats() map[string]interface{} {
} }
} }
// GetRules 获取所有规则的详细列表 // loadStatsData 从文件加载计数数据
func (m *ShieldManager) loadStatsData() {
if m.config.StatsFile == "" {
return
}
// 检查文件是否存在
data, err := ioutil.ReadFile(m.config.StatsFile)
if err != nil {
if !os.IsNotExist(err) {
logger.Error("读取Shield计数数据文件失败", "error", err)
}
return
}
var statsData ShieldStatsData
err = json.Unmarshal(data, &statsData)
if err != nil {
logger.Error("解析Shield计数数据失败", "error", err)
return
}
// 恢复计数数据
m.rulesMutex.Lock()
if statsData.BlockedDomainsCount != nil {
m.blockedDomainsCount = statsData.BlockedDomainsCount
}
if statsData.ResolvedDomainsCount != nil {
m.resolvedDomainsCount = statsData.ResolvedDomainsCount
}
m.rulesMutex.Unlock()
logger.Info("Shield计数数据加载成功")
}
// saveStatsData 保存计数数据到文件
func (m *ShieldManager) saveStatsData() {
if m.config.StatsFile == "" {
return
}
// 创建数据目录
statsDir := filepath.Dir(m.config.StatsFile)
err := os.MkdirAll(statsDir, 0755)
if err != nil {
logger.Error("创建Shield统计数据目录失败", "error", err)
return
}
// 收集计数数据
m.rulesMutex.RLock()
statsData := &ShieldStatsData{
BlockedDomainsCount: make(map[string]int),
ResolvedDomainsCount: make(map[string]int),
LastSaved: time.Now(),
}
// 复制数据
for k, v := range m.blockedDomainsCount {
statsData.BlockedDomainsCount[k] = v
}
for k, v := range m.resolvedDomainsCount {
statsData.ResolvedDomainsCount[k] = v
}
m.rulesMutex.RUnlock()
// 序列化数据
jsonData, err := json.MarshalIndent(statsData, "", " ")
if err != nil {
logger.Error("序列化Shield计数数据失败", "error", err)
return
}
// 写入文件
err = ioutil.WriteFile(m.config.StatsFile, jsonData, 0644)
if err != nil {
logger.Error("保存Shield计数数据到文件失败", "error", err)
return
}
logger.Info("Shield计数数据保存成功")
}
// startAutoSaveStats 启动计数数据自动保存功能
func (m *ShieldManager) startAutoSaveStats() {
if m.config.StatsFile == "" || m.config.StatsSaveInterval <= 0 {
return
}
ticker := time.NewTicker(time.Duration(m.config.StatsSaveInterval) * time.Second)
defer ticker.Stop()
logger.Info("启动Shield计数数据自动保存功能", "interval", m.config.StatsSaveInterval, "file", m.config.StatsFile)
// 定期保存数据
for {
select {
case <-ticker.C:
m.saveStatsData()
case <-m.updateCtx.Done():
return
}
}
}
// GetRules 获取所有规则
func (m *ShieldManager) GetRules() map[string]interface{} { func (m *ShieldManager) GetRules() map[string]interface{} {
m.rulesMutex.RLock() m.rulesMutex.RLock()
defer m.rulesMutex.RUnlock() defer m.rulesMutex.RUnlock()