Firewall refactor
This commit is contained in:
@@ -8,11 +8,15 @@ export const ModeSelector = (props:Omit<SegmentedControlProps, "data">) => (
|
||||
data={[
|
||||
{
|
||||
value: RuleMode.IN,
|
||||
label: 'Inbound',
|
||||
label: 'IN',
|
||||
},
|
||||
{
|
||||
value: RuleMode.FORWARD,
|
||||
label: 'FWD',
|
||||
},
|
||||
{
|
||||
value: RuleMode.OUT,
|
||||
label: 'Outbound',
|
||||
label: 'OUT',
|
||||
}
|
||||
]}
|
||||
size={props.size?props.size:"xs"}
|
||||
|
||||
@@ -13,6 +13,10 @@ export const ProtocolSelector = (props:Omit<SegmentedControlProps, "data">) => (
|
||||
value: Protocol.UDP,
|
||||
label: 'UDP',
|
||||
},
|
||||
{
|
||||
value: Protocol.BOTH,
|
||||
label: 'BOTH',
|
||||
},
|
||||
{
|
||||
value: Protocol.ANY,
|
||||
label: 'ANY',
|
||||
|
||||
@@ -5,6 +5,7 @@ import { getapi, postapi } from "../../js/utils"
|
||||
export enum Protocol {
|
||||
TCP = "tcp",
|
||||
UDP = "udp",
|
||||
BOTH = "both",
|
||||
ANY = "any"
|
||||
}
|
||||
|
||||
@@ -15,16 +16,17 @@ export enum ActionType {
|
||||
}
|
||||
|
||||
export enum RuleMode {
|
||||
OUT = "O",
|
||||
IN = "I",
|
||||
OUT = "out",
|
||||
IN = "in",
|
||||
FORWARD = "forward"
|
||||
}
|
||||
|
||||
export type Rule = {
|
||||
active: boolean
|
||||
name:string,
|
||||
proto: Protocol,
|
||||
ip_src: string,
|
||||
ip_dst: string,
|
||||
src: string,
|
||||
dst: string,
|
||||
port_src_from: number,
|
||||
port_dst_from: number,
|
||||
port_src_to: number,
|
||||
@@ -48,6 +50,7 @@ export type FirewallSettings = {
|
||||
keep_rules: boolean,
|
||||
allow_loopback: boolean,
|
||||
allow_established: boolean,
|
||||
allow_icmp: boolean
|
||||
}
|
||||
|
||||
|
||||
@@ -74,16 +77,6 @@ export const firewall = {
|
||||
disable: async() => {
|
||||
return await getapi("firewall/disable") as ServerResponse;
|
||||
},
|
||||
rulenable: async (rule_id:number) => {
|
||||
return await getapi(`firewall/rule/${rule_id}/enable`) as ServerResponse;
|
||||
},
|
||||
ruledisable: async (rule_id:number) => {
|
||||
return await getapi(`firewall/rule/${rule_id}/disable`) as ServerResponse;
|
||||
},
|
||||
rulerename: async (rule_id:number, name: string) => {
|
||||
const { status } = await postapi(`firewall/rule/${rule_id}/rename`,{ name }) as ServerResponse;
|
||||
return status === "ok"?undefined:status
|
||||
},
|
||||
ruleset: async (data:RuleAddForm) => {
|
||||
return await postapi("firewall/rules/set", data) as ServerResponseListed;
|
||||
}
|
||||
|
||||
@@ -14,19 +14,26 @@ interface ItemProps extends AutocompleteItem {
|
||||
}
|
||||
|
||||
interface InterfaceInputProps extends Omit<SelectProps, "data">{
|
||||
initialCustomInterfaces?:AutocompleteItem[]
|
||||
initialCustomInterfaces?:AutocompleteItem[],
|
||||
includeInterfaceNames?:boolean
|
||||
}
|
||||
|
||||
export const InterfaceInput = (props:InterfaceInputProps) => {
|
||||
|
||||
const { initialCustomInterfaces, ...propeties } = props
|
||||
export const InterfaceInput = ({ initialCustomInterfaces, includeInterfaceNames, ...props }:InterfaceInputProps) => {
|
||||
|
||||
const [customIpInterfaces, setCustomIpInterfaces] = useState<AutocompleteItem[]>(initialCustomInterfaces??[]);
|
||||
const interfacesQuery = ipInterfacesQuery()
|
||||
|
||||
const interfaces = (!interfacesQuery.isLoading?
|
||||
(interfacesQuery.data!.map(item => ({netint:item.name, value:item.addr, label:item.addr})) as AutocompleteItem[]):
|
||||
[])
|
||||
const getInterfaces = () => {
|
||||
if (interfacesQuery.isLoading || !interfacesQuery.data) return []
|
||||
if(includeInterfaceNames){
|
||||
const result = interfacesQuery.data.map(item => ({netint:"IP", value:item.addr, label:item.addr})) as AutocompleteItem[]
|
||||
interfacesQuery.data.map(item => item.name).filter((item, index, arr) => arr.indexOf(item) === index).forEach(item => result.push({netint:"INT", value:item, label:item}))
|
||||
return result
|
||||
}
|
||||
return (interfacesQuery.data.map(item => ({netint:item.name, value:item.addr, label:item.addr})) as AutocompleteItem[])
|
||||
}
|
||||
|
||||
const interfaces = getInterfaces()
|
||||
|
||||
return <Select
|
||||
placeholder="10.1.1.1"
|
||||
@@ -43,6 +50,6 @@ export const InterfaceInput = (props:InterfaceInputProps) => {
|
||||
return item;
|
||||
}}
|
||||
style={props.style?{width:"100%", ...props.style}:{width:"100%"}}
|
||||
{...propeties}
|
||||
{...props}
|
||||
/>
|
||||
}
|
||||
@@ -5,7 +5,7 @@ import { FirewallSettings, firewall } from '../../components/Firewall/utils';
|
||||
|
||||
export function SettingsModal({ opened, onClose }:{ opened:boolean, onClose:()=>void }) {
|
||||
|
||||
const [settings, setSettings] = useState<FirewallSettings>({keep_rules:false, allow_established:true, allow_loopback:true})
|
||||
const [settings, setSettings] = useState<FirewallSettings>({keep_rules:false, allow_established:true, allow_loopback:true, allow_icmp:true})
|
||||
|
||||
useEffect(()=>{
|
||||
firewall.settings().then( res => {
|
||||
@@ -39,6 +39,7 @@ export function SettingsModal({ opened, onClose }:{ opened:boolean, onClose:()=>
|
||||
<Space h="md" />
|
||||
<Switch label="Allow established connection (essential to allow opening connection) (Dangerous to disable)" checked={settings.allow_established} onChange={v => setSettings({...settings, allow_established:v.target.checked})}/>
|
||||
<Space h="md" />
|
||||
<Switch label="Allow icmp packets" checked={settings.allow_icmp} onChange={v => setSettings({...settings, allow_icmp:v.target.checked})}/>
|
||||
|
||||
<Group position="right" mt="md">
|
||||
<Button loading={submitLoading} onClick={submitRequest}>Save Setting</Button>
|
||||
|
||||
@@ -106,8 +106,8 @@ export const Firewall = () => {
|
||||
active: true,
|
||||
name: "Rule name",
|
||||
proto: Protocol.TCP,
|
||||
ip_src: "any",
|
||||
ip_dst: "any",
|
||||
src: "",
|
||||
dst: "",
|
||||
port_src_from: 1,
|
||||
port_dst_from: 8080,
|
||||
port_src_to: 65535,
|
||||
@@ -140,18 +140,15 @@ export const Firewall = () => {
|
||||
{(provided, snapshot) => {
|
||||
const customInt = [
|
||||
{ value: "0.0.0.0/0", netint: "ANY IPv4", label: "0.0.0.0/0" },
|
||||
{ value: "::/0", netint: "ANY IPv6", label: "::/0" }
|
||||
{ value: "::/0", netint: "ANY IPv6", label: "::/0" },
|
||||
{ value: "", netint: "ANY", label: "ANY" }
|
||||
]
|
||||
const src_custom_int = customInt.map(v => v.value).includes(item.ip_src) || item.ip_dst == "any"?[]:[{ value: item.ip_src, netint: "SELECTED", label: item.ip_src }]
|
||||
const dst_custom_int = customInt.map(v => v.value).includes(item.ip_dst) || item.ip_dst == "any"?[]:[{ value: item.ip_dst, netint: "SELECTED", label: item.ip_dst }]
|
||||
const src_custom_int = customInt.map(v => v.value).includes(item.src)?[]:[{ value: item.src, netint: "SELECTED", label: item.src }]
|
||||
const dst_custom_int = customInt.map(v => v.value).includes(item.dst)?[]:[{ value: item.dst, netint: "SELECTED", label: item.dst }]
|
||||
const [srcPortEnabled, setSrcPortEnabled] = useState(item.port_src_from != 1 || item.port_src_to != 65535)
|
||||
const [dstPortEnabled, setDstPortEnabled] = useState(item.port_dst_from != 1 || item.port_dst_to != 65535)
|
||||
const [srcPortValue, setSrcPortValue] = useState(item.port_src_from==item.port_src_to?`${item.port_src_from}`:`${item.port_src_from}-${item.port_src_to}`)
|
||||
const [dstPortValue, setDstPortValue] = useState(item.port_dst_from==item.port_dst_to?`${item.port_dst_from}`:`${item.port_dst_from}-${item.port_dst_to}`)
|
||||
const [ipFilteringEnabled, setIpFilteringEnabled] = useState(!(item.ip_dst == "any" || item.ip_src == "any"))
|
||||
|
||||
const [srcIp, setSrcIp] = useState(item.ip_src!="any"?item.ip_src:"")
|
||||
const [dstIp, setDstIp] = useState(item.ip_dst!="any"?item.ip_dst:"")
|
||||
|
||||
const port_range_setter = (rule:Rule, v:string, {src=false, dst=false}:{src?:boolean, dst?:boolean}) => {
|
||||
const elements = v.split("-")
|
||||
@@ -173,39 +170,23 @@ export const Firewall = () => {
|
||||
const ip_setter = (rule:Rule, v:string|null, {src=false, dst=false}:{src?:boolean, dst?:boolean}) => {
|
||||
const values = v?v:""
|
||||
if (src){
|
||||
rule.ip_src = values
|
||||
setSrcIp(values)
|
||||
rule.src = values
|
||||
}
|
||||
if (dst){
|
||||
rule.ip_dst = values
|
||||
setDstIp(values)
|
||||
rule.dst = values
|
||||
}
|
||||
updateMe()
|
||||
}
|
||||
|
||||
const set_filtering_ip = (value:boolean) => {
|
||||
if (!value){
|
||||
item.ip_src = "any"
|
||||
item.ip_dst = "any"
|
||||
}else{
|
||||
item.ip_src = srcIp
|
||||
item.ip_dst = dstIp
|
||||
}
|
||||
setIpFilteringEnabled(value)
|
||||
updateMe()
|
||||
}
|
||||
|
||||
const disable_style = { opacity:"0.4", cursor:"not-allowed" }
|
||||
const proto_any = item.proto == Protocol.ANY
|
||||
const disabletab = {
|
||||
ips:!ipFilteringEnabled,
|
||||
port_box: proto_any,
|
||||
src_port: !srcPortEnabled || proto_any,
|
||||
dst_port: !dstPortEnabled || proto_any
|
||||
}
|
||||
|
||||
const additionalStyle = {
|
||||
ips:disabletab.ips?disable_style:{},
|
||||
port_box: disabletab.port_box?disable_style:{},
|
||||
src_port: disabletab.src_port?disable_style:{},
|
||||
dst_port: disabletab.dst_port?disable_style:{}
|
||||
@@ -254,11 +235,9 @@ export const Firewall = () => {
|
||||
<div style={{width:"100%"}}>
|
||||
<InterfaceInput
|
||||
initialCustomInterfaces={[...src_custom_int, ...customInt]}
|
||||
value={srcIp}
|
||||
value={item.src}
|
||||
onChange={v => ip_setter(item, v, {src:true})}
|
||||
disabled={disabletab.ips}
|
||||
error={!disabletab.ips && !srcIp}
|
||||
style={additionalStyle.ips}
|
||||
includeInterfaceNames
|
||||
/>
|
||||
<Space h="sm" />
|
||||
<div className="center-flex" style={{width:"100%"}}>
|
||||
@@ -289,11 +268,9 @@ export const Firewall = () => {
|
||||
<div style={{width:"100%"}}>
|
||||
<InterfaceInput
|
||||
initialCustomInterfaces={[...dst_custom_int, ...customInt]}
|
||||
defaultValue={dstIp}
|
||||
defaultValue={item.dst}
|
||||
onChange={v => ip_setter(item, v, {dst:true})}
|
||||
disabled={disabletab.ips}
|
||||
error={!disabletab.ips && !dstIp}
|
||||
style={additionalStyle.ips}
|
||||
includeInterfaceNames
|
||||
/>
|
||||
<Space h="sm" />
|
||||
<div className="center-flex" style={{width:"100%"}}>
|
||||
@@ -338,14 +315,6 @@ export const Firewall = () => {
|
||||
onChange={(value)=>{item.proto = value as Protocol;updateMe()}}
|
||||
style={{width:"100%"}}
|
||||
/>
|
||||
<Space h="xs" />
|
||||
|
||||
<Button
|
||||
size="xs" variant="light"
|
||||
color={ipFilteringEnabled?"lime":"red"}
|
||||
onClick={()=>set_filtering_ip(!ipFilteringEnabled)}
|
||||
style={{width:"100%"}}
|
||||
>{ipFilteringEnabled?"IP Filtering ON":"IP Filtering OFF"}</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Space h="md" />
|
||||
|
||||
Reference in New Issue
Block a user