feat(opnsense-config): ip_in_range function works

This commit is contained in:
jeangab 2024-11-07 09:22:22 -05:00
parent 0700265622
commit 85786cf648
2 changed files with 87 additions and 76 deletions

View File

@ -1,3 +1,7 @@
use std::cmp::Ordering;
use std::net::IpAddr;
use std::net::Ipv4Addr;
use super::opnsense::{OPNsense, StaticMap}; use super::opnsense::{OPNsense, StaticMap};
use crate::infra::maybe_string::MaybeString; use crate::infra::maybe_string::MaybeString;
use crate::modules::opnsense::NumberOption; use crate::modules::opnsense::NumberOption;
@ -13,7 +17,7 @@ pub enum DhcpError {
InvalidMacAddress(String), InvalidMacAddress(String),
InvalidIpAddress(String), InvalidIpAddress(String),
IpAddressAlreadyMapped(String), IpAddressAlreadyMapped(String),
MacAddressAlreadyMapped(String), MacAddressAlreadyMapped(String),
IpAddressOutOfRange(String), IpAddressOutOfRange(String),
} }
@ -22,9 +26,15 @@ impl std::fmt::Display for DhcpError {
match self { match self {
DhcpError::InvalidMacAddress(mac) => write!(f, "Invalid MAC address format: {}", mac), DhcpError::InvalidMacAddress(mac) => write!(f, "Invalid MAC address format: {}", mac),
DhcpError::InvalidIpAddress(ip) => write!(f, "Invalid IP address format: {}", ip), DhcpError::InvalidIpAddress(ip) => write!(f, "Invalid IP address format: {}", ip),
DhcpError::IpAddressAlreadyMapped(ip) => write!(f, "IP address {} is already mapped", ip), DhcpError::IpAddressAlreadyMapped(ip) => {
DhcpError::MacAddressAlreadyMapped(mac) => write!(f, "MAC address {} is already mapped", mac), write!(f, "IP address {} is already mapped", ip)
DhcpError::IpAddressOutOfRange(ip) => write!(f, "IP address {} is out of interface range", 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( pub fn add_static_mapping(
&mut self, &mut self,
mac: String, mac: String,
ipaddr: String, ipaddr: Ipv4Addr,
hostname: String, hostname: String,
) -> Result<(), DhcpError> { ) -> Result<(), DhcpError> {
let range: Range = todo!();
if !Self::is_valid_mac(&mac) { if !Self::is_valid_mac(&mac) {
return Err(DhcpError::InvalidMacAddress(mac)); return Err(DhcpError::InvalidMacAddress(mac));
} }
if !Self::is_valid_ip(&ipaddr) { // if !Self::is_ip_in_range(&ipaddr, range) {
return Err(DhcpError::InvalidIpAddress(ipaddr)); // return Err(DhcpError::IpAddressOutOfRange(ipaddr));
} // }
if !Self::is_ip_in_range(&ipaddr) {
return Err(DhcpError::IpAddressOutOfRange(ipaddr));
}
let existing_mappings = &self.opnsense.dhcpd.lan.staticmaps; 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 { // TODO
mac, // if existing_mappings.iter().any(|m| m.ipaddr == ipaddr) {
ipaddr, // return Err(DhcpError::IpAddressAlreadyMapped(ipaddr));
hostname, // }
descr: Default::default(),
winsserver: Default::default(),
dnsserver: Default::default(),
ntpserver: Default::default(),
};
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(()) Ok(())
} }
@ -88,51 +96,28 @@ impl<'a> DhcpConfig<'a> {
return false; return false;
} }
parts.iter().all(|part| { parts
part.len() == 2 && part.chars().all(|c| c.is_ascii_hexdigit()) .iter()
}) .all(|part| part.len() == 2 && part.chars().all(|c| c.is_ascii_hexdigit()))
} }
fn is_valid_ip(ip: &str) -> bool { fn is_ip_in_range(ip: &Ipv4Addr, range: Range) -> bool {
ip.parse::<IpAddr>().is_ok() let range_start = range
} .from
.parse::<Ipv4Addr>()
.expect("Invalid DHCP range start");
let range_end = range.to.parse::<Ipv4Addr>().expect("Invalid DHCP range to");
fn is_ip_in_range(ip: &str) -> bool { let start_compare = range_start.cmp(ip);
if let Ok(addr) = ip.parse::<IpAddr>() { let end_compare = range_end.cmp(ip);
if let IpAddr::V4(ipv4) = addr {
let octets = ipv4.octets(); if (Ordering::Less == start_compare || Ordering::Equal == start_compare)
return octets[0] == 192 && octets[1] == 168 && octets[2] == 1; && (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)] #[cfg(test)]
mod test { mod test {
use std::net::Ipv4Addr;
use crate::infra::yaserde::to_xml_str; use crate::infra::yaserde::to_xml_str;
use super::*; use super::*;
@ -183,8 +169,7 @@ mod test {
yaserde::de::from_str(SERIALIZED_DHCPD).expect("Deserialize Dhcpd failed"); yaserde::de::from_str(SERIALIZED_DHCPD).expect("Deserialize Dhcpd failed");
assert_eq!( assert_eq!(
to_xml_str(&dhcpd) to_xml_str(&dhcpd).expect("Serialize Dhcpd failed"),
.expect("Serialize Dhcpd failed"),
SERIALIZED_DHCPD SERIALIZED_DHCPD
); );
} }
@ -244,4 +229,32 @@ mod test {
<pool/> <pool/>
</lan> </lan>
</dhcpd>\n"; </dhcpd>\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::<Ipv4Addr>().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::<Ipv4Addr>().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::<Ipv4Addr>().unwrap();
assert_eq!(DhcpConfig::is_ip_in_range(&ip, range.clone()), true);
// Test IP before range
let ip = "192.168.1.99".parse::<Ipv4Addr>().unwrap();
assert_eq!(DhcpConfig::is_ip_in_range(&ip, range.clone()), false);
// Test IP after range
let ip = "192.168.1.201".parse::<Ipv4Addr>().unwrap();
assert_eq!(DhcpConfig::is_ip_in_range(&ip, range.clone()), false);
}
} }

View File

@ -320,11 +320,9 @@ pub struct NumberOption {
item: MaybeString, item: MaybeString,
} }
#[derive(Default, PartialEq, Debug, YaSerialize, YaDeserialize)] #[derive(Default, Clone, PartialEq, Debug, YaSerialize, YaDeserialize)]
pub struct Range { pub struct Range {
#[yaserde(rename = "from")]
pub from: String, pub from: String,
#[yaserde(rename = "to")]
pub to: String, pub to: String,
} }