netlink-packet-netfilter 0.4.0

netlink packet types for the netfilter subprotocol
Documentation
// SPDX-License-Identifier: MIT

use crate::conntrack::attributes::ConntrackAttribute;
use crate::nlas::{default_nlas, parse_all_nlas};
use netlink_packet_core::{
    DecodeError, DefaultNla, Emitable, Parseable, ParseableParametrized,
};

#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub enum ConntrackMessage {
    New(Vec<ConntrackAttribute>),
    Get(Vec<ConntrackAttribute>),
    Delete(Vec<ConntrackAttribute>),
    Other {
        message_type: u8,
        attributes: Vec<DefaultNla>,
    },
}

const IPCTNL_MSG_CT_NEW: u8 = 0;
const IPCTNL_MSG_CT_GET: u8 = 1;
const IPCTNL_MSG_CT_DELETE: u8 = 2;

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ConntrackMessageType {
    New,
    Get,
    Delete,
    Other(u8),
}

impl From<u8> for ConntrackMessageType {
    fn from(value: u8) -> Self {
        match value {
            IPCTNL_MSG_CT_NEW => Self::New,
            IPCTNL_MSG_CT_GET => Self::Get,
            IPCTNL_MSG_CT_DELETE => Self::Delete,
            v => Self::Other(v),
        }
    }
}

impl From<ConntrackMessageType> for u8 {
    fn from(value: ConntrackMessageType) -> Self {
        match value {
            ConntrackMessageType::New => IPCTNL_MSG_CT_NEW,
            ConntrackMessageType::Get => IPCTNL_MSG_CT_GET,
            ConntrackMessageType::Delete => IPCTNL_MSG_CT_DELETE,
            ConntrackMessageType::Other(v) => v,
        }
    }
}

impl ConntrackMessage {
    pub fn message_type(&self) -> ConntrackMessageType {
        match self {
            ConntrackMessage::New(_) => ConntrackMessageType::New,
            ConntrackMessage::Get(_) => ConntrackMessageType::Get,
            ConntrackMessage::Delete(_) => ConntrackMessageType::Delete,
            ConntrackMessage::Other { message_type, .. } => {
                (*message_type).into()
            }
        }
    }
}

impl Emitable for ConntrackMessage {
    fn buffer_len(&self) -> usize {
        match self {
            ConntrackMessage::New(attributes) => {
                attributes.as_slice().buffer_len()
            }
            ConntrackMessage::Get(attributes) => {
                attributes.as_slice().buffer_len()
            }
            ConntrackMessage::Delete(attributes) => {
                attributes.as_slice().buffer_len()
            }
            ConntrackMessage::Other { attributes, .. } => {
                attributes.as_slice().buffer_len()
            }
        }
    }

    fn emit(&self, buffer: &mut [u8]) {
        match self {
            ConntrackMessage::New(attributes) => {
                attributes.as_slice().emit(buffer)
            }
            ConntrackMessage::Get(attributes) => {
                attributes.as_slice().emit(buffer)
            }
            ConntrackMessage::Delete(attributes) => {
                attributes.as_slice().emit(buffer)
            }
            ConntrackMessage::Other { attributes, .. } => {
                attributes.as_slice().emit(buffer)
            }
        };
    }
}

impl ParseableParametrized<[u8], u8> for ConntrackMessage {
    fn parse_with_param(
        buf: &[u8],
        message_type: u8,
    ) -> Result<Self, DecodeError> {
        Ok(match ConntrackMessageType::from(message_type) {
            ConntrackMessageType::New => {
                let attributes = parse_all_nlas(buf, |nla_buf| {
                    ConntrackAttribute::parse(&nla_buf)
                })?;
                ConntrackMessage::New(attributes)
            }
            ConntrackMessageType::Get => {
                let attributes = parse_all_nlas(buf, |nla_buf| {
                    ConntrackAttribute::parse(&nla_buf)
                })?;
                ConntrackMessage::Get(attributes)
            }
            ConntrackMessageType::Delete => {
                let nlas = parse_all_nlas(buf, |nla_buf| {
                    ConntrackAttribute::parse(&nla_buf)
                })?;
                ConntrackMessage::Delete(nlas)
            }
            ConntrackMessageType::Other(message_type) => {
                ConntrackMessage::Other {
                    message_type,
                    attributes: default_nlas(buf)?,
                }
            }
        })
    }
}