use crate::{errors::*, FirewallBackend, ProcessContext};
use slog::{debug, info, o, trace};
use std::{
io::{prelude::*, BufWriter},
process::Command,
};
use strum::Display;
mod process;
mod rule;
pub mod types;
const NF_IP_PRI_NAT_DST: i16 = -100;
const NF_IP_PRI_FILTER: i16 = 0;
const NF_IP_PRI_NAT_SRC: i16 = 100;
const NF_PRIORITY_IP_NAT_PREROUTING_DFW: i16 = NF_IP_PRI_NAT_DST - 5;
const NF_PRIORITY_IP6_NAT_PREROUTING_DFW: i16 = NF_IP_PRI_NAT_DST - 5;
const NF_PRIORITY_INET_FILTER_ANY_DFW: i16 = NF_IP_PRI_FILTER - 5;
const NF_PRIORITY_IP_NAT_POSTROUTING_DFW: i16 = NF_IP_PRI_NAT_SRC - 5;
const NF_PRIORITY_IP6_NAT_POSTROUTING_DFW: i16 = NF_IP_PRI_NAT_SRC - 5;
const DFW_MARK: &str = "0xdf";
#[derive(Debug)]
pub struct Nftables;
impl FirewallBackend for Nftables {
type Rule = String;
type Defaults = types::Defaults;
fn apply(rules: Vec<Self::Rule>, ctx: &ProcessContext<Nftables>) -> Result<()> {
if ctx.dry_run {
info!(ctx.logger, "Performing dry-run, will not update any rules");
} else {
let rule_file = tempfile::Builder::new().tempfile()?;
let rule_file_path = rule_file.as_ref().as_os_str().to_os_string();
debug!(ctx.logger, "Writing rules to temporary file";
o!("file_path" => rule_file_path.to_string_lossy().into_owned()));
let mut writer = BufWriter::new(rule_file);
for rule in rules {
writeln!(writer, "{}", rule)?;
}
writer.flush()?;
trace!(ctx.logger, "Finished writing rules to temporary file");
info!(ctx.logger, "Applying rules (using nft)");
let output = Command::new("nft").arg("-f").arg(rule_file_path).output()?;
if !output.status.success() {
return Err(DFWError::NFTablesError {
stdout: String::from_utf8_lossy(&output.stdout).into_owned(),
stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
}
.into());
} else {
return Ok(());
}
}
Ok(())
}
}
#[derive(Debug, Clone, Copy, Display)]
#[strum(serialize_all = "snake_case")]
pub enum Family {
Ip,
Ip6,
Inet,
Arp,
Bridge,
Netdev,
}
#[derive(Debug, Clone, Copy, Display)]
#[strum(serialize_all = "snake_case")]
pub enum Type {
Filter,
Route,
Nat,
}
#[derive(Debug, Clone, Copy, Display)]
#[strum(serialize_all = "snake_case")]
pub enum Hook {
Ingress,
Prerouting,
Input,
Forward,
Output,
Postrouting,
}