Add ARP / RARP selectors extraction

This commit is contained in:
Pierre HUBERT 2023-12-30 13:11:04 +01:00
parent 8182ecd7f6
commit b3f89309c4
3 changed files with 97 additions and 27 deletions

View File

@ -45,7 +45,7 @@ pub struct NetworkFilterRuleProtocolMac {
#[derive(serde::Serialize, serde::Deserialize, Debug)] #[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(rename = "arp")] #[serde(rename = "arp")]
pub struct NetworkFilterRuleProtocolArp { pub struct NetworkFilterRuleProtocolArpXML {
#[serde( #[serde(
rename(serialize = "@srcmacaddr"), rename(serialize = "@srcmacaddr"),
skip_serializing_if = "Option::is_none" skip_serializing_if = "Option::is_none"
@ -247,11 +247,11 @@ pub struct NetworkFilterRuleXML {
/// Match arp protocol /// Match arp protocol
#[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")] #[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")]
pub arp_selectors: Vec<NetworkFilterRuleProtocolArp>, pub arp_selectors: Vec<NetworkFilterRuleProtocolArpXML>,
/// Match rarp protocol /// Match rarp protocol
#[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")] #[serde(default, rename = "rarp", skip_serializing_if = "Vec::is_empty")]
pub rarp_selectors: Vec<NetworkFilterRuleProtocolArp>, pub rarp_selectors: Vec<NetworkFilterRuleProtocolArpXML>,
/// Match IPv4 protocol /// Match IPv4 protocol
#[serde(default, rename = "ip", skip_serializing_if = "Vec::is_empty")] #[serde(default, rename = "ip", skip_serializing_if = "Vec::is_empty")]

View File

@ -1,5 +1,5 @@
use crate::libvirt_lib_structures::nwfilter::{ use crate::libvirt_lib_structures::nwfilter::{
NetworkFilterRefXML, NetworkFilterRuleProtocolAll, NetworkFilterRuleProtocolArp, NetworkFilterRefXML, NetworkFilterRuleProtocolAll, NetworkFilterRuleProtocolArpXML,
NetworkFilterRuleProtocolIpvx, NetworkFilterRuleProtocolLayer4, NetworkFilterRuleProtocolMac, NetworkFilterRuleProtocolIpvx, NetworkFilterRuleProtocolLayer4, NetworkFilterRuleProtocolMac,
NetworkFilterRuleXML, NetworkFilterXML, NetworkFilterRuleXML, NetworkFilterXML,
}; };
@ -56,6 +56,35 @@ fn extract_mac_address_or_var(
Ok(n.as_ref().map(|n| n.0.to_string())) Ok(n.as_ref().map(|n| n.0.to_string()))
} }
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct NetworkFilterIPv4OrVar(pub String);
impl NetworkFilterIPv4OrVar {
pub fn is_valid(&self) -> bool {
is_var_def(&self.0) || net_utils::is_ipv4_address_valid(&self.0)
}
}
impl From<&String> for NetworkFilterIPv4OrVar {
fn from(value: &String) -> Self {
Self(value.to_string())
}
}
fn extract_ipv4_or_var(n: &Option<NetworkFilterIPv4OrVar>) -> anyhow::Result<Option<String>> {
if let Some(ip) = n {
if !ip.is_valid() {
return Err(NetworkFilterExtraction(format!(
"Invalid IPv4 address or variable! {}",
ip.0
))
.into());
}
}
Ok(n.as_ref().map(|n| n.0.to_string()))
}
fn extract_nw_filter_comment(n: &Option<String>) -> anyhow::Result<Option<String>> { fn extract_nw_filter_comment(n: &Option<String>) -> anyhow::Result<Option<String>> {
if let Some(comment) = n { if let Some(comment) = n {
if comment.len() > 256 || comment.contains('\"') || comment.contains('\n') { if comment.len() > 256 || comment.contains('\"') || comment.contains('\n') {
@ -169,15 +198,15 @@ impl NetworkFilter {
}) })
} }
fn lib2rest_process_arp_rule(n: &NetworkFilterRuleProtocolArp) -> NetworkSelectorARP { fn lib2rest_process_arp_rule(n: &NetworkFilterRuleProtocolArpXML) -> NetworkSelectorARP {
NetworkSelectorARP { NetworkSelectorARP {
srcmacaddr: n.srcmacaddr.as_ref().map(|v| v.into()), srcmacaddr: n.srcmacaddr.as_ref().map(|v| v.into()),
srcmacmask: n.srcmacmask.as_ref().map(|v| v.into()), srcmacmask: n.srcmacmask.as_ref().map(|v| v.into()),
dstmacaddr: n.dstmacaddr.as_ref().map(|v| v.into()), dstmacaddr: n.dstmacaddr.as_ref().map(|v| v.into()),
dstmacmask: n.dstmacmask.as_ref().map(|v| v.into()), dstmacmask: n.dstmacmask.as_ref().map(|v| v.into()),
arpsrcipaddr: n.arpsrcipaddr.clone(), arpsrcipaddr: n.arpsrcipaddr.as_ref().map(|v| v.into()),
arpsrcipmask: n.arpsrcipmask, arpsrcipmask: n.arpsrcipmask,
arpdstipaddr: n.arpdstipaddr.clone(), arpdstipaddr: n.arpdstipaddr.as_ref().map(|v| v.into()),
arpdstipmask: n.arpdstipmask, arpdstipmask: n.arpdstipmask,
comment: n.comment.clone(), comment: n.comment.clone(),
} }
@ -391,6 +420,22 @@ impl NetworkFilter {
}) })
} }
fn rest2lib_process_arp_selector(
selector: &NetworkSelectorARP,
) -> anyhow::Result<NetworkFilterRuleProtocolArpXML> {
Ok(NetworkFilterRuleProtocolArpXML {
srcmacaddr: extract_mac_address_or_var(&selector.srcmacaddr)?,
srcmacmask: extract_mac_address_or_var(&selector.srcmacmask)?,
dstmacaddr: extract_mac_address_or_var(&selector.dstmacaddr)?,
dstmacmask: extract_mac_address_or_var(&selector.dstmacmask)?,
arpsrcipaddr: extract_ipv4_or_var(&selector.arpsrcipaddr)?,
arpsrcipmask: selector.arpsrcipmask,
arpdstipaddr: extract_ipv4_or_var(&selector.arpdstipaddr)?,
arpdstipmask: selector.arpdstipmask,
comment: extract_nw_filter_comment(&selector.comment)?,
})
}
fn rest2lib_process_rule(rule: &NetworkFilterRule) -> anyhow::Result<NetworkFilterRuleXML> { fn rest2lib_process_rule(rule: &NetworkFilterRule) -> anyhow::Result<NetworkFilterRuleXML> {
let mut rule_xml = NetworkFilterRuleXML { let mut rule_xml = NetworkFilterRuleXML {
action: rule.action.to_xml(), action: rule.action.to_xml(),
@ -428,10 +473,20 @@ impl NetworkFilter {
}) })
} }
NetworkFilterSelector::Arp(_) => todo!(), NetworkFilterSelector::Arp(a) => {
NetworkFilterSelector::Rarp(_) => todo!(), rule_xml
.arp_selectors
.push(Self::rest2lib_process_arp_selector(a)?);
}
NetworkFilterSelector::Rarp(a) => {
rule_xml
.rarp_selectors
.push(Self::rest2lib_process_arp_selector(a)?);
}
NetworkFilterSelector::IPv4(_) => todo!(), NetworkFilterSelector::IPv4(_) => todo!(),
NetworkFilterSelector::IPv6(_) => todo!(), NetworkFilterSelector::IPv6(_) => todo!(),
NetworkFilterSelector::TCP(_) => todo!(), NetworkFilterSelector::TCP(_) => todo!(),
NetworkFilterSelector::UDP(_) => todo!(), NetworkFilterSelector::UDP(_) => todo!(),
NetworkFilterSelector::SCTP(_) => todo!(), NetworkFilterSelector::SCTP(_) => todo!(),
@ -608,19 +663,6 @@ impl Layer4State {
} }
} }
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct NetworkFilterSelectorIP {
srcmacaddr: Option<String>,
srcmacmask: Option<String>,
dstmacaddr: Option<String>,
dstmacmask: Option<String>,
srcipaddr: Option<String>,
srcipmask: Option<u8>,
dstipaddr: Option<String>,
dstipmask: Option<u8>,
comment: Option<String>,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct NetworkSelectorMac { pub struct NetworkSelectorMac {
src_mac_addr: Option<NetworkFilterMacAddressOrVar>, src_mac_addr: Option<NetworkFilterMacAddressOrVar>,
@ -636,13 +678,26 @@ pub struct NetworkSelectorARP {
srcmacmask: Option<NetworkFilterMacAddressOrVar>, srcmacmask: Option<NetworkFilterMacAddressOrVar>,
dstmacaddr: Option<NetworkFilterMacAddressOrVar>, dstmacaddr: Option<NetworkFilterMacAddressOrVar>,
dstmacmask: Option<NetworkFilterMacAddressOrVar>, dstmacmask: Option<NetworkFilterMacAddressOrVar>,
arpsrcipaddr: Option<String>, arpsrcipaddr: Option<NetworkFilterIPv4OrVar>,
arpsrcipmask: Option<u8>, arpsrcipmask: Option<u8>,
arpdstipaddr: Option<String>, arpdstipaddr: Option<NetworkFilterIPv4OrVar>,
arpdstipmask: Option<u8>, arpdstipmask: Option<u8>,
comment: Option<String>, comment: Option<String>,
} }
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct NetworkFilterSelectorIP {
srcmacaddr: Option<String>,
srcmacmask: Option<String>,
dstmacaddr: Option<String>,
dstmacmask: Option<String>,
srcipaddr: Option<String>,
srcipmask: Option<u8>,
dstipaddr: Option<String>,
dstipmask: Option<u8>,
comment: Option<String>,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct NetworkSelectorLayer4<IPv> { pub struct NetworkSelectorLayer4<IPv> {
srcmacaddr: Option<NetworkFilterMacAddressOrVar>, srcmacaddr: Option<NetworkFilterMacAddressOrVar>,

View File

@ -1,4 +1,5 @@
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::str::FromStr;
pub fn extract_ipv4(ip: IpAddr) -> Ipv4Addr { pub fn extract_ipv4(ip: IpAddr) -> Ipv4Addr {
match ip { match ip {
@ -18,16 +19,20 @@ pub fn extract_ipv6(ip: IpAddr) -> Ipv6Addr {
} }
} }
pub fn is_ipv4_address_valid<D: AsRef<str>>(ip: D) -> bool {
Ipv4Addr::from_str(ip.as_ref()).is_ok()
}
pub fn is_mac_address_valid<D: AsRef<str>>(mac: D) -> bool { pub fn is_mac_address_valid<D: AsRef<str>>(mac: D) -> bool {
lazy_regex::regex!("^([a-fA-F0-9]{2}[:-]){5}[a-fA-F0-9]{2}$").is_match(mac.as_ref()) lazy_regex::regex!("^([a-fA-F0-9]{2}[:-]){5}[a-fA-F0-9]{2}$").is_match(mac.as_ref())
} }
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::utils::net_utils::is_mac_address_valid; use crate::utils::net_utils::{is_ipv4_address_valid, is_mac_address_valid};
#[test] #[test]
fn mac_addresses() { fn test_is_mac_address_valid() {
assert!(is_mac_address_valid("FF:FF:FF:FF:FF:FF")); assert!(is_mac_address_valid("FF:FF:FF:FF:FF:FF"));
assert!(is_mac_address_valid("02:42:a4:6e:f2:be")); assert!(is_mac_address_valid("02:42:a4:6e:f2:be"));
@ -35,4 +40,14 @@ mod tests {
assert!(!is_mac_address_valid("FF:FF:FF:FF:FF:FZ")); assert!(!is_mac_address_valid("FF:FF:FF:FF:FF:FZ"));
assert!(!is_mac_address_valid("FF:FF:FF:FF:FF:FF:FF")); assert!(!is_mac_address_valid("FF:FF:FF:FF:FF:FF:FF"));
} }
#[test]
fn test_is_ipv4_address_valid() {
assert!(is_ipv4_address_valid("10.0.0.1"));
assert!(is_ipv4_address_valid("2.56.58.156"));
assert!(!is_ipv4_address_valid("tata"));
assert!(!is_ipv4_address_valid("1.25.25.288"));
assert!(!is_ipv4_address_valid("5.5.5.5.5"));
}
} }