From 2a8a490099af556738bb490847ec4f29bdf88ffa Mon Sep 17 00:00:00 2001 From: shellrow Date: Sat, 9 Aug 2025 23:22:32 +0900 Subject: [PATCH 1/4] Update dependencies --- Cargo.toml | 23 +++++++++++------------ src/net/stat.rs | 8 ++++---- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8cd4f86..1f82957 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,9 +19,9 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" tracing = { version = "0.1" } tracing-subscriber = { version = "0.3", features = ["time", "chrono"] } -netdev = { version = "0.36", features = ["serde"] } -nex = { version = "0.22", features = ["serde"] } -tokio = { version = "1.38" } +netdev = { version = "0.37", features = ["serde"] } +nex = { version = "0.23", features = ["serde"] } +tokio = { version = "1" } clap = { version = "4.5", features = ["cargo"] } crossterm = "0.27" rand = "0.8" @@ -32,20 +32,19 @@ futures = {version = "0.3"} netsock = { version = "0.3", features = ["serde"] } #reqwest = { version="0.12", default-features = false, features = ["json", "rustls-tls", "stream"] } chrono = { version = "0.4", features = ["serde"] } -time = { version = "0.3", features = ["local-offset"] } ipnet = { version = "2.11" } home = "0.5" termtree = "0.5" indicatif = { version = "0.18" } inquire = "0.6" -#ndb-oui = { version = "0.2", features = ["bundled"] } -ndb-tcp-service = { version = "0.2", features = ["bundled"] } -ndb-udp-service = { version = "0.2", features = ["bundled"] } -ndb-as = { version = "0.2", features = ["bundled"] } -ndb-ipv4-asn = { version = "0.2", features = ["bundled"] } -ndb-ipv6-asn = { version = "0.2", features = ["bundled"] } -ndb-ipv4-country = { version = "0.2", features = ["bundled"] } -ndb-ipv6-country = { version = "0.2", features = ["bundled"] } +#ndb-oui = { version = "0.3", features = ["bundled"] } +ndb-tcp-service = { version = "0.3", features = ["bundled"] } +ndb-udp-service = { version = "0.3", features = ["bundled"] } +ndb-as = { version = "0.3", features = ["bundled"] } +ndb-ipv4-asn = { version = "0.3", features = ["bundled"] } +ndb-ipv6-asn = { version = "0.3", features = ["bundled"] } +ndb-ipv4-country = { version = "0.3", features = ["bundled"] } +ndb-ipv6-country = { version = "0.3", features = ["bundled"] } [target.'cfg(windows)'.dependencies] winreg = "0.50" diff --git a/src/net/stat.rs b/src/net/stat.rs index f747e76..05ad5d8 100644 --- a/src/net/stat.rs +++ b/src/net/stat.rs @@ -795,11 +795,11 @@ impl NetStatData { country_code: { if nex::net::ip::is_global_ip(&host.ip_addr) { match host.ip_addr { - IpAddr::V4(ipv4) => match ipv4_country_db.lookup(ipv4) { + IpAddr::V4(ipv4) => match ipv4_country_db.lookup(&ipv4) { Some(country) => country.to_string(), None => "N/A".to_string(), }, - IpAddr::V6(ipv6) => match ipv6_country_db.lookup(ipv6) { + IpAddr::V6(ipv6) => match ipv6_country_db.lookup(&ipv6) { Some(country) => country.to_string(), None => "N/A".to_string(), }, @@ -812,11 +812,11 @@ impl NetStatData { if nex::net::ip::is_global_ip(&host.ip_addr) { match host.ip_addr { IpAddr::V4(ipv4) => ipv4_asn_db - .lookup(ipv4) + .lookup(&ipv4) .and_then(|asn| as_db.get_name(*asn)) .map_or_else(|| String::from("N/A"), |asn| asn.to_string()), IpAddr::V6(ipv6) => ipv6_asn_db - .lookup(ipv6) + .lookup(&ipv6) .and_then(|asn| as_db.get_name(*asn)) .map_or_else(|| String::from("N/A"), |asn| asn.to_string()), } From e4c2c18cebb9593719d3136b0796203c5ff5faf9 Mon Sep 17 00:00:00 2001 From: shellrow Date: Sat, 9 Aug 2025 23:33:43 +0900 Subject: [PATCH 2/4] Remove unused --- Cargo.toml | 2 - src/db/ip.rs | 0 src/db/mod.rs | 15 ------- src/db/oui.rs | 36 --------------- src/db/service.rs | 104 -------------------------------------------- src/main.rs | 1 - src/net/http.rs | 66 ---------------------------- src/net/mod.rs | 1 - src/net/stat.rs | 3 -- src/notification.rs | 28 ------------ 10 files changed, 256 deletions(-) delete mode 100644 src/db/ip.rs delete mode 100644 src/db/oui.rs delete mode 100644 src/db/service.rs delete mode 100644 src/net/http.rs delete mode 100644 src/notification.rs diff --git a/Cargo.toml b/Cargo.toml index 1f82957..a0c760c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,14 +30,12 @@ comfy-table = "7.1" hickory-resolver = { version = "0.24" } futures = {version = "0.3"} netsock = { version = "0.3", features = ["serde"] } -#reqwest = { version="0.12", default-features = false, features = ["json", "rustls-tls", "stream"] } chrono = { version = "0.4", features = ["serde"] } ipnet = { version = "2.11" } home = "0.5" termtree = "0.5" indicatif = { version = "0.18" } inquire = "0.6" -#ndb-oui = { version = "0.3", features = ["bundled"] } ndb-tcp-service = { version = "0.3", features = ["bundled"] } ndb-udp-service = { version = "0.3", features = ["bundled"] } ndb-as = { version = "0.3", features = ["bundled"] } diff --git a/src/db/ip.rs b/src/db/ip.rs deleted file mode 100644 index e69de29..0000000 diff --git a/src/db/mod.rs b/src/db/mod.rs index 6a764b1..60d9e67 100644 --- a/src/db/mod.rs +++ b/src/db/mod.rs @@ -1,5 +1,4 @@ use anyhow::Result; -//use ndb_oui::OuiDb; use ndb_as::AsDb; use ndb_ipv4_asn::Ipv4AsnDb; use ndb_ipv4_country::Ipv4CountryDb; @@ -9,10 +8,6 @@ use ndb_tcp_service::TcpServiceDb; use ndb_udp_service::UdpServiceDb; use std::sync::{OnceLock, RwLock}; -//pub mod oui; -//pub mod service; - -//pub static OUI_DB: OnceLock> = OnceLock::new(); pub static TCP_SERVICE_DB: OnceLock> = OnceLock::new(); pub static UDP_SERVICE_DB: OnceLock> = OnceLock::new(); pub static AS_DB: OnceLock> = OnceLock::new(); @@ -26,7 +21,6 @@ pub fn init_databases() -> Result<()> { tracing::info!("Initializing databases..."); init_tcp_service_db()?; init_udp_service_db()?; - //init_oui_db()?; init_as_db()?; init_ipv4_asn_db()?; init_ipv6_asn_db()?; @@ -36,15 +30,6 @@ pub fn init_databases() -> Result<()> { Ok(()) } -/* pub fn init_oui_db() -> Result<()> { - // Initialize OUI database - let oui_db = OuiDb::bundled(); - OUI_DB - .set(RwLock::new(oui_db)) - .map_err(|_| anyhow::anyhow!("Failed to set OUI_DB in OnceLock"))?; - Ok(()) -} */ - pub fn init_tcp_service_db() -> Result<()> { // Initialize TCP Service database let tcp_service_db = TcpServiceDb::bundled(); diff --git a/src/db/oui.rs b/src/db/oui.rs deleted file mode 100644 index afa3207..0000000 --- a/src/db/oui.rs +++ /dev/null @@ -1,36 +0,0 @@ -use anyhow::Result; -use ndb_oui::OuiDb; - -#[cfg(not(feature = "bundled"))] -use std::path::PathBuf; - -pub const OUI_CSV_NAME: &str = "oui.csv"; -pub const OUI_R2_URL: &str = "https://r2.ntap.io/oui.csv"; - -#[cfg(not(feature = "bundled"))] -pub fn get_oui_db_filepath() -> Option { - match crate::sys::get_database_dir_path() { - Some(mut db_dir) => { - db_dir.push(OUI_CSV_NAME); - Some(db_dir) - } - None => { - eprintln!("Error: Could not get database directory path"); - None - } - } -} - -#[cfg(feature = "bundled")] -pub fn get_oui_db() -> Result { - Ok(OuiDb::bundled()) -} - -#[cfg(not(feature = "bundled"))] -pub fn get_oui_db() -> Result { - let path = get_oui_db_filepath() - .ok_or_else(|| anyhow::anyhow!("Failed to get OUI database file path"))?; - let reader = std::fs::File::open(path) - .map_err(|e| anyhow::anyhow!("Failed to open OUI database file: {}", e))?; - OuiDb::from_csv(reader) -} diff --git a/src/db/service.rs b/src/db/service.rs deleted file mode 100644 index c41298e..0000000 --- a/src/db/service.rs +++ /dev/null @@ -1,104 +0,0 @@ -use anyhow::Result; -use ndb_tcp_service::TcpServiceDb; -use ndb_udp_service::UdpServiceDb; - -#[cfg(not(feature = "bundled"))] -use std::path::PathBuf; - -pub const TCP_SERVICE_CSV_NAME: &str = "tcp.csv"; -pub const TCP_SERVICE_R2_URL: &str = "https://r2.ntap.io/tcp-services.csv"; - -pub const UDP_SERVICE_CSV_NAME: &str = "udp.csv"; -pub const UDP_SERVICE_R2_URL: &str = "https://r2.ntap.io/udp-services.csv"; - -#[cfg(not(feature = "bundled"))] -pub fn get_tcp_db_filepath() -> Option { - match crate::sys::get_database_dir_path() { - Some(mut db_dir) => { - db_dir.push(TCP_SERVICE_CSV_NAME); - Some(db_dir) - } - None => { - eprintln!("Error: Could not get database directory path"); - None - } - } -} - -#[cfg(not(feature = "bundled"))] -pub fn get_udp_db_filepath() -> Option { - match crate::sys::get_database_dir_path() { - Some(mut db_dir) => { - db_dir.push(UDP_SERVICE_CSV_NAME); - Some(db_dir) - } - None => { - eprintln!("Error: Could not get database directory path"); - None - } - } -} - -#[cfg(feature = "bundled")] -pub fn get_tcp_service_db() -> Result { - Ok(TcpServiceDb::bundled()) -} - -#[cfg(not(feature = "bundled"))] -pub fn get_tcp_service_db() -> Result { - let path = get_tcp_db_filepath() - .ok_or_else(|| anyhow::anyhow!("Failed to get TCP database file path"))?; - let reader = std::fs::File::open(path) - .map_err(|e| anyhow::anyhow!("Failed to open TCP database file: {}", e))?; - TcpServiceDb::from_csv(reader) -} - -#[cfg(feature = "bundled")] -pub fn get_udp_service_db() -> Result { - Ok(UdpServiceDb::bundled()) -} - -#[cfg(not(feature = "bundled"))] -pub fn get_udp_service_db() -> Result { - let path = get_udp_db_filepath() - .ok_or_else(|| anyhow::anyhow!("Failed to get UDP database file path"))?; - let reader = std::fs::File::open(path) - .map_err(|e| anyhow::anyhow!("Failed to open UDP database file: {}", e))?; - UdpServiceDb::from_csv(reader) -} - -/* /// In-memory service database with hash map -pub struct ServiceDatabase { - pub tcp: TcpServiceDb, - pub udp: UdpServiceDb, -} - -impl ServiceDatabase { - #[cfg(feature = "bundled")] - pub fn load() -> Result { - let db = ServiceDatabase { - tcp: TcpServiceDb::bundled(), - udp: UdpServiceDb::bundled(), - }; - Ok(db) - } - #[cfg(not(feature = "bundled"))] - pub fn load() -> Result { - use std::fs::File; - let tcp_path = get_tcp_db_filepath().ok_or_else(|| { - anyhow::anyhow!("Failed to get TCP database file path") - })?; - let udp_path = get_udp_db_filepath().ok_or_else(|| { - anyhow::anyhow!("Failed to get UDP database file path") - })?; - let mut tcp_reader = File::open(tcp_path) - .map_err(|e| anyhow::anyhow!("Failed to open TCP database file: {}", e))?; - let mut udp_reader = File::open(udp_path) - .map_err(|e| anyhow::anyhow!("Failed to open UDP database file: {}", e))?; - let db = ServiceDatabase { - tcp: TcpServiceDb::from_csv(tcp_reader)?, - udp: UdpServiceDb::from_csv(udp_reader)?, - }; - Ok(db) - } -} */ diff --git a/src/main.rs b/src/main.rs index a326ec7..eed910f 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,7 +4,6 @@ mod deps; mod handler; mod log; mod net; -mod notification; mod process; mod sys; mod tui; diff --git a/src/net/http.rs b/src/net/http.rs deleted file mode 100644 index 445e791..0000000 --- a/src/net/http.rs +++ /dev/null @@ -1,66 +0,0 @@ -use futures::stream::StreamExt; -use serde::{Deserialize, Serialize}; -use std::{error::Error, io::Write, path::PathBuf}; - -pub const DEFAULT_USER_AGENT_FIREFOX: &str = - "Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/121.0"; -pub const DEFAULT_USER_AGENT_CHROME: &str = - "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum DownloadProgress { - ContentLength(u64), - Downloaded(u64), -} - -pub async fn download_file(url: String, save_file_path: PathBuf) -> Result<(), Box> { - // Check and create download dir - let file_path = std::path::Path::new(&save_file_path); - if let Some(parent_dir) = file_path.parent() { - if !parent_dir.exists() { - std::fs::create_dir_all(parent_dir)?; - } - } else { - return Err("Invalid save file path".into()); - } - // Download file - let response = reqwest::get(&url).await?; - let mut dest = std::fs::File::create(&save_file_path)?; - let content = response.bytes().await?; - dest.write_all(&content)?; - Ok(()) -} - -pub async fn download_file_with_progress( - url: String, - save_file_path: PathBuf, - progress_tx: tokio::sync::mpsc::Sender, -) -> Result<(), Box> { - // Check and create download dir - let file_path = std::path::Path::new(&save_file_path); - if let Some(parent_dir) = file_path.parent() { - if !parent_dir.exists() { - std::fs::create_dir_all(parent_dir)?; - } - } else { - return Err("Invalid save file path".into()); - } - // Download file with progress - let response = reqwest::get(&url).await?; - let content_length = response.content_length().unwrap_or(0); - progress_tx - .send(DownloadProgress::ContentLength(content_length)) - .await?; - let mut dest = std::fs::File::create(&save_file_path)?; - let mut downloaded: u64 = 0; - let mut stream = response.bytes_stream(); - while let Some(chunk) = stream.next().await { - let chunk = chunk?; - downloaded += chunk.len() as u64; - dest.write_all(&chunk)?; - progress_tx - .send(DownloadProgress::Downloaded(downloaded)) - .await?; - } - Ok(()) -} diff --git a/src/net/mod.rs b/src/net/mod.rs index 3c86ec7..cf2bfec 100644 --- a/src/net/mod.rs +++ b/src/net/mod.rs @@ -2,7 +2,6 @@ pub mod dns; pub mod host; -//pub mod http; pub mod interface; pub mod ip; pub mod packet; diff --git a/src/net/stat.rs b/src/net/stat.rs index 05ad5d8..5fff13c 100644 --- a/src/net/stat.rs +++ b/src/net/stat.rs @@ -9,7 +9,6 @@ use crate::net::socket::{ AddressFamily, LocalSocket, ProtocolPort, SocketConnection, SocketDisplayInfo, SocketInfoOption, SocketProcess, TransportProtocol, }; -use crate::notification::Notification; use crate::process::{ProcessDisplayInfo, ProcessInfo}; use bytes::Bytes; use netdev::{mac::MacAddr, Interface}; @@ -595,7 +594,6 @@ pub struct Overview { pub top_processes: Vec, pub top_remote_hosts: Vec, pub top_app_protocols: Vec, - pub notificatons: Vec, } impl Overview { @@ -605,7 +603,6 @@ impl Overview { top_processes: Vec::new(), top_remote_hosts: Vec::new(), top_app_protocols: Vec::new(), - notificatons: Vec::new(), } } } diff --git a/src/notification.rs b/src/notification.rs deleted file mode 100644 index 7261be1..0000000 --- a/src/notification.rs +++ /dev/null @@ -1,28 +0,0 @@ -#![allow(unused)] - -use serde::{Deserialize, Serialize}; - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub enum NotificationType { - Traffic, - RemoteHost, - Protocol, -} - -impl NotificationType { - pub fn name(&self) -> String { - match self { - NotificationType::Traffic => "Traffic".to_string(), - NotificationType::RemoteHost => "Remote Host".to_string(), - NotificationType::Protocol => "Protocol".to_string(), - } - } -} - -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Notification { - pub title: String, - pub body: String, - pub notification_type: NotificationType, - pub timestamp: String, -} From 41d037559332b019757db86ac439e96f69b3b72d Mon Sep 17 00:00:00 2001 From: shellrow Date: Sun, 10 Aug 2025 00:05:55 +0900 Subject: [PATCH 3/4] Change default mode --- resources/doc/USAGE.md | 4 +- src/handler/monitor.rs | 105 ++++++++++++++++++++++++++ src/handler/stat.rs | 166 ----------------------------------------- src/main.rs | 11 +-- 4 files changed, 110 insertions(+), 176 deletions(-) diff --git a/resources/doc/USAGE.md b/resources/doc/USAGE.md index 54da22b..894f424 100644 --- a/resources/doc/USAGE.md +++ b/resources/doc/USAGE.md @@ -12,11 +12,11 @@ ntap [OPTIONS] [COMMAND] ``` ## Default Behavior -By default, if no subcommand is specified, ntap enters the `stat` mode, which displays continuous network statistics: +By default, if no subcommand is specified, ntap enters the `monitor` mode, which displays live network usage statistics: ```bash ntap ``` -This default mode captures packets on all available network interfaces and continuously displays live network statistics, providing a quick and easy way to monitor current network activity without the need for additional configuration. +This default mode captures packets on all available network interfaces and continuously displays live network usage, providing a quick and easy way to monitor current network activity without the need for additional configuration. ## Commands diff --git a/src/handler/monitor.rs b/src/handler/monitor.rs index f20b900..4429f92 100644 --- a/src/handler/monitor.rs +++ b/src/handler/monitor.rs @@ -206,3 +206,108 @@ pub fn monitor(app: &ArgMatches) -> Result<()> { )?; Ok(()) } + +pub fn monitor_default(app: &ArgMatches) -> Result<()> { + // Check .ntap directory + match crate::sys::get_config_dir_path() { + Some(_config_dir) => {} + None => { + let err_msg = "Could not get config directory path"; + tracing::error!("{err_msg}"); + anyhow::bail!(err_msg); + } + } + + // Check dependencies (Currently only for Windows) + match crate::sys::check_deps() { + Ok(_) => {} + Err(e) => { + tracing::error!("Error: {:?}", e); + anyhow::bail!(e.to_string()); + } + } + + // Load AppConfig + let mut config = AppConfig::load(); + + // Initialize logger + crate::log::init_logger(&config)?; + + // Initialize DB + crate::db::init_databases()?; + + if app.contains_id("tickrate") { + config.display.tick_rate = *app.get_one("tickrate").unwrap_or(&1000); + } + + // Start threads + let mut threads: Vec> = vec![]; + + let netstat_strage: Arc = Arc::new(NetStatStrage::new()); + let mut netstat_strage_socket = Arc::clone(&netstat_strage); + let mut netstat_strage_ui = Arc::clone(&netstat_strage); + + let target_interfaces: Vec; + if config.network.interfaces.is_empty() { + target_interfaces = crate::net::interface::get_usable_interfaces(); + } else { + target_interfaces = + crate::net::interface::get_interfaces_by_name(&config.network.interfaces); + } + let mut pcap_thread_index = 0; + let pcap_handlers = target_interfaces + .iter() + .map(|iface| { + let mut netstat_strage_pcap = Arc::clone(&netstat_strage); + let iface = iface.clone(); + let pcap_option = crate::net::pcap::PacketCaptureOptions::from_interface(&iface); + let thread_name = format!("pcap-thread-{}", iface.name.clone()); + let pcap_thread = thread::Builder::new().name(thread_name.clone()); + let pcap_handler = pcap_thread.spawn(move || { + crate::net::pcap::start_background_capture( + pcap_option, + &mut netstat_strage_pcap, + iface, + ); + }); + tracing::info!("start thread {}", thread_name); + pcap_thread_index += 1; + pcap_handler + }) + .collect::>(); + + let socket_handler = thread::spawn(move || { + tracing::info!("start thread socket_info_update"); + crate::net::socket::start_socket_info_update(&mut netstat_strage_socket); + }); + + for pcap_handler in pcap_handlers { + match pcap_handler { + Ok(handle) => { + threads.push(handle); + } + Err(e) => { + tracing::error!("Error: {:?}", e); + } + } + } + threads.push(socket_handler); + + if config.network.reverse_dns { + let mut netstat_strage_dns = Arc::clone(&netstat_strage); + let dns_handler = thread::spawn(move || { + tracing::info!("start thread dns_map_update"); + crate::net::dns::start_dns_map_update(&mut netstat_strage_dns); + }); + threads.push(dns_handler); + } + + tracing::info!("start TUI, netstat_data_update"); + + crate::tui::monitor::terminal::run( + config, + app.contains_id("enhanced-graphics"), + &mut netstat_strage_ui, + )?; + Ok(()) +} diff --git a/src/handler/stat.rs b/src/handler/stat.rs index c4f4d70..c99e95d 100644 --- a/src/handler/stat.rs +++ b/src/handler/stat.rs @@ -10,172 +10,6 @@ use std::thread; use nex::packet::ethernet::EtherType; use nex::packet::ip::IpNextProtocol; -pub fn show_stat_default(app: &ArgMatches) -> Result<()> { - // Check .ntap directory - match crate::sys::get_config_dir_path() { - Some(_config_dir) => {} - None => { - let err_msg = "Could not get config directory path"; - tracing::error!("{err_msg}"); - anyhow::bail!(err_msg); - } - } - - // Check dependencies (Currently only for Windows) - match crate::sys::check_deps() { - Ok(_) => {} - Err(e) => { - tracing::error!("Error: {:?}", e); - anyhow::bail!(e.to_string()); - } - } - - // Load AppConfig - let mut config = AppConfig::load(); - - // Initialize logger - crate::log::init_logger(&config)?; - - // Initialize DB - crate::db::init_databases()?; - - if app.contains_id("tickrate") { - config.display.tick_rate = *app.get_one("tickrate").unwrap_or(&1000); - } - - // Interface filter - if app.contains_id("interfaces") { - match app.get_many::("interfaces") { - Some(interfaces) => { - config.network.interfaces = interfaces.cloned().collect(); - } - None => { - config.network.interfaces = Vec::new(); - } - } - } - - // Protocol filter - let mut ethertypes: HashSet = HashSet::new(); - let mut ip_next_protocols: HashSet = HashSet::new(); - if app.contains_id("protocols") { - match app.get_many::("protocols") { - Some(protocols_ref) => { - let protocols: Vec = protocols_ref.cloned().collect(); - for protocol in protocols { - if let Some(ethertype) = crate::net::packet::get_ethertype_from_str(&protocol) { - ethertypes.insert(ethertype); - } - if let Some(ip_next_protocol) = - crate::net::packet::get_ip_next_protocol_from_str(&protocol) - { - ip_next_protocols.insert(ip_next_protocol); - } - } - } - None => {} - } - } - - // IP Address filter - let ips: HashSet = match app.get_many::("ips") { - Some(ips_ref) => ips_ref.cloned().collect(), - None => HashSet::new(), - }; - - // Port filter - let ports: HashSet = match app.get_many::("ports") { - Some(ports_ref) => ports_ref.cloned().collect(), - None => HashSet::new(), - }; - - if !ip_next_protocols.is_empty() || ips.len() > 0 || ports.len() > 0 { - ethertypes.insert(EtherType::Ipv4); - ethertypes.insert(EtherType::Ipv6); - if ports.len() > 0 { - ip_next_protocols.insert(IpNextProtocol::Tcp); - ip_next_protocols.insert(IpNextProtocol::Udp); - } - } - - // Start threads - let mut threads: Vec> = vec![]; - - let netstat_strage: Arc = Arc::new(NetStatStrage::new()); - let mut netstat_strage_socket = Arc::clone(&netstat_strage); - let mut netstat_strage_ui = Arc::clone(&netstat_strage); - - let target_interfaces: Vec; - if config.network.interfaces.is_empty() { - target_interfaces = crate::net::interface::get_usable_interfaces(); - } else { - target_interfaces = - crate::net::interface::get_interfaces_by_name(&config.network.interfaces); - } - let mut pcap_thread_index = 0; - let pcap_handlers = target_interfaces - .iter() - .map(|iface| { - let mut netstat_strage_pcap = Arc::clone(&netstat_strage); - let iface = iface.clone(); - let mut pcap_option = crate::net::pcap::PacketCaptureOptions::from_interface(&iface); - pcap_option.ether_types = ethertypes.clone(); - pcap_option.ip_protocols = ip_next_protocols.clone(); - pcap_option.src_ips = ips.clone(); - pcap_option.src_ports = ports.clone(); - pcap_option.dst_ips = ips.clone(); - pcap_option.dst_ports = ports.clone(); - let thread_name = format!("pcap-thread-{}", iface.name.clone()); - let pcap_thread = thread::Builder::new().name(thread_name.clone()); - let pcap_handler = pcap_thread.spawn(move || { - crate::net::pcap::start_background_capture( - pcap_option, - &mut netstat_strage_pcap, - iface, - ); - }); - tracing::info!("start thread {}", thread_name); - pcap_thread_index += 1; - pcap_handler - }) - .collect::>(); - - let socket_handler = thread::spawn(move || { - tracing::info!("start thread socket_info_update"); - crate::net::socket::start_socket_info_update(&mut netstat_strage_socket); - }); - - for pcap_handler in pcap_handlers { - match pcap_handler { - Ok(handle) => { - threads.push(handle); - } - Err(e) => { - tracing::error!("Error: {:?}", e); - } - } - } - threads.push(socket_handler); - - if config.network.reverse_dns { - let mut netstat_strage_dns = Arc::clone(&netstat_strage); - let dns_handler = thread::spawn(move || { - tracing::info!("start thread dns_map_update"); - crate::net::dns::start_dns_map_update(&mut netstat_strage_dns); - }); - threads.push(dns_handler); - } - - tracing::info!("start TUI, netstat_data_update"); - - crate::tui::stat::terminal::run( - config, - app.contains_id("enhanced-graphics"), - &mut netstat_strage_ui, - )?; - Ok(()) -} - pub fn show_stat(app: &ArgMatches) -> Result<()> { let sub_args = match app.subcommand_matches("stat") { Some(matches) => matches, diff --git a/src/main.rs b/src/main.rs index eed910f..1ff71c0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -29,10 +29,9 @@ fn main() -> Result<()> { AppCommands::Interface => handler::interface::show_default_interface(), AppCommands::Route => handler::route::show_routes(), AppCommands::Socket => handler::socket::show_socket_info(&args), - //AppCommands::Update => handler::update::download_db_files(), AppCommands::Default => { - // If no subcommand is specified, enter stat mode by default - handler::stat::show_stat_default(&args) + // If no subcommand is specified, enter monitor mode by default + handler::monitor::monitor_default(&args) } } } @@ -41,7 +40,7 @@ fn parse_args() -> ArgMatches { let app: Command = Command::new(crate_name!()) .version(crate_version!()) .about(crate_description!()) - .after_help("By default, if no options are specified, ntap enters the stat mode.") + .after_help("By default, if no options are specified, ntap enters the monitor mode.") .arg( Arg::new("interfaces") .help("Specify the interfaces by name. Example: ntap -i eth0,eth1") @@ -246,10 +245,6 @@ fn parse_args() -> ArgMatches { .subcommand(Command::new("route") .about("Show IP routing table") ) - // Sub-command for update ntap database - //.subcommand(Command::new("update") - // .about("Update ntap database") - //) ; app.get_matches() } From e74de8f0515b2cc6896c2cc4448086ac6721ea8e Mon Sep 17 00:00:00 2001 From: shellrow Date: Sun, 10 Aug 2025 14:31:07 +0900 Subject: [PATCH 4/4] Bump version to 0.9.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a0c760c..f2f549e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ntap" -version = "0.8.0" +version = "0.9.0" edition = "2021" authors = ["shellrow "] description = "Network traffic monitor/analyzer"