From 44c93d06843b92ecffe2778dc7f393bc11be12ae Mon Sep 17 00:00:00 2001 From: Giuliano Bellini s294739 Date: Sat, 10 Sep 2022 17:51:12 +0200 Subject: [PATCH] added output folder management and added graph description to readme --- .gitignore | 3 +++ Cargo.toml | 6 +++--- README.md | 23 +++++++++++++++++++---- src/args.rs | 6 +++--- src/main.rs | 6 +++--- src/thread_write_report_functions.rs | 21 ++++++++++++++------- 6 files changed, 45 insertions(+), 20 deletions(-) diff --git a/.gitignore b/.gitignore index 33571ae1..7456337c 100644 --- a/.gitignore +++ b/.gitignore @@ -226,4 +226,7 @@ $RECYCLE.BIN/ #graphs *.svg +#folder with reports +/sniffnet_* + .idea \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 24135aa8..64bab5bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,7 @@ name = "sniffnet" version = "0.3.2" edition = "2021" -description = "Application to sniff and filter network traffic. Generates a human-readable report of the observed packets." +description = "Framework to dig into network traffic through graphical and textual reports" repository = "https://github.com/Crirock/pdsproject" readme = "README.md" keywords = ["filter", "network", "packet", "sniffer", "parser"] @@ -19,10 +19,10 @@ chrono = "0.4.20" crossterm = "0.13.3" colored = "2.0.0" thousands = "0.2.0" -plotters = { version = "0.3.4" } +plotters = "0.3.4" -#used for debug purposes to measure time needed to write output file report +#used for debug purposes to measure time needed to write output reports #[features] #default = ["elapsed_time"] #elapsed_time = [] \ No newline at end of file diff --git a/README.md b/README.md index eb675344..1d3c554b 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Sniffnet generates a graphical representation of the filtered traffic's intensity and a detailed textual report about the observed packets. - +

@@ -112,7 +112,24 @@ ## User interactions during application execution - **Stop**: to stop the application execution, the user can type a 's' character in the terminal window. +## Graphical report structure +

