feat: local addresses identification and directed broadcast support

This commit is contained in:
Giuliano Bellini s294739
2023-05-01 19:00:08 +02:00
parent 83a1bb82ac
commit 211ea028b4
24 changed files with 562 additions and 187 deletions

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800px" height="600px" viewBox="0 0 800 600" version="1.1">
<g id="surface1">
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 412.941406 485.992188 L 374.300781 485.992188 C 347.089844 485.992188 324.972656 502.578125 324.972656 522.988281 L 324.972656 563.003906 C 324.972656 583.414062 347.089844 600 374.300781 600 L 412.941406 600 C 440.152344 600 462.265625 583.414062 462.265625 563.003906 L 462.265625 522.988281 C 462.265625 502.519531 440.152344 485.992188 412.941406 485.992188 Z M 412.941406 485.992188 "/>
<path style=" stroke:none;fill-rule:nonzero;fill:rgb(0%,0%,0%);fill-opacity:1;" d="M 140.492188 176.21875 L 211.769531 182.878906 C 234.375 184.976562 255.832031 175.234375 263.972656 159.265625 C 274.25 139.101562 288.554688 123.195312 306.886719 111.601562 C 332.867188 95.199219 365.175781 86.9375 403.816406 86.9375 C 443.851562 86.9375 475.75 94.832031 499.425781 110.554688 C 523.101562 126.339844 534.859375 145.207031 534.859375 167.339844 C 534.859375 183.25 528.199219 197.800781 514.882812 210.996094 C 506.25 219.382812 479.695312 237.015625 435.382812 263.960938 C 390.988281 290.90625 361.476562 315.199219 346.679688 336.777344 C 331.550781 358.851562 326.289062 383.332031 324.976562 407.871094 C 323.824219 428.898438 346.183594 446.410156 374.300781 446.410156 L 414.585938 446.410156 C 440.234375 446.410156 461.445312 431.671875 463.746094 412.558594 C 465.390625 398.808594 468.433594 388.386719 473.039062 381.296875 C 480.765625 369.148438 500.742188 353.117188 532.804688 333.140625 C 594.875 294.605469 635.320312 264.144531 654.3125 241.703125 C 673.222656 219.320312 682.757812 195.582031 682.757812 170.484375 C 682.757812 125.167969 657.027344 85.398438 605.480469 51.238281 C 554.015625 17.078125 484.628906 0 397.484375 0 C 314.617188 0 247.777344 16.832031 196.808594 50.558594 C 153.398438 79.292969 127.007812 113.328125 117.71875 152.605469 C 114.839844 164.074219 125.28125 174.800781 140.492188 176.21875 Z M 140.492188 176.21875 "/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 2.1 KiB

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="48" height="48" fill="white" fill-opacity="0.01"/>
<path d="M24 15C26.7614 15 29 12.7614 29 10C29 7.23858 26.7614 5 24 5C21.2386 5 19 7.23858 19 10C19 12.7614 21.2386 15 24 15Z" fill="#2F88FF" stroke="#000000" stroke-width="4"/>
<path d="M24 15V23" stroke="#000000" stroke-width="4" stroke-linecap="round"/>
<path d="M30 23V33" stroke="#000000" stroke-width="4" stroke-linecap="round"/>
<path d="M18 23V33" stroke="#000000" stroke-width="4" stroke-linecap="round"/>
<path d="M7 33V23L41 23.0128V33" stroke="#000000" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M41 41V42" stroke="#000000" stroke-width="5" stroke-linecap="round"/>
<path d="M7 41V42" stroke="#000000" stroke-width="5" stroke-linecap="round"/>
<path d="M18 41V42" stroke="#000000" stroke-width="5" stroke-linecap="round"/>
<path d="M30 41V42" stroke="#000000" stroke-width="5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg fill="#000000" height="800px" width="800px" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
viewBox="0 0 26.39 26.39" xml:space="preserve">
<g>
<g id="c14_house">
<path d="M3.588,24.297c0,0-0.024,0.59,0.553,0.59c0.718,0,6.652-0.008,6.652-0.008l0.01-5.451c0,0-0.094-0.898,0.777-0.898h2.761
c1.031,0,0.968,0.898,0.968,0.898l-0.012,5.434c0,0,5.628,0,6.512,0c0.732,0,0.699-0.734,0.699-0.734V14.076L13.33,5.913
l-9.742,8.164C3.588,14.077,3.588,24.297,3.588,24.297z"/>
<path d="M0,13.317c0,0,0.826,1.524,2.631,0l10.781-9.121l10.107,9.064c2.088,1.506,2.871,0,2.871,0L13.412,1.504L0,13.317z"/>
<polygon points="23.273,4.175 20.674,4.175 20.685,7.328 23.273,9.525 "/>
</g>
<g id="Capa_1_216_">
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 923 B

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?><!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<svg width="800px" height="800px" viewBox="0 0 48 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="48" height="48" fill="white" fill-opacity="0.01"/>
<path d="M24 15C26.7614 15 29 12.7614 29 10C29 7.23858 26.7614 5 24 5C21.2386 5 19 7.23858 19 10C19 12.7614 21.2386 15 24 15Z" fill="#2F88FF" stroke="#000000" stroke-width="4"/>
<path d="M24 15V23" stroke="#000000" stroke-width="4" stroke-linecap="round"/>
<path d="M18 33V23L41 23.0128V33" stroke="#000000" stroke-width="4" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M41 41V42" stroke="#000000" stroke-width="5" stroke-linecap="round"/>
<path d="M7 41V42" stroke="#000000" stroke-width="5" stroke-linecap="round"/>
<path d="M18 41V42" stroke="#000000" stroke-width="5" stroke-linecap="round"/>
<path d="M30 41V42" stroke="#000000" stroke-width="5" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 989 B

