use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr};
use serde::{Deserialize, Serialize};
use super::types::{AddressFamily, MemInfo, Protocol, SocketState, TcpInfo, TcpState, Timer};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum SocketInfo {
Inet(Box<InetSocket>),
Unix(UnixSocket),
Netlink(NetlinkSocket),
Packet(PacketSocket),
}
impl SocketInfo {
pub fn state(&self) -> SocketState {
match self {
SocketInfo::Inet(s) => s.state,
SocketInfo::Unix(s) => s.state,
SocketInfo::Netlink(_) => SocketState::Close,
SocketInfo::Packet(_) => SocketState::Close,
}
}
pub fn inode(&self) -> u32 {
match self {
SocketInfo::Inet(s) => s.inode,
SocketInfo::Unix(s) => s.inode,
SocketInfo::Netlink(s) => s.inode,
SocketInfo::Packet(s) => s.inode,
}
}
pub fn uid(&self) -> Option<u32> {
match self {
SocketInfo::Inet(s) => Some(s.uid),
SocketInfo::Unix(s) => s.uid,
SocketInfo::Netlink(s) => Some(s.portid),
SocketInfo::Packet(s) => Some(s.uid),
}
}
pub fn as_inet(&self) -> Option<&InetSocket> {
match self {
SocketInfo::Inet(s) => Some(s),
_ => None,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct InetSocket {
pub family: AddressFamily,
pub protocol: Protocol,
pub state: SocketState,
pub local: SocketAddr,
pub remote: SocketAddr,
pub interface: u32,
pub cookie: u64,
pub timer: Timer,
pub recv_q: u32,
pub send_q: u32,
pub uid: u32,
pub inode: u32,
pub refcnt: u32,
pub mark: Option<u32>,
pub cgroup_id: Option<u64>,
pub tcp_info: Option<TcpInfo>,
pub mem_info: Option<MemInfo>,
pub congestion: Option<String>,
pub tos: Option<u8>,
pub tclass: Option<u8>,
pub shutdown: Option<u8>,
pub v6only: Option<bool>,
}
impl InetSocket {
pub fn new(
family: AddressFamily,
protocol: Protocol,
state: TcpState,
local: SocketAddr,
remote: SocketAddr,
) -> Self {
Self {
family,
protocol,
state: SocketState::Tcp(state),
local,
remote,
interface: 0,
cookie: 0,
timer: Timer::Off,
recv_q: 0,
send_q: 0,
uid: 0,
inode: 0,
refcnt: 0,
mark: None,
cgroup_id: None,
tcp_info: None,
mem_info: None,
congestion: None,
tos: None,
tclass: None,
shutdown: None,
v6only: None,
}
}
pub fn is_listening(&self) -> bool {
matches!(self.state, SocketState::Tcp(TcpState::Listen))
}
pub fn is_connected(&self) -> bool {
matches!(self.state, SocketState::Tcp(TcpState::Established))
}
pub fn netid(&self) -> &'static str {
match (self.protocol, self.family) {
(Protocol::Tcp, AddressFamily::Inet) => "tcp",
(Protocol::Tcp, AddressFamily::Inet6) => "tcp6",
(Protocol::Udp, AddressFamily::Inet) => "udp",
(Protocol::Udp, AddressFamily::Inet6) => "udp6",
(Protocol::Sctp, AddressFamily::Inet) => "sctp",
(Protocol::Sctp, AddressFamily::Inet6) => "sctp6",
(Protocol::Dccp, AddressFamily::Inet) => "dccp",
(Protocol::Dccp, AddressFamily::Inet6) => "dccp6",
(Protocol::Mptcp, AddressFamily::Inet) => "mptcp",
(Protocol::Mptcp, AddressFamily::Inet6) => "mptcp6",
(Protocol::Raw, AddressFamily::Inet) => "raw",
(Protocol::Raw, AddressFamily::Inet6) => "raw6",
_ => "unknown",
}
}
}
impl Default for InetSocket {
fn default() -> Self {
Self::new(
AddressFamily::Inet,
Protocol::Tcp,
TcpState::Unknown,
SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0),
SocketAddr::new(IpAddr::V4(Ipv4Addr::UNSPECIFIED), 0),
)
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[repr(u8)]
pub enum UnixType {
Stream = libc::SOCK_STREAM as u8,
Dgram = libc::SOCK_DGRAM as u8,
Seqpacket = libc::SOCK_SEQPACKET as u8,
}
impl UnixType {
pub fn from_u8(value: u8) -> Option<Self> {
match value as i32 {
libc::SOCK_STREAM => Some(Self::Stream),
libc::SOCK_DGRAM => Some(Self::Dgram),
libc::SOCK_SEQPACKET => Some(Self::Seqpacket),
_ => None,
}
}
pub fn netid(&self) -> &'static str {
match self {
Self::Stream => "u_str",
Self::Dgram => "u_dgr",
Self::Seqpacket => "u_seq",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UnixSocket {
pub socket_type: UnixType,
pub state: SocketState,
pub path: Option<String>,
pub abstract_name: Option<String>,
pub inode: u32,
pub cookie: u64,
pub peer_inode: Option<u32>,
pub vfs_dev: Option<u32>,
pub vfs_inode: Option<u32>,
pub recv_q: Option<u32>,
pub send_q: Option<u32>,
pub pending_connections: Option<Vec<u32>>,
pub uid: Option<u32>,
pub mem_info: Option<MemInfo>,
pub shutdown: Option<u8>,
}
impl UnixSocket {
pub fn new(socket_type: UnixType, state: SocketState, inode: u32) -> Self {
Self {
socket_type,
state,
path: None,
abstract_name: None,
inode,
cookie: 0,
peer_inode: None,
vfs_dev: None,
vfs_inode: None,
recv_q: None,
send_q: None,
pending_connections: None,
uid: None,
mem_info: None,
shutdown: None,
}
}
pub fn name(&self) -> String {
if let Some(ref path) = self.path {
path.clone()
} else if let Some(ref name) = self.abstract_name {
format!("@{}", name)
} else {
String::new()
}
}
pub fn netid(&self) -> &'static str {
self.socket_type.netid()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NetlinkSocket {
pub protocol: u8,
pub portid: u32,
pub dst_portid: u32,
pub dst_group: u32,
pub groups: u32,
pub inode: u32,
pub cookie: u64,
pub recv_q: Option<u32>,
pub send_q: Option<u32>,
pub mem_info: Option<MemInfo>,
}
impl NetlinkSocket {
pub fn protocol_name(&self) -> &'static str {
match self.protocol {
0 => "route",
1 => "unused",
2 => "usersock",
3 => "firewall",
4 => "sock_diag",
5 => "nflog",
6 => "xfrm",
7 => "selinux",
8 => "iscsi",
9 => "audit",
10 => "fib_lookup",
11 => "connector",
12 => "netfilter",
13 => "ip6_fw",
14 => "dnrtmsg",
15 => "kobject_uevent",
16 => "generic",
18 => "scsitransport",
19 => "ecryptfs",
20 => "rdma",
21 => "crypto",
22 => "smc",
_ => "unknown",
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PacketSocket {
pub socket_type: u8,
pub protocol: u16,
pub interface: u32,
pub inode: u32,
pub cookie: u64,
pub uid: u32,
pub recv_q: Option<u32>,
pub send_q: Option<u32>,
pub fanout: Option<u32>,
pub mem_info: Option<MemInfo>,
}
impl PacketSocket {
pub fn netid(&self) -> &'static str {
match self.socket_type as i32 {
libc::SOCK_RAW => "p_raw",
libc::SOCK_DGRAM => "p_dgr",
_ => "packet",
}
}
pub fn protocol_name(&self) -> &'static str {
match self.protocol {
0x0003 => "802.3", 0x0004 => "ax25",
0x0800 => "ip",
0x0806 => "arp",
0x8035 => "rarp",
0x86DD => "ipv6",
0x8863 => "pppoe_disc",
0x8864 => "pppoe_sess",
0x888E => "802.1x",
0x88A8 => "802.1ad",
0x88CC => "lldp",
_ => "unknown",
}
}
}
pub fn parse_ipv4(data: &[u8]) -> Ipv4Addr {
if data.len() >= 4 {
Ipv4Addr::new(data[0], data[1], data[2], data[3])
} else {
Ipv4Addr::UNSPECIFIED
}
}
pub fn parse_ipv6(data: &[u8]) -> Ipv6Addr {
if data.len() >= 16 {
let mut octets = [0u8; 16];
octets.copy_from_slice(&data[..16]);
Ipv6Addr::from(octets)
} else {
Ipv6Addr::UNSPECIFIED
}
}
pub fn parse_port(data: &[u8]) -> u16 {
if data.len() >= 2 {
u16::from_be_bytes([data[0], data[1]])
} else {
0
}
}