Skip to main content

reddb_server/config/
presets.rs

1// Scan presets: passive, stealth, aggressive
2// Each preset defines behavior, rate limits, and which modules to run
3
4use std::time::Duration;
5
6/// Scan preset configuration
7#[derive(Debug, Clone)]
8pub struct ScanPreset {
9    pub name: &'static str,
10    pub description: &'static str,
11    pub modules: Vec<Module>,
12    pub rate_limit: RateLimit,
13    pub parallelism: Parallelism,
14    pub save_incremental: bool,
15    pub output_format: OutputFormat,
16}
17
18/// Modules to execute
19#[derive(Debug, Clone, PartialEq)]
20pub enum Module {
21    // Passive (no direct contact)
22    DnsPassive,       // DNS records only
23    WhoisLookup,      // WHOIS info
24    CertTransparency, // CT logs
25    SearchEngines,    // Google/Bing dorking
26    ArchiveOrg,       // Wayback machine
27
28    // Stealth (minimal contact, looks normal)
29    TlsCert,        // TLS certificate check
30    HttpHeaders,    // HTTP headers (1 request)
31    DnsEnumeration, // Subdomain bruteforce (slow)
32    PortScanCommon, // Only common ports (80, 443, 22, etc)
33
34    // Aggressive (all-out scanning)
35    PortScanFull, // All 65535 ports
36    DirFuzzing,   // Directory fuzzing
37    VulnScanning, // Nikto-style vuln scan
38    WebCrawling,  // Full site crawl
39}
40
41/// Rate limiting strategy
42#[derive(Debug, Clone)]
43pub struct RateLimit {
44    pub requests_per_second: u32,
45    pub delay_between_requests: Duration,
46    pub max_concurrent: usize,
47    pub jitter: bool, // Add random delay to avoid patterns
48}
49
50/// Parallelism configuration
51#[derive(Debug, Clone)]
52pub struct Parallelism {
53    pub threads: usize,
54    pub batch_size: usize,
55    pub queue_size: usize,
56}
57
58/// Output format
59#[derive(Debug, Clone)]
60pub enum OutputFormat {
61    Text,
62    Json,
63    Both,
64}
65
66impl ScanPreset {
67    /// Passive preset - 100% OSINT, zero direct contact
68    pub fn passive() -> Self {
69        Self {
70            name: "passive",
71            description: "100% passive reconnaissance using OSINT sources only",
72            modules: vec![
73                Module::DnsPassive,
74                Module::WhoisLookup,
75                Module::CertTransparency,
76                Module::SearchEngines,
77                Module::ArchiveOrg,
78            ],
79            rate_limit: RateLimit {
80                requests_per_second: 5,
81                delay_between_requests: Duration::from_millis(200),
82                max_concurrent: 3,
83                jitter: true,
84            },
85            parallelism: Parallelism {
86                threads: 5,
87                batch_size: 10,
88                queue_size: 100,
89            },
90            save_incremental: true,
91            output_format: OutputFormat::Json,
92        }
93    }
94
95    /// Stealth preset - Minimal contact, looks like normal traffic
96    pub fn stealth() -> Self {
97        Self {
98            name: "stealth",
99            description: "Minimal contact, rate-limited, incremental scanning",
100            modules: vec![
101                // Start with passive
102                Module::DnsPassive,
103                Module::WhoisLookup,
104                Module::CertTransparency,
105                // Then minimal active
106                Module::TlsCert,
107                Module::HttpHeaders,
108                Module::DnsEnumeration,
109                Module::PortScanCommon,
110            ],
111            rate_limit: RateLimit {
112                requests_per_second: 10,
113                delay_between_requests: Duration::from_millis(100),
114                max_concurrent: 5,
115                jitter: true, // Random delays to avoid patterns
116            },
117            parallelism: Parallelism {
118                threads: 10,
119                batch_size: 20,
120                queue_size: 200,
121            },
122            save_incremental: true, // Save progress continuously
123            output_format: OutputFormat::Both,
124        }
125    }
126
127    /// Aggressive preset - Maximum speed, full coverage
128    pub fn aggressive() -> Self {
129        Self {
130            name: "aggressive",
131            description: "Full-speed scanning with all modules enabled",
132            modules: vec![
133                // All passive modules
134                Module::DnsPassive,
135                Module::WhoisLookup,
136                Module::CertTransparency,
137                Module::SearchEngines,
138                Module::ArchiveOrg,
139                // All active modules
140                Module::TlsCert,
141                Module::HttpHeaders,
142                Module::DnsEnumeration,
143                Module::PortScanFull,
144                Module::DirFuzzing,
145                Module::VulnScanning,
146                Module::WebCrawling,
147            ],
148            rate_limit: RateLimit {
149                requests_per_second: 100,
150                delay_between_requests: Duration::from_millis(10),
151                max_concurrent: 50,
152                jitter: false,
153            },
154            parallelism: Parallelism {
155                threads: 100,
156                batch_size: 100,
157                queue_size: 1000,
158            },
159            save_incremental: true,
160            output_format: OutputFormat::Text,
161        }
162    }
163
164    /// Get preset by name
165    pub fn from_name(name: &str) -> Option<Self> {
166        match name.to_lowercase().as_str() {
167            "passive" => Some(Self::passive()),
168            "stealth" => Some(Self::stealth()),
169            "aggressive" | "aggresive" => Some(Self::aggressive()),
170            _ => None,
171        }
172    }
173
174    /// Check if module is enabled
175    pub fn has_module(&self, module: &Module) -> bool {
176        self.modules.contains(module)
177    }
178}
179
180impl Default for ScanPreset {
181    fn default() -> Self {
182        Self::stealth() // Default to stealth mode
183    }
184}
185
186#[cfg(test)]
187mod tests {
188    use super::*;
189
190    #[test]
191    fn test_presets() {
192        let passive = ScanPreset::passive();
193        assert_eq!(passive.name, "passive");
194        assert_eq!(passive.modules.len(), 5);
195        assert!(passive.has_module(&Module::DnsPassive));
196        assert!(!passive.has_module(&Module::PortScanFull));
197
198        let stealth = ScanPreset::stealth();
199        assert_eq!(stealth.name, "stealth");
200        assert!(stealth.save_incremental);
201
202        let aggressive = ScanPreset::aggressive();
203        assert_eq!(aggressive.name, "aggressive");
204        assert!(aggressive.modules.len() > stealth.modules.len());
205    }
206
207    #[test]
208    fn test_from_name() {
209        assert!(ScanPreset::from_name("passive").is_some());
210        assert!(ScanPreset::from_name("stealth").is_some());
211        assert!(ScanPreset::from_name("aggressive").is_some());
212        assert!(ScanPreset::from_name("invalid").is_none());
213    }
214}