aboutsummaryrefslogtreecommitdiff
path: root/rustables
diff options
context:
space:
mode:
Diffstat (limited to 'rustables')
-rw-r--r--rustables/Cargo.toml32
-rw-r--r--rustables/build.rs160
-rw-r--r--rustables/examples/add-rules.rs248
-rw-r--r--rustables/examples/filter-ethernet.rs133
-rw-r--r--rustables/src/batch.rs200
-rw-r--r--rustables/src/chain.rs292
-rw-r--r--rustables/src/expr/bitwise.rs69
-rw-r--r--rustables/src/expr/cmp.rs220
-rw-r--r--rustables/src/expr/counter.rs46
-rw-r--r--rustables/src/expr/ct.rs87
-rw-r--r--rustables/src/expr/immediate.rs126
-rw-r--r--rustables/src/expr/log.rs112
-rw-r--r--rustables/src/expr/lookup.rs79
-rw-r--r--rustables/src/expr/masquerade.rs24
-rw-r--r--rustables/src/expr/meta.rs175
-rw-r--r--rustables/src/expr/mod.rs242
-rw-r--r--rustables/src/expr/nat.rs99
-rw-r--r--rustables/src/expr/payload.rs531
-rw-r--r--rustables/src/expr/register.rs34
-rw-r--r--rustables/src/expr/reject.rs96
-rw-r--r--rustables/src/expr/verdict.rs148
-rw-r--r--rustables/src/expr/wrapper.rs60
-rw-r--r--rustables/src/lib.rs205
-rw-r--r--rustables/src/query.rs130
-rw-r--r--rustables/src/rule.rs341
-rw-r--r--rustables/src/set.rs273
-rw-r--r--rustables/src/table.rs171
-rw-r--r--rustables/tests/expr.rs700
-rw-r--r--rustables/tests_wrapper.h1
-rw-r--r--rustables/wrapper.h12
30 files changed, 0 insertions, 5046 deletions
diff --git a/rustables/Cargo.toml b/rustables/Cargo.toml
deleted file mode 100644
index 5ac819b..0000000
--- a/rustables/Cargo.toml
+++ /dev/null
@@ -1,32 +0,0 @@
-[package]
-name = "rustables"
-version = "0.7.0"
-authors = ["lafleur@boum.org, Simon Thoby, Mullvad VPN"]
-license = "GPL-3.0-or-later"
-description = "Safe abstraction for libnftnl. Provides low-level userspace access to the in-kernel nf_tables subsystem"
-repository = "https://gitlab.com/rustwall/rustables"
-readme = "../README.md"
-keywords = ["nftables", "nft", "firewall", "iptables", "netfilter"]
-categories = ["network-programming", "os::unix-apis", "api-bindings"]
-edition = "2018"
-
-[features]
-query = []
-unsafe-raw-handles = []
-
-[dependencies]
-bitflags = "1.0"
-thiserror = "1.0"
-log = "0.4"
-libc = "0.2.43"
-mnl = "0.2"
-
-[dev-dependencies]
-ipnetwork = "0.16"
-
-[build-dependencies]
-bindgen = "0.53.1"
-pkg-config = "0.3"
-regex = "1.5.4"
-lazy_static = "1.4.0"
-
diff --git a/rustables/build.rs b/rustables/build.rs
deleted file mode 100644
index 180e06b..0000000
--- a/rustables/build.rs
+++ /dev/null
@@ -1,160 +0,0 @@
-use bindgen;
-use lazy_static::lazy_static;
-use regex::{Captures, Regex};
-use pkg_config;
-use std::env;
-use std::fs::File;
-use std::io::Write;
-use std::path::PathBuf;
-use std::borrow::Cow;
-
-
-const SYS_HEADER_FILE: &str = "wrapper.h";
-const SYS_BINDINGS_FILE: &str = "src/sys.rs";
-const TESTS_HEADER_FILE: &str = "tests_wrapper.h";
-const TESTS_BINDINGS_FILE: &str = "tests/sys.rs";
-const MIN_LIBNFTNL_VERSION: &str = "1.0.6";
-
-
-fn get_env(var: &'static str) -> Option<PathBuf> {
- println!("cargo:rerun-if-env-changed={}", var);
- env::var_os(var).map(PathBuf::from)
-}
-
-/// Set env vars to help rustc find linked libraries.
-fn setup_libs() {
- if let Some(lib_dir) = get_env("LIBNFTNL_LIB_DIR") {
- if !lib_dir.is_dir() {
- panic!(
- "libnftnl library directory does not exist: {}",
- lib_dir.display()
- );
- }
- println!("cargo:rustc-link-search=native={}", lib_dir.display());
- println!("cargo:rustc-link-lib=nftnl");
- } else {
- // Trying with pkg-config instead
- println!("Minimum libnftnl version: {}", MIN_LIBNFTNL_VERSION);
- pkg_config::Config::new()
- .atleast_version(MIN_LIBNFTNL_VERSION)
- .probe("libnftnl")
- .unwrap();
- }
-
- if let Some(lib_dir) = get_env("LIBMNL_LIB_DIR") {
- if !lib_dir.is_dir() {
- panic!(
- "libmnl library directory does not exist: {}",
- lib_dir.display()
- );
- }
- println!("cargo:rustc-link-search=native={}", lib_dir.display());
- println!("cargo:rustc-link-lib=mnl");
- } else {
- // Trying with pkg-config instead
- pkg_config::Config::new()
- .atleast_version("1.0.0")
- .probe("libmnl")
- .unwrap();
- }
-}
-
-/// Recast nft_*_attributes from u32 to u16 in header file `before`.
-fn reformat_units(before: &str) -> Cow<str> {
- lazy_static! {
- static ref RE: Regex = Regex::new(r"(pub type nft[a-zA-Z_]*_attributes) = u32;").unwrap();
- }
- RE.replace_all(before, |captures: &Captures| {
- format!("{} = u16;", &captures[1])
- })
-}
-
-fn generate_consts() {
- // Tell cargo to invalidate the built crate whenever the headers change.
- println!("cargo:rerun-if-changed={}", SYS_HEADER_FILE);
-
- let bindings = bindgen::Builder::default()
- .header(SYS_HEADER_FILE)
- .generate_comments(false)
- .prepend_enum_name(false)
- .use_core()
- .whitelist_function("^nftnl_.+$")
- .whitelist_type("^nftnl_.+$")
- .whitelist_var("^nftnl_.+$")
- .whitelist_var("^NFTNL_.+$")
- .blacklist_type("(FILE|iovec)")
- .blacklist_type("^_IO_.+$")
- .blacklist_type("^__.+$")
- .blacklist_type("nlmsghdr")
- .raw_line("#![allow(non_camel_case_types)]\n\n")
- .raw_line("pub use libc;")
- .raw_line("use libc::{c_char, c_int, c_ulong, c_void, iovec, nlmsghdr, FILE};")
- .raw_line("use core::option::Option;")
- .ctypes_prefix("libc")
- // Tell cargo to invalidate the built crate whenever any of the
- // included header files changed.
- .parse_callbacks(Box::new(bindgen::CargoCallbacks))
- // Finish the builder and generate the bindings.
- .generate()
- // Unwrap the Result and panic on failure.
- .expect("Error: unable to generate bindings");
-
- let mut s = bindings.to_string()
- // Add newlines because in alpine bindgen doesn't add them after
- // statements.
- .replace(" ; ", ";\n")
- .replace("#[derive(Debug, Copy, Clone)]", "");
- let re = Regex::new(r"libc::(c_[a-z]*)").unwrap();
- s = re.replace_all(&s, "$1").into();
- let re = Regex::new(r"::core::option::(Option)").unwrap();
- s = re.replace_all(&s, "$1").into();
- let re = Regex::new(r"_bindgen_ty_[0-9]+").unwrap();
- s = re.replace_all(&s, "u32").into();
- // Change struct bodies to c_void.
- let re = Regex::new(r"(pub struct .*) \{\n *_unused: \[u8; 0\],\n\}\n").unwrap();
- s = re.replace_all(&s, "$1(c_void);\n").into();
- let re = Regex::new(r"pub type u32 = u32;\n").unwrap();
- s = re.replace_all(&s, "").into();
-
- // Write the bindings to the rust header file.
- let out_path = PathBuf::from(SYS_BINDINGS_FILE);
- File::create(out_path)
- .expect("Error: could not create rust header file.")
- .write_all(&s.as_bytes())
- .expect("Error: could not write to the rust header file.");
-}
-
-fn generate_test_consts() {
- // Tell cargo to invalidate the built crate whenever the headers change.
- println!("cargo:rerun-if-changed={}", TESTS_HEADER_FILE);
-
- let bindings = bindgen::Builder::default()
- .header(TESTS_HEADER_FILE)
- .generate_comments(false)
- .prepend_enum_name(false)
- .raw_line("#![allow(non_camel_case_types, dead_code)]\n\n")
- // Tell cargo to invalidate the built crate whenever any of the
- // included header files changed.
- .parse_callbacks(Box::new(bindgen::CargoCallbacks))
- // Finish the builder and generate the bindings.
- .generate()
- // Unwrap the Result and panic on failure.
- .expect("Error: unable to generate bindings needed for tests.");
-
- // Add newlines because in alpine bindgen doesn't add them after statements.
- let s = bindings.to_string().replace(" ; ", ";\n");
- let s = reformat_units(&s);
-
- // Write the bindings to the rust header file.
- let out_path = PathBuf::from(TESTS_BINDINGS_FILE);
- File::create(out_path)
- .expect("Error: could not create rust header file.")
- .write_all(&s.as_bytes())
- .expect("Error: could not write to the rust header file.");
-}
-
-fn main() {
- setup_libs();
- generate_consts();
- generate_test_consts();
-}
diff --git a/rustables/examples/add-rules.rs b/rustables/examples/add-rules.rs
deleted file mode 100644
index 3aae7ee..0000000
--- a/rustables/examples/add-rules.rs
+++ /dev/null
@@ -1,248 +0,0 @@
-//! Adds a table, two chains and some rules to netfilter.
-//!
-//! This example uses `verdict accept` everywhere. So even after running this the firewall won't
-//! block anything. This is so anyone trying to run this does not end up in a strange state
-//! where they don't understand why their network is broken. Try changing to `verdict drop` if
-//! you want to see the block working.
-//!
-//! 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-table {
-//! chain chain-for-outgoing-packets {
-//! type filter hook output priority 0; policy accept;
-//! ip daddr 10.1.0.0/24 counter packets 0 bytes 0 accept
-//! }
-//!
-//! chain chain-for-incoming-packets {
-//! type filter hook input priority 0; policy accept;
-//! iif "lo" accept
-//! }
-//! }
-//! ```
-//!
-//! Try pinging any IP in the network range denoted by the outgoing rule and see the counter
-//! increment:
-//! ```bash
-//! $ ping 10.1.0.7
-//! ```
-//!
-//! Everything created by this example can be removed by running
-//! ```bash
-//! # nft delete table inet example-table
-//! ```
-
-use ipnetwork::{IpNetwork, Ipv4Network};
-use rustables::{nft_expr, sys::libc, Batch, Chain, FinalizedBatch, ProtoFamily, Rule, Table};
-use std::{
- ffi::{self, CString},
- io,
- net::Ipv4Addr,
- rc::Rc
-};
-
-const TABLE_NAME: &str = "example-table";
-const OUT_CHAIN_NAME: &str = "chain-for-outgoing-packets";
-const IN_CHAIN_NAME: &str = "chain-for-incoming-packets";
-
-fn main() -> Result<(), Error> {
- // Create a batch. This is used to store all the netlink messages we will later send.
- // Creating a new batch also automatically writes the initial batch begin message needed
- // to tell netlink this is a single transaction that might arrive over multiple netlink packets.
- let mut batch = Batch::new();
-
- // Create a netfilter table operating on both IPv4 and IPv6 (ProtoFamily::Inet)
- let table = Rc::new(Table::new(&CString::new(TABLE_NAME).unwrap(), ProtoFamily::Inet));
- // Add the table to the batch with the `MsgType::Add` type, thus instructing netfilter to add
- // this table under its `ProtoFamily::Inet` ruleset.
- batch.add(&Rc::clone(&table), rustables::MsgType::Add);
-
- // Create input and output chains under the table we created above.
- // Hook the chains to the input and output event hooks, with highest priority (priority zero).
- // See the `Chain::set_hook` documentation for details.
- let mut out_chain = Chain::new(&CString::new(OUT_CHAIN_NAME).unwrap(), Rc::clone(&table));
- let mut in_chain = Chain::new(&CString::new(IN_CHAIN_NAME).unwrap(), Rc::clone(&table));
-
- out_chain.set_hook(rustables::Hook::Out, 0);
- in_chain.set_hook(rustables::Hook::In, 0);
-
- // Set the default policies on the chains. If no rule matches a packet processed by the
- // `out_chain` or the `in_chain` it will accept the packet.
- out_chain.set_policy(rustables::Policy::Accept);
- in_chain.set_policy(rustables::Policy::Accept);
-
- let out_chain = Rc::new(out_chain);
- let in_chain = Rc::new(in_chain);
-
- // Add the two chains to the batch with the `MsgType` to tell netfilter to create the chains
- // under the table.
- batch.add(&Rc::clone(&out_chain), rustables::MsgType::Add);
- batch.add(&Rc::clone(&in_chain), rustables::MsgType::Add);
-
- // === ADD RULE ALLOWING ALL TRAFFIC TO THE LOOPBACK DEVICE ===
-
- // Create a new rule object under the input chain.
- let mut allow_loopback_in_rule = Rule::new(Rc::clone(&in_chain));
- // Lookup the interface index of the loopback interface.
- let lo_iface_index = iface_index("lo")?;
-
- // First expression to be evaluated in this rule is load the meta information "iif"
- // (incoming interface index) into the comparison register of netfilter.
- // When an incoming network packet is processed by this rule it will first be processed by this
- // expression, which will load the interface index of the interface the packet came from into
- // a special "register" in netfilter.
- allow_loopback_in_rule.add_expr(&nft_expr!(meta iif));
- // Next expression in the rule is to compare the value loaded into the register with our desired
- // interface index, and succeed only if it's equal. For any packet processed where the equality
- // does not hold the packet is said to not match this rule, and the packet moves on to be
- // processed by the next rule in the chain instead.
- allow_loopback_in_rule.add_expr(&nft_expr!(cmp == lo_iface_index));
-
- // Add a verdict expression to the rule. Any packet getting this far in the expression
- // processing without failing any expression will be given the verdict added here.
- allow_loopback_in_rule.add_expr(&nft_expr!(verdict accept));
-
- // Add the rule to the batch.
- batch.add(&allow_loopback_in_rule, rustables::MsgType::Add);
-
- // === ADD A RULE ALLOWING (AND COUNTING) ALL PACKETS TO THE 10.1.0.0/24 NETWORK ===
-
- let mut block_out_to_private_net_rule = Rule::new(Rc::clone(&out_chain));
- let private_net_ip = Ipv4Addr::new(10, 1, 0, 0);
- let private_net_prefix = 24;
- let private_net = IpNetwork::V4(Ipv4Network::new(private_net_ip, private_net_prefix)?);
-
- // Load the `nfproto` metadata into the netfilter register. This metadata denotes which layer3
- // protocol the packet being processed is using.
- block_out_to_private_net_rule.add_expr(&nft_expr!(meta nfproto));
- // Check if the currently processed packet is an IPv4 packet. This must be done before payload
- // data assuming the packet uses IPv4 can be loaded in the next expression.
- block_out_to_private_net_rule.add_expr(&nft_expr!(cmp == libc::NFPROTO_IPV4 as u8));
-
- // Load the IPv4 destination address into the netfilter register.
- block_out_to_private_net_rule.add_expr(&nft_expr!(payload ipv4 daddr));
- // Mask out the part of the destination address that is not part of the network bits. The result
- // of this bitwise masking is stored back into the same netfilter register.
- block_out_to_private_net_rule.add_expr(&nft_expr!(bitwise mask private_net.mask(), xor 0));
- // Compare the result of the masking with the IP of the network we are interested in.
- block_out_to_private_net_rule.add_expr(&nft_expr!(cmp == private_net.ip()));
-
- // Add a packet counter to the rule. Shows how many packets have been evaluated against this
- // expression. Since expressions are evaluated from first to last, putting this counter before
- // the above IP net check would make the counter increment on all packets also *not* matching
- // those expressions. Because the counter would then be evaluated before it fails a check.
- // Similarly, if the counter was added after the verdict it would always remain at zero. Since
- // when the packet hits the verdict expression any further processing of expressions stop.
- block_out_to_private_net_rule.add_expr(&nft_expr!(counter));
-
- // Accept all the packets matching the rule so far.
- block_out_to_private_net_rule.add_expr(&nft_expr!(verdict accept));
-
- // Add the rule to the batch. Without this nothing would be sent over netlink and netfilter,
- // and all the work on `block_out_to_private_net_rule` so far would go to waste.
- batch.add(&block_out_to_private_net_rule, rustables::MsgType::Add);
-
- // === ADD A RULE ALLOWING ALL OUTGOING ICMPv6 PACKETS WITH TYPE 133 AND CODE 0 ===
-
- let mut allow_router_solicitation = Rule::new(Rc::clone(&out_chain));
-
- // Check that the packet is IPv6 and ICMPv6
- allow_router_solicitation.add_expr(&nft_expr!(meta nfproto));
- allow_router_solicitation.add_expr(&nft_expr!(cmp == libc::NFPROTO_IPV6 as u8));
- allow_router_solicitation.add_expr(&nft_expr!(meta l4proto));
- allow_router_solicitation.add_expr(&nft_expr!(cmp == libc::IPPROTO_ICMPV6 as u8));
-
- allow_router_solicitation.add_expr(&rustables::expr::Payload::Transport(
- rustables::expr::TransportHeaderField::Icmpv6(rustables::expr::Icmpv6HeaderField::Type),
- ));
- allow_router_solicitation.add_expr(&nft_expr!(cmp == 133u8));
- allow_router_solicitation.add_expr(&rustables::expr::Payload::Transport(
- rustables::expr::TransportHeaderField::Icmpv6(rustables::expr::Icmpv6HeaderField::Code),
- ));
- allow_router_solicitation.add_expr(&nft_expr!(cmp == 0u8));
-
- allow_router_solicitation.add_expr(&nft_expr!(verdict accept));
-
- batch.add(&allow_router_solicitation, rustables::MsgType::Add);
-
- // === FINALIZE THE TRANSACTION AND SEND THE DATA TO NETFILTER ===
-
- // Finalize the batch. This means the batch end message is written into the batch, telling
- // netfilter the we reached the end of the transaction message. It's also converted to a type
- // that implements `IntoIterator<Item = &'a [u8]>`, thus allowing us to get the raw netlink data
- // out so it can be sent over a netlink socket to netfilter.
- match batch.finalize() {
- Some(mut finalized_batch) => {
- // Send the entire batch and process any returned messages.
- send_and_process(&mut finalized_batch)?;
- Ok(())
- },
- None => todo!()
- }
-}
-
-// Look up the interface index for a given interface name.
-fn iface_index(name: &str) -> Result<libc::c_uint, Error> {
- let c_name = CString::new(name)?;
- let index = unsafe { libc::if_nametoindex(c_name.as_ptr()) };
- if index == 0 {
- Err(Error::from(io::Error::last_os_error()))
- } else {
- Ok(index)
- }
-}
-
-fn send_and_process(batch: &mut FinalizedBatch) -> Result<(), Error> {
- // Create a netlink socket to netfilter.
- let socket = mnl::Socket::new(mnl::Bus::Netfilter)?;
- // Send all the bytes in the batch.
- socket.send_all(&mut *batch)?;
-
- // Try to parse the messages coming back from netfilter. This part is still very unclear.
- let portid = socket.portid();
- let mut buffer = vec![0; rustables::nft_nlmsg_maxsize() as usize];
- let very_unclear_what_this_is_for = 2;
- while let Some(message) = socket_recv(&socket, &mut buffer[..])? {
- match mnl::cb_run(message, very_unclear_what_this_is_for, portid)? {
- mnl::CbResult::Stop => {
- break;
- }
- mnl::CbResult::Ok => (),
- }
- }
- Ok(())
-}
-
-fn socket_recv<'a>(socket: &mnl::Socket, buf: &'a mut [u8]) -> Result<Option<&'a [u8]>, Error> {
- let ret = socket.recv(buf)?;
- if ret > 0 {
- Ok(Some(&buf[..ret]))
- } else {
- Ok(None)
- }
-}
-
-#[derive(Debug)]
-struct Error(String);
-
-impl From<io::Error> for Error {
- fn from(error: io::Error) -> Self {
- Error(error.to_string())
- }
-}
-
-impl From<ffi::NulError> for Error {
- fn from(error: ffi::NulError) -> Self {
- Error(error.to_string())
- }
-}
-
-impl From<ipnetwork::IpNetworkError> for Error {
- fn from(error: ipnetwork::IpNetworkError) -> Self {
- Error(error.to_string())
- }
-}
diff --git a/rustables/examples/filter-ethernet.rs b/rustables/examples/filter-ethernet.rs
deleted file mode 100644
index b16c49e..0000000
--- a/rustables/examples/filter-ethernet.rs
+++ /dev/null
@@ -1,133 +0,0 @@
-//! 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, sys::libc, Batch, Chain, FinalizedBatch, ProtoFamily, Rule, Table};
-use std::{ffi::CString, io, 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() -> Result<(), Error> {
- // 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_and_process(&mut finalized_batch)?;
- Ok(())
- },
- None => todo!()
- }
-}
-
-fn send_and_process(batch: &mut FinalizedBatch) -> Result<(), Error> {
- // Create a netlink socket to netfilter.
- let socket = mnl::Socket::new(mnl::Bus::Netfilter)?;
- // Send all the bytes in the batch.
- socket.send_all(&mut *batch)?;
-
- // Try to parse the messages coming back from netfilter. This part is still very unclear.
- let portid = socket.portid();
- let mut buffer = vec![0; rustables::nft_nlmsg_maxsize() as usize];
- let very_unclear_what_this_is_for = 2;
- while let Some(message) = socket_recv(&socket, &mut buffer[..])? {
- match mnl::cb_run(message, very_unclear_what_this_is_for, portid)? {
- mnl::CbResult::Stop => {
- break;
- }
- mnl::CbResult::Ok => (),
- }
- }
- Ok(())
-}
-
-fn socket_recv<'a>(socket: &mnl::Socket, buf: &'a mut [u8]) -> Result<Option<&'a [u8]>, Error> {
- let ret = socket.recv(buf)?;
- if ret > 0 {
- Ok(Some(&buf[..ret]))
- } else {
- Ok(None)
- }
-}
-
-#[derive(Debug)]
-struct Error(String);
-
-impl From<io::Error> for Error {
- fn from(error: io::Error) -> Self {
- Error(error.to_string())
- }
-}
diff --git a/rustables/src/batch.rs b/rustables/src/batch.rs
deleted file mode 100644
index c8ec5aa..0000000
--- a/rustables/src/batch.rs
+++ /dev/null
@@ -1,200 +0,0 @@
-use crate::{MsgType, NlMsg};
-use crate::sys::{self as sys, libc};
-use std::ffi::c_void;
-use std::os::raw::c_char;
-use std::ptr;
-use thiserror::Error;
-
-/// Error while communicating with netlink
-#[derive(Error, Debug)]
-#[error("Error while communicating with netlink")]
-pub struct NetlinkError(());
-
-#[cfg(feature = "query")]
-/// Check if the kernel supports batched netlink messages to netfilter.
-pub fn batch_is_supported() -> std::result::Result<bool, NetlinkError> {
- match unsafe { sys::nftnl_batch_is_supported() } {
- 1 => Ok(true),
- 0 => Ok(false),
- _ => Err(NetlinkError(())),
- }
-}
-
-/// A batch of netfilter messages to be performed in one atomic operation. Corresponds to
-/// `nftnl_batch` in libnftnl.
-pub struct Batch {
- pub(crate) batch: *mut sys::nftnl_batch,
- pub(crate) seq: u32,
- pub(crate) is_empty: bool,
-}
-
-impl Batch {
- /// Creates a new nftnl batch with the [default page size].
- ///
- /// [default page size]: fn.default_batch_page_size.html
- pub fn new() -> Self {
- Self::with_page_size(default_batch_page_size())
- }
-
- pub unsafe fn from_raw(batch: *mut sys::nftnl_batch, seq: u32) -> Self {
- Batch {
- batch,
- seq,
- // we assume this batch is not empty by default
- is_empty: false,
- }
- }
-
- /// Creates a new nftnl batch with the given batch size.
- pub fn with_page_size(batch_page_size: u32) -> Self {
- let batch = try_alloc!(unsafe {
- sys::nftnl_batch_alloc(batch_page_size, crate::nft_nlmsg_maxsize())
- });
- let mut this = Batch {
- batch,
- seq: 0,
- is_empty: true,
- };
- this.write_begin_msg();
- this
- }
-
- /// Adds the given message to this batch.
- pub fn add<T: NlMsg>(&mut self, msg: &T, msg_type: MsgType) {
- trace!("Writing NlMsg with seq {} to batch", self.seq);
- unsafe { msg.write(self.current(), self.seq, msg_type) };
- self.is_empty = false;
- self.next()
- }
-
- /// Adds all the messages in the given iterator to this batch. If any message fails to be added
- /// the error for that failure is returned and all messages up until that message stays added
- /// to the batch.
- pub fn add_iter<T, I>(&mut self, msg_iter: I, msg_type: MsgType)
- where
- T: NlMsg,
- I: Iterator<Item = T>,
- {
- for msg in msg_iter {
- self.add(&msg, msg_type);
- }
- }
-
- /// Adds the final end message to the batch and returns a [`FinalizedBatch`] that can be used
- /// to send the messages to netfilter.
- ///
- /// Return None if there is no object in the batch (this could block forever).
- ///
- /// [`FinalizedBatch`]: struct.FinalizedBatch.html
- pub fn finalize(mut self) -> Option<FinalizedBatch> {
- self.write_end_msg();
- if self.is_empty {
- return None;
- }
- Some(FinalizedBatch { batch: self })
- }
-
- fn current(&self) -> *mut c_void {
- unsafe { sys::nftnl_batch_buffer(self.batch) }
- }
-
- fn next(&mut self) {
- if unsafe { sys::nftnl_batch_update(self.batch) } < 0 {
- // See try_alloc definition.
- std::process::abort();
- }
- self.seq += 1;
- }
-
- fn write_begin_msg(&mut self) {
- unsafe { sys::nftnl_batch_begin(self.current() as *mut c_char, self.seq) };
- self.next();
- }
-
- fn write_end_msg(&mut self) {
- unsafe { sys::nftnl_batch_end(self.current() as *mut c_char, self.seq) };
- self.next();
- }
-
- #[cfg(feature = "unsafe-raw-handles")]
- /// Returns the raw handle.
- pub fn as_ptr(&self) -> *const sys::nftnl_batch {
- self.batch as *const sys::nftnl_batch
- }
-
- #[cfg(feature = "unsafe-raw-handles")]
- /// Returns a mutable version of the raw handle.
- pub fn as_mut_ptr(&mut self) -> *mut sys::nftnl_batch {
- self.batch
- }
-}
-
-impl Drop for Batch {
- fn drop(&mut self) {
- unsafe { sys::nftnl_batch_free(self.batch) };
- }
-}
-
-/// A wrapper over [`Batch`], guaranteed to start with a proper batch begin and end with a proper
-/// batch end message. Created from [`Batch::finalize`].
-///
-/// Can be turned into an iterator of the byte buffers to send to netlink to execute this batch.
-///
-/// [`Batch`]: struct.Batch.html
-/// [`Batch::finalize`]: struct.Batch.html#method.finalize
-pub struct FinalizedBatch {
- batch: Batch,
-}
-
-impl FinalizedBatch {
- /// Returns the iterator over byte buffers to send to netlink.
- pub fn iter(&mut self) -> Iter<'_> {
- let num_pages = unsafe { sys::nftnl_batch_iovec_len(self.batch.batch) as usize };
- let mut iovecs = vec![
- libc::iovec {
- iov_base: ptr::null_mut(),
- iov_len: 0,
- };
- num_pages
- ];
- let iovecs_ptr = iovecs.as_mut_ptr();
- unsafe {
- sys::nftnl_batch_iovec(self.batch.batch, iovecs_ptr, num_pages as u32);
- }
- Iter {
- iovecs: iovecs.into_iter(),
- _marker: ::std::marker::PhantomData,
- }
- }
-}
-
-impl<'a> IntoIterator for &'a mut FinalizedBatch {
- type Item = &'a [u8];
- type IntoIter = Iter<'a>;
-
- fn into_iter(self) -> Iter<'a> {
- self.iter()
- }
-}
-
-pub struct Iter<'a> {
- iovecs: ::std::vec::IntoIter<libc::iovec>,
- _marker: ::std::marker::PhantomData<&'a ()>,
-}
-
-impl<'a> Iterator for Iter<'a> {
- type Item = &'a [u8];
-
- fn next(&mut self) -> Option<&'a [u8]> {
- self.iovecs.next().map(|iovec| unsafe {
- ::std::slice::from_raw_parts(iovec.iov_base as *const u8, iovec.iov_len)
- })
- }
-}
-
-/// selected batch page is 256 Kbytes long to load ruleset of
-/// half a million rules without hitting -EMSGSIZE due to large
-/// iovec.
-pub fn default_batch_page_size() -> u32 {
- unsafe { libc::sysconf(libc::_SC_PAGESIZE) as u32 * 32 }
-}
diff --git a/rustables/src/chain.rs b/rustables/src/chain.rs
deleted file mode 100644
index 20043ac..0000000
--- a/rustables/src/chain.rs
+++ /dev/null
@@ -1,292 +0,0 @@
-use crate::{MsgType, Table};
-use crate::sys::{self as sys, libc};
-#[cfg(feature = "query")]
-use std::convert::TryFrom;
-use std::{
- ffi::{c_void, CStr, CString},
- fmt,
- os::raw::c_char,
- rc::Rc,
-};
-
-pub type Priority = i32;
-
-/// The netfilter event hooks a chain can register for.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-#[repr(u16)]
-pub enum Hook {
- /// Hook into the pre-routing stage of netfilter. Corresponds to `NF_INET_PRE_ROUTING`.
- PreRouting = libc::NF_INET_PRE_ROUTING as u16,
- /// Hook into the input stage of netfilter. Corresponds to `NF_INET_LOCAL_IN`.
- In = libc::NF_INET_LOCAL_IN as u16,
- /// Hook into the forward stage of netfilter. Corresponds to `NF_INET_FORWARD`.
- Forward = libc::NF_INET_FORWARD as u16,
- /// Hook into the output stage of netfilter. Corresponds to `NF_INET_LOCAL_OUT`.
- Out = libc::NF_INET_LOCAL_OUT as u16,
- /// Hook into the post-routing stage of netfilter. Corresponds to `NF_INET_POST_ROUTING`.
- PostRouting = libc::NF_INET_POST_ROUTING as u16,
-}
-
-/// A chain policy. Decides what to do with a packet that was processed by the chain but did not
-/// match any rules.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-#[repr(u32)]
-pub enum Policy {
- /// Accept the packet.
- Accept = libc::NF_ACCEPT as u32,
- /// Drop the packet.
- Drop = libc::NF_DROP as u32,
-}
-
-/// Base chain type.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum ChainType {
- /// Used to filter packets.
- /// Supported protocols: ip, ip6, inet, arp, and bridge tables.
- Filter,
- /// Used to reroute packets if IP headers or packet marks are modified.
- /// Supported protocols: ip, and ip6 tables.
- Route,
- /// Used to perform NAT.
- /// Supported protocols: ip, and ip6 tables.
- Nat,
-}
-
-impl ChainType {
- fn as_c_str(&self) -> &'static [u8] {
- match *self {
- ChainType::Filter => b"filter\0",
- ChainType::Route => b"route\0",
- ChainType::Nat => b"nat\0",
- }
- }
-}
-
-/// Abstraction of a `nftnl_chain`. Chains reside inside [`Table`]s and they hold [`Rule`]s.
-///
-/// There are two types of chains, "base chain" and "regular chain". See [`set_hook`] for more
-/// details.
-///
-/// [`Table`]: struct.Table.html
-/// [`Rule`]: struct.Rule.html
-/// [`set_hook`]: #method.set_hook
-pub struct Chain {
- pub(crate) chain: *mut sys::nftnl_chain,
- pub(crate) table: Rc<Table>,
-}
-
-impl Chain {
- /// Creates a new chain instance inside the given [`Table`] and with the given name.
- ///
- /// [`Table`]: struct.Table.html
- pub fn new<T: AsRef<CStr>>(name: &T, table: Rc<Table>) -> Chain {
- unsafe {
- let chain = try_alloc!(sys::nftnl_chain_alloc());
- sys::nftnl_chain_set_u32(
- chain,
- sys::NFTNL_CHAIN_FAMILY as u16,
- table.get_family() as u32,
- );
- sys::nftnl_chain_set_str(
- chain,
- sys::NFTNL_CHAIN_TABLE as u16,
- table.get_name().as_ptr(),
- );
- sys::nftnl_chain_set_str(chain, sys::NFTNL_CHAIN_NAME as u16, name.as_ref().as_ptr());
- Chain { chain, table }
- }
- }
-
- pub unsafe fn from_raw(chain: *mut sys::nftnl_chain, table: Rc<Table>) -> Self {
- Chain { chain, table }
- }
-
- /// Sets the hook and priority for this chain. Without calling this method the chain well
- /// become a "regular chain" without any hook and will thus not receive any traffic unless
- /// some rule forward packets to it via goto or jump verdicts.
- ///
- /// By calling `set_hook` with a hook the chain that is created will be registered with that
- /// hook and is thus a "base chain". A "base chain" is an entry point for packets from the
- /// networking stack.
- pub fn set_hook(&mut self, hook: Hook, priority: Priority) {
- unsafe {
- sys::nftnl_chain_set_u32(self.chain, sys::NFTNL_CHAIN_HOOKNUM as u16, hook as u32);
- sys::nftnl_chain_set_s32(self.chain, sys::NFTNL_CHAIN_PRIO as u16, priority);
- }
- }
-
- /// Set the type of a base chain. This only applies if the chain has been registered
- /// with a hook by calling `set_hook`.
- pub fn set_type(&mut self, chain_type: ChainType) {
- unsafe {
- sys::nftnl_chain_set_str(
- self.chain,
- sys::NFTNL_CHAIN_TYPE as u16,
- chain_type.as_c_str().as_ptr() as *const c_char,
- );
- }
- }
-
- /// Sets the default policy for this chain. That means what action netfilter will apply to
- /// packets processed by this chain, but that did not match any rules in it.
- pub fn set_policy(&mut self, policy: Policy) {
- unsafe {
- sys::nftnl_chain_set_u32(self.chain, sys::NFTNL_CHAIN_POLICY as u16, policy as u32);
- }
- }
-
- /// Returns the userdata of this chain.
- pub fn get_userdata(&self) -> Option<&CStr> {
- unsafe {
- let ptr = sys::nftnl_chain_get_str(self.chain, sys::NFTNL_CHAIN_USERDATA as u16);
- if ptr == std::ptr::null() {
- return None;
- }
- Some(CStr::from_ptr(ptr))
- }
- }
-
- /// Update the userdata of this chain.
- pub fn set_userdata(&self, data: &CStr) {
- unsafe {
- sys::nftnl_chain_set_str(self.chain, sys::NFTNL_CHAIN_USERDATA as u16, data.as_ptr());
- }
- }
-
- /// Returns the name of this chain.
- pub fn get_name(&self) -> &CStr {
- unsafe {
- let ptr = sys::nftnl_chain_get_str(self.chain, sys::NFTNL_CHAIN_NAME as u16);
- if ptr.is_null() {
- panic!("Impossible situation: retrieving the name of a chain failed")
- } else {
- CStr::from_ptr(ptr)
- }
- }
- }
-
- /// Returns a textual description of the chain.
- pub fn get_str(&self) -> CString {
- let mut descr_buf = vec![0i8; 4096];
- unsafe {
- sys::nftnl_chain_snprintf(
- descr_buf.as_mut_ptr(),
- (descr_buf.len() - 1) as u64,
- self.chain,
- sys::NFTNL_OUTPUT_DEFAULT,
- 0,
- );
- CStr::from_ptr(descr_buf.as_ptr()).to_owned()
- }
- }
-
- /// Returns a reference to the [`Table`] this chain belongs to
- ///
- /// [`Table`]: struct.Table.html
- pub fn get_table(&self) -> Rc<Table> {
- self.table.clone()
- }
-
- #[cfg(feature = "unsafe-raw-handles")]
- /// Returns the raw handle.
- pub fn as_ptr(&self) -> *const sys::nftnl_chain {
- self.chain as *const sys::nftnl_chain
- }
-
- #[cfg(feature = "unsafe-raw-handles")]
- /// Returns a mutable version of the raw handle.
- pub fn as_mut_ptr(&mut self) -> *mut sys::nftnl_chain {
- self.chain
- }
-}
-
-impl fmt::Debug for Chain {
- /// Return a string representation of the chain.
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(fmt, "{:?}", self.get_str())
- }
-}
-
-impl PartialEq for Chain {
- fn eq(&self, other: &Self) -> bool {
- self.get_table() == other.get_table() && self.get_name() == other.get_name()
- }
-}
-
-unsafe impl crate::NlMsg for Chain {
- unsafe fn write(&self, buf: *mut c_void, seq: u32, msg_type: MsgType) {
- let raw_msg_type = match msg_type {
- MsgType::Add => libc::NFT_MSG_NEWCHAIN,
- MsgType::Del => libc::NFT_MSG_DELCHAIN,
- };
- let flags: u16 = match msg_type {
- MsgType::Add => (libc::NLM_F_ACK | libc::NLM_F_CREATE) as u16,
- MsgType::Del => libc::NLM_F_ACK as u16,
- } | libc::NLM_F_ACK as u16;
- let header = sys::nftnl_nlmsg_build_hdr(
- buf as *mut c_char,
- raw_msg_type as u16,
- self.table.get_family() as u16,
- flags,
- seq,
- );
- sys::nftnl_chain_nlmsg_build_payload(header, self.chain);
- }
-}
-
-impl Drop for Chain {
- fn drop(&mut self) {
- unsafe { sys::nftnl_chain_free(self.chain) };
- }
-}
-
-#[cfg(feature = "query")]
-pub fn get_chains_cb<'a>(
- header: &libc::nlmsghdr,
- (table, chains): &mut (&Rc<Table>, &mut Vec<Chain>),
-) -> libc::c_int {
- unsafe {
- let chain = sys::nftnl_chain_alloc();
- if chain == std::ptr::null_mut() {
- return mnl::mnl_sys::MNL_CB_ERROR;
- }
- let err = sys::nftnl_chain_nlmsg_parse(header, chain);
- if err < 0 {
- error!("Failed to parse nelink chain message - {}", err);
- sys::nftnl_chain_free(chain);
- return err;
- }
-
- let table_name = CStr::from_ptr(sys::nftnl_chain_get_str(
- chain,
- sys::NFTNL_CHAIN_TABLE as u16,
- ));
- let family = sys::nftnl_chain_get_u32(chain, sys::NFTNL_CHAIN_FAMILY as u16);
- let family = match crate::ProtoFamily::try_from(family as i32) {
- Ok(family) => family,
- Err(crate::InvalidProtocolFamily) => {
- error!("The netlink table didn't have a valid protocol family !?");
- sys::nftnl_chain_free(chain);
- return mnl::mnl_sys::MNL_CB_ERROR;
- }
- };
-
- if table_name != table.get_name() {
- sys::nftnl_chain_free(chain);
- return mnl::mnl_sys::MNL_CB_OK;
- }
-
- if family != crate::ProtoFamily::Unspec && family != table.get_family() {
- sys::nftnl_chain_free(chain);
- return mnl::mnl_sys::MNL_CB_OK;
- }
-
- chains.push(Chain::from_raw(chain, table.clone()));
- }
- mnl::mnl_sys::MNL_CB_OK
-}
-
-#[cfg(feature = "query")]
-pub fn list_chains_for_table(table: Rc<Table>) -> Result<Vec<Chain>, crate::query::Error> {
- crate::query::list_objects_with_data(libc::NFT_MSG_GETCHAIN as u16, get_chains_cb, &table, None)
-}
diff --git a/rustables/src/expr/bitwise.rs b/rustables/src/expr/bitwise.rs
deleted file mode 100644
index 59ef41b..0000000
--- a/rustables/src/expr/bitwise.rs
+++ /dev/null
@@ -1,69 +0,0 @@
-use super::{Expression, Rule, ToSlice};
-use crate::sys::{self, libc};
-use std::ffi::c_void;
-use std::os::raw::c_char;
-
-/// Expression for performing bitwise masking and XOR on the data in a register.
-pub struct Bitwise<M: ToSlice, X: ToSlice> {
- mask: M,
- xor: X,
-}
-
-impl<M: ToSlice, X: ToSlice> Bitwise<M, X> {
- /// Returns a new `Bitwise` instance that first masks the value it's applied to with `mask`
- /// and then performs xor with the value in `xor`.
- pub fn new(mask: M, xor: X) -> Self {
- Self { mask, xor }
- }
-}
-
-impl<M: ToSlice, X: ToSlice> Expression for Bitwise<M, X> {
- fn get_raw_name() -> *const c_char {
- b"bitwise\0" as *const _ as *const c_char
- }
-
- fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
- unsafe {
- let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name()));
-
- let mask = self.mask.to_slice();
- let xor = self.xor.to_slice();
- assert!(mask.len() == xor.len());
- let len = mask.len() as u32;
-
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_BITWISE_SREG as u16,
- libc::NFT_REG_1 as u32,
- );
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_BITWISE_DREG as u16,
- libc::NFT_REG_1 as u32,
- );
- sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_BITWISE_LEN as u16, len);
-
- sys::nftnl_expr_set(
- expr,
- sys::NFTNL_EXPR_BITWISE_MASK as u16,
- mask.as_ref() as *const _ as *const c_void,
- len,
- );
- sys::nftnl_expr_set(
- expr,
- sys::NFTNL_EXPR_BITWISE_XOR as u16,
- xor.as_ref() as *const _ as *const c_void,
- len,
- );
-
- expr
- }
- }
-}
-
-#[macro_export]
-macro_rules! nft_expr_bitwise {
- (mask $mask:expr,xor $xor:expr) => {
- $crate::expr::Bitwise::new($mask, $xor)
- };
-}
diff --git a/rustables/src/expr/cmp.rs b/rustables/src/expr/cmp.rs
deleted file mode 100644
index 384f0b4..0000000
--- a/rustables/src/expr/cmp.rs
+++ /dev/null
@@ -1,220 +0,0 @@
-use super::{DeserializationError, Expression, Rule, ToSlice};
-use crate::sys::{self, libc};
-use std::{
- borrow::Cow,
- ffi::{c_void, CString},
- os::raw::c_char,
-};
-
-/// Comparison operator.
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum CmpOp {
- /// Equals.
- Eq,
- /// Not equal.
- Neq,
- /// Less than.
- Lt,
- /// Less than, or equal.
- Lte,
- /// Greater than.
- Gt,
- /// Greater than, or equal.
- Gte,
-}
-
-impl CmpOp {
- /// Returns the corresponding `NFT_*` constant for this comparison operation.
- pub fn to_raw(self) -> u32 {
- use self::CmpOp::*;
- match self {
- Eq => libc::NFT_CMP_EQ as u32,
- Neq => libc::NFT_CMP_NEQ as u32,
- Lt => libc::NFT_CMP_LT as u32,
- Lte => libc::NFT_CMP_LTE as u32,
- Gt => libc::NFT_CMP_GT as u32,
- Gte => libc::NFT_CMP_GTE as u32,
- }
- }
-
- pub fn from_raw(val: u32) -> Result<Self, DeserializationError> {
- use self::CmpOp::*;
- match val as i32 {
- libc::NFT_CMP_EQ => Ok(Eq),
- libc::NFT_CMP_NEQ => Ok(Neq),
- libc::NFT_CMP_LT => Ok(Lt),
- libc::NFT_CMP_LTE => Ok(Lte),
- libc::NFT_CMP_GT => Ok(Gt),
- libc::NFT_CMP_GTE => Ok(Gte),
- _ => Err(DeserializationError::InvalidValue),
- }
- }
-}
-
-/// Comparator expression. Allows comparing the content of the netfilter register with any value.
-#[derive(Debug, PartialEq)]
-pub struct Cmp<T> {
- op: CmpOp,
- data: T,
-}
-
-impl<T: ToSlice> Cmp<T> {
- /// Returns a new comparison expression comparing the value loaded in the register with the
- /// data in `data` using the comparison operator `op`.
- pub fn new(op: CmpOp, data: T) -> Self {
- Cmp { op, data }
- }
-}
-
-impl<T: ToSlice> Expression for Cmp<T> {
- fn get_raw_name() -> *const c_char {
- b"cmp\0" as *const _ as *const c_char
- }
-
- fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
- unsafe {
- let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name()));
-
- let data = self.data.to_slice();
- trace!("Creating a cmp expr comparing with data {:?}", data);
-
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_CMP_SREG as u16,
- libc::NFT_REG_1 as u32,
- );
- sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_CMP_OP as u16, self.op.to_raw());
- sys::nftnl_expr_set(
- expr,
- sys::NFTNL_EXPR_CMP_DATA as u16,
- data.as_ptr() as *const c_void,
- data.len() as u32,
- );
-
- expr
- }
- }
-}
-
-impl<const N: usize> Expression for Cmp<[u8; N]> {
- fn get_raw_name() -> *const c_char {
- Cmp::<u8>::get_raw_name()
- }
-
- /// The raw data contained inside `Cmp` expressions can only be deserialized to
- /// arrays of bytes, to ensure that the memory layout of retrieved data cannot be
- /// violated. It is your responsibility to provide the correct length of the byte
- /// data. If the data size is invalid, you will get the error
- /// `DeserializationError::InvalidDataSize`.
- ///
- /// Example (warning, no error checking!):
- /// ```rust
- /// use std::ffi::CString;
- /// use std::net::Ipv4Addr;
- /// use std::rc::Rc;
- ///
- /// use rustables::{Chain, expr::{Cmp, CmpOp}, ProtoFamily, Rule, Table};
- ///
- /// let table = Rc::new(Table::new(&CString::new("mytable").unwrap(), ProtoFamily::Inet));
- /// let chain = Rc::new(Chain::new(&CString::new("mychain").unwrap(), table));
- /// let mut rule = Rule::new(chain);
- /// rule.add_expr(&Cmp::new(CmpOp::Eq, 1337u16));
- /// for expr in Rc::new(rule).get_exprs() {
- /// println!("{:?}", expr.decode_expr::<Cmp<[u8; 2]>>().unwrap());
- /// }
- /// ```
- /// These limitations occur because casting bytes to any type of the same size
- /// as the raw input would be *extremely* dangerous in terms of memory safety.
- fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError> {
- unsafe {
- let ref_len = std::mem::size_of::<[u8; N]>() as u32;
- let mut data_len = 0;
- let data = sys::nftnl_expr_get(
- expr,
- sys::NFTNL_EXPR_CMP_DATA as u16,
- &mut data_len as *mut u32,
- );
-
- if data.is_null() {
- return Err(DeserializationError::NullPointer);
- } else if data_len != ref_len {
- return Err(DeserializationError::InvalidDataSize);
- }
-
- let data = *(data as *const [u8; N]);
-
- let op = CmpOp::from_raw(sys::nftnl_expr_get_u32(expr, sys::NFTNL_EXPR_CMP_OP as u16))?;
- Ok(Cmp { op, data })
- }
- }
-
- // call to the other implementation to generate the expression
- fn to_expr(&self, rule: &Rule) -> *mut sys::nftnl_expr {
- Cmp {
- data: &self.data as &[u8],
- op: self.op,
- }
- .to_expr(rule)
- }
-}
-
-#[macro_export(local_inner_macros)]
-macro_rules! nft_expr_cmp {
- (@cmp_op ==) => {
- $crate::expr::CmpOp::Eq
- };
- (@cmp_op !=) => {
- $crate::expr::CmpOp::Neq
- };
- (@cmp_op <) => {
- $crate::expr::CmpOp::Lt
- };
- (@cmp_op <=) => {
- $crate::expr::CmpOp::Lte
- };
- (@cmp_op >) => {
- $crate::expr::CmpOp::Gt
- };
- (@cmp_op >=) => {
- $crate::expr::CmpOp::Gte
- };
- ($op:tt $data:expr) => {
- $crate::expr::Cmp::new(nft_expr_cmp!(@cmp_op $op), $data)
- };
-}
-
-/// Can be used to compare the value loaded by [`Meta::IifName`] and [`Meta::OifName`]. Please
-/// note that it is faster to check interface index than name.
-///
-/// [`Meta::IifName`]: enum.Meta.html#variant.IifName
-/// [`Meta::OifName`]: enum.Meta.html#variant.OifName
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub enum InterfaceName {
- /// Interface name must be exactly the value of the `CString`.
- Exact(CString),
- /// Interface name must start with the value of the `CString`.
- ///
- /// `InterfaceName::StartingWith("eth")` will look like `eth*` when printed and match against
- /// `eth0`, `eth1`, ..., `eth99` and so on.
- StartingWith(CString),
-}
-
-impl ToSlice for InterfaceName {
- fn to_slice(&self) -> Cow<'_, [u8]> {
- let bytes = match *self {
- InterfaceName::Exact(ref name) => name.as_bytes_with_nul(),
- InterfaceName::StartingWith(ref name) => name.as_bytes(),
- };
- Cow::from(bytes)
- }
-}
-
-impl<'a> ToSlice for &'a InterfaceName {
- fn to_slice(&self) -> Cow<'_, [u8]> {
- let bytes = match *self {
- InterfaceName::Exact(ref name) => name.as_bytes_with_nul(),
- InterfaceName::StartingWith(ref name) => name.as_bytes(),
- };
- Cow::from(bytes)
- }
-}
diff --git a/rustables/src/expr/counter.rs b/rustables/src/expr/counter.rs
deleted file mode 100644
index 71064df..0000000
--- a/rustables/src/expr/counter.rs
+++ /dev/null
@@ -1,46 +0,0 @@
-use super::{DeserializationError, Expression, Rule};
-use crate::sys;
-use std::os::raw::c_char;
-
-/// A counter expression adds a counter to the rule that is incremented to count number of packets
-/// and number of bytes for all packets that has matched the rule.
-#[derive(Debug, PartialEq)]
-pub struct Counter {
- pub nb_bytes: u64,
- pub nb_packets: u64,
-}
-
-impl Counter {
- pub fn new() -> Self {
- Self {
- nb_bytes: 0,
- nb_packets: 0,
- }
- }
-}
-
-impl Expression for Counter {
- fn get_raw_name() -> *const c_char {
- b"counter\0" as *const _ as *const c_char
- }
-
- fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError> {
- unsafe {
- let nb_bytes = sys::nftnl_expr_get_u64(expr, sys::NFTNL_EXPR_CTR_BYTES as u16);
- let nb_packets = sys::nftnl_expr_get_u64(expr, sys::NFTNL_EXPR_CTR_PACKETS as u16);
- Ok(Counter {
- nb_bytes,
- nb_packets,
- })
- }
- }
-
- fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
- unsafe {
- let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name()));
- sys::nftnl_expr_set_u64(expr, sys::NFTNL_EXPR_CTR_BYTES as u16, self.nb_bytes);
- sys::nftnl_expr_set_u64(expr, sys::NFTNL_EXPR_CTR_PACKETS as u16, self.nb_packets);
- expr
- }
- }
-}
diff --git a/rustables/src/expr/ct.rs b/rustables/src/expr/ct.rs
deleted file mode 100644
index 7d6614c..0000000
--- a/rustables/src/expr/ct.rs
+++ /dev/null
@@ -1,87 +0,0 @@
-use super::{DeserializationError, Expression, Rule};
-use crate::sys::{self, libc};
-use std::os::raw::c_char;
-
-bitflags::bitflags! {
- pub struct States: u32 {
- const INVALID = 1;
- const ESTABLISHED = 2;
- const RELATED = 4;
- const NEW = 8;
- const UNTRACKED = 64;
- }
-}
-
-pub enum Conntrack {
- State,
- Mark { set: bool },
-}
-
-impl Conntrack {
- fn raw_key(&self) -> u32 {
- match *self {
- Conntrack::State => libc::NFT_CT_STATE as u32,
- Conntrack::Mark { .. } => libc::NFT_CT_MARK as u32,
- }
- }
-}
-
-impl Expression for Conntrack {
- fn get_raw_name() -> *const c_char {
- b"ct\0" as *const _ as *const c_char
- }
-
- fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError>
- where
- Self: Sized,
- {
- unsafe {
- let ct_key = sys::nftnl_expr_get_u32(expr, sys::NFTNL_EXPR_CT_KEY as u16);
- let ct_sreg_is_set = sys::nftnl_expr_is_set(expr, sys::NFTNL_EXPR_CT_SREG as u16);
-
- match ct_key as i32 {
- libc::NFT_CT_STATE => Ok(Conntrack::State),
- libc::NFT_CT_MARK => Ok(Conntrack::Mark {
- set: ct_sreg_is_set,
- }),
- _ => Err(DeserializationError::InvalidValue),
- }
- }
- }
-
- fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
- unsafe {
- let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name()));
-
- if let Conntrack::Mark { set: true } = self {
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_CT_SREG as u16,
- libc::NFT_REG_1 as u32,
- );
- } else {
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_CT_DREG as u16,
- libc::NFT_REG_1 as u32,
- );
- }
- sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_CT_KEY as u16, self.raw_key());
-
- expr
- }
- }
-}
-
-#[macro_export]
-macro_rules! nft_expr_ct {
- (state) => {
- $crate::expr::Conntrack::State
- };
- (mark set) => {
- $crate::expr::Conntrack::Mark { set: true }
- };
- (mark) => {
- $crate::expr::Conntrack::Mark { set: false }
- };
-}
diff --git a/rustables/src/expr/immediate.rs b/rustables/src/expr/immediate.rs
deleted file mode 100644
index 0787e06..0000000
--- a/rustables/src/expr/immediate.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-use super::{DeserializationError, Expression, Register, Rule, ToSlice};
-use crate::sys;
-use std::ffi::c_void;
-use std::os::raw::c_char;
-
-/// An immediate expression. Used to set immediate data.
-/// Verdicts are handled separately by [crate::expr::Verdict].
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub struct Immediate<T> {
- pub data: T,
- pub register: Register,
-}
-
-impl<T> Immediate<T> {
- pub fn new(data: T, register: Register) -> Self {
- Self { data, register }
- }
-}
-
-impl<T: ToSlice> Expression for Immediate<T> {
- fn get_raw_name() -> *const c_char {
- b"immediate\0" as *const _ as *const c_char
- }
-
- fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
- unsafe {
- let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name()));
-
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_IMM_DREG as u16,
- self.register.to_raw(),
- );
-
- let data = self.data.to_slice();
- sys::nftnl_expr_set(
- expr,
- sys::NFTNL_EXPR_IMM_DATA as u16,
- data.as_ptr() as *const c_void,
- data.len() as u32,
- );
-
- expr
- }
- }
-}
-
-impl<const N: usize> Expression for Immediate<[u8; N]> {
- fn get_raw_name() -> *const c_char {
- Immediate::<u8>::get_raw_name()
- }
-
- /// The raw data contained inside `Immediate` expressions can only be deserialized to
- /// arrays of bytes, to ensure that the memory layout of retrieved data cannot be
- /// violated. It is your responsibility to provide the correct length of the byte
- /// data. If the data size is invalid, you will get the error
- /// `DeserializationError::InvalidDataSize`.
- ///
- /// Example (warning, no error checking!):
- /// ```rust
- /// use std::ffi::CString;
- /// use std::net::Ipv4Addr;
- /// use std::rc::Rc;
- ///
- /// use rustables::{Chain, expr::{Immediate, Register}, ProtoFamily, Rule, Table};
- ///
- /// let table = Rc::new(Table::new(&CString::new("mytable").unwrap(), ProtoFamily::Inet));
- /// let chain = Rc::new(Chain::new(&CString::new("mychain").unwrap(), table));
- /// let mut rule = Rule::new(chain);
- /// rule.add_expr(&Immediate::new(42u8, Register::Reg1));
- /// for expr in Rc::new(rule).get_exprs() {
- /// println!("{:?}", expr.decode_expr::<Immediate<[u8; 1]>>().unwrap());
- /// }
- /// ```
- /// These limitations occur because casting bytes to any type of the same size
- /// as the raw input would be *extremely* dangerous in terms of memory safety.
- // As casting bytes to any type of the same size as the input would
- // be *extremely* dangerous in terms of memory safety,
- // rustables only accept to deserialize expressions with variable-size data
- // to arrays of bytes, so that the memory layout cannot be invalid.
- fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError> {
- unsafe {
- let ref_len = std::mem::size_of::<[u8; N]>() as u32;
- let mut data_len = 0;
- let data = sys::nftnl_expr_get(
- expr,
- sys::NFTNL_EXPR_IMM_DATA as u16,
- &mut data_len as *mut u32,
- );
-
- if data.is_null() {
- return Err(DeserializationError::NullPointer);
- } else if data_len != ref_len {
- return Err(DeserializationError::InvalidDataSize);
- }
-
- let data = *(data as *const [u8; N]);
-
- let register = Register::from_raw(sys::nftnl_expr_get_u32(
- expr,
- sys::NFTNL_EXPR_IMM_DREG as u16,
- ))?;
-
- Ok(Immediate { data, register })
- }
- }
-
- // call to the other implementation to generate the expression
- fn to_expr(&self, rule: &Rule) -> *mut sys::nftnl_expr {
- Immediate {
- register: self.register,
- data: &self.data as &[u8],
- }
- .to_expr(rule)
- }
-}
-
-#[macro_export]
-macro_rules! nft_expr_immediate {
- (data $value:expr) => {
- $crate::expr::Immediate {
- data: $value,
- register: $crate::expr::Register::Reg1,
- }
- };
-}
diff --git a/rustables/src/expr/log.rs b/rustables/src/expr/log.rs
deleted file mode 100644
index 5c06897..0000000
--- a/rustables/src/expr/log.rs
+++ /dev/null
@@ -1,112 +0,0 @@
-use super::{DeserializationError, Expression, Rule};
-use crate::sys;
-use std::ffi::{CStr, CString};
-use std::os::raw::c_char;
-use thiserror::Error;
-
-/// A Log expression will log all packets that match the rule.
-#[derive(Debug, PartialEq)]
-pub struct Log {
- pub group: Option<LogGroup>,
- pub prefix: Option<LogPrefix>,
-}
-
-impl Expression for Log {
- fn get_raw_name() -> *const sys::libc::c_char {
- b"log\0" as *const _ as *const c_char
- }
-
- fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError>
- where
- Self: Sized,
- {
- unsafe {
- let mut group = None;
- if sys::nftnl_expr_is_set(expr, sys::NFTNL_EXPR_LOG_GROUP as u16) {
- group = Some(LogGroup(sys::nftnl_expr_get_u32(
- expr,
- sys::NFTNL_EXPR_LOG_GROUP as u16,
- ) as u16));
- }
- let mut prefix = None;
- if sys::nftnl_expr_is_set(expr, sys::NFTNL_EXPR_LOG_PREFIX as u16) {
- let raw_prefix = sys::nftnl_expr_get_str(expr, sys::NFTNL_EXPR_LOG_PREFIX as u16);
- if raw_prefix.is_null() {
- return Err(DeserializationError::NullPointer);
- } else {
- prefix = Some(LogPrefix(CStr::from_ptr(raw_prefix).to_owned()));
- }
- }
- Ok(Log { group, prefix })
- }
- }
-
- fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
- unsafe {
- let expr = try_alloc!(sys::nftnl_expr_alloc(b"log\0" as *const _ as *const c_char));
- if let Some(log_group) = self.group {
- sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_LOG_GROUP as u16, log_group.0 as u32);
- };
- if let Some(LogPrefix(prefix)) = &self.prefix {
- sys::nftnl_expr_set_str(expr, sys::NFTNL_EXPR_LOG_PREFIX as u16, prefix.as_ptr());
- };
-
- expr
- }
- }
-}
-
-#[derive(Error, Debug)]
-pub enum LogPrefixError {
- #[error("The log prefix string is more than 128 characters long")]
- TooLongPrefix,
- #[error("The log prefix string contains an invalid Nul character.")]
- PrefixContainsANul(#[from] std::ffi::NulError),
-}
-
-/// The NFLOG group that will be assigned to each log line.
-#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
-pub struct LogGroup(pub u16);
-
-/// A prefix that will get prepended to each log line.
-#[derive(Debug, Clone, PartialEq)]
-pub struct LogPrefix(CString);
-
-impl LogPrefix {
- /// Create a new LogPrefix from a String. Converts it to CString as needed by nftnl. Note
- /// that LogPrefix should not be more than 127 characters long.
- pub fn new(prefix: &str) -> Result<Self, LogPrefixError> {
- if prefix.chars().count() > 127 {
- return Err(LogPrefixError::TooLongPrefix);
- }
- Ok(LogPrefix(CString::new(prefix)?))
- }
-}
-
-#[macro_export]
-macro_rules! nft_expr_log {
- (group $group:ident prefix $prefix:expr) => {
- $crate::expr::Log {
- group: $group,
- prefix: $prefix,
- }
- };
- (prefix $prefix:expr) => {
- $crate::expr::Log {
- group: None,
- prefix: $prefix,
- }
- };
- (group $group:ident) => {
- $crate::expr::Log {
- group: $group,
- prefix: None,
- }
- };
- () => {
- $crate::expr::Log {
- group: None,
- prefix: None,
- }
- };
-}
diff --git a/rustables/src/expr/lookup.rs b/rustables/src/expr/lookup.rs
deleted file mode 100644
index 8e288a0..0000000
--- a/rustables/src/expr/lookup.rs
+++ /dev/null
@@ -1,79 +0,0 @@
-use super::{DeserializationError, Expression, Rule};
-use crate::set::Set;
-use crate::sys::{self, libc};
-use std::ffi::{CStr, CString};
-use std::os::raw::c_char;
-
-#[derive(Debug, PartialEq)]
-pub struct Lookup {
- set_name: CString,
- set_id: u32,
-}
-
-impl Lookup {
- /// Creates a new lookup entry.
- /// May return None if the set have no name.
- pub fn new<K>(set: &Set<'_, K>) -> Option<Self> {
- set.get_name().map(|set_name| Lookup {
- set_name: set_name.to_owned(),
- set_id: set.get_id(),
- })
- }
-}
-
-impl Expression for Lookup {
- fn get_raw_name() -> *const libc::c_char {
- b"lookup\0" as *const _ as *const c_char
- }
-
- fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError>
- where
- Self: Sized,
- {
- unsafe {
- let set_name = sys::nftnl_expr_get_str(expr, sys::NFTNL_EXPR_LOOKUP_SET as u16);
- let set_id = sys::nftnl_expr_get_u32(expr, sys::NFTNL_EXPR_LOOKUP_SET_ID as u16);
-
- if set_name.is_null() {
- return Err(DeserializationError::NullPointer);
- }
-
- let set_name = CStr::from_ptr(set_name).to_owned();
-
- Ok(Lookup { set_id, set_name })
- }
- }
-
- fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
- unsafe {
- let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name()));
-
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_LOOKUP_SREG as u16,
- libc::NFT_REG_1 as u32,
- );
- sys::nftnl_expr_set_str(
- expr,
- sys::NFTNL_EXPR_LOOKUP_SET as u16,
- self.set_name.as_ptr() as *const _ as *const c_char,
- );
- sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_LOOKUP_SET_ID as u16, self.set_id);
-
- // This code is left here since it's quite likely we need it again when we get further
- // if self.reverse {
- // sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_LOOKUP_FLAGS as u16,
- // libc::NFT_LOOKUP_F_INV as u32);
- // }
-
- expr
- }
- }
-}
-
-#[macro_export]
-macro_rules! nft_expr_lookup {
- ($set:expr) => {
- $crate::expr::Lookup::new($set)
- };
-}
diff --git a/rustables/src/expr/masquerade.rs b/rustables/src/expr/masquerade.rs
deleted file mode 100644
index c1a06de..0000000
--- a/rustables/src/expr/masquerade.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-use super::{DeserializationError, Expression, Rule};
-use crate::sys;
-use std::os::raw::c_char;
-
-/// Sets the source IP to that of the output interface.
-#[derive(Debug, PartialEq)]
-pub struct Masquerade;
-
-impl Expression for Masquerade {
- fn get_raw_name() -> *const sys::libc::c_char {
- b"masq\0" as *const _ as *const c_char
- }
-
- fn from_expr(_expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError>
- where
- Self: Sized,
- {
- Ok(Masquerade)
- }
-
- fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
- try_alloc!(unsafe { sys::nftnl_expr_alloc(Self::get_raw_name()) })
- }
-}
diff --git a/rustables/src/expr/meta.rs b/rustables/src/expr/meta.rs
deleted file mode 100644
index bf77774..0000000
--- a/rustables/src/expr/meta.rs
+++ /dev/null
@@ -1,175 +0,0 @@
-use super::{DeserializationError, Expression, Rule};
-use crate::sys::{self, libc};
-use std::os::raw::c_char;
-
-/// A meta expression refers to meta data associated with a packet.
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[non_exhaustive]
-pub enum Meta {
- /// Packet ethertype protocol (skb->protocol), invalid in OUTPUT.
- Protocol,
- /// Packet mark.
- Mark { set: bool },
- /// Packet input interface index (dev->ifindex).
- Iif,
- /// Packet output interface index (dev->ifindex).
- Oif,
- /// Packet input interface name (dev->name)
- IifName,
- /// Packet output interface name (dev->name).
- OifName,
- /// Packet input interface type (dev->type).
- IifType,
- /// Packet output interface type (dev->type).
- OifType,
- /// Originating socket UID (fsuid).
- SkUid,
- /// Originating socket GID (fsgid).
- SkGid,
- /// Netfilter protocol (Transport layer protocol).
- NfProto,
- /// Layer 4 protocol number.
- L4Proto,
- /// Socket control group (skb->sk->sk_classid).
- Cgroup,
- /// A 32bit pseudo-random number
- PRandom,
-}
-
-impl Meta {
- /// Returns the corresponding `NFT_*` constant for this meta expression.
- pub fn to_raw_key(&self) -> u32 {
- use Meta::*;
- match *self {
- Protocol => libc::NFT_META_PROTOCOL as u32,
- Mark { .. } => libc::NFT_META_MARK as u32,
- Iif => libc::NFT_META_IIF as u32,
- Oif => libc::NFT_META_OIF as u32,
- IifName => libc::NFT_META_IIFNAME as u32,
- OifName => libc::NFT_META_OIFNAME as u32,
- IifType => libc::NFT_META_IIFTYPE as u32,
- OifType => libc::NFT_META_OIFTYPE as u32,
- SkUid => libc::NFT_META_SKUID as u32,
- SkGid => libc::NFT_META_SKGID as u32,
- NfProto => libc::NFT_META_NFPROTO as u32,
- L4Proto => libc::NFT_META_L4PROTO as u32,
- Cgroup => libc::NFT_META_CGROUP as u32,
- PRandom => libc::NFT_META_PRANDOM as u32,
- }
- }
-
- fn from_raw(val: u32) -> Result<Self, DeserializationError> {
- match val as i32 {
- libc::NFT_META_PROTOCOL => Ok(Self::Protocol),
- libc::NFT_META_MARK => Ok(Self::Mark { set: false }),
- libc::NFT_META_IIF => Ok(Self::Iif),
- libc::NFT_META_OIF => Ok(Self::Oif),
- libc::NFT_META_IIFNAME => Ok(Self::IifName),
- libc::NFT_META_OIFNAME => Ok(Self::OifName),
- libc::NFT_META_IIFTYPE => Ok(Self::IifType),
- libc::NFT_META_OIFTYPE => Ok(Self::OifType),
- libc::NFT_META_SKUID => Ok(Self::SkUid),
- libc::NFT_META_SKGID => Ok(Self::SkGid),
- libc::NFT_META_NFPROTO => Ok(Self::NfProto),
- libc::NFT_META_L4PROTO => Ok(Self::L4Proto),
- libc::NFT_META_CGROUP => Ok(Self::Cgroup),
- libc::NFT_META_PRANDOM => Ok(Self::PRandom),
- _ => Err(DeserializationError::InvalidValue),
- }
- }
-}
-
-impl Expression for Meta {
- fn get_raw_name() -> *const libc::c_char {
- b"meta\0" as *const _ as *const c_char
- }
-
- fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError>
- where
- Self: Sized,
- {
- unsafe {
- let mut ret = Self::from_raw(sys::nftnl_expr_get_u32(
- expr,
- sys::NFTNL_EXPR_META_KEY as u16,
- ))?;
-
- if let Self::Mark { ref mut set } = ret {
- *set = sys::nftnl_expr_is_set(expr, sys::NFTNL_EXPR_META_SREG as u16);
- }
-
- Ok(ret)
- }
- }
-
- fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
- unsafe {
- let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name()));
-
- if let Meta::Mark { set: true } = self {
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_META_SREG as u16,
- libc::NFT_REG_1 as u32,
- );
- } else {
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_META_DREG as u16,
- libc::NFT_REG_1 as u32,
- );
- }
- sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_META_KEY as u16, self.to_raw_key());
- expr
- }
- }
-}
-
-#[macro_export]
-macro_rules! nft_expr_meta {
- (proto) => {
- $crate::expr::Meta::Protocol
- };
- (mark set) => {
- $crate::expr::Meta::Mark { set: true }
- };
- (mark) => {
- $crate::expr::Meta::Mark { set: false }
- };
- (iif) => {
- $crate::expr::Meta::Iif
- };
- (oif) => {
- $crate::expr::Meta::Oif
- };
- (iifname) => {
- $crate::expr::Meta::IifName
- };
- (oifname) => {
- $crate::expr::Meta::OifName
- };
- (iiftype) => {
- $crate::expr::Meta::IifType
- };
- (oiftype) => {
- $crate::expr::Meta::OifType
- };
- (skuid) => {
- $crate::expr::Meta::SkUid
- };
- (skgid) => {
- $crate::expr::Meta::SkGid
- };
- (nfproto) => {
- $crate::expr::Meta::NfProto
- };
- (l4proto) => {
- $crate::expr::Meta::L4Proto
- };
- (cgroup) => {
- $crate::expr::Meta::Cgroup
- };
- (random) => {
- $crate::expr::Meta::PRandom
- };
-}
diff --git a/rustables/src/expr/mod.rs b/rustables/src/expr/mod.rs
deleted file mode 100644
index fbf49d6..0000000
--- a/rustables/src/expr/mod.rs
+++ /dev/null
@@ -1,242 +0,0 @@
-//! A module with all the nftables expressions that can be added to [`Rule`]s to build up how
-//! they match against packets.
-//!
-//! [`Rule`]: struct.Rule.html
-
-use std::borrow::Cow;
-use std::net::IpAddr;
-use std::net::Ipv4Addr;
-use std::net::Ipv6Addr;
-
-use super::rule::Rule;
-use crate::sys::{self, libc};
-use thiserror::Error;
-
-mod bitwise;
-pub use self::bitwise::*;
-
-mod cmp;
-pub use self::cmp::*;
-
-mod counter;
-pub use self::counter::*;
-
-pub mod ct;
-pub use self::ct::*;
-
-mod immediate;
-pub use self::immediate::*;
-
-mod log;
-pub use self::log::*;
-
-mod lookup;
-pub use self::lookup::*;
-
-mod masquerade;
-pub use self::masquerade::*;
-
-mod meta;
-pub use self::meta::*;
-
-mod nat;
-pub use self::nat::*;
-
-mod payload;
-pub use self::payload::*;
-
-mod reject;
-pub use self::reject::{IcmpCode, Reject};
-
-mod register;
-pub use self::register::Register;
-
-mod verdict;
-pub use self::verdict::*;
-
-mod wrapper;
-pub use self::wrapper::ExpressionWrapper;
-
-#[derive(Debug, Error)]
-pub enum DeserializationError {
- #[error("The expected expression type doesn't match the name of the raw expression")]
- /// The expected expression type doesn't match the name of the raw expression
- InvalidExpressionKind,
-
- #[error("Deserializing the requested type isn't implemented yet")]
- /// Deserializing the requested type isn't implemented yet
- NotImplemented,
-
- #[error("The expression value cannot be deserialized to the requested type")]
- /// The expression value cannot be deserialized to the requested type
- InvalidValue,
-
- #[error("A pointer was null while a non-null pointer was expected")]
- /// A pointer was null while a non-null pointer was expected
- NullPointer,
-
- #[error(
- "The size of a raw value was incoherent with the expected type of the deserialized value"
- )]
- /// The size of a raw value was incoherent with the expected type of the deserialized value
- InvalidDataSize,
-
- #[error(transparent)]
- /// Couldn't find a matching protocol
- InvalidProtolFamily(#[from] super::InvalidProtocolFamily),
-}
-
-/// Trait for every safe wrapper of an nftables expression.
-pub trait Expression {
- /// Returns the raw name used by nftables to identify the rule.
- fn get_raw_name() -> *const libc::c_char;
-
- /// Try to parse the expression from a raw nftables expression,
- /// returning a [DeserializationError] if the attempted parsing failed.
- fn from_expr(_expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError>
- where
- Self: Sized,
- {
- Err(DeserializationError::NotImplemented)
- }
-
- /// Allocates and returns the low level `nftnl_expr` representation of this expression.
- /// The caller to this method is responsible for freeing the expression.
- fn to_expr(&self, rule: &Rule) -> *mut sys::nftnl_expr;
-}
-
-/// A type that can be converted into a byte buffer.
-pub trait ToSlice {
- /// Returns the data this type represents.
- fn to_slice(&self) -> Cow<'_, [u8]>;
-}
-
-impl<'a> ToSlice for &'a [u8] {
- fn to_slice(&self) -> Cow<'_, [u8]> {
- Cow::Borrowed(self)
- }
-}
-
-impl<'a> ToSlice for &'a [u16] {
- fn to_slice(&self) -> Cow<'_, [u8]> {
- let ptr = self.as_ptr() as *const u8;
- let len = self.len() * 2;
- Cow::Borrowed(unsafe { std::slice::from_raw_parts(ptr, len) })
- }
-}
-
-impl ToSlice for IpAddr {
- fn to_slice(&self) -> Cow<'_, [u8]> {
- match *self {
- IpAddr::V4(ref addr) => addr.to_slice(),
- IpAddr::V6(ref addr) => addr.to_slice(),
- }
- }
-}
-
-impl ToSlice for Ipv4Addr {
- fn to_slice(&self) -> Cow<'_, [u8]> {
- Cow::Owned(self.octets().to_vec())
- }
-}
-
-impl ToSlice for Ipv6Addr {
- fn to_slice(&self) -> Cow<'_, [u8]> {
- Cow::Owned(self.octets().to_vec())
- }
-}
-
-impl ToSlice for u8 {
- fn to_slice(&self) -> Cow<'_, [u8]> {
- Cow::Owned(vec![*self])
- }
-}
-
-impl ToSlice for u16 {
- fn to_slice(&self) -> Cow<'_, [u8]> {
- let b0 = (*self & 0x00ff) as u8;
- let b1 = (*self >> 8) as u8;
- Cow::Owned(vec![b0, b1])
- }
-}
-
-impl ToSlice for u32 {
- fn to_slice(&self) -> Cow<'_, [u8]> {
- let b0 = *self as u8;
- let b1 = (*self >> 8) as u8;
- let b2 = (*self >> 16) as u8;
- let b3 = (*self >> 24) as u8;
- Cow::Owned(vec![b0, b1, b2, b3])
- }
-}
-
-impl ToSlice for i32 {
- fn to_slice(&self) -> Cow<'_, [u8]> {
- let b0 = *self as u8;
- let b1 = (*self >> 8) as u8;
- let b2 = (*self >> 16) as u8;
- let b3 = (*self >> 24) as u8;
- Cow::Owned(vec![b0, b1, b2, b3])
- }
-}
-
-impl<'a> ToSlice for &'a str {
- fn to_slice(&self) -> Cow<'_, [u8]> {
- Cow::from(self.as_bytes())
- }
-}
-
-#[macro_export(local_inner_macros)]
-macro_rules! nft_expr {
- (bitwise mask $mask:expr,xor $xor:expr) => {
- nft_expr_bitwise!(mask $mask, xor $xor)
- };
- (cmp $op:tt $data:expr) => {
- nft_expr_cmp!($op $data)
- };
- (counter) => {
- $crate::expr::Counter { nb_bytes: 0, nb_packets: 0}
- };
- (ct $key:ident set) => {
- nft_expr_ct!($key set)
- };
- (ct $key:ident) => {
- nft_expr_ct!($key)
- };
- (immediate $expr:ident $value:expr) => {
- nft_expr_immediate!($expr $value)
- };
- (log group $group:ident prefix $prefix:expr) => {
- nft_expr_log!(group $group prefix $prefix)
- };
- (log group $group:ident) => {
- nft_expr_log!(group $group)
- };
- (log prefix $prefix:expr) => {
- nft_expr_log!(prefix $prefix)
- };
- (log) => {
- nft_expr_log!()
- };
- (lookup $set:expr) => {
- nft_expr_lookup!($set)
- };
- (masquerade) => {
- $crate::expr::Masquerade
- };
- (meta $expr:ident set) => {
- nft_expr_meta!($expr set)
- };
- (meta $expr:ident) => {
- nft_expr_meta!($expr)
- };
- (payload $proto:ident $field:ident) => {
- nft_expr_payload!($proto $field)
- };
- (verdict $verdict:ident) => {
- nft_expr_verdict!($verdict)
- };
- (verdict $verdict:ident $chain:expr) => {
- nft_expr_verdict!($verdict $chain)
- };
-}
diff --git a/rustables/src/expr/nat.rs b/rustables/src/expr/nat.rs
deleted file mode 100644
index 8beaa30..0000000
--- a/rustables/src/expr/nat.rs
+++ /dev/null
@@ -1,99 +0,0 @@
-use super::{DeserializationError, Expression, Register, Rule};
-use crate::ProtoFamily;
-use crate::sys::{self, libc};
-use std::{convert::TryFrom, os::raw::c_char};
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-#[repr(i32)]
-pub enum NatType {
- /// Source NAT. Changes the source address of a packet
- SNat = libc::NFT_NAT_SNAT,
- /// Destination NAT. Changeth the destination address of a packet
- DNat = libc::NFT_NAT_DNAT,
-}
-
-impl NatType {
- fn from_raw(val: u32) -> Result<Self, DeserializationError> {
- match val as i32 {
- libc::NFT_NAT_SNAT => Ok(NatType::SNat),
- libc::NFT_NAT_DNAT => Ok(NatType::DNat),
- _ => Err(DeserializationError::InvalidValue),
- }
- }
-}
-
-/// A source or destination NAT statement. Modifies the source or destination address
-/// (and possibly port) of packets.
-#[derive(Debug, PartialEq)]
-pub struct Nat {
- pub nat_type: NatType,
- pub family: ProtoFamily,
- pub ip_register: Register,
- pub port_register: Option<Register>,
-}
-
-impl Expression for Nat {
- fn get_raw_name() -> *const libc::c_char {
- b"nat\0" as *const _ as *const c_char
- }
-
- fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError>
- where
- Self: Sized,
- {
- unsafe {
- let nat_type = NatType::from_raw(sys::nftnl_expr_get_u32(
- expr,
- sys::NFTNL_EXPR_NAT_TYPE as u16,
- ))?;
-
- let family = ProtoFamily::try_from(sys::nftnl_expr_get_u32(
- expr,
- sys::NFTNL_EXPR_NAT_FAMILY as u16,
- ) as i32)?;
-
- let ip_register = Register::from_raw(sys::nftnl_expr_get_u32(
- expr,
- sys::NFTNL_EXPR_NAT_REG_ADDR_MIN as u16,
- ))?;
-
- let mut port_register = None;
- if sys::nftnl_expr_is_set(expr, sys::NFTNL_EXPR_NAT_REG_PROTO_MIN as u16) {
- port_register = Some(Register::from_raw(sys::nftnl_expr_get_u32(
- expr,
- sys::NFTNL_EXPR_NAT_REG_PROTO_MIN as u16,
- ))?);
- }
-
- Ok(Nat {
- ip_register,
- nat_type,
- family,
- port_register,
- })
- }
- }
-
- fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
- let expr = try_alloc!(unsafe { sys::nftnl_expr_alloc(Self::get_raw_name()) });
-
- unsafe {
- sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_NAT_TYPE as u16, self.nat_type as u32);
- sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_NAT_FAMILY as u16, self.family as u32);
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_NAT_REG_ADDR_MIN as u16,
- self.ip_register.to_raw(),
- );
- if let Some(port_register) = self.port_register {
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_NAT_REG_PROTO_MIN as u16,
- port_register.to_raw(),
- );
- }
- }
-
- expr
- }
-}
diff --git a/rustables/src/expr/payload.rs b/rustables/src/expr/payload.rs
deleted file mode 100644
index 7612fd9..0000000
--- a/rustables/src/expr/payload.rs
+++ /dev/null
@@ -1,531 +0,0 @@
-use super::{DeserializationError, Expression, Rule};
-use crate::sys::{self, libc};
-use std::os::raw::c_char;
-
-pub trait HeaderField {
- fn offset(&self) -> u32;
- fn len(&self) -> u32;
-}
-
-/// Payload expressions refer to data from the packet's payload.
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum Payload {
- LinkLayer(LLHeaderField),
- Network(NetworkHeaderField),
- Transport(TransportHeaderField),
-}
-
-impl Payload {
- pub fn build(&self) -> RawPayload {
- match *self {
- Payload::LinkLayer(ref f) => RawPayload::LinkLayer(RawPayloadData {
- offset: f.offset(),
- len: f.len(),
- }),
- Payload::Network(ref f) => RawPayload::Network(RawPayloadData {
- offset: f.offset(),
- len: f.len(),
- }),
- Payload::Transport(ref f) => RawPayload::Transport(RawPayloadData {
- offset: f.offset(),
- len: f.offset(),
- }),
- }
- }
-}
-
-impl Expression for Payload {
- fn get_raw_name() -> *const libc::c_char {
- RawPayload::get_raw_name()
- }
-
- fn to_expr(&self, rule: &Rule) -> *mut sys::nftnl_expr {
- self.build().to_expr(rule)
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub struct RawPayloadData {
- offset: u32,
- len: u32,
-}
-
-/// Because deserializing a `Payload` expression is not possible (there is not enough information
-/// in the expression itself, this enum should be used to deserialize payloads.
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum RawPayload {
- LinkLayer(RawPayloadData),
- Network(RawPayloadData),
- Transport(RawPayloadData),
-}
-
-impl RawPayload {
- fn base(&self) -> u32 {
- match self {
- Self::LinkLayer(_) => libc::NFT_PAYLOAD_LL_HEADER as u32,
- Self::Network(_) => libc::NFT_PAYLOAD_NETWORK_HEADER as u32,
- Self::Transport(_) => libc::NFT_PAYLOAD_TRANSPORT_HEADER as u32,
- }
- }
-}
-
-impl HeaderField for RawPayload {
- fn offset(&self) -> u32 {
- match self {
- Self::LinkLayer(ref f) | Self::Network(ref f) | Self::Transport(ref f) => f.offset,
- }
- }
-
- fn len(&self) -> u32 {
- match self {
- Self::LinkLayer(ref f) | Self::Network(ref f) | Self::Transport(ref f) => f.len,
- }
- }
-}
-
-impl Expression for RawPayload {
- fn get_raw_name() -> *const libc::c_char {
- b"payload\0" as *const _ as *const c_char
- }
-
- fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError> {
- unsafe {
- let base = sys::nftnl_expr_get_u32(expr, sys::NFTNL_EXPR_PAYLOAD_BASE as u16);
- let offset = sys::nftnl_expr_get_u32(expr, sys::NFTNL_EXPR_PAYLOAD_OFFSET as u16);
- let len = sys::nftnl_expr_get_u32(expr, sys::NFTNL_EXPR_PAYLOAD_LEN as u16);
- match base as i32 {
- libc::NFT_PAYLOAD_LL_HEADER => Ok(Self::LinkLayer(RawPayloadData { offset, len })),
- libc::NFT_PAYLOAD_NETWORK_HEADER => {
- Ok(Self::Network(RawPayloadData { offset, len }))
- }
- libc::NFT_PAYLOAD_TRANSPORT_HEADER => {
- Ok(Self::Transport(RawPayloadData { offset, len }))
- }
-
- _ => return Err(DeserializationError::InvalidValue),
- }
- }
- }
-
- fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
- unsafe {
- let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name()));
-
- sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_PAYLOAD_BASE as u16, self.base());
- sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_PAYLOAD_OFFSET as u16, self.offset());
- sys::nftnl_expr_set_u32(expr, sys::NFTNL_EXPR_PAYLOAD_LEN as u16, self.len());
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_PAYLOAD_DREG as u16,
- libc::NFT_REG_1 as u32,
- );
-
- expr
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[non_exhaustive]
-pub enum LLHeaderField {
- Daddr,
- Saddr,
- EtherType,
-}
-
-impl HeaderField for LLHeaderField {
- fn offset(&self) -> u32 {
- use self::LLHeaderField::*;
- match *self {
- Daddr => 0,
- Saddr => 6,
- EtherType => 12,
- }
- }
-
- fn len(&self) -> u32 {
- use self::LLHeaderField::*;
- match *self {
- Daddr => 6,
- Saddr => 6,
- EtherType => 2,
- }
- }
-}
-
-impl LLHeaderField {
- pub fn from_raw_data(data: &RawPayloadData) -> Result<Self, DeserializationError> {
- let off = data.offset;
- let len = data.len;
-
- if off == 0 && len == 6 {
- Ok(Self::Daddr)
- } else if off == 6 && len == 6 {
- Ok(Self::Saddr)
- } else if off == 12 && len == 2 {
- Ok(Self::EtherType)
- } else {
- Err(DeserializationError::InvalidValue)
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-pub enum NetworkHeaderField {
- Ipv4(Ipv4HeaderField),
- Ipv6(Ipv6HeaderField),
-}
-
-impl HeaderField for NetworkHeaderField {
- fn offset(&self) -> u32 {
- use self::NetworkHeaderField::*;
- match *self {
- Ipv4(ref f) => f.offset(),
- Ipv6(ref f) => f.offset(),
- }
- }
-
- fn len(&self) -> u32 {
- use self::NetworkHeaderField::*;
- match *self {
- Ipv4(ref f) => f.len(),
- Ipv6(ref f) => f.len(),
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[non_exhaustive]
-pub enum Ipv4HeaderField {
- Ttl,
- Protocol,
- Saddr,
- Daddr,
-}
-
-impl HeaderField for Ipv4HeaderField {
- fn offset(&self) -> u32 {
- use self::Ipv4HeaderField::*;
- match *self {
- Ttl => 8,
- Protocol => 9,
- Saddr => 12,
- Daddr => 16,
- }
- }
-
- fn len(&self) -> u32 {
- use self::Ipv4HeaderField::*;
- match *self {
- Ttl => 1,
- Protocol => 1,
- Saddr => 4,
- Daddr => 4,
- }
- }
-}
-
-impl Ipv4HeaderField {
- pub fn from_raw_data(data: &RawPayloadData) -> Result<Self, DeserializationError> {
- let off = data.offset;
- let len = data.len;
-
- if off == 8 && len == 1 {
- Ok(Self::Ttl)
- } else if off == 9 && len == 1 {
- Ok(Self::Protocol)
- } else if off == 12 && len == 4 {
- Ok(Self::Saddr)
- } else if off == 16 && len == 4 {
- Ok(Self::Daddr)
- } else {
- Err(DeserializationError::InvalidValue)
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[non_exhaustive]
-pub enum Ipv6HeaderField {
- NextHeader,
- HopLimit,
- Saddr,
- Daddr,
-}
-
-impl HeaderField for Ipv6HeaderField {
- fn offset(&self) -> u32 {
- use self::Ipv6HeaderField::*;
- match *self {
- NextHeader => 6,
- HopLimit => 7,
- Saddr => 8,
- Daddr => 24,
- }
- }
-
- fn len(&self) -> u32 {
- use self::Ipv6HeaderField::*;
- match *self {
- NextHeader => 1,
- HopLimit => 1,
- Saddr => 16,
- Daddr => 16,
- }
- }
-}
-
-impl Ipv6HeaderField {
- pub fn from_raw_data(data: &RawPayloadData) -> Result<Self, DeserializationError> {
- let off = data.offset;
- let len = data.len;
-
- if off == 6 && len == 1 {
- Ok(Self::NextHeader)
- } else if off == 7 && len == 1 {
- Ok(Self::HopLimit)
- } else if off == 8 && len == 16 {
- Ok(Self::Saddr)
- } else if off == 24 && len == 16 {
- Ok(Self::Daddr)
- } else {
- Err(DeserializationError::InvalidValue)
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[non_exhaustive]
-pub enum TransportHeaderField {
- Tcp(TcpHeaderField),
- Udp(UdpHeaderField),
- Icmpv6(Icmpv6HeaderField),
-}
-
-impl HeaderField for TransportHeaderField {
- fn offset(&self) -> u32 {
- use self::TransportHeaderField::*;
- match *self {
- Tcp(ref f) => f.offset(),
- Udp(ref f) => f.offset(),
- Icmpv6(ref f) => f.offset(),
- }
- }
-
- fn len(&self) -> u32 {
- use self::TransportHeaderField::*;
- match *self {
- Tcp(ref f) => f.len(),
- Udp(ref f) => f.len(),
- Icmpv6(ref f) => f.len(),
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[non_exhaustive]
-pub enum TcpHeaderField {
- Sport,
- Dport,
-}
-
-impl HeaderField for TcpHeaderField {
- fn offset(&self) -> u32 {
- use self::TcpHeaderField::*;
- match *self {
- Sport => 0,
- Dport => 2,
- }
- }
-
- fn len(&self) -> u32 {
- use self::TcpHeaderField::*;
- match *self {
- Sport => 2,
- Dport => 2,
- }
- }
-}
-
-impl TcpHeaderField {
- pub fn from_raw_data(data: &RawPayloadData) -> Result<Self, DeserializationError> {
- let off = data.offset;
- let len = data.len;
-
- if off == 0 && len == 2 {
- Ok(Self::Sport)
- } else if off == 2 && len == 2 {
- Ok(Self::Dport)
- } else {
- Err(DeserializationError::InvalidValue)
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[non_exhaustive]
-pub enum UdpHeaderField {
- Sport,
- Dport,
- Len,
-}
-
-impl HeaderField for UdpHeaderField {
- fn offset(&self) -> u32 {
- use self::UdpHeaderField::*;
- match *self {
- Sport => 0,
- Dport => 2,
- Len => 4,
- }
- }
-
- fn len(&self) -> u32 {
- use self::UdpHeaderField::*;
- match *self {
- Sport => 2,
- Dport => 2,
- Len => 2,
- }
- }
-}
-
-impl UdpHeaderField {
- pub fn from_raw_data(data: &RawPayloadData) -> Result<Self, DeserializationError> {
- let off = data.offset;
- let len = data.len;
-
- if off == 0 && len == 2 {
- Ok(Self::Sport)
- } else if off == 2 && len == 2 {
- Ok(Self::Dport)
- } else if off == 4 && len == 2 {
- Ok(Self::Len)
- } else {
- Err(DeserializationError::InvalidValue)
- }
- }
-}
-
-#[derive(Debug, Copy, Clone, Eq, PartialEq)]
-#[non_exhaustive]
-pub enum Icmpv6HeaderField {
- Type,
- Code,
- Checksum,
-}
-
-impl HeaderField for Icmpv6HeaderField {
- fn offset(&self) -> u32 {
- use self::Icmpv6HeaderField::*;
- match *self {
- Type => 0,
- Code => 1,
- Checksum => 2,
- }
- }
-
- fn len(&self) -> u32 {
- use self::Icmpv6HeaderField::*;
- match *self {
- Type => 1,
- Code => 1,
- Checksum => 2,
- }
- }
-}
-
-impl Icmpv6HeaderField {
- pub fn from_raw_data(data: &RawPayloadData) -> Result<Self, DeserializationError> {
- let off = data.offset;
- let len = data.len;
-
- if off == 0 && len == 1 {
- Ok(Self::Type)
- } else if off == 1 && len == 1 {
- Ok(Self::Code)
- } else if off == 2 && len == 2 {
- Ok(Self::Checksum)
- } else {
- Err(DeserializationError::InvalidValue)
- }
- }
-}
-
-#[macro_export(local_inner_macros)]
-macro_rules! nft_expr_payload {
- (@ipv4_field ttl) => {
- $crate::expr::Ipv4HeaderField::Ttl
- };
- (@ipv4_field protocol) => {
- $crate::expr::Ipv4HeaderField::Protocol
- };
- (@ipv4_field saddr) => {
- $crate::expr::Ipv4HeaderField::Saddr
- };
- (@ipv4_field daddr) => {
- $crate::expr::Ipv4HeaderField::Daddr
- };
-
- (@ipv6_field nextheader) => {
- $crate::expr::Ipv6HeaderField::NextHeader
- };
- (@ipv6_field hoplimit) => {
- $crate::expr::Ipv6HeaderField::HopLimit
- };
- (@ipv6_field saddr) => {
- $crate::expr::Ipv6HeaderField::Saddr
- };
- (@ipv6_field daddr) => {
- $crate::expr::Ipv6HeaderField::Daddr
- };
-
- (@tcp_field sport) => {
- $crate::expr::TcpHeaderField::Sport
- };
- (@tcp_field dport) => {
- $crate::expr::TcpHeaderField::Dport
- };
-
- (@udp_field sport) => {
- $crate::expr::UdpHeaderField::Sport
- };
- (@udp_field dport) => {
- $crate::expr::UdpHeaderField::Dport
- };
- (@udp_field len) => {
- $crate::expr::UdpHeaderField::Len
- };
-
- (ethernet daddr) => {
- $crate::expr::Payload::LinkLayer($crate::expr::LLHeaderField::Daddr)
- };
- (ethernet saddr) => {
- $crate::expr::Payload::LinkLayer($crate::expr::LLHeaderField::Saddr)
- };
- (ethernet ethertype) => {
- $crate::expr::Payload::LinkLayer($crate::expr::LLHeaderField::EtherType)
- };
-
- (ipv4 $field:ident) => {
- $crate::expr::Payload::Network($crate::expr::NetworkHeaderField::Ipv4(
- nft_expr_payload!(@ipv4_field $field),
- ))
- };
- (ipv6 $field:ident) => {
- $crate::expr::Payload::Network($crate::expr::NetworkHeaderField::Ipv6(
- nft_expr_payload!(@ipv6_field $field),
- ))
- };
-
- (tcp $field:ident) => {
- $crate::expr::Payload::Transport($crate::expr::TransportHeaderField::Tcp(
- nft_expr_payload!(@tcp_field $field),
- ))
- };
- (udp $field:ident) => {
- $crate::expr::Payload::Transport($crate::expr::TransportHeaderField::Udp(
- nft_expr_payload!(@udp_field $field),
- ))
- };
-}
diff --git a/rustables/src/expr/register.rs b/rustables/src/expr/register.rs
deleted file mode 100644
index f0aed94..0000000
--- a/rustables/src/expr/register.rs
+++ /dev/null
@@ -1,34 +0,0 @@
-use std::fmt::Debug;
-
-use crate::sys::libc;
-
-use super::DeserializationError;
-
-/// A netfilter data register. The expressions store and read data to and from these
-/// when evaluating rule statements.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-#[repr(i32)]
-pub enum Register {
- Verdict = libc::NFT_REG_VERDICT,
- Reg1 = libc::NFT_REG_1,
- Reg2 = libc::NFT_REG_2,
- Reg3 = libc::NFT_REG_3,
- Reg4 = libc::NFT_REG_4,
-}
-
-impl Register {
- pub fn to_raw(self) -> u32 {
- self as u32
- }
-
- pub fn from_raw(val: u32) -> Result<Self, DeserializationError> {
- match val as i32 {
- libc::NFT_REG_VERDICT => Ok(Self::Verdict),
- libc::NFT_REG_1 => Ok(Self::Reg1),
- libc::NFT_REG_2 => Ok(Self::Reg2),
- libc::NFT_REG_3 => Ok(Self::Reg3),
- libc::NFT_REG_4 => Ok(Self::Reg4),
- _ => Err(DeserializationError::InvalidValue),
- }
- }
-}
diff --git a/rustables/src/expr/reject.rs b/rustables/src/expr/reject.rs
deleted file mode 100644
index 2ea0cbf..0000000
--- a/rustables/src/expr/reject.rs
+++ /dev/null
@@ -1,96 +0,0 @@
-use super::{DeserializationError, Expression, Rule};
-use crate::ProtoFamily;
-use crate::sys::{self, libc::{self, c_char}};
-
-/// A reject expression that defines the type of rejection message sent
-/// when discarding a packet.
-#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
-pub enum Reject {
- /// Return an ICMP unreachable packet
- Icmp(IcmpCode),
- /// Reject by sending a TCP RST packet
- TcpRst,
-}
-
-impl Reject {
- fn to_raw(&self, family: ProtoFamily) -> u32 {
- use libc::*;
- let value = match *self {
- Self::Icmp(..) => match family {
- ProtoFamily::Bridge | ProtoFamily::Inet => NFT_REJECT_ICMPX_UNREACH,
- _ => NFT_REJECT_ICMP_UNREACH,
- },
- Self::TcpRst => NFT_REJECT_TCP_RST,
- };
- value as u32
- }
-}
-
-impl Expression for Reject {
- fn get_raw_name() -> *const libc::c_char {
- b"reject\0" as *const _ as *const c_char
- }
-
- fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError>
- where
- Self: Sized,
- {
- unsafe {
- if sys::nftnl_expr_get_u32(expr, sys::NFTNL_EXPR_REJECT_TYPE as u16)
- == libc::NFT_REJECT_TCP_RST as u32
- {
- Ok(Self::TcpRst)
- } else {
- Ok(Self::Icmp(IcmpCode::from_raw(sys::nftnl_expr_get_u8(
- expr,
- sys::NFTNL_EXPR_REJECT_CODE as u16,
- ))?))
- }
- }
- }
-
- fn to_expr(&self, rule: &Rule) -> *mut sys::nftnl_expr {
- let family = rule.get_chain().get_table().get_family();
-
- unsafe {
- let expr = try_alloc!(sys::nftnl_expr_alloc(Self::get_raw_name()));
-
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_REJECT_TYPE as u16,
- self.to_raw(family),
- );
-
- let reject_code = match *self {
- Reject::Icmp(code) => code as u8,
- Reject::TcpRst => 0,
- };
-
- sys::nftnl_expr_set_u8(expr, sys::NFTNL_EXPR_REJECT_CODE as u16, reject_code);
-
- expr
- }
- }
-}
-
-/// An ICMP reject code.
-#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
-#[repr(u8)]
-pub enum IcmpCode {
- NoRoute = libc::NFT_REJECT_ICMPX_NO_ROUTE as u8,
- PortUnreach = libc::NFT_REJECT_ICMPX_PORT_UNREACH as u8,
- HostUnreach = libc::NFT_REJECT_ICMPX_HOST_UNREACH as u8,
- AdminProhibited = libc::NFT_REJECT_ICMPX_ADMIN_PROHIBITED as u8,
-}
-
-impl IcmpCode {
- fn from_raw(code: u8) -> Result<Self, DeserializationError> {
- match code as i32 {
- libc::NFT_REJECT_ICMPX_NO_ROUTE => Ok(Self::NoRoute),
- libc::NFT_REJECT_ICMPX_PORT_UNREACH => Ok(Self::PortUnreach),
- libc::NFT_REJECT_ICMPX_HOST_UNREACH => Ok(Self::HostUnreach),
- libc::NFT_REJECT_ICMPX_ADMIN_PROHIBITED => Ok(Self::AdminProhibited),
- _ => Err(DeserializationError::InvalidValue),
- }
- }
-}
diff --git a/rustables/src/expr/verdict.rs b/rustables/src/expr/verdict.rs
deleted file mode 100644
index 3c4c374..0000000
--- a/rustables/src/expr/verdict.rs
+++ /dev/null
@@ -1,148 +0,0 @@
-use super::{DeserializationError, Expression, Rule};
-use crate::sys::{self, libc::{self, c_char}};
-use std::ffi::{CStr, CString};
-
-/// A verdict expression. In the background, this is usually an "Immediate" expression in nftnl
-/// terms, but here it is simplified to only represent a verdict.
-#[derive(Debug, Clone, Eq, PartialEq, Hash)]
-pub enum Verdict {
- /// Silently drop the packet.
- Drop,
- /// Accept the packet and let it pass.
- Accept,
- Queue,
- Continue,
- Break,
- Jump {
- chain: CString,
- },
- Goto {
- chain: CString,
- },
- Return,
-}
-
-impl Verdict {
- fn chain(&self) -> Option<&CStr> {
- match *self {
- Verdict::Jump { ref chain } => Some(chain.as_c_str()),
- Verdict::Goto { ref chain } => Some(chain.as_c_str()),
- _ => None,
- }
- }
-}
-
-impl Expression for Verdict {
- fn get_raw_name() -> *const libc::c_char {
- b"immediate\0" as *const _ as *const c_char
- }
-
- fn from_expr(expr: *const sys::nftnl_expr) -> Result<Self, DeserializationError> {
- unsafe {
- let mut chain = None;
- if sys::nftnl_expr_is_set(expr, sys::NFTNL_EXPR_IMM_CHAIN as u16) {
- let raw_chain = sys::nftnl_expr_get_str(expr, sys::NFTNL_EXPR_IMM_CHAIN as u16);
-
- if raw_chain.is_null() {
- return Err(DeserializationError::NullPointer);
- }
- chain = Some(CStr::from_ptr(raw_chain).to_owned());
- }
-
- let verdict = sys::nftnl_expr_get_u32(expr, sys::NFTNL_EXPR_IMM_VERDICT as u16);
-
- match verdict as i32 {
- libc::NF_DROP => Ok(Verdict::Drop),
- libc::NF_ACCEPT => Ok(Verdict::Accept),
- libc::NF_QUEUE => Ok(Verdict::Queue),
- libc::NFT_CONTINUE => Ok(Verdict::Continue),
- libc::NFT_BREAK => Ok(Verdict::Break),
- libc::NFT_JUMP => {
- if let Some(chain) = chain {
- Ok(Verdict::Jump { chain })
- } else {
- Err(DeserializationError::InvalidValue)
- }
- }
- libc::NFT_GOTO => {
- if let Some(chain) = chain {
- Ok(Verdict::Goto { chain })
- } else {
- Err(DeserializationError::InvalidValue)
- }
- }
- libc::NFT_RETURN => Ok(Verdict::Return),
- _ => Err(DeserializationError::InvalidValue),
- }
- }
- }
-
- fn to_expr(&self, _rule: &Rule) -> *mut sys::nftnl_expr {
- let immediate_const = match *self {
- Verdict::Drop => libc::NF_DROP,
- Verdict::Accept => libc::NF_ACCEPT,
- Verdict::Queue => libc::NF_QUEUE,
- Verdict::Continue => libc::NFT_CONTINUE,
- Verdict::Break => libc::NFT_BREAK,
- Verdict::Jump { .. } => libc::NFT_JUMP,
- Verdict::Goto { .. } => libc::NFT_GOTO,
- Verdict::Return => libc::NFT_RETURN,
- };
- unsafe {
- let expr = try_alloc!(sys::nftnl_expr_alloc(
- b"immediate\0" as *const _ as *const c_char
- ));
-
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_IMM_DREG as u16,
- libc::NFT_REG_VERDICT as u32,
- );
-
- if let Some(chain) = self.chain() {
- sys::nftnl_expr_set_str(expr, sys::NFTNL_EXPR_IMM_CHAIN as u16, chain.as_ptr());
- }
- sys::nftnl_expr_set_u32(
- expr,
- sys::NFTNL_EXPR_IMM_VERDICT as u16,
- immediate_const as u32,
- );
-
- expr
- }
- }
-}
-
-#[macro_export]
-macro_rules! nft_expr_verdict {
- (drop) => {
- $crate::expr::Verdict::Drop
- };
- (accept) => {
- $crate::expr::Verdict::Accept
- };
- (reject icmp $code:expr) => {
- $crate::expr::Verdict::Reject(RejectionType::Icmp($code))
- };
- (reject tcp-rst) => {
- $crate::expr::Verdict::Reject(RejectionType::TcpRst)
- };
- (queue) => {
- $crate::expr::Verdict::Queue
- };
- (continue) => {
- $crate::expr::Verdict::Continue
- };
- (break) => {
- $crate::expr::Verdict::Break
- };
- (jump $chain:expr) => {
- $crate::expr::Verdict::Jump { chain: $chain }
- };
- (goto $chain:expr) => {
- $crate::expr::Verdict::Goto { chain: $chain }
- };
- (return) => {
- $crate::expr::Verdict::Return
- };
-}
diff --git a/rustables/src/expr/wrapper.rs b/rustables/src/expr/wrapper.rs
deleted file mode 100644
index 1bcc520..0000000
--- a/rustables/src/expr/wrapper.rs
+++ /dev/null
@@ -1,60 +0,0 @@
-use std::ffi::CStr;
-use std::ffi::CString;
-use std::fmt::Debug;
-use std::rc::Rc;
-
-use super::{DeserializationError, Expression};
-use crate::{sys, Rule};
-
-pub struct ExpressionWrapper {
- pub(crate) expr: *const sys::nftnl_expr,
- // we also need the rule here to ensure that the rule lives as long as the `expr` pointer
- #[allow(dead_code)]
- pub(crate) rule: Rc<Rule>,
-}
-
-impl Debug for ExpressionWrapper {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{:?}", self.get_str())
- }
-}
-
-impl ExpressionWrapper {
- /// Retrieves a textual description of the expression.
- pub fn get_str(&self) -> CString {
- let mut descr_buf = vec![0i8; 4096];
- unsafe {
- sys::nftnl_expr_snprintf(
- descr_buf.as_mut_ptr(),
- (descr_buf.len() - 1) as u64,
- self.expr,
- sys::NFTNL_OUTPUT_DEFAULT,
- 0,
- );
- CStr::from_ptr(descr_buf.as_ptr()).to_owned()
- }
- }
-
- /// Retrieves the type of expression ("log", "counter", ...).
- pub fn get_kind(&self) -> Option<&CStr> {
- unsafe {
- let ptr = sys::nftnl_expr_get_str(self.expr, sys::NFTNL_EXPR_NAME as u16);
- if !ptr.is_null() {
- Some(CStr::from_ptr(ptr))
- } else {
- None
- }
- }
- }
-
- /// Attempt to decode the expression as the type T.
- pub fn decode_expr<T: Expression>(&self) -> Result<T, DeserializationError> {
- if let Some(kind) = self.get_kind() {
- let raw_name = unsafe { CStr::from_ptr(T::get_raw_name()) };
- if kind == raw_name {
- return T::from_expr(self.expr);
- }
- }
- Err(DeserializationError::InvalidExpressionKind)
- }
-}
diff --git a/rustables/src/lib.rs b/rustables/src/lib.rs
deleted file mode 100644
index 6eedf9f..0000000
--- a/rustables/src/lib.rs
+++ /dev/null
@@ -1,205 +0,0 @@
-// Copyryght (c) 2021 GPL lafleur@boum.org and Simon Thoby
-//
-// This file is free software: you may copy, redistribute and/or modify it
-// under the terms of the GNU General Public License as published by the
-// Free Software Foundation, either version 3 of the License, or (at your
-// option) any later version.
-//
-// This file is distributed in the hope that it will be useful, but
-// WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-// General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see the LICENSE file.
-//
-// This file incorporates work covered by the following copyright and
-// permission notice:
-//
-// Copyright 2018 Amagicom AB.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Safe abstraction for [`libnftnl`]. Provides low-level userspace access to the in-kernel
-//! nf_tables subsystem. See [`rustables-sys`] for the low level FFI bindings to the C library.
-//!
-//! Can be used to create and remove tables, chains, sets and rules from the nftables firewall,
-//! the successor to iptables.
-//!
-//! This library currently has quite rough edges and does not make adding and removing netfilter
-//! entries super easy and elegant. That is partly because the library needs more work, but also
-//! partly because nftables is super low level and extremely customizable, making it hard, and
-//! probably wrong, to try and create a too simple/limited wrapper. See examples for inspiration.
-//! One can also look at how the original project this crate was developed to support uses it:
-//! [Mullvad VPN app](https://github.com/mullvad/mullvadvpn-app)
-//!
-//! Understanding how to use [`libnftnl`] and implementing this crate has mostly been done by
-//! reading the source code for the [`nftables`] program and attaching debuggers to the `nft`
-//! binary. Since the implementation is mostly based on trial and error, there might of course be
-//! a number of places where the underlying library is used in an invalid or not intended way.
-//! Large portions of [`libnftnl`] are also not covered yet. Contributions are welcome!
-//!
-//! # Selecting version of `libnftnl`
-//!
-//! See the documentation for the corresponding sys crate for details: [`rustables-sys`].
-//! This crate has the same features as the sys crate, and selecting version works the same.
-//!
-//! # Access to raw handles
-//!
-//! Retrieving raw handles is considered unsafe and should only ever be enabled if you absoluetely
-//! need it. It is disabled by default and hidden behind the feature gate `unsafe-raw-handles`.
-//! The reason for that special treatment is we cannot guarantee the lack of aliasing. For example,
-//! a program using a const handle to a object in a thread and writing through a mutable handle
-//! in another could reach all kind of undefined (and dangerous!) behaviors.
-//! By enabling that feature flag, you acknowledge that guaranteeing the respect of safety
-//! invariants is now your responsibility!
-//! Despite these shortcomings, that feature is still available because it may allow you to perform
-//! manipulations that this library doesn't currently expose. If that is your case, we would
-//! be very happy to hear from you and maybe help you get the necessary functionality upstream.
-//!
-//! Our current lack of confidence in our availability to provide a safe abstraction over the
-//! use of raw handles in the face of concurrency is the reason we decided to settly on `Rc`
-//! pointers instead of `Arc` (besides, this should gives us some nice performance boost, not
-//! that it matters much of course) and why we do not declare the types exposes by the library
-//! as `Send` nor `Sync`.
-//!
-//! [`libnftnl`]: https://netfilter.org/projects/libnftnl/
-//! [`nftables`]: https://netfilter.org/projects/nftables/
-//! [`rustables-sys`]: https://crates.io/crates/rustables-sys
-
-use thiserror::Error;
-
-#[macro_use]
-extern crate log;
-
-pub mod sys;
-use sys::libc;
-use std::{convert::TryFrom, ffi::c_void, ops::Deref};
-
-macro_rules! try_alloc {
- ($e:expr) => {{
- let ptr = $e;
- if ptr.is_null() {
- // OOM, and the tried allocation was likely very small,
- // so we are in a very tight situation. We do what libstd does, aborts.
- std::process::abort();
- }
- ptr
- }};
-}
-
-mod batch;
-#[cfg(feature = "query")]
-pub use batch::{batch_is_supported, default_batch_page_size};
-pub use batch::{Batch, FinalizedBatch, NetlinkError};
-
-pub mod expr;
-
-pub mod table;
-pub use table::Table;
-#[cfg(feature = "query")]
-pub use table::{get_tables_cb, list_tables};
-
-mod chain;
-#[cfg(feature = "query")]
-pub use chain::{get_chains_cb, list_chains_for_table};
-pub use chain::{Chain, ChainType, Hook, Policy, Priority};
-
-pub mod query;
-
-mod rule;
-pub use rule::Rule;
-#[cfg(feature = "query")]
-pub use rule::{get_rules_cb, list_rules_for_chain};
-
-pub mod set;
-
-/// The type of the message as it's sent to netfilter. A message consists of an object, such as a
-/// [`Table`], [`Chain`] or [`Rule`] for example, and a [`MsgType`] to describe what to do with
-/// that object. If a [`Table`] object is sent with `MsgType::Add` then that table will be added
-/// to netfilter, if sent with `MsgType::Del` it will be removed.
-///
-/// [`Table`]: struct.Table.html
-/// [`Chain`]: struct.Chain.html
-/// [`Rule`]: struct.Rule.html
-/// [`MsgType`]: enum.MsgType.html
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-pub enum MsgType {
- /// Add the object to netfilter.
- Add,
- /// Remove the object from netfilter.
- Del,
-}
-
-/// Denotes a protocol. Used to specify which protocol a table or set belongs to.
-#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
-#[repr(u16)]
-pub enum ProtoFamily {
- Unspec = libc::NFPROTO_UNSPEC as u16,
- /// Inet - Means both IPv4 and IPv6
- Inet = libc::NFPROTO_INET as u16,
- Ipv4 = libc::NFPROTO_IPV4 as u16,
- Arp = libc::NFPROTO_ARP as u16,
- NetDev = libc::NFPROTO_NETDEV as u16,
- Bridge = libc::NFPROTO_BRIDGE as u16,
- Ipv6 = libc::NFPROTO_IPV6 as u16,
- DecNet = libc::NFPROTO_DECNET as u16,
-}
-#[derive(Error, Debug)]
-#[error("Couldn't find a matching protocol")]
-pub struct InvalidProtocolFamily;
-
-impl TryFrom<i32> for ProtoFamily {
- type Error = InvalidProtocolFamily;
- fn try_from(value: i32) -> Result<Self, Self::Error> {
- match value {
- libc::NFPROTO_UNSPEC => Ok(ProtoFamily::Unspec),
- libc::NFPROTO_INET => Ok(ProtoFamily::Inet),
- libc::NFPROTO_IPV4 => Ok(ProtoFamily::Ipv4),
- libc::NFPROTO_ARP => Ok(ProtoFamily::Arp),
- libc::NFPROTO_NETDEV => Ok(ProtoFamily::NetDev),
- libc::NFPROTO_BRIDGE => Ok(ProtoFamily::Bridge),
- libc::NFPROTO_IPV6 => Ok(ProtoFamily::Ipv6),
- libc::NFPROTO_DECNET => Ok(ProtoFamily::DecNet),
- _ => Err(InvalidProtocolFamily),
- }
- }
-}
-
-/// Trait for all types in this crate that can serialize to a Netlink message.
-///
-/// # Unsafe
-///
-/// This trait is unsafe to implement because it must never serialize to anything larger than the
-/// largest possible netlink message. Internally the `nft_nlmsg_maxsize()` function is used to make
-/// sure the `buf` pointer passed to `write` always has room for the largest possible Netlink
-/// message.
-pub unsafe trait NlMsg {
- /// Serializes the Netlink message to the buffer at `buf`. `buf` must have space for at least
- /// `nft_nlmsg_maxsize()` bytes. This is not checked by the compiler, which is why this method
- /// is unsafe.
- unsafe fn write(&self, buf: *mut c_void, seq: u32, msg_type: MsgType);
-}
-
-unsafe impl<T, R> NlMsg for T
-where
- T: Deref<Target = R>,
- R: NlMsg,
-{
- unsafe fn write(&self, buf: *mut c_void, seq: u32, msg_type: MsgType) {
- self.deref().write(buf, seq, msg_type);
- }
-}
-
-/// The largest nf_tables netlink message is the set element message, which
-/// contains the NFTA_SET_ELEM_LIST_ELEMENTS attribute. This attribute is
-/// a nest that describes the set elements. Given that the netlink attribute
-/// length (nla_len) is 16 bits, the largest message is a bit larger than
-/// 64 KBytes.
-pub fn nft_nlmsg_maxsize() -> u32 {
- u32::from(::std::u16::MAX) + unsafe { libc::sysconf(libc::_SC_PAGESIZE) } as u32
-}
diff --git a/rustables/src/query.rs b/rustables/src/query.rs
deleted file mode 100644
index 02c4082..0000000
--- a/rustables/src/query.rs
+++ /dev/null
@@ -1,130 +0,0 @@
-use crate::{nft_nlmsg_maxsize, sys, ProtoFamily};
-use sys::libc;
-
-/// Returns a buffer containing a netlink message which requests a list of all the netfilter
-/// matching objects (e.g. tables, chains, rules, ...).
-/// Supply the type of objects to retrieve (e.g. libc::NFT_MSG_GETTABLE), and optionally
-/// a callback to execute on the header, to set parameters for example.
-/// To pass arbitrary data inside that callback, please use a closure.
-pub fn get_list_of_objects<Error>(
- seq: u32,
- target: u16,
- setup_cb: Option<&dyn Fn(&mut libc::nlmsghdr) -> Result<(), Error>>,
-) -> Result<Vec<u8>, Error> {
- let mut buffer = vec![0; nft_nlmsg_maxsize() as usize];
- let hdr = unsafe {
- &mut *sys::nftnl_nlmsg_build_hdr(
- buffer.as_mut_ptr() as *mut libc::c_char,
- target,
- ProtoFamily::Unspec as u16,
- (libc::NLM_F_ROOT | libc::NLM_F_MATCH) as u16,
- seq,
- )
- };
- if let Some(cb) = setup_cb {
- cb(hdr)?;
- }
- Ok(buffer)
-}
-
-#[cfg(feature = "query")]
-mod inner {
- use crate::FinalizedBatch;
-
- use super::*;
-
- #[derive(thiserror::Error, Debug)]
- pub enum Error {
- #[error("Unable to open netlink socket to netfilter")]
- NetlinkOpenError(#[source] std::io::Error),
-
- #[error("Unable to send netlink command to netfilter")]
- NetlinkSendError(#[source] std::io::Error),
-
- #[error("Error while reading from netlink socket")]
- NetlinkRecvError(#[source] std::io::Error),
-
- #[error("Error while processing an incoming netlink message")]
- ProcessNetlinkError(#[source] std::io::Error),
-
- #[error("Custom error when customizing the query")]
- InitError(#[from] Box<dyn std::error::Error + 'static>),
-
- #[error("Couldn't allocate a netlink object, out of memory ?")]
- NetlinkAllocationFailed,
- }
-
- /// List objects of a certain type (e.g. libc::NFT_MSG_GETTABLE) with the help of an helper
- /// function called by mnl::cb_run2.
- /// The callback expect a tuple of additional data (supplied as an argument to
- /// this function) and of the output vector, to which it should append the parsed
- /// object it received.
- pub fn list_objects_with_data<'a, A, T>(
- data_type: u16,
- cb: fn(&libc::nlmsghdr, &mut (&'a A, &mut Vec<T>)) -> libc::c_int,
- additional_data: &'a A,
- req_hdr_customize: Option<&dyn Fn(&mut libc::nlmsghdr) -> Result<(), Error>>,
- ) -> Result<Vec<T>, Error>
- where
- T: 'a,
- {
- debug!("listing objects of kind {}", data_type);
- let socket = mnl::Socket::new(mnl::Bus::Netfilter).map_err(Error::NetlinkOpenError)?;
-
- let seq = 0;
- let portid = 0;
-
- let chains_buf = get_list_of_objects(seq, data_type, req_hdr_customize)?;
- socket.send(&chains_buf).map_err(Error::NetlinkSendError)?;
-
- let mut res = Vec::new();
-
- let mut msg_buffer = vec![0; nft_nlmsg_maxsize() as usize];
- while socket
- .recv(&mut msg_buffer)
- .map_err(Error::NetlinkRecvError)?
- > 0
- {
- if let mnl::CbResult::Stop = mnl::cb_run2(
- &msg_buffer,
- seq,
- portid,
- cb,
- &mut (additional_data, &mut res),
- )
- .map_err(Error::ProcessNetlinkError)?
- {
- break;
- }
- }
-
- Ok(res)
- }
-
- pub fn send_batch(batch: &mut FinalizedBatch) -> Result<(), Error> {
- let socket = mnl::Socket::new(mnl::Bus::Netfilter).map_err(Error::NetlinkOpenError)?;
-
- let seq = 0;
- let portid = socket.portid();
-
- socket.send_all(batch).map_err(Error::NetlinkSendError)?;
- debug!("sent");
-
- let mut msg_buffer = vec![0; nft_nlmsg_maxsize() as usize];
- while socket
- .recv(&mut msg_buffer)
- .map_err(Error::NetlinkRecvError)?
- > 0
- {
- if let mnl::CbResult::Stop =
- mnl::cb_run(&msg_buffer, seq, portid).map_err(Error::ProcessNetlinkError)?
- {
- break;
- }
- }
- Ok(())
- }
-}
-
-#[cfg(feature = "query")]
-pub use inner::*;
diff --git a/rustables/src/rule.rs b/rustables/src/rule.rs
deleted file mode 100644
index c8cb90d..0000000
--- a/rustables/src/rule.rs
+++ /dev/null
@@ -1,341 +0,0 @@
-use crate::expr::ExpressionWrapper;
-use crate::{chain::Chain, expr::Expression, MsgType};
-use crate::sys::{self, libc};
-use std::ffi::{c_void, CStr, CString};
-use std::fmt::Debug;
-use std::os::raw::c_char;
-use std::rc::Rc;
-
-/// A nftables firewall rule.
-pub struct Rule {
- pub(crate) rule: *mut sys::nftnl_rule,
- pub(crate) chain: Rc<Chain>,
-}
-
-impl Rule {
- /// Creates a new rule object in the given [`Chain`].
- ///
- /// [`Chain`]: struct.Chain.html
- pub fn new(chain: Rc<Chain>) -> Rule {
- unsafe {
- let rule = try_alloc!(sys::nftnl_rule_alloc());
- sys::nftnl_rule_set_u32(
- rule,
- sys::NFTNL_RULE_FAMILY as u16,
- chain.get_table().get_family() as u32,
- );
- sys::nftnl_rule_set_str(
- rule,
- sys::NFTNL_RULE_TABLE as u16,
- chain.get_table().get_name().as_ptr(),
- );
- sys::nftnl_rule_set_str(
- rule,
- sys::NFTNL_RULE_CHAIN as u16,
- chain.get_name().as_ptr(),
- );
-
- Rule { rule, chain }
- }
- }
-
- pub unsafe fn from_raw(rule: *mut sys::nftnl_rule, chain: Rc<Chain>) -> Self {
- Rule { rule, chain }
- }
-
- pub fn get_position(&self) -> u64 {
- unsafe { sys::nftnl_rule_get_u64(self.rule, sys::NFTNL_RULE_POSITION as u16) }
- }
-
- /// Sets the position of this rule within the chain it lives in. By default a new rule is added
- /// to the end of the chain.
- pub fn set_position(&mut self, position: u64) {
- unsafe {
- sys::nftnl_rule_set_u64(self.rule, sys::NFTNL_RULE_POSITION as u16, position);
- }
- }
-
- pub fn get_handle(&self) -> u64 {
- unsafe { sys::nftnl_rule_get_u64(self.rule, sys::NFTNL_RULE_HANDLE as u16) }
- }
-
- pub fn set_handle(&mut self, handle: u64) {
- unsafe {
- sys::nftnl_rule_set_u64(self.rule, sys::NFTNL_RULE_HANDLE as u16, handle);
- }
- }
-
- /// Adds an expression to this rule. Expressions are evaluated from first to last added.
- /// As soon as an expression does not match the packet it's being evaluated for, evaluation
- /// stops and the packet is evaluated against the next rule in the chain.
- pub fn add_expr(&mut self, expr: &impl Expression) {
- unsafe { sys::nftnl_rule_add_expr(self.rule, expr.to_expr(self)) }
- }
-
- /// Returns a reference to the [`Chain`] this rule lives in.
- ///
- /// [`Chain`]: struct.Chain.html
- pub fn get_chain(&self) -> Rc<Chain> {
- self.chain.clone()
- }
-
- /// Returns the userdata of this chain.
- pub fn get_userdata(&self) -> Option<&CStr> {
- unsafe {
- let ptr = sys::nftnl_rule_get_str(self.rule, sys::NFTNL_RULE_USERDATA as u16);
- if !ptr.is_null() {
- Some(CStr::from_ptr(ptr))
- } else {
- None
- }
- }
- }
-
- /// Updates the userdata of this chain.
- pub fn set_userdata(&self, data: &CStr) {
- unsafe {
- sys::nftnl_rule_set_str(self.rule, sys::NFTNL_RULE_USERDATA as u16, data.as_ptr());
- }
- }
-
- /// Returns a textual description of the rule.
- pub fn get_str(&self) -> CString {
- let mut descr_buf = vec![0i8; 4096];
- unsafe {
- sys::nftnl_rule_snprintf(
- descr_buf.as_mut_ptr(),
- (descr_buf.len() - 1) as u64,
- self.rule,
- sys::NFTNL_OUTPUT_DEFAULT,
- 0,
- );
- CStr::from_ptr(descr_buf.as_ptr()).to_owned()
- }
- }
-
- /// Retrieves an iterator to loop over the expressions of the rule
- pub fn get_exprs(self: &Rc<Self>) -> RuleExprsIter {
- RuleExprsIter::new(self.clone())
- }
-
- #[cfg(feature = "unsafe-raw-handles")]
- /// Returns the raw handle.
- pub fn as_ptr(&self) -> *const sys::nftnl_rule {
- self.rule as *const sys::nftnl_rule
- }
-
- #[cfg(feature = "unsafe-raw-handles")]
- /// Returns a mutable version of the raw handle.
- pub fn as_mut_ptr(&mut self) -> *mut sys::nftnl_rule {
- self.rule
- }
-
- /// Perform a deep comparizon of rules, by checking they have the same expressions inside.
- /// This is not enabled by default in our PartialEq implementation because of the
- /// difficulty to compare an expression generated by the library with the expressions returned
- /// by the kernel when iterating over the currently in-use rules. The kernel-returned
- /// expressions may have additional attributes despite being generated from the same rule.
- /// This is particularly true for the 'nat' expression).
- pub fn deep_eq(&self, other: &Self) -> bool {
- if self != other {
- return false;
- }
-
- let self_exprs =
- try_alloc!(unsafe { sys::nftnl_expr_iter_create(self.rule as *const sys::nftnl_rule) });
- let other_exprs = try_alloc!(unsafe {
- sys::nftnl_expr_iter_create(other.rule as *const sys::nftnl_rule)
- });
-
- loop {
- let self_next = unsafe { sys::nftnl_expr_iter_next(self_exprs) };
- let other_next = unsafe { sys::nftnl_expr_iter_next(other_exprs) };
- if self_next.is_null() && other_next.is_null() {
- return true;
- } else if self_next.is_null() || other_next.is_null() {
- return false;
- }
-
- // we are falling back on comparing the strings, because there is no easy mechanism to
- // perform a memcmp() between the two expressions :/
- let mut self_str = [0; 256];
- let mut other_str = [0; 256];
- unsafe {
- sys::nftnl_expr_snprintf(
- self_str.as_mut_ptr(),
- (self_str.len() - 1) as u64,
- self_next,
- sys::NFTNL_OUTPUT_DEFAULT,
- 0,
- );
- sys::nftnl_expr_snprintf(
- other_str.as_mut_ptr(),
- (other_str.len() - 1) as u64,
- other_next,
- sys::NFTNL_OUTPUT_DEFAULT,
- 0,
- );
- }
-
- if self_str != other_str {
- return false;
- }
- }
- }
-}
-
-impl Debug for Rule {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{:?}", self.get_str())
- }
-}
-
-impl PartialEq for Rule {
- fn eq(&self, other: &Self) -> bool {
- if self.get_chain() != other.get_chain() {
- return false;
- }
-
- unsafe {
- if sys::nftnl_rule_is_set(self.rule, sys::NFTNL_RULE_HANDLE as u16)
- && sys::nftnl_rule_is_set(other.rule, sys::NFTNL_RULE_HANDLE as u16)
- {
- if self.get_handle() != other.get_handle() {
- return false;
- }
- }
- if sys::nftnl_rule_is_set(self.rule, sys::NFTNL_RULE_POSITION as u16)
- && sys::nftnl_rule_is_set(other.rule, sys::NFTNL_RULE_POSITION as u16)
- {
- if self.get_position() != other.get_position() {
- return false;
- }
- }
- }
-
- return false;
- }
-}
-
-unsafe impl crate::NlMsg for Rule {
- unsafe fn write(&self, buf: *mut c_void, seq: u32, msg_type: MsgType) {
- let type_ = match msg_type {
- MsgType::Add => libc::NFT_MSG_NEWRULE,
- MsgType::Del => libc::NFT_MSG_DELRULE,
- };
- let flags: u16 = match msg_type {
- MsgType::Add => (libc::NLM_F_CREATE | libc::NLM_F_APPEND | libc::NLM_F_EXCL) as u16,
- MsgType::Del => 0u16,
- } | libc::NLM_F_ACK as u16;
- let header = sys::nftnl_nlmsg_build_hdr(
- buf as *mut c_char,
- type_ as u16,
- self.chain.get_table().get_family() as u16,
- flags,
- seq,
- );
- sys::nftnl_rule_nlmsg_build_payload(header, self.rule);
- }
-}
-
-impl Drop for Rule {
- fn drop(&mut self) {
- unsafe { sys::nftnl_rule_free(self.rule) };
- }
-}
-
-pub struct RuleExprsIter {
- rule: Rc<Rule>,
- iter: *mut sys::nftnl_expr_iter,
-}
-
-impl RuleExprsIter {
- fn new(rule: Rc<Rule>) -> Self {
- let iter =
- try_alloc!(unsafe { sys::nftnl_expr_iter_create(rule.rule as *const sys::nftnl_rule) });
- RuleExprsIter { rule, iter }
- }
-}
-
-impl Iterator for RuleExprsIter {
- type Item = ExpressionWrapper;
-
- fn next(&mut self) -> Option<Self::Item> {
- let next = unsafe { sys::nftnl_expr_iter_next(self.iter) };
- if next.is_null() {
- trace!("RulesExprsIter iterator ending");
- None
- } else {
- trace!("RulesExprsIter returning new expression");
- Some(ExpressionWrapper {
- expr: next,
- rule: self.rule.clone(),
- })
- }
- }
-}
-
-impl Drop for RuleExprsIter {
- fn drop(&mut self) {
- unsafe { sys::nftnl_expr_iter_destroy(self.iter) };
- }
-}
-
-#[cfg(feature = "query")]
-pub fn get_rules_cb(
- header: &libc::nlmsghdr,
- (chain, rules): &mut (&Rc<Chain>, &mut Vec<Rule>),
-) -> libc::c_int {
- unsafe {
- let rule = sys::nftnl_rule_alloc();
- if rule == std::ptr::null_mut() {
- return mnl::mnl_sys::MNL_CB_ERROR;
- }
- let err = sys::nftnl_rule_nlmsg_parse(header, rule);
- if err < 0 {
- error!("Failed to parse nelink rule message - {}", err);
- sys::nftnl_rule_free(rule);
- return err;
- }
-
- rules.push(Rule::from_raw(rule, chain.clone()));
- }
- mnl::mnl_sys::MNL_CB_OK
-}
-
-#[cfg(feature = "query")]
-pub fn list_rules_for_chain(chain: &Rc<Chain>) -> Result<Vec<Rule>, crate::query::Error> {
- crate::query::list_objects_with_data(
- libc::NFT_MSG_GETRULE as u16,
- get_rules_cb,
- &chain,
- // only retrieve rules from the currently targetted chain
- Some(&|hdr| unsafe {
- let rule = sys::nftnl_rule_alloc();
- if rule as *const _ == std::ptr::null() {
- return Err(crate::query::Error::NetlinkAllocationFailed);
- }
-
- sys::nftnl_rule_set_str(
- rule,
- sys::NFTNL_RULE_TABLE as u16,
- chain.get_table().get_name().as_ptr(),
- );
- sys::nftnl_rule_set_u32(
- rule,
- sys::NFTNL_RULE_FAMILY as u16,
- chain.get_table().get_family() as u32,
- );
- sys::nftnl_rule_set_str(
- rule,
- sys::NFTNL_RULE_CHAIN as u16,
- chain.get_name().as_ptr(),
- );
-
- sys::nftnl_rule_nlmsg_build_payload(hdr, rule);
-
- sys::nftnl_rule_free(rule);
- Ok(())
- }),
- )
-}
diff --git a/rustables/src/set.rs b/rustables/src/set.rs
deleted file mode 100644
index d6b9514..0000000
--- a/rustables/src/set.rs
+++ /dev/null
@@ -1,273 +0,0 @@
-use crate::{table::Table, MsgType, ProtoFamily};
-use crate::sys::{self, libc};
-use std::{
- cell::Cell,
- ffi::{c_void, CStr, CString},
- fmt::Debug,
- net::{Ipv4Addr, Ipv6Addr},
- os::raw::c_char,
- rc::Rc,
-};
-
-#[macro_export]
-macro_rules! nft_set {
- ($name:expr, $id:expr, $table:expr, $family:expr) => {
- $crate::set::Set::new($name, $id, $table, $family)
- };
- ($name:expr, $id:expr, $table:expr, $family:expr; [ ]) => {
- nft_set!($name, $id, $table, $family)
- };
- ($name:expr, $id:expr, $table:expr, $family:expr; [ $($value:expr,)* ]) => {{
- let mut set = nft_set!($name, $id, $table, $family).expect("Set allocation failed");
- $(
- set.add($value).expect(stringify!(Unable to add $value to set $name));
- )*
- set
- }};
-}
-
-pub struct Set<'a, K> {
- pub(crate) set: *mut sys::nftnl_set,
- pub(crate) table: &'a Table,
- pub(crate) family: ProtoFamily,
- _marker: ::std::marker::PhantomData<K>,
-}
-
-impl<'a, K> Set<'a, K> {
- pub fn new(name: &CStr, id: u32, table: &'a Table, family: ProtoFamily) -> Self
- where
- K: SetKey,
- {
- unsafe {
- let set = try_alloc!(sys::nftnl_set_alloc());
-
- sys::nftnl_set_set_u32(set, sys::NFTNL_SET_FAMILY as u16, family as u32);
- sys::nftnl_set_set_str(set, sys::NFTNL_SET_TABLE as u16, table.get_name().as_ptr());
- sys::nftnl_set_set_str(set, sys::NFTNL_SET_NAME as u16, name.as_ptr());
- sys::nftnl_set_set_u32(set, sys::NFTNL_SET_ID as u16, id);
-
- sys::nftnl_set_set_u32(
- set,
- sys::NFTNL_SET_FLAGS as u16,
- (libc::NFT_SET_ANONYMOUS | libc::NFT_SET_CONSTANT) as u32,
- );
- sys::nftnl_set_set_u32(set, sys::NFTNL_SET_KEY_TYPE as u16, K::TYPE);
- sys::nftnl_set_set_u32(set, sys::NFTNL_SET_KEY_LEN as u16, K::LEN);
-
- Set {
- set,
- table,
- family,
- _marker: ::std::marker::PhantomData,
- }
- }
- }
-
- pub unsafe fn from_raw(set: *mut sys::nftnl_set, table: &'a Table, family: ProtoFamily) -> Self
- where
- K: SetKey,
- {
- Set {
- set,
- table,
- family,
- _marker: ::std::marker::PhantomData,
- }
- }
-
- pub fn add(&mut self, key: &K)
- where
- K: SetKey,
- {
- unsafe {
- let elem = try_alloc!(sys::nftnl_set_elem_alloc());
-
- let data = key.data();
- let data_len = data.len() as u32;
- trace!("Adding key {:?} with len {}", data, data_len);
- sys::nftnl_set_elem_set(
- elem,
- sys::NFTNL_SET_ELEM_KEY as u16,
- data.as_ref() as *const _ as *const c_void,
- data_len,
- );
- sys::nftnl_set_elem_add(self.set, elem);
- }
- }
-
- pub fn elems_iter(&'a self) -> SetElemsIter<'a, K> {
- SetElemsIter::new(self)
- }
-
- #[cfg(feature = "unsafe-raw-handles")]
- /// Returns the raw handle.
- pub fn as_ptr(&self) -> *const sys::nftnl_set {
- self.set as *const sys::nftnl_set
- }
-
- #[cfg(feature = "unsafe-raw-handles")]
- /// Returns a mutable version of the raw handle.
- pub fn as_mut_ptr(&self) -> *mut sys::nftnl_set {
- self.set
- }
-
- pub fn get_family(&self) -> ProtoFamily {
- self.family
- }
-
- /// Returns a textual description of the set.
- pub fn get_str(&self) -> CString {
- let mut descr_buf = vec![0i8; 4096];
- unsafe {
- sys::nftnl_set_snprintf(
- descr_buf.as_mut_ptr(),
- (descr_buf.len() - 1) as u64,
- self.set,
- sys::NFTNL_OUTPUT_DEFAULT,
- 0,
- );
- CStr::from_ptr(descr_buf.as_ptr()).to_owned()
- }
- }
-
- pub fn get_name(&self) -> Option<&CStr> {
- unsafe {
- let ptr = sys::nftnl_set_get_str(self.set, sys::NFTNL_SET_NAME as u16);
- if !ptr.is_null() {
- Some(CStr::from_ptr(ptr))
- } else {
- None
- }
- }
- }
-
- pub fn get_id(&self) -> u32 {
- unsafe { sys::nftnl_set_get_u32(self.set, sys::NFTNL_SET_ID as u16) }
- }
-}
-
-impl<'a, K> Debug for Set<'a, K> {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{:?}", self.get_str())
- }
-}
-
-unsafe impl<'a, K> crate::NlMsg for Set<'a, K> {
- unsafe fn write(&self, buf: *mut c_void, seq: u32, msg_type: MsgType) {
- let type_ = match msg_type {
- MsgType::Add => libc::NFT_MSG_NEWSET,
- MsgType::Del => libc::NFT_MSG_DELSET,
- };
- let header = sys::nftnl_nlmsg_build_hdr(
- buf as *mut c_char,
- type_ as u16,
- self.table.get_family() as u16,
- (libc::NLM_F_APPEND | libc::NLM_F_CREATE | libc::NLM_F_ACK) as u16,
- seq,
- );
- sys::nftnl_set_nlmsg_build_payload(header, self.set);
- }
-}
-
-impl<'a, K> Drop for Set<'a, K> {
- fn drop(&mut self) {
- unsafe { sys::nftnl_set_free(self.set) };
- }
-}
-
-pub struct SetElemsIter<'a, K> {
- set: &'a Set<'a, K>,
- iter: *mut sys::nftnl_set_elems_iter,
- ret: Rc<Cell<i32>>,
-}
-
-impl<'a, K> SetElemsIter<'a, K> {
- fn new(set: &'a Set<'a, K>) -> Self {
- let iter = try_alloc!(unsafe {
- sys::nftnl_set_elems_iter_create(set.set as *const sys::nftnl_set)
- });
- SetElemsIter {
- set,
- iter,
- ret: Rc::new(Cell::new(1)),
- }
- }
-}
-
-impl<'a, K: 'a> Iterator for SetElemsIter<'a, K> {
- type Item = SetElemsMsg<'a, K>;
-
- fn next(&mut self) -> Option<Self::Item> {
- if self.ret.get() <= 0 || unsafe { sys::nftnl_set_elems_iter_cur(self.iter).is_null() } {
- trace!("SetElemsIter iterator ending");
- None
- } else {
- trace!("SetElemsIter returning new SetElemsMsg");
- Some(SetElemsMsg {
- set: self.set,
- iter: self.iter,
- ret: self.ret.clone(),
- })
- }
- }
-}
-
-impl<'a, K> Drop for SetElemsIter<'a, K> {
- fn drop(&mut self) {
- unsafe { sys::nftnl_set_elems_iter_destroy(self.iter) };
- }
-}
-
-pub struct SetElemsMsg<'a, K> {
- set: &'a Set<'a, K>,
- iter: *mut sys::nftnl_set_elems_iter,
- ret: Rc<Cell<i32>>,
-}
-
-unsafe impl<'a, K> crate::NlMsg for SetElemsMsg<'a, K> {
- unsafe fn write(&self, buf: *mut c_void, seq: u32, msg_type: MsgType) {
- trace!("Writing SetElemsMsg to NlMsg");
- let (type_, flags) = match msg_type {
- MsgType::Add => (
- libc::NFT_MSG_NEWSETELEM,
- libc::NLM_F_CREATE | libc::NLM_F_EXCL | libc::NLM_F_ACK,
- ),
- MsgType::Del => (libc::NFT_MSG_DELSETELEM, libc::NLM_F_ACK),
- };
- let header = sys::nftnl_nlmsg_build_hdr(
- buf as *mut c_char,
- type_ as u16,
- self.set.get_family() as u16,
- flags as u16,
- seq,
- );
- self.ret.set(sys::nftnl_set_elems_nlmsg_build_payload_iter(
- header, self.iter,
- ));
- }
-}
-
-pub trait SetKey {
- const TYPE: u32;
- const LEN: u32;
-
- fn data(&self) -> Box<[u8]>;
-}
-
-impl SetKey for Ipv4Addr {
- const TYPE: u32 = 7;
- const LEN: u32 = 4;
-
- fn data(&self) -> Box<[u8]> {
- self.octets().to_vec().into_boxed_slice()
- }
-}
-
-impl SetKey for Ipv6Addr {
- const TYPE: u32 = 8;
- const LEN: u32 = 16;
-
- fn data(&self) -> Box<[u8]> {
- self.octets().to_vec().into_boxed_slice()
- }
-}
diff --git a/rustables/src/table.rs b/rustables/src/table.rs
deleted file mode 100644
index 2f21453..0000000
--- a/rustables/src/table.rs
+++ /dev/null
@@ -1,171 +0,0 @@
-use crate::{MsgType, ProtoFamily};
-use crate::sys::{self, libc};
-#[cfg(feature = "query")]
-use std::convert::TryFrom;
-use std::{
- ffi::{c_void, CStr, CString},
- fmt::Debug,
- os::raw::c_char,
-};
-
-/// Abstraction of `nftnl_table`. The top level container in netfilter. A table has a protocol
-/// family and contain [`Chain`]s that in turn hold the rules.
-///
-/// [`Chain`]: struct.Chain.html
-pub struct Table {
- table: *mut sys::nftnl_table,
- family: ProtoFamily,
-}
-
-impl Table {
- /// Creates a new table instance with the given name and protocol family.
- pub fn new<T: AsRef<CStr>>(name: &T, family: ProtoFamily) -> Table {
- unsafe {
- let table = try_alloc!(sys::nftnl_table_alloc());
-
- sys::nftnl_table_set_u32(table, sys::NFTNL_TABLE_FAMILY as u16, family as u32);
- sys::nftnl_table_set_str(table, sys::NFTNL_TABLE_NAME as u16, name.as_ref().as_ptr());
- sys::nftnl_table_set_u32(table, sys::NFTNL_TABLE_FLAGS as u16, 0u32);
- Table { table, family }
- }
- }
-
- pub unsafe fn from_raw(table: *mut sys::nftnl_table, family: ProtoFamily) -> Self {
- Table { table, family }
- }
-
- /// Returns the name of this table.
- pub fn get_name(&self) -> &CStr {
- unsafe {
- let ptr = sys::nftnl_table_get_str(self.table, sys::NFTNL_TABLE_NAME as u16);
- if ptr.is_null() {
- panic!("Impossible situation: retrieving the name of a chain failed")
- } else {
- CStr::from_ptr(ptr)
- }
- }
- }
-
- /// Returns a textual description of the table.
- pub fn get_str(&self) -> CString {
- let mut descr_buf = vec![0i8; 4096];
- unsafe {
- sys::nftnl_table_snprintf(
- descr_buf.as_mut_ptr(),
- (descr_buf.len() - 1) as u64,
- self.table,
- sys::NFTNL_OUTPUT_DEFAULT,
- 0,
- );
- CStr::from_ptr(descr_buf.as_ptr()).to_owned()
- }
- }
-
- /// Returns the protocol family for this table.
- pub fn get_family(&self) -> ProtoFamily {
- self.family
- }
-
- /// Returns the userdata of this chain.
- pub fn get_userdata(&self) -> Option<&CStr> {
- unsafe {
- let ptr = sys::nftnl_table_get_str(self.table, sys::NFTNL_TABLE_USERDATA as u16);
- if !ptr.is_null() {
- Some(CStr::from_ptr(ptr))
- } else {
- None
- }
- }
- }
-
- /// Update the userdata of this chain.
- pub fn set_userdata(&self, data: &CStr) {
- unsafe {
- sys::nftnl_table_set_str(self.table, sys::NFTNL_TABLE_USERDATA as u16, data.as_ptr());
- }
- }
-
- #[cfg(feature = "unsafe-raw-handles")]
- /// Returns the raw handle.
- pub fn as_ptr(&self) -> *const sys::nftnl_table {
- self.table as *const sys::nftnl_table
- }
-
- #[cfg(feature = "unsafe-raw-handles")]
- /// Returns a mutable version of the raw handle.
- pub fn as_mut_ptr(&self) -> *mut sys::nftnl_table {
- self.table
- }
-}
-
-impl PartialEq for Table {
- fn eq(&self, other: &Self) -> bool {
- self.get_name() == other.get_name() && self.get_family() == other.get_family()
- }
-}
-
-impl Debug for Table {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
- write!(f, "{:?}", self.get_str())
- }
-}
-
-unsafe impl crate::NlMsg for Table {
- unsafe fn write(&self, buf: *mut c_void, seq: u32, msg_type: MsgType) {
- let raw_msg_type = match msg_type {
- MsgType::Add => libc::NFT_MSG_NEWTABLE,
- MsgType::Del => libc::NFT_MSG_DELTABLE,
- };
- let header = sys::nftnl_nlmsg_build_hdr(
- buf as *mut c_char,
- raw_msg_type as u16,
- self.family as u16,
- libc::NLM_F_ACK as u16,
- seq,
- );
- sys::nftnl_table_nlmsg_build_payload(header, self.table);
- }
-}
-
-impl Drop for Table {
- fn drop(&mut self) {
- unsafe { sys::nftnl_table_free(self.table) };
- }
-}
-
-#[cfg(feature = "query")]
-/// A callback to parse the response for messages created with `get_tables_nlmsg`.
-pub fn get_tables_cb(
- header: &libc::nlmsghdr,
- (_, tables): &mut (&(), &mut Vec<Table>),
-) -> libc::c_int {
- unsafe {
- let table = sys::nftnl_table_alloc();
- if table == std::ptr::null_mut() {
- return mnl::mnl_sys::MNL_CB_ERROR;
- }
- let err = sys::nftnl_table_nlmsg_parse(header, table);
- if err < 0 {
- error!("Failed to parse nelink table message - {}", err);
- sys::nftnl_table_free(table);
- return err;
- }
- let family = sys::nftnl_table_get_u32(table, sys::NFTNL_TABLE_FAMILY as u16);
- match crate::ProtoFamily::try_from(family as i32) {
- Ok(family) => {
- tables.push(Table::from_raw(table, family));
- mnl::mnl_sys::MNL_CB_OK
- }
- Err(crate::InvalidProtocolFamily) => {
- error!("The netlink table didn't have a valid protocol family !?");
- sys::nftnl_table_free(table);
- mnl::mnl_sys::MNL_CB_ERROR
- }
- }
- }
-}
-
-#[cfg(feature = "query")]
-pub fn list_tables() -> Result<Vec<Table>, crate::query::Error> {
- crate::query::list_objects_with_data(libc::NFT_MSG_GETTABLE as u16, get_tables_cb, &(), None)
-}
diff --git a/rustables/tests/expr.rs b/rustables/tests/expr.rs
deleted file mode 100644
index 5c27119..0000000
--- a/rustables/tests/expr.rs
+++ /dev/null
@@ -1,700 +0,0 @@
-use rustables::{nft_nlmsg_maxsize, Chain, MsgType, NlMsg, ProtoFamily, Rule, Table};
-use rustables::set::Set;
-use rustables::sys::libc::{nlmsghdr, AF_UNIX, NFNETLINK_V0, NFNL_SUBSYS_NFTABLES, NF_DROP};
-use rustables::expr::{
- Bitwise, Cmp, CmpOp, Conntrack, Counter, Expression, HeaderField, IcmpCode, Immediate, Log,
- LogGroup, LogPrefix, Lookup, Meta, Nat, NatType, Payload, Register, Reject, TcpHeaderField,
- TransportHeaderField, Verdict
-};
-use std::ffi::{c_void, CStr};
-use std::mem::size_of;
-use std::net::Ipv4Addr;
-use std::rc::Rc;
-use thiserror::Error;
-
-mod sys;
-use sys::*;
-
-fn get_subsystem_from_nlmsghdr_type(x: u16) -> u8 {
- ((x & 0xff00) >> 8) as u8
-}
-fn get_operation_from_nlmsghdr_type(x: u16) -> u8 {
- (x & 0x00ff) as u8
-}
-
-const TABLE_NAME: &[u8; 10] = b"mocktable\0";
-const CHAIN_NAME: &[u8; 10] = b"mockchain\0";
-
-type NetLinkType = u16;
-
-#[derive(Debug, PartialEq)]
-enum NetlinkExpr {
- Nested(NetLinkType, Vec<NetlinkExpr>),
- Final(NetLinkType, Vec<u8>),
- List(Vec<NetlinkExpr>),
-}
-
-#[derive(Debug, Error)]
-#[error("empty data")]
-struct EmptyDataError;
-
-impl NetlinkExpr {
- fn to_raw(self) -> Vec<u8> {
- match self {
- NetlinkExpr::Final(ty, val) => {
- let len = val.len() + 4;
- let mut res = Vec::with_capacity(len);
-
- res.extend(&(len as u16).to_le_bytes());
- res.extend(&ty.to_le_bytes());
- res.extend(val);
- // alignment
- while res.len() % 4 != 0 {
- res.push(0);
- }
-
- res
- }
- NetlinkExpr::Nested(ty, exprs) => {
- // some heuristic to decrease allocations (even though this is
- // only useful for testing so performance is not an objective)
- let mut sub = Vec::with_capacity(exprs.len() * 50);
-
- for expr in exprs {
- sub.append(&mut expr.to_raw());
- }
-
- let len = sub.len() + 4;
- let mut res = Vec::with_capacity(len);
-
- // set the "NESTED" flag
- res.extend(&(len as u16).to_le_bytes());
- res.extend(&(ty | 0x8000).to_le_bytes());
- res.extend(sub);
-
- res
- }
- NetlinkExpr::List(exprs) => {
- // some heuristic to decrease allocations (even though this is
- // only useful for testing so performance is not an objective)
- let mut list = Vec::with_capacity(exprs.len() * 50);
-
- for expr in exprs {
- list.append(&mut expr.to_raw());
- }
-
- list
- }
- }
- }
-}
-
-#[repr(C)]
-#[derive(Clone, Copy)]
-struct Nfgenmsg {
- family: u8, /* AF_xxx */
- version: u8, /* nfnetlink version */
- res_id: u16, /* resource id */
-}
-
-fn get_test_rule() -> Rule {
- let table = Rc::new(Table::new(
- &CStr::from_bytes_with_nul(TABLE_NAME).unwrap(),
- ProtoFamily::Inet,
- ));
- let chain = Rc::new(Chain::new(
- &CStr::from_bytes_with_nul(CHAIN_NAME).unwrap(),
- Rc::clone(&table),
- ));
- let rule = Rule::new(Rc::clone(&chain));
- rule
-}
-
-fn get_test_nlmsg_from_expr(
- rule: &mut Rule,
- expr: &impl Expression,
-) -> (nlmsghdr, Nfgenmsg, Vec<u8>) {
- rule.add_expr(expr);
-
- let mut buf = vec![0u8; nft_nlmsg_maxsize() as usize];
- unsafe {
- rule.write(buf.as_mut_ptr() as *mut c_void, 0, MsgType::Add);
-
- // right now the message is composed of the following parts:
- // - nlmsghdr (contains the message size and type)
- // - nfgenmsg (nftables header that describes the message family)
- // - the raw expression that we want to validate
-
- let size_of_hdr = size_of::<nlmsghdr>();
- let size_of_nfgenmsg = size_of::<Nfgenmsg>();
- let nlmsghdr = *(buf[0..size_of_hdr].as_ptr() as *const nlmsghdr);
- let nfgenmsg =
- *(buf[size_of_hdr..size_of_hdr + size_of_nfgenmsg].as_ptr() as *const Nfgenmsg);
- let raw_expr = buf[size_of_hdr + size_of_nfgenmsg..nlmsghdr.nlmsg_len as usize]
- .iter()
- .map(|x| *x)
- .collect();
-
- // sanity checks on the global message (this should be very similar/factorisable for the
- // most part in other tests)
- // TODO: check the messages flags
- assert_eq!(
- get_subsystem_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
- NFNL_SUBSYS_NFTABLES as u8
- );
- assert_eq!(
- get_operation_from_nlmsghdr_type(nlmsghdr.nlmsg_type),
- NFT_MSG_NEWRULE as u8
- );
- assert_eq!(nlmsghdr.nlmsg_seq, 0);
- assert_eq!(nlmsghdr.nlmsg_pid, 0);
- assert_eq!(nfgenmsg.family, AF_UNIX as u8);
- assert_eq!(nfgenmsg.version, NFNETLINK_V0 as u8);
- assert_eq!(nfgenmsg.res_id.to_be(), 0);
-
- (nlmsghdr, nfgenmsg, raw_expr)
- }
-}
-
-#[test]
-fn bitwise_expr_is_valid() {
- let netmask = Ipv4Addr::new(255, 255, 255, 0);
- let bitwise = Bitwise::new(netmask, 0);
- let mut rule = get_test_rule();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &bitwise);
- assert_eq!(nlmsghdr.nlmsg_len, 124);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"bitwise\0".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 cmp = Cmp::new(CmpOp::Eq, 0);
- let mut rule = get_test_rule();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &cmp);
- assert_eq!(nlmsghdr.nlmsg_len, 100);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"cmp\0".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(1u16, 0u32.to_be_bytes().to_vec())]
- )
- ]
- )
- ]
- )]
- )
- ])
- .to_raw()
- );
-}
-
-#[test]
-fn counter_expr_is_valid() {
- let nb_bytes = 123456u64;
- let nb_packets = 987u64;
- let mut counter = Counter::new();
- counter.nb_bytes = nb_bytes;
- counter.nb_packets = nb_packets;
-
- let mut rule = get_test_rule();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &counter);
- assert_eq!(nlmsghdr.nlmsg_len, 100);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"counter\0".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::State;
- let mut rule = get_test_rule();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &ct);
- assert_eq!(nlmsghdr.nlmsg_len, 88);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"ct\0".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(42u8, Register::Reg1);
- let mut rule = get_test_rule();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &immediate);
- assert_eq!(nlmsghdr.nlmsg_len, 100);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"immediate\0".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 {
- group: Some(LogGroup(1)),
- prefix: Some(LogPrefix::new("mockprefix").unwrap()),
- };
- let mut rule = get_test_rule();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &log);
- assert_eq!(nlmsghdr.nlmsg_len, 96);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"log\0".to_vec()),
- NetlinkExpr::Nested(
- NFTA_EXPR_DATA,
- vec![
- NetlinkExpr::Final(NFTA_LOG_PREFIX, b"mockprefix\0".to_vec()),
- NetlinkExpr::Final(NFTA_LOG_GROUP, 1u16.to_be_bytes().to_vec())
- ]
- )
- ]
- )]
- )
- ])
- .to_raw()
- );
-}
-
-#[test]
-fn lookup_expr_is_valid() {
- let set_name = &CStr::from_bytes_with_nul(b"mockset\0").unwrap();
- let mut rule = get_test_rule();
- let table = rule.get_chain().get_table();
- let mut set = Set::new(set_name, 0, &table, ProtoFamily::Inet);
- let address: Ipv4Addr = [8, 8, 8, 8].into();
- set.add(&address);
- let lookup = Lookup::new(&set).unwrap();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &lookup);
- assert_eq!(nlmsghdr.nlmsg_len, 104);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"lookup\0".to_vec()),
- NetlinkExpr::Nested(
- NFTA_EXPR_DATA,
- vec![
- NetlinkExpr::Final(
- NFTA_LOOKUP_SREG,
- NFT_REG_1.to_be_bytes().to_vec()
- ),
- NetlinkExpr::Final(NFTA_LOOKUP_SET, b"mockset\0".to_vec()),
- NetlinkExpr::Final(NFTA_LOOKUP_SET_ID, 0u32.to_be_bytes().to_vec()),
- ]
- )
- ]
- )]
- )
- ])
- .to_raw()
- );
-}
-
-use rustables::expr::Masquerade;
-#[test]
-fn masquerade_expr_is_valid() {
- let masquerade = Masquerade;
- let mut rule = get_test_rule();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &masquerade);
- assert_eq!(nlmsghdr.nlmsg_len, 76);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"masq\0".to_vec()),
- NetlinkExpr::Nested(NFTA_EXPR_DATA, vec![]),
- ]
- )]
- )
- ])
- .to_raw()
- );
-}
-
-#[test]
-fn meta_expr_is_valid() {
- let meta = Meta::Protocol;
- let mut rule = get_test_rule();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &meta);
- assert_eq!(nlmsghdr.nlmsg_len, 92);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"meta\0".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 {
- nat_type: NatType::SNat,
- family: ProtoFamily::Ipv4,
- ip_register: Register::Reg1,
- port_register: None,
- };
- let mut rule = get_test_rule();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &nat);
- assert_eq!(nlmsghdr.nlmsg_len, 96);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"nat\0".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,
- // TODO find the right value to substitute here.
- //(ProtoFamily::Ipv4 as u16).to_le_bytes().to_vec()
- 2u32.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() {
- // TODO test loaded payload ?
- let tcp_header_field = TcpHeaderField::Sport;
- let transport_header_field = TransportHeaderField::Tcp(tcp_header_field);
- let payload = Payload::Transport(transport_header_field);
- let mut rule = get_test_rule();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &payload);
- assert_eq!(nlmsghdr.nlmsg_len, 108);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"payload\0".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()
- 0u32.to_be_bytes().to_vec()
- ),
- ]
- )
- ]
- )]
- )
- ])
- .to_raw()
- );
-}
-
-#[test]
-fn reject_expr_is_valid() {
- let code = IcmpCode::NoRoute;
- let reject = Reject::Icmp(code);
- let mut rule = get_test_rule();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &reject);
- assert_eq!(nlmsghdr.nlmsg_len, 92);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"reject\0".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 = Verdict::Drop;
- let mut rule = get_test_rule();
- let (nlmsghdr, _nfgenmsg, raw_expr) = get_test_nlmsg_from_expr(&mut rule, &verdict);
- assert_eq!(nlmsghdr.nlmsg_len, 104);
-
- assert_eq!(
- raw_expr,
- NetlinkExpr::List(vec![
- NetlinkExpr::Final(NFTA_RULE_TABLE, TABLE_NAME.to_vec()),
- NetlinkExpr::Final(NFTA_RULE_CHAIN, CHAIN_NAME.to_vec()),
- NetlinkExpr::Nested(
- NFTA_RULE_EXPRESSIONS,
- vec![NetlinkExpr::Nested(
- NFTA_LIST_ELEM,
- vec![
- NetlinkExpr::Final(NFTA_EXPR_NAME, b"immediate\0".to_vec()),
- // TODO find the right arrangement for Verdict's data.
- 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() //0u32.to_be_bytes().to_vec()
- ),]
- )],
- ),
- ]
- )
- ]
- )]
- )
- ])
- .to_raw()
- );
-}
diff --git a/rustables/tests_wrapper.h b/rustables/tests_wrapper.h
deleted file mode 100644
index 8f976e8..0000000
--- a/rustables/tests_wrapper.h
+++ /dev/null
@@ -1 +0,0 @@
-#include "linux/netfilter/nf_tables.h"
diff --git a/rustables/wrapper.h b/rustables/wrapper.h
deleted file mode 100644
index e6eb221..0000000
--- a/rustables/wrapper.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#include <libnftnl/batch.h>
-#include <libnftnl/chain.h>
-#include <libnftnl/common.h>
-#include <libnftnl/expr.h>
-#include <libnftnl/gen.h>
-#include <libnftnl/object.h>
-#include <libnftnl/rule.h>
-#include <libnftnl/ruleset.h>
-#include <libnftnl/set.h>
-#include <libnftnl/table.h>
-#include <libnftnl/trace.h>
-#include <libnftnl/udata.h>