123 lines
3.5 KiB
Rust
123 lines
3.5 KiB
Rust
use std::path::{Path, PathBuf};
|
|
|
|
use sysinfo::{System, SystemExt, Pid, PidExt, ProcessExt};
|
|
use serde::{Serialize, Deserialize};
|
|
use std::os::windows::io::AsRawHandle;
|
|
|
|
#[cfg(windows)]
|
|
use {
|
|
tokio::net::windows::named_pipe::NamedPipeServer,
|
|
windows::Win32::{
|
|
Foundation::HANDLE,
|
|
System::Pipes::GetNamedPipeClientProcessId,
|
|
},
|
|
};
|
|
|
|
#[cfg(unix)]
|
|
use tokio::net::UnixStream;
|
|
|
|
use crate::errors::*;
|
|
|
|
|
|
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq, Hash)]
|
|
pub struct Client {
|
|
pub pid: u32,
|
|
pub exe: Option<PathBuf>,
|
|
}
|
|
|
|
|
|
#[cfg(unix)]
|
|
pub fn get_client_parent(stream: &UnixStream) -> Result<Client, ClientInfoError> {
|
|
let pid = stream.peer_cred()?;
|
|
get_process_parent_info(pid)?
|
|
}
|
|
|
|
|
|
#[cfg(windows)]
|
|
pub fn get_client_parent(stream: &NamedPipeServer) -> Result<Client, ClientInfoError> {
|
|
let raw_handle = stream.as_raw_handle();
|
|
let mut pid = 0u32;
|
|
let handle = HANDLE(raw_handle as _);
|
|
unsafe { GetNamedPipeClientProcessId(handle, &mut pid as *mut u32)? };
|
|
|
|
get_process_parent_info(pid)
|
|
}
|
|
|
|
|
|
fn get_process_parent_info(pid: u32) -> Result<Client, ClientInfoError> {
|
|
let sys_pid = Pid::from_u32(pid);
|
|
let mut sys = System::new();
|
|
sys.refresh_process(sys_pid);
|
|
let proc = sys.process(sys_pid)
|
|
.ok_or(ClientInfoError::ProcessNotFound)?;
|
|
|
|
let parent_pid_sys = proc.parent()
|
|
.ok_or(ClientInfoError::ParentPidNotFound)?;
|
|
sys.refresh_process(parent_pid_sys);
|
|
let parent = sys.process(parent_pid_sys)
|
|
.ok_or(ClientInfoError::ParentProcessNotFound)?;
|
|
|
|
let exe = match parent.exe() {
|
|
p if p == Path::new("") => None,
|
|
p => Some(PathBuf::from(p)),
|
|
};
|
|
|
|
Ok(Client { pid: parent_pid_sys.as_u32(), exe })
|
|
}
|
|
|
|
|
|
// async fn get_associated_pids(local_port: u16) -> Result<Vec<u32>, netstat2::error::Error> {
|
|
// let state = APP.get().unwrap().state::<AppState>();
|
|
// let AppConfig {
|
|
// listen_addr: app_listen_addr,
|
|
// listen_port: app_listen_port,
|
|
// ..
|
|
// } = *state.config.read().await;
|
|
|
|
// let sockets_iter = netstat2::iterate_sockets_info(
|
|
// AddressFamilyFlags::IPV4,
|
|
// ProtocolFlags::TCP
|
|
// )?;
|
|
// for item in sockets_iter {
|
|
// let sock_info = item?;
|
|
// let proto_info = match sock_info.protocol_socket_info {
|
|
// ProtocolSocketInfo::Tcp(tcp_info) => tcp_info,
|
|
// ProtocolSocketInfo::Udp(_) => {continue;}
|
|
// };
|
|
|
|
// if proto_info.local_port == local_port
|
|
// && proto_info.remote_port == app_listen_port
|
|
// && proto_info.local_addr == app_listen_addr
|
|
// && proto_info.remote_addr == app_listen_addr
|
|
// {
|
|
// return Ok(sock_info.associated_pids)
|
|
// }
|
|
// }
|
|
// Ok(vec![])
|
|
// }
|
|
|
|
|
|
// Theoretically, on some systems, multiple processes can share a socket
|
|
// pub async fn get_clients(local_port: u16) -> Result<Vec<Option<Client>>, ClientInfoError> {
|
|
// let mut clients = Vec::new();
|
|
// let mut sys = System::new();
|
|
// for p in get_associated_pids(local_port).await? {
|
|
// let pid = Pid::from_u32(p);
|
|
// sys.refresh_process(pid);
|
|
// let proc = sys.process(pid)
|
|
// .ok_or(ClientInfoError::ProcessNotFound)?;
|
|
|
|
// let client = Client {
|
|
// pid: p,
|
|
// exe: proc.exe().to_path_buf(),
|
|
// };
|
|
// clients.push(Some(client));
|
|
// }
|
|
|
|
// if clients.is_empty() {
|
|
// clients.push(None);
|
|
// }
|
|
|
|
// Ok(clients)
|
|
// }
|