forked from AdguardTeam/AdGuardHome
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Pull request: 3185 detecting recursion
Merge in DNS/adguard-home from 3185-recursion to master Closes AdguardTeam#3185. Squashed commit of the following: commit 2fa4422 Merge: 7975957 7a48e92 Author: Eugene Burkov <e.burkov@adguard.com> Date: Thu May 27 19:04:44 2021 +0300 Merge branch 'master' into 3185-recursion commit 7975957 Author: Eugene Burkov <e.burkov@adguard.com> Date: Thu May 27 17:36:22 2021 +0300 dnsforward: imp docs commit 1af7131 Author: Eugene Burkov <e.burkov@adguard.com> Date: Thu May 27 17:15:00 2021 +0300 dnsforward: imp code, tests, docs commit f3f9145 Author: Eugene Burkov <e.burkov@adguard.com> Date: Thu May 27 15:45:44 2021 +0300 dnsforward: add recursion detector
- Loading branch information
1 parent
f7e6d4a
commit eff3e71
Showing
6 changed files
with
324 additions
and
23 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
package dnsforward | ||
|
||
import ( | ||
"bytes" | ||
"encoding/binary" | ||
"time" | ||
|
||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet" | ||
"github.com/AdguardTeam/golibs/cache" | ||
"github.com/AdguardTeam/golibs/log" | ||
"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 s. | ||
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+aghnet.MaxDomainNameLen) | ||
// The binary.BigEndian byte order is used everywhere except when the | ||
// real machine's endianess 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 [aghnet.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() | ||
} |
Oops, something went wrong.