Add Layer4 rules support

This commit is contained in:
Pierre HUBERT 2024-01-04 15:30:25 +01:00
parent c40ee037da
commit 975b4ab395
2 changed files with 187 additions and 13 deletions

View File

@ -1,6 +1,7 @@
import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward"; import ArrowDownwardIcon from "@mui/icons-material/ArrowDownward";
import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward"; import ArrowUpwardIcon from "@mui/icons-material/ArrowUpward";
import DeleteIcon from "@mui/icons-material/Delete"; import DeleteIcon from "@mui/icons-material/Delete";
import PlaylistAddIcon from "@mui/icons-material/PlaylistAdd";
import { import {
Button, Button,
Card, Card,
@ -11,20 +12,20 @@ import {
Tooltip, Tooltip,
} from "@mui/material"; } from "@mui/material";
import { import {
NWFSArp,
NWFSArpOrRARP, NWFSArpOrRARP,
NWFSIPBase, NWFSIPBase,
NWFSLayer4Base,
NWFSMac, NWFSMac,
NWFSelector, NWFSelector,
NWFilterRule, NWFilterRule,
} from "../../api/NWFilterApi"; } from "../../api/NWFilterApi";
import { ServerApi } from "../../api/ServerApi";
import { EditSection } from "./EditSection"; import { EditSection } from "./EditSection";
import { IPInput, IPInputWithMask } from "./IPInput";
import { MACInput } from "./MACInput";
import { PortInput } from "./PortInput";
import { SelectInput } from "./SelectInput"; import { SelectInput } from "./SelectInput";
import { TextInput } from "./TextInput"; 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: { export function NWFilterRules(p: {
editable: boolean; editable: boolean;
@ -255,6 +256,20 @@ function NWFSelectorEdit(p: {
<NWFSelectorIP {...p} selector={p.selector} version={6} /> <NWFSelectorIP {...p} selector={p.selector} version={6} />
)} )}
{(p.selector.type === "tcp" ||
p.selector.type === "udp" ||
p.selector.type === "sctp" ||
p.selector.type === "icmp") && (
<NWFSelectorLayer4 {...p} selector={p.selector} version={4} />
)}
{(p.selector.type === "tcpipv6" ||
p.selector.type === "udpipv6" ||
p.selector.type === "sctpipv6" ||
p.selector.type === "icmpipv6") && (
<NWFSelectorLayer4 {...p} selector={p.selector} version={6} />
)}
<TextInput <TextInput
editable={p.editable} editable={p.editable}
label="Comment" label="Comment"
@ -354,9 +369,9 @@ function NWFSelectorArp(
<MACInput <MACInput
{...p} {...p}
label="Src mac mask" label="Src mac mask"
value={p.selector.srcmacaddr} value={p.selector.srcmacmask}
onValueChange={(v) => { onValueChange={(v) => {
p.selector.srcmacaddr = v; p.selector.srcmacmask = v;
p.onChange?.(); p.onChange?.();
}} }}
/> />
@ -372,9 +387,9 @@ function NWFSelectorArp(
<MACInput <MACInput
{...p} {...p}
label="Dst mac mask" label="Dst mac mask"
value={p.selector.dstmacaddr} value={p.selector.dstmacmask}
onValueChange={(v) => { onValueChange={(v) => {
p.selector.dstmacaddr = v; p.selector.dstmacmask = v;
p.onChange?.(); p.onChange?.();
}} }}
/> />
@ -423,9 +438,9 @@ function NWFSelectorIP(
<MACInput <MACInput
{...p} {...p}
label="Src mac mask" label="Src mac mask"
value={p.selector.srcmacaddr} value={p.selector.srcmacmask}
onValueChange={(v) => { onValueChange={(v) => {
p.selector.srcmacaddr = v; p.selector.srcmacmask = v;
p.onChange?.(); p.onChange?.();
}} }}
/> />
@ -441,9 +456,9 @@ function NWFSelectorIP(
<MACInput <MACInput
{...p} {...p}
label="Dst mac mask" label="Dst mac mask"
value={p.selector.dstmacaddr} value={p.selector.dstmacmask}
onValueChange={(v) => { onValueChange={(v) => {
p.selector.dstmacaddr = v; p.selector.dstmacmask = v;
p.onChange?.(); p.onChange?.();
}} }}
/> />
@ -474,3 +489,134 @@ function NWFSelectorIP(
</> </>
); );
} }
function NWFSelectorLayer4(
p: SpecificSelectorEditorWithIPVersion<NWFSLayer4Base>
): React.ReactElement {
return (
<>
<MACInput
{...p}
label="Src mac address"
value={p.selector.srcmacaddr}
onValueChange={(v) => {
p.selector.srcmacaddr = v;
p.onChange?.();
}}
/>
<IPInputWithMask
{...p}
label="Source IP address / mask"
ip={p.selector.srcipaddr}
mask={p.selector.srcipmask}
version={p.version}
onValueChange={(ip, mask) => {
p.selector.srcipaddr = ip;
p.selector.srcipmask = mask;
p.onChange?.();
}}
/>
<IPInputWithMask
{...p}
label="Destination IP address / mask"
ip={p.selector.dstipaddr}
mask={p.selector.dstipmask}
version={p.version}
onValueChange={(ip, mask) => {
p.selector.dstipaddr = ip;
p.selector.dstipmask = mask;
p.onChange?.();
}}
/>
<IPInput
{...p}
label="Source IP from"
value={p.selector.srcipfrom}
onValueChange={(ip) => {
p.selector.srcipfrom = ip;
p.onChange?.();
}}
/>
<IPInput
{...p}
label="Source IP to"
value={p.selector.srcipto}
onValueChange={(ip) => {
p.selector.srcipto = ip;
p.onChange?.();
}}
/>
<IPInput
{...p}
label="Destination IP from"
value={p.selector.dstipfrom}
onValueChange={(ip) => {
p.selector.dstipfrom = ip;
p.onChange?.();
}}
/>
<IPInput
{...p}
label="Destination IP to"
value={p.selector.dstipto}
onValueChange={(ip) => {
p.selector.dstipto = ip;
p.onChange?.();
}}
/>
<PortInput
{...p}
label="Source port start"
value={p.selector.srcportstart}
onChange={(port) => {
p.selector.srcportstart = port;
p.onChange?.();
}}
/>
<PortInput
{...p}
label="Source port end"
value={p.selector.srcportend}
onChange={(port) => {
p.selector.srcportend = port;
p.onChange?.();
}}
/>
<PortInput
{...p}
label="Destination port start"
value={p.selector.dstportstart}
onChange={(port) => {
p.selector.dstportstart = port;
p.onChange?.();
}}
/>
<PortInput
{...p}
label="Destination port end"
value={p.selector.dstportend}
onChange={(port) => {
p.selector.dstportend = port;
p.onChange?.();
}}
/>
<SelectInput
{...p}
label="Connection state"
value={p.selector.state}
onValueChange={(s) => {
p.selector.state = s as any;
p.onChange?.();
}}
options={[
{ label: "None", value: undefined },
{ label: "NEW", value: "NEW" },
{ label: "ESTABLISHED", value: "ESTABLISHED" },
{ label: "RELATED", value: "RELATED" },
{ label: "INVALID", value: "INVALID" },
{ label: "NONE", value: "NONE" },
]}
/>
</>
);
}

View File

@ -0,0 +1,28 @@
import { TextInput } from "./TextInput";
export function PortInput(p: {
editable: boolean;
label: string;
value?: number;
onChange: (value: number | undefined) => void;
}): React.ReactElement {
return (
<TextInput
{...p}
value={p.value?.toString() ?? ""}
type="number"
onValueChange={(v) => {
p.onChange?.(sanitizePort(v));
}}
/>
);
}
function sanitizePort(port?: string): number | undefined {
if (port === undefined) return undefined;
const val = Number(port);
if (val < 0) return 0;
if (val > 65535) return 65535;
return val;
}