143 lines
4.0 KiB
Rust
143 lines
4.0 KiB
Rust
use crate::constants;
|
|
use crate::utils::net_utils;
|
|
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
|
|
|
#[derive(thiserror::Error, Debug)]
|
|
enum NatDefError {
|
|
#[error("Invalid nat definition: {0}")]
|
|
InvalidNatDef(&'static str),
|
|
}
|
|
|
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
#[serde(tag = "type", rename_all = "lowercase")]
|
|
pub enum NatSourceIP<IPv> {
|
|
Interface { name: String },
|
|
Ip { ip: IPv },
|
|
}
|
|
|
|
#[derive(Debug, Copy, Clone, serde::Serialize, serde::Deserialize)]
|
|
pub enum NatProtocol {
|
|
TCP,
|
|
UDP,
|
|
Both,
|
|
}
|
|
|
|
impl NatProtocol {
|
|
pub fn has_tcp(&self) -> bool {
|
|
!matches!(&self, NatProtocol::UDP)
|
|
}
|
|
|
|
pub fn has_udp(&self) -> bool {
|
|
!matches!(&self, NatProtocol::TCP)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
#[serde(tag = "type", rename_all = "lowercase")]
|
|
pub enum NatHostPort {
|
|
Single { port: u16 },
|
|
Range { start: u16, end: u16 },
|
|
}
|
|
|
|
impl NatHostPort {
|
|
pub fn as_seq(&self) -> Vec<u16> {
|
|
match self {
|
|
NatHostPort::Single { port } => vec![*port],
|
|
NatHostPort::Range { start, end } => (*start..(*end + 1)).collect(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
|
|
pub struct Nat<IPv> {
|
|
pub protocol: NatProtocol,
|
|
pub host_ip: NatSourceIP<IPv>,
|
|
pub host_port: NatHostPort,
|
|
pub guest_ip: IPv,
|
|
pub guest_port: u16,
|
|
pub comment: Option<String>,
|
|
}
|
|
|
|
impl<IPv> Nat<IPv> {
|
|
pub fn check(&self) -> anyhow::Result<()> {
|
|
if let NatSourceIP::Interface { name } = &self.host_ip {
|
|
if !net_utils::is_net_interface_name_valid(name) {
|
|
return Err(NatDefError::InvalidNatDef("Invalid nat interface name!").into());
|
|
}
|
|
}
|
|
|
|
if let NatHostPort::Range { start, end } = &self.host_port {
|
|
if *start == 0 {
|
|
return Err(NatDefError::InvalidNatDef("Invalid start range!").into());
|
|
}
|
|
|
|
if start > end {
|
|
return Err(NatDefError::InvalidNatDef("Invalid port range!").into());
|
|
}
|
|
|
|
if u16::MAX - (end - start) < self.guest_port {
|
|
return Err(NatDefError::InvalidNatDef("Guest port is too high!").into());
|
|
}
|
|
}
|
|
|
|
if self.guest_port == 0 {
|
|
return Err(NatDefError::InvalidNatDef("Invalid guest port!").into());
|
|
}
|
|
|
|
if let Some(comment) = &self.comment {
|
|
if comment.len() > constants::NET_NAT_COMMENT_MAX_SIZE {
|
|
return Err(NatDefError::InvalidNatDef("Comment is too large!").into());
|
|
}
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
impl Nat<Ipv4Addr> {
|
|
pub fn generalize(&self) -> Nat<IpAddr> {
|
|
Nat {
|
|
protocol: self.protocol,
|
|
host_ip: match &self.host_ip {
|
|
NatSourceIP::Ip { ip } => NatSourceIP::Ip {
|
|
ip: IpAddr::V4(*ip),
|
|
},
|
|
NatSourceIP::Interface { name } => NatSourceIP::Interface {
|
|
name: name.to_string(),
|
|
},
|
|
},
|
|
host_port: self.host_port.clone(),
|
|
guest_ip: IpAddr::V4(self.guest_ip),
|
|
guest_port: self.guest_port,
|
|
comment: self.comment.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Nat<Ipv6Addr> {
|
|
pub fn generalize(&self) -> Nat<IpAddr> {
|
|
Nat {
|
|
protocol: self.protocol,
|
|
host_ip: match &self.host_ip {
|
|
NatSourceIP::Ip { ip } => NatSourceIP::Ip {
|
|
ip: IpAddr::V6(*ip),
|
|
},
|
|
NatSourceIP::Interface { name } => NatSourceIP::Interface {
|
|
name: name.to_string(),
|
|
},
|
|
},
|
|
host_port: self.host_port.clone(),
|
|
guest_ip: IpAddr::V6(self.guest_ip),
|
|
guest_port: self.guest_port,
|
|
comment: self.comment.clone(),
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize, Default)]
|
|
pub struct NetNat {
|
|
pub interface: String,
|
|
pub ipv4: Option<Vec<Nat<Ipv4Addr>>>,
|
|
pub ipv6: Option<Vec<Nat<Ipv6Addr>>>,
|
|
}
|