summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2019-09-19 19:47:46 +0200
committerAram Drevekenin <aram@poor.dev>2019-09-19 19:47:46 +0200
commit5745d9d8bf1e3038ba6cf1a5b815008e01a812b4 (patch)
treee815b9ba03d06ded56b55428841de0aba008a769
parent3d54c7fd8e7691c05753d5463776c86e50bbf268 (diff)
refactor(connection): remote stale netstat crate and reorder everything
-rw-r--r--Cargo.lock22
-rw-r--r--Cargo.toml3
-rw-r--r--src/display/ui.rs11
-rw-r--r--src/display/ui_state.rs30
-rw-r--r--src/lib.rs19
-rw-r--r--src/main.rs3
-rw-r--r--src/network/connection.rs73
-rw-r--r--src/network/mod.rs7
-rw-r--r--src/network/sniffer.rs (renamed from src/traffic.rs)105
-rw-r--r--src/network/utilization.rs (renamed from src/store/network_utilization.rs)8
-rw-r--r--src/os/linux.rs58
-rw-r--r--src/store/current_connections.rs92
-rw-r--r--src/store/mod.rs5
-rw-r--r--tests/cli.rs13
-rw-r--r--tests/fakes/fake_input.rs129
-rw-r--r--tests/snapshots/cli__bi_directional_traffic-2.snap6
-rw-r--r--tests/snapshots/cli__multiple_connections_from_remote_ip-2.snap6
-rw-r--r--tests/snapshots/cli__multiple_packets_of_traffic_from_different_connections-2.snap8
-rw-r--r--tests/snapshots/cli__multiple_packets_of_traffic_from_single_connection-2.snap6
-rw-r--r--tests/snapshots/cli__multiple_processes_with_multiple_connections-2.snap8
-rw-r--r--tests/snapshots/cli__one_packet_of_traffic-2.snap6
-rw-r--r--tests/snapshots/cli__one_process_with_multiple_connections-2.snap6
-rw-r--r--tests/snapshots/cli__sustained_traffic_from_multiple_processes-2.snap6
-rw-r--r--tests/snapshots/cli__sustained_traffic_from_multiple_processes.snap6
-rw-r--r--tests/snapshots/cli__sustained_traffic_from_multiple_processes_bi_directional-2.snap6
-rw-r--r--tests/snapshots/cli__sustained_traffic_from_multiple_processes_bi_directional.snap6
-rw-r--r--tests/snapshots/cli__sustained_traffic_from_one_process-2.snap4
-rw-r--r--tests/snapshots/cli__sustained_traffic_from_one_process.snap6
28 files changed, 278 insertions, 380 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 5133761..2c98fed 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -872,15 +872,6 @@ dependencies = [
]
[[package]]
-name = "netstat"
-version = "0.7.0"
-source = "git+https://github.com/imsnif/netstat-rs.git#5ec603a3dfbed21f39755f11e04855ebad08c78d"
-dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "nodrop"
version = "0.1.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1873,14 +1864,6 @@ dependencies = [
]
[[package]]
-name = "timer"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "tokio"
version = "0.1.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2175,17 +2158,14 @@ version = "0.1.0"
dependencies = [
"assert_cmd 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cargo-insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)",
"insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ipnetwork 0.14.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "netstat 0.7.0 (git+https://github.com/imsnif/netstat-rs.git)",
"packet 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"pnet 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"predicates 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
"procfs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"structopt 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"termion 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "timer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tui 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2352,7 +2332,6 @@ dependencies = [
"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
"checksum native-tls 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b2df1a4c22fd44a62147fd8f13dd0f95c9d8ca7b2610299b2a2f9cf8964274e"
"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
-"checksum netstat 0.7.0 (git+https://github.com/imsnif/netstat-rs.git)" = "<none>"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum normalize-line-endings 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2e0a1a39eab95caf4f5556da9289b9e68f0aafac901b2ce80daaf020d3b733a8"
"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
@@ -2464,7 +2443,6 @@ dependencies = [
"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
-"checksum timer 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "31d42176308937165701f50638db1c31586f183f1aab416268216577aec7306b"
"checksum tokio 0.1.22 (registry+https://github.com/rust-lang/crates.io-index)" = "5a09c0b5bb588872ab2f09afa13ee6e9dac11e10a0ec9e8e3ba39a5a5d530af6"
"checksum tokio-buf 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8fb220f46c53859a4b7ec083e41dec9778ff0b1851c0942b211edb89e0ccdc46"
"checksum tokio-current-thread 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d16217cad7f1b840c5a97dfb3c43b0c871fef423a6e8d2118c604e843662a443"
diff --git a/Cargo.toml b/Cargo.toml
index 32410d0..0aa43a2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -8,12 +8,9 @@ authors = ["Aram Drevekenin <aram@poor.dev>"]
pnet = "0.22.0"
procfs = "0.5.3"
ipnetwork = "0.14.0"
-timer = "0.2.0"
-chrono = "0.4.7"
tui = "0.5"
termion = "1.5"
structopt = "0.3"
-netstat = { git = "https://github.com/imsnif/netstat-rs.git" }
[dev-dependencies]
assert_cmd = "0.10"
diff --git a/src/display/ui.rs b/src/display/ui.rs
index 225ab64..460ff93 100644
--- a/src/display/ui.rs
+++ b/src/display/ui.rs
@@ -1,4 +1,5 @@
use ::std::fmt;
+use ::std::collections::HashMap;
use ::tui::backend::Backend;
use ::tui::layout::{Constraint, Direction, Layout, Rect};
use ::tui::style::{Color, Style};
@@ -7,7 +8,7 @@ use ::tui::widgets::{Block, Borders, Row, Table, Widget};
use ::tui::Terminal;
use crate::display::{Bandwidth, UIState};
-use crate::store::{CurrentConnections, NetworkUtilization};
+use crate::network::{Connection, Utilization};
struct DisplayBandwidth(f64);
@@ -92,7 +93,7 @@ fn render_connections_table(state: &UIState, frame: &mut Frame<impl Backend>, re
.map(|(connection, connection_data)| {
format_row_data(
connection.to_string(),
- connection_data.processes.join(", "),
+ connection_data.process_name.to_string(),
connection_data,
)
});
@@ -126,11 +127,11 @@ fn render_remote_ip_table(state: &UIState, frame: &mut Frame<impl Backend>, rect
}
pub fn display_loop(
- network_utilization: &NetworkUtilization,
+ network_utilization: &Utilization,
terminal: &mut Terminal<impl Backend>,
- current_connections: CurrentConnections,
+ connections_to_procs: HashMap<Connection, String>,
) {
- let state = UIState::new(current_connections, &network_utilization);
+ let state = UIState::new(connections_to_procs, &network_utilization);
terminal
.draw(|mut f| {
let screen_horizontal_halves = split(Direction::Horizontal, f.size());
diff --git a/src/display/ui_state.rs b/src/display/ui_state.rs
index 2fff47a..b2be517 100644
--- a/src/display/ui_state.rs
+++ b/src/display/ui_state.rs
@@ -1,8 +1,7 @@
-use ::std::collections::BTreeMap;
+use ::std::collections::{BTreeMap, HashMap};
use ::std::net::Ipv4Addr;
-use crate::store::{CurrentConnections, NetworkUtilization};
-use crate::traffic::Connection;
+use crate::network::{Connection, Utilization};
pub trait Bandwidth {
fn get_total_bytes_downloaded(&self) -> u128;
@@ -20,7 +19,7 @@ pub struct NetworkData {
pub struct ConnectionData {
pub total_bytes_downloaded: u128,
pub total_bytes_uploaded: u128,
- pub processes: Vec<String>,
+ pub process_name: String,
}
impl Bandwidth for ConnectionData {
@@ -49,13 +48,13 @@ pub struct UIState {
impl UIState {
pub fn new(
- current_connections: CurrentConnections,
- network_utilization: &NetworkUtilization,
+ connections_to_procs: HashMap<Connection, String>,
+ network_utilization: &Utilization,
) -> Self {
let mut processes: BTreeMap<String, NetworkData> = BTreeMap::new();
let mut remote_ips: BTreeMap<Ipv4Addr, NetworkData> = BTreeMap::new();
let mut connections: BTreeMap<Connection, ConnectionData> = BTreeMap::new();
- for (connection, mut associated_processes) in current_connections.connections {
+ for (connection, process_name) in connections_to_procs {
if let Some(connection_bandwidth_utilization) =
network_utilization.connections.get(&connection)
{
@@ -63,19 +62,18 @@ impl UIState {
.entry(connection.remote_socket.ip.clone())
.or_default();
let connection_data = connections.entry(connection).or_default();
- for process in &associated_processes {
- let data_for_process = processes.entry(process.to_string()).or_default();
- data_for_process.total_bytes_downloaded +=
- &connection_bandwidth_utilization.total_bytes_downloaded;
- data_for_process.total_bytes_uploaded +=
- &connection_bandwidth_utilization.total_bytes_uploaded;
- data_for_process.connection_count += 1;
- }
- connection_data.processes.append(&mut associated_processes);
+ let data_for_process = processes.entry(process_name.clone()).or_default();
+
+ data_for_process.total_bytes_downloaded +=
+ &connection_bandwidth_utilization.total_bytes_downloaded;
+ data_for_process.total_bytes_uploaded +=
+ &connection_bandwidth_utilization.total_bytes_uploaded;
+ data_for_process.connection_count += 1;
connection_data.total_bytes_downloaded +=
&connection_bandwidth_utilization.total_bytes_downloaded;
connection_data.total_bytes_uploaded +=
&connection_bandwidth_utilization.total_bytes_uploaded;
+ connection_data.process_name = process_name;
data_for_remote_ip.total_bytes_downloaded +=
connection_bandwidth_utilization.total_bytes_downloaded;
data_for_remote_ip.total_bytes_uploaded +=
diff --git a/src/lib.rs b/src/lib.rs
index 05518f1..15e4590 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,15 +1,13 @@
mod display;
-mod store;
-mod traffic;
+pub mod network;
use display::display_loop;
-use store::{CurrentConnections, NetworkUtilization};
-use traffic::Sniffer;
+use network::{Sniffer, Connection, Utilization};
-use ::netstat::SocketInfo;
use ::pnet::datalink::{DataLinkReceiver, NetworkInterface};
use ::std::sync::atomic::{AtomicBool, Ordering};
use ::std::sync::{Arc, Mutex};
+use ::std::collections::HashMap;
use ::std::{thread, time};
use ::termion::event::{Event, Key};
use ::tui::backend::Backend;
@@ -18,8 +16,7 @@ use ::tui::Terminal;
pub struct OsInput {
pub network_interface: NetworkInterface,
pub network_frames: Box<DataLinkReceiver>,
- pub get_process_name: fn(i32) -> Option<String>,
- pub get_open_sockets: fn() -> Vec<SocketInfo>,
+ pub get_open_sockets: fn() -> HashMap<Connection, String>,
pub keyboard_events: Box<Iterator<Item = Event> + Send + Sync + 'static>,
}
@@ -32,7 +29,6 @@ where
let running = r.clone();
let keyboard_events = os_input.keyboard_events; // TODO: as methods in os_interface
- let get_process_name = os_input.get_process_name;
let get_open_sockets = os_input.get_open_sockets;
let stdin_handler = thread::spawn(move || {
@@ -49,7 +45,7 @@ where
});
let mut sniffer = Sniffer::new(os_input.network_interface, os_input.network_frames);
- let network_utilization = Arc::new(Mutex::new(NetworkUtilization::new()));
+ let network_utilization = Arc::new(Mutex::new(Utilization::new()));
let display_handler = thread::spawn({
let network_utilization = network_utilization.clone();
@@ -58,11 +54,10 @@ where
terminal.clear().unwrap();
terminal.hide_cursor().unwrap();
while displaying.load(Ordering::SeqCst) {
- let current_connections =
- CurrentConnections::new(&get_process_name, &get_open_sockets);
+ let connections_to_procs = get_open_sockets();
{
let mut network_utilization = network_utilization.lock().unwrap();
- display_loop(&network_utilization, &mut terminal, current_connections);
+ display_loop(&network_utilization, &mut terminal, connections_to_procs);
network_utilization.reset();
}
thread::sleep(time::Duration::from_secs(1));
diff --git a/src/main.rs b/src/main.rs
index 87a08a9..7dbb40b 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -20,7 +20,7 @@ fn main() {
);
use os::{
- get_datalink_channel, get_interface, get_open_sockets, get_process_name, KeyboardEvents,
+ get_datalink_channel, get_interface, get_open_sockets, KeyboardEvents,
};
let opt = Opt::from_args();
@@ -34,7 +34,6 @@ fn main() {
let os_input = what::OsInput {
network_interface,
network_frames,
- get_process_name,
get_open_sockets,
keyboard_events,
};
diff --git a/src/network/connection.rs b/src/network/connection.rs
new file mode 100644
index 0000000..a535ade
--- /dev/null
+++ b/src/network/connection.rs
@@ -0,0 +1,73 @@
+use ::std::fmt;
+use ::std::net::Ipv4Addr;
+
+
+use ::std::net::SocketAddr;
+use ::std::mem::swap;
+
+#[derive(PartialEq, Hash, Eq, Debug, Clone, PartialOrd, Ord)]
+pub enum Protocol {
+ Tcp,
+ Udp,
+}
+
+impl fmt::Display for Protocol {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match *self {
+ Protocol::Tcp => write!(f, "tcp"),
+ Protocol::Udp => write!(f, "udp"),
+ }
+ }
+}
+
+#[derive(PartialEq, Hash, Eq, Debug, Clone, PartialOrd, Ord)]
+pub struct Socket {
+ pub ip: Ipv4Addr,
+ pub port: u16,
+}
+
+impl fmt::Display for Socket {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}:{}", self.ip, self.port)
+ }
+}
+
+#[derive(PartialEq, Hash, Eq, Debug, Clone, PartialOrd, Ord)]
+pub struct Connection {
+ pub local_socket: Socket,
+ pub remote_socket: Socket,
+ pub protocol: Protocol,
+}
+
+impl fmt::Display for Connection {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(
+ f,
+ "{} => {} ({})",
+ self.local_socket, self.remote_socket, self.protocol
+ )
+ }
+}
+
+impl Connection {
+ pub fn new (local_socket: SocketAddr, remote_socket: SocketAddr, protocol: Protocol) -> Option<Self> {
+ match (local_socket, remote_socket) {
+ (SocketAddr::V4(local_socket), SocketAddr::V4(remote_socket)) => Some(Connection {
+ // we use our own Socket here because SocketAddr is not sorable
+ local_socket: Socket {
+ ip: *local_socket.ip(),
+ port: local_socket.port(),
+ },
+ remote_socket: Socket {
+ ip: *remote_socket.ip(),
+ port: remote_socket.port(),
+ },
+ protocol,
+ }),
+ (_, _) => None,
+ }
+ }
+ pub fn swap_direction (&mut self) {
+ swap(&mut self.local_socket, &mut self.remote_socket);
+ }
+}
diff --git a/src/network/mod.rs b/src/network/mod.rs
new file mode 100644
index 0000000..bca8fb6
--- /dev/null
+++ b/src/network/mod.rs
@@ -0,0 +1,7 @@
+mod sniffer;
+mod connection;
+mod utilization;
+
+pub use sniffer::*;
+pub use connection::*;
+pub use utilization::*;
diff --git a/src/traffic.rs b/src/network/sniffer.rs
index 7b475b3..c25300f 100644
--- a/src/traffic.rs
+++ b/src/network/sniffer.rs
@@ -1,6 +1,4 @@
use ::std::boxed::Box;
-use ::std::fmt;
-use ::std::net::Ipv4Addr;
use ::pnet::datalink::{DataLinkReceiver, NetworkInterface};
use ::pnet::packet::ethernet::{EtherType, EthernetPacket};
@@ -11,40 +9,9 @@ use ::pnet::packet::udp::UdpPacket;
use ::pnet::packet::Packet;
use ::ipnetwork::IpNetwork;
+use ::std::net::{IpAddr, SocketAddr};
-#[derive(PartialEq, Hash, Eq, Debug, Clone, PartialOrd, Ord)]
-pub struct Socket {
- pub ip: Ipv4Addr,
- pub port: u16,
-}
-
-impl fmt::Display for Socket {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}:{}", self.ip, self.port)
- }
-}
-
-pub struct Sniffer {
- network_interface: NetworkInterface,
- network_frames: Box<DataLinkReceiver>,
-}
-
-#[derive(PartialEq, Hash, Eq, Debug, Clone, PartialOrd, Ord)]
-pub struct Connection {
- pub local_socket: Socket,
- pub remote_socket: Socket,
- pub protocol: Protocol,
-}
-
-impl fmt::Display for Connection {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(
- f,
- "{} => {} ({})",
- self.local_socket, self.remote_socket, self.protocol
- )
- }
-}
+use crate::network::{Connection, Protocol};
pub struct Segment {
pub connection: Connection,
@@ -52,21 +19,6 @@ pub struct Segment {
pub ip_length: u128,
}
-#[derive(PartialEq, Hash, Eq, Debug, Clone, PartialOrd, Ord)]
-pub enum Protocol {
- Tcp,
- Udp,
-}
-
-impl fmt::Display for Protocol {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match *self {
- Protocol::Tcp => write!(f, "tcp"),
- Protocol::Udp => write!(f, "udp"),
- }
- }
-}
-
#[derive(PartialEq, Hash, Eq, Debug, Clone, PartialOrd)]
pub enum Direction {
Download,
@@ -74,30 +26,20 @@ pub enum Direction {
}
impl Direction {
- pub fn make_connection(&self, from: Socket, to: Socket, protocol: Protocol) -> Connection {
- match self {
- Direction::Upload => Connection {
- local_socket: from,
- remote_socket: to,
- protocol,
- },
- Direction::Download => Connection {
- local_socket: to,
- remote_socket: from,
- protocol,
- },
+ pub fn new (network_interface_ips: &Vec<IpNetwork>, ip_packet: &Ipv4Packet) -> Self {
+ match network_interface_ips
+ .iter()
+ .any(|ip_network| ip_network.ip() == ip_packet.get_source())
+ {
+ true => Direction::Upload,
+ false => Direction::Download,
}
}
}
-fn find_direction(network_interface_ips: &Vec<IpNetwork>, ip_packet: &Ipv4Packet) -> Direction {
- match network_interface_ips
- .iter()
- .any(|ip_network| ip_network.ip() == ip_packet.get_source())
- {
- true => Direction::Upload,
- false => Direction::Download,
- }
+pub struct Sniffer {
+ network_interface: NetworkInterface,
+ network_frames: Box<DataLinkReceiver>,
}
impl Sniffer {
@@ -137,22 +79,15 @@ impl Sniffer {
}
_ => return None,
};
- let direction = find_direction(&self.network_interface.ips, &ip_packet);
- let from = Socket {
- ip: ip_packet.get_source(),
- port: source_port,
- };
- let to = Socket {
- ip: ip_packet.get_destination(),
- port: destination_port,
- };
- let connection = direction.make_connection(from, to, protocol);
+ let direction = Direction::new(&self.network_interface.ips, &ip_packet);
+ let from = SocketAddr::new(IpAddr::V4(ip_packet.get_source()), source_port);
+ let to = SocketAddr::new(IpAddr::V4(ip_packet.get_destination()), destination_port );
+ let mut connection = Connection::new(from, to, protocol)?;
+ if let Direction::Download = direction {
+ connection.swap_direction();
+ }
let ip_length = ip_packet.get_total_length() as u128;
- Some(Segment {
- connection,
- ip_length,
- direction,
- })
+ Some(Segment { connection, ip_length, direction })
}
_ => None,
}
diff --git a/src/store/network_utilization.rs b/src/network/utilization.rs
index de429aa..3b67a0a 100644
--- a/src/store/network_utilization.rs
+++ b/src/network/utilization.rs
@@ -1,4 +1,4 @@
-use crate::traffic::{Connection, Direction, Segment};
+use crate::network::{Connection, Direction, Segment};
use ::std::collections::HashMap;
@@ -16,14 +16,14 @@ impl TotalBandwidth {
}
}
-pub struct NetworkUtilization {
+pub struct Utilization {
pub connections: HashMap<Connection, TotalBandwidth>,
}
-impl NetworkUtilization {
+impl Utilization {
pub fn new() -> Self {
let connections = HashMap::new();
- NetworkUtilization { connections }
+ Utilization { connections }
}
pub fn reset(&mut self) {
self.connections.clear();
diff --git a/src/os/linux.rs b/src/os/linux.rs
index 3d7c41e..aa31452 100644
--- a/src/os/linux.rs
+++ b/src/os/linux.rs
@@ -1,13 +1,16 @@
-use ::netstat::{get_sockets_info, AddressFamilyFlags, ProtocolFlags, SocketInfo};
use ::pnet::datalink::Channel::Ethernet;
use ::pnet::datalink::DataLinkReceiver;
use ::pnet::datalink::{self, NetworkInterface};
-use ::std::fs::File;
-use ::std::io::prelude::*;
use ::std::io::stdin;
use ::termion::event::Event;
use ::termion::input::TermRead;
+use ::std::collections::HashMap;
+
+use ::procfs::FDTarget;
+
+use what::network::{Connection, Protocol};
+
pub struct KeyboardEvents;
impl Iterator for KeyboardEvents {
@@ -37,23 +40,40 @@ pub fn get_interface(interface_name: &str) -> Option<NetworkInterface> {
.find(|iface| iface.name == interface_name)
}
-fn read_proc_comm(id: i32) -> std::io::Result<String> {
- let filename = format!("/proc/{}/comm", id);
- let mut file = File::open(filename)?;
- let mut contents = String::new();
- file.read_to_string(&mut contents)?;
- Ok(contents)
-}
+pub fn get_open_sockets() -> HashMap<Connection, String> {
+ let mut open_sockets = HashMap::new(); // TODO: better
+ let all_procs = procfs::all_processes();
-pub fn get_process_name(id: i32) -> Option<String> {
- match read_proc_comm(id) {
- Ok(contents) => Some(contents),
- Err(_) => None,
+ let mut inode_to_procname = HashMap::new();
+ for process in all_procs {
+ if let Ok(fds) = process.fd() {
+ let procname = process.stat.comm;
+ for fd in fds {
+ if let FDTarget::Socket(inode) = fd.target {
+ inode_to_procname.insert(inode, procname.clone());
+ }
+ }
+ }
+ }
+
+ let tcp = ::procfs::tcp().unwrap();
+ for entry in tcp.into_iter() {
+ if let (Some(connection), Some(procname)) = (
+ Connection::new(entry.local_address, entry.remote_address, Protocol::Tcp),
+ inode_to_procname.get(&entry.inode),
+ ) {
+ open_sockets.insert(connection, procname.clone());
+ };
}
-}
-pub fn get_open_sockets() -> Vec<SocketInfo> {
- let af_flags = AddressFamilyFlags::IPV4;
- let proto_flags = ProtocolFlags::TCP | ProtocolFlags::UDP;
- get_sockets_info(af_flags, proto_flags).unwrap_or_default()
+ let udp = ::procfs::udp().unwrap();
+ for entry in udp.into_iter() {
+ if let (Some(connection), Some(procname)) = (
+ Connection::new(entry.local_address, entry.remote_address, Protocol::Udp),
+ inode_to_procname.get(&entry.inode),
+ ) {
+ open_sockets.insert(connection, procname.clone());
+ };
+ }
+ open_sockets
}
diff --git a/src/store/current_connections.rs b/src/store/current_connections.rs
deleted file mode 100644
index fc7b5fc..0000000
--- a/src/store/current_connections.rs
+++ /dev/null
@@ -1,92 +0,0 @@
-use crate::traffic::{Connection, Protocol, Socket};
-
-use ::netstat::{ProtocolSocketInfo, SocketInfo};
-use ::std::collections::HashMap;
-use ::std::net::{IpAddr, Ipv4Addr};
-
-fn get_ipv4_address(ip: IpAddr) -> Option<Ipv4Addr> {
- match ip {
- IpAddr::V4(addr) => Some(addr),
- IpAddr::V6(_) => None,
- }
-}
-
-fn build_ipv4_connection(
- local_ip: Option<Ipv4Addr>,
- remote_ip: Option<Ipv4Addr>,
- local_port: u16,
- remote_port: u16,
- protocol: Protocol,
-) -> Option<Connection> {
- match (local_ip, remote_ip) {
- (Some(local_ip), Some(remote_ip)) => Some(Connection {
- local_socket: Socket {
- ip: local_ip,
- port: local_port,
- },
- remote_socket: Socket {
- ip: remote_ip,
- port: remote_port,
- },
- protocol,
- }),
- (_, _) => None,
- }
-}
-
-pub struct CurrentConnections {
- pub connections: HashMap<Connection, Vec<String>>,
-}
-
-impl CurrentConnections {
- pub fn new(
- get_process_name: &Fn(i32) -> Option<String>,
- get_open_sockets: &Fn() -> Vec<SocketInfo>,
- ) -> Self {
- let sockets_info = get_open_sockets();
- let mut connections = HashMap::new();
- for si in sockets_info {
- match si.protocol_socket_info {
- ProtocolSocketInfo::Tcp(tcp_si) => {
- let local_addr = get_ipv4_address(tcp_si.local_addr);
- let remote_addr = get_ipv4_address(tcp_si.remote_addr);
- if let Some(conn) = build_ipv4_connection(
- local_addr,
- remote_addr,
- tcp_si.local_port,
- tcp_si.remote_port,
- Protocol::Tcp,
- ) {
- connections.insert(
- conn,
- si.associated_pids
- .iter()
- .map(|pid| get_process_name(*pid as i32).unwrap())
- .collect(),
- ); // TODO: handle None
- }
- }
- ProtocolSocketInfo::Udp(udp_si) => {
- let local_addr = get_ipv4_address(udp_si.local_addr);
- let remote_addr = get_ipv4_address(udp_si.remote_addr);
- if let Some(conn) = build_ipv4_connection(
- local_addr,
- remote_addr,
- udp_si.local_port,
- udp_si.remote_port,
- Protocol::Udp,
- ) {
- connections.insert(
- conn,
- si.associated_pids
- .iter()
- .map(|pid| get_process_name(*pid as i32).unwrap())
- .collect(),
- );
- }
- }
- }
- }
- CurrentConnections { connections }
- }
-}
diff --git a/src/store/mod.rs b/src/store/mod.rs
deleted file mode 100644
index afe72ee..0000000
--- a/src/store/mod.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-mod current_connections;
-mod network_utilization;
-
-pub use current_connections::*;
-pub use network_utilization::*;
diff --git a/tests/cli.rs b/tests/cli.rs
index 938add4..5e88ff4 100644
--- a/tests/cli.rs
+++ b/tests/cli.rs
@@ -2,7 +2,7 @@ mod fakes;
use fakes::TerminalEvent::*;
use fakes::{
- get_interface, get_open_sockets, get_process_name, KeyboardEvents, NetworkFrames, TestBackend,
+ get_interface, get_open_sockets, KeyboardEvents, NetworkFrames, TestBackend,
};
use ::insta::assert_snapshot;
@@ -70,7 +70,6 @@ fn basic_startup() {
let os_input = what::OsInput {
n