Add new attribute to 'all' rules

This commit is contained in:
Pierre HUBERT 2024-01-04 16:53:24 +01:00
parent 307e5d1b50
commit 8cd32d35e2
5 changed files with 291 additions and 98 deletions

View File

@ -9,13 +9,6 @@ pub struct NetworkFilterRefXML {
pub filter: String,
}
#[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(rename = "all")]
pub struct NetworkFilterRuleProtocolAllXML {
#[serde(rename = "@comment", skip_serializing_if = "Option::is_none")]
pub comment: Option<String>,
}
#[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(rename = "mac")]
pub struct NetworkFilterRuleProtocolMac {
@ -50,7 +43,6 @@ pub struct NetworkFilterRuleProtocolArpXML {
pub arpdstipaddr: Option<String>,
#[serde(rename = "@arpdstipmask", skip_serializing_if = "Option::is_none")]
pub arpdstipmask: Option<u8>,
#[serde(rename = "@comment", skip_serializing_if = "Option::is_none")]
pub comment: Option<String>,
}
@ -114,7 +106,37 @@ pub struct NetworkFilterRuleProtocolLayer4<IPv> {
pub dstportend: Option<u16>,
#[serde(rename = "@state", skip_serializing_if = "Option::is_none")]
pub state: Option<String>,
#[serde(rename = "@comment", skip_serializing_if = "Option::is_none")]
pub comment: Option<String>,
}
#[derive(serde::Serialize, serde::Deserialize, Debug)]
#[serde(rename = "all")]
pub struct NetworkFilterRuleProtocolAllXML<IPv> {
#[serde(rename = "@srcmacaddr", skip_serializing_if = "Option::is_none")]
pub srcmacaddr: Option<String>,
#[serde(rename = "@srcipaddr", skip_serializing_if = "Option::is_none")]
pub srcipaddr: Option<IPv>,
#[serde(rename = "@srcipmask", skip_serializing_if = "Option::is_none")]
pub srcipmask: Option<u8>,
#[serde(rename = "@dstipaddr", skip_serializing_if = "Option::is_none")]
pub dstipaddr: Option<IPv>,
#[serde(rename = "@dstipmask", skip_serializing_if = "Option::is_none")]
pub dstipmask: Option<u8>,
/// Start of range of source IP address
#[serde(rename = "@srcipfrom", skip_serializing_if = "Option::is_none")]
pub srcipfrom: Option<IPv>,
/// End of range of source IP address
#[serde(rename = "@srcipto", skip_serializing_if = "Option::is_none")]
pub srcipto: Option<IPv>,
/// Start of range of destination IP address
#[serde(rename = "@dstipfrom", skip_serializing_if = "Option::is_none")]
pub dstipfrom: Option<IPv>,
/// End of range of destination IP address
#[serde(rename = "@dstipto", skip_serializing_if = "Option::is_none")]
pub dstipto: Option<IPv>,
#[serde(rename = "@state", skip_serializing_if = "Option::is_none")]
pub state: Option<String>,
#[serde(rename = "@comment", skip_serializing_if = "Option::is_none")]
pub comment: Option<String>,
}
@ -129,14 +151,6 @@ pub struct NetworkFilterRuleXML {
#[serde(rename = "@priority")]
pub priority: Option<i32>,
/// Match all protocols
#[serde(default, rename = "all", skip_serializing_if = "Vec::is_empty")]
pub all_selectors: Vec<NetworkFilterRuleProtocolAllXML>,
/// Match all ipv6 protocols
#[serde(default, rename = "all-ipv6", skip_serializing_if = "Vec::is_empty")]
pub all_ipv6_selectors: Vec<NetworkFilterRuleProtocolAllXML>,
/// Match mac protocol
#[serde(default, rename = "mac", skip_serializing_if = "Vec::is_empty")]
pub mac_selectors: Vec<NetworkFilterRuleProtocolMac>,
@ -173,6 +187,10 @@ pub struct NetworkFilterRuleXML {
#[serde(default, rename = "icmp", skip_serializing_if = "Vec::is_empty")]
pub icmp_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv4Addr>>,
/// Match all protocols
#[serde(default, rename = "all", skip_serializing_if = "Vec::is_empty")]
pub all_selectors: Vec<NetworkFilterRuleProtocolAllXML<Ipv4Addr>>,
/// Match TCP IPv6 protocol
#[serde(default, rename = "tcp-ipv6", skip_serializing_if = "Vec::is_empty")]
pub tcp_ipv6_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv6Addr>>,
@ -188,6 +206,10 @@ pub struct NetworkFilterRuleXML {
/// Match ICMP IPv6 protocol
#[serde(default, rename = "icmpv6", skip_serializing_if = "Vec::is_empty")]
pub imcp_ipv6_selectors: Vec<NetworkFilterRuleProtocolLayer4<Ipv6Addr>>,
/// Match all ipv6 protocols
#[serde(default, rename = "all-ipv6", skip_serializing_if = "Vec::is_empty")]
pub all_ipv6_selectors: Vec<NetworkFilterRuleProtocolAllXML<Ipv6Addr>>,
}
#[derive(serde::Serialize, serde::Deserialize, Debug)]

View File

@ -308,11 +308,6 @@ impl Layer4State {
}
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct NetworkSelectorAll {
comment: Option<String>,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct NetworkSelectorMac {
src_mac_addr: Option<NetworkFilterMacAddressOrVar>,
@ -371,10 +366,28 @@ pub struct NetworkFilterSelectorLayer4<IPv> {
comment: Option<String>,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
pub struct NetworkSelectorAll<IPv> {
comment: Option<String>,
srcmacaddr: Option<NetworkFilterMacAddressOrVar>,
srcipaddr: Option<IPv>,
srcipmask: Option<u8>,
dstipaddr: Option<IPv>,
dstipmask: Option<u8>,
/// Start of range of source IP address
srcipfrom: Option<IPv>,
/// End of range of source IP address
srcipto: Option<IPv>,
/// Start of range of destination IP address
dstipfrom: Option<IPv>,
/// End of range of destination IP address
dstipto: Option<IPv>,
state: Option<Layer4State>,
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
#[serde(tag = "type", rename_all = "lowercase")]
pub enum NetworkFilterSelector {
All(NetworkSelectorAll),
Mac(NetworkSelectorMac),
Arp(NetworkSelectorARP),
Rarp(NetworkSelectorARP),
@ -384,11 +397,12 @@ pub enum NetworkFilterSelector {
UDP(NetworkFilterSelectorLayer4<Ipv4Addr>),
SCTP(NetworkFilterSelectorLayer4<Ipv4Addr>),
ICMP(NetworkFilterSelectorLayer4<Ipv4Addr>),
Allipv6(NetworkSelectorAll),
All(NetworkSelectorAll<Ipv4Addr>),
TCPipv6(NetworkFilterSelectorLayer4<Ipv6Addr>),
UDPipv6(NetworkFilterSelectorLayer4<Ipv6Addr>),
SCTPipv6(NetworkFilterSelectorLayer4<Ipv6Addr>),
ICMPipv6(NetworkFilterSelectorLayer4<Ipv6Addr>),
Allipv6(NetworkSelectorAll<Ipv6Addr>),
}
#[derive(serde::Serialize, serde::Deserialize, Debug, Clone)]
@ -416,12 +430,6 @@ pub struct NetworkFilter {
}
impl NetworkFilter {
fn lib2rest_process_all_rule(n: &NetworkFilterRuleProtocolAllXML) -> NetworkSelectorAll {
NetworkSelectorAll {
comment: n.comment.clone(),
}
}
fn lib2rest_process_mac_rule(n: &NetworkFilterRuleProtocolMac) -> NetworkFilterSelector {
NetworkFilterSelector::Mac(NetworkSelectorMac {
src_mac_addr: n.srcmacaddr.as_ref().map(|v| v.into()),
@ -484,28 +492,29 @@ impl NetworkFilter {
})
}
fn lib2rest_process_all_rule<IPv: Copy>(
n: &NetworkFilterRuleProtocolAllXML<IPv>,
) -> anyhow::Result<NetworkSelectorAll<IPv>> {
Ok(NetworkSelectorAll {
srcmacaddr: n.srcmacaddr.as_ref().map(|v| v.into()),
srcipaddr: n.srcipaddr,
srcipmask: n.srcipmask,
dstipaddr: n.dstipaddr,
dstipmask: n.dstipmask,
srcipfrom: n.srcipfrom,
srcipto: n.srcipto,
dstipfrom: n.dstipfrom,
dstipto: n.dstipto,
state: n.state.as_deref().map(Layer4State::from_xml).transpose()?,
comment: n.comment.clone(),
})
}
pub fn lib2rest(xml: NetworkFilterXML) -> anyhow::Result<Self> {
let mut rules = Vec::with_capacity(xml.rules.len());
for rule in &xml.rules {
let mut selectors = Vec::new();
// All selectors
selectors.append(
&mut rule
.all_selectors
.iter()
.map(|r| NetworkFilterSelector::All(Self::lib2rest_process_all_rule(r)))
.collect(),
);
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
@ -638,6 +647,31 @@ impl NetworkFilter {
.collect::<Result<Vec<_>, anyhow::Error>>()?,
);
// All selectors
selectors.append(
&mut rule
.all_selectors
.iter()
.map(|r| {
Ok(NetworkFilterSelector::All(Self::lib2rest_process_all_rule(
r,
)?))
})
.collect::<Result<Vec<_>, anyhow::Error>>()?,
);
selectors.append(
&mut rule
.all_ipv6_selectors
.iter()
.map(|r| {
Ok(NetworkFilterSelector::Allipv6(
Self::lib2rest_process_all_rule(r)?,
))
})
.collect::<Result<Vec<_>, anyhow::Error>>()?,
);
rules.push(NetworkFilterRule {
action: NetworkFilterAction::from_xml(&rule.action)?,
direction: NetworkFilterDirection::from_xml(&rule.direction)?,
@ -664,14 +698,6 @@ impl NetworkFilter {
})
}
fn rest2lib_process_all_selector(
selector: &NetworkSelectorAll,
) -> anyhow::Result<NetworkFilterRuleProtocolAllXML> {
Ok(NetworkFilterRuleProtocolAllXML {
comment: extract_nw_filter_comment(&selector.comment)?,
})
}
fn rest2lib_process_arp_selector(
selector: &NetworkSelectorARP,
) -> anyhow::Result<NetworkFilterRuleProtocolArpXML> {
@ -728,6 +754,26 @@ impl NetworkFilter {
})
}
fn rest2lib_process_all_selector<IPv: Copy>(
selector: &NetworkSelectorAll<IPv>,
) -> anyhow::Result<NetworkFilterRuleProtocolAllXML<IPv>> {
Ok(NetworkFilterRuleProtocolAllXML {
srcmacaddr: extract_mac_address_or_var(&selector.srcmacaddr)?,
srcipaddr: selector.srcipaddr,
// This IP mask is not checked
srcipmask: selector.srcipmask,
dstipaddr: selector.dstipaddr,
// This IP mask is not checked
dstipmask: selector.dstipmask,
srcipfrom: selector.srcipfrom,
srcipto: selector.srcipto,
dstipfrom: selector.dstipfrom,
dstipto: selector.dstipto,
state: selector.state.map(|s| s.to_xml()),
comment: extract_nw_filter_comment(&selector.comment)?,
})
}
fn rest2lib_process_rule(rule: &NetworkFilterRule) -> anyhow::Result<NetworkFilterRuleXML> {
let mut rule_xml = NetworkFilterRuleXML {
action: rule.action.to_xml(),
@ -738,18 +784,6 @@ impl NetworkFilter {
for sel in &rule.selectors {
match sel {
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) => {
rule_xml.mac_selectors.push(NetworkFilterRuleProtocolMac {
srcmacaddr: extract_mac_address_or_var(&mac.src_mac_addr)?,
@ -765,6 +799,7 @@ impl NetworkFilter {
.arp_selectors
.push(Self::rest2lib_process_arp_selector(a)?);
}
NetworkFilterSelector::Rarp(a) => {
rule_xml
.rarp_selectors
@ -774,7 +809,6 @@ impl NetworkFilter {
NetworkFilterSelector::IPv4(ip) => rule_xml
.ipv4_selectors
.push(Self::rest2lib_process_ip_selector(ip)?),
NetworkFilterSelector::IPv6(ip) => rule_xml
.ipv6_selectors
.push(Self::rest2lib_process_ip_selector(ip)?),
@ -795,6 +829,12 @@ impl NetworkFilter {
.icmp_selectors
.push(Self::rest2lib_process_layer4_selector(icmp)?),
NetworkFilterSelector::All(all) => {
rule_xml
.all_selectors
.push(Self::rest2lib_process_all_selector(all)?);
}
NetworkFilterSelector::TCPipv6(tcpv6) => rule_xml
.tcp_ipv6_selectors
.push(Self::rest2lib_process_layer4_selector(tcpv6)?),
@ -810,6 +850,12 @@ impl NetworkFilter {
NetworkFilterSelector::ICMPipv6(icmpv6) => rule_xml
.imcp_ipv6_selectors
.push(Self::rest2lib_process_layer4_selector(icmpv6)?),
NetworkFilterSelector::Allipv6(all) => {
rule_xml
.all_ipv6_selectors
.push(Self::rest2lib_process_all_selector(all)?);
}
}
}

View File

@ -6,18 +6,6 @@ export interface NWFilterChain {
suffix?: string;
}
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;
@ -97,9 +85,29 @@ export type NFWSUDPv6 = NWFSLayer4Base & { type: "udpipv6" };
export type NFWSSCTPv6 = NWFSLayer4Base & { type: "sctpipv6" };
export type NFWSICMPv6 = NWFSLayer4Base & { type: "icmpipv6" };
export interface NWFSAllBase {
srcmacaddr?: string;
srcipaddr?: string;
srcipmask?: number;
dstipaddr?: string;
dstipmask?: number;
srcipfrom?: string;
srcipto?: string;
dstipfrom?: string;
dstipto?: string;
state?: Layer4State;
comment?: string;
}
export type NWFSAll = NWFSAllBase & {
type: "all";
};
export type NWFSAllIPv6 = NWFSAllBase & {
type: "allipv6";
};
export type NWFSelector =
| NWFSAll
| NWFSAllIPv6
| NWFSMac
| NWFSArp
| NWFSRArp
@ -109,10 +117,12 @@ export type NWFSelector =
| NFWSUDPv4
| NFWSSCTPv4
| NFWSICMPv4
| NWFSAll
| NFWSTCPv6
| NFWSUDPv6
| NFWSSCTPv6
| NFWSICMPv6;
| NFWSICMPv6
| NWFSAllIPv6;
export interface NWFilterRule {
action: "drop" | "reject" | "accept" | "return" | "continue";

View File

@ -0,0 +1,27 @@
import { Layer4State } from "../../api/NWFilterApi";
import { SelectInput } from "./SelectInput";
export function NWFConnStateInput(p: {
editable: boolean;
value?: Layer4State;
onChange: (s?: Layer4State) => void;
}): React.ReactElement {
return (
<SelectInput
{...p}
label="Connection state"
value={p.value}
onValueChange={(s) => {
p.onChange?.(s as any);
}}
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

@ -12,6 +12,7 @@ import {
Tooltip,
} from "@mui/material";
import {
NWFSAllBase,
NWFSArpOrRARP,
NWFSIPBase,
NWFSLayer4Base,
@ -23,10 +24,11 @@ import { ServerApi } from "../../api/ServerApi";
import { EditSection } from "./EditSection";
import { IPInput, IPInputWithMask } from "./IPInput";
import { MACInput } from "./MACInput";
import { NWFConnStateInput } from "./NWFConnStateInput";
import { NWFilterPriorityInput } from "./NWFilterPriorityInput";
import { PortInput } from "./PortInput";
import { SelectInput } from "./SelectInput";
import { TextInput } from "./TextInput";
import { NWFilterPriorityInput } from "./NWFilterPriorityInput";
export function NWFilterRules(p: {
editable: boolean;
@ -216,9 +218,6 @@ function NWFSelectorEdit(p: {
}}
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" },
@ -232,10 +231,14 @@ function NWFSelectorEdit(p: {
{ label: "SCTP over IPv4", value: "sctp" },
{ label: "ICMPv4", value: "icmp" },
{ label: "All over IPv4", value: "all" },
{ label: "TCP over IPv6", value: "tcpipv6" },
{ label: "UDP over IPv6", value: "udpipv6" },
{ label: "SCTP over IPv6", value: "sctpipv6" },
{ label: "ICMPv6", value: "icmpipv6" },
{ label: "All over IPv6", value: "allipv6" },
]}
/>
@ -262,6 +265,10 @@ function NWFSelectorEdit(p: {
<NWFSelectorLayer4 {...p} selector={p.selector} version={4} />
)}
{p.selector.type === "all" && (
<NWFSelectorAll {...p} selector={p.selector} version={4} />
)}
{(p.selector.type === "tcpipv6" ||
p.selector.type === "udpipv6" ||
p.selector.type === "sctpipv6" ||
@ -269,6 +276,10 @@ function NWFSelectorEdit(p: {
<NWFSelectorLayer4 {...p} selector={p.selector} version={6} />
)}
{p.selector.type === "allipv6" && (
<NWFSelectorAll {...p} selector={p.selector} version={6} />
)}
<TextInput
editable={p.editable}
label="Comment"
@ -599,22 +610,99 @@ function NWFSelectorLayer4(
p.onChange?.();
}}
/>
<SelectInput
<NWFConnStateInput
{...p}
label="Connection state"
value={p.selector.state}
onValueChange={(s) => {
p.selector.state = s as any;
onChange={(v) => {
p.selector.state = v;
p.onChange?.();
}}
/>
</>
);
}
function NWFSelectorAll(
p: SpecificSelectorEditorWithIPVersion<NWFSAllBase>
): 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?.();
}}
/>
<NWFConnStateInput
{...p}
value={p.selector.state}
onChange={(v) => {
p.selector.state = v;
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" },
]}
/>
</>
);