From 8d56c447b7b5b7fff42e539b9d4ed5835fc61792 Mon Sep 17 00:00:00 2001 From: Giuliano Bellini s294739 Date: Tue, 6 Feb 2024 10:55:12 +0100 Subject: [PATCH] feat: created Service enum --- build.rs | 8 +- src/gui/pages/overview_page.rs | 4 +- src/main.rs | 2 +- src/networking/manage_packets.rs | 45 ++-- src/networking/types/app_protocol.rs | 203 +++--------------- .../types/info_address_port_pair.rs | 4 +- src/networking/types/info_traffic.rs | 4 +- src/report/get_report_entries.rs | 17 +- 8 files changed, 68 insertions(+), 219 deletions(-) diff --git a/build.rs b/build.rs index f6f1eb75..14002398 100644 --- a/build.rs +++ b/build.rs @@ -23,16 +23,16 @@ fn set_icon() { fn build_services_phf() { let path = Path::new(&env::var("OUT_DIR").unwrap()).join("services.rs"); - let mut file = BufWriter::new(File::create(&path).unwrap()); + let mut file = BufWriter::new(File::create(path).unwrap()); let mut services_map = phf_codegen::Map::new(); let input = BufReader::new(File::open("./services.txt").unwrap()); for line in input.lines().flatten() { - let mut parts = line.split("\t"); + let mut parts = line.split('\t'); let service = format!("\"{}\"", parts.next().unwrap()); let key = parts.next().unwrap().to_uppercase(); - services_map.entry(key, &*service); + services_map.entry(key, &service); } write!( @@ -41,5 +41,5 @@ fn build_services_phf() { services_map.build() ) .unwrap(); - write!(&mut file, ";\n").unwrap(); + writeln!(&mut file, ";").unwrap(); } diff --git a/src/gui/pages/overview_page.rs b/src/gui/pages/overview_page.rs index bd59febf..0afbdcab 100644 --- a/src/gui/pages/overview_page.rs +++ b/src/gui/pages/overview_page.rs @@ -48,7 +48,7 @@ get_active_filters_string, get_formatted_bytes_string_with_b, get_percentage_string, }; use crate::utils::types::icon::Icon; -use crate::{AppProtocol, ChartType, ConfigSettings, Language, RunningPage, StyleType}; +use crate::{ChartType, ConfigSettings, Language, RunningPage, Service, StyleType}; /// Computes the body of gui overview page pub fn overview_page(sniffer: &Sniffer) -> Container> { @@ -398,7 +398,7 @@ fn col_app(width: f32, sniffer: &Sniffer) -> Column<'static, Message, Renderer width * 0.88 { + if app == &Service::Unknown && incoming_bar_len + outgoing_bar_len > width * 0.88 { let incoming_proportion = incoming_bar_len / (incoming_bar_len + outgoing_bar_len); incoming_bar_len = width * 0.88 * incoming_proportion; outgoing_bar_len = width * 0.88 * (1.0 - incoming_proportion); diff --git a/src/main.rs b/src/main.rs index ca59887c..648dfeaa 100644 --- a/src/main.rs +++ b/src/main.rs @@ -19,7 +19,7 @@ use gui::styles::types::style_type::StyleType; use gui::types::runtime_data::RunTimeData; use gui::types::sniffer::Sniffer; -use networking::types::app_protocol::AppProtocol; +use networking::types::app_protocol::Service; use networking::types::byte_multiple::ByteMultiple; use networking::types::info_traffic::InfoTraffic; use networking::types::ip_version::IpVersion; diff --git a/src/networking/manage_packets.rs b/src/networking/manage_packets.rs index ee3995ab..85b7bc49 100644 --- a/src/networking/manage_packets.rs +++ b/src/networking/manage_packets.rs @@ -12,6 +12,7 @@ use crate::mmdb::country::get_country; use crate::mmdb::types::mmdb_reader::MmdbReader; use crate::networking::types::address_port_pair::AddressPortPair; +use crate::networking::types::app_protocol::Service; use crate::networking::types::data_info_host::DataInfoHost; use crate::networking::types::host::Host; use crate::networking::types::icmp_type::{IcmpType, IcmpTypeV4, IcmpTypeV6}; @@ -153,50 +154,56 @@ fn analyze_transport_header( } } -pub fn get_app_protocol(key: &AddressPortPair, traffic_direction: TrafficDirection) -> String { +pub fn get_app_protocol(key: &AddressPortPair, traffic_direction: TrafficDirection) -> Service { if key.port1.is_none() || key.port2.is_none() { - return "-".to_string(); + return Service::NotApplicable; } - let get_query_key = |port: u16, protocol: Protocol| format!("{}/{}", port, protocol); + let get_query_key = |port: u16, protocol: Protocol| format!("{port}/{protocol}"); // to return the service associated with the highest score: // score = service_is_some * (port_is_well_known + bonus_direction) - // service_is_some: 1 if some, 0 if none + // service_is_some: 1 if some, 0 if unknown // port_is_well_known: 3 if well known, 1 if not // bonus_direction: +1 assigned to remote port - let compute_service_score = |service: &&str, port: u16, bonus_direction: bool| { - let service_is_some = if service.eq(&"?") { 0 } else { 1 }; + let compute_service_score = |service: &Service, port: u16, bonus_direction: bool| { + let service_is_some = u8::from(service != &Service::Unknown); let port_is_well_known = if port < 1024 { 3 } else { 1 }; - let bonus_direction = if bonus_direction { 1 } else { 0 }; - return service_is_some * (port_is_well_known + bonus_direction); + let bonus_direction = u8::from(bonus_direction); + service_is_some * (port_is_well_known + bonus_direction) }; let port1 = key.port1.unwrap(); let port2 = key.port2.unwrap(); - let service1 = SERVICES - .get(&get_query_key(port1, key.protocol)) - .unwrap_or(&"?"); - let service2 = SERVICES - .get(&get_query_key(port2, key.protocol)) - .unwrap_or(&"?"); + let service1 = Service::from_str( + SERVICES + .get(&get_query_key(port1, key.protocol)) + .unwrap_or(&"?"), + ) + .unwrap_or_default(); + let service2 = Service::from_str( + SERVICES + .get(&get_query_key(port2, key.protocol)) + .unwrap_or(&"?"), + ) + .unwrap_or_default(); let score1 = compute_service_score( - service1, + &service1, port1, traffic_direction.ne(&TrafficDirection::Outgoing), ); let score2 = compute_service_score( - service2, + &service2, port2, traffic_direction.eq(&TrafficDirection::Outgoing), ); if score1 > score2 { - service1.to_string() + service1 } else { - service2.to_string() + service2 } } @@ -211,7 +218,7 @@ pub fn modify_or_insert_in_map( ) -> InfoAddressPortPair { let now = Local::now(); let mut traffic_direction = TrafficDirection::default(); - let mut application_protocol = "?".to_string(); + let mut application_protocol = Service::Unknown; if !info_traffic_mutex.lock().unwrap().map.contains_key(key) { // first occurrence of key diff --git a/src/networking/types/app_protocol.rs b/src/networking/types/app_protocol.rs index 0b01e6da..26c5538c 100644 --- a/src/networking/types/app_protocol.rs +++ b/src/networking/types/app_protocol.rs @@ -1,58 +1,11 @@ use std::fmt; +use std::str::FromStr; -/// Enum representing the possible observed values of application layer protocol. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)] -#[allow(clippy::upper_case_acronyms)] -pub enum AppProtocol { - /// File Transfer Protocol - FTP, - /// Secure Shell - SSH, - /// Telnet - Telnet, - /// Simple Mail Transfer Protocol - SMTP, - /// Terminal Access Controller Access-Control System - TACACS, - /// Domain Name System - DNS, - /// Dynamic Host Configuration Protocol - DHCP, - /// Trivial File Transfer Protocol - TFTP, - /// Hypertext Transfer Protocol - HTTP, - /// Post Office Protocol - POP, - /// Network Time Protocol - NTP, - /// NetBIOS - NetBIOS, - /// Post Office Protocol 3 over TLS/SSL - POP3S, - /// Internet Message Access Protocol - IMAP, - /// Simple Network Management Protocol - SNMP, - /// Border Gateway Protocol - BGP, - /// Lightweight Directory Access Protocol - LDAP, - ///Hypertext Transfer Protocol over TLS/SSL - HTTPS, - /// Lightweight Directory Access Protocol over TLS/SSL - LDAPS, - /// File Transfer Protocol over TLS/SSL - FTPS, - /// Multicast DNS - #[allow(non_camel_case_types)] - mDNS, - ///Internet Message Access Protocol over TLS/SSL - IMAPS, - /// Simple Service Discovery Protocol - SSDP, - /// Extensible Messaging and Presence Protocol | - XMPP, +/// Upper layer services. +#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)] +pub enum Service { + /// One of the known services. + Name(String), /// Not identified #[default] Unknown, @@ -60,149 +13,41 @@ pub enum AppProtocol { NotApplicable, } -/// Given an integer in the range `0..=65535`, this function returns an `Option` containing -/// the respective application protocol represented by a value of the `AppProtocol` enum. -/// Only the most common application layer protocols are considered; if a unknown port number -/// is provided, this function returns `None`. -/// -/// # Arguments -/// -/// * `port` - An integer representing the transport layer port to be mapped to -/// an application layer protocol. -/// -/// # Examples -/// -/// ``` -/// let x = from_port_to_application_protocol(25); -/// //Simple Mail Transfer Protocol -/// assert_eq!(x, Option::Some(AppProtocol::SMTP)); -/// -/// let y = from_port_to_application_protocol(1999); -/// //Unknown port-to-protocol mapping -/// assert_eq!(y, Option::None); -/// ``` -pub fn from_port_to_application_protocol(port: Option) -> AppProtocol { - if let Some(res) = port { - match res { - 20..=21 => AppProtocol::FTP, - 22 => AppProtocol::SSH, - 23 => AppProtocol::Telnet, - 25 => AppProtocol::SMTP, - 49 => AppProtocol::TACACS, - 53 => AppProtocol::DNS, - 67..=68 => AppProtocol::DHCP, - 69 => AppProtocol::TFTP, - 80 | 8080 => AppProtocol::HTTP, - 109..=110 => AppProtocol::POP, - 123 => AppProtocol::NTP, - 137..=139 => AppProtocol::NetBIOS, - 143 | 220 => AppProtocol::IMAP, - 161..=162 | 199 => AppProtocol::SNMP, - 179 => AppProtocol::BGP, - 389 => AppProtocol::LDAP, - 443 => AppProtocol::HTTPS, - 636 => AppProtocol::LDAPS, - 989..=990 => AppProtocol::FTPS, - 993 => AppProtocol::IMAPS, - 995 => AppProtocol::POP3S, - 1900 => AppProtocol::SSDP, - 5222 => AppProtocol::XMPP, - 5353 => AppProtocol::mDNS, - _ => AppProtocol::Unknown, - } - } else { - // ICMP - AppProtocol::NotApplicable - } -} - -impl fmt::Display for AppProtocol { +impl fmt::Display for Service { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.eq(&AppProtocol::Unknown) { - write!(f, "?") - } else if self.eq(&AppProtocol::NotApplicable) { - write!(f, "-") - } else { - write!(f, "{self:?}") + match self { + Service::Name(name) => write!(f, "{name}"), + Service::Unknown => write!(f, "?"), + Service::NotApplicable => write!(f, "-"), } } } -// impl AppProtocol { -// pub(crate) const ALL: [AppProtocol; 25] = [ -// AppProtocol::Unknown, -// AppProtocol::BGP, -// AppProtocol::DHCP, -// AppProtocol::DNS, -// AppProtocol::FTP, -// AppProtocol::FTPS, -// AppProtocol::HTTP, -// AppProtocol::HTTPS, -// AppProtocol::IMAP, -// AppProtocol::IMAPS, -// AppProtocol::LDAP, -// AppProtocol::LDAPS, -// AppProtocol::mDNS, -// AppProtocol::NetBIOS, -// AppProtocol::NTP, -// AppProtocol::POP, -// AppProtocol::POP3S, -// AppProtocol::SMTP, -// AppProtocol::SNMP, -// AppProtocol::SSDP, -// AppProtocol::SSH, -// AppProtocol::TACACS, -// AppProtocol::Telnet, -// AppProtocol::TFTP, -// AppProtocol::XMPP, -// ]; -// } +impl FromStr for Service { + type Err = (); + + fn from_str(s: &str) -> Result { + Ok(match s { + "" | "?" => Self::Unknown, + "-" => Self::NotApplicable, + name => Self::Name(name.to_string()), + }) + } +} #[cfg(test)] mod tests { use super::*; - #[test] - fn from_port_to_application_protocol_ftp() { - let result1 = from_port_to_application_protocol(Some(20)); - assert_eq!(AppProtocol::FTP, result1); - let result2 = from_port_to_application_protocol(Some(21)); - assert_eq!(AppProtocol::FTP, result2); - } - - #[test] - fn from_port_to_application_protocol_ssh() { - let result = from_port_to_application_protocol(Some(22)); - assert_eq!(AppProtocol::SSH, result); - } - - #[test] - fn from_port_to_application_protocol_unknown() { - let result = from_port_to_application_protocol(Some(500)); - assert_eq!(AppProtocol::Unknown, result); - } - - #[test] - fn from_port_to_application_protocol_not_applicable() { - let result = from_port_to_application_protocol(None); - assert_eq!(AppProtocol::NotApplicable, result); - } - - #[test] - fn app_protocol_display_ftp() { - let test_str = AppProtocol::FTP.to_string(); - assert_eq!(test_str, "FTP"); - } - #[test] fn app_protocol_display_unknown() { - let test_str = AppProtocol::Unknown.to_string(); + let test_str = Service::Unknown.to_string(); assert_eq!(test_str, "?"); } #[test] fn app_protocol_display_not_applicable() { - let test_str = AppProtocol::NotApplicable.to_string(); + let test_str = Service::NotApplicable.to_string(); assert_eq!(test_str, "-"); } } diff --git a/src/networking/types/info_address_port_pair.rs b/src/networking/types/info_address_port_pair.rs index f4a8e6c8..3b4f9dd9 100644 --- a/src/networking/types/info_address_port_pair.rs +++ b/src/networking/types/info_address_port_pair.rs @@ -7,7 +7,7 @@ use crate::networking::types::icmp_type::IcmpType; use crate::networking::types::traffic_direction::TrafficDirection; -use crate::AppProtocol; +use crate::Service; /// Struct useful to format the output report file and to keep track of statistics about the sniffed traffic. /// @@ -27,7 +27,7 @@ pub struct InfoAddressPortPair { /// Last occurrence of information exchange featuring the associate address:port pair as a source or destination. pub final_timestamp: DateTime, /// Application layer protocol carried by the associated address:port pair. - pub app_protocol: String, + pub app_protocol: Service, /// Determines if the connection is incoming or outgoing pub traffic_direction: TrafficDirection, /// Types of the ICMP messages exchanged, with the relative count (this is empty if not ICMP) diff --git a/src/networking/types/info_traffic.rs b/src/networking/types/info_traffic.rs index 4ba1e699..a9df2f78 100644 --- a/src/networking/types/info_traffic.rs +++ b/src/networking/types/info_traffic.rs @@ -9,7 +9,7 @@ use crate::networking::types::host::Host; use crate::networking::types::info_address_port_pair::InfoAddressPortPair; use crate::networking::types::traffic_direction::TrafficDirection; -use crate::AppProtocol; +use crate::Service; /// Struct to be shared between the threads in charge of parsing packets and update reports. pub struct InfoTraffic { @@ -34,7 +34,7 @@ pub struct InfoTraffic { /// Collection of favorite hosts that exchanged data in the last interval pub favorites_last_interval: HashSet, /// Map of the application layer protocols with their data info - pub app_protocols: HashMap, + pub app_protocols: HashMap, /// Map of the addresses waiting for a rDNS resolution; used to NOT send multiple rDNS for the same address pub addresses_waiting_resolution: HashMap, /// Map of the resolved addresses with their full rDNS value and the corresponding host diff --git a/src/report/get_report_entries.rs b/src/report/get_report_entries.rs index 88baf218..9dff4d2d 100644 --- a/src/report/get_report_entries.rs +++ b/src/report/get_report_entries.rs @@ -8,7 +8,7 @@ use crate::networking::types::host::Host; use crate::networking::types::info_address_port_pair::InfoAddressPortPair; use crate::report::types::sort_type::SortType; -use crate::{AppProtocol, ChartType, InfoTraffic, ReportSortType, Sniffer}; +use crate::{ChartType, InfoTraffic, ReportSortType, Service, Sniffer}; /// Returns the elements which satisfy the search constraints and belong to the given page, /// and the total number of elements which satisfy the search constraints @@ -87,18 +87,18 @@ pub fn get_host_entries( pub fn get_app_entries( info_traffic: &Arc>, chart_type: ChartType, -) -> Vec<(String, DataInfo)> { +) -> Vec<(Service, DataInfo)> { let info_traffic_lock = info_traffic.lock().unwrap(); - let mut sorted_vec: Vec<(&String, &DataInfo)> = info_traffic_lock + let mut sorted_vec: Vec<(&Service, &DataInfo)> = info_traffic_lock .app_protocols .iter() - .filter(|(app_protocol, _)| app_protocol != &"-") + .filter(|(app_protocol, _)| app_protocol != &&Service::NotApplicable) .collect(); sorted_vec.sort_by(|&(p1, a), &(p2, b)| { - if p1 == "?" { + if p1 == &Service::Unknown { Ordering::Greater - } else if p2 == &"?" { + } else if p2 == &Service::Unknown { Ordering::Less } else { match chart_type { @@ -108,8 +108,5 @@ pub fn get_app_entries( } }); - sorted_vec - .iter() - .map(|e| (String::from(e.0), *e.1)) - .collect() + sorted_vec.iter().map(|e| (e.0.clone(), *e.1)).collect() }