DNSSEC逻辑优化

This commit is contained in:
Alex Yang
2025-12-16 01:14:04 +08:00
parent 0b365e6dfe
commit fb3b28c22f
8 changed files with 6056 additions and 172 deletions

View File

@@ -23,11 +23,11 @@ import (
)
// BlockedDomain 屏蔽域名统计
type BlockedDomain struct {
Domain string
Count int64
LastSeen time.Time
DNSSEC bool // 是否使用了DNSSEC
}
// ClientStats 客户端统计
@@ -57,6 +57,7 @@ type QueryLog struct {
BlockRule string // 屏蔽规则(如果被屏蔽)
BlockType string // 屏蔽类型(如果被屏蔽)
FromCache bool // 是否来自缓存
DNSSEC bool // 是否使用了DNSSEC
}
// StatsData 用于持久化的统计数据结构
@@ -111,6 +112,9 @@ type Server struct {
// DNS查询缓存
dnsCache *DNSCache // DNS响应缓存
// 域名DNSSEC状态映射表
domainDNSSECStatus map[string]bool // 域名到DNSSEC状态的映射
}
// Stats DNS服务器统计信息
@@ -172,6 +176,8 @@ func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shie
ipGeolocationCacheTTL: 24 * time.Hour, // 缓存有效期24小时
// DNS查询缓存初始化
dnsCache: NewDNSCache(cacheTTL),
// 初始化域名DNSSEC状态映射表
domainDNSSECStatus: make(map[string]bool),
}
// 加载已保存的统计数据
@@ -338,7 +344,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
})
// 添加查询日志
s.addQueryLog(sourceIP, domain, queryType, responseTime, "error", "", "", false)
s.addQueryLog(sourceIP, domain, queryType, responseTime, "error", "", "", false, false)
return
}
@@ -355,7 +361,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
})
// 添加查询日志
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", false)
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", false, false)
return
}
@@ -377,7 +383,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
})
// 添加查询日志
s.addQueryLog(sourceIP, domain, queryType, responseTime, "blocked", blockRule, blockType, false)
s.addQueryLog(sourceIP, domain, queryType, responseTime, "blocked", blockRule, blockType, false, false)
return
}
@@ -398,8 +404,29 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
}
})
// 检查缓存响应是否包含DNSSEC记录
cachedDNSSEC := false
for _, rr := range cachedResponse.Answer {
if _, ok := rr.(*dns.RRSIG); ok {
cachedDNSSEC = true
break
}
}
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)
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", true, cachedDNSSEC)
logger.Debug("从缓存返回DNS响应", "domain", domain, "type", queryType)
return
}
@@ -425,6 +452,34 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
}
})
// 检查响应是否包含DNSSEC记录
responseDNSSEC := false
if response != nil {
for _, rr := range response.Answer {
if _, ok := rr.(*dns.RRSIG); ok {
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状态
if responseDNSSEC {
s.updateDomainDNSSECStatus(domain, true)
}
}
// 如果响应成功,缓存结果(增强版缓存存储)
if response != nil && response.Rcode == dns.RcodeSuccess {
// 创建响应副本以避免后续修改影响缓存
@@ -436,7 +491,7 @@ func (s *Server) handleDNSRequest(w dns.ResponseWriter, r *dns.Msg) {
}
// 添加查询日志 - 标记为实时
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", false)
s.addQueryLog(sourceIP, domain, queryType, responseTime, "allowed", "", "", false, responseDNSSEC)
}
// handleHostsResponse 处理hosts文件匹配的响应
@@ -543,6 +598,10 @@ func (s *Server) handleBlockedResponse(w dns.ResponseWriter, r *dns.Msg, domain
// forwardDNSRequestWithCache 转发DNS请求到上游服务器并返回响应
func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg, time.Duration) {
// 尝试所有上游DNS服务器
var backupResponse *dns.Msg
var backupRtt time.Duration
var hasBackup bool
for _, upstream := range s.config.UpstreamDNS {
response, rtt, err := s.resolver.Exchange(r, upstream)
if err == nil && response != nil {
@@ -626,25 +685,64 @@ func (s *Server) forwardDNSRequestWithCache(r *dns.Msg, domain string) (*dns.Msg
if !signatureValid {
logger.Warn("DNSSEC验证失败至少一个签名无效", "domain", domain, "server", upstream)
}
// 如果响应成功且包含DNSSEC记录优先返回
if response.Rcode == dns.RcodeSuccess {
logger.Debug("DNS查询成功优先返回DNSSEC结果", "domain", domain, "server", upstream, "rtt", rtt)
// 记录解析域名统计
s.updateResolvedDomainStats(domain)
s.updateStats(func(stats *Stats) {
stats.Allowed++
})
return response, rtt
}
} 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
}
}
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 {
logger.Debug("使用备选响应没有找到包含DNSSEC的结果", "domain", domain)
// 记录解析域名统计
s.updateResolvedDomainStats(domain)
s.updateStats(func(stats *Stats) {
stats.Allowed++
})
return backupResponse, backupRtt
}
// 所有上游服务器都失败,返回服务器失败错误
response := new(dns.Msg)
response.SetReply(r)
@@ -720,6 +818,31 @@ func (s *Server) updateClientStats(ip string) {
}
}
// updateDomainDNSSECStatus 更新域名的DNSSEC状态
func (s *Server) updateDomainDNSSECStatus(domain string, dnssec bool) {
// 确保域名是小写
domain = strings.ToLower(domain)
// 更新域名的DNSSEC状态
s.resolvedDomainsMutex.Lock()
defer s.resolvedDomainsMutex.Unlock()
// 更新resolvedDomains中的DNSSEC状态
if entry, exists := s.resolvedDomains[domain]; exists {
entry.DNSSEC = dnssec
} else {
s.resolvedDomains[domain] = &BlockedDomain{
Domain: domain,
Count: 1,
LastSeen: time.Now(),
DNSSEC: dnssec,
}
}
// 更新domainDNSSECStatus映射
s.domainDNSSECStatus[domain] = dnssec
}
// updateResolvedDomainStats 更新解析域名统计
func (s *Server) updateResolvedDomainStats(domain string) {
s.resolvedDomainsMutex.Lock()
@@ -733,6 +856,7 @@ func (s *Server) updateResolvedDomainStats(domain string) {
Domain: domain,
Count: 1,
LastSeen: time.Now(),
DNSSEC: false,
}
}
}
@@ -745,7 +869,7 @@ func (s *Server) updateStats(update func(*Stats)) {
}
// addQueryLog 添加查询日志
func (s *Server) addQueryLog(clientIP, domain, queryType string, responseTime int64, result, blockRule, blockType string, fromCache bool) {
func (s *Server) addQueryLog(clientIP, domain, queryType string, responseTime int64, result, blockRule, blockType string, fromCache, dnssec bool) {
// 获取IP地理位置
location := s.getIpGeolocation(clientIP)
@@ -761,6 +885,7 @@ func (s *Server) addQueryLog(clientIP, domain, queryType string, responseTime in
BlockRule: blockRule,
BlockType: blockType,
FromCache: fromCache,
DNSSEC: dnssec,
}
// 添加到日志列表