lnwasi 0.0.3

Netlink Library for Web Assembly
Documentation
use std::collections::HashMap;

use anyhow::Result;
use serde::Serialize;

use crate::{consts, request::NetlinkRequestData, utils::align_of};

pub struct NetlinkMessage {
    pub header: NetlinkMessageHeader,
    pub data: Vec<u8>,
}

impl NetlinkMessage {
    pub fn from(mut buf: &[u8]) -> std::io::Result<Vec<Self>> {
        let mut msgs = Vec::new();

        while buf.len() >= consts::NLMSG_HDRLEN {
            let header = unsafe { *(buf.as_ptr() as *const NetlinkMessageHeader) };
            let len = align_of(header.nlmsg_len as usize, consts::NLMSG_ALIGNTO);
            let data = buf[consts::NLMSG_HDRLEN..header.nlmsg_len as usize].to_vec();

            msgs.push(Self { header, data });
            buf = &buf[len..];
        }

        Ok(msgs)
    }
}

#[repr(C)]
#[derive(Clone, Copy, Serialize, Debug)]
pub struct NetlinkMessageHeader {
    pub nlmsg_len: u32,
    pub nlmsg_type: u16,
    pub nlmsg_flags: u16,
    pub nlmsg_seq: u32,
    pub nlmsg_pid: u32,
}

impl NetlinkMessageHeader {
    pub fn new(proto: u16, flags: i32) -> Self {
        Self {
            nlmsg_len: std::mem::size_of::<Self>() as u32,
            nlmsg_type: proto,
            nlmsg_flags: (libc::NLM_F_REQUEST | flags) as u16,
            nlmsg_seq: 0,
            nlmsg_pid: 0,
        }
    }
}

pub struct NetlinkRouteAttr {
    pub rt_attr: RtAttr,
    pub value: Vec<u8>,
    pub children: Option<Vec<Box<dyn NetlinkRequestData>>>,
}

impl NetlinkRequestData for NetlinkRouteAttr {
    fn len(&self) -> usize {
        self.rt_attr.rta_len as usize
    }

    fn is_empty(&self) -> bool {
        self.rt_attr.rta_len == 0
    }

    fn serialize(&self) -> Result<Vec<u8>> {
        let mut buf = Vec::new();
        buf.extend_from_slice(&self.rt_attr.rta_len.to_ne_bytes());
        buf.extend_from_slice(&self.rt_attr.rta_type.to_ne_bytes());
        buf.extend_from_slice(&self.value);

        let align_to = align_of(buf.len(), consts::RTA_ALIGNTO);
        if buf.len() < align_to {
            buf.resize(align_to, 0);
        }

        if let Some(children) = &self.children {
            for child in children {
                buf.extend_from_slice(&child.serialize()?);
            }
        }

        let len = buf.len();
        buf[..2].copy_from_slice(&(len as u16).to_ne_bytes());

        Ok(buf)
    }
}

impl NetlinkRouteAttr {
    pub fn new(rta_type: u16, value: Vec<u8>) -> Self {
        Self {
            rt_attr: RtAttr {
                rta_len: (consts::RT_ATTR_SIZE + value.len()) as u16,
                rta_type,
            },
            value,
            children: None,
        }
    }

    pub fn map(mut buf: &[u8]) -> Result<HashMap<u16, Vec<u8>>> {
        let mut attrs = HashMap::new();

        while buf.len() >= consts::RT_ATTR_SIZE {
            let rt_attr = unsafe { *(buf.as_ptr() as *const RtAttr) };
            let len = align_of(rt_attr.rta_len as usize, consts::RTA_ALIGNTO);
            let value = buf[consts::RT_ATTR_SIZE..rt_attr.rta_len as usize].to_vec();

            attrs.insert(rt_attr.rta_type, value);
            buf = &buf[len..];
        }

        Ok(attrs)
    }

    pub fn from(mut buf: &[u8]) -> Result<Vec<Self>> {
        let mut attrs = Vec::new();

        while buf.len() >= consts::RT_ATTR_SIZE {
            let rt_attr = unsafe { *(buf.as_ptr() as *const RtAttr) };
            let len = align_of(rt_attr.rta_len as usize, consts::RTA_ALIGNTO);
            let value = buf[consts::RT_ATTR_SIZE..rt_attr.rta_len as usize].to_vec();

            attrs.push(Self {
                rt_attr,
                value,
                children: None,
            });
            buf = &buf[len..];
        }

        Ok(attrs)
    }

