Add Layer4 selectors extraction
This commit is contained in:
		@@ -227,7 +227,7 @@ pub struct NetworkFilterRuleProtocolLayer4<IPv> {
 | 
				
			|||||||
    pub comment: Option<String>,
 | 
					    pub comment: Option<String>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Debug)]
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug, Default)]
 | 
				
			||||||
#[serde(rename = "rule")]
 | 
					#[serde(rename = "rule")]
 | 
				
			||||||
pub struct NetworkFilterRuleXML {
 | 
					pub struct NetworkFilterRuleXML {
 | 
				
			||||||
    #[serde(rename(serialize = "@action"))]
 | 
					    #[serde(rename(serialize = "@action"))]
 | 
				
			||||||
@@ -275,7 +275,7 @@ pub struct NetworkFilterRuleXML {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /// Match ICMP protocol
 | 
					    /// Match ICMP protocol
 | 
				
			||||||
    #[serde(default, rename = "icmp", skip_serializing_if = "Vec::is_empty")]
 | 
					    #[serde(default, rename = "icmp", skip_serializing_if = "Vec::is_empty")]
 | 
				
			||||||
    pub imcp_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv4Addr>>,
 | 
					    pub icmp_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv4Addr>>,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Match TCP IPv6 protocol
 | 
					    /// Match TCP IPv6 protocol
 | 
				
			||||||
    #[serde(default, rename = "tcp-ipv6", skip_serializing_if = "Vec::is_empty")]
 | 
					    #[serde(default, rename = "tcp-ipv6", skip_serializing_if = "Vec::is_empty")]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -96,14 +96,14 @@ fn extract_ip_or_var<const V: usize>(
 | 
				
			|||||||
    Ok(n.as_ref().map(|n| n.0.to_string()))
 | 
					    Ok(n.as_ref().map(|n| n.0.to_string()))
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn extract_ip_mask<const V: usize>(n: &Option<u8>) -> anyhow::Result<Option<u8>> {
 | 
					fn extract_ip_mask<const V: usize>(n: Option<u8>) -> anyhow::Result<Option<u8>> {
 | 
				
			||||||
    if let Some(mask) = n {
 | 
					    if let Some(mask) = n {
 | 
				
			||||||
        if !net_utils::is_mask_valid(V, *mask) {
 | 
					        if !net_utils::is_mask_valid(V, mask) {
 | 
				
			||||||
            return Err(NetworkFilterExtraction(format!("Invalid IPv{V} mask! {}", mask)).into());
 | 
					            return Err(NetworkFilterExtraction(format!("Invalid IPv{V} mask! {mask}")).into());
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Ok(*n)
 | 
					    Ok(n)
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn extract_nw_filter_comment(n: &Option<String>) -> anyhow::Result<Option<String>> {
 | 
					fn extract_nw_filter_comment(n: &Option<String>) -> anyhow::Result<Option<String>> {
 | 
				
			||||||
@@ -192,6 +192,211 @@ impl NetworkFilterChain {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)]
 | 
				
			||||||
 | 
					#[serde(rename_all = "lowercase")]
 | 
				
			||||||
 | 
					pub enum NetworkFilterAction {
 | 
				
			||||||
 | 
					    /// matching the rule silently discards the packet with no further analysis
 | 
				
			||||||
 | 
					    Drop,
 | 
				
			||||||
 | 
					    /// matching the rule generates an ICMP reject message with no further analysis
 | 
				
			||||||
 | 
					    Reject,
 | 
				
			||||||
 | 
					    /// matching the rule accepts the packet with no further analysis
 | 
				
			||||||
 | 
					    Accept,
 | 
				
			||||||
 | 
					    /// matching the rule passes this filter, but returns control to the calling filter for further
 | 
				
			||||||
 | 
					    /// analysis
 | 
				
			||||||
 | 
					    Return,
 | 
				
			||||||
 | 
					    /// matching the rule goes on to the next rule for further analysis
 | 
				
			||||||
 | 
					    Continue,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl NetworkFilterAction {
 | 
				
			||||||
 | 
					    pub fn from_xml(xml: &str) -> anyhow::Result<Self> {
 | 
				
			||||||
 | 
					        Ok(match xml {
 | 
				
			||||||
 | 
					            "drop" => Self::Drop,
 | 
				
			||||||
 | 
					            "reject" => Self::Reject,
 | 
				
			||||||
 | 
					            "accept" => Self::Accept,
 | 
				
			||||||
 | 
					            "return" => Self::Return,
 | 
				
			||||||
 | 
					            "continue" => Self::Continue,
 | 
				
			||||||
 | 
					            s => {
 | 
				
			||||||
 | 
					                return Err(LibVirtStructError::ParseFilteringChain(format!(
 | 
				
			||||||
 | 
					                    "Unkown filter action {s}!"
 | 
				
			||||||
 | 
					                ))
 | 
				
			||||||
 | 
					                .into());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn to_xml(&self) -> String {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::Drop => "drop",
 | 
				
			||||||
 | 
					            Self::Reject => "reject",
 | 
				
			||||||
 | 
					            Self::Accept => "accept",
 | 
				
			||||||
 | 
					            Self::Return => "return",
 | 
				
			||||||
 | 
					            Self::Continue => "continue",
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_string()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
				
			||||||
 | 
					#[serde(rename_all = "lowercase")]
 | 
				
			||||||
 | 
					pub enum NetworkFilterDirection {
 | 
				
			||||||
 | 
					    In,
 | 
				
			||||||
 | 
					    Out,
 | 
				
			||||||
 | 
					    InOut,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl NetworkFilterDirection {
 | 
				
			||||||
 | 
					    pub fn from_xml(xml: &str) -> anyhow::Result<Self> {
 | 
				
			||||||
 | 
					        Ok(match xml {
 | 
				
			||||||
 | 
					            "in" => Self::In,
 | 
				
			||||||
 | 
					            "out" => Self::Out,
 | 
				
			||||||
 | 
					            "inout" => Self::InOut,
 | 
				
			||||||
 | 
					            s => {
 | 
				
			||||||
 | 
					                return Err(LibVirtStructError::ParseFilteringChain(format!(
 | 
				
			||||||
 | 
					                    "Unkown filter direction {s}!"
 | 
				
			||||||
 | 
					                ))
 | 
				
			||||||
 | 
					                .into());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn to_xml(&self) -> String {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            NetworkFilterDirection::In => "in",
 | 
				
			||||||
 | 
					            NetworkFilterDirection::Out => "out",
 | 
				
			||||||
 | 
					            NetworkFilterDirection::InOut => "inout",
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_string()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)]
 | 
				
			||||||
 | 
					pub enum Layer4State {
 | 
				
			||||||
 | 
					    NEW,
 | 
				
			||||||
 | 
					    ESTABLISHED,
 | 
				
			||||||
 | 
					    RELATED,
 | 
				
			||||||
 | 
					    INVALID,
 | 
				
			||||||
 | 
					    NONE,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Layer4State {
 | 
				
			||||||
 | 
					    pub fn from_xml(xml: &str) -> anyhow::Result<Self> {
 | 
				
			||||||
 | 
					        Ok(match xml {
 | 
				
			||||||
 | 
					            "NEW" => Self::NEW,
 | 
				
			||||||
 | 
					            "ESTABLISHED" => Self::ESTABLISHED,
 | 
				
			||||||
 | 
					            "RELATED" => Self::RELATED,
 | 
				
			||||||
 | 
					            "INVALID" => Self::INVALID,
 | 
				
			||||||
 | 
					            "NONE" => Self::NONE,
 | 
				
			||||||
 | 
					            s => {
 | 
				
			||||||
 | 
					                return Err(LibVirtStructError::ParseFilteringChain(format!(
 | 
				
			||||||
 | 
					                    "Unkown layer4 state '{s}'!"
 | 
				
			||||||
 | 
					                ))
 | 
				
			||||||
 | 
					                .into());
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn to_xml(&self) -> String {
 | 
				
			||||||
 | 
					        match self {
 | 
				
			||||||
 | 
					            Self::NEW => "NEW",
 | 
				
			||||||
 | 
					            Self::ESTABLISHED => "ESTABLISHED",
 | 
				
			||||||
 | 
					            Self::RELATED => "RELATED",
 | 
				
			||||||
 | 
					            Self::INVALID => "INVALID",
 | 
				
			||||||
 | 
					            Self::NONE => "NONE",
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        .to_string()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct NetworkSelectorMac {
 | 
				
			||||||
 | 
					    src_mac_addr: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    src_mac_mask: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    dst_mac_addr: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    dst_mac_mask: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    comment: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct NetworkSelectorARP {
 | 
				
			||||||
 | 
					    srcmacaddr: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    srcmacmask: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    dstmacaddr: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    dstmacmask: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    arpsrcipaddr: Option<NetworkFilterIPv4OrVar>,
 | 
				
			||||||
 | 
					    arpsrcipmask: Option<u8>,
 | 
				
			||||||
 | 
					    arpdstipaddr: Option<NetworkFilterIPv4OrVar>,
 | 
				
			||||||
 | 
					    arpdstipmask: Option<u8>,
 | 
				
			||||||
 | 
					    comment: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct NetworkFilterSelectorIP<const V: usize> {
 | 
				
			||||||
 | 
					    srcmacaddr: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    srcmacmask: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    dstmacaddr: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    dstmacmask: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    srcipaddr: Option<NetworkFilterIPOrVar<V>>,
 | 
				
			||||||
 | 
					    srcipmask: Option<u8>,
 | 
				
			||||||
 | 
					    dstipaddr: Option<NetworkFilterIPOrVar<V>>,
 | 
				
			||||||
 | 
					    dstipmask: Option<u8>,
 | 
				
			||||||
 | 
					    comment: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct NetworkFilterSelectorLayer4<IPv> {
 | 
				
			||||||
 | 
					    srcmacaddr: Option<NetworkFilterMacAddressOrVar>,
 | 
				
			||||||
 | 
					    srcipaddr: Option<IPv>,
 | 
				
			||||||
 | 
					    srcipmask: Option<u8>,
 | 
				
			||||||
 | 
					    dstipaddr: Option<IPv>,
 | 
				
			||||||
 | 
					    dstipmask: Option<u8>,
 | 
				
			||||||
 | 
					    /// Start of range of source IP address
 | 
				
			||||||
 | 
					    srcipfrom: Option<IPv>,
 | 
				
			||||||
 | 
					    /// End of range of source IP address
 | 
				
			||||||
 | 
					    srcipto: Option<IPv>,
 | 
				
			||||||
 | 
					    /// Start of range of destination IP address
 | 
				
			||||||
 | 
					    dstipfrom: Option<IPv>,
 | 
				
			||||||
 | 
					    /// End of range of destination IP address
 | 
				
			||||||
 | 
					    dstipto: Option<IPv>,
 | 
				
			||||||
 | 
					    srcportstart: Option<u16>,
 | 
				
			||||||
 | 
					    srcportend: Option<u16>,
 | 
				
			||||||
 | 
					    dstportstart: Option<u16>,
 | 
				
			||||||
 | 
					    dstportend: Option<u16>,
 | 
				
			||||||
 | 
					    state: Option<Layer4State>,
 | 
				
			||||||
 | 
					    comment: Option<String>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
				
			||||||
 | 
					#[serde(tag = "type", rename_all = "lowercase")]
 | 
				
			||||||
 | 
					pub enum NetworkFilterSelector {
 | 
				
			||||||
 | 
					    All,
 | 
				
			||||||
 | 
					    Mac(NetworkSelectorMac),
 | 
				
			||||||
 | 
					    Arp(NetworkSelectorARP),
 | 
				
			||||||
 | 
					    Rarp(NetworkSelectorARP),
 | 
				
			||||||
 | 
					    IPv4(NetworkFilterSelectorIP<4>),
 | 
				
			||||||
 | 
					    IPv6(NetworkFilterSelectorIP<6>),
 | 
				
			||||||
 | 
					    TCP(NetworkFilterSelectorLayer4<Ipv4Addr>),
 | 
				
			||||||
 | 
					    UDP(NetworkFilterSelectorLayer4<Ipv4Addr>),
 | 
				
			||||||
 | 
					    SCTP(NetworkFilterSelectorLayer4<Ipv4Addr>),
 | 
				
			||||||
 | 
					    ICMP(NetworkFilterSelectorLayer4<Ipv4Addr>),
 | 
				
			||||||
 | 
					    TCPipv6(NetworkFilterSelectorLayer4<Ipv6Addr>),
 | 
				
			||||||
 | 
					    UDPipv6(NetworkFilterSelectorLayer4<Ipv6Addr>),
 | 
				
			||||||
 | 
					    SCTPipv6(NetworkFilterSelectorLayer4<Ipv6Addr>),
 | 
				
			||||||
 | 
					    ICMPipv6(NetworkFilterSelectorLayer4<Ipv6Addr>),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
				
			||||||
 | 
					pub struct NetworkFilterRule {
 | 
				
			||||||
 | 
					    action: NetworkFilterAction,
 | 
				
			||||||
 | 
					    direction: NetworkFilterDirection,
 | 
				
			||||||
 | 
					    /// optional; the priority of the rule controls the order in which the rule will be instantiated
 | 
				
			||||||
 | 
					    /// relative to other rules
 | 
				
			||||||
 | 
					    ///
 | 
				
			||||||
 | 
					    /// Valid values are in the range of -1000 to 1000.
 | 
				
			||||||
 | 
					    priority: Option<i32>,
 | 
				
			||||||
 | 
					    selectors: Vec<NetworkFilterSelector>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Network filter definition
 | 
					/// Network filter definition
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
					#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
				
			||||||
pub struct NetworkFilter {
 | 
					pub struct NetworkFilter {
 | 
				
			||||||
@@ -251,8 +456,8 @@ impl NetworkFilter {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    fn lib2rest_process_layer4_rule<IPv: Copy>(
 | 
					    fn lib2rest_process_layer4_rule<IPv: Copy>(
 | 
				
			||||||
        n: &NetworkFilterRuleProtocolLayer4<IPv>,
 | 
					        n: &NetworkFilterRuleProtocolLayer4<IPv>,
 | 
				
			||||||
    ) -> anyhow::Result<NetworkSelectorLayer4<IPv>> {
 | 
					    ) -> anyhow::Result<NetworkFilterSelectorLayer4<IPv>> {
 | 
				
			||||||
        Ok(NetworkSelectorLayer4 {
 | 
					        Ok(NetworkFilterSelectorLayer4 {
 | 
				
			||||||
            srcmacaddr: n.srcmacaddr.as_ref().map(|v| v.into()),
 | 
					            srcmacaddr: n.srcmacaddr.as_ref().map(|v| v.into()),
 | 
				
			||||||
            srcipaddr: n.srcipaddr,
 | 
					            srcipaddr: n.srcipaddr,
 | 
				
			||||||
            srcipmask: n.srcipmask,
 | 
					            srcipmask: n.srcipmask,
 | 
				
			||||||
@@ -362,7 +567,7 @@ impl NetworkFilter {
 | 
				
			|||||||
            );
 | 
					            );
 | 
				
			||||||
            selectors.append(
 | 
					            selectors.append(
 | 
				
			||||||
                &mut rule
 | 
					                &mut rule
 | 
				
			||||||
                    .imcp_selectors
 | 
					                    .icmp_selectors
 | 
				
			||||||
                    .iter()
 | 
					                    .iter()
 | 
				
			||||||
                    .map(|r| {
 | 
					                    .map(|r| {
 | 
				
			||||||
                        Ok(NetworkFilterSelector::ICMP(
 | 
					                        Ok(NetworkFilterSelector::ICMP(
 | 
				
			||||||
@@ -468,9 +673,33 @@ impl NetworkFilter {
 | 
				
			|||||||
            dstmacaddr: extract_mac_address_or_var(&selector.dstmacaddr)?,
 | 
					            dstmacaddr: extract_mac_address_or_var(&selector.dstmacaddr)?,
 | 
				
			||||||
            dstmacmask: extract_mac_address_or_var(&selector.dstmacmask)?,
 | 
					            dstmacmask: extract_mac_address_or_var(&selector.dstmacmask)?,
 | 
				
			||||||
            srcipaddr: extract_ip_or_var(&selector.srcipaddr)?,
 | 
					            srcipaddr: extract_ip_or_var(&selector.srcipaddr)?,
 | 
				
			||||||
            srcipmask: extract_ip_mask::<V>(&selector.srcipmask)?,
 | 
					            srcipmask: extract_ip_mask::<V>(selector.srcipmask)?,
 | 
				
			||||||
            dstipaddr: extract_ip_or_var(&selector.dstipaddr)?,
 | 
					            dstipaddr: extract_ip_or_var(&selector.dstipaddr)?,
 | 
				
			||||||
            dstipmask: extract_ip_mask::<V>(&selector.dstipmask)?,
 | 
					            dstipmask: extract_ip_mask::<V>(selector.dstipmask)?,
 | 
				
			||||||
 | 
					            comment: extract_nw_filter_comment(&selector.comment)?,
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn rest2lib_process_layer4_selector<IPv: Copy>(
 | 
				
			||||||
 | 
					        selector: &NetworkFilterSelectorLayer4<IPv>,
 | 
				
			||||||
 | 
					    ) -> anyhow::Result<NetworkFilterRuleProtocolLayer4<IPv>> {
 | 
				
			||||||
 | 
					        Ok(NetworkFilterRuleProtocolLayer4 {
 | 
				
			||||||
 | 
					            srcmacaddr: extract_mac_address_or_var(&selector.srcmacaddr)?,
 | 
				
			||||||
 | 
					            srcipaddr: selector.srcipaddr,
 | 
				
			||||||
 | 
					            // This IP mask is not checked
 | 
				
			||||||
 | 
					            srcipmask: selector.srcipmask,
 | 
				
			||||||
 | 
					            dstipaddr: selector.dstipaddr,
 | 
				
			||||||
 | 
					            // This IP mask is not checked
 | 
				
			||||||
 | 
					            dstipmask: selector.dstipmask,
 | 
				
			||||||
 | 
					            srcipfrom: selector.srcipfrom,
 | 
				
			||||||
 | 
					            srcipto: selector.srcipto,
 | 
				
			||||||
 | 
					            dstipfrom: selector.dstipfrom,
 | 
				
			||||||
 | 
					            dstipto: selector.dstipto,
 | 
				
			||||||
 | 
					            srcportstart: selector.srcportstart,
 | 
				
			||||||
 | 
					            srcportend: selector.srcportend,
 | 
				
			||||||
 | 
					            dstportstart: selector.dstportstart,
 | 
				
			||||||
 | 
					            dstportend: selector.dstportend,
 | 
				
			||||||
 | 
					            state: selector.state.map(|s| s.to_xml()),
 | 
				
			||||||
            comment: extract_nw_filter_comment(&selector.comment)?,
 | 
					            comment: extract_nw_filter_comment(&selector.comment)?,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@@ -480,20 +709,7 @@ impl NetworkFilter {
 | 
				
			|||||||
            action: rule.action.to_xml(),
 | 
					            action: rule.action.to_xml(),
 | 
				
			||||||
            direction: rule.direction.to_xml(),
 | 
					            direction: rule.direction.to_xml(),
 | 
				
			||||||
            priority: rule.priority,
 | 
					            priority: rule.priority,
 | 
				
			||||||
            all_selectors: vec![],
 | 
					            ..Default::default()
 | 
				
			||||||
            mac_selectors: vec![],
 | 
					 | 
				
			||||||
            arp_selectors: vec![],
 | 
					 | 
				
			||||||
            rarp_selectors: vec![],
 | 
					 | 
				
			||||||
            ipv4_selectors: vec![],
 | 
					 | 
				
			||||||
            ipv6_selectors: vec![],
 | 
					 | 
				
			||||||
            tcp_selectors: vec![],
 | 
					 | 
				
			||||||
            udp_selectors: vec![],
 | 
					 | 
				
			||||||
            sctp_selectors: vec![],
 | 
					 | 
				
			||||||
            imcp_selectors: vec![],
 | 
					 | 
				
			||||||
            tcp_ipv6_selectors: vec![],
 | 
					 | 
				
			||||||
            udp_ipv6_selectors: vec![],
 | 
					 | 
				
			||||||
            sctp_ipv6_selectors: vec![],
 | 
					 | 
				
			||||||
            imcp_ipv6_selectors: vec![],
 | 
					 | 
				
			||||||
        };
 | 
					        };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        for sel in &rule.selectors {
 | 
					        for sel in &rule.selectors {
 | 
				
			||||||
@@ -531,14 +747,37 @@ impl NetworkFilter {
 | 
				
			|||||||
                    .ipv6_selectors
 | 
					                    .ipv6_selectors
 | 
				
			||||||
                    .push(Self::rest2lib_process_ip_selector(ip)?),
 | 
					                    .push(Self::rest2lib_process_ip_selector(ip)?),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                NetworkFilterSelector::TCP(_) => todo!(),
 | 
					                NetworkFilterSelector::TCP(tcp) => rule_xml
 | 
				
			||||||
                NetworkFilterSelector::UDP(_) => todo!(),
 | 
					                    .tcp_selectors
 | 
				
			||||||
                NetworkFilterSelector::SCTP(_) => todo!(),
 | 
					                    .push(Self::rest2lib_process_layer4_selector(tcp)?),
 | 
				
			||||||
                NetworkFilterSelector::ICMP(_) => todo!(),
 | 
					
 | 
				
			||||||
                NetworkFilterSelector::TCPipv6(_) => todo!(),
 | 
					                NetworkFilterSelector::UDP(udp) => rule_xml
 | 
				
			||||||
                NetworkFilterSelector::UDPipv6(_) => todo!(),
 | 
					                    .udp_selectors
 | 
				
			||||||
                NetworkFilterSelector::SCTPipv6(_) => todo!(),
 | 
					                    .push(Self::rest2lib_process_layer4_selector(udp)?),
 | 
				
			||||||
                NetworkFilterSelector::ICMPipv6(_) => todo!(),
 | 
					
 | 
				
			||||||
 | 
					                NetworkFilterSelector::SCTP(sctp) => rule_xml
 | 
				
			||||||
 | 
					                    .sctp_selectors
 | 
				
			||||||
 | 
					                    .push(Self::rest2lib_process_layer4_selector(sctp)?),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                NetworkFilterSelector::ICMP(icmp) => rule_xml
 | 
				
			||||||
 | 
					                    .icmp_selectors
 | 
				
			||||||
 | 
					                    .push(Self::rest2lib_process_layer4_selector(icmp)?),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                NetworkFilterSelector::TCPipv6(tcpv6) => rule_xml
 | 
				
			||||||
 | 
					                    .tcp_ipv6_selectors
 | 
				
			||||||
 | 
					                    .push(Self::rest2lib_process_layer4_selector(tcpv6)?),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                NetworkFilterSelector::UDPipv6(udpv6) => rule_xml
 | 
				
			||||||
 | 
					                    .udp_ipv6_selectors
 | 
				
			||||||
 | 
					                    .push(Self::rest2lib_process_layer4_selector(udpv6)?),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                NetworkFilterSelector::SCTPipv6(sctpv6) => rule_xml
 | 
				
			||||||
 | 
					                    .sctp_ipv6_selectors
 | 
				
			||||||
 | 
					                    .push(Self::rest2lib_process_layer4_selector(sctpv6)?),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					                NetworkFilterSelector::ICMPipv6(icmpv6) => rule_xml
 | 
				
			||||||
 | 
					                    .imcp_ipv6_selectors
 | 
				
			||||||
 | 
					                    .push(Self::rest2lib_process_layer4_selector(icmpv6)?),
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -591,211 +830,6 @@ impl NetworkFilter {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)]
 | 
					 | 
				
			||||||
#[serde(rename_all = "lowercase")]
 | 
					 | 
				
			||||||
pub enum NetworkFilterAction {
 | 
					 | 
				
			||||||
    /// matching the rule silently discards the packet with no further analysis
 | 
					 | 
				
			||||||
    Drop,
 | 
					 | 
				
			||||||
    /// matching the rule generates an ICMP reject message with no further analysis
 | 
					 | 
				
			||||||
    Reject,
 | 
					 | 
				
			||||||
    /// matching the rule accepts the packet with no further analysis
 | 
					 | 
				
			||||||
    Accept,
 | 
					 | 
				
			||||||
    /// matching the rule passes this filter, but returns control to the calling filter for further
 | 
					 | 
				
			||||||
    /// analysis
 | 
					 | 
				
			||||||
    Return,
 | 
					 | 
				
			||||||
    /// matching the rule goes on to the next rule for further analysis
 | 
					 | 
				
			||||||
    Continue,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl NetworkFilterAction {
 | 
					 | 
				
			||||||
    pub fn from_xml(xml: &str) -> anyhow::Result<Self> {
 | 
					 | 
				
			||||||
        Ok(match xml {
 | 
					 | 
				
			||||||
            "drop" => Self::Drop,
 | 
					 | 
				
			||||||
            "reject" => Self::Reject,
 | 
					 | 
				
			||||||
            "accept" => Self::Accept,
 | 
					 | 
				
			||||||
            "return" => Self::Return,
 | 
					 | 
				
			||||||
            "continue" => Self::Continue,
 | 
					 | 
				
			||||||
            s => {
 | 
					 | 
				
			||||||
                return Err(LibVirtStructError::ParseFilteringChain(format!(
 | 
					 | 
				
			||||||
                    "Unkown filter action {s}!"
 | 
					 | 
				
			||||||
                ))
 | 
					 | 
				
			||||||
                .into());
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn to_xml(&self) -> String {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            Self::Drop => "drop",
 | 
					 | 
				
			||||||
            Self::Reject => "reject",
 | 
					 | 
				
			||||||
            Self::Accept => "accept",
 | 
					 | 
				
			||||||
            Self::Return => "return",
 | 
					 | 
				
			||||||
            Self::Continue => "continue",
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        .to_string()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
					 | 
				
			||||||
#[serde(rename_all = "lowercase")]
 | 
					 | 
				
			||||||
pub enum NetworkFilterDirection {
 | 
					 | 
				
			||||||
    In,
 | 
					 | 
				
			||||||
    Out,
 | 
					 | 
				
			||||||
    InOut,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl NetworkFilterDirection {
 | 
					 | 
				
			||||||
    pub fn from_xml(xml: &str) -> anyhow::Result<Self> {
 | 
					 | 
				
			||||||
        Ok(match xml {
 | 
					 | 
				
			||||||
            "in" => Self::In,
 | 
					 | 
				
			||||||
            "out" => Self::Out,
 | 
					 | 
				
			||||||
            "inout" => Self::InOut,
 | 
					 | 
				
			||||||
            s => {
 | 
					 | 
				
			||||||
                return Err(LibVirtStructError::ParseFilteringChain(format!(
 | 
					 | 
				
			||||||
                    "Unkown filter direction {s}!"
 | 
					 | 
				
			||||||
                ))
 | 
					 | 
				
			||||||
                .into());
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn to_xml(&self) -> String {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            NetworkFilterDirection::In => "in",
 | 
					 | 
				
			||||||
            NetworkFilterDirection::Out => "out",
 | 
					 | 
				
			||||||
            NetworkFilterDirection::InOut => "inout",
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        .to_string()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
					 | 
				
			||||||
pub enum Layer4State {
 | 
					 | 
				
			||||||
    NEW,
 | 
					 | 
				
			||||||
    ESTABLISHED,
 | 
					 | 
				
			||||||
    RELATED,
 | 
					 | 
				
			||||||
    INVALID,
 | 
					 | 
				
			||||||
    NONE,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Layer4State {
 | 
					 | 
				
			||||||
    pub fn from_xml(xml: &str) -> anyhow::Result<Self> {
 | 
					 | 
				
			||||||
        Ok(match xml {
 | 
					 | 
				
			||||||
            "NEW" => Self::NEW,
 | 
					 | 
				
			||||||
            "ESTABLISHED" => Self::ESTABLISHED,
 | 
					 | 
				
			||||||
            "RELATED" => Self::RELATED,
 | 
					 | 
				
			||||||
            "INVALID" => Self::INVALID,
 | 
					 | 
				
			||||||
            "NONE" => Self::NONE,
 | 
					 | 
				
			||||||
            s => {
 | 
					 | 
				
			||||||
                return Err(LibVirtStructError::ParseFilteringChain(format!(
 | 
					 | 
				
			||||||
                    "Unkown layer4 state '{s}'!"
 | 
					 | 
				
			||||||
                ))
 | 
					 | 
				
			||||||
                .into());
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
        })
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn to_xml(&self) -> String {
 | 
					 | 
				
			||||||
        match self {
 | 
					 | 
				
			||||||
            Self::NEW => "NEW",
 | 
					 | 
				
			||||||
            Self::ESTABLISHED => "ESTABLISHED",
 | 
					 | 
				
			||||||
            Self::RELATED => "RELATED",
 | 
					 | 
				
			||||||
            Self::INVALID => "INVALID",
 | 
					 | 
				
			||||||
            Self::NONE => "NONE",
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        .to_string()
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
					 | 
				
			||||||
pub struct NetworkSelectorMac {
 | 
					 | 
				
			||||||
    src_mac_addr: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    src_mac_mask: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    dst_mac_addr: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    dst_mac_mask: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    comment: Option<String>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
					 | 
				
			||||||
pub struct NetworkSelectorARP {
 | 
					 | 
				
			||||||
    srcmacaddr: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    srcmacmask: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    dstmacaddr: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    dstmacmask: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    arpsrcipaddr: Option<NetworkFilterIPv4OrVar>,
 | 
					 | 
				
			||||||
    arpsrcipmask: Option<u8>,
 | 
					 | 
				
			||||||
    arpdstipaddr: Option<NetworkFilterIPv4OrVar>,
 | 
					 | 
				
			||||||
    arpdstipmask: Option<u8>,
 | 
					 | 
				
			||||||
    comment: Option<String>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
					 | 
				
			||||||
pub struct NetworkFilterSelectorIP<const V: usize> {
 | 
					 | 
				
			||||||
    srcmacaddr: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    srcmacmask: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    dstmacaddr: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    dstmacmask: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    srcipaddr: Option<NetworkFilterIPOrVar<V>>,
 | 
					 | 
				
			||||||
    srcipmask: Option<u8>,
 | 
					 | 
				
			||||||
    dstipaddr: Option<NetworkFilterIPOrVar<V>>,
 | 
					 | 
				
			||||||
    dstipmask: Option<u8>,
 | 
					 | 
				
			||||||
    comment: Option<String>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
					 | 
				
			||||||
pub struct NetworkSelectorLayer4<IPv> {
 | 
					 | 
				
			||||||
    srcmacaddr: Option<NetworkFilterMacAddressOrVar>,
 | 
					 | 
				
			||||||
    srcipaddr: Option<IPv>,
 | 
					 | 
				
			||||||
    srcipmask: Option<u8>,
 | 
					 | 
				
			||||||
    dstipaddr: Option<IPv>,
 | 
					 | 
				
			||||||
    dstipmask: Option<u8>,
 | 
					 | 
				
			||||||
    /// Start of range of source IP address
 | 
					 | 
				
			||||||
    srcipfrom: Option<IPv>,
 | 
					 | 
				
			||||||
    /// End of range of source IP address
 | 
					 | 
				
			||||||
    srcipto: Option<IPv>,
 | 
					 | 
				
			||||||
    /// Start of range of destination IP address
 | 
					 | 
				
			||||||
    dstipfrom: Option<IPv>,
 | 
					 | 
				
			||||||
    /// End of range of destination IP address
 | 
					 | 
				
			||||||
    dstipto: Option<IPv>,
 | 
					 | 
				
			||||||
    srcportstart: Option<u16>,
 | 
					 | 
				
			||||||
    srcportend: Option<u16>,
 | 
					 | 
				
			||||||
    dstportstart: Option<u16>,
 | 
					 | 
				
			||||||
    dstportend: Option<u16>,
 | 
					 | 
				
			||||||
    state: Option<Layer4State>,
 | 
					 | 
				
			||||||
    comment: Option<String>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
					 | 
				
			||||||
#[serde(tag = "type", rename_all = "lowercase")]
 | 
					 | 
				
			||||||
pub enum NetworkFilterSelector {
 | 
					 | 
				
			||||||
    All,
 | 
					 | 
				
			||||||
    Mac(NetworkSelectorMac),
 | 
					 | 
				
			||||||
    Arp(NetworkSelectorARP),
 | 
					 | 
				
			||||||
    Rarp(NetworkSelectorARP),
 | 
					 | 
				
			||||||
    IPv4(NetworkFilterSelectorIP<4>),
 | 
					 | 
				
			||||||
    IPv6(NetworkFilterSelectorIP<6>),
 | 
					 | 
				
			||||||
    TCP(NetworkSelectorLayer4<Ipv4Addr>),
 | 
					 | 
				
			||||||
    UDP(NetworkSelectorLayer4<Ipv4Addr>),
 | 
					 | 
				
			||||||
    SCTP(NetworkSelectorLayer4<Ipv4Addr>),
 | 
					 | 
				
			||||||
    ICMP(NetworkSelectorLayer4<Ipv4Addr>),
 | 
					 | 
				
			||||||
    TCPipv6(NetworkSelectorLayer4<Ipv6Addr>),
 | 
					 | 
				
			||||||
    UDPipv6(NetworkSelectorLayer4<Ipv6Addr>),
 | 
					 | 
				
			||||||
    SCTPipv6(NetworkSelectorLayer4<Ipv6Addr>),
 | 
					 | 
				
			||||||
    ICMPipv6(NetworkSelectorLayer4<Ipv6Addr>),
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
					 | 
				
			||||||
pub struct NetworkFilterRule {
 | 
					 | 
				
			||||||
    action: NetworkFilterAction,
 | 
					 | 
				
			||||||
    direction: NetworkFilterDirection,
 | 
					 | 
				
			||||||
    /// optional; the priority of the rule controls the order in which the rule will be instantiated
 | 
					 | 
				
			||||||
    /// relative to other rules
 | 
					 | 
				
			||||||
    ///
 | 
					 | 
				
			||||||
    /// Valid values are in the range of -1000 to 1000.
 | 
					 | 
				
			||||||
    priority: Option<i32>,
 | 
					 | 
				
			||||||
    selectors: Vec<NetworkFilterSelector>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#[cfg(test)]
 | 
					#[cfg(test)]
 | 
				
			||||||
mod test {
 | 
					mod test {
 | 
				
			||||||
    use crate::libvirt_rest_structures::nw_filter::is_var_def;
 | 
					    use crate::libvirt_rest_structures::nw_filter::is_var_def;
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user