Files
VirtWeb/virtweb_backend/src/nat/nat_definition.rs

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>>>,
}