-
-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
352 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,3 +27,5 @@ pub mod packet; | |
pub mod section; | ||
|
||
pub mod dns; | ||
|
||
pub mod pid; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
use std::hash::{DefaultHasher, Hash, Hasher}; | ||
use std::net::IpAddr; | ||
use std::num::ParseIntError; | ||
|
||
pub mod tcp; | ||
pub mod udp; | ||
|
||
use tcp::TcpConnectionMap; | ||
use udp::UdpConnectionMap; | ||
|
||
use crate::app::AppResult; | ||
use crate::packet::network::{IpPacket, IpProto}; | ||
use crate::packet::NetworkPacket; | ||
|
||
pub fn get_pid(packet: NetworkPacket, map: &ConnectionMap) -> Option<usize> { | ||
match packet { | ||
NetworkPacket::Ip(ip_packet) => match ip_packet { | ||
IpPacket::V4(ipv4_packet) => match ipv4_packet.proto { | ||
IpProto::Tcp(tcp_packet) => { | ||
let connection = Connection { | ||
ip_local: IpAddr::V4(ipv4_packet.src_ip), | ||
port_local: Some(tcp_packet.src_port), | ||
ip_remote: IpAddr::V4(ipv4_packet.dst_ip), | ||
port_remote: Some(tcp_packet.dst_port), | ||
}; | ||
return map.tcp.map.get(&connection.calculate_hash()).copied(); | ||
} | ||
|
||
IpProto::Udp(udp_packet) => { | ||
let connection = Connection { | ||
ip_local: IpAddr::V4(ipv4_packet.src_ip), | ||
port_local: Some(udp_packet.src_port), | ||
ip_remote: IpAddr::V4(ipv4_packet.dst_ip), | ||
port_remote: Some(udp_packet.dst_port), | ||
}; | ||
return map.udp.map.get(&connection.calculate_hash()).copied(); | ||
} | ||
_ => {} | ||
}, | ||
_ => {} | ||
}, | ||
_ => {} | ||
}; | ||
None | ||
} | ||
|
||
fn decode_hex_ipv4(hex_str: &str) -> AppResult<[u8; 4]> { | ||
let mut bytes = Vec::new(); | ||
for i in (0..hex_str.len()).step_by(2) { | ||
let byte_str = &hex_str[i..i + 2]; | ||
let byte = u8::from_str_radix(byte_str, 16)?; | ||
bytes.push(byte); | ||
} | ||
let mut res: [u8; 4] = bytes.as_slice().try_into()?; | ||
res.reverse(); | ||
Ok(res) | ||
} | ||
|
||
fn decode_hex_port(hex_str: &str) -> Result<u16, ParseIntError> { | ||
Ok(u16::from_be_bytes([ | ||
u8::from_str_radix(&hex_str[..2], 16)?, | ||
u8::from_str_radix(&hex_str[2..], 16)?, | ||
])) | ||
} | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct ConnectionMap { | ||
tcp: TcpConnectionMap, | ||
udp: UdpConnectionMap, | ||
} | ||
|
||
impl ConnectionMap { | ||
pub fn new() -> Self { | ||
Self { | ||
tcp: TcpConnectionMap::new(), | ||
udp: UdpConnectionMap::new(), | ||
} | ||
} | ||
} | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct Connection { | ||
ip_local: IpAddr, | ||
port_local: Option<u16>, | ||
ip_remote: IpAddr, | ||
port_remote: Option<u16>, | ||
} | ||
|
||
impl Hash for Connection { | ||
fn hash<H: Hasher>(&self, state: &mut H) { | ||
self.ip_local.hash(state); | ||
self.port_local.hash(state); | ||
self.ip_remote.hash(state); | ||
self.port_remote.hash(state); | ||
} | ||
} | ||
|
||
impl Connection { | ||
pub fn calculate_hash(&self) -> u64 { | ||
let mut s = DefaultHasher::new(); | ||
self.hash(&mut s); | ||
s.finish() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
use std::{ | ||
collections::HashMap, | ||
fs::{self, File}, | ||
io::Read, | ||
net::{IpAddr, Ipv4Addr}, | ||
}; | ||
|
||
use super::{decode_hex_ipv4, decode_hex_port, Connection}; | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct TcpConnectionMap { | ||
pub map: HashMap<u64, usize>, | ||
} | ||
|
||
impl TcpConnectionMap { | ||
fn inode_map() -> HashMap<usize, u64> { | ||
let mut map = HashMap::new(); | ||
let mut file = File::open("/proc/net/tcp").unwrap(); | ||
let mut buffer = String::new(); | ||
file.read_to_string(&mut buffer).unwrap(); | ||
|
||
let mut lines_tcp = buffer.lines(); | ||
lines_tcp.next(); | ||
|
||
for line in lines_tcp { | ||
let splits: Vec<&str> = line.split_whitespace().collect(); | ||
let ip_local: &str = splits[1]; | ||
let mut ip_local_port = ip_local.split(":"); | ||
let ip_local = ip_local_port.next().unwrap(); | ||
let port_local = ip_local_port.next().unwrap(); | ||
|
||
let ip_local = decode_hex_ipv4(ip_local).unwrap(); | ||
let ip_local = IpAddr::V4(Ipv4Addr::from(ip_local)); | ||
|
||
let port_local = decode_hex_port(port_local).unwrap(); | ||
|
||
let ip_remote = splits[2]; | ||
let mut ip_remote_port = ip_remote.split(":"); | ||
let ip_remote = ip_remote_port.next().unwrap(); | ||
let port_remote = ip_remote_port.next().unwrap(); | ||
|
||
let ip_remote = decode_hex_ipv4(ip_remote).unwrap(); | ||
let ip_remote = IpAddr::V4(Ipv4Addr::from(ip_remote)); | ||
|
||
let port_remote = decode_hex_port(port_remote).unwrap(); | ||
|
||
let inode = splits[9].parse::<usize>().unwrap(); | ||
|
||
let connection = Connection { | ||
ip_local, | ||
port_local: Some(port_local), | ||
ip_remote, | ||
port_remote: Some(port_remote), | ||
}; | ||
|
||
map.insert(inode, connection.calculate_hash()); | ||
} | ||
map | ||
} | ||
|
||
pub fn new() -> Self { | ||
let mut map: HashMap<u64, usize> = HashMap::new(); | ||
|
||
let inode_map = Self::inode_map(); | ||
|
||
if let Ok(entries) = fs::read_dir("/proc") { | ||
for entry in entries.flatten() { | ||
let pid_str = entry.file_name(); | ||
let pid_str = pid_str.to_str().unwrap(); | ||
if !pid_str.chars().all(char::is_numeric) { | ||
continue; | ||
} | ||
let fd_dir = format!("/proc/{}/fd", pid_str); | ||
if let Ok(fds) = fs::read_dir(&fd_dir) { | ||
for fd in fds.flatten() { | ||
let link_path = fd.path(); | ||
|
||
if let Ok(link_target) = fs::read_link(&link_path) { | ||
// Socket inodes are typically shown as "socket:[inode]" | ||
if let Some(inode_str) = link_target.to_str() { | ||
if inode_str.starts_with("socket:[") && inode_str.ends_with(']') { | ||
if let Ok(inode) = | ||
inode_str[8..inode_str.len() - 1].parse::<usize>() | ||
{ | ||
if let Some(connection_hash) = inode_map.get(&inode) { | ||
let pid = pid_str.parse::<usize>().unwrap(); | ||
map.insert(*connection_hash, pid); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
Self { map } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
use std::{ | ||
collections::HashMap, | ||
fs::{self, File}, | ||
io::Read, | ||
net::{IpAddr, Ipv4Addr}, | ||
}; | ||
|
||
use super::{decode_hex_ipv4, decode_hex_port, Connection}; | ||
|
||
#[derive(Clone, Debug)] | ||
pub struct UdpConnectionMap { | ||
pub map: HashMap<u64, usize>, | ||
} | ||
|
||
impl UdpConnectionMap { | ||
fn inode_map() -> HashMap<usize, u64> { | ||
let mut map = HashMap::new(); | ||
let mut file = File::open("/proc/net/udp").unwrap(); | ||
let mut buffer = String::new(); | ||
file.read_to_string(&mut buffer).unwrap(); | ||
|
||
let mut lines_tcp = buffer.lines(); | ||
lines_tcp.next(); | ||
|
||
for line in lines_tcp { | ||
let splits: Vec<&str> = line.split_whitespace().collect(); | ||
let ip_local: &str = splits[1]; | ||
let mut ip_local_port = ip_local.split(":"); | ||
let ip_local = ip_local_port.next().unwrap(); | ||
let port_local = ip_local_port.next().unwrap(); | ||
|
||
let ip_local = decode_hex_ipv4(ip_local).unwrap(); | ||
let ip_local = IpAddr::V4(Ipv4Addr::from(ip_local)); | ||
|
||
let port_local = decode_hex_port(port_local).unwrap(); | ||
|
||
let ip_remote = splits[2]; | ||
let mut ip_remote_port = ip_remote.split(":"); | ||
let ip_remote = ip_remote_port.next().unwrap(); | ||
let port_remote = ip_remote_port.next().unwrap(); | ||
|
||
let ip_remote = decode_hex_ipv4(ip_remote).unwrap(); | ||
let ip_remote = IpAddr::V4(Ipv4Addr::from(ip_remote)); | ||
|
||
let port_remote = decode_hex_port(port_remote).unwrap(); | ||
|
||
let inode = splits[9].parse::<usize>().unwrap(); | ||
|
||
let connection = Connection { | ||
ip_local, | ||
port_local: Some(port_local), | ||
ip_remote, | ||
port_remote: Some(port_remote), | ||
}; | ||
|
||
map.insert(inode, connection.calculate_hash()); | ||
} | ||
map | ||
} | ||
|
||
pub fn new() -> Self { | ||
let mut map: HashMap<u64, usize> = HashMap::new(); | ||
|
||
let inode_map = Self::inode_map(); | ||
|
||
if let Ok(entries) = fs::read_dir("/proc") { | ||
for entry in entries.flatten() { | ||
let pid_str = entry.file_name(); | ||
let pid_str = pid_str.to_str().unwrap(); | ||
if !pid_str.chars().all(char::is_numeric) { | ||
continue; | ||
} | ||
let fd_dir = format!("/proc/{}/fd", pid_str); | ||
if let Ok(fds) = fs::read_dir(&fd_dir) { | ||
for fd in fds.flatten() { | ||
let link_path = fd.path(); | ||
|
||
if let Ok(link_target) = fs::read_link(&link_path) { | ||
if let Some(inode_str) = link_target.to_str() { | ||
if inode_str.starts_with("socket:[") && inode_str.ends_with(']') { | ||
if let Ok(inode) = | ||
inode_str[8..inode_str.len() - 1].parse::<usize>() | ||
{ | ||
if let Some(connection_hash) = inode_map.get(&inode) { | ||
let pid = pid_str.parse::<usize>().unwrap(); | ||
map.insert(*connection_hash, pid); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
Self { map } | ||
} | ||
} |
Oops, something went wrong.