use schemars::JsonSchema;
use std::{borrow::Cow, collections::HashSet};
use crate::visitor::deserialize_optional_flags;
use crate::{
expr::Expression, stmt::Statement, types::*, visitor::single_string_to_option_vec,
DEFAULT_CHAIN, DEFAULT_FAMILY, DEFAULT_TABLE,
};
use serde::{Deserialize, Serialize};
use strum_macros::EnumString;
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Nftables<'a> {
#[serde(rename = "nftables")]
pub objects: Cow<'a, [NfObject<'a>]>,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
pub enum NfObject<'a> {
CmdObject(NfCmd<'a>),
ListObject(NfListObject<'a>),
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum NfListObject<'a> {
Table(Table<'a>),
Chain(Chain<'a>),
Rule(Rule<'a>),
Set(Box<Set<'a>>),
Map(Box<Map<'a>>),
Element(Element<'a>),
FlowTable(FlowTable<'a>),
Counter(Counter<'a>),
Quota(Quota<'a>),
#[serde(rename = "ct helper")]
CTHelper(CTHelper<'a>),
Limit(Limit<'a>),
#[serde(rename = "metainfo")]
MetainfoObject(MetainfoObject<'a>),
CTTimeout(CTTimeout<'a>),
#[serde(rename = "ct expectation")]
CTExpectation(CTExpectation<'a>),
SynProxy(SynProxy<'a>),
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum NfCmd<'a> {
Add(NfListObject<'a>),
Replace(Rule<'a>),
Create(NfListObject<'a>), Insert(NfListObject<'a>),
Delete(NfListObject<'a>), List(NfListObject<'a>),
Reset(ResetObject<'a>),
Flush(FlushObject<'a>),
Rename(Chain<'a>),
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum ResetObject<'a> {
Counter(Counter<'a>),
Counters(Cow<'a, [Counter<'a>]>),
Quota(Quota<'a>),
Quotas(Cow<'a, [Quota<'a>]>),
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum FlushObject<'a> {
Table(Table<'a>),
Chain(Chain<'a>),
Set(Box<Set<'a>>),
Map(Box<Map<'a>>),
Meter(Meter<'a>),
Ruleset(Option<Ruleset>),
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Table<'a> {
pub family: NfFamily,
pub name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
}
impl Default for Table<'_> {
fn default() -> Self {
Table {
family: DEFAULT_FAMILY,
name: DEFAULT_TABLE.into(),
handle: None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Chain<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub newname: Option<Cow<'a, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none", rename = "type")]
pub _type: Option<NfChainType>, #[serde(skip_serializing_if = "Option::is_none")]
pub hook: Option<NfHook>,
#[serde(skip_serializing_if = "Option::is_none")]
pub prio: Option<i32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dev: Option<Cow<'a, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub policy: Option<NfChainPolicy>,
}
impl Default for Chain<'_> {
fn default() -> Self {
Chain {
family: DEFAULT_FAMILY,
table: DEFAULT_TABLE.into(),
name: DEFAULT_CHAIN.into(),
newname: None,
handle: None,
_type: None,
hook: None,
prio: None,
dev: None,
policy: None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Rule<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub chain: Cow<'a, str>,
pub expr: Cow<'a, [Statement<'a>]>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub index: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub comment: Option<Cow<'a, str>>,
}
impl Default for Rule<'_> {
fn default() -> Self {
Rule {
family: DEFAULT_FAMILY,
table: DEFAULT_TABLE.into(),
chain: DEFAULT_CHAIN.into(),
expr: [][..].into(),
handle: None,
index: None,
comment: None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Set<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
#[serde(rename = "type")]
pub set_type: SetTypeValue<'a>,
#[serde(skip_serializing_if = "Option::is_none")]
pub policy: Option<SetPolicy>,
#[serde(
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_optional_flags",
default
)]
pub flags: Option<HashSet<SetFlag>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub elem: Option<Cow<'a, [Expression<'a>]>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout: Option<u32>,
#[serde(rename = "gc-interval", skip_serializing_if = "Option::is_none")]
pub gc_interval: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub comment: Option<Cow<'a, str>>,
}
impl Default for Set<'_> {
fn default() -> Self {
Set {
family: DEFAULT_FAMILY,
table: DEFAULT_TABLE.into(),
name: "myset".into(),
handle: None,
set_type: SetTypeValue::Single(SetType::Ipv4Addr),
policy: None,
flags: None,
elem: None,
timeout: None,
gc_interval: None,
size: None,
comment: None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Map<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
#[serde(rename = "type")]
pub set_type: SetTypeValue<'a>,
pub map: SetTypeValue<'a>,
#[serde(skip_serializing_if = "Option::is_none")]
pub policy: Option<SetPolicy>,
#[serde(
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_optional_flags",
default
)]
pub flags: Option<HashSet<SetFlag>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub elem: Option<Cow<'a, [Expression<'a>]>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout: Option<u32>,
#[serde(rename = "gc-interval", skip_serializing_if = "Option::is_none")]
pub gc_interval: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub comment: Option<Cow<'a, str>>,
}
impl Default for Map<'_> {
fn default() -> Self {
Map {
family: DEFAULT_FAMILY,
table: DEFAULT_TABLE.into(),
name: "mymap".into(),
handle: None,
set_type: SetTypeValue::Single(SetType::Ipv4Addr),
map: SetTypeValue::Single(SetType::Ipv4Addr),
policy: None,
flags: None,
elem: None,
timeout: None,
gc_interval: None,
size: None,
comment: None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
pub enum SetTypeValue<'a> {
Single(SetType),
Concatenated(Cow<'a, [SetType]>),
}
#[derive(
Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, EnumString, JsonSchema,
)]
#[serde(rename_all = "lowercase")]
pub enum SetType {
#[serde(rename = "ipv4_addr")]
#[strum(serialize = "ipv4_addr")]
Ipv4Addr,
#[serde(rename = "ipv6_addr")]
#[strum(serialize = "ipv6_addr")]
Ipv6Addr,
#[serde(rename = "ether_addr")]
#[strum(serialize = "ether_addr")]
EtherAddr,
#[serde(rename = "inet_proto")]
#[strum(serialize = "inet_proto")]
InetProto,
#[serde(rename = "inet_service")]
#[strum(serialize = "inet_service")]
InetService,
#[serde(rename = "mark")]
#[strum(serialize = "mark")]
Mark,
#[serde(rename = "ifname")]
#[strum(serialize = "ifname")]
Ifname,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum SetPolicy {
Performance,
Memory,
}
#[derive(
Clone, Copy, Debug, Eq, PartialEq, Serialize, Deserialize, EnumString, Hash, JsonSchema,
)]
#[serde(rename_all = "lowercase")]
#[strum(serialize_all = "lowercase")]
pub enum SetFlag {
Constant,
Interval,
Timeout,
Dynamic,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum SetOp {
Add,
Update,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Element<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub name: Cow<'a, str>,
pub elem: Cow<'a, [Expression<'a>]>,
}
impl Default for Element<'_> {
fn default() -> Self {
Element {
family: DEFAULT_FAMILY,
table: DEFAULT_TABLE.into(),
name: "myset".into(),
elem: [][..].into(),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct FlowTable<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
pub hook: Option<NfHook>,
pub prio: Option<u32>,
#[serde(
default,
skip_serializing_if = "Option::is_none",
deserialize_with = "single_string_to_option_vec"
)]
pub dev: Option<Cow<'a, [Cow<'a, str>]>>,
}
impl Default for FlowTable<'_> {
fn default() -> Self {
FlowTable {
family: DEFAULT_FAMILY,
table: DEFAULT_TABLE.into(),
name: "myflowtable".into(),
handle: None,
hook: None,
prio: None,
dev: None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Counter<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub packets: Option<u32>,
pub bytes: Option<u32>,
}
impl Default for Counter<'_> {
fn default() -> Self {
Counter {
family: DEFAULT_FAMILY,
table: DEFAULT_TABLE.into(),
name: "mycounter".into(),
handle: None,
packets: None,
bytes: None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Quota<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bytes: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub used: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub inv: Option<bool>,
}
impl Default for Quota<'_> {
fn default() -> Self {
Quota {
family: DEFAULT_FAMILY,
table: DEFAULT_TABLE.into(),
name: "myquota".into(),
handle: None,
bytes: None,
used: None,
inv: None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "ct helper")]
pub struct CTHelper<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
#[serde(rename = "type")]
pub _type: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub protocol: Option<Cow<'a, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub l3proto: Option<Cow<'a, str>>,
}
impl Default for CTHelper<'_> {
fn default() -> Self {
CTHelper {
family: DEFAULT_FAMILY,
table: DEFAULT_TABLE.into(),
name: "mycthelper".into(),
handle: None,
_type: "ftp".into(),
protocol: None,
l3proto: None,
}
}
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Limit<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub rate: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub per: Option<NfTimeUnit>,
#[serde(skip_serializing_if = "Option::is_none")]
pub burst: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub unit: Option<LimitUnit>,
pub inv: Option<bool>,
}
impl Default for Limit<'_> {
fn default() -> Self {
Limit {
family: DEFAULT_FAMILY,
table: DEFAULT_TABLE.into(),
name: "mylimit".into(),
handle: None,
rate: None,
per: None,
burst: None,
unit: None,
inv: None,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum LimitUnit {
Packets,
Bytes,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Meter<'a> {
pub name: Cow<'a, str>,
pub key: Expression<'a>,
pub stmt: Box<Statement<'a>>,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct Ruleset {}
impl Default for Ruleset {
fn default() -> Self {
Ruleset {}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct MetainfoObject<'a> {
#[serde(skip_serializing_if = "Option::is_none")]
pub version: Option<Cow<'a, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub release_name: Option<Cow<'a, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub json_schema_version: Option<u32>,
}
impl Default for MetainfoObject<'_> {
fn default() -> Self {
MetainfoObject {
version: None,
release_name: None,
json_schema_version: None,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct CTTimeout<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub protocol: Option<CTHProto>,
#[serde(skip_serializing_if = "Option::is_none")]
pub state: Option<Cow<'a, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub value: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub l3proto: Option<Cow<'a, str>>,
}
impl Default for CTTimeout<'_> {
fn default() -> Self {
CTTimeout {
family: DEFAULT_FAMILY,
table: DEFAULT_TABLE.into(),
name: "mycttimeout".into(),
handle: None,
protocol: None,
state: None,
value: None,
l3proto: None,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct CTExpectation<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub l3proto: Option<Cow<'a, str>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub protocol: Option<CTHProto>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dport: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub timeout: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub size: Option<u32>,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct SynProxy<'a> {
pub family: NfFamily,
pub table: Cow<'a, str>,
pub name: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub handle: Option<u32>,
#[serde(skip_serializing_if = "Option::is_none")]
pub mss: Option<u16>,
#[serde(skip_serializing_if = "Option::is_none")]
pub wscale: Option<u8>,
#[serde(
skip_serializing_if = "Option::is_none",
deserialize_with = "deserialize_optional_flags",
default
)]
pub flags: Option<HashSet<SynProxyFlag>>,
}