On Tue Apr 2, 2024 at 7:16 PM CEST, Stefan Hanreich wrote: > Adds an enum containing most of the statements defined in the > nftables-json schema [1]. > > [1] > https://manpages.debian.org/bookworm/libnftables1/libnftables-json.5.en.html#STATEMENTS > > Co-authored-by: Wolfgang Bumiller <w.bumil...@proxmox.com> > Signed-off-by: Stefan Hanreich <s.hanre...@proxmox.com> > --- > proxmox-nftables/Cargo.toml | 1 + > proxmox-nftables/src/lib.rs | 2 + > proxmox-nftables/src/statement.rs | 321 ++++++++++++++++++++++++++++++ > proxmox-nftables/src/types.rs | 17 ++ > 4 files changed, 341 insertions(+) > create mode 100644 proxmox-nftables/src/statement.rs > > diff --git a/proxmox-nftables/Cargo.toml b/proxmox-nftables/Cargo.toml > index 7e607e8..153716d 100644 > --- a/proxmox-nftables/Cargo.toml > +++ b/proxmox-nftables/Cargo.toml > @@ -15,6 +15,7 @@ config-ext = ["dep:proxmox-ve-config"] > > [dependencies] > log = "0.4" > +anyhow = "1" > > serde = { version = "1", features = [ "derive" ] } > serde_json = "1" > diff --git a/proxmox-nftables/src/lib.rs b/proxmox-nftables/src/lib.rs > index 712858b..40f6bab 100644 > --- a/proxmox-nftables/src/lib.rs > +++ b/proxmox-nftables/src/lib.rs > @@ -1,5 +1,7 @@ > pub mod expression; > pub mod helper; > +pub mod statement; > pub mod types; > > pub use expression::Expression; > +pub use statement::Statement; > diff --git a/proxmox-nftables/src/statement.rs > b/proxmox-nftables/src/statement.rs > new file mode 100644 > index 0000000..e569f33 > --- /dev/null > +++ b/proxmox-nftables/src/statement.rs > @@ -0,0 +1,321 @@ > +use anyhow::{bail, Error};
Hmm, you don't use either here - you sure you didn't mean to introduce `anyhow` later? > +use serde::{Deserialize, Serialize}; > + > +use crate::expression::Meta; > +use crate::helper::{NfVec, Null}; > +use crate::types::{RateTimescale, RateUnit, Verdict}; > +use crate::Expression; > + > +#[derive(Clone, Debug, Deserialize, Serialize)] > +#[serde(rename_all = "lowercase")] > +pub enum Statement { > + Match(Match), > + Mangle(Mangle), > + Limit(Limit), > + Notrack(Null), > + Reject(Reject), > + Set(Set), > + Log(Log), > + #[serde(rename = "ct helper")] > + CtHelper(String), > + Vmap(Vmap), > + Comment(String), > + > + #[serde(untagged)] > + Verdict(Verdict), > +} > + > +impl Statement { > + pub const fn make_accept() -> Self { > + Statement::Verdict(Verdict::Accept(Null)) > + } > + > + pub const fn make_drop() -> Self { > + Statement::Verdict(Verdict::Drop(Null)) > + } > + > + pub const fn make_return() -> Self { > + Statement::Verdict(Verdict::Return(Null)) > + } > + > + pub const fn make_continue() -> Self { > + Statement::Verdict(Verdict::Continue(Null)) > + } > + > + pub fn jump(target: impl Into<String>) -> Self { > + Statement::Verdict(Verdict::Jump { > + target: target.into(), > + }) > + } > + > + pub fn goto(target: impl Into<String>) -> Self { > + Statement::Verdict(Verdict::Goto { > + target: target.into(), > + }) > + } > +} > + > +impl From<Match> for Statement { > + #[inline] > + fn from(m: Match) -> Statement { > + Statement::Match(m) > + } > +} > + > +impl From<Mangle> for Statement { > + #[inline] > + fn from(m: Mangle) -> Statement { > + Statement::Mangle(m) > + } > +} > + > +impl From<Reject> for Statement { > + #[inline] > + fn from(m: Reject) -> Statement { > + Statement::Reject(m) > + } > +} > + > +impl From<Set> for Statement { > + #[inline] > + fn from(m: Set) -> Statement { > + Statement::Set(m) > + } > +} > + > +impl From<Vmap> for Statement { > + #[inline] > + fn from(m: Vmap) -> Statement { > + Statement::Vmap(m) > + } > +} > + > +impl From<Log> for Statement { > + #[inline] > + fn from(log: Log) -> Statement { > + Statement::Log(log) > + } > +} > + > +impl<T: Into<Limit>> From<T> for Statement { > + #[inline] > + fn from(limit: T) -> Statement { > + Statement::Limit(limit.into()) > + } > +} > + > +#[derive(Clone, Debug, Deserialize, Serialize)] > +#[serde(rename_all = "lowercase")] > +pub enum RejectType { > + #[serde(rename = "tcp reset")] > + TcpRst, > + IcmpX, > + Icmp, > + IcmpV6, > +} > + > +#[derive(Clone, Debug, Default, Deserialize, Serialize)] > +pub struct Reject { > + #[serde(rename = "type", skip_serializing_if = "Option::is_none")] > + ty: Option<RejectType>, > + #[serde(skip_serializing_if = "Option::is_none")] > + expr: Option<Expression>, > +} > + > +#[derive(Clone, Debug, Default, Deserialize, Serialize)] > +#[serde(rename_all = "kebab-case")] > +pub struct Log { > + #[serde(skip_serializing_if = "Option::is_none")] > + prefix: Option<String>, > + > + #[serde(skip_serializing_if = "Option::is_none")] > + group: Option<i64>, > + > + #[serde(skip_serializing_if = "Option::is_none")] > + snaplen: Option<i64>, > + > + #[serde(skip_serializing_if = "Option::is_none")] > + queue_threshold: Option<i64>, > + > + #[serde(skip_serializing_if = "Option::is_none")] > + level: Option<LogLevel>, > + > + #[serde(default, skip_serializing_if = "Vec::is_empty")] > + flags: NfVec<LogFlag>, > +} > + > +impl Log { > + pub fn new_nflog(prefix: String, group: i64) -> Self { > + Self { > + prefix: Some(prefix), > + group: Some(group), > + ..Default::default() > + } > + } > +} > + > +#[derive(Clone, Debug, Deserialize, Serialize)] > +#[serde(rename_all = "lowercase")] > +pub enum LogLevel { > + Emerg, > + Alert, > + Crit, > + Err, > + Warn, > + Notice, > + Info, > + Debug, > + Audit, > +} > + > +impl LogLevel { > + pub fn nflog_level(&self) -> u8 { > + match self { > + LogLevel::Emerg => 0, > + LogLevel::Alert => 1, > + LogLevel::Crit => 2, > + LogLevel::Err => 3, > + LogLevel::Warn => 4, > + LogLevel::Notice => 5, > + LogLevel::Info => 6, > + LogLevel::Debug => 7, > + LogLevel::Audit => 7, > + } > + } > +} > + > +#[derive(Clone, Debug, Deserialize, Serialize)] > +#[serde(rename_all = "lowercase")] > +pub enum LogFlag { > + #[serde(rename = "tcp sequence")] > + TcpSequence, > + #[serde(rename = "tcp options")] > + TcpOptions, > + #[serde(rename = "ip options")] > + IpOptions, > + > + Skuid, > + Ether, > + All, > +} > + > +#[derive(Clone, Debug, Deserialize, Serialize)] > +#[serde(untagged)] > +pub enum Limit { > + Named(String), > + Anonymous(AnonymousLimit), > +} > + > +impl<T: Into<AnonymousLimit>> From<T> for Limit { > + fn from(value: T) -> Self { > + Limit::Anonymous(value.into()) > + } > +} > + > +#[derive(Clone, Debug, Deserialize, Serialize, Default)] > +pub struct AnonymousLimit { > + pub rate: i64, > + > + #[serde(skip_serializing_if = "Option::is_none")] > + pub rate_unit: Option<RateUnit>, > + > + pub per: RateTimescale, > + > + #[serde(skip_serializing_if = "Option::is_none")] > + pub burst: Option<i64>, > + > + #[serde(skip_serializing_if = "Option::is_none")] > + pub burst_unit: Option<RateUnit>, > + > + #[serde(skip_serializing_if = "Option::is_none")] > + pub inv: Option<bool>, > +} > + > +#[derive(Clone, Debug, Deserialize, Serialize)] > +pub struct Vmap { > + key: Expression, > + data: Expression, > +} > + > +#[derive(Clone, Debug, Deserialize, Serialize)] > +pub struct Match { > + op: Operator, > + left: Expression, > + right: Expression, > +} > + > +impl Match { > + pub fn new(op: Operator, left: impl Into<Expression>, right: impl > Into<Expression>) -> Self { > + Self { > + op, > + left: left.into(), > + right: right.into(), > + } > + } > + > + pub fn new_eq(left: impl Into<Expression>, right: impl Into<Expression>) > -> Self { > + Self::new(Operator::Eq, left, right) > + } > + > + pub fn new_ne(left: impl Into<Expression>, right: impl Into<Expression>) > -> Self { > + Self::new(Operator::Ne, left, right) > + } > +} > + > +#[derive(Clone, Debug, Deserialize, Serialize)] > +pub enum Operator { > + #[serde(rename = "&")] > + And, > + #[serde(rename = "|")] > + Or, > + #[serde(rename = "^")] > + Xor, > + #[serde(rename = "<<")] > + ShiftLeft, > + #[serde(rename = ">>")] > + ShiftRight, > + #[serde(rename = "==")] > + Eq, > + #[serde(rename = "!=")] > + Ne, > + #[serde(rename = "<")] > + Lt, > + #[serde(rename = ">")] > + Gt, > + #[serde(rename = "<=")] > + Le, > + #[serde(rename = ">=")] > + Ge, > + #[serde(rename = "in")] > + In, > +} > + > +#[derive(Clone, Debug, Deserialize, Serialize)] > +pub struct Mangle { > + pub key: Expression, > + pub value: Expression, > +} > + > +impl Mangle { > + pub fn set_mark(value: impl Into<Expression>) -> Self { > + Self { > + key: Meta::new("mark").into(), > + value: value.into(), > + } > + } > +} > + > +#[derive(Clone, Debug, Deserialize, Serialize)] > +#[serde(rename_all = "lowercase")] > +pub enum SetOperation { > + Add, > + Update, > +} > + > +#[derive(Clone, Debug, Deserialize, Serialize)] > +pub struct Set { > + pub op: SetOperation, > + pub elem: Expression, > + pub set: String, > + pub stmt: Option<NfVec<Statement>>, > +} > diff --git a/proxmox-nftables/src/types.rs b/proxmox-nftables/src/types.rs > index 942c866..b99747b 100644 > --- a/proxmox-nftables/src/types.rs > +++ b/proxmox-nftables/src/types.rs > @@ -30,6 +30,23 @@ impl Display for Verdict { > } > } > > +#[derive(Clone, Debug, Deserialize, Serialize)] > +pub enum RateUnit { > + Packets, > + Bytes, > +} > + > +#[derive(Clone, Debug, Deserialize, Serialize, Default)] > +#[cfg_attr(test, derive(Eq, PartialEq))] > +#[serde(rename_all = "lowercase")] > +pub enum RateTimescale { > + #[default] > + Second, > + Minute, > + Hour, > + Day, > +} > + > #[derive(Clone, Debug, Deserialize, Serialize)] > pub struct ElemConfig { > timeout: Option<i64>, _______________________________________________ pve-devel mailing list pve-devel@lists.proxmox.com https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel