diff --git a/src/afterfact.rs b/src/afterfact.rs index 8cbe21a5..3779c35c 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -36,8 +36,8 @@ pub struct DisplayFormat<'a> { pub fn after_fact() { let fn_emit_csv_err = |err: Box| { AlertMessage::alert( - &mut std::io::stderr().lock(), - format!("Failed to write CSV. {}", err), + &mut BufWriter::new(std::io::stderr().lock()), + &format!("Failed to write CSV. {}", err), ) .ok(); process::exit(1); @@ -51,8 +51,8 @@ pub fn after_fact() { Ok(file) => Box::new(BufWriter::new(file)), Err(err) => { AlertMessage::alert( - &mut std::io::stderr().lock(), - format!("Failed to open file. {}", err), + &mut BufWriter::new(std::io::stderr().lock()), + &format!("Failed to open file. {}", err), ) .ok(); process::exit(1); diff --git a/src/detections/configs.rs b/src/detections/configs.rs index 492f209e..52c7ccd8 100644 --- a/src/detections/configs.rs +++ b/src/detections/configs.rs @@ -5,6 +5,7 @@ use clap::{App, AppSettings, ArgMatches}; use hashbrown::HashMap; use hashbrown::HashSet; use lazy_static::lazy_static; +use std::io::BufWriter; use std::sync::RwLock; lazy_static! { pub static ref CONFIG: RwLock = RwLock::new(ConfigReader::new()); @@ -140,8 +141,8 @@ impl TargetEventTime { Ok(dt) => Some(dt.with_timezone(&Utc)), Err(err) => { AlertMessage::alert( - &mut std::io::stderr().lock(), - format!("start-timeline field: {}", err), + &mut BufWriter::new(std::io::stderr().lock()), + &format!("start-timeline field: {}", err), ) .ok(); None @@ -157,8 +158,8 @@ impl TargetEventTime { Ok(dt) => Some(dt.with_timezone(&Utc)), Err(err) => { AlertMessage::alert( - &mut std::io::stderr().lock(), - format!("end-timeline field: {}", err), + &mut BufWriter::new(std::io::stderr().lock()), + &format!("end-timeline field: {}", err), ) .ok(); None diff --git a/src/detections/detection.rs b/src/detections/detection.rs index 92d4a3c8..77fa1e76 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -1,8 +1,10 @@ extern crate csv; +use crate::detections::configs; use crate::detections::print::AlertMessage; use crate::detections::print::ERROR_LOG_PATH; use crate::detections::print::MESSAGES; +use crate::detections::print::QUIET_ERRORS_FLAG; use crate::detections::rule; use crate::detections::rule::AggResult; use crate::detections::rule::RuleNode; @@ -88,10 +90,10 @@ impl Detection { err_msgs_result.err().iter().for_each(|err_msgs| { let errmsg_body = format!("Failed to parse rule file. (FilePath : {})", rule.rulepath); - AlertMessage::warn(&mut std::io::stdout().lock(), errmsg_body).ok(); + AlertMessage::warn(&mut std::io::stdout().lock(), &errmsg_body).ok(); err_msgs.iter().for_each(|err_msg| { - AlertMessage::warn(&mut std::io::stdout().lock(), err_msg.to_string()).ok(); + AlertMessage::warn(&mut std::io::stdout().lock(), &err_msg.to_string()).ok(); }); parseerror_count += 1; println!(""); // 一行開けるためのprintln diff --git a/src/detections/print.rs b/src/detections/print.rs index d2fdd691..54c97738 100644 --- a/src/detections/print.rs +++ b/src/detections/print.rs @@ -249,6 +249,7 @@ impl AlertMessage { mod tests { use crate::detections::print::{AlertMessage, Message}; use serde_json::Value; + use std::io::BufWriter; #[test] fn test_create_and_append_message() { @@ -361,17 +362,21 @@ mod tests { #[test] fn test_error_message() { let input = "TEST!"; - let stdout = std::io::stdout(); - let mut stdout = stdout.lock(); - AlertMessage::alert(&mut stdout, input.to_string()).expect("[ERROR] TEST!"); + AlertMessage::alert( + &mut BufWriter::new(std::io::stdout().lock()), + &input.to_string(), + ) + .expect("[ERROR] TEST!"); } #[test] fn test_warn_message() { let input = "TESTWarn!"; - let stdout = std::io::stdout(); - let mut stdout = stdout.lock(); - AlertMessage::warn(&mut stdout, input.to_string()).expect("[WARN] TESTWarn!"); + AlertMessage::warn( + &mut BufWriter::new(std::io::stdout().lock()), + &input.to_string(), + ) + .expect("[WARN] TESTWarn!"); } #[test] diff --git a/src/detections/rule/count.rs b/src/detections/rule/count.rs index 133b9e31..b49759ec 100644 --- a/src/detections/rule/count.rs +++ b/src/detections/rule/count.rs @@ -1,5 +1,7 @@ +use crate::detections::configs; use crate::detections::print::AlertMessage; use crate::detections::print::ERROR_LOG_PATH; +use crate::detections::print::QUIET_ERRORS_FLAG; use crate::detections::rule::AggResult; use crate::detections::rule::AggregationParseInfo; use crate::detections::rule::Message; @@ -69,35 +71,41 @@ fn get_alias_value_in_record( return Some(value.to_string().replace("\"", "")); } None => { - AlertMessage::alert( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), - match is_by_alias { - true => format!( - "count by clause alias value not found in count process. rule file:{} EventID:{}", - Path::new(&rule.rulepath) - .file_name() - .unwrap() - .to_str() - .unwrap(), - utils::get_event_value(&utils::get_event_id_key(), record).unwrap() - ), - false => format!( - "count field clause alias value not found in count process. rule file:{} EventID:{}", - Path::new(&rule.rulepath) - .file_name() - .unwrap() - .to_str() - .unwrap(), - utils::get_event_value(&utils::get_event_id_key(), record).unwrap() - ), - }, - ) - .ok(); + let errmsg = match is_by_alias { + true => format!( + "count by clause alias value not found in count process. rule file:{} EventID:{}", + Path::new(&rule.rulepath) + .file_name() + .unwrap() + .to_str() + .unwrap(), + utils::get_event_value(&utils::get_event_id_key(), record).unwrap() + ), + false => format!( + "count field clause alias value not found in count process. rule file:{} EventID:{}", + Path::new(&rule.rulepath) + .file_name() + .unwrap() + .to_str() + .unwrap(), + utils::get_event_value(&utils::get_event_id_key(), record).unwrap() + ), + }; + if configs::CONFIG.read().unwrap().args.is_present("verbose") { + AlertMessage::alert(&mut BufWriter::new(std::io::stderr().lock()), &errmsg).ok(); + } + if !*QUIET_ERRORS_FLAG { + AlertMessage::alert( + &mut BufWriter::new( + OpenOptions::new() + .append(true) + .open(ERROR_LOG_PATH.to_string()) + .unwrap(), + ), + &errmsg, + ) + .ok(); + } return None; } }; @@ -190,16 +198,22 @@ impl TimeFrameInfo { ttype = "d".to_owned(); tnum.retain(|c| c != 'd'); } else { - AlertMessage::alert( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), - format!("Timeframe is invalid. Input value:{}", value), - ) - .ok(); + let errmsg = format!("Timeframe is invalid. Input value:{}", value); + if configs::CONFIG.read().unwrap().args.is_present("verbose") { + AlertMessage::alert(&mut BufWriter::new(std::io::stderr().lock()), &errmsg).ok(); + } + if !*QUIET_ERRORS_FLAG { + AlertMessage::alert( + &mut BufWriter::new( + OpenOptions::new() + .append(true) + .open(ERROR_LOG_PATH.to_string()) + .unwrap(), + ), + &errmsg, + ) + .ok(); + } } return TimeFrameInfo { timetype: ttype, @@ -227,16 +241,22 @@ pub fn get_sec_timeframe(timeframe: &Option) -> Option { } } Err(err) => { - AlertMessage::alert( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), - format!("Timeframe number is invalid. timeframe.{}", err), - ) - .ok(); + let errmsg = format!("Timeframe number is invalid. timeframe. {}", err); + if configs::CONFIG.read().unwrap().args.is_present("verbose") { + AlertMessage::alert(&mut BufWriter::new(std::io::stderr().lock()), &errmsg).ok(); + } + if !*QUIET_ERRORS_FLAG { + AlertMessage::alert( + &mut BufWriter::new( + OpenOptions::new() + .append(true) + .open(ERROR_LOG_PATH.to_string()) + .unwrap(), + ), + &errmsg, + ) + .ok(); + } return Option::None; } } diff --git a/src/main.rs b/src/main.rs index 38ce6163..a4c89a77 100644 --- a/src/main.rs +++ b/src/main.rs @@ -7,6 +7,7 @@ use evtx::{EvtxParser, ParserSettings}; use hayabusa::detections::detection::{self, EvtxRecordInfo}; use hayabusa::detections::print::AlertMessage; use hayabusa::detections::print::ERROR_LOG_PATH; +use hayabusa::detections::print::QUIET_ERRORS_FLAG; use hayabusa::detections::rule::{get_detection_keys, RuleNode}; use hayabusa::filter; use hayabusa::omikuji::Omikuji; @@ -73,8 +74,8 @@ impl App { if let Some(csv_path) = configs::CONFIG.read().unwrap().args.value_of("output") { if Path::new(csv_path).exists() { AlertMessage::alert( - &mut std::io::stderr().lock(), - format!( + &mut BufWriter::new(std::io::stderr().lock()), + &format!( " The file {} already exists. Please specify a different filename.", csv_path ), @@ -83,12 +84,19 @@ impl App { return; } } - AlertMessage::create_error_log(ERROR_LOG_PATH.to_string()); + if !configs::CONFIG + .read() + .unwrap() + .args + .is_present("quiet-errors") + { + AlertMessage::create_error_log(ERROR_LOG_PATH.to_string()); + } if let Some(filepath) = configs::CONFIG.read().unwrap().args.value_of("filepath") { if !filepath.ends_with(".evtx") { AlertMessage::alert( - &mut std::io::stderr().lock(), - "--filepath only accepts .evtx files.".to_owned(), + &mut BufWriter::new(std::io::stderr().lock()), + &"--filepath only accepts .evtx files.".to_string(), ) .ok(); return; @@ -98,8 +106,8 @@ impl App { let evtx_files = self.collect_evtxfiles(&directory); if evtx_files.len() == 0 { AlertMessage::alert( - &mut std::io::stderr().lock(), - "No .evtx files were found.".to_owned(), + &mut BufWriter::new(std::io::stderr().lock()), + &"No .evtx files were found.".to_string(), ) .ok(); return; @@ -124,16 +132,22 @@ impl App { fn collect_evtxfiles(&self, dirpath: &str) -> Vec { let entries = fs::read_dir(dirpath); if entries.is_err() { - AlertMessage::alert( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), - format!("{}", entries.unwrap_err()), - ) - .ok(); + let errmsg = format!("{}", entries.unwrap_err()); + if configs::CONFIG.read().unwrap().args.is_present("verbose") { + AlertMessage::alert(&mut BufWriter::new(std::io::stderr().lock()), &errmsg).ok(); + } + if !*QUIET_ERRORS_FLAG { + AlertMessage::alert( + &mut BufWriter::new( + OpenOptions::new() + .append(true) + .open(ERROR_LOG_PATH.to_string()) + .unwrap(), + ), + &errmsg, + ) + .ok(); + } return vec![]; } @@ -165,7 +179,11 @@ impl App { match fs::read_to_string("./contributors.txt") { Ok(contents) => println!("{}", contents), Err(err) => { - AlertMessage::alert(&mut std::io::stderr().lock(), format!("{}", err)).ok(); + AlertMessage::alert( + &mut BufWriter::new(std::io::stderr().lock()), + &format!("{}", err), + ) + .ok(); } } } @@ -232,16 +250,22 @@ impl App { evtx_filepath, record_result.unwrap_err() ); - AlertMessage::alert( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), - errmsg, - ) - .ok(); + if configs::CONFIG.read().unwrap().args.is_present("verbose") { + AlertMessage::alert(&mut BufWriter::new(std::io::stderr().lock()), &errmsg) + .ok(); + } + if !*QUIET_ERRORS_FLAG { + AlertMessage::alert( + &mut BufWriter::new( + OpenOptions::new() + .append(true) + .open(ERROR_LOG_PATH.to_string()) + .unwrap(), + ), + &errmsg, + ) + .ok(); + } continue; } diff --git a/src/yaml.rs b/src/yaml.rs index 568f59b5..bb59143c 100644 --- a/src/yaml.rs +++ b/src/yaml.rs @@ -4,6 +4,7 @@ extern crate yaml_rust; use crate::detections::configs; use crate::detections::print::AlertMessage; use crate::detections::print::ERROR_LOG_PATH; +use crate::detections::print::QUIET_ERRORS_FLAG; use crate::filter::RuleExclude; use std::collections::HashMap; use std::ffi::OsStr; @@ -74,19 +75,25 @@ impl ParseYaml { // 個別のファイルの読み込みは即終了としない。 let read_content = self.read_file(path); if read_content.is_err() { - AlertMessage::warn( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), - format!( - "fail to read file: {}\n{} ", - entry.path().display(), - read_content.unwrap_err() - ), - )?; + let errmsg = format!( + "fail to read file: {}\n{} ", + entry.path().display(), + read_content.unwrap_err() + ); + if configs::CONFIG.read().unwrap().args.is_present("verbose") { + AlertMessage::warn(&mut BufWriter::new(std::io::stderr().lock()), &errmsg)?; + } + if !*QUIET_ERRORS_FLAG { + AlertMessage::warn( + &mut BufWriter::new( + OpenOptions::new() + .append(true) + .open(ERROR_LOG_PATH.to_string()) + .unwrap(), + ), + &errmsg, + )?; + } self.errorrule_count += 1; return io::Result::Ok(ret); } @@ -94,19 +101,25 @@ impl ParseYaml { // ここも個別のファイルの読み込みは即終了としない。 let yaml_contents = YamlLoader::load_from_str(&read_content.unwrap()); if yaml_contents.is_err() { - AlertMessage::warn( - &mut BufWriter::new( - OpenOptions::new() - .append(true) - .open(ERROR_LOG_PATH.to_string()) - .unwrap(), - ), - format!( - "Failed to parse yml: {}\n{} ", - entry.path().display(), - yaml_contents.unwrap_err() - ), - )?; + let errmsg = format!( + "Failed to parse yml: {}\n{} ", + entry.path().display(), + yaml_contents.unwrap_err() + ); + if configs::CONFIG.read().unwrap().args.is_present("verbose") { + AlertMessage::warn(&mut BufWriter::new(std::io::stderr().lock()), &errmsg)?; + } + if !*QUIET_ERRORS_FLAG { + AlertMessage::warn( + &mut BufWriter::new( + OpenOptions::new() + .append(true) + .open(ERROR_LOG_PATH.to_string()) + .unwrap(), + ), + &errmsg, + )?; + } self.errorrule_count += 1; return io::Result::Ok(ret); }