View File

@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="iso-8859-1"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg fill="#000000" version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"
width="800px" height="800px" viewBox="0 0 973.1 973.1" xml:space="preserve"
>
<g>
<path d="M502.29,788.199h-47c-33.1,0-60,26.9-60,60v64.9c0,33.1,26.9,60,60,60h47c33.101,0,60-26.9,60-60v-64.9
C562.29,815,535.391,788.199,502.29,788.199z"/>
<path d="M170.89,285.8l86.7,10.8c27.5,3.4,53.6-12.4,63.5-38.3c12.5-32.7,29.9-58.5,52.2-77.3c31.601-26.6,70.9-40,117.9-40
c48.7,0,87.5,12.8,116.3,38.3c28.8,25.6,43.1,56.2,43.1,92.1c0,25.8-8.1,49.4-24.3,70.8c-10.5,13.6-42.8,42.2-96.7,85.9
c-54,43.7-89.899,83.099-107.899,118.099c-18.4,35.801-24.8,75.5-26.4,115.301c-1.399,34.1,25.8,62.5,60,62.5h49
c31.2,0,57-23.9,59.8-54.9c2-22.299,5.7-39.199,11.301-50.699c9.399-19.701,33.699-45.701,72.699-78.1
C723.59,477.8,772.79,428.4,795.891,392c23-36.3,34.6-74.8,34.6-115.5c0-73.5-31.3-138-94-193.4c-62.6-55.4-147-83.1-253-83.1
c-100.8,0-182.1,27.3-244.1,82c-52.8,46.6-84.9,101.8-96.2,165.5C139.69,266.1,152.39,283.5,170.89,285.8z"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -5,7 +5,7 @@
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<Message> {
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)

View File

@@ -24,7 +24,7 @@
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(<StyleTuple as Into<iced::theme::Container>>::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(<StyleTuple as Into<iced::theme::Container>>::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(<StyleTuple as Into<iced::theme::Container>>::into(
StyleTuple(style, ElementType::Tooltip),

View File

@@ -32,9 +32,9 @@
};
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),
);

View File

@@ -379,7 +379,7 @@ fn add_or_remove_favorite(&mut self, host: Host, add: bool) {
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);
}

View File

@@ -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<Mutex<InfoTraffic>>,
key: AddressPortPair,
my_interface_addresses: &Vec<Address>,
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<Mutex<InfoTraffic>>,
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<Address>,
) -> TrafficDirection {
let my_interface_addresses_string: Vec<String> = 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<Address>) -> 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<Address>) -> bool {
let mut ret_val = false;
// check if directed broadcast
let my_broadcast_addresses: Vec<String> = 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<u8> = 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<Address>,
) -> 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<String>, Option<Capture<Active>>) {
let cap_result = Capture::from_device(&*device.name)
@@ -420,7 +560,12 @@ pub fn get_capture_result(device: &Device) -> (Option<String>, Option<Capture<Ac
#[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 @@ fn ipv6_many_zeros_but_no_compression() {
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<Address> = 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<Address> = 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);
}
}

View File

@@ -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,
}

View File

@@ -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<String>,
/// 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 @@ fn default() -> Self {
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 @@ pub fn print_gui(&self) -> String {
.unwrap()
.to_string()
.replace('|', "")
.add(&*format!(" {} ", &self.country))
}
pub fn get_host(&self) -> Host {

View File

@@ -7,6 +7,7 @@
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<AppProtocol, DataInfo>,
/// Map of the hosts with their data info
pub hosts: HashMap<Host, (DataInfo, bool)>,
pub hosts: HashMap<Host, DataInfoHost>,
}
impl InfoTraffic {

View File

@@ -3,11 +3,13 @@
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;

View File

@@ -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
}
}

View File

@@ -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
}
}

View File

@@ -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(),
},
));

View File

@@ -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,
}

View File

@@ -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<Mutex<InfoTraffic>>,
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);

View File

@@ -8,14 +8,15 @@
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,
}
},
);
}
}
}

View File

@@ -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()
}

View File

@@ -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,
};

View File

@@ -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 fn get_country_code(
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<Renderer> {
Svg::new(Handle::from_memory(Vec::from(match language {
@@ -306,9 +315,16 @@ pub fn get_flag_from_language_code(language: &str) -> Svg<Renderer> {
.width(Length::Fixed(FLAGS_WIDTH_SMALL))
}
pub fn get_flag_from_country_code(country: &str, width: f32) -> Svg<Renderer> {
fn get_flag_from_country_code(
country: &str,
width: f32,
is_local: bool,
traffic_type: TrafficType,
language: Language,
) -> (Svg<Renderer>, 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<Renderer> {
"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(<StyleTuple as Into<iced::theme::Container>>::into(
StyleTuple(style, ElementType::Tooltip),
))
}

View File

@@ -3,7 +3,7 @@
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