+ + See details + +The graphical report consists of a svg file, constantly updated while sniffnet is running. +It is suggested to open this file with a web browser, in order to be able to comfortably refresh it. + +It reports the amount of sent (outgoing) and received (incoming) bits and packets per second. + +Note that the number of bits and packets in the graph refers to one single second even if the update frequency is different. + +The default update frequency is set to 5 seconds, but you can change it launching the application with the ```-i``` option. +Note that the default interval of 5 seconds is more suitable if the network traffic is constant and steady (e.g., large file download); +in case of intermittent traffic, you can consider using a lower time interval. + +
## Textual report structure @@ -120,8 +137,6 @@ ## Textual report structure See details -In this section is reported the structure of the output report file generated, to help the users better understand and interpret it. - ### Report header The first section of the textual report contains a header summarizing different useful information. @@ -267,7 +282,7 @@ ### Wrong command line options specification - **Already existing output folder**: there is no particular limitation on the output folder name. -However if the provided name corresponds to an already existing directory of your PC, keep in mind that the directory will be deleted and overwritten. +However, if the provided name corresponds to an already existing directory of your PC, keep in mind that the directory will be deleted and overwritten. - **Invalid transport layer protocol filter**: diff --git a/src/args.rs b/src/args.rs index 3667a5f4..2efefd98 100644 --- a/src/args.rs +++ b/src/args.rs @@ -60,11 +60,11 @@ pub struct Args { #[clap(short, long="net", value_parser, default_value = "no filter")] pub network_layer_filter: String, - /// Name of output file to contain the textual report, if omitted a default file is chosen. + /// Name of the output folder to contain reports, if omitted a default name is chosen. /// /// This option must be followed by a textual value. - #[clap(short, long, value_parser, forbid_empty_values = true, default_value = "sniffnet_report.txt")] - pub output_file: String, + #[clap(short, long, value_parser, forbid_empty_values = true, default_value = "sniffnet_report")] + pub output_folder: String, /// Filters packets on the basis of the transport layer protocol (TCP or UDP). /// diff --git a/src/main.rs b/src/main.rs index 8576f068..772fe521 100644 --- a/src/main.rs +++ b/src/main.rs @@ -56,7 +56,7 @@ fn main() { // parse arguments let args = Args::parse(); let mut adapter: String = args.adapter; - let output_file: String = args.output_file; + let output_folder: String = args.output_folder; let lowest_port = args.lowest_port; let highest_port = args.highest_port; let min_packets = args.minimum_packets; @@ -121,7 +121,7 @@ fn main() { let status_pair3 = status_pair1.clone(); println!("{}{}{}", "\r\n\n\tSniffing network adapter '".cyan().italic(), device_name.cyan().italic(), "'\r".cyan().italic()); - println!("{}{}{}", "\tThe file '".cyan().italic(), output_file.cyan().italic(), + println!("{}{}{}", "\tThe folder '".cyan().italic(), output_folder.cyan().italic(), "' will be periodically updated\r".cyan().italic()); println!("{}{}{}{}", "\r\n\tPress the key\r".cyan().bold(), "\r\n\t\t- 'p' to pause\r".yellow().bold(), "\r\n\t\t- 's' to stop\r".red().bold(), "\r\n\tthe application\n\n\r".cyan().bold()); @@ -140,7 +140,7 @@ fn main() { let thread_write_report = thread::spawn(move || { sleep_and_write_report_loop(lowest_port, highest_port, interval, min_packets, device_name, network_layer, - transport_layer, app_layer.unwrap(), output_file, + transport_layer, app_layer.unwrap(), output_folder, mutex_map2, status_pair3); }); diff --git a/src/thread_write_report_functions.rs b/src/thread_write_report_functions.rs index f6fde8dc..abfdde7b 100644 --- a/src/thread_write_report_functions.rs +++ b/src/thread_write_report_functions.rs @@ -10,7 +10,7 @@ use std::fs::File; use std::sync::{Arc, Condvar, Mutex}; use std::time::{Duration}; -use std::thread; +use std::{fs, thread}; use chrono::{Local}; use std::io::{BufWriter, Write}; use colored::Colorize; @@ -55,7 +55,7 @@ /// * `app_layer` - An AppProtocol representing the application protocol to be filtered. Specified by the user through the /// ```--app``` option. /// -/// * `output_file` - A String representing the output report file name. Specified by the user through the +/// * `output_folder` - A String representing the folder to contain the reports. Specified by the user through the /// ```-o``` option. /// /// * `info_traffic_mutex` - Struct with all the relevant info on the network traffic analyzed. @@ -63,9 +63,16 @@ /// * `status_pair` - Shared variable to check the application current status. pub fn sleep_and_write_report_loop(lowest_port: u16, highest_port: u16, interval: u64, min_packets: u128, device_name: String, network_layer: String, transport_layer: String, app_layer: AppProtocol, - output_file: String, info_traffic_mutex: Arc>, + output_folder: String, info_traffic_mutex: Arc>, status_pair: Arc<(Mutex, Condvar)>) { + if fs::create_dir(output_folder.clone()).is_err() { + fs::remove_dir_all(output_folder.clone()).unwrap(); + fs::create_dir(output_folder.clone()).unwrap(); + } + + let path_graph = &*format!("{}/bandwidth.svg", output_folder); + let mut times_report_updated: u128 = 0; let mut last_report_updated_console: u128 = 0; let time_origin = Local::now(); @@ -93,7 +100,7 @@ pub fn sleep_and_write_report_loop(lowest_port: u16, highest_port: u16, interval thread::sleep(Duration::from_secs(interval)); times_report_updated += 1; - let mut output = BufWriter::new(File::create(output_file.clone()).expect("Error creating output file\n\r")); + let mut output = BufWriter::new(File::create(format!("{}/report.txt", output_folder.clone())).expect("Error creating output file\n\r")); let info_traffic = info_traffic_mutex.lock().expect("Error acquiring mutex\n\r"); @@ -134,7 +141,7 @@ pub fn sleep_and_write_report_loop(lowest_port: u16, highest_port: u16, interval // graphs - let root_area = SVGBackend::new("bandwidth.svg", (1250, 700)).into_drawing_area(); + let root_area = SVGBackend::new(path_graph, (1250, 700)).into_drawing_area(); root_area.fill(&GREY).expect("Error drawing graph"); let (bits_area, packets_area) = root_area.split_vertically(350); let (_, footer) = root_area.split_vertically(680); @@ -284,7 +291,7 @@ pub fn sleep_and_write_report_loop(lowest_port: u16, highest_port: u16, interval } else if *status == Status::Stop { println!("{}{}{}\r", "\tThe final report is available in the file '".cyan().italic(), - output_file.clone().cyan().bold(), "'\n\n\r".cyan().italic()); + output_folder.clone().cyan().bold(), "'\n\n\r".cyan().italic()); return; } } @@ -485,7 +492,7 @@ fn get_app_count_string(app_count: HashMap, tot_packets: u128 /// /// # Arguments /// -/// * `output_file` - A String representing the output report file name. Specified by the user through the +/// * `output` - A String representing the output report file name. Specified by the user through the /// ```-o``` option. /// /// * `device_name` - A String representing the name of th network adapter to be sniffed. Specified by the user through the