webscan/
lib.rs

1mod http;
2mod uri;
3mod domain;
4mod status;
5
6use std::time::{Duration, Instant};
7use std::collections::HashMap;
8use std::sync::{Mutex, Arc};
9use std::sync::mpsc::{channel ,Sender, Receiver};
10use tokio::time::{timeout};
11
12pub use status::ScanStatus;
13pub use http::{RequestMethod, ResponseStatus};
14
15/// Structure for uri scan  
16/// 
17/// Should be constructed using UriScanner::new
18#[derive(Clone)]
19pub struct UriScanner {
20    /// Base URI of scan target.  
21    base_uri: String,
22    /// Word-list of files or directories
23    word_list: Vec<String>,
24    /// Request Method
25    request_method: RequestMethod,
26    /// Timeout setting of uri scan.  
27    timeout: Duration,
28    /// Accept invalid certs
29    accept_invalid_certs: bool,
30    /// Result of uri scan.  
31    scan_result: UriScanResult,
32    /// List of content buffers to find in returned pages
33    content_list: Vec<Vec<u8>>,
34    /// Sender for progress messaging
35    tx: Arc<Mutex<Sender<String>>>,
36    /// Receiver for progress messaging
37    rx: Arc<Mutex<Receiver<String>>>,
38}
39
40/// Structure for domain scan  
41/// 
42/// Should be constructed using DomainScanner::new
43#[derive(Clone)]
44pub struct DomainScanner {
45    /// Base Domain Name of scan target.  
46    base_domain: String,
47    /// Word-list of name
48    word_list: Vec<String>,
49    /// Timeout setting of domain scan.  
50    timeout: Duration,
51    /// Result of domain scan.  
52    scan_result: DomainScanResult,
53    /// Sender for progress messaging
54    tx: Arc<Mutex<Sender<String>>>,
55    /// Receiver for progress messaging
56    rx: Arc<Mutex<Receiver<String>>>,
57}
58
59/// Result of UriScanner::run_scan  
60#[derive(Clone)]
61pub struct UriScanResult {
62    /// HashMap of responses. 
63    /// 
64    /// (URI, Status)
65    pub responses: HashMap<String, ResponseStatus>,
66    /// Time from start to end of scan.  
67    pub scan_time: Duration,
68    /// Scan job status
69    pub scan_status: ScanStatus,
70}
71
72/// Result of DomainScanner::run_scan  
73#[derive(Clone)]
74pub struct DomainScanResult {
75    /// HashMap of domain-map. 
76    /// 
77    /// (Domain, IP Address)
78    pub domain_map: HashMap<String, Vec<String>>,
79    /// Time from start to end of scan.  
80    pub scan_time: Duration,
81    /// Scan job status
82    pub scan_status: ScanStatus,
83}
84
85impl UriScanner{
86    /// Construct new UriScanner  
87    pub fn new() -> Result<UriScanner, String> {
88        let ini_scan_result = UriScanResult{
89            responses: HashMap::new(),
90            scan_time: Duration::from_millis(0),
91            scan_status: ScanStatus::Ready,
92        };
93        let (tx, rx) = channel();
94        let uri_scanner = UriScanner{
95            base_uri: String::new(),
96            word_list: vec![],
97            request_method: RequestMethod::Head,
98            timeout: Duration::from_millis(30000),
99            accept_invalid_certs: false,
100            scan_result: ini_scan_result,
101            content_list: vec![],
102            tx: Arc::new(Mutex::new(tx)),
103            rx: Arc::new(Mutex::new(rx)),
104        };
105        Ok(uri_scanner)
106    }
107    /// Set base URI of scan target.  
108    pub fn set_base_uri(&mut self, base_uri: String) {
109        self.base_uri = base_uri;
110    }
111    /// Add word(file name or dir name) to word-list
112    pub fn add_word(&mut self, word: String) {
113        if word.len() != 0 { self.word_list.push(word) }
114    }
115    /// Set request method
116    pub fn set_request_method(&mut self, method: RequestMethod) {
117        self.request_method = method;
118    }
119    /// Set scan timeout  
120    pub fn set_timeout(&mut self, timeout: Duration){
121        self.timeout = timeout;
122    }
123    /// Set option to accept invalid certificates
124    pub fn set_accept_invalid_certs(&mut self, accept: bool) {
125        self.accept_invalid_certs = accept;
126    }
127    /// Add content vector to search for in response bytes
128    pub fn add_content(&mut self, content: Vec<u8>) {
129        if content.len() != 0 { self.content_list.push(content) }
130    }
131    /// Run scan with current settings. 
132    /// 
133    /// Results are stored in UriScanner::scan_result
134    pub async fn run_scan(&mut self){
135        let start_time = Instant::now();
136        let res = timeout(self.timeout, uri::scan_uri(&self.base_uri, &self.word_list, &self.request_method, self.accept_invalid_certs, &self.content_list, &self.tx)).await;
137        match res {
138            Ok(responses) => {
139                self.scan_result.responses = responses;
140                self.scan_result.scan_status = ScanStatus::Done;
141            },
142            Err(_) => {
143                self.scan_result.scan_status = ScanStatus::Timeout;
144            },
145        }
146        //self.scan_result.responses = uri::scan_uri(&self.base_uri, &self.word_list).await;
147        self.scan_result.scan_time = Instant::now().duration_since(start_time);
148    }
149    /// Return scan result.
150    pub fn get_result(&mut self) -> UriScanResult{
151        return self.scan_result.clone();
152    }
153    /// Run scan and return result
154    pub async fn scan(&mut self) -> UriScanResult {
155        self.run_scan().await;
156        self.scan_result.clone()
157    }
158    /// Get progress receiver
159    pub fn get_progress_receiver(&self) -> Arc<Mutex<Receiver<String>>> {
160        self.rx.clone()
161    }
162}
163
164impl DomainScanner {
165    /// Construct new UriScanner  
166    pub fn new() -> Result<DomainScanner, String> {
167        let ini_scan_result = DomainScanResult {
168            domain_map: HashMap::new(), 
169            scan_time: Duration::from_millis(0),
170            scan_status: ScanStatus::Ready,
171        };
172        let (tx, rx) = channel();
173        let domain_scanner = DomainScanner {
174            base_domain: String::new(),
175            word_list: vec![],
176            timeout: Duration::from_millis(30000),
177            scan_result: ini_scan_result,
178            tx: Arc::new(Mutex::new(tx)),
179            rx: Arc::new(Mutex::new(rx)),
180        };
181        Ok(domain_scanner)
182    }
183    /// Set base Domain of scan target.  
184    pub fn set_base_domain(&mut self, base_domain: String) {
185        self.base_domain = base_domain;
186    }
187    /// Add word to word-list
188    pub fn add_word(&mut self, word: String) {
189        self.word_list.push(word);
190    }
191    /// Set scan timeout  
192    pub fn set_timeout(&mut self, timeout: Duration){
193        self.timeout = timeout;
194    }
195    /// Run scan with current settings. 
196    /// 
197    /// Results are stored in DomainScanner::scan_result
198    pub async fn run_scan(&mut self){
199        let start_time = Instant::now();
200        let res = timeout(self.timeout, domain::scan_domain(&self.base_domain, &self.word_list, &self.tx)).await;
201        match res {
202            Ok(domain_map) => {
203                self.scan_result.domain_map = domain_map;
204                self.scan_result.scan_status = ScanStatus::Done;
205            },
206            Err(_) => {
207                self.scan_result.scan_status = ScanStatus::Timeout;
208            },
209        }
210        //self.scan_result.domain_map = domain::scan_domain(&self.base_domain, &self.word_list).await;
211        self.scan_result.scan_time = Instant::now().duration_since(start_time);
212    }
213    /// Return scan result.
214    pub fn get_result(&mut self) -> DomainScanResult{
215        return self.scan_result.clone();
216    }
217    /// Run scan and return result
218    pub async fn scan(&mut self) -> DomainScanResult {
219        self.run_scan().await;
220        self.scan_result.clone()
221    }
222    /// Get progress receiver
223    pub fn get_progress_receiver(&self) -> Arc<Mutex<Receiver<String>>> {
224        self.rx.clone()
225    }
226}