From af43365d95c85378cd2f93c866e0acd7416f6356 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Mon, 4 Dec 2023 11:47:46 +0000 Subject: [PATCH 1/7] added ability to exlude ip_v4 and ip_v4:port --- src/cli.rs | 15 ++++++++++++++- src/main.rs | 10 +++++++++- src/network/utilization.rs | 37 ++++++++++++++++++++++++++++++++++++- 3 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 644a500ad..d70a43a64 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,4 +1,7 @@ -use std::{net::Ipv4Addr, path::PathBuf}; +use std::{ + net::{Ipv4Addr, SocketAddrV4}, + path::PathBuf, +}; use clap::{Args, Parser}; use clap_verbosity_flag::{InfoLevel, Verbosity}; @@ -38,6 +41,16 @@ pub struct Opt { #[derivative(Default(value = "Verbosity::new(0, 0)"))] pub verbosity: Verbosity, + #[arg(short, long)] + /// exclude ip addres with <-e x.x.x.x> + /// exclude multiple ip addresses with <-e x.x.x.x -e y.y.y.y> + pub excluded_ipv4: Option>, + + #[arg(long)] + /// exclude ip addres with <-e x.x.x.x:zzzz> + /// exclude multiple ip addresses and port with <-e x.x.x.x:zzzz -e y.y.y.y:zzzz> + pub excluded_ipv4_port: Option>, + #[command(flatten)] pub render_opts: RenderOpts, } diff --git a/src/main.rs b/src/main.rs index 8f765f490..5fb0e8c57 100644 --- a/src/main.rs +++ b/src/main.rs @@ -138,7 +138,15 @@ where move || { while running.load(Ordering::Acquire) { let render_start_time = Instant::now(); - let utilization = { network_utilization.lock().unwrap().clone_and_reset() }; + let mut utilization = { network_utilization.lock().unwrap().clone_and_reset() }; + match opts.excluded_ipv4 { + Some(ref ex) => utilization.remove_ip(ex), + None => {} + }; + match opts.excluded_ipv4_port { + Some(ref ex) => utilization.remove_ip_port(ex), + None => {} + }; let OpenSockets { sockets_to_procs } = get_open_sockets(); let mut ip_to_host = IpTable::new(); if let Some(dns_client) = dns_client.as_mut() { diff --git a/src/network/utilization.rs b/src/network/utilization.rs index c44356b6e..940c33833 100644 --- a/src/network/utilization.rs +++ b/src/network/utilization.rs @@ -1,4 +1,7 @@ -use std::collections::HashMap; +use std::{ + collections::HashMap, + net::{Ipv4Addr, SocketAddrV4}, +}; use crate::network::{Connection, Direction, Segment}; @@ -42,4 +45,36 @@ impl Utilization { } } } + pub fn remove_ip(&mut self, ips: &Vec) { + // might be possible to refactor this part better + // i still don't understand the whole borrow/own system very well yet + let placeholder = self.connections.clone(); + for util in placeholder { + match util.0.remote_socket.ip { + std::net::IpAddr::V4(ip) => { + if ips.contains(&ip) { + self.connections.remove_entry(&util.0); + } + } + std::net::IpAddr::V6(..) => { /* nothing here yet (maybe implement it for ipV6 too) */ + } + } + } + } + pub fn remove_ip_port(&mut self, ips: &Vec) { + // might be possible to refactor this part better + // i still don't understand the whole borrow/own system very well yet + let placeholder = self.connections.clone(); + for util in placeholder { + match util.0.remote_socket.ip { + std::net::IpAddr::V4(ip) => { + if ips.contains(&SocketAddrV4::new(ip, util.0.remote_socket.port)) { + self.connections.remove_entry(&util.0); + } + } + std::net::IpAddr::V6(..) => { /* nothing here yet (maybe implement it for ipV6 too) */ + } + } + } + } } From 148fae0b7febbcad72dab64c47d88ba7da66e1a0 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Tue, 5 Dec 2023 18:19:28 +0000 Subject: [PATCH 2/7] fixed clippy issues --- src/cli.rs | 2 +- src/main.rs | 14 ++++++-------- src/network/utilization.rs | 4 ++-- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index d70a43a64..329dc4d50 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -46,7 +46,7 @@ pub struct Opt { /// exclude multiple ip addresses with <-e x.x.x.x -e y.y.y.y> pub excluded_ipv4: Option>, - #[arg(long)] + #[arg(short = 'E', long)] /// exclude ip addres with <-e x.x.x.x:zzzz> /// exclude multiple ip addresses and port with <-e x.x.x.x:zzzz -e y.y.y.y:zzzz> pub excluded_ipv4_port: Option>, diff --git a/src/main.rs b/src/main.rs index 5fb0e8c57..10fa61fe6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -139,14 +139,12 @@ where while running.load(Ordering::Acquire) { let render_start_time = Instant::now(); let mut utilization = { network_utilization.lock().unwrap().clone_and_reset() }; - match opts.excluded_ipv4 { - Some(ref ex) => utilization.remove_ip(ex), - None => {} - }; - match opts.excluded_ipv4_port { - Some(ref ex) => utilization.remove_ip_port(ex), - None => {} - }; + if let Some(ref ex) = opts.excluded_ipv4 { + utilization.remove_ip(ex) + } + if let Some(ref ex) = opts.excluded_ipv4_port { + utilization.remove_ip_port(ex) + } let OpenSockets { sockets_to_procs } = get_open_sockets(); let mut ip_to_host = IpTable::new(); if let Some(dns_client) = dns_client.as_mut() { diff --git a/src/network/utilization.rs b/src/network/utilization.rs index 940c33833..6240a8a28 100644 --- a/src/network/utilization.rs +++ b/src/network/utilization.rs @@ -45,7 +45,7 @@ impl Utilization { } } } - pub fn remove_ip(&mut self, ips: &Vec) { + pub fn remove_ip(&mut self, ips: &[Ipv4Addr]) { // might be possible to refactor this part better // i still don't understand the whole borrow/own system very well yet let placeholder = self.connections.clone(); @@ -61,7 +61,7 @@ impl Utilization { } } } - pub fn remove_ip_port(&mut self, ips: &Vec) { + pub fn remove_ip_port(&mut self, ips: &[SocketAddrV4]) { // might be possible to refactor this part better // i still don't understand the whole borrow/own system very well yet let placeholder = self.connections.clone(); From 2aa6de40281169773fafba64ee9824a5e02543a5 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Thu, 7 Dec 2023 12:27:54 +0000 Subject: [PATCH 3/7] made ip exclutions better --- src/cli.rs | 44 ++++++++++++++++++++++++++----- src/display/ui.rs | 5 +++- src/display/ui_state.rs | 54 +++++++++++++++++++++++++++++++++++--- src/main.rs | 9 ++----- src/network/utilization.rs | 37 +------------------------- 5 files changed, 95 insertions(+), 54 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index 329dc4d50..db775b0d3 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -1,8 +1,37 @@ use std::{ - net::{Ipv4Addr, SocketAddrV4}, + net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6}, path::PathBuf, + str::FromStr, }; +#[derive(Clone, Debug)] +pub enum HostFilter { + Ipv4Addr(Ipv4Addr), + Ipv6Addr(Ipv6Addr), + SocketAddrV4(SocketAddrV4), + SocketAddrV6(SocketAddrV6), + Hostname(String), +} + +impl FromStr for HostFilter { + type Err = String; + + fn from_str(s: &str) -> Result { + if let Ok(ipv4) = s.parse() { + return Ok(HostFilter::Ipv4Addr(ipv4)); + } else if let Ok(ipv6) = s.parse() { + return Ok(HostFilter::Ipv6Addr(ipv6)); + } else if let Ok(socketv4) = s.parse() { + return Ok(HostFilter::SocketAddrV4(socketv4)); + } else if let Ok(socketv6) = s.parse() { + return Ok(HostFilter::SocketAddrV6(socketv6)); + } else { + // might need validation + return Ok(HostFilter::Hostname(s.to_string())); + } + } +} + use clap::{Args, Parser}; use clap_verbosity_flag::{InfoLevel, Verbosity}; use derivative::Derivative; @@ -44,12 +73,13 @@ pub struct Opt { #[arg(short, long)] /// exclude ip addres with <-e x.x.x.x> /// exclude multiple ip addresses with <-e x.x.x.x -e y.y.y.y> - pub excluded_ipv4: Option>, - - #[arg(short = 'E', long)] - /// exclude ip addres with <-e x.x.x.x:zzzz> - /// exclude multiple ip addresses and port with <-e x.x.x.x:zzzz -e y.y.y.y:zzzz> - pub excluded_ipv4_port: Option>, + /// examples: + /// IpV4: 127.0.0.1 + /// IpV6: 2001:db8::1 OR 2001:0db8:85a3:0000:0000:8a2e:0370:7334 + /// SocketAddrV4: 127.0.0.1:8080 + /// SocketAddrV6: "[2001:0db8:85a3:0000:0000:8a2e:0370:7334]:8080" + /// hostname: String + pub excluded: Option>, #[command(flatten)] pub render_opts: RenderOpts, diff --git a/src/display/ui.rs b/src/display/ui.rs index df0978f06..730189912 100644 --- a/src/display/ui.rs +++ b/src/display/ui.rs @@ -4,7 +4,7 @@ use chrono::prelude::*; use ratatui::{backend::Backend, Terminal}; use crate::{ - cli::RenderOpts, + cli::{HostFilter, RenderOpts}, display::{ components::{HeaderDetails, HelpText, Layout, Table}, UIState, @@ -179,6 +179,9 @@ where self.state.update(connections_to_procs, utilization); self.ip_to_host.extend(ip_to_host); } + pub fn set_excluded(&mut self, ex: Option>) { + self.state.excluded_ips = ex; + } pub fn end(&mut self) { self.terminal.show_cursor().unwrap(); } diff --git a/src/display/ui_state.rs b/src/display/ui_state.rs index 1295ef935..2960cdc06 100644 --- a/src/display/ui_state.rs +++ b/src/display/ui_state.rs @@ -3,10 +3,11 @@ use std::{ collections::{HashMap, HashSet, VecDeque}, hash::Hash, iter::FromIterator, - net::{IpAddr, Ipv4Addr, Ipv6Addr}, + net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr}, }; use crate::{ + cli::HostFilter, display::BandwidthUnitFamily, mt_log, network::{Connection, LocalSocket, Utilization}, @@ -92,14 +93,61 @@ pub struct UIState { pub connections_map: HashMap, /// Used for reducing logging noise. known_orphan_sockets: VecDeque, + pub excluded_ips: Option>, } impl UIState { - pub fn update( + pub fn update( &mut self, connections_to_procs: HashMap, - network_utilization: Utilization, + mut network_utilization: Utilization, ) { + println!("{:?}", self.excluded_ips); + if let Some(excluded_addresses) = &self.excluded_ips { + for ex in excluded_addresses { + network_utilization.connections.retain(|k, _| { + let ip_address = k.remote_socket.ip; + let port = k.remote_socket.port; + let socket = SocketAddr::new(ip_address, port); + + match ex { + HostFilter::Ipv4Addr(ipaddr) => { + if let IpAddr::V4(ipv4) = ip_address { + &ipv4 != ipaddr + } else { + true + } + } + HostFilter::Ipv6Addr(ipaddr) => { + if let IpAddr::V6(ipv6) = ip_address { + &ipv6 != ipaddr + } else { + true + } + } + HostFilter::SocketAddrV4(socketaddr) => { + if let SocketAddr::V4(socketv4) = socket { + &socketv4 != socketaddr + } else { + true + } + } + HostFilter::SocketAddrV6(socketaddr) => { + if let SocketAddr::V6(socketv6) = socket { + &socketv6 != socketaddr + } else { + true + } + } + HostFilter::Hostname(name) => { + // not implemented yet + true + } + } + }); + } + } + self.utilization_data.push_back(UtilizationData { connections_to_procs, network_utilization, diff --git a/src/main.rs b/src/main.rs index 10fa61fe6..81e2247b3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -138,13 +138,7 @@ where move || { while running.load(Ordering::Acquire) { let render_start_time = Instant::now(); - let mut utilization = { network_utilization.lock().unwrap().clone_and_reset() }; - if let Some(ref ex) = opts.excluded_ipv4 { - utilization.remove_ip(ex) - } - if let Some(ref ex) = opts.excluded_ipv4_port { - utilization.remove_ip_port(ex) - } + let utilization = { network_utilization.lock().unwrap().clone_and_reset() }; let OpenSockets { sockets_to_procs } = get_open_sockets(); let mut ip_to_host = IpTable::new(); if let Some(dns_client) = dns_client.as_mut() { @@ -161,6 +155,7 @@ where let mut ui = ui.lock().unwrap(); let paused = paused.load(Ordering::SeqCst); let ui_offset = ui_offset.load(Ordering::SeqCst); + ui.set_excluded(opts.excluded.clone()); if !paused { ui.update_state(sockets_to_procs, utilization, ip_to_host); } diff --git a/src/network/utilization.rs b/src/network/utilization.rs index 6240a8a28..c44356b6e 100644 --- a/src/network/utilization.rs +++ b/src/network/utilization.rs @@ -1,7 +1,4 @@ -use std::{ - collections::HashMap, - net::{Ipv4Addr, SocketAddrV4}, -}; +use std::collections::HashMap; use crate::network::{Connection, Direction, Segment}; @@ -45,36 +42,4 @@ impl Utilization { } } } - pub fn remove_ip(&mut self, ips: &[Ipv4Addr]) { - // might be possible to refactor this part better - // i still don't understand the whole borrow/own system very well yet - let placeholder = self.connections.clone(); - for util in placeholder { - match util.0.remote_socket.ip { - std::net::IpAddr::V4(ip) => { - if ips.contains(&ip) { - self.connections.remove_entry(&util.0); - } - } - std::net::IpAddr::V6(..) => { /* nothing here yet (maybe implement it for ipV6 too) */ - } - } - } - } - pub fn remove_ip_port(&mut self, ips: &[SocketAddrV4]) { - // might be possible to refactor this part better - // i still don't understand the whole borrow/own system very well yet - let placeholder = self.connections.clone(); - for util in placeholder { - match util.0.remote_socket.ip { - std::net::IpAddr::V4(ip) => { - if ips.contains(&SocketAddrV4::new(ip, util.0.remote_socket.port)) { - self.connections.remove_entry(&util.0); - } - } - std::net::IpAddr::V6(..) => { /* nothing here yet (maybe implement it for ipV6 too) */ - } - } - } - } } From f4cad333da53b6d8c8be8ae8bef7ca30faaea509 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Thu, 7 Dec 2023 18:30:34 +0000 Subject: [PATCH 4/7] formating --- src/cli.rs | 10 +++++----- src/display/ui_state.rs | 5 ++--- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/cli.rs b/src/cli.rs index db775b0d3..a0dff269d 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -18,16 +18,16 @@ impl FromStr for HostFilter { fn from_str(s: &str) -> Result { if let Ok(ipv4) = s.parse() { - return Ok(HostFilter::Ipv4Addr(ipv4)); + Ok(HostFilter::Ipv4Addr(ipv4)) } else if let Ok(ipv6) = s.parse() { - return Ok(HostFilter::Ipv6Addr(ipv6)); + Ok(HostFilter::Ipv6Addr(ipv6)) } else if let Ok(socketv4) = s.parse() { - return Ok(HostFilter::SocketAddrV4(socketv4)); + Ok(HostFilter::SocketAddrV4(socketv4)) } else if let Ok(socketv6) = s.parse() { - return Ok(HostFilter::SocketAddrV6(socketv6)); + Ok(HostFilter::SocketAddrV6(socketv6)) } else { // might need validation - return Ok(HostFilter::Hostname(s.to_string())); + Ok(HostFilter::Hostname(s.to_string())) } } } diff --git a/src/display/ui_state.rs b/src/display/ui_state.rs index 2960cdc06..f85fdc1fc 100644 --- a/src/display/ui_state.rs +++ b/src/display/ui_state.rs @@ -97,12 +97,11 @@ pub struct UIState { } impl UIState { - pub fn update( + pub fn update( &mut self, connections_to_procs: HashMap, mut network_utilization: Utilization, ) { - println!("{:?}", self.excluded_ips); if let Some(excluded_addresses) = &self.excluded_ips { for ex in excluded_addresses { network_utilization.connections.retain(|k, _| { @@ -139,7 +138,7 @@ impl UIState { true } } - HostFilter::Hostname(name) => { + HostFilter::Hostname(_name) => { // not implemented yet true } From b37571a5002d283d00c3161ed5f31dca31d31b31 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Fri, 8 Dec 2023 17:24:31 +0000 Subject: [PATCH 5/7] fix fmt --- src/display/ui.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/display/ui.rs b/src/display/ui.rs index c882549d1..5954959cd 100644 --- a/src/display/ui.rs +++ b/src/display/ui.rs @@ -4,7 +4,7 @@ use chrono::prelude::*; use ratatui::{backend::Backend, Terminal}; use crate::{ - cli::{Opt, RenderOpts, HostFilter}, + cli::{HostFilter, Opt, RenderOpts}, display::{ components::{HeaderDetails, HelpText, Layout, Table}, UIState, From 3ba1f9c61525395ad1c13cdf94cf1f91f6c6f57a Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Fri, 8 Dec 2023 17:27:59 +0000 Subject: [PATCH 6/7] added changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92be8d57f..4110fb34c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) * Display bandwidth in different unit families #328 - @cyqsimon * CI: ensure a changelog entry exists for each PR #331 - @cyqsimon * Show interface names #340 - @ilyes-ced +* Add option to exclude IPs #341 - @ilyes-ced ### Changed From b2dde6f5ae2d72f532625a8281d9fb6ea5879ab8 Mon Sep 17 00:00:00 2001 From: ilyes-ced Date: Fri, 8 Dec 2023 21:22:39 +0000 Subject: [PATCH 7/7] added hostname filtering --- src/display/ui.rs | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/src/display/ui.rs b/src/display/ui.rs index 5954959cd..56e9d97de 100644 --- a/src/display/ui.rs +++ b/src/display/ui.rs @@ -177,9 +177,36 @@ where utilization: Utilization, ip_to_host: HashMap, ) { + let hostnames: Vec = self + .state + .excluded_ips + .clone() + .unwrap_or_default() + .iter() + .filter_map(|hf| match hf { + HostFilter::Hostname(s) => Some(s.clone()), + _ => None, + }) + .collect(); + for (k, v) in &ip_to_host { + if hostnames.contains(v) { + match &self.state.excluded_ips { + None => {} + Some(_) => match k { + IpAddr::V4(ip) => self.push_to_excluded_ips(HostFilter::Ipv4Addr(*ip)), + IpAddr::V6(ip) => self.push_to_excluded_ips(HostFilter::Ipv6Addr(*ip)), + }, + } + } + } self.state.update(connections_to_procs, utilization); self.ip_to_host.extend(ip_to_host); } + fn push_to_excluded_ips(&mut self, ip: HostFilter) { + let mut vec = self.state.excluded_ips.take().unwrap_or_default(); + vec.push(ip); + self.state.excluded_ips = Some(vec); + } pub fn set_excluded(&mut self, ex: Option>) { self.state.excluded_ips = ex; }