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.
- Loading branch information
1 parent
557bbcb
commit f3f9145
Showing
5 changed files
with
311 additions
and
19 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
package dnsforward | ||
|
||
import ( | ||
"bytes" | ||
"encoding/binary" | ||
"time" | ||
|
||
"github.com/AdguardTeam/golibs/cache" | ||
"github.com/AdguardTeam/golibs/log" | ||
"github.com/miekg/dns" | ||
) | ||
|
||
// recursionDetector detects recursion in DNS forwarding. | ||
type recursionDetector struct { | ||
ttl time.Duration | ||
suspects cache.Cache | ||
} | ||
|
||
// check checks if the passed req was already sent by s. | ||
func (rd *recursionDetector) check(msg dns.Msg) (yes bool) { | ||
now := time.Now() | ||
|
||
if len(msg.Question) == 0 { | ||
return false | ||
} | ||
|
||
key := msgToSignature(msg) | ||
expire := rd.suspects.Get(key) | ||
if expire == nil { | ||
return false | ||
} | ||
|
||
return binary.BigEndian.Uint64(expire) > uint64(now.Unix()) | ||
} | ||
|
||
// suspect adds the req to the recursion tracking cache. | ||
func (rd *recursionDetector) suspect(msg dns.Msg) { | ||
now := time.Now() | ||
|
||
if len(msg.Question) == 0 { | ||
return | ||
} | ||
|
||
key := msgToSignature(msg) | ||
expire := make([]byte, 64) | ||
binary.BigEndian.PutUint64(expire, uint64(now.Add(rd.ttl).Unix())) | ||
|
||
rd.suspects.Set(key, expire) | ||
} | ||
|
||
// reset reinitializes the recursionDetector. | ||
func (rd *recursionDetector) reset() { | ||
rd.suspects.Clear() | ||
} | ||
|
||
// newRecursionDetector returns the initialized *recursionDetector. | ||
func newRecursionDetector(ttl time.Duration, suspectsNum uint) (rd *recursionDetector) { | ||
return &recursionDetector{ | ||
ttl: ttl, | ||
suspects: cache.New(cache.Config{ | ||
EnableLRU: true, | ||
MaxCount: suspectsNum, | ||
}), | ||
} | ||
} | ||
|
||
// msgToSignature converts msg into it's signature represented in bytes. | ||
func msgToSignature(msg dns.Msg) (sig []byte) { | ||
const ( | ||
uint16sz = 16 | ||
maxNameLen = 253 | ||
) | ||
|
||
sig = make([]byte, uint16sz*2+maxNameLen) | ||
binary.BigEndian.PutUint16(sig[0:], msg.Id) | ||
q := msg.Question[0] | ||
binary.BigEndian.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 [253]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.