WIP REST routes to create / update Network filters
This commit is contained in:
		@@ -1,3 +1,4 @@
 | 
			
		||||
use crate::constants;
 | 
			
		||||
use crate::controllers::{HttpResult, LibVirtReq};
 | 
			
		||||
use crate::libvirt_lib_structures::XMLUuid;
 | 
			
		||||
use crate::libvirt_rest_structures::nw_filter::NetworkFilter;
 | 
			
		||||
@@ -8,6 +9,37 @@ pub struct NetworkFilterID {
 | 
			
		||||
    uid: XMLUuid,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Create a new nw filter
 | 
			
		||||
pub async fn create(client: LibVirtReq, req: web::Json<NetworkFilter>) -> HttpResult {
 | 
			
		||||
    let network = match req.0.rest2lib() {
 | 
			
		||||
        Ok(d) => d,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to extract network filter info! {e}");
 | 
			
		||||
            return Ok(HttpResponse::BadRequest()
 | 
			
		||||
                .json(format!("Failed to extract network filter info! {e}")));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if constants::BUILTIN_NETWORK_FILTER_RULES.contains(&network.name.as_str()) {
 | 
			
		||||
        return Ok(HttpResponse::ExpectationFailed()
 | 
			
		||||
            .json("Builtin network filter rules shall not be modified!"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // TODO : remove
 | 
			
		||||
    return Ok(HttpResponse::Ok().json(network));
 | 
			
		||||
 | 
			
		||||
    let uid = match client.update_network_filter(req.0, network).await {
 | 
			
		||||
        Ok(u) => u,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to update network filter! {e}");
 | 
			
		||||
            return Ok(HttpResponse::InternalServerError()
 | 
			
		||||
                .json(format!("Failed to update network filter! {e}")));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Ok().json(NetworkFilterID { uid }))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Get the list of network filters
 | 
			
		||||
pub async fn list(client: LibVirtReq) -> HttpResult {
 | 
			
		||||
    let networks = match client.get_full_network_filters_list().await {
 | 
			
		||||
@@ -21,7 +53,7 @@ pub async fn list(client: LibVirtReq) -> HttpResult {
 | 
			
		||||
 | 
			
		||||
    let networks = networks
 | 
			
		||||
        .into_iter()
 | 
			
		||||
        .map(|n| NetworkFilter::from_xml(n).unwrap())
 | 
			
		||||
        .map(|n| NetworkFilter::lib2rest(n).unwrap())
 | 
			
		||||
        .collect::<Vec<_>>();
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Ok().json(networks))
 | 
			
		||||
@@ -29,6 +61,36 @@ pub async fn list(client: LibVirtReq) -> HttpResult {
 | 
			
		||||
 | 
			
		||||
/// Get the information about a single network filter
 | 
			
		||||
pub async fn get_single(client: LibVirtReq, req: web::Path<NetworkFilterID>) -> HttpResult {
 | 
			
		||||
    let nwfilter = NetworkFilter::from_xml(client.get_single_network_filter(req.uid).await?)?;
 | 
			
		||||
    let nwfilter = NetworkFilter::lib2rest(client.get_single_network_filter(req.uid).await?)?;
 | 
			
		||||
    Ok(HttpResponse::Ok().json(nwfilter))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Update the information about a single network filter
 | 
			
		||||
pub async fn update(
 | 
			
		||||
    client: LibVirtReq,
 | 
			
		||||
    path: web::Path<NetworkFilterID>,
 | 
			
		||||
    body: web::Json<NetworkFilter>,
 | 
			
		||||
) -> HttpResult {
 | 
			
		||||
    let mut network = match body.0.rest2lib() {
 | 
			
		||||
        Ok(n) => n,
 | 
			
		||||
        Err(e) => {
 | 
			
		||||
            log::error!("Failed to extract network filter info! {e}");
 | 
			
		||||
            return Ok(HttpResponse::BadRequest()
 | 
			
		||||
                .json(format!("Failed to extract network filter info!\n${e}")));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
    network.uuid = Some(path.uid);
 | 
			
		||||
 | 
			
		||||
    if constants::BUILTIN_NETWORK_FILTER_RULES.contains(&network.name.as_str()) {
 | 
			
		||||
        return Ok(HttpResponse::ExpectationFailed()
 | 
			
		||||
            .json("Builtin network filter rules shall not be modified!"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if let Err(e) = client.update_network_filter(body.0, network).await {
 | 
			
		||||
        log::error!("Failed to update network filter! {e}");
 | 
			
		||||
        return Ok(HttpResponse::InternalServerError()
 | 
			
		||||
            .json(format!("Failed to update network filter!\n${e}")));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Ok(HttpResponse::Ok().json("Network filter updated"))
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ use crate::libvirt_lib_structures::nwfilter::NetworkFilterXML;
 | 
			
		||||
use crate::libvirt_lib_structures::XMLUuid;
 | 
			
		||||
use crate::libvirt_rest_structures::hypervisor::HypervisorInfo;
 | 
			
		||||
use crate::libvirt_rest_structures::net::NetworkInfo;
 | 
			
		||||
use crate::libvirt_rest_structures::nw_filter::NetworkFilter;
 | 
			
		||||
use crate::libvirt_rest_structures::vm::VMInfo;
 | 
			
		||||
use actix::Addr;
 | 
			
		||||
 | 
			
		||||
@@ -185,4 +186,14 @@ impl LibVirtClient {
 | 
			
		||||
    pub async fn get_single_network_filter(&self, id: XMLUuid) -> anyhow::Result<NetworkFilterXML> {
 | 
			
		||||
        self.0.send(libvirt_actor::GetNWFilterXMLReq(id)).await?
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Update the information about a single domain
 | 
			
		||||
    pub async fn update_network_filter(
 | 
			
		||||
        &self,
 | 
			
		||||
        _vm_def: NetworkFilter,
 | 
			
		||||
        xml: NetworkFilterXML,
 | 
			
		||||
    ) -> anyhow::Result<XMLUuid> {
 | 
			
		||||
        println!("nwfilter xml to update: {:#?}", xml);
 | 
			
		||||
        todo!()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -238,60 +238,60 @@ pub struct NetworkFilterRuleXML {
 | 
			
		||||
    pub priority: Option<i32>,
 | 
			
		||||
 | 
			
		||||
    /// Match all protocols
 | 
			
		||||
    #[serde(skip_serializing_if = "Option::is_none")]
 | 
			
		||||
    pub all: Option<NetworkFilterRuleProtocolAll>,
 | 
			
		||||
    #[serde(skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub all: Vec<NetworkFilterRuleProtocolAll>,
 | 
			
		||||
 | 
			
		||||
    /// Match mac protocol
 | 
			
		||||
    #[serde(default, rename = "mac", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub mac_rules: Vec<NetworkFilterRuleProtocolMac>,
 | 
			
		||||
    pub mac_selectors: Vec<NetworkFilterRuleProtocolMac>,
 | 
			
		||||
 | 
			
		||||
    /// Match arp protocol
 | 
			
		||||
    #[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub arp_rules: Vec<NetworkFilterRuleProtocolArp>,
 | 
			
		||||
    pub arp_selectors: Vec<NetworkFilterRuleProtocolArp>,
 | 
			
		||||
 | 
			
		||||
    /// Match rarp protocol
 | 
			
		||||
    #[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub rarp_rules: Vec<NetworkFilterRuleProtocolArp>,
 | 
			
		||||
    pub rarp_selectors: Vec<NetworkFilterRuleProtocolArp>,
 | 
			
		||||
 | 
			
		||||
    /// Match IPv4 protocol
 | 
			
		||||
    #[serde(default, rename = "ip", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub ipv4_rules: Vec<NetworkFilterRuleProtocolIpvx>,
 | 
			
		||||
    pub ipv4_selectors: Vec<NetworkFilterRuleProtocolIpvx>,
 | 
			
		||||
 | 
			
		||||
    /// Match IPv6 protocol
 | 
			
		||||
    #[serde(default, rename = "ipv6", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub ipv6_rules: Vec<NetworkFilterRuleProtocolIpvx>,
 | 
			
		||||
    pub ipv6_selectors: Vec<NetworkFilterRuleProtocolIpvx>,
 | 
			
		||||
 | 
			
		||||
    /// Match TCP protocol
 | 
			
		||||
    #[serde(default, rename = "tcp", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub tcp_rules: Vec<NetworkFilterRuleProtocolLayer4<Ipv4Addr>>,
 | 
			
		||||
    pub tcp_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv4Addr>>,
 | 
			
		||||
 | 
			
		||||
    /// Match UDP protocol
 | 
			
		||||
    #[serde(default, rename = "udp", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub udp_rules: Vec<NetworkFilterRuleProtocolLayer4<Ipv4Addr>>,
 | 
			
		||||
    pub udp_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv4Addr>>,
 | 
			
		||||
 | 
			
		||||
    /// Match SCTP protocol
 | 
			
		||||
    #[serde(default, rename = "sctp", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub sctp_rules: Vec<NetworkFilterRuleProtocolLayer4<Ipv4Addr>>,
 | 
			
		||||
    pub sctp_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv4Addr>>,
 | 
			
		||||
 | 
			
		||||
    /// Match ICMP protocol
 | 
			
		||||
    #[serde(default, rename = "icmp", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub imcp_rules: Vec<NetworkFilterRuleProtocolLayer4<Ipv4Addr>>,
 | 
			
		||||
    pub imcp_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv4Addr>>,
 | 
			
		||||
 | 
			
		||||
    /// Match TCP IPv6 protocol
 | 
			
		||||
    #[serde(default, rename = "tcp-ipv6", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub tcp_ipv6_rules: Vec<NetworkFilterRuleProtocolLayer4<Ipv6Addr>>,
 | 
			
		||||
    pub tcp_ipv6_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv6Addr>>,
 | 
			
		||||
 | 
			
		||||
    /// Match UDP IPv6 protocol
 | 
			
		||||
    #[serde(default, rename = "udp-ipv6", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub udp_ipv6_rules: Vec<NetworkFilterRuleProtocolLayer4<Ipv6Addr>>,
 | 
			
		||||
    pub udp_ipv6_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv6Addr>>,
 | 
			
		||||
 | 
			
		||||
    /// Match SCTP IPv6 protocol
 | 
			
		||||
    #[serde(default, rename = "sctp-ipv6", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub sctp_ipv6_rules: Vec<NetworkFilterRuleProtocolLayer4<Ipv6Addr>>,
 | 
			
		||||
    pub sctp_ipv6_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv6Addr>>,
 | 
			
		||||
 | 
			
		||||
    /// Match ICMP IPv6 protocol
 | 
			
		||||
    #[serde(default, rename = "icmpv6", skip_serializing_if = "Vec::is_empty")]
 | 
			
		||||
    pub imcp_ipv6_rules: Vec<NetworkFilterRuleProtocolLayer4<Ipv6Addr>>,
 | 
			
		||||
    pub imcp_ipv6_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv6Addr>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug)]
 | 
			
		||||
@@ -299,8 +299,12 @@ pub struct NetworkFilterRuleXML {
 | 
			
		||||
pub struct NetworkFilterXML {
 | 
			
		||||
    #[serde(rename(serialize = "@name"))]
 | 
			
		||||
    pub name: String,
 | 
			
		||||
    #[serde(rename(serialize = "@chain"), default)]
 | 
			
		||||
    pub chain: String,
 | 
			
		||||
    #[serde(
 | 
			
		||||
        rename(serialize = "@chain"),
 | 
			
		||||
        skip_serializing_if = "Option::is_none",
 | 
			
		||||
        default
 | 
			
		||||
    )]
 | 
			
		||||
    pub chain: Option<String>,
 | 
			
		||||
    #[serde(
 | 
			
		||||
        skip_serializing_if = "Option::is_none",
 | 
			
		||||
        rename(serialize = "@priority"),
 | 
			
		||||
 
 | 
			
		||||
@@ -1,12 +1,25 @@
 | 
			
		||||
use crate::libvirt_lib_structures::nwfilter::{
 | 
			
		||||
    NetworkFilterRuleProtocolAll, NetworkFilterRuleProtocolArp, NetworkFilterRuleProtocolIpvx,
 | 
			
		||||
    NetworkFilterRuleProtocolLayer4, NetworkFilterRuleProtocolMac, NetworkFilterXML,
 | 
			
		||||
    NetworkFilterRefXML, NetworkFilterRuleProtocolAll, NetworkFilterRuleProtocolArp,
 | 
			
		||||
    NetworkFilterRuleProtocolIpvx, NetworkFilterRuleProtocolLayer4, NetworkFilterRuleProtocolMac,
 | 
			
		||||
    NetworkFilterRuleXML, NetworkFilterXML,
 | 
			
		||||
};
 | 
			
		||||
use crate::libvirt_lib_structures::XMLUuid;
 | 
			
		||||
use crate::libvirt_rest_structures::LibVirtStructError;
 | 
			
		||||
use crate::libvirt_rest_structures::LibVirtStructError::StructureExtraction;
 | 
			
		||||
use lazy_regex::regex;
 | 
			
		||||
use std::net::{Ipv4Addr, Ipv6Addr};
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
			
		||||
pub struct NetworkFilterName(pub String);
 | 
			
		||||
 | 
			
		||||
impl NetworkFilterName {
 | 
			
		||||
    pub fn is_valid(&self) -> bool {
 | 
			
		||||
        regex!("^[a-zA-Z0-9-_]+$").is_match(&self.0)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)]
 | 
			
		||||
#[serde(rename_all = "lowercase")]
 | 
			
		||||
pub enum NetworkFilterChainProtocol {
 | 
			
		||||
    Root,
 | 
			
		||||
    Mac,
 | 
			
		||||
@@ -60,12 +73,8 @@ pub struct NetworkFilterChain {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl NetworkFilterChain {
 | 
			
		||||
    pub fn from_xml(xml: &str) -> anyhow::Result<Option<Self>> {
 | 
			
		||||
        if xml.is_empty() {
 | 
			
		||||
            return Ok(None);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(Some(match xml.split_once('-') {
 | 
			
		||||
    pub fn from_xml(xml: &str) -> anyhow::Result<Self> {
 | 
			
		||||
        Ok(match xml.split_once('-') {
 | 
			
		||||
            None => Self {
 | 
			
		||||
                protocol: NetworkFilterChainProtocol::from_xml(xml)?,
 | 
			
		||||
                suffix: None,
 | 
			
		||||
@@ -74,7 +83,7 @@ impl NetworkFilterChain {
 | 
			
		||||
                protocol: NetworkFilterChainProtocol::from_xml(prefix)?,
 | 
			
		||||
                suffix: Some(suffix.to_string()),
 | 
			
		||||
            },
 | 
			
		||||
        }))
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn to_xml(&self) -> String {
 | 
			
		||||
@@ -88,31 +97,31 @@ impl NetworkFilterChain {
 | 
			
		||||
/// Network filter definition
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
			
		||||
pub struct NetworkFilter {
 | 
			
		||||
    name: String,
 | 
			
		||||
    name: NetworkFilterName,
 | 
			
		||||
    chain: Option<NetworkFilterChain>,
 | 
			
		||||
    priority: Option<i32>,
 | 
			
		||||
    uuid: Option<XMLUuid>,
 | 
			
		||||
    /// Referenced filters rules
 | 
			
		||||
    join_rules: Vec<String>,
 | 
			
		||||
    join_filters: Vec<NetworkFilterName>,
 | 
			
		||||
    rules: Vec<NetworkFilterRule>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl NetworkFilter {
 | 
			
		||||
    fn process_all_rule(_n: &NetworkFilterRuleProtocolAll) -> NetworkFilterSelector {
 | 
			
		||||
    fn lib2rest_process_all_rule(_n: &NetworkFilterRuleProtocolAll) -> NetworkFilterSelector {
 | 
			
		||||
        NetworkFilterSelector::All
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn process_mac_rule(n: &NetworkFilterRuleProtocolMac) -> NetworkFilterSelector {
 | 
			
		||||
        NetworkFilterSelector::Mac {
 | 
			
		||||
    fn lib2rest_process_mac_rule(n: &NetworkFilterRuleProtocolMac) -> NetworkFilterSelector {
 | 
			
		||||
        NetworkFilterSelector::Mac(NetworkSelectorMac {
 | 
			
		||||
            src_mac_addr: n.srcmacaddr.clone(),
 | 
			
		||||
            src_mac_mask: n.srcmacmask.clone(),
 | 
			
		||||
            dst_mac_addr: n.dstmacaddr.clone(),
 | 
			
		||||
            dst_mac_mask: n.dstmacmask.clone(),
 | 
			
		||||
            comment: n.comment.clone(),
 | 
			
		||||
        }
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn process_arp_rule(n: &NetworkFilterRuleProtocolArp) -> NetworkSelectorARP {
 | 
			
		||||
    fn lib2rest_process_arp_rule(n: &NetworkFilterRuleProtocolArp) -> NetworkSelectorARP {
 | 
			
		||||
        NetworkSelectorARP {
 | 
			
		||||
            srcmacaddr: n.srcmacaddr.clone(),
 | 
			
		||||
            srcmacmask: n.srcmacmask.clone(),
 | 
			
		||||
@@ -126,7 +135,7 @@ impl NetworkFilter {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn process_ip_rule(n: &NetworkFilterRuleProtocolIpvx) -> NetworkFilterSelectorIP {
 | 
			
		||||
    fn lib2rest_process_ip_rule(n: &NetworkFilterRuleProtocolIpvx) -> NetworkFilterSelectorIP {
 | 
			
		||||
        NetworkFilterSelectorIP {
 | 
			
		||||
            srcmacaddr: n.srcmacaddr.clone(),
 | 
			
		||||
            srcmacmask: n.srcmacmask.clone(),
 | 
			
		||||
@@ -140,7 +149,7 @@ impl NetworkFilter {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn process_layer4_rule<IPv: Copy>(
 | 
			
		||||
    fn lib2rest_process_layer4_rule<IPv: Copy>(
 | 
			
		||||
        n: &NetworkFilterRuleProtocolLayer4<IPv>,
 | 
			
		||||
    ) -> anyhow::Result<NetworkSelectorLayer4<IPv>> {
 | 
			
		||||
        Ok(NetworkSelectorLayer4 {
 | 
			
		||||
@@ -162,120 +171,148 @@ impl NetworkFilter {
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn from_xml(xml: NetworkFilterXML) -> anyhow::Result<Self> {
 | 
			
		||||
    pub fn lib2rest(xml: NetworkFilterXML) -> anyhow::Result<Self> {
 | 
			
		||||
        let mut rules = Vec::with_capacity(xml.rules.len());
 | 
			
		||||
        for rule in &xml.rules {
 | 
			
		||||
            let mut selectors = Vec::new();
 | 
			
		||||
 | 
			
		||||
            // All selector
 | 
			
		||||
            selectors.append(&mut rule.all.iter().map(Self::process_all_rule).collect());
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .all
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(Self::lib2rest_process_all_rule)
 | 
			
		||||
                    .collect(),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Mac rules
 | 
			
		||||
            selectors.append(&mut rule.mac_rules.iter().map(Self::process_mac_rule).collect());
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .mac_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(Self::lib2rest_process_mac_rule)
 | 
			
		||||
                    .collect(),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // ARP - RARP rules
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .arp_rules
 | 
			
		||||
                    .arp_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|r| NetworkFilterSelector::Arp(Self::process_arp_rule(r)))
 | 
			
		||||
                    .map(|r| NetworkFilterSelector::Arp(Self::lib2rest_process_arp_rule(r)))
 | 
			
		||||
                    .collect(),
 | 
			
		||||
            );
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .rarp_rules
 | 
			
		||||
                    .rarp_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|r| NetworkFilterSelector::Rarp(Self::process_arp_rule(r)))
 | 
			
		||||
                    .map(|r| NetworkFilterSelector::Rarp(Self::lib2rest_process_arp_rule(r)))
 | 
			
		||||
                    .collect(),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // IPv4 - IPv6 rules
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .ipv4_rules
 | 
			
		||||
                    .ipv4_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|r| NetworkFilterSelector::IPv4(Self::process_ip_rule(r)))
 | 
			
		||||
                    .map(|r| NetworkFilterSelector::IPv4(Self::lib2rest_process_ip_rule(r)))
 | 
			
		||||
                    .collect(),
 | 
			
		||||
            );
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .ipv6_rules
 | 
			
		||||
                    .ipv6_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|r| NetworkFilterSelector::IPv6(Self::process_ip_rule(r)))
 | 
			
		||||
                    .map(|r| NetworkFilterSelector::IPv6(Self::lib2rest_process_ip_rule(r)))
 | 
			
		||||
                    .collect(),
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            // Layer 4 protocols
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .tcp_rules
 | 
			
		||||
                    .tcp_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|r| Ok(NetworkFilterSelector::TCP(Self::process_layer4_rule(r)?)))
 | 
			
		||||
                    .map(|r| {
 | 
			
		||||
                        Ok(NetworkFilterSelector::TCP(
 | 
			
		||||
                            Self::lib2rest_process_layer4_rule(r)?,
 | 
			
		||||
                        ))
 | 
			
		||||
                    })
 | 
			
		||||
                    .collect::<Result<Vec<_>, anyhow::Error>>()?,
 | 
			
		||||
            );
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .udp_rules
 | 
			
		||||
                    .udp_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|r| Ok(NetworkFilterSelector::UDP(Self::process_layer4_rule(r)?)))
 | 
			
		||||
                    .map(|r| {
 | 
			
		||||
                        Ok(NetworkFilterSelector::UDP(
 | 
			
		||||
                            Self::lib2rest_process_layer4_rule(r)?,
 | 
			
		||||
                        ))
 | 
			
		||||
                    })
 | 
			
		||||
                    .collect::<Result<Vec<_>, anyhow::Error>>()?,
 | 
			
		||||
            );
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .sctp_rules
 | 
			
		||||
                    .sctp_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|r| Ok(NetworkFilterSelector::SCTP(Self::process_layer4_rule(r)?)))
 | 
			
		||||
                    .map(|r| {
 | 
			
		||||
                        Ok(NetworkFilterSelector::SCTP(
 | 
			
		||||
                            Self::lib2rest_process_layer4_rule(r)?,
 | 
			
		||||
                        ))
 | 
			
		||||
                    })
 | 
			
		||||
                    .collect::<Result<Vec<_>, anyhow::Error>>()?,
 | 
			
		||||
            );
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .imcp_rules
 | 
			
		||||
                    .imcp_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|r| Ok(NetworkFilterSelector::ICMP(Self::process_layer4_rule(r)?)))
 | 
			
		||||
                    .map(|r| {
 | 
			
		||||
                        Ok(NetworkFilterSelector::ICMP(
 | 
			
		||||
                            Self::lib2rest_process_layer4_rule(r)?,
 | 
			
		||||
                        ))
 | 
			
		||||
                    })
 | 
			
		||||
                    .collect::<Result<Vec<_>, anyhow::Error>>()?,
 | 
			
		||||
            );
 | 
			
		||||
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .tcp_ipv6_rules
 | 
			
		||||
                    .tcp_ipv6_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|r| {
 | 
			
		||||
                        Ok(NetworkFilterSelector::TCPipv6(Self::process_layer4_rule(
 | 
			
		||||
                            r,
 | 
			
		||||
                        )?))
 | 
			
		||||
                        Ok(NetworkFilterSelector::TCPipv6(
 | 
			
		||||
                            Self::lib2rest_process_layer4_rule(r)?,
 | 
			
		||||
                        ))
 | 
			
		||||
                    })
 | 
			
		||||
                    .collect::<Result<Vec<_>, anyhow::Error>>()?,
 | 
			
		||||
            );
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .udp_ipv6_rules
 | 
			
		||||
                    .udp_ipv6_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|r| {
 | 
			
		||||
                        Ok(NetworkFilterSelector::UDPipv6(Self::process_layer4_rule(
 | 
			
		||||
                            r,
 | 
			
		||||
                        )?))
 | 
			
		||||
                        Ok(NetworkFilterSelector::UDPipv6(
 | 
			
		||||
                            Self::lib2rest_process_layer4_rule(r)?,
 | 
			
		||||
                        ))
 | 
			
		||||
                    })
 | 
			
		||||
                    .collect::<Result<Vec<_>, anyhow::Error>>()?,
 | 
			
		||||
            );
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .sctp_ipv6_rules
 | 
			
		||||
                    .sctp_ipv6_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|r| {
 | 
			
		||||
                        Ok(NetworkFilterSelector::SCTPipv6(Self::process_layer4_rule(
 | 
			
		||||
                            r,
 | 
			
		||||
                        )?))
 | 
			
		||||
                        Ok(NetworkFilterSelector::SCTPipv6(
 | 
			
		||||
                            Self::lib2rest_process_layer4_rule(r)?,
 | 
			
		||||
                        ))
 | 
			
		||||
                    })
 | 
			
		||||
                    .collect::<Result<Vec<_>, anyhow::Error>>()?,
 | 
			
		||||
            );
 | 
			
		||||
            selectors.append(
 | 
			
		||||
                &mut rule
 | 
			
		||||
                    .imcp_ipv6_rules
 | 
			
		||||
                    .imcp_ipv6_selectors
 | 
			
		||||
                    .iter()
 | 
			
		||||
                    .map(|r| {
 | 
			
		||||
                        Ok(NetworkFilterSelector::ICMPipv6(Self::process_layer4_rule(
 | 
			
		||||
                            r,
 | 
			
		||||
                        )?))
 | 
			
		||||
                        Ok(NetworkFilterSelector::ICMPipv6(
 | 
			
		||||
                            Self::lib2rest_process_layer4_rule(r)?,
 | 
			
		||||
                        ))
 | 
			
		||||
                    })
 | 
			
		||||
                    .collect::<Result<Vec<_>, anyhow::Error>>()?,
 | 
			
		||||
            );
 | 
			
		||||
@@ -289,21 +326,123 @@ impl NetworkFilter {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(Self {
 | 
			
		||||
            name: xml.name,
 | 
			
		||||
            name: NetworkFilterName(xml.name),
 | 
			
		||||
            uuid: xml.uuid,
 | 
			
		||||
            chain: NetworkFilterChain::from_xml(&xml.chain)?,
 | 
			
		||||
            chain: xml
 | 
			
		||||
                .chain
 | 
			
		||||
                .as_deref()
 | 
			
		||||
                .map(NetworkFilterChain::from_xml)
 | 
			
		||||
                .transpose()?,
 | 
			
		||||
            priority: xml.priority,
 | 
			
		||||
            join_rules: xml
 | 
			
		||||
            join_filters: xml
 | 
			
		||||
                .filterrefs
 | 
			
		||||
                .iter()
 | 
			
		||||
                .map(|i| i.filter.to_string())
 | 
			
		||||
                .map(|i| NetworkFilterName(i.filter.to_string()))
 | 
			
		||||
                .collect(),
 | 
			
		||||
            rules,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn rest2lib_process_rule(rule: &NetworkFilterRule) -> anyhow::Result<NetworkFilterRuleXML> {
 | 
			
		||||
        let mut rule_xml = NetworkFilterRuleXML {
 | 
			
		||||
            action: rule.action.to_xml(),
 | 
			
		||||
            direction: rule.direction.to_xml(),
 | 
			
		||||
            priority: rule.priority,
 | 
			
		||||
            all: vec![],
 | 
			
		||||
            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 {
 | 
			
		||||
            match sel {
 | 
			
		||||
                NetworkFilterSelector::All => {
 | 
			
		||||
                    rule_xml.all.push(NetworkFilterRuleProtocolAll {});
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                NetworkFilterSelector::Mac(mac) => {
 | 
			
		||||
                    todo!()
 | 
			
		||||
                    /*rule_xml.mac_selectors.push(NetworkFilterRuleProtocolMac {
 | 
			
		||||
                        srcmacaddr: mac.src_mac_addr,
 | 
			
		||||
                        srcmacmask: mac.src_mac_mask,
 | 
			
		||||
                        dstmacaddr: mac.,
 | 
			
		||||
                        dstmacmask: None,
 | 
			
		||||
                        comment: None,
 | 
			
		||||
                    })*/
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                NetworkFilterSelector::Arp(_) => todo!(),
 | 
			
		||||
                NetworkFilterSelector::Rarp(_) => todo!(),
 | 
			
		||||
                NetworkFilterSelector::IPv4(_) => todo!(),
 | 
			
		||||
                NetworkFilterSelector::IPv6(_) => todo!(),
 | 
			
		||||
                NetworkFilterSelector::TCP(_) => todo!(),
 | 
			
		||||
                NetworkFilterSelector::UDP(_) => todo!(),
 | 
			
		||||
                NetworkFilterSelector::SCTP(_) => todo!(),
 | 
			
		||||
                NetworkFilterSelector::ICMP(_) => todo!(),
 | 
			
		||||
                NetworkFilterSelector::TCPipv6(_) => todo!(),
 | 
			
		||||
                NetworkFilterSelector::UDPipv6(_) => todo!(),
 | 
			
		||||
                NetworkFilterSelector::SCTPipv6(_) => todo!(),
 | 
			
		||||
                NetworkFilterSelector::ICMPipv6(_) => todo!(),
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(rule_xml)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn rest2lib(&self) -> anyhow::Result<NetworkFilterXML> {
 | 
			
		||||
        if !self.name.is_valid() {
 | 
			
		||||
            return Err(StructureExtraction("Network filter name is invalid!").into());
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if let Some(priority) = self.priority {
 | 
			
		||||
            if !(-1000..=1000).contains(&priority) {
 | 
			
		||||
                return Err(StructureExtraction("Network priority is invalid!").into());
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for fref in &self.join_filters {
 | 
			
		||||
            if !fref.is_valid() {
 | 
			
		||||
                return Err(
 | 
			
		||||
                    StructureExtraction("Referenced network filter name is invalid!").into(),
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut rules = Vec::with_capacity(self.rules.len());
 | 
			
		||||
 | 
			
		||||
        for rule in &self.rules {
 | 
			
		||||
            rules.push(Self::rest2lib_process_rule(rule)?);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Ok(NetworkFilterXML {
 | 
			
		||||
            name: self.name.0.to_string(),
 | 
			
		||||
            uuid: self.uuid,
 | 
			
		||||
            chain: self.chain.as_ref().map(|c| c.to_xml()),
 | 
			
		||||
            priority: self.priority,
 | 
			
		||||
            filterrefs: self
 | 
			
		||||
                .join_filters
 | 
			
		||||
                .iter()
 | 
			
		||||
                .map(|jf| NetworkFilterRefXML {
 | 
			
		||||
                    filter: jf.0.to_string(),
 | 
			
		||||
                })
 | 
			
		||||
                .collect::<Vec<_>>(),
 | 
			
		||||
            rules,
 | 
			
		||||
        })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[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,
 | 
			
		||||
@@ -348,6 +487,7 @@ impl NetworkFilterAction {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
			
		||||
#[serde(rename_all = "lowercase")]
 | 
			
		||||
pub enum NetworkFilterDirection {
 | 
			
		||||
    In,
 | 
			
		||||
    Out,
 | 
			
		||||
@@ -430,6 +570,15 @@ pub struct NetworkFilterSelectorIP {
 | 
			
		||||
    comment: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
			
		||||
pub struct NetworkSelectorMac {
 | 
			
		||||
    src_mac_addr: Option<String>,
 | 
			
		||||
    src_mac_mask: Option<String>,
 | 
			
		||||
    dst_mac_addr: Option<String>,
 | 
			
		||||
    dst_mac_mask: Option<String>,
 | 
			
		||||
    comment: Option<String>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
			
		||||
pub struct NetworkSelectorARP {
 | 
			
		||||
    srcmacaddr: Option<String>,
 | 
			
		||||
@@ -467,15 +616,10 @@ pub struct NetworkSelectorLayer4<IPv> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
 | 
			
		||||
#[serde(tag = "type", rename_all = "lowercase")]
 | 
			
		||||
pub enum NetworkFilterSelector {
 | 
			
		||||
    All,
 | 
			
		||||
    Mac {
 | 
			
		||||
        src_mac_addr: Option<String>,
 | 
			
		||||
        src_mac_mask: Option<String>,
 | 
			
		||||
        dst_mac_addr: Option<String>,
 | 
			
		||||
        dst_mac_mask: Option<String>,
 | 
			
		||||
        comment: Option<String>,
 | 
			
		||||
    },
 | 
			
		||||
    Mac(NetworkSelectorMac),
 | 
			
		||||
    Arp(NetworkSelectorARP),
 | 
			
		||||
    Rarp(NetworkSelectorARP),
 | 
			
		||||
    IPv4(NetworkFilterSelectorIP),
 | 
			
		||||
 
 | 
			
		||||
@@ -240,6 +240,10 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
                web::get().to(network_controller::stop),
 | 
			
		||||
            )
 | 
			
		||||
            // Network filters controller
 | 
			
		||||
            .route(
 | 
			
		||||
                "/api/nwfilter/create",
 | 
			
		||||
                web::post().to(nwfilter_controller::create),
 | 
			
		||||
            )
 | 
			
		||||
            .route(
 | 
			
		||||
                "/api/nwfilter/list",
 | 
			
		||||
                web::get().to(nwfilter_controller::list),
 | 
			
		||||
@@ -248,6 +252,10 @@ async fn main() -> std::io::Result<()> {
 | 
			
		||||
                "/api/nwfilter/{uid}",
 | 
			
		||||
                web::get().to(nwfilter_controller::get_single),
 | 
			
		||||
            )
 | 
			
		||||
            .route(
 | 
			
		||||
                "/api/nwfilter/{uid}",
 | 
			
		||||
                web::put().to(nwfilter_controller::update),
 | 
			
		||||
            )
 | 
			
		||||
            // Static assets
 | 
			
		||||
            .route("/", web::get().to(static_controller::root_index))
 | 
			
		||||
            .route(
 | 
			
		||||
 
 | 
			
		||||
@@ -17,3 +17,22 @@ pub fn extract_ipv6(ip: IpAddr) -> Ipv6Addr {
 | 
			
		||||
        IpAddr::V6(i) => i,
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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())
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[cfg(test)]
 | 
			
		||||
mod tests {
 | 
			
		||||
    use crate::utils::net_utils::is_mac_address_valid;
 | 
			
		||||
 | 
			
		||||
    #[test]
 | 
			
		||||
    fn mac_addresses() {
 | 
			
		||||
        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("tata"));
 | 
			
		||||
        assert!(!is_mac_address_valid("FF:FF:FF:FF:FF:FZ"));
 | 
			
		||||
        assert!(!is_mac_address_valid("FF:FF:FF:FF:FF:FF:FF"));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user