Skip to main content

network_inspector/
unix.rs

1// Unix domain sockets from /proc/net/unix, correlated with process fd inodes.
2
3use crate::tcp;
4
5#[derive(Debug, Clone)]
6pub struct UnixSocketEntry {
7    pub path: String,
8}
9
10/// Parse /proc/net/unix and return path names for sockets belonging to `pid`.
11/// Path may be empty for anonymous sockets.
12#[cfg(target_os = "linux")]
13pub fn list_unix_sockets(pid: i32) -> Vec<UnixSocketEntry> {
14    let inodes = tcp::process_socket_inodes(pid);
15    let raw = match std::fs::read_to_string("/proc/net/unix") {
16        Ok(r) => r,
17        Err(_) => return vec![],
18    };
19
20    let mut out = Vec::new();
21    for line in raw.lines().skip(1) {
22        // Format: "address refcount protocol flags type st inode path"
23        // Path can contain spaces; inode is 7th field (index 6).
24        let parts: Vec<&str> = line.split_whitespace().collect();
25        if parts.len() < 7 {
26            continue;
27        }
28        let inode: u64 = match parts[6].parse() {
29            Ok(n) => n,
30            Err(_) => continue,
31        };
32        if !inodes.contains(&inode) {
33            continue;
34        }
35        let path = if parts.len() > 7 {
36            parts[7..].join(" ").trim().to_string()
37        } else {
38            String::new()
39        };
40        out.push(UnixSocketEntry { path });
41    }
42    out
43}
44
45#[cfg(not(target_os = "linux"))]
46pub fn list_unix_sockets(_pid: i32) -> Vec<UnixSocketEntry> {
47    vec![]
48}
49
50#[cfg(test)]
51mod tests {
52    use super::UnixSocketEntry;
53
54    #[test]
55    fn unix_socket_entry_debug() {
56        let e = UnixSocketEntry {
57            path: "/tmp/test.sock".to_string(),
58        };
59        let debug = format!("{:?}", e);
60        assert!(debug.contains("test.sock"));
61    }
62}