Finish verion 0.1.0
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
use async_trait::async_trait;
|
||||
use network_interface::{Addr, NetworkInterface, NetworkInterfaceConfig};
|
||||
use sha2::Digest;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use wtfnet_core::ErrorCode;
|
||||
use wtfnet_platform::{
|
||||
@@ -189,7 +190,11 @@ fn parse_ipv6_hex(value: &str) -> Option<std::net::Ipv6Addr> {
|
||||
Some(std::net::Ipv6Addr::from(bytes))
|
||||
}
|
||||
|
||||
fn parse_linux_tcp(path: &str, is_v6: bool) -> Result<Vec<ListenSocket>, PlatformError> {
|
||||
fn parse_linux_tcp_with_inode_map(
|
||||
path: &str,
|
||||
is_v6: bool,
|
||||
inode_map: &HashMap<String, ProcInfo>,
|
||||
) -> Result<Vec<ListenSocket>, PlatformError> {
|
||||
let contents = std::fs::read_to_string(path)
|
||||
.map_err(|err| PlatformError::new(ErrorCode::IoError, err.to_string()))?;
|
||||
let mut sockets = Vec::new();
|
||||
@@ -206,15 +211,28 @@ fn parse_linux_tcp(path: &str, is_v6: bool) -> Result<Vec<ListenSocket>, Platfor
|
||||
if state != "0A" {
|
||||
continue;
|
||||
}
|
||||
let inode = parts.get(9).copied();
|
||||
if let Some(local_addr) = parse_proc_socket_addr(local, is_v6) {
|
||||
let (pid, ppid, process_name, process_path) =
|
||||
inode.and_then(|value| inode_map.get(value)).map_or(
|
||||
(None, None, None, None),
|
||||
|info| {
|
||||
(
|
||||
Some(info.pid),
|
||||
info.ppid,
|
||||
info.name.clone(),
|
||||
info.path.clone(),
|
||||
)
|
||||
},
|
||||
);
|
||||
sockets.push(ListenSocket {
|
||||
proto: "tcp".to_string(),
|
||||
local_addr,
|
||||
state: Some("LISTEN".to_string()),
|
||||
pid: None,
|
||||
ppid: None,
|
||||
process_name: None,
|
||||
process_path: None,
|
||||
pid,
|
||||
ppid,
|
||||
process_name,
|
||||
process_path,
|
||||
owner: None,
|
||||
});
|
||||
}
|
||||
@@ -222,7 +240,11 @@ fn parse_linux_tcp(path: &str, is_v6: bool) -> Result<Vec<ListenSocket>, Platfor
|
||||
Ok(sockets)
|
||||
}
|
||||
|
||||
fn parse_linux_udp(path: &str, is_v6: bool) -> Result<Vec<ListenSocket>, PlatformError> {
|
||||
fn parse_linux_udp_with_inode_map(
|
||||
path: &str,
|
||||
is_v6: bool,
|
||||
inode_map: &HashMap<String, ProcInfo>,
|
||||
) -> Result<Vec<ListenSocket>, PlatformError> {
|
||||
let contents = std::fs::read_to_string(path)
|
||||
.map_err(|err| PlatformError::new(ErrorCode::IoError, err.to_string()))?;
|
||||
let mut sockets = Vec::new();
|
||||
@@ -235,15 +257,28 @@ fn parse_linux_udp(path: &str, is_v6: bool) -> Result<Vec<ListenSocket>, Platfor
|
||||
continue;
|
||||
}
|
||||
let local = parts[1];
|
||||
let inode = parts.get(9).copied();
|
||||
if let Some(local_addr) = parse_proc_socket_addr(local, is_v6) {
|
||||
let (pid, ppid, process_name, process_path) =
|
||||
inode.and_then(|value| inode_map.get(value)).map_or(
|
||||
(None, None, None, None),
|
||||
|info| {
|
||||
(
|
||||
Some(info.pid),
|
||||
info.ppid,
|
||||
info.name.clone(),
|
||||
info.path.clone(),
|
||||
)
|
||||
},
|
||||
);
|
||||
sockets.push(ListenSocket {
|
||||
proto: "udp".to_string(),
|
||||
local_addr,
|
||||
state: None,
|
||||
pid: None,
|
||||
ppid: None,
|
||||
process_name: None,
|
||||
process_path: None,
|
||||
pid,
|
||||
ppid,
|
||||
process_name,
|
||||
process_path,
|
||||
owner: None,
|
||||
});
|
||||
}
|
||||
@@ -298,6 +333,80 @@ fn extract_port(value: &str) -> Option<u16> {
|
||||
None
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ProcInfo {
|
||||
pid: u32,
|
||||
ppid: Option<u32>,
|
||||
name: Option<String>,
|
||||
path: Option<String>,
|
||||
}
|
||||
|
||||
fn build_inode_map() -> HashMap<String, ProcInfo> {
|
||||
let mut map = HashMap::new();
|
||||
let entries = match std::fs::read_dir("/proc") {
|
||||
Ok(entries) => entries,
|
||||
Err(_) => return map,
|
||||
};
|
||||
for entry in entries.flatten() {
|
||||
let file_name = entry.file_name();
|
||||
let name = match file_name.to_str() {
|
||||
Some(name) => name,
|
||||
None => continue,
|
||||
};
|
||||
let pid = match name.parse::<u32>() {
|
||||
Ok(pid) => pid,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
let comm = std::fs::read_to_string(format!("/proc/{}/comm", pid))
|
||||
.ok()
|
||||
.map(|value| value.trim().to_string());
|
||||
let path = std::fs::read_link(format!("/proc/{}/exe", pid))
|
||||
.ok()
|
||||
.and_then(|value| value.to_str().map(|s| s.to_string()));
|
||||
let ppid = read_ppid(pid);
|
||||
|
||||
let info = ProcInfo {
|
||||
pid,
|
||||
ppid,
|
||||
name: comm,
|
||||
path,
|
||||
};
|
||||
|
||||
let fd_dir = match std::fs::read_dir(format!("/proc/{}/fd", pid)) {
|
||||
Ok(dir) => dir,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
for fd in fd_dir.flatten() {
|
||||
if let Ok(target) = std::fs::read_link(fd.path()) {
|
||||
if let Some(target) = target.to_str() {
|
||||
if let Some(inode) = parse_socket_inode(target) {
|
||||
map.entry(inode).or_insert_with(|| info.clone());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
map
|
||||
}
|
||||
|
||||
fn parse_socket_inode(value: &str) -> Option<String> {
|
||||
let value = value.strip_prefix("socket:[")?;
|
||||
let value = value.strip_suffix(']')?;
|
||||
Some(value.to_string())
|
||||
}
|
||||
|
||||
fn read_ppid(pid: u32) -> Option<u32> {
|
||||
let stat = std::fs::read_to_string(format!("/proc/{}/stat", pid)).ok()?;
|
||||
let end = stat.rfind(')')?;
|
||||
let rest = stat.get(end + 2..)?;
|
||||
let mut parts = rest.split_whitespace();
|
||||
let _state = parts.next()?;
|
||||
let ppid = parts.next()?.parse::<u32>().ok()?;
|
||||
Some(ppid)
|
||||
}
|
||||
|
||||
fn load_native_roots(store: &str) -> Result<Vec<RootCert>, PlatformError> {
|
||||
let certs = rustls_native_certs::load_native_certs()
|
||||
.map_err(|err| PlatformError::new(ErrorCode::IoError, err.to_string()))?;
|
||||
@@ -377,11 +486,28 @@ fn format_fingerprint(bytes: &[u8]) -> String {
|
||||
#[async_trait]
|
||||
impl PortsProvider for LinuxPortsProvider {
|
||||
async fn listening(&self) -> Result<Vec<ListenSocket>, PlatformError> {
|
||||
let inode_map = build_inode_map();
|
||||
let mut sockets = Vec::new();
|
||||
sockets.extend(parse_linux_tcp("/proc/net/tcp", false)?);
|
||||
sockets.extend(parse_linux_tcp("/proc/net/tcp6", true)?);
|
||||
sockets.extend(parse_linux_udp("/proc/net/udp", false)?);
|
||||
sockets.extend(parse_linux_udp("/proc/net/udp6", true)?);
|
||||
sockets.extend(parse_linux_tcp_with_inode_map(
|
||||
"/proc/net/tcp",
|
||||
false,
|
||||
&inode_map,
|
||||
)?);
|
||||
sockets.extend(parse_linux_tcp_with_inode_map(
|
||||
"/proc/net/tcp6",
|
||||
true,
|
||||
&inode_map,
|
||||
)?);
|
||||
sockets.extend(parse_linux_udp_with_inode_map(
|
||||
"/proc/net/udp",
|
||||
false,
|
||||
&inode_map,
|
||||
)?);
|
||||
sockets.extend(parse_linux_udp_with_inode_map(
|
||||
"/proc/net/udp6",
|
||||
true,
|
||||
&inode_map,
|
||||
)?);
|
||||
Ok(sockets)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user