dnssec优化

This commit is contained in:
Alex Yang
2025-12-16 12:23:22 +08:00
parent fb3b28c22f
commit 50d2b5fbdb
40 changed files with 36602 additions and 457878 deletions

View File

@@ -2,8 +2,13 @@
"dns": { "dns": {
"port": 53, "port": 53,
"upstreamDNS": [ "upstreamDNS": [
"223.5.5.5:53", "8.8.8.8:53",
"223.6.6.6:53" "8.8.4.4:53",
"1.1.1.1:53"
],
"dnssecUpstreamDNS": [
"8.8.8.8:53",
"1.1.1.1:53"
], ],
"timeout": 5000, "timeout": 5000,
"statsFile": "data/stats.json", "statsFile": "data/stats.json",
@@ -48,7 +53,7 @@
{ {
"name": "CNList", "name": "CNList",
"url": "https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/list/china.list", "url": "https://gitea.amazehome.xyz/AMAZEHOME/hosts-and-filters/raw/branch/main/list/china.list",
"enabled": true "enabled": false
}, },
{ {
"name": "大圣净化", "name": "大圣净化",

View File

@@ -9,12 +9,12 @@ import (
type DNSConfig struct { type DNSConfig struct {
Port int `json:"port"` Port int `json:"port"`
UpstreamDNS []string `json:"upstreamDNS"` UpstreamDNS []string `json:"upstreamDNS"`
DNSSECUpstreamDNS []string `json:"dnssecUpstreamDNS"` // 用于DNSSEC查询的专用服务器
Timeout int `json:"timeout"` Timeout int `json:"timeout"`
StatsFile string `json:"statsFile"` // 统计数据持久化文件 StatsFile string `json:"statsFile"` // 统计数据持久化文件
SaveInterval int `json:"saveInterval"` // 数据保存间隔(秒) SaveInterval int `json:"saveInterval"` // 数据保存间隔(秒)
CacheTTL int `json:"cacheTTL"` // DNS缓存过期时间分钟 CacheTTL int `json:"cacheTTL"` // DNS缓存过期时间分钟
EnableDNSSEC bool `json:"enableDNSSEC"` // 是否启用DNSSEC支持 EnableDNSSEC bool `json:"enableDNSSEC"` // 是否启用DNSSEC支持
DNSSECValidation bool `json:"dnssecValidation"` // 是否进行DNSSEC验证
} }
// HTTPConfig HTTP控制台配置 // HTTPConfig HTTP控制台配置
@@ -97,7 +97,10 @@ func LoadConfig(path string) (*Config, error) {
} }
// DNSSEC默认配置 // DNSSEC默认配置
config.DNS.EnableDNSSEC = true // 默认启用DNSSEC支持 config.DNS.EnableDNSSEC = true // 默认启用DNSSEC支持
config.DNS.DNSSECValidation = true // 默认启用DNSSEC验证 // DNSSEC专用服务器默认配置
if len(config.DNS.DNSSECUpstreamDNS) == 0 {
config.DNS.DNSSECUpstreamDNS = []string{"8.8.8.8:53", "1.1.1.1:53"}
}
if config.HTTP.Port == 0 { if config.HTTP.Port == 0 {
config.HTTP.Port = 8080 config.HTTP.Port = 8080
} }

View File

@@ -1,3 +0,0 @@
# Hosts文件
# 格式IP 域名
# 例如127.0.0.1 localhost

File diff suppressed because it is too large Load Diff

View File

@@ -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/

View File

View File

@@ -1,5 +0,0 @@
{
"blockedDomainsCount": {},
"resolvedDomainsCount": {},
"lastSaved": "2025-12-16T01:12:54.117224025+08:00"
}

View File

@@ -1,390 +0,0 @@
{
"stats": {
"Queries": 459,
"Blocked": 289,
"Allowed": 38,
"Errors": 2,
"LastQuery": "2025-12-16T01:12:35.399832971+08:00",
"AvgResponseTime": 23.838779956427015,
"TotalResponseTime": 10942,
"QueryTypes": {
"A": 384,
"AAAA": 74,
"NS": 1
},
"SourceIPs": {
"10.35.10.11": true,
"10.35.10.78": true
},
"CpuUsage": 4.5420326223337515
},
"blockedDomains": {
"apd-pcdnwxnat.teg.tencent-cloud.net": {
"Domain": "apd-pcdnwxnat.teg.tencent-cloud.net",
"Count": 4,
"LastSeen": "2025-12-16T01:07:45.683974324+08:00",
"DNSSEC": false
},
"api-play-zjg.amemv.com": {
"Domain": "api-play-zjg.amemv.com",
"Count": 2,
"LastSeen": "2025-12-16T00:56:28.585234386+08:00",
"DNSSEC": false
},
"api.amemv.com": {
"Domain": "api.amemv.com",
"Count": 2,
"LastSeen": "2025-12-16T01:02:14.483436776+08:00",
"DNSSEC": false
},
"api.cloud.huawei.com": {
"Domain": "api.cloud.huawei.com",
"Count": 2,
"LastSeen": "2025-12-16T00:59:00.590899741+08:00",
"DNSSEC": false
},
"aweme.snssdk.com": {
"Domain": "aweme.snssdk.com",
"Count": 2,
"LastSeen": "2025-12-16T01:02:14.477891024+08:00",
"DNSSEC": false
},
"dns.weixin.qq.com.cn": {
"Domain": "dns.weixin.qq.com.cn",
"Count": 2,
"LastSeen": "2025-12-16T01:00:30.339793906+08:00",
"DNSSEC": false
},
"events-drcn.op.dbankcloud.cn": {
"Domain": "events-drcn.op.dbankcloud.cn",
"Count": 1,
"LastSeen": "2025-12-16T00:59:00.410516917+08:00",
"DNSSEC": false
},
"example.com": {
"Domain": "example.com",
"Count": 4,
"LastSeen": "2025-12-16T00:24:02.487540915+08:00",
"DNSSEC": false
},
"is.snssdk.com": {
"Domain": "is.snssdk.com",
"Count": 8,
"LastSeen": "2025-12-16T01:09:38.470711184+08:00",
"DNSSEC": false
},
"logservice.hicloud.com": {
"Domain": "logservice.hicloud.com",
"Count": 6,
"LastSeen": "2025-12-16T01:08:08.757132913+08:00",
"DNSSEC": false
},
"metrics1.data.hicloud.com": {
"Domain": "metrics1.data.hicloud.com",
"Count": 2,
"LastSeen": "2025-12-16T00:58:59.524905368+08:00",
"DNSSEC": false
},
"mon.snssdk.com": {
"Domain": "mon.snssdk.com",
"Count": 8,
"LastSeen": "2025-12-16T01:00:55.57905172+08:00",
"DNSSEC": false
},
"n98-lf9-dy-ncdn-tos-sub.bytegecko.com": {
"Domain": "n98-lf9-dy-ncdn-tos-sub.bytegecko.com",
"Count": 4,
"LastSeen": "2025-12-16T00:56:17.822823664+08:00",
"DNSSEC": false
},
"pull-cold-f5.douyincdn.com": {
"Domain": "pull-cold-f5.douyincdn.com",
"Count": 1,
"LastSeen": "2025-12-16T00:50:59.675809552+08:00",
"DNSSEC": false
},
"pull-flv-f26-proxy.douyincdn.com": {
"Domain": "pull-flv-f26-proxy.douyincdn.com",
"Count": 1,
"LastSeen": "2025-12-16T00:51:04.511409613+08:00",
"DNSSEC": false
},
"pull-flv-gravity-t11.douyincdn.com": {
"Domain": "pull-flv-gravity-t11.douyincdn.com",
"Count": 1,
"LastSeen": "2025-12-16T00:44:40.368998519+08:00",
"DNSSEC": false
},
"pull-flv-l11.douyincdn.com": {
"Domain": "pull-flv-l11.douyincdn.com",
"Count": 6,
"LastSeen": "2025-12-16T01:06:09.423848585+08:00",
"DNSSEC": false
},
"pull-hls-c11.douyincdn.com": {
"Domain": "pull-hls-c11.douyincdn.com",
"Count": 1,
"LastSeen": "2025-12-16T00:51:06.567218221+08:00",
"DNSSEC": false
},
"pull-hs-f5-encryption.flive.douyincdn.com": {
"Domain": "pull-hs-f5-encryption.flive.douyincdn.com",
"Count": 1,
"LastSeen": "2025-12-16T00:50:55.098891115+08:00",
"DNSSEC": false
},
"push-rtmp-f5-enc.douyincdn.com": {
"Domain": "push-rtmp-f5-enc.douyincdn.com",
"Count": 1,
"LastSeen": "2025-12-16T00:29:23.706753775+08:00",
"DNSSEC": false
},
"push-rtmp-vr-l11.douyincdn.com": {
"Domain": "push-rtmp-vr-l11.douyincdn.com",
"Count": 1,
"LastSeen": "2025-12-16T00:29:26.936331624+08:00",
"DNSSEC": false
},
"so.com.amazehome.xyz": {
"Domain": "so.com.amazehome.xyz",
"Count": 10,
"LastSeen": "2025-12-16T00:23:16.05805465+08:00",
"DNSSEC": false
},
"v1-daily-colda.douyinvod.com": {
"Domain": "v1-daily-colda.douyinvod.com",
"Count": 2,
"LastSeen": "2025-12-16T00:56:30.93606758+08:00",
"DNSSEC": false
},
"v11-cold.douyinvod.com": {
"Domain": "v11-cold.douyinvod.com",
"Count": 2,
"LastSeen": "2025-12-16T01:09:28.578195896+08:00",
"DNSSEC": false
},
"v3-cold-src1.douyinvod.com": {
"Domain": "v3-cold-src1.douyinvod.com",
"Count": 2,
"LastSeen": "2025-12-16T00:56:28.771013239+08:00",
"DNSSEC": false
},
"v3-cold-src2.douyinvod.com": {
"Domain": "v3-cold-src2.douyinvod.com",
"Count": 2,
"LastSeen": "2025-12-16T00:56:29.537685838+08:00",
"DNSSEC": false
},
"v5-ali-northeast.douyinvod.com": {
"Domain": "v5-ali-northeast.douyinvod.com",
"Count": 6,
"LastSeen": "2025-12-16T01:09:28.219836837+08:00",
"DNSSEC": false
},
"v5-gzb-hl-qn2-cn-coldy.douyinvod.com": {
"Domain": "v5-gzb-hl-qn2-cn-coldy.douyinvod.com",
"Count": 2,
"LastSeen": "2025-12-16T00:56:31.263238064+08:00",
"DNSSEC": false
},
"v5-gzb-hl-tc-cn-coldy-a.douyinvod.com": {
"Domain": "v5-gzb-hl-tc-cn-coldy-a.douyinvod.com",
"Count": 12,
"LastSeen": "2025-12-16T01:01:41.204686837+08:00",
"DNSSEC": false
},
"v5-gzb2-hl-ali-cn-coldy.douyinvod.com": {
"Domain": "v5-gzb2-hl-ali-cn-coldy.douyinvod.com",
"Count": 2,
"LastSeen": "2025-12-16T00:56:30.185221681+08:00",
"DNSSEC": false
},
"v5-se-bd-daily.douyinvod.com": {
"Domain": "v5-se-bd-daily.douyinvod.com",
"Count": 72,
"LastSeen": "2025-12-16T01:01:41.204345546+08:00",
"DNSSEC": false
},
"v5-se-jx-daily-cold.douyinvod.com": {
"Domain": "v5-se-jx-daily-cold.douyinvod.com",
"Count": 2,
"LastSeen": "2025-12-16T00:56:30.005220454+08:00",
"DNSSEC": false
},
"v5-se-qn-daily-cm-cold.douyinvod.com": {
"Domain": "v5-se-qn-daily-cm-cold.douyinvod.com",
"Count": 6,
"LastSeen": "2025-12-16T01:12:35.400019922+08:00",
"DNSSEC": false
},
"v95-bj-cold.douyinvod.com": {
"Domain": "v95-bj-cold.douyinvod.com",
"Count": 86,
"LastSeen": "2025-12-16T01:11:10.171494828+08:00",
"DNSSEC": false
},
"webcast.amemv.com": {
"Domain": "webcast.amemv.com",
"Count": 2,
"LastSeen": "2025-12-16T01:02:14.49107423+08:00",
"DNSSEC": false
},
"whoami.akamai.net": {
"Domain": "whoami.akamai.net",
"Count": 18,
"LastSeen": "2025-12-16T01:09:27.949998275+08:00",
"DNSSEC": false
},
"www.cctv.com": {
"Domain": "www.cctv.com",
"Count": 2,
"LastSeen": "2025-12-16T00:53:03.77980281+08:00",
"DNSSEC": false
},
"www.makeding.com": {
"Domain": "www.makeding.com",
"Count": 1,
"LastSeen": "2025-12-16T00:51:41.740245462+08:00",
"DNSSEC": false
}
},
"resolvedDomains": {
"": {
"Domain": "",
"Count": 1,
"LastSeen": "2025-12-16T00:20:54.619863811+08:00",
"DNSSEC": false
},
"delta.com": {
"Domain": "delta.com",
"Count": 1,
"LastSeen": "2025-12-16T00:53:33.578002695+08:00",
"DNSSEC": false
},
"dig.bdurl.net": {
"Domain": "dig.bdurl.net",
"Count": 1,
"LastSeen": "2025-12-16T01:02:14.515446999+08:00",
"DNSSEC": false
},
"dnssec.xyz": {
"Domain": "dnssec.xyz",
"Count": 2,
"LastSeen": "2025-12-16T01:11:49.58353264+08:00",
"DNSSEC": false
},
"example.com": {
"Domain": "example.com",
"Count": 7,
"LastSeen": "2025-12-16T01:11:37.696121452+08:00",
"DNSSEC": false
},
"example.com.1.amazehome.xyz": {
"Domain": "example.com.1.amazehome.xyz",
"Count": 2,
"LastSeen": "2025-12-16T00:24:06.45881199+08:00",
"DNSSEC": false
},
"example.com.amazehome.xyz": {
"Domain": "example.com.amazehome.xyz",
"Count": 6,
"LastSeen": "2025-12-16T01:11:37.578787298+08:00",
"DNSSEC": false
},
"lg.com": {
"Domain": "lg.com",
"Count": 1,
"LastSeen": "2025-12-16T00:53:43.9845998+08:00",
"DNSSEC": false
},
"metrics1-drcn.dt.dbankcloud.cn": {
"Domain": "metrics1-drcn.dt.dbankcloud.cn",
"Count": 1,
"LastSeen": "2025-12-16T01:08:19.365690393+08:00",
"DNSSEC": false
},
"pull-x4-q5-tsl.douyincdn.com": {
"Domain": "pull-x4-q5-tsl.douyincdn.com",
"Count": 1,
"LastSeen": "2025-12-16T00:20:33.570724485+08:00",
"DNSSEC": false
},
"so.com": {
"Domain": "so.com",
"Count": 2,
"LastSeen": "2025-12-16T00:21:54.173952653+08:00",
"DNSSEC": false
},
"so.com.amazehome.xyz": {
"Domain": "so.com.amazehome.xyz",
"Count": 2,
"LastSeen": "2025-12-16T00:21:54.1289594+08:00",
"DNSSEC": false
},
"vc-mirror.ndcpp.com": {
"Domain": "vc-mirror.ndcpp.com",
"Count": 1,
"LastSeen": "2025-12-16T00:56:30.999461533+08:00",
"DNSSEC": false
},
"vcl-brain-lf.ndcpp.com": {
"Domain": "vcl-brain-lf.ndcpp.com",
"Count": 1,
"LastSeen": "2025-12-16T00:56:38.428517286+08:00",
"DNSSEC": false
},
"www.cntv.cn": {
"Domain": "www.cntv.cn",
"Count": 1,
"LastSeen": "2025-12-16T00:52:38.706305541+08:00",
"DNSSEC": false
},
"www.ctv.com": {
"Domain": "www.ctv.com",
"Count": 1,
"LastSeen": "2025-12-16T00:52:57.73227397+08:00",
"DNSSEC": false
},
"www.example.com": {
"Domain": "www.example.com",
"Count": 4,
"LastSeen": "2025-12-16T01:11:56.939364975+08:00",
"DNSSEC": true
},
"www.facebook.com": {
"Domain": "www.facebook.com",
"Count": 1,
"LastSeen": "2025-12-16T00:51:49.35787273+08:00",
"DNSSEC": false
},
"www.so.com": {
"Domain": "www.so.com",
"Count": 2,
"LastSeen": "2025-12-16T00:50:02.298375031+08:00",
"DNSSEC": false
}
},
"clientStats": {
"10.35.10.11": {
"IP": "10.35.10.11",
"Count": 277,
"LastSeen": "2025-12-16T01:12:35.399834442+08:00"
},
"10.35.10.78": {
"IP": "10.35.10.78",
"Count": 182,
"LastSeen": "2025-12-16T01:12:31.71955342+08:00"
}
},
"hourlyStats": {
"2025-12-16-00": 151,
"2025-12-16-01": 138
},
"dailyStats": {
"2025-12-16": 289
},
"monthlyStats": {
"2025-12": 289
},
"lastSaved": "2025-12-16T01:12:54.109817779+08:00"
}

View File

@@ -1,3 +0,0 @@
# Hosts文件
# 格式IP 域名
# 例如127.0.0.1 localhost

View File

@@ -1,3 +0,0 @@
# 本地规则文件
# 格式:域名
# 例如example.com

View File

@@ -1,5 +0,0 @@
{
"blockedDomainsCount": {},
"resolvedDomainsCount": {},
"lastSaved": "2025-12-16T00:38:44.046867267+08:00"
}

View File

@@ -1,37 +0,0 @@
{
"stats": {
"Queries": 1,
"Blocked": 0,
"Allowed": 1,
"Errors": 0,
"LastQuery": "2025-12-16T00:38:14.408835937+08:00",
"AvgResponseTime": 6,
"TotalResponseTime": 6,
"QueryTypes": {
"A": 1
},
"SourceIPs": {
"127.0.0.1": true
},
"CpuUsage": 8.270676691729323
},
"blockedDomains": {},
"resolvedDomains": {
"google.com": {
"Domain": "google.com",
"Count": 1,
"LastSeen": "2025-12-16T00:38:14.416155945+08:00"
}
},
"clientStats": {
"127.0.0.1": {
"IP": "127.0.0.1",
"Count": 1,
"LastSeen": "2025-12-16T00:38:14.408844699+08:00"
}
},
"hourlyStats": {},
"dailyStats": {},
"monthlyStats": {},
"lastSaved": "2025-12-16T00:38:44.043395448+08:00"
}

Binary file not shown.

View File

@@ -11,6 +11,7 @@ import (
type DNSCacheItem struct { type DNSCacheItem struct {
Response *dns.Msg // DNS响应消息 Response *dns.Msg // DNS响应消息
Expiry time.Time // 过期时间 Expiry time.Time // 过期时间
HasDNSSEC bool // 是否包含DNSSEC记录
} }
// DNSCache DNS缓存结构 // DNSCache DNS缓存结构
@@ -38,6 +39,36 @@ func cacheKey(qName string, qType uint16) string {
return qName + "|" + dns.TypeToString[qType] return qName + "|" + dns.TypeToString[qType]
} }
// hasDNSSECRecords 检查响应是否包含DNSSEC记录
func hasDNSSECRecords(response *dns.Msg) bool {
// 检查响应中是否包含DNSKEY或RRSIG记录
for _, rr := range response.Answer {
if _, ok := rr.(*dns.DNSKEY); ok {
return true
}
if _, ok := rr.(*dns.RRSIG); ok {
return true
}
}
for _, rr := range response.Ns {
if _, ok := rr.(*dns.DNSKEY); ok {
return true
}
if _, ok := rr.(*dns.RRSIG); ok {
return true
}
}
for _, rr := range response.Extra {
if _, ok := rr.(*dns.DNSKEY); ok {
return true
}
if _, ok := rr.(*dns.RRSIG); ok {
return true
}
}
return false
}
// Set 设置缓存项 // Set 设置缓存项
func (c *DNSCache) Set(qName string, qType uint16, response *dns.Msg, ttl time.Duration) { func (c *DNSCache) Set(qName string, qType uint16, response *dns.Msg, ttl time.Duration) {
if ttl <= 0 { if ttl <= 0 {
@@ -48,6 +79,7 @@ func (c *DNSCache) Set(qName string, qType uint16, response *dns.Msg, ttl time.D
item := &DNSCacheItem{ item := &DNSCacheItem{
Response: response.Copy(), // 复制响应以避免外部修改 Response: response.Copy(), // 复制响应以避免外部修改
Expiry: time.Now().Add(ttl), Expiry: time.Now().Add(ttl),
HasDNSSEC: hasDNSSECRecords(response), // 检查并设置DNSSEC标志
} }
c.mutex.Lock() c.mutex.Lock()

View File

@@ -129,6 +129,10 @@ type Stats struct {
QueryTypes map[string]int64 // 查询类型统计 QueryTypes map[string]int64 // 查询类型统计
SourceIPs map[string]bool // 活跃来源IP SourceIPs map[string]bool // 活跃来源IP
CpuUsage float64 // CPU使用率(%) CpuUsage float64 // CPU使用率(%)
DNSSECQueries int64 // DNSSEC查询总数
DNSSECSuccess int64 // DNSSEC验证成功数
DNSSECFailed int64 // DNSSEC验证失败数
DNSSECEnabled bool // 是否启用了DNSSEC
} }
// NewServer 创建DNS服务器实例 // NewServer 创建DNS服务器实例
@@ -160,6 +164,10 @@ func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shie
QueryTypes: make(map[string]int64), QueryTypes: make(map[string]int64),
SourceIPs: make(map[string]bool), SourceIPs: make(map[string]bool),
CpuUsage: 0, CpuUsage: 0,
DNSSECQueries: 0,
DNSSECSuccess: 0,
DNSSECFailed: 0,
DNSSECEnabled: config.EnableDNSSEC,
}, },
blockedDomains: make(map[string]*BlockedDomain), blockedDomains: make(map[string]*BlockedDomain),
resolvedDomains: make(map[string]*BlockedDomain), resolvedDomains: make(map[string]*BlockedDomain),
@@ -387,8 +395,27 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
return return
} }
// 检查缓存中是否有响应(增强版缓存查询 // 检查缓存中是否有响应(优先查找带DNSSEC的缓存项
if cachedResponse, found := s.dnsCache.Get(r.Question[0].Name, qType); found { var cachedResponse *dns.Msg
var found bool
var cachedDNSSEC bool
// 1. 首先检查是否有普通缓存项
if tempResponse, tempFound := s.dnsCache.Get(r.Question[0].Name, qType); tempFound {
cachedResponse = tempResponse
found = tempFound
cachedDNSSEC = s.hasDNSSECRecords(tempResponse)
}
// 2. 如果启用了DNSSEC且没有找到带DNSSEC的缓存项
// 尝试从所有缓存中查找是否有其他响应包含DNSSEC记录
// 这里可以进一步优化比如在缓存中标记DNSSEC状态快速查找
if s.config.EnableDNSSEC && !cachedDNSSEC {
// 目前的缓存实现不支持按DNSSEC状态查找所以这里暂时跳过
// 后续可以考虑改进缓存实现添加DNSSEC状态标记
}
if found {
// 缓存命中,直接返回缓存的响应 // 缓存命中,直接返回缓存的响应
cachedResponseCopy := cachedResponse.Copy() // 创建响应副本避免并发修改问题 cachedResponseCopy := cachedResponse.Copy() // 创建响应副本避免并发修改问题
cachedResponseCopy.Id = r.Id // 更新ID以匹配请求 cachedResponseCopy.Id = r.Id // 更新ID以匹配请求
@@ -404,30 +431,18 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
} }
}) })
// 检查缓存响应是否包含DNSSEC记录 // 如果缓存响应包含DNSSEC记录更新DNSSEC查询计数
cachedDNSSEC := false if cachedDNSSEC {
for _, rr := range cachedResponse.Answer { s.updateStats(func(stats *Stats) {
if _, ok := rr.(*dns.RRSIG); ok { stats.DNSSECQueries++
cachedDNSSEC = true // 缓存响应视为DNSSEC成功
break stats.DNSSECSuccess++
} })
}
for _, rr := range cachedResponse.Ns {
if _, ok := rr.(*dns.RRSIG); ok {
cachedDNSSEC = true
break
}
}
for _, rr := range cachedResponse.Extra {
if _, ok := rr.(*dns.RRSIG); ok {
cachedDNSSEC = true
break
}
} }
// 添加查询日志 - 标记为缓存 // 添加查询日志 - 标记为缓存
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", true, cachedDNSSEC) s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", true, cachedDNSSEC)
logger.Debug("从缓存返回DNS响应", "domain", domain, "type", queryType) logger.Debug("从缓存返回DNS响应", "domain", domain, "type", queryType, "dnssec", cachedDNSSEC)
return return
} }
@@ -452,26 +467,15 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
} }
}) })
// 检查响应是否包含DNSSEC记录 // 检查响应是否包含DNSSEC记录并验证结果
responseDNSSEC := false responseDNSSEC := false
if response != nil { if response != nil {
for _, rr := range response.Answer { // 使用hasDNSSECRecords函数检查是否包含DNSSEC记录
if _, ok := rr.(*dns.RRSIG); ok { responseDNSSEC = s.hasDNSSECRecords(response)
// 检查AD标志确认DNSSEC验证是否成功
if response.AuthenticatedData {
responseDNSSEC = true responseDNSSEC = true
break
}
}
for _, rr := range response.Ns {
if _, ok := rr.(*dns.RRSIG); ok {
responseDNSSEC = true
break
}
}
for _, rr := range response.Extra {
if _, ok := rr.(*dns.RRSIG); ok {
responseDNSSEC = true
break
}
} }
// 更新域名的DNSSEC状态 // 更新域名的DNSSEC状态
@@ -487,7 +491,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
// 设置合理的TTL不超过默认的30分钟 // 设置合理的TTL不超过默认的30分钟
defaultCacheTTL := 30 * time.Minute defaultCacheTTL := 30 * time.Minute
s.dnsCache.Set(r.Question[0].Name, qType, responseCopy, defaultCacheTTL) s.dnsCache.Set(r.Question[0].Name, qType, responseCopy, defaultCacheTTL)
logger.Debug("DNS响应已缓存", "domain", domain, "type", queryType, "ttl", defaultCacheTTL) logger.Debug("DNS响应已缓存", "domain", domain, "type", queryType, "ttl", defaultCacheTTL, "dnssec", responseDNSSEC)
} }
// 添加查询日志 - 标记为实时 // 添加查询日志 - 标记为实时
@@ -598,142 +602,139 @@ func (s *Server) handleBlockedResponse(w dns.ResponseWriter, r *dns.Msg, domain
// forwardDNSRequestWithCache 转发DNS请求到上游服务器并返回响应 // forwardDNSRequestWithCache 转发DNS请求到上游服务器并返回响应
func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg, time.Duration) { func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg, time.Duration) {
// 尝试所有上游DNS服务器 // 尝试所有上游DNS服务器
var bestResponse *dns.Msg
var bestRtt time.Duration
var hasBestResponse bool
var hasDNSSECResponse bool
var backupResponse *dns.Msg var backupResponse *dns.Msg
var backupRtt time.Duration var backupRtt time.Duration
var hasBackup bool var hasBackup bool
// DNSSEC专用服务器列表从配置中获取
dnssecServers := s.config.DNSSECUpstreamDNS
// 1. 首先尝试所有配置的上游DNS服务器
for _, upstream := range s.config.UpstreamDNS { for _, upstream := range s.config.UpstreamDNS {
response, rtt, err := s.resolver.Exchange(r, upstream) response, rtt, err := s.resolver.Exchange(r, upstream)
if err == nil && response != nil { if err == nil && response != nil {
// 设置递归可用标志 // 设置递归可用标志
response.RecursionAvailable = true response.RecursionAvailable = true
// 完整DNSSEC支持验证DNSSEC签名 // 检查是否包含DNSSEC记录
if s.config.EnableDNSSEC { containsDNSSEC := s.hasDNSSECRecords(response)
// 提取DNSKEY和RRSIG记录
dnskeys := make(map[uint16]*dns.DNSKEY) // KeyTag -> DNSKEY
rrsigs := make([]*dns.RRSIG, 0)
// 从响应中提取所有DNSKEY和RRSIG记录 // 如果响应成功根据DNSSEC状态选择最佳响应
for _, rr := range response.Answer { if response.Rcode == dns.RcodeSuccess {
if dnskey, ok := rr.(*dns.DNSKEY); ok { // 优先选择带有DNSSEC记录的响应
tag := dnskey.KeyTag() if containsDNSSEC {
dnskeys[tag] = dnskey bestResponse = response
} else if rrsig, ok := rr.(*dns.RRSIG); ok { bestRtt = rtt
rrsigs = append(rrsigs, rrsig) hasBestResponse = true
hasDNSSECResponse = true
logger.Debug("找到带DNSSEC的最佳响应", "domain", domain, "server", upstream, "rtt", rtt)
} else if !hasBestResponse {
// 没有带DNSSEC的响应时保存第一个成功响应
bestResponse = response
bestRtt = rtt
hasBestResponse = true
logger.Debug("找到最佳响应", "domain", domain, "server", upstream, "rtt", rtt)
}
// 保存为备选响应
if !hasBackup {
backupResponse = response
backupRtt = rtt
hasBackup = true
} }
} }
for _, rr := range response.Ns {
if dnskey, ok := rr.(*dns.DNSKEY); ok {
tag := dnskey.KeyTag()
dnskeys[tag] = dnskey
} else if rrsig, ok := rr.(*dns.RRSIG); ok {
rrsigs = append(rrsigs, rrsig)
}
}
for _, rr := range response.Extra {
if dnskey, ok := rr.(*dns.DNSKEY); ok {
tag := dnskey.KeyTag()
dnskeys[tag] = dnskey
} else if rrsig, ok := rr.(*dns.RRSIG); ok {
rrsigs = append(rrsigs, rrsig)
} }
} }
// 如果有RRSIG记录尝试验证签名 // 2. 当启用DNSSEC且没有找到带DNSSEC的响应时向DNSSEC专用服务器发送请求
if len(rrsigs) > 0 { if s.config.EnableDNSSEC && !hasDNSSECResponse {
logger.Debug("DNS响应包含DNSSEC记录", "domain", domain, "server", upstream, "rrsig_count", len(rrsigs), "dnskey_count", len(dnskeys)) logger.Debug("向DNSSEC专用服务器发送请求", "domain", domain)
// 验证签名 // 增加DNSSEC查询计数
signatureValid := true s.updateStats(func(stats *Stats) {
for _, rrsig := range rrsigs { stats.DNSSECQueries++
// 查找对应的DNSKEY })
dnskey, exists := dnskeys[rrsig.KeyTag]
if !exists {
logger.Warn("DNSSEC验证失败找不到对应的DNSKEY", "domain", domain, "server", upstream, "key_tag", rrsig.KeyTag)
signatureValid = false
continue
}
// 收集需要验证的记录集 for _, dnssecServer := range dnssecServers {
rrset := make([]dns.RR, 0) response, rtt, err := s.resolver.Exchange(r, dnssecServer)
for _, rr := range response.Answer { if err == nil && response != nil {
if rr.Header().Name == rrsig.Header().Name && rr.Header().Rrtype == rrsig.TypeCovered { // 设置递归可用标志
rrset = append(rrset, rr) response.RecursionAvailable = true
}
}
for _, rr := range response.Ns {
if rr.Header().Name == rrsig.Header().Name && rr.Header().Rrtype == rrsig.TypeCovered {
rrset = append(rrset, rr)
}
}
// 验证签名 // 检查是否包含DNSSEC记录
if len(rrset) > 0 { containsDNSSEC := s.hasDNSSECRecords(response)
err := rrsig.Verify(dnskey, rrset)
if err != nil { if response.Rcode == dns.RcodeSuccess {
logger.Warn("DNSSEC签名验证失败", "domain", domain, "server", upstream, "error", err, "key_tag", rrsig.KeyTag) // 验证DNSSEC记录
signatureValid = false signatureValid := s.verifyDNSSEC(response)
} else {
logger.Debug("DNSSEC签名验证成功", "domain", domain, "server", upstream, "key_tag", rrsig.KeyTag)
}
}
}
// 设置AD标志Authenticated Data // 设置AD标志Authenticated Data
response.AuthenticatedData = signatureValid response.AuthenticatedData = signatureValid
if !signatureValid {
logger.Warn("DNSSEC验证失败至少一个签名无效", "domain", domain, "server", upstream) if signatureValid {
// 更新DNSSEC验证成功计数
s.updateStats(func(stats *Stats) {
stats.DNSSECSuccess++
})
} else {
// 更新DNSSEC验证失败计数
s.updateStats(func(stats *Stats) {
stats.DNSSECFailed++
})
} }
// 如果响应成功且包含DNSSEC记录,优先返回 // 优先使用DNSSEC专用服务器的响应尤其是带有DNSSEC记录
if response.Rcode == dns.RcodeSuccess { if containsDNSSEC {
logger.Debug("DNS查询成功优先返回DNSSEC结果", "domain", domain, "server", upstream, "rtt", rtt) // 即使之前有最佳响应也优先使用DNSSEC专用服务器的DNSSEC响应
bestResponse = response
bestRtt = rtt
hasBestResponse = true
hasDNSSECResponse = true
logger.Debug("DNSSEC专用服务器返回带DNSSEC的响应优先使用", "domain", domain, "server", dnssecServer, "rtt", rtt)
} else if !hasBestResponse || hasBestResponse && !s.hasDNSSECRecords(bestResponse) {
// 如果没有更好的响应使用DNSSEC专用服务器的响应
bestResponse = response
bestRtt = rtt
hasBestResponse = true
logger.Debug("使用DNSSEC专用服务器的响应", "domain", domain, "server", dnssecServer, "rtt", rtt)
}
// 更新备选响应
if !hasBackup {
backupResponse = response
backupRtt = rtt
hasBackup = true
}
}
}
}
}
// 3. 返回最佳响应
if hasBestResponse {
// 记录解析域名统计 // 记录解析域名统计
s.updateResolvedDomainStats(domain) s.updateResolvedDomainStats(domain)
// 检查最佳响应是否包含DNSSEC记录
bestHasDNSSEC := s.hasDNSSECRecords(bestResponse)
// 更新域名的DNSSEC状态
if bestHasDNSSEC {
s.updateDomainDNSSECStatus(domain, true)
}
s.updateStats(func(stats *Stats) { s.updateStats(func(stats *Stats) {
stats.Allowed++ stats.Allowed++
}) })
return response, rtt return bestResponse, bestRtt
}
} else {
logger.Debug("DNS响应不包含DNSSEC记录", "domain", domain, "server", upstream)
// 如果响应成功,保存为备选响应
if response.Rcode == dns.RcodeSuccess && !hasBackup {
backupResponse = response
backupRtt = rtt
hasBackup = true
logger.Debug("保存为备选响应", "domain", domain, "server", upstream, "rtt", rtt)
}
}
} else {
// DNSSEC已禁用使用原有逻辑
if response.Rcode == dns.RcodeSuccess {
logger.Debug("DNS查询成功", "domain", domain, "rtt", rtt, "server", upstream)
// 记录解析域名统计
s.updateResolvedDomainStats(domain)
s.updateStats(func(stats *Stats) {
stats.Allowed++
})
return response, rtt
}
}
} else if !hasBackup && response != nil && response.Rcode == dns.RcodeSuccess {
// 保存第一个成功但有错误的响应作为备选
backupResponse = response
backupRtt = rtt
hasBackup = true
logger.Debug("保存为备选响应", "domain", domain, "server", upstream, "rtt", rtt)
}
} }
// 如果有备选响应,返回该响应 // 如果有备选响应,返回该响应
if hasBackup { if hasBackup {
logger.Debug("使用备选响应,没有找到包含DNSSEC的结果", "domain", domain) logger.Debug("使用备选响应,没有找到更好的结果", "domain", domain)
// 记录解析域名统计 // 记录解析域名统计
s.updateResolvedDomainStats(domain) s.updateResolvedDomainStats(domain)
@@ -818,6 +819,112 @@ func (s *Server) updateClientStats(ip string) {
} }
} }
// hasDNSSECRecords 检查响应是否包含DNSSEC记录
func (s *Server) hasDNSSECRecords(response *dns.Msg) bool {
// 检查响应中是否包含DNSKEY或RRSIG记录
for _, rr := range response.Answer {
if _, ok := rr.(*dns.DNSKEY); ok {
return true
}
if _, ok := rr.(*dns.RRSIG); ok {
return true
}
}
for _, rr := range response.Ns {
if _, ok := rr.(*dns.DNSKEY); ok {
return true
}
if _, ok := rr.(*dns.RRSIG); ok {
return true
}
}
for _, rr := range response.Extra {
if _, ok := rr.(*dns.DNSKEY); ok {
return true
}
if _, ok := rr.(*dns.RRSIG); ok {
return true
}
}
return false
}
// verifyDNSSEC 验证DNSSEC签名
func (s *Server) verifyDNSSEC(response *dns.Msg) bool {
// 提取DNSKEY和RRSIG记录
dnskeys := make(map[uint16]*dns.DNSKEY) // KeyTag -> DNSKEY
rrsigs := make([]*dns.RRSIG, 0)
// 从响应中提取所有DNSKEY和RRSIG记录
for _, rr := range response.Answer {
if dnskey, ok := rr.(*dns.DNSKEY); ok {
tag := dnskey.KeyTag()
dnskeys[tag] = dnskey
} else if rrsig, ok := rr.(*dns.RRSIG); ok {
rrsigs = append(rrsigs, rrsig)
}
}
for _, rr := range response.Ns {
if dnskey, ok := rr.(*dns.DNSKEY); ok {
tag := dnskey.KeyTag()
dnskeys[tag] = dnskey
} else if rrsig, ok := rr.(*dns.RRSIG); ok {
rrsigs = append(rrsigs, rrsig)
}
}
for _, rr := range response.Extra {
if dnskey, ok := rr.(*dns.DNSKEY); ok {
tag := dnskey.KeyTag()
dnskeys[tag] = dnskey
} else if rrsig, ok := rr.(*dns.RRSIG); ok {
rrsigs = append(rrsigs, rrsig)
}
}
// 如果没有RRSIG记录验证失败
if len(rrsigs) == 0 {
return false
}
// 验证所有RRSIG记录
signatureValid := true
for _, rrsig := range rrsigs {
// 查找对应的DNSKEY
dnskey, exists := dnskeys[rrsig.KeyTag]
if !exists {
logger.Warn("DNSSEC验证失败找不到对应的DNSKEY", "key_tag", rrsig.KeyTag)
signatureValid = false
continue
}
// 收集需要验证的记录集
rrset := make([]dns.RR, 0)
for _, rr := range response.Answer {
if rr.Header().Name == rrsig.Header().Name && rr.Header().Rrtype == rrsig.TypeCovered {
rrset = append(rrset, rr)
}
}
for _, rr := range response.Ns {
if rr.Header().Name == rrsig.Header().Name && rr.Header().Rrtype == rrsig.TypeCovered {
rrset = append(rrset, rr)
}
}
// 验证签名
if len(rrset) > 0 {
err := rrsig.Verify(dnskey, rrset)
if err != nil {
logger.Warn("DNSSEC签名验证失败", "error", err, "key_tag", rrsig.KeyTag)
signatureValid = false
} else {
logger.Debug("DNSSEC签名验证成功", "key_tag", rrsig.KeyTag)
}
}
}
return signatureValid
}
// updateDomainDNSSECStatus 更新域名的DNSSEC状态 // updateDomainDNSSECStatus 更新域名的DNSSEC状态
func (s *Server) updateDomainDNSSECStatus(domain string, dnssec bool) { func (s *Server) updateDomainDNSSECStatus(domain string, dnssec bool) {
// 确保域名是小写 // 确保域名是小写
@@ -935,6 +1042,10 @@ func (s *Server) GetStats() *Stats {
QueryTypes: queryTypesCopy, QueryTypes: queryTypesCopy,
SourceIPs: sourceIPsCopy, SourceIPs: sourceIPsCopy,
CpuUsage: s.stats.CpuUsage, CpuUsage: s.stats.CpuUsage,
DNSSECQueries: s.stats.DNSSECQueries,
DNSSECSuccess: s.stats.DNSSECSuccess,
DNSSECFailed: s.stats.DNSSECFailed,
DNSSECEnabled: s.stats.DNSSECEnabled,
} }
} }
@@ -1360,6 +1471,8 @@ func (s *Server) loadStatsData() {
s.statsMutex.Lock() s.statsMutex.Lock()
if statsData.Stats != nil { if statsData.Stats != nil {
s.stats = statsData.Stats s.stats = statsData.Stats
// 确保使用当前配置中的EnableDNSSEC值覆盖从文件加载的值
s.stats.DNSSECEnabled = s.config.EnableDNSSEC
} }
s.statsMutex.Unlock() s.statsMutex.Unlock()

View File

@@ -219,6 +219,12 @@ func (s *Server) handleStats(w http.ResponseWriter, r *http.Request) {
// 格式化平均响应时间为两位小数 // 格式化平均响应时间为两位小数
formattedResponseTime := float64(int(dnsStats.AvgResponseTime*100)) / 100 formattedResponseTime := float64(int(dnsStats.AvgResponseTime*100)) / 100
// 计算DNSSEC使用率
dnssecUsage := float64(0)
if dnsStats.Queries > 0 {
dnssecUsage = float64(dnsStats.DNSSECQueries) / float64(dnsStats.Queries) * 100
}
// 构建响应数据,确保所有字段都反映服务器的真实状态 // 构建响应数据,确保所有字段都反映服务器的真实状态
stats := map[string]interface{}{ stats := map[string]interface{}{
"dns": map[string]interface{}{ "dns": map[string]interface{}{
@@ -232,12 +238,21 @@ func (s *Server) handleStats(w http.ResponseWriter, r *http.Request) {
"QueryTypes": dnsStats.QueryTypes, "QueryTypes": dnsStats.QueryTypes,
"SourceIPs": dnsStats.SourceIPs, "SourceIPs": dnsStats.SourceIPs,
"CpuUsage": dnsStats.CpuUsage, "CpuUsage": dnsStats.CpuUsage,
"DNSSECQueries": dnsStats.DNSSECQueries,
"DNSSECSuccess": dnsStats.DNSSECSuccess,
"DNSSECFailed": dnsStats.DNSSECFailed,
"DNSSECEnabled": dnsStats.DNSSECEnabled,
}, },
"shield": shieldStats, "shield": shieldStats,
"topQueryType": topQueryType, "topQueryType": topQueryType,
"activeIPs": activeIPCount, "activeIPs": activeIPCount,
"avgResponseTime": formattedResponseTime, "avgResponseTime": formattedResponseTime,
"cpuUsage": dnsStats.CpuUsage, "cpuUsage": dnsStats.CpuUsage,
"dnssecEnabled": dnsStats.DNSSECEnabled,
"dnssecQueries": dnsStats.DNSSECQueries,
"dnssecSuccess": dnsStats.DNSSECSuccess,
"dnssecFailed": dnsStats.DNSSECFailed,
"dnssecUsage": float64(int(dnssecUsage*100)) / 100, // 保留两位小数
"time": time.Now(), "time": time.Now(),
} }
@@ -355,6 +370,12 @@ func (s *Server) buildStatsData() map[string]interface{} {
// 格式化平均响应时间 // 格式化平均响应时间
formattedResponseTime := float64(int(dnsStats.AvgResponseTime*100)) / 100 formattedResponseTime := float64(int(dnsStats.AvgResponseTime*100)) / 100
// 计算DNSSEC使用率
dnssecUsage := float64(0)
if dnsStats.Queries > 0 {
dnssecUsage = float64(dnsStats.DNSSECQueries) / float64(dnsStats.Queries) * 100
}
return map[string]interface{}{ return map[string]interface{}{
"dns": map[string]interface{}{ "dns": map[string]interface{}{
"Queries": dnsStats.Queries, "Queries": dnsStats.Queries,
@@ -367,12 +388,21 @@ func (s *Server) buildStatsData() map[string]interface{} {
"QueryTypes": dnsStats.QueryTypes, "QueryTypes": dnsStats.QueryTypes,
"SourceIPs": dnsStats.SourceIPs, "SourceIPs": dnsStats.SourceIPs,
"CpuUsage": dnsStats.CpuUsage, "CpuUsage": dnsStats.CpuUsage,
"DNSSECQueries": dnsStats.DNSSECQueries,
"DNSSECSuccess": dnsStats.DNSSECSuccess,
"DNSSECFailed": dnsStats.DNSSECFailed,
"DNSSECEnabled": dnsStats.DNSSECEnabled,
}, },
"shield": shieldStats, "shield": shieldStats,
"topQueryType": topQueryType, "topQueryType": topQueryType,
"activeIPs": activeIPCount, "activeIPs": activeIPCount,
"avgResponseTime": formattedResponseTime, "avgResponseTime": formattedResponseTime,
"cpuUsage": dnsStats.CpuUsage, "cpuUsage": dnsStats.CpuUsage,
"dnssecEnabled": dnsStats.DNSSECEnabled,
"dnssecQueries": dnsStats.DNSSECQueries,
"dnssecSuccess": dnsStats.DNSSECSuccess,
"dnssecFailed": dnsStats.DNSSECFailed,
"dnssecUsage": float64(int(dnssecUsage*100)) / 100, // 保留两位小数
} }
} }
@@ -709,19 +739,25 @@ func (s *Server) handleTopDomains(w http.ResponseWriter, r *http.Request) {
// 合并并去重域名统计 // 合并并去重域名统计
domainMap := make(map[string]int64) domainMap := make(map[string]int64)
dnssecStatusMap := make(map[string]bool)
for _, domain := range blockedDomains { for _, domain := range blockedDomains {
domainMap[domain.Domain] += domain.Count domainMap[domain.Domain] += domain.Count
dnssecStatusMap[domain.Domain] = domain.DNSSEC
} }
for _, domain := range resolvedDomains { for _, domain := range resolvedDomains {
domainMap[domain.Domain] += domain.Count domainMap[domain.Domain] += domain.Count
dnssecStatusMap[domain.Domain] = domain.DNSSEC
} }
// 转换为切片并排序 // 转换为切片并排序
domainList := make([]map[string]interface{}, 0, len(domainMap)) domainList := make([]map[string]interface{}, 0, len(domainMap))
for domain, count := range domainMap { for domain, count := range domainMap {
dnssec, hasDNSSEC := dnssecStatusMap[domain]
domainList = append(domainList, map[string]interface{}{ domainList = append(domainList, map[string]interface{}{
"domain": domain, "domain": domain,
"count": count, "count": count,
"dnssec": hasDNSSEC && dnssec,
}) })
} }

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +0,0 @@
{
"blockedDomainsCount": {},
"resolvedDomainsCount": {},
"lastSaved": "2025-11-29T02:08:50.6341349+08:00"
}

176
start-dns-server.sh Executable file
View File

@@ -0,0 +1,176 @@
#!/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-serverPID: ${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 "$@"

View File

@@ -334,6 +334,42 @@
</div> </div>
</div> </div>
<!-- DNSSEC使用率卡片 -->
<div class="bg-white rounded-lg p-4 card-shadow relative overflow-hidden">
<!-- 颜色蒙版 -->
<div class="absolute -bottom-8 -right-8 w-24 h-24 rounded-full bg-primary opacity-10"></div>
<div class="relative z-10">
<div class="flex items-center justify-between mb-4">
<h3 class="text-gray-500 font-medium">DNSSEC使用率</h3>
<div class="p-2 rounded-full bg-primary/10 text-primary">
<i class="fa fa-lock"></i>
</div>
</div>
<div class="mb-2">
<div class="flex items-end justify-between">
<p class="text-3xl font-bold" id="dnssec-usage">0%</p>
<span class="text-primary text-sm flex items-center">
<i class="fa fa-check mr-1"></i>
<span id="dnssec-status">已禁用</span>
</span>
</div>
</div>
<div class="flex items-center space-x-4 text-xs text-gray-500">
<div class="flex items-center">
<span class="w-2 h-2 bg-green-500 rounded-full mr-1"></span>
<span>成功: <span id="dnssec-success">0</span></span>
</div>
<div class="flex items-center">
<span class="w-2 h-2 bg-red-500 rounded-full mr-1"></span>
<span>失败: <span id="dnssec-failed">0</span></span>
</div>
<div class="flex items-center">
<span class="w-2 h-2 bg-blue-500 rounded-full mr-1"></span>
<span>总查询: <span id="dnssec-queries">0</span></span>
</div>
</div>
</div>
</div>
</div> </div>

View File

@@ -1018,6 +1018,60 @@ function updateStatsCards(stats) {
animateValue('error-queries', errorQueries); animateValue('error-queries', errorQueries);
animateValue('active-ips', activeIPs); animateValue('active-ips', activeIPs);
// DNSSEC相关数据
let dnssecEnabled = false, dnssecQueries = 0, dnssecSuccess = 0, dnssecFailed = 0, dnssecUsage = 0;
// 检查DNSSEC数据
if (stats) {
// 优先使用顶层字段
dnssecEnabled = stats.dnssecEnabled || false;
dnssecQueries = stats.dnssecQueries || 0;
dnssecSuccess = stats.dnssecSuccess || 0;
dnssecFailed = stats.dnssecFailed || 0;
dnssecUsage = stats.dnssecUsage || 0;
// 如果dns对象存在优先使用其中的数据
if (stats.dns) {
dnssecEnabled = stats.dns.DNSSECEnabled || dnssecEnabled;
dnssecQueries = stats.dns.DNSSECQueries || dnssecQueries;
dnssecSuccess = stats.dns.DNSSECSuccess || dnssecSuccess;
dnssecFailed = stats.dns.DNSSECFailed || dnssecFailed;
}
// 如果没有直接提供使用率,计算使用率
if (dnssecUsage === 0 && totalQueries > 0) {
dnssecUsage = (dnssecQueries / totalQueries) * 100;
}
}
// 更新DNSSEC统计卡片
const dnssecUsageElement = document.getElementById('dnssec-usage');
const dnssecStatusElement = document.getElementById('dnssec-status');
const dnssecSuccessElement = document.getElementById('dnssec-success');
const dnssecFailedElement = document.getElementById('dnssec-failed');
const dnssecQueriesElement = document.getElementById('dnssec-queries');
if (dnssecUsageElement) {
dnssecUsageElement.textContent = `${Math.round(dnssecUsage)}%`;
}
if (dnssecStatusElement) {
dnssecStatusElement.textContent = dnssecEnabled ? '已启用' : '已禁用';
dnssecStatusElement.className = `text-sm flex items-center ${dnssecEnabled ? 'text-success' : 'text-danger'}`;
}
if (dnssecSuccessElement) {
dnssecSuccessElement.textContent = formatNumber(dnssecSuccess);
}
if (dnssecFailedElement) {
dnssecFailedElement.textContent = formatNumber(dnssecFailed);
}
if (dnssecQueriesElement) {
dnssecQueriesElement.textContent = formatNumber(dnssecQueries);
}
// 直接更新文本和百分比,移除动画效果 // 直接更新文本和百分比,移除动画效果
const topQueryTypeElement = document.getElementById('top-query-type'); const topQueryTypeElement = document.getElementById('top-query-type');
const queryTypePercentageElement = document.getElementById('query-type-percentage'); const queryTypePercentageElement = document.getElementById('query-type-percentage');

View File

@@ -1,24 +0,0 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./static/**/*.{html,js}",
],
theme: {
extend: {
colors: {
primary: '#165DFF',
secondary: '#36CFFB',
success: '#00B42A',
warning: '#FF7D00',
danger: '#F53F3F',
info: '#86909C',
dark: '#1D2129',
light: '#F2F3F5',
},
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
},
},
},
plugins: [],
}