78
vendor/github.com/pion/transport/replaydetector/fixedbig.go
generated
vendored
Normal file
78
vendor/github.com/pion/transport/replaydetector/fixedbig.go
generated
vendored
Normal file
@@ -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
|
||||
}
|
||||
116
vendor/github.com/pion/transport/replaydetector/replaydetector.go
generated
vendored
Normal file
116
vendor/github.com/pion/transport/replaydetector/replaydetector.go
generated
vendored
Normal file
@@ -0,0 +1,116 @@
|
||||
// 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.
|
||||
// Created ReplayDetector doesn't allow wrapping.
|
||||
// It can handle monotonically increasing sequence number up to
|
||||
// full 64bit number. It is suitable for DTLS replay protection.
|
||||
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
|
||||
}
|
||||
diff := (d.latestSeq - seq) % d.maxSeq
|
||||
d.mask.SetBit(uint(diff))
|
||||
}, true
|
||||
}
|
||||
|
||||
// WithWrap creates ReplayDetector allowing sequence wrapping.
|
||||
// This is suitable for short bitwidth counter like SRTP and SRTCP.
|
||||
func WithWrap(windowSize uint, maxSeq uint64) ReplayDetector {
|
||||
return &wrappedSlidingWindowDetector{
|
||||
maxSeq: maxSeq,
|
||||
windowSize: windowSize,
|
||||
mask: newFixedBigInt(windowSize),
|
||||
}
|
||||
}
|
||||
|
||||
type wrappedSlidingWindowDetector struct {
|
||||
latestSeq uint64
|
||||
maxSeq uint64
|
||||
windowSize uint
|
||||
mask *fixedBigInt
|
||||
init bool
|
||||
}
|
||||
|
||||
func (d *wrappedSlidingWindowDetector) Check(seq uint64) (accept func(), ok bool) {
|
||||
if seq > d.maxSeq {
|
||||
// Exceeded upper limit.
|
||||
return func() {}, false
|
||||
}
|
||||
if !d.init {
|
||||
if seq != 0 {
|
||||
d.latestSeq = seq - 1
|
||||
} else {
|
||||
d.latestSeq = d.maxSeq
|
||||
}
|
||||
d.init = true
|
||||
}
|
||||
|
||||
diff := int64(d.latestSeq) - int64(seq)
|
||||
// Wrap the number.
|
||||
if diff > int64(d.maxSeq)/2 {
|
||||
diff -= int64(d.maxSeq + 1)
|
||||
} else if diff <= -int64(d.maxSeq)/2 {
|
||||
diff += int64(d.maxSeq + 1)
|
||||
}
|
||||
|
||||
if diff >= int64(d.windowSize) {
|
||||
// Too old.
|
||||
return func() {}, false
|
||||
}
|
||||
if diff >= 0 {
|
||||
if d.mask.Bit(uint(diff)) != 0 {
|
||||
// The sequence number is duplicated.
|
||||
return func() {}, false
|
||||
}
|
||||
}
|
||||
|
||||
return func() {
|
||||
if diff < 0 {
|
||||
// Update the head of the window.
|
||||
d.mask.Lsh(uint(-diff))
|
||||
d.latestSeq = seq
|
||||
}
|
||||
d.mask.SetBit(uint(d.latestSeq - seq))
|
||||
}, true
|
||||
}
|
||||
Reference in New Issue
Block a user