procfs/
net.rs

1// Don't throw clippy warnings for manual string stripping.
2// The suggested fix with `strip_prefix` removes support for Rust 1.33 and 1.38
3#![allow(clippy::manual_strip)]
4
5//! Information about the networking layer.
6//!
7//! This module corresponds to the `/proc/net` directory and contains various information about the
8//! networking layer.
9//!
10//! # Example
11//!
12//! Here's an example that will print out all of the open and listening TCP sockets, and their
13//! corresponding processes, if know.  This mimics the "netstat" utility, but for TCP only.  You
14//! can run this example yourself with:
15//!
16//! > cargo run --example=netstat
17//!
18//! ```rust
19//! # use procfs::process::{FDTarget, Stat};
20//! # use std::collections::HashMap;
21//! let all_procs = procfs::process::all_processes().unwrap();
22//!
23//! // build up a map between socket inodes and process stat info:
24//! let mut map: HashMap<u64, Stat> = HashMap::new();
25//! for p in all_procs {
26//!     let Ok(process) = p else {
27//!         // process vanished
28//!         continue;
29//!     };
30//!     if let (Ok(stat), Ok(fds)) = (process.stat(), process.fd()) {
31//!         for fd in fds {
32//!             if let FDTarget::Socket(inode) = fd.unwrap().target {
33//!                 map.insert(inode, stat.clone());
34//!             }
35//!         }
36//!     }
37//! }
38//!
39//! // get the tcp table
40//! let tcp = procfs::net::tcp().unwrap();
41//! let tcp6 = procfs::net::tcp6().unwrap();
42//! println!("{:<26} {:<26} {:<15} {:<8} {}", "Local address", "Remote address", "State", "Inode", "PID/Program name");
43//! for entry in tcp.into_iter().chain(tcp6) {
44//!     // find the process (if any) that has an open FD to this entry's inode
45//!     let local_address = format!("{}", entry.local_address);
46//!     let remote_addr = format!("{}", entry.remote_address);
47//!     let state = format!("{:?}", entry.state);
48//!     if let Some(stat) = map.get(&entry.inode) {
49//!         println!("{:<26} {:<26} {:<15} {:<12} {}/{}", local_address, remote_addr, state, entry.inode, stat.pid, stat.comm);
50//!     } else {
51//!         // We might not always be able to find the process associated with this socket
52//!         println!("{:<26} {:<26} {:<15} {:<12} -", local_address, remote_addr, state, entry.inode);
53//!     }
54//! }
55//! ```
56use crate::ProcResult;
57use crate::{current_system_info, Current};
58pub use procfs_core::net::*;
59use procfs_core::FromReadSI;
60use std::collections::HashMap;
61
62/// Reads the tcp socket table
63///
64/// Note that this is the socket table for the current process.  If you want to
65/// see the socket table for another process, then see [Process::tcp()](crate::process::Process::tcp())
66pub fn tcp() -> ProcResult<Vec<TcpNetEntry>> {
67    TcpNetEntries::from_file("/proc/net/tcp", current_system_info()).map(|e| e.0)
68}
69
70/// Reads the tcp6 socket table
71///
72/// Note that this is the socket table for the current process.  If you want to
73/// see the socket table for another process, then see [Process::tcp6()](crate::process::Process::tcp6())
74pub fn tcp6() -> ProcResult<Vec<TcpNetEntry>> {
75    TcpNetEntries::from_file("/proc/net/tcp6", current_system_info()).map(|e| e.0)
76}
77
78/// Reads the udp socket table
79///
80/// Note that this is the socket table for the current process.  If you want to
81/// see the socket table for another process, then see [Process::udp()](crate::process::Process::udp())
82pub fn udp() -> ProcResult<Vec<UdpNetEntry>> {
83    UdpNetEntries::from_file("/proc/net/udp", current_system_info()).map(|e| e.0)
84}
85
86/// Reads the udp6 socket table
87///
88/// Note that this is the socket table for the current process.  If you want to
89/// see the socket table for another process, then see [Process::udp6()](crate::process::Process::udp6())
90pub fn udp6() -> ProcResult<Vec<UdpNetEntry>> {
91    UdpNetEntries::from_file("/proc/net/udp6", current_system_info()).map(|e| e.0)
92}
93
94impl Current for UnixNetEntries {
95    const PATH: &'static str = "/proc/net/unix";
96}
97
98/// Reads the unix socket table
99///
100/// Note that this is the socket table for the current process.  If you want to
101/// see the socket table for another process, then see [Process::unix()](crate::process::Process::unix())
102pub fn unix() -> ProcResult<Vec<UnixNetEntry>> {
103    UnixNetEntries::current().map(|e| e.0)
104}
105
106impl super::Current for ArpEntries {
107    const PATH: &'static str = "/proc/net/arp";
108}
109
110/// Reads the ARP table
111///
112/// Note that this is the ARP table for the current progress.  If you want to
113/// see the ARP table for another process, then see [Process::arp()](crate::process::Process::arp())
114pub fn arp() -> ProcResult<Vec<ARPEntry>> {
115    ArpEntries::current().map(|e| e.0)
116}
117
118impl super::Current for InterfaceDeviceStatus {
119    const PATH: &'static str = "/proc/net/dev";
120}
121
122/// Returns basic network device statistics for all interfaces
123///
124/// This data is from the `/proc/net/dev` file.
125///
126/// For an example, see the [interface_stats.rs](https://github.com/eminence/procfs/tree/master/examples)
127/// example in the source repo.
128///
129/// Note that this returns information from the networking namespace of the
130/// current process.  If you want information for some otherr process, see
131/// [Process::dev_status()](crate::process::Process::dev_status())
132pub fn dev_status() -> ProcResult<HashMap<String, DeviceStatus>> {
133    InterfaceDeviceStatus::current().map(|e| e.0)
134}
135
136impl super::Current for RouteEntries {
137    const PATH: &'static str = "/proc/net/route";
138}
139
140/// Reads the ipv4 route table
141///
142/// This data is from the `/proc/net/route` file
143///
144/// Note that this returns information from the networking namespace of the
145/// current process.  If you want information for some other process, see
146/// [Process::route()](crate::process::Process::route())
147pub fn route() -> ProcResult<Vec<RouteEntry>> {
148    RouteEntries::current().map(|r| r.0)
149}
150
151impl super::Current for Snmp {
152    const PATH: &'static str = "/proc/net/snmp";
153}
154
155/// Reads the network management information by Simple Network Management Protocol
156///
157/// This data is from the `/proc/net/snmp` file and for IPv4 Protocol
158///
159/// Note that this returns information from the networking namespace of the
160/// current process.  If you want information for some other process, see
161/// [Process::snmp()](crate::process::Process::snmp())
162pub fn snmp() -> ProcResult<Snmp> {
163    Snmp::current()
164}
165
166impl super::Current for Snmp6 {
167    const PATH: &'static str = "/proc/net/snmp6";
168}
169
170/// Reads the network management information of IPv6 by Simple Network Management Protocol
171///
172/// This data is from the `/proc/net/snmp6` file and for IPv6 Protocol
173///
174/// Note that this returns information from the networking namespace of the
175/// current process.  If you want information for some other process, see
176/// [Process::snmp6()](crate::process::Process::snmp6())
177pub fn snmp6() -> ProcResult<Snmp6> {
178    Snmp6::current()
179}
180
181#[cfg(test)]
182mod tests {
183    use super::*;
184
185    #[test]
186    fn test_tcp() {
187        for entry in tcp().unwrap() {
188            println!("{:?}", entry);
189            assert_eq!(entry.state, TcpState::from_u8(entry.state.to_u8()).unwrap());
190        }
191    }
192
193    #[test]
194    fn test_tcp6() {
195        for entry in tcp6().unwrap() {
196            println!("{:?}", entry);
197            assert_eq!(entry.state, TcpState::from_u8(entry.state.to_u8()).unwrap());
198        }
199    }
200
201    #[test]
202    fn test_udp() {
203        for entry in udp().unwrap() {
204            println!("{:?}", entry);
205            assert_eq!(entry.state, UdpState::from_u8(entry.state.to_u8()).unwrap());
206        }
207    }
208
209    #[test]
210    fn test_udp6() {
211        for entry in udp6().unwrap() {
212            println!("{:?}", entry);
213        }
214    }
215
216    #[test]
217    fn test_unix() {
218        for entry in unix().unwrap() {
219            println!("{:?}", entry);
220        }
221    }
222
223    #[test]
224    fn test_dev_status() {
225        let status = dev_status().unwrap();
226        println!("{:#?}", status);
227    }
228
229    #[test]
230    fn test_arp() {
231        for entry in arp().unwrap() {
232            println!("{:?}", entry);
233        }
234    }
235
236    #[test]
237    fn test_route() {
238        for entry in route().unwrap() {
239            println!("{:?}", entry);
240        }
241    }
242
243    #[test]
244    fn test_snmp() {
245        let snmp = snmp().unwrap();
246        println!("{:?}", snmp);
247    }
248
249    #[test]
250    fn test_snmp6() {
251        let snmp6 = snmp6().unwrap();
252        println!("{:?}", snmp6);
253    }
254}