Parse NW filters XML structure
This commit is contained in:
parent
b4f765d486
commit
3849b0d51d
@ -1,5 +1,7 @@
|
|||||||
use crate::app_config::AppConfig;
|
use crate::app_config::AppConfig;
|
||||||
use crate::libvirt_lib_structures::{DomainState, DomainXML, NetworkXML, XMLUuid};
|
use crate::libvirt_lib_structures::{
|
||||||
|
DomainState, DomainXML, NetworkFilterXML, NetworkXML, XMLUuid,
|
||||||
|
};
|
||||||
use crate::libvirt_rest_structures::*;
|
use crate::libvirt_rest_structures::*;
|
||||||
use actix::{Actor, Context, Handler, Message};
|
use actix::{Actor, Context, Handler, Message};
|
||||||
use image::ImageOutputFormat;
|
use image::ImageOutputFormat;
|
||||||
@ -7,6 +9,7 @@ use std::io::Cursor;
|
|||||||
use virt::connect::Connect;
|
use virt::connect::Connect;
|
||||||
use virt::domain::Domain;
|
use virt::domain::Domain;
|
||||||
use virt::network::Network;
|
use virt::network::Network;
|
||||||
|
use virt::nwfilter::NWFilter;
|
||||||
use virt::stream::Stream;
|
use virt::stream::Stream;
|
||||||
use virt::sys;
|
use virt::sys;
|
||||||
use virt::sys::VIR_DOMAIN_XML_SECURE;
|
use virt::sys::VIR_DOMAIN_XML_SECURE;
|
||||||
@ -549,3 +552,39 @@ impl Handler<StopNetwork> for LibVirtActor {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "anyhow::Result<Vec<XMLUuid>>")]
|
||||||
|
pub struct GetNWFiltersListReq;
|
||||||
|
|
||||||
|
impl Handler<GetNWFiltersListReq> for LibVirtActor {
|
||||||
|
type Result = anyhow::Result<Vec<XMLUuid>>;
|
||||||
|
|
||||||
|
fn handle(&mut self, _msg: GetNWFiltersListReq, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
log::debug!("Get full list of network filters");
|
||||||
|
let networks = self.m.list_all_nw_filters(0)?;
|
||||||
|
let mut ids = Vec::with_capacity(networks.len());
|
||||||
|
|
||||||
|
for d in networks {
|
||||||
|
ids.push(XMLUuid::parse_from_str(&d.get_uuid_string()?)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(ids)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Message)]
|
||||||
|
#[rtype(result = "anyhow::Result<NetworkFilterXML>")]
|
||||||
|
pub struct GetNWFilterXMLReq(pub XMLUuid);
|
||||||
|
|
||||||
|
impl Handler<GetNWFilterXMLReq> for LibVirtActor {
|
||||||
|
type Result = anyhow::Result<NetworkFilterXML>;
|
||||||
|
|
||||||
|
fn handle(&mut self, msg: GetNWFilterXMLReq, _ctx: &mut Self::Context) -> Self::Result {
|
||||||
|
log::debug!("Get network filter XML:\n{}", msg.0.as_string());
|
||||||
|
let filter = NWFilter::lookup_by_uuid_string(&self.m, &msg.0.as_string())?;
|
||||||
|
let xml = filter.get_xml_desc(0)?;
|
||||||
|
log::debug!("XML = {}", xml);
|
||||||
|
NetworkFilterXML::parse_xml(xml)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -46,3 +46,31 @@ pub const DISK_SIZE_MAX: usize = 1000 * 1000 * 2;
|
|||||||
|
|
||||||
/// Network mac address default prefix
|
/// Network mac address default prefix
|
||||||
pub const NET_MAC_ADDR_PREFIX: &str = "52:54:00";
|
pub const NET_MAC_ADDR_PREFIX: &str = "52:54:00";
|
||||||
|
|
||||||
|
/// Built-in network filter rules
|
||||||
|
pub const BUILTIN_NETWORK_FILTER_RULES: [&str; 24] = [
|
||||||
|
"allow-arp",
|
||||||
|
"allow-dhcp",
|
||||||
|
"allow-dhcp-server",
|
||||||
|
"allow-dhcpv6",
|
||||||
|
"allow-dhcpv6-server",
|
||||||
|
"allow-incoming-ipv4",
|
||||||
|
"allow-incoming-ipv6",
|
||||||
|
"allow-ipv4",
|
||||||
|
"allow-ipv6",
|
||||||
|
"clean-traffic",
|
||||||
|
"clean-traffic-gateway",
|
||||||
|
"no-arp-ip-spoofing",
|
||||||
|
"no-arp-mac-spoofing",
|
||||||
|
"no-arp-spoofing",
|
||||||
|
"no-ip-multicast",
|
||||||
|
"no-ip-spoofing",
|
||||||
|
"no-ipv6-multicast",
|
||||||
|
"no-ipv6-spoofing",
|
||||||
|
"no-mac-broadcast",
|
||||||
|
"no-mac-spoofing",
|
||||||
|
"no-other-l2-traffic",
|
||||||
|
"no-other-rarp-traffic",
|
||||||
|
"qemu-announce-self",
|
||||||
|
"qemu-announce-self-rarp",
|
||||||
|
];
|
||||||
|
@ -8,6 +8,7 @@ use std::io::ErrorKind;
|
|||||||
pub mod auth_controller;
|
pub mod auth_controller;
|
||||||
pub mod iso_controller;
|
pub mod iso_controller;
|
||||||
pub mod network_controller;
|
pub mod network_controller;
|
||||||
|
pub mod nwfilter_controller;
|
||||||
pub mod server_controller;
|
pub mod server_controller;
|
||||||
pub mod static_controller;
|
pub mod static_controller;
|
||||||
pub mod vm_controller;
|
pub mod vm_controller;
|
||||||
|
36
virtweb_backend/src/controllers/nwfilter_controller.rs
Normal file
36
virtweb_backend/src/controllers/nwfilter_controller.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
use crate::controllers::{HttpResult, LibVirtReq};
|
||||||
|
use crate::libvirt_lib_structures::XMLUuid;
|
||||||
|
use actix_web::{web, HttpResponse};
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct NetworkFilterID {
|
||||||
|
uid: XMLUuid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the list of network filters
|
||||||
|
pub async fn list(client: LibVirtReq) -> HttpResult {
|
||||||
|
let networks = match client.get_full_network_filters_list().await {
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("Failed to get the list of network filters! {e}");
|
||||||
|
return Ok(HttpResponse::InternalServerError()
|
||||||
|
.json(format!("Failed to get the list of networks! {e}")));
|
||||||
|
}
|
||||||
|
Ok(l) => l,
|
||||||
|
};
|
||||||
|
|
||||||
|
/*let networks = networks
|
||||||
|
.into_iter()
|
||||||
|
.map(|n| NetworkInfo::from_xml(n).unwrap())
|
||||||
|
.collect::<Vec<_>>();*/
|
||||||
|
// TODO : turn into lib structure
|
||||||
|
println!("{:#?}", networks);
|
||||||
|
|
||||||
|
Ok(HttpResponse::Ok().body(format!("{:#?}", networks)))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the information about a single network filter
|
||||||
|
pub async fn get_single(client: LibVirtReq, req: web::Path<NetworkFilterID>) -> HttpResult {
|
||||||
|
let nwfilter = client.get_single_network_filter(req.uid).await?;
|
||||||
|
// TODO : turn into lib structure
|
||||||
|
Ok(HttpResponse::Ok().body(format!("{:#?}", nwfilter)))
|
||||||
|
}
|
@ -16,6 +16,7 @@ struct StaticConfig {
|
|||||||
iso_mimetypes: &'static [&'static str],
|
iso_mimetypes: &'static [&'static str],
|
||||||
net_mac_prefix: &'static str,
|
net_mac_prefix: &'static str,
|
||||||
constraints: ServerConstraints,
|
constraints: ServerConstraints,
|
||||||
|
builtin_network_rules: &'static [&'static str],
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(serde::Serialize)]
|
#[derive(serde::Serialize)]
|
||||||
@ -45,6 +46,7 @@ pub async fn static_config(local_auth: LocalAuthEnabled) -> impl Responder {
|
|||||||
oidc_auth_enabled: !AppConfig::get().disable_oidc,
|
oidc_auth_enabled: !AppConfig::get().disable_oidc,
|
||||||
iso_mimetypes: &constants::ALLOWED_ISO_MIME_TYPES,
|
iso_mimetypes: &constants::ALLOWED_ISO_MIME_TYPES,
|
||||||
net_mac_prefix: constants::NET_MAC_ADDR_PREFIX,
|
net_mac_prefix: constants::NET_MAC_ADDR_PREFIX,
|
||||||
|
builtin_network_rules: &constants::BUILTIN_NETWORK_FILTER_RULES,
|
||||||
constraints: ServerConstraints {
|
constraints: ServerConstraints {
|
||||||
iso_max_size: constants::ISO_MAX_SIZE,
|
iso_max_size: constants::ISO_MAX_SIZE,
|
||||||
|
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
use crate::actors::libvirt_actor;
|
use crate::actors::libvirt_actor;
|
||||||
use crate::actors::libvirt_actor::LibVirtActor;
|
use crate::actors::libvirt_actor::LibVirtActor;
|
||||||
use crate::libvirt_lib_structures::{DomainState, DomainXML, NetworkXML, XMLUuid};
|
use crate::libvirt_lib_structures::{
|
||||||
|
DomainState, DomainXML, NetworkFilterXML, NetworkXML, XMLUuid,
|
||||||
|
};
|
||||||
use crate::libvirt_rest_structures::{HypervisorInfo, NetworkInfo, VMInfo};
|
use crate::libvirt_rest_structures::{HypervisorInfo, NetworkInfo, VMInfo};
|
||||||
use actix::Addr;
|
use actix::Addr;
|
||||||
|
|
||||||
@ -165,4 +167,19 @@ impl LibVirtClient {
|
|||||||
pub async fn stop_network(&self, id: XMLUuid) -> anyhow::Result<()> {
|
pub async fn stop_network(&self, id: XMLUuid) -> anyhow::Result<()> {
|
||||||
self.0.send(libvirt_actor::StopNetwork(id)).await?
|
self.0.send(libvirt_actor::StopNetwork(id)).await?
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the full list of network filters
|
||||||
|
pub async fn get_full_network_filters_list(&self) -> anyhow::Result<Vec<NetworkFilterXML>> {
|
||||||
|
let ids = self.0.send(libvirt_actor::GetNWFiltersListReq).await??;
|
||||||
|
let mut info = Vec::with_capacity(ids.len());
|
||||||
|
for id in ids {
|
||||||
|
info.push(self.get_single_network_filter(id).await?)
|
||||||
|
}
|
||||||
|
Ok(info)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the information about a single domain
|
||||||
|
pub async fn get_single_network_filter(&self, id: XMLUuid) -> anyhow::Result<NetworkFilterXML> {
|
||||||
|
self.0.send(libvirt_actor::GetNWFilterXMLReq(id)).await?
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
use std::net::{IpAddr, Ipv4Addr};
|
use std::net::{IpAddr, Ipv4Addr};
|
||||||
|
|
||||||
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
|
#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, Debug)]
|
||||||
@ -548,3 +549,316 @@ impl NetworkXML {
|
|||||||
Ok(network_xml)
|
Ok(network_xml)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||||
|
#[serde(rename = "filterref")]
|
||||||
|
pub struct NetworkFilterRefXML {
|
||||||
|
#[serde(rename(serialize = "@filter"))]
|
||||||
|
pub filter: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||||
|
#[serde(rename = "all")]
|
||||||
|
pub struct NetworkFilterRuleProtocolAll {}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||||
|
#[serde(rename = "mac")]
|
||||||
|
pub struct NetworkFilterRuleProtocolMac {
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcmacaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcmacaddr: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcmacmask"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcmacmask: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstmacaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstmacaddr: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstmacmask"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstmacmask: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@comment"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
comment: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||||
|
#[serde(rename = "arp")]
|
||||||
|
pub struct NetworkFilterRuleProtocolArp {
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcmacaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcmacaddr: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcmacmask"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcmacmask: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstmacaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstmacaddr: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstmacmask"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstmacmask: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@arpsrcipaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
arpsrcipaddr: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@arpsrcipmask"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
arpsrcipmask: Option<u8>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@arpdstipaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
arpdstipaddr: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@arpdstipmask"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
arpdstipmask: Option<u8>,
|
||||||
|
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@comment"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
comment: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||||
|
#[serde(rename = "ipvx")]
|
||||||
|
pub struct NetworkFilterRuleProtocolIpvx {
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcmacaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcmacaddr: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcmacmask"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcmacmask: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstmacaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstmacaddr: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstmacmask"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstmacmask: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcipaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcipaddr: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcipmask"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcipmask: Option<u8>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstipaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstipaddr: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstipmask"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstipmask: Option<u8>,
|
||||||
|
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@comment"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
comment: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||||
|
#[serde(rename = "layer4")]
|
||||||
|
pub struct NetworkFilterRuleProtocolLayer4 {
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcmacaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcmacaddr: Option<String>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcipaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcipaddr: Option<IpAddr>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcipmask"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcipmask: Option<u8>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstipaddr"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstipaddr: Option<IpAddr>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstipmask"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstipmask: Option<u8>,
|
||||||
|
/// Start of range of source IP address
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcipfrom"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcipfrom: Option<IpAddr>,
|
||||||
|
/// End of range of source IP address
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcipto"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcipto: Option<IpAddr>,
|
||||||
|
/// Start of range of destination IP address
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstipfrom"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstipfrom: Option<IpAddr>,
|
||||||
|
/// End of range of destination IP address
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstipto"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstipto: Option<IpAddr>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcportstart"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcportstart: Option<u16>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@srcportend"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
srcportend: Option<u16>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstportstart"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstportstart: Option<u16>,
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@dstportend"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
dstportend: Option<u16>,
|
||||||
|
#[serde(rename(serialize = "@state"), skip_serializing_if = "Option::is_none")]
|
||||||
|
state: Option<String>,
|
||||||
|
|
||||||
|
#[serde(
|
||||||
|
rename(serialize = "@comment"),
|
||||||
|
skip_serializing_if = "Option::is_none"
|
||||||
|
)]
|
||||||
|
comment: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||||
|
#[serde(rename = "rule")]
|
||||||
|
pub struct NetworkFilterRuleXML {
|
||||||
|
#[serde(rename(serialize = "@action"))]
|
||||||
|
pub action: String,
|
||||||
|
#[serde(rename(serialize = "@direction"))]
|
||||||
|
pub direction: String,
|
||||||
|
#[serde(rename(serialize = "@priority"))]
|
||||||
|
pub priority: Option<i32>,
|
||||||
|
|
||||||
|
/// Match all protocols
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub all: Option<NetworkFilterRuleProtocolAll>,
|
||||||
|
|
||||||
|
/// Match mac protocol
|
||||||
|
#[serde(default, rename = "mac", skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub mac_rules: Vec<NetworkFilterRuleProtocolMac>,
|
||||||
|
|
||||||
|
/// Match arp protocol
|
||||||
|
#[serde(default, rename = "arp", skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub arp_rules: Vec<NetworkFilterRuleProtocolArp>,
|
||||||
|
|
||||||
|
/// Match IPv4 protocol
|
||||||
|
#[serde(default, rename = "ip", skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub ipv4_rules: Vec<NetworkFilterRuleProtocolIpvx>,
|
||||||
|
|
||||||
|
/// Match IPv6 protocol
|
||||||
|
#[serde(default, rename = "ipv6", skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub ipv6_rules: Vec<NetworkFilterRuleProtocolIpvx>,
|
||||||
|
|
||||||
|
/// Match TCP protocol
|
||||||
|
#[serde(default, rename = "tcp", skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub tcp_rules: Vec<NetworkFilterRuleProtocolLayer4>,
|
||||||
|
|
||||||
|
/// Match UDP protocol
|
||||||
|
#[serde(default, rename = "udp", skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub udp_rules: Vec<NetworkFilterRuleProtocolLayer4>,
|
||||||
|
|
||||||
|
/// Match SCTP protocol
|
||||||
|
#[serde(default, rename = "sctp", skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub sctp_rules: Vec<NetworkFilterRuleProtocolLayer4>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(serde::Serialize, serde::Deserialize, Debug)]
|
||||||
|
#[serde(rename = "filter")]
|
||||||
|
pub struct NetworkFilterXML {
|
||||||
|
#[serde(rename(serialize = "@name"))]
|
||||||
|
pub name: String,
|
||||||
|
#[serde(rename(serialize = "@chain"), default)]
|
||||||
|
pub chain: String,
|
||||||
|
#[serde(
|
||||||
|
skip_serializing_if = "Option::is_none",
|
||||||
|
rename(serialize = "@priority"),
|
||||||
|
default
|
||||||
|
)]
|
||||||
|
pub priority: Option<i32>,
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub uuid: Option<XMLUuid>,
|
||||||
|
#[serde(default, rename = "filterref", skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub filterrefs: Vec<NetworkFilterRefXML>,
|
||||||
|
#[serde(default, rename = "rule", skip_serializing_if = "Vec::is_empty")]
|
||||||
|
pub rules: Vec<NetworkFilterRuleXML>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NetworkFilterXML {
|
||||||
|
pub fn parse_xml<D: Display>(xml: D) -> anyhow::Result<Self> {
|
||||||
|
let xml = xml.to_string();
|
||||||
|
|
||||||
|
// We need to put all filter refs at the same location
|
||||||
|
let mut filter_refs = Vec::new();
|
||||||
|
let xml = lazy_regex::regex_replace_all!(r#"<filterref.*/>"#, &xml, |r: &str| {
|
||||||
|
filter_refs.push(r.to_string());
|
||||||
|
|
||||||
|
if r.contains('\n') {
|
||||||
|
log::warn!("A filterref contain a new line. This is a symptom of a new unsupported child attribute of <filterref /> object!");
|
||||||
|
}
|
||||||
|
|
||||||
|
""
|
||||||
|
});
|
||||||
|
|
||||||
|
let filter_refs = filter_refs.join("\n");
|
||||||
|
let xml = xml.replace("</filter>", &format!("{filter_refs}</filter>"));
|
||||||
|
log::debug!("Effective NW filter rule parsed: {xml}");
|
||||||
|
|
||||||
|
Ok(serde_xml_rs::from_str(&xml)?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -700,6 +700,144 @@ impl NetworkInfo {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub enum NetworkFilterChain {
|
||||||
|
Root,
|
||||||
|
Mac,
|
||||||
|
STP,
|
||||||
|
VLAN,
|
||||||
|
ARP,
|
||||||
|
RARP,
|
||||||
|
IPv4,
|
||||||
|
IPv6,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Network filter definition
|
||||||
|
pub struct NetworkFilter {
|
||||||
|
name: String,
|
||||||
|
chain: Option<NetworkFilterChain>,
|
||||||
|
priority: Option<i32>,
|
||||||
|
uuid: Option<XMLUuid>,
|
||||||
|
/// Referenced filters rules
|
||||||
|
join_rules: Vec<String>,
|
||||||
|
rules: Vec<NetworkFilterRule>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum NetworkFilterAction {
|
||||||
|
/// matching the rule silently discards the packet with no further analysis
|
||||||
|
Drop,
|
||||||
|
/// matching the rule generates an ICMP reject message with no further analysis
|
||||||
|
Reject,
|
||||||
|
/// matching the rule accepts the packet with no further analysis
|
||||||
|
Accept,
|
||||||
|
/// matching the rule passes this filter, but returns control to the calling filter for further
|
||||||
|
/// analysis
|
||||||
|
Return,
|
||||||
|
/// matching the rule goes on to the next rule for further analysis
|
||||||
|
Continue,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum NetworkFilterDirection {
|
||||||
|
In,
|
||||||
|
Out,
|
||||||
|
InOut,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Layer4State {
|
||||||
|
NEW,
|
||||||
|
ESTABLISHED,
|
||||||
|
RELATED,
|
||||||
|
INVALID,
|
||||||
|
NONE,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Layer4Type {
|
||||||
|
TCP,
|
||||||
|
UDP,
|
||||||
|
SCTP,
|
||||||
|
ICMP,
|
||||||
|
TCPipv6,
|
||||||
|
UDPipv6,
|
||||||
|
SCTPipv6,
|
||||||
|
ICMPipv6,
|
||||||
|
}
|
||||||
|
|
||||||
|
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>,
|
||||||
|
},
|
||||||
|
Arp {
|
||||||
|
srcmacaddr: Option<String>,
|
||||||
|
srcmacmask: Option<String>,
|
||||||
|
dstmacaddr: Option<String>,
|
||||||
|
dstmacmask: Option<String>,
|
||||||
|
arpsrcipaddr: Option<IpAddr>,
|
||||||
|
arpsrcipmask: Option<u8>,
|
||||||
|
arpdstipaddr: Option<IpAddr>,
|
||||||
|
arpdstipmask: Option<u8>,
|
||||||
|
comment: Option<String>,
|
||||||
|
},
|
||||||
|
IPv4 {
|
||||||
|
srcmacaddr: Option<String>,
|
||||||
|
srcmacmask: Option<String>,
|
||||||
|
dstmacaddr: Option<String>,
|
||||||
|
dstmacmask: Option<String>,
|
||||||
|
srcipaddr: Option<Ipv4Addr>,
|
||||||
|
srcipmask: Option<u8>,
|
||||||
|
dstipaddr: Option<Ipv4Addr>,
|
||||||
|
dstipmask: Option<u8>,
|
||||||
|
comment: Option<String>,
|
||||||
|
},
|
||||||
|
IPv6 {
|
||||||
|
srcmacaddr: Option<String>,
|
||||||
|
srcmacmask: Option<String>,
|
||||||
|
dstmacaddr: Option<String>,
|
||||||
|
dstmacmask: Option<String>,
|
||||||
|
srcipaddr: Option<Ipv6Addr>,
|
||||||
|
srcipmask: Option<u8>,
|
||||||
|
dstipaddr: Option<Ipv6Addr>,
|
||||||
|
dstipmask: Option<u8>,
|
||||||
|
comment: Option<String>,
|
||||||
|
},
|
||||||
|
Layer4 {
|
||||||
|
r#type: Layer4Type,
|
||||||
|
srcmacaddr: Option<String>,
|
||||||
|
srcipaddr: Option<IpAddr>,
|
||||||
|
srcipmask: Option<u8>,
|
||||||
|
dstipaddr: Option<IpAddr>,
|
||||||
|
dstipmask: Option<u8>,
|
||||||
|
/// Start of range of source IP address
|
||||||
|
srcipfrom: Option<IpAddr>,
|
||||||
|
/// End of range of source IP address
|
||||||
|
srcipto: Option<IpAddr>,
|
||||||
|
/// Start of range of destination IP address
|
||||||
|
dstipfrom: Option<IpAddr>,
|
||||||
|
/// End of range of destination IP address
|
||||||
|
dstipto: Option<IpAddr>,
|
||||||
|
srcportstart: Option<u16>,
|
||||||
|
srcportend: Option<u16>,
|
||||||
|
dstportstart: Option<u16>,
|
||||||
|
dstportend: Option<u16>,
|
||||||
|
state: Option<Layer4State>,
|
||||||
|
comment: Option<String>,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct NetworkFilterRule {
|
||||||
|
action: NetworkFilterAction,
|
||||||
|
direction: NetworkFilterDirection,
|
||||||
|
/// optional; the priority of the rule controls the order in which the rule will be instantiated
|
||||||
|
/// relative to other rules
|
||||||
|
///
|
||||||
|
/// Valid values are in the range of -1000 to 1000.
|
||||||
|
priority: Option<i32>,
|
||||||
|
selectors: Vec<NetworkFilterSelector>,
|
||||||
|
}
|
||||||
|
|
||||||
fn extract_ipv4(ip: IpAddr) -> Ipv4Addr {
|
fn extract_ipv4(ip: IpAddr) -> Ipv4Addr {
|
||||||
match ip {
|
match ip {
|
||||||
IpAddr::V4(i) => i,
|
IpAddr::V4(i) => i,
|
||||||
|
@ -22,8 +22,8 @@ use virtweb_backend::constants::{
|
|||||||
MAX_INACTIVITY_DURATION, MAX_SESSION_DURATION, SESSION_COOKIE_NAME,
|
MAX_INACTIVITY_DURATION, MAX_SESSION_DURATION, SESSION_COOKIE_NAME,
|
||||||
};
|
};
|
||||||
use virtweb_backend::controllers::{
|
use virtweb_backend::controllers::{
|
||||||
auth_controller, iso_controller, network_controller, server_controller, static_controller,
|
auth_controller, iso_controller, network_controller, nwfilter_controller, server_controller,
|
||||||
vm_controller,
|
static_controller, vm_controller,
|
||||||
};
|
};
|
||||||
use virtweb_backend::libvirt_client::LibVirtClient;
|
use virtweb_backend::libvirt_client::LibVirtClient;
|
||||||
use virtweb_backend::middlewares::auth_middleware::AuthChecker;
|
use virtweb_backend::middlewares::auth_middleware::AuthChecker;
|
||||||
@ -239,6 +239,15 @@ async fn main() -> std::io::Result<()> {
|
|||||||
"/api/network/{uid}/stop",
|
"/api/network/{uid}/stop",
|
||||||
web::get().to(network_controller::stop),
|
web::get().to(network_controller::stop),
|
||||||
)
|
)
|
||||||
|
// Network filters controller
|
||||||
|
.route(
|
||||||
|
"/api/nwfilter/list",
|
||||||
|
web::get().to(nwfilter_controller::list),
|
||||||
|
)
|
||||||
|
.route(
|
||||||
|
"/api/nwfilter/{uid}",
|
||||||
|
web::get().to(nwfilter_controller::get_single),
|
||||||
|
)
|
||||||
// Static assets
|
// Static assets
|
||||||
.route("/", web::get().to(static_controller::root_index))
|
.route("/", web::get().to(static_controller::root_index))
|
||||||
.route(
|
.route(
|
||||||
|
Loading…
Reference in New Issue
Block a user