all: resync with master
This commit is contained in:
parent
158d4f0249
commit
5c6bb33e3a
|
@ -265,8 +265,8 @@
|
||||||
# need to build a few of these.
|
# need to build a few of these.
|
||||||
'variables':
|
'variables':
|
||||||
'channel': 'beta'
|
'channel': 'beta'
|
||||||
'dockerFrontend': '${bamboo.adguardRegistryBasePath}/home-js-builder:2.0'
|
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||||
'dockerGo': '${bamboo.adguardRegistryBasePath}/go-builder:1.22.5--1'
|
'dockerGo': 'adguard/go-builder:1.22.5--1'
|
||||||
# release-vX.Y.Z branches are the branches from which the actual final
|
# release-vX.Y.Z branches are the branches from which the actual final
|
||||||
# release is built.
|
# release is built.
|
||||||
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
- '^release-v[0-9]+\.[0-9]+\.[0-9]+':
|
||||||
|
@ -281,5 +281,5 @@
|
||||||
# are the ones that actually get released.
|
# are the ones that actually get released.
|
||||||
'variables':
|
'variables':
|
||||||
'channel': 'release'
|
'channel': 'release'
|
||||||
'dockerFrontend': '${bamboo.adguardRegistryBasePath}/home-js-builder:2.0'
|
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||||
'dockerGo': '${bamboo.adguardRegistryBasePath}/go-builder:1.22.5--1'
|
'dockerGo': 'adguard/go-builder:1.22.5--1'
|
||||||
|
|
|
@ -194,6 +194,6 @@
|
||||||
# Set the default release channel on the release branch to beta, as we
|
# Set the default release channel on the release branch to beta, as we
|
||||||
# may need to build a few of these.
|
# may need to build a few of these.
|
||||||
'variables':
|
'variables':
|
||||||
'dockerFrontend': '${bamboo.adguardRegistryBasePath}/home-js-builder:2.0'
|
'dockerFrontend': 'adguard/home-js-builder:2.0'
|
||||||
'dockerGo': '${bamboo.adguardRegistryBasePath}/go-builder:1.22.5--1'
|
'dockerGo': 'adguard/go-builder:1.22.5--1'
|
||||||
'channel': 'candidate'
|
'channel': 'candidate'
|
||||||
|
|
|
@ -1,115 +0,0 @@
|
||||||
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()
|
|
||||||
}
|
|
|
@ -1,148 +0,0 @@
|
||||||
package dnsforward
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/binary"
|
|
||||||
"testing"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/miekg/dns"
|
|
||||||
"github.com/stretchr/testify/assert"
|
|
||||||
)
|
|
||||||
|
|
||||||
func TestRecursionDetector_Check(t *testing.T) {
|
|
||||||
rd := newRecursionDetector(0, 2)
|
|
||||||
|
|
||||||
const (
|
|
||||||
recID = 1234
|
|
||||||
recTTL = time.Hour * 100
|
|
||||||
)
|
|
||||||
|
|
||||||
const nonRecID = recID * 2
|
|
||||||
|
|
||||||
sampleQuestion := dns.Question{
|
|
||||||
Name: "some.domain",
|
|
||||||
Qtype: dns.TypeAAAA,
|
|
||||||
}
|
|
||||||
sampleMsg := dns.Msg{
|
|
||||||
MsgHdr: dns.MsgHdr{
|
|
||||||
Id: recID,
|
|
||||||
},
|
|
||||||
Question: []dns.Question{sampleQuestion},
|
|
||||||
}
|
|
||||||
|
|
||||||
// Manually add the message with big ttl.
|
|
||||||
key := msgToSignature(sampleMsg)
|
|
||||||
expire := make([]byte, uint64sz)
|
|
||||||
binary.BigEndian.PutUint64(expire, uint64(time.Now().Add(recTTL).UnixNano()))
|
|
||||||
rd.recentRequests.Set(key, expire)
|
|
||||||
|
|
||||||
// Add an expired message.
|
|
||||||
sampleMsg.Id = nonRecID
|
|
||||||
rd.add(sampleMsg)
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
questions []dns.Question
|
|
||||||
id uint16
|
|
||||||
want bool
|
|
||||||
}{{
|
|
||||||
name: "recurrent",
|
|
||||||
questions: []dns.Question{sampleQuestion},
|
|
||||||
id: recID,
|
|
||||||
want: true,
|
|
||||||
}, {
|
|
||||||
name: "not_suspected",
|
|
||||||
questions: []dns.Question{sampleQuestion},
|
|
||||||
id: recID + 1,
|
|
||||||
want: false,
|
|
||||||
}, {
|
|
||||||
name: "expired",
|
|
||||||
questions: []dns.Question{sampleQuestion},
|
|
||||||
id: nonRecID,
|
|
||||||
want: false,
|
|
||||||
}, {
|
|
||||||
name: "empty",
|
|
||||||
questions: []dns.Question{},
|
|
||||||
id: nonRecID,
|
|
||||||
want: false,
|
|
||||||
}}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
sampleMsg.Id = tc.id
|
|
||||||
sampleMsg.Question = tc.questions
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
detected := rd.check(sampleMsg)
|
|
||||||
assert.Equal(t, tc.want, detected)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRecursionDetector_Suspect(t *testing.T) {
|
|
||||||
rd := newRecursionDetector(0, 1)
|
|
||||||
|
|
||||||
testCases := []struct {
|
|
||||||
name string
|
|
||||||
msg dns.Msg
|
|
||||||
want int
|
|
||||||
}{{
|
|
||||||
name: "simple",
|
|
||||||
msg: dns.Msg{
|
|
||||||
MsgHdr: dns.MsgHdr{
|
|
||||||
Id: 1234,
|
|
||||||
},
|
|
||||||
Question: []dns.Question{{
|
|
||||||
Name: "some.domain",
|
|
||||||
Qtype: dns.TypeA,
|
|
||||||
}},
|
|
||||||
},
|
|
||||||
want: 1,
|
|
||||||
}, {
|
|
||||||
name: "unencumbered",
|
|
||||||
msg: dns.Msg{},
|
|
||||||
want: 0,
|
|
||||||
}}
|
|
||||||
|
|
||||||
for _, tc := range testCases {
|
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
|
||||||
t.Cleanup(rd.clear)
|
|
||||||
rd.add(tc.msg)
|
|
||||||
assert.Equal(t, tc.want, rd.recentRequests.Stats().Count)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var sink []byte
|
|
||||||
|
|
||||||
func BenchmarkMsgToSignature(b *testing.B) {
|
|
||||||
const name = "some.not.very.long.host.name"
|
|
||||||
|
|
||||||
msg := dns.Msg{
|
|
||||||
MsgHdr: dns.MsgHdr{
|
|
||||||
Id: 1234,
|
|
||||||
},
|
|
||||||
Question: []dns.Question{{
|
|
||||||
Name: name,
|
|
||||||
Qtype: dns.TypeAAAA,
|
|
||||||
}},
|
|
||||||
}
|
|
||||||
|
|
||||||
b.Run("efficient", func(b *testing.B) {
|
|
||||||
b.ReportAllocs()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
sink = msgToSignature(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.NotEmpty(b, sink)
|
|
||||||
})
|
|
||||||
|
|
||||||
b.Run("inefficient", func(b *testing.B) {
|
|
||||||
b.ReportAllocs()
|
|
||||||
|
|
||||||
for i := 0; i < b.N; i++ {
|
|
||||||
sink = msgToSignatureSlow(msg)
|
|
||||||
}
|
|
||||||
|
|
||||||
assert.NotEmpty(b, sink)
|
|
||||||
})
|
|
||||||
}
|
|
Loading…
Reference in New Issue