use nftnl::{Batch, Chain, FinalizedBatch, ProtoFamily, Rule, Table, nft_expr, nftnl_sys::libc};
use std::{ffi::CStr, io};
const TABLE_NAME: &CStr = c"example-filter-ethernet";
const OUT_CHAIN_NAME: &CStr = c"chain-for-outgoing-packets";
const BLOCK_THIS_MAC: &[u8] = &[0, 0, 0, 0, 0, 0];
fn main() -> io::Result<()> {
let mut batch = Batch::new();
let table = Table::new(TABLE_NAME, ProtoFamily::Inet);
batch.add(&table, nftnl::MsgType::Add);
let mut out_chain = Chain::new(OUT_CHAIN_NAME, &table);
out_chain.set_hook(nftnl::Hook::Out, 3);
out_chain.set_policy(nftnl::Policy::Accept);
batch.add(&out_chain, nftnl::MsgType::Add);
let mut block_ethernet_rule = Rule::new(&out_chain);
block_ethernet_rule.add_expr(&nft_expr!(meta iiftype));
block_ethernet_rule.add_expr(&nft_expr!(cmp == libc::ARPHRD_ETHER));
block_ethernet_rule.add_expr(&nft_expr!(payload ethernet daddr));
block_ethernet_rule.add_expr(&nft_expr!(cmp == BLOCK_THIS_MAC));
block_ethernet_rule.add_expr(&nft_expr!(verdict drop));
batch.add(&block_ethernet_rule, nftnl::MsgType::Add);
let mut random_rule = Rule::new(&out_chain);
random_rule.add_expr(&nft_expr!(counter));
random_rule.add_expr(&nft_expr!(meta random));
random_rule.add_expr(&nft_expr!(cmp > (u32::MAX / 2).to_be()));
random_rule.add_expr(&nft_expr!(counter));
batch.add(&random_rule, nftnl::MsgType::Add);
let finalized_batch = batch.finalize();
send_and_process(&finalized_batch)?;
Ok(())
}
fn send_and_process(batch: &FinalizedBatch) -> io::Result<()> {
let socket = mnl::Socket::new(mnl::Bus::Netfilter)?;
let portid = socket.portid();
socket.send_all(batch)?;
let mut buffer = vec![0; nftnl::nft_nlmsg_maxsize() as usize];
let mut expected_seqs = batch.sequence_numbers();
while !expected_seqs.is_empty() {
for message in socket.recv(&mut buffer[..])? {
let message = message?;
let expected_seq = expected_seqs.next().expect("Unexpected ACK");
mnl::cb_run(message, expected_seq, portid)?;
}
}
Ok(())
}