1#[cfg(test)]
2#[path = "../../tests/flow/config.rs"]
3mod tests;
4
5use std::cmp::min;
6
7use log::info;
8use rand::Rng;
9use rand::distributions::Standard;
10use rand::prelude::Distribution;
11
12use crate::bytes::{ByteBufferMut, DynamicByteBuffer};
13use crate::flow::error::FlowControllerError;
14use crate::settings::{Settings, keys};
15use crate::utils::random::get_rng;
16use crate::utils::sync::AsyncExecutor;
17use crate::utils::unix_timestamp_ms;
18use crate::weighted_random;
19
20#[derive(Debug, Clone)]
25pub enum FakeBodyMode {
26 Empty,
28 Random {
30 min_length: usize,
31 max_length: usize,
32 service: bool,
33 },
34 Constant {
36 packet_length: usize,
37 },
38}
39
40impl FakeBodyMode {
41 #[inline]
43 pub(crate) fn description(&self) -> String {
44 match self {
45 FakeBodyMode::Empty => "Empty".to_string(),
46 FakeBodyMode::Random {
47 min_length,
48 max_length,
49 service,
50 } => format!("Random({min_length}..{max_length},svc={service})"),
51 FakeBodyMode::Constant {
52 packet_length,
53 } => format!("Constant({packet_length})"),
54 }
55 }
56
57 pub fn max_len(&self) -> usize {
59 match self {
60 FakeBodyMode::Empty => 0,
61 FakeBodyMode::Random {
62 max_length,
63 ..
64 } => *max_length,
65 FakeBodyMode::Constant {
66 packet_length,
67 } => *packet_length,
68 }
69 }
70
71 pub fn get_length(&self, max_packet_size: usize, taken_packet_size: usize, is_service: bool) -> usize {
72 match self {
73 FakeBodyMode::Empty => 0,
74 FakeBodyMode::Random {
75 min_length,
76 max_length,
77 service,
78 } => {
79 if !service || (is_service && *service) {
80 let body_space = max_packet_size.saturating_sub(taken_packet_size);
81 let effective_max = min(*max_length, body_space);
82 if effective_max <= *min_length {
83 effective_max
84 } else {
85 get_rng().gen_range(*min_length..effective_max)
86 }
87 } else {
88 0
89 }
90 }
91 FakeBodyMode::Constant {
92 packet_length,
93 } => min(max_packet_size, *packet_length).saturating_sub(taken_packet_size),
94 }
95 }
96}
97
98#[derive(Debug, Clone)]
103pub enum FieldType<L> {
104 Random,
106 Constant {
108 value: L,
109 },
110 Volatile {
112 value: L,
113 change_probability: f64,
114 },
115 Switching {
117 value: L,
118 next_switch: u128,
119 switch_timeout: u64,
120 },
121 Incremental {
123 value: L,
124 },
125}
126
127trait WrappingIncrement: Copy {
128 fn wrapping_inc(self) -> Self;
129}
130macro_rules! impl_wrapping_increment {
131 ($($t:ty)*) => { $(
132 impl WrappingIncrement for $t {
133 #[inline] fn wrapping_inc(self) -> Self { self.wrapping_add(1) }
134 }
135 )* };
136}
137impl_wrapping_increment!(u8 u16 u32 u64);
138
139#[allow(private_bounds)]
140impl<L: Copy + WrappingIncrement> FieldType<L> {
141 pub fn apply(&mut self) -> L
142 where
143 Standard: Distribution<L>,
144 {
145 match self {
146 FieldType::Random => get_rng().r#gen::<L>(),
147 FieldType::Constant {
148 value,
149 } => *value,
150 FieldType::Volatile {
151 value,
152 change_probability,
153 } => {
154 if get_rng().r#gen::<f64>() > *change_probability {
155 *value = get_rng().r#gen::<L>();
156 }
157 *value
158 }
159 FieldType::Switching {
160 value,
161 next_switch,
162 switch_timeout,
163 } => {
164 if unix_timestamp_ms() > *next_switch {
165 *next_switch = unix_timestamp_ms() + *switch_timeout as u128;
166 *value = get_rng().r#gen::<L>();
167 }
168 *value
169 }
170 FieldType::Incremental {
171 value,
172 } => {
173 *value = value.wrapping_inc();
174 *value
175 }
176 }
177 }
178}
179
180#[derive(Debug, Clone)]
181pub enum FieldTypeHolder {
182 U8(FieldType<u8>),
183 U16(FieldType<u16>),
184 U32(FieldType<u32>),
185 U64(FieldType<u64>),
186}
187
188#[derive(Debug, Clone)]
193pub struct FakeHeaderConfig {
194 pattern: Vec<FieldTypeHolder>,
195}
196
197impl FakeHeaderConfig {
198 pub fn new(pattern: Vec<FieldTypeHolder>) -> Self {
199 Self {
200 pattern,
201 }
202 }
203
204 pub fn random<AE: AsyncExecutor>(settings: &Settings<AE>) -> Self {
211 let mut rng = get_rng();
212 let header_prob = settings.get(&keys::FAKE_HEADER_PROBABILITY);
213 if rng.r#gen::<f64>() < header_prob {
214 let min_len = settings.get(&keys::FAKE_HEADER_LENGTH_MIN) as usize;
215 let max_len = settings.get(&keys::FAKE_HEADER_LENGTH_MAX) as usize;
216 let len = if min_len >= max_len {
217 max_len
218 } else {
219 rng.gen_range(min_len..=max_len)
220 };
221 let volatile_prob_min = settings.get(&keys::FAKE_HEADER_VOLATILE_CHANGE_PROB_MIN);
222 let volatile_prob_max = settings.get(&keys::FAKE_HEADER_VOLATILE_CHANGE_PROB_MAX);
223 let switching_timeout_min = settings.get(&keys::FAKE_HEADER_SWITCHING_TIMEOUT_MIN_MS);
224 let switching_timeout_max = settings.get(&keys::FAKE_HEADER_SWITCHING_TIMEOUT_MAX_MS);
225 let fields = (0..len)
226 .map(|_| {
227 FieldTypeHolder::U8(weighted_random! {
228 settings.get(&keys::FAKE_HEADER_FIELD_WEIGHT_RANDOM) => FieldType::Random,
229 settings.get(&keys::FAKE_HEADER_FIELD_WEIGHT_CONSTANT) => FieldType::Constant {
230 value: rng.r#gen::<u8>(),
231 },
232 settings.get(&keys::FAKE_HEADER_FIELD_WEIGHT_VOLATILE) => FieldType::Volatile {
233 value: rng.r#gen::<u8>(),
234 change_probability: rng.gen_range(volatile_prob_min..=volatile_prob_max),
235 },
236 settings.get(&keys::FAKE_HEADER_FIELD_WEIGHT_SWITCHING) => {
237 let switch_timeout = rng.gen_range(switching_timeout_min..=switching_timeout_max);
238 FieldType::Switching {
239 value: rng.r#gen::<u8>(),
240 next_switch: unix_timestamp_ms() + switch_timeout as u128,
241 switch_timeout,
242 }
243 }
244 settings.get(&keys::FAKE_HEADER_FIELD_WEIGHT_INCREMENTAL) => FieldType::Incremental {
245 value: rng.r#gen::<u8>(),
246 },
247 })
248 })
249 .collect();
250 Self::new(fields)
251 } else {
252 Self::new(vec![])
253 }
254 }
255
256 pub fn len(&self) -> usize {
257 self.pattern.iter().fold(0, |a, f| {
258 a + match f {
259 FieldTypeHolder::U8(_) => size_of::<u8>(),
260 FieldTypeHolder::U16(_) => size_of::<u16>(),
261 FieldTypeHolder::U32(_) => size_of::<u32>(),
262 FieldTypeHolder::U64(_) => size_of::<u64>(),
263 }
264 })
265 }
266
267 pub fn is_empty(&self) -> bool {
268 self.len() == 0
269 }
270
271 pub fn fill(&mut self, buffer: DynamicByteBuffer) {
272 self.pattern.iter_mut().fold(0, |a, f| {
273 a + match f {
274 FieldTypeHolder::U8(holder) => {
275 buffer.set(a, holder.apply());
276 size_of::<u8>()
277 }
278 FieldTypeHolder::U16(holder) => {
279 let holder_size = size_of::<u16>();
280 let field_slice = buffer.rebuffer_both(a, a + holder_size);
281 field_slice.slice_mut().copy_from_slice(&holder.apply().to_be_bytes());
282 holder_size
283 }
284 FieldTypeHolder::U32(holder) => {
285 let holder_size = size_of::<u32>();
286 let field_slice = buffer.rebuffer_both(a, a + holder_size);
287 field_slice.slice_mut().copy_from_slice(&holder.apply().to_be_bytes());
288 holder_size
289 }
290 FieldTypeHolder::U64(holder) => {
291 let holder_size = size_of::<u64>();
292 let field_slice = buffer.rebuffer_both(a, a + holder_size);
293 field_slice.slice_mut().copy_from_slice(&holder.apply().to_be_bytes());
294 holder_size
295 }
296 }
297 });
298 }
299}
300
301#[derive(Debug, Clone)]
303pub struct FlowConfig {
304 pub(super) fake_body_mode: FakeBodyMode,
306 pub(super) fake_header_mode: FakeHeaderConfig,
308}
309
310impl FlowConfig {
311 pub fn new(fake_body_mode: FakeBodyMode, fake_header_mode: FakeHeaderConfig) -> Self {
312 Self {
313 fake_body_mode,
314 fake_header_mode,
315 }
316 }
317
318 pub fn random<AE: AsyncExecutor>(settings: &Settings<AE>) -> Self {
331 let fake_header_mode = FakeHeaderConfig::random(settings);
332
333 let min_len = settings.get(&keys::FAKE_BODY_LENGTH_MIN) as usize;
334 let max_len = settings.get(&keys::FAKE_BODY_LENGTH_MAX) as usize;
335
336 let constant_min = (settings.get(&keys::FAKE_BODY_CONSTANT_LENGTH_MIN) as usize).clamp(min_len, settings.mtu());
337 let constant_max = (settings.get(&keys::FAKE_BODY_CONSTANT_LENGTH_MAX) as usize).clamp(min_len, settings.mtu());
338 let constant_length = if constant_min >= constant_max {
339 constant_min
340 } else {
341 get_rng().gen_range(constant_min..=constant_max)
342 };
343
344 let fake_body_mode = weighted_random! {
345 settings.get(&keys::FAKE_BODY_WEIGHT_EMPTY) => FakeBodyMode::Empty,
346 settings.get(&keys::FAKE_BODY_WEIGHT_RANDOM) => FakeBodyMode::Random {
347 min_length: min_len,
348 max_length: max_len,
349 service: false,
350 },
351 settings.get(&keys::FAKE_BODY_WEIGHT_CONSTANT) => FakeBodyMode::Constant {
352 packet_length: constant_length,
353 },
354 settings.get(&keys::FAKE_BODY_WEIGHT_SERVICE) => FakeBodyMode::Random {
355 min_length: min_len,
356 max_length: max_len,
357 service: true,
358 }
359 };
360
361 info!("flow_config: fake_body={:?}, fake_header_len={}", fake_body_mode, fake_header_mode.len());
362 Self {
363 fake_body_mode,
364 fake_header_mode,
365 }
366 }
367
368 pub fn max_overhead(&self) -> usize {
371 self.fake_header_mode.len() + self.fake_body_mode.max_len()
372 }
373
374 pub fn max_user_payload(&self, mtu: usize, crypto_overhead: usize, tailer_len: usize) -> usize {
379 let fixed = self.fake_header_mode.len() + crypto_overhead + tailer_len;
380 match &self.fake_body_mode {
381 FakeBodyMode::Constant {
382 packet_length,
383 } => packet_length.min(&mtu).saturating_sub(fixed),
384 _ => mtu.saturating_sub(self.max_overhead() + crypto_overhead + tailer_len),
385 }
386 }
387
388 pub fn assert(&self, max_packet_size: usize) -> Result<(), FlowControllerError> {
390 match &self.fake_body_mode {
391 FakeBodyMode::Constant {
392 packet_length,
393 } => {
394 if *packet_length > max_packet_size {
395 return Err(FlowControllerError::AssertionFailed {
396 message: format!("constant fake body packet_length ({packet_length}) must not exceed max_packet_size ({max_packet_size})"),
397 });
398 }
399 }
400 FakeBodyMode::Random {
401 min_length,
402 max_length,
403 ..
404 } => {
405 if min_length > max_length {
406 return Err(FlowControllerError::AssertionFailed {
407 message: format!("random fake body min_length ({min_length}) must be <= max_length ({max_length})"),
408 });
409 }
410 }
411 FakeBodyMode::Empty => {}
412 }
413
414 let header_len = self.fake_header_mode.len();
415 if header_len > max_packet_size {
416 return Err(FlowControllerError::AssertionFailed {
417 message: format!("fake header length ({header_len}) must not exceed max_packet_size ({max_packet_size})"),
418 });
419 }
420
421 Ok(())
422 }
423}