aboutsummaryrefslogtreecommitdiff
path: root/src/fw.rs
diff options
context:
space:
mode:
authorQuentin <quentin@dufour.io>2020-07-04 17:16:21 +0200
committerQuentin <quentin@dufour.io>2020-07-04 17:16:21 +0200
commit7ec74a21d4b90a2ee9c8f4a7ce90babbebef824a (patch)
tree1e4284195676f4586cd15cb4d3e1da03a9cd11b6 /src/fw.rs
parent5dd4544360906de246de9e33abbfd741681d2fea (diff)
parent4f4b6b048d53f3c4c9cc2437ba6bc6a9e70cb8c7 (diff)
downloaddiplonat-7ec74a21d4b90a2ee9c8f4a7ce90babbebef824a.tar.gz
diplonat-7ec74a21d4b90a2ee9c8f4a7ce90babbebef824a.zip
Merge pull request 'Automatically manage firewall rules (iptables) for services' (#1) from add-firewall-rules into master
Reviewed-on: https://git.deuxfleurs.fr/Deuxfleurs/diplonat/pulls/1
Diffstat (limited to 'src/fw.rs')
-rw-r--r--src/fw.rs81
1 files changed, 81 insertions, 0 deletions
diff --git a/src/fw.rs b/src/fw.rs
new file mode 100644
index 0000000..bc4d119
--- /dev/null
+++ b/src/fw.rs
@@ -0,0 +1,81 @@
+use iptables;
+use regex::Regex;
+use std::collections::HashSet;
+use crate::messages;
+use anyhow::{Result,Context};
+use log::*;
+
+pub fn setup(ipt: &iptables::IPTables) -> Result<()> {
+
+ // ensure we start from a clean state without any rule already set
+ cleanup(ipt)?;
+
+ 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")?;
+
+ Ok(())
+}
+
+pub fn open_ports(ipt: &iptables::IPTables, ports: messages::PublicExposedPorts) -> Result<()> {
+ for p in ports.tcp_ports {
+ ipt.append("filter", "DIPLONAT", &format!("-p tcp --dport {} -j ACCEPT", p)).context("Failed to insert port rule")?;
+ }
+
+ for p in ports.udp_ports {
+ ipt.append("filter", "DIPLONAT", &format!("-p udp --dport {} -j ACCEPT", p)).context("Failed to insert port rule")?;
+ }
+
+ Ok(())
+}
+
+pub fn get_opened_ports(ipt: &iptables::IPTables) -> Result<messages::PublicExposedPorts> {
+ let mut ports = messages::PublicExposedPorts {
+ tcp_ports: HashSet::new(),
+ udp_ports: HashSet::new()
+ };
+
+ let list = ipt.list("filter", "DIPLONAT")?;
+ 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 {
+ let caps = re.captures(&i);
+ match caps {
+ Some(c) => {
+
+ if let (Some(raw_proto), Some(raw_port)) = (c.get(1), c.get(2)) {
+
+ let proto = String::from(raw_proto.as_str());
+ let number = String::from(raw_port.as_str()).parse::<u16>()?;
+
+ if proto == "tcp" {
+ ports.tcp_ports.insert(number);
+ } else {
+ ports.udp_ports.insert(number);
+ }
+
+ } else {
+ error!("Unexpected rule found in DIPLONAT chain")
+ }
+
+ },
+ _ => {}
+ }
+ }
+
+ Ok(ports)
+}
+
+pub fn cleanup(ipt: &iptables::IPTables) -> Result<()> {
+
+ if ipt.chain_exists("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(())
+}
+