WIP REST routes to create / update Network filters
This commit is contained in:
virtweb_backend/src
@ -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),
|
||||
|
Reference in New Issue
Block a user