From 07002656222a5bfc2f8126dcac449e9ec4d093b4 Mon Sep 17 00:00:00 2001 From: jeangab Date: Thu, 7 Nov 2024 07:49:13 -0500 Subject: [PATCH] wip: Implement add static mapping public function --- .../opnsense-config/src/modules/dhcp.rs | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) diff --git a/harmony-rs/opnsense-config/src/modules/dhcp.rs b/harmony-rs/opnsense-config/src/modules/dhcp.rs index ef18aaf..b09d6d7 100644 --- a/harmony-rs/opnsense-config/src/modules/dhcp.rs +++ b/harmony-rs/opnsense-config/src/modules/dhcp.rs @@ -8,6 +8,111 @@ pub struct DhcpConfig<'a> { opnsense: &'a mut OPNsense, } +#[derive(Debug)] +pub enum DhcpError { + InvalidMacAddress(String), + InvalidIpAddress(String), + IpAddressAlreadyMapped(String), + MacAddressAlreadyMapped(String), + IpAddressOutOfRange(String), +} + +impl std::fmt::Display for DhcpError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DhcpError::InvalidMacAddress(mac) => write!(f, "Invalid MAC address format: {}", mac), + DhcpError::InvalidIpAddress(ip) => write!(f, "Invalid IP address format: {}", ip), + DhcpError::IpAddressAlreadyMapped(ip) => write!(f, "IP address {} is already mapped", ip), + DhcpError::MacAddressAlreadyMapped(mac) => write!(f, "MAC address {} is already mapped", mac), + DhcpError::IpAddressOutOfRange(ip) => write!(f, "IP address {} is out of interface range", ip), + } + } +} + +impl std::error::Error for DhcpError {} + +impl<'a> DhcpConfig<'a> { + pub fn new(opnsense: &'a mut OPNsense) -> Self { + Self { opnsense } + } + + pub fn add_static_mapping( + &mut self, + mac: String, + ipaddr: String, + hostname: String, + ) -> Result<(), DhcpError> { + if !Self::is_valid_mac(&mac) { + return Err(DhcpError::InvalidMacAddress(mac)); + } + + if !Self::is_valid_ip(&ipaddr) { + return Err(DhcpError::InvalidIpAddress(ipaddr)); + } + + if !Self::is_ip_in_range(&ipaddr) { + return Err(DhcpError::IpAddressOutOfRange(ipaddr)); + } + + let existing_mappings = &self.opnsense.dhcpd.lan.staticmaps; + + if existing_mappings.iter().any(|m| m.ipaddr == ipaddr) { + return Err(DhcpError::IpAddressAlreadyMapped(ipaddr)); + } + + if existing_mappings.iter().any(|m| m.mac == mac) { + return Err(DhcpError::MacAddressAlreadyMapped(mac)); + } + + let static_map = StaticMap { + mac, + ipaddr, + hostname, + descr: Default::default(), + winsserver: Default::default(), + dnsserver: Default::default(), + ntpserver: Default::default(), + }; + + self.opnsense.dhcpd.lan.staticmaps.push(static_map); + Ok(()) + } + + pub fn get_static_mappings(&self) -> &[StaticMap] { + &self.opnsense.dhcpd.lan.staticmaps + } + + fn is_valid_mac(mac: &str) -> bool { + let parts: Vec<&str> = mac.split(':').collect(); + if parts.len() != 6 { + return false; + } + + parts.iter().all(|part| { + part.len() == 2 && part.chars().all(|c| c.is_ascii_hexdigit()) + }) + } + + fn is_valid_ip(ip: &str) -> bool { + ip.parse::().is_ok() + } + + fn is_ip_in_range(ip: &str) -> bool { + if let Ok(addr) = ip.parse::() { + if let IpAddr::V4(ipv4) = addr { + let octets = ipv4.octets(); + return octets[0] == 192 && octets[1] == 168 && octets[2] == 1; + } + } + false + } +} + +pub struct DhcpConfig<'a> { + opnsense: &'a mut OPNsense, +} + + impl<'a> DhcpConfig<'a> { pub fn new(opnsense: &'a mut OPNsense) -> Self { Self { opnsense }