diff --git a/resources/countries_flags/4x3/question-mark-svgrepo-com.svg b/resources/countries_flags/4x3/question-mark-svgrepo-com.svg
deleted file mode 100644
index c4b3abd1..00000000
--- a/resources/countries_flags/4x3/question-mark-svgrepo-com.svg
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
diff --git a/resources/countries_flags/4x3/zz-broadcast.svg b/resources/countries_flags/4x3/zz-broadcast.svg
new file mode 100644
index 00000000..22a3fba1
--- /dev/null
+++ b/resources/countries_flags/4x3/zz-broadcast.svg
@@ -0,0 +1,13 @@
+
+
\ No newline at end of file
diff --git a/resources/countries_flags/4x3/zz-home.svg b/resources/countries_flags/4x3/zz-home.svg
new file mode 100644
index 00000000..bf2147d6
--- /dev/null
+++ b/resources/countries_flags/4x3/zz-home.svg
@@ -0,0 +1,16 @@
+
+
+
\ No newline at end of file
diff --git a/resources/countries_flags/4x3/zz-multicast.svg b/resources/countries_flags/4x3/zz-multicast.svg
new file mode 100644
index 00000000..f11e6473
--- /dev/null
+++ b/resources/countries_flags/4x3/zz-multicast.svg
@@ -0,0 +1,11 @@
+
+
\ No newline at end of file
diff --git a/resources/countries_flags/4x3/zz-unknown.svg b/resources/countries_flags/4x3/zz-unknown.svg
new file mode 100644
index 00000000..efb9c0a0
--- /dev/null
+++ b/resources/countries_flags/4x3/zz-unknown.svg
@@ -0,0 +1,17 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/gui/pages/inspect_page.rs b/src/gui/pages/inspect_page.rs
index 85067292..8ebde945 100644
--- a/src/gui/pages/inspect_page.rs
+++ b/src/gui/pages/inspect_page.rs
@@ -5,7 +5,7 @@ use crate::gui::styles::types::element_type::ElementType;
use crate::gui::styles::types::style_tuple::StyleTuple;
use crate::gui::types::message::Message;
use crate::report::get_report_entries::get_searched_entries;
-use crate::utils::countries::{get_flag_from_country_code, FLAGS_WIDTH_SMALL};
+use crate::utils::countries::{get_flag_tooltip, FLAGS_WIDTH_SMALL};
use crate::utils::formatted_strings::{get_connection_color, get_open_report_tooltip};
use crate::{Language, RunningPage, Sniffer, StyleType};
use iced::widget::{Button, Column, Container, Row, Scrollable, Text, Tooltip};
@@ -66,33 +66,27 @@ pub fn inspect_page(sniffer: &Sniffer) -> Container {
for index in &search_results {
let info_traffic_lock = sniffer.info_traffic.lock().unwrap();
let key_val = info_traffic_lock.map.get_index(*index).unwrap();
- let entry_color = get_connection_color(key_val.1.traffic_type, sniffer.style);
- let mut entry_row = Row::new().align_items(Alignment::Center).push(
- Text::new(format!(
- " {}{}",
- key_val.0.print_gui(),
- key_val.1.print_gui()
- ))
- .style(iced::theme::Text::Color(entry_color))
- .font(SARASA_MONO_SC_BOLD),
- );
- if key_val.1.country.is_empty() {
- entry_row = entry_row
- .push(
- Text::new("?")
- .width(Length::Fixed(FLAGS_WIDTH_SMALL))
- .style(iced::theme::Text::Color(entry_color))
- .font(SARASA_MONO_SC_BOLD),
- )
- .push(Text::new(" "));
- } else {
- entry_row = entry_row
- .push(get_flag_from_country_code(
- &key_val.1.country,
- FLAGS_WIDTH_SMALL,
+ let entry_color = get_connection_color(key_val.1.traffic_direction, sniffer.style);
+ let entry_row = Row::new()
+ .align_items(Alignment::Center)
+ .push(
+ Text::new(format!(
+ " {}{}",
+ key_val.0.print_gui(),
+ key_val.1.print_gui()
))
- .push(Text::new(" "));
- }
+ .style(iced::theme::Text::Color(entry_color))
+ .font(SARASA_MONO_SC_BOLD),
+ )
+ .push(get_flag_tooltip(
+ &key_val.1.country,
+ FLAGS_WIDTH_SMALL,
+ key_val.1.is_local,
+ key_val.1.traffic_type,
+ sniffer.language,
+ sniffer.style,
+ ))
+ .push(Text::new(" "));
scroll_report = scroll_report.push(
button(entry_row)
diff --git a/src/gui/pages/notifications_page.rs b/src/gui/pages/notifications_page.rs
index 852a6437..3b34a57e 100644
--- a/src/gui/pages/notifications_page.rs
+++ b/src/gui/pages/notifications_page.rs
@@ -24,7 +24,7 @@ use crate::translations::translations::{
packets_exceeded_translation, packets_exceeded_value_translation, per_second_translation,
threshold_translation,
};
-use crate::utils::countries::{get_flag_from_country_code, FLAGS_WIDTH_BIG};
+use crate::utils::countries::{get_flag_tooltip, FLAGS_WIDTH_BIG};
use crate::utils::formatted_strings::get_formatted_bytes_string;
use crate::{Language, RunningPage, Sniffer, StyleType};
@@ -187,9 +187,8 @@ fn packets_notification_log(
Tooltip::new(
Text::new("e").font(ICONS).size(80),
packets_exceeded_translation(language),
- Position::Left,
+ Position::FollowCursor,
)
- .gap(5)
.font(font)
.style(>::into(
StyleTuple(style, ElementType::Tooltip),
@@ -266,9 +265,8 @@ fn bytes_notification_log(
Tooltip::new(
Text::new("f").font(ICONS).size(80),
bytes_exceeded_translation(language),
- Position::Left,
+ Position::FollowCursor,
)
- .gap(5)
.font(font)
.style(>::into(
StyleTuple(style, ElementType::Tooltip),
@@ -323,8 +321,14 @@ fn favorite_notification_log(
let details_str = format!("{domain} - {}", asn.name);
let mut row_flag_details = Row::new().align_items(Alignment::Center).spacing(5);
if !country.is_empty() {
- row_flag_details =
- row_flag_details.push(get_flag_from_country_code(&country, FLAGS_WIDTH_BIG));
+ row_flag_details = row_flag_details.push(get_flag_tooltip(
+ &country,
+ FLAGS_WIDTH_BIG,
+ logged_notification.data_info_host.is_local,
+ logged_notification.data_info_host.traffic_type,
+ language,
+ style,
+ ));
}
row_flag_details = row_flag_details.push(Text::new(details_str).font(font));
let content = Row::new()
@@ -335,9 +339,8 @@ fn favorite_notification_log(
Tooltip::new(
Text::new("g").font(ICONS).size(80),
favorite_transmitted_translation(language),
- Position::Left,
+ Position::FollowCursor,
)
- .gap(5)
.font(font)
.style(>::into(
StyleTuple(style, ElementType::Tooltip),
diff --git a/src/gui/pages/overview_page.rs b/src/gui/pages/overview_page.rs
index 9f6f38a7..3ed8425f 100644
--- a/src/gui/pages/overview_page.rs
+++ b/src/gui/pages/overview_page.rs
@@ -32,9 +32,9 @@ use crate::translations::translations::{
};
use crate::translations::translations_2::{
data_representation_translation, dropped_packets_translation, host_translation,
- of_total_translation, only_top_30_hosts,
+ of_total_translation, only_top_30_hosts_translation,
};
-use crate::utils::countries::{get_flag_from_country_code, FLAGS_WIDTH_BIG};
+use crate::utils::countries::{get_flag_tooltip, FLAGS_WIDTH_BIG};
use crate::utils::formatted_strings::{
get_active_filters_string, get_formatted_bytes_string, get_percentage_string,
};
@@ -402,12 +402,12 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> {
.align_items(Alignment::Center);
let entries = get_host_entries(&sniffer.info_traffic, chart_type);
- for (host, (data_info, is_favorite)) in &entries {
+ for (host, data_info_host) in &entries {
let (mut incoming_bar_len, mut outgoing_bar_len) = get_bars_length(
width * 0.86,
chart_type,
- entries.get(0).unwrap().1 .0.clone(),
- data_info,
+ entries.get(0).unwrap().1.data_info.clone(),
+ &data_info_host.data_info,
);
let star_button = button(
@@ -423,7 +423,7 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> {
.style(
StyleTuple(
sniffer.style,
- if *is_favorite {
+ if data_info_host.is_favorite {
ElementType::Starred
} else {
ElementType::NotStarred
@@ -431,7 +431,10 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> {
)
.into(),
)
- .on_press(Message::AddOrRemoveFavorite(host.clone(), !*is_favorite));
+ .on_press(Message::AddOrRemoveFavorite(
+ host.clone(),
+ !data_info_host.is_favorite,
+ ));
// normalize smaller values
if incoming_bar_len > 0.0 && incoming_bar_len < 3.0 {
@@ -454,10 +457,11 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> {
}))
.push(horizontal_space(Length::FillPortion(1)))
.push(Text::new(if chart_type.eq(&ChartType::Packets) {
- data_info.tot_packets().to_string()
+ data_info_host.data_info.tot_packets().to_string()
} else {
let mut bytes_string =
- get_formatted_bytes_string(data_info.tot_bytes()).replace(" ", " ");
+ get_formatted_bytes_string(data_info_host.data_info.tot_bytes())
+ .replace(" ", " ");
bytes_string.push('B');
bytes_string
})),
@@ -490,7 +494,14 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> {
.align_items(Alignment::Center)
.spacing(5)
.push(star_button)
- .push(get_flag_from_country_code(&host.country, FLAGS_WIDTH_BIG))
+ .push(get_flag_tooltip(
+ &host.country,
+ FLAGS_WIDTH_BIG,
+ data_info_host.is_local,
+ data_info_host.traffic_type,
+ sniffer.language,
+ sniffer.style,
+ ))
.push(host_bar);
scroll_host = scroll_host.push(
@@ -508,7 +519,7 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message> {
if entries.len() == 30 {
scroll_host = scroll_host.push(vertical_space(Length::Fixed(25.0))).push(
- Text::new(only_top_30_hosts(sniffer.language))
+ Text::new(only_top_30_hosts_translation(sniffer.language))
.horizontal_alignment(Horizontal::Center)
.font(font),
);
diff --git a/src/gui/types/sniffer.rs b/src/gui/types/sniffer.rs
index 7a26e011..79a1a78e 100644
--- a/src/gui/types/sniffer.rs
+++ b/src/gui/types/sniffer.rs
@@ -379,7 +379,7 @@ impl Sniffer {
info_traffic.favorite_hosts.remove(&host);
}
if let Some(host_info) = info_traffic.hosts.get_mut(&host) {
- host_info.1 = add;
+ host_info.is_favorite = add;
}
drop(info_traffic);
}
diff --git a/src/networking/manage_packets.rs b/src/networking/manage_packets.rs
index 58cfacf1..a97262dc 100644
--- a/src/networking/manage_packets.rs
+++ b/src/networking/manage_packets.rs
@@ -1,19 +1,23 @@
+use std::net::{IpAddr, Ipv4Addr};
use std::sync::{Arc, Mutex};
use chrono::Local;
use dns_lookup::lookup_addr;
use etherparse::{Ethernet2Header, IpHeader, TransportHeader};
use maxminddb::Reader;
-use pcap::{Active, Capture, Device};
+use pcap::{Active, Address, Capture, Device};
use crate::networking::types::address_port_pair::AddressPortPair;
use crate::networking::types::app_protocol::from_port_to_application_protocol;
use crate::networking::types::asn::Asn;
use crate::networking::types::data_info::DataInfo;
+use crate::networking::types::data_info_host::DataInfoHost;
use crate::networking::types::info_address_port_pair::InfoAddressPortPair;
+use crate::networking::types::traffic_direction::TrafficDirection;
use crate::networking::types::traffic_type::TrafficType;
use crate::utils::asn::get_asn;
use crate::utils::countries::get_country_code;
+use crate::IpVersion::{IPv4, IPv6};
use crate::{AppProtocol, InfoTraffic, IpVersion, TransProtocol};
/// This function analyzes the data link layer header passed as parameter and updates variables
@@ -111,26 +115,40 @@ pub fn analyze_transport_header(
pub fn modify_or_insert_in_map(
info_traffic_mutex: &Arc>,
key: AddressPortPair,
+ my_interface_addresses: &Vec,
mac_address1: String,
mac_address2: String,
exchanged_bytes: u128,
- traffic_type: TrafficType,
application_protocol: AppProtocol,
country_db_reader: &Reader<&[u8]>,
asn_db_reader: &Reader<&[u8]>,
) -> InfoAddressPortPair {
let now = Local::now();
- let very_long_address = key.address1.len() > 25 || key.address2.len() > 25;
+ let mut traffic_direction = TrafficDirection::default();
+ let source_ip = &key.address1.clone();
+ let destination_ip = &key.address2.clone();
+ let very_long_address = source_ip.len() > 25 || destination_ip.len() > 25;
+ let mut is_local = false;
+ let mut traffic_type = TrafficType::default();
+
let mut info_traffic = info_traffic_mutex
.lock()
.expect("Error acquiring mutex\n\r");
let len = info_traffic.map.len();
let index = info_traffic.map.get_index_of(&key).unwrap_or(len);
let (country, asn) = if index == len {
- // first occurrence of key => retrieve country code and asn
+ // first occurrence of key => retrieve traffic type, country code and asn
+ traffic_type = get_traffic_type(destination_ip, my_interface_addresses);
+ traffic_direction = get_traffic_direction(source_ip, my_interface_addresses);
+ is_local = is_local_connection(
+ source_ip,
+ destination_ip,
+ traffic_direction,
+ my_interface_addresses,
+ );
(
- get_country_code(traffic_type, &key, country_db_reader),
- get_asn(traffic_type, &key, asn_db_reader),
+ get_country_code(traffic_direction, &key, country_db_reader),
+ get_asn(traffic_direction, &key, asn_db_reader),
)
} else {
// this key already occurred
@@ -154,11 +172,13 @@ pub fn modify_or_insert_in_map(
final_timestamp: now,
app_protocol: application_protocol,
very_long_address,
+ traffic_direction,
traffic_type,
country,
asn,
r_dns: None,
index,
+ is_local,
})
.clone();
@@ -175,10 +195,10 @@ pub fn modify_or_insert_in_map(
pub fn reverse_dns_lookup(
info_traffic: Arc>,
key: AddressPortPair,
- traffic_type: TrafficType,
+ traffic_direction: TrafficDirection,
) {
- let address_to_lookup = match traffic_type {
- TrafficType::Outgoing => key.address2.clone(),
+ let address_to_lookup = match traffic_direction {
+ TrafficDirection::Outgoing => key.address2.clone(),
_ => key.address1.clone(),
};
@@ -213,40 +233,74 @@ pub fn reverse_dns_lookup(
info_traffic_lock
.hosts
.entry(new_info.get_host())
- .and_modify(|(data_info, _)| {
- if new_info.traffic_type == TrafficType::Outgoing {
- data_info.outgoing_packets += new_info.transmitted_packets;
- data_info.outgoing_bytes += new_info.transmitted_bytes;
+ .and_modify(|data_info_host| {
+ if new_info.traffic_direction == TrafficDirection::Outgoing {
+ data_info_host.data_info.outgoing_packets += new_info.transmitted_packets;
+ data_info_host.data_info.outgoing_bytes += new_info.transmitted_bytes;
} else {
- data_info.incoming_packets += new_info.transmitted_packets;
- data_info.incoming_bytes += new_info.transmitted_bytes;
+ data_info_host.data_info.incoming_packets += new_info.transmitted_packets;
+ data_info_host.data_info.incoming_bytes += new_info.transmitted_bytes;
}
})
- .or_insert(if new_info.traffic_type == TrafficType::Outgoing {
- (
- DataInfo {
- incoming_packets: 0,
- outgoing_packets: new_info.transmitted_packets,
- incoming_bytes: 0,
- outgoing_bytes: new_info.transmitted_bytes,
- },
- false,
- )
- } else {
- (
- DataInfo {
- incoming_packets: new_info.transmitted_packets,
- outgoing_packets: 0,
- incoming_bytes: new_info.transmitted_bytes,
- outgoing_bytes: 0,
- },
- false,
- )
- });
+ .or_insert(
+ if new_info.traffic_direction == TrafficDirection::Outgoing {
+ DataInfoHost {
+ data_info: DataInfo {
+ incoming_packets: 0,
+ outgoing_packets: new_info.transmitted_packets,
+ incoming_bytes: 0,
+ outgoing_bytes: new_info.transmitted_bytes,
+ },
+ is_favorite: false,
+ is_local: new_info.is_local,
+ traffic_type: new_info.traffic_type,
+ }
+ } else {
+ DataInfoHost {
+ data_info: DataInfo {
+ incoming_packets: new_info.transmitted_packets,
+ outgoing_packets: 0,
+ incoming_bytes: new_info.transmitted_bytes,
+ outgoing_bytes: 0,
+ },
+ is_favorite: false,
+ is_local: new_info.is_local,
+ traffic_type: new_info.traffic_type,
+ }
+ },
+ );
drop(info_traffic_lock);
}
+/// Returns the traffic direction observed (incoming or outgoing)
+fn get_traffic_direction(
+ source_ip: &String,
+ my_interface_addresses: &Vec,
+) -> TrafficDirection {
+ let my_interface_addresses_string: Vec = my_interface_addresses
+ .iter()
+ .map(|address| address.addr.to_string())
+ .collect();
+
+ if my_interface_addresses_string.contains(source_ip) {
+ TrafficDirection::Outgoing
+ } else {
+ TrafficDirection::Incoming
+ }
+}
+
+/// Returns the traffic type observed (unicast, multicast or broadcast)
+fn get_traffic_type(destination_ip: &String, my_interface_addresses: &Vec) -> TrafficType {
+ if is_multicast_address(destination_ip) {
+ TrafficType::Multicast
+ } else if is_broadcast_address(destination_ip, my_interface_addresses) {
+ TrafficType::Broadcast
+ } else {
+ TrafficType::Unicast
+ }
+}
+
/// Determines if the input address is a multicast address or not.
///
/// # Arguments
@@ -280,8 +334,23 @@ pub fn is_multicast_address(address: &str) -> bool {
/// # Arguments
///
/// * `address` - string representing an IPv4 or IPv6 network address.
-pub fn is_broadcast_address(address: &str) -> bool {
+pub fn is_broadcast_address(address: &str, my_interface_addresses: &Vec) -> bool {
let mut ret_val = false;
+
+ // check if directed broadcast
+ let my_broadcast_addresses: Vec = my_interface_addresses
+ .iter()
+ .map(|address| {
+ address
+ .broadcast_addr
+ .unwrap_or("255.255.255.255".parse().unwrap())
+ .to_string()
+ })
+ .collect();
+ if my_broadcast_addresses.contains(&address.to_string()) {
+ return true;
+ }
+
if !address.contains(':') {
//IPv4 address
let groups: Vec = address
@@ -295,11 +364,82 @@ pub fn is_broadcast_address(address: &str) -> bool {
{
ret_val = true;
}
- // still missing a check for directed broadcast!
}
ret_val
}
+/// Determines if the connection is local
+fn is_local_connection(
+ source_ip: &String,
+ destination_ip: &String,
+ traffic_direction: TrafficDirection,
+ my_interface_addresses: &Vec,
+) -> bool {
+ let mut ret_val = false;
+
+ let address_to_lookup = match traffic_direction {
+ TrafficDirection::Outgoing => destination_ip,
+ _ => source_ip,
+ };
+ let address_to_lookup_type = if address_to_lookup.contains(":") {
+ IPv6
+ } else {
+ IPv4
+ };
+
+ for address in my_interface_addresses {
+ match address.addr {
+ IpAddr::V4(local_addr) if address_to_lookup_type.eq(&IPv4) => {
+ // check if the two IPv4 addresses are in the same subnet
+ let address_to_lookup_parsed: Ipv4Addr =
+ address_to_lookup.parse().unwrap_or(Ipv4Addr::from(0));
+ // remote is link local?
+ if address_to_lookup_parsed.is_link_local() {
+ ret_val = true;
+ }
+ // is the same subnet?
+ else if let Some(IpAddr::V4(netmask)) = address.netmask {
+ let mut local_subnet = Vec::new();
+ let mut remote_subnet = Vec::new();
+ let netmask_digits = netmask.octets();
+ let local_addr_digits = local_addr.octets();
+ let remote_addr_digits = address_to_lookup_parsed.octets();
+ for (i, netmask_digit) in netmask_digits.iter().enumerate() {
+ local_subnet.push(netmask_digit & local_addr_digits[i]);
+ remote_subnet.push(netmask_digit & remote_addr_digits[i]);
+ }
+ if local_subnet == remote_subnet {
+ ret_val = true;
+ }
+ }
+ }
+ IpAddr::V6(local_addr) if address_to_lookup_type.eq(&IPv6) => {
+ // check if the two IPv6 addresses are in the same subnet
+ // remote is link local?
+ if address_to_lookup.starts_with("fe80") {
+ ret_val = true;
+ }
+ // is the same subnet?
+ else if let Some(IpAddr::V6(netmask)) = address.netmask {
+ let netmask_len = netmask.to_string().len();
+ let local_address_string = local_addr.to_string();
+ let local_subnet = local_address_string.get(0..netmask_len).unwrap_or("");
+ let remote_subnet = address_to_lookup.get(0..netmask_len).unwrap_or("");
+ if !local_subnet.is_empty()
+ && !remote_subnet.is_empty()
+ && local_subnet == remote_subnet
+ {
+ ret_val = true;
+ }
+ }
+ }
+ _ => {}
+ }
+ }
+
+ ret_val
+}
+
/// Determines if the capture opening resolves into an Error
pub fn get_capture_result(device: &Device) -> (Option, Option>) {
let cap_result = Capture::from_device(&*device.name)
@@ -420,7 +560,12 @@ fn ipv6_from_long_dec_to_short_hex(ipv6_long: [u8; 16]) -> String {
#[cfg(test)]
mod tests {
- use crate::networking::manage_packets::{ipv6_from_long_dec_to_short_hex, mac_from_dec_to_hex};
+ use crate::networking::manage_packets::{
+ ipv6_from_long_dec_to_short_hex, is_local_connection, mac_from_dec_to_hex,
+ };
+ use crate::networking::types::traffic_direction::TrafficDirection;
+ use pcap::Address;
+ use std::net::{IpAddr, Ipv4Addr};
#[test]
fn mac_simple_test() {
@@ -533,4 +678,60 @@ mod tests {
ipv6_from_long_dec_to_short_hex([0, 16, 16, 0, 0, 1, 7, 0, 0, 2, 216, 0, 1, 0, 0, 1]);
assert_eq!(result, "10:1000:1:700:2:d800:100:1".to_string());
}
+
+ #[test]
+ fn is_local_connection_ipv4_test() {
+ let mut address_vec: Vec = Vec::new();
+ let my_address = Address {
+ addr: IpAddr::V4("172.20.10.9".parse().unwrap()),
+ netmask: Some(IpAddr::V4("255.255.255.240".parse().unwrap())),
+ broadcast_addr: None,
+ dst_addr: None,
+ };
+ address_vec.push(my_address);
+
+ let result1 = is_local_connection(
+ &"172.20.10.9".to_string(),
+ &"104.18.43.158".to_string(),
+ TrafficDirection::Outgoing,
+ &address_vec,
+ );
+ assert_eq!(result1, false);
+
+ let result2 = is_local_connection(
+ &"172.20.10.9".to_string(),
+ &"172.20.10.15".to_string(),
+ TrafficDirection::Outgoing,
+ &address_vec,
+ );
+ assert_eq!(result2, true);
+
+ let result3 = is_local_connection(
+ &"172.20.10.9".to_string(),
+ &"172.20.10.16".to_string(),
+ TrafficDirection::Outgoing,
+ &address_vec,
+ );
+ assert_eq!(result3, false);
+ }
+
+ #[test]
+ fn is_local_connection_ipv4_multicast_test() {
+ let mut address_vec: Vec = Vec::new();
+ let my_address = Address {
+ addr: IpAddr::V4("172.20.10.9".parse().unwrap()),
+ netmask: Some(IpAddr::V4("255.255.255.240".parse().unwrap())),
+ broadcast_addr: None,
+ dst_addr: None,
+ };
+ address_vec.push(my_address);
+
+ let result1 = is_local_connection(
+ &"172.20.10.9".to_string(),
+ &"224.0.0.251".to_string(),
+ TrafficDirection::Outgoing,
+ &address_vec,
+ );
+ assert_eq!(result1, false);
+ }
}
diff --git a/src/networking/types/data_info_host.rs b/src/networking/types/data_info_host.rs
new file mode 100644
index 00000000..c31845b2
--- /dev/null
+++ b/src/networking/types/data_info_host.rs
@@ -0,0 +1,17 @@
+//! Module defining the `DataInfoHost` struct related to hosts.
+
+use crate::networking::types::data_info::DataInfo;
+use crate::networking::types::traffic_type::TrafficType;
+
+/// Host-related information.
+#[derive(Clone, Default)]
+pub struct DataInfoHost {
+ /// Incoming and outgoing packets and bytes
+ pub data_info: DataInfo,
+ /// Determine if this host is one of the favorites
+ pub is_favorite: bool,
+ /// Determine if the connection with this host is local
+ pub is_local: bool,
+ /// Determine if the connection with this host is multicast or broadcast
+ pub traffic_type: TrafficType,
+}
diff --git a/src/networking/types/info_address_port_pair.rs b/src/networking/types/info_address_port_pair.rs
index 8c827d2d..84da827d 100644
--- a/src/networking/types/info_address_port_pair.rs
+++ b/src/networking/types/info_address_port_pair.rs
@@ -3,12 +3,12 @@
use std::fmt;
use std::net::IpAddr;
-use std::ops::Add;
use chrono::{DateTime, Local};
use crate::networking::types::asn::Asn;
use crate::networking::types::host::Host;
+use crate::networking::types::traffic_direction::TrafficDirection;
use crate::networking::types::traffic_type::TrafficType;
use crate::utils::formatted_strings::get_formatted_bytes_string;
use crate::AppProtocol;
@@ -34,8 +34,6 @@ pub struct InfoAddressPortPair {
pub app_protocol: AppProtocol,
/// Check if source or destination is an IPv6 address longer than 25 bytes (used for Display
pub very_long_address: bool,
- /// Flag to determine which of the address is that of the sniffed adapter or remote
- pub traffic_type: TrafficType,
/// Country of the remote IP address
pub country: String,
/// Autonomous System of the remote IP address
@@ -44,6 +42,12 @@ pub struct InfoAddressPortPair {
pub r_dns: Option,
/// Integer corresponding to the index inside the connections map
pub index: usize,
+ /// Determines if the connection is incoming or outgoing
+ pub traffic_direction: TrafficDirection,
+ /// Determines if the connection is unicast, multicast or broadcast
+ pub traffic_type: TrafficType,
+ /// Determines if the connection is local
+ pub is_local: bool,
}
impl Default for InfoAddressPortPair {
@@ -57,11 +61,13 @@ impl Default for InfoAddressPortPair {
final_timestamp: Default::default(),
app_protocol: AppProtocol::Other,
very_long_address: false,
- traffic_type: TrafficType::Other,
+ traffic_direction: TrafficDirection::default(),
+ traffic_type: TrafficType::default(),
country: String::new(),
asn: Default::default(),
r_dns: None,
index: 0,
+ is_local: false,
}
}
}
@@ -73,7 +79,6 @@ impl InfoAddressPortPair {
.unwrap()
.to_string()
.replace('|', "")
- .add(&*format!(" {} ", &self.country))
}
pub fn get_host(&self) -> Host {
diff --git a/src/networking/types/info_traffic.rs b/src/networking/types/info_traffic.rs
index 05a79113..ad4933ab 100644
--- a/src/networking/types/info_traffic.rs
+++ b/src/networking/types/info_traffic.rs
@@ -7,6 +7,7 @@ use indexmap::IndexMap;
use crate::networking::types::address_port_pair::AddressPortPair;
use crate::networking::types::data_info::DataInfo;
+use crate::networking::types::data_info_host::DataInfoHost;
use crate::networking::types::host::Host;
use crate::networking::types::info_address_port_pair::InfoAddressPortPair;
use crate::AppProtocol;
@@ -38,7 +39,7 @@ pub struct InfoTraffic {
/// Map of the application layer protocols with their data info
pub app_protocols: HashMap,
/// Map of the hosts with their data info
- pub hosts: HashMap,
+ pub hosts: HashMap,
}
impl InfoTraffic {
diff --git a/src/networking/types/mod.rs b/src/networking/types/mod.rs
index cbc4b183..6df89a79 100644
--- a/src/networking/types/mod.rs
+++ b/src/networking/types/mod.rs
@@ -3,11 +3,13 @@ pub mod app_protocol;
pub mod asn;
pub mod byte_multiple;
pub mod data_info;
+pub mod data_info_host;
pub mod filters;
pub mod host;
pub mod info_address_port_pair;
pub mod info_traffic;
pub mod ip_version;
pub mod search_parameters;
+pub mod traffic_direction;
pub mod traffic_type;
pub mod trans_protocol;
diff --git a/src/networking/types/traffic_direction.rs b/src/networking/types/traffic_direction.rs
new file mode 100644
index 00000000..6cf2d8b8
--- /dev/null
+++ b/src/networking/types/traffic_direction.rs
@@ -0,0 +1,14 @@
+/// Enum representing the possible traffic direction (incoming or outgoing).
+#[derive(Clone, Copy, PartialEq, Eq)]
+pub enum TrafficDirection {
+ /// Incoming traffic (from remote address to local interface)
+ Incoming,
+ /// Outgoing traffic (from local interface to remote address)
+ Outgoing,
+}
+
+impl Default for TrafficDirection {
+ fn default() -> Self {
+ Self::Incoming
+ }
+}
diff --git a/src/networking/types/traffic_type.rs b/src/networking/types/traffic_type.rs
index 3cb5fdb6..9d55c18a 100644
--- a/src/networking/types/traffic_type.rs
+++ b/src/networking/types/traffic_type.rs
@@ -1,14 +1,16 @@
-/// Enum representing the possible traffic type (incoming, outgoing or multicast).
+/// Enum representing the possible traffic type (unicast, multicast or broadcast).
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum TrafficType {
- /// Incoming traffic (from remote address to local interface)
- Incoming,
- /// Outgoing traffic (from local interface to remote address)
- Outgoing,
- /// Multicast traffic (from remote address to multicast address)
+ /// Unicast traffic
+ Unicast,
+ /// Multicast traffic (destination is a multicast address)
Multicast,
- /// Multicast traffic (from remote address to broadcast address)
+ /// Broadcast traffic (destination is a broadcast address)
Broadcast,
- /// Not identified
- Other,
+}
+
+impl Default for TrafficType {
+ fn default() -> Self {
+ Self::Unicast
+ }
}
diff --git a/src/notifications/notify_and_log.rs b/src/notifications/notify_and_log.rs
index d033a01f..5c341e8f 100644
--- a/src/notifications/notify_and_log.rs
+++ b/src/notifications/notify_and_log.rs
@@ -100,6 +100,7 @@ pub fn notify_and_log(
.push_front(LoggedNotification::FavoriteTransmitted(
FavoriteTransmitted {
host: host.clone(),
+ data_info_host: info_traffic_lock.hosts.get(host).unwrap().clone(),
timestamp: Local::now().to_string().get(11..19).unwrap().to_string(),
},
));
diff --git a/src/notifications/types/logged_notification.rs b/src/notifications/types/logged_notification.rs
index fb1f892c..d723a576 100644
--- a/src/notifications/types/logged_notification.rs
+++ b/src/notifications/types/logged_notification.rs
@@ -1,3 +1,4 @@
+use crate::networking::types::data_info_host::DataInfoHost;
use crate::networking::types::host::Host;
use crate::ByteMultiple;
@@ -31,5 +32,6 @@ pub struct BytesThresholdExceeded {
#[derive(Clone)]
pub struct FavoriteTransmitted {
pub(crate) host: Host,
+ pub(crate) data_info_host: DataInfoHost,
pub(crate) timestamp: String,
}
diff --git a/src/report/get_report_entries.rs b/src/report/get_report_entries.rs
index a1c2ff19..98789caf 100644
--- a/src/report/get_report_entries.rs
+++ b/src/report/get_report_entries.rs
@@ -1,8 +1,8 @@
use std::cmp::{min, Ordering};
use std::sync::{Arc, Mutex};
-use crate::networking::types::address_port_pair::AddressPortPair;
use crate::networking::types::data_info::DataInfo;
+use crate::networking::types::data_info_host::DataInfoHost;
use crate::networking::types::host::Host;
use crate::networking::types::search_parameters::SearchParameters;
use crate::{AppProtocol, ChartType, InfoTraffic};
@@ -102,13 +102,13 @@ pub fn get_searched_entries(
pub fn get_host_entries(
info_traffic: &Arc>,
chart_type: ChartType,
-) -> Vec<(Host, (DataInfo, bool))> {
+) -> Vec<(Host, DataInfoHost)> {
let info_traffic_lock = info_traffic.lock().unwrap();
- let mut sorted_vec: Vec<(&Host, &(DataInfo, bool))> = info_traffic_lock.hosts.iter().collect();
+ let mut sorted_vec: Vec<(&Host, &DataInfoHost)> = info_traffic_lock.hosts.iter().collect();
- sorted_vec.sort_by(|&(_, (a, _)), &(_, (b, _))| match chart_type {
- ChartType::Packets => b.tot_packets().cmp(&a.tot_packets()),
- ChartType::Bytes => b.tot_bytes().cmp(&a.tot_bytes()),
+ sorted_vec.sort_by(|&(_, a), &(_, b)| match chart_type {
+ ChartType::Packets => b.data_info.tot_packets().cmp(&a.data_info.tot_packets()),
+ ChartType::Bytes => b.data_info.tot_bytes().cmp(&a.data_info.tot_bytes()),
});
let n_entry = min(sorted_vec.len(), 30);
diff --git a/src/secondary_threads/parse_packets.rs b/src/secondary_threads/parse_packets.rs
index e93c8942..6977e40c 100644
--- a/src/secondary_threads/parse_packets.rs
+++ b/src/secondary_threads/parse_packets.rs
@@ -8,14 +8,15 @@ use etherparse::PacketHeaders;
use pcap::{Active, Capture, Device};
use crate::networking::manage_packets::{
- analyze_link_header, analyze_network_header, analyze_transport_header, is_broadcast_address,
- is_multicast_address, modify_or_insert_in_map, reverse_dns_lookup,
+ analyze_link_header, analyze_network_header, analyze_transport_header, modify_or_insert_in_map,
+ reverse_dns_lookup,
};
use crate::networking::types::address_port_pair::AddressPortPair;
use crate::networking::types::data_info::DataInfo;
+use crate::networking::types::data_info_host::DataInfoHost;
use crate::networking::types::filters::Filters;
use crate::networking::types::info_address_port_pair::InfoAddressPortPair;
-use crate::networking::types::traffic_type::TrafficType;
+use crate::networking::types::traffic_direction::TrafficDirection;
use crate::utils::countries::COUNTRY_MMDB;
use crate::{AppProtocol, InfoTraffic, IpVersion, TransProtocol};
@@ -32,11 +33,6 @@ pub fn parse_packets(
) {
let capture_id = *current_capture_id.lock().unwrap();
- let mut my_interface_addresses = Vec::new();
- for address in device.addresses {
- my_interface_addresses.push(address.addr.to_string());
- }
-
let network_layer_filter = filters.ip;
let transport_layer_filter = filters.transport;
let app_layer_filter = filters.application;
@@ -47,7 +43,6 @@ pub fn parse_packets(
let mut network_protocol;
let mut transport_protocol;
let mut application_protocol;
- let mut traffic_type;
let mut skip_packet;
let mut reported_packet;
@@ -78,7 +73,6 @@ pub fn parse_packets(
network_protocol = IpVersion::Other;
transport_protocol = TransProtocol::Other;
application_protocol = AppProtocol::Other;
- traffic_type = TrafficType::Other;
skip_packet = false;
reported_packet = false;
@@ -116,16 +110,6 @@ pub fn parse_packets(
continue;
}
- if my_interface_addresses.contains(&address1) {
- traffic_type = TrafficType::Outgoing;
- } else if my_interface_addresses.contains(&address2) {
- traffic_type = TrafficType::Incoming;
- } else if is_multicast_address(&address2) {
- traffic_type = TrafficType::Multicast;
- } else if is_broadcast_address(&address2) {
- traffic_type = TrafficType::Broadcast;
- }
-
let key: AddressPortPair = AddressPortPair::new(
address1.clone(),
port1,
@@ -145,10 +129,10 @@ pub fn parse_packets(
new_info = modify_or_insert_in_map(
info_traffic_mutex,
key.clone(),
+ &device.addresses,
mac_address1,
mac_address2,
exchanged_bytes,
- traffic_type,
application_protocol,
&country_db_reader,
&asn_db_reader,
@@ -168,7 +152,7 @@ pub fn parse_packets(
}
if reported_packet {
- if traffic_type == TrafficType::Outgoing {
+ if new_info.traffic_direction == TrafficDirection::Outgoing {
//increment number of sent packets and bytes
info_traffic.tot_sent_packets += 1;
info_traffic.tot_sent_bytes += exchanged_bytes;
@@ -201,7 +185,7 @@ pub fn parse_packets(
reverse_dns_lookup(
info_traffic2,
key2,
- new_info.traffic_type,
+ new_info.traffic_direction,
);
})
.unwrap();
@@ -216,38 +200,48 @@ pub fn parse_packets(
info_traffic
.hosts
.entry(new_info.get_host())
- .and_modify(|(data_info, _)| {
- if traffic_type == TrafficType::Outgoing {
- data_info.outgoing_packets += 1;
- data_info.outgoing_bytes += exchanged_bytes;
+ .and_modify(|data_info_host| {
+ if new_info.traffic_direction
+ == TrafficDirection::Outgoing
+ {
+ data_info_host.data_info.outgoing_packets += 1;
+ data_info_host.data_info.outgoing_bytes +=
+ exchanged_bytes;
} else {
- data_info.incoming_packets += 1;
- data_info.incoming_bytes += exchanged_bytes;
+ data_info_host.data_info.incoming_packets += 1;
+ data_info_host.data_info.incoming_bytes +=
+ exchanged_bytes;
}
})
.or_insert(
- if new_info.traffic_type == TrafficType::Outgoing {
- (
- DataInfo {
+ if new_info.traffic_direction
+ == TrafficDirection::Outgoing
+ {
+ DataInfoHost {
+ data_info: DataInfo {
incoming_packets: 0,
outgoing_packets: new_info
.transmitted_packets,
incoming_bytes: 0,
outgoing_bytes: new_info.transmitted_bytes,
},
- false,
- )
+ is_favorite: false,
+ is_local: new_info.is_local,
+ traffic_type: new_info.traffic_type,
+ }
} else {
- (
- DataInfo {
+ DataInfoHost {
+ data_info: DataInfo {
incoming_packets: new_info
.transmitted_packets,
outgoing_packets: 0,
incoming_bytes: new_info.transmitted_bytes,
outgoing_bytes: 0,
},
- false,
- )
+ is_favorite: false,
+ is_local: new_info.is_local,
+ traffic_type: new_info.traffic_type,
+ }
},
);
}
@@ -258,7 +252,7 @@ pub fn parse_packets(
.app_protocols
.entry(application_protocol)
.and_modify(|data_info| {
- if traffic_type == TrafficType::Outgoing {
+ if new_info.traffic_direction == TrafficDirection::Outgoing {
data_info.outgoing_packets += 1;
data_info.outgoing_bytes += exchanged_bytes;
} else {
@@ -266,21 +260,23 @@ pub fn parse_packets(
data_info.incoming_bytes += exchanged_bytes;
}
})
- .or_insert(if traffic_type == TrafficType::Outgoing {
- DataInfo {
- incoming_packets: 0,
- outgoing_packets: 1,
- incoming_bytes: 0,
- outgoing_bytes: exchanged_bytes,
- }
- } else {
- DataInfo {
- incoming_packets: 1,
- outgoing_packets: 0,
- incoming_bytes: exchanged_bytes,
- outgoing_bytes: 0,
- }
- });
+ .or_insert(
+ if new_info.traffic_direction == TrafficDirection::Outgoing {
+ DataInfo {
+ incoming_packets: 0,
+ outgoing_packets: 1,
+ incoming_bytes: 0,
+ outgoing_bytes: exchanged_bytes,
+ }
+ } else {
+ DataInfo {
+ incoming_packets: 1,
+ outgoing_packets: 0,
+ incoming_bytes: exchanged_bytes,
+ outgoing_bytes: 0,
+ }
+ },
+ );
}
}
}
diff --git a/src/translations/translations_2.rs b/src/translations/translations_2.rs
index 9c1ba171..42311351 100644
--- a/src/translations/translations_2.rs
+++ b/src/translations/translations_2.rs
@@ -67,10 +67,28 @@ pub fn host_translation(language: Language) -> &'static str {
}
}
-pub fn only_top_30_hosts(language: Language) -> &'static str {
+pub fn only_top_30_hosts_translation(language: Language) -> &'static str {
match language {
Language::EN => "Only the top 30 hosts are displayed here",
Language::IT => "Solo i maggiori 30 host sono mostrati qui",
_ => "Only the top 30 hosts are displayed here",
}
}
+
+pub fn local_translation(language: Language) -> String {
+ match language {
+ Language::EN => "Local",
+ Language::IT => "Locale",
+ _ => "Local",
+ }
+ .to_string()
+}
+
+pub fn unknown_translation(language: Language) -> String {
+ match language {
+ Language::EN => "Unknown",
+ Language::IT => "Sconosciuto",
+ _ => "Unknown",
+ }
+ .to_string()
+}
diff --git a/src/utils/asn.rs b/src/utils/asn.rs
index 2b90da08..74068353 100644
--- a/src/utils/asn.rs
+++ b/src/utils/asn.rs
@@ -1,17 +1,17 @@
use crate::networking::types::address_port_pair::AddressPortPair;
use crate::networking::types::asn::Asn;
-use crate::networking::types::traffic_type::TrafficType;
+use crate::networking::types::traffic_direction::TrafficDirection;
use maxminddb::{geoip2, MaxMindDBError, Reader};
pub const ASN_MMDB: &[u8] = include_bytes!("../../resources/DB/GeoLite2-ASN.mmdb");
pub fn get_asn(
- traffic_type: TrafficType,
+ traffic_direction: TrafficDirection,
key: &AddressPortPair,
asn_db_reader: &Reader<&[u8]>,
) -> Asn {
- let address_to_lookup = match traffic_type {
- TrafficType::Outgoing => &key.address2,
+ let address_to_lookup = match traffic_direction {
+ TrafficDirection::Outgoing => &key.address2,
_ => &key.address1,
};
diff --git a/src/utils/countries.rs b/src/utils/countries.rs
index df329b8f..4b83ad1f 100644
--- a/src/utils/countries.rs
+++ b/src/utils/countries.rs
@@ -1,19 +1,26 @@
-use iced::widget::{svg::Handle, Svg};
+use crate::gui::styles::types::element_type::ElementType;
+use crate::gui::styles::types::style_tuple::StyleTuple;
+use crate::gui::types::message::Message;
+use crate::{Language, StyleType};
+use iced::widget::{svg::Handle, Svg, Tooltip};
use iced::{Length, Renderer};
+use iced_native::widget::tooltip::Position;
use maxminddb::{geoip2, MaxMindDBError, Reader};
use crate::networking::types::address_port_pair::AddressPortPair;
+use crate::networking::types::traffic_direction::TrafficDirection;
use crate::networking::types::traffic_type::TrafficType;
+use crate::translations::translations_2::{local_translation, unknown_translation};
pub const COUNTRY_MMDB: &[u8] = include_bytes!("../../resources/DB/GeoLite2-Country.mmdb");
pub fn get_country_code(
- traffic_type: TrafficType,
+ traffic_direction: TrafficDirection,
key: &AddressPortPair,
country_db_reader: &Reader<&[u8]>,
) -> String {
- let address_to_lookup = match traffic_type {
- TrafficType::Outgoing => &key.address2,
+ let address_to_lookup = match traffic_direction {
+ TrafficDirection::Outgoing => &key.address2,
_ => &key.address1,
};
@@ -29,7 +36,7 @@ pub fn get_country_code(
String::new()
}
-pub const FLAGS_WIDTH_SMALL: f32 = 15.0;
+pub const FLAGS_WIDTH_SMALL: f32 = 20.0;
pub const FLAGS_WIDTH_BIG: f32 = 37.5;
pub const AD: &[u8] = include_bytes!("../../resources/countries_flags/4x3/ad.svg");
@@ -281,8 +288,10 @@ pub const YT: &[u8] = include_bytes!("../../resources/countries_flags/4x3/yt.svg
pub const ZA: &[u8] = include_bytes!("../../resources/countries_flags/4x3/za.svg");
pub const ZM: &[u8] = include_bytes!("../../resources/countries_flags/4x3/zm.svg");
pub const ZW: &[u8] = include_bytes!("../../resources/countries_flags/4x3/zw.svg");
-pub const UNKNOWN: &[u8] =
- include_bytes!("../../resources/countries_flags/4x3/question-mark-svgrepo-com.svg");
+pub const HOME: &[u8] = include_bytes!("../../resources/countries_flags/4x3/zz-home.svg");
+pub const MULTICAST: &[u8] = include_bytes!("../../resources/countries_flags/4x3/zz-multicast.svg");
+pub const BROADCAST: &[u8] = include_bytes!("../../resources/countries_flags/4x3/zz-broadcast.svg");
+pub const UNKNOWN: &[u8] = include_bytes!("../../resources/countries_flags/4x3/zz-unknown.svg");
pub fn get_flag_from_language_code(language: &str) -> Svg {
Svg::new(Handle::from_memory(Vec::from(match language {
@@ -306,9 +315,16 @@ pub fn get_flag_from_language_code(language: &str) -> Svg {
.width(Length::Fixed(FLAGS_WIDTH_SMALL))
}
-pub fn get_flag_from_country_code(country: &str, width: f32) -> Svg {
+fn get_flag_from_country_code(
+ country: &str,
+ width: f32,
+ is_local: bool,
+ traffic_type: TrafficType,
+ language: Language,
+) -> (Svg, String) {
#![allow(clippy::too_many_lines)]
- Svg::new(Handle::from_memory(Vec::from(match country {
+ let mut tooltip = country.to_string();
+ let svg = Svg::new(Handle::from_memory(Vec::from(match country {
"AD" => AD,
"AE" => AE,
"AF" => AF,
@@ -558,7 +574,49 @@ pub fn get_flag_from_country_code(country: &str, width: f32) -> Svg {
"ZA" => ZA,
"ZM" => ZM,
"ZW" => ZW,
- _ => UNKNOWN,
+ _ => {
+ if is_local {
+ tooltip = local_translation(language);
+ HOME
+ } else if traffic_type.eq(&TrafficType::Multicast) {
+ tooltip = "Multicast".to_string();
+ MULTICAST
+ } else if traffic_type.eq(&TrafficType::Broadcast) {
+ tooltip = "Broadcast".to_string();
+ BROADCAST
+ } else {
+ tooltip = unknown_translation(language);
+ UNKNOWN
+ }
+ }
})))
.width(Length::Fixed(width))
+ .height(Length::Fixed(width * 0.75));
+
+ (svg, tooltip)
+}
+
+pub fn get_flag_tooltip(
+ country: &str,
+ width: f32,
+ is_local: bool,
+ traffic_type: TrafficType,
+ language: Language,
+ style: StyleType,
+) -> Tooltip<'static, Message> {
+ let (content, tooltip) =
+ get_flag_from_country_code(country, width, is_local, traffic_type, language);
+ let mut position = Position::FollowCursor;
+ let mut snap = true;
+
+ if width == FLAGS_WIDTH_SMALL {
+ position = Position::Right;
+ snap = false;
+ }
+
+ Tooltip::new(content, tooltip, position)
+ .snap_within_viewport(snap)
+ .style(>::into(
+ StyleTuple(style, ElementType::Tooltip),
+ ))
}
diff --git a/src/utils/formatted_strings.rs b/src/utils/formatted_strings.rs
index d3a3a157..b5bf9f54 100644
--- a/src/utils/formatted_strings.rs
+++ b/src/utils/formatted_strings.rs
@@ -3,7 +3,7 @@ use std::path::PathBuf;
use iced::Color;
use crate::networking::types::filters::Filters;
-use crate::networking::types::traffic_type::TrafficType;
+use crate::networking::types::traffic_direction::TrafficDirection;
use crate::translations::translations::{
active_filters_translation, none_translation, open_report_translation,
};
@@ -55,8 +55,8 @@ pub fn get_active_filters_string(filters: &Filters, language: Language) -> Strin
}
/// Returns the color to be used for a specific connection of the relevant connections table in gui run page
-pub fn get_connection_color(traffic_type: TrafficType, style: StyleType) -> Color {
- if traffic_type == TrafficType::Outgoing {
+pub fn get_connection_color(traffic_direction: TrafficDirection, style: StyleType) -> Color {
+ if traffic_direction == TrafficDirection::Outgoing {
get_colors(style).outgoing
} else {
get_colors(style).incoming