WIP REST routes to create / update Network filters

This commit is contained in:
Pierre HUBERT 2023-12-29 20:11:21 +01:00
parent 61c567846d
commit 7b74e7b75a
6 changed files with 331 additions and 83 deletions

View File

@ -1,3 +1,4 @@
use crate::constants;
use crate::controllers::{HttpResult, LibVirtReq}; use crate::controllers::{HttpResult, LibVirtReq};
use crate::libvirt_lib_structures::XMLUuid; use crate::libvirt_lib_structures::XMLUuid;
use crate::libvirt_rest_structures::nw_filter::NetworkFilter; use crate::libvirt_rest_structures::nw_filter::NetworkFilter;
@ -8,6 +9,37 @@ pub struct NetworkFilterID {
uid: XMLUuid, 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 /// Get the list of network filters
pub async fn list(client: LibVirtReq) -> HttpResult { pub async fn list(client: LibVirtReq) -> HttpResult {
let networks = match client.get_full_network_filters_list().await { let networks = match client.get_full_network_filters_list().await {
@ -21,7 +53,7 @@ pub async fn list(client: LibVirtReq) -> HttpResult {
let networks = networks let networks = networks
.into_iter() .into_iter()
.map(|n| NetworkFilter::from_xml(n).unwrap()) .map(|n| NetworkFilter::lib2rest(n).unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
Ok(HttpResponse::Ok().json(networks)) Ok(HttpResponse::Ok().json(networks))
@ -29,6 +61,36 @@ pub async fn list(client: LibVirtReq) -> HttpResult {
/// Get the information about a single network filter /// Get the information about a single network filter
pub async fn get_single(client: LibVirtReq, req: web::Path<NetworkFilterID>) -> HttpResult { 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)) 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"))
}

View File

@ -6,6 +6,7 @@ use crate::libvirt_lib_structures::nwfilter::NetworkFilterXML;
use crate::libvirt_lib_structures::XMLUuid; use crate::libvirt_lib_structures::XMLUuid;
use crate::libvirt_rest_structures::hypervisor::HypervisorInfo; use crate::libvirt_rest_structures::hypervisor::HypervisorInfo;
use crate::libvirt_rest_structures::net::NetworkInfo; use crate::libvirt_rest_structures::net::NetworkInfo;
use crate::libvirt_rest_structures::nw_filter::NetworkFilter;
use crate::libvirt_rest_structures::vm::VMInfo; use crate::libvirt_rest_structures::vm::VMInfo;
use actix::Addr; use actix::Addr;
@ -185,4 +186,14 @@ impl LibVirtClient {
pub async fn get_single_network_filter(&self, id: XMLUuid) -> anyhow::Result<NetworkFilterXML> { pub async fn get_single_network_filter(&self, id: XMLUuid) -> anyhow::Result<NetworkFilterXML> {
self.0.send(libvirt_actor::GetNWFilterXMLReq(id)).await? 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!()
}
} }

View File

@ -238,60 +238,60 @@ pub struct NetworkFilterRuleXML {
pub priority: Option<i32>, pub priority: Option<i32>,
/// Match all protocols /// Match all protocols
#[serde(skip_serializing_if = "Option::is_none")] #[serde(skip_serializing_if = "Vec::is_empty")]
pub all: Option<NetworkFilterRuleProtocolAll>, pub all: Vec<NetworkFilterRuleProtocolAll>,
/// Match mac protocol /// Match mac protocol
#[serde(default, rename = "mac", skip_serializing_if = "Vec::is_empty")] #[serde(default, rename = "mac", skip_serializing_if = "Vec::is_empty")]
pub mac_rules: Vec<NetworkFilterRuleProtocolMac>, pub mac_selectors: Vec<NetworkFilterRuleProtocolMac>,
/// Match arp protocol /// Match arp protocol
#[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")] #[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")]
pub arp_rules: Vec<NetworkFilterRuleProtocolArp>, pub arp_selectors: Vec<NetworkFilterRuleProtocolArp>,
/// Match rarp protocol /// Match rarp protocol
#[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")] #[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")]
pub rarp_rules: Vec<NetworkFilterRuleProtocolArp>, pub rarp_selectors: Vec<NetworkFilterRuleProtocolArp>,
/// Match IPv4 protocol /// Match IPv4 protocol
#[serde(default, rename = "ip", skip_serializing_if = "Vec::is_empty")] #[serde(default, rename = "ip", skip_serializing_if = "Vec::is_empty")]
pub ipv4_rules: Vec<NetworkFilterRuleProtocolIpvx>, pub ipv4_selectors: Vec<NetworkFilterRuleProtocolIpvx>,
/// Match IPv6 protocol /// Match IPv6 protocol
#[serde(default, rename = "ipv6", skip_serializing_if = "Vec::is_empty")] #[serde(default, rename = "ipv6", skip_serializing_if = "Vec::is_empty")]
pub ipv6_rules: Vec<NetworkFilterRuleProtocolIpvx>, pub ipv6_selectors: Vec<NetworkFilterRuleProtocolIpvx>,
/// Match TCP protocol /// Match TCP protocol
#[serde(default, rename = "tcp", skip_serializing_if = "Vec::is_empty")] #[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 /// Match UDP protocol
#[serde(default, rename = "udp", skip_serializing_if = "Vec::is_empty")] #[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 /// Match SCTP protocol
#[serde(default, rename = "sctp", skip_serializing_if = "Vec::is_empty")] #[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 /// 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_rules: Vec<NetworkFilterRuleProtocolLayer4<Ipv4Addr>>, pub imcp_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")]
pub tcp_ipv6_rules: Vec<NetworkFilterRuleProtocolLayer4<Ipv6Addr>>, pub tcp_ipv6_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv6Addr>>,
/// Match UDP IPv6 protocol /// Match UDP IPv6 protocol
#[serde(default, rename = "udp-ipv6", skip_serializing_if = "Vec::is_empty")] #[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 /// Match SCTP IPv6 protocol
#[serde(default, rename = "sctp-ipv6", skip_serializing_if = "Vec::is_empty")] #[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 /// Match ICMP IPv6 protocol
#[serde(default, rename = "icmpv6", skip_serializing_if = "Vec::is_empty")] #[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)] #[derive(serde::Serialize, serde::Deserialize, Debug)]
@ -299,8 +299,12 @@ pub struct NetworkFilterRuleXML {
pub struct NetworkFilterXML { pub struct NetworkFilterXML {
#[serde(rename(serialize = "@name"))] #[serde(rename(serialize = "@name"))]
pub name: String, pub name: String,
#[serde(rename(serialize = "@chain"), default)] #[serde(
pub chain: String, rename(serialize = "@chain"),
skip_serializing_if = "Option::is_none",
default
)]
pub chain: Option<String>,
#[serde( #[serde(
skip_serializing_if = "Option::is_none", skip_serializing_if = "Option::is_none",
rename(serialize = "@priority"), rename(serialize = "@priority"),

View File

@ -1,12 +1,25 @@
use crate::libvirt_lib_structures::nwfilter::{ use crate::libvirt_lib_structures::nwfilter::{
NetworkFilterRuleProtocolAll, NetworkFilterRuleProtocolArp, NetworkFilterRuleProtocolIpvx, NetworkFilterRefXML, NetworkFilterRuleProtocolAll, NetworkFilterRuleProtocolArp,
NetworkFilterRuleProtocolLayer4, NetworkFilterRuleProtocolMac, NetworkFilterXML, NetworkFilterRuleProtocolIpvx, NetworkFilterRuleProtocolLayer4, NetworkFilterRuleProtocolMac,
NetworkFilterRuleXML, NetworkFilterXML,
}; };
use crate::libvirt_lib_structures::XMLUuid; use crate::libvirt_lib_structures::XMLUuid;
use crate::libvirt_rest_structures::LibVirtStructError; use crate::libvirt_rest_structures::LibVirtStructError;
use crate::libvirt_rest_structures::LibVirtStructError::StructureExtraction;
use lazy_regex::regex;
use std::net::{Ipv4Addr, Ipv6Addr}; 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)] #[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)]
#[serde(rename_all = "lowercase")]
pub enum NetworkFilterChainProtocol { pub enum NetworkFilterChainProtocol {
Root, Root,
Mac, Mac,
@ -60,12 +73,8 @@ pub struct NetworkFilterChain {
} }
impl NetworkFilterChain { impl NetworkFilterChain {
pub fn from_xml(xml: &str) -> anyhow::Result<Option<Self>> { pub fn from_xml(xml: &str) -> anyhow::Result<Self> {
if xml.is_empty() { Ok(match xml.split_once('-') {
return Ok(None);
}
Ok(Some(match xml.split_once('-') {
None => Self { None => Self {
protocol: NetworkFilterChainProtocol::from_xml(xml)?, protocol: NetworkFilterChainProtocol::from_xml(xml)?,
suffix: None, suffix: None,
@ -74,7 +83,7 @@ impl NetworkFilterChain {
protocol: NetworkFilterChainProtocol::from_xml(prefix)?, protocol: NetworkFilterChainProtocol::from_xml(prefix)?,
suffix: Some(suffix.to_string()), suffix: Some(suffix.to_string()),
}, },
})) })
} }
pub fn to_xml(&self) -> String { pub fn to_xml(&self) -> String {
@ -88,31 +97,31 @@ impl NetworkFilterChain {
/// 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 {
name: String, name: NetworkFilterName,
chain: Option<NetworkFilterChain>, chain: Option<NetworkFilterChain>,
priority: Option<i32>, priority: Option<i32>,
uuid: Option<XMLUuid>, uuid: Option<XMLUuid>,
/// Referenced filters rules /// Referenced filters rules
join_rules: Vec<String>, join_filters: Vec<NetworkFilterName>,
rules: Vec<NetworkFilterRule>, rules: Vec<NetworkFilterRule>,
} }
impl NetworkFilter { impl NetworkFilter {
fn process_all_rule(_n: &NetworkFilterRuleProtocolAll) -> NetworkFilterSelector { fn lib2rest_process_all_rule(_n: &NetworkFilterRuleProtocolAll) -> NetworkFilterSelector {
NetworkFilterSelector::All NetworkFilterSelector::All
} }
fn process_mac_rule(n: &NetworkFilterRuleProtocolMac) -> NetworkFilterSelector { fn lib2rest_process_mac_rule(n: &NetworkFilterRuleProtocolMac) -> NetworkFilterSelector {
NetworkFilterSelector::Mac { NetworkFilterSelector::Mac(NetworkSelectorMac {
src_mac_addr: n.srcmacaddr.clone(), src_mac_addr: n.srcmacaddr.clone(),
src_mac_mask: n.srcmacmask.clone(), src_mac_mask: n.srcmacmask.clone(),
dst_mac_addr: n.dstmacaddr.clone(), dst_mac_addr: n.dstmacaddr.clone(),
dst_mac_mask: n.dstmacmask.clone(), dst_mac_mask: n.dstmacmask.clone(),
comment: n.comment.clone(), comment: n.comment.clone(),
} })
} }
fn process_arp_rule(n: &NetworkFilterRuleProtocolArp) -> NetworkSelectorARP { fn lib2rest_process_arp_rule(n: &NetworkFilterRuleProtocolArp) -> NetworkSelectorARP {
NetworkSelectorARP { NetworkSelectorARP {
srcmacaddr: n.srcmacaddr.clone(), srcmacaddr: n.srcmacaddr.clone(),
srcmacmask: n.srcmacmask.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 { NetworkFilterSelectorIP {
srcmacaddr: n.srcmacaddr.clone(), srcmacaddr: n.srcmacaddr.clone(),
srcmacmask: n.srcmacmask.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>, n: &NetworkFilterRuleProtocolLayer4<IPv>,
) -> anyhow::Result<NetworkSelectorLayer4<IPv>> { ) -> anyhow::Result<NetworkSelectorLayer4<IPv>> {
Ok(NetworkSelectorLayer4 { 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()); let mut rules = Vec::with_capacity(xml.rules.len());
for rule in &xml.rules { for rule in &xml.rules {
let mut selectors = Vec::new(); let mut selectors = Vec::new();
// All selector // 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 // 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 // ARP - RARP rules
selectors.append( selectors.append(
&mut rule &mut rule
.arp_rules .arp_selectors
.iter() .iter()
.map(|r| NetworkFilterSelector::Arp(Self::process_arp_rule(r))) .map(|r| NetworkFilterSelector::Arp(Self::lib2rest_process_arp_rule(r)))
.collect(), .collect(),
); );
selectors.append( selectors.append(
&mut rule &mut rule
.rarp_rules .rarp_selectors
.iter() .iter()
.map(|r| NetworkFilterSelector::Rarp(Self::process_arp_rule(r))) .map(|r| NetworkFilterSelector::Rarp(Self::lib2rest_process_arp_rule(r)))
.collect(), .collect(),
); );
// IPv4 - IPv6 rules // IPv4 - IPv6 rules
selectors.append( selectors.append(
&mut rule &mut rule
.ipv4_rules .ipv4_selectors
.iter() .iter()
.map(|r| NetworkFilterSelector::IPv4(Self::process_ip_rule(r))) .map(|r| NetworkFilterSelector::IPv4(Self::lib2rest_process_ip_rule(r)))
.collect(), .collect(),
); );
selectors.append( selectors.append(
&mut rule &mut rule
.ipv6_rules .ipv6_selectors
.iter() .iter()
.map(|r| NetworkFilterSelector::IPv6(Self::process_ip_rule(r))) .map(|r| NetworkFilterSelector::IPv6(Self::lib2rest_process_ip_rule(r)))
.collect(), .collect(),
); );
// Layer 4 protocols // Layer 4 protocols
selectors.append( selectors.append(
&mut rule &mut rule
.tcp_rules .tcp_selectors
.iter() .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>>()?, .collect::<Result<Vec<_>, anyhow::Error>>()?,
); );
selectors.append( selectors.append(
&mut rule &mut rule
.udp_rules .udp_selectors
.iter() .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>>()?, .collect::<Result<Vec<_>, anyhow::Error>>()?,
); );
selectors.append( selectors.append(
&mut rule &mut rule
.sctp_rules .sctp_selectors
.iter() .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>>()?, .collect::<Result<Vec<_>, anyhow::Error>>()?,
); );
selectors.append( selectors.append(
&mut rule &mut rule
.imcp_rules .imcp_selectors
.iter() .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>>()?, .collect::<Result<Vec<_>, anyhow::Error>>()?,
); );
selectors.append( selectors.append(
&mut rule &mut rule
.tcp_ipv6_rules .tcp_ipv6_selectors
.iter() .iter()
.map(|r| { .map(|r| {
Ok(NetworkFilterSelector::TCPipv6(Self::process_layer4_rule( Ok(NetworkFilterSelector::TCPipv6(
r, Self::lib2rest_process_layer4_rule(r)?,
)?)) ))
}) })
.collect::<Result<Vec<_>, anyhow::Error>>()?, .collect::<Result<Vec<_>, anyhow::Error>>()?,
); );
selectors.append( selectors.append(
&mut rule &mut rule
.udp_ipv6_rules .udp_ipv6_selectors
.iter() .iter()
.map(|r| { .map(|r| {
Ok(NetworkFilterSelector::UDPipv6(Self::process_layer4_rule( Ok(NetworkFilterSelector::UDPipv6(
r, Self::lib2rest_process_layer4_rule(r)?,
)?)) ))
}) })
.collect::<Result<Vec<_>, anyhow::Error>>()?, .collect::<Result<Vec<_>, anyhow::Error>>()?,
); );
selectors.append( selectors.append(
&mut rule &mut rule
.sctp_ipv6_rules .sctp_ipv6_selectors
.iter() .iter()
.map(|r| { .map(|r| {
Ok(NetworkFilterSelector::SCTPipv6(Self::process_layer4_rule( Ok(NetworkFilterSelector::SCTPipv6(
r, Self::lib2rest_process_layer4_rule(r)?,
)?)) ))
}) })
.collect::<Result<Vec<_>, anyhow::Error>>()?, .collect::<Result<Vec<_>, anyhow::Error>>()?,
); );
selectors.append( selectors.append(
&mut rule &mut rule
.imcp_ipv6_rules .imcp_ipv6_selectors
.iter() .iter()
.map(|r| { .map(|r| {
Ok(NetworkFilterSelector::ICMPipv6(Self::process_layer4_rule( Ok(NetworkFilterSelector::ICMPipv6(
r, Self::lib2rest_process_layer4_rule(r)?,
)?)) ))
}) })
.collect::<Result<Vec<_>, anyhow::Error>>()?, .collect::<Result<Vec<_>, anyhow::Error>>()?,
); );
@ -289,21 +326,123 @@ impl NetworkFilter {
} }
Ok(Self { Ok(Self {
name: xml.name, name: NetworkFilterName(xml.name),
uuid: xml.uuid, uuid: xml.uuid,
chain: NetworkFilterChain::from_xml(&xml.chain)?, chain: xml
.chain
.as_deref()
.map(NetworkFilterChain::from_xml)
.transpose()?,
priority: xml.priority, priority: xml.priority,
join_rules: xml join_filters: xml
.filterrefs .filterrefs
.iter() .iter()
.map(|i| i.filter.to_string()) .map(|i| NetworkFilterName(i.filter.to_string()))
.collect(), .collect(),
rules, 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)] #[derive(serde::Serialize, serde::Deserialize, Debug, Copy, Clone)]
#[serde(rename_all = "lowercase")]
pub enum NetworkFilterAction { pub enum NetworkFilterAction {
/// matching the rule silently discards the packet with no further analysis /// matching the rule silently discards the packet with no further analysis
Drop, Drop,
@ -348,6 +487,7 @@ impl NetworkFilterAction {
} }
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
#[serde(rename_all = "lowercase")]
pub enum NetworkFilterDirection { pub enum NetworkFilterDirection {
In, In,
Out, Out,
@ -430,6 +570,15 @@ pub struct NetworkFilterSelectorIP {
comment: Option<String>, 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)] #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct NetworkSelectorARP { pub struct NetworkSelectorARP {
srcmacaddr: Option<String>, srcmacaddr: Option<String>,
@ -467,15 +616,10 @@ pub struct NetworkSelectorLayer4<IPv> {
} }
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum NetworkFilterSelector { pub enum NetworkFilterSelector {
All, All,
Mac { Mac(NetworkSelectorMac),
src_mac_addr: Option<String>,
src_mac_mask: Option<String>,
dst_mac_addr: Option<String>,
dst_mac_mask: Option<String>,
comment: Option<String>,
},
Arp(NetworkSelectorARP), Arp(NetworkSelectorARP),
Rarp(NetworkSelectorARP), Rarp(NetworkSelectorARP),
IPv4(NetworkFilterSelectorIP), IPv4(NetworkFilterSelectorIP),

View File

@ -240,6 +240,10 @@ async fn main() -> std::io::Result<()> {
web::get().to(network_controller::stop), web::get().to(network_controller::stop),
) )
// Network filters controller // Network filters controller
.route(
"/api/nwfilter/create",
web::post().to(nwfilter_controller::create),
)
.route( .route(
"/api/nwfilter/list", "/api/nwfilter/list",
web::get().to(nwfilter_controller::list), web::get().to(nwfilter_controller::list),
@ -248,6 +252,10 @@ async fn main() -> std::io::Result<()> {
"/api/nwfilter/{uid}", "/api/nwfilter/{uid}",
web::get().to(nwfilter_controller::get_single), web::get().to(nwfilter_controller::get_single),
) )
.route(
"/api/nwfilter/{uid}",
web::put().to(nwfilter_controller::update),
)
// Static assets // Static assets
.route("/", web::get().to(static_controller::root_index)) .route("/", web::get().to(static_controller::root_index))
.route( .route(

View File

@ -17,3 +17,22 @@ pub fn extract_ipv6(ip: IpAddr) -> Ipv6Addr {
IpAddr::V6(i) => i, 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"));
}
}