///! Adds a table, chain and a rule that blocks all traffic to a given MAC address ///! ///! Run the following to print out current active tables, chains and rules in netfilter. Must be ///! executed as root: ///! ```bash ///! # nft list ruleset ///! ``` ///! After running this example, the output should be the following: ///! ```ignore ///! table inet example-filter-ethernet { ///! chain chain-for-outgoing-packets { ///! type filter hook output priority 3; policy accept; ///! ether daddr 00:00:00:00:00:00 drop ///! counter packets 0 bytes 0 meta random > 2147483647 counter packets 0 bytes 0 ///! } ///! } ///! ``` ///! ///! ///! Everything created by this example can be removed by running ///! ```bash ///! # nft delete table inet example-filter-ethernet ///! ``` //use rustables::{nft_expr, query::send_batch, sys::libc, Batch, Chain, ProtoFamily, Rule, Table}; use std::{ffi::CString, rc::Rc}; // //const TABLE_NAME: &str = "example-filter-ethernet"; //const OUT_CHAIN_NAME: &str = "chain-for-outgoing-packets"; // //const BLOCK_THIS_MAC: &[u8] = &[0, 0, 0, 0, 0, 0]; // fn main() { // // For verbose explanations of what all these lines up until the rule creation does, see the // // `add-rules` example. // let mut batch = Batch::new(); // let table = Rc::new(Table::new( // &CString::new(TABLE_NAME).unwrap(), // ProtoFamily::Inet, // )); // batch.add(&Rc::clone(&table), rustables::MsgType::Add); // // let mut out_chain = Chain::new(&CString::new(OUT_CHAIN_NAME).unwrap(), Rc::clone(&table)); // out_chain.set_hook(rustables::Hook::Out, 3); // out_chain.set_policy(rustables::Policy::Accept); // let out_chain = Rc::new(out_chain); // batch.add(&Rc::clone(&out_chain), rustables::MsgType::Add); // // // === ADD RULE DROPPING ALL TRAFFIC TO THE MAC ADDRESS IN `BLOCK_THIS_MAC` === // // let mut block_ethernet_rule = Rule::new(Rc::clone(&out_chain)); // // // Check that the interface type is an ethernet interface. Must be done before we can check // // payload values in the ethernet header. // block_ethernet_rule.add_expr(&nft_expr!(meta iiftype)); // block_ethernet_rule.add_expr(&nft_expr!(cmp == libc::ARPHRD_ETHER)); // // // Compare the ethernet destination address against the MAC address we want to drop // block_ethernet_rule.add_expr(&nft_expr!(payload ethernet daddr)); // block_ethernet_rule.add_expr(&nft_expr!(cmp == BLOCK_THIS_MAC)); // // // Drop the matching packets. // block_ethernet_rule.add_expr(&nft_expr!(verdict drop)); // // batch.add(&block_ethernet_rule, rustables::MsgType::Add); // // // === FOR FUN, ADD A PACKET THAT MATCHES 50% OF ALL PACKETS === // // // This packet has a counter before and after the check that has 50% chance of matching. // // So after a number of packets has passed through this rule, the first counter should have a // // value approximately double that of the second counter. This rule has no verdict, so it never // // does anything with the matching packets. // let mut random_rule = Rule::new(Rc::clone(&out_chain)); // // This counter expression will be evaluated (and increment the counter) for all packets coming // // through. // random_rule.add_expr(&nft_expr!(counter)); // // // Load a pseudo-random 32 bit unsigned integer into the netfilter register. // random_rule.add_expr(&nft_expr!(meta random)); // // Check if the random integer is larger than `u32::MAX/2`, thus having 50% chance of success. // random_rule.add_expr(&nft_expr!(cmp > (::std::u32::MAX / 2).to_be())); // // // Add a second counter. This will only be incremented for the packets passing the random check. // random_rule.add_expr(&nft_expr!(counter)); // // batch.add(&random_rule, rustables::MsgType::Add); // // // === FINALIZE THE TRANSACTION AND SEND THE DATA TO NETFILTER === // // match batch.finalize() { // Some(mut finalized_batch) => { // send_batch(&mut finalized_batch).expect("Couldn't process the batch"); // } // None => todo!(), // } }