Compare commits

..

1 Commits

Author SHA1 Message Date
XOF
b2749e053a 添加 docker-compose.yml 2026-01-06 02:37:36 +08:00
2 changed files with 51 additions and 43 deletions

View File

@@ -7,4 +7,4 @@ services:
- "8845:8845" - "8845:8845"
volumes: volumes:
- ./data:/godns/data - ./data:/godns/data
restart: unless-stopped restart: unless-stopped

View File

@@ -7,7 +7,6 @@ import (
"strings" "strings"
"sync" "sync"
"time" "time"
"strconv"
"github.com/miekg/dns" "github.com/miekg/dns"
@@ -165,19 +164,21 @@ func (h *Handler) exchange(req *dns.Msg) *dns.Msg {
} }
func getDnsRequestCacheKey(m *dns.Msg) string { func getDnsRequestCacheKey(m *dns.Msg) string {
if len(m.Question) == 0 { var dnssec string
return "" if o := m.IsEdns0(); o != nil {
// 区分 DNSSEC 请求,避免将非 DNSSEC 响应返回给需要 DNSSEC 的客户端
if o.Do() {
dnssec = "DO"
}
// 服务多区域的公共dns使用
// for _, s := range o.Option {
// switch e := s.(type) {
// case *dns.EDNS0_SUBNET:
// edns = e.Address.String()
// }
// }
} }
return fmt.Sprintf("%s#%d#%s", model.GetDomainNameFromDnsMsg(m), m.Question[0].Qtype, dnssec)
var b strings.Builder
b.Grow(64)
b.WriteString(model.GetDomainNameFromDnsMsg(m))
b.WriteByte('#')
b.WriteString(strconv.Itoa(int(m.Question[0].Qtype)))
if o := m.IsEdns0(); o != nil && o.Do() {
b.WriteString("#DO")
}
return b.String()
} }
func getDnsResponseTtl(m *dns.Msg) time.Duration { func getDnsResponseTtl(m *dns.Msg) time.Duration {
@@ -416,14 +417,8 @@ func (h *Handler) HandleRequest(w dns.ResponseWriter, req *dns.Msg) {
} }
} }
var builderPool = sync.Pool{ // uniqueAnswer 去除重复的 DNS 资源记录
New: func() interface{} { // 基于域名、类型和记录数据进行去重,比字符串分割更高效和可靠
b := new(strings.Builder)
b.Grow(128)
return b
},
}
func uniqueAnswer(records []dns.RR) []dns.RR { func uniqueAnswer(records []dns.RR) []dns.RR {
if len(records) == 0 { if len(records) == 0 {
return records return records
@@ -442,8 +437,11 @@ func uniqueAnswer(records []dns.RR) []dns.RR {
continue continue
} }
builder := builderPool.Get().(*strings.Builder) // 构造唯一键:域名 + 类型 + 记录数据
// 使用 strings.Builder 优化字符串拼接性能
var builder strings.Builder
builder.Grow(128) // Pre-allocate reasonable capacity
var key string var key string
switch v := rr.(type) { switch v := rr.(type) {
case *dns.A: case *dns.A:
@@ -494,10 +492,9 @@ func uniqueAnswer(records []dns.RR) []dns.RR {
builder.WriteString(v.Mbox) builder.WriteString(v.Mbox)
key = builder.String() key = builder.String()
default: default:
// 对于其他类型,回退到完整字符串表示
key = rr.String() key = rr.String()
} }
builder.Reset()
builderPool.Put(builder)
if !seen[key] { if !seen[key] {
seen[key] = true seen[key] = true
@@ -554,6 +551,7 @@ func (h *Handler) getTheFastestResults(req *dns.Msg) []*dns.Msg {
go func(j int) { go func(j int) {
msg, _, err := preferUpstreams[j].Exchange(req.Copy()) msg, _, err := preferUpstreams[j].Exchange(req.Copy())
// 记录上游服务器统计
if h.stats != nil { if h.stats != nil {
h.stats.RecordUpstreamQuery(preferUpstreams[j].Address, err != nil) h.stats.RecordUpstreamQuery(preferUpstreams[j].Address, err != nil)
} }
@@ -565,12 +563,12 @@ func (h *Handler) getTheFastestResults(req *dns.Msg) []*dns.Msg {
mutex.Lock() mutex.Lock()
defer mutex.Unlock() defer mutex.Unlock()
finishedCount++
// 已经结束直接退出
if finished { if finished {
return return
} }
finishedCount++
if err == nil { if err == nil {
if preferUpstreams[j].IsValidMsg(msg) { if preferUpstreams[j].IsValidMsg(msg) {
if preferUpstreams[j].IsPrimary { if preferUpstreams[j].IsPrimary {
@@ -580,15 +578,27 @@ func (h *Handler) getTheFastestResults(req *dns.Msg) []*dns.Msg {
} }
msgs[j] = msg msgs[j] = msg
} else if preferUpstreams[j].IsPrimary { } else if preferUpstreams[j].IsPrimary {
// 策略:国内 DNS 返回了 国外 服务器,计数但是不记入结果,以 国外 DNS 为准
primaryIndex = append(primaryIndex, j) primaryIndex = append(primaryIndex, j)
} }
} }
shouldFinish := finishedCount == len(preferUpstreams) || // 全部结束直接退出
(len(primaryIndex) > 0 && len(freedomIndex) > 0) || if finishedCount == len(preferUpstreams) {
(len(primaryIndex) > 0 && (msgs[primaryIndex[0]] != nil || len(freedomIndex) > 0)) finished = true
wg.Done()
if shouldFinish && !finished { return
}
// 两组 DNS 都有一个返回结果,退出
if len(primaryIndex) > 0 && len(freedomIndex) > 0 {
finished = true
wg.Done()
return
}
// 满足任一条件退出
// - 国内 DNS 返回了 国内 服务器
// - 国内 DNS 返回国外服务器 且 国外 DNS 有可用结果
if len(primaryIndex) > 0 && (msgs[primaryIndex[0]] != nil || len(freedomIndex) > 0) {
finished = true finished = true
wg.Done() wg.Done()
} }
@@ -601,19 +611,19 @@ func (h *Handler) getTheFastestResults(req *dns.Msg) []*dns.Msg {
func (h *Handler) getAnyResult(req *dns.Msg) []*dns.Msg { func (h *Handler) getAnyResult(req *dns.Msg) []*dns.Msg {
matchedUpstreams := h.matchedUpstreams(req) matchedUpstreams := h.matchedUpstreams(req)
msgs := make([]*dns.Msg, len(matchedUpstreams))
var mutex sync.Mutex
var finishedCount int
var finished bool
var wg sync.WaitGroup var wg sync.WaitGroup
wg.Add(1) wg.Add(1)
msgs := make([]*dns.Msg, len(matchedUpstreams))
var mutex sync.Mutex
var finishedCount int
var finished bool
for i := 0; i < len(matchedUpstreams); i++ { for i := 0; i < len(matchedUpstreams); i++ {
go func(j int) { go func(j int) {
msg, _, err := matchedUpstreams[j].Exchange(req.Copy()) msg, _, err := matchedUpstreams[j].Exchange(req.Copy())
// 记录上游服务器统计
if h.stats != nil { if h.stats != nil {
h.stats.RecordUpstreamQuery(matchedUpstreams[j].Address, err != nil) h.stats.RecordUpstreamQuery(matchedUpstreams[j].Address, err != nil)
} }
@@ -621,18 +631,16 @@ func (h *Handler) getAnyResult(req *dns.Msg) []*dns.Msg {
if err != nil { if err != nil {
h.logger.Printf("upstream error %s: %v %s", matchedUpstreams[j].Address, model.GetDomainNameFromDnsMsg(req), err) h.logger.Printf("upstream error %s: %v %s", matchedUpstreams[j].Address, model.GetDomainNameFromDnsMsg(req), err)
} }
mutex.Lock() mutex.Lock()
defer mutex.Unlock() defer mutex.Unlock()
finishedCount++
if finished { if finished {
return return
} }
finishedCount++ // 已结束或任意上游返回成功时退出
shouldFinish := err == nil || finishedCount == len(matchedUpstreams) if err == nil || finishedCount == len(matchedUpstreams) {
if shouldFinish && !finished {
finished = true finished = true
msgs[j] = msg msgs[j] = msg
wg.Done() wg.Done()