From 636876570b3bbda6813b87294a93e15df8f0f78e Mon Sep 17 00:00:00 2001 From: Cooper Quintin Date: Tue, 20 Aug 2024 16:58:07 -0700 Subject: [PATCH 01/10] first pass at changing the UI color based on state --- bin/src/daemon.rs | 23 ++++++++++++++++++----- bin/src/diag.rs | 5 +++++ bin/src/framebuffer.rs | 1 + bin/src/server.rs | 3 ++- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/bin/src/daemon.rs b/bin/src/daemon.rs index bec950b..d87ed20 100644 --- a/bin/src/daemon.rs +++ b/bin/src/daemon.rs @@ -23,7 +23,7 @@ use rayhunter::diag_device::DiagDevice; use axum::routing::{get, post}; use axum::Router; use stats::get_qmdl_manifest; -use tokio::sync::mpsc::{self, Sender}; +use tokio::sync::mpsc::{self, Sender, Receiver}; use tokio::sync::oneshot::error::TryRecvError; use tokio::task::JoinHandle; use tokio_util::task::TaskTracker; @@ -43,11 +43,13 @@ async fn run_server( config: &config::Config, qmdl_store_lock: Arc>, server_shutdown_rx: oneshot::Receiver<()>, + ui_update_tx: Sender, diag_device_sender: Sender ) -> JoinHandle<()> { let state = Arc::new(ServerState { qmdl_store_lock, diag_device_ctrl_sender: diag_device_sender, + ui_update_sender: ui_update_tx, readonly_mode: config.readonly_mode }); @@ -123,13 +125,15 @@ fn run_ctrl_c_thread( }) } -async fn update_ui(task_tracker: &TaskTracker, config: &config::Config, mut ui_shutdown_rx: oneshot::Receiver<()>){ +async fn update_ui(task_tracker: &TaskTracker, config: &config::Config, mut ui_shutdown_rx: oneshot::Receiver<()>, mut ui_update_rx: Receiver){ static IMAGE_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/static/images/"); let display_level = config.ui_level; if display_level == 0 { info!("Invisible mode, not spawning UI."); } + let mut display_color = framebuffer::Color565::Green; + task_tracker.spawn_blocking(move || { let mut fb: Framebuffer = Framebuffer::new(); // this feels wrong, is there a more rusty way to do this? @@ -149,6 +153,14 @@ async fn update_ui(task_tracker: &TaskTracker, config: &config::Config, mut ui_ Err(e) => panic!("error receiving shutdown message: {e}") } + match ui_update_rx.try_recv() { + Ok(color) => { + display_color = color; + }, + Err(tokio::sync::mpsc::error::TryRecvError::Empty) => {}, + Err(e) => panic!("error receiving framebuffer update message: {e}") + } + match display_level { 2 => { fb.draw_gif(img.unwrap()); @@ -164,7 +176,7 @@ async fn update_ui(task_tracker: &TaskTracker, config: &config::Config, mut ui_ fb.draw_line(framebuffer::Color565::Cyan, 25); }, 1 | _ => { - fb.draw_line(framebuffer::Color565::Green, 2); + fb.draw_line(display_color, 2); }, }; sleep(Duration::from_millis(100)); @@ -195,10 +207,11 @@ async fn main() -> Result<(), RayhunterError> { run_diag_read_thread(&task_tracker, dev, rx, qmdl_store_lock.clone()); } let (ui_shutdown_tx, ui_shutdown_rx) = oneshot::channel(); + let (ui_update_tx, ui_update_rx) = mpsc::channel::(1); let (server_shutdown_tx, server_shutdown_rx) = oneshot::channel::<()>(); run_ctrl_c_thread(&task_tracker, tx.clone(), server_shutdown_tx, ui_shutdown_tx, qmdl_store_lock.clone()); - run_server(&task_tracker, &config, qmdl_store_lock.clone(), server_shutdown_rx, tx).await; - update_ui(&task_tracker, &config, ui_shutdown_rx).await; + run_server(&task_tracker, &config, qmdl_store_lock.clone(), server_shutdown_rx, ui_update_tx, tx).await; + update_ui(&task_tracker, &config, ui_shutdown_rx, ui_update_rx).await; task_tracker.close(); task_tracker.wait().await; diff --git a/bin/src/diag.rs b/bin/src/diag.rs index b7bf850..53f423b 100644 --- a/bin/src/diag.rs +++ b/bin/src/diag.rs @@ -20,6 +20,7 @@ use tokio_util::io::ReaderStream; use tokio_util::task::TaskTracker; use futures::{StreamExt, TryStreamExt}; +use crate::framebuffer; use crate::qmdl_store::RecordingStore; use crate::server::ServerState; @@ -172,6 +173,8 @@ pub async fn start_recording(State(state): State>) -> Result<(S let qmdl_writer = QmdlWriter::new(qmdl_file); state.diag_device_ctrl_sender.send(DiagDeviceCtrlMessage::StartRecording((qmdl_writer, analysis_file))).await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send stop recording message: {}", e)))?; + state.ui_update_sender.send(framebuffer::Color565::Green).await + .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send ui update message: {}", e)))?; Ok((StatusCode::ACCEPTED, "ok".to_string())) } @@ -184,6 +187,8 @@ pub async fn stop_recording(State(state): State>) -> Result<(St .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't close current qmdl entry: {}", e)))?; state.diag_device_ctrl_sender.send(DiagDeviceCtrlMessage::StopRecording).await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send stop recording message: {}", e)))?; + state.ui_update_sender.send(framebuffer::Color565::White).await + .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send ui update message: {}", e)))?; Ok((StatusCode::ACCEPTED, "ok".to_string())) } diff --git a/bin/src/framebuffer.rs b/bin/src/framebuffer.rs index 13fd614..48066a6 100644 --- a/bin/src/framebuffer.rs +++ b/bin/src/framebuffer.rs @@ -11,6 +11,7 @@ struct Dimensions { } #[allow(dead_code)] +#[derive(Copy, Clone)] pub enum Color565 { Red = 0b1111100000000000, Green = 0b0000011111100000, diff --git a/bin/src/server.rs b/bin/src/server.rs index bef6311..6f91edd 100644 --- a/bin/src/server.rs +++ b/bin/src/server.rs @@ -11,12 +11,13 @@ use tokio::sync::RwLock; use tokio_util::io::ReaderStream; use include_dir::{include_dir, Dir}; -use crate::DiagDeviceCtrlMessage; +use crate::{framebuffer, DiagDeviceCtrlMessage}; use crate::qmdl_store::RecordingStore; pub struct ServerState { pub qmdl_store_lock: Arc>, pub diag_device_ctrl_sender: Sender, + pub ui_update_sender: Sender, pub readonly_mode: bool } From f27b6327f23d6d6d2a1988c3ed284d920c96ba24 Mon Sep 17 00:00:00 2001 From: Cooper Quintin Date: Thu, 22 Aug 2024 15:55:22 -0700 Subject: [PATCH 02/10] adding flag to qmdl metadata for when hueristic is triggered --- bin/src/diag.rs | 5 +++++ bin/src/qmdl_store.rs | 7 +++++++ bin/src/stats.rs | 9 +++++++-- 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/bin/src/diag.rs b/bin/src/diag.rs index 53f423b..eb7c8ce 100644 --- a/bin/src/diag.rs +++ b/bin/src/diag.rs @@ -34,6 +34,7 @@ struct AnalysisWriter { writer: BufWriter, harness: Harness, bytes_written: usize, + has_warning: bool, } // We write our analysis results to a file immediately to minimize the amount of @@ -48,6 +49,7 @@ impl AnalysisWriter { writer: BufWriter::new(file), harness: Harness::new_with_all_analyzers(), bytes_written: 0, + has_warning: false, }; let metadata = result.harness.get_metadata(); result.write(&metadata).await?; @@ -60,6 +62,7 @@ impl AnalysisWriter { let row = self.harness.analyze_qmdl_messages(container); if !row.is_empty() { self.write(&row).await?; + self.has_warning = ! &row.analysis.is_empty() } Ok(self.bytes_written) } @@ -150,6 +153,8 @@ pub fn run_diag_read_thread( let index = qmdl_store.current_entry.expect("DiagDevice had qmdl_writer, but QmdlStore didn't have current entry???"); qmdl_store.update_entry_analysis_size(index, analysis_file_len as usize).await .expect("failed to update analysis file size"); + qmdl_store.update_entry_has_warning(index, analysis_writer.has_warning).await + .expect("failed to update analysis file has warning"); } }, Err(err) => { diff --git a/bin/src/qmdl_store.rs b/bin/src/qmdl_store.rs index accd7ce..61498b7 100644 --- a/bin/src/qmdl_store.rs +++ b/bin/src/qmdl_store.rs @@ -40,6 +40,7 @@ pub struct ManifestEntry { pub last_message_time: Option>, pub qmdl_size_bytes: usize, pub analysis_size_bytes: usize, + pub has_warning: bool, } impl ManifestEntry { @@ -51,6 +52,7 @@ impl ManifestEntry { last_message_time: None, qmdl_size_bytes: 0, analysis_size_bytes: 0, + has_warning: false, } } @@ -169,6 +171,11 @@ impl RecordingStore { self.manifest.entries[entry_index].last_message_time = Some(Local::now()); self.write_manifest().await } + + pub async fn update_entry_has_warning(&mut self, entry_index: usize, has_warning: bool) -> Result<(), RecordingStoreError> { + self.manifest.entries[entry_index].has_warning = has_warning; + self.write_manifest().await + } // Sets the given entry's analysis file size pub async fn update_entry_analysis_size(&mut self, entry_index: usize, size_bytes: usize) -> Result<(), RecordingStoreError> { diff --git a/bin/src/stats.rs b/bin/src/stats.rs index 28d5a81..96d165b 100644 --- a/bin/src/stats.rs +++ b/bin/src/stats.rs @@ -1,12 +1,12 @@ use std::sync::Arc; -use crate::qmdl_store::ManifestEntry; +use crate::{framebuffer, qmdl_store::ManifestEntry}; use crate::server::ServerState; use axum::Json; use axum::extract::State; use axum::http::StatusCode; -use log::error; +use log::{error, info}; use serde::Serialize; use tokio::process::Command; @@ -121,6 +121,11 @@ pub async fn get_qmdl_manifest(State(state): State>) -> Result< let qmdl_store = state.qmdl_store_lock.read().await; let mut entries = qmdl_store.manifest.entries.clone(); let current_entry = qmdl_store.current_entry.map(|index| entries.remove(index)); + if current_entry.clone().unwrap().has_warning { + info!("a heuristic triggered on this run!"); + state.ui_update_sender.send(framebuffer::Color565::Red).await + .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send ui update message: {}", e)))?; + } Ok(Json(ManifestStats { entries, current_entry, From 0beebdd2c61e8ce7c166238c788dbf7bfe4b0975 Mon Sep 17 00:00:00 2001 From: Cooper Quintin Date: Thu, 22 Aug 2024 15:56:09 -0700 Subject: [PATCH 03/10] update style for web page to match UI and have color alert on heuristic trigger --- bin/static/css/style.css | 5 +++++ bin/static/index.html | 1 + bin/static/js/main.js | 5 ++++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/bin/static/css/style.css b/bin/static/css/style.css index de89e27..4ef7e54 100644 --- a/bin/static/css/style.css +++ b/bin/static/css/style.css @@ -22,6 +22,11 @@ th[scope='row'] { } tr.current { + background-color: #53fe7b; + font-weight: bold; +} + +tr.warning { background-color: #fe537b; font-weight: bold; } diff --git a/bin/static/index.html b/bin/static/index.html index 878f79d..5ee0555 100644 --- a/bin/static/index.html +++ b/bin/static/index.html @@ -25,6 +25,7 @@ Date Started Date of Last Message Size (bytes) + Has Warning PCAP QMDL diff --git a/bin/static/js/main.js b/bin/static/js/main.js index fd78bee..9b46eeb 100644 --- a/bin/static/js/main.js +++ b/bin/static/js/main.js @@ -33,7 +33,7 @@ function createEntryRow(entry) { name.scope = 'row'; name.innerText = entry.name; row.appendChild(name); - for (const key of ['start_time', 'last_message_time', 'qmdl_size_bytes']) { + for (const key of ['start_time', 'last_message_time', 'qmdl_size_bytes', 'has_warning']) { const td = document.createElement('td'); td.innerText = entry[key]; row.appendChild(td); @@ -50,6 +50,9 @@ function createEntryRow(entry) { qmdl_link.innerText = 'qmdl'; qmdl_td.appendChild(qmdl_link); row.appendChild(qmdl_td); + if(entry["has_warning"]){ + row.classList.add('warning'); + } return row; } From 0043c78c3e60a97a61552199be9c53486b76a01b Mon Sep 17 00:00:00 2001 From: Cooper Quintin Date: Thu, 22 Aug 2024 16:08:48 -0700 Subject: [PATCH 04/10] add test analyzer --- lib/src/analysis/analyzer.rs | 3 +- lib/src/analysis/example_analyzer.rs | 45 ++++++++++++++++++++++++++++ lib/src/analysis/mod.rs | 1 + 3 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 lib/src/analysis/example_analyzer.rs diff --git a/lib/src/analysis/analyzer.rs b/lib/src/analysis/analyzer.rs index fbd65ef..e3d69b0 100644 --- a/lib/src/analysis/analyzer.rs +++ b/lib/src/analysis/analyzer.rs @@ -4,7 +4,7 @@ use serde::Serialize; use crate::{diag::MessagesContainer, gsmtap_parser}; -use super::{imsi_provided::ImsiProvidedAnalyzer, information_element::InformationElement, lte_downgrade::LteSib6And7DowngradeAnalyzer, null_cipher::NullCipherAnalyzer}; +use super::{imsi_provided::ImsiProvidedAnalyzer, information_element::InformationElement, lte_downgrade::LteSib6And7DowngradeAnalyzer, null_cipher::NullCipherAnalyzer, example_analyzer::ExampleAnalyzer}; /// Qualitative measure of how severe a Warning event type is. /// The levels should break down like this: @@ -102,6 +102,7 @@ impl Harness { harness.add_analyzer(Box::new(LteSib6And7DowngradeAnalyzer{})); harness.add_analyzer(Box::new(ImsiProvidedAnalyzer{})); harness.add_analyzer(Box::new(NullCipherAnalyzer{})); + harness.add_analyzer(Box::new(ExampleAnalyzer{count:0})); harness } diff --git a/lib/src/analysis/example_analyzer.rs b/lib/src/analysis/example_analyzer.rs new file mode 100644 index 0000000..24a41ea --- /dev/null +++ b/lib/src/analysis/example_analyzer.rs @@ -0,0 +1,45 @@ +use std::borrow::Cow; + +use telcom_parser::lte_rrc::{PCCH_MessageType, PCCH_MessageType_c1, PagingUE_Identity}; + +use super::analyzer::{Analyzer, Event, EventType, Severity}; +use super::information_element::{InformationElement, LteInformationElement}; + +pub struct ExampleAnalyzer{ + pub count: i32, +} + +impl Analyzer for ExampleAnalyzer{ + fn get_name(&self) -> Cow { + Cow::from("Example Analyzer") + } + + fn get_description(&self) -> Cow { + Cow::from("Always returns true, if you are seeing this you are either a developer or you are about to have problems.") + } + + fn analyze_information_element(&mut self, ie: &InformationElement) -> Option { + self.count += 1; + if self.count % 100 == 0 { + return Some(Event { + event_type: EventType::Informational , + message: "multiple of 100 events processed".to_string(), + }) + } + let InformationElement::LTE(LteInformationElement::PCCH(pcch_msg)) = ie else { + return None; + }; + let PCCH_MessageType::C1(PCCH_MessageType_c1::Paging(paging)) = &pcch_msg.message else { + return None; + }; + for record in &paging.paging_record_list.as_ref()?.0 { + if let PagingUE_Identity::S_TMSI(_) = record.ue_identity { + return Some(Event { + event_type: EventType::QualitativeWarning { severity: Severity::Low }, + message: "TMSI was provided to cell".to_string(), + }) + } + } + None + } +} diff --git a/lib/src/analysis/mod.rs b/lib/src/analysis/mod.rs index aa0b490..7a19435 100644 --- a/lib/src/analysis/mod.rs +++ b/lib/src/analysis/mod.rs @@ -3,3 +3,4 @@ pub mod information_element; pub mod lte_downgrade; pub mod imsi_provided; pub mod null_cipher; +pub mod example_analyzer; From ffd5e60f65a411c103794fb7069de7ccb9b3973f Mon Sep 17 00:00:00 2001 From: Cooper Quintin Date: Wed, 2 Oct 2024 10:58:21 -0700 Subject: [PATCH 05/10] rename example_analyzer to test_analyzer --- lib/src/analysis/analyzer.rs | 6 ++++-- lib/src/analysis/mod.rs | 2 +- lib/src/analysis/{example_analyzer.rs => test_analyzer.rs} | 4 ++-- 3 files changed, 7 insertions(+), 5 deletions(-) rename lib/src/analysis/{example_analyzer.rs => test_analyzer.rs} (96%) diff --git a/lib/src/analysis/analyzer.rs b/lib/src/analysis/analyzer.rs index e3d69b0..0fea29c 100644 --- a/lib/src/analysis/analyzer.rs +++ b/lib/src/analysis/analyzer.rs @@ -4,7 +4,7 @@ use serde::Serialize; use crate::{diag::MessagesContainer, gsmtap_parser}; -use super::{imsi_provided::ImsiProvidedAnalyzer, information_element::InformationElement, lte_downgrade::LteSib6And7DowngradeAnalyzer, null_cipher::NullCipherAnalyzer, example_analyzer::ExampleAnalyzer}; +use super::{imsi_provided::ImsiProvidedAnalyzer, information_element::InformationElement, lte_downgrade::LteSib6And7DowngradeAnalyzer, null_cipher::NullCipherAnalyzer, test_analyzer::TestAnalyzer}; /// Qualitative measure of how severe a Warning event type is. /// The levels should break down like this: @@ -102,7 +102,9 @@ impl Harness { harness.add_analyzer(Box::new(LteSib6And7DowngradeAnalyzer{})); harness.add_analyzer(Box::new(ImsiProvidedAnalyzer{})); harness.add_analyzer(Box::new(NullCipherAnalyzer{})); - harness.add_analyzer(Box::new(ExampleAnalyzer{count:0})); + if cfg!(debug_assertions) { + harness.add_analyzer(Box::new(TestAnalyzer{count:0})); + } harness } diff --git a/lib/src/analysis/mod.rs b/lib/src/analysis/mod.rs index 7a19435..a0cdd3f 100644 --- a/lib/src/analysis/mod.rs +++ b/lib/src/analysis/mod.rs @@ -3,4 +3,4 @@ pub mod information_element; pub mod lte_downgrade; pub mod imsi_provided; pub mod null_cipher; -pub mod example_analyzer; +pub mod test_analyzer; diff --git a/lib/src/analysis/example_analyzer.rs b/lib/src/analysis/test_analyzer.rs similarity index 96% rename from lib/src/analysis/example_analyzer.rs rename to lib/src/analysis/test_analyzer.rs index 24a41ea..65235af 100644 --- a/lib/src/analysis/example_analyzer.rs +++ b/lib/src/analysis/test_analyzer.rs @@ -5,11 +5,11 @@ use telcom_parser::lte_rrc::{PCCH_MessageType, PCCH_MessageType_c1, PagingUE_Ide use super::analyzer::{Analyzer, Event, EventType, Severity}; use super::information_element::{InformationElement, LteInformationElement}; -pub struct ExampleAnalyzer{ +pub struct TestAnalyzer{ pub count: i32, } -impl Analyzer for ExampleAnalyzer{ +impl Analyzer for TestAnalyzer{ fn get_name(&self) -> Cow { Cow::from("Example Analyzer") } From a66c507e43050ba70628fd3af6e95716ee1166e7 Mon Sep 17 00:00:00 2001 From: Cooper Quintin Date: Wed, 2 Oct 2024 10:59:33 -0700 Subject: [PATCH 06/10] refactor ui update to not depend on server --- bin/src/daemon.rs | 4 ++-- bin/src/diag.rs | 15 +++++++++++---- bin/src/stats.rs | 9 ++------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/bin/src/daemon.rs b/bin/src/daemon.rs index d87ed20..d939549 100644 --- a/bin/src/daemon.rs +++ b/bin/src/daemon.rs @@ -198,16 +198,16 @@ async fn main() -> Result<(), RayhunterError> { let qmdl_store_lock = Arc::new(RwLock::new(init_qmdl_store(&config).await?)); let (tx, rx) = mpsc::channel::(1); + let (ui_update_tx, ui_update_rx) = mpsc::channel::(1); if !config.readonly_mode { let mut dev = DiagDevice::new().await .map_err(RayhunterError::DiagInitError)?; dev.config_logs().await .map_err(RayhunterError::DiagInitError)?; - run_diag_read_thread(&task_tracker, dev, rx, qmdl_store_lock.clone()); + run_diag_read_thread(&task_tracker, dev, rx, ui_update_tx.clone(), qmdl_store_lock.clone()); } let (ui_shutdown_tx, ui_shutdown_rx) = oneshot::channel(); - let (ui_update_tx, ui_update_rx) = mpsc::channel::(1); let (server_shutdown_tx, server_shutdown_rx) = oneshot::channel::<()>(); run_ctrl_c_thread(&task_tracker, tx.clone(), server_shutdown_tx, ui_shutdown_tx, qmdl_store_lock.clone()); run_server(&task_tracker, &config, qmdl_store_lock.clone(), server_shutdown_rx, ui_update_tx, tx).await; diff --git a/bin/src/diag.rs b/bin/src/diag.rs index eb7c8ce..f486738 100644 --- a/bin/src/diag.rs +++ b/bin/src/diag.rs @@ -11,7 +11,7 @@ use rayhunter::diag::{DataType, MessagesContainer}; use rayhunter::diag_device::DiagDevice; use serde::Serialize; use tokio::sync::RwLock; -use tokio::sync::mpsc::Receiver; +use tokio::sync::mpsc::{Receiver, Sender}; use rayhunter::qmdl::QmdlWriter; use log::{debug, error, info}; use tokio::fs::File; @@ -58,13 +58,13 @@ impl AnalysisWriter { // Runs the analysis harness on the given container, serializing the results // to the analysis file and returning the file's new length. - pub async fn analyze(&mut self, container: MessagesContainer) -> Result { + pub async fn analyze(&mut self, container: MessagesContainer) -> Result<(usize, bool), std::io::Error> { let row = self.harness.analyze_qmdl_messages(container); if !row.is_empty() { self.write(&row).await?; self.has_warning = ! &row.analysis.is_empty() } - Ok(self.bytes_written) + Ok((self.bytes_written, self.has_warning)) } async fn write(&mut self, value: &T) -> Result<(), std::io::Error> { @@ -87,6 +87,7 @@ pub fn run_diag_read_thread( task_tracker: &TaskTracker, mut dev: DiagDevice, mut qmdl_file_rx: Receiver, + ui_update_sender: Sender, qmdl_store_lock: Arc> ) { task_tracker.spawn(async move { @@ -147,8 +148,14 @@ pub fn run_diag_read_thread( } if let Some(analysis_writer) = maybe_analysis_writer.as_mut() { - let analysis_file_len = analysis_writer.analyze(container).await + let analysis_output = analysis_writer.analyze(container).await .expect("failed to analyze container"); + let (analysis_file_len, heuristic_warning) = analysis_output; + if heuristic_warning { + info!("a heuristic triggered on this run!"); + ui_update_sender.send(framebuffer::Color565::Red).await + .expect("couldn't send ui update message: {}"); + } let mut qmdl_store = qmdl_store_lock.write().await; let index = qmdl_store.current_entry.expect("DiagDevice had qmdl_writer, but QmdlStore didn't have current entry???"); qmdl_store.update_entry_analysis_size(index, analysis_file_len as usize).await diff --git a/bin/src/stats.rs b/bin/src/stats.rs index 96d165b..28d5a81 100644 --- a/bin/src/stats.rs +++ b/bin/src/stats.rs @@ -1,12 +1,12 @@ use std::sync::Arc; -use crate::{framebuffer, qmdl_store::ManifestEntry}; +use crate::qmdl_store::ManifestEntry; use crate::server::ServerState; use axum::Json; use axum::extract::State; use axum::http::StatusCode; -use log::{error, info}; +use log::error; use serde::Serialize; use tokio::process::Command; @@ -121,11 +121,6 @@ pub async fn get_qmdl_manifest(State(state): State>) -> Result< let qmdl_store = state.qmdl_store_lock.read().await; let mut entries = qmdl_store.manifest.entries.clone(); let current_entry = qmdl_store.current_entry.map(|index| entries.remove(index)); - if current_entry.clone().unwrap().has_warning { - info!("a heuristic triggered on this run!"); - state.ui_update_sender.send(framebuffer::Color565::Red).await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send ui update message: {}", e)))?; - } Ok(Json(ManifestStats { entries, current_entry, From c72e7012d1215c44b2fea1e11342dfb48ea26fa0 Mon Sep 17 00:00:00 2001 From: Cooper Quintin Date: Wed, 2 Oct 2024 14:19:33 -0700 Subject: [PATCH 07/10] refactor to pass around color instead of display state for framebuffer channel --- bin/src/daemon.rs | 10 +++++----- bin/src/diag.rs | 8 ++++---- bin/src/framebuffer.rs | 14 ++++++++++++++ bin/src/server.rs | 2 +- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/bin/src/daemon.rs b/bin/src/daemon.rs index d939549..a98b41c 100644 --- a/bin/src/daemon.rs +++ b/bin/src/daemon.rs @@ -43,7 +43,7 @@ async fn run_server( config: &config::Config, qmdl_store_lock: Arc>, server_shutdown_rx: oneshot::Receiver<()>, - ui_update_tx: Sender, + ui_update_tx: Sender, diag_device_sender: Sender ) -> JoinHandle<()> { let state = Arc::new(ServerState { @@ -125,7 +125,7 @@ fn run_ctrl_c_thread( }) } -async fn update_ui(task_tracker: &TaskTracker, config: &config::Config, mut ui_shutdown_rx: oneshot::Receiver<()>, mut ui_update_rx: Receiver){ +async fn update_ui(task_tracker: &TaskTracker, config: &config::Config, mut ui_shutdown_rx: oneshot::Receiver<()>, mut ui_update_rx: Receiver){ static IMAGE_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/static/images/"); let display_level = config.ui_level; if display_level == 0 { @@ -154,8 +154,8 @@ async fn update_ui(task_tracker: &TaskTracker, config: &config::Config, mut ui_ } match ui_update_rx.try_recv() { - Ok(color) => { - display_color = color; + Ok(state) => { + display_color = Framebuffer::get_color_from_state(state); }, Err(tokio::sync::mpsc::error::TryRecvError::Empty) => {}, Err(e) => panic!("error receiving framebuffer update message: {e}") @@ -198,7 +198,7 @@ async fn main() -> Result<(), RayhunterError> { let qmdl_store_lock = Arc::new(RwLock::new(init_qmdl_store(&config).await?)); let (tx, rx) = mpsc::channel::(1); - let (ui_update_tx, ui_update_rx) = mpsc::channel::(1); + let (ui_update_tx, ui_update_rx) = mpsc::channel::(1); if !config.readonly_mode { let mut dev = DiagDevice::new().await .map_err(RayhunterError::DiagInitError)?; diff --git a/bin/src/diag.rs b/bin/src/diag.rs index f486738..9a3bd10 100644 --- a/bin/src/diag.rs +++ b/bin/src/diag.rs @@ -87,7 +87,7 @@ pub fn run_diag_read_thread( task_tracker: &TaskTracker, mut dev: DiagDevice, mut qmdl_file_rx: Receiver, - ui_update_sender: Sender, + ui_update_sender: Sender, qmdl_store_lock: Arc> ) { task_tracker.spawn(async move { @@ -153,7 +153,7 @@ pub fn run_diag_read_thread( let (analysis_file_len, heuristic_warning) = analysis_output; if heuristic_warning { info!("a heuristic triggered on this run!"); - ui_update_sender.send(framebuffer::Color565::Red).await + ui_update_sender.send(framebuffer::DisplayState::WarningDetected).await .expect("couldn't send ui update message: {}"); } let mut qmdl_store = qmdl_store_lock.write().await; @@ -185,7 +185,7 @@ pub async fn start_recording(State(state): State>) -> Result<(S let qmdl_writer = QmdlWriter::new(qmdl_file); state.diag_device_ctrl_sender.send(DiagDeviceCtrlMessage::StartRecording((qmdl_writer, analysis_file))).await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send stop recording message: {}", e)))?; - state.ui_update_sender.send(framebuffer::Color565::Green).await + state.ui_update_sender.send(framebuffer::DisplayState::Recording).await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send ui update message: {}", e)))?; Ok((StatusCode::ACCEPTED, "ok".to_string())) } @@ -199,7 +199,7 @@ pub async fn stop_recording(State(state): State>) -> Result<(St .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't close current qmdl entry: {}", e)))?; state.diag_device_ctrl_sender.send(DiagDeviceCtrlMessage::StopRecording).await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send stop recording message: {}", e)))?; - state.ui_update_sender.send(framebuffer::Color565::White).await + state.ui_update_sender.send(framebuffer::DisplayState::Paused).await .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, format!("couldn't send ui update message: {}", e)))?; Ok((StatusCode::ACCEPTED, "ok".to_string())) } diff --git a/bin/src/framebuffer.rs b/bin/src/framebuffer.rs index 48066a6..d98f39f 100644 --- a/bin/src/framebuffer.rs +++ b/bin/src/framebuffer.rs @@ -23,6 +23,12 @@ pub enum Color565 { Pink = 0b1111010010011111, } +pub enum DisplayState { + Recording, + Paused, + WarningDetected, +} + #[derive(Copy, Clone)] pub struct Framebuffer<'a> { dimensions: Dimensions, @@ -37,6 +43,14 @@ impl Framebuffer<'_>{ } } + pub fn get_color_from_state(state: DisplayState) -> Color565 { + match state { + DisplayState::Paused => Color565::White, + DisplayState::Recording => Color565::Green, + DisplayState::WarningDetected => Color565::Red, + } + } + fn write(&mut self, img: DynamicImage) { let mut width = img.width(); let mut height = img.height(); diff --git a/bin/src/server.rs b/bin/src/server.rs index 6f91edd..028df21 100644 --- a/bin/src/server.rs +++ b/bin/src/server.rs @@ -17,7 +17,7 @@ use crate::qmdl_store::RecordingStore; pub struct ServerState { pub qmdl_store_lock: Arc>, pub diag_device_ctrl_sender: Sender, - pub ui_update_sender: Sender, + pub ui_update_sender: Sender, pub readonly_mode: bool } From 2428d015750e25a0d4eb8d1e914b6c87a77d3c5a Mon Sep 17 00:00:00 2001 From: Cooper Quintin Date: Wed, 2 Oct 2024 16:00:48 -0700 Subject: [PATCH 08/10] add debug feature flag for test analyzer --- lib/Cargo.toml | 3 +++ lib/src/analysis/analyzer.rs | 5 ++++- make.sh | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/Cargo.toml b/lib/Cargo.toml index fc2c5e5..13ab783 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -24,3 +24,6 @@ tokio = { version = "1.35.1", features = ["full"] } futures-core = "0.3.30" futures = "0.3.30" serde = { version = "1.0.197", features = ["derive"] } + +[features] +debug = [] \ No newline at end of file diff --git a/lib/src/analysis/analyzer.rs b/lib/src/analysis/analyzer.rs index 0fea29c..d76e63f 100644 --- a/lib/src/analysis/analyzer.rs +++ b/lib/src/analysis/analyzer.rs @@ -1,6 +1,7 @@ use std::borrow::Cow; use chrono::{DateTime, FixedOffset}; use serde::Serialize; +use log::warn; use crate::{diag::MessagesContainer, gsmtap_parser}; @@ -102,7 +103,9 @@ impl Harness { harness.add_analyzer(Box::new(LteSib6And7DowngradeAnalyzer{})); harness.add_analyzer(Box::new(ImsiProvidedAnalyzer{})); harness.add_analyzer(Box::new(NullCipherAnalyzer{})); - if cfg!(debug_assertions) { + + #[cfg(feature="debug")] { + warn!("Loading test analyzers!"); harness.add_analyzer(Box::new(TestAnalyzer{count:0})); } harness diff --git a/make.sh b/make.sh index 96f6fd7..5af2e25 100755 --- a/make.sh +++ b/make.sh @@ -1,4 +1,4 @@ #!/bin/sh -cargo build --release --target="armv7-unknown-linux-gnueabihf" +cargo build --release --target="armv7-unknown-linux-gnueabihf" #--features debug adb push target/armv7-unknown-linux-gnueabihf/release/rayhunter-daemon /data/rayhunter/rayhunter-daemon adb shell '/bin/rootshell -c "/etc/init.d/rayhunter_daemon restart"' From 16ef97980ccdf3384c4a6f46f9d4cbfbf0f2cabb Mon Sep 17 00:00:00 2001 From: Cooper Quintin Date: Wed, 2 Oct 2024 16:12:04 -0700 Subject: [PATCH 09/10] remove warning status from qmdl manifest --- bin/src/diag.rs | 2 -- bin/src/qmdl_store.rs | 7 ------- bin/static/index.html | 1 - bin/static/js/main.js | 5 +---- lib/src/analysis/analyzer.rs | 9 +++++++-- 5 files changed, 8 insertions(+), 16 deletions(-) diff --git a/bin/src/diag.rs b/bin/src/diag.rs index 9a3bd10..00085ca 100644 --- a/bin/src/diag.rs +++ b/bin/src/diag.rs @@ -160,8 +160,6 @@ pub fn run_diag_read_thread( let index = qmdl_store.current_entry.expect("DiagDevice had qmdl_writer, but QmdlStore didn't have current entry???"); qmdl_store.update_entry_analysis_size(index, analysis_file_len as usize).await .expect("failed to update analysis file size"); - qmdl_store.update_entry_has_warning(index, analysis_writer.has_warning).await - .expect("failed to update analysis file has warning"); } }, Err(err) => { diff --git a/bin/src/qmdl_store.rs b/bin/src/qmdl_store.rs index 61498b7..accd7ce 100644 --- a/bin/src/qmdl_store.rs +++ b/bin/src/qmdl_store.rs @@ -40,7 +40,6 @@ pub struct ManifestEntry { pub last_message_time: Option>, pub qmdl_size_bytes: usize, pub analysis_size_bytes: usize, - pub has_warning: bool, } impl ManifestEntry { @@ -52,7 +51,6 @@ impl ManifestEntry { last_message_time: None, qmdl_size_bytes: 0, analysis_size_bytes: 0, - has_warning: false, } } @@ -171,11 +169,6 @@ impl RecordingStore { self.manifest.entries[entry_index].last_message_time = Some(Local::now()); self.write_manifest().await } - - pub async fn update_entry_has_warning(&mut self, entry_index: usize, has_warning: bool) -> Result<(), RecordingStoreError> { - self.manifest.entries[entry_index].has_warning = has_warning; - self.write_manifest().await - } // Sets the given entry's analysis file size pub async fn update_entry_analysis_size(&mut self, entry_index: usize, size_bytes: usize) -> Result<(), RecordingStoreError> { diff --git a/bin/static/index.html b/bin/static/index.html index 5ee0555..878f79d 100644 --- a/bin/static/index.html +++ b/bin/static/index.html @@ -25,7 +25,6 @@ Date Started Date of Last Message Size (bytes) - Has Warning PCAP QMDL diff --git a/bin/static/js/main.js b/bin/static/js/main.js index 9b46eeb..fd78bee 100644 --- a/bin/static/js/main.js +++ b/bin/static/js/main.js @@ -33,7 +33,7 @@ function createEntryRow(entry) { name.scope = 'row'; name.innerText = entry.name; row.appendChild(name); - for (const key of ['start_time', 'last_message_time', 'qmdl_size_bytes', 'has_warning']) { + for (const key of ['start_time', 'last_message_time', 'qmdl_size_bytes']) { const td = document.createElement('td'); td.innerText = entry[key]; row.appendChild(td); @@ -50,9 +50,6 @@ function createEntryRow(entry) { qmdl_link.innerText = 'qmdl'; qmdl_td.appendChild(qmdl_link); row.appendChild(qmdl_td); - if(entry["has_warning"]){ - row.classList.add('warning'); - } return row; } diff --git a/lib/src/analysis/analyzer.rs b/lib/src/analysis/analyzer.rs index d76e63f..a4a962e 100644 --- a/lib/src/analysis/analyzer.rs +++ b/lib/src/analysis/analyzer.rs @@ -1,11 +1,16 @@ use std::borrow::Cow; use chrono::{DateTime, FixedOffset}; use serde::Serialize; -use log::warn; use crate::{diag::MessagesContainer, gsmtap_parser}; -use super::{imsi_provided::ImsiProvidedAnalyzer, information_element::InformationElement, lte_downgrade::LteSib6And7DowngradeAnalyzer, null_cipher::NullCipherAnalyzer, test_analyzer::TestAnalyzer}; +use super::{imsi_provided::ImsiProvidedAnalyzer, information_element::InformationElement, lte_downgrade::LteSib6And7DowngradeAnalyzer, null_cipher::NullCipherAnalyzer}; + +#[cfg(feature="debug")] + use log::warn; + +#[cfg(feature="debug")] + use super::test_analyzer::TestAnalyzer; /// Qualitative measure of how severe a Warning event type is. /// The levels should break down like this: From 5f505def8771c02ec660592397ded8818e07118d Mon Sep 17 00:00:00 2001 From: Cooper Quintin Date: Wed, 2 Oct 2024 16:19:13 -0700 Subject: [PATCH 10/10] dont keep has warning around --- bin/src/diag.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/bin/src/diag.rs b/bin/src/diag.rs index 00085ca..564679a 100644 --- a/bin/src/diag.rs +++ b/bin/src/diag.rs @@ -34,7 +34,6 @@ struct AnalysisWriter { writer: BufWriter, harness: Harness, bytes_written: usize, - has_warning: bool, } // We write our analysis results to a file immediately to minimize the amount of @@ -49,7 +48,6 @@ impl AnalysisWriter { writer: BufWriter::new(file), harness: Harness::new_with_all_analyzers(), bytes_written: 0, - has_warning: false, }; let metadata = result.harness.get_metadata(); result.write(&metadata).await?; @@ -62,9 +60,8 @@ impl AnalysisWriter { let row = self.harness.analyze_qmdl_messages(container); if !row.is_empty() { self.write(&row).await?; - self.has_warning = ! &row.analysis.is_empty() } - Ok((self.bytes_written, self.has_warning)) + Ok((self.bytes_written, ! &row.analysis.is_empty())) } async fn write(&mut self, value: &T) -> Result<(), std::io::Error> {