use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::{borrow::Cow, collections::HashSet};
use crate::stmt::{Counter, JumpTarget, Statement};
use crate::visitor::deserialize_flags;
use strum_macros::EnumString;
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
pub enum Expression<'a> {
String(Cow<'a, str>),
Number(u32),
Boolean(bool),
List(Vec<Expression<'a>>),
BinaryOperation(Box<BinaryOperation<'a>>),
Range(Box<Range<'a>>),
Named(NamedExpression<'a>),
Verdict(Verdict<'a>),
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum NamedExpression<'a> {
Concat(Vec<Expression<'a>>),
Set(Vec<SetItem<'a>>),
Map(Box<Map<'a>>),
Prefix(Prefix<'a>),
Payload(Payload<'a>),
Exthdr(Exthdr<'a>),
#[serde(rename = "tcp option")]
TcpOption(TcpOption<'a>),
#[serde(rename = "sctp chunk")]
SctpChunk(SctpChunk<'a>),
Meta(Meta),
RT(RT),
CT(CT<'a>),
Numgen(Numgen),
JHash(JHash<'a>),
SymHash(SymHash),
Fib(Fib),
Elem(Elem<'a>),
Socket(Socket<'a>),
Osf(Osf<'a>),
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "map")]
pub struct Map<'a> {
pub key: Expression<'a>,
pub data: Expression<'a>,
}
impl Default for Map<'_> {
fn default() -> Self {
Map {
key: Expression::Boolean(true),
data: Expression::Boolean(false),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
pub enum SetItem<'a> {
Element(Expression<'a>),
Mapping(Expression<'a>, Expression<'a>),
MappingStatement(Expression<'a>, Statement<'a>),
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "prefix")]
pub struct Prefix<'a> {
pub addr: Box<Expression<'a>>,
pub len: u32,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "range")]
pub struct Range<'a> {
pub range: [Expression<'a>; 2],
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(untagged)]
pub enum Payload<'a> {
PayloadField(PayloadField<'a>),
PayloadRaw(PayloadRaw),
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct PayloadRaw {
pub base: PayloadBase,
pub offset: u32,
pub len: u32,
}
impl Default for PayloadRaw {
fn default() -> Self {
PayloadRaw {
base: PayloadBase::LL,
offset: 0,
len: 0,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub struct PayloadField<'a> {
pub protocol: Cow<'a, str>,
pub field: Cow<'a, str>,
}
impl Default for PayloadField<'_> {
fn default() -> Self {
PayloadField {
protocol: "arp".into(),
field: "ptype".into(),
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum PayloadBase {
LL,
NH,
TH,
IH,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "exthdr")]
pub struct Exthdr<'a> {
pub name: Cow<'a, str>,
pub field: Option<Cow<'a, str>>,
pub offset: Option<u32>,
}
impl Default for Exthdr<'_> {
fn default() -> Self {
Exthdr {
name: "frag".into(),
field: None,
offset: None,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "tcp option")]
pub struct TcpOption<'a> {
pub name: Cow<'a, str>,
pub field: Option<Cow<'a, str>>,
}
impl Default for TcpOption<'_> {
fn default() -> Self {
TcpOption {
name: "maxseg".into(),
field: None,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "sctp chunk")]
pub struct SctpChunk<'a> {
pub name: Cow<'a, str>,
pub field: Cow<'a, str>,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "meta")]
pub struct Meta {
pub key: MetaKey,
}
impl Default for Meta {
fn default() -> Self {
Meta {
key: MetaKey::L4proto,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum MetaKey {
Pkttype,
Length,
Protocol,
Nfproto,
L4proto,
Iif,
Iifname,
Iiftype,
Iifkind,
Iifgroup,
Oif,
Oifname,
Oiftype,
Oifkind,
Oifgroup,
Ibridgename,
Obridgename,
Ibriport,
Obriport,
Mark,
Priority,
Rtclassid,
Skuid,
Skgid,
Cpu,
Cgroup,
Secpath,
Random,
Nftrace,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "rt")]
pub struct RT {
pub key: RTKey,
#[serde(skip_serializing_if = "Option::is_none")]
pub family: Option<RTFamily>,
}
impl Default for RT {
fn default() -> Self {
RT {
key: RTKey::NextHop,
family: None,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum RTKey {
ClassId,
NextHop,
MTU,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum RTFamily {
IP,
IP6,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "ct")]
pub struct CT<'a> {
pub key: Cow<'a, str>,
#[serde(skip_serializing_if = "Option::is_none")]
pub family: Option<CTFamily>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dir: Option<CTDir>,
}
impl Default for CT<'_> {
fn default() -> Self {
CT {
key: "l3proto".into(),
family: None,
dir: None,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum CTFamily {
IP,
IP6,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum CTDir {
Original,
Reply,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "numgen")]
pub struct Numgen {
pub mode: NgMode,
#[serde(rename = "mod")]
pub ng_mod: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub offset: Option<u32>,
}
impl Default for Numgen {
fn default() -> Self {
Numgen {
mode: NgMode::Inc,
ng_mod: 7,
offset: None,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum NgMode {
Inc,
Random,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "jhash")]
pub struct JHash<'a> {
#[serde(rename = "mod")]
pub hash_mod: u32,
#[serde(skip_serializing_if = "Option::is_none")]
pub offset: Option<u32>,
pub expr: Box<Expression<'a>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub seed: Option<u32>,
}
impl Default for JHash<'_> {
fn default() -> Self {
JHash {
hash_mod: 7,
offset: None,
expr: Box::new(Expression::Named(NamedExpression::Payload(
Payload::PayloadField(PayloadField {
protocol: "ip".into(),
field: "saddr".into(),
}),
))),
seed: None,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "symhash")]
pub struct SymHash {
#[serde(rename = "mod")]
pub hash_mod: u32,
pub offset: Option<u32>,
}
impl Default for SymHash {
fn default() -> Self {
SymHash {
hash_mod: 2,
offset: None,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "fib")]
pub struct Fib {
pub result: FibResult,
#[serde(deserialize_with = "deserialize_flags")]
pub flags: HashSet<FibFlag>,
}
impl Default for Fib {
fn default() -> Self {
let mut flags = HashSet::with_capacity(1);
flags.insert(FibFlag::Iif);
Fib {
result: FibResult::Oif,
flags,
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum FibResult {
Oif,
Oifname,
Type,
}
#[derive(
Debug, Clone, Copy, Eq, PartialEq, Serialize, Deserialize, EnumString, Hash, JsonSchema,
)]
#[serde(rename_all = "lowercase")]
#[strum(serialize_all = "lowercase")]
pub enum FibFlag {
Saddr,
Daddr,
Mark,
Iif,
Oif,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
pub enum BinaryOperation<'a> {
#[serde(rename = "&")]
AND(Expression<'a>, Expression<'a>),
#[serde(rename = "|")]
OR(Vec<Expression<'a>>),
#[serde(rename = "^")]
XOR(Expression<'a>, Expression<'a>),
#[serde(rename = "<<")]
LSHIFT(Expression<'a>, Expression<'a>),
#[serde(rename = ">>")]
RSHIFT(Expression<'a>, Expression<'a>),
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum Verdict<'a> {
Accept,
Drop,
Continue,
Return,
Jump(JumpTarget<'a>),
Goto(JumpTarget<'a>),
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "elem")]
pub struct Elem<'a> {
pub val: Box<Expression<'a>>,
pub timeout: Option<u32>,
pub expires: Option<u32>,
pub comment: Option<Cow<'a, str>>,
pub counter: Option<Counter<'a>>,
}
impl Default for Elem<'_> {
fn default() -> Self {
Elem {
val: Box::new(Expression::String("10.2.3.4".into())),
timeout: None,
expires: None,
comment: None,
counter: None,
}
}
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "socket")]
pub struct Socket<'a> {
pub key: Cow<'a, SocketAttr>,
}
impl Default for Socket<'_> {
fn default() -> Self {
Socket {
key: Cow::Borrowed(&SocketAttr::Wildcard),
}
}
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum SocketAttr {
Transparent,
Mark,
Wildcard,
Cgroupv2,
}
#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
#[serde(rename = "osf")]
pub struct Osf<'a> {
pub key: Cow<'a, str>,
pub ttl: OsfTtl,
}
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize, JsonSchema)]
#[serde(rename_all = "lowercase")]
pub enum OsfTtl {
Loose,
Skip,
}