corrections after review

This commit is contained in:
darkgallium 2020-07-04 16:59:41 +02:00
parent a59ed38121
commit 4f4b6b048d
2 changed files with 40 additions and 35 deletions

View File

@ -2,61 +2,58 @@ use iptables;
use regex::Regex; use regex::Regex;
use std::collections::HashSet; use std::collections::HashSet;
use crate::messages; use crate::messages;
use anyhow::{Result,Context};
use log::*;
#[derive(Debug)] pub fn setup(ipt: &iptables::IPTables) -> Result<()> {
pub struct FirewallError(String);
impl From<iptables::error::IPTError> for FirewallError { // ensure we start from a clean state without any rule already set
fn from(error: iptables::error::IPTError) -> Self { cleanup(ipt)?;
FirewallError(error.to_string())
} ipt.new_chain("filter", "DIPLONAT").context("Failed to create new chain")?;
} ipt.insert_unique("filter", "INPUT", "-j DIPLONAT", 1).context("Failed to insert jump rule")?;
pub fn setup(ipt: &iptables::IPTables) -> Result<(), FirewallError> {
if !ipt.chain_exists("filter", "DIPLONAT")? {
ipt.new_chain("filter", "DIPLONAT")?;
}
ipt.insert_unique("filter", "INPUT", "-j DIPLONAT", 1)?;
Ok(()) Ok(())
} }
pub fn open_ports(ipt: &iptables::IPTables, ports: messages::PublicExposedPorts) -> Result<(), FirewallError> { pub fn open_ports(ipt: &iptables::IPTables, ports: messages::PublicExposedPorts) -> Result<()> {
for p in ports.tcp_ports { for p in ports.tcp_ports {
ipt.append("filter", "DIPLONAT", &format!("-p tcp --dport {} -j ACCEPT", p))?; ipt.append("filter", "DIPLONAT", &format!("-p tcp --dport {} -j ACCEPT", p)).context("Failed to insert port rule")?;
} }
for p in ports.udp_ports { for p in ports.udp_ports {
ipt.append("filter", "DIPLONAT", &format!("-p udp --dport {} -j ACCEPT", p))?; ipt.append("filter", "DIPLONAT", &format!("-p udp --dport {} -j ACCEPT", p)).context("Failed to insert port rule")?;
} }
Ok(()) Ok(())
} }
pub fn get_opened_ports(ipt: &iptables::IPTables) -> Result<messages::PublicExposedPorts, FirewallError> { pub fn get_opened_ports(ipt: &iptables::IPTables) -> Result<messages::PublicExposedPorts> {
let mut ports = messages::PublicExposedPorts { let mut ports = messages::PublicExposedPorts {
tcp_ports: HashSet::new(), tcp_ports: HashSet::new(),
udp_ports: HashSet::new() udp_ports: HashSet::new()
}; };
let list = ipt.list("filter", "DIPLONAT")?; let list = ipt.list("filter", "DIPLONAT")?;
let re = Regex::new(r"\-A.*? \-p (\w+).*\-\-dport (\d+).*?\-j ACCEPT").unwrap(); let re = Regex::new(r"\-A.*? \-p (\w+).*\-\-dport (\d+).*?\-j ACCEPT").context("Regex matching open ports encountered an unexpected rule")?;
for i in list { for i in list {
let caps = re.captures(&i); let caps = re.captures(&i);
match caps { match caps {
Some(c) => { Some(c) => {
let raw_proto = c.get(1).unwrap();
let raw_port = c.get(2).unwrap(); if let (Some(raw_proto), Some(raw_port)) = (c.get(1), c.get(2)) {
let proto = String::from(raw_proto.as_str()); let proto = String::from(raw_proto.as_str());
let number = String::from(raw_port.as_str()).parse::<u16>().unwrap(); let number = String::from(raw_port.as_str()).parse::<u16>()?;
if proto == "tcp" {
ports.tcp_ports.insert(number);
} else {
ports.udp_ports.insert(number);
}
if proto == "tcp" {
ports.tcp_ports.insert(number);
} else { } else {
ports.udp_ports.insert(number); error!("Unexpected rule found in DIPLONAT chain")
} }
}, },
@ -67,10 +64,18 @@ pub fn get_opened_ports(ipt: &iptables::IPTables) -> Result<messages::PublicExpo
Ok(ports) Ok(ports)
} }
pub fn cleanup(ipt: &iptables::IPTables) -> Result<(), FirewallError> { pub fn cleanup(ipt: &iptables::IPTables) -> Result<()> {
ipt.flush_chain("filter", "DIPLONAT")?;
ipt.delete("filter", "INPUT", "-j DIPLONAT")?; if ipt.chain_exists("filter", "DIPLONAT")? {
ipt.delete_chain("filter", "DIPLONAT")?; ipt.flush_chain("filter", "DIPLONAT").context("Failed to flush the DIPLONAT chain")?;
if ipt.exists("filter", "INPUT", "-j DIPLONAT")? {
ipt.delete("filter", "INPUT", "-j DIPLONAT").context("Failed to delete jump rule")?;
}
ipt.delete_chain("filter", "DIPLONAT").context("Failed to delete chain")?;
}
Ok(()) Ok(())
} }

View File

@ -23,13 +23,13 @@ pub struct FirewallActor {
impl FirewallActor { impl FirewallActor {
pub async fn new(_refresh: Duration, rxp: &watch::Receiver<messages::PublicExposedPorts>) -> Result<Self> { pub async fn new(_refresh: Duration, rxp: &watch::Receiver<messages::PublicExposedPorts>) -> Result<Self> {
let ctx = Self { let ctx = Self {
ipt: iptables::new(false).unwrap(), ipt: iptables::new(false)?,
rx_ports: rxp.clone(), rx_ports: rxp.clone(),
last_ports: messages::PublicExposedPorts::new(), last_ports: messages::PublicExposedPorts::new(),
refresh: _refresh, refresh: _refresh,
}; };
fw::setup(&ctx.ipt).expect("iptables setup failed"); fw::setup(&ctx.ipt)?;
return Ok(ctx); return Ok(ctx);
} }
@ -56,7 +56,7 @@ impl FirewallActor {
} }
pub async fn do_fw_update(&self) -> Result<()> { pub async fn do_fw_update(&self) -> Result<()> {
let curr_opened_ports = fw::get_opened_ports(&self.ipt).unwrap(); let curr_opened_ports = fw::get_opened_ports(&self.ipt)?;
let diff_tcp = self.last_ports.tcp_ports.difference(&curr_opened_ports.tcp_ports).copied().collect::<HashSet<u16>>(); let diff_tcp = self.last_ports.tcp_ports.difference(&curr_opened_ports.tcp_ports).copied().collect::<HashSet<u16>>();
let diff_udp = self.last_ports.udp_ports.difference(&curr_opened_ports.udp_ports).copied().collect::<HashSet<u16>>(); let diff_udp = self.last_ports.udp_ports.difference(&curr_opened_ports.udp_ports).copied().collect::<HashSet<u16>>();
@ -66,7 +66,7 @@ impl FirewallActor {
udp_ports: diff_udp udp_ports: diff_udp
}; };
fw::open_ports(&self.ipt, ports_to_open).unwrap(); fw::open_ports(&self.ipt, ports_to_open)?;
return Ok(()); return Ok(());
} }