#[cfg(target_os = "windows")] pub fn get_process_name_from_port(port: u16) -> Option { use winapi::shared::minwindef::ULONG; use winapi::shared::winerror::ERROR_INSUFFICIENT_BUFFER; use winapi::um::iphlpapi::GetExtendedTcpTable; use winapi::shared::tcpmib::{MIB_TCPTABLE_OWNER_PID, MIB_TCPROW_OWNER_PID}; let mut size: ULONG = 0; let table_class = 5; // TCP_TABLE_OWNER_PID_ALL let mut table = vec![0u8; 1024]; unsafe { let mut ret = GetExtendedTcpTable( table.as_mut_ptr() as *mut _, &mut size, 0, 2, // AF_INET table_class, 0, ); if ret == ERROR_INSUFFICIENT_BUFFER { table.resize(size as usize, 0); ret = GetExtendedTcpTable( table.as_mut_ptr() as *mut _, &mut size, 0, 2, // AF_INET table_class, 0, ); } if ret == 0 { let tcp_table = &*(table.as_ptr() as *const MIB_TCPTABLE_OWNER_PID); let row_ptr = &tcp_table.table[0] as *const MIB_TCPROW_OWNER_PID; for i in 0..tcp_table.dwNumEntries { let row = &*row_ptr.add(i as usize); // Local port is in network byte order let local_port = u16::from_be(row.dwLocalPort as u16); if local_port == port { return get_process_name_from_pid(row.dwOwningPid); } } } } None } #[cfg(target_os = "windows")] pub fn get_process_name_from_port_udp(port: u16) -> Option { use winapi::shared::minwindef::ULONG; use winapi::shared::winerror::ERROR_INSUFFICIENT_BUFFER; use winapi::um::iphlpapi::GetExtendedUdpTable; use winapi::shared::udpmib::{MIB_UDPTABLE_OWNER_PID, MIB_UDPROW_OWNER_PID}; let mut size: ULONG = 0; let table_class = 1; // UDP_TABLE_OWNER_PID let mut table = vec![0u8; 1024]; unsafe { let mut ret = GetExtendedUdpTable( table.as_mut_ptr() as *mut _, &mut size, 0, 2, // AF_INET table_class, 0, ); if ret == ERROR_INSUFFICIENT_BUFFER { table.resize(size as usize, 0); ret = GetExtendedUdpTable( table.as_mut_ptr() as *mut _, &mut size, 0, 2, // AF_INET table_class, 0, ); } if ret == 0 { let udp_table = &*(table.as_ptr() as *const MIB_UDPTABLE_OWNER_PID); let row_ptr = &udp_table.table[0] as *const MIB_UDPROW_OWNER_PID; for i in 0..udp_table.dwNumEntries { let row = &*row_ptr.add(i as usize); let local_port = u16::from_be(row.dwLocalPort as u16); if local_port == port { return get_process_name_from_pid(row.dwOwningPid); } } } } None } #[cfg(target_os = "windows")] fn get_process_name_from_pid(pid: u32) -> Option { use winapi::um::processthreadsapi::OpenProcess; use winapi::um::psapi::GetModuleBaseNameW; use winapi::um::winnt::{PROCESS_QUERY_INFORMATION, PROCESS_VM_READ}; use winapi::um::handleapi::CloseHandle; use std::os::windows::ffi::OsStringExt; unsafe { let handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, 0, pid); if handle.is_null() { return None; } let mut buffer = [0u16; 1024]; let len = GetModuleBaseNameW(handle, std::ptr::null_mut(), buffer.as_mut_ptr(), buffer.len() as u32); CloseHandle(handle); if len > 0 { let name = std::ffi::OsString::from_wide(&buffer[..len as usize]); return Some(name.to_string_lossy().into_owned()); } } None } #[cfg(target_os = "linux")] pub fn get_process_name_from_port(port: u16) -> Option { use std::fs; use std::io::{BufRead, BufReader}; let hex_port = format!("{:04X}", port); let check_net_file = |path: &str| -> Option { let file = fs::File::open(path).ok()?; let reader = BufReader::new(file); for line in reader.lines().skip(1).filter_map(Result::ok) { let parts: Vec<&str> = line.split_whitespace().collect(); if parts.len() >= 10 { let local_addr = parts[1]; if local_addr.ends_with(&format!(":{}", hex_port)) { if let Ok(inode) = parts[9].parse::() { return Some(inode); } } } } None }; let target_inode = check_net_file("/proc/net/tcp") .or_else(|| check_net_file("/proc/net/tcp6")) .or_else(|| check_net_file("/proc/net/udp")) .or_else(|| check_net_file("/proc/net/udp6"))?; let socket_str = format!("socket:[{}]", target_inode); for entry in fs::read_dir("/proc").ok()?.filter_map(Result::ok) { let file_name = entry.file_name(); let pid_str = file_name.to_string_lossy(); if !pid_str.chars().all(char::is_numeric) { continue; } let fd_dir = entry.path().join("fd"); if let Ok(fd_entries) = fs::read_dir(fd_dir) { for fd_entry in fd_entries.filter_map(Result::ok) { if let Ok(target) = fs::read_link(fd_entry.path()) { if target.to_string_lossy() == socket_str { let exe_path = entry.path().join("exe"); if let Ok(exe_link) = fs::read_link(exe_path) { if let Some(name) = exe_link.file_name() { return Some(name.to_string_lossy().into_owned()); } } if let Ok(comm) = fs::read_to_string(entry.path().join("comm")) { return Some(comm.trim().to_string()); } } } } } } None } #[cfg(not(any(target_os = "windows", target_os = "linux")))] pub fn get_process_name_from_port(_port: u16) -> Option { None } #[cfg(not(target_os = "windows"))] pub fn get_process_name_from_port_udp(port: u16) -> Option { get_process_name_from_port(port) }