WIP REST routes to create / update Network filters
This commit is contained in:
parent
61c567846d
commit
7b74e7b75a
@ -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"))
|
||||||
|
}
|
||||||
|
@ -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!()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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"),
|
||||||
|
@ -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),
|
||||||
|
@ -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(
|
||||||
|
@ -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"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user