From c3de4b8392d06b27199cbf13ccde584b8027fb22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?= Date: Tue, 18 Mar 2025 19:47:02 +0000 Subject: [PATCH 1/5] DNS: Retry with EDNS0 when response is truncated --- app/dns/dnscommon.go | 11 ++++++++--- app/dns/nameserver_udp.go | 21 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/app/dns/dnscommon.go b/app/dns/dnscommon.go index 42f9da2ce073..5f3d08ac90fa 100644 --- a/app/dns/dnscommon.go +++ b/app/dns/dnscommon.go @@ -35,6 +35,9 @@ type IPRecord struct { IP []net.Address Expire time.Time RCode dnsmessage.RCode + + // Truncated is for udp dns to indicates if the response is truncated and needs to be retried + Truncated bool } func (r *IPRecord) getIPs() ([]net.Address, error) { @@ -65,6 +68,7 @@ type dnsRequest struct { start time.Time expire time.Time msg *dnsmessage.Message + ctx context.Context } func genEDNS0Options(clientIP net.IP) *dnsmessage.Resource { @@ -179,9 +183,10 @@ func parseResponse(payload []byte) (*IPRecord, error) { now := time.Now() ipRecord := &IPRecord{ - ReqID: h.ID, - RCode: h.RCode, - Expire: now.Add(time.Second * 600), + ReqID: h.ID, + RCode: h.RCode, + Expire: now.Add(time.Second * 600), + Truncated: h.Truncated, } L: diff --git a/app/dns/nameserver_udp.go b/app/dns/nameserver_udp.go index 47d7043571a5..a088eef4b837 100644 --- a/app/dns/nameserver_udp.go +++ b/app/dns/nameserver_udp.go @@ -128,6 +128,26 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot return } + // if truncated, retry with EDNS0 option(udp payload size: 1350) + if ipRec.Truncated { + // if already has EDNS0 option, no need to retry + if ok && len(req.msg.Additionals) == 0 { + // copy necessary meta data from original request + // and add EDNS0 option + opt := new(dnsmessage.Resource) + common.Must(opt.Header.SetEDNS0(1350, 0xfe00, true)) + newMsg := *req.msg + newReq := *req + newMsg.Additionals = append(newMsg.Additionals, *opt) + newMsg.ID = s.newReqID() + newReq.msg = &newMsg + s.addPendingRequest(&newReq) + b, _ := dns.PackMessage(req.msg) + s.udpServer.Dispatch(toDnsContext(newReq.ctx, s.address.String()), *s.address, b) + return + } + } + var rec record switch req.reqType { case dnsmessage.TypeA: @@ -194,6 +214,7 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, client reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP)) for _, req := range reqs { + req.ctx = ctx s.addPendingRequest(req) b, _ := dns.PackMessage(req.msg) s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b) From d639ccc62778ea9e4c7c13d7a4528808763ff638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?= Date: Tue, 18 Mar 2025 20:29:58 +0000 Subject: [PATCH 2/5] Fix test --- app/dns/dnscommon.go | 15 ++++++--------- app/dns/dnscommon_test.go | 5 +++-- app/dns/nameserver_udp.go | 22 +++++++++++++++------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/app/dns/dnscommon.go b/app/dns/dnscommon.go index 5f3d08ac90fa..c2689d6dc178 100644 --- a/app/dns/dnscommon.go +++ b/app/dns/dnscommon.go @@ -31,13 +31,11 @@ type record struct { // IPRecord is a cacheable item for a resolved domain type IPRecord struct { - ReqID uint16 - IP []net.Address - Expire time.Time - RCode dnsmessage.RCode - - // Truncated is for udp dns to indicates if the response is truncated and needs to be retried - Truncated bool + ReqID uint16 + IP []net.Address + Expire time.Time + RCode dnsmessage.RCode + RawHeader *dnsmessage.Header } func (r *IPRecord) getIPs() ([]net.Address, error) { @@ -68,7 +66,6 @@ type dnsRequest struct { start time.Time expire time.Time msg *dnsmessage.Message - ctx context.Context } func genEDNS0Options(clientIP net.IP) *dnsmessage.Resource { @@ -186,7 +183,7 @@ func parseResponse(payload []byte) (*IPRecord, error) { ReqID: h.ID, RCode: h.RCode, Expire: now.Add(time.Second * 600), - Truncated: h.Truncated, + RawHeader: &h, } L: diff --git a/app/dns/dnscommon_test.go b/app/dns/dnscommon_test.go index d11f8632692c..a7eb60e3723b 100644 --- a/app/dns/dnscommon_test.go +++ b/app/dns/dnscommon_test.go @@ -51,7 +51,7 @@ func Test_parseResponse(t *testing.T) { }{ { "empty", - &IPRecord{0, []net.Address(nil), time.Time{}, dnsmessage.RCodeSuccess}, + &IPRecord{0, []net.Address(nil), time.Time{}, dnsmessage.RCodeSuccess, nil}, false, }, { @@ -66,12 +66,13 @@ func Test_parseResponse(t *testing.T) { []net.Address{net.ParseAddress("8.8.8.8"), net.ParseAddress("8.8.4.4")}, time.Time{}, dnsmessage.RCodeSuccess, + nil, }, false, }, { "aaaa record", - &IPRecord{2, []net.Address{net.ParseAddress("2001::123:8888"), net.ParseAddress("2001::123:8844")}, time.Time{}, dnsmessage.RCodeSuccess}, + &IPRecord{2, []net.Address{net.ParseAddress("2001::123:8888"), net.ParseAddress("2001::123:8844")}, time.Time{}, dnsmessage.RCodeSuccess, nil}, false, }, } diff --git a/app/dns/nameserver_udp.go b/app/dns/nameserver_udp.go index a088eef4b837..88b4149796f2 100644 --- a/app/dns/nameserver_udp.go +++ b/app/dns/nameserver_udp.go @@ -27,7 +27,7 @@ type ClassicNameServer struct { name string address *net.Destination ips map[string]*record - requests map[uint16]*dnsRequest + requests map[uint16]*udpDnsRequest pub *pubsub.Service udpServer *udp.Dispatcher cleanup *task.Periodic @@ -35,6 +35,11 @@ type ClassicNameServer struct { queryStrategy QueryStrategy } +type udpDnsRequest struct { + dnsRequest + ctx context.Context +} + // NewClassicNameServer creates udp server object for remote resolving. func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher, queryStrategy QueryStrategy) *ClassicNameServer { // default to 53 if unspecific @@ -45,7 +50,7 @@ func NewClassicNameServer(address net.Destination, dispatcher routing.Dispatcher s := &ClassicNameServer{ address: &address, ips: make(map[string]*record), - requests: make(map[uint16]*dnsRequest), + requests: make(map[uint16]*udpDnsRequest), pub: pubsub.NewService(), name: strings.ToUpper(address.String()), queryStrategy: queryStrategy, @@ -101,7 +106,7 @@ func (s *ClassicNameServer) Cleanup() error { } if len(s.requests) == 0 { - s.requests = make(map[uint16]*dnsRequest) + s.requests = make(map[uint16]*udpDnsRequest) } return nil @@ -129,7 +134,7 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot } // if truncated, retry with EDNS0 option(udp payload size: 1350) - if ipRec.Truncated { + if ipRec.RawHeader.Truncated { // if already has EDNS0 option, no need to retry if ok && len(req.msg.Additionals) == 0 { // copy necessary meta data from original request @@ -199,7 +204,7 @@ func (s *ClassicNameServer) newReqID() uint16 { return uint16(atomic.AddUint32(&s.reqID, 1)) } -func (s *ClassicNameServer) addPendingRequest(req *dnsRequest) { +func (s *ClassicNameServer) addPendingRequest(req *udpDnsRequest) { s.Lock() defer s.Unlock() @@ -214,8 +219,11 @@ func (s *ClassicNameServer) sendQuery(ctx context.Context, domain string, client reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP)) for _, req := range reqs { - req.ctx = ctx - s.addPendingRequest(req) + udpReq := &udpDnsRequest{ + dnsRequest: *req, + ctx: ctx, + } + s.addPendingRequest(udpReq) b, _ := dns.PackMessage(req.msg) s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b) } From b6a3e0718ff14396f24cc9f1cede92c2345729c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?= Date: Wed, 19 Mar 2025 04:36:27 +0000 Subject: [PATCH 3/5] fix --- app/dns/nameserver_udp.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/dns/nameserver_udp.go b/app/dns/nameserver_udp.go index 88b4149796f2..7d307b364b98 100644 --- a/app/dns/nameserver_udp.go +++ b/app/dns/nameserver_udp.go @@ -147,7 +147,7 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot newMsg.ID = s.newReqID() newReq.msg = &newMsg s.addPendingRequest(&newReq) - b, _ := dns.PackMessage(req.msg) + b, _ := dns.PackMessage(newReq.msg) s.udpServer.Dispatch(toDnsContext(newReq.ctx, s.address.String()), *s.address, b) return } From 6437143bb74cb7e68d3fff89264877d081029677 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?= Date: Thu, 20 Mar 2025 15:35:49 +0000 Subject: [PATCH 4/5] Fix nil resource body --- app/dns/nameserver_udp.go | 1 + 1 file changed, 1 insertion(+) diff --git a/app/dns/nameserver_udp.go b/app/dns/nameserver_udp.go index 7d307b364b98..967576bc81af 100644 --- a/app/dns/nameserver_udp.go +++ b/app/dns/nameserver_udp.go @@ -141,6 +141,7 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot // and add EDNS0 option opt := new(dnsmessage.Resource) common.Must(opt.Header.SetEDNS0(1350, 0xfe00, true)) + opt.Body = &dnsmessage.OPTResource{} newMsg := *req.msg newReq := *req newMsg.Additionals = append(newMsg.Additionals, *opt) From d40c0374d24be6e47952a70e55df9482d806a911 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=A3=8E=E6=89=87=E6=BB=91=E7=BF=94=E7=BF=BC?= Date: Thu, 20 Mar 2025 16:09:11 +0000 Subject: [PATCH 5/5] Fix test --- app/dns/dnscommon_test.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/dns/dnscommon_test.go b/app/dns/dnscommon_test.go index a7eb60e3723b..4c6f9d73804b 100644 --- a/app/dns/dnscommon_test.go +++ b/app/dns/dnscommon_test.go @@ -85,8 +85,9 @@ func Test_parseResponse(t *testing.T) { } if got != nil { - // reset the time + // reset the time and RawHeader got.Expire = time.Time{} + got.RawHeader = nil } if cmp.Diff(got, tt.want) != "" { t.Error(cmp.Diff(got, tt.want))