diff --git a/virtweb_backend/src/constants.rs b/virtweb_backend/src/constants.rs index 924db1a..9f22a79 100644 --- a/virtweb_backend/src/constants.rs +++ b/virtweb_backend/src/constants.rs @@ -74,3 +74,6 @@ pub const BUILTIN_NETWORK_FILTER_RULES: [&str; 24] = [ "qemu-announce-self", "qemu-announce-self-rarp", ]; + +/// List of valid network chains +pub const NETWORK_CHAINS: [&str; 8] = ["root", "mac", "stp", "vlan", "arp", "rarp", "ipv4", "ipv6"]; diff --git a/virtweb_backend/src/controllers/server_controller.rs b/virtweb_backend/src/controllers/server_controller.rs index ad413ec..d029059 100644 --- a/virtweb_backend/src/controllers/server_controller.rs +++ b/virtweb_backend/src/controllers/server_controller.rs @@ -15,8 +15,9 @@ struct StaticConfig { oidc_auth_enabled: bool, iso_mimetypes: &'static [&'static str], net_mac_prefix: &'static str, - constraints: ServerConstraints, builtin_nwfilter_rules: &'static [&'static str], + nwfilter_chains: &'static [&'static str], + constraints: ServerConstraints, } #[derive(serde::Serialize)] @@ -25,6 +26,12 @@ struct LenConstraints { max: usize, } +#[derive(serde::Serialize)] +struct SLenConstraints { + min: i64, + max: i64, +} + #[derive(serde::Serialize)] struct ServerConstraints { iso_max_size: usize, @@ -37,6 +44,9 @@ struct ServerConstraints { net_name_size: LenConstraints, net_title_size: LenConstraints, dhcp_reservation_host_name: LenConstraints, + nwfilter_name_size: LenConstraints, + nwfilter_comment_size: LenConstraints, + nwfilter_priority: SLenConstraints, } pub async fn static_config(local_auth: LocalAuthEnabled) -> impl Responder { @@ -47,6 +57,7 @@ pub async fn static_config(local_auth: LocalAuthEnabled) -> impl Responder { iso_mimetypes: &constants::ALLOWED_ISO_MIME_TYPES, net_mac_prefix: constants::NET_MAC_ADDR_PREFIX, builtin_nwfilter_rules: &constants::BUILTIN_NETWORK_FILTER_RULES, + nwfilter_chains: &constants::NETWORK_CHAINS, constraints: ServerConstraints { iso_max_size: constants::ISO_MAX_SIZE, @@ -71,6 +82,13 @@ pub async fn static_config(local_auth: LocalAuthEnabled) -> impl Responder { net_title_size: LenConstraints { min: 0, max: 50 }, dhcp_reservation_host_name: LenConstraints { min: 2, max: 250 }, + + nwfilter_name_size: LenConstraints { min: 2, max: 250 }, + nwfilter_comment_size: LenConstraints { min: 0, max: 256 }, + nwfilter_priority: SLenConstraints { + min: -1000, + max: 1000, + }, }, }) } diff --git a/virtweb_frontend/src/api/ServerApi.ts b/virtweb_frontend/src/api/ServerApi.ts index 71ea1f7..6ab909e 100644 --- a/virtweb_frontend/src/api/ServerApi.ts +++ b/virtweb_frontend/src/api/ServerApi.ts @@ -6,8 +6,9 @@ export interface ServerConfig { oidc_auth_enabled: boolean; iso_mimetypes: string[]; net_mac_prefix: string; - constraints: ServerConstraints; builtin_nwfilter_rules: string[]; + nwfilter_chains: string[]; + constraints: ServerConstraints; } export interface ServerConstraints { @@ -21,6 +22,9 @@ export interface ServerConstraints { net_name_size: LenConstraint; net_title_size: LenConstraint; dhcp_reservation_host_name: LenConstraint; + nwfilter_name_size: LenConstraint; + nwfilter_comment_size: LenConstraint; + nwfilter_priority: LenConstraint; } export interface LenConstraint { diff --git a/virtweb_frontend/src/routes/EditNWFilterRoute.tsx b/virtweb_frontend/src/routes/EditNWFilterRoute.tsx index 038f4df..7eb729d 100644 --- a/virtweb_frontend/src/routes/EditNWFilterRoute.tsx +++ b/virtweb_frontend/src/routes/EditNWFilterRoute.tsx @@ -17,6 +17,7 @@ export function CreateNWFilterRoute(): React.ReactElement { const [nwfilter, setNWFilter] = React.useState({ name: "my-filter", + chain: { protocol: "root" }, join_filters: [], rules: [], }); diff --git a/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx b/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx index 7b383c6..43829d8 100644 --- a/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx +++ b/virtweb_frontend/src/widgets/nwfilter/NWFilterDetails.tsx @@ -1,4 +1,4 @@ -import { Button } from "@mui/material"; +import { Button, Grid } from "@mui/material"; import React, { ReactElement } from "react"; import { useNavigate } from "react-router-dom"; import { @@ -12,6 +12,10 @@ import { useSnackbar } from "../../hooks/providers/SnackbarProvider"; import { AsyncWidget } from "../AsyncWidget"; import { TabsWidget } from "../TabsWidget"; import { XMLAsyncWidget } from "../XMLWidget"; +import { EditSection } from "../forms/EditSection"; +import { TextInput } from "../forms/TextInput"; +import { ServerApi } from "../../api/ServerApi"; +import { SelectInput } from "../forms/SelectInput"; interface DetailsProps { nwfilter: NWFilter; @@ -96,7 +100,51 @@ export function NetworkFilterDetailsInner( function NetworkFilterDetailsTabGeneral( p: InnerDetailsProps ): React.ReactElement { - return <>; + return ( + + {/* Metadata section */} + + { + p.nwfilter.name = v ?? ""; + p.onChange?.(); + }} + checkValue={(v) => /^[a-zA-Z0-9\_\-]+$/.test(v)} + size={ServerApi.Config.constraints.nwfilter_name_size} + /> + + + + { + p.nwfilter.chain = v ? { protocol: v } : undefined; + p.onChange?.(); + }} + options={ServerApi.Config.nwfilter_chains.map((c) => { + return { label: c, value: c }; + })} + /> + + { + p.nwfilter.priority = v && v !== "" ? Number(v) : undefined; + p.onChange?.(); + }} + size={ServerApi.Config.constraints.nwfilter_priority} + /> + + + ); } function NetworkFilterDetailsTabXML(p: InnerDetailsProps): React.ReactElement {