mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2024-12-15 11:22:49 +03:00
dea8a585f8
Updates #4016. Squashed commit of the following: commit 83bb15c5a5098103cd17e76b49f456fb4fa73408 Merge: 81905503313555b1
Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Mon Dec 27 19:36:44 2021 +0300 Merge branch 'master' into 4016-rw-subdomain commit 81905503c977c004d7ddca1d4e7537bf76443a6e Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Mon Dec 27 19:35:51 2021 +0300 filtering: fix self reqs commit b706f481f00232d28dade0bd747a7496753c7deb Merge: 29cf83de661f4ece
Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Mon Dec 27 19:13:08 2021 +0300 Merge branch 'master' into 4016-rw-subdomain commit 29cf83de8e3ff60ea1c471c2a161055b1377392d Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Mon Dec 27 19:07:08 2021 +0300 all: fix docs commit 9213fd8ec2b81e65b1198ab241400065f14684b1 Author: Ainar Garipov <A.Garipov@AdGuard.COM> Date: Mon Dec 27 18:44:06 2021 +0300 filtering: fix rw to subdomain
116 lines
2.8 KiB
Go
116 lines
2.8 KiB
Go
package dnsforward
|
|
|
|
import (
|
|
"bytes"
|
|
"encoding/binary"
|
|
"time"
|
|
|
|
"github.com/AdguardTeam/golibs/cache"
|
|
"github.com/AdguardTeam/golibs/log"
|
|
"github.com/AdguardTeam/golibs/netutil"
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
// uint* sizes in bytes to improve readability.
|
|
//
|
|
// TODO(e.burkov): Remove when there will be a more regardful way to define
|
|
// those. See https://github.com/golang/go/issues/29982.
|
|
const (
|
|
uint16sz = 2
|
|
uint64sz = 8
|
|
)
|
|
|
|
// recursionDetector detects recursion in DNS forwarding.
|
|
type recursionDetector struct {
|
|
recentRequests cache.Cache
|
|
ttl time.Duration
|
|
}
|
|
|
|
// check checks if the passed req was already sent by the server.
|
|
func (rd *recursionDetector) check(msg dns.Msg) (ok bool) {
|
|
if len(msg.Question) == 0 {
|
|
return false
|
|
}
|
|
|
|
key := msgToSignature(msg)
|
|
expireData := rd.recentRequests.Get(key)
|
|
if expireData == nil {
|
|
return false
|
|
}
|
|
|
|
expire := time.Unix(0, int64(binary.BigEndian.Uint64(expireData)))
|
|
|
|
return time.Now().Before(expire)
|
|
}
|
|
|
|
// add caches the msg if it has anything in the questions section.
|
|
func (rd *recursionDetector) add(msg dns.Msg) {
|
|
now := time.Now()
|
|
|
|
if len(msg.Question) == 0 {
|
|
return
|
|
}
|
|
|
|
key := msgToSignature(msg)
|
|
expire64 := uint64(now.Add(rd.ttl).UnixNano())
|
|
expire := make([]byte, uint64sz)
|
|
binary.BigEndian.PutUint64(expire, expire64)
|
|
|
|
rd.recentRequests.Set(key, expire)
|
|
}
|
|
|
|
// clear clears the recent requests cache.
|
|
func (rd *recursionDetector) clear() {
|
|
rd.recentRequests.Clear()
|
|
}
|
|
|
|
// newRecursionDetector returns the initialized *recursionDetector.
|
|
func newRecursionDetector(ttl time.Duration, suspectsNum uint) (rd *recursionDetector) {
|
|
return &recursionDetector{
|
|
recentRequests: cache.New(cache.Config{
|
|
EnableLRU: true,
|
|
MaxCount: suspectsNum,
|
|
}),
|
|
ttl: ttl,
|
|
}
|
|
}
|
|
|
|
// msgToSignature converts msg into it's signature represented in bytes.
|
|
func msgToSignature(msg dns.Msg) (sig []byte) {
|
|
sig = make([]byte, uint16sz*2+netutil.MaxDomainNameLen)
|
|
// The binary.BigEndian byte order is used everywhere except when the real
|
|
// machine's endianness is needed.
|
|
byteOrder := binary.BigEndian
|
|
byteOrder.PutUint16(sig[0:], msg.Id)
|
|
q := msg.Question[0]
|
|
byteOrder.PutUint16(sig[uint16sz:], q.Qtype)
|
|
copy(sig[2*uint16sz:], []byte(q.Name))
|
|
|
|
return sig
|
|
}
|
|
|
|
// msgToSignatureSlow converts msg into it's signature represented in bytes in
|
|
// the less efficient way.
|
|
//
|
|
// See BenchmarkMsgToSignature.
|
|
func msgToSignatureSlow(msg dns.Msg) (sig []byte) {
|
|
type msgSignature struct {
|
|
name [netutil.MaxDomainNameLen]byte
|
|
id uint16
|
|
qtype uint16
|
|
}
|
|
|
|
b := bytes.NewBuffer(sig)
|
|
q := msg.Question[0]
|
|
signature := msgSignature{
|
|
id: msg.Id,
|
|
qtype: q.Qtype,
|
|
}
|
|
copy(signature.name[:], q.Name)
|
|
if err := binary.Write(b, binary.BigEndian, signature); err != nil {
|
|
log.Debug("writing message signature: %s", err)
|
|
}
|
|
|
|
return b.Bytes()
|
|
}
|