use netlink_packet_core::{
emit_u32_be, emit_u64_be, parse_string, parse_u32_be, parse_u64_be,
DecodeError, DefaultNla, Emitable, ErrorContext as _, Nla, NlaBuffer,
Parseable, ParseableParametrized, NLA_F_NESTED,
};
use crate::nftables::{
attributes::{list::VecListAttribute, ExpressionAttribute, ListAttribute},
set::{description::VecSetDescription, SetDescription, SetFlags},
};
const NFTA_SET_UNSEPC: u16 = 0;
const NFTA_SET_TABLE: u16 = 1;
const NFTA_SET_NAME: u16 = 2;
const NFTA_SET_FLAGS: u16 = 3;
const NFTA_SET_KEY_TYPE: u16 = 4;
const NFTA_SET_KEY_LEN: u16 = 5;
const NFTA_SET_DATA_TYPE: u16 = 6;
const NFTA_SET_DATA_LEN: u16 = 7;
const NFTA_SET_POLICY: u16 = 8;
const NFTA_SET_DESC: u16 = 9;
const NFTA_SET_ID: u16 = 10;
const NFTA_SET_TIMEOUT: u16 = 11;
const NFTA_SET_GC_INTERVAL: u16 = 12;
const NFTA_SET_USERDATA: u16 = 13;
const NFTA_SET_OBJ_TYPE: u16 = 15;
const NFTA_SET_HANDLE: u16 = 16;
const NFTA_SET_EXPR: u16 = 17;
const NFTA_SET_EXPRESSIONS: u16 = 18;
const NFTA_SET_TYPE: u16 = 19;
const NFTA_SET_COUNT: u16 = 20;
#[derive(Debug, PartialEq, Eq, Clone)]
#[non_exhaustive]
pub enum SetAttribute {
Unspecified,
Table(String),
Name(String),
Flags(SetFlags),
KeyType(u32),
KeyLen(u32),
DataType(u32),
DataLen(u32),
Policy(u32),
Description(Vec<SetDescription>),
Id(u32),
Timeout(u64),
GarbageCollectionInterval(u32),
UserData(Vec<u8>),
ObjectType(u32),
Handle(u64),
Expression(ExpressionAttribute),
ListExpressions(Vec<ListAttribute<ExpressionAttribute>>),
Type(String),
Count(u32),
Other(DefaultNla),
}
impl Nla for SetAttribute {
fn value_len(&self) -> usize {
match self {
Self::Unspecified => 0,
Self::Table(string) | Self::Name(string) | Self::Type(string) => {
string.len() + 1
}
Self::UserData(bytes) => bytes.len(),
Self::Flags(_)
| Self::KeyType(_)
| Self::KeyLen(_)
| Self::DataType(_)
| Self::DataLen(_)
| Self::Policy(_)
| Self::Id(_)
| Self::GarbageCollectionInterval(_)
| Self::ObjectType(_)
| Self::Count(_) => 4,
Self::Timeout(_) | Self::Handle(_) => 8,
Self::Description(attr) => attr.as_slice().buffer_len(),
Self::Expression(ex) => ex.buffer_len(),
Self::ListExpressions(exs) => exs.as_slice().buffer_len(),
Self::Other(attr) => attr.value_len(),
}
}
fn kind(&self) -> u16 {
match self {
Self::Unspecified => NFTA_SET_UNSEPC,
Self::Table(_) => NFTA_SET_TABLE,
Self::Name(_) => NFTA_SET_NAME,
Self::Flags(_) => NFTA_SET_FLAGS,
Self::KeyType(_) => NFTA_SET_KEY_TYPE,
Self::KeyLen(_) => NFTA_SET_KEY_LEN,
Self::DataType(_) => NFTA_SET_DATA_TYPE,
Self::DataLen(_) => NFTA_SET_DATA_LEN,
Self::Policy(_) => NFTA_SET_POLICY,
Self::Description(_) => NFTA_SET_DESC | NLA_F_NESTED,
Self::Id(_) => NFTA_SET_ID,
Self::Timeout(_) => NFTA_SET_TIMEOUT,
Self::GarbageCollectionInterval(_) => NFTA_SET_GC_INTERVAL,
Self::UserData(_) => NFTA_SET_USERDATA,
Self::ObjectType(_) => NFTA_SET_OBJ_TYPE,
Self::Handle(_) => NFTA_SET_HANDLE,
Self::Expression(_) => NFTA_SET_EXPR | NLA_F_NESTED,
Self::ListExpressions(_) => NFTA_SET_EXPRESSIONS | NLA_F_NESTED,
Self::Type(_) => NFTA_SET_TYPE,
Self::Count(_) => NFTA_SET_COUNT,
Self::Other(attr) => attr.kind(),
}
}
fn emit_value(&self, buffer: &mut [u8]) {
match self {
Self::Unspecified => {}
Self::Table(string) | Self::Name(string) | Self::Type(string) => {
buffer[..string.len()].copy_from_slice(string.as_bytes());
buffer[string.len()] = 0;
}
Self::UserData(bytes) => {
buffer[..bytes.len()].copy_from_slice(bytes.as_slice())
}
Self::Flags(bits) => emit_u32_be(buffer, bits.bits()).unwrap(),
Self::KeyType(value)
| Self::KeyLen(value)
| Self::DataType(value)
| Self::DataLen(value)
| Self::Policy(value)
| Self::Id(value)
| Self::GarbageCollectionInterval(value)
| Self::ObjectType(value)
| Self::Count(value) => emit_u32_be(buffer, *value).unwrap(),
Self::Timeout(value) | Self::Handle(value) => {
emit_u64_be(buffer, *value).unwrap()
}
Self::Description(desc) => desc.as_slice().emit(buffer),
Self::Expression(ex) => ex.emit(buffer),
Self::ListExpressions(exps) => exps.as_slice().emit(buffer),
Self::Other(attr) => attr.emit_value(buffer),
}
}
fn is_nested(&self) -> bool {
matches!(
self,
Self::Description(_)
| Self::Expression(_)
| Self::ListExpressions(_)
) || (self.kind() & NLA_F_NESTED) != 0
}
}
impl<'a, T: AsRef<[u8]> + ?Sized> Parseable<NlaBuffer<&'a T>> for SetAttribute {
fn parse(buf: &NlaBuffer<&'a T>) -> Result<Self, DecodeError> {
let payload = buf.value();
Ok(match buf.kind() {
NFTA_SET_UNSEPC => Self::Unspecified,
NFTA_SET_TABLE => Self::Table(
parse_string(payload)
.context("invalid NFTA_SET_TABLE value")?,
),
NFTA_SET_NAME => Self::Name(
parse_string(payload).context("invalid NFTA_SET_NAME value")?,
),
NFTA_SET_FLAGS => Self::Flags(SetFlags::from_bits_retain(
parse_u32_be(payload)
.context("invalid NFTA_SET_FLAGS value")?,
)),
NFTA_SET_KEY_TYPE => Self::KeyType(
parse_u32_be(payload)
.context("invalid NFTA_SET_KEY_TYPE value")?,
),
NFTA_SET_KEY_LEN => Self::KeyLen(
parse_u32_be(payload)
.context("invalid NFTA_SET_KEY_LEN value")?,
),
NFTA_SET_DATA_TYPE => Self::DataType(
parse_u32_be(payload)
.context("invalid NFTA_SET_DATA_TYPE value")?,
),
NFTA_SET_DATA_LEN => Self::DataLen(
parse_u32_be(payload)
.context("invalid NFTA_SET_DATA_LEN value")?,
),
NFTA_SET_POLICY => Self::Policy(
parse_u32_be(payload)
.context("invalid NFTA_SET_POLICY value")?,
),
NFTA_SET_DESC => Self::Description(
VecSetDescription::parse(payload)
.context("invalid NFTA_SET_DESC value")?
.0,
),
NFTA_SET_ID => Self::Id(
parse_u32_be(payload).context("invalid NFTA_SET_ID value")?,
),
NFTA_SET_TIMEOUT => Self::Timeout(
parse_u64_be(payload)
.context("invalid NFTA_SET_TIMEOUT value")?,
),
NFTA_SET_GC_INTERVAL => Self::GarbageCollectionInterval(
parse_u32_be(payload)
.context("invalid NFTA_SET_GC_INTERVAL value")?,
),
NFTA_SET_USERDATA => Self::UserData(payload.to_vec()),
NFTA_SET_OBJ_TYPE => Self::ObjectType(
parse_u32_be(payload)
.context("invalid NFTA_SET_OBJ_TYPE value")?,
),
NFTA_SET_HANDLE => Self::Handle(
parse_u64_be(payload)
.context("invalid NFTA_SET_HANDLE value")?,
),
NFTA_SET_EXPR => Self::Expression(
ExpressionAttribute::parse_with_param(
&NlaBuffer::new(payload),
None,
)
.context("invalid NFTA_SET_EXPR value")?,
),
NFTA_SET_EXPRESSIONS => Self::ListExpressions(
VecListAttribute::parse(payload)
.context("invalid NFTA_SET_EXPRESSIONS value")?
.0,
),
NFTA_SET_TYPE => Self::Type(
parse_string(payload).context("invalid NFTA_SET_TYPE value")?,
),
NFTA_SET_COUNT => Self::Count(
parse_u32_be(payload)
.context("invalid NFTA_SET_COUNT value")?,
),
_ => Self::Other(DefaultNla::parse(buf)?),
})
}
}