DNS: Retry with EDNS0 when response is truncated

pull/4516/head
风扇滑翔翼 2025-03-18 19:47:02 +00:00 committed by GitHub
parent 2cba2c4d59
commit c3de4b8392
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 29 additions and 3 deletions

View File

@ -35,6 +35,9 @@ type IPRecord struct {
IP []net.Address IP []net.Address
Expire time.Time Expire time.Time
RCode dnsmessage.RCode 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) { func (r *IPRecord) getIPs() ([]net.Address, error) {
@ -65,6 +68,7 @@ type dnsRequest struct {
start time.Time start time.Time
expire time.Time expire time.Time
msg *dnsmessage.Message msg *dnsmessage.Message
ctx context.Context
} }
func genEDNS0Options(clientIP net.IP) *dnsmessage.Resource { func genEDNS0Options(clientIP net.IP) *dnsmessage.Resource {
@ -182,6 +186,7 @@ func parseResponse(payload []byte) (*IPRecord, error) {
ReqID: h.ID, ReqID: h.ID,
RCode: h.RCode, RCode: h.RCode,
Expire: now.Add(time.Second * 600), Expire: now.Add(time.Second * 600),
Truncated: h.Truncated,
} }
L: L:

View File

@ -128,6 +128,26 @@ func (s *ClassicNameServer) HandleResponse(ctx context.Context, packet *udp_prot
return 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 var rec record
switch req.reqType { switch req.reqType {
case dnsmessage.TypeA: 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)) reqs := buildReqMsgs(domain, option, s.newReqID, genEDNS0Options(clientIP))
for _, req := range reqs { for _, req := range reqs {
req.ctx = ctx
s.addPendingRequest(req) s.addPendingRequest(req)
b, _ := dns.PackMessage(req.msg) b, _ := dns.PackMessage(req.msg)
s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b) s.udpServer.Dispatch(toDnsContext(ctx, s.address.String()), *s.address, b)