use crate::unix::UnixProcess;
use log::debug;
use nix::unistd::Pid;
use procfs::process::FDTarget;
use std::collections::HashSet;
use std::io::Error;
fn find_target_inodes(port: u16) -> Vec<u64> {
let tcp = procfs::net::tcp();
let tcp6 = procfs::net::tcp6();
let udp = procfs::net::udp();
let udp6 = procfs::net::udp6();
let mut target_inodes = Vec::new();
trait NetEntry {
fn local_address(&self) -> std::net::SocketAddr;
fn inode(&self) -> u64;
}
impl NetEntry for procfs::net::TcpNetEntry {
fn local_address(&self) -> std::net::SocketAddr {
self.local_address
}
fn inode(&self) -> u64 {
self.inode
}
}
impl NetEntry for procfs::net::UdpNetEntry {
fn local_address(&self) -> std::net::SocketAddr {
self.local_address
}
fn inode(&self) -> u64 {
self.inode
}
}
fn add_matching_inodes<T: NetEntry>(
target_inodes: &mut Vec<u64>,
net_entries: procfs::ProcResult<Vec<T>>,
port: u16,
) {
if let Ok(net_entries) = net_entries {
target_inodes.extend(
net_entries
.into_iter()
.filter(move |net_entry| net_entry.local_address().port() == port)
.map(|net_entry| net_entry.inode()),
);
}
}
add_matching_inodes(&mut target_inodes, tcp, port);
add_matching_inodes(&mut target_inodes, tcp6, port);
add_matching_inodes(&mut target_inodes, udp, port);
add_matching_inodes(&mut target_inodes, udp6, port);
target_inodes
}
pub fn find_target_processes(port: u16) -> Result<Vec<UnixProcess>, Error> {
let mut target_pids: Vec<UnixProcess> = vec![];
let mut seen_pids: HashSet<i32> = HashSet::new();
let inodes = find_target_inodes(port);
for inode in inodes {
let processes = procfs::process::all_processes().map_err(std::io::Error::other)?;
for p in processes {
let process = match p {
Ok(p) => p,
Err(_) => continue,
};
if seen_pids.contains(&process.pid) {
continue;
}
if let Ok(fds) = process.fd() {
for fd in fds {
let fd = match fd {
Ok(fd) => fd,
Err(_) => continue,
};
if let FDTarget::Socket(sock_inode) = fd.target {
if inode == sock_inode {
let name = match process.cmdline() {
Ok(parts) => parts.join(" "),
Err(_) => continue,
};
debug!("Found process '{}' with PID {}", name, process.pid());
seen_pids.insert(process.pid);
target_pids.push(UnixProcess::new(Pid::from_raw(process.pid), name));
}
}
}
}
}
}
Ok(target_pids)
}