1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
const SIZE_OF_INTEGER: usize = 32;
const BITMAP_LEN: usize = 1024 / SIZE_OF_INTEGER;
const BITMAP_INDEX_MASK: u64 = BITMAP_LEN as u64 - 1;
const REDUNDANT_BIT_SHIFTS: u64 = 5;
const REDUNDANT_BITS: u64 = (1 << REDUNDANT_BIT_SHIFTS);
const BITMAP_LOC_MASK: u64 = (REDUNDANT_BITS - 1);
const WINDOW_SIZE: u64 = 512;
#[derive(Default)]
pub struct AntiReplay {
last: u64,
bitmap: [u32; BITMAP_LEN],
}
impl AntiReplay {
pub fn new() -> Self {
Self::default()
}
pub fn within_window(&self, seq: u64) -> bool {
if seq == 0 {
return false;
}
if seq > self.last {
return true;
}
if (seq + WINDOW_SIZE) < self.last {
return false;
}
let bit_location = seq & BITMAP_LOC_MASK;
let index = (seq >> REDUNDANT_BIT_SHIFTS) & BITMAP_INDEX_MASK;
self.bitmap[index as usize] & (1 << bit_location) == 0
}
pub fn update_window(&mut self, seq: u64) {
if !self.within_window(seq) {
return;
}
let index = seq >> REDUNDANT_BIT_SHIFTS;
if seq > self.last {
let index_cur = self.last >> REDUNDANT_BIT_SHIFTS;
let mut diff = index - index_cur;
if diff > BITMAP_LEN as u64 {
diff = BITMAP_LEN as u64;
}
for id in 0..diff {
let iindex = (id + index_cur + 1) & BITMAP_INDEX_MASK;
self.bitmap[iindex as usize] = 0;
}
self.last = seq;
}
let index = index & BITMAP_INDEX_MASK;
let bit_location = seq & BITMAP_LOC_MASK;
self.bitmap[index as usize] |= 1 << bit_location;
}
}
#[test]
pub fn window() {
let mut e = AntiReplay::default();
assert_eq!(e.within_window(0), false);
assert_eq!(e.within_window(1), true);
assert_eq!(e.within_window(2000), true);
e.update_window(2000);
assert_eq!(e.within_window(2000), false);
assert_eq!(e.within_window(2001), true);
assert_eq!(e.within_window(1000), false);
e.update_window(20000);
assert_eq!(e.within_window(2000), false);
assert_eq!(e.within_window(2002), false);
assert_eq!(e.within_window(20000), false);
assert_eq!(e.within_window(20001), true);
assert_eq!(e.within_window(10000), false);
e.update_window(200000);
assert_eq!(e.within_window(20000), false);
assert_eq!(e.within_window(20002), false);
assert_eq!(e.within_window(200000), false);
assert_eq!(e.within_window(200001), true);
assert_eq!(e.within_window(100000), false);
assert_eq!(e.within_window(1), false);
}