diff options
| author | Linus Färnstrand <linus@mullvad.net> | 2019-04-03 17:42:55 +0200 |
|---|---|---|
| committer | Linus Färnstrand <linus@mullvad.net> | 2019-04-03 17:42:55 +0200 |
| commit | 5d5392d39cc00696cd42c547587bbd7d767dd1c9 (patch) | |
| tree | ab306f220d70432731d1b565936edaab9abc5884 | |
| parent | ff97b87b8a5a547ae31dd8fde14cc2d60482e7e8 (diff) | |
| parent | 0fafa528a46f592082085155a27ee427e662af01 (diff) | |
| download | mullvadvpn-5d5392d39cc00696cd42c547587bbd7d767dd1c9.tar.xz mullvadvpn-5d5392d39cc00696cd42c547587bbd7d767dd1c9.zip | |
Merge branch 'upgrade-nftnl'
| -rw-r--r-- | Cargo.lock | 14 | ||||
| -rw-r--r-- | talpid-core/Cargo.toml | 2 | ||||
| -rw-r--r-- | talpid-core/src/firewall/linux.rs | 390 |
3 files changed, 199 insertions, 207 deletions
diff --git a/Cargo.lock b/Cargo.lock index ed0f8d6239..ae84577039 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1250,19 +1250,19 @@ dependencies = [ [[package]] name = "nftnl" version = "0.1.0" -source = "git+https://github.com/mullvad/nftnl-rs?rev=f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6#f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6" +source = "git+https://github.com/mullvad/nftnl-rs?rev=29651f4370fdf22cc2e3abf5097a51f8ff17e3a3#29651f4370fdf22cc2e3abf5097a51f8ff17e3a3" dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "error-chain 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "err-derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "nftnl-sys 0.1.0 (git+https://github.com/mullvad/nftnl-rs?rev=f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6)", + "nftnl-sys 0.1.0 (git+https://github.com/mullvad/nftnl-rs?rev=29651f4370fdf22cc2e3abf5097a51f8ff17e3a3)", ] [[package]] name = "nftnl-sys" version = "0.1.0" -source = "git+https://github.com/mullvad/nftnl-rs?rev=f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6#f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6" +source = "git+https://github.com/mullvad/nftnl-rs?rev=29651f4370fdf22cc2e3abf5097a51f8ff17e3a3#29651f4370fdf22cc2e3abf5097a51f8ff17e3a3" dependencies = [ "libc 0.2.51 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1997,7 +1997,7 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "mnl 0.1.0 (git+https://github.com/mullvad/mnl-rs?rev=f0d19501b9b85be9a1ffaec8317a378bcbdf4fa6)", "netlink-socket 0.0.2 (git+https://github.com/mullvad/netlink?branch=ignore-hw-address)", - "nftnl 0.1.0 (git+https://github.com/mullvad/nftnl-rs?rev=f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6)", + "nftnl 0.1.0 (git+https://github.com/mullvad/nftnl-rs?rev=29651f4370fdf22cc2e3abf5097a51f8ff17e3a3)", "nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "notify 4.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "openvpn-plugin 0.3.0 (git+https://github.com/mullvad/openvpn-plugin-rs?branch=auth-failed-event)", @@ -2727,8 +2727,8 @@ dependencies = [ "checksum mnl-sys 0.1.0 (git+https://github.com/mullvad/mnl-rs?rev=f0d19501b9b85be9a1ffaec8317a378bcbdf4fa6)" = "<none>" "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum netlink-socket 0.0.2 (git+https://github.com/mullvad/netlink?branch=ignore-hw-address)" = "<none>" -"checksum nftnl 0.1.0 (git+https://github.com/mullvad/nftnl-rs?rev=f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6)" = "<none>" -"checksum nftnl-sys 0.1.0 (git+https://github.com/mullvad/nftnl-rs?rev=f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6)" = "<none>" +"checksum nftnl 0.1.0 (git+https://github.com/mullvad/nftnl-rs?rev=29651f4370fdf22cc2e3abf5097a51f8ff17e3a3)" = "<none>" +"checksum nftnl-sys 0.1.0 (git+https://github.com/mullvad/nftnl-rs?rev=29651f4370fdf22cc2e3abf5097a51f8ff17e3a3)" = "<none>" "checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17" "checksum nix 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46f0f3210768d796e8fa79ec70ee6af172dacbe7147f5e69be5240a47778302b" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" diff --git a/talpid-core/Cargo.toml b/talpid-core/Cargo.toml index 1d2e0f5276..5d577d1c46 100644 --- a/talpid-core/Cargo.toml +++ b/talpid-core/Cargo.toml @@ -44,7 +44,7 @@ netlink-socket = { git = "https://github.com/mullvad/netlink", branch = "ignore- notify = "4.0" resolv-conf = "0.6.1" rtnetlink = { git = "https://github.com/mullvad/netlink", branch = "ignore-hw-address" } -nftnl = { git = "https://github.com/mullvad/nftnl-rs", rev = "f0b1492fd2fd1f737dbffd047c9c60c300e6f7d6", features = ["nftnl-1-1-0"] } +nftnl = { git = "https://github.com/mullvad/nftnl-rs", rev = "29651f4370fdf22cc2e3abf5097a51f8ff17e3a3", features = ["nftnl-1-1-0"] } mnl = { git = "https://github.com/mullvad/mnl-rs", rev = "f0d19501b9b85be9a1ffaec8317a378bcbdf4fa6", features = ["mnl-1-0-4"] } which = "2.0" err-derive = "0.1.5" diff --git a/talpid-core/src/firewall/linux.rs b/talpid-core/src/firewall/linux.rs index d073853ad0..e687a7c7a7 100644 --- a/talpid-core/src/firewall/linux.rs +++ b/talpid-core/src/firewall/linux.rs @@ -5,36 +5,48 @@ use lazy_static::lazy_static; use libc; use nftnl::{ expr::{self, Verdict}, - nft_expr, nft_expr_bitwise, nft_expr_cmp, nft_expr_ct, nft_expr_meta, nft_expr_payload, table, - Batch, Chain, FinalizedBatch, ProtoFamily, Rule, Table, + nft_expr, table, Batch, Chain, FinalizedBatch, ProtoFamily, Rule, Table, }; use std::{ env, ffi::{CStr, CString}, + io, net::{IpAddr, Ipv4Addr}, }; use talpid_types::net::{Endpoint, TransportProtocol}; -error_chain! { - errors { - /// Unable to open netlink socket to netfilter - NetlinkOpenError { description("Unable to open netlink socket to netfilter") } - /// Unable to send netlink command to netfilter - NetlinkSendError { description("Unable to send netlink command to netfilter") } - /// Error while reading from netlink socket - NetlinkRecvError { description("Error while reading from netlink socket") } - /// Error while processing an incoming netlink message - ProcessNetlinkError { description("Error while processing an incoming netlink message") } - /// Failed to verify that our tables are set. Probably means that - /// it's the host does not support nftables properly. - NetfilterTableNotSetError{ description("Failed to set firewall rules") } - } - links { - Nftnl(nftnl::Error, nftnl::ErrorKind) #[doc = "Error in nftnl"]; - } - foreign_links { - IfaceIndexLookupError(crate::linux::IfaceIndexLookupError); - } +pub type Result<T> = std::result::Result<T, Error>; + +/// Errors that can happen when interacting with Linux netfilter. +#[derive(err_derive::Error, Debug)] +pub enum Error { + /// Unable to open netlink socket to netfilter. + #[error(display = "Unable to open netlink socket to netfilter")] + NetlinkOpenError(#[error(cause)] io::Error), + + /// Unable to send netlink command to netfilter. + #[error(display = "Unable to send netlink command to netfilter")] + NetlinkSendError(#[error(cause)] io::Error), + + /// Error while reading from netlink socket. + #[error(display = "Error while reading from netlink socket")] + NetlinkRecvError(#[error(cause)] io::Error), + + /// Error while processing an incoming netlink message. + #[error(display = "Error while processing an incoming netlink message")] + ProcessNetlinkError(#[error(cause)] io::Error), + + /// Failed to verify that our tables are set. Probably means that + /// it's the host that does not support nftables properly. + #[error(display = "Failed to set firewall rules")] + NetfilterTableNotSetError, + + /// Unable to translate network interface name into index. + #[error( + display = "Unable to translate network interface name \"{}\" into index", + _0 + )] + LookupIfaceIndexError(String, #[error(cause)] crate::linux::IfaceIndexLookupError), } lazy_static! { @@ -78,21 +90,21 @@ impl FirewallT for Firewall { } fn apply_policy(&mut self, policy: FirewallPolicy) -> Result<()> { - let table = Table::new(&self.table_name, ProtoFamily::Inet)?; - let batch = PolicyBatch::new(&table)?.finalize(&policy)?; + let table = Table::new(&self.table_name, ProtoFamily::Inet); + let batch = PolicyBatch::new(&table).finalize(&policy)?; self.send_and_process(&batch)?; self.verify_tables(&[&TABLE_NAME]) } fn reset_policy(&mut self) -> Result<()> { - let table = Table::new(&self.table_name, ProtoFamily::Inet)?; + let table = Table::new(&self.table_name, ProtoFamily::Inet); let batch = { - let mut batch = Batch::new()?; + let mut batch = Batch::new(); // Our batch will add and remove the table even though the goal is just to remove it. // This because only removing it throws a strange error if the table does not exist. - batch.add(&table, nftnl::MsgType::Add)?; - batch.add(&table, nftnl::MsgType::Del)?; - batch.finalize()? + batch.add(&table, nftnl::MsgType::Add); + batch.add(&table, nftnl::MsgType::Del); + batch.finalize() }; log::debug!("Removing table and chain from netfilter"); @@ -102,18 +114,15 @@ impl FirewallT for Firewall { impl Firewall { fn send_and_process(&self, batch: &FinalizedBatch) -> Result<()> { - let socket = - mnl::Socket::new(mnl::Bus::Netfilter).chain_err(|| ErrorKind::NetlinkOpenError)?; - socket - .send_all(batch) - .chain_err(|| ErrorKind::NetlinkSendError)?; + let socket = mnl::Socket::new(mnl::Bus::Netfilter).map_err(Error::NetlinkOpenError)?; + socket.send_all(batch).map_err(Error::NetlinkSendError)?; let portid = socket.portid(); let mut buffer = vec![0; nftnl::nft_nlmsg_maxsize() as usize]; let seq = 0; while let Some(message) = Self::socket_recv(&socket, &mut buffer[..])? { - match mnl::cb_run(message, seq, portid).chain_err(|| ErrorKind::ProcessNetlinkError)? { + match mnl::cb_run(message, seq, portid).map_err(Error::ProcessNetlinkError)? { mnl::CbResult::Stop => { log::trace!("cb_run STOP"); break; @@ -125,22 +134,21 @@ impl Firewall { } fn verify_tables(&self, expected_tables: &[&CStr]) -> Result<()> { - let socket = - mnl::Socket::new(mnl::Bus::Netfilter).chain_err(|| ErrorKind::NetlinkOpenError)?; + let socket = mnl::Socket::new(mnl::Bus::Netfilter).map_err(Error::NetlinkOpenError)?; let portid = socket.portid(); let seq = 0; let get_tables_msg = table::get_tables_nlmsg(seq);; socket .send(&get_tables_msg) - .chain_err(|| ErrorKind::NetlinkSendError)?; + .map_err(Error::NetlinkSendError)?; let mut table_set = ::std::collections::HashSet::new(); let mut msg_buffer = vec![0; nftnl::nft_nlmsg_maxsize() as usize]; while let Some(message) = Self::socket_recv(&socket, &mut msg_buffer)? { match mnl::cb_run2(message, seq, portid, table::get_tables_cb, &mut table_set) - .chain_err(|| ErrorKind::ProcessNetlinkError)? + .map_err(Error::ProcessNetlinkError)? { mnl::CbResult::Stop => { log::trace!("cb_run STOP"); @@ -156,14 +164,14 @@ impl Firewall { "Expected '{}' netfilter table to be set, but it is not", expected_table.to_string_lossy() ); - bail!(ErrorKind::NetfilterTableNotSetError) + bail!(Error::NetfilterTableNotSetError) } } Ok(()) } fn socket_recv<'a>(socket: &mnl::Socket, buf: &'a mut [u8]) -> Result<Option<&'a [u8]>> { - let ret = socket.recv(buf).chain_err(|| ErrorKind::NetlinkRecvError)?; + let ret = socket.recv(buf).map_err(Error::NetlinkRecvError)?; log::trace!("Read {} bytes from netlink", ret); if ret > 0 { Ok(Some(&buf[..ret])) @@ -182,36 +190,36 @@ struct PolicyBatch<'a> { impl<'a> PolicyBatch<'a> { /// Bootstrap a new nftnl message batch object and add the initial messages creating the /// table and chains. - pub fn new(table: &'a Table) -> Result<Self> { - let mut batch = Batch::new()?; - let mut out_chain = Chain::new(&*OUT_CHAIN_NAME, table)?; - let mut in_chain = Chain::new(&*IN_CHAIN_NAME, table)?; + pub fn new(table: &'a Table) -> Self { + let mut batch = Batch::new(); + let mut out_chain = Chain::new(&*OUT_CHAIN_NAME, table); + let mut in_chain = Chain::new(&*IN_CHAIN_NAME, table); out_chain.set_hook(nftnl::Hook::Out, 0); in_chain.set_hook(nftnl::Hook::In, 0); out_chain.set_policy(nftnl::Policy::Drop); in_chain.set_policy(nftnl::Policy::Drop); - batch.add(table, nftnl::MsgType::Add)?; - batch.add(table, nftnl::MsgType::Del)?; - batch.add(table, nftnl::MsgType::Add)?; - batch.add(&out_chain, nftnl::MsgType::Add)?; - batch.add(&in_chain, nftnl::MsgType::Add)?; + batch.add(table, nftnl::MsgType::Add); + batch.add(table, nftnl::MsgType::Del); + batch.add(table, nftnl::MsgType::Add); + batch.add(&out_chain, nftnl::MsgType::Add); + batch.add(&in_chain, nftnl::MsgType::Add); - Ok(PolicyBatch { + PolicyBatch { batch, in_chain, out_chain, - }) + } } /// Finalize the nftnl message batch by adding every firewall rule needed to satisfy the given /// policy. pub fn finalize(mut self, policy: &FirewallPolicy) -> Result<FinalizedBatch> { self.add_loopback_rules()?; - self.add_dhcp_rules()?; + self.add_dhcp_rules(); self.add_policy_specific_rules(policy)?; - Ok(self.batch.finalize()?) + Ok(self.batch.finalize()) } fn add_loopback_rules(&mut self) -> Result<()> { @@ -219,54 +227,53 @@ impl<'a> PolicyBatch<'a> { self.batch.add( &allow_interface_rule(&self.out_chain, Direction::Out, LOOPBACK_IFACE_NAME)?, nftnl::MsgType::Add, - )?; + ); self.batch.add( &allow_interface_rule(&self.in_chain, Direction::In, LOOPBACK_IFACE_NAME)?, nftnl::MsgType::Add, - )?; + ); Ok(()) } - fn add_dhcp_rules(&mut self) -> Result<()> { + fn add_dhcp_rules(&mut self) { use self::TransportProtocol::Udp; const SERVER_PORT_V4: u16 = 67; const CLIENT_PORT_V4: u16 = 68; const SERVER_PORT_V6: u16 = 547; const CLIENT_PORT_V6: u16 = 546; { - let mut out_v4 = Rule::new(&self.out_chain)?; - check_port(&mut out_v4, Udp, End::Src, CLIENT_PORT_V4)?; - check_ip(&mut out_v4, End::Dst, IpAddr::V4(Ipv4Addr::BROADCAST))?; - check_port(&mut out_v4, Udp, End::Dst, SERVER_PORT_V4)?; - add_verdict(&mut out_v4, &Verdict::Accept)?; - self.batch.add(&out_v4, nftnl::MsgType::Add)?; + let mut out_v4 = Rule::new(&self.out_chain); + check_port(&mut out_v4, Udp, End::Src, CLIENT_PORT_V4); + check_ip(&mut out_v4, End::Dst, IpAddr::V4(Ipv4Addr::BROADCAST)); + check_port(&mut out_v4, Udp, End::Dst, SERVER_PORT_V4); + add_verdict(&mut out_v4, &Verdict::Accept); + self.batch.add(&out_v4, nftnl::MsgType::Add); } { - let mut in_v4 = Rule::new(&self.in_chain)?; - check_port(&mut in_v4, Udp, End::Src, SERVER_PORT_V4)?; - check_port(&mut in_v4, Udp, End::Dst, CLIENT_PORT_V4)?; - add_verdict(&mut in_v4, &Verdict::Accept)?; - self.batch.add(&in_v4, nftnl::MsgType::Add)?; + let mut in_v4 = Rule::new(&self.in_chain); + check_port(&mut in_v4, Udp, End::Src, SERVER_PORT_V4); + check_port(&mut in_v4, Udp, End::Dst, CLIENT_PORT_V4); + add_verdict(&mut in_v4, &Verdict::Accept); + self.batch.add(&in_v4, nftnl::MsgType::Add); } for dhcpv6_server in &*super::DHCPV6_SERVER_ADDRS { - let mut out_v6 = Rule::new(&self.out_chain)?; - check_net(&mut out_v6, End::Src, *super::LOCAL_INET6_NET)?; - check_port(&mut out_v6, Udp, End::Src, CLIENT_PORT_V6)?; - check_ip(&mut out_v6, End::Dst, *dhcpv6_server)?; - check_port(&mut out_v6, Udp, End::Dst, SERVER_PORT_V6)?; - add_verdict(&mut out_v6, &Verdict::Accept)?; - self.batch.add(&out_v6, nftnl::MsgType::Add)?; + let mut out_v6 = Rule::new(&self.out_chain); + check_net(&mut out_v6, End::Src, *super::LOCAL_INET6_NET); + check_port(&mut out_v6, Udp, End::Src, CLIENT_PORT_V6); + check_ip(&mut out_v6, End::Dst, *dhcpv6_server); + check_port(&mut out_v6, Udp, End::Dst, SERVER_PORT_V6); + add_verdict(&mut out_v6, &Verdict::Accept); + self.batch.add(&out_v6, nftnl::MsgType::Add); } { - let mut in_v6 = Rule::new(&self.in_chain)?; - check_net(&mut in_v6, End::Src, *super::LOCAL_INET6_NET)?; - check_port(&mut in_v6, Udp, End::Src, SERVER_PORT_V6)?; - check_net(&mut in_v6, End::Dst, *super::LOCAL_INET6_NET)?; - check_port(&mut in_v6, Udp, End::Dst, CLIENT_PORT_V6)?; - add_verdict(&mut in_v6, &Verdict::Accept)?; - self.batch.add(&in_v6, nftnl::MsgType::Add)?; + let mut in_v6 = Rule::new(&self.in_chain); + check_net(&mut in_v6, End::Src, *super::LOCAL_INET6_NET); + check_port(&mut in_v6, Udp, End::Src, SERVER_PORT_V6); + check_net(&mut in_v6, End::Dst, *super::LOCAL_INET6_NET); + check_port(&mut in_v6, Udp, End::Dst, CLIENT_PORT_V6); + add_verdict(&mut in_v6, &Verdict::Accept); + self.batch.add(&in_v6, nftnl::MsgType::Add); } - Ok(()) } fn add_policy_specific_rules(&mut self, policy: &FirewallPolicy) -> Result<()> { @@ -276,8 +283,8 @@ impl<'a> PolicyBatch<'a> { pingable_hosts, allow_lan, } => { - self.add_allow_icmp_pingable_hosts(&pingable_hosts)?; - self.add_allow_endpoint_rules(peer_endpoint)?; + self.add_allow_icmp_pingable_hosts(&pingable_hosts); + self.add_allow_endpoint_rules(peer_endpoint); *allow_lan } FirewallPolicy::Connected { @@ -285,7 +292,7 @@ impl<'a> PolicyBatch<'a> { tunnel, allow_lan, } => { - self.add_allow_endpoint_rules(peer_endpoint)?; + self.add_allow_endpoint_rules(peer_endpoint); self.add_dns_rule(tunnel, TransportProtocol::Udp)?; self.add_dns_rule(tunnel, TransportProtocol::Tcp)?; self.add_allow_tunnel_rules(tunnel)?; @@ -295,56 +302,52 @@ impl<'a> PolicyBatch<'a> { }; if allow_lan { - self.add_allow_lan_rules()?; + self.add_allow_lan_rules(); } Ok(()) } - fn add_allow_endpoint_rules(&mut self, endpoint: &Endpoint) -> Result<()> { - let mut in_rule = Rule::new(&self.in_chain)?; - check_endpoint(&mut in_rule, End::Src, endpoint)?; + fn add_allow_endpoint_rules(&mut self, endpoint: &Endpoint) { + let mut in_rule = Rule::new(&self.in_chain); + check_endpoint(&mut in_rule, End::Src, endpoint); - in_rule.add_expr(&nft_expr!(ct state))?; + in_rule.add_expr(&nft_expr!(ct state)); let allowed_states = nftnl::expr::ct::States::ESTABLISHED.bits(); - in_rule.add_expr(&nft_expr!(bitwise mask allowed_states, xor 0u32))?; - in_rule.add_expr(&nft_expr!(cmp != 0u32))?; - add_verdict(&mut in_rule, &Verdict::Accept)?; - - self.batch.add(&in_rule, nftnl::MsgType::Add)?; + in_rule.add_expr(&nft_expr!(bitwise mask allowed_states, xor 0u32)); + in_rule.add_expr(&nft_expr!(cmp != 0u32)); + add_verdict(&mut in_rule, &Verdict::Accept); + self.batch.add(&in_rule, nftnl::MsgType::Add); - let mut out_rule = Rule::new(&self.out_chain)?; - check_endpoint(&mut out_rule, End::Dst, endpoint)?; - add_verdict(&mut out_rule, &Verdict::Accept)?; - self.batch.add(&out_rule, nftnl::MsgType::Add)?; + let mut out_rule = Rule::new(&self.out_chain); + check_endpoint(&mut out_rule, End::Dst, endpoint); + add_verdict(&mut out_rule, &Verdict::Accept); - Ok(()) + self.batch.add(&out_rule, nftnl::MsgType::Add); } - fn add_allow_icmp_pingable_hosts(&mut self, pingable_hosts: &[IpAddr]) -> Result<()> { + fn add_allow_icmp_pingable_hosts(&mut self, pingable_hosts: &[IpAddr]) { for host in pingable_hosts { let icmp_proto = match &host { &IpAddr::V4(_) => libc::IPPROTO_ICMP as u8, &IpAddr::V6(_) => libc::IPPROTO_ICMPV6 as u8, }; - let mut out_rule = Rule::new(&self.out_chain)?; - check_ip(&mut out_rule, End::Dst, *host)?; - out_rule.add_expr(&nft_expr!(meta l4proto))?; - out_rule.add_expr(&nft_expr!(cmp == icmp_proto))?; - add_verdict(&mut out_rule, &Verdict::Accept)?; - self.batch.add(&out_rule, nftnl::MsgType::Add)?; + let mut out_rule = Rule::new(&self.out_chain); + check_ip(&mut out_rule, End::Dst, *host); + out_rule.add_expr(&nft_expr!(meta l4proto)); + out_rule.add_expr(&nft_expr!(cmp == icmp_proto)); + add_verdict(&mut out_rule, &Verdict::Accept); + self.batch.add(&out_rule, nftnl::MsgType::Add); - let mut in_rule = Rule::new(&self.in_chain)?; - check_ip(&mut in_rule, End::Src, *host)?; - in_rule.add_expr(&nft_expr!(meta l4proto))?; - in_rule.add_expr(&nft_expr!(cmp == icmp_proto))?; - add_verdict(&mut in_rule, &Verdict::Accept)?; - self.batch.add(&in_rule, nftnl::MsgType::Add)?; + let mut in_rule = Rule::new(&self.in_chain); + check_ip(&mut in_rule, End::Src, *host); + in_rule.add_expr(&nft_expr!(meta l4proto)); + in_rule.add_expr(&nft_expr!(cmp == icmp_proto)); + add_verdict(&mut in_rule, &Verdict::Accept); + self.batch.add(&in_rule, nftnl::MsgType::Add); } - - Ok(()) } fn add_dns_rule( @@ -357,10 +360,10 @@ impl<'a> PolicyBatch<'a> { if let Some(ipv6_gateway) = tunnel.ipv6_gateway { self.add_allow_dns_rule(&tunnel.interface, protocol, ipv6_gateway.into())?; }; - let mut block_rule = Rule::new(&self.out_chain)?; - check_port(&mut block_rule, protocol, End::Dst, 53)?; - add_verdict(&mut block_rule, &Verdict::Drop)?; - self.batch.add(&block_rule, nftnl::MsgType::Add)?; + let mut block_rule = Rule::new(&self.out_chain); + check_port(&mut block_rule, protocol, End::Dst, 53); + add_verdict(&mut block_rule, &Verdict::Drop); + self.batch.add(&block_rule, nftnl::MsgType::Add); Ok(()) } @@ -371,21 +374,21 @@ impl<'a> PolicyBatch<'a> { protocol: TransportProtocol, host: IpAddr, ) -> Result<()> { - let mut allow_rule = Rule::new(&self.out_chain)?; + let mut allow_rule = Rule::new(&self.out_chain); let daddr = match host { IpAddr::V4(_) => nft_expr!(payload ipv4 daddr), IpAddr::V6(_) => nft_expr!(payload ipv6 daddr), }; check_iface(&mut allow_rule, Direction::Out, interface)?; - check_port(&mut allow_rule, protocol, End::Dst, 53)?; - check_l3proto(&mut allow_rule, host)?; + check_port(&mut allow_rule, protocol, End::Dst, 53); + check_l3proto(&mut allow_rule, host); - allow_rule.add_expr(&daddr)?; - allow_rule.add_expr(&nft_expr!(cmp == host))?; - add_verdict(&mut allow_rule, &Verdict::Accept)?; + allow_rule.add_expr(&daddr); + allow_rule.add_expr(&nft_expr!(cmp == host)); + add_verdict(&mut allow_rule, &Verdict::Accept); - self.batch.add(&allow_rule, nftnl::MsgType::Add)?; + self.batch.add(&allow_rule, nftnl::MsgType::Add); Ok(()) } @@ -393,53 +396,52 @@ impl<'a> PolicyBatch<'a> { self.batch.add( &allow_interface_rule(&self.out_chain, Direction::Out, &tunnel.interface[..])?, nftnl::MsgType::Add, - )?; + ); self.batch.add( &allow_interface_rule(&self.in_chain, Direction::In, &tunnel.interface[..])?, nftnl::MsgType::Add, - )?; + ); Ok(()) } - fn add_allow_lan_rules(&mut self) -> Result<()> { + fn add_allow_lan_rules(&mut self) { // LAN -> LAN for chain in &[&self.in_chain, &self.out_chain] { for net in &*super::PRIVATE_NETS { - let mut rule = Rule::new(chain)?; - check_net(&mut rule, End::Src, *net)?; - check_net(&mut rule, End::Dst, *net)?; - add_verdict(&mut rule, &Verdict::Accept)?; - self.batch.add(&rule, nftnl::MsgType::Add)?; + let mut rule = Rule::new(chain); + check_net(&mut rule, End::Src, *net); + check_net(&mut rule, End::Dst, *net); + add_verdict(&mut rule, &Verdict::Accept); + self.batch.add(&rule, nftnl::MsgType::Add); } - let mut rule = Rule::new(chain)?; - check_net(&mut rule, End::Src, *super::LOCAL_INET6_NET)?; - check_net(&mut rule, End::Dst, *super::LOCAL_INET6_NET)?; - add_verdict(&mut rule, &Verdict::Accept)?; - self.batch.add(&rule, nftnl::MsgType::Add)?; + let mut rule = Rule::new(chain); + check_net(&mut rule, End::Src, *super::LOCAL_INET6_NET); + check_net(&mut rule, End::Dst, *super::LOCAL_INET6_NET); + add_verdict(&mut rule, &Verdict::Accept); + self.batch.add(&rule, nftnl::MsgType::Add); } // LAN -> multicast for net in &*super::PRIVATE_NETS { - let mut rule = Rule::new(&self.out_chain)?; - check_net(&mut rule, End::Src, *net)?; - check_net(&mut rule, End::Dst, *super::MULTICAST_NET)?; - add_verdict(&mut rule, &Verdict::Accept)?; + let mut rule = Rule::new(&self.out_chain); + check_net(&mut rule, End::Src, *net); + check_net(&mut rule, End::Dst, *super::MULTICAST_NET); + add_verdict(&mut rule, &Verdict::Accept); - self.batch.add(&rule, nftnl::MsgType::Add)?; + self.batch.add(&rule, nftnl::MsgType::Add); // LAN -> SSDP + WS-Discovery protocols - let mut rule = Rule::new(&self.out_chain)?; - check_net(&mut rule, End::Src, *net)?; - check_ip(&mut rule, End::Dst, *super::SSDP_IP)?; - add_verdict(&mut rule, &Verdict::Accept)?; + let mut rule = Rule::new(&self.out_chain); + check_net(&mut rule, End::Src, *net); + check_ip(&mut rule, End::Dst, *super::SSDP_IP); + add_verdict(&mut rule, &Verdict::Accept); - self.batch.add(&rule, nftnl::MsgType::Add)?; + self.batch.add(&rule, nftnl::MsgType::Add); } - let mut rule = Rule::new(&self.out_chain)?; - check_net(&mut rule, End::Src, *super::LOCAL_INET6_NET)?; - check_net(&mut rule, End::Dst, *super::MULTICAST_INET6_NET)?; - add_verdict(&mut rule, &Verdict::Accept)?; - self.batch.add(&rule, nftnl::MsgType::Add)?; - Ok(()) + let mut rule = Rule::new(&self.out_chain); + check_net(&mut rule, End::Src, *super::LOCAL_INET6_NET); + check_net(&mut rule, End::Dst, *super::MULTICAST_INET6_NET); + add_verdict(&mut rule, &Verdict::Accept); + self.batch.add(&rule, nftnl::MsgType::Add); } } @@ -448,86 +450,78 @@ fn allow_interface_rule<'a>( direction: Direction, iface: &str, ) -> Result<Rule<'a>> { - let mut rule = Rule::new(&chain)?; + let mut rule = Rule::new(&chain); check_iface(&mut rule, direction, iface)?; - add_verdict(&mut rule, &Verdict::Accept)?; + add_verdict(&mut rule, &Verdict::Accept); Ok(rule) } fn check_iface(rule: &mut Rule, direction: Direction, iface: &str) -> Result<()> { - let iface_index = crate::linux::iface_index(iface)?; + let iface_index = crate::linux::iface_index(iface) + .map_err(|e| Error::LookupIfaceIndexError(iface.to_owned(), e))?; rule.add_expr(&match direction { Direction::In => nft_expr!(meta iif), Direction::Out => nft_expr!(meta oif), - })?; - rule.add_expr(&nft_expr!(cmp == iface_index))?; + }); + rule.add_expr(&nft_expr!(cmp == iface_index)); Ok(()) } -fn check_net(rule: &mut Rule, end: End, net: IpNetwork) -> Result<()> { +fn check_net(rule: &mut Rule, end: End, net: IpNetwork) { // Must check network layer protocol before loading network layer payload - check_l3proto(rule, net.ip())?; + check_l3proto(rule, net.ip()); rule.add_expr(&match (net, end) { (IpNetwork::V4(_), End::Src) => nft_expr!(payload ipv4 saddr), (IpNetwork::V4(_), End::Dst) => nft_expr!(payload ipv4 daddr), (IpNetwork::V6(_), End::Src) => nft_expr!(payload ipv6 saddr), (IpNetwork::V6(_), End::Dst) => nft_expr!(payload ipv6 daddr), - })?; + }); match net { - IpNetwork::V4(_) => rule.add_expr(&nft_expr!(bitwise mask net.mask(), xor 0u32))?, - IpNetwork::V6(_) => { - rule.add_expr(&nft_expr!(bitwise mask net.mask(), xor &[0u16; 8][..]))? - } + IpNetwork::V4(_) => rule.add_expr(&nft_expr!(bitwise mask net.mask(), xor 0u32)), + IpNetwork::V6(_) => rule.add_expr(&nft_expr!(bitwise mask net.mask(), xor &[0u16; 8][..])), }; - rule.add_expr(&nft_expr!(cmp == net.ip()))?; - - Ok(()) + rule.add_expr(&nft_expr!(cmp == net.ip())); } -fn check_endpoint(rule: &mut Rule, end: End, endpoint: &Endpoint) -> Result<()> { - check_ip(rule, end, endpoint.address.ip())?; - check_port(rule, endpoint.protocol, end, endpoint.address.port())?; - Ok(()) +fn check_endpoint(rule: &mut Rule, end: End, endpoint: &Endpoint) { + check_ip(rule, end, endpoint.address.ip()); + check_port(rule, endpoint.protocol, end, endpoint.address.port()); } - -fn check_ip(rule: &mut Rule, end: End, ip: IpAddr) -> Result<()> { +fn check_ip(rule: &mut Rule, end: End, ip: IpAddr) { // Must check network layer protocol before loading network layer payload - check_l3proto(rule, ip)?; + check_l3proto(rule, ip); rule.add_expr(&match (ip, end) { (IpAddr::V4(..), End::Src) => nft_expr!(payload ipv4 saddr), (IpAddr::V4(..), End::Dst) => nft_expr!(payload ipv4 daddr), (IpAddr::V6(..), End::Src) => nft_expr!(payload ipv6 saddr), (IpAddr::V6(..), End::Dst) => nft_expr!(payload ipv6 daddr), - })?; + }); match ip { - IpAddr::V4(addr) => rule.add_expr(&nft_expr!(cmp == addr))?, - IpAddr::V6(addr) => rule.add_expr(&nft_expr!(cmp == addr))?, + IpAddr::V4(addr) => rule.add_expr(&nft_expr!(cmp == addr)), + IpAddr::V6(addr) => rule.add_expr(&nft_expr!(cmp == addr)), } - Ok(()) } -fn check_port(rule: &mut Rule, protocol: TransportProtocol, end: End, port: u16) -> Result<()> { +fn check_port(rule: &mut Rule, protocol: TransportProtocol, end: End, port: u16) { // Must check transport layer protocol before loading transport layer payload - check_l4proto(rule, protocol)?; + check_l4proto(rule, protocol); rule.add_expr(&match (protocol, end) { (TransportProtocol::Udp, End::Src) => nft_expr!(payload udp sport), (TransportProtocol::Udp, End::Dst) => nft_expr!(payload udp dport), (TransportProtocol::Tcp, End::Src) => nft_expr!(payload tcp sport), (TransportProtocol::Tcp, End::Dst) => nft_expr!(payload tcp dport), - })?; - rule.add_expr(&nft_expr!(cmp == port.to_be()))?; - Ok(()) + }); + rule.add_expr(&nft_expr!(cmp == port.to_be())); } -fn check_l3proto(rule: &mut Rule, ip: IpAddr) -> Result<()> { - rule.add_expr(&nft_expr!(meta nfproto))?; - rule.add_expr(&nft_expr!(cmp == l3proto(ip)))?; - Ok(()) +fn check_l3proto(rule: &mut Rule, ip: IpAddr) { + rule.add_expr(&nft_expr!(meta nfproto)); + rule.add_expr(&nft_expr!(cmp == l3proto(ip))); } fn l3proto(addr: IpAddr) -> u8 { @@ -537,10 +531,9 @@ fn l3proto(addr: IpAddr) -> u8 { } } -fn check_l4proto(rule: &mut Rule, protocol: TransportProtocol) -> Result<()> { - rule.add_expr(&nft_expr!(meta l4proto))?; - rule.add_expr(&nft_expr!(cmp == l4proto(protocol)))?; - Ok(()) +fn check_l4proto(rule: &mut Rule, protocol: TransportProtocol) { + rule.add_expr(&nft_expr!(meta l4proto)); + rule.add_expr(&nft_expr!(cmp == l4proto(protocol))); } fn l4proto(protocol: TransportProtocol) -> u8 { @@ -550,10 +543,9 @@ fn l4proto(protocol: TransportProtocol) -> u8 { } } -fn add_verdict(rule: &mut Rule, verdict: &expr::Verdict) -> Result<()> { +fn add_verdict(rule: &mut Rule, verdict: &expr::Verdict) { if *ADD_COUNTERS { - rule.add_expr(&nft_expr!(counter))?; + rule.add_expr(&nft_expr!(counter)); } - rule.add_expr(verdict)?; - Ok(()) + rule.add_expr(verdict); } |
