From 4d99e3e384196bbbd306b74fe6c830d8ce472e07 Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Sun, 19 Mar 2023 02:31:54 +0900 Subject: [PATCH 01/15] perf: removed unnecessary to_string --- src/detections/configs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/detections/configs.rs b/src/detections/configs.rs index 96286a067..1210772af 100644 --- a/src/detections/configs.rs +++ b/src/detections/configs.rs @@ -1281,7 +1281,7 @@ pub fn load_pivot_keywords(path: &str) { PIVOT_KEYWORD .write() .unwrap() - .get_mut(&key.to_string()) + .get_mut(key) .unwrap() .fields .insert(value.to_string()); From db9bbb3bd7959af115bd14cb2970b46d4b04ba7f Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Sun, 19 Mar 2023 02:33:01 +0900 Subject: [PATCH 02/15] perf(message): replaced String with CompactString in parse_message --- src/detections/message.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/detections/message.rs b/src/detections/message.rs index 7551e867d..56310d4d2 100644 --- a/src/detections/message.rs +++ b/src/detections/message.rs @@ -190,7 +190,7 @@ pub fn parse_message( eventkey_alias: &EventKeyAliasConfig, ) -> CompactString { let mut return_message = output; - let mut hash_map: HashMap = HashMap::new(); + let mut hash_map: HashMap = HashMap::new(); for caps in ALIASREGEX.captures_iter(&return_message) { let full_target_str = &caps[0]; let target_length = full_target_str.chars().count() - 2; // The meaning of 2 is two percent @@ -227,15 +227,15 @@ pub fn parse_message( let hash_value = get_serde_number_to_string(tmp_event_record); if hash_value.is_some() { if let Some(hash_value) = hash_value { - hash_map.insert(full_target_str.to_string(), hash_value.to_string()); + hash_map.insert(CompactString::from(full_target_str), hash_value); } } else { - hash_map.insert(full_target_str.to_string(), "n/a".to_string()); + hash_map.insert(CompactString::from(full_target_str), "n/a".into()); } } - for (k, v) in &hash_map { - return_message = CompactString::new(return_message.replace(k, v)); + for (k, v) in hash_map { + return_message = CompactString::new(return_message.replace(k.as_str(), v.as_str())); } return_message } From 7f712183f2bfc41ce861aaf185aabec5c4ca3b72 Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Sun, 19 Mar 2023 02:36:56 +0900 Subject: [PATCH 03/15] perf(afterfact): removed unnecessary to_owned --- src/afterfact.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/afterfact.rs b/src/afterfact.rs index 55cb62b25..2d501eb57 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -101,7 +101,7 @@ pub fn set_output_color(no_color_flag: bool) -> HashMap { fn _get_output_color(color_map: &HashMap, level: &str) -> Option { let mut color = None; if let Some(c) = color_map.get(&CompactString::from(level.to_lowercase())) { - color = Some(c.output_color.to_owned()); + color = Some(c.output_color); } color } From 959e10a92dd3a927bfb096f5b561a7a922fdc519 Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Sun, 19 Mar 2023 02:44:28 +0900 Subject: [PATCH 04/15] perf(afterfact): removed unnecessary to_string --- src/afterfact.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/afterfact.rs b/src/afterfact.rs index 2d501eb57..3354bb2c1 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -1564,7 +1564,7 @@ fn extract_author_name(yaml_path: &str, stored_static: &StoredStatic) -> Nested< { if let Some(author) = yaml["author"].as_str() { let mut ret = Nested::::new(); - for author in author.to_string().split(',').map(|s| { + for author in author.split(',').map(|s| { // 各要素の括弧以降の記載は名前としないためtmpの一番最初の要素のみを参照する // データの中にdouble quote と single quoteが入っているためここで除外する s.split('(').next().unwrap_or_default().to_string() @@ -1576,7 +1576,7 @@ fn extract_author_name(yaml_path: &str, stored_static: &StoredStatic) -> Nested< .iter() .map(|r| { r.split('/') - .map(|p| p.to_string().replace(['"', '\''], "").trim().to_string()) + .map(|p| p.trim().replace(['"', '\''], "")) .collect::() }) .collect(); From 32fd1bd7d16516422395ec8b630bf7e29c4f176b Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Sun, 19 Mar 2023 15:42:43 +0900 Subject: [PATCH 05/15] perf(afterfact): removed unnecessary replace --- src/afterfact.rs | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/afterfact.rs b/src/afterfact.rs index 3354bb2c1..3601ab577 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -761,12 +761,12 @@ fn _get_serialized_disp_output(data: &Vec<(CompactString, Profile)>, header: boo ret.push( _format_cellpos( &d.1.to_value() - .replace("🛂r", "\r") - .replace("🛂n", "\n") - .replace("🛂t", "\t") - .replace(['\n', '\r', '\t'], " ") - .split_whitespace() - .join(" "), + .replace("🛂r", "") + .replace("🛂n", "") + .replace("🛂t", ""), + // .replace(['\n', '\r', '\t'], " ") + // .split_whitespace() + // .join(" "), ColPos::First, ) .replace('|', "🦅"), @@ -775,12 +775,12 @@ fn _get_serialized_disp_output(data: &Vec<(CompactString, Profile)>, header: boo ret.push( _format_cellpos( &d.1.to_value() - .replace("🛂r", "\r") - .replace("🛂n", "\n") - .replace("🛂t", "\t") - .replace(['\n', '\r', '\t'], " ") - .split_whitespace() - .join(" "), + .replace("🛂r", "") + .replace("🛂n", "") + .replace("🛂t", ""), + // .replace(['\n', '\r', '\t'], " ") + // .split_whitespace() + // .join(" "), ColPos::Last, ) .replace('|', "🦅"), @@ -789,12 +789,12 @@ fn _get_serialized_disp_output(data: &Vec<(CompactString, Profile)>, header: boo ret.push( _format_cellpos( &d.1.to_value() - .replace("🛂r", "\r") - .replace("🛂n", "\n") - .replace("🛂t", "\t") - .replace(['\n', '\r', '\t'], " ") - .split_whitespace() - .join(" "), + .replace("🛂r", "") + .replace("🛂n", "") + .replace("🛂t", ""), + // .replace(['\n', '\r', '\t'], " ") + // .split_whitespace() + // .join(" "), ColPos::Other, ) .replace('|', "🦅"), From 58a0c7e8164389511424f3a56a2bcd5106fea8b1 Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Sun, 19 Mar 2023 15:43:32 +0900 Subject: [PATCH 06/15] perf(afterfact): removed unnecessary borrow and replaced String with CompactString --- src/afterfact.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/afterfact.rs b/src/afterfact.rs index 3601ab577..00f1ae73f 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -933,27 +933,28 @@ fn _print_detection_summary_by_date( for (idx, level) in level_abbr.iter().enumerate() { // output_levelsはlevelsからundefinedを除外した配列であり、各要素は必ず初期化されているのでSomeであることが保証されているのでunwrapをそのまま実施 let detections_by_day = detect_counts_by_date.get(&level[1]).unwrap(); - let mut max_detect_str = String::default(); + let mut max_detect_str = CompactString::default(); let mut tmp_cnt: i128 = 0; let mut exist_max_data = false; for (date, cnt) in detections_by_day { if cnt > &tmp_cnt { exist_max_data = true; - max_detect_str = format!("{} ({})", date, cnt.to_formatted_string(&Locale::en)); + max_detect_str = + format!("{} ({})", date, cnt.to_formatted_string(&Locale::en)).into(); tmp_cnt = *cnt; } } wtr.set_color(ColorSpec::new().set_fg(_get_output_color( color_map, - LEVEL_FULL.get(&level[1].as_str()).unwrap(), + LEVEL_FULL.get(level[1].as_str()).unwrap(), ))) .ok(); if !exist_max_data { - max_detect_str = "n/a".to_string(); + max_detect_str = "n/a".into(); } let output_str = format!( "{}: {}", - LEVEL_FULL.get(&level[1].as_str()).unwrap(), + LEVEL_FULL.get(level[1].as_str()).unwrap(), &max_detect_str ); write!(wtr, "{output_str}").ok(); @@ -997,8 +998,8 @@ fn _print_detection_summary_by_computer( if stored_static.html_report_flag { html_output_stock.push(format!( "### Computers with most unique {} detections: {{#computers_with_most_unique_{}_detections}}", - LEVEL_FULL.get(&level[1].as_str()).unwrap(), - LEVEL_FULL.get(&level[1].as_str()).unwrap() + LEVEL_FULL.get(level[1].as_str()).unwrap(), + LEVEL_FULL.get(level[1].as_str()).unwrap() )); for x in sorted_detections.iter() { html_output_stock.push(format!( @@ -1024,13 +1025,13 @@ fn _print_detection_summary_by_computer( wtr.set_color(ColorSpec::new().set_fg(_get_output_color( color_map, - LEVEL_FULL.get(&level[1].as_str()).unwrap(), + LEVEL_FULL.get(level[1].as_str()).unwrap(), ))) .ok(); writeln!( wtr, "{}: {}", - LEVEL_FULL.get(&level[1].as_str()).unwrap(), + LEVEL_FULL.get(level[1].as_str()).unwrap(), &result_str ) .ok(); @@ -1056,12 +1057,12 @@ fn _print_detection_summary_tables( let mut col_output: Vec = vec![]; col_output.push(format!( "Top {} alerts:", - LEVEL_FULL.get(&level[1].as_str()).unwrap() + LEVEL_FULL.get(level[1].as_str()).unwrap() )); col_color.push(_get_table_color( color_map, - LEVEL_FULL.get(&level[1].as_str()).unwrap(), + LEVEL_FULL.get(level[1].as_str()).unwrap(), )); // output_levelsはlevelsからundefinedを除外した配列であり、各要素は必ず初期化されているのでSomeであることが保証されているのでunwrapをそのまま実施 @@ -1075,8 +1076,8 @@ fn _print_detection_summary_tables( if stored_static.html_report_flag { html_output_stock.push(format!( "### Top {} alerts: {{#top_{}_alerts}}", - LEVEL_FULL.get(&level[1].as_str()).unwrap(), - LEVEL_FULL.get(&level[1].as_str()).unwrap() + LEVEL_FULL.get(level[1].as_str()).unwrap(), + LEVEL_FULL.get(level[1].as_str()).unwrap() )); for x in sorted_detections.iter() { html_output_stock.push(format!( @@ -1092,7 +1093,7 @@ fn _print_detection_summary_tables( html_output_stock.push(""); } - let take_cnt = if "informational" == *LEVEL_FULL.get(&level[1].as_str()).unwrap_or(&"-") { + let take_cnt = if "informational" == *LEVEL_FULL.get(level[1].as_str()).unwrap_or(&"-") { 10 } else { 5 From b2cb41cf0c6d295251ccff72ae89ce99ad768161 Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Mon, 20 Mar 2023 09:04:24 +0900 Subject: [PATCH 07/15] perf(afterfact): removed unnecessary to_owned --- src/afterfact.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/afterfact.rs b/src/afterfact.rs index 00f1ae73f..3c81a23be 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -112,7 +112,7 @@ fn _get_table_color( ) -> Option { let mut color = None; if let Some(c) = color_map.get(&CompactString::from(level.to_lowercase())) { - color = Some(c.table_color.to_owned()); + color = Some(c.table_color); } color } From 5e5298493a479581e4b25c1b801a0e6b43130d91 Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Mon, 20 Mar 2023 09:06:08 +0900 Subject: [PATCH 08/15] perf(afterfact): set vector size and removed unnecessary from method call --- src/afterfact.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/afterfact.rs b/src/afterfact.rs index 3c81a23be..aef8aa3c9 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -278,7 +278,7 @@ fn emit_csv( let mut rule_title_path_map: HashMap = HashMap::new(); let mut rule_author_counter: HashMap = HashMap::new(); - let levels = Vec::from(["crit", "high", "med ", "low ", "info", "undefined"]); + let levels = ["crit", "high", "med ", "low ", "info", "undefined"]; // レベル別、日ごとの集計用変数の初期化 for level_init in levels { detect_counts_by_date_and_level.insert(CompactString::from(level_init), HashMap::new()); @@ -288,7 +288,7 @@ fn emit_csv( if displayflag { println!(); } - let mut timestamps: Vec = Vec::new(); + let mut timestamps: Vec = vec![0; MESSAGEKEYS.lock().unwrap().len()]; let mut plus_header = true; let mut detected_record_idset: HashSet = HashSet::new(); From a766d11bd33059d4796013841aaad00d1178569b Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Mon, 20 Mar 2023 09:07:06 +0900 Subject: [PATCH 09/15] perf(afterfact): replaced vec String with Nested String --- src/afterfact.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/afterfact.rs b/src/afterfact.rs index aef8aa3c9..2bf2f13bd 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -357,7 +357,7 @@ fn emit_csv( get_writable_color( _get_output_color( &color_map, - LEVEL_FULL.get(&detect_info.level.as_str()).unwrap_or(&""), + LEVEL_FULL.get(detect_info.level.as_str()).unwrap_or(&""), ), stored_static.common_options.no_color, ), @@ -1054,7 +1054,7 @@ fn _print_detection_summary_tables( let mut output = vec![]; let mut col_color = vec![]; for level in level_abbr.iter() { - let mut col_output: Vec = vec![]; + let mut col_output: Nested = Nested::::new(); col_output.push(format!( "Top {} alerts:", LEVEL_FULL.get(level[1].as_str()).unwrap() @@ -1111,7 +1111,7 @@ fn _print_detection_summary_tables( take_cnt - sorted_detections.len() }; for _x in 0..na_cnt { - col_output.push("n/a".to_string()); + col_output.push("n/a"); } output.push(col_output); } @@ -1133,15 +1133,15 @@ fn _print_detection_summary_tables( .set_style(TableComponent::BottomBorderIntersections, hlch); tb.add_row(vec![ - Cell::new(output[2 * x][1..].join("\n")) + Cell::new(output[2 * x].iter().skip(1).join("\n")) .fg(col_color[2 * x].unwrap_or(comfy_table::Color::Reset)), - Cell::new(output[2 * x + 1][1..].join("\n")) + Cell::new(output[2 * x + 1].iter().skip(1).join("\n")) .fg(col_color[2 * x + 1].unwrap_or(comfy_table::Color::Reset)), ]); } - let odd_row = &output[4][1..6]; - let even_row = &output[4][6..11]; + let odd_row = &mut output[4].iter().skip(1).take(5); + let even_row = &mut output[4].iter().skip(1).take(5); tb.add_row(vec![ Cell::new(&output[4][0]).fg(col_color[4].unwrap_or(comfy_table::Color::Reset)), Cell::new(""), From 096698ad31b3df77ceb4f59f3164229a6bae0d49 Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Mon, 20 Mar 2023 09:30:14 +0900 Subject: [PATCH 10/15] perf(filter, yaml): replaced String with ComapctString --- src/filter.rs | 20 ++++++++++---------- src/yaml.rs | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/filter.rs b/src/filter.rs index 2f37d1397..0669a1cde 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -1,7 +1,9 @@ use crate::detections::configs::{self, StoredStatic}; use crate::detections::message::{AlertMessage, ERROR_LOG_STACK}; +use compact_str::CompactString; use hashbrown::HashMap; use regex::Regex; +use std::borrow::Borrow; use std::fs::File; use std::io::{BufRead, BufReader}; @@ -13,7 +15,7 @@ pub struct DataFilterRule { #[derive(Clone, Debug)] pub struct RuleExclude { - pub no_use_rule: HashMap, + pub no_use_rule: HashMap, } impl RuleExclude { @@ -67,15 +69,13 @@ impl RuleExclude { return; } let reader = BufReader::new(f.unwrap()); - for v in reader.lines() { - let v = v.unwrap().split('#').collect::>()[0] - .trim() - .to_string(); - if v.is_empty() || !configs::IDS_REGEX.is_match(&v) { - // 空行は無視する。IDの検証 - continue; + reader.lines().for_each(|line| { + let line_contents = line.unwrap(); + let v = line_contents.split('#').collect::>()[0].trim(); + if !v.borrow().is_empty() && configs::IDS_REGEX.is_match(v) { + // IDのフォーマットにあっているもののみ追加する + self.no_use_rule.insert(v.into(), filename.into()); } - self.no_use_rule.insert(v, filename.to_owned()); - } + }); } } diff --git a/src/yaml.rs b/src/yaml.rs index 9916bd72a..9594a393d 100644 --- a/src/yaml.rs +++ b/src/yaml.rs @@ -243,12 +243,12 @@ impl ParseYaml { let files = yaml_docs.into_iter().filter_map(|(filepath, yaml_doc)| { //除外されたルールは無視する - let rule_id = &yaml_doc["id"].as_str(); + let rule_id = yaml_doc["id"].as_str(); if rule_id.is_some() { - if let Some(v) = exclude_ids - .no_use_rule - .get(&rule_id.unwrap_or(&String::default()).to_string()) + if let Some(matched_rule_id) = + exclude_ids.no_use_rule.get(rule_id.unwrap_or_default()) { + let v = matched_rule_id.as_str(); let entry_key = if utils::contains_str(v, "exclude_rule") { "excluded" } else { From 7a446e204bbdaaf133728ade4b90b28750635f20 Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Sun, 26 Mar 2023 22:58:57 +0900 Subject: [PATCH 11/15] Revert "perf(filter, yaml): replaced String with ComapctString" This reverts commit 096698ad31b3df77ceb4f59f3164229a6bae0d49. --- src/filter.rs | 20 ++++++++++---------- src/yaml.rs | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/filter.rs b/src/filter.rs index 0669a1cde..2f37d1397 100644 --- a/src/filter.rs +++ b/src/filter.rs @@ -1,9 +1,7 @@ use crate::detections::configs::{self, StoredStatic}; use crate::detections::message::{AlertMessage, ERROR_LOG_STACK}; -use compact_str::CompactString; use hashbrown::HashMap; use regex::Regex; -use std::borrow::Borrow; use std::fs::File; use std::io::{BufRead, BufReader}; @@ -15,7 +13,7 @@ pub struct DataFilterRule { #[derive(Clone, Debug)] pub struct RuleExclude { - pub no_use_rule: HashMap, + pub no_use_rule: HashMap, } impl RuleExclude { @@ -69,13 +67,15 @@ impl RuleExclude { return; } let reader = BufReader::new(f.unwrap()); - reader.lines().for_each(|line| { - let line_contents = line.unwrap(); - let v = line_contents.split('#').collect::>()[0].trim(); - if !v.borrow().is_empty() && configs::IDS_REGEX.is_match(v) { - // IDのフォーマットにあっているもののみ追加する - self.no_use_rule.insert(v.into(), filename.into()); + for v in reader.lines() { + let v = v.unwrap().split('#').collect::>()[0] + .trim() + .to_string(); + if v.is_empty() || !configs::IDS_REGEX.is_match(&v) { + // 空行は無視する。IDの検証 + continue; } - }); + self.no_use_rule.insert(v, filename.to_owned()); + } } } diff --git a/src/yaml.rs b/src/yaml.rs index de9f92ee6..989df6140 100644 --- a/src/yaml.rs +++ b/src/yaml.rs @@ -243,12 +243,12 @@ impl ParseYaml { let files = yaml_docs.into_iter().filter_map(|(filepath, yaml_doc)| { //除外されたルールは無視する - let rule_id = yaml_doc["id"].as_str(); + let rule_id = &yaml_doc["id"].as_str(); if rule_id.is_some() { - if let Some(matched_rule_id) = - exclude_ids.no_use_rule.get(rule_id.unwrap_or_default()) + if let Some(v) = exclude_ids + .no_use_rule + .get(&rule_id.unwrap_or(&String::default()).to_string()) { - let v = matched_rule_id.as_str(); let entry_key = if utils::contains_str(v, "exclude_rule") { "excluded" } else { From c1ef6ea02f254d853430d16a2ff94016ab470496 Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Wed, 29 Mar 2023 01:18:40 +0900 Subject: [PATCH 12/15] perf: replaced compact string with cow in profile --- src/afterfact.rs | 144 ++++--------- src/detections/detection.rs | 414 ++++++++++++++++++++---------------- src/detections/message.rs | 8 +- src/options/profile.rs | 133 ++++++------ 4 files changed, 334 insertions(+), 365 deletions(-) diff --git a/src/afterfact.rs b/src/afterfact.rs index 45578fe27..aa88bf4c6 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -1611,6 +1611,7 @@ mod tests { use compact_str::CompactString; use hashbrown::HashMap; use serde_json::Value; + use std::borrow::Cow; use std::fs::File; use std::fs::{read_to_string, remove_file}; use std::io; @@ -1754,54 +1755,29 @@ mod tests { }, enable_unsupported_rules: false, }; + let ch = mock_ch_filter + .get(&CompactString::from("security")) + .unwrap_or(&CompactString::default()) + .clone(); let mut profile_converter: HashMap<&str, Profile> = HashMap::from([ ( "Timestamp", - Profile::Timestamp(format_time(&expect_time, false, &output_option)), - ), - ( - "Computer", - Profile::Computer(CompactString::from(test_computername2)), - ), - ( - "Channel", - Profile::Channel( - mock_ch_filter - .get(&CompactString::from("security")) - .unwrap_or(&CompactString::default()) - .to_owned(), - ), - ), - ("Level", Profile::Level(CompactString::from(test_level))), - ( - "EventID", - Profile::EventID(CompactString::from(test_eventid)), - ), - ( - "MitreAttack", - Profile::MitreTactics(CompactString::from(test_attack)), - ), - ( - "RecordID", - Profile::RecordID(CompactString::from(test_record_id)), - ), - ( - "RuleTitle", - Profile::RuleTitle(CompactString::from(test_title)), + Profile::Timestamp(format_time(&expect_time, false, &output_option).into()), ), + ("Computer", Profile::Computer(test_computername2.into())), + ("Channel", Profile::Channel(ch.into())), + ("Level", Profile::Level(test_level.into())), + ("EventID", Profile::EventID(test_eventid.into())), + ("MitreAttack", Profile::MitreTactics(test_attack.into())), + ("RecordID", Profile::RecordID(test_record_id.into())), + ("RuleTitle", Profile::RuleTitle(test_title.into())), ( "RecordInformation", - Profile::AllFieldInfo(CompactString::from(test_recinfo)), - ), - ( - "RuleFile", - Profile::RuleFile(CompactString::from(test_rulepath)), + Profile::AllFieldInfo(test_recinfo.into()), ), - ( - "EvtxFile", - Profile::EvtxFile(CompactString::from(test_filepath)), - ), - ("Tags", Profile::MitreTags(CompactString::from(test_attack))), + ("RuleFile", Profile::RuleFile(test_rulepath.into())), + ("EvtxFile", Profile::EvtxFile(test_filepath.into())), + ("Tags", Profile::MitreTags(test_attack.into())), ]); let eventkey_alias = load_eventkey_alias( utils::check_setting_path( @@ -1832,7 +1808,7 @@ mod tests { &eventkey_alias, ); *profile_converter.get_mut("Computer").unwrap() = - Profile::Computer(CompactString::from(test_computername)); + Profile::Computer(test_computername.into()); message::insert( &event, @@ -2072,54 +2048,26 @@ mod tests { }, enable_unsupported_rules: false, }; + let ch = mock_ch_filter + .get(&CompactString::from("security")) + .unwrap_or(&CompactString::default()) + .clone(); let mut profile_converter: HashMap<&str, Profile> = HashMap::from([ ( "Timestamp", - Profile::Timestamp(format_time(&expect_time, false, &output_option)), - ), - ( - "Computer", - Profile::Computer(CompactString::from(test_computername2)), + Profile::Timestamp(format_time(&expect_time, false, &output_option).into()), ), - ( - "Channel", - Profile::Channel( - mock_ch_filter - .get(&CompactString::from("security")) - .unwrap_or(&CompactString::default()) - .to_owned(), - ), - ), - ("Level", Profile::Level(CompactString::from(test_level))), - ( - "EventID", - Profile::EventID(CompactString::from(test_eventid)), - ), - ( - "MitreAttack", - Profile::MitreTactics(CompactString::from(test_attack)), - ), - ( - "RecordID", - Profile::RecordID(CompactString::from(test_record_id)), - ), - ( - "RuleTitle", - Profile::RuleTitle(CompactString::from(test_title)), - ), - ( - "AllFieldInfo", - Profile::AllFieldInfo(CompactString::from(test_recinfo)), - ), - ( - "RuleFile", - Profile::RuleFile(CompactString::from(test_rulepath)), - ), - ( - "EvtxFile", - Profile::EvtxFile(CompactString::from(test_filepath)), - ), - ("Tags", Profile::MitreTags(CompactString::from(test_attack))), + ("Computer", Profile::Computer(test_computername2.into())), + ("Channel", Profile::Channel(ch.into())), + ("Level", Profile::Level(test_level.into())), + ("EventID", Profile::EventID(test_eventid.into())), + ("MitreAttack", Profile::MitreTactics(test_attack.into())), + ("RecordID", Profile::RecordID(test_record_id.into())), + ("RuleTitle", Profile::RuleTitle(test_title.into())), + ("AllFieldInfo", Profile::AllFieldInfo(test_recinfo.into())), + ("RuleFile", Profile::RuleFile(test_rulepath.into())), + ("EvtxFile", Profile::EvtxFile(test_filepath.into())), + ("Tags", Profile::MitreTags(test_attack.into())), ]); let eventkey_alias = load_eventkey_alias( utils::check_setting_path( @@ -2150,7 +2098,7 @@ mod tests { &eventkey_alias, ); *profile_converter.get_mut("Computer").unwrap() = - Profile::Computer(CompactString::from(test_computername)); + Profile::Computer(test_computername.into()); message::insert( &event, @@ -2319,43 +2267,39 @@ mod tests { let data: Vec<(CompactString, Profile)> = vec![ ( CompactString::new("Timestamp"), - Profile::Timestamp(CompactString::new(format_time( - &test_timestamp, - false, - &output_option, - ))), + Profile::Timestamp(format_time(&test_timestamp, false, &output_option).into()), ), ( CompactString::new("Computer"), - Profile::Computer(CompactString::new(test_computername)), + Profile::Computer(test_computername.into()), ), ( CompactString::new("Channel"), - Profile::Channel(CompactString::new(test_channel)), + Profile::Channel(test_channel.into()), ), ( CompactString::new("EventID"), - Profile::EventID(CompactString::new(test_eventid)), + Profile::EventID(test_eventid.into()), ), ( CompactString::new("Level"), - Profile::Level(CompactString::new(test_level)), + Profile::Level(test_level.into()), ), ( CompactString::new("RecordID"), - Profile::RecordID(CompactString::new(test_recid)), + Profile::RecordID(test_recid.into()), ), ( CompactString::new("RuleTitle"), - Profile::RuleTitle(CompactString::new(test_title)), + Profile::RuleTitle(test_title.into()), ), ( CompactString::new("Details"), - Profile::Details(CompactString::new(output)), + Profile::Details(output.into()), ), ( CompactString::new("RecordInformation"), - Profile::AllFieldInfo(CompactString::new(test_recinfo)), + Profile::AllFieldInfo(test_recinfo.into()), ), ]; assert_eq!(_get_serialized_disp_output(&data, true), expect_header); diff --git a/src/detections/detection.rs b/src/detections/detection.rs index bc750d9b5..1fbd97add 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -250,7 +250,7 @@ impl Detection { let default_time = Utc.with_ymd_and_hms(1970, 1, 1, 0, 0, 0).unwrap(); let time = message::get_event_time(&record_info.record, stored_static.json_input_flag) .unwrap_or(default_time); - let level = rule.yaml["level"].as_str().unwrap_or("-"); + let level = rule.yaml["level"].as_str().unwrap_or("-").to_string(); let mut profile_converter: HashMap<&str, Profile> = HashMap::new(); let tags_config_values: Vec<&CompactString> = TAGS_CONFIG.values().collect(); @@ -262,21 +262,25 @@ impl Detection { Timestamp(_) => { profile_converter.insert( key.as_str(), - Timestamp(format_time( - &time, - false, - stored_static.output_option.as_ref().unwrap(), - )), + Timestamp( + format_time( + &time, + false, + stored_static.output_option.as_ref().unwrap(), + ) + .into(), + ), ); } Computer(_) => { profile_converter.insert( key.as_str(), - Computer(CompactString::from( + Computer( record_info.record["Event"]["System"]["Computer"] .to_string() - .replace('\"', ""), - )), + .replace('\"', "") + .into(), + ), ); } Channel(_) => { @@ -298,47 +302,50 @@ impl Detection { ); } Level(_) => { - profile_converter.insert( - key.as_str(), - Level(CompactString::from( - *LEVEL_ABBR_MAP.get(level).unwrap_or(&level), - )), - ); + let str_level = level.as_str(); + let prof_level = LEVEL_ABBR_MAP + .get(str_level) + .unwrap_or(&str_level) + .to_string(); + profile_converter.insert(key.as_str(), Level(prof_level.into())); } EventID(_) => { - profile_converter.insert(key.as_str(), EventID(eid.clone())); + profile_converter.insert(key.as_str(), EventID(eid.to_string().into())); } RecordID(_) => { - profile_converter.insert(key.as_str(), RecordID(rec_id.to_owned())); + profile_converter.insert(key.as_str(), RecordID(rec_id.to_string().into())); } RuleTitle(_) => { profile_converter.insert( key.as_str(), - RuleTitle(CompactString::from( - rule.yaml["title"].as_str().unwrap_or(""), - )), + RuleTitle( + rule.yaml["title"] + .as_str() + .unwrap_or_default() + .to_string() + .into(), + ), ); } RuleFile(_) => { - profile_converter.insert( - key.as_str(), - RuleFile(CompactString::from( - Path::new(&rule.rulepath) - .file_name() - .unwrap_or_default() - .to_str() - .unwrap_or_default(), - )), + let rule_file_path = CompactString::from( + Path::new(&rule.rulepath) + .file_name() + .unwrap_or_default() + .to_str() + .unwrap_or_default(), ); + profile_converter.insert(key.as_str(), RuleFile(rule_file_path.into())); } EvtxFile(_) => { profile_converter.insert( key.as_str(), - EvtxFile(CompactString::from( + EvtxFile( Path::new(&record_info.evtx_filepath) - .to_str() - .unwrap_or_default(), - )), + .display() + .to_string() + .into(), + ), ); } MitreTactics(_) => { @@ -349,76 +356,84 @@ impl Detection { .join(" ¦ "), ); - profile_converter.insert(key.as_str(), MitreTactics(tactics)); + profile_converter.insert(key.as_str(), MitreTactics(tactics.into())); } MitreTags(_) => { - let techniques = CompactString::from( - &tag_info - .iter() - .filter(|x| { - !tags_config_values.contains(&&CompactString::from(*x)) - && (x.starts_with("attack.t") - || x.starts_with("attack.g") - || x.starts_with("attack.s")) - }) - .map(|y| { - let replaced_tag = y.replace("attack.", ""); - make_ascii_titlecase(&replaced_tag) - }) - .join(" ¦ "), - ); - profile_converter.insert(key.as_str(), MitreTags(techniques)); - } - OtherTags(_) => { - let tags = CompactString::from( - &tag_info - .iter() - .filter(|x| { - !(TAGS_CONFIG.values().contains(&CompactString::from(*x)) - || x.starts_with("attack.t") + let techniques = tag_info + .iter() + .filter(|x| { + !tags_config_values.contains(&&CompactString::from(*x)) + && (x.starts_with("attack.t") || x.starts_with("attack.g") || x.starts_with("attack.s")) - }) - .join(" ¦ "), - ); - profile_converter.insert(key.as_str(), OtherTags(tags)); + }) + .map(|y| { + let replaced_tag = y.replace("attack.", ""); + make_ascii_titlecase(&replaced_tag) + }) + .join(" ¦ "); + profile_converter.insert(key.as_str(), MitreTags(techniques.into())); + } + OtherTags(_) => { + let tags = tag_info + .iter() + .filter(|x| { + !(TAGS_CONFIG.values().contains(&CompactString::from(*x)) + || x.starts_with("attack.t") + || x.starts_with("attack.g") + || x.starts_with("attack.s")) + }) + .join(" ¦ "); + profile_converter.insert(key.as_str(), OtherTags(tags.into())); } RuleAuthor(_) => { profile_converter.insert( key.as_str(), - RuleAuthor(CompactString::from( - rule.yaml["author"].as_str().unwrap_or("-"), - )), + RuleAuthor( + rule.yaml["author"] + .as_str() + .unwrap_or("-") + .to_string() + .into(), + ), ); } RuleCreationDate(_) => { profile_converter.insert( key.as_str(), - RuleCreationDate(CompactString::from( - rule.yaml["date"].as_str().unwrap_or("-"), - )), + RuleCreationDate( + rule.yaml["date"].as_str().unwrap_or("-").to_string().into(), + ), ); } RuleModifiedDate(_) => { profile_converter.insert( key.as_str(), - RuleModifiedDate(CompactString::from( - rule.yaml["modified"].as_str().unwrap_or("-"), - )), + RuleModifiedDate( + rule.yaml["modified"] + .as_str() + .unwrap_or("-") + .to_string() + .into(), + ), ); } Status(_) => { profile_converter.insert( key.as_str(), - Status(CompactString::from( - rule.yaml["status"].as_str().unwrap_or("-"), - )), + Status( + rule.yaml["status"] + .as_str() + .unwrap_or("-") + .to_string() + .into(), + ), ); } RuleID(_) => { profile_converter.insert( key.as_str(), - RuleID(CompactString::from(rule.yaml["id"].as_str().unwrap_or("-"))), + RuleID(rule.yaml["id"].as_str().unwrap_or("-").to_string().into()), ); } Provider(_) => { @@ -429,32 +444,33 @@ impl Detection { ); profile_converter.insert( key.as_str(), - Provider(CompactString::from( - stored_static.disp_abbr_generic.replace_all( - stored_static - .provider_abbr_config - .get(&provider_value) - .unwrap_or(&provider_value), - &stored_static.disp_abbr_general_values, - ), - )), + Provider( + stored_static + .disp_abbr_generic + .replace_all( + stored_static + .provider_abbr_config + .get(&provider_value) + .unwrap_or(&provider_value), + &stored_static.disp_abbr_general_values, + ) + .into(), + ), ); } RenderedMessage(_) => { let convert_value = if let Some(message) = record_info.record["Event"]["RenderingInfo"]["Message"].as_str() { - CompactString::from( - message - .replace('\t', "\\t") - .split("\r\n") - .map(|x| x.trim()) - .join("\\r\\n"), - ) + message + .replace('\t', "\\t") + .split("\r\n") + .map(|x| x.trim()) + .join("\\r\\n") } else { - CompactString::from("n/a") + "n/a".into() }; - profile_converter.insert(key.as_str(), RenderedMessage(convert_value)); + profile_converter.insert(key.as_str(), RenderedMessage(convert_value.into())); } TgtASN(_) | TgtCountry(_) | TgtCity(_) => { if profile_converter.contains_key(key.as_str()) { @@ -519,13 +535,13 @@ impl Detection { .map(|x| if x.is_empty() { "-" } else { x }); profile_converter .entry("TgtASN") - .and_modify(|p| *p = TgtASN(tgt_data.next().unwrap().into())); - profile_converter - .entry("TgtCountry") - .and_modify(|p| *p = TgtCountry(tgt_data.next().unwrap().into())); + .and_modify(|p| *p = TgtASN(tgt_data.next().unwrap().to_owned().into())); + profile_converter.entry("TgtCountry").and_modify(|p| { + *p = TgtCountry(tgt_data.next().unwrap().to_owned().into()) + }); profile_converter .entry("TgtCity") - .and_modify(|p| *p = TgtCity(tgt_data.next().unwrap().into())); + .and_modify(|p| *p = TgtCity(tgt_data.next().unwrap().to_owned().into())); } SrcASN(_) | SrcCountry(_) | SrcCity(_) => { if profile_converter.contains_key(key.as_str()) { @@ -593,13 +609,13 @@ impl Detection { .map(|x| if x.is_empty() { "-" } else { x }); profile_converter .entry("SrcASN") - .and_modify(|p| *p = SrcASN(src_data.next().unwrap().into())); - profile_converter - .entry("SrcCountry") - .and_modify(|p| *p = SrcCountry(src_data.next().unwrap().into())); + .and_modify(|p| *p = SrcASN(src_data.next().unwrap().to_owned().into())); + profile_converter.entry("SrcCountry").and_modify(|p| { + *p = SrcCountry(src_data.next().unwrap().to_owned().into()) + }); profile_converter .entry("SrcCity") - .and_modify(|p| *p = SrcCity(src_data.next().unwrap().into())); + .and_modify(|p| *p = SrcCity(src_data.next().unwrap().to_owned().into())); } _ => {} } @@ -618,10 +634,16 @@ impl Detection { let detect_info = DetectInfo { rulepath: CompactString::from(&rule.rulepath), ruletitle: CompactString::from(rule.yaml["title"].as_str().unwrap_or("-")), - level: CompactString::from(LEVEL_ABBR_MAP.get(level).unwrap_or(&level).to_string()), + level: CompactString::from( + LEVEL_ABBR_MAP + .get(&level.as_str()) + .unwrap_or(&level.as_str()) + .to_string(), + ), computername: CompactString::from( record_info.record["Event"]["System"]["Computer"] - .to_string() + .as_str() + .unwrap_or_default() .replace('\"', ""), ), eventid: eid, @@ -646,7 +668,7 @@ impl Detection { let output = Detection::create_count_output(rule, &agg_result); let mut profile_converter: HashMap<&str, Profile> = HashMap::new(); - let level = rule.yaml["level"].as_str().unwrap_or("-"); + let level = rule.yaml["level"].as_str().unwrap_or("-").to_string(); let tags_config_values: Vec<&CompactString> = TAGS_CONFIG.values().collect(); for (key, profile) in stored_static.profiles.as_ref().unwrap().iter() { @@ -654,141 +676,152 @@ impl Detection { Timestamp(_) => { profile_converter.insert( key.as_str(), - Timestamp(format_time( - &agg_result.start_timedate, - false, - stored_static.output_option.as_ref().unwrap(), - )), + Timestamp( + format_time( + &agg_result.start_timedate, + false, + stored_static.output_option.as_ref().unwrap(), + ) + .into(), + ), ); } Computer(_) => { - profile_converter.insert(key.as_str(), Computer(CompactString::from("-"))); + profile_converter.insert(key.as_str(), Computer("-".into())); } Channel(_) => { - profile_converter.insert(key.as_str(), Channel(CompactString::from("-"))); + profile_converter.insert(key.as_str(), Channel("-".into())); } Level(_) => { - profile_converter.insert( - key.as_str(), - Level(CompactString::from( - LEVEL_ABBR_MAP.get(level).unwrap_or(&level).to_string(), - )), - ); + let str_level = level.as_str(); + let prof_level = LEVEL_ABBR_MAP + .get(str_level) + .unwrap_or(&str_level) + .to_string(); + + profile_converter.insert(key.as_str(), Level(prof_level.into())); } EventID(_) => { - profile_converter.insert(key.as_str(), EventID(CompactString::from("-"))); + profile_converter.insert(key.as_str(), EventID("-".into())); } RecordID(_) => { - profile_converter.insert(key.as_str(), RecordID(CompactString::from(""))); + profile_converter.insert(key.as_str(), RecordID("".into())); } RuleTitle(_) => { profile_converter.insert( key.as_str(), - RuleTitle(CompactString::from( - rule.yaml["title"].as_str().unwrap_or(""), - )), + RuleTitle( + rule.yaml["title"] + .as_str() + .unwrap_or_default() + .to_owned() + .into(), + ), ); } RuleFile(_) => { - profile_converter.insert( - key.as_str(), - RuleFile(CompactString::from( - Path::new(&rule.rulepath) - .file_name() - .unwrap_or_default() - .to_str() - .unwrap_or_default(), - )), - ); + let rule_path = Path::new(&rule.rulepath) + .file_name() + .unwrap_or_default() + .to_str() + .unwrap_or_default() + .to_string(); + + profile_converter.insert(key.as_str(), RuleFile(rule_path.into())); } EvtxFile(_) => { - profile_converter.insert(key.as_str(), EvtxFile(CompactString::from("-"))); + profile_converter.insert(key.as_str(), EvtxFile("-".into())); } MitreTactics(_) => { - let tactics = CompactString::from( - &tag_info - .iter() - .filter(|x| tags_config_values.contains(&&CompactString::from(*x))) - .join(" ¦ "), - ); - profile_converter.insert(key.as_str(), MitreTactics(tactics)); + let tactics = tag_info + .iter() + .filter(|x| tags_config_values.contains(&&CompactString::from(*x))) + .join(" ¦ "); + profile_converter.insert(key.as_str(), MitreTactics(tactics.into())); } MitreTags(_) => { - let techniques = CompactString::from( - &tag_info - .iter() - .filter(|x| { - !tags_config_values.contains(&&CompactString::from(*x)) - && (x.starts_with("attack.t") - || x.starts_with("attack.g") - || x.starts_with("attack.s")) - }) - .map(|y| { - let replaced_tag = y.replace("attack.", ""); - make_ascii_titlecase(&replaced_tag) - }) - .join(" ¦ "), - ); - profile_converter.insert(key.as_str(), MitreTags(techniques)); - } - OtherTags(_) => { - let tags = CompactString::from( - &tag_info - .iter() - .filter(|x| { - !(tags_config_values.contains(&&CompactString::from(*x)) - || x.starts_with("attack.t") + let techniques = tag_info + .iter() + .filter(|x| { + !tags_config_values.contains(&&CompactString::from(*x)) + && (x.starts_with("attack.t") || x.starts_with("attack.g") || x.starts_with("attack.s")) - }) - .join(" ¦ "), - ); - profile_converter.insert(key.as_str(), OtherTags(tags)); + }) + .map(|y| { + let replaced_tag = y.replace("attack.", ""); + make_ascii_titlecase(&replaced_tag) + }) + .join(" ¦ "); + profile_converter.insert(key.as_str(), MitreTags(techniques.into())); + } + OtherTags(_) => { + let tags = tag_info + .iter() + .filter(|x| { + !(tags_config_values.contains(&&CompactString::from(*x)) + || x.starts_with("attack.t") + || x.starts_with("attack.g") + || x.starts_with("attack.s")) + }) + .join(" ¦ "); + profile_converter.insert(key.as_str(), OtherTags(tags.into())); } RuleAuthor(_) => { profile_converter.insert( key.as_str(), - RuleAuthor(CompactString::from( - rule.yaml["author"].as_str().unwrap_or("-"), - )), + RuleAuthor( + rule.yaml["author"] + .as_str() + .unwrap_or("-") + .to_owned() + .into(), + ), ); } RuleCreationDate(_) => { profile_converter.insert( key.as_str(), - RuleCreationDate(CompactString::from( - rule.yaml["date"].as_str().unwrap_or("-"), - )), + RuleCreationDate( + rule.yaml["date"].as_str().unwrap_or("-").to_owned().into(), + ), ); } RuleModifiedDate(_) => { profile_converter.insert( key.as_str(), - RuleModifiedDate(CompactString::from( - rule.yaml["modified"].as_str().unwrap_or("-"), - )), + RuleModifiedDate( + rule.yaml["modified"] + .as_str() + .unwrap_or("-") + .to_owned() + .into(), + ), ); } Status(_) => { profile_converter.insert( key.as_str(), - Status(CompactString::from( - rule.yaml["status"].as_str().unwrap_or("-"), - )), + Status( + rule.yaml["status"] + .as_str() + .unwrap_or("-") + .to_owned() + .into(), + ), ); } RuleID(_) => { profile_converter.insert( key.as_str(), - RuleID(CompactString::from(rule.yaml["id"].as_str().unwrap_or("-"))), + RuleID(rule.yaml["id"].as_str().unwrap_or("-").to_owned().into()), ); } Provider(_) => { - profile_converter.insert(key.as_str(), Provider(CompactString::from("-"))); + profile_converter.insert(key.as_str(), Provider("-".into())); } RenderedMessage(_) => { - profile_converter - .insert(key.as_str(), RenderedMessage(CompactString::from("-"))); + profile_converter.insert(key.as_str(), RenderedMessage("-".into())); } TgtASN(_) | TgtCountry(_) | TgtCity(_) => { if profile_converter.contains_key(key.as_str()) { @@ -809,11 +842,16 @@ impl Detection { _ => {} } } - + let str_level = level.as_str(); let detect_info = DetectInfo { rulepath: CompactString::from(&rule.rulepath), ruletitle: CompactString::from(rule.yaml["title"].as_str().unwrap_or("-")), - level: CompactString::from(*LEVEL_ABBR_MAP.get(level).unwrap_or(&level)), + level: CompactString::from( + LEVEL_ABBR_MAP + .get(str_level) + .unwrap_or(&str_level) + .to_string(), + ), computername: CompactString::from("-"), eventid: CompactString::from("-"), detail: output, diff --git a/src/detections/message.rs b/src/detections/message.rs index 56310d4d2..13371cfd7 100644 --- a/src/detections/message.rs +++ b/src/detections/message.rs @@ -143,19 +143,17 @@ pub fn insert( if detect_info.detail.is_empty() { replaced_profiles.push((key.to_owned(), profile.to_owned())); } else { - replaced_profiles.push((key.to_owned(), Details(detect_info.detail))); + replaced_profiles.push((key.to_owned(), Details(detect_info.detail.into()))); detect_info.detail = CompactString::default(); } } AllFieldInfo(_) => { if is_agg { - replaced_profiles - .push((key.to_owned(), AllFieldInfo(CompactString::from("-")))); + replaced_profiles.push((key.to_owned(), AllFieldInfo("-".into()))); } else { let rec = utils::create_recordinfos(event_record); let rec = if rec.is_empty() { "-".to_string() } else { rec }; - replaced_profiles - .push((key.to_owned(), AllFieldInfo(CompactString::from(rec)))); + replaced_profiles.push((key.to_owned(), AllFieldInfo(rec.into()))); } } Literal(_) => replaced_profiles.push((key.to_owned(), profile.to_owned())), diff --git a/src/options/profile.rs b/src/options/profile.rs index 17c1e4f62..2fb2541f9 100644 --- a/src/options/profile.rs +++ b/src/options/profile.rs @@ -11,6 +11,7 @@ use crate::yaml; use compact_str::CompactString; use itertools::Itertools; use nested::Nested; +use std::borrow::Cow; use std::fs::OpenOptions; use std::io::{BufWriter, Write}; use std::path::Path; @@ -18,34 +19,34 @@ use yaml_rust::{Yaml, YamlEmitter, YamlLoader}; #[derive(Eq, PartialEq, Hash, Clone, Debug)] pub enum Profile { - Timestamp(CompactString), - Computer(CompactString), - Channel(CompactString), - Level(CompactString), - EventID(CompactString), - RecordID(CompactString), - RuleTitle(CompactString), - AllFieldInfo(CompactString), - RuleFile(CompactString), - EvtxFile(CompactString), - MitreTactics(CompactString), - MitreTags(CompactString), - OtherTags(CompactString), - RuleAuthor(CompactString), - RuleCreationDate(CompactString), - RuleModifiedDate(CompactString), - Status(CompactString), - RuleID(CompactString), - Provider(CompactString), - Details(CompactString), - RenderedMessage(CompactString), - SrcASN(CompactString), - SrcCountry(CompactString), - SrcCity(CompactString), - TgtASN(CompactString), - TgtCountry(CompactString), - TgtCity(CompactString), - Literal(CompactString), // profiles.yamlの固定文字列を変換なしでそのまま出力する場合 + Timestamp(Cow<'static, str>), + Computer(Cow<'static, str>), + Channel(Cow<'static, str>), + Level(Cow<'static, str>), + EventID(Cow<'static, str>), + RecordID(Cow<'static, str>), + RuleTitle(Cow<'static, str>), + AllFieldInfo(Cow<'static, str>), + RuleFile(Cow<'static, str>), + EvtxFile(Cow<'static, str>), + MitreTactics(Cow<'static, str>), + MitreTags(Cow<'static, str>), + OtherTags(Cow<'static, str>), + RuleAuthor(Cow<'static, str>), + RuleCreationDate(Cow<'static, str>), + RuleModifiedDate(Cow<'static, str>), + Status(Cow<'static, str>), + RuleID(Cow<'static, str>), + Provider(Cow<'static, str>), + Details(Cow<'static, str>), + RenderedMessage(Cow<'static, str>), + SrcASN(Cow<'static, str>), + SrcCountry(Cow<'static, str>), + SrcCity(Cow<'static, str>), + TgtASN(Cow<'static, str>), + TgtCountry(Cow<'static, str>), + TgtCity(Cow<'static, str>), + Literal(Cow<'static, str>), // profiles.yamlの固定文字列を変換なしでそのまま出力する場合 } impl Profile { @@ -62,31 +63,31 @@ impl Profile { pub fn convert(&self, converted_string: &CompactString) -> Self { match self { - Timestamp(_) => Timestamp(converted_string.to_owned()), - Computer(_) => Computer(converted_string.to_owned()), - Channel(_) => Channel(converted_string.to_owned()), - Level(_) => Level(converted_string.to_owned()), - EventID(_) => EventID(converted_string.to_owned()), - RecordID(_) => RecordID(converted_string.to_owned()), - RuleTitle(_) => RuleTitle(converted_string.to_owned()), - RuleFile(_) => RuleFile(converted_string.to_owned()), - EvtxFile(_) => EvtxFile(converted_string.to_owned()), - MitreTactics(_) => MitreTactics(converted_string.to_owned()), - MitreTags(_) => MitreTags(converted_string.to_owned()), - OtherTags(_) => OtherTags(converted_string.to_owned()), - RuleAuthor(_) => RuleAuthor(converted_string.to_owned()), - RuleCreationDate(_) => RuleCreationDate(converted_string.to_owned()), - RuleModifiedDate(_) => RuleModifiedDate(converted_string.to_owned()), - Status(_) => Status(converted_string.to_owned()), - RuleID(_) => RuleID(converted_string.to_owned()), - Provider(_) => Provider(converted_string.to_owned()), - RenderedMessage(_) => RenderedMessage(converted_string.to_owned()), - SrcASN(_) => SrcASN(converted_string.to_owned()), - SrcCountry(_) => SrcCountry(converted_string.to_owned()), - SrcCity(_) => SrcCity(converted_string.to_owned()), - TgtASN(_) => TgtASN(converted_string.to_owned()), - TgtCountry(_) => TgtCountry(converted_string.to_owned()), - TgtCity(_) => TgtCity(converted_string.to_owned()), + Timestamp(_) => Timestamp(converted_string.to_owned().into()), + Computer(_) => Computer(converted_string.to_owned().into()), + Channel(_) => Channel(converted_string.to_owned().into()), + Level(_) => Level(converted_string.to_owned().into()), + EventID(_) => EventID(converted_string.to_owned().into()), + RecordID(_) => RecordID(converted_string.to_owned().into()), + RuleTitle(_) => RuleTitle(converted_string.to_owned().into()), + RuleFile(_) => RuleFile(converted_string.to_owned().into()), + EvtxFile(_) => EvtxFile(converted_string.to_owned().into()), + MitreTactics(_) => MitreTactics(converted_string.to_owned().into()), + MitreTags(_) => MitreTags(converted_string.to_owned().into()), + OtherTags(_) => OtherTags(converted_string.to_owned().into()), + RuleAuthor(_) => RuleAuthor(converted_string.to_owned().into()), + RuleCreationDate(_) => RuleCreationDate(converted_string.to_owned().into()), + RuleModifiedDate(_) => RuleModifiedDate(converted_string.to_owned().into()), + Status(_) => Status(converted_string.to_owned().into()), + RuleID(_) => RuleID(converted_string.to_owned().into()), + Provider(_) => Provider(converted_string.to_owned().into()), + RenderedMessage(_) => RenderedMessage(converted_string.to_owned().into()), + SrcASN(_) => SrcASN(converted_string.to_owned().into()), + SrcCountry(_) => SrcCountry(converted_string.to_owned().into()), + SrcCity(_) => SrcCity(converted_string.to_owned().into()), + TgtASN(_) => TgtASN(converted_string.to_owned().into()), + TgtCountry(_) => TgtCountry(converted_string.to_owned().into()), + TgtCity(_) => TgtCity(converted_string.to_owned().into()), p => p.to_owned(), } } @@ -116,7 +117,7 @@ impl From<&str> for Profile { "%Provider%" => Provider(Default::default()), "%Details%" => Details(Default::default()), "%RenderedMessage%" => RenderedMessage(Default::default()), - s => Literal(CompactString::from(s)), // profiles.yamlの固定文字列を変換なしでそのまま出力する場合 + s => Literal(s.to_string().into()), // profiles.yamlの固定文字列を変換なしでそのまま出力する場合 } } } @@ -229,30 +230,18 @@ pub fn load_profile( } // insert preserved keyword when get-ip option specified. if GEOIP_DB_PARSER.read().unwrap().is_some() { - ret.push(( - CompactString::from("SrcASN"), - SrcASN(CompactString::default()), - )); + ret.push((CompactString::from("SrcASN"), SrcASN(Cow::default()))); ret.push(( CompactString::from("SrcCountry"), - SrcCountry(CompactString::default()), - )); - ret.push(( - CompactString::from("SrcCity"), - SrcCity(CompactString::default()), - )); - ret.push(( - CompactString::from("TgtASN"), - TgtASN(CompactString::default()), + SrcCountry(Cow::default()), )); + ret.push((CompactString::from("SrcCity"), SrcCity(Cow::default()))); + ret.push((CompactString::from("TgtASN"), TgtASN(Cow::default()))); ret.push(( CompactString::from("TgtCountry"), - TgtCountry(CompactString::default()), - )); - ret.push(( - CompactString::from("TgtCity"), - TgtCity(CompactString::default()), + TgtCountry(Cow::default()), )); + ret.push((CompactString::from("TgtCity"), TgtCity(Cow::default()))); } Some(ret) } From d9f31818b3e2b03df349167634018fde80b54747 Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Wed, 29 Mar 2023 01:32:25 +0900 Subject: [PATCH 13/15] style(afterfact): fixed clippy warning --- src/afterfact.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/afterfact.rs b/src/afterfact.rs index aa88bf4c6..776391c62 100644 --- a/src/afterfact.rs +++ b/src/afterfact.rs @@ -1611,7 +1611,6 @@ mod tests { use compact_str::CompactString; use hashbrown::HashMap; use serde_json::Value; - use std::borrow::Cow; use std::fs::File; use std::fs::{read_to_string, remove_file}; use std::io; From b82028825c2d3e69db529d45b6fc714393dd3378 Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Sun, 2 Apr 2023 19:12:26 +0900 Subject: [PATCH 14/15] docs(CHANGELOG): updated changelog #984 --- CHANGELOG-Japanese.md | 1 + CHANGELOG.md | 1 + 2 files changed, 2 insertions(+) diff --git a/CHANGELOG-Japanese.md b/CHANGELOG-Japanese.md index 553c47b21..02f135302 100644 --- a/CHANGELOG-Japanese.md +++ b/CHANGELOG-Japanese.md @@ -6,6 +6,7 @@ - ファイル(CSV, JSON, JSONL)出力の際に`Level`の余分なスペースを削除した。 (#979) (@hitenkoku) - `-M, --multiline`オプション利用時にルール作者名の出力を複数行出力対応をした。 (#980) (@hitenkoku) +- Stringの代わりにCoWを利用することで、約5%の速度向上を実現した。 (#984) (@hitenkoku) **バグ修正:** diff --git a/CHANGELOG.md b/CHANGELOG.md index c53a745b8..9c2f18a1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ - Removed an extra space when outputting `Level` to files(CSV, JSON, JSONL). (#979) (@hitenkoku) - Made rule authors multiple lines with `-M, --multiline` option. (#980) (@hitenkoku) +- Approximately 3-5% speed increase by replaced String with CoW. (#984) (@hitenkoku) **Bug Fixes:** From 904dd04979b05bfe76500a9136fc2b98afdd3825 Mon Sep 17 00:00:00 2001 From: DastInDark <2350416+hitenkoku@users.noreply.github.com> Date: Sun, 2 Apr 2023 19:59:31 +0900 Subject: [PATCH 15/15] style: cargo fmt --- src/detections/detection.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/detections/detection.rs b/src/detections/detection.rs index 18ea31c38..205c02a69 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -388,12 +388,12 @@ impl Detection { } RuleAuthor(_) => { let author = if stored_static.multiline_flag { - rule.yaml["author"] - .as_str() - .unwrap_or("-") - .split([',', '/', ';']) - .map(|x| x.trim()) - .join("🛂🛂") + rule.yaml["author"] + .as_str() + .unwrap_or("-") + .split([',', '/', ';']) + .map(|x| x.trim()) + .join("🛂🛂") } else { rule.yaml["author"].as_str().unwrap_or("-").to_string() }; @@ -770,12 +770,12 @@ impl Detection { } RuleAuthor(_) => { let author = if stored_static.multiline_flag { - rule.yaml["author"] - .as_str() - .unwrap_or("-") - .split([',', '/', ';']) - .map(|x| x.trim()) - .join("🛂🛂") + rule.yaml["author"] + .as_str() + .unwrap_or("-") + .split([',', '/', ';']) + .map(|x| x.trim()) + .join("🛂🛂") } else { rule.yaml["author"].as_str().unwrap_or("-").to_string() };