diff options
Diffstat (limited to 'src/lib.rs')
-rw-r--r-- | src/lib.rs | 179 |
1 files changed, 48 insertions, 131 deletions
@@ -1,4 +1,4 @@ -// Copyryght (c) 2021 GPL lafleur@boum.org and Simon Thoby +// Copyryght (c) 2021-2022 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 @@ -24,106 +24,70 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Safe abstraction for [`libnftnl`]. Provides userspace access to the in-kernel nf_tables -//! subsystem. Can be used to create and remove tables, chains, sets and rules from the nftables +//! Safe abstraction for userspace access to the in-kernel nf_tables subsystem. +//! 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! +//! Understanding how to use the netlink subsystem and implementing this crate has mostly been done by +//! reading the source code for the [`nftables`] userspace program and its corresponding kernel code, +//! as well as 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 forged netlink messages are used in an invalid or not intended way. +//! Contributions are welcome! //! -//! # Supported versions of `libnftnl` -//! -//! This crate will automatically link to the currently installed version of libnftnl upon build. -//! It requires libnftnl version 1.0.6 or higher. See how the low level FFI bindings to the C -//! library are generated in [`build.rs`]. -//! -//! # Access to raw handles -//! -//! Retrieving raw handles is considered unsafe and should only ever be enabled if you absolutely -//! 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 exposed by the library as `Send` -//! nor `Sync`. -//! -//! [`libnftnl`]: https://netfilter.org/projects/libnftnl/ //! [`nftables`]: https://netfilter.org/projects/nftables/ -//! [`build.rs`]: https://gitlab.com/rustwall/rustables/-/blob/master/build.rs - -use thiserror::Error; #[macro_use] extern crate log; -pub mod sys; -use std::{convert::TryFrom, ffi::c_void, ops::Deref}; -use sys::libc; - -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 - }}; -} +use libc; + +use rustables_macros::nfnetlink_enum; +use std::convert::TryFrom; mod batch; -#[cfg(feature = "query")] -pub use batch::{batch_is_supported, default_batch_page_size}; -pub use batch::{Batch, FinalizedBatch, NetlinkError}; +pub use batch::{default_batch_page_size, Batch}; -pub mod expr; +pub mod data_type; -pub mod table; +mod table; +pub use table::list_tables; 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 use chain::list_chains_for_table; +pub use chain::{Chain, ChainPolicy, ChainPriority, ChainType, Hook, HookClass}; -mod chain_methods; -pub use chain_methods::ChainMethods; +pub mod error; pub mod query; +pub(crate) mod nlmsg; +pub(crate) mod parser; +pub(crate) mod parser_impls; + mod rule; +pub use rule::list_rules_for_chain; pub use rule::Rule; -#[cfg(feature = "query")] -pub use rule::{get_rules_cb, list_rules_for_chain}; + +pub mod expr; mod rule_methods; -pub use rule_methods::{iface_index, Protocol, RuleMethods, Error as MatchError}; +pub use rule_methods::{iface_index, Protocol}; pub mod set; pub use set::Set; +pub mod sys; + +#[cfg(test)] +mod tests; + /// 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 @@ -133,7 +97,7 @@ pub use set::Set; /// [`Chain`]: struct.Chain.html /// [`Rule`]: struct.Rule.html /// [`MsgType`]: enum.MsgType.html -#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] +#[derive(Debug, Copy, Clone, Eq, PartialEq)] pub enum MsgType { /// Add the object to netfilter. Add, @@ -142,69 +106,22 @@ pub enum MsgType { } /// 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, +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[nfnetlink_enum(i32)] +pub enum ProtocolFamily { + Unspec = libc::NFPROTO_UNSPEC, /// 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), - } - } + Inet = libc::NFPROTO_INET, + Ipv4 = libc::NFPROTO_IPV4, + Arp = libc::NFPROTO_ARP, + NetDev = libc::NFPROTO_NETDEV, + Bridge = libc::NFPROTO_BRIDGE, + Ipv6 = libc::NFPROTO_IPV6, + DecNet = libc::NFPROTO_DECNET, } -/// 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); +impl Default for ProtocolFamily { + fn default() -> Self { + ProtocolFamily::Unspec } } - -/// 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 -} |