Compare commits
1 Commits
e8478fe118
...
b2749e053a
| Author | SHA1 | Date | |
|---|---|---|---|
| b2749e053a |
@@ -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使用
|
||||||
var b strings.Builder
|
// for _, s := range o.Option {
|
||||||
b.Grow(64)
|
// switch e := s.(type) {
|
||||||
b.WriteString(model.GetDomainNameFromDnsMsg(m))
|
// case *dns.EDNS0_SUBNET:
|
||||||
b.WriteByte('#')
|
// edns = e.Address.String()
|
||||||
b.WriteString(strconv.Itoa(int(m.Question[0].Qtype)))
|
// }
|
||||||
if o := m.IsEdns0(); o != nil && o.Do() {
|
// }
|
||||||
b.WriteString("#DO")
|
|
||||||
}
|
}
|
||||||
return b.String()
|
return fmt.Sprintf("%s#%d#%s", model.GetDomainNameFromDnsMsg(m), m.Question[0].Qtype, dnssec)
|
||||||
}
|
}
|
||||||
|
|
||||||
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,7 +437,10 @@ 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) {
|
||||||
@@ -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()
|
||||||
|
|||||||
Reference in New Issue
Block a user