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",
|
||||
"futures",
|
||||
"igd",
|
||||
"libc",
|
||||
"log",
|
||||
"mnl",
|
||||
"nftnl",
|
||||
"pretty_env_logger",
|
||||
"reqwest",
|
||||
"serde",
|
||||
|
@ -164,6 +167,20 @@ dependencies = [
|
|||
"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]]
|
||||
name = "fnv"
|
||||
version = "1.0.6"
|
||||
|
@ -548,9 +565,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.66"
|
||||
version = "0.2.70"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
|
||||
checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
|
@ -620,6 +637,27 @@ dependencies = [
|
|||
"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]]
|
||||
name = "native-tls"
|
||||
version = "0.2.3"
|
||||
|
@ -649,6 +687,30 @@ dependencies = [
|
|||
"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]]
|
||||
name = "nom"
|
||||
version = "4.2.3"
|
||||
|
@ -764,6 +826,32 @@ dependencies = [
|
|||
"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]]
|
||||
name = "proc-macro-hack"
|
||||
version = "0.5.11"
|
||||
|
@ -952,6 +1040,17 @@ dependencies = [
|
|||
"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]]
|
||||
name = "ryu"
|
||||
version = "1.0.2"
|
||||
|
@ -1071,6 +1170,29 @@ dependencies = [
|
|||
"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]]
|
||||
name = "tempfile"
|
||||
version = "3.1.0"
|
||||
|
|
|
@ -17,3 +17,6 @@ serde = { version = "1.0.107", features = ["derive"] }
|
|||
serde_json = "1.0.53"
|
||||
serde-lexpr = "0.1.1"
|
||||
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