diff --git a/Cargo.lock b/Cargo.lock index 62bf1e6a..dd0f2dad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,7 +63,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "46254cf2fdcdf1badb5934448c1bcbe046a56537b3987d96c51a7afc5d03f293" dependencies = [ "addr2line", - "cfg-if", + "cfg-if 0.1.10", "libc", "miniz_oxide", "object", @@ -112,6 +112,12 @@ version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +[[package]] +name = "bytes" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" + [[package]] name = "cargo_metadata" version = "0.6.4" @@ -137,6 +143,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "chrono" version = "0.4.19" @@ -198,7 +210,7 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -229,7 +241,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 0.1.10", "crossbeam-utils", "lazy_static", "maybe-uninit", @@ -244,7 +256,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 0.1.10", "lazy_static", ] @@ -412,7 +424,7 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da80be589a72651dcda34d8b35bcdc9b7254ad06325611074d9cc0fbb19f60ee" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "crc32fast", "libc", "miniz_oxide", @@ -436,7 +448,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -494,6 +506,15 @@ dependencies = [ "unindent", ] +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "itoa" version = "0.4.6" @@ -529,9 +550,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.77" +version = "0.2.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +checksum = "ba4aede83fc3617411dc6993bc8c70919750c1c257c6ca6a502aed6e0e2394ae" [[package]] name = "linked-hash-map" @@ -539,13 +560,22 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" +[[package]] +name = "lock_api" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96ffd135b2fd7b973ac026d28085defbe8983df057ced3eb4f2130b0831312" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] @@ -579,6 +609,38 @@ dependencies = [ "autocfg", ] +[[package]] +name = "mio" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2182a122f3b7f3f5329cb1972cee089ba2459a0a80a56935e6e674f096f8d839" +dependencies = [ + "libc", + "log", + "miow", + "ntapi", + "winapi", +] + +[[package]] +name = "miow" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" +dependencies = [ + "socket2", + "winapi", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", +] + [[package]] name = "num-derive" version = "0.3.2" @@ -625,6 +687,43 @@ version = "0.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ab52be62400ca80aa00285d25253d7f7c437b7375c4de678f5405d3afe82ca5" +[[package]] +name = "once_cell" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af8b08b04175473088b46763e51ee54da5f9a164bc162f615b91bc179dbf15a3" + +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if 1.0.0", + "instant", + "libc", + "redox_syscall 0.2.5", + "smallvec", + "winapi", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc0e1f259c92177c30a4c9d177246edd0a3568b25756a977d0632cf8fa37e905" + [[package]] name = "pkg-config" version = "0.3.18" @@ -804,6 +903,15 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_syscall" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +dependencies = [ + "bitflags", +] + [[package]] name = "regex" version = "1.3.9" @@ -934,6 +1042,15 @@ dependencies = [ "serde", ] +[[package]] +name = "signal-hook-registry" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16f1d0fef1604ba8f7a073c7e701f213e056707210e9020af4528e0101ce11a6" +dependencies = [ + "libc", +] + [[package]] name = "simplelog" version = "0.8.0" @@ -961,6 +1078,23 @@ dependencies = [ "walkdir", ] +[[package]] +name = "smallvec" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" + +[[package]] +name = "socket2" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "winapi", +] + [[package]] name = "strsim" version = "0.8.0" @@ -994,10 +1128,10 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "rand 0.7.3", - "redox_syscall", + "redox_syscall 0.1.57", "remove_dir_all", "winapi", ] @@ -1079,6 +1213,37 @@ dependencies = [ "winapi", ] +[[package]] +name = "tokio" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d56477f6ed99e10225f38f9f75f872f29b8b8bd8c0b946f63345bb144e9eeda" +dependencies = [ + "autocfg", + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caf7b11a536f46a809a8a9f0bb4237020f70ecbf115b842360afb127ea2fda57" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "unicode-width" version = "0.1.8" @@ -1193,11 +1358,13 @@ dependencies = [ "flate2", "lazy_static", "linked-hash-map", + "num_cpus", "quick-xml 0.17.2", "regex", "serde", "serde_derive", "serde_json", + "tokio", "yaml-rust", ] diff --git a/Cargo.toml b/Cargo.toml index 6bd34971..54dce47f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,6 +21,8 @@ lazy_static = "1.4.0" chrono = "0.4.19" yaml-rust = "0.4" linked-hash-map = "0.5.3" +tokio = { version = "1", features = ["full"] } +num_cpus = "1.13.0" [target.x86_64-pc-windows-gnu] linker = "x86_64-w64-mingw32-gcc" diff --git a/src/detections/detection.rs b/src/detections/detection.rs index 8976bfe5..64221314 100644 --- a/src/detections/detection.rs +++ b/src/detections/detection.rs @@ -4,10 +4,15 @@ use crate::detections::print::MESSAGES; use crate::detections::rule; use crate::detections::rule::RuleNode; use crate::yaml::ParseYaml; + use evtx::err; use evtx::{EvtxParser, ParserSettings, SerializedEvtxRecord}; use serde_json::{Error, Value}; -use std::path::PathBuf; +use tokio::runtime; +use tokio::{spawn, task::JoinHandle}; + +use std::{fs::File, sync::Arc}; +use std::{path::PathBuf, time::Instant}; const DIRPATH_RULES: &str = "rules"; @@ -26,74 +31,17 @@ impl Detection { } // parse rule files - let mut selection_rules = self.parse_rule_files(); - if selection_rules.is_empty() { + let rules = self.parse_rule_files(); + if rules.is_empty() { return; } - // serialize from evtx files to json - let evtx_records = self.serialize_evtx_to_jsons(evtx_files); + // transform from evtx files into json + let records = self.evtx_to_jsons(evtx_files); - // select rule files and collect message - let mut message = MESSAGES.lock().unwrap(); - selection_rules.iter_mut().for_each(|rule| { - evtx_records.iter().for_each(|event_record| { - if !rule.select(event_record) { - return; - } - - message.insert( - event_record, - rule.yaml["title"].as_str().unwrap_or("").to_string(), - rule.yaml["output"].as_str().unwrap_or("").to_string(), - ) - }); - }); - } - - // serialize evtx files to json - fn serialize_evtx_to_jsons(&self, evtx_files: Vec) -> Vec { - return evtx_files - .iter() - .filter_map(|evtx_file| { - // convert to evtx parser - match EvtxParser::from_path(evtx_file) { - Ok(parser) => Option::Some(parser), - Err(e) => { - eprintln!("{}", e); - return Option::None; - } - } - }) - .map(|mut cur| { - let mut parse_config = ParserSettings::default(); - parse_config = parse_config.separate_json_attributes(true); - cur = cur.with_configuration(parse_config); - let ret: Vec>> = - cur.records_json().collect(); - return ret; - }) - .flatten() - .filter_map(|json_record| { - // convert from evtx parser to evtx json string records - if json_record.is_ok() { - return Option::Some(json_record.unwrap()); - } else { - eprintln!("{}", json_record.unwrap_err()); - return Option::None; - } - }) - .filter_map(|json_record| { - // serialize json from json string - let result_json: Result = serde_json::from_str(&json_record.data); //// https://rust-lang-nursery.github.io/rust-cookbook/encoding/complex.html - if result_json.is_err() { - eprintln!("{}", result_json.unwrap_err()); - return Option::None; - } else { - return result_json.ok(); - } - }) - .collect(); + runtime::Runtime::new() + .unwrap() + .block_on(self.execute_rule(rules, records)); } fn parse_rule_files(&self) -> Vec { @@ -135,4 +83,187 @@ impl Detection { }) .collect(); } + + // evtxファイルをjsonに変換する。 + fn evtx_to_jsons(&mut self, evtx_files: Vec) -> Vec { + // EvtxParserを生成する。 + let evtx_parsers: Vec> = evtx_files + .iter() + .filter_map(|evtx_file| { + // convert to evtx parser + match EvtxParser::from_path(evtx_file) { + Ok(parser) => Option::Some(parser), + Err(e) => { + eprintln!("{}", e); + return Option::None; + } + } + }) + .collect(); + + let xml_records = runtime::Runtime::new() + .unwrap() + .block_on(self.evtx_to_xml(evtx_parsers)); + + return runtime::Runtime::new() + .unwrap() + .block_on(self.xml_to_json(xml_records)); + } + + // evtxファイルからxmlを生成する。 + async fn evtx_to_xml( + &mut self, + evtx_parsers: Vec>, + ) -> Vec> { + // evtx_parser.records_json()でevtxをxmlに変換するJobを作成 + let handles: Vec>>>> = evtx_parsers + .into_iter() + .map(|mut evtx_parser| { + return spawn(async move { + let mut parse_config = ParserSettings::default(); + parse_config = parse_config.separate_json_attributes(true); + evtx_parser = evtx_parser.with_configuration(parse_config); + let values = evtx_parser.records_json().collect(); + return values; + }); + }) + .collect(); + + // 作成したjobを実行し(handle.awaitの部分)、スレッドの実行時にエラーが発生した場合、標準エラー出力に出しておく + let mut ret = vec![]; + for handle in handles { + let future_result = handle.await; + if future_result.is_err() { + eprintln!("{}", future_result.unwrap_err()); + continue; + } + + ret.push(future_result.unwrap()); + } + + // xmlの変換でエラーが出た場合、標準エラー出力に出しておく + return ret + .into_iter() + .flatten() + .filter_map(|parse_result| { + if parse_result.is_err() { + eprintln!("{}", parse_result.unwrap_err()); + return Option::None; + } + + return Option::Some(parse_result.unwrap()); + }) + .collect(); + } + + async fn xml_to_json(&mut self, xml_records: Vec>) -> Vec { + // xmlからjsonに変換するJobを作成 + let handles: Vec>> = xml_records + .into_iter() + .map(|xml_record| { + return spawn(async move { + return serde_json::from_str(&xml_record.data); + }); + }) + .collect(); + + // 作成したjobを実行し(handle.awaitの部分)、スレッドの実行時にエラーが発生した場合、標準エラー出力に出しておく + let mut ret = vec![]; + for handle in handles { + let future_result = handle.await; + if future_result.is_err() { + eprintln!("{}", future_result.unwrap_err()); + continue; + } + + ret.push(future_result.unwrap()); + } + + // xmlの変換でエラーが出た場合、標準エラー出力に出しておく + return ret + .into_iter() + .filter_map(|parse_result| { + if parse_result.is_err() { + eprintln!("{}", parse_result.unwrap_err()); + return Option::None; + } + + return Option::Some(parse_result.unwrap()); + }) + .collect(); + } + + async fn execute_rule(&mut self, rules: Vec, records: Vec) { + // 排他制御と所有権共有のため、recordをRwLockとArcで囲む + // recordは不変参照(mutが不要)なので、不変参照なら複数スレッドが同時にロックを取得できるようにRwLockを用いている。 + // RwLockの代わりにMutexを使うこともできるが、これは不変参照であっても同時に1スレッドしかロックを取得できず、パフォーマンスが良くないと思う。 + let mut records_arcs = vec![]; + for record_chunk in Detection::chunks(records, num_cpus::get() * 4) { + let record_chunk_arc = Arc::new(record_chunk); + records_arcs.push(record_chunk_arc); + } + + // 所有権共有のため、ruleをArcで囲む + let rules_arc = Arc::new(rules); + + // ルール実行するスレッドを作成。 + let mut handles = vec![]; + for record_chunk_arc in &records_arcs { + let records_arc_clone = Arc::clone(&record_chunk_arc); + let rules_clones = Arc::clone(&rules_arc); + + let handle: JoinHandle> = spawn(async move { + let mut ret = vec![]; + for record in records_arc_clone.iter() { + for rule in rules_clones.iter() { + if rule.select(record) { + // TODO ここはtrue/falseじゃなくて、ruleとrecordのタプルをretにpushする実装に変更したい。 + ret.push(true); + } else { + ret.push(false); + } + } + } + return ret; + }); + handles.push(handle); + } + + // メッセージを追加する。これを上記のspawnの中でやると、ロックの取得で逆に時間がかかるので、外に出す + let mut message = MESSAGES.lock().unwrap(); + let mut handles_ite = handles.into_iter(); + for record_chunk_arc in &records_arcs { + let mut handles_ret_ite = handles_ite.next().unwrap().await.unwrap().into_iter(); + for rule in rules_arc.iter() { + for record_arc in record_chunk_arc.iter() { + if handles_ret_ite.next().unwrap() == true { + // TODO メッセージが多いと、rule.select()よりもこの処理の方が時間かかる。 + message.insert( + record_arc, + rule.yaml["title"].as_str().unwrap_or("").to_string(), + rule.yaml["output"].as_str().unwrap_or("").to_string(), + ); + } + } + } + } + } + + // 配列を指定したサイズで分割する。Vector.chunksと同じ動作をするが、Vectorの関数だとinto的なことができないので自作 + fn chunks(ary: Vec, size: usize) -> Vec> { + let arylen = ary.len(); + let mut ite = ary.into_iter(); + + let mut ret = vec![]; + for i in 0..arylen { + if i % size == 0 { + ret.push(vec![]); + ret.iter_mut().last().unwrap().push(ite.next().unwrap()); + } else { + ret.iter_mut().last().unwrap().push(ite.next().unwrap()); + } + } + + return ret; + } } diff --git a/src/detections/rule.rs b/src/detections/rule.rs index bbded052..a5c3547b 100644 --- a/src/detections/rule.rs +++ b/src/detections/rule.rs @@ -36,7 +36,7 @@ fn concat_selection_key(key_list: &Vec) -> String { }); } -fn parse_selection(yaml: &Yaml) -> Option> { +fn parse_selection(yaml: &Yaml) -> Option> { // TODO detection-selectionが存在しない場合のチェック let selection_yaml = &yaml["detection"]["selection"]; if selection_yaml.is_badvalue() { @@ -45,7 +45,10 @@ fn parse_selection(yaml: &Yaml) -> Option> { return Option::Some(parse_selection_recursively(vec![], &selection_yaml)); } -fn parse_selection_recursively(key_list: Vec, yaml: &Yaml) -> Box { +fn parse_selection_recursively( + key_list: Vec, + yaml: &Yaml, +) -> Box { if yaml.as_hash().is_some() { // 連想配列はAND条件と解釈する let yaml_hash = yaml.as_hash().unwrap(); @@ -80,6 +83,8 @@ pub struct RuleNode { detection: Option, } +unsafe impl Sync for RuleNode {} + impl RuleNode { pub fn init(&mut self) -> Result<(), Vec> { let mut errmsgs: Vec = vec![]; @@ -105,11 +110,11 @@ impl RuleNode { } } - pub fn select(&mut self, event_record: &Value) -> bool { + pub fn select(&self, event_record: &Value) -> bool { let selection = self .detection - .as_mut() - .and_then(|detect_node| detect_node.selection.as_mut()); + .as_ref() + .and_then(|detect_node| detect_node.selection.as_ref()); if selection.is_none() { return false; } @@ -120,7 +125,7 @@ impl RuleNode { // Ruleファイルのdetectionを表すノード struct DetectionNode { - pub selection: Option>, + pub selection: Option>, } impl DetectionNode { @@ -135,7 +140,7 @@ impl DetectionNode { // Ruleファイルの detection- selection配下のノードはこのtraitを実装する。 trait SelectionNode { - fn select(&mut self, event_record: &Value) -> bool; + fn select(&self, event_record: &Value) -> bool; fn init(&mut self) -> Result<(), Vec>; } @@ -144,6 +149,8 @@ struct AndSelectionNode { pub child_nodes: Vec>, } +unsafe impl Send for AndSelectionNode {} + impl AndSelectionNode { pub fn new() -> AndSelectionNode { return AndSelectionNode { @@ -153,8 +160,8 @@ impl AndSelectionNode { } impl SelectionNode for AndSelectionNode { - fn select(&mut self, event_record: &Value) -> bool { - return self.child_nodes.iter_mut().all(|child_node| { + fn select(&self, event_record: &Value) -> bool { + return self.child_nodes.iter().all(|child_node| { return child_node.select(event_record); }); } @@ -192,6 +199,8 @@ struct OrSelectionNode { pub child_nodes: Vec>, } +unsafe impl Send for OrSelectionNode {} + impl OrSelectionNode { pub fn new() -> OrSelectionNode { return OrSelectionNode { @@ -201,8 +210,8 @@ impl OrSelectionNode { } impl SelectionNode for OrSelectionNode { - fn select(&mut self, event_record: &Value) -> bool { - return self.child_nodes.iter_mut().any(|child_node| { + fn select(&self, event_record: &Value) -> bool { + return self.child_nodes.iter().any(|child_node| { return child_node.select(event_record); }); } @@ -242,6 +251,8 @@ struct LeafSelectionNode { matcher: Option>, } +unsafe impl Send for LeafSelectionNode {} + impl LeafSelectionNode { fn new(key_list: Vec, value_yaml: Yaml) -> LeafSelectionNode { return LeafSelectionNode { @@ -272,7 +283,7 @@ impl LeafSelectionNode { } impl SelectionNode for LeafSelectionNode { - fn select(&mut self, event_record: &Value) -> bool { + fn select(&self, event_record: &Value) -> bool { if self.matcher.is_none() { return false; } @@ -300,7 +311,7 @@ impl SelectionNode for LeafSelectionNode { if self.key_list.len() > 0 && self.key_list[0].to_string() == "EventData" { let values = utils::get_event_value(&"Event.EventData.Data".to_string(), event_record); if values.is_none() { - return self.matcher.as_mut().unwrap().is_match(Option::None); + return self.matcher.as_ref().unwrap().is_match(Option::None); } // 配列じゃなくて、文字列や数値等の場合は普通通りに比較する。 @@ -309,7 +320,7 @@ impl SelectionNode for LeafSelectionNode { { return self .matcher - .as_mut() + .as_ref() .unwrap() .is_match(Option::Some(eventdata_data)); } @@ -323,17 +334,17 @@ impl SelectionNode for LeafSelectionNode { .any(|ary_element| { return self .matcher - .as_mut() + .as_ref() .unwrap() .is_match(Option::Some(ary_element)); }); } else { - return self.matcher.as_mut().unwrap().is_match(Option::None); + return self.matcher.as_ref().unwrap().is_match(Option::None); } } let event_value = self.get_event_value(event_record); - return self.matcher.as_mut().unwrap().is_match(event_value); + return self.matcher.as_ref().unwrap().is_match(event_value); } fn init(&mut self) -> Result<(), Vec> { @@ -374,7 +385,7 @@ impl SelectionNode for LeafSelectionNode { trait LeafMatcher { fn is_target_key(&self, key_list: &Vec) -> bool; - fn is_match(&mut self, event_value: Option<&Value>) -> bool; + fn is_match(&self, event_value: Option<&Value>) -> bool; fn init(&mut self, key_list: &Vec, select_value: &Yaml) -> Result<(), Vec>; } @@ -449,7 +460,7 @@ impl LeafMatcher for RegexMatcher { return Result::Ok(()); } - fn is_match(&mut self, event_value: Option<&Value>) -> bool { + fn is_match(&self, event_value: Option<&Value>) -> bool { // unwrap_orの引数に""ではなく" "を指定しているのは、 // event_valueが文字列じゃない場合にis_event_value_nullの値がfalseになるように、len() == 0とならない値を指定している。 let is_event_value_null = event_value.is_none() @@ -504,7 +515,7 @@ impl LeafMatcher for MinlengthMatcher { return Result::Ok(()); } - fn is_match(&mut self, event_value: Option<&Value>) -> bool { + fn is_match(&self, event_value: Option<&Value>) -> bool { return match event_value.unwrap_or(&Value::Null) { Value::String(s) => s.len() as i64 >= self.min_len, Value::Number(n) => n.to_string().len() as i64 >= self.min_len, @@ -564,7 +575,7 @@ impl LeafMatcher for RegexesFileMatcher { return Result::Ok(()); } - fn is_match(&mut self, event_value: Option<&Value>) -> bool { + fn is_match(&self, event_value: Option<&Value>) -> bool { return match event_value.unwrap_or(&Value::Null) { Value::String(s) => !utils::check_regex(s, 0, &self.regexes_csv_content).is_empty(), Value::Number(n) => { @@ -626,7 +637,7 @@ impl LeafMatcher for WhitelistFileMatcher { return Result::Ok(()); } - fn is_match(&mut self, event_value: Option<&Value>) -> bool { + fn is_match(&self, event_value: Option<&Value>) -> bool { return match event_value.unwrap_or(&Value::Null) { Value::String(s) => utils::check_whitelist(s, &self.whitelist_csv_content), Value::Number(n) => utils::check_whitelist(&n.to_string(), &self.whitelist_csv_content),