diff --git a/virtweb_backend/src/libvirt_lib_structures/nwfilter.rs b/virtweb_backend/src/libvirt_lib_structures/nwfilter.rs index 623aa7b..ff5fdea 100644 --- a/virtweb_backend/src/libvirt_lib_structures/nwfilter.rs +++ b/virtweb_backend/src/libvirt_lib_structures/nwfilter.rs @@ -11,7 +11,10 @@ pub struct NetworkFilterRefXML { #[derive(serde::Serialize, serde::Deserialize, Debug)] #[serde(rename = "all")] -pub struct NetworkFilterRuleProtocolAll {} +pub struct NetworkFilterRuleProtocolAllXML { + #[serde(rename = "@comment", skip_serializing_if = "Option::is_none")] + pub comment: Option, +} #[derive(serde::Serialize, serde::Deserialize, Debug)] #[serde(rename = "mac")] @@ -128,7 +131,11 @@ pub struct NetworkFilterRuleXML { /// Match all protocols #[serde(default, rename = "all", skip_serializing_if = "Vec::is_empty")] - pub all_selectors: Vec, + pub all_selectors: Vec, + + /// Match all ipv6 protocols + #[serde(default, rename = "all-ipv6", skip_serializing_if = "Vec::is_empty")] + pub all_ipv6_selectors: Vec, /// Match mac protocol #[serde(default, rename = "mac", skip_serializing_if = "Vec::is_empty")] diff --git a/virtweb_backend/src/libvirt_rest_structures/nw_filter.rs b/virtweb_backend/src/libvirt_rest_structures/nw_filter.rs index 29233f2..755ba0e 100644 --- a/virtweb_backend/src/libvirt_rest_structures/nw_filter.rs +++ b/virtweb_backend/src/libvirt_rest_structures/nw_filter.rs @@ -1,5 +1,5 @@ use crate::libvirt_lib_structures::nwfilter::{ - NetworkFilterRefXML, NetworkFilterRuleProtocolAll, NetworkFilterRuleProtocolArpXML, + NetworkFilterRefXML, NetworkFilterRuleProtocolAllXML, NetworkFilterRuleProtocolArpXML, NetworkFilterRuleProtocolIpvx, NetworkFilterRuleProtocolLayer4, NetworkFilterRuleProtocolMac, NetworkFilterRuleXML, NetworkFilterXML, }; @@ -308,6 +308,11 @@ impl Layer4State { } } +#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] +pub struct NetworkSelectorAll { + comment: Option, +} + #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] pub struct NetworkSelectorMac { src_mac_addr: Option, @@ -369,7 +374,7 @@ pub struct NetworkFilterSelectorLayer4 { #[derive(serde::Serialize, serde::Deserialize, Debug, Clone)] #[serde(tag = "type", rename_all = "lowercase")] pub enum NetworkFilterSelector { - All, + All(NetworkSelectorAll), Mac(NetworkSelectorMac), Arp(NetworkSelectorARP), Rarp(NetworkSelectorARP), @@ -379,6 +384,7 @@ pub enum NetworkFilterSelector { UDP(NetworkFilterSelectorLayer4), SCTP(NetworkFilterSelectorLayer4), ICMP(NetworkFilterSelectorLayer4), + Allipv6(NetworkSelectorAll), TCPipv6(NetworkFilterSelectorLayer4), UDPipv6(NetworkFilterSelectorLayer4), SCTPipv6(NetworkFilterSelectorLayer4), @@ -410,8 +416,10 @@ pub struct NetworkFilter { } impl NetworkFilter { - fn lib2rest_process_all_rule(_n: &NetworkFilterRuleProtocolAll) -> NetworkFilterSelector { - NetworkFilterSelector::All + fn lib2rest_process_all_rule(n: &NetworkFilterRuleProtocolAllXML) -> NetworkSelectorAll { + NetworkSelectorAll { + comment: n.comment.clone(), + } } fn lib2rest_process_mac_rule(n: &NetworkFilterRuleProtocolMac) -> NetworkFilterSelector { @@ -481,16 +489,24 @@ impl NetworkFilter { for rule in &xml.rules { let mut selectors = Vec::new(); - // All selector + // All selectors selectors.append( &mut rule .all_selectors .iter() - .map(Self::lib2rest_process_all_rule) + .map(|r| NetworkFilterSelector::All(Self::lib2rest_process_all_rule(r))) .collect(), ); - // Mac rules + selectors.append( + &mut rule + .all_ipv6_selectors + .iter() + .map(|r| NetworkFilterSelector::Allipv6(Self::lib2rest_process_all_rule(r))) + .collect(), + ); + + // Mac selectors selectors.append( &mut rule .mac_selectors @@ -499,7 +515,7 @@ impl NetworkFilter { .collect(), ); - // ARP - RARP rules + // ARP - RARP selectors selectors.append( &mut rule .arp_selectors @@ -515,7 +531,7 @@ impl NetworkFilter { .collect(), ); - // IPv4 - IPv6 rules + // IPv4 - IPv6 selectors selectors.append( &mut rule .ipv4_selectors @@ -531,7 +547,7 @@ impl NetworkFilter { .collect(), ); - // Layer 4 protocols + // Layer 4 protocols selectors selectors.append( &mut rule .tcp_selectors @@ -648,6 +664,14 @@ impl NetworkFilter { }) } + fn rest2lib_process_all_selector( + selector: &NetworkSelectorAll, + ) -> anyhow::Result { + Ok(NetworkFilterRuleProtocolAllXML { + comment: extract_nw_filter_comment(&selector.comment)?, + }) + } + fn rest2lib_process_arp_selector( selector: &NetworkSelectorARP, ) -> anyhow::Result { @@ -714,8 +738,16 @@ impl NetworkFilter { for sel in &rule.selectors { match sel { - NetworkFilterSelector::All => { - rule_xml.all_selectors.push(NetworkFilterRuleProtocolAll {}); + NetworkFilterSelector::All(all) => { + rule_xml + .all_selectors + .push(Self::rest2lib_process_all_selector(all)?); + } + + NetworkFilterSelector::Allipv6(all) => { + rule_xml + .all_ipv6_selectors + .push(Self::rest2lib_process_all_selector(all)?); } NetworkFilterSelector::Mac(mac) => { diff --git a/virtweb_frontend/src/api/NWFilterApi.ts b/virtweb_frontend/src/api/NWFilterApi.ts index 0e76cd4..4d0385f 100644 --- a/virtweb_frontend/src/api/NWFilterApi.ts +++ b/virtweb_frontend/src/api/NWFilterApi.ts @@ -6,10 +6,18 @@ export interface NWFilterChain { suffix?: string; } -export interface NWFSAll { - type: "all"; +export interface NWFSAllBase { + comment?: string; } +export type NWFSAll = NWFSAllBase & { + type: "all"; +}; + +export type NWFSAllIPv6 = NWFSAllBase & { + type: "allipv6"; +}; + export interface NWFSMac { type: "mac"; src_mac_addr?: string; @@ -91,6 +99,7 @@ export type NFWSICMPv6 = NWFSLayer4Base & { type: "icmpipv6" }; export type NWFSelector = | NWFSAll + | NWFSAllIPv6 | NWFSMac | NWFSArp | NWFSRArp diff --git a/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx b/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx index 0938e75..5ea6987 100644 --- a/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx +++ b/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx @@ -7,12 +7,16 @@ import { CardActions, CardContent, IconButton, + Paper, + Tooltip, } from "@mui/material"; -import { NWFilterRule } from "../../api/NWFilterApi"; +import { NWFSMac, NWFSelector, NWFilterRule } from "../../api/NWFilterApi"; import { EditSection } from "./EditSection"; import { SelectInput } from "./SelectInput"; import { TextInput } from "./TextInput"; import { ServerApi } from "../../api/ServerApi"; +import PlaylistAddIcon from "@mui/icons-material/PlaylistAdd"; +import { MACInput } from "./MACInput"; export function NWFilterRules(p: { editable: boolean; @@ -72,6 +76,18 @@ function NWRuleEdit(p: { onGoDown?: () => void; onDelete: () => void; }): React.ReactElement { + const addSelector = () => { + p.rule.selectors.push({ + type: "all", + }); + p.onChange?.(); + }; + + const deleteSelector = (num: number) => { + p.rule.selectors.splice(num, 1); + p.onChange?.(); + }; + return ( @@ -120,23 +136,51 @@ function NWRuleEdit(p: { size={ServerApi.Config.constraints.nwfilter_priority} /> + + {p.rule.selectors.map((s, n) => ( + deleteSelector(n)} + /> + ))} {p.editable && (
- - - + + + + + + - {p.onGoUp && ( - - - + + {ServerApi.Config.constraints.nwfilter_selectors_count.max > + p.rule.selectors.length && ( + + + + + )} + + {p.onGoUp && ( + + + + + + )} + {p.onGoDown && ( - - - + + + + + )}
)} @@ -144,3 +188,126 @@ function NWRuleEdit(p: {
); } + +function NWFSelectorEdit(p: { + editable: boolean; + selector: NWFSelector; + onDelete: () => void; + onChange?: () => void; +}): React.ReactElement { + return ( + +
+
+ { + p.selector.type = v! as any; + p.onChange?.(); + }} + value={p.selector.type} + options={[ + { label: "All over IPv4", value: "all" }, + { label: "All over IPv6", value: "allipv6" }, + + { label: "MAC (Ethernet)", value: "mac" }, + + { label: "ARP", value: "arp" }, + { label: "RARP", value: "rarp" }, + + { label: "IPv4", value: "ipv4" }, + { label: "IPv6", value: "ipv6" }, + + { label: "TCP over IPv4", value: "tcp" }, + { label: "UDP over IPv4", value: "udp" }, + { label: "SCTP over IPv4", value: "sctp" }, + { label: "ICMPv4", value: "icmp" }, + + { label: "TCP over IPv6", value: "tcpipv6" }, + { label: "UDP over IPv6", value: "udpipv6" }, + { label: "SCTP over IPv6", value: "sctpipv6" }, + { label: "ICMPv6", value: "icmpipv6" }, + ]} + /> + + {p.selector.type === "mac" && ( + + )} + + { + p.selector.comment = v; + p.onChange?.(); + }} + size={ServerApi.Config.constraints.nwfilter_comment_size} + /> +
+ + {p.editable && ( +
+ + + + + +
+ )} +
+
+ ); +} + +interface SpecificSelectorEditor { + editable: boolean; + selector: E; + onChange?: () => void; +} + +function NWFSelectorMac( + p: SpecificSelectorEditor +): React.ReactElement { + return ( + <> + { + p.selector.src_mac_addr = v; + p.onChange?.(); + }} + /> + { + p.selector.src_mac_mask = v; + p.onChange?.(); + }} + /> + { + p.selector.dst_mac_addr = v; + p.onChange?.(); + }} + /> + { + p.selector.dst_mac_mask = v; + p.onChange?.(); + }} + /> + + ); +}