diff --git a/harmony-rs/opnsense-config/src/modules/dhcp.rs b/harmony-rs/opnsense-config/src/modules/dhcp.rs index b09d6d7..0b5b766 100644 --- a/harmony-rs/opnsense-config/src/modules/dhcp.rs +++ b/harmony-rs/opnsense-config/src/modules/dhcp.rs @@ -1,3 +1,7 @@ +use std::cmp::Ordering; +use std::net::IpAddr; +use std::net::Ipv4Addr; + use super::opnsense::{OPNsense, StaticMap}; use crate::infra::maybe_string::MaybeString; use crate::modules::opnsense::NumberOption; @@ -13,7 +17,7 @@ pub enum DhcpError { InvalidMacAddress(String), InvalidIpAddress(String), IpAddressAlreadyMapped(String), - MacAddressAlreadyMapped(String), + MacAddressAlreadyMapped(String), IpAddressOutOfRange(String), } @@ -22,9 +26,15 @@ impl std::fmt::Display for DhcpError { 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), + 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) + } } } } @@ -39,42 +49,40 @@ impl<'a> DhcpConfig<'a> { pub fn add_static_mapping( &mut self, mac: String, - ipaddr: String, + ipaddr: Ipv4Addr, hostname: String, ) -> Result<(), DhcpError> { + let range: Range = todo!(); 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)); - } + // if !Self::is_ip_in_range(&ipaddr, range) { + // 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(), - }; + // TODO + // if existing_mappings.iter().any(|m| m.ipaddr == ipaddr) { + // return Err(DhcpError::IpAddressAlreadyMapped(ipaddr)); + // } - self.opnsense.dhcpd.lan.staticmaps.push(static_map); + // 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(()) } @@ -88,51 +96,28 @@ impl<'a> DhcpConfig<'a> { return false; } - parts.iter().all(|part| { - part.len() == 2 && part.chars().all(|c| c.is_ascii_hexdigit()) - }) + 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: &Ipv4Addr, range: Range) -> bool { + let range_start = range + .from + .parse::() + .expect("Invalid DHCP range start"); + let range_end = range.to.parse::().expect("Invalid DHCP range to"); - 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; - } + let start_compare = range_start.cmp(ip); + let end_compare = range_end.cmp(ip); + + if (Ordering::Less == start_compare || Ordering::Equal == start_compare) + && (Ordering::Greater == end_compare || Ordering::Equal == end_compare) + { + return true; + } else { + return false; } - false - } -} - -pub struct DhcpConfig<'a> { - opnsense: &'a mut OPNsense, -} - - -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) { - 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); - } - - pub fn get_static_mappings(&self) -> &[StaticMap] { - &self.opnsense.dhcpd.lan.staticmaps } } @@ -172,6 +157,7 @@ pub struct DhcpRange { #[cfg(test)] mod test { + use std::net::Ipv4Addr; use crate::infra::yaserde::to_xml_str; use super::*; @@ -183,8 +169,7 @@ mod test { yaserde::de::from_str(SERIALIZED_DHCPD).expect("Deserialize Dhcpd failed"); assert_eq!( - to_xml_str(&dhcpd) - .expect("Serialize Dhcpd failed"), + to_xml_str(&dhcpd).expect("Serialize Dhcpd failed"), SERIALIZED_DHCPD ); } @@ -244,4 +229,32 @@ mod test { \n"; + + #[test] + fn test_ip_in_range() { + let range = Range { + from: "192.168.1.100".to_string(), + to: "192.168.1.200".to_string(), + }; + + // Test IP within range + let ip = "192.168.1.150".parse::().unwrap(); + assert_eq!(DhcpConfig::is_ip_in_range(&ip, range.clone()), true); + + // Test IP at start of range + let ip = "192.168.1.100".parse::().unwrap(); + assert_eq!(DhcpConfig::is_ip_in_range(&ip, range.clone()), true); + + // Test IP at end of range + let ip = "192.168.1.200".parse::().unwrap(); + assert_eq!(DhcpConfig::is_ip_in_range(&ip, range.clone()), true); + + // Test IP before range + let ip = "192.168.1.99".parse::().unwrap(); + assert_eq!(DhcpConfig::is_ip_in_range(&ip, range.clone()), false); + + // Test IP after range + let ip = "192.168.1.201".parse::().unwrap(); + assert_eq!(DhcpConfig::is_ip_in_range(&ip, range.clone()), false); + } } diff --git a/harmony-rs/opnsense-config/src/modules/opnsense.rs b/harmony-rs/opnsense-config/src/modules/opnsense.rs index 78011b0..6ed6df4 100644 --- a/harmony-rs/opnsense-config/src/modules/opnsense.rs +++ b/harmony-rs/opnsense-config/src/modules/opnsense.rs @@ -320,11 +320,9 @@ pub struct NumberOption { item: MaybeString, } -#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] +#[derive(Default, Clone, PartialEq, Debug, YaSerialize, YaDeserialize)] pub struct Range { - #[yaserde(rename = "from")] pub from: String, - #[yaserde(rename = "to")] pub to: String, }