Skip to main content

typhoon/flow/decoy/
mod.rs

1//! Decoy traffic communication modes for flow obfuscation.
2//!
3//! The runtime trait [`DecoyProvider`] (made object-safe via `async-trait`) drives the three
4//! callbacks: `start`, `feed_input`, and `feed_output`. The construction trait
5//! [`DecoyCommunicationMode`] extends it with `new()` and is the target of [`decoy_factory`].
6//!
7//! A [`DecoyFactory`] is a type-erased `Arc<dyn Fn(…) -> Box<dyn DecoyProvider>>` so that
8//! different flows or users can hold different concrete provider types at runtime.
9//! Use [`decoy_factory::<T, AE, DP>()`](decoy_factory) to wrap a concrete type, or
10//! [`random_decoy_factory()`] for the default behavior (random selection per invocation).
11mod common;
12mod heavy;
13mod noisy;
14mod simple;
15mod smooth;
16mod sparse;
17
18use std::sync::atomic::AtomicU32;
19use std::sync::{Arc, Weak};
20
21pub use common::{DecoyCommunicationMode, DecoyFlowSender, DecoyProvider};
22pub use heavy::HeavyDecoyProvider;
23use log::info;
24pub use noisy::NoisyDecoyProvider;
25pub use simple::SimpleDecoyProvider;
26pub use smooth::SmoothDecoyProvider;
27pub use sparse::SparseDecoyProvider;
28
29pub use crate::cache::DerivedValue;
30use crate::settings::Settings;
31use crate::settings::keys::{DECOY_PROVIDER_WEIGHT_HEAVY, DECOY_PROVIDER_WEIGHT_NOISY, DECOY_PROVIDER_WEIGHT_SIMPLE, DECOY_PROVIDER_WEIGHT_SMOOTH, DECOY_PROVIDER_WEIGHT_SPARSE};
32pub use crate::tailer::{IdentityType, PacketFlags, Tailer};
33use crate::utils::sync::AsyncExecutor;
34use crate::weighted_random;
35
36/// A factory that constructs a `Box<dyn DecoyProvider>` for a given identity source and flow manager.
37pub type DecoyFactory<T, AE> = Arc<dyn Fn(Weak<dyn DecoyFlowSender>, Arc<Settings<AE>>, DerivedValue<T>, Arc<AtomicU32>) -> Box<dyn DecoyProvider> + Send + Sync>;
38
39/// Lift a concrete `DecoyCommunicationMode` type into a `DecoyFactory`.
40pub fn decoy_factory<T, AE, DP>() -> DecoyFactory<T, AE>
41where
42    T: IdentityType + Clone + 'static,
43    AE: AsyncExecutor + 'static,
44    DP: DecoyCommunicationMode<T, AE> + 'static,
45{
46    Arc::new(|manager, settings, identity, counter| {
47        info!("decoy provider: {}", <DP as DecoyCommunicationMode<T, AE>>::name());
48        Box::new(DP::new(manager, settings, identity, counter, None))
49    })
50}
51
52/// Factory that randomly selects one of the five built-in decoy providers per invocation,
53/// weighted by the `DECOY_PROVIDER_WEIGHT_*` settings.
54pub fn random_decoy_factory<T, AE>() -> DecoyFactory<T, AE>
55where
56    T: IdentityType + Clone + 'static,
57    AE: AsyncExecutor + 'static,
58{
59    Arc::new(|manager, settings, identity, counter| {
60        weighted_random! {
61            settings.get(&DECOY_PROVIDER_WEIGHT_SIMPLE) => {
62                info!("decoy provider: {}", <SimpleDecoyProvider as DecoyCommunicationMode<T, AE>>::name());
63                Box::new(SimpleDecoyProvider::new(manager, settings, identity, counter, None)) as Box<dyn DecoyProvider>
64            },
65            settings.get(&DECOY_PROVIDER_WEIGHT_SPARSE) => {
66                info!("decoy provider: {}", <SparseDecoyProvider<T, AE> as DecoyCommunicationMode<T, AE>>::name());
67                Box::new(SparseDecoyProvider::new(manager, settings, identity, counter, None)) as Box<dyn DecoyProvider>
68            },
69            settings.get(&DECOY_PROVIDER_WEIGHT_NOISY) => {
70                info!("decoy provider: {}", <NoisyDecoyProvider<T, AE> as DecoyCommunicationMode<T, AE>>::name());
71                Box::new(NoisyDecoyProvider::new(manager, settings, identity, counter, None)) as Box<dyn DecoyProvider>
72            },
73            settings.get(&DECOY_PROVIDER_WEIGHT_SMOOTH) => {
74                info!("decoy provider: {}", <SmoothDecoyProvider<T, AE> as DecoyCommunicationMode<T, AE>>::name());
75                Box::new(SmoothDecoyProvider::new(manager, settings, identity, counter, None)) as Box<dyn DecoyProvider>
76            },
77            settings.get(&DECOY_PROVIDER_WEIGHT_HEAVY) => {
78                info!("decoy provider: {}", <HeavyDecoyProvider<T, AE> as DecoyCommunicationMode<T, AE>>::name());
79                Box::new(HeavyDecoyProvider::new(manager, settings, identity, counter, None)) as Box<dyn DecoyProvider>
80            },
81        }
82    })
83}