From 2f15b601bc5f8121e8b22c6263014ba78df0b880 Mon Sep 17 00:00:00 2001 From: sad Date: Mon, 7 Oct 2024 17:25:38 +0000 Subject: [PATCH] fix some issue with server/client ident --- Cargo.lock | 332 ++++++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 1 + src/main.rs | 139 ++++++++++++++++------ 3 files changed, 436 insertions(+), 36 deletions(-) create mode 100644 Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..cf42a05 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,332 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "blackwall" +version = "0.1.0" +dependencies = [ + "colored", + "pnet", +] + +[[package]] +name = "colored" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf2150cce219b664a8a70df7a1f933836724b503f8a413af9365b4dcc4d90b8" +dependencies = [ + "lazy_static", + "windows-sys", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "ipnetwork" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf466541e9d546596ee94f9f69590f89473455f88372423e0008fc1a7daf100e" +dependencies = [ + "serde", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "no-std-net" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43794a0ace135be66a25d3ae77d41b91615fb68ae937f904090203e81f755b65" + +[[package]] +name = "pnet" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "682396b533413cc2e009fbb48aadf93619a149d3e57defba19ff50ce0201bd0d" +dependencies = [ + "ipnetwork", + "pnet_base", + "pnet_datalink", + "pnet_packet", + "pnet_sys", + "pnet_transport", +] + +[[package]] +name = "pnet_base" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc190d4067df16af3aba49b3b74c469e611cad6314676eaf1157f31aa0fb2f7" +dependencies = [ + "no-std-net", +] + +[[package]] +name = "pnet_datalink" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e79e70ec0be163102a332e1d2d5586d362ad76b01cec86f830241f2b6452a7b7" +dependencies = [ + "ipnetwork", + "libc", + "pnet_base", + "pnet_sys", + "winapi", +] + +[[package]] +name = "pnet_macros" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13325ac86ee1a80a480b0bc8e3d30c25d133616112bb16e86f712dcf8a71c863" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn", +] + +[[package]] +name = "pnet_macros_support" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eed67a952585d509dd0003049b1fc56b982ac665c8299b124b90ea2bdb3134ab" +dependencies = [ + "pnet_base", +] + +[[package]] +name = "pnet_packet" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c96ebadfab635fcc23036ba30a7d33a80c39e8461b8bd7dc7bb186acb96560f" +dependencies = [ + "glob", + "pnet_base", + "pnet_macros", + "pnet_macros_support", +] + +[[package]] +name = "pnet_sys" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d4643d3d4db6b08741050c2f3afa9a892c4244c085a72fcda93c9c2c9a00f4b" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "pnet_transport" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f604d98bc2a6591cf719b58d3203fd882bdd6bf1db696c4ac97978e9f4776bf" +dependencies = [ + "libc", + "pnet_base", + "pnet_packet", + "pnet_sys", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" + +[[package]] +name = "serde" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.210" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89132cd0bf050864e1d38dc3bbc07a0eb8e7530af26344d3d2bbbef83499f590" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/README.md b/README.md index 525b789..38a831f 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ # BlackWall A WIP next gen firewall for Linux. + ![blackwall demo](/docs/demo.png) diff --git a/src/main.rs b/src/main.rs index ccfce49..8c85535 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,10 +1,10 @@ +use colored::*; use pnet::datalink; -use std::fs::{File, read_dir}; -use std::io::{BufRead, BufReader}; use std::collections::{HashMap, HashSet}; +use std::fs::{read_dir, read_to_string, File}; +use std::io::{BufRead, BufReader}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::path::Path; -use colored::*; #[derive(Debug, Clone, PartialEq, Eq, Hash)] enum PortType { @@ -33,13 +33,16 @@ fn main() -> Result<(), Box> { let open_ports = get_open_ports()?; for interface in interfaces { - println!("{}", format!("Interface: {}", interface.name).green().bold()); - + println!( + "{}", + format!("Interface: {}", interface.name).green().bold() + ); + let mut interface_ports: HashSet = HashSet::new(); for ip in &interface.ips { println!(" {}", format!("IP: {}", ip).cyan()); - + if let Some(ports) = open_ports.get(&ip.ip()) { interface_ports.extend(ports.iter().cloned()); } @@ -48,23 +51,29 @@ fn main() -> Result<(), Box> { if !interface_ports.is_empty() { println!(" {}", "Open ports:".yellow()); for port in interface_ports { - let port_type_color = if port.port_type == PortType::TCP { "TCP".blue() } else { "UDP".magenta() }; + let port_type_color = if port.port_type == PortType::TCP { + "TCP".blue() + } else { + "UDP".magenta() + }; let conn_type_color = match port.connection_type { ConnectionType::Server => "Server".green(), ConnectionType::Client => "Client".yellow(), ConnectionType::Unknown => "Unknown".red(), }; - println!(" {} ({}) - {} - {} ({})", - port.number.to_string().white().bold(), - port_type_color, - port.process_name.cyan(), - conn_type_color, - port.state.white()); + println!( + " {} ({}) - {} - {} ({})", + port.number.to_string().white().bold(), + port_type_color, + port.process_name.cyan(), + conn_type_color, + port.state.white() + ); } } else { println!(" {}", "No open ports found".red()); } - + println!(); } @@ -80,7 +89,11 @@ fn get_open_ports() -> Result>, Box().ok()) { + if let Some(pid) = path + .file_name() + .and_then(|n| n.to_str()) + .and_then(|s| s.parse::().ok()) + { let fd_dir = path.join("fd"); if fd_dir.is_dir() { for fd_entry in read_dir(fd_dir)? { @@ -89,7 +102,9 @@ fn get_open_ports() -> Result>, Box Result>, Box>, inode_to_pid: &HashMap, port_type: PortType, - is_ipv6: bool + is_ipv6: bool, ) -> Result<(), Box> { let file = File::open(file_path)?; let reader = BufReader::new(file); @@ -135,22 +174,31 @@ fn parse_connections( }; let port = u16::from_str_radix(address_parts[1], 16)?; let process_name = get_process_name(inode_to_pid.get(inode))?; - let (connection_type, state) = determine_connection_type(&port_type, state_hex, local_address, remote_address); - let port_info = PortInfo { - number: port, - port_type: port_type.clone(), + let (connection_type, state) = + determine_connection_type(&port_type, state_hex, local_address, remote_address); + let port_info = PortInfo { + number: port, + port_type: port_type.clone(), process_name, connection_type, state, }; - open_ports.entry(ip).or_insert_with(HashSet::new).insert(port_info); + open_ports + .entry(ip) + .or_insert_with(HashSet::new) + .insert(port_info); } } } Ok(()) } -fn determine_connection_type(port_type: &PortType, state_hex: &str, local_address: &str, remote_address: &str) -> (ConnectionType, String) { +fn determine_connection_type( + port_type: &PortType, + state_hex: &str, + local_address: &str, + remote_address: &str, +) -> (ConnectionType, String) { let state = u8::from_str_radix(state_hex, 16).unwrap_or(0); match port_type { @@ -158,13 +206,15 @@ fn determine_connection_type(port_type: &PortType, state_hex: &str, local_addres match state { 1 => { // ESTABLISHED: Check if the remote port is 0 (unlikely for a client) - let remote_port = u16::from_str_radix(remote_address.split(':').last().unwrap_or("0"), 16).unwrap_or(0); + let remote_port = + u16::from_str_radix(remote_address.split(':').last().unwrap_or("0"), 16) + .unwrap_or(0); if remote_port == 0 { (ConnectionType::Server, "ESTABLISHED".to_string()) } else { (ConnectionType::Client, "ESTABLISHED".to_string()) } - }, + } 2 => (ConnectionType::Client, "SYN_SENT".to_string()), 3 => (ConnectionType::Server, "SYN_RECV".to_string()), 4 => (ConnectionType::Unknown, "FIN_WAIT1".to_string()), @@ -177,26 +227,43 @@ fn determine_connection_type(port_type: &PortType, state_hex: &str, local_addres 11 => (ConnectionType::Unknown, "CLOSING".to_string()), _ => (ConnectionType::Unknown, format!("UNKNOWN ({})", state)), } - }, + } PortType::UDP => { if remote_address == "00000000:0000" { (ConnectionType::Server, "UNCONN".to_string()) } else { (ConnectionType::Client, "ESTABLISHED".to_string()) } - }, + } } } - fn get_process_name(pid: Option<&u32>) -> Result> { match pid { Some(&pid) => { let comm_path = Path::new("/proc").join(pid.to_string()).join("comm"); - let mut name = std::fs::read_to_string(comm_path)?; - name.truncate(name.trim_end().len()); - Ok(name) - }, + let cmdline_path = Path::new("/proc").join(pid.to_string()).join("cmdline"); + + // Try to read from comm file first + if let Ok(mut name) = read_to_string(&comm_path) { + name.truncate(name.trim_end().len()); + if !name.is_empty() { + return Ok(name); + } + } + + // If comm is empty or unreadable, try cmdline + if let Ok(cmdline) = read_to_string(&cmdline_path) { + let parts: Vec<&str> = cmdline.split('\0').collect(); + if !parts.is_empty() { + if let Some(name) = Path::new(parts[0]).file_name() { + return Ok(name.to_string_lossy().into_owned()); + } + } + } + + Ok("Unknown".to_string()) + } None => Ok("Unknown".to_string()), } }