use std::fmt::Debug;
mod bitwise;
mod cmp;
mod immediate;
mod lookup;
mod meta;
mod payload;
mod register;
use crate::nftables::attributes::ListAttribute;
pub use self::{
bitwise::Bitwise, cmp::Cmp, cmp::Operator, immediate::Immediate,
lookup::Lookup, meta::Meta, meta::MetaKey, payload::ChecksumFlags,
payload::ChecksumType, payload::Payload, register::Register,
};
use netlink_packet_core::{
parse_string, DecodeError, DefaultNla, Emitable, ErrorContext, Nla,
NlaBuffer, NlasIterator, Parseable, ParseableParametrized, NLA_F_NESTED,
};
const NFTA_EXPR_UNSPEC: u16 = 0;
const NFTA_EXPR_NAME: u16 = 1;
const NFTA_EXPR_DATA: u16 = 2;
#[derive(Debug, Clone, Eq, PartialEq)]
#[non_exhaustive]
pub enum Expressions {
Bitwise(Vec<Bitwise>),
Cmp(Vec<Cmp>),
Immediate(Vec<Immediate>),
Lookup(Vec<Lookup>),
Meta(Vec<Meta>),
Payload(Vec<Payload>),
Unknown(Vec<DefaultNla>),
Other {
expression_type: String,
attributes: Vec<DefaultNla>,
},
}
#[derive(Debug, Clone, Eq, PartialEq)]
#[non_exhaustive]
pub enum ExpressionAttribute {
Unspec,
Name(String),
Data(Expressions),
Other(DefaultNla),
}
impl From<Expressions> for ListAttribute<ExpressionAttribute> {
fn from(ex: Expressions) -> Self {
let name = match &ex {
Expressions::Bitwise(_) => Some("bitwise"),
Expressions::Cmp(_) => Some("cmp"),
Expressions::Immediate(_) => Some("immediate"),
Expressions::Lookup(_) => Some("lookup"),
Expressions::Meta(_) => Some("meta"),
Expressions::Payload(_) => Some("payload"),
Expressions::Unknown(_) => None,
Expressions::Other {
ref expression_type,
..
} => Some(expression_type.as_str()),
};
if let Some(name) = name {
ListAttribute::Element(vec![
ExpressionAttribute::Name(name.to_string()),
ExpressionAttribute::Data(ex),
])
} else {
ListAttribute::Element(vec![ExpressionAttribute::Data(ex)])
}
}
}
impl Emitable for Expressions {
fn buffer_len(&self) -> usize {
match self {
Self::Bitwise(attrs) => attrs.as_slice().buffer_len(),
Self::Cmp(attrs) => attrs.as_slice().buffer_len(),
Self::Immediate(attrs) => attrs.as_slice().buffer_len(),
Self::Lookup(attrs) => attrs.as_slice().buffer_len(),
Self::Meta(attrs) => attrs.as_slice().buffer_len(),
Self::Payload(attrs) => attrs.as_slice().buffer_len(),
Self::Unknown(attrs) => attrs.as_slice().buffer_len(),
Self::Other { attributes, .. } => {
attributes.as_slice().buffer_len()
}
}
}
fn emit(&self, buffer: &mut [u8]) {
match self {
Self::Bitwise(attrs) => attrs.as_slice().emit(buffer),
Self::Cmp(attrs) => attrs.as_slice().emit(buffer),
Self::Immediate(attrs) => attrs.as_slice().emit(buffer),
Self::Lookup(attrs) => attrs.as_slice().emit(buffer),
Self::Meta(attrs) => attrs.as_slice().emit(buffer),
Self::Payload(attrs) => attrs.as_slice().emit(buffer),
Self::Unknown(attrs) => attrs.as_slice().emit(buffer),
Self::Other { attributes, .. } => {
attributes.as_slice().emit(buffer)
}
}
}
}
impl<T: AsRef<[u8]> + ?Sized + Debug> ParseableParametrized<T, Option<String>>
for Expressions
{
fn parse_with_param(
buf: &T,
name: Option<String>,
) -> Result<Self, DecodeError> {
Ok(match name {
None => {
let mut nlas = vec![];
for nla in NlasIterator::new(buf) {
let nla = nla
.context(format!("invalid NFTA_EXPR_DATA {:?}", buf))?;
nlas.push(DefaultNla::parse(&nla)?);
}
Self::Unknown(nlas)
}
Some(name) => match name.as_str() {
"bitwise" => {
let mut nlas = vec![];
for nla in NlasIterator::new(buf) {
let nla = nla.context(format!(
"invalid NFTA_EXPR_DATA {:?}",
buf
))?;
nlas.push(Bitwise::parse(&nla)?);
}
Self::Bitwise(nlas)
}
"cmp" => {
let mut nlas = vec![];
for nla in NlasIterator::new(buf) {
let nla = nla.context(format!(
"invalid NFTA_EXPR_DATA {:?}",
buf
))?;
nlas.push(Cmp::parse(&nla)?);
}
Self::Cmp(nlas)
}
"immediate" => {
let mut nlas = vec![];
for nla in NlasIterator::new(buf) {
let nla = nla.context(format!(
"invalid NFTA_EXPR_DATA {:?}",
buf
))?;
nlas.push(Immediate::parse(&nla)?);
}
Self::Immediate(nlas)
}
"lookup" => {
let mut nlas = vec![];
for nla in NlasIterator::new(buf) {
let nla = nla.context(format!(
"invalid NFTA_EXPR_DATA {:?}",
buf
))?;
nlas.push(Lookup::parse(&nla)?);
}
Self::Lookup(nlas)
}
"meta" => {
let mut nlas = vec![];
for nla in NlasIterator::new(buf) {
let nla = nla.context(format!(
"invalid NFTA_EXPR_DATA {:?}",
buf
))?;
nlas.push(Meta::parse(&nla)?);
}
Self::Meta(nlas)
}
"payload" => {
let mut nlas = vec![];
for nla in NlasIterator::new(buf) {
let nla = nla.context(format!(
"invalid NFTA_EXPR_DATA {:?}",
buf
))?;
nlas.push(Payload::parse(&nla)?);
}
Self::Payload(nlas)
}
name => {
let mut nlas = vec![];
for nla in NlasIterator::new(buf) {
let nla = nla.context(format!(
"invalid NFTA_EXPR_DATA {:?}",
buf
))?;
nlas.push(DefaultNla::parse(&nla)?);
}
Self::Other {
expression_type: name.to_string(),
attributes: nlas,
}
}
},
})
}
}
impl Nla for ExpressionAttribute {
fn value_len(&self) -> usize {
match self {
Self::Unspec => 0,
Self::Name(string) => string.len() + 1,
Self::Data(exps) => exps.buffer_len(),
Self::Other(attr) => attr.value_len(),
}
}
fn kind(&self) -> u16 {
match self {
Self::Unspec => NFTA_EXPR_UNSPEC,
Self::Name(_) => NFTA_EXPR_NAME,
Self::Data(_) => NFTA_EXPR_DATA | NLA_F_NESTED,
Self::Other(attr) => attr.kind(),
}
}
fn emit_value(&self, buffer: &mut [u8]) {
match self {
Self::Unspec => {}
Self::Name(string) => {
buffer[..string.len()].copy_from_slice(string.as_bytes());
buffer[string.len()] = 0;
}
Self::Data(exps) => exps.emit(buffer),
Self::Other(attr) => attr.emit_value(buffer),
}
}
fn is_nested(&self) -> bool {
matches!(self, Self::Data(_)) || (self.kind() & NLA_F_NESTED) != 0
}
}
impl<'a, T: AsRef<[u8]> + ?Sized>
ParseableParametrized<NlaBuffer<&'a T>, Option<String>>
for ExpressionAttribute
{
fn parse_with_param(
buf: &NlaBuffer<&'a T>,
name: Option<String>,
) -> Result<Self, DecodeError> {
let payload = buf.value();
Ok(match buf.kind() {
NFTA_EXPR_UNSPEC => Self::Unspec,
NFTA_EXPR_NAME => Self::Name(
parse_string(payload).context("invalid NFTA_EXPR_NAME")?,
),
NFTA_EXPR_DATA => Self::Data(
Expressions::parse_with_param(payload, name)
.context("invalid NFTA_EXPR_DATA")?,
),
_ => Self::Other(DefaultNla::parse(buf)?),
})
}
}