diff --git a/src/network/create_config/validation.rs b/src/network/create_config/validation.rs index 898a18190..137e547a7 100644 --- a/src/network/create_config/validation.rs +++ b/src/network/create_config/validation.rs @@ -138,13 +138,13 @@ pub fn validate_subnets( /// Get the first IP address in a subnet (network address + 1). fn first_ip_in_subnet(network: &IpNet) -> NetavarkResult { - match network { + let first_ip = match network { IpNet::V4(net_v4) => { let network_addr: u32 = net_v4.network().into(); let first_ip = network_addr .checked_add(1) .ok_or_else(|| NetavarkError::msg("Subnet address overflow"))?; - Ok(IpAddr::V4(first_ip.into())) + IpAddr::V4(first_ip.into()) } IpNet::V6(net_v6) => { use std::net::Ipv6Addr; @@ -154,9 +154,18 @@ fn first_ip_in_subnet(network: &IpNet) -> NetavarkResult { let first_ip_u128 = addr_u128 .checked_add(1) .ok_or_else(|| NetavarkError::msg("Subnet address overflow"))?; - Ok(IpAddr::V6(Ipv6Addr::from(first_ip_u128.to_be_bytes()))) + IpAddr::V6(Ipv6Addr::from(first_ip_u128.to_be_bytes())) } + }; + + if !network.contains(&first_ip) { + return Err(NetavarkError::msg(format!( + "could not create gateway for subnet {}", + network + ))); } + + Ok(first_ip) } /// Validate lease range IP addresses against a subnet. @@ -219,6 +228,56 @@ fn validate_lease_range( Ok(()) } +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn validate_subnet_adds_first_ip_as_gateway() { + let mut subnet = Subnet { + subnet: "10.100.0.0/24".parse().unwrap(), + gateway: None, + lease_range: None, + }; + + validate_subnet(&mut subnet, true, false, &[]).unwrap(); + + assert_eq!(subnet.gateway, Some("10.100.0.1".parse().unwrap())); + } + + #[test] + fn validate_subnet_rejects_ipv4_subnet_without_gateway_address() { + let mut subnet = Subnet { + subnet: "10.100.0.1/32".parse().unwrap(), + gateway: None, + lease_range: None, + }; + + let err = validate_subnet(&mut subnet, true, false, &[]).unwrap_err(); + + assert_eq!( + err.to_string(), + "could not create gateway for subnet 10.100.0.1/32" + ); + } + + #[test] + fn validate_subnet_rejects_ipv6_subnet_without_gateway_address() { + let mut subnet = Subnet { + subnet: "fd00::1/128".parse().unwrap(), + gateway: None, + lease_range: None, + }; + + let err = validate_subnet(&mut subnet, true, false, &[]).unwrap_err(); + + assert_eq!( + err.to_string(), + "could not create gateway for subnet fd00::1/128" + ); + } +} + /// Validate a single subnet. /// This function validates the subnet, checks for conflicts with used networks, /// validates/creates the gateway, and validates the lease range.