383 lines
14 KiB
Rust
383 lines
14 KiB
Rust
|
|
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<String> = 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::<Vec<String>>()
|
|
.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<H : Hasher>(&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<u64>,
|
|
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<u64>, 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<u64>, pid : u64) -> bool {
|
|
let inode = Tcp_Socket::get_tcp_file_inode(pid);
|
|
seen_inodes.contains(&inode)
|
|
}
|
|
|
|
pub fn add_inode(seen_inodes : &mut HashSet<u64>, 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::<u64>::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::<u64>().unwrap()) {
|
|
Tcp_Socket::add_inode(& mut seen_inodes, pid.parse::<u64>().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::<Vec<String>>()
|
|
.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<socket::Tcp_Socket> {
|
|
let mut sockets = Vec::<socket::Tcp_Socket>::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::<u64>::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::<u64>::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::<u64>::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));
|
|
}
|
|
}
|