diff --git a/src/api2/types.rs b/src/api2/types.rs index b65e4850..8f051fc4 100644 --- a/src/api2/types.rs +++ b/src/api2/types.rs @@ -509,27 +509,21 @@ pub struct Interface { /// Interface name pub name: String, #[serde(skip_serializing_if="Option::is_none")] - pub method_v4: Option, + pub method_v4: Option, #[serde(skip_serializing_if="Option::is_none")] pub method_v6: Option, #[serde(skip_serializing_if="Option::is_none")] - /// IPv4 address - pub address_v4: Option, + /// IPv4 address with netmask + pub cidr_v4: Option, #[serde(skip_serializing_if="Option::is_none")] /// IPv4 gateway pub gateway_v4: Option, #[serde(skip_serializing_if="Option::is_none")] - /// IPv4 netmask - pub netmask_v4: Option, - #[serde(skip_serializing_if="Option::is_none")] - /// IPv6 address - pub address_v6: Option, + /// IPv6 address with netmask + pub cidr_v6: Option, #[serde(skip_serializing_if="Option::is_none")] /// IPv6 gateway pub gateway_v6: Option, - #[serde(skip_serializing_if="Option::is_none")] - /// IPv6 netmask - pub netmask_v6: Option, #[serde(skip_serializing_if="Vec::is_empty")] pub options_v4: Vec, #[serde(skip_serializing_if="Vec::is_empty")] diff --git a/src/config/network.rs b/src/config/network.rs index 70e027e0..c493a26f 100644 --- a/src/config/network.rs +++ b/src/config/network.rs @@ -26,12 +26,10 @@ impl Interface { active: false, method_v4: None, method_v6: None, - address_v4: None, + cidr_v4: None, gateway_v4: None, - netmask_v4: None, - address_v6: None, + cidr_v6: None, gateway_v6: None, - netmask_v6: None, options_v4: Vec::new(), options_v6: Vec::new(), } @@ -55,9 +53,9 @@ impl Interface { Ok(()) } - fn set_address_v4(&mut self, address: String) -> Result<(), Error> { - if self.address_v4.is_none() { - self.address_v4 = Some(address); + fn set_cidr_v4(&mut self, address: String) -> Result<(), Error> { + if self.cidr_v4.is_none() { + self.cidr_v4 = Some(address); } else { bail!("duplicate IPv4 address."); } @@ -73,22 +71,9 @@ impl Interface { Ok(()) } - fn set_netmask_v4(&mut self, mask: u8) -> Result<(), Error> { - if self.netmask_v4.is_none() { - if mask > 0 && mask <= 32 { - self.netmask_v4 = Some(mask); - } else { - bail!("invalid ipv4 netmaks '{}'", mask); - } - } else { - bail!("duplicate IPv4 netmask."); - } - Ok(()) - } - - fn set_address_v6(&mut self, address: String) -> Result<(), Error> { - if self.address_v6.is_none() { - self.address_v6 = Some(address); + fn set_cidr_v6(&mut self, address: String) -> Result<(), Error> { + if self.cidr_v6.is_none() { + self.cidr_v6 = Some(address); } else { bail!("duplicate IPv6 address."); } @@ -104,19 +89,6 @@ impl Interface { Ok(()) } - fn set_netmask_v6(&mut self, mask: u8) -> Result<(), Error> { - if self.netmask_v6.is_none() { - if mask > 0 && mask <= 128 { - self.netmask_v6 = Some(mask); - } else { - bail!("invalid ipv6 netmaks '{}'", mask); - } - } else { - bail!("duplicate IPv6 netmask."); - } - Ok(()) - } - fn push_addon_option(&mut self, text: String) { if self.method_v4.is_none() && self.method_v6.is_some() { self.options_v6.push(text); @@ -126,12 +98,8 @@ impl Interface { } fn write_iface_attributes_v4(&self, w: &mut dyn Write) -> Result<(), Error> { - if let Some(address) = &self.address_v4 { - if let Some(netmask) = self.netmask_v4 { - writeln!(w, " address {}/{}", address, netmask)?; - } else { - writeln!(w, " address {}", address)?; - } + if let Some(address) = &self.cidr_v4 { + writeln!(w, " address {}", address)?; } if let Some(gateway) = &self.gateway_v4 { writeln!(w, " gateway {}", gateway)?; @@ -144,12 +112,8 @@ impl Interface { } fn write_iface_attributes_v6(&self, w: &mut dyn Write) -> Result<(), Error> { - if let Some(address) = &self.address_v6 { - if let Some(netmask) = self.netmask_v6 { - writeln!(w, " address {}/{}", address, netmask)?; - } else { - writeln!(w, " address {}", address)?; - } + if let Some(address) = &self.cidr_v6 { + writeln!(w, " address {}", address)?; } if let Some(gateway) = &self.gateway_v6 { writeln!(w, " gateway {}", gateway)?; diff --git a/src/config/network/helper.rs b/src/config/network/helper.rs index 7e6c9e49..2dc0e8cb 100644 --- a/src/config/network/helper.rs +++ b/src/config/network/helper.rs @@ -6,6 +6,8 @@ use nix::sys::socket::{socket, AddressFamily, SockType, SockFlag}; use nix::ioctl_read_bad; use regex::Regex; +use proxmox::*; // for IP macros + pub static IPV4_REVERSE_MASK: &[&'static str] = &[ "0.0.0.0", "128.0.0.0", @@ -52,6 +54,44 @@ lazy_static! { }; } +pub fn parse_cidr(cidr: &str) -> Result<(String, u8, bool), Error> { + + lazy_static! { + pub static ref CIDR_V4_REGEX: Regex = Regex::new( + concat!(r"^(", IPV4RE!(), r")(?:/(\d{1,2}))?$") + ).unwrap(); + pub static ref CIDR_V6_REGEX: Regex = Regex::new( + concat!(r"^(", IPV6RE!(), r")(?:/(\d{1,3}))?$") + ).unwrap(); + } + + if let Some(caps) = CIDR_V4_REGEX.captures(&cidr) { + let address = &caps[1]; + let mask = &caps[2]; + let mask = u8::from_str_radix(mask, 10) + .map(|mask| { + if !(mask > 0 && mask <= 32) { + bail!("IPv4 mask '{}' is out of range (1..32).", mask); + } + Ok(mask) + })?; + return Ok((address.to_string(), mask.unwrap(), false)); + } else if let Some(caps) = CIDR_V6_REGEX.captures(&cidr) { + let address = &caps[1]; + let mask = &caps[2]; + let mask = u8::from_str_radix(mask, 10) + .map(|mask| { + if !(mask >= 1 && mask <= 128) { + bail!("IPv6 mask '{}' is out of range (1..128).", mask); + } + Ok(mask) + })?; + return Ok((address.to_string(), mask.unwrap(), true)); + } else { + bail!("invalid address/mask '{}'", cidr); + } +} + pub fn get_network_interfaces() -> Result, Error> { const PROC_NET_DEV: &str = "/proc/net/dev"; diff --git a/src/config/network/parser.rs b/src/config/network/parser.rs index 232385f9..dee13aa8 100644 --- a/src/config/network/parser.rs +++ b/src/config/network/parser.rs @@ -6,8 +6,6 @@ use anyhow::{Error, bail, format_err}; use lazy_static::lazy_static; use regex::Regex; -use proxmox::*; // for IP macros - use super::helper::*; use super::lexer::*; @@ -91,33 +89,13 @@ impl NetworkParser { fn parse_iface_address(&mut self, interface: &mut Interface) -> Result<(), Error> { self.eat(Token::Address)?; - let address = self.next_text()?; + let cidr = self.next_text()?; - lazy_static! { - pub static ref ADDRESS_V4_REGEX: Regex = Regex::new( - concat!(r"^(", IPV4RE!(), r")(?:/(\d{1,2}))?$") - ).unwrap(); - pub static ref ADDRESS_V6_REGEX: Regex = Regex::new( - concat!(r"^(", IPV6RE!(), r")(?:/(\d{1,2}))?$") - ).unwrap(); - } - - if let Some(caps) = ADDRESS_V4_REGEX.captures(&address) { - let address = caps.get(1).unwrap().as_str(); - interface.set_address_v4(address.to_string())?; - if let Some(mask) = caps.get(2) { - let mask = u8::from_str_radix(mask.as_str(), 10)?; - interface.set_netmask_v4(mask)?; - } - } else if let Some(caps) = ADDRESS_V6_REGEX.captures(&address) { - let address = caps.get(1).unwrap().as_str(); - interface.set_address_v6(address.to_string())?; - if let Some(mask) = caps.get(2) { - let mask = u8::from_str_radix(mask.as_str(), 10)?; - interface.set_netmask_v6(mask)?; - } + let (_address, _mask, ipv6) = parse_cidr(&cidr)?; + if ipv6 { + interface.set_cidr_v6(cidr)?; } else { - bail!("unable to parse IP address"); + interface.set_cidr_v4(cidr)?; } self.eat(Token::Newline)?; @@ -163,29 +141,6 @@ impl NetworkParser { Ok(()) } - fn parse_iface_netmask(&mut self, interface: &mut Interface) -> Result<(), Error> { - self.eat(Token::Netmask)?; - let netmask = self.next_text()?; - - if let Some(mask) = IPV4_MASK_HASH_LOCALNET.get(netmask.as_str()) { - interface.set_netmask_v4(*mask)?; - } else { - match u8::from_str_radix(netmask.as_str(), 10) { - Ok(mask) => { - if mask <= 32 { interface.set_netmask_v4(mask)?; } - interface.set_netmask_v6(mask)?; - } - Err(err) => { - bail!("unable to parse netmask '{}' - {}", netmask, err); - } - } - } - - self.eat(Token::Newline)?; - - Ok(()) - } - fn parse_iface_attributes(&mut self, interface: &mut Interface) -> Result<(), Error> { loop { @@ -198,7 +153,7 @@ impl NetworkParser { match self.peek()? { Token::Address => self.parse_iface_address(interface)?, Token::Gateway => self.parse_iface_gateway(interface)?, - Token::Netmask => self.parse_iface_netmask(interface)?, + Token::Netmask => bail!("netmask is deprecated and no longer supported"), _ => { self.parse_iface_addon_attribute(interface)?; },