diff --git a/virtweb_backend/src/libvirt_lib_structures/nwfilter.rs b/virtweb_backend/src/libvirt_lib_structures/nwfilter.rs index 059c5f0..2359272 100644 --- a/virtweb_backend/src/libvirt_lib_structures/nwfilter.rs +++ b/virtweb_backend/src/libvirt_lib_structures/nwfilter.rs @@ -1,6 +1,6 @@ use crate::libvirt_lib_structures::XMLUuid; use std::fmt::Display; -use std::net::IpAddr; +use std::net::{Ipv4Addr, Ipv6Addr}; #[derive(serde::Serialize, serde::Deserialize, Debug)] #[serde(rename = "filterref")] @@ -20,27 +20,27 @@ pub struct NetworkFilterRuleProtocolMac { rename(serialize = "@srcmacaddr"), skip_serializing_if = "Option::is_none" )] - srcmacaddr: Option, + pub srcmacaddr: Option, #[serde( rename(serialize = "@srcmacmask"), skip_serializing_if = "Option::is_none" )] - srcmacmask: Option, + pub srcmacmask: Option, #[serde( rename(serialize = "@dstmacaddr"), skip_serializing_if = "Option::is_none" )] - dstmacaddr: Option, + pub dstmacaddr: Option, #[serde( rename(serialize = "@dstmacmask"), skip_serializing_if = "Option::is_none" )] - dstmacmask: Option, + pub dstmacmask: Option, #[serde( rename(serialize = "@comment"), skip_serializing_if = "Option::is_none" )] - comment: Option, + pub comment: Option, } #[derive(serde::Serialize, serde::Deserialize, Debug)] @@ -50,48 +50,48 @@ pub struct NetworkFilterRuleProtocolArp { rename(serialize = "@srcmacaddr"), skip_serializing_if = "Option::is_none" )] - srcmacaddr: Option, + pub srcmacaddr: Option, #[serde( rename(serialize = "@srcmacmask"), skip_serializing_if = "Option::is_none" )] - srcmacmask: Option, + pub srcmacmask: Option, #[serde( rename(serialize = "@dstmacaddr"), skip_serializing_if = "Option::is_none" )] - dstmacaddr: Option, + pub dstmacaddr: Option, #[serde( rename(serialize = "@dstmacmask"), skip_serializing_if = "Option::is_none" )] - dstmacmask: Option, + pub dstmacmask: Option, #[serde( rename(serialize = "@arpsrcipaddr"), skip_serializing_if = "Option::is_none" )] - arpsrcipaddr: Option, + pub arpsrcipaddr: Option, #[serde( rename(serialize = "@arpsrcipmask"), skip_serializing_if = "Option::is_none" )] - arpsrcipmask: Option, + pub arpsrcipmask: Option, #[serde( rename(serialize = "@arpdstipaddr"), skip_serializing_if = "Option::is_none" )] - arpdstipaddr: Option, + pub arpdstipaddr: Option, #[serde( rename(serialize = "@arpdstipmask"), skip_serializing_if = "Option::is_none" )] - arpdstipmask: Option, + pub arpdstipmask: Option, #[serde( rename(serialize = "@comment"), skip_serializing_if = "Option::is_none" )] - comment: Option, + pub comment: Option, } #[derive(serde::Serialize, serde::Deserialize, Debug)] @@ -101,130 +101,130 @@ pub struct NetworkFilterRuleProtocolIpvx { rename(serialize = "@srcmacaddr"), skip_serializing_if = "Option::is_none" )] - srcmacaddr: Option, + pub srcmacaddr: Option, #[serde( rename(serialize = "@srcmacmask"), skip_serializing_if = "Option::is_none" )] - srcmacmask: Option, + pub srcmacmask: Option, #[serde( rename(serialize = "@dstmacaddr"), skip_serializing_if = "Option::is_none" )] - dstmacaddr: Option, + pub dstmacaddr: Option, #[serde( rename(serialize = "@dstmacmask"), skip_serializing_if = "Option::is_none" )] - dstmacmask: Option, + pub dstmacmask: Option, #[serde( rename(serialize = "@srcipaddr"), skip_serializing_if = "Option::is_none" )] - srcipaddr: Option, + pub srcipaddr: Option, #[serde( rename(serialize = "@srcipmask"), skip_serializing_if = "Option::is_none" )] - srcipmask: Option, + pub srcipmask: Option, #[serde( rename(serialize = "@dstipaddr"), skip_serializing_if = "Option::is_none" )] - dstipaddr: Option, + pub dstipaddr: Option, #[serde( rename(serialize = "@dstipmask"), skip_serializing_if = "Option::is_none" )] - dstipmask: Option, + pub dstipmask: Option, #[serde( rename(serialize = "@comment"), skip_serializing_if = "Option::is_none" )] - comment: Option, + pub comment: Option, } #[derive(serde::Serialize, serde::Deserialize, Debug)] #[serde(rename = "layer4")] -pub struct NetworkFilterRuleProtocolLayer4 { +pub struct NetworkFilterRuleProtocolLayer4 { #[serde( rename(serialize = "@srcmacaddr"), skip_serializing_if = "Option::is_none" )] - srcmacaddr: Option, + pub srcmacaddr: Option, #[serde( rename(serialize = "@srcipaddr"), skip_serializing_if = "Option::is_none" )] - srcipaddr: Option, + pub srcipaddr: Option, #[serde( rename(serialize = "@srcipmask"), skip_serializing_if = "Option::is_none" )] - srcipmask: Option, + pub srcipmask: Option, #[serde( rename(serialize = "@dstipaddr"), skip_serializing_if = "Option::is_none" )] - dstipaddr: Option, + pub dstipaddr: Option, #[serde( rename(serialize = "@dstipmask"), skip_serializing_if = "Option::is_none" )] - dstipmask: Option, + pub dstipmask: Option, /// Start of range of source IP address #[serde( rename(serialize = "@srcipfrom"), skip_serializing_if = "Option::is_none" )] - srcipfrom: Option, + pub srcipfrom: Option, /// End of range of source IP address #[serde( rename(serialize = "@srcipto"), skip_serializing_if = "Option::is_none" )] - srcipto: Option, + pub srcipto: Option, /// Start of range of destination IP address #[serde( rename(serialize = "@dstipfrom"), skip_serializing_if = "Option::is_none" )] - dstipfrom: Option, + pub dstipfrom: Option, /// End of range of destination IP address #[serde( rename(serialize = "@dstipto"), skip_serializing_if = "Option::is_none" )] - dstipto: Option, + pub dstipto: Option, #[serde( rename(serialize = "@srcportstart"), skip_serializing_if = "Option::is_none" )] - srcportstart: Option, + pub srcportstart: Option, #[serde( rename(serialize = "@srcportend"), skip_serializing_if = "Option::is_none" )] - srcportend: Option, + pub srcportend: Option, #[serde( rename(serialize = "@dstportstart"), skip_serializing_if = "Option::is_none" )] - dstportstart: Option, + pub dstportstart: Option, #[serde( rename(serialize = "@dstportend"), skip_serializing_if = "Option::is_none" )] - dstportend: Option, + pub dstportend: Option, #[serde(rename(serialize = "@state"), skip_serializing_if = "Option::is_none")] - state: Option, + pub state: Option, #[serde( rename(serialize = "@comment"), skip_serializing_if = "Option::is_none" )] - comment: Option, + pub comment: Option, } #[derive(serde::Serialize, serde::Deserialize, Debug)] @@ -249,6 +249,10 @@ pub struct NetworkFilterRuleXML { #[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")] pub arp_rules: Vec, + /// Match rarp protocol + #[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")] + pub rarp_rules: Vec, + /// Match IPv4 protocol #[serde(default, rename = "ip", skip_serializing_if = "Vec::is_empty")] pub ipv4_rules: Vec, @@ -259,15 +263,35 @@ pub struct NetworkFilterRuleXML { /// Match TCP protocol #[serde(default, rename = "tcp", skip_serializing_if = "Vec::is_empty")] - pub tcp_rules: Vec, + pub tcp_rules: Vec>, /// Match UDP protocol #[serde(default, rename = "udp", skip_serializing_if = "Vec::is_empty")] - pub udp_rules: Vec, + pub udp_rules: Vec>, /// Match SCTP protocol #[serde(default, rename = "sctp", skip_serializing_if = "Vec::is_empty")] - pub sctp_rules: Vec, + pub sctp_rules: Vec>, + + /// Match ICMP protocol + #[serde(default, rename = "icmp", skip_serializing_if = "Vec::is_empty")] + pub imcp_rules: Vec>, + + /// Match TCP IPv6 protocol + #[serde(default, rename = "tcp-ipv6", skip_serializing_if = "Vec::is_empty")] + pub tcp_ipv6_rules: Vec>, + + /// Match UDP IPv6 protocol + #[serde(default, rename = "udp-ipv6", skip_serializing_if = "Vec::is_empty")] + pub udp_ipv6_rules: Vec>, + + /// Match SCTP IPv6 protocol + #[serde(default, rename = "sctp-ipv6", skip_serializing_if = "Vec::is_empty")] + pub sctp_ipv6_rules: Vec>, + + /// Match ICMP IPv6 protocol + #[serde(default, rename = "icmpv6", skip_serializing_if = "Vec::is_empty")] + pub imcp_ipv6_rules: Vec>, } #[derive(serde::Serialize, serde::Deserialize, Debug)] diff --git a/virtweb_backend/src/libvirt_rest_structures/nw_filter.rs b/virtweb_backend/src/libvirt_rest_structures/nw_filter.rs index 1132600..5642ef8 100644 --- a/virtweb_backend/src/libvirt_rest_structures/nw_filter.rs +++ b/virtweb_backend/src/libvirt_rest_structures/nw_filter.rs @@ -1,7 +1,10 @@ -use crate::libvirt_lib_structures::nwfilter::NetworkFilterXML; +use crate::libvirt_lib_structures::nwfilter::{ + NetworkFilterRuleProtocolAll, NetworkFilterRuleProtocolArp, NetworkFilterRuleProtocolIpvx, + NetworkFilterRuleProtocolLayer4, NetworkFilterRuleProtocolMac, NetworkFilterXML, +}; use crate::libvirt_lib_structures::XMLUuid; use crate::libvirt_rest_structures::LibVirtStructError; -use std::net::{IpAddr, Ipv4Addr, Ipv6Addr}; +use std::net::{Ipv4Addr, Ipv6Addr}; #[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)] pub enum NetworkFilterChainProtocol { @@ -30,7 +33,7 @@ impl NetworkFilterChainProtocol { return Err(LibVirtStructError::ParseFilteringChain(format!( "Unknown filtering chain: {xml}! " )) - .into()) + .into()); } }) } @@ -95,12 +98,187 @@ pub struct NetworkFilter { } impl NetworkFilter { + fn process_all_rule(_n: &NetworkFilterRuleProtocolAll) -> NetworkFilterSelector { + NetworkFilterSelector::All + } + + fn process_mac_rule(n: &NetworkFilterRuleProtocolMac) -> NetworkFilterSelector { + NetworkFilterSelector::Mac { + 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 { + NetworkSelectorARP { + srcmacaddr: n.srcmacaddr.clone(), + srcmacmask: n.srcmacmask.clone(), + dstmacaddr: n.dstmacaddr.clone(), + dstmacmask: n.dstmacmask.clone(), + arpsrcipaddr: n.arpsrcipaddr.clone(), + arpsrcipmask: n.arpsrcipmask, + arpdstipaddr: n.arpdstipaddr.clone(), + arpdstipmask: n.arpdstipmask, + comment: n.comment.clone(), + } + } + + fn process_ip_rule(n: &NetworkFilterRuleProtocolIpvx) -> NetworkFilterSelectorIP { + NetworkFilterSelectorIP { + srcmacaddr: n.srcmacaddr.clone(), + srcmacmask: n.srcmacmask.clone(), + dstmacaddr: n.dstmacaddr.clone(), + dstmacmask: n.dstmacmask.clone(), + srcipaddr: n.srcipaddr.clone(), + srcipmask: n.srcipmask, + dstipaddr: n.dstipaddr.clone(), + dstipmask: n.dstipmask, + comment: n.comment.clone(), + } + } + + fn process_layer4_rule( + n: &NetworkFilterRuleProtocolLayer4, + ) -> anyhow::Result> { + Ok(NetworkSelectorLayer4 { + srcmacaddr: n.srcmacaddr.clone(), + srcipaddr: n.srcipaddr, + srcipmask: n.srcipmask, + dstipaddr: n.dstipaddr, + dstipmask: n.dstipmask, + srcipfrom: n.srcipfrom, + srcipto: n.srcipto, + dstipfrom: n.dstipfrom, + dstipto: n.dstipto, + srcportstart: n.srcportstart, + srcportend: n.srcportend, + dstportstart: n.dstportstart, + dstportend: n.dstportend, + state: n.state.as_deref().map(Layer4State::from_xml).transpose()?, + comment: n.comment.clone(), + }) + } + pub fn from_xml(xml: NetworkFilterXML) -> anyhow::Result { let mut rules = Vec::with_capacity(xml.rules.len()); for rule in &xml.rules { let mut selectors = Vec::new(); - // TODO : add other selectors + // All selector + selectors.append(&mut rule.all.iter().map(Self::process_all_rule).collect()); + + // Mac rules + selectors.append(&mut rule.mac_rules.iter().map(Self::process_mac_rule).collect()); + + // ARP - RARP rules + selectors.append( + &mut rule + .arp_rules + .iter() + .map(|r| NetworkFilterSelector::Arp(Self::process_arp_rule(r))) + .collect(), + ); + selectors.append( + &mut rule + .rarp_rules + .iter() + .map(|r| NetworkFilterSelector::Rarp(Self::process_arp_rule(r))) + .collect(), + ); + + // IPv4 - IPv6 rules + selectors.append( + &mut rule + .ipv4_rules + .iter() + .map(|r| NetworkFilterSelector::IPv4(Self::process_ip_rule(r))) + .collect(), + ); + selectors.append( + &mut rule + .ipv6_rules + .iter() + .map(|r| NetworkFilterSelector::IPv6(Self::process_ip_rule(r))) + .collect(), + ); + + // Layer 4 protocols + selectors.append( + &mut rule + .tcp_rules + .iter() + .map(|r| Ok(NetworkFilterSelector::TCP(Self::process_layer4_rule(r)?))) + .collect::, anyhow::Error>>()?, + ); + selectors.append( + &mut rule + .udp_rules + .iter() + .map(|r| Ok(NetworkFilterSelector::UDP(Self::process_layer4_rule(r)?))) + .collect::, anyhow::Error>>()?, + ); + selectors.append( + &mut rule + .sctp_rules + .iter() + .map(|r| Ok(NetworkFilterSelector::SCTP(Self::process_layer4_rule(r)?))) + .collect::, anyhow::Error>>()?, + ); + selectors.append( + &mut rule + .imcp_rules + .iter() + .map(|r| Ok(NetworkFilterSelector::ICMP(Self::process_layer4_rule(r)?))) + .collect::, anyhow::Error>>()?, + ); + + selectors.append( + &mut rule + .tcp_ipv6_rules + .iter() + .map(|r| { + Ok(NetworkFilterSelector::TCPipv6(Self::process_layer4_rule( + r, + )?)) + }) + .collect::, anyhow::Error>>()?, + ); + selectors.append( + &mut rule + .udp_ipv6_rules + .iter() + .map(|r| { + Ok(NetworkFilterSelector::UDPipv6(Self::process_layer4_rule( + r, + )?)) + }) + .collect::, anyhow::Error>>()?, + ); + selectors.append( + &mut rule + .sctp_ipv6_rules + .iter() + .map(|r| { + Ok(NetworkFilterSelector::SCTPipv6(Self::process_layer4_rule( + r, + )?)) + }) + .collect::, anyhow::Error>>()?, + ); + selectors.append( + &mut rule + .imcp_ipv6_rules + .iter() + .map(|r| { + Ok(NetworkFilterSelector::ICMPipv6(Self::process_layer4_rule( + r, + )?)) + }) + .collect::, anyhow::Error>>()?, + ); rules.push(NetworkFilterRule { action: NetworkFilterAction::from_xml(&rule.action)?, @@ -152,7 +330,7 @@ impl NetworkFilterAction { return Err(LibVirtStructError::ParseFilteringChain(format!( "Unkown filter action {s}!" )) - .into()) + .into()); } }) } @@ -186,7 +364,7 @@ impl NetworkFilterDirection { return Err(LibVirtStructError::ParseFilteringChain(format!( "Unkown filter direction {s}!" )) - .into()) + .into()); } }) } @@ -210,28 +388,81 @@ pub enum Layer4State { NONE, } -#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] -pub enum Layer4Type { - TCP, - UDP, - SCTP, - ICMP, - TCPipv6, - UDPipv6, - SCTPipv6, - ICMPipv6, +impl Layer4State { + pub fn from_xml(xml: &str) -> anyhow::Result { + 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 NetworkFilterSelectorIP { +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 NetworkSelectorARP { + srcmacaddr: Option, + srcmacmask: Option, + dstmacaddr: Option, + dstmacmask: Option, + arpsrcipaddr: Option, + arpsrcipmask: Option, + arpdstipaddr: Option, + arpdstipmask: Option, + comment: Option, +} + +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct NetworkSelectorLayer4 { + srcmacaddr: Option, srcipaddr: Option, srcipmask: Option, dstipaddr: Option, dstipmask: Option, + /// Start of range of source IP address + srcipfrom: Option, + /// End of range of source IP address + srcipto: Option, + /// Start of range of destination IP address + dstipfrom: Option, + /// End of range of destination IP address + dstipto: Option, + srcportstart: Option, + srcportend: Option, + dstportstart: Option, + dstportend: Option, + state: Option, comment: Option, } @@ -245,41 +476,18 @@ pub enum NetworkFilterSelector { dst_mac_mask: Option, comment: Option, }, - Arp { - srcmacaddr: Option, - srcmacmask: Option, - dstmacaddr: Option, - dstmacmask: Option, - arpsrcipaddr: Option, - arpsrcipmask: Option, - arpdstipaddr: Option, - arpdstipmask: Option, - comment: Option, - }, - IPv4(NetworkFilterSelectorIP), - IPv6(NetworkFilterSelectorIP), - Layer4 { - r#type: Layer4Type, - srcmacaddr: Option, - srcipaddr: Option, - srcipmask: Option, - dstipaddr: Option, - dstipmask: Option, - /// Start of range of source IP address - srcipfrom: Option, - /// End of range of source IP address - srcipto: Option, - /// Start of range of destination IP address - dstipfrom: Option, - /// End of range of destination IP address - dstipto: Option, - srcportstart: Option, - srcportend: Option, - dstportstart: Option, - dstportend: Option, - state: Option, - comment: Option, - }, + Arp(NetworkSelectorARP), + Rarp(NetworkSelectorARP), + IPv4(NetworkFilterSelectorIP), + IPv6(NetworkFilterSelectorIP), + TCP(NetworkSelectorLayer4), + UDP(NetworkSelectorLayer4), + SCTP(NetworkSelectorLayer4), + ICMP(NetworkSelectorLayer4), + TCPipv6(NetworkSelectorLayer4), + UDPipv6(NetworkSelectorLayer4), + SCTPipv6(NetworkSelectorLayer4), + ICMPipv6(NetworkSelectorLayer4), } #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]