dae/control/dns_control.go

677 lines
18 KiB
Go
Raw Normal View History

2023-02-25 01:38:21 +07:00
/*
* SPDX-License-Identifier: AGPL-3.0-only
* Copyright (c) 2022-2024, daeuniverse Organization <dae@v2raya.org>
2023-02-25 01:38:21 +07:00
*/
package control
import (
"context"
2023-02-25 01:38:21 +07:00
"fmt"
"math"
"net"
"net/netip"
"strconv"
"strings"
"sync"
"time"
2023-03-14 14:01:55 +07:00
"github.com/daeuniverse/dae/common/consts"
"github.com/daeuniverse/dae/common/netutils"
"github.com/daeuniverse/dae/component/dns"
"github.com/daeuniverse/dae/component/outbound"
"github.com/daeuniverse/dae/component/outbound/dialer"
"github.com/daeuniverse/outbound/pkg/fastrand"
dnsmessage "github.com/miekg/dns"
2023-04-07 22:06:04 +07:00
"github.com/mohae/deepcopy"
"github.com/sirupsen/logrus"
2023-02-25 01:38:21 +07:00
)
const (
MaxDnsLookupDepth = 3
minFirefoxCacheTtl = 120
2023-02-25 01:38:21 +07:00
)
2023-04-07 22:06:04 +07:00
type IpVersionPrefer int
const (
IpVersionPrefer_No IpVersionPrefer = 0
IpVersionPrefer_4 IpVersionPrefer = 4
IpVersionPrefer_6 IpVersionPrefer = 6
)
2023-02-25 01:38:21 +07:00
var (
ErrUnsupportedQuestionType = fmt.Errorf("unsupported question type")
2023-02-25 01:38:21 +07:00
)
var (
UnspecifiedAddressA = netip.MustParseAddr("0.0.0.0")
UnspecifiedAddressAAAA = netip.MustParseAddr("::")
)
2023-02-25 01:38:21 +07:00
type DnsControllerOption struct {
Log *logrus.Logger
CacheAccessCallback func(cache *DnsCache) (err error)
CacheRemoveCallback func(cache *DnsCache) (err error)
NewCache func(fqdn string, answers []dnsmessage.RR, deadline time.Time, originalDeadline time.Time) (cache *DnsCache, err error)
BestDialerChooser func(req *udpRequest, upstream *dns.Upstream) (*dialArgument, error)
TimeoutExceedCallback func(dialArgument *dialArgument, err error)
IpVersionPrefer int
FixedDomainTtl map[string]int
2023-02-25 01:38:21 +07:00
}
type DnsController struct {
2023-04-07 22:06:04 +07:00
handling sync.Map
routing *dns.Dns
qtypePrefer uint16
2023-02-25 01:38:21 +07:00
log *logrus.Logger
cacheAccessCallback func(cache *DnsCache) (err error)
cacheRemoveCallback func(cache *DnsCache) (err error)
newCache func(fqdn string, answers []dnsmessage.RR, deadline time.Time, originalDeadline time.Time) (cache *DnsCache, err error)
2023-02-25 01:38:21 +07:00
bestDialerChooser func(req *udpRequest, upstream *dns.Upstream) (*dialArgument, error)
// timeoutExceedCallback is used to report this dialer is broken for the NetworkType
timeoutExceedCallback func(dialArgument *dialArgument, err error)
2023-02-25 01:38:21 +07:00
fixedDomainTtl map[string]int
2023-02-25 01:38:21 +07:00
// mutex protects the dnsCache.
dnsCacheMu sync.Mutex
dnsCache map[string]*DnsCache
dnsForwarderCacheMu sync.Mutex
dnsForwarderCache map[string]DnsForwarder
2023-02-25 01:38:21 +07:00
}
func parseIpVersionPreference(prefer int) (uint16, error) {
2023-04-07 22:06:04 +07:00
switch prefer := IpVersionPrefer(prefer); prefer {
case IpVersionPrefer_No:
return 0, nil
case IpVersionPrefer_4:
return dnsmessage.TypeA, nil
case IpVersionPrefer_6:
return dnsmessage.TypeAAAA, nil
default:
return 0, fmt.Errorf("unknown preference: %v", prefer)
}
}
2023-02-25 01:38:21 +07:00
func NewDnsController(routing *dns.Dns, option *DnsControllerOption) (c *DnsController, err error) {
2023-04-07 22:06:04 +07:00
// Parse ip version preference.
prefer, err := parseIpVersionPreference(option.IpVersionPrefer)
if err != nil {
return nil, err
}
2023-02-25 01:38:21 +07:00
return &DnsController{
2023-04-07 22:06:04 +07:00
routing: routing,
qtypePrefer: prefer,
2023-02-25 01:38:21 +07:00
log: option.Log,
cacheAccessCallback: option.CacheAccessCallback,
cacheRemoveCallback: option.CacheRemoveCallback,
newCache: option.NewCache,
bestDialerChooser: option.BestDialerChooser,
timeoutExceedCallback: option.TimeoutExceedCallback,
2023-02-25 01:38:21 +07:00
fixedDomainTtl: option.FixedDomainTtl,
dnsCacheMu: sync.Mutex{},
dnsCache: make(map[string]*DnsCache),
dnsForwarderCacheMu: sync.Mutex{},
dnsForwarderCache: make(map[string]DnsForwarder),
2023-02-25 01:38:21 +07:00
}, nil
}
func (c *DnsController) cacheKey(qname string, qtype uint16) string {
2023-02-25 01:38:21 +07:00
// To fqdn.
return dnsmessage.CanonicalName(qname) + strconv.Itoa(int(qtype))
2023-04-07 22:06:04 +07:00
}
func (c *DnsController) RemoveDnsRespCache(cacheKey string) {
2023-04-07 22:06:04 +07:00
c.dnsCacheMu.Lock()
_, ok := c.dnsCache[cacheKey]
2023-04-07 22:06:04 +07:00
if ok {
delete(c.dnsCache, cacheKey)
2023-02-25 01:38:21 +07:00
}
2023-04-07 22:06:04 +07:00
c.dnsCacheMu.Unlock()
}
func (c *DnsController) LookupDnsRespCache(cacheKey string, ignoreFixedTtl bool) (cache *DnsCache) {
2023-02-25 01:38:21 +07:00
c.dnsCacheMu.Lock()
cache, ok := c.dnsCache[cacheKey]
2023-02-25 01:38:21 +07:00
c.dnsCacheMu.Unlock()
if !ok {
return nil
}
var deadline time.Time
if !ignoreFixedTtl {
deadline = cache.Deadline
} else {
deadline = cache.OriginalDeadline
}
// We should make sure the cache did not expire, or
2023-03-17 12:13:42 +07:00
// return nil and request a new lookup to refresh the cache.
if !deadline.After(time.Now()) {
2023-02-25 01:38:21 +07:00
return nil
}
if err := c.cacheAccessCallback(cache); err != nil {
c.log.Warnf("failed to BatchUpdateDomainRouting: %v", err)
2023-02-25 01:38:21 +07:00
return nil
}
return cache
}
// LookupDnsRespCache_ will modify the msg in place.
func (c *DnsController) LookupDnsRespCache_(msg *dnsmessage.Msg, cacheKey string, ignoreFixedTtl bool) (resp []byte) {
cache := c.LookupDnsRespCache(cacheKey, ignoreFixedTtl)
2023-02-25 01:38:21 +07:00
if cache != nil {
cache.FillInto(msg)
msg.Compress = true
2023-02-25 01:38:21 +07:00
b, err := msg.Pack()
if err != nil {
c.log.Warnf("failed to pack: %v", err)
return nil
}
return b
}
return nil
}
// NormalizeAndCacheDnsResp_ handle DNS resp in place.
func (c *DnsController) NormalizeAndCacheDnsResp_(msg *dnsmessage.Msg) (err error) {
2023-02-25 01:38:21 +07:00
// Check healthy resp.
if !msg.Response || len(msg.Question) == 0 {
return nil
2023-02-25 01:38:21 +07:00
}
q := msg.Question[0]
2023-02-25 01:38:21 +07:00
// Check suc resp.
if msg.Rcode != dnsmessage.RcodeSuccess {
return nil
2023-02-25 01:38:21 +07:00
}
// Get TTL.
var ttl uint32
for i := range msg.Answer {
if ttl == 0 {
ttl = msg.Answer[i].Header().Ttl
break
}
}
if ttl == 0 {
// It seems no answers (NXDomain).
ttl = minFirefoxCacheTtl
}
2023-02-25 01:38:21 +07:00
// Check req type.
switch q.Qtype {
2023-02-25 01:38:21 +07:00
case dnsmessage.TypeA, dnsmessage.TypeAAAA:
default:
// Update DnsCache.
if err = c.updateDnsCache(msg, ttl, &q); err != nil {
return err
}
return nil
2023-02-25 01:38:21 +07:00
}
// Set ttl.
for i := range msg.Answer {
2023-02-25 01:38:21 +07:00
// Set TTL = zero. This requests applications must resend every request.
// However, it may be not defined in the standard.
msg.Answer[i].Header().Ttl = 0
2023-02-25 01:38:21 +07:00
}
// Check if request A/AAAA record.
var reqIpRecord bool
2023-02-25 01:38:21 +07:00
loop:
for i := range msg.Question {
switch msg.Question[i].Qtype {
2023-02-25 01:38:21 +07:00
case dnsmessage.TypeA, dnsmessage.TypeAAAA:
reqIpRecord = true
2023-02-25 01:38:21 +07:00
break loop
}
}
if !reqIpRecord {
// Update DnsCache.
if err = c.updateDnsCache(msg, ttl, &q); err != nil {
return err
}
return nil
2023-02-25 01:38:21 +07:00
}
// Update DnsCache.
if err = c.updateDnsCache(msg, ttl, &q); err != nil {
return err
}
// Pack to get newData.
return nil
}
func (c *DnsController) updateDnsCache(msg *dnsmessage.Msg, ttl uint32, q *dnsmessage.Question) error {
2023-02-25 01:38:21 +07:00
// Update DnsCache.
if c.log.IsLevelEnabled(logrus.TraceLevel) {
c.log.WithFields(logrus.Fields{
"_qname": q.Name,
"rcode": msg.Rcode,
"ans": FormatDnsRsc(msg.Answer),
2023-02-25 01:38:21 +07:00
}).Tracef("Update DNS record cache")
}
2023-03-17 12:13:42 +07:00
if err := c.UpdateDnsCacheTtl(q.Name, q.Qtype, msg.Answer, int(ttl)); err != nil {
return err
2023-02-25 01:38:21 +07:00
}
return nil
2023-02-25 01:38:21 +07:00
}
type daedlineFunc func(now time.Time, host string) (deadline time.Time, originalDeadline time.Time)
func (c *DnsController) __updateDnsCacheDeadline(host string, dnsTyp uint16, answers []dnsmessage.RR, deadlineFunc daedlineFunc) (err error) {
2023-02-25 01:38:21 +07:00
var fqdn string
if strings.HasSuffix(host, ".") {
fqdn = strings.ToLower(host)
2023-02-25 01:38:21 +07:00
host = host[:len(host)-1]
} else {
fqdn = dnsmessage.CanonicalName(host)
2023-02-25 01:38:21 +07:00
}
// Bypass pure IP.
if _, err = netip.ParseAddr(host); err == nil {
return nil
}
now := time.Now()
deadline, originalDeadline := deadlineFunc(now, host)
cacheKey := c.cacheKey(fqdn, dnsTyp)
2023-02-25 01:38:21 +07:00
c.dnsCacheMu.Lock()
cache, ok := c.dnsCache[cacheKey]
if ok {
cache.Answer = answers
cache.Deadline = deadline
cache.OriginalDeadline = originalDeadline
c.dnsCacheMu.Unlock()
2023-02-25 01:38:21 +07:00
} else {
cache, err = c.newCache(fqdn, answers, deadline, originalDeadline)
2023-02-25 01:38:21 +07:00
if err != nil {
c.dnsCacheMu.Unlock()
return err
}
c.dnsCache[cacheKey] = cache
c.dnsCacheMu.Unlock()
}
if err = c.cacheAccessCallback(cache); err != nil {
return err
}
2023-02-25 01:38:21 +07:00
return nil
}
func (c *DnsController) UpdateDnsCacheDeadline(host string, dnsTyp uint16, answers []dnsmessage.RR, deadline time.Time) (err error) {
return c.__updateDnsCacheDeadline(host, dnsTyp, answers, func(now time.Time, host string) (daedline time.Time, originalDeadline time.Time) {
if fixedTtl, ok := c.fixedDomainTtl[host]; ok {
/// NOTICE: Cannot set TTL accurately.
if now.Sub(deadline).Seconds() > float64(fixedTtl) {
deadline := now.Add(time.Duration(fixedTtl) * time.Second)
return deadline, deadline
}
}
return deadline, deadline
})
}
func (c *DnsController) UpdateDnsCacheTtl(host string, dnsTyp uint16, answers []dnsmessage.RR, ttl int) (err error) {
return c.__updateDnsCacheDeadline(host, dnsTyp, answers, func(now time.Time, host string) (daedline time.Time, originalDeadline time.Time) {
originalDeadline = now.Add(time.Duration(ttl) * time.Second)
if fixedTtl, ok := c.fixedDomainTtl[host]; ok {
return now.Add(time.Duration(fixedTtl) * time.Second), originalDeadline
} else {
return originalDeadline, originalDeadline
}
})
}
2023-02-25 01:38:21 +07:00
type udpRequest struct {
realSrc netip.AddrPort
realDst netip.AddrPort
src netip.AddrPort
lConn *net.UDPConn
routingResult *bpfRoutingResult
}
type dialArgument struct {
l4proto consts.L4ProtoStr
ipversion consts.IpVersionStr
bestDialer *dialer.Dialer
bestOutbound *outbound.DialerGroup
bestTarget netip.AddrPort
mark uint32
2024-08-27 08:49:51 +07:00
mptcp bool
2023-02-25 01:38:21 +07:00
}
func (c *DnsController) Handle_(dnsMessage *dnsmessage.Msg, req *udpRequest) (err error) {
if c.log.IsLevelEnabled(logrus.TraceLevel) && len(dnsMessage.Question) > 0 {
q := dnsMessage.Question[0]
c.log.Tracef("Received UDP(DNS) %v <-> %v: %v %v",
RefineSourceToShow(req.realSrc, req.realDst.Addr()), req.realDst.String(), strings.ToLower(q.Name), QtypeToString(q.Qtype),
)
}
2023-04-07 22:06:04 +07:00
if dnsMessage.Response {
return fmt.Errorf("DNS request expected but DNS response received")
}
// Prepare qname, qtype.
var qname string
var qtype uint16
if len(dnsMessage.Question) != 0 {
qname = dnsMessage.Question[0].Name
qtype = dnsMessage.Question[0].Qtype
2023-04-07 22:06:04 +07:00
}
// Check ip version preference and qtype.
switch qtype {
case dnsmessage.TypeA, dnsmessage.TypeAAAA:
if c.qtypePrefer == 0 {
return c.handle_(dnsMessage, req, true)
}
default:
return c.handle_(dnsMessage, req, true)
}
// Try to make both A and AAAA lookups.
dnsMessage2 := deepcopy.Copy(dnsMessage).(*dnsmessage.Msg)
dnsMessage2.Id = uint16(fastrand.Intn(math.MaxUint16))
var qtype2 uint16
2023-04-07 22:06:04 +07:00
switch qtype {
case dnsmessage.TypeA:
qtype2 = dnsmessage.TypeAAAA
case dnsmessage.TypeAAAA:
qtype2 = dnsmessage.TypeA
default:
return fmt.Errorf("unexpected qtype path")
}
dnsMessage2.Question[0].Qtype = qtype2
2023-04-07 22:06:04 +07:00
done := make(chan struct{})
go func() {
_ = c.handle_(dnsMessage2, req, false)
done <- struct{}{}
}()
err = c.handle_(dnsMessage, req, false)
<-done
if err != nil {
return err
}
// Join results and consider whether to response.
resp := c.LookupDnsRespCache_(dnsMessage, c.cacheKey(qname, qtype), true)
2023-04-07 22:06:04 +07:00
if resp == nil {
// resp is not valid.
c.log.WithFields(logrus.Fields{
"qname": qname,
}).Tracef("Reject %v due to resp not valid", qtype)
2023-04-07 22:06:04 +07:00
return c.sendReject_(dnsMessage, req)
}
// resp is valid.
cache2 := c.LookupDnsRespCache(c.cacheKey(qname, qtype2), true)
if c.qtypePrefer == qtype || cache2 == nil || !cache2.IncludeAnyIp() {
return sendPkt(c.log, resp, req.realDst, req.realSrc, req.src, req.lConn)
2023-04-07 22:06:04 +07:00
} else {
return c.sendReject_(dnsMessage, req)
}
}
func (c *DnsController) handle_(
dnsMessage *dnsmessage.Msg,
2023-04-07 22:06:04 +07:00
req *udpRequest,
needResp bool,
) (err error) {
// Prepare qname, qtype.
var qname string
var qtype uint16
if len(dnsMessage.Question) != 0 {
q := dnsMessage.Question[0]
qname = q.Name
qtype = q.Qtype
2023-04-07 22:06:04 +07:00
}
// Route request.
2023-04-07 22:06:04 +07:00
upstreamIndex, upstream, err := c.routing.RequestSelect(qname, qtype)
if err != nil {
return err
}
cacheKey := c.cacheKey(qname, qtype)
if upstreamIndex == consts.DnsRequestOutboundIndex_Reject {
// Reject with empty answer.
c.RemoveDnsRespCache(cacheKey)
2023-04-07 22:06:04 +07:00
return c.sendReject_(dnsMessage, req)
}
2023-04-07 22:06:04 +07:00
// No parallel for the same lookup.
_mu, _ := c.handling.LoadOrStore(cacheKey, new(sync.Mutex))
2023-04-07 22:06:04 +07:00
mu := _mu.(*sync.Mutex)
mu.Lock()
defer mu.Unlock()
defer c.handling.Delete(cacheKey)
2023-04-07 22:06:04 +07:00
if resp := c.LookupDnsRespCache_(dnsMessage, cacheKey, false); resp != nil {
2023-02-25 01:38:21 +07:00
// Send cache to client directly.
2023-04-07 22:06:04 +07:00
if needResp {
if err = sendPkt(c.log, resp, req.realDst, req.realSrc, req.src, req.lConn); err != nil {
2023-04-07 22:06:04 +07:00
return fmt.Errorf("failed to write cached DNS resp: %w", err)
}
2023-02-25 01:38:21 +07:00
}
if c.log.IsLevelEnabled(logrus.DebugLevel) && len(dnsMessage.Question) > 0 {
q := dnsMessage.Question[0]
c.log.Debugf("UDP(DNS) %v <-> Cache: %v %v",
RefineSourceToShow(req.realSrc, req.realDst.Addr()), strings.ToLower(q.Name), QtypeToString(q.Qtype),
2023-02-25 01:38:21 +07:00
)
}
return nil
}
if c.log.IsLevelEnabled(logrus.TraceLevel) {
upstreamName := upstreamIndex.String()
2023-02-25 01:38:21 +07:00
if upstream != nil {
upstreamName = upstream.String()
}
c.log.WithFields(logrus.Fields{
"question": dnsMessage.Question,
2023-02-25 01:38:21 +07:00
"upstream": upstreamName,
}).Traceln("Request to DNS upstream")
}
// Re-pack DNS packet.
data, err := dnsMessage.Pack()
if err != nil {
return fmt.Errorf("pack DNS packet: %w", err)
}
return c.dialSend(0, req, data, dnsMessage.Id, upstream, needResp)
2023-02-25 01:38:21 +07:00
}
2023-04-07 22:06:04 +07:00
// sendReject_ send empty answer.
func (c *DnsController) sendReject_(dnsMessage *dnsmessage.Msg, req *udpRequest) (err error) {
dnsMessage.Answer = nil
dnsMessage.Rcode = dnsmessage.RcodeSuccess
2023-04-07 22:06:04 +07:00
dnsMessage.Response = true
dnsMessage.RecursionAvailable = true
dnsMessage.Truncated = false
dnsMessage.Compress = true
2023-04-07 22:06:04 +07:00
if c.log.IsLevelEnabled(logrus.TraceLevel) {
c.log.WithFields(logrus.Fields{
"question": dnsMessage.Question,
}).Traceln("Reject")
2023-04-07 22:06:04 +07:00
}
data, err := dnsMessage.Pack()
if err != nil {
return fmt.Errorf("pack DNS packet: %w", err)
}
if err = sendPkt(c.log, data, req.realDst, req.realSrc, req.src, req.lConn); err != nil {
2023-04-07 22:06:04 +07:00
return err
}
return nil
}
func (c *DnsController) dialSend(invokingDepth int, req *udpRequest, data []byte, id uint16, upstream *dns.Upstream, needResp bool) (err error) {
2023-02-25 01:38:21 +07:00
if invokingDepth >= MaxDnsLookupDepth {
return fmt.Errorf("too deep DNS lookup invoking (depth: %v); there may be infinite loop in your DNS response routing", MaxDnsLookupDepth)
}
upstreamName := "asis"
if upstream == nil {
// As-is.
// As-is should not be valid in response routing, thus using connection realDest is reasonable.
var ip46 netutils.Ip46
if req.realDst.Addr().Is4() {
ip46.Ip4 = req.realDst.Addr()
} else {
ip46.Ip6 = req.realDst.Addr()
}
upstream = &dns.Upstream{
Scheme: "udp",
Hostname: req.realDst.Addr().String(),
Port: req.realDst.Port(),
Ip46: &ip46,
}
} else {
upstreamName = upstream.String()
}
// Select best dial arguments (outbound, dialer, l4proto, ipversion, etc.)
dialArgument, err := c.bestDialerChooser(req, upstream)
if err != nil {
return err
}
networkType := &dialer.NetworkType{
L4Proto: dialArgument.l4proto,
IpVersion: dialArgument.ipversion,
IsDns: true,
2023-02-25 01:38:21 +07:00
}
// Dial and send.
var respMsg *dnsmessage.Msg
2023-02-25 01:38:21 +07:00
// defer in a recursive call will delay Close(), thus we Close() before
// the next recursive call. However, a connection cannot be closed twice.
// We should set a connClosed flag to avoid it.
var connClosed bool
ctxDial, cancel := context.WithTimeout(context.TODO(), consts.DefaultDialTimeout)
defer cancel()
// get forwarder from cache
c.dnsForwarderCacheMu.Lock()
forwarder, ok := c.dnsForwarderCache[upstreamName]
if !ok {
forwarder, err = newDnsForwarder(upstream, *dialArgument)
if err != nil {
c.dnsForwarderCacheMu.Unlock()
return err
2023-02-25 01:38:21 +07:00
}
c.dnsForwarderCache[upstreamName] = forwarder
}
c.dnsForwarderCacheMu.Unlock()
2023-02-25 01:38:21 +07:00
defer func() {
if !connClosed {
forwarder.Close()
2023-02-25 01:38:21 +07:00
}
}()
2023-02-25 01:38:21 +07:00
if err != nil {
return err
}
respMsg, err = forwarder.ForwardDNS(ctxDial, data)
if err != nil {
return err
2023-02-25 01:38:21 +07:00
}
// Close conn before the recursive call.
forwarder.Close()
2023-02-25 01:38:21 +07:00
connClosed = true
// Route response.
upstreamIndex, nextUpstream, err := c.routing.ResponseSelect(respMsg, upstream)
if err != nil {
return err
}
switch upstreamIndex {
case consts.DnsResponseOutboundIndex_Accept:
// Accept.
if c.log.IsLevelEnabled(logrus.TraceLevel) {
c.log.WithFields(logrus.Fields{
"question": respMsg.Question,
2023-02-25 01:38:21 +07:00
"upstream": upstreamName,
}).Traceln("Accept")
}
case consts.DnsResponseOutboundIndex_Reject:
// Reject the request with empty answer.
respMsg.Answer = nil
2023-02-25 01:38:21 +07:00
if c.log.IsLevelEnabled(logrus.TraceLevel) {
c.log.WithFields(logrus.Fields{
"question": respMsg.Question,
2023-02-25 01:38:21 +07:00
"upstream": upstreamName,
}).Traceln("Reject with empty answer")
}
// We also cache response reject.
2023-02-25 01:38:21 +07:00
default:
if c.log.IsLevelEnabled(logrus.TraceLevel) {
c.log.WithFields(logrus.Fields{
"question": respMsg.Question,
2023-02-25 01:38:21 +07:00
"last_upstream": upstreamName,
"next_upstream": nextUpstream.String(),
}).Traceln("Change DNS upstream and resend")
}
2023-04-07 22:06:04 +07:00
return c.dialSend(invokingDepth+1, req, data, id, nextUpstream, needResp)
2023-02-25 01:38:21 +07:00
}
if upstreamIndex.IsReserved() && c.log.IsLevelEnabled(logrus.InfoLevel) {
var (
qname string
qtype string
)
if len(respMsg.Question) > 0 {
q := respMsg.Question[0]
qname = strings.ToLower(q.Name)
qtype = QtypeToString(q.Qtype)
2023-02-25 01:38:21 +07:00
}
fields := logrus.Fields{
"network": networkType.String(),
"outbound": dialArgument.bestOutbound.Name,
"policy": dialArgument.bestOutbound.GetSelectionPolicy(),
2023-02-28 20:25:15 +07:00
"dialer": dialArgument.bestDialer.Property().Name,
2023-03-30 00:55:56 +07:00
"_qname": qname,
2023-02-25 01:38:21 +07:00
"qtype": qtype,
"pid": req.routingResult.Pid,
"dscp": req.routingResult.Dscp,
2023-02-25 01:38:21 +07:00
"pname": ProcessName2String(req.routingResult.Pname[:]),
"mac": Mac2String(req.routingResult.Mac[:]),
}
switch upstreamIndex {
case consts.DnsResponseOutboundIndex_Accept:
c.log.WithFields(fields).Infof("%v <-> %v", RefineSourceToShow(req.realSrc, req.realDst.Addr()), RefineAddrPortToShow(dialArgument.bestTarget))
2023-02-25 01:38:21 +07:00
case consts.DnsResponseOutboundIndex_Reject:
c.log.WithFields(fields).Infof("%v -> reject", RefineSourceToShow(req.realSrc, req.realDst.Addr()))
2023-02-25 01:38:21 +07:00
default:
return fmt.Errorf("unknown upstream: %v", upstreamIndex.String())
}
}
if err = c.NormalizeAndCacheDnsResp_(respMsg); err != nil {
2023-02-25 01:38:21 +07:00
return err
}
2023-04-07 22:06:04 +07:00
if needResp {
// Keep the id the same with request.
respMsg.Id = id
respMsg.Compress = true
data, err = respMsg.Pack()
if err != nil {
return err
}
if err = sendPkt(c.log, data, req.realDst, req.realSrc, req.src, req.lConn); err != nil {
2023-04-07 22:06:04 +07:00
return err
}
2023-02-25 01:38:21 +07:00
}
return nil
}