-
Notifications
You must be signed in to change notification settings - Fork 160
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implements RFC 6347 Section 4.1.2.6. Set config.ReplayProtectionWindow to change the size of the protection window. Default is 64.
- Loading branch information
Showing
9 changed files
with
520 additions
and
7 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,78 @@ | ||
package replaydetector | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
// fixedBigInt is the fix-sized multi-word integer. | ||
type fixedBigInt struct { | ||
bits []uint64 | ||
n uint | ||
msbMask uint64 | ||
} | ||
|
||
// newFixedBigInt creates a new fix-sized multi-word int. | ||
func newFixedBigInt(n uint) *fixedBigInt { | ||
chunkSize := (n + 63) / 64 | ||
if chunkSize == 0 { | ||
chunkSize = 1 | ||
} | ||
return &fixedBigInt{ | ||
bits: make([]uint64, chunkSize), | ||
n: n, | ||
msbMask: (1 << (64 - n%64)) - 1, | ||
} | ||
} | ||
|
||
// Lsh is the left shift operation. | ||
func (s *fixedBigInt) Lsh(n uint) { | ||
if n == 0 { | ||
return | ||
} | ||
nChunk := int(n / 64) | ||
nN := n % 64 | ||
|
||
for i := len(s.bits) - 1; i >= 0; i-- { | ||
var carry uint64 | ||
if i-nChunk >= 0 { | ||
carry = s.bits[i-nChunk] << nN | ||
if i-nChunk-1 >= 0 { | ||
carry |= s.bits[i-nChunk-1] >> (64 - nN) | ||
} | ||
} | ||
s.bits[i] = (s.bits[i] << n) | carry | ||
} | ||
s.bits[len(s.bits)-1] &= s.msbMask | ||
} | ||
|
||
// Bit returns i-th bit of the fixedBigInt. | ||
func (s *fixedBigInt) Bit(i uint) uint { | ||
if i >= s.n { | ||
return 0 | ||
} | ||
chunk := i / 64 | ||
pos := i % 64 | ||
if s.bits[chunk]&(1<<pos) != 0 { | ||
return 1 | ||
} | ||
return 0 | ||
} | ||
|
||
// SetBit sets i-th bit to 1. | ||
func (s *fixedBigInt) SetBit(i uint) { | ||
if i >= s.n { | ||
return | ||
} | ||
chunk := i / 64 | ||
pos := i % 64 | ||
s.bits[chunk] |= 1 << pos | ||
} | ||
|
||
// String returns string representation of fixedBigInt. | ||
func (s *fixedBigInt) String() string { | ||
var out string | ||
for i := len(s.bits) - 1; i >= 0; i-- { | ||
out += fmt.Sprintf("%016X", s.bits[i]) | ||
} | ||
return out | ||
} |
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,58 @@ | ||
package replaydetector | ||
|
||
import ( | ||
"fmt" | ||
) | ||
|
||
func Example_fixedBigInt_SetBit() { | ||
bi := newFixedBigInt(224) | ||
|
||
bi.SetBit(0) | ||
fmt.Println(bi.String()) | ||
bi.Lsh(1) | ||
fmt.Println(bi.String()) | ||
|
||
bi.Lsh(0) | ||
fmt.Println(bi.String()) | ||
|
||
bi.SetBit(10) | ||
fmt.Println(bi.String()) | ||
bi.Lsh(20) | ||
fmt.Println(bi.String()) | ||
|
||
bi.SetBit(80) | ||
fmt.Println(bi.String()) | ||
bi.Lsh(4) | ||
fmt.Println(bi.String()) | ||
|
||
bi.SetBit(130) | ||
fmt.Println(bi.String()) | ||
bi.Lsh(64) | ||
fmt.Println(bi.String()) | ||
|
||
bi.SetBit(7) | ||
fmt.Println(bi.String()) | ||
|
||
bi.Lsh(129) | ||
fmt.Println(bi.String()) | ||
|
||
for i := 0; i < 256; i++ { | ||
bi.Lsh(1) | ||
bi.SetBit(0) | ||
} | ||
fmt.Println(bi.String()) | ||
|
||
// output: | ||
// 0000000000000000000000000000000000000000000000000000000000000001 | ||
// 0000000000000000000000000000000000000000000000000000000000000002 | ||
// 0000000000000000000000000000000000000000000000000000000000000002 | ||
// 0000000000000000000000000000000000000000000000000000000000000402 | ||
// 0000000000000000000000000000000000000000000000000000000040200000 | ||
// 0000000000000000000000000000000000000000000100000000000040200000 | ||
// 0000000000000000000000000000000000000000001000000000000402000000 | ||
// 0000000000000000000000000000000400000000001000000000000402000000 | ||
// 0000000000000004000000000010000000000004020000000000000000000000 | ||
// 0000000000000004000000000010000000000004020000000000000000000080 | ||
// 0000000004000000000000000000010000000000000000000000000000000000 | ||
// 00000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF | ||
} |
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,51 @@ | ||
// Package replaydetector provides packet replay detection algorithm. | ||
package replaydetector | ||
|
||
// ReplayDetector is the interface of sequence replay detector. | ||
type ReplayDetector interface { | ||
// Check returns true if given sequence number is not replayed. | ||
// Call accept() to mark the packet is received properly. | ||
Check(seq uint64) (accept func(), ok bool) | ||
} | ||
|
||
type slidingWindowDetector struct { | ||
latestSeq uint64 | ||
maxSeq uint64 | ||
windowSize uint | ||
mask *fixedBigInt | ||
} | ||
|
||
// New creates ReplayDetector. | ||
func New(windowSize uint, maxSeq uint64) ReplayDetector { | ||
return &slidingWindowDetector{ | ||
maxSeq: maxSeq, | ||
windowSize: windowSize, | ||
mask: newFixedBigInt(windowSize), | ||
} | ||
} | ||
|
||
func (d *slidingWindowDetector) Check(seq uint64) (accept func(), ok bool) { | ||
if seq > d.maxSeq { | ||
// Exceeded upper limit. | ||
return func() {}, false | ||
} | ||
|
||
if seq <= d.latestSeq { | ||
if d.latestSeq > uint64(d.windowSize)+seq { | ||
return func() {}, false | ||
} | ||
if d.mask.Bit(uint(d.latestSeq-seq)) != 0 { | ||
// The sequence number is duplicated. | ||
return func() {}, false | ||
} | ||
} | ||
|
||
return func() { | ||
if seq > d.latestSeq { | ||
// Update the head of the window. | ||
d.mask.Lsh(uint(seq - d.latestSeq)) | ||
d.latestSeq = seq | ||
} | ||
d.mask.SetBit(uint(d.latestSeq - seq)) | ||
}, true | ||
} |
Oops, something went wrong.