DNSSEC逻辑优化
This commit is contained in:
163
dns/server.go
163
dns/server.go
@@ -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,
|
||||
}
|
||||
|
||||
// 添加到日志列表
|
||||
|
||||
Reference in New Issue
Block a user