diff --git a/src/client.rs b/src/client.rs index 7727dd48..bfa1b8d4 100644 --- a/src/client.rs +++ b/src/client.rs @@ -32,31 +32,33 @@ pub fn initialize( .default_headers(header_map) .redirect(policy); - let client = if proxy.is_some() && !proxy.unwrap().is_empty() { - match Proxy::all(proxy.unwrap()) { - Ok(proxy_obj) => client.proxy(proxy_obj), - Err(e) => { - eprintln!( - "{} {} Could not add proxy ({:?}) to Client configuration", - status_colorizer("ERROR"), - module_colorizer("Client::initialize"), - proxy - ); - eprintln!( - "{} {} {}", - status_colorizer("ERROR"), - module_colorizer("Client::initialize"), - e - ); + let client = match proxy { + // a proxy is specified, need to add it to the client + Some(some_proxy) => { + if !some_proxy.is_empty() { + // it's not an empty string + match Proxy::all(some_proxy) { + Ok(proxy_obj) => client.proxy(proxy_obj), + Err(e) => { + eprintln!( + "{} {} {}", + status_colorizer("ERROR"), + module_colorizer("Client::initialize"), + e + ); - #[cfg(test)] - panic!(); - #[cfg(not(test))] - exit(1); + #[cfg(test)] + panic!(); + #[cfg(not(test))] + exit(1); + } + } + } else { + client // Some("") was used? } } - } else { - client + // no proxy specified + None => client, }; match client.build() { diff --git a/src/filters.rs b/src/filters.rs index 12442156..6b5e5a4f 100644 --- a/src/filters.rs +++ b/src/filters.rs @@ -53,7 +53,7 @@ impl FeroxFilter for WildcardFilter { /// Examine size, dynamic, and content_len to determine whether or not the response received /// is a wildcard response and therefore should be filtered out fn should_filter_response(&self, response: &FeroxResponse) -> bool { - log::trace!("enter: should_filter_response({:?} {:?})", self, response); + log::trace!("enter: should_filter_response({:?} {})", self, response); // quick return if dont_filter is set if CONFIGURATION.dont_filter { @@ -114,7 +114,7 @@ pub struct StatusCodeFilter { impl FeroxFilter for StatusCodeFilter { /// Check `filter_code` against what was passed in via -C|--filter-status fn should_filter_response(&self, response: &FeroxResponse) -> bool { - log::trace!("enter: should_filter_response({:?} {:?})", self, response); + log::trace!("enter: should_filter_response({:?} {})", self, response); if response.status().as_u16() == self.filter_code { log::debug!( diff --git a/src/heuristics.rs b/src/heuristics.rs index 577d982d..7b53ab26 100644 --- a/src/heuristics.rs +++ b/src/heuristics.rs @@ -89,8 +89,10 @@ pub async fn wildcard_test( if !CONFIGURATION.quiet { let msg = format!( - "{} {:>10} Wildcard response is dynamic; {} ({} + url length) responses; toggle this behavior by using {}\n", + "{} {:>8}l {:>8}w {:>8}c Wildcard response is dynamic; {} ({} + url length) responses; toggle this behavior by using {}\n", status_colorizer("WLD"), + ferox_response.line_count(), + ferox_response.word_count(), wildcard.dynamic, style("auto-filtering").yellow(), style(wc_length - url_len).cyan(), @@ -110,8 +112,10 @@ pub async fn wildcard_test( if !CONFIGURATION.quiet { let msg = format!( - "{} {:>10} Wildcard response is static; {} {} responses; toggle this behavior by using {}\n", + "{} {:>8}l {:>8}w {:>8}c Wildcard response is static; {} {} responses; toggle this behavior by using {}\n", status_colorizer("WLD"), + ferox_response.line_count(), + ferox_response.word_count(), wc_length, style("auto-filtering").yellow(), style(wc_length).cyan(), @@ -235,7 +239,7 @@ async fn make_wildcard_request( } } } - log::trace!("exit: make_wildcard_request -> {:?}", ferox_response); + log::trace!("exit: make_wildcard_request -> {}", ferox_response); return Some(ferox_response); } } diff --git a/src/lib.rs b/src/lib.rs index 0eb4a6c5..a4d9abf2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -103,6 +103,19 @@ pub struct FeroxResponse { headers: HeaderMap, } +/// Implement Display for FeroxResponse +impl fmt::Display for FeroxResponse { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!( + f, + "FeroxResponse {{ url: {}, status: {}, content-length: {} }}", + self.url(), + self.status(), + self.content_length() + ) + } +} + /// `FeroxResponse` implementation impl FeroxResponse { /// Get the `StatusCode` of this `FeroxResponse` diff --git a/src/logger.rs b/src/logger.rs index f3bc726f..3c681a3a 100644 --- a/src/logger.rs +++ b/src/logger.rs @@ -19,8 +19,8 @@ pub fn initialize(verbosity: u8) { 0 => (), 1 => env::set_var("RUST_LOG", "warn"), 2 => env::set_var("RUST_LOG", "info"), - 3 => env::set_var("RUST_LOG", "debug,hyper=info,reqwest=info"), - _ => env::set_var("RUST_LOG", "trace,hyper=info,reqwest=info"), + 3 => env::set_var("RUST_LOG", "feroxbuster=debug,info"), + _ => env::set_var("RUST_LOG", "feroxbuster=trace,info"), } } } @@ -55,9 +55,10 @@ pub fn initialize(verbosity: u8) { }; let msg = format!( - "{} {:10.03} {}\n", + "{} {:10.03} {} {}\n", style(level_name).bg(level_color).black(), style(t).dim(), + record.target(), style(record.args()).dim(), ); diff --git a/src/parser.rs b/src/parser.rs index 888f175d..ed50e7bc 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -55,7 +55,7 @@ pub fn initialize() -> App<'static, 'static> { .long("verbosity") .takes_value(false) .multiple(true) - .help("Increase verbosity level (use -vv or more for greater effect)"), + .help("Increase verbosity level (use -vv or more for greater effect. [CAUTION] 4 -v's is probably too much)"), ) .arg( Arg::with_name("proxy") diff --git a/src/reporter.rs b/src/reporter.rs index 4feb8483..09d94070 100644 --- a/src/reporter.rs +++ b/src/reporter.rs @@ -1,5 +1,5 @@ use crate::config::{CONFIGURATION, PROGRESS_PRINTER}; -use crate::utils::{ferox_print, make_request, status_colorizer}; +use crate::utils::{create_report_string, ferox_print, make_request}; use crate::{FeroxChannel, FeroxResponse}; use console::strip_ansi_codes; use std::io::Write; @@ -95,23 +95,13 @@ async fn spawn_terminal_reporter( log::trace!("received {} on reporting channel", resp.url()); if CONFIGURATION.status_codes.contains(&resp.status().as_u16()) { - let report = if CONFIGURATION.quiet { - // -q used, just need the url - format!("{}\n", resp.url()) - } else { - // normal printing with status and size - let status = status_colorizer(&resp.status().as_str()); - format!( - // example output - // 200 3280 https://localhost.com/FAQ - "{} {:>8}l {:>8}w {:>8}c {}\n", - status, - resp.line_count(), - resp.word_count(), - resp.content_length(), - resp.url() - ) - }; + let report = create_report_string( + resp.status().as_str(), + &resp.line_count().to_string(), + &resp.word_count().to_string(), + &resp.content_length().to_string(), + &resp.url().to_string(), + ); // print to stdout ferox_print(&report, &PROGRESS_PRINTER); diff --git a/src/scanner.rs b/src/scanner.rs index ea5f665d..6b8819be 100644 --- a/src/scanner.rs +++ b/src/scanner.rs @@ -285,7 +285,7 @@ fn create_urls(target_url: &str, word: &str, extensions: &[String]) -> Vec /// handles 2xx and 3xx responses by either checking if the url ends with a / (2xx) /// or if the Location header is present and matches the base url + / (3xx) fn response_is_directory(response: &FeroxResponse) -> bool { - log::trace!("enter: is_directory({:?})", response); + log::trace!("enter: is_directory({})", response); if response.status().is_redirection() { // status code is 3xx @@ -311,10 +311,7 @@ fn response_is_directory(response: &FeroxResponse) -> bool { } } None => { - log::debug!( - "expected Location header, but none was found: {:?}", - response - ); + log::debug!("expected Location header, but none was found: {}", response); log::trace!("exit: is_directory -> false"); return false; } @@ -370,7 +367,7 @@ async fn try_recursion( transmitter: UnboundedSender, ) { log::trace!( - "enter: try_recursion({:?}, {}, {:?})", + "enter: try_recursion({}, {}, {:?})", response, base_depth, transmitter @@ -528,11 +525,7 @@ async fn make_requests( if new_ferox_response.is_file() { // very likely a file, simply request and report - log::debug!( - "Singular extraction: {} ({})", - new_ferox_response.url(), - new_ferox_response.status().as_str(), - ); + log::debug!("Singular extraction: {}", new_ferox_response); send_report(report_chan.clone(), new_ferox_response); @@ -540,11 +533,7 @@ async fn make_requests( } if !CONFIGURATION.no_recursion { - log::debug!( - "Recursive extraction: {} ({})", - new_ferox_response.url(), - new_ferox_response.status().as_str() - ); + log::debug!("Recursive extraction: {}", new_ferox_response); if new_ferox_response.status().is_success() && !new_ferox_response.url().as_str().ends_with('/') @@ -570,7 +559,7 @@ async fn make_requests( /// Simple helper to send a `FeroxResponse` over the tx side of an `mpsc::unbounded_channel` fn send_report(report_sender: UnboundedSender, response: FeroxResponse) { - log::trace!("enter: send_report({:?}, {:?}", report_sender, response); + log::trace!("enter: send_report({:?}, {}", report_sender, response); match report_sender.send(response) { Ok(_) => {} diff --git a/src/utils.rs b/src/utils.rs index e70a8f87..0279cd4a 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -1,8 +1,10 @@ -use crate::{FeroxError, FeroxResult}; +use crate::{ + config::{CONFIGURATION, PROGRESS_PRINTER}, + FeroxError, FeroxResult, +}; use console::{strip_ansi_codes, style, user_attended}; use indicatif::ProgressBar; -use reqwest::Url; -use reqwest::{Client, Response}; +use reqwest::{Client, Response, Url}; #[cfg(not(target_os = "windows"))] use rlimit::{getrlimit, setrlimit, Resource, Rlim}; use std::convert::TryInto; @@ -244,7 +246,6 @@ pub async fn make_request(client: &Client, url: &Url) -> FeroxResult { match client.get(url.to_owned()).send().await { Ok(resp) => { - log::debug!("requested Url: {}", resp.url()); log::trace!("exit: make_request -> {:?}", resp); Ok(resp) } @@ -253,6 +254,19 @@ pub async fn make_request(client: &Client, url: &Url) -> FeroxResult { if e.to_string().contains("operation timed out") { // only warn for timeouts, while actual errors are still left as errors log::warn!("Error while making request: {}", e); + } else if e.is_redirect() { + if let Some(last_redirect) = e.url() { + // get where we were headed (last_redirect) and where we came from (url) + let fancy_message = format!("{} !=> {}", url, last_redirect); + + let report = if let Some(msg_status) = e.status() { + create_report_string(msg_status.as_str(), "-1", "-1", "-1", &fancy_message) + } else { + create_report_string("UNK", "-1", "-1", "-1", &fancy_message) + }; + + ferox_print(&report, &PROGRESS_PRINTER) + }; } else { log::error!("Error while making request: {}", e); } @@ -261,6 +275,30 @@ pub async fn make_request(client: &Client, url: &Url) -> FeroxResult { } } +/// Helper to create the standard line for output to file/terminal +/// +/// example output: +/// 200 127l 283w 4134c http://localhost/faq +pub fn create_report_string( + status: &str, + line_count: &str, + word_count: &str, + content_length: &str, + url: &str, +) -> String { + if CONFIGURATION.quiet { + // -q used, just need the url + format!("{}\n", url) + } else { + // normal printing with status and sizes + let color_status = status_colorizer(status); + format!( + "{} {:>8}l {:>8}w {:>8}c {}\n", + color_status, line_count, word_count, content_length, url + ) + } +} + /// Attempts to set the soft limit for the RLIMIT_NOFILE resource /// /// RLIMIT_NOFILE is the maximum number of file descriptors that can be opened by this process