#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types)]
use libc::_SC_PAGESIZE;
use libc::{
bind, c_void, getsockname, getsockopt, recvmsg, setsockopt, sockaddr, sysconf, AF_NETLINK,
MSG_TRUNC, SOCK_RAW,
};
use libc::{close, iovec, msghdr, SOL_NETLINK};
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(C)]
pub struct Socket {
pub fd: i32,
pub addr: Sockaddr,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
#[repr(C)]
pub struct Sockaddr {
pub family: u16,
pad: u16,
pub pid: u32,
pub groups: u32,
}
impl Socket {
pub const AUTOPID: u32 = 0;
pub const DUMP_SIZE: usize = 32768;
pub const fn new() -> Socket {
Socket {
fd: -1,
addr: Sockaddr {
family: AF_NETLINK as u16,
pad: 0,
pid: Socket::AUTOPID,
groups: 0,
},
}
}
pub const fn set(&mut self, fd: i32, addr: Sockaddr) {
self.fd = fd;
self.addr = addr;
}
pub const fn fd(&self) -> i32 {
self.fd
}
pub const fn addr(&self) -> Sockaddr {
self.addr
}
pub fn reset(&mut self) {
self.fd = -1;
self.addr = Sockaddr {
family: AF_NETLINK as u16,
pad: 0,
pid: Socket::AUTOPID,
groups: 0,
};
}
pub fn as_ptr(&self) -> *const Self {
self
}
pub fn as_mut_ptr(&mut self) -> *mut Self {
self
}
pub fn buffer_size() -> usize {
unsafe { sysconf(_SC_PAGESIZE).min(8192) as usize }
}
pub const fn portid(&self) -> u32 {
self.addr.pid
}
pub fn __open(&mut self, bus: i32, flags: i32) -> *mut Socket {
unsafe {
self.fd = libc::socket(AF_NETLINK, SOCK_RAW | flags, bus);
if self.fd == -1 {
return std::ptr::null_mut();
}
self
}
}
pub fn open(&mut self, bus: i32) -> *mut Socket {
self.__open(bus, 0)
}
pub fn open2(&mut self, bus: i32, flags: i32) -> *mut Socket {
self.__open(bus, flags)
}
pub fn fdopen(&mut self) -> *mut Socket {
unsafe {
self.addr = Sockaddr::new();
let mut addr_len = size_of::<Sockaddr>() as u32;
if getsockname(
self.fd,
&mut self.addr as *mut Sockaddr as *mut sockaddr,
&mut addr_len,
) == -1
{
return std::ptr::null_mut();
}
self
}
}
pub fn bind(&mut self, groups: u32, pid: u32) -> i32 {
unsafe {
self.addr.set(AF_NETLINK as u16, pid, groups);
let addr_size = size_of::<Sockaddr>() as u32;
if bind(
self.fd,
&self.addr as *const Sockaddr as *const sockaddr,
addr_size,
) < 0
{
return -1;
}
let mut actual_len = addr_size;
if getsockname(
self.fd,
&mut self.addr as *mut Sockaddr as *mut sockaddr,
&mut actual_len,
) < 0
{
return -1;
}
if actual_len != addr_size || self.addr.family != AF_NETLINK as u16 {
return -1;
}
0
}
}
pub fn sendto(&mut self, buf: *const u8, len: usize) -> isize {
unsafe {
libc::sendto(
self.fd,
buf as *const c_void,
len,
0,
&self.addr as *const Sockaddr as *const sockaddr,
size_of::<Sockaddr>() as u32,
)
}
}
pub fn recvfrom(&mut self, buf: *mut u8, bufsiz: usize) -> isize {
unsafe {
let mut iov = iovec {
iov_base: buf as *mut c_void,
iov_len: bufsiz,
};
let mut msg = msghdr {
msg_name: &mut self.addr as *mut Sockaddr as *mut c_void,
msg_namelen: size_of::<Sockaddr>() as u32,
msg_iov: &mut iov,
msg_iovlen: 1,
msg_control: std::ptr::null_mut(),
msg_controllen: 0,
msg_flags: 0,
};
let ret = recvmsg(self.fd, &mut msg, 0);
if ret == -1 {
return ret;
}
if (msg.msg_flags & MSG_TRUNC) != 0 {
eprintln!("Message truncated");
return -1;
}
if msg.msg_namelen != size_of::<Sockaddr>() as u32 {
eprintln!("Unexpected address length {}", msg.msg_namelen);
return -1;
}
ret
}
}
pub fn close(&mut self) -> i32 {
unsafe { close(self.fd) }
}
pub fn setsockopt(&mut self, type_: i32, buf: *mut u8, len: u32) -> i32 {
unsafe { setsockopt(self.fd, SOL_NETLINK as i32, type_, buf as *mut c_void, len) }
}
pub fn getsockopt(&mut self, type_: i32, buf: *mut u8, len: *mut u32) -> i32 {
unsafe { getsockopt(self.fd, SOL_NETLINK as i32, type_, buf as *mut c_void, len) }
}
}
impl Sockaddr {
pub const fn new() -> Sockaddr {
Sockaddr {
family: AF_NETLINK as u16,
pad: 0,
pid: 0,
groups: 0,
}
}
pub const fn set(&mut self, family: u16, pid: u32, groups: u32) {
self.family = family;
self.pid = pid;
self.groups = groups;
}
pub const fn reset(&mut self) {
self.family = AF_NETLINK as u16;
self.pid = 0;
self.groups = 0;
}
pub const fn family(&self) -> u16 {
self.family
}
pub const fn pid(&self) -> u32 {
self.pid
}
pub const fn groups(&self) -> u32 {
self.groups
}
pub fn as_ptr(&self) -> *const Sockaddr {
self
}
pub fn as_mut_ptr(&mut self) -> *mut Sockaddr {
self
}
pub const fn size() -> usize {
size_of::<Sockaddr>()
}
}
impl From<u128> for Socket {
fn from(u: u128) -> Socket {
let bytes = u.to_ne_bytes();
Socket {
fd: i32::from_ne_bytes(bytes[0..4].try_into().unwrap()),
addr: Sockaddr {
family: u16::from_ne_bytes(bytes[4..6].try_into().unwrap()),
pad: 0,
pid: u32::from_ne_bytes(bytes[8..12].try_into().unwrap()),
groups: u32::from_ne_bytes(bytes[12..16].try_into().unwrap()),
},
}
}
}
impl From<Socket> for u128 {
fn from(s: Socket) -> u128 {
let mut bytes = [0u8; 16];
bytes[0..4].copy_from_slice(&s.fd.to_ne_bytes());
bytes[4..6].copy_from_slice(&s.addr.family.to_ne_bytes());
bytes[8..12].copy_from_slice(&s.addr.pid.to_ne_bytes());
bytes[12..16].copy_from_slice(&s.addr.groups.to_ne_bytes());
u128::from_ne_bytes(bytes)
}
}
impl From<Sockaddr> for sockaddr {
fn from(saddr: Sockaddr) -> sockaddr {
let pid_bytes = saddr.pid.to_ne_bytes();
let group_bytes = saddr.groups.to_ne_bytes();
sockaddr {
sa_family: saddr.family,
sa_data: [
0,
0,
pid_bytes[0] as i8,
pid_bytes[1] as i8,
pid_bytes[2] as i8,
pid_bytes[3] as i8,
group_bytes[0] as i8,
group_bytes[1] as i8,
group_bytes[2] as i8,
group_bytes[3] as i8,
0,
0,
0,
0,
],
}
}
}
impl From<sockaddr> for Sockaddr {
fn from(sa: sockaddr) -> Sockaddr {
let pid_bytes = [
sa.sa_data[2] as u8,
sa.sa_data[3] as u8,
sa.sa_data[4] as u8,
sa.sa_data[5] as u8,
];
let groups_bytes = [
sa.sa_data[6] as u8,
sa.sa_data[7] as u8,
sa.sa_data[8] as u8,
sa.sa_data[9] as u8,
];
Sockaddr {
family: sa.sa_family,
pad: 0,
pid: u32::from_ne_bytes(pid_bytes),
groups: u32::from_ne_bytes(groups_bytes),
}
}
}