From b3f89309c4fe91e828758f6c6df70bbd05f402e1 Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Sat, 30 Dec 2023 13:11:04 +0100 Subject: [PATCH] Add ARP / RARP selectors extraction --- .../src/libvirt_lib_structures/nwfilter.rs | 8 +- .../src/libvirt_rest_structures/nw_filter.rs | 97 +++++++++++++++---- virtweb_backend/src/utils/net_utils.rs | 19 +++- 3 files changed, 97 insertions(+), 27 deletions(-) diff --git a/virtweb_backend/src/libvirt_lib_structures/nwfilter.rs b/virtweb_backend/src/libvirt_lib_structures/nwfilter.rs index 0febbd9..68944cb 100644 --- a/virtweb_backend/src/libvirt_lib_structures/nwfilter.rs +++ b/virtweb_backend/src/libvirt_lib_structures/nwfilter.rs @@ -45,7 +45,7 @@ pub struct NetworkFilterRuleProtocolMac { #[derive(serde::Serialize, serde::Deserialize, Debug)] #[serde(rename = "arp")] -pub struct NetworkFilterRuleProtocolArp { +pub struct NetworkFilterRuleProtocolArpXML { #[serde( rename(serialize = "@srcmacaddr"), skip_serializing_if = "Option::is_none" @@ -247,11 +247,11 @@ pub struct NetworkFilterRuleXML { /// Match arp protocol #[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")] - pub arp_selectors: Vec, + pub arp_selectors: Vec, /// Match rarp protocol - #[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")] - pub rarp_selectors: Vec, + #[serde(default, rename = "rarp", skip_serializing_if = "Vec::is_empty")] + pub rarp_selectors: Vec, /// Match IPv4 protocol #[serde(default, rename = "ip", skip_serializing_if = "Vec::is_empty")] diff --git a/virtweb_backend/src/libvirt_rest_structures/nw_filter.rs b/virtweb_backend/src/libvirt_rest_structures/nw_filter.rs index c817d6f..76fd522 100644 --- a/virtweb_backend/src/libvirt_rest_structures/nw_filter.rs +++ b/virtweb_backend/src/libvirt_rest_structures/nw_filter.rs @@ -1,5 +1,5 @@ use crate::libvirt_lib_structures::nwfilter::{ - NetworkFilterRefXML, NetworkFilterRuleProtocolAll, NetworkFilterRuleProtocolArp, + NetworkFilterRefXML, NetworkFilterRuleProtocolAll, NetworkFilterRuleProtocolArpXML, NetworkFilterRuleProtocolIpvx, NetworkFilterRuleProtocolLayer4, NetworkFilterRuleProtocolMac, NetworkFilterRuleXML, NetworkFilterXML, }; @@ -56,6 +56,35 @@ fn extract_mac_address_or_var( 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) -> anyhow::Result> { + 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) -> anyhow::Result> { if let Some(comment) = 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 { srcmacaddr: n.srcmacaddr.as_ref().map(|v| v.into()), srcmacmask: n.srcmacmask.as_ref().map(|v| v.into()), dstmacaddr: n.dstmacaddr.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, - arpdstipaddr: n.arpdstipaddr.clone(), + arpdstipaddr: n.arpdstipaddr.as_ref().map(|v| v.into()), arpdstipmask: n.arpdstipmask, comment: n.comment.clone(), } @@ -391,6 +420,22 @@ impl NetworkFilter { }) } + fn rest2lib_process_arp_selector( + selector: &NetworkSelectorARP, + ) -> anyhow::Result { + 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 { let mut rule_xml = NetworkFilterRuleXML { action: rule.action.to_xml(), @@ -428,10 +473,20 @@ impl NetworkFilter { }) } - NetworkFilterSelector::Arp(_) => todo!(), - NetworkFilterSelector::Rarp(_) => todo!(), + NetworkFilterSelector::Arp(a) => { + 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::IPv6(_) => todo!(), + NetworkFilterSelector::TCP(_) => todo!(), NetworkFilterSelector::UDP(_) => todo!(), NetworkFilterSelector::SCTP(_) => todo!(), @@ -608,19 +663,6 @@ impl Layer4State { } } -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub struct NetworkFilterSelectorIP { - srcmacaddr: Option, - srcmacmask: Option, - dstmacaddr: Option, - dstmacmask: Option, - srcipaddr: Option, - srcipmask: Option, - dstipaddr: Option, - dstipmask: Option, - comment: Option, -} - #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct NetworkSelectorMac { src_mac_addr: Option, @@ -636,13 +678,26 @@ pub struct NetworkSelectorARP { srcmacmask: Option, dstmacaddr: Option, dstmacmask: Option, - arpsrcipaddr: Option, + arpsrcipaddr: Option, arpsrcipmask: Option, - arpdstipaddr: Option, + arpdstipaddr: Option, arpdstipmask: Option, comment: Option, } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct NetworkFilterSelectorIP { + srcmacaddr: Option, + srcmacmask: Option, + dstmacaddr: Option, + dstmacmask: Option, + srcipaddr: Option, + srcipmask: Option, + dstipaddr: Option, + dstipmask: Option, + comment: Option, +} + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct NetworkSelectorLayer4 { srcmacaddr: Option, diff --git a/virtweb_backend/src/utils/net_utils.rs b/virtweb_backend/src/utils/net_utils.rs index d01d261..e4b29b2 100644 --- a/virtweb_backend/src/utils/net_utils.rs +++ b/virtweb_backend/src/utils/net_utils.rs @@ -1,4 +1,5 @@ use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::str::FromStr; pub fn extract_ipv4(ip: IpAddr) -> Ipv4Addr { match ip { @@ -18,16 +19,20 @@ pub fn extract_ipv6(ip: IpAddr) -> Ipv6Addr { } } +pub fn is_ipv4_address_valid>(ip: D) -> bool { + Ipv4Addr::from_str(ip.as_ref()).is_ok() +} + pub fn is_mac_address_valid>(mac: D) -> bool { lazy_regex::regex!("^([a-fA-F0-9]{2}[:-]){5}[a-fA-F0-9]{2}$").is_match(mac.as_ref()) } #[cfg(test)] 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] - 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("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: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")); + } }