    pub fn add_child(&mut self, rta_type: u16, value: Vec<u8>) {
        let attr = Box::new(NetlinkRouteAttr::new(rta_type, value));
        self.rt_attr.rta_len += attr.len() as u16;

        match &mut self.children {
            None => self.children = Some(vec![attr]),
            Some(children) => children.push(attr),
        }
    }

    pub fn add_child_from_attr(&mut self, attr: Box<(impl NetlinkRequestData + 'static)>) {
        self.rt_attr.rta_len += attr.len() as u16;

        match &mut self.children {
            None => self.children = Some(vec![attr]),
            Some(children) => children.push(attr),
        }
    }
}

#[repr(C)]
#[derive(Clone, Copy, Debug)]
pub struct RtAttr {
    pub rta_len: u16,
    pub rta_type: u16,
}

#[repr(C)]
#[derive(Clone, Copy, Default, Debug, Serialize)]
pub struct InfoMessage {
    pub family: u8,
    pub _pad: u8,
    pub ifi_type: u16,
    pub index: i32,
    pub flags: u32,
    pub change: u32,
}

impl NetlinkRequestData for InfoMessage {
    fn len(&self) -> usize {
        consts::IF_INFO_MSG_SIZE
    }

    fn is_empty(&self) -> bool {
        self.family == 0
    }

    fn serialize(&self) -> Result<Vec<u8>> {
        bincode::serialize(self).map_err(|e| e.into())
    }
}

impl InfoMessage {
    pub fn new(family: i32) -> Self {
        Self {
            family: family as u8,
            ..Default::default()
        }
    }

    pub fn deserialize(buf: &[u8]) -> Result<Self> {
        Ok(unsafe { *(buf[..consts::IF_INFO_MSG_SIZE].as_ptr() as *const Self) })
    }
}

#[repr(C)]
#[derive(Clone, Copy, Default, Debug, Serialize)]
pub struct AddressMessage {
    pub family: u8,
    pub prefix_len: u8,
    pub flags: u8,
    pub scope: u8,
    pub index: i32,
}

impl NetlinkRequestData for AddressMessage {
    fn len(&self) -> usize {
        consts::IF_ADDR_MSG_SIZE
    }

    fn is_empty(&self) -> bool {
        self.family == 0
    }

    fn serialize(&self) -> Result<Vec<u8>> {
        bincode::serialize(self).map_err(|e| e.into())
    }
}

impl AddressMessage {
    pub fn new(family: i32) -> Self {
        Self {
            family: family as u8,
            ..Default::default()
        }
    }

    pub fn deserialize(buf: &[u8]) -> Result<Self> {
        Ok(unsafe { *(buf[..consts::IF_ADDR_MSG_SIZE].as_ptr() as *const Self) })
    }
}

#[repr(C)]
#[derive(Clone, Copy, Default, Debug, Serialize)]
pub struct RouteMessage {
    pub family: u8,
    pub dst_len: u8,
    pub src_len: u8,
    pub tos: u8,
    pub table: u8,
    pub protocol: u8,
    pub scope: u8,
    pub rtm_type: u8,
    pub flags: u32,
}

impl NetlinkRequestData for RouteMessage {
    fn len(&self) -> usize {
        consts::ROUTE_MSG_SIZE
    }

    fn is_empty(&self) -> bool {
        self.family == 0
    }

    fn serialize(&self) -> Result<Vec<u8>> {
        bincode::serialize(self).map_err(|e| e.into())
    }
}

impl RouteMessage {
    pub fn new_rt_msg() -> Self {
        Self {
            table: libc::RT_TABLE_MAIN,
            protocol: libc::RTPROT_BOOT,
            scope: libc::RT_SCOPE_UNIVERSE,
            rtm_type: libc::RTN_UNICAST,
            ..Default::default()
        }
    }

    pub fn new_rt_del_msg() -> Self {
        Self {
            table: libc::RT_TABLE_MAIN,
            scope: libc::RT_SCOPE_NOWHERE,
            ..Default::default()
        }
    }

    pub fn new_rt_list_msg(family: u8) -> Self {
        Self {
            family,
            ..Default::default()
        }
    }

    pub fn deserialize(buf: &[u8]) -> Result<Self> {
        Ok(unsafe { *(buf[..consts::ROUTE_MSG_SIZE].as_ptr() as *const Self) })
    }
}