diff --git a/leaf/src/app/process_finder.rs b/leaf/src/app/process_finder.rs index 95771c684..23933db49 100644 --- a/leaf/src/app/process_finder.rs +++ b/leaf/src/app/process_finder.rs @@ -1,8 +1,8 @@ +use log::debug; +use netstat2::{get_sockets_info, AddressFamilyFlags, ProtocolFlags, ProtocolSocketInfo, TcpState}; use std::net; use std::net::IpAddr; -use log::debug; -use netstat2::{AddressFamilyFlags, get_sockets_info, ProtocolFlags, ProtocolSocketInfo, TcpState}; -use sysinfo::{ProcessExt, System, SystemExt, Pid, PidExt}; +use sysinfo::{Pid, PidExt, ProcessExt, System, SystemExt}; #[derive(Debug)] pub struct PortInfo { @@ -26,15 +26,15 @@ impl From for PortInfo { ProtocolSocketInfo::Udp(_) => "UDP", }; let system = System::new_all(); - // system.refresh_system(); let pid = socket_info.associated_pids.first().unwrap(); - let process_info = system - .process(Pid::from(pid.to_owned() as usize)) - .map(|p| ProcessInfo { - name: p.name().to_owned(), - pid: p.pid().as_u32(), - process_path: p.exe().to_string_lossy().to_string(), - }); + let process_info = + system + .process(Pid::from(pid.to_owned() as usize)) + .map(|p| ProcessInfo { + name: p.name().to_owned(), + pid: p.pid().as_u32(), + process_path: p.exe().to_string_lossy().to_string(), + }); Self { address: socket_info.local_addr(), port: socket_info.local_port(), @@ -45,6 +45,7 @@ impl From for PortInfo { } pub fn find_process(protocol: &str, ip: IpAddr, port: u16) -> Option { + debug!("looking up process for {}:{}:{}", protocol, ip, port); let mut af_flags: AddressFamilyFlags = AddressFamilyFlags::from_bits(0).unwrap(); if ip.is_ipv6() { af_flags |= AddressFamilyFlags::IPV6; @@ -52,7 +53,6 @@ pub fn find_process(protocol: &str, ip: IpAddr, port: u16) -> Option { if ip.is_ipv4() { af_flags |= AddressFamilyFlags::IPV4; } - let mut proto_flags: ProtocolFlags = ProtocolFlags::from_bits(0).unwrap(); if protocol == "udp" { proto_flags |= ProtocolFlags::UDP; @@ -60,17 +60,19 @@ pub fn find_process(protocol: &str, ip: IpAddr, port: u16) -> Option { if protocol == "tcp" { proto_flags |= ProtocolFlags::TCP; } + let start_time = tokio::time::Instant::now(); let sockets = get_sockets_info(af_flags, proto_flags).unwrap_or_default(); - let mut ports = sockets + let mut port_infos = sockets .into_iter() .filter(|socket_info| match &socket_info.protocol_socket_info { ProtocolSocketInfo::Tcp(tcp) => tcp.state != TcpState::Closed, ProtocolSocketInfo::Udp(_) => true, }) .map(|socket_info| PortInfo::from(socket_info)); - let port = ports.find(|p| p.port == port); - if let Some(ref p) = port { - debug!("find process port {:?}", p); + let port_info = port_infos.find(|p| p.address == ip && p.port == port); + if let Some(ref p) = port_info { + let elapsed = tokio::time::Instant::now().duration_since(start_time); + debug!("found process [{}ms] {:?}", elapsed.as_millis(), p); } - return port; + return port_info; } diff --git a/leaf/src/app/router.rs b/leaf/src/app/router.rs index 096e94753..c44e66b16 100644 --- a/leaf/src/app/router.rs +++ b/leaf/src/app/router.rs @@ -13,11 +13,7 @@ use crate::app::SyncDnsClient; use crate::config; use crate::session::{Network, Session, SocksAddr}; -#[cfg(any( - target_os = "windows", - target_os = "macos", - target_os = "linux" -))] +#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] use crate::app::process_finder; pub trait Condition: Send + Sync + Unpin { @@ -361,35 +357,26 @@ impl Condition for DomainMatcher { } } -#[cfg(any( - target_os = "windows", - target_os = "macos", - target_os = "linux" -))] +#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] struct ProcessPidMatcher { value: String, } -#[cfg(any( - target_os = "windows", - target_os = "macos", - target_os = "linux" -))] +#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] impl ProcessPidMatcher { fn new(value: String) -> Self { ProcessPidMatcher { value } } } -#[cfg(any( - target_os = "windows", - target_os = "macos", - target_os = "linux" -))] +#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] impl Condition for ProcessPidMatcher { fn apply(&self, sess: &Session) -> bool { - let port_info = process_finder::find_process(&sess.network.to_string(), - sess.source.ip(), sess.source.port()); + let port_info = process_finder::find_process( + &sess.network.to_string(), + sess.source.ip(), + sess.source.port(), + ); if let Some(port) = port_info { if let Some(process_info) = port.process_info { if process_info.pid.to_string() == self.value { @@ -402,39 +389,37 @@ impl Condition for ProcessPidMatcher { } } -#[cfg(any( - target_os = "windows", - target_os = "macos", - target_os = "linux" -))] +#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] struct ProcessNameMatcher { value: String, } -#[cfg(any( - target_os = "windows", - target_os = "macos", - target_os = "linux" -))] +#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] impl ProcessNameMatcher { fn new(value: String) -> Self { ProcessNameMatcher { value } } } -#[cfg(any( - target_os = "windows", - target_os = "macos", - target_os = "linux" -))] +#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] impl Condition for ProcessNameMatcher { fn apply(&self, sess: &Session) -> bool { - let port_info = process_finder::find_process(&sess.network.to_string(), - sess.source.ip(), sess.source.port()); + let port_info = process_finder::find_process( + &sess.network.to_string(), + sess.source.ip(), + sess.source.port(), + ); if let Some(port) = port_info { if let Some(info) = port.process_info { - if info.process_path.to_lowercase().contains(&self.value.to_lowercase()) { - debug!("[{}] matches process name [{}]", info.process_path, &self.value); + if info + .process_path + .to_lowercase() + .contains(&self.value.to_lowercase()) + { + debug!( + "[{}] matches process name [{}]", + info.process_path, &self.value + ); return true; } } @@ -443,20 +428,12 @@ impl Condition for ProcessNameMatcher { } } -#[cfg(any( - target_os = "windows", - target_os = "macos", - target_os = "linux" -))] +#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] struct ProcessMatcher { condition: Box, } -#[cfg(any( - target_os = "windows", - target_os = "macos", - target_os = "linux" -))] +#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] impl ProcessMatcher { fn new(processes: &mut Vec) -> Self { let mut cond_or = ConditionOr::new(); @@ -477,11 +454,7 @@ impl ProcessMatcher { } } -#[cfg(any( - target_os = "windows", - target_os = "macos", - target_os = "linux" -))] +#[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] impl Condition for ProcessMatcher { fn apply(&self, sess: &Session) -> bool { self.condition.apply(sess) @@ -601,11 +574,7 @@ impl Router { cond_and.add(Box::new(InboundTagMatcher::new(&mut rr.inbound_tags))); } - #[cfg(any( - target_os = "windows", - target_os = "macos", - target_os = "linux" - ))] + #[cfg(any(target_os = "windows", target_os = "macos", target_os = "linux"))] if rr.processes.len() > 0 { cond_and.add(Box::new(ProcessMatcher::new(&mut rr.processes))); }