diff --git a/virtweb_backend/src/controllers/nwfilter_controller.rs b/virtweb_backend/src/controllers/nwfilter_controller.rs index 9135538..5edc8c3 100644 --- a/virtweb_backend/src/controllers/nwfilter_controller.rs +++ b/virtweb_backend/src/controllers/nwfilter_controller.rs @@ -1,5 +1,6 @@ use crate::controllers::{HttpResult, LibVirtReq}; use crate::libvirt_lib_structures::XMLUuid; +use crate::libvirt_rest_structures::NetworkFilter; use actix_web::{web, HttpResponse}; #[derive(serde::Serialize, serde::Deserialize)] @@ -18,19 +19,16 @@ pub async fn list(client: LibVirtReq) -> HttpResult { Ok(l) => l, }; - /*let networks = networks - .into_iter() - .map(|n| NetworkInfo::from_xml(n).unwrap()) - .collect::>();*/ - // TODO : turn into lib structure - println!("{:#?}", networks); + let networks = networks + .into_iter() + .map(|n| NetworkFilter::from_xml(n).unwrap()) + .collect::>(); - Ok(HttpResponse::Ok().body(format!("{:#?}", networks))) + Ok(HttpResponse::Ok().json(networks)) } /// Get the information about a single network filter pub async fn get_single(client: LibVirtReq, req: web::Path) -> HttpResult { - let nwfilter = client.get_single_network_filter(req.uid).await?; - // TODO : turn into lib structure - Ok(HttpResponse::Ok().body(format!("{:#?}", nwfilter))) + let nwfilter = NetworkFilter::from_xml(client.get_single_network_filter(req.uid).await?)?; + Ok(HttpResponse::Ok().json(nwfilter)) } diff --git a/virtweb_backend/src/libvirt_rest_structures.rs b/virtweb_backend/src/libvirt_rest_structures.rs index 73af939..41ac39f 100644 --- a/virtweb_backend/src/libvirt_rest_structures.rs +++ b/virtweb_backend/src/libvirt_rest_structures.rs @@ -5,9 +5,9 @@ use crate::libvirt_lib_structures::{ DomainCPUTopology, DomainCPUXML, DomainInputXML, DomainMemoryXML, DomainNetInterfaceXML, DomainVCPUXML, DomainXML, FeaturesXML, GraphicsXML, NetIntModelXML, NetIntSourceXML, NetMacAddress, NetworkBridgeXML, NetworkDHCPHostXML, NetworkDHCPRangeXML, NetworkDHCPXML, - NetworkDNSForwarderXML, NetworkDNSXML, NetworkDomainXML, NetworkForwardXML, NetworkIPXML, - NetworkXML, OSLoaderXML, OSTypeXML, TPMBackendXML, TPMDeviceXML, VideoModelXML, VideoXML, - XMLUuid, ACPIXML, OSXML, + NetworkDNSForwarderXML, NetworkDNSXML, NetworkDomainXML, NetworkFilterXML, NetworkForwardXML, + NetworkIPXML, NetworkXML, OSLoaderXML, OSTypeXML, TPMBackendXML, TPMDeviceXML, VideoModelXML, + VideoXML, XMLUuid, ACPIXML, OSXML, }; use crate::libvirt_rest_structures::LibVirtStructError::StructureExtraction; use crate::utils::disks_utils::Disk; @@ -18,6 +18,8 @@ use num::Integer; use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; use std::ops::{Div, Mul}; +// TODO : split into multiple files + #[derive(thiserror::Error, Debug)] enum LibVirtStructError { #[error("StructureExtractionError: {0}")] @@ -26,6 +28,8 @@ enum LibVirtStructError { DomainExtraction(String), #[error("MBConvertError: {0}")] MBConvert(String), + #[error("ParseFilteringChain: {0}")] + ParseFilteringChain(String), } #[derive(serde::Serialize)] @@ -700,7 +704,8 @@ impl NetworkInfo { } } -pub enum NetworkFilterChain { +#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)] +pub enum NetworkFilterChainProtocol { Root, Mac, STP, @@ -711,7 +716,75 @@ pub enum NetworkFilterChain { IPv6, } +impl NetworkFilterChainProtocol { + pub fn from_xml(xml: &str) -> anyhow::Result { + Ok(match xml { + "root" => Self::Root, + "mac" => Self::Mac, + "stp" => Self::STP, + "vlan" => Self::VLAN, + "arp" => Self::ARP, + "rarp" => Self::RARP, + "ipv4" => Self::IPv4, + "ipv6" => Self::IPv6, + _ => { + return Err(LibVirtStructError::ParseFilteringChain(format!( + "Unknown filtering chain: {xml}! " + )) + .into()) + } + }) + } + + pub fn to_xml(&self) -> String { + match self { + Self::Root => "root", + Self::Mac => "mac", + Self::STP => "stp", + Self::VLAN => "vlan", + Self::ARP => "arp", + Self::RARP => "rarp", + Self::IPv4 => "ipv4", + Self::IPv6 => "ipv6", + } + .to_string() + } +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct NetworkFilterChain { + protocol: NetworkFilterChainProtocol, + suffix: Option, +} + +impl NetworkFilterChain { + pub fn from_xml(xml: &str) -> anyhow::Result> { + if xml.is_empty() { + return Ok(None); + } + + Ok(Some(match xml.split_once('-') { + None => Self { + protocol: NetworkFilterChainProtocol::from_xml(xml)?, + suffix: None, + }, + Some((prefix, suffix)) => Self { + protocol: NetworkFilterChainProtocol::from_xml(prefix)?, + suffix: Some(suffix.to_string()), + }, + })) + } + + pub fn to_xml(&self) -> String { + match &self.suffix { + None => self.protocol.to_xml(), + Some(s) => format!("{}-{s}", self.protocol.to_xml()), + } + } +} + /// Network filter definition +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct NetworkFilter { name: String, chain: Option, @@ -722,6 +795,24 @@ pub struct NetworkFilter { rules: Vec, } +impl NetworkFilter { + pub fn from_xml(xml: NetworkFilterXML) -> anyhow::Result { + Ok(Self { + name: xml.name, + uuid: xml.uuid, + chain: NetworkFilterChain::from_xml(&xml.chain)?, + priority: xml.priority, + join_rules: xml + .filterrefs + .iter() + .map(|i| i.filter.to_string()) + .collect(), + rules: vec![], // TODO ! + }) + } +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)] pub enum NetworkFilterAction { /// matching the rule silently discards the packet with no further analysis Drop, @@ -736,12 +827,14 @@ pub enum NetworkFilterAction { Continue, } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub enum NetworkFilterDirection { In, Out, InOut, } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub enum Layer4State { NEW, ESTABLISHED, @@ -750,6 +843,7 @@ pub enum Layer4State { NONE, } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub enum Layer4Type { TCP, UDP, @@ -761,6 +855,20 @@ pub enum Layer4Type { ICMPipv6, } +#[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 enum NetworkFilterSelector { All, Mac { @@ -781,28 +889,8 @@ pub enum NetworkFilterSelector { arpdstipmask: Option, comment: Option, }, - IPv4 { - srcmacaddr: Option, - srcmacmask: Option, - dstmacaddr: Option, - dstmacmask: Option, - srcipaddr: Option, - srcipmask: Option, - dstipaddr: Option, - dstipmask: Option, - comment: Option, - }, - IPv6 { - srcmacaddr: Option, - srcmacmask: Option, - dstmacaddr: Option, - dstmacmask: Option, - srcipaddr: Option, - srcipmask: Option, - dstipaddr: Option, - dstipmask: Option, - comment: Option, - }, + IPv4(NetworkFilterSelectorIP), + IPv6(NetworkFilterSelectorIP), Layer4 { r#type: Layer4Type, srcmacaddr: Option, @@ -827,6 +915,7 @@ pub enum NetworkFilterSelector { }, } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct NetworkFilterRule { action: NetworkFilterAction, direction: NetworkFilterDirection,