config: support netmask when parsing interfaces file
This commit is contained in:
parent
b1456a8ea7
commit
645a47ff6e
@ -57,38 +57,57 @@ lazy_static! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn parse_cidr(cidr: &str) -> Result<(String, u8, bool), Error> {
|
pub fn parse_cidr(cidr: &str) -> Result<(String, u8, bool), Error> {
|
||||||
|
let (address, mask, is_v6) = parse_address_or_cidr(cidr)?;
|
||||||
|
if let Some(mask) = mask {
|
||||||
|
return Ok((address, mask, is_v6));
|
||||||
|
} else {
|
||||||
|
bail!("missing netmask in '{}'", cidr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_netmask(mask: u8, is_v6: bool) -> Result<(), Error> {
|
||||||
|
if is_v6 {
|
||||||
|
if !(mask >= 1 && mask <= 128) {
|
||||||
|
bail!("IPv6 mask '{}' is out of range (1..128).", mask);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if !(mask > 0 && mask <= 32) {
|
||||||
|
bail!("IPv4 mask '{}' is out of range (1..32).", mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse ip address with otional cidr mask
|
||||||
|
pub fn parse_address_or_cidr(cidr: &str) -> Result<(String, Option<u8>, bool), Error> {
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
pub static ref CIDR_V4_REGEX: Regex = Regex::new(
|
pub static ref CIDR_V4_REGEX: Regex = Regex::new(
|
||||||
concat!(r"^(", IPV4RE!(), r")(?:/(\d{1,2}))$")
|
concat!(r"^(", IPV4RE!(), r")(?:/(\d{1,2}))?$")
|
||||||
).unwrap();
|
).unwrap();
|
||||||
pub static ref CIDR_V6_REGEX: Regex = Regex::new(
|
pub static ref CIDR_V6_REGEX: Regex = Regex::new(
|
||||||
concat!(r"^(", IPV6RE!(), r")(?:/(\d{1,3}))$")
|
concat!(r"^(", IPV6RE!(), r")(?:/(\d{1,3}))?$")
|
||||||
).unwrap();
|
).unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(caps) = CIDR_V4_REGEX.captures(&cidr) {
|
if let Some(caps) = CIDR_V4_REGEX.captures(&cidr) {
|
||||||
let address = &caps[1];
|
let address = &caps[1];
|
||||||
let mask = &caps[2];
|
if let Some(mask) = caps.get(2) {
|
||||||
let mask = u8::from_str_radix(mask, 10)
|
let mask = u8::from_str_radix(mask.as_str(), 10)?;
|
||||||
.map(|mask| {
|
check_netmask(mask, false)?;
|
||||||
if !(mask > 0 && mask <= 32) {
|
return Ok((address.to_string(), Some(mask), false));
|
||||||
bail!("IPv4 mask '{}' is out of range (1..32).", mask);
|
} else {
|
||||||
}
|
return Ok((address.to_string(), None, false));
|
||||||
Ok(mask)
|
}
|
||||||
})?;
|
|
||||||
return Ok((address.to_string(), mask.unwrap(), false));
|
|
||||||
} else if let Some(caps) = CIDR_V6_REGEX.captures(&cidr) {
|
} else if let Some(caps) = CIDR_V6_REGEX.captures(&cidr) {
|
||||||
let address = &caps[1];
|
let address = &caps[1];
|
||||||
let mask = &caps[2];
|
if let Some(mask) = caps.get(2) {
|
||||||
let mask = u8::from_str_radix(mask, 10)
|
let mask = u8::from_str_radix(mask.as_str(), 10)?;
|
||||||
.map(|mask| {
|
check_netmask(mask, true)?;
|
||||||
if !(mask >= 1 && mask <= 128) {
|
return Ok((address.to_string(), Some(mask), true));
|
||||||
bail!("IPv6 mask '{}' is out of range (1..128).", mask);
|
} else {
|
||||||
}
|
return Ok((address.to_string(), None, true));
|
||||||
Ok(mask)
|
}
|
||||||
})?;
|
|
||||||
return Ok((address.to_string(), mask.unwrap(), true));
|
|
||||||
} else {
|
} else {
|
||||||
bail!("invalid address/mask '{}'", cidr);
|
bail!("invalid address/mask '{}'", cidr);
|
||||||
}
|
}
|
||||||
|
@ -86,20 +86,35 @@ impl <R: BufRead> NetworkParser<R> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_iface_address(&mut self, interface: &mut Interface) -> Result<(), Error> {
|
fn parse_netmask(&mut self) -> Result<u8, Error> {
|
||||||
self.eat(Token::Address)?;
|
self.eat(Token::Netmask)?;
|
||||||
let cidr = self.next_text()?;
|
let netmask = self.next_text()?;
|
||||||
|
|
||||||
let (_address, _mask, ipv6) = parse_cidr(&cidr)?;
|
let mask = if let Some(mask) = IPV4_MASK_HASH_LOCALNET.get(netmask.as_str()) {
|
||||||
if ipv6 {
|
*mask
|
||||||
interface.set_cidr_v6(cidr)?;
|
|
||||||
} else {
|
} else {
|
||||||
interface.set_cidr_v4(cidr)?;
|
match u8::from_str_radix(netmask.as_str(), 10) {
|
||||||
}
|
Ok(mask) => mask,
|
||||||
|
Err(err) => {
|
||||||
|
bail!("unable to parse netmask '{}'", netmask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
self.eat(Token::Newline)?;
|
self.eat(Token::Newline)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(mask)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_iface_address(&mut self) -> Result<(String, Option<u8>, bool), Error> {
|
||||||
|
self.eat(Token::Address)?;
|
||||||
|
let cidr = self.next_text()?;
|
||||||
|
|
||||||
|
let (_address, mask, ipv6) = parse_address_or_cidr(&cidr)?;
|
||||||
|
|
||||||
|
self.eat(Token::Newline)?;
|
||||||
|
|
||||||
|
Ok((cidr, mask, ipv6))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn parse_iface_gateway(&mut self, interface: &mut Interface) -> Result<(), Error> {
|
fn parse_iface_gateway(&mut self, interface: &mut Interface) -> Result<(), Error> {
|
||||||
@ -191,6 +206,9 @@ impl <R: BufRead> NetworkParser<R> {
|
|||||||
address_family_v6: bool,
|
address_family_v6: bool,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
|
|
||||||
|
let mut netmask = None;
|
||||||
|
let mut address_list = Vec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match self.peek()? {
|
match self.peek()? {
|
||||||
Token::Attribute => { self.eat(Token::Attribute)?; },
|
Token::Attribute => { self.eat(Token::Attribute)?; },
|
||||||
@ -214,8 +232,15 @@ impl <R: BufRead> NetworkParser<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match self.peek()? {
|
match self.peek()? {
|
||||||
Token::Address => self.parse_iface_address(interface)?,
|
Token::Address => {
|
||||||
|
let (cidr, mask, is_v6) = self.parse_iface_address()?;
|
||||||
|
address_list.push((cidr, mask, is_v6));
|
||||||
|
}
|
||||||
Token::Gateway => self.parse_iface_gateway(interface)?,
|
Token::Gateway => self.parse_iface_gateway(interface)?,
|
||||||
|
Token::Netmask => {
|
||||||
|
//Note: netmask is deprecated, but we try to do our best
|
||||||
|
netmask = Some(self.parse_netmask()?);
|
||||||
|
}
|
||||||
Token::MTU => {
|
Token::MTU => {
|
||||||
let mtu = self.parse_iface_mtu()?;
|
let mtu = self.parse_iface_mtu()?;
|
||||||
interface.mtu = Some(mtu);
|
interface.mtu = Some(mtu);
|
||||||
@ -255,8 +280,6 @@ impl <R: BufRead> NetworkParser<R> {
|
|||||||
interface.bond_xmit_hash_policy = Some(policy);
|
interface.bond_xmit_hash_policy = Some(policy);
|
||||||
self.eat(Token::Newline)?;
|
self.eat(Token::Newline)?;
|
||||||
}
|
}
|
||||||
Token::Netmask => bail!("netmask is deprecated and no longer supported"),
|
|
||||||
|
|
||||||
_ => { // parse addon attributes
|
_ => { // parse addon attributes
|
||||||
let option = self.parse_to_eol()?;
|
let option = self.parse_to_eol()?;
|
||||||
if !option.is_empty() {
|
if !option.is_empty() {
|
||||||
@ -270,6 +293,38 @@ impl <R: BufRead> NetworkParser<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(netmask) = netmask {
|
||||||
|
if address_list.len() > 1 {
|
||||||
|
bail!("unable to apply netmask to multiple addresses (please use cidr notation)");
|
||||||
|
} else if address_list.len() == 1 {
|
||||||
|
let (mut cidr, mask, is_v6) = address_list.pop().unwrap();
|
||||||
|
if mask.is_some() {
|
||||||
|
// address already has a mask - ignore netmask
|
||||||
|
} else {
|
||||||
|
check_netmask(netmask, is_v6)?;
|
||||||
|
cidr.push_str(&format!("/{}", netmask));
|
||||||
|
}
|
||||||
|
if is_v6 {
|
||||||
|
interface.set_cidr_v6(cidr)?;
|
||||||
|
} else {
|
||||||
|
interface.set_cidr_v4(cidr)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// no address - simply ignore useless netmask
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (cidr, mask, is_v6) in address_list {
|
||||||
|
if mask.is_none() {
|
||||||
|
bail!("missing netmask in '{}'", cidr);
|
||||||
|
}
|
||||||
|
if is_v6 {
|
||||||
|
interface.set_cidr_v6(cidr)?;
|
||||||
|
} else {
|
||||||
|
interface.set_cidr_v4(cidr)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user