#![allow(clippy::manual_strip)]
use crate::ProcResult;
use crate::{build_internal_error, expect, from_iter, from_str};
use std::collections::HashMap;
use bitflags::bitflags;
use std::io::BufRead;
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6};
use std::{path::PathBuf, str::FromStr};
#[cfg(feature = "serde1")]
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum TcpState {
Established = 1,
SynSent,
SynRecv,
FinWait1,
FinWait2,
TimeWait,
Close,
CloseWait,
LastAck,
Listen,
Closing,
NewSynRecv,
}
impl TcpState {
pub fn from_u8(num: u8) -> Option<TcpState> {
match num {
0x01 => Some(TcpState::Established),
0x02 => Some(TcpState::SynSent),
0x03 => Some(TcpState::SynRecv),
0x04 => Some(TcpState::FinWait1),
0x05 => Some(TcpState::FinWait2),
0x06 => Some(TcpState::TimeWait),
0x07 => Some(TcpState::Close),
0x08 => Some(TcpState::CloseWait),
0x09 => Some(TcpState::LastAck),
0x0A => Some(TcpState::Listen),
0x0B => Some(TcpState::Closing),
0x0C => Some(TcpState::NewSynRecv),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
TcpState::Established => 0x01,
TcpState::SynSent => 0x02,
TcpState::SynRecv => 0x03,
TcpState::FinWait1 => 0x04,
TcpState::FinWait2 => 0x05,
TcpState::TimeWait => 0x06,
TcpState::Close => 0x07,
TcpState::CloseWait => 0x08,
TcpState::LastAck => 0x09,
TcpState::Listen => 0x0A,
TcpState::Closing => 0x0B,
TcpState::NewSynRecv => 0x0C,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum UdpState {
Established = 1,
Close = 7,
}
impl UdpState {
pub fn from_u8(num: u8) -> Option<UdpState> {
match num {
0x01 => Some(UdpState::Established),
0x07 => Some(UdpState::Close),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
UdpState::Established => 0x01,
UdpState::Close => 0x07,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub enum UnixState {
UNCONNECTED = 1,
CONNECTING = 2,
CONNECTED = 3,
DISCONNECTING = 4,
}
impl UnixState {
pub fn from_u8(num: u8) -> Option<UnixState> {
match num {
0x01 => Some(UnixState::UNCONNECTED),
0x02 => Some(UnixState::CONNECTING),
0x03 => Some(UnixState::CONNECTED),
0x04 => Some(UnixState::DISCONNECTING),
_ => None,
}
}
pub fn to_u8(&self) -> u8 {
match self {
UnixState::UNCONNECTED => 0x01,
UnixState::CONNECTING => 0x02,
UnixState::CONNECTED => 0x03,
UnixState::DISCONNECTING => 0x04,
}
}
}
#[derive(Debug, Clone)]
#[non_exhaustive]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct TcpNetEntry {
pub local_address: SocketAddr,
pub remote_address: SocketAddr,
pub state: TcpState,
pub rx_queue: u32,
pub tx_queue: u32,
pub uid: u32,
pub inode: u64,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UdpNetEntry {
pub local_address: SocketAddr,
pub remote_address: SocketAddr,
pub state: UdpState,
pub rx_queue: u32,
pub tx_queue: u32,
pub uid: u32,
pub inode: u64,
}
#[derive(Debug, Clone)]
#[non_exhaustive]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UnixNetEntry {
pub ref_count: u32,
pub socket_type: u16,
pub state: UnixState,
pub inode: u64,
pub path: Option<PathBuf>,
}
fn parse_addressport_str(s: &str, little_endian: bool) -> ProcResult<SocketAddr> {
let mut las = s.split(':');
let ip_part = expect!(las.next(), "ip_part");
let port = expect!(las.next(), "port");
let port = from_str!(u16, port, 16);
use std::convert::TryInto;
let read_u32 = if little_endian {
u32::from_le_bytes
} else {
u32::from_be_bytes
};
if ip_part.len() == 8 {
let bytes = expect!(hex::decode(ip_part));
let ip_u32 = read_u32(bytes[..4].try_into().unwrap());
let ip = Ipv4Addr::from(ip_u32);
Ok(SocketAddr::V4(SocketAddrV4::new(ip, port)))
} else if ip_part.len() == 32 {
let bytes = expect!(hex::decode(ip_part));
let ip_a = read_u32(bytes[0..4].try_into().unwrap());
let ip_b = read_u32(bytes[4..8].try_into().unwrap());
let ip_c = read_u32(bytes[8..12].try_into().unwrap());
let ip_d = read_u32(bytes[12..16].try_into().unwrap());
let ip = Ipv6Addr::new(
((ip_a >> 16) & 0xffff) as u16,
(ip_a & 0xffff) as u16,
((ip_b >> 16) & 0xffff) as u16,
(ip_b & 0xffff) as u16,
((ip_c >> 16) & 0xffff) as u16,
(ip_c & 0xffff) as u16,
((ip_d >> 16) & 0xffff) as u16,
(ip_d & 0xffff) as u16,
);
Ok(SocketAddr::V6(SocketAddrV6::new(ip, port, 0, 0)))
} else {
Err(build_internal_error!(format!(
"Unable to parse {:?} as an address:port",
s
)))
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct TcpNetEntries(pub Vec<TcpNetEntry>);
impl super::FromBufReadSI for TcpNetEntries {
fn from_buf_read<R: BufRead>(r: R, system_info: &crate::SystemInfo) -> ProcResult<Self> {
let mut vec = Vec::new();
for line in r.lines().skip(1) {
let line = line?;
let mut s = line.split_whitespace();
s.next();
let local_address = expect!(s.next(), "tcp::local_address");
let rem_address = expect!(s.next(), "tcp::rem_address");
let state = expect!(s.next(), "tcp::st");
let mut tx_rx_queue = expect!(s.next(), "tcp::tx_queue:rx_queue").splitn(2, ':');
let tx_queue = from_str!(u32, expect!(tx_rx_queue.next(), "tcp::tx_queue"), 16);
let rx_queue = from_str!(u32, expect!(tx_rx_queue.next(), "tcp::rx_queue"), 16);
s.next(); s.next(); let uid = from_str!(u32, expect!(s.next(), "tcp::uid"));
s.next(); let inode = expect!(s.next(), "tcp::inode");
vec.push(TcpNetEntry {
local_address: parse_addressport_str(local_address, system_info.is_little_endian())?,
remote_address: parse_addressport_str(rem_address, system_info.is_little_endian())?,
rx_queue,
tx_queue,
state: expect!(TcpState::from_u8(from_str!(u8, state, 16))),
uid,
inode: from_str!(u64, inode),
});
}
Ok(TcpNetEntries(vec))
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UdpNetEntries(pub Vec<UdpNetEntry>);
impl super::FromBufReadSI for UdpNetEntries {
fn from_buf_read<R: BufRead>(r: R, system_info: &crate::SystemInfo) -> ProcResult<Self> {
let mut vec = Vec::new();
for line in r.lines().skip(1) {
let line = line?;
let mut s = line.split_whitespace();
s.next();
let local_address = expect!(s.next(), "udp::local_address");
let rem_address = expect!(s.next(), "udp::rem_address");
let state = expect!(s.next(), "udp::st");
let mut tx_rx_queue = expect!(s.next(), "udp::tx_queue:rx_queue").splitn(2, ':');
let tx_queue: u32 = from_str!(u32, expect!(tx_rx_queue.next(), "udp::tx_queue"), 16);
let rx_queue: u32 = from_str!(u32, expect!(tx_rx_queue.next(), "udp::rx_queue"), 16);
s.next(); s.next(); let uid = from_str!(u32, expect!(s.next(), "udp::uid"));
s.next(); let inode = expect!(s.next(), "udp::inode");
vec.push(UdpNetEntry {
local_address: parse_addressport_str(local_address, system_info.is_little_endian())?,
remote_address: parse_addressport_str(rem_address, system_info.is_little_endian())?,
rx_queue,
tx_queue,
state: expect!(UdpState::from_u8(from_str!(u8, state, 16))),
uid,
inode: from_str!(u64, inode),
});
}
Ok(UdpNetEntries(vec))
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct UnixNetEntries(pub Vec<UnixNetEntry>);
impl super::FromBufRead for UnixNetEntries {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut vec = Vec::new();
for line in r.lines().skip(1) {
let line = line?;
let mut s = line.split_whitespace();
s.next(); let ref_count = from_str!(u32, expect!(s.next()), 16);
s.next(); s.next(); let socket_type = from_str!(u16, expect!(s.next()), 16);
let state = from_str!(u8, expect!(s.next()), 16);
let inode = from_str!(u64, expect!(s.next()));
let path = s.next().map(PathBuf::from);
vec.push(UnixNetEntry {
ref_count,
socket_type,
inode,
state: expect!(UnixState::from_u8(state)),
path,
});
}
Ok(UnixNetEntries(vec))
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct ARPEntry {
pub ip_address: Ipv4Addr,
pub hw_type: ARPHardware,
pub flags: ARPFlags,
pub hw_address: Option<[u8; 6]>,
pub device: String,
}
bitflags! {
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct ARPHardware: u32 {
const NETROM = 0;
const ETHER = 1;
const EETHER = 2;
const AX25 = 3;
const PRONET = 4;
const CHAOS = 5;
const IEEE802 = 6;
const ARCNET = 7;
const APPLETLK = 8;
const DLCI = 15;
const ATM = 19;
const METRICOM = 23;
const IEEE1394 = 24;
const EUI64 = 27;
const INFINIBAND = 32;
}
}
bitflags! {
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct ARPFlags: u32 {
const COM = 0x02;
const PERM = 0x04;
const PUBL = 0x08;
const USETRAILERS = 0x10;
const NETMASK = 0x20;
const DONTPUB = 0x40;
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct ArpEntries(pub Vec<ARPEntry>);
impl super::FromBufRead for ArpEntries {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut vec = Vec::new();
for line in r.lines().skip(1) {
let line = line?;
let mut line = line.split_whitespace();
let ip_address = expect!(Ipv4Addr::from_str(expect!(line.next())));
let hw = from_str!(u32, &expect!(line.next())[2..], 16);
let hw = ARPHardware::from_bits_truncate(hw);
let flags = from_str!(u32, &expect!(line.next())[2..], 16);
let flags = ARPFlags::from_bits_truncate(flags);
let mac = expect!(line.next());
let mut mac: Vec<Result<u8, _>> = mac.split(':').map(|s| Ok(from_str!(u8, s, 16))).collect();
let mac = if mac.len() == 6 {
let mac_block_f = mac.pop().unwrap()?;
let mac_block_e = mac.pop().unwrap()?;
let mac_block_d = mac.pop().unwrap()?;
let mac_block_c = mac.pop().unwrap()?;
let mac_block_b = mac.pop().unwrap()?;
let mac_block_a = mac.pop().unwrap()?;
if mac_block_a == 0
&& mac_block_b == 0
&& mac_block_c == 0
&& mac_block_d == 0
&& mac_block_e == 0
&& mac_block_f == 0
{
None
} else {
Some([
mac_block_a,
mac_block_b,
mac_block_c,
mac_block_d,
mac_block_e,
mac_block_f,
])
}
} else {
None
};
let _mask = expect!(line.next());
let dev = expect!(line.next());
vec.push(ARPEntry {
ip_address,
hw_type: hw,
flags,
hw_address: mac,
device: dev.to_string(),
})
}
Ok(ArpEntries(vec))
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct DeviceStatus {
pub name: String,
pub recv_bytes: u64,
pub recv_packets: u64,
pub recv_errs: u64,
pub recv_drop: u64,
pub recv_fifo: u64,
pub recv_frame: u64,
pub recv_compressed: u64,
pub recv_multicast: u64,
pub sent_bytes: u64,
pub sent_packets: u64,
pub sent_errs: u64,
pub sent_drop: u64,
pub sent_fifo: u64,
pub sent_colls: u64,
pub sent_carrier: u64,
pub sent_compressed: u64,
}
impl DeviceStatus {
fn from_str(s: &str) -> ProcResult<DeviceStatus> {
let mut split = s.split_whitespace();
let name: String = expect!(from_iter(&mut split));
let recv_bytes = expect!(from_iter(&mut split));
let recv_packets = expect!(from_iter(&mut split));
let recv_errs = expect!(from_iter(&mut split));
let recv_drop = expect!(from_iter(&mut split));
let recv_fifo = expect!(from_iter(&mut split));
let recv_frame = expect!(from_iter(&mut split));
let recv_compressed = expect!(from_iter(&mut split));
let recv_multicast = expect!(from_iter(&mut split));
let sent_bytes = expect!(from_iter(&mut split));
let sent_packets = expect!(from_iter(&mut split));
let sent_errs = expect!(from_iter(&mut split));
let sent_drop = expect!(from_iter(&mut split));
let sent_fifo = expect!(from_iter(&mut split));
let sent_colls = expect!(from_iter(&mut split));
let sent_carrier = expect!(from_iter(&mut split));
let sent_compressed = expect!(from_iter(&mut split));
Ok(DeviceStatus {
name: name.trim_end_matches(':').to_owned(),
recv_bytes,
recv_packets,
recv_errs,
recv_drop,
recv_fifo,
recv_frame,
recv_compressed,
recv_multicast,
sent_bytes,
sent_packets,
sent_errs,
sent_drop,
sent_fifo,
sent_colls,
sent_carrier,
sent_compressed,
})
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct InterfaceDeviceStatus(pub HashMap<String, DeviceStatus>);
impl super::FromBufRead for InterfaceDeviceStatus {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut map = HashMap::new();
for line in r.lines().skip(2) {
let dev = DeviceStatus::from_str(&line?)?;
map.insert(dev.name.clone(), dev);
}
Ok(InterfaceDeviceStatus(map))
}
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct RouteEntry {
pub iface: String,
pub destination: Ipv4Addr,
pub gateway: Ipv4Addr,
pub flags: u16,
pub refcnt: u16,
pub in_use: u16,
pub metrics: u32,
pub mask: Ipv4Addr,
pub mtu: u32,
pub window: u32,
pub irtt: u32,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
pub struct RouteEntries(pub Vec<RouteEntry>);
impl super::FromBufRead for RouteEntries {
fn from_buf_read<R: BufRead>(r: R) -> ProcResult<Self> {
let mut vec = Vec::new();
for line in r.lines().skip(1) {
let line = line?;
let mut line = line.split_whitespace();
let iface = expect!(line.next());
let destination = from_str!(u32, expect!(line.next()), 16).to_ne_bytes().into();
let gateway = from_str!(u32, expect!(line.next()), 16).to_ne_bytes().into();
let flags = from_str!(u16, expect!(line.next()), 16);
let refcnt = from_str!(u16, expect!(line.next()), 10);
let in_use = from_str!(u16, expect!(line.next()), 10);
let metrics = from_str!(u32, expect!(line.next()), 10);
let mask = from_str!(u32, expect!(line.next()), 16).to_ne_bytes().into();
let mtu = from_str!(u32, expect!(line.next()), 10);
let window = from_str!(u32, expect!(line.next()), 10);
let irtt = from_str!(u32, expect!(line.next()), 10);
vec.push(RouteEntry {
iface: iface.to_string(),
destination,
gateway,
flags,
refcnt,
in_use,
metrics,
mask,
mtu,
window,
irtt,
});
}
Ok(RouteEntries(vec))
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::net::IpAddr;
#[test]
fn test_parse_ipaddr() {
use std::str::FromStr;
let addr = parse_addressport_str("0100007F:1234", true).unwrap();
assert_eq!(addr.port(), 0x1234);
match addr.ip() {
IpAddr::V4(addr) => assert_eq!(addr, Ipv4Addr::new(127, 0, 0, 1)),
_ => panic!("Not IPv4"),
}
let addr = parse_addressport_str("5014002A14080140000000000E200000:0050", true).unwrap();
assert_eq!(addr.port(), 80);
match addr.ip() {
IpAddr::V6(addr) => assert_eq!(addr, Ipv6Addr::from_str("2a00:1450:4001:814::200e").unwrap()),
_ => panic!("Not IPv6"),
}
let addr = parse_addressport_str("B80D01200000000067452301EFCDAB89:0", true).unwrap();
assert_eq!(addr.port(), 0);
match addr.ip() {
IpAddr::V6(addr) => assert_eq!(addr, Ipv6Addr::from_str("2001:db8::123:4567:89ab:cdef").unwrap()),
_ => panic!("Not IPv6"),
}
let addr = parse_addressport_str("1234:1234", true);
assert!(addr.is_err());
}
#[test]
fn test_tcpstate_from() {
assert_eq!(TcpState::from_u8(0xA).unwrap(), TcpState::Listen);
}
}