From 719ab3b26526b1fc5dc755531569d7596f9a8d28 Mon Sep 17 00:00:00 2001 From: Pierre Hubert Date: Thu, 4 Jan 2024 13:02:58 +0100 Subject: [PATCH] Can define ARP rules --- .../src/widgets/forms/IPInput.tsx | 54 ++++++++++++ .../src/widgets/forms/NWFilterRules.tsx | 82 ++++++++++++++++++- 2 files changed, 135 insertions(+), 1 deletion(-) diff --git a/virtweb_frontend/src/widgets/forms/IPInput.tsx b/virtweb_frontend/src/widgets/forms/IPInput.tsx index 9a66bb9..c497e7a 100644 --- a/virtweb_frontend/src/widgets/forms/IPInput.tsx +++ b/virtweb_frontend/src/widgets/forms/IPInput.tsx @@ -1,3 +1,4 @@ +import React from "react"; import { TextInput } from "./TextInput"; export function IPInput(p: { @@ -18,6 +19,47 @@ export function IPInput(p: { ); } +export function IPInputWithMask(p: { + label: string; + editable: boolean; + ip?: string; + mask?: number; + onValueChange?: (ip?: string, mask?: number) => void; + version: 4 | 6; +}): React.ReactElement { + const showSlash = React.useRef(!!p.mask); + + const currValue = + (p.ip ?? "") + (p.mask || showSlash.current ? "/" : "") + (p.mask ?? ""); + + const { onValueChange, ...props } = p; + return ( + { + showSlash.current = false; + if (!v) { + onValueChange?.(undefined, undefined); + return; + } + + const split = v?.split("/"); + const ip = + p.version === 4 ? sanitizeIpV4(split[0]) : sanitizeIpV6(split[0]); + let mask = undefined; + + if (split.length > 1) { + showSlash.current = true; + mask = sanitizeMask(p.version, split[1]); + } + + onValueChange?.(ip, mask); + }} + value={currValue} + {...props} + /> + ); +} + function sanitizeIpV4(s: string | undefined): string | undefined { if (s === "" || s === undefined) return s; @@ -77,3 +119,15 @@ function sanitizeIpV6(s: string | undefined): string | undefined { return needAnotherIteration ? sanitizeIpV6(res) : res; } + +function sanitizeMask(version: 4 | 6, mask?: string): number | undefined { + if (!mask) return undefined; + + const value = Math.floor(Number(mask)); + + if (version === 4) { + return value < 0 || value > 32 ? 32 : value; + } else { + return value < 0 || value > 64 ? 64 : value; + } +} diff --git a/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx b/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx index 5ea6987..ad699dc 100644 --- a/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx +++ b/virtweb_frontend/src/widgets/forms/NWFilterRules.tsx @@ -10,13 +10,20 @@ import { Paper, Tooltip, } from "@mui/material"; -import { NWFSMac, NWFSelector, NWFilterRule } from "../../api/NWFilterApi"; +import { + NWFSArp, + NWFSArpOrRARP, + 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"; +import { IPInput, IPInputWithMask } from "./IPInput"; export function NWFilterRules(p: { editable: boolean; @@ -235,6 +242,10 @@ function NWFSelectorEdit(p: { )} + {(p.selector.type === "arp" || p.selector.type === "rarp") && ( + + )} + ); } + +function NWFSelectorArp( + p: SpecificSelectorEditor +): React.ReactElement { + return ( + <> + { + p.selector.srcmacaddr = v; + p.onChange?.(); + }} + /> + { + p.selector.srcmacaddr = v; + p.onChange?.(); + }} + /> + { + p.selector.dstmacaddr = v; + p.onChange?.(); + }} + /> + { + p.selector.dstmacaddr = v; + p.onChange?.(); + }} + /> + { + p.selector.arpsrcipaddr = ip; + p.selector.arpsrcipmask = mask; + p.onChange?.(); + }} + /> + { + p.selector.arpdstipaddr = ip; + p.selector.arpdstipmask = mask; + p.onChange?.(); + }} + /> + + ); +}