pub mod socket { use std::cmp::PartialEq; use regex::Regex; use std::collections::HashSet; use std::fmt::Display; use std::fs; use std::hash::{Hash, Hasher}; use std::os::unix::fs::MetadataExt; use crate::pids; #[derive(PartialEq)] #[derive(Clone)] #[derive(Debug)] pub struct Peer { pub ip_address: String, pub port: usize, } #[derive(PartialEq, Copy)] #[derive(Clone)] #[derive(Debug)] pub struct Id { pub real : usize, pub effective : usize, pub saved_set : usize, pub fs : usize, } impl Id { pub fn new(real : usize, effective : usize, saved_set : usize, fs : usize) -> Id { Id { real, effective, saved_set, fs, } } pub fn create_def() -> Id { Id::new(0,0,0,0) } } impl Peer { fn new() -> Peer { Peer { ip_address: "0.0.0.0".to_string(), port: 0, } } pub fn build_from_hex(hex_peer : &str) -> Peer { let mut split = hex_peer.split(":"); let hex_ip = split.nth(0).unwrap(); let hex_port = split.nth(0).unwrap(); Peer { ip_address: Self::convert_ip_hex_dec(hex_ip), port: Self::convert_port_hex_dec(hex_port), } } fn convert_ip_hex_dec(ip_address: &str) -> String { let mut buffer: String = String::new(); let mut ip_quads: Vec = vec![]; for (i, v) in ip_address.chars().enumerate() { if i % 2 == 1 { buffer.push(v); ip_quads.push( u64::from_str_radix(&buffer, 16) .expect("upsi 2") .to_string(), ); buffer = String::new(); } else { buffer.push(v); } } ip_quads .iter() .rev() .map(|x| x.to_owned()) .collect::>() .join(".") } pub fn convert_port_hex_dec(port: &str) -> usize { usize::from_str_radix(port, 16).expect("upsi 3") } pub fn get_ip_string(&self) -> String { self.clone().ip_address } pub fn get_port_string(&self) -> String{ if self.port == 0 { String::from("*")} else {self.port.to_string()} } } #[derive(PartialEq)] #[derive(Clone)] #[derive(Debug)] pub enum Tcp_SocketState { Established, SYN_Sent, SYN_Recv, FIN_Wait1, FIN_Wait2, TIME_Wait, Close, Close_Wait, Last_ACK, Listening, Closing, New_SYN_Recv, Bound_Inactive, Max_States, Undefined, } impl Tcp_SocketState { pub fn new(index : usize) -> Tcp_SocketState { match index { 1 => Tcp_SocketState::Established, 2 => Tcp_SocketState::SYN_Sent, 3 => Tcp_SocketState::SYN_Recv, 4 => Tcp_SocketState::FIN_Wait1, 5 => Tcp_SocketState::FIN_Wait2, 6 => Tcp_SocketState::TIME_Wait, 7 => Tcp_SocketState::Close, 8 => Tcp_SocketState::Close_Wait, 9 => Tcp_SocketState::Last_ACK, 10 => Tcp_SocketState::Listening, 11 => Tcp_SocketState::Closing, 12 => Tcp_SocketState::New_SYN_Recv, 13 => Tcp_SocketState::Bound_Inactive, 14 => Tcp_SocketState::Max_States, _ => Tcp_SocketState::Undefined, } } pub fn to_string(&self) -> String { match self { Tcp_SocketState::Established => String::from("Established"), Tcp_SocketState::SYN_Sent => String::from("SYN_Sent"), Tcp_SocketState::SYN_Recv => String::from("SYN_Recv"), Tcp_SocketState::FIN_Wait1 => String::from("FIN_Wait1"), Tcp_SocketState::FIN_Wait2 => String::from("FIN_Wait2"), Tcp_SocketState::TIME_Wait => String::from("TIME_Wait"), Tcp_SocketState::Close => String::from("Close"), Tcp_SocketState::Close_Wait => String::from("Close_Wait"), Tcp_SocketState::Last_ACK => String::from("Last_ACK"), Tcp_SocketState::Listening => String::from("Listening"), Tcp_SocketState::Closing => String::from("Closing"), Tcp_SocketState::New_SYN_Recv => String::from("New_SYN_Recv"), Tcp_SocketState::Bound_Inactive => String::from("Bound_Inactive"), Tcp_SocketState::Max_States => String::from("Max_States"), Tcp_SocketState::Undefined => String::from("Undefined"), } } } pub fn pids_to_string(pids : pids) -> String { let mut ret_str = String::from(""); pids.iter().for_each(|x| { ret_str.push_str(&x.to_string()); ret_str.push_str(", "); }); ret_str.drain(ret_str.len()-2..ret_str.len()); ret_str } impl PartialEq for Tcp_Socket { fn eq(&self, other: &Self) -> bool { return self.inode == other.inode; } } impl Eq for Tcp_Socket {} impl Hash for Tcp_Socket { fn hash(&self, state: &mut H) -> (){ let mut state = self.inode * 31; state = state + 11; } } #[derive(Clone, Debug)] pub struct Tcp_Socket { peer_loc: Peer, peer_rem: Peer, pub pids: HashSet, state : Tcp_SocketState, user : Id, group : Id, pub inode : u64 } #[derive(Clone,Copy, PartialEq)] pub enum Combination{ tnap, tna, } impl Tcp_Socket { pub fn new(peer_loc : Peer, peer_rem : Peer, pids : HashSet, state : Tcp_SocketState, user : Id, group : Id, inode : u64) -> Tcp_Socket { Tcp_Socket { peer_loc, peer_rem, pids, state, user, group, inode, } } fn get_tcp_file_inode(pid: u64) -> u64 { let mut path = String::from("/proc/"); path.push_str(&pid.to_string()); path.push_str("/net/tcp"); let inode = fs::metadata(&path) .expect("Cannot read metadata") .ino(); inode } pub fn add_pid(socket : &mut Tcp_Socket, pid : u64) -> () { socket.pids.insert(pid); } pub fn add_uid_gid(socket : &mut Tcp_Socket, uid : Id, gid : Id) -> (){ socket.user = uid; socket.group = gid; } pub fn check_inode_seen(seen_inodes : &HashSet, pid : u64) -> bool { let inode = Tcp_Socket::get_tcp_file_inode(pid); seen_inodes.contains(&inode) } pub fn add_inode(seen_inodes : &mut HashSet, pid: u64){ let inode = Tcp_Socket::get_tcp_file_inode(pid); seen_inodes.insert(inode); } pub fn get_loc_ip_string(&self) -> String{ self.peer_loc.get_ip_string() } pub fn get_loc_port_string(&self) -> String{ self.peer_loc.get_port_string() } pub fn get_rem_ip_string(&self) -> String{ self.peer_rem.get_ip_string() } pub fn get_rem_port_string(&self) -> String{ self.peer_rem.get_port_string() } pub fn to_string (&self, combination: Combination) -> String { let mut ret_str = String::from(""); match combination { Combination::tnap => { //state rem_ip:rem_port loc_ip:loc_port real|effective-uid real|effective-gid pids(.,.,.,.) ret_str.push_str(&self.clone().to_string(Combination::tna)); ret_str.push(' '); ret_str.push_str(&self.user.real.to_string()); ret_str.push('|'); ret_str.push_str(&self.user.effective.to_string()); ret_str.push(' '); ret_str.push_str(&self.group.real.to_string()); ret_str.push('|'); ret_str.push_str(&self.group.effective.to_string()); ret_str.push_str(&pids_to_string(self.clone().pids)); ret_str } Combination::tna => { //state rem_ip:rem_port loc_ip:loc_port ret_str.push_str(&self.state.to_string()); ret_str.push(' '); ret_str.push_str(&self.peer_loc.ip_address); ret_str.push(':'); let loc_port_str = self.peer_loc.port.clone().to_string(); ret_str.push_str(if self.peer_loc.port == 0 { "*" } else { &loc_port_str }); ret_str.push(' '); ret_str.push_str(&self.peer_rem.ip_address); ret_str.push(':'); let rem_port_str = self.peer_rem.port.clone().to_string(); ret_str.push_str(if self.peer_rem.port == 0 { "*" } else { &rem_port_str }); ret_str.push('\n'); ret_str } } } pub fn get_state(&self) -> Tcp_SocketState{ self.state.clone() } fn get_all_unique_socket_infos() -> String { let pattern = Regex::new(r"^[1-4]?[0-9]{1,6}$").expect("kannst kein regex??"); let contents = fs::read_dir("/proc/").expect("upsi 4 (proc kann nicht gelesen werden, Berechtigung?)"); let mut seen_inodes = HashSet::::new(); let mut complete_file: String = String::new(); for dir in contents { match dir { Ok(dir) => { if !pattern.is_match( &dir.file_name() .into_string() .expect("Dateiname ist kein gueltiger Unicode-String")[..], ) { continue; } let mut path = dir.path().into_os_string().into_string().expect("gehtnd"); path.push_str("/net/tcp"); let pid = &path.split("/").nth(2).expect("gesplittert"); if !Tcp_Socket::check_inode_seen(&seen_inodes, pid.parse::().unwrap()) { Tcp_Socket::add_inode(& mut seen_inodes, pid.parse::().unwrap()); let test = &fs::read_to_string(path) .expect("Could not read proc/pid/net/tcp") .lines() .skip(1) // .map(|x| socket::convert_line(x.to_string())) .map(|x| x.to_owned()) .collect::>() .join("\n"); complete_file.push_str(test); } else{ continue; } }, Err(_) => continue, }; } // complete_file complete_file } } } #[cfg(test)] mod tests { use crate::socket::socket::Combination; use super::*; fn init_sockets() -> Vec { let mut sockets = Vec::::new(); let root_uid = socket::Id::new(0,0,0,0); let root_gid = root_uid.clone(); let mux_uid = socket::Id::new(1000,1000,1000,1000); let mux_gid = mux_uid.clone(); let sudo_mux_uid = socket::Id::new(1000,0,0,0); let sudo_mux_gid = root_gid.clone(); // sockets.push(socket::Socket::new("93.83.160.12", 21345, "0.0.0.0", 0, Vec::::new(), socket::SocketState::Listening, root_uid, root_gid, 123123)); // sockets.push(socket::Socket::new("195.201.90.97", 8843, "0.0.0.0", 443, Vec::::new(), socket::SocketState::Established, mux_uid, mux_gid, 218389)); // sockets.push(socket::Socket::new("255.255.255.255", 193193, "0.0.0.0", 8080, Vec::::new(), socket::SocketState::Listening, sudo_mux_uid, sudo_mux_gid, 1301011)); sockets } #[test] fn test_build_from_hex() -> () { let hex_val = "0100007F"; assert_eq!(socket::Peer::build_from_hex("0100007F:F168"), socket::Peer { ip_address: "127.0.0.1".to_owned(), port: 61800 }); assert_eq!(socket::Peer::build_from_hex("980FB23E:ACCE"), socket::Peer { ip_address: "62.178.15.152".to_owned(), port: 44238 }); assert_eq!(socket::Peer::build_from_hex("00000000:30C8"), socket::Peer { ip_address: "0.0.0.0".to_owned(), port: 12488 }); } #[test] fn test_to_string() -> () { let sockets = init_sockets(); assert_eq!("93.83.160.12:21345 0.0.0.0:*\n", sockets[0].clone().to_string(Combination::tna)); assert_eq!("195.201.90.97:8843 0.0.0.0:443\n", sockets[1].clone().to_string(Combination::tna)); assert_eq!("255.255.255.255:193193 0.0.0.0:8080\n", sockets[2].clone().to_string(Combination::tna)); } }