mirror of
https://github.com/GyulyVGC/sniffnet.git
synced 2025-12-23 22:29:01 -05:00
feat: created Service enum
This commit is contained in:
8
build.rs
8
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();
|
||||
}
|
||||
|
||||
@@ -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<Message, Renderer<StyleType>> {
|
||||
@@ -398,7 +398,7 @@ fn col_app(width: f32, sniffer: &Sniffer) -> Column<'static, Message, Renderer<S
|
||||
);
|
||||
|
||||
// check if Unknown is longer than the first entry
|
||||
if app == &"?" && incoming_bar_len + outgoing_bar_len > 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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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<AppProtocol>` 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<u16>) -> 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<Self, Self::Err> {
|
||||
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, "-");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Local>,
|
||||
/// 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)
|
||||
|
||||
@@ -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<Host>,
|
||||
/// Map of the application layer protocols with their data info
|
||||
pub app_protocols: HashMap<String, DataInfo>,
|
||||
pub app_protocols: HashMap<Service, DataInfo>,
|
||||
/// Map of the addresses waiting for a rDNS resolution; used to NOT send multiple rDNS for the same address
|
||||
pub addresses_waiting_resolution: HashMap<String, DataInfo>,
|
||||
/// Map of the resolved addresses with their full rDNS value and the corresponding host
|
||||
|
||||
@@ -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<Mutex<InfoTraffic>>,
|
||||
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()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user