refactor: simplify dns proxy replies

This commit is contained in:
wweir
2026-03-30 23:03:49 +08:00
parent e705dd4dd3
commit 53c55aef24
+48 -46
View File
@@ -30,19 +30,21 @@ func (r *Router) ServeDNS(w dns.ResponseWriter, req *dns.Msg) {
case r.DirectRule.Match(domain):
case r.ProxyRule.Match(domain) && isAddressQuestion(qtype):
resp, err := r.dnsProxyReply(domain, w.LocalAddr(), req)
if err != nil {
slog.Warn("proxy dns", "error", err, "domain", domain)
_ = w.WriteMsg(r.dnsFail(req, dns.RcodeServerFailure))
case r.ProxyRule.Match(domain):
if isAddressQuestion(qtype) {
resp, err := r.dnsProxyReply(domain, w.LocalAddr(), req)
if err != nil {
slog.Warn("proxy dns", "error", err, "domain", domain)
_ = w.WriteMsg(r.dnsFail(req, dns.RcodeServerFailure))
return
}
_ = w.WriteMsg(resp)
return
}
if isProxySensitiveQuestion(qtype) {
_ = w.WriteMsg(r.dnsNoData(req))
return
}
_ = w.WriteMsg(resp)
return
case r.ProxyRule.Match(domain) && isProxySensitiveQuestion(qtype):
_ = w.WriteMsg(r.dnsNoData(req))
return
}
// 2. direct query, do not fallback to proxy to avoid side-effect
@@ -61,45 +63,27 @@ func (r *Router) dnsFail(req *dns.Msg, rcode int) *dns.Msg {
}
func (r *Router) dnsNoData(req *dns.Msg) *dns.Msg {
m := new(dns.Msg)
m.SetReply(req)
return m
return dnsReply(req)
}
func (r *Router) dnsProxyReply(domain string, localAddr net.Addr, req *dns.Msg) (*dns.Msg, error) {
qtype := req.Question[0].Qtype
m := new(dns.Msg)
m.SetReply(req)
reply := dnsReply(req)
switch qtype {
case dns.TypeA:
localIP, err := r.proxyReplyIP(localAddr, qtype)
if err != nil {
if errors.Is(err, errNoLocalIPForQuestionType) {
return m, nil
}
return nil, err
localIP, err := r.proxyReplyIP(localAddr, qtype)
if err != nil {
if errors.Is(err, errNoLocalIPForQuestionType) {
return reply, nil
}
m.Answer = []dns.RR{&dns.A{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 20},
A: localIP,
}}
case dns.TypeAAAA:
localIP, err := r.proxyReplyIP(localAddr, qtype)
if err != nil {
if errors.Is(err, errNoLocalIPForQuestionType) {
return m, nil
}
return nil, err
}
m.Answer = []dns.RR{&dns.AAAA{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 20},
AAAA: localIP,
}}
default:
// ServeDNS only calls dnsProxyReply for A/AAAA questions.
return nil, err
}
return m, nil
record, err := proxyReplyRecord(domain, qtype, localIP)
if err != nil {
return nil, err
}
reply.Answer = []dns.RR{record}
return reply, nil
}
func (r *Router) proxyReplyIP(localAddr net.Addr, qtype uint16) (net.IP, error) {
@@ -146,11 +130,29 @@ func isAddressQuestion(qtype uint16) bool {
}
func isProxySensitiveQuestion(qtype uint16) bool {
return qtype == dns.TypeHTTPS || qtype == dns.TypeSVCB
}
func dnsReply(req *dns.Msg) *dns.Msg {
reply := new(dns.Msg)
reply.SetReply(req)
return reply
}
func proxyReplyRecord(domain string, qtype uint16, localIP net.IP) (dns.RR, error) {
switch qtype {
case dns.TypeHTTPS, dns.TypeSVCB:
return true
case dns.TypeA:
return &dns.A{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeA, Class: dns.ClassINET, Ttl: 20},
A: localIP,
}, nil
case dns.TypeAAAA:
return &dns.AAAA{
Hdr: dns.RR_Header{Name: domain, Rrtype: dns.TypeAAAA, Class: dns.ClassINET, Ttl: 20},
AAAA: localIP,
}, nil
default:
return false
return nil, fmt.Errorf("unsupported question type %d", qtype)
}
}