支持DNSSEC

This commit is contained in:
Alex Yang
2025-12-15 23:54:11 +08:00
parent 9aa328d466
commit ba26e2b647
12 changed files with 1169 additions and 141 deletions

View File

@@ -104,6 +104,7 @@ func NewServer(config *config.DNSConfig, shieldConfig *config.ShieldConfig, shie
resolver: &dns.Client{
Net: "udp",
Timeout: time.Duration(config.Timeout) * time.Millisecond,
UDPSize: 4096, // 增大UDP包大小以支持DNSSEC记录
},
ctx: ctx,
cancel: cancel,
@@ -431,13 +432,43 @@ func (s *Server) handleBlockedResponse(w dns.ResponseWriter, r *dns.Msg, domain
// forwardDNSRequest 转发DNS请求到上游服务器
func (s *Server) forwardDNSRequest(w dns.ResponseWriter, r *dns.Msg, domain string) {
// 复制请求保留原始请求的DO标志
reqCopy := r.Copy()
// 尝试所有上游DNS服务器
for _, upstream := range s.config.UpstreamDNS {
response, rtt, err := s.resolver.Exchange(r, upstream)
if err == nil && response != nil && response.Rcode == dns.RcodeSuccess {
// 设置UDP客户端的Size以支持EDNS0和DNSSEC
s.resolver.UDPSize = 4096
response, rtt, err := s.resolver.Exchange(reqCopy, upstream)
if err == nil && response != nil {
// 设置递归可用标志
response.RecursionAvailable = true
// 如果启用了DNSSEC确保响应包含DNSSEC记录
if s.config.EnableDNSSEC {
logger.Debug("DNSSEC启用转发DNSSEC记录", "domain", domain, "server", upstream)
}
// 保留客户端请求中的DO标志
if edns0 := r.IsEdns0(); edns0 != nil {
// 检查客户端是否请求了DNSSEC (设置了DO标志)
if edns0.Do() {
// 客户端请求了DNSSEC确保响应包含EDNS0和DO标志
if responseOpt := response.IsEdns0(); responseOpt != nil {
responseOpt.SetDo()
} else {
// 添加EDNS0选项并设置DO标志
responseOpt := new(dns.OPT)
responseOpt.Hdr.Name = "."
responseOpt.Hdr.Rrtype = dns.TypeOPT
responseOpt.SetDo()
response.Extra = append(response.Extra, responseOpt)
}
logger.Debug("保留DO标志", "domain", domain, "server", upstream)
}
}
w.WriteMsg(response)
logger.Debug("DNS查询成功", "domain", domain, "rtt", rtt, "server", upstream)
@@ -456,6 +487,20 @@ func (s *Server) forwardDNSRequest(w dns.ResponseWriter, r *dns.Msg, domain stri
response.SetReply(r)
response.RecursionAvailable = true
response.SetRcode(r, dns.RcodeServerFailure)
// 保留客户端请求中的DO标志
if edns0 := r.IsEdns0(); edns0 != nil {
// 检查客户端是否请求了DNSSEC (设置了DO标志)
if edns0.Do() {
// 添加EDNS0选项并设置DO标志
responseOpt := new(dns.OPT)
responseOpt.Hdr.Name = "."
responseOpt.Hdr.Rrtype = dns.TypeOPT
responseOpt.SetDo()
response.Extra = append(response.Extra, responseOpt)
}
}
w.WriteMsg(response)
logger.Error("DNS查询失败", "domain", domain)