use iptables; use regex::Regex; use std::collections::HashSet; use crate::messages; #[derive(Debug)] pub struct FirewallError(String); impl From for FirewallError { fn from(error: iptables::error::IPTError) -> Self { FirewallError(error.to_string()) } } 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(()) } pub fn open_ports(ipt: &iptables::IPTables, ports: messages::PublicExposedPorts) -> Result<(), FirewallError> { for p in ports.tcp_ports { ipt.append("filter", "DIPLONAT", &format!("-p tcp --dport {} -j ACCEPT", p))?; } for p in ports.udp_ports { ipt.append("filter", "DIPLONAT", &format!("-p udp --dport {} -j ACCEPT", p))?; } Ok(()) } pub fn get_opened_ports(ipt: &iptables::IPTables) -> Result { 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").unwrap(); for i in list { let caps = re.captures(&i); match caps { Some(c) => { let raw_proto = c.get(1).unwrap(); let raw_port = c.get(2).unwrap(); let proto = String::from(raw_proto.as_str()); let number = String::from(raw_port.as_str()).parse::().unwrap(); if proto == "tcp" { ports.tcp_ports.insert(number); } else { ports.udp_ports.insert(number); } }, _ => {} } } Ok(ports) } pub fn cleanup(ipt: &iptables::IPTables) -> Result<(), FirewallError> { ipt.flush_chain("filter", "DIPLONAT")?; ipt.delete("filter", "INPUT", "-j DIPLONAT")?; ipt.delete_chain("filter", "DIPLONAT")?; Ok(()) }