use std::net::Ipv4Addr;
use libc::NF_DROP;
use crate::{
expr::{
Bitwise, Cmp, CmpOp, Conntrack, ConntrackKey, Counter, ExpressionList, HeaderField,
HighLevelPayload, IcmpCode, Immediate, Log, Lookup, Masquerade, Meta, MetaType, Nat,
NatType, Register, Reject, RejectType, TCPHeaderField, TransportHeaderField, VerdictKind,
},
set::SetBuilder,
sys::{
NFTA_BITWISE_DREG, NFTA_BITWISE_LEN, NFTA_BITWISE_MASK, NFTA_BITWISE_SREG,
NFTA_BITWISE_XOR, NFTA_CMP_DATA, NFTA_CMP_OP, NFTA_CMP_SREG, NFTA_COUNTER_BYTES,
NFTA_COUNTER_PACKETS, NFTA_CT_DREG, NFTA_CT_KEY, NFTA_DATA_VALUE, NFTA_DATA_VERDICT,
NFTA_EXPR_DATA, NFTA_EXPR_NAME, NFTA_IMMEDIATE_DATA, NFTA_IMMEDIATE_DREG, NFTA_LIST_ELEM,
NFTA_LOG_GROUP, NFTA_LOG_PREFIX, NFTA_LOOKUP_SET, NFTA_LOOKUP_SREG, NFTA_META_DREG,
NFTA_META_KEY, NFTA_NAT_FAMILY, NFTA_NAT_REG_ADDR_MIN, NFTA_NAT_TYPE, NFTA_PAYLOAD_BASE,
NFTA_PAYLOAD_DREG, NFTA_PAYLOAD_LEN, NFTA_PAYLOAD_OFFSET, NFTA_REJECT_ICMP_CODE,
NFTA_REJECT_TYPE, NFTA_RULE_CHAIN, NFTA_RULE_EXPRESSIONS, NFTA_RULE_TABLE,
NFTA_VERDICT_CODE, NFT_CMP_EQ, NFT_CT_STATE, NFT_META_PROTOCOL, NFT_NAT_SNAT,
NFT_PAYLOAD_TRANSPORT_HEADER, NFT_REG_1, NFT_REG_VERDICT, NFT_REJECT_ICMPX_UNREACH,
},
tests::{get_test_table, SET_NAME},
ProtocolFamily,
};
use super::{get_test_nlmsg, get_test_rule, NetlinkExpr, CHAIN_NAME, TABLE_NAME};
#[test]
fn bitwise_expr_is_valid() {
let netmask = Ipv4Addr::new(255, 255, 255, 0);
let bitwise = Bitwise::new(netmask.octets(), [0, 0, 0, 0]).unwrap();
let mut rule = get_test_rule().with_expressions(ExpressionList::default().with_value(bitwise));
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 124);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"bitwise".to_vec()),
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
NetlinkExpr::Final(
NFTA_BITWISE_SREG,
NFT_REG_1.to_be_bytes().to_vec()
),
NetlinkExpr::Final(
NFTA_BITWISE_DREG,
NFT_REG_1.to_be_bytes().to_vec()
),
NetlinkExpr::Final(NFTA_BITWISE_LEN, 4u32.to_be_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_BITWISE_MASK,
vec![NetlinkExpr::Final(
NFTA_DATA_VALUE,
vec![255, 255, 255, 0]
)]
),
NetlinkExpr::Nested(
NFTA_BITWISE_XOR,
vec![NetlinkExpr::Final(
NFTA_DATA_VALUE,
0u32.to_be_bytes().to_vec()
)]
)
]
)
]
)]
)
])
.to_raw()
);
}
#[test]
fn cmp_expr_is_valid() {
let val = [1u8, 2, 3, 4];
let cmp = Cmp::new(CmpOp::Eq, val.clone());
let mut rule = get_test_rule().with_expressions(vec![cmp]);
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 100);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"cmp".to_vec()),
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
NetlinkExpr::Final(NFTA_CMP_SREG, NFT_REG_1.to_be_bytes().to_vec()),
NetlinkExpr::Final(NFTA_CMP_OP, NFT_CMP_EQ.to_be_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_CMP_DATA,
vec![NetlinkExpr::Final(NFTA_DATA_VALUE, val.to_vec())]
)
]
)
]
)]
)
])
.to_raw()
);
}
#[test]
fn counter_expr_is_valid() {
let nb_bytes = 123456u64;
let nb_packets = 987u64;
let counter = Counter::default()
.with_nb_bytes(nb_bytes)
.with_nb_packets(nb_packets);
let mut rule = get_test_rule().with_expressions(vec![counter]);
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 100);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"counter".to_vec()),
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
NetlinkExpr::Final(
NFTA_COUNTER_BYTES,
nb_bytes.to_be_bytes().to_vec()
),
NetlinkExpr::Final(
NFTA_COUNTER_PACKETS,
nb_packets.to_be_bytes().to_vec()
)
]
)
]
)]
)
])
.to_raw()
);
}
#[test]
fn ct_expr_is_valid() {
let ct = Conntrack::default().with_retrieve_value(ConntrackKey::State);
let mut rule = get_test_rule().with_expressions(vec![ct]);
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 88);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"ct".to_vec()),
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
NetlinkExpr::Final(
NFTA_CT_KEY,
NFT_CT_STATE.to_be_bytes().to_vec()
),
NetlinkExpr::Final(NFTA_CT_DREG, NFT_REG_1.to_be_bytes().to_vec())
]
)
]
)]
)
])
.to_raw()
)
}
#[test]
fn immediate_expr_is_valid() {
let immediate = Immediate::new_data(vec![42u8], Register::Reg1);
let mut rule =
get_test_rule().with_expressions(ExpressionList::default().with_value(immediate));
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 100);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"immediate".to_vec()),
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
NetlinkExpr::Final(
NFTA_IMMEDIATE_DREG,
NFT_REG_1.to_be_bytes().to_vec()
),
NetlinkExpr::Nested(
NFTA_IMMEDIATE_DATA,
vec![NetlinkExpr::Final(1u16, 42u8.to_be_bytes().to_vec())]
)
]
)
]
)]
)
])
.to_raw()
);
}
#[test]
fn log_expr_is_valid() {
let log = Log::new(Some(1337), Some("mockprefix")).expect("Could not build a log expression");
let mut rule = get_test_rule().with_expressions(ExpressionList::default().with_value(log));
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 96);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"log".to_vec()),
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
NetlinkExpr::Final(NFTA_LOG_GROUP, 1337u16.to_be_bytes().to_vec()),
NetlinkExpr::Final(NFTA_LOG_PREFIX, b"mockprefix".to_vec()),
]
)
]
)]
)
])
.to_raw()
);
}
#[test]
fn lookup_expr_is_valid() {
let table = get_test_table();
let mut set_builder = SetBuilder::new(SET_NAME, &table).unwrap();
let address: Ipv4Addr = [8, 8, 8, 8].into();
set_builder.add(&address);
let (set, _set_elements) = set_builder.finish();
let lookup = Lookup::new(&set).unwrap();
let mut rule = get_test_rule().with_expressions(ExpressionList::default().with_value(lookup));
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 96);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"lookup".to_vec()),
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
NetlinkExpr::Final(NFTA_LOOKUP_SET, b"mockset".to_vec()),
NetlinkExpr::Final(
NFTA_LOOKUP_SREG,
NFT_REG_1.to_be_bytes().to_vec()
),
]
)
]
)]
)
])
.to_raw()
);
}
#[test]
fn masquerade_expr_is_valid() {
let masquerade = Masquerade::default();
let mut rule = get_test_rule().with_expressions(vec![masquerade]);
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 72);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"masq".to_vec()),
NetlinkExpr::Nested(NFTA_EXPR_DATA, vec![]),
]
)]
)
])
.to_raw()
);
}
#[test]
fn meta_expr_is_valid() {
let meta = Meta::default()
.with_key(MetaType::Protocol)
.with_dreg(Register::Reg1);
let mut rule = get_test_rule().with_expressions(vec![meta]);
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 88);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"meta".to_vec()),
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
NetlinkExpr::Final(
NFTA_META_KEY,
NFT_META_PROTOCOL.to_be_bytes().to_vec()
),
NetlinkExpr::Final(
NFTA_META_DREG,
NFT_REG_1.to_be_bytes().to_vec()
)
]
)
]
)]
)
])
.to_raw()
);
}
#[test]
fn nat_expr_is_valid() {
let nat = Nat::default()
.with_nat_type(NatType::SNat)
.with_family(ProtocolFamily::Ipv4)
.with_ip_register(Register::Reg1);
let mut rule = get_test_rule().with_expressions(vec![nat]);
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 96);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"nat".to_vec()),
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
NetlinkExpr::Final(
NFTA_NAT_TYPE,
NFT_NAT_SNAT.to_be_bytes().to_vec()
),
NetlinkExpr::Final(
NFTA_NAT_FAMILY,
(ProtocolFamily::Ipv4 as u32).to_be_bytes().to_vec(),
),
NetlinkExpr::Final(
NFTA_NAT_REG_ADDR_MIN,
NFT_REG_1.to_be_bytes().to_vec()
)
]
)
]
)]
)
])
.to_raw()
);
}
#[test]
fn payload_expr_is_valid() {
let tcp_header_field = TCPHeaderField::Sport;
let transport_header_field = TransportHeaderField::Tcp(tcp_header_field);
let payload = HighLevelPayload::Transport(transport_header_field);
let mut rule = get_test_rule().with_expressions(vec![payload.build()]);
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 108);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"payload".to_vec()),
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
NetlinkExpr::Final(
NFTA_PAYLOAD_DREG,
NFT_REG_1.to_be_bytes().to_vec()
),
NetlinkExpr::Final(
NFTA_PAYLOAD_BASE,
NFT_PAYLOAD_TRANSPORT_HEADER.to_be_bytes().to_vec()
),
NetlinkExpr::Final(
NFTA_PAYLOAD_OFFSET,
tcp_header_field.offset().to_be_bytes().to_vec()
),
NetlinkExpr::Final(
NFTA_PAYLOAD_LEN,
tcp_header_field.len().to_be_bytes().to_vec()
),
]
)
]
)]
)
])
.to_raw()
);
}
#[test]
fn reject_expr_is_valid() {
let code = IcmpCode::NoRoute;
let reject = Reject::default()
.with_type(RejectType::IcmpxUnreach)
.with_icmp_code(code);
let mut rule = get_test_rule().with_expressions(vec![reject]);
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 92);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"reject".to_vec()),
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
NetlinkExpr::Final(
NFTA_REJECT_TYPE,
NFT_REJECT_ICMPX_UNREACH.to_be_bytes().to_vec()
),
NetlinkExpr::Final(
NFTA_REJECT_ICMP_CODE,
(code as u8).to_be_bytes().to_vec()
),
]
)
]
)]
)
])
.to_raw()
);
}
#[test]
fn verdict_expr_is_valid() {
let verdict = Immediate::new_verdict(VerdictKind::Drop);
let mut rule = get_test_rule().with_expressions(ExpressionList::default().with_value(verdict));
let mut buf = Vec::new();
let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg(&mut buf, &mut rule);
assert_eq!(nlmsghdr.nlmsg_len, 104);
assert_eq!(
raw_expr,
NetlinkExpr::List(vec![
NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.as_bytes().to_vec()),
NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.as_bytes().to_vec()),
NetlinkExpr::Nested(
NFTA_RULE_EXPRESSIONS,
vec![NetlinkExpr::Nested(
NFTA_LIST_ELEM,
vec![
NetlinkExpr::Final(NFTA_EXPR_NAME, b"immediate".to_vec()),
NetlinkExpr::Nested(
NFTA_EXPR_DATA,
vec![
NetlinkExpr::Final(
NFTA_IMMEDIATE_DREG,
NFT_REG_VERDICT.to_be_bytes().to_vec()
),
NetlinkExpr::Nested(
NFTA_IMMEDIATE_DATA,
vec![NetlinkExpr::Nested(
NFTA_DATA_VERDICT,
vec![NetlinkExpr::Final(
NFTA_VERDICT_CODE,
NF_DROP.to_be_bytes().to_vec()
),]
)],
),
]
)
]
)]
)
])
.to_raw()
);
}