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}