check: crawl input dir for QMDL, update to new analysis format

This commit is contained in:
Will Greenberg
2025-07-14 13:09:51 -07:00
committed by Cooper Quintin
parent 0915103ede
commit e81df18315
3 changed files with 67 additions and 49 deletions
Generated
+20
View File
@@ -2374,6 +2374,7 @@ dependencies = [
"rayhunter", "rayhunter",
"simple_logger", "simple_logger",
"tokio", "tokio",
"walkdir",
] ]
[[package]] [[package]]
@@ -2583,6 +2584,15 @@ version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
[[package]]
name = "same-file"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.2.0" version = "1.2.0"
@@ -3233,6 +3243,16 @@ version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]]
name = "walkdir"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [
"same-file",
"winapi-util",
]
[[package]] [[package]]
name = "want" name = "want"
version = "0.3.1" version = "0.3.1"
+13
View File
@@ -0,0 +1,13 @@
[package]
name = "rayhunter-check"
version = "0.4.0"
edition = "2024"
[dependencies]
rayhunter = { path = "../lib" }
futures = { version = "0.3.30", default-features = false }
log = "0.4.20"
tokio = { version = "1.44.2", default-features = false, features = ["fs", "signal", "process", "rt-multi-thread"] }
clap = { version = "4.5.2", features = ["derive"] }
simple_logger = "5.0.0"
walkdir = "2.5.0"
+34 -49
View File
@@ -1,6 +1,6 @@
use clap::Parser; use clap::Parser;
use futures::TryStreamExt; use futures::TryStreamExt;
use log::{info, warn}; use log::{error, info, warn};
use rayhunter::{ use rayhunter::{
analysis::analyzer::{AnalyzerConfig, EventType, Harness}, analysis::analyzer::{AnalyzerConfig, EventType, Harness},
diag::DataType, diag::DataType,
@@ -9,34 +9,27 @@ use rayhunter::{
qmdl::QmdlReader, qmdl::QmdlReader,
}; };
use std::{collections::HashMap, future, path::PathBuf, pin::pin}; use std::{collections::HashMap, future, path::PathBuf, pin::pin};
use tokio::fs::{File, metadata, read_dir}; use tokio::fs::File;
use walkdir::WalkDir;
mod dummy_analyzer;
#[derive(Parser, Debug)] #[derive(Parser, Debug)]
#[command(version, about)] #[command(version, about)]
struct Args { struct Args {
#[arg(short = 'p', long)] #[arg(short = 'p', long)]
qmdl_path: PathBuf, path: PathBuf,
#[arg(short = 'c', long)] #[arg(long)]
pcapify: bool, pcapify: bool,
#[arg(long)] #[arg(long)]
show_skipped: bool, show_skipped: bool,
#[arg(long)]
enable_dummy_analyzer: bool,
#[arg(short, long)] #[arg(short, long)]
verbose: bool, verbose: bool,
} }
async fn analyze_file(enable_dummy_analyzer: bool, qmdl_path: &str, show_skipped: bool) { async fn analyze_file(qmdl_path: &str, show_skipped: bool) {
let mut harness = Harness::new_with_config(&AnalyzerConfig::default()); let mut harness = Harness::new_with_config(&AnalyzerConfig::default());
if enable_dummy_analyzer {
harness.add_analyzer(Box::new(dummy_analyzer::TestAnalyzer { count: 0 }));
}
let qmdl_file = &mut File::open(&qmdl_path).await.expect("failed to open file"); let qmdl_file = &mut File::open(&qmdl_path).await.expect("failed to open file");
let file_size = qmdl_file let file_size = qmdl_file
.metadata() .metadata()
@@ -58,26 +51,27 @@ async fn analyze_file(enable_dummy_analyzer: bool, qmdl_path: &str, show_skipped
.await .await
.expect("failed getting QMDL container") .expect("failed getting QMDL container")
{ {
let row = harness.analyze_qmdl_messages(container); for row in harness.analyze_qmdl_messages(container) {
total_messages += 1; total_messages += 1;
for reason in row.skipped_message_reasons { if let Some(reason) = row.skipped_message_reason {
*skipped_reasons.entry(reason).or_insert(0) += 1; *skipped_reasons.entry(reason).or_insert(0) += 1;
skipped += 1; skipped += 1;
} continue;
for analysis in row.analysis { }
for maybe_event in analysis.events { for maybe_event in row.events {
let Some(event) = maybe_event else { continue }; let Some(event) = maybe_event else { continue };
let Some(timestamp) = row.packet_timestamp else { continue };
match event.event_type { match event.event_type {
EventType::Informational => { EventType::Informational => {
info!( info!(
"{}: INFO - {} {}", "{}: INFO - {} {}",
qmdl_path, analysis.timestamp, event.message, qmdl_path, timestamp, event.message,
); );
} }
EventType::QualitativeWarning { severity } => { EventType::QualitativeWarning { severity } => {
warn!( warn!(
"{}: WARNING (Severity: {:?}) - {} {}", "{}: WARNING (Severity: {:?}) - {} {}",
qmdl_path, severity, analysis.timestamp, event.message, qmdl_path, severity, timestamp, event.message,
); );
warnings += 1; warnings += 1;
} }
@@ -144,36 +138,27 @@ async fn main() {
.unwrap(); .unwrap();
info!("Analyzers:"); info!("Analyzers:");
let mut harness = Harness::new_with_config(&AnalyzerConfig::default()); let harness = Harness::new_with_config(&AnalyzerConfig::default());
if args.enable_dummy_analyzer {
harness.add_analyzer(Box::new(dummy_analyzer::TestAnalyzer { count: 0 }));
}
for analyzer in harness.get_metadata().analyzers { for analyzer in harness.get_metadata().analyzers {
info!(" - {}: {}", analyzer.name, analyzer.description); info!(" - {}: {} (v{})", analyzer.name, analyzer.description, analyzer.version);
} }
let metadata = metadata(&args.qmdl_path) for maybe_entry in WalkDir::new(&args.path) {
.await let Ok(entry) = maybe_entry else {
.expect("failed to get metadata"); error!("failed to open dir entry {:?}", maybe_entry);
if metadata.is_dir() { continue;
let mut dir = read_dir(&args.qmdl_path).await.expect("failed to read dir"); };
while let Some(entry) = dir.next_entry().await.expect("failed to get entry") { let name = entry.file_name();
let name = entry.file_name(); let name_str = name.to_str().unwrap();
let name_str = name.to_str().unwrap(); // instead of relying on the QMDL extension, can we check if a file is
if name_str.ends_with(".qmdl") { // QMDL by inspecting the contents?
let path = entry.path(); if name_str.ends_with(".qmdl") {
let path_str = path.to_str().unwrap(); let path = entry.path();
analyze_file(args.enable_dummy_analyzer, path_str, args.show_skipped).await; let path_str = path.to_str().unwrap();
if args.pcapify { analyze_file(path_str, args.show_skipped).await;
pcapify(&path).await; if args.pcapify {
} pcapify(&path.to_path_buf()).await;
} }
} }
} else {
let path = args.qmdl_path.to_str().unwrap();
analyze_file(args.enable_dummy_analyzer, path, args.show_skipped).await;
if args.pcapify {
pcapify(&args.qmdl_path).await;
}
} }
} }