use crate::Firewall;
use crate::command::{CommandRunner, combine_delete_outcomes};
use crate::enums::{Action, Protocol, RuleStatus};
use crate::error::UfwError;
use crate::parser::find_port_status;
pub struct PortBuilder<'a> {
fw: &'a Firewall,
port: u16,
}
impl<'a> PortBuilder<'a> {
pub(crate) fn new(fw: &'a Firewall, port: u16) -> Self {
PortBuilder { fw, port }
}
pub fn allow(self) -> PortActionBuilder {
PortActionBuilder {
port: self.port,
action: Action::Allow,
}
}
pub fn deny(self) -> PortActionBuilder {
PortActionBuilder {
port: self.port,
action: Action::Deny,
}
}
pub fn delete(self) -> PortDeleteBuilder {
PortDeleteBuilder { port: self.port }
}
pub fn status(self) -> PortStatus<'a> {
PortStatus {
fw: self.fw,
port: self.port,
}
}
}
pub struct PortActionBuilder {
port: u16,
action: Action,
}
impl PortActionBuilder {
pub fn tcp(self) -> PortFinalizer {
PortFinalizer {
action: self.action,
port: self.port,
protocol: Protocol::Tcp,
}
}
pub fn udp(self) -> PortFinalizer {
PortFinalizer {
action: self.action,
port: self.port,
protocol: Protocol::Udp,
}
}
pub fn both(self) -> PortFinalizer {
PortFinalizer {
action: self.action,
port: self.port,
protocol: Protocol::Both,
}
}
}
pub struct PortFinalizer {
port: u16,
action: Action,
protocol: Protocol,
}
impl PortFinalizer {
pub fn apply(&self) -> Result<(), UfwError> {
let protocols: &[&str] = match self.protocol {
Protocol::Tcp => &["tcp"],
Protocol::Udp => &["udp"],
Protocol::Both => &["tcp", "udp"],
};
let action_str = match self.action {
Action::Allow => "allow",
Action::Deny => "deny",
};
for proto in protocols {
let rule = format!("{}/{}", self.port, proto);
CommandRunner::run("sudo", &["ufw", action_str, &rule])?;
}
Ok(())
}
}
pub struct PortDeleteBuilder {
port: u16,
}
impl PortDeleteBuilder {
pub fn tcp(self) -> PortDeleteFinalizer {
PortDeleteFinalizer {
port: self.port,
protocol: Protocol::Tcp,
}
}
pub fn udp(self) -> PortDeleteFinalizer {
PortDeleteFinalizer {
port: self.port,
protocol: Protocol::Udp,
}
}
pub fn both(self) -> PortDeleteFinalizer {
PortDeleteFinalizer {
port: self.port,
protocol: Protocol::Both,
}
}
}
pub struct PortDeleteFinalizer {
port: u16,
protocol: Protocol,
}
impl PortDeleteFinalizer {
pub fn apply(&self) -> Result<bool, UfwError> {
let outcomes: Vec<Result<_, _>> = match self.protocol {
Protocol::Tcp => {
vec![
CommandRunner::delete(
"sudo",
&["ufw", "delete", "allow", &format!("{}/tcp", self.port)],
),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "deny", &format!("{}/tcp", self.port)],
),
]
}
Protocol::Udp => {
vec![
CommandRunner::delete(
"sudo",
&["ufw", "delete", "allow", &format!("{}/udp", self.port)],
),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "deny", &format!("{}/udp", self.port)],
),
]
}
Protocol::Both => {
vec![
CommandRunner::delete(
"sudo",
&["ufw", "delete", "allow", &self.port.to_string()],
),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "deny", &self.port.to_string()],
),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "allow", &format!("{}/tcp", self.port)],
),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "deny", &format!("{}/tcp", self.port)],
),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "allow", &format!("{}/udp", self.port)],
),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "deny", &format!("{}/udp", self.port)],
),
]
}
};
combine_delete_outcomes(outcomes)
}
}
pub struct PortStatus<'a> {
fw: &'a Firewall,
port: u16,
}
impl<'a> PortStatus<'a> {
pub fn tcp(&self) -> Result<RuleStatus, UfwError> {
let rules = self.fw.ports()?;
Ok(find_port_status(&rules, self.port, Protocol::Tcp))
}
pub fn udp(&self) -> Result<RuleStatus, UfwError> {
let rules = self.fw.ports()?;
Ok(find_port_status(&rules, self.port, Protocol::Udp))
}
pub fn both(&self) -> Result<RuleStatus, UfwError> {
let rules = self.fw.ports()?;
Ok(find_port_status(&rules, self.port, Protocol::Both))
}
}