use std::net::IpAddr;
use crate::Firewall;
use crate::command::{CommandRunner, combine_delete_outcomes};
use crate::enums::{Action, Protocol, RuleStatus};
use crate::error::UfwError;
use crate::parser::find_ip_status;
pub struct Ipv4Builder<'a> {
fw: &'a Firewall,
ip: IpAddr,
}
impl<'a> Ipv4Builder<'a> {
pub(crate) fn new(fw: &'a Firewall, ip: IpAddr) -> Self {
Ipv4Builder { fw, ip }
}
pub fn allow(self) -> Ipv4ActionBuilder {
Ipv4ActionBuilder {
ip: self.ip,
action: Action::Allow,
}
}
pub fn deny(self) -> Ipv4ActionBuilder {
Ipv4ActionBuilder {
ip: self.ip,
action: Action::Deny,
}
}
pub fn delete(self) -> Ipv4DeleteBuilder {
Ipv4DeleteBuilder { ip: self.ip }
}
pub fn status(self) -> Ipv4Status<'a> {
Ipv4Status {
fw: self.fw,
ip: self.ip,
}
}
}
pub struct Ipv4ActionBuilder {
ip: IpAddr,
action: Action,
}
impl Ipv4ActionBuilder {
pub fn tcp(self) -> Ipv4Finalizer {
Ipv4Finalizer {
action: self.action,
ip: self.ip,
protocol: Protocol::Tcp,
}
}
pub fn udp(self) -> Ipv4Finalizer {
Ipv4Finalizer {
action: self.action,
ip: self.ip,
protocol: Protocol::Udp,
}
}
pub fn both(self) -> Ipv4Finalizer {
Ipv4Finalizer {
action: self.action,
ip: self.ip,
protocol: Protocol::Both,
}
}
}
pub struct Ipv4Finalizer {
ip: IpAddr,
action: Action,
protocol: Protocol,
}
impl Ipv4Finalizer {
pub fn apply(&self) -> Result<(), UfwError> {
let ip_str = self.ip.to_string();
let action_str = match self.action {
Action::Allow => "allow",
Action::Deny => "deny",
};
match self.protocol {
Protocol::Both => {
CommandRunner::run("sudo", &["ufw", action_str, "from", &ip_str])?;
}
Protocol::Tcp | Protocol::Udp => {
let proto_str = match self.protocol {
Protocol::Tcp => "tcp",
Protocol::Udp => "udp",
_ => unreachable!(),
};
CommandRunner::run(
"sudo",
&["ufw", action_str, "from", &ip_str, "proto", proto_str],
)?;
}
}
Ok(())
}
}
pub struct Ipv4DeleteBuilder {
ip: IpAddr,
}
impl Ipv4DeleteBuilder {
pub fn tcp(self) -> Ipv4DeleteFinalizer {
Ipv4DeleteFinalizer {
ip: self.ip,
protocol: Protocol::Tcp,
}
}
pub fn udp(self) -> Ipv4DeleteFinalizer {
Ipv4DeleteFinalizer {
ip: self.ip,
protocol: Protocol::Udp,
}
}
pub fn both(self) -> Ipv4DeleteFinalizer {
Ipv4DeleteFinalizer {
ip: self.ip,
protocol: Protocol::Both,
}
}
}
pub struct Ipv4DeleteFinalizer {
ip: IpAddr,
protocol: Protocol,
}
impl Ipv4DeleteFinalizer {
pub fn apply(&self) -> Result<bool, UfwError> {
let ip_str = self.ip.to_string();
let outcomes: Vec<Result<_, _>> = match self.protocol {
Protocol::Both => {
vec![
CommandRunner::delete("sudo", &["ufw", "delete", "allow", "from", &ip_str]),
CommandRunner::delete("sudo", &["ufw", "delete", "deny", "from", &ip_str]),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "allow", "from", &ip_str, "proto", "tcp"],
),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "deny", "from", &ip_str, "proto", "tcp"],
),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "allow", "from", &ip_str, "proto", "udp"],
),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "deny", "from", &ip_str, "proto", "udp"],
),
]
}
Protocol::Tcp => {
vec![
CommandRunner::delete(
"sudo",
&["ufw", "delete", "allow", "from", &ip_str, "proto", "tcp"],
),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "deny", "from", &ip_str, "proto", "tcp"],
),
]
}
Protocol::Udp => {
vec![
CommandRunner::delete(
"sudo",
&["ufw", "delete", "allow", "from", &ip_str, "proto", "udp"],
),
CommandRunner::delete(
"sudo",
&["ufw", "delete", "deny", "from", &ip_str, "proto", "udp"],
),
]
}
};
combine_delete_outcomes(outcomes)
}
}
pub struct Ipv4Status<'a> {
fw: &'a Firewall,
ip: IpAddr,
}
impl<'a> Ipv4Status<'a> {
pub fn tcp(&self) -> Result<RuleStatus, UfwError> {
let rules = self.fw.ips()?;
Ok(find_ip_status(&rules, self.ip, Protocol::Tcp))
}
pub fn udp(&self) -> Result<RuleStatus, UfwError> {
let rules = self.fw.ips()?;
Ok(find_ip_status(&rules, self.ip, Protocol::Udp))
}
pub fn both(&self) -> Result<RuleStatus, UfwError> {
let rules = self.fw.ips()?;
Ok(find_ip_status(&rules, self.ip, Protocol::Both))
}
}