diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e008d2a0..bf83a6a91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ All Sniffnet releases with the relative changes are documented in this file. - Introduced new filtering capabilities to allow users specify custom values of ports and IP addresses ([#414](https://github.com/GyulyVGC/sniffnet/pull/414)) - The size of text and widgets can now be customised by setting a proper zoom value (fixes [#202](https://github.com/GyulyVGC/sniffnet/issues/202) and [#344](https://github.com/GyulyVGC/sniffnet/issues/344)) - Added possibility to totally customize the app's theme via styles defined in TOML files ([#286](https://github.com/GyulyVGC/sniffnet/pull/286) and [#419](https://github.com/GyulyVGC/sniffnet/pull/419)) +- Added support for more link types in addition to Ethernet: raw IP packets and null/loopback packets are now correctly parsed ([#421](https://github.com/GyulyVGC/sniffnet/pull/421)) - IP addresses can now be copied to clipboard from the popup related to a given entry of the connections table, and a new search parameter has been introduced in Inspect page to allow users filter their connections based on IP address values ([#409](https://github.com/GyulyVGC/sniffnet/pull/409)) - Added Japanese translation 🇯🇵 ([#343](https://github.com/GyulyVGC/sniffnet/pull/343)) - Added Uzbek translation 🇺🇿 ([#385](https://github.com/GyulyVGC/sniffnet/pull/385)) diff --git a/Cargo.lock b/Cargo.lock index c04f6e3fa..2c0b0b9f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -201,7 +201,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -279,7 +279,7 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -353,13 +353,13 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f" +checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" dependencies = [ "glob", "libc", - "libloading 0.7.4", + "libloading 0.8.1", ] [[package]] @@ -942,7 +942,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -2118,7 +2118,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -2247,7 +2247,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -2298,7 +2298,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -2330,7 +2330,7 @@ checksum = "b7db010ec5ff3d4385e4f133916faacd9dad0f6a09394c92d825b3aed310fa0a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -2438,7 +2438,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -2560,9 +2560,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.71" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75cb1540fadbd5b8fbccc4dddad2734eba435053f725621c070711a14bb5f4b8" +checksum = "2dd5e8a1f1029c43224ad5898e50140c2aebb1705f19e67c918ebf5b9e797fe1" dependencies = [ "unicode-ident", ] @@ -2584,9 +2584,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.33" +version = "1.0.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a" dependencies = [ "proc-macro2", ] @@ -2851,7 +2851,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.43", + "syn 2.0.44", "unicode-ident", ] @@ -3058,14 +3058,14 @@ checksum = "43576ca501357b9b071ac53cdc7da8ef0cbd9493d8df094cd821777ea6e894d3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] name = "serde_json" -version = "1.0.108" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b" +checksum = "cb0652c533506ad7a2e353cce269330d6afd8bdfb6d75e0ace5b35aacbd7b9e9" dependencies = [ "itoa", "ryu", @@ -3122,7 +3122,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -3394,9 +3394,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.43" +version = "2.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee659fb5f3d355364e1f3e5bc10fb82068efbf824a1e9d1c9504244a6469ad53" +checksum = "92d27c2c202598d05175a6dd3af46824b7f747f8d8e9b14c623f19fa5069735d" dependencies = [ "proc-macro2", "quote", @@ -3457,22 +3457,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.52" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a48fd946b02c0a526b2e9481c8e2a17755e47039164a86c4070446e3a4614d" +checksum = "b2cd5904763bad08ad5513ddbb12cf2ae273ca53fa9f68e843e236ec6dfccc09" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.52" +version = "1.0.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7fbe9b594d6568a6a1443250a7e67d80b74e1e96f6d1715e1e21cc1888291d3" +checksum = "3dcf4a824cce0aeacd6f38ae6f24234c8e80d68632338ebaa1443b5df9e29e19" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] [[package]] @@ -3922,7 +3922,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", "wasm-bindgen-shared", ] @@ -3956,7 +3956,7 @@ checksum = "f0eb82fcb7930ae6219a7ecfd55b217f5f0893484b7a13022ebb2b2bf20b5283" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -4719,5 +4719,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.43", + "syn 2.0.44", ] diff --git a/src/configs/types/config_device.rs b/src/configs/types/config_device.rs index 3e89852bd..a01f891a8 100644 --- a/src/configs/types/config_device.rs +++ b/src/configs/types/config_device.rs @@ -7,6 +7,7 @@ use pcap::{Device, DeviceFlags}; use serde::{Deserialize, Serialize}; use crate::networking::types::my_device::MyDevice; +use crate::networking::types::my_link_type::MyLinkType; #[cfg(not(test))] use crate::SNIFFNET_LOWERCASE; @@ -57,6 +58,7 @@ impl ConfigDevice { name: device.name, desc: device.desc, addresses: Arc::new(Mutex::new(device.addresses)), + link_type: MyLinkType::NotYetAssigned, }; } } @@ -70,6 +72,7 @@ impl ConfigDevice { name: standard_device.name, desc: standard_device.desc, addresses: Arc::new(Mutex::new(standard_device.addresses)), + link_type: MyLinkType::NotYetAssigned, } } } diff --git a/src/countries/country_utils.rs b/src/countries/country_utils.rs index 87e359f6f..49e8990c7 100644 --- a/src/countries/country_utils.rs +++ b/src/countries/country_utils.rs @@ -21,6 +21,7 @@ use crate::countries::types::country::Country; use crate::gui::styles::container::ContainerType; use crate::gui::styles::svg::SvgType; use crate::gui::types::message::Message; +use crate::networking::types::data_info_host::DataInfoHost; use crate::networking::types::traffic_type::TrafficType; use crate::translations::translations_2::{ local_translation, unknown_translation, your_network_adapter_translation, @@ -31,6 +32,7 @@ fn get_flag_from_country( country: Country, width: f32, is_local: bool, + is_loopback: bool, traffic_type: TrafficType, language: Language, ) -> (Svg>, String) { @@ -284,7 +286,11 @@ fn get_flag_from_country( Country::ZM => ZM, Country::ZW => ZW, Country::ZZ => { - if is_local { + if is_loopback { + tooltip = your_network_adapter_translation(language); + svg_style = SvgType::AdaptColor; + COMPUTER + } else if is_local { tooltip = local_translation(language); svg_style = SvgType::AdaptColor; HOME @@ -313,13 +319,21 @@ fn get_flag_from_country( pub fn get_flag_tooltip( country: Country, width: f32, - is_local: bool, - traffic_type: TrafficType, + host_info: &DataInfoHost, language: Language, font: Font, ) -> Tooltip<'static, Message, Renderer> { - let (content, tooltip) = - get_flag_from_country(country, width, is_local, traffic_type, language); + let is_local = host_info.is_local; + let is_loopback = host_info.is_loopback; + let traffic_type = host_info.traffic_type; + let (content, tooltip) = get_flag_from_country( + country, + width, + is_local, + is_loopback, + traffic_type, + language, + ); let mut tooltip = Tooltip::new(content, tooltip, Position::FollowCursor) .font(font) @@ -335,27 +349,30 @@ pub fn get_flag_tooltip( pub fn get_computer_tooltip( is_my_address: bool, + is_local: bool, traffic_type: TrafficType, language: Language, font: Font, ) -> Tooltip<'static, Message, Renderer> { let content = Svg::new(Handle::from_memory(Vec::from( - match (is_my_address, traffic_type) { - (true, _) => COMPUTER, - (false, TrafficType::Multicast) => MULTICAST, - (false, TrafficType::Broadcast) => BROADCAST, - (false, TrafficType::Unicast) => UNKNOWN, + match (is_my_address, is_local, traffic_type) { + (true, _, _) => COMPUTER, + (false, true, _) => HOME, + (false, false, TrafficType::Multicast) => MULTICAST, + (false, false, TrafficType::Broadcast) => BROADCAST, + (false, false, TrafficType::Unicast) => UNKNOWN, }, ))) .style(SvgType::AdaptColor) .width(Length::Fixed(FLAGS_WIDTH_BIG)) .height(Length::Fixed(FLAGS_WIDTH_BIG * 0.75)); - let tooltip = match (is_my_address, traffic_type) { - (true, _) => your_network_adapter_translation(language), - (false, TrafficType::Multicast) => "Multicast".to_string(), - (false, TrafficType::Broadcast) => "Broadcast".to_string(), - (false, TrafficType::Unicast) => unknown_translation(language), + let tooltip = match (is_my_address, is_local, traffic_type) { + (true, _, _) => your_network_adapter_translation(language), + (false, true, _) => local_translation(language), + (false, false, TrafficType::Multicast) => "Multicast".to_string(), + (false, false, TrafficType::Broadcast) => "Broadcast".to_string(), + (false, false, TrafficType::Unicast) => unknown_translation(language), }; Tooltip::new(content, tooltip, Position::FollowCursor) diff --git a/src/gui/pages/connection_details_page.rs b/src/gui/pages/connection_details_page.rs index b4066b119..0d9d9e7e6 100644 --- a/src/gui/pages/connection_details_page.rs +++ b/src/gui/pages/connection_details_page.rs @@ -18,7 +18,9 @@ use crate::gui::styles::text::TextType; use crate::gui::styles::types::gradient_type::GradientType; use crate::gui::types::message::Message; use crate::gui::types::timing_events::TimingEvents; -use crate::networking::manage_packets::{get_address_to_lookup, get_traffic_type, is_my_address}; +use crate::networking::manage_packets::{ + get_address_to_lookup, get_traffic_type, is_local_connection, is_my_address, +}; use crate::networking::types::address_port_pair::AddressPortPair; use crate::networking::types::host::Host; use crate::networking::types::icmp_type::IcmpType; @@ -105,14 +107,7 @@ fn page_content( if let Some((r_dns, host)) = host_option { host_info_col = get_host_info_col(&r_dns, &host, font, language); let host_info = host_info_option.unwrap_or_default(); - let flag = get_flag_tooltip( - host.country, - FLAGS_WIDTH_BIG, - host_info.is_local, - host_info.traffic_type, - language, - font, - ); + let flag = get_flag_tooltip(host.country, FLAGS_WIDTH_BIG, &host_info, language, font); let computer = get_local_tooltip(sniffer, &address_to_lookup, key); if address_to_lookup.eq(&key.address1) { source_caption = source_caption.push(flag); @@ -310,16 +305,15 @@ fn get_local_tooltip( style, language, .. } = sniffer.configs.lock().unwrap().settings; + let local_address = if address_to_lookup.eq(&key.address1) { + &key.address2 + } else { + &key.address1 + }; let my_interface_addresses = &*sniffer.device.addresses.lock().unwrap(); get_computer_tooltip( - is_my_address( - if address_to_lookup.eq(&key.address1) { - &key.address2 - } else { - &key.address1 - }, - my_interface_addresses, - ), + is_my_address(local_address, my_interface_addresses), + is_local_connection(local_address, my_interface_addresses), get_traffic_type( if address_to_lookup.eq(&key.address1) { &key.address2 @@ -338,7 +332,7 @@ fn get_src_or_dest_col( caption: Row<'static, Message, Renderer>, ip: &String, port: Option, - mac: &str, + mac: &Option, font: Font, language: Language, timing_events: &TimingEvents, @@ -348,6 +342,9 @@ fn get_src_or_dest_col( } else { address_translation(language) }; + + let mac_str = if let Some(val) = mac { val } else { "-" }; + Column::new() .spacing(4) .push( @@ -369,7 +366,7 @@ fn get_src_or_dest_col( ) .push(TextType::highlighted_subtitle_with_desc( mac_address_translation(language), - mac, + mac_str, font, )) } diff --git a/src/gui/pages/notifications_page.rs b/src/gui/pages/notifications_page.rs index 0a6ec414d..74a5963e2 100644 --- a/src/gui/pages/notifications_page.rs +++ b/src/gui/pages/notifications_page.rs @@ -312,11 +312,10 @@ fn favorite_notification_log( language: Language, font: Font, ) -> Container<'static, Message, Renderer> { - let domain = logged_notification.host.domain; let country = logged_notification.host.country; - let asn = logged_notification.host.asn; + let asn = &logged_notification.host.asn; - let mut domain_asn_str = domain; + let mut domain_asn_str = logged_notification.host.domain; if !asn.name.is_empty() { domain_asn_str.push_str(&format!(" - {}", asn.name)); } @@ -327,8 +326,7 @@ fn favorite_notification_log( .push(get_flag_tooltip( country, FLAGS_WIDTH_BIG, - logged_notification.data_info_host.is_local, - logged_notification.data_info_host.traffic_type, + &logged_notification.data_info_host, language, font, )) diff --git a/src/gui/pages/overview_page.rs b/src/gui/pages/overview_page.rs index 5d35f6753..ae6064c9f 100644 --- a/src/gui/pages/overview_page.rs +++ b/src/gui/pages/overview_page.rs @@ -41,6 +41,7 @@ use crate::translations::translations_2::{ data_representation_translation, dropped_packets_translation, host_translation, only_top_30_hosts_translation, }; +use crate::translations::translations_3::unsupported_link_type_translation; use crate::utils::formatted_strings::{ get_active_filters_string, get_formatted_bytes_string_with_b, get_percentage_string, }; @@ -140,18 +141,27 @@ fn body_no_packets( language: Language, waiting: &str, ) -> Column<'static, Message, Renderer> { - let adapter_name = device.name.clone(); - let (icon_text, nothing_to_see_text) = if device.addresses.lock().unwrap().is_empty() { + let link_type = device.link_type; + let mut adapter_info = device.name.clone(); + adapter_info.push_str(&format!("\n{}", link_type.full_print_on_one_line(language))); + let (icon_text, nothing_to_see_text) = if !link_type.is_supported() { ( Icon::Warning.to_text().size(60), - no_addresses_translation(language, &adapter_name) + unsupported_link_type_translation(language, &adapter_info) + .horizontal_alignment(Horizontal::Center) + .font(font), + ) + } else if device.addresses.lock().unwrap().is_empty() { + ( + Icon::Warning.to_text().size(60), + no_addresses_translation(language, &adapter_info) .horizontal_alignment(Horizontal::Center) .font(font), ) } else { ( Icon::get_hourglass(waiting.len()).size(60), - waiting_translation(language, &adapter_name) + waiting_translation(language, &adapter_info) .horizontal_alignment(Horizontal::Center) .font(font), ) @@ -295,8 +305,7 @@ fn col_host(width: f32, sniffer: &Sniffer) -> Column<'static, Message, Renderer< .push(get_flag_tooltip( host.country, FLAGS_WIDTH_BIG, - data_info_host.is_local, - data_info_host.traffic_type, + data_info_host, language, font, )) @@ -419,24 +428,13 @@ fn lazy_col_info( style, language, .. } = sniffer.configs.lock().unwrap().settings; let font = style.get_extension().font; - let filtered_bytes = - sniffer.runtime_data.tot_sent_bytes + sniffer.runtime_data.tot_received_bytes; - let all_bytes = sniffer.runtime_data.all_bytes; - let col_device_filters = col_device_filters(language, font, &sniffer.filters, &sniffer.device); + let col_device = col_device(language, font, &sniffer.device); let col_data_representation = col_data_representation(language, font, sniffer.traffic_chart.chart_type); - let col_bytes_packets = col_bytes_packets( - language, - dropped, - total, - filtered, - all_bytes, - filtered_bytes, - font, - ); + let col_bytes_packets = col_bytes_packets(language, dropped, total, filtered, font, sniffer); let content = Column::new() .align_items(Alignment::Center) @@ -445,14 +443,14 @@ fn lazy_col_info( Row::new() .height(Length::Fixed(120.0)) .push( - Scrollable::new(col_device_filters) - .width(Length::Fill) - .direction(Direction::Vertical(ScrollbarType::properties())), + Scrollable::new(col_device) + .width(Length::FillPortion(1)) + .direction(Direction::Horizontal(ScrollbarType::properties())), ) .push(Rule::vertical(25)) - .push(col_data_representation), + .push(col_data_representation.width(Length::FillPortion(1))), ) - .push(Rule::horizontal(25)) + .push(Rule::horizontal(15)) .push( Scrollable::new(col_bytes_packets) .width(Length::Fill) @@ -507,28 +505,25 @@ fn container_chart(sniffer: &Sniffer, font: Font) -> Container Column<'static, Message, Renderer> { + let link_type = device.link_type; #[cfg(not(target_os = "windows"))] let adapter_info = &device.name; #[cfg(target_os = "windows")] - let adapter_name = &device.name; - #[cfg(target_os = "windows")] - let adapter_info = device.desc.as_ref().unwrap_or(adapter_name); + let adapter_info = device.desc.as_ref().unwrap_or(&device.name); Column::new() - .width(Length::FillPortion(1)) + .spacing(10) .push(TextType::highlighted_subtitle_with_desc( network_adapter_translation(language), adapter_info, font, )) - .push(vertical_space(15)) - .push(get_active_filters_col(filters, language, font, false)) + .push(link_type.link_type_col(language, font)) } fn col_data_representation( @@ -536,7 +531,7 @@ fn col_data_representation( font: Font, chart_type: ChartType, ) -> Column<'static, Message, Renderer> { - let mut ret_val = Column::new().spacing(5).width(Length::FillPortion(1)).push( + let mut ret_val = Column::new().spacing(5).push( Text::new(format!("{}:", data_representation_translation(language))) .style(TextType::Subtitle) .font(font), @@ -570,10 +565,14 @@ fn col_bytes_packets( dropped: u32, total: u128, filtered: u128, - all_bytes: u128, - filtered_bytes: u128, font: Font, + sniffer: &Sniffer, ) -> Column<'static, Message, Renderer> { + let filtered_bytes = + sniffer.runtime_data.tot_sent_bytes + sniffer.runtime_data.tot_received_bytes; + let all_bytes = sniffer.runtime_data.all_bytes; + let filters = &sniffer.filters; + let dropped_val = if dropped > 0 { format!( "{} {}", @@ -594,7 +593,8 @@ fn col_bytes_packets( }; Column::new() - .spacing(15) + .spacing(10) + .push(get_active_filters_col(filters, language, font, false)) .push(TextType::highlighted_subtitle_with_desc( filtered_bytes_translation(language), &bytes_value, diff --git a/src/gui/types/runtime_data.rs b/src/gui/types/runtime_data.rs index 6390e48df..ddd1426b5 100644 --- a/src/gui/types/runtime_data.rs +++ b/src/gui/types/runtime_data.rs @@ -1,5 +1,5 @@ //! Module defining the `RunTimeData` struct, useful to to generate chart and to display statistics about network traffic -//! + use std::collections::VecDeque; use crate::notifications::types::logged_notification::LoggedNotification; diff --git a/src/gui/types/sniffer.rs b/src/gui/types/sniffer.rs index 6300f2323..7465108a6 100644 --- a/src/gui/types/sniffer.rs +++ b/src/gui/types/sniffer.rs @@ -24,6 +24,7 @@ use crate::networking::types::filters::Filters; use crate::networking::types::host::Host; use crate::networking::types::ip_collection::AddressCollection; use crate::networking::types::my_device::MyDevice; +use crate::networking::types::my_link_type::MyLinkType; use crate::networking::types::port_collection::PortCollection; use crate::networking::types::search_parameters::SearchParameters; use crate::notifications::notify_and_log::notify_and_log; @@ -351,7 +352,7 @@ impl Sniffer { let current_device_name = &*self.device.name.clone(); self.set_adapter(current_device_name); let device = self.device.clone(); - let (pcap_error, cap) = get_capture_result(&device); + let (pcap_error, cap_result) = get_capture_result(&device); self.pcap_error = pcap_error.clone(); let info_traffic_mutex = self.info_traffic.clone(); *info_traffic_mutex.lock().unwrap() = InfoTraffic::new(); @@ -364,17 +365,19 @@ impl Sniffer { if pcap_error.is_none() { // no pcap error + let cap = cap_result.unwrap(); let current_capture_id = self.current_capture_id.clone(); let filters = self.filters.clone(); let country_mmdb_reader = self.country_mmdb_reader.clone(); let asn_mmdb_reader = self.asn_mmdb_reader.clone(); + self.device.link_type = MyLinkType::from_pcap_link_type(cap.get_datalink()); thread::Builder::new() .name("thread_parse_packets".to_string()) .spawn(move || { parse_packets( ¤t_capture_id, &device, - cap.unwrap(), + cap, &filters, &info_traffic_mutex, &country_mmdb_reader, @@ -406,6 +409,7 @@ impl Sniffer { name: dev.name, desc: dev.desc, addresses: self.device.addresses.clone(), + link_type: MyLinkType::NotYetAssigned, }; break; } diff --git a/src/networking/manage_packets.rs b/src/networking/manage_packets.rs index 694ae554d..2aa958463 100644 --- a/src/networking/manage_packets.rs +++ b/src/networking/manage_packets.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::str::FromStr; use std::sync::{Arc, Mutex}; use chrono::Local; @@ -28,14 +29,12 @@ use crate::{AppProtocol, InfoTraffic, IpVersion, Protocol}; /// Returns the relevant collected information. pub fn analyze_headers( headers: PacketHeaders, - mac_addresses: &mut (String, String), + mac_addresses: &mut (Option, Option), exchanged_bytes: &mut u128, icmp_type: &mut IcmpType, packet_filters_fields: &mut PacketFiltersFields, ) -> Option { - if !analyze_link_header(headers.link, &mut mac_addresses.0, &mut mac_addresses.1) { - return None; - } + analyze_link_header(headers.link, &mut mac_addresses.0, &mut mac_addresses.1); if !analyze_network_header( headers.ip, @@ -71,16 +70,15 @@ pub fn analyze_headers( /// Returns false if packet has to be skipped. fn analyze_link_header( link_header: Option, - mac_address1: &mut String, - mac_address2: &mut String, -) -> bool { - match link_header { - Some(header) => { - *mac_address1 = mac_from_dec_to_hex(header.source); - *mac_address2 = mac_from_dec_to_hex(header.destination); - true - } - _ => false, + mac_address1: &mut Option, + mac_address2: &mut Option, +) { + if let Some(header) = link_header { + *mac_address1 = Some(mac_from_dec_to_hex(header.source)); + *mac_address2 = Some(mac_from_dec_to_hex(header.destination)); + } else { + *mac_address1 = None; + *mac_address2 = None; } } @@ -167,7 +165,7 @@ pub fn modify_or_insert_in_map( info_traffic_mutex: &Arc>, key: &AddressPortPair, my_device: &MyDevice, - mac_addresses: (String, String), + mac_addresses: (Option, Option), icmp_type: IcmpType, exchanged_bytes: u128, application_protocol: AppProtocol, @@ -192,8 +190,13 @@ pub fn modify_or_insert_in_map( // determine traffic direction let source_ip = &key.address1; let destination_ip = &key.address2; - traffic_direction = - get_traffic_direction(source_ip, destination_ip, &my_interface_addresses); + traffic_direction = get_traffic_direction( + source_ip, + destination_ip, + key.port1, + key.port2, + &my_interface_addresses, + ); }; let mut info_traffic = info_traffic_mutex @@ -264,6 +267,7 @@ pub fn reverse_dns_lookup( &my_interface_addresses, traffic_direction, ); + let is_loopback = is_loopback(&address_to_lookup); let is_local = is_local_connection(&address_to_lookup, &my_interface_addresses); let country = get_country(&address_to_lookup, country_db_reader); let asn = get_asn(&address_to_lookup, asn_db_reader); @@ -301,6 +305,7 @@ pub fn reverse_dns_lookup( .or_insert(DataInfoHost { data_info: other_data, is_favorite: false, + is_loopback, is_local, traffic_type, }); @@ -316,6 +321,8 @@ pub fn reverse_dns_lookup( fn get_traffic_direction( source_ip: &String, destination_ip: &String, + source_port: Option, + dest_port: Option, my_interface_addresses: &[Address], ) -> TrafficDirection { let my_interface_addresses_string: Vec = my_interface_addresses @@ -323,6 +330,17 @@ fn get_traffic_direction( .map(|address| address.addr.to_string()) .collect(); + // first let's handle TCP and UDP loopback + if is_loopback(source_ip) && is_loopback(destination_ip) { + if let (Some(sport), Some(dport)) = (source_port, dest_port) { + return if sport > dport { + TrafficDirection::Outgoing + } else { + TrafficDirection::Incoming + }; + } + } + if my_interface_addresses_string.contains(source_ip) { // source is local TrafficDirection::Outgoing @@ -410,8 +428,14 @@ fn is_broadcast_address(address: &str, my_interface_addresses: &[Address]) -> bo false } +fn is_loopback(address_to_lookup: &str) -> bool { + IpAddr::from_str(address_to_lookup) + .unwrap_or(IpAddr::V4(Ipv4Addr::UNSPECIFIED)) + .is_loopback() +} + /// Determines if the connection is local -fn is_local_connection(address_to_lookup: &str, my_interface_addresses: &Vec
) -> bool { +pub fn is_local_connection(address_to_lookup: &str, my_interface_addresses: &Vec
) -> bool { let mut ret_val = false; let address_to_lookup_type = if address_to_lookup.contains(':') { @@ -478,22 +502,18 @@ fn is_local_connection(address_to_lookup: &str, my_interface_addresses: &Vec) -> bool { - let mut ret_val = false; - +pub fn is_my_address(local_address: &String, my_interface_addresses: &Vec
) -> bool { for address in my_interface_addresses { - if address.addr.to_string().eq(address_to_lookup) { - ret_val = true; - break; + if address.addr.to_string().eq(local_address) { + return true; } } - - ret_val + is_loopback(local_address) } /// Determines if the capture opening resolves into an Error pub fn get_capture_result(device: &MyDevice) -> (Option, Option>) { - let cap_result = Capture::from_device(&*device.name) + let cap_result = Capture::from_device(device.to_pcap_device()) .expect("Capture initialization error\n\r") .promisc(true) .snaplen(256) //limit stored packets slice dimension (to keep more in the buffer) @@ -662,30 +682,40 @@ mod tests { let result1 = get_traffic_direction( &"172.20.10.9".to_string(), &"99.88.77.00".to_string(), + Some(99), + Some(99), &address_vec, ); assert_eq!(result1, TrafficDirection::Outgoing); let result2 = get_traffic_direction( &"172.20.10.10".to_string(), &"172.20.10.9".to_string(), + Some(99), + Some(99), &address_vec, ); assert_eq!(result2, TrafficDirection::Incoming); let result3 = get_traffic_direction( &"172.20.10.9".to_string(), &"0.0.0.0".to_string(), + Some(99), + Some(99), &address_vec, ); assert_eq!(result3, TrafficDirection::Outgoing); let result4 = get_traffic_direction( &"0.0.0.0".to_string(), &"172.20.10.9".to_string(), + Some(99), + Some(99), &address_vec, ); assert_eq!(result4, TrafficDirection::Incoming); let result4 = get_traffic_direction( &"0.0.0.0".to_string(), &"172.20.10.10".to_string(), + Some(99), + Some(99), &address_vec, ); assert_eq!(result4, TrafficDirection::Outgoing); diff --git a/src/networking/types/data_info_host.rs b/src/networking/types/data_info_host.rs index b129978fa..68b54d042 100644 --- a/src/networking/types/data_info_host.rs +++ b/src/networking/types/data_info_host.rs @@ -10,6 +10,8 @@ pub struct DataInfoHost { pub data_info: DataInfo, /// Determine if this host is one of the favorites pub is_favorite: bool, + /// Determine if the connection is loopback (the "remote" is loopback) + pub is_loopback: bool, /// Determine if the connection with this host is local pub is_local: bool, /// Determine if the connection with this host is unicast, multicast, or broadcast diff --git a/src/networking/types/info_address_port_pair.rs b/src/networking/types/info_address_port_pair.rs index 2ede47a8c..9c16e517b 100644 --- a/src/networking/types/info_address_port_pair.rs +++ b/src/networking/types/info_address_port_pair.rs @@ -17,9 +17,9 @@ use crate::AppProtocol; #[derive(Clone, Default)] pub struct InfoAddressPortPair { /// Source MAC address - pub mac_address1: String, + pub mac_address1: Option, /// Destination MAC address - pub mac_address2: String, + pub mac_address2: Option, /// Amount of bytes transmitted between the pair. pub transmitted_bytes: u128, /// Amount of packets transmitted between the pair. diff --git a/src/networking/types/mod.rs b/src/networking/types/mod.rs index 2134f3284..8bc652c19 100644 --- a/src/networking/types/mod.rs +++ b/src/networking/types/mod.rs @@ -12,6 +12,7 @@ pub mod info_traffic; pub mod ip_collection; pub mod ip_version; pub mod my_device; +pub mod my_link_type; pub mod packet_filters_fields; pub mod port_collection; pub mod protocol; diff --git a/src/networking/types/my_device.rs b/src/networking/types/my_device.rs index f267a8115..3e347d15b 100644 --- a/src/networking/types/my_device.rs +++ b/src/networking/types/my_device.rs @@ -1,6 +1,8 @@ use std::sync::{Arc, Mutex}; -use pcap::Address; +use pcap::{Address, Device, DeviceFlags}; + +use crate::networking::types::my_link_type::MyLinkType; /// Represents the current inspected device. /// Used to keep in sync the device addresses in case of changes @@ -10,4 +12,21 @@ pub struct MyDevice { pub name: String, pub desc: Option, pub addresses: Arc>>, + pub link_type: MyLinkType, +} + +impl MyDevice { + pub fn to_pcap_device(&self) -> Device { + for device in Device::list().unwrap_or_default() { + if device.name.eq(&self.name) { + return device; + } + } + Device::lookup().unwrap_or(None).unwrap_or(Device { + name: String::new(), + desc: None, + addresses: vec![], + flags: DeviceFlags::empty(), + }) + } } diff --git a/src/networking/types/my_link_type.rs b/src/networking/types/my_link_type.rs new file mode 100644 index 000000000..24d2750cc --- /dev/null +++ b/src/networking/types/my_link_type.rs @@ -0,0 +1,87 @@ +use iced::widget::Column; +use iced::{Font, Renderer}; +use pcap::Linktype; + +use crate::gui::styles::text::TextType; +use crate::gui::types::message::Message; +use crate::translations::translations_3::link_type_translation; +use crate::{Language, StyleType}; + +/// Currently supported link types +#[derive(Copy, Clone)] +pub enum MyLinkType { + Null(Linktype), + Ethernet(Linktype), + RawIp(Linktype), + Loop(Linktype), + IPv4(Linktype), + IPv6(Linktype), + Unsupported(Linktype), + NotYetAssigned, +} + +impl MyLinkType { + pub fn is_supported(self) -> bool { + !matches!(self, Self::Unsupported(_) | Self::NotYetAssigned) + } + + pub fn from_pcap_link_type(link_type: Linktype) -> Self { + match link_type { + Linktype::NULL => Self::Null(link_type), + Linktype::ETHERNET => Self::Ethernet(link_type), + Linktype(12) => Self::RawIp(link_type), + Linktype::LOOP => Self::Loop(link_type), + Linktype::IPV4 => Self::IPv4(link_type), + Linktype::IPV6 => Self::IPv6(link_type), + _ => Self::Unsupported(link_type), + } + } + + pub fn full_print_on_one_line(self, language: Language) -> String { + match self { + Self::Null(l) + | Self::Ethernet(l) + | Self::RawIp(l) + | Self::Loop(l) + | Self::IPv4(l) + | Self::IPv6(l) + | Self::Unsupported(l) => { + format!( + "{}: {} ({})", + link_type_translation(language), + l.get_name().unwrap_or(l.0.to_string()), + l.get_description().unwrap_or(String::new()) + ) + } + Self::NotYetAssigned => String::new(), + } + } + + pub fn link_type_col( + self, + language: Language, + font: Font, + ) -> Column<'static, Message, Renderer> { + match self { + Self::Null(l) + | Self::Ethernet(l) + | Self::RawIp(l) + | Self::Loop(l) + | Self::IPv4(l) + | Self::IPv6(l) + | Self::Unsupported(l) => { + let link_info = format!( + "{} ({})", + l.get_name().unwrap_or(l.0.to_string()), + l.get_description().unwrap_or(String::new()) + ); + TextType::highlighted_subtitle_with_desc( + link_type_translation(language), + &link_info, + font, + ) + } + Self::NotYetAssigned => Column::new().height(0), + } + } +} diff --git a/src/report/get_report_entries.rs b/src/report/get_report_entries.rs index aa0f2480e..0010df1ad 100644 --- a/src/report/get_report_entries.rs +++ b/src/report/get_report_entries.rs @@ -120,8 +120,7 @@ pub fn get_searched_entries(sniffer: &Sniffer) -> (Vec, usize) { let flag = get_flag_tooltip( host.country, FLAGS_WIDTH_SMALL, - host_info.is_local, - host_info.traffic_type, + host_info, language, style.get_extension().font, ); diff --git a/src/secondary_threads/parse_packets.rs b/src/secondary_threads/parse_packets.rs index 33ac999e5..338ca49e2 100644 --- a/src/secondary_threads/parse_packets.rs +++ b/src/secondary_threads/parse_packets.rs @@ -1,11 +1,12 @@ //! Module containing functions executed by the thread in charge of parsing sniffed packets and //! inserting them in the shared map. +use std::io::ErrorKind; use std::sync::{Arc, Mutex}; use std::thread; -use etherparse::PacketHeaders; -use pcap::{Active, Capture}; +use etherparse::{PacketHeaders, ReadError}; +use pcap::{Active, Capture, Packet}; use crate::mmdb::types::mmdb_reader::MmdbReader; use crate::networking::manage_packets::{ @@ -17,6 +18,7 @@ use crate::networking::types::filters::Filters; use crate::networking::types::icmp_type::IcmpType; use crate::networking::types::info_address_port_pair::InfoAddressPortPair; use crate::networking::types::my_device::MyDevice; +use crate::networking::types::my_link_type::MyLinkType; use crate::networking::types::packet_filters_fields::PacketFiltersFields; use crate::InfoTraffic; @@ -33,6 +35,8 @@ pub fn parse_packets( ) { let capture_id = *current_capture_id.lock().unwrap(); + let my_link_type = MyLinkType::from_pcap_link_type(cap.get_datalink()); + loop { match cap.next_packet() { Err(_) => { @@ -45,152 +49,193 @@ pub fn parse_packets( if *current_capture_id.lock().unwrap() != capture_id { return; } - match PacketHeaders::from_ethernet_slice(&packet) { - Err(_) => { + if let Ok(headers) = get_sniffable_headers(&packet, my_link_type) { + let mut exchanged_bytes = 0; + let mut mac_addresses = (None, None); + let mut icmp_type = IcmpType::default(); + let mut packet_filters_fields = PacketFiltersFields::default(); + + let key_option = analyze_headers( + headers, + &mut mac_addresses, + &mut exchanged_bytes, + &mut icmp_type, + &mut packet_filters_fields, + ); + if key_option.is_none() { continue; } - Ok(headers) => { - let mut exchanged_bytes = 0; - let mut mac_addresses = (String::new(), String::new()); - let mut icmp_type = IcmpType::default(); - let mut packet_filters_fields = PacketFiltersFields::default(); - - let key_option = analyze_headers( - headers, - &mut mac_addresses, - &mut exchanged_bytes, - &mut icmp_type, - &mut packet_filters_fields, - ); - if key_option.is_none() { - continue; - } - let key = key_option.unwrap(); - let application_protocol = get_app_protocol(key.port1, key.port2); - let mut new_info = InfoAddressPortPair::default(); - - let passed_filters = filters.matches(&packet_filters_fields); - if passed_filters { - new_info = modify_or_insert_in_map( - info_traffic_mutex, - &key, - device, - mac_addresses, - icmp_type, - exchanged_bytes, - application_protocol, - ); - } + let key = key_option.unwrap(); + let application_protocol = get_app_protocol(key.port1, key.port2); + let mut new_info = InfoAddressPortPair::default(); - let mut info_traffic = info_traffic_mutex - .lock() - .expect("Error acquiring mutex\n\r"); - //increment number of sniffed packets and bytes - info_traffic.all_packets += 1; - info_traffic.all_bytes += exchanged_bytes; - // update dropped packets number - if let Ok(stats) = cap.stats() { - info_traffic.dropped_packets = stats.dropped; - } + let passed_filters = filters.matches(&packet_filters_fields); + if passed_filters { + new_info = modify_or_insert_in_map( + info_traffic_mutex, + &key, + device, + mac_addresses, + icmp_type, + exchanged_bytes, + application_protocol, + ); + } - if passed_filters { - info_traffic.add_packet(exchanged_bytes, new_info.traffic_direction); + let mut info_traffic = info_traffic_mutex + .lock() + .expect("Error acquiring mutex\n\r"); + //increment number of sniffed packets and bytes + info_traffic.all_packets += 1; + info_traffic.all_bytes += exchanged_bytes; + // update dropped packets number + if let Ok(stats) = cap.stats() { + info_traffic.dropped_packets = stats.dropped; + } + + if passed_filters { + info_traffic.add_packet(exchanged_bytes, new_info.traffic_direction); - // check the rDNS status of this address and act accordingly - let address_to_lookup = - get_address_to_lookup(&key, new_info.traffic_direction); - let r_dns_already_resolved = info_traffic - .addresses_resolved + // check the rDNS status of this address and act accordingly + let address_to_lookup = + get_address_to_lookup(&key, new_info.traffic_direction); + let r_dns_already_resolved = info_traffic + .addresses_resolved + .contains_key(&address_to_lookup); + let mut r_dns_waiting_resolution = false; + if !r_dns_already_resolved { + r_dns_waiting_resolution = info_traffic + .addresses_waiting_resolution .contains_key(&address_to_lookup); - let mut r_dns_waiting_resolution = false; - if !r_dns_already_resolved { - r_dns_waiting_resolution = info_traffic - .addresses_waiting_resolution - .contains_key(&address_to_lookup); - } + } - match (r_dns_waiting_resolution, r_dns_already_resolved) { - (false, false) => { - // rDNS not requested yet (first occurrence of this address to lookup) + match (r_dns_waiting_resolution, r_dns_already_resolved) { + (false, false) => { + // rDNS not requested yet (first occurrence of this address to lookup) - // Add this address to the map of addresses waiting for a resolution - // Useful to NOT perform again a rDNS lookup for this entry - info_traffic.addresses_waiting_resolution.insert( - address_to_lookup, - DataInfo::new_with_first_packet( - exchanged_bytes, + // Add this address to the map of addresses waiting for a resolution + // Useful to NOT perform again a rDNS lookup for this entry + info_traffic.addresses_waiting_resolution.insert( + address_to_lookup, + DataInfo::new_with_first_packet( + exchanged_bytes, + new_info.traffic_direction, + ), + ); + + // launch new thread to resolve host name + let key2 = key.clone(); + let info_traffic2 = info_traffic_mutex.clone(); + let device2 = device.clone(); + let country_db_reader_2 = country_mmdb_reader.clone(); + let asn_db_reader_2 = asn_mmdb_reader.clone(); + thread::Builder::new() + .name("thread_reverse_dns_lookup".to_string()) + .spawn(move || { + reverse_dns_lookup( + &info_traffic2, + &key2, new_info.traffic_direction, - ), - ); - - // launch new thread to resolve host name - let key2 = key.clone(); - let info_traffic2 = info_traffic_mutex.clone(); - let device2 = device.clone(); - let country_db_reader_2 = country_mmdb_reader.clone(); - let asn_db_reader_2 = asn_mmdb_reader.clone(); - thread::Builder::new() - .name("thread_reverse_dns_lookup".to_string()) - .spawn(move || { - reverse_dns_lookup( - &info_traffic2, - &key2, - new_info.traffic_direction, - &device2, - &country_db_reader_2, - &asn_db_reader_2, - ); - }) - .unwrap(); - } - (true, false) => { - // waiting for a previously requested rDNS resolution - // update the corresponding waiting address data - info_traffic - .addresses_waiting_resolution - .entry(address_to_lookup) - .and_modify(|data_info| { - data_info.add_packet( - exchanged_bytes, - new_info.traffic_direction, - ); - }); - } - (_, true) => { - // rDNS already resolved - // update the corresponding host's data info - let host = info_traffic - .addresses_resolved - .get(&address_to_lookup) - .unwrap() - .1 - .clone(); - info_traffic.hosts.entry(host).and_modify(|data_info_host| { - data_info_host.data_info.add_packet( + &device2, + &country_db_reader_2, + &asn_db_reader_2, + ); + }) + .unwrap(); + } + (true, false) => { + // waiting for a previously requested rDNS resolution + // update the corresponding waiting address data + info_traffic + .addresses_waiting_resolution + .entry(address_to_lookup) + .and_modify(|data_info| { + data_info.add_packet( exchanged_bytes, new_info.traffic_direction, ); }); - } } - - //increment the packet count for the sniffed app protocol - info_traffic - .app_protocols - .entry(application_protocol) - .and_modify(|data_info| { - data_info + (_, true) => { + // rDNS already resolved + // update the corresponding host's data info + let host = info_traffic + .addresses_resolved + .get(&address_to_lookup) + .unwrap() + .1 + .clone(); + info_traffic.hosts.entry(host).and_modify(|data_info_host| { + data_info_host + .data_info .add_packet(exchanged_bytes, new_info.traffic_direction); - }) - .or_insert(DataInfo::new_with_first_packet( - exchanged_bytes, - new_info.traffic_direction, - )); + }); + } } + + //increment the packet count for the sniffed app protocol + info_traffic + .app_protocols + .entry(application_protocol) + .and_modify(|data_info| { + data_info.add_packet(exchanged_bytes, new_info.traffic_direction); + }) + .or_insert(DataInfo::new_with_first_packet( + exchanged_bytes, + new_info.traffic_direction, + )); } } } } } } + +fn get_sniffable_headers<'a>( + packet: &'a Packet, + my_link_type: MyLinkType, +) -> Result, ReadError> { + match my_link_type { + MyLinkType::Ethernet(_) => PacketHeaders::from_ethernet_slice(packet), + MyLinkType::RawIp(_) | MyLinkType::IPv4(_) | MyLinkType::IPv6(_) => { + PacketHeaders::from_ip_slice(packet) + } + MyLinkType::Null(_) | MyLinkType::Loop(_) => from_null_slice(packet), + MyLinkType::Unsupported(_) | MyLinkType::NotYetAssigned => { + PacketHeaders::from_ethernet_slice(packet) + } + } +} + +fn from_null_slice(packet: &[u8]) -> Result { + if packet.len() <= 4 { + return Err(ReadError::UnexpectedEndOfSlice(packet.len())); + } + + let is_valid_af_inet = { + // based on https://wiki.wireshark.org/NullLoopback.md (2023-12-31) + fn matches(value: u32) -> bool { + match value { + // 2 = IPv4 on all platforms + // 24, 28, or 30 = IPv6 depending on platform + 2 | 24 | 28 | 30 => true, + _ => false, + } + } + let h = &packet[..4]; + let b = [h[0], h[1], h[2], h[3]]; + // check both big endian and little endian representations + // as some OS'es use native endianess and others use big endian + matches(u32::from_le_bytes(b)) || matches(u32::from_be_bytes(b)) + }; + + if is_valid_af_inet { + PacketHeaders::from_ip_slice(&packet[4..]) + } else { + Err(ReadError::IoError(std::io::Error::new( + ErrorKind::InvalidData, + "Invalid AF_INET / AF_INET6 value", + ))) + } +} diff --git a/src/translations/translations.rs b/src/translations/translations.rs index 31d0a3ba4..361047d2f 100644 --- a/src/translations/translations.rs +++ b/src/translations/translations.rs @@ -451,63 +451,64 @@ pub fn no_addresses_translation( language: Language, adapter: &str, ) -> Text<'static, Renderer> { + let network_adapter_translation = network_adapter_translation(language); Text::new(match language { Language::EN => format!("No traffic can be observed because the adapter you selected has no active addresses...\n\n\ - Network adapter: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ If you are sure you are connected to the internet, try choosing a different adapter."), Language::IT => format!("Non è osservabile alcun traffico perché l'adattatore di rete selezionato non ha indirizzi attivi...\n\n\ - Adattatore di rete: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Se sei sicuro di essere connesso ad internet, prova a scegliere un adattatore diverso."), Language::FR => format!("Aucun trafic ne peut être observé, car la carte réseau que vous avez saisie n'a pas d'adresse...\n\n\ - Carte réseau : {adapter}\n\n\ + {network_adapter_translation} : {adapter}\n\n\ Si vous êtes sûr d'être connecté à internet, essayez une autre carte."), Language::ES => format!("No se puede observar ningún tráfico porque el adaptador seleccionado no tiene direcciones activas...\n\n\ - Adaptador de red : {adapter}\n\n\ + {network_adapter_translation} : {adapter}\n\n\ Si estás seguro de que estás conectado a Internet, prueba a elegir otro adaptador."), Language::PL => format!("Nie można zaobserwować żadnego ruchu, ponieważ wybrany adapter nie ma aktywnych adresów...\n\n\ - Adapter sieciowy: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Jeśli jesteś pewien, że jesteś podłączony do internetu, spróbuj wybrać inny adapter."), Language::DE => format!("Es kann kein Netzwerkverkehr beobachtet werden, weil der Adapter keine aktiven Adressen hat...\n\n\ - Netzwerkadapter: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Wenn du dir sicher bist, dass du mit dem Internet verbunden bist, probier einen anderen Adapter auszuwählen."), Language::UK => format!("Не зафіксовано жодного мережевого трафіку тому що вибраний адаптер немає активних адрес... \n\n\ - Мережквий адаптер: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Якщо Ти впевнений, що підключений до інтернету, спробуй вибрати інший адаптер."), Language::ZH => format!("您选择的网络适配器当前无活动网络...\n\n\ - 网络适配器: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ 如果您确信您已成功连接互联网, 请尝试选择其他网络适配器."), Language::RO => format!("Niciun trafic nu poate fi observat deoarece adaptorul selectat nu are adrese active...\n\n\ - Adaptor de rețea: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Dacă sunteți sigur că sunteți conectat la internet, încercați să alegeți un alt adaptor."), Language::KO => format!("선택한 어댑터에 유효한 주소가 없기 때문에 트래픽을 확인할 수 없습니다...\n\n\ - 네트워크 어뎁터: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ 인터넷이 연결되어있다면 다른 어댑터로 시도해보세요."), Language::TR => format!("Seçtiğiniz adaptör aktif bir adrese sahip olmadığı için hiç bir trafik izlenemez...\n\n\ - Ağ adaptörü: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Eğer gerçekten internete bağlı olduğunuza eminseniz, başka bir adaptör seçmeyi deneyiniz."), Language::RU => format!("Наблюдение за трафиком не возможно, потому что Вы выбрали интерфейс без активного адреса...\n\n\ - Сетевой интерфейс: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Если Вы уверены, что подключены к Интернету, попробуйте выбрать другой интерфейс."), Language::PT => format!("Não é possível observar tráfego porque o adaptador que selecionou não tem endereços ativos...\n\n\ - Adaptador de rede: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Se tiver a certeza que está ligado à internet, tente escolher um adaptador diferente."), Language::EL => format!("Δεν μπορεί να ανιχνευθεί κίνηση επειδή ο προσαρμογέας που επέλεξες δεν έχει ενεργές διευθύνσεις...\n\n\ - Προσαρμογέας δικτύου: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Αν είσαι σίγουρος ότι είσαι συνδεδεμένος στο διαδίκτυο, δοκίμασε αν επιλέξεις έναν διαφορετικό προσαρμογέα."), // Language::FA => format!("هیچ آمد و شدی قابل مشاهده نیست چون مبدلی که انتخاب کرده اید هیچ نشانی فعالی ندارد...\n\n\ // مبدل شبکه: {adapter}\n\n\ // اگر مطمئن هستید به اینترنت وصل هستید، سعی کنید مبدل متفاوتی را انتخاب کنید."), Language::SV => format!("Det går inte att observa någon trafik eftersom den valda adaptern inte har några aktiva adresser ...\n\n\ - Nätverksadapter: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Om du är säker att du är ansluten till internet, testa att välja en annan adapter."), Language::FI => format!("Liikennettä ei voitu havainnoida, koska valitulla sovittimella ei ole aktiivista osoitetta...\n\n\ - Verkkosovitin: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Jos olet varma että sinulla on internet-yhteys, kokeile valita toinen verkkosovitin."), Language::JA => format!("選択されたアダプターが有効なアドレスを持っていないため、トラフィックを観測できていません...\n\n\ - ネットワーク アダプター: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ インターネットに接続しているか確認し、別のネットワーク アダプターを試してください。"), Language::UZ => format!("Trafik kuzatilmaydi, chunki siz tanlagan adapterda faol manzillar yo'q...\n\n\ - Tarmoq adapteri: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Internetga ulanganingizga ishonchingiz komil bo'lsa, boshqa adapterni tanlashga harakat qiling"), }) } @@ -516,64 +517,65 @@ pub fn waiting_translation( language: Language, adapter: &str, ) -> Text<'static, Renderer> { + let network_adapter_translation = network_adapter_translation(language); Text::new(match language { Language::EN => format!("No traffic has been observed yet. Waiting for network packets...\n\n\ - Network adapter: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Are you sure you are connected to the internet and you have selected the correct adapter?"), Language::IT => format!("Nessun tipo di traffico è stato osservato finora. Attendo pacchetti di rete...\n\n\ - Adattatore di rete: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Sei sicuro di esser connesso ad internet e di aver selezionato l'adattatore corretto?"), Language::FR => format!("Aucun trafic n'a été capturé pour le moment. En attente de paquets...\n\n\ - Carte réseau : {adapter}\n\n\ + {network_adapter_translation} : {adapter}\n\n\ Êtes-vous sûr d'être connecté à internet et d'avoir selectionné la bonne carte réseau ?"), Language::ES => format!("Aún no se ha captado tráfico. Esperando paquetes...\n\n\ - Adaptador de red : {adapter}\n\n\ + {network_adapter_translation} : {adapter}\n\n\ ¿Está seguro de que está conectado a Internet y ha seleccionado la tarjeta de red correcta?"), Language::PL => format!("Nie zaobserowano żadnego ruchu sieciowego. Oczekiwanie na pakiety...\n\n\ - Adapter sieciowy: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Czy na pewno jesteś podłączony do internetu i wybrałeś właściwy adapter?"), Language::DE => format!("Noch kein Netzwerkverkehr beobachtet. Warte auf Pakete...\n\n\ - Netzwerkadapter: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Bist du sicher, dass du mit dem Internet verbunden bist und den richtigen Adapter ausgewählt hast?"), Language::UK => format!("Не зафіксовано жодного мережевого трафіку. Очікування на пакети...\n\n\ - Мережквий адаптер: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Чи Ти дійсно підключений до інтернету і вибрав відповідний мережевий адаптер?"), Language::ZH => format!("暂无流量数据. 等待网络活动中......\n\n\ - 网络适配器: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ 您确信您已成功连接到互联网, 并选择了当前正在使用的的网络适配器吗?"), Language::RO => format!("Nu a fost observat încă trafic. Se așteaptă pachetele de rețea...\n\n\ - Adaptor de rețea: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Ești sigur că ești conectat la internet și ai selectat adaptorul corect?"), Language::KO => format!("아직 트래픽이 관찰되지 않았습니다. 네트워크 패킷 대기 중...\n\n\ - 네트워크 어뎁터: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ 인터넷에 연결되어 있고 올바른 어댑터를 선택하셨습니까?"), Language::TR => format!("Henüz bir trafik algılanamadı. Ağ paketleri için bekleniyor...\n\n\ - Ağ adaptörü: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ İnternete bağlı olduğunuza ve doğru adaptörü seçtiğinize emin misiniz?"), Language::RU => format!("Трафик не обнаружен. Ожидаем сетевые пакеты...\n\n\ - Сетевой интерфейс: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Вы уверены, что подключены к Интернету и выбрали правильный интерфейс?"), Language::PT => format!("Ainda não foi observado tráfego. Aguardando por pacotes...\n\n\ - Adaptador de rede: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Tem a certeza de que está ligado à internet e selecionou o adaptador correto?"), Language::EL => format!("Δεν έχει παρατηρηθεί κίνηση μέχρι στιγμής. Ανέμενε για πακέτα δικτύου...\n\n\ - Προσαρμογέας δικτύου: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Είσαι σίγουρος ότι είσαι συνδεδεμένος στο διαδίκτυο και ότι έχεις επιλέξει τον σωστό προσαρμογέα;"), // Language::FA => format!("هنوز هیچ آمد و شدی مشاهده نشده است. در حال انتظار برای بسته های شبکه...\n\n // مبدل شبکه: {adapter}\n\n // آیا مطمئن هستید به اینترنت وصل هستید و مبدل درست را انتخاب کرده اید؟"), Language::SV => format!("Ingen trafik har observerats ännu. Väntar på paket ...\n\n\ - Nätverksadapter: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Är du säker på att du är ansluten till internet och att du har valt rätt adapter?"), Language::FI => format!("Ei vielä havaittua liikennettä. Odotetaan verkkopaketteja...\n\n\ - Verkkosovitin: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Onhan sinulla varmasti internet-yhteys ja olet valinnut oikean verkkosovittimen."), Language::JA => format!("トラフィックがまだ観測できていません。ネットワーク パケットを待っています...\n\n\ - ネットワーク アダプター: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ インターネットに接続していて、正しいアダプターを選択していますか?"), Language::UZ => format!( "Hali hech qanday trafik aniqlanmadi. Tarmoq paketlari kutilmoqda...\n\n\ - Tarmoq adapteri: {adapter}\n\n\ + {network_adapter_translation}: {adapter}\n\n\ Internetga ulanganingizga va to'g'ri adapterni tanlaganingizga ishonchingiz komilmi?"), }) } diff --git a/src/translations/translations_3.rs b/src/translations/translations_3.rs index 77d6041e4..163af584f 100644 --- a/src/translations/translations_3.rs +++ b/src/translations/translations_3.rs @@ -1,6 +1,10 @@ #![allow(clippy::match_same_arms)] -use crate::Language; +use iced::widget::Text; +use iced::Renderer; + +use crate::translations::translations::network_adapter_translation; +use crate::{Language, StyleType}; // This is referred to settings (General settings) pub fn general_translation(language: Language) -> &'static str { @@ -81,3 +85,26 @@ pub fn messages_translation(language: Language) -> &'static str { _ => "Messages", } } + +pub fn link_type_translation(language: Language) -> &'static str { + match language { + Language::EN => "Link type", + Language::IT => "Tipo di collegamento", + _ => "Link type", + } +} + +pub fn unsupported_link_type_translation( + language: Language, + adapter: &str, +) -> Text<'static, Renderer> { + let mut string = match language { + Language::EN => "The link type associated with this adapter is not supported by Sniffnet yet...", + Language::IT => "Il tipo di collegamento associato a questo adattatore di rete non è ancora supportato da Sniffnet...", + _ => "The link type associated with this adapter is not supported by Sniffnet yet...", + }.to_string(); + + let network_adapter_translation = network_adapter_translation(language); + string.push_str(&format!("\n\n{network_adapter_translation}: {adapter}")); + Text::new(string) +}