mirror of
https://github.com/daeuniverse/dae.git
synced 2025-07-06 08:22:38 +07:00
fix: dns problem
This commit is contained in:
@ -177,31 +177,32 @@ func EnsureAdditionalOpt(dm *dnsmessage.Message, isReqAdd bool) (bool, error) {
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type RscWrapper struct {
|
||||||
|
Rsc dnsmessage.Resource
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w RscWrapper) String() string {
|
||||||
|
return fmt.Sprintf("%v: %v", w.Rsc.Header.GoString(), w.Rsc.Body.GoString())
|
||||||
|
}
|
||||||
|
func FormatDnsRsc(ans []dnsmessage.Resource) (w []string) {
|
||||||
|
for _, a := range ans {
|
||||||
|
w = append(w, RscWrapper{Rsc: a}.String())
|
||||||
|
}
|
||||||
|
return w
|
||||||
|
}
|
||||||
|
|
||||||
// DnsRespHandler handle DNS resp. This function should be invoked when cache miss.
|
// DnsRespHandler handle DNS resp. This function should be invoked when cache miss.
|
||||||
func (c *ControlPlane) DnsRespHandler(data []byte) (newData []byte, err error) {
|
func (c *ControlPlane) DnsRespHandler(data []byte, validateRushAns bool) (newData []byte, err error) {
|
||||||
var msg dnsmessage.Message
|
var msg dnsmessage.Message
|
||||||
if err = msg.Unpack(data); err != nil {
|
if err = msg.Unpack(data); err != nil {
|
||||||
return nil, fmt.Errorf("unpack dns pkt: %w", err)
|
return nil, fmt.Errorf("unpack dns pkt: %w", err)
|
||||||
}
|
}
|
||||||
defer func() {
|
|
||||||
if err == nil {
|
|
||||||
exist, e := EnsureAdditionalOpt(&msg, false)
|
|
||||||
if e != nil && !errors.Is(e, UnsupportedQuestionTypeError) {
|
|
||||||
c.log.Warnf("EnsureAdditionalOpt: %v", e)
|
|
||||||
}
|
|
||||||
if e == nil && !exist {
|
|
||||||
// Additional record OPT in the request was ensured, and in normal case the resp should also set it.
|
|
||||||
// This DNS packet may be a rush-answer, and we should reject it.
|
|
||||||
// Note that additional record OPT may not be supported by home router either.
|
|
||||||
err = SuspectedRushAnswerError
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
FlipDnsQuestionCase(&msg)
|
|
||||||
// Check healthy resp.
|
// Check healthy resp.
|
||||||
if !msg.Response || msg.RCode != dnsmessage.RCodeSuccess || len(msg.Questions) == 0 {
|
if !msg.Response || len(msg.Questions) == 0 {
|
||||||
return data, nil
|
return data, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FlipDnsQuestionCase(&msg)
|
||||||
q := msg.Questions[0]
|
q := msg.Questions[0]
|
||||||
// Align Name.
|
// Align Name.
|
||||||
if len(msg.Answers) > 0 &&
|
if len(msg.Answers) > 0 &&
|
||||||
@ -213,12 +214,22 @@ func (c *ControlPlane) DnsRespHandler(data []byte) (newData []byte, err error) {
|
|||||||
msg.Additionals[i].Header.Name.Data = q.Name.Data
|
msg.Additionals[i].Header.Name.Data = q.Name.Data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for i := range msg.Authorities {
|
||||||
|
if strings.EqualFold(msg.Authorities[i].Header.Name.String(), q.Name.String()) {
|
||||||
|
msg.Authorities[i].Header.Name.Data = q.Name.Data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check suc resp.
|
||||||
|
if msg.RCode != dnsmessage.RCodeSuccess {
|
||||||
|
return msg.Pack()
|
||||||
|
}
|
||||||
|
|
||||||
// Check req type.
|
// Check req type.
|
||||||
switch q.Type {
|
switch q.Type {
|
||||||
case dnsmessage.TypeA, dnsmessage.TypeAAAA:
|
case dnsmessage.TypeA, dnsmessage.TypeAAAA:
|
||||||
default:
|
default:
|
||||||
return data, nil
|
return msg.Pack()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set ttl.
|
// Set ttl.
|
||||||
@ -244,10 +255,25 @@ func (c *ControlPlane) DnsRespHandler(data []byte) (newData []byte, err error) {
|
|||||||
return msg.Pack()
|
return msg.Pack()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if validateRushAns {
|
||||||
|
exist, e := EnsureAdditionalOpt(&msg, false)
|
||||||
|
if e != nil && !errors.Is(e, UnsupportedQuestionTypeError) {
|
||||||
|
c.log.Warnf("EnsureAdditionalOpt: %v", e)
|
||||||
|
}
|
||||||
|
if e == nil && !exist {
|
||||||
|
// Additional record OPT in the request was ensured, and in normal case the resp should also set it.
|
||||||
|
// This DNS packet may be a rush-answer, and we should reject it.
|
||||||
|
return nil, SuspectedRushAnswerError
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Update dnsCache.
|
// Update dnsCache.
|
||||||
c.log.WithFields(logrus.Fields{
|
c.log.WithFields(logrus.Fields{
|
||||||
"qname": q.Name,
|
"qname": q.Name,
|
||||||
"ans": msg.Answers,
|
"rcode": msg.RCode,
|
||||||
|
"ans": FormatDnsRsc(msg.Answers),
|
||||||
|
"auth": FormatDnsRsc(msg.Authorities),
|
||||||
|
"addi": FormatDnsRsc(msg.Additionals),
|
||||||
}).Tracef("Update DNS record cache")
|
}).Tracef("Update DNS record cache")
|
||||||
c.mutex.Lock()
|
c.mutex.Lock()
|
||||||
fqdn := strings.ToLower(q.Name.String())
|
fqdn := strings.ToLower(q.Name.String())
|
||||||
|
@ -80,26 +80,23 @@ func sendPktWithHdr(data []byte, from netip.AddrPort, lConn *net.UDPConn, to net
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ControlPlane) RelayToUDP(lConn *net.UDPConn, to netip.AddrPort, isDNS bool, dummyFrom *netip.AddrPort) UdpHandler {
|
func (c *ControlPlane) RelayToUDP(lConn *net.UDPConn, to netip.AddrPort, isDNS bool, dummyFrom *netip.AddrPort, validateRushAns bool) UdpHandler {
|
||||||
return func(data []byte, from netip.AddrPort) (err error) {
|
return func(data []byte, from netip.AddrPort) (err error) {
|
||||||
|
// Do not return conn-unrelated err in this func.
|
||||||
|
|
||||||
if isDNS {
|
if isDNS {
|
||||||
data, err = c.DnsRespHandler(data)
|
data, err = c.DnsRespHandler(data, validateRushAns)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, SuspectedRushAnswerError) {
|
if errors.Is(err, SuspectedRushAnswerError) {
|
||||||
if from.Addr().IsPrivate() {
|
|
||||||
// Additional record OPT may not be supported by home router.
|
|
||||||
// And we should trust home devices even if they make rush-answer.
|
|
||||||
c.log.Tracef("DnsRespHandler: received %v", err)
|
|
||||||
err = nil
|
|
||||||
goto sendToClient
|
|
||||||
}
|
|
||||||
// Reject DNS rush-answer.
|
// Reject DNS rush-answer.
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
c.log.Debugf("DnsRespHandler: %v", err)
|
c.log.Debugf("DnsRespHandler: %v", err)
|
||||||
|
if data == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sendToClient:
|
|
||||||
if dummyFrom != nil {
|
if dummyFrom != nil {
|
||||||
from = *dummyFrom
|
from = *dummyFrom
|
||||||
}
|
}
|
||||||
@ -163,8 +160,12 @@ func (c *ControlPlane) handlePkt(data []byte, lConn *net.UDPConn, lAddrPort neti
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We only validate rush-ans when outbound is direct and pkt does not send to a home device.
|
||||||
|
// Because additional record OPT may not be supported by home router.
|
||||||
|
// So se should trust home devices even if they make rush-answer (or looks like).
|
||||||
|
validateRushAns := addrHdr.Outbound == uint8(consts.OutboundDirect) && !dest.Addr().IsPrivate()
|
||||||
ue, err := DefaultUdpEndpointPool.GetOrCreate(lAddrPort, &UdpEndpointOptions{
|
ue, err := DefaultUdpEndpointPool.GetOrCreate(lAddrPort, &UdpEndpointOptions{
|
||||||
Handler: c.RelayToUDP(lConn, lAddrPort, isDns, dummyFrom),
|
Handler: c.RelayToUDP(lConn, lAddrPort, isDns, dummyFrom, validateRushAns),
|
||||||
NatTimeout: natTimeout,
|
NatTimeout: natTimeout,
|
||||||
DialerFunc: func() (*dialer.Dialer, error) {
|
DialerFunc: func() (*dialer.Dialer, error) {
|
||||||
newDialer, err := outbound.Select()
|
newDialer, err := outbound.Select()
|
||||||
|
Reference in New Issue
Block a user