Automatically manage firewall rules (iptables) for services #1
3 changed files with 228 additions and 2 deletions
126
Cargo.lock
generated
126
Cargo.lock
generated
|
@ -127,7 +127,10 @@ dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"futures",
|
"futures",
|
||||||
"igd",
|
"igd",
|
||||||
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
"mnl",
|
||||||
|
"nftnl",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
"serde",
|
"serde",
|
||||||
|
@ -164,6 +167,20 @@ dependencies = [
|
||||||
"termcolor",
|
"termcolor",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "err-derive"
|
||||||
|
version = "0.2.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "22deed3a8124cff5fa835713fa105621e43bbdc46690c3a6b68328a012d350d4"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"rustversion",
|
||||||
|
"syn",
|
||||||
|
"synstructure",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fnv"
|
name = "fnv"
|
||||||
version = "1.0.6"
|
version = "1.0.6"
|
||||||
|
@ -548,9 +565,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "libc"
|
name = "libc"
|
||||||
version = "0.2.66"
|
version = "0.2.70"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "log"
|
name = "log"
|
||||||
|
@ -620,6 +637,27 @@ dependencies = [
|
||||||
"ws2_32-sys",
|
"ws2_32-sys",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mnl"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6efb50a48dbacd112e7e847b9847fa530ec4a473ba6322a2f82c42ef333e226"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"mnl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "mnl-sys"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "5302035599c722b3a5b92a6502ff73c501dc6d100c53b89f0fae0cb932a37122"
|
||||||
|
dependencies = [
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "native-tls"
|
name = "native-tls"
|
||||||
version = "0.2.3"
|
version = "0.2.3"
|
||||||
|
@ -649,6 +687,30 @@ dependencies = [
|
||||||
"winapi 0.3.8",
|
"winapi 0.3.8",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nftnl"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f3727d1e8c1c9af88857f46539c3030693158a2a7586056b8cab6ded523bf7aa"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags",
|
||||||
|
"err-derive",
|
||||||
|
"libc",
|
||||||
|
"log",
|
||||||
|
"nftnl-sys",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nftnl-sys"
|
||||||
|
version = "0.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "dba134c9b125b7d7c13d813388aaeb2aeeba60fb1eb702799163fb845086ca33"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"libc",
|
||||||
|
"pkg-config",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "nom"
|
name = "nom"
|
||||||
version = "4.2.3"
|
version = "4.2.3"
|
||||||
|
@ -764,6 +826,32 @@ dependencies = [
|
||||||
"log",
|
"log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "98e9e4b82e0ef281812565ea4751049f1bdcdfccda7d3f459f2e138a40c08678"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro-error-attr",
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"version_check 0.9.1",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro-error-attr"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "4f5444ead4e9935abd7f27dc51f7e852a0569ac888096d5ec2499470794e2e53"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"syn-mid",
|
||||||
|
"version_check 0.9.1",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "proc-macro-hack"
|
name = "proc-macro-hack"
|
||||||
version = "0.5.11"
|
version = "0.5.11"
|
||||||
|
@ -952,6 +1040,17 @@ dependencies = [
|
||||||
"winreg",
|
"winreg",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustversion"
|
||||||
|
version = "1.0.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b3bba175698996010c4f6dce5e7f173b6eb781fce25d2cfc45e27091ce0b79f6"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ryu"
|
name = "ryu"
|
||||||
version = "1.0.2"
|
version = "1.0.2"
|
||||||
|
@ -1071,6 +1170,29 @@ dependencies = [
|
||||||
"unicode-xid",
|
"unicode-xid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn-mid"
|
||||||
|
version = "0.5.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "synstructure"
|
||||||
|
version = "0.12.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
"unicode-xid",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "tempfile"
|
name = "tempfile"
|
||||||
version = "3.1.0"
|
version = "3.1.0"
|
||||||
|
|
|
@ -17,3 +17,6 @@ serde = { version = "1.0.107", features = ["derive"] }
|
||||||
serde_json = "1.0.53"
|
serde_json = "1.0.53"
|
||||||
serde-lexpr = "0.1.1"
|
serde-lexpr = "0.1.1"
|
||||||
anyhow = "1.0.28"
|
anyhow = "1.0.28"
|
||||||
|
nftnl = "0.3.0"
|
||||||
|
mnl = "0.2.0"
|
||||||
|
libc = "0.2.70"
|
||||||
|
|
101
src/fw.rs
Normal file
101
src/fw.rs
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
use nftnl::{nft_expr, Batch, Chain, FinalizedBatch, ProtoFamily, Rule, Table};
|
||||||
|
use std::{
|
||||||
|
ffi::{self, CString},
|
||||||
|
io,
|
||||||
|
};
|
||||||
|
use mnl;
|
||||||
|
use libc;
|
||||||
|
|
||||||
|
const TABLE_NAME: &str = "diplonat";
|
||||||
|
const OUT_CHAIN_NAME: &str = "out";
|
||||||
|
const IN_CHAIN_NAME: &str = "in";
|
||||||
|
|
||||||
|
#[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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn send_and_process(batch: &FinalizedBatch) -> Result<(), Error> {
|
||||||
|
let socket = mnl::Socket::new(mnl::Bus::Netfilter)?;
|
||||||
|
socket.send_all(batch)?;
|
||||||
|
|
||||||
|
let portid = socket.portid();
|
||||||
|
let mut buffer = vec![0; nftnl::nft_nlmsg_maxsize() as usize];
|
||||||
|
|
||||||
|
while let Some(message) = socket_recv(&socket, &mut buffer[..])? {
|
||||||
|
match mnl::cb_run(message, 2, 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn add_port_allowed(port: u16) -> Result<(), Error> {
|
||||||
|
let mut batch = Batch::new();
|
||||||
|
|
||||||
|
// TODO: at the moment, I haven't found a way to properly separate setup part (create table and
|
||||||
|
// chains) and the add rule part because the add rule part needs a reference on the chains.
|
||||||
|
// apparently creating a table and chains that already exist seems to do nothing so it works
|
||||||
|
// doing the following. To be done properly though
|
||||||
|
|
||||||
|
let table = Table::new(&CString::new(TABLE_NAME).unwrap(), ProtoFamily::Inet);
|
||||||
|
|
||||||
|
batch.add(&table, nftnl::MsgType::Add);
|
||||||
|
|
||||||
|
let mut out_chain = Chain::new(&CString::new(OUT_CHAIN_NAME).unwrap(), &table);
|
||||||
|
let mut in_chain = Chain::new(&CString::new(IN_CHAIN_NAME).unwrap(), &table);
|
||||||
|
|
||||||
|
out_chain.set_hook(nftnl::Hook::Out, 0);
|
||||||
|
in_chain.set_hook(nftnl::Hook::In, 0);
|
||||||
|
|
||||||
|
out_chain.set_policy(nftnl::Policy::Accept);
|
||||||
|
in_chain.set_policy(nftnl::Policy::Drop);
|
||||||
|
|
||||||
|
batch.add(&out_chain, nftnl::MsgType::Add);
|
||||||
|
batch.add(&in_chain, nftnl::MsgType::Add);
|
||||||
|
|
||||||
|
let mut _rule = Rule::new(&in_chain);
|
||||||
|
|
||||||
|
_rule.add_expr(&nft_expr!(meta nfproto));
|
||||||
|
_rule.add_expr(&nft_expr!(cmp == libc::NFPROTO_IPV4 as u8));
|
||||||
|
|
||||||
|
_rule.add_expr(&nft_expr!(meta l4proto));
|
||||||
|
_rule.add_expr(&nft_expr!(cmp == libc::IPPROTO_TCP as u8));
|
||||||
|
|
||||||
|
_rule.add_expr(&nftnl::expr::Payload::Transport(
|
||||||
|
nftnl::expr::TransportHeaderField::Tcp(nftnl::expr::TcpHeaderField::Dport),
|
||||||
|
));
|
||||||
|
_rule.add_expr(&nft_expr!(cmp == port.to_be()));
|
||||||
|
|
||||||
|
_rule.add_expr(&nft_expr!(verdict accept));
|
||||||
|
|
||||||
|
batch.add(&_rule, nftnl::MsgType::Add);
|
||||||
|
|
||||||
|
let finalized_batch = batch.finalize();
|
||||||
|
send_and_process(&finalized_batch)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in a new issue