refactoring: firewall model changed using ufw model (due to docker iussues)

This commit is contained in:
Domingo Dirutigliano
2023-09-29 16:10:28 +02:00
parent 2657428d6e
commit b11fa66909
8 changed files with 241 additions and 161 deletions

View File

@@ -1,6 +1,6 @@
import asyncio import asyncio
from modules.firewall.nftables import FiregexTables from modules.firewall.nftables import FiregexTables
from modules.firewall.models import Rule from modules.firewall.models import *
from utils.sqlite import SQLite from utils.sqlite import SQLite
from modules.firewall.models import Action from modules.firewall.models import Action
@@ -25,13 +25,31 @@ class FirewallManager:
nft.set( nft.set(
map(Rule.from_dict, self.db.query('SELECT * FROM rules WHERE active = 1 ORDER BY rule_id;')), map(Rule.from_dict, self.db.query('SELECT * FROM rules WHERE active = 1 ORDER BY rule_id;')),
policy=self.policy, policy=self.policy,
allow_loopback=self.allow_loopback, opt=self.settings
allow_established=self.allow_established,
allow_icmp=self.allow_icmp
) )
else: else:
nft.reset() nft.reset()
@property
def settings(self):
return FirewallSettings(
keep_rules=self.keep_rules,
allow_loopback=self.allow_loopback,
allow_established=self.allow_established,
allow_icmp=self.allow_icmp,
multicast_dns=self.multicast_dns,
allow_upnp=self.allow_upnp
)
@settings.setter
def settings(self, value:FirewallSettings):
self.keep_rules=value.keep_rules,
self.allow_loopback=value.allow_loopback,
self.allow_established=value.allow_established,
self.allow_icmp=value.allow_icmp,
self.multicast_dns=value.multicast_dns,
self.allow_upnp=value.allow_upnp
@property @property
def policy(self): def policy(self):
return self.db.get("POLICY", Action.ACCEPT) return self.db.get("POLICY", Action.ACCEPT)
@@ -80,4 +98,19 @@ class FirewallManager:
def allow_established(self, value): def allow_established(self, value):
self.db.set("allow_established", "1" if value else "0") self.db.set("allow_established", "1" if value else "0")
@property
def multicast_dns(self):
return self.db.get("multicast_dns", "1") == "1"
@multicast_dns.setter
def multicast_dns(self, value):
self.db.set("multicast_dns", "1" if value else "0")
@property
def allow_upnp(self):
return self.db.get("allow_upnp", "1") == "1"
@allow_upnp.setter
def allow_upnp(self, value):
self.db.set("allow_upnp", "1" if value else "0")

View File

@@ -1,7 +1,9 @@
from enum import Enum from enum import Enum
from utils import PortType
from pydantic import BaseModel
class Rule: class Rule:
def __init__(self, proto: str, src:str, dst:str, port_src_from:str, port_dst_from:str, port_src_to:str, port_dst_to:str, action:str, mode:str): def __init__(self, proto: str, src:str, dst:str, port_src_from:str, port_dst_from:str, port_src_to:str, port_dst_to:str, action:str, mode:str, **other):
self.proto = proto self.proto = proto
self.src = src self.src = src
self.dst = dst self.dst = dst
@@ -14,20 +16,9 @@ class Rule:
self.output_mode = mode == "out" self.output_mode = mode == "out"
self.forward_mode = mode == "forward" self.forward_mode = mode == "forward"
@classmethod @classmethod
def from_dict(cls, var: dict): def from_dict(cls, var: dict):
return cls( return cls(**var)
proto=var["proto"],
src=var["src"],
dst=var["dst"],
port_dst_from=var["port_dst_from"],
port_dst_to=var["port_dst_to"],
port_src_from=var["port_src_from"],
port_src_to=var["port_src_to"],
action=var["action"],
mode=var["mode"]
)
class Protocol(str, Enum): class Protocol(str, Enum):
TCP = "tcp", TCP = "tcp",
@@ -45,3 +36,36 @@ class Action(str, Enum):
ACCEPT = "accept", ACCEPT = "accept",
DROP = "drop", DROP = "drop",
REJECT = "reject" REJECT = "reject"
class RuleModel(BaseModel):
active: bool
name: str
proto: Protocol
src: str
dst: str
port_src_from: PortType
port_dst_from: PortType
port_src_to: PortType
port_dst_to: PortType
action: Action
mode:Mode
class RuleFormAdd(BaseModel):
rules: list[RuleModel]
policy: Action
class RuleInfo(BaseModel):
rules: list[RuleModel]
policy: Action
enabled: bool
class RenameForm(BaseModel):
name:str
class FirewallSettings(BaseModel):
keep_rules: bool
allow_loopback: bool
allow_established: bool
allow_icmp: bool
multicast_dns: bool
allow_upnp: bool

View File

@@ -1,89 +1,166 @@
from modules.firewall.models import Rule, Protocol, Mode, Action from modules.firewall.models import *
from utils import nftables_int_to_json, ip_family, NFTableManager, is_ip_parse from utils import nftables_int_to_json, ip_family, NFTableManager, is_ip_parse
import copy import copy
class FiregexTables(NFTableManager): class FiregexTables(NFTableManager):
rules_chain_in = "firewall_rules_in" rules_chain_in = "firegex_firewall_rules_in"
rules_chain_out = "firewall_rules_out" rules_chain_out = "firegex_firewall_rules_out"
rules_chain_fwd = "firewall_rules_fwd" rules_chain_fwd = "firegex_firewall_rules_fwd"
filter_table = "filter"
def init_comands(self, policy:str=Action.ACCEPT, allow_loopback=False, allow_established=False, allow_icmp=False): def init_comands(self, policy:str=Action.ACCEPT, opt: FirewallSettings = None):
return [ return [
{"add":{"chain":{ {"add":{"table":{"name":self.filter_table,"family":"ip"}}},
"family":"inet", {"add":{"table":{"name":self.filter_table,"family":"ip6"}}},
"table":self.table_name,
"name":self.rules_chain_in, {"add":{"chain":{"family":"ip","table":self.filter_table, "name":"INPUT","type":"filter","hook":"input","prio":0,"policy":policy}}},
"type":"filter", {"add":{"chain":{"family":"ip6","table":self.filter_table,"name":"INPUT","type":"filter","hook":"input","prio":0,"policy":policy}}},
"hook":"prerouting", {"add":{"chain":{"family":"ip","table":self.filter_table,"name":"FORWARD","type":"filter","hook":"forward","prio":0,"policy":policy}}},
"prio":0, {"add":{"chain":{"family":"ip6","table":self.filter_table,"name":"FORWARD","type":"filter","hook":"forward","prio":0,"policy":policy}}},
"policy":policy {"add":{"chain":{"family":"ip","table":self.filter_table,"name":"OUTPUT","type":"filter","hook":"output","prio":0,"policy":Action.ACCEPT}}},
}}}, {"add":{"chain":{"family":"ip6","table":self.filter_table,"name":"OUTPUT","type":"filter","hook":"output","prio":0,"policy":Action.ACCEPT}}},
{"add":{"chain":{
"family":"inet", {"add":{"chain":{"family":"ip","table":self.filter_table,"name":self.rules_chain_in}}},
"table":self.table_name, {"add":{"chain":{"family":"ip6","table":self.filter_table,"name":self.rules_chain_in}}},
"name":self.rules_chain_fwd, {"add":{"chain":{"family":"ip","table":self.filter_table,"name":self.rules_chain_out}}},
"type":"filter", {"add":{"chain":{"family":"ip6","table":self.filter_table,"name":self.rules_chain_out}}},
"hook":"forward", {"add":{"chain":{"family":"ip","table":self.filter_table,"name":self.rules_chain_fwd}}},
"prio":0, {"add":{"chain":{"family":"ip6","table":self.filter_table,"name":self.rules_chain_fwd}}},
"policy":policy ] + (([
}}},
{"add":{"chain":{
"family":"inet",
"table":self.table_name,
"name":self.rules_chain_out,
"type":"filter",
"hook":"postrouting",
"prio":0,
"policy":Action.ACCEPT
}}},
] + ([
{ "add":{ "rule": { { "add":{ "rule": {
"family": "inet", "table": self.table_name, "chain": self.rules_chain_out, "family": "ip", "table": self.filter_table, "chain": self.rules_chain_out,
"expr": [{ "match": { "op": "==", "left": { "meta": { "key": "iif" }}, "right": "lo"}},{"accept": None}] "expr": [{ "match": { "op": "==", "left": { "meta": { "key": "iif" }}, "right": "lo"}},{"accept": None}]
}}}, }}},
{ "add":{ "rule": { { "add":{ "rule": {
"family": "inet", "table": self.table_name, "chain": self.rules_chain_in, "family": "ip", "table": self.filter_table, "chain": self.rules_chain_in,
"expr": [{ "match": { "op": "==", "left": { "meta": { "key": "iif" }}, "right": "lo"}},{"accept": None}]
}}},
{ "add":{ "rule": {
"family": "ip6", "table": self.filter_table, "chain": self.rules_chain_out,
"expr": [{ "match": { "op": "==", "left": { "meta": { "key": "iif" }}, "right": "lo"}},{"accept": None}]
}}},
{ "add":{ "rule": {
"family": "ip6", "table": self.filter_table, "chain": self.rules_chain_in,
"expr": [{ "match": { "op": "==", "left": { "meta": { "key": "iif" }}, "right": "lo"}},{"accept": None}] "expr": [{ "match": { "op": "==", "left": { "meta": { "key": "iif" }}, "right": "lo"}},{"accept": None}]
}}} }}}
] if allow_loopback else []) + ([ ] if opt.allow_loopback else []) + ([
{ "add":{ "rule": { { "add":{ "rule": {
"family": "inet", "table": self.table_name, "chain": self.rules_chain_in, "family": "ip", "table": self.filter_table, "chain": self.rules_chain_in,
"expr": [{ "match": {"op": "in", "left": { "ct": { "key": "state" }},"right": ["established"]} }, { "accept": None }] "expr": [{ "match": {"op": "in", "left": { "ct": { "key": "state" }},"right": ["established", "related"]} }, { "accept": None }]
}}}, }}},
{ "add":{ "rule": { { "add":{ "rule": {
"family": "inet", "table": self.table_name, "chain": self.rules_chain_fwd, "family": "ip", "table": self.filter_table, "chain": self.rules_chain_fwd,
"expr": [{ "match": {"op": "in", "left": { "ct": { "key": "state" }},"right": ["established"]} }, { "accept": None }] "expr": [{ "match": {"op": "in", "left": { "ct": { "key": "state" }},"right": ["established", "related"]} }, { "accept": None }]
}}} }}},
] if allow_established else []) + ([
{ "add":{ "rule": { { "add":{ "rule": {
"family": "inet", "table": self.table_name, "chain": self.rules_chain_in, "family": "ip", "table": self.filter_table, "chain": self.rules_chain_out,
"expr": [{ "match": {"op": "in", "left": { "ct": { "key": "state" }},"right": ["established", "related"]} }, { "accept": None }]
}}},
{ "add":{ "rule": {
"family": "ip6", "table": self.filter_table, "chain": self.rules_chain_in,
"expr": [{ "match": {"op": "in", "left": { "ct": { "key": "state" }},"right": ["established", "related"]} }, { "accept": None }]
}}},
{ "add":{ "rule": {
"family": "ip6", "table": self.filter_table, "chain": self.rules_chain_fwd,
"expr": [{ "match": {"op": "in", "left": { "ct": { "key": "state" }},"right": ["established", "related"]} }, { "accept": None }]
}}},
{ "add":{ "rule": {
"family": "ip6", "table": self.filter_table, "chain": self.rules_chain_out,
"expr": [{ "match": {"op": "in", "left": { "ct": { "key": "state" }},"right": ["established", "related"]} }, { "accept": None }]
}}}
] if opt.allow_established else []) + ([
{ "add":{ "rule": {
"family": "ip", "table": self.filter_table, "chain": self.rules_chain_in,
"expr": [{ "match": { "op": "==", "left": { "meta": { "key": "l4proto" } }, "right": "icmp"} }, { "accept": None }] "expr": [{ "match": { "op": "==", "left": { "meta": { "key": "l4proto" } }, "right": "icmp"} }, { "accept": None }]
}}}, }}},
{ "add":{ "rule": { { "add":{ "rule": {
"family": "inet", "table": self.table_name, "chain": self.rules_chain_fwd, "family": "ip", "table": self.filter_table, "chain": self.rules_chain_fwd,
"expr": [{ "match": { "op": "==", "left": { "meta": { "key": "l4proto" } }, "right": "icmp"} }, { "accept": None }] "expr": [{ "match": { "op": "==", "left": { "meta": { "key": "l4proto" } }, "right": "icmp"} }, { "accept": None }]
}}}, }}},
{ "add":{ "rule": { { "add":{ "rule": {
"family": "inet", "table": self.table_name, "chain": self.rules_chain_in, "family": "ip6", "table": self.filter_table, "chain": self.rules_chain_in,
"expr": [{ "match": { "op": "==", "left": { "meta": { "key": "l4proto" } }, "right": "ipv6-icmp"} }, { "accept": None }] "expr": [{ "match": { "op": "==", "left": { "meta": { "key": "l4proto" } }, "right": "ipv6-icmp"} }, { "accept": None }]
}}}, }}},
{ "add":{ "rule": { { "add":{ "rule": {
"family": "inet", "table": self.table_name, "chain": self.rules_chain_fwd, "family": "ip6", "table": self.filter_table, "chain": self.rules_chain_fwd,
"expr": [{ "match": { "op": "==", "left": { "meta": { "key": "l4proto" } }, "right": "ipv6-icmp"} }, { "accept": None }] "expr": [{ "match": { "op": "==", "left": { "meta": { "key": "l4proto" } }, "right": "ipv6-icmp"} }, { "accept": None }]
}}} }}}
] if allow_icmp else []) ] if opt.allow_icmp else []) + ([
{ "add":{ "rule": {
"family": "ip", "table": self.filter_table, "chain": self.rules_chain_in,
"expr": [
{ 'match': {'left': {'payload': {'protocol': "ip", 'field': 'daddr'}}, 'op': '==', 'right': nftables_int_to_json("224.0.0.251/32")} },
{ 'match': {'left': {'payload': {'protocol': "udp", 'field': 'dport'}}, 'op': '==', 'right': 5353} },
{ "accept": None }
]
}}},
{ "add":{ "rule": {
"family": "ip6", "table": self.filter_table, "chain": self.rules_chain_in,
"expr": [
{ 'match': {'left': {'payload': {'protocol': "ip6", 'field': 'daddr'}}, 'op': '==', 'right': nftables_int_to_json("ff02::fb/128")} },
{ 'match': {'left': {'payload': {'protocol': "udp", 'field': 'dport'}}, 'op': '==', 'right': 5353} },
{ "accept": None }
]
}}},
] if opt.multicast_dns else []) + ([
{ "add":{ "rule": {
"family": "ip", "table": self.filter_table, "chain": self.rules_chain_in,
"expr": [
{ 'match': {'left': {'payload': {'protocol': "ip", 'field': 'daddr'}}, 'op': '==', 'right': nftables_int_to_json("239.255.255.250/32")} },
{ 'match': {'left': {'payload': {'protocol': "udp", 'field': 'dport'}}, 'op': '==', 'right': 1900} },
{ "accept": None }
]
}}},
{ "add":{ "rule": {
"family": "ip6", "table": self.filter_table, "chain": self.rules_chain_in,
"expr": [
{ 'match': {'left': {'payload': {'protocol': "ip6", 'field': 'daddr'}}, 'op': '==', 'right': nftables_int_to_json("ff02::f/128")} },
{ 'match': {'left': {'payload': {'protocol': "udp", 'field': 'dport'}}, 'op': '==', 'right': 1900} },
{ "accept": None }
]
}}},
] if opt.allow_upnp else [])) if opt else []
def __init__(self): def __init__(self):
super().__init__(self.init_comands(),[ super().__init__(self.init_comands(),[
{"flush":{"chain":{"table":self.table_name,"family":"inet", "name":self.rules_chain_in}}}, {"add":{"chain":{"family":"ip","table":self.filter_table, "name":"INPUT","type":"filter","hook":"input","prio":0,"policy":Action.ACCEPT}}},
{"delete":{"chain":{"table":self.table_name,"family":"inet", "name":self.rules_chain_in}}}, {"add":{"chain":{"family":"ip6","table":self.filter_table,"name":"INPUT","type":"filter","hook":"input","prio":0,"policy":Action.ACCEPT}}},
{"flush":{"chain":{"table":self.table_name,"family":"inet", "name":self.rules_chain_out}}}, {"add":{"chain":{"family":"ip","table":self.filter_table,"name":"FORWARD","type":"filter","hook":"forward","prio":0,"policy":Action.ACCEPT}}},
{"delete":{"chain":{"table":self.table_name,"family":"inet", "name":self.rules_chain_out}}}, {"add":{"chain":{"family":"ip6","table":self.filter_table,"name":"FORWARD","type":"filter","hook":"forward","prio":0,"policy":Action.ACCEPT}}},
{"flush":{"chain":{"table":self.table_name,"family":"inet", "name":self.rules_chain_fwd}}}, {"flush":{"chain":{"table":self.filter_table,"family":"ip", "name":self.rules_chain_in}}},
{"delete":{"chain":{"table":self.table_name,"family":"inet", "name":self.rules_chain_fwd}}}, {"flush":{"chain":{"table":self.filter_table,"family":"ip", "name":self.rules_chain_out}}},
{"flush":{"chain":{"table":self.filter_table,"family":"ip", "name":self.rules_chain_fwd}}},
{"flush":{"chain":{"table":self.filter_table,"family":"ip6", "name":self.rules_chain_in}}},
{"flush":{"chain":{"table":self.filter_table,"family":"ip6", "name":self.rules_chain_out}}},
{"flush":{"chain":{"table":self.filter_table,"family":"ip6", "name":self.rules_chain_fwd}}},
]) ])
def set(self, srvs:list[Rule], policy:str="accept", allow_loopback=False, allow_established=False, allow_icmp=False): def chain_to_firegex(self, chain:str):
match chain:
case "INPUT": return self.rules_chain_in
case "OUTPUT": return self.rules_chain_out
case "FORWARD": return self.rules_chain_fwd
return None
def insert_firegex_chains(self):
rules:list[dict] = list(self.list_rules(tables=[self.filter_table], chains=["INPUT", "OUTPUT", "FORWARD"]))
for family in ["ip", "ip6"]:
for chain in ["INPUT", "OUTPUT", "FORWARD"]:
found = False
rule_to_add = [{ "jump": { "target": self.chain_to_firegex(chain) }}]
for r in rules:
if r.get("family") == family and r.get("table") == "filter" and r.get("chain") == chain and r.get("expr") == rule_to_add:
found = True
break
if found: continue
yield { "add":{ "rule": {
"family": family,
"table": self.filter_table,
"chain": chain,
"expr": rule_to_add
}}}
def set(self, srvs:list[Rule], policy:str=Action.ACCEPT, opt:FirewallSettings = None):
srvs = list(srvs) srvs = list(srvs)
self.reset() self.reset()
if policy == Action.REJECT: if policy == Action.REJECT:
@@ -99,7 +176,8 @@ class FiregexTables(NFTableManager):
action=Action.REJECT, action=Action.REJECT,
mode=Mode.IN mode=Mode.IN
)) ))
rules = self.init_comands(policy, allow_loopback=allow_loopback, allow_established=allow_established, allow_icmp=allow_icmp) + self.get_rules(*srvs)
rules = self.init_comands(policy, opt) + list(self.insert_firegex_chains()) + self.get_rules(*srvs)
self.cmd(*rules) self.cmd(*rules)
def get_rules(self,*srvs:Rule): def get_rules(self,*srvs:Rule):
@@ -113,18 +191,22 @@ class FiregexTables(NFTableManager):
final_srvs.append(udp_rule) final_srvs.append(udp_rule)
final_srvs.append(ele) final_srvs.append(ele)
families = ["ip", "ip6"]
for srv in final_srvs: for srv in final_srvs:
ip_filters = [] ip_filters = []
if srv.src != "": if srv.src != "":
if is_ip_parse(srv.src): if is_ip_parse(srv.src):
ip_filters.append({'match': {'left': {'payload': {'protocol': ip_family(srv.src), 'field': 'saddr'}}, 'op': '==', 'right': nftables_int_to_json(srv.src)}}) ip_filters.append({'match': {'left': {'payload': {'protocol': ip_family(srv.src), 'field': 'saddr'}}, 'op': '==', 'right': nftables_int_to_json(srv.src)}})
families = [ip_family(srv.src)]
else: else:
ip_filters.append({"match": { "op": "==", "left": { "meta": { "key": "iifname" } }, "right": srv.src} }) ip_filters.append({"match": { "op": "==", "left": { "meta": { "key": "iifname" } }, "right": srv.src} })
if srv.dst != "": if srv.dst != "":
if is_ip_parse(srv.dst): if is_ip_parse(srv.dst):
ip_filters.append({'match': {'left': {'payload': {'protocol': ip_family(srv.dst), 'field': 'daddr'}}, 'op': '==', 'right': nftables_int_to_json(srv.dst)}}) ip_filters.append({'match': {'left': {'payload': {'protocol': ip_family(srv.dst), 'field': 'daddr'}}, 'op': '==', 'right': nftables_int_to_json(srv.dst)}})
families = [ip_family(srv.dst)]
else: else:
ip_filters.append({"match": { "op": "==", "left": { "meta": { "key": "oifname" } }, "right": srv.dst} }) ip_filters.append({"match": { "op": "==", "left": { "meta": { "key": "oifname" } }, "right": srv.dst} })
@@ -140,12 +222,13 @@ class FiregexTables(NFTableManager):
port_filters.append({'match': {'left': {'meta': {'key': 'l4proto'}}, 'op': '==', 'right': srv.proto}}) #filter the protocol if no port is specified port_filters.append({'match': {'left': {'meta': {'key': 'l4proto'}}, 'op': '==', 'right': srv.proto}}) #filter the protocol if no port is specified
end_rules = [{'accept': None} if srv.action == "accept" else {'reject': {}} if (srv.action == "reject" and not srv.output_mode) else {'drop': None}] end_rules = [{'accept': None} if srv.action == "accept" else {'reject': {}} if (srv.action == "reject" and not srv.output_mode) else {'drop': None}]
#If srv.output_mode is True, then the rule is in the output chain, so the reject action is not allowed
for fam in families:
rules.append({ "add":{ "rule": { rules.append({ "add":{ "rule": {
"family": "inet", "family": fam,
"table": self.table_name, "table": self.filter_table,
"chain": self.rules_chain_out if srv.output_mode else self.rules_chain_in if srv.input_mode else self.rules_chain_fwd, "chain": self.rules_chain_out if srv.output_mode else self.rules_chain_in if srv.input_mode else self.rules_chain_fwd,
"expr": ip_filters + port_filters + end_rules "expr": ip_filters + port_filters + end_rules
#If srv.output_mode is True, then the rule is in the output chain, so the reject action is not allowed
}}}) }}})
return rules return rules

View File

@@ -1,8 +1,8 @@
import base64 import base64
class Service: class Service:
def __init__(self, id: str, status: str, port: int, name: str, proto: str, ip_int: str): def __init__(self, service_id: str, status: str, port: int, name: str, proto: str, ip_int: str, **other):
self.id = id self.id = service_id
self.status = status self.status = status
self.port = port self.port = port
self.name = name self.name = name
@@ -11,36 +11,20 @@ class Service:
@classmethod @classmethod
def from_dict(cls, var: dict): def from_dict(cls, var: dict):
return cls( return cls(**var)
id=var["service_id"],
status=var["status"],
port=var["port"],
name=var["name"],
proto=var["proto"],
ip_int=var["ip_int"]
)
class Regex: class Regex:
def __init__(self, id: int, regex: bytes, mode: str, service_id: str, is_blacklist: bool, blocked_packets: int, is_case_sensitive: bool, active: bool): def __init__(self, regex_id: int, regex: bytes, mode: str, service_id: str, is_blacklist: bool, blocked_packets: int, is_case_sensitive: bool, active: bool, **other):
self.regex = regex self.regex = regex
self.mode = mode self.mode = mode
self.service_id = service_id self.service_id = service_id
self.is_blacklist = is_blacklist self.is_blacklist = is_blacklist
self.blocked_packets = blocked_packets self.blocked_packets = blocked_packets
self.id = id self.id = regex_id
self.is_case_sensitive = is_case_sensitive self.is_case_sensitive = is_case_sensitive
self.active = active self.active = active
@classmethod @classmethod
def from_dict(cls, var: dict): def from_dict(cls, var: dict):
return cls( return cls(**var)
id=var["regex_id"],
regex=base64.b64decode(var["regex"]),
mode=var["mode"],
service_id=var["service_id"],
is_blacklist=var["is_blacklist"],
blocked_packets=var["blocked_packets"],
is_case_sensitive=var["is_case_sensitive"],
active=var["active"]
)

View File

@@ -1,5 +1,5 @@
class Service: class Service:
def __init__(self, service_id: str, active: bool, public_port: int, proxy_port: int, name: str, proto: str, ip_src: str, ip_dst:str): def __init__(self, service_id: str, active: bool, public_port: int, proxy_port: int, name: str, proto: str, ip_src: str, ip_dst:str, **other):
self.service_id = service_id self.service_id = service_id
self.active = active self.active = active
self.public_port = public_port self.public_port = public_port
@@ -11,13 +11,4 @@ class Service:
@classmethod @classmethod
def from_dict(cls, var: dict): def from_dict(cls, var: dict):
return cls( return cls(**var)
service_id=var["service_id"],
active=var["active"],
public_port=var["public_port"],
proxy_port=var["proxy_port"],
name=var["name"],
proto=var["proto"],
ip_src=var["ip_src"],
ip_dst=var["ip_dst"]
)

View File

@@ -1,44 +1,11 @@
import sqlite3 import sqlite3
from fastapi import APIRouter, HTTPException from fastapi import APIRouter, HTTPException
from pydantic import BaseModel
from utils.sqlite import SQLite from utils.sqlite import SQLite
from utils import ip_parse, ip_family, socketio_emit, PortType from utils import ip_parse, ip_family, socketio_emit
from utils.models import ResetRequest, StatusMessageModel from utils.models import ResetRequest, StatusMessageModel
from modules.firewall.nftables import FiregexTables from modules.firewall.nftables import FiregexTables
from modules.firewall.firewall import FirewallManager from modules.firewall.firewall import FirewallManager
from modules.firewall.models import Protocol, Mode, Action from modules.firewall.models import *
class RuleModel(BaseModel):
active: bool
name: str
proto: Protocol
src: str
dst: str
port_src_from: PortType
port_dst_from: PortType
port_src_to: PortType
port_dst_to: PortType
action: Action
mode:Mode
class RuleFormAdd(BaseModel):
rules: list[RuleModel]
policy: Action
class RuleInfo(BaseModel):
rules: list[RuleModel]
policy: Action
enabled: bool
class RenameForm(BaseModel):
name:str
class FirewallSettings(BaseModel):
keep_rules: bool
allow_loopback: bool
allow_established: bool
allow_icmp: bool
db = SQLite('db/firewall-rules.db', { db = SQLite('db/firewall-rules.db', {
'rules': { 'rules': {
@@ -101,20 +68,12 @@ async def apply_changes():
@app.get("/settings", response_model=FirewallSettings) @app.get("/settings", response_model=FirewallSettings)
async def get_settings(): async def get_settings():
"""Get the firewall settings""" """Get the firewall settings"""
return { return firewall.settings
"keep_rules": firewall.keep_rules,
"allow_loopback": firewall.allow_loopback,
"allow_established": firewall.allow_established,
"allow_icmp": firewall.allow_icmp
}
@app.post("/settings/set", response_model=StatusMessageModel) @app.post("/settings/set", response_model=StatusMessageModel)
async def set_settings(form: FirewallSettings): async def set_settings(form: FirewallSettings):
"""Set the firewall settings""" """Set the firewall settings"""
firewall.keep_rules = form.keep_rules firewall.settings = form
firewall.allow_loopback = form.allow_loopback
firewall.allow_established = form.allow_established
firewall.allow_icmp = form.allow_icmp
return await apply_changes() return await apply_changes()
@app.get('/rules', response_model=RuleInfo) @app.get('/rules', response_model=RuleInfo)

View File

@@ -50,7 +50,9 @@ export type FirewallSettings = {
keep_rules: boolean, keep_rules: boolean,
allow_loopback: boolean, allow_loopback: boolean,
allow_established: boolean, allow_established: boolean,
allow_icmp: boolean allow_icmp: boolean,
multicast_dns: boolean,
allow_upnp: boolean
} }

View File

@@ -5,7 +5,7 @@ import { FirewallSettings, firewall } from '../../components/Firewall/utils';
export function SettingsModal({ opened, onClose }:{ opened:boolean, onClose:()=>void }) { export function SettingsModal({ opened, onClose }:{ opened:boolean, onClose:()=>void }) {
const [settings, setSettings] = useState<FirewallSettings>({keep_rules:false, allow_established:true, allow_loopback:true, allow_icmp:true}) const [settings, setSettings] = useState<FirewallSettings>({keep_rules:false, allow_established:true, allow_loopback:true, allow_icmp:true, allow_upnp:true, multicast_dns:true})
useEffect(()=>{ useEffect(()=>{
firewall.settings().then( res => { firewall.settings().then( res => {
@@ -40,6 +40,10 @@ export function SettingsModal({ opened, onClose }:{ opened:boolean, onClose:()=>
<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})}/> <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" /> <Space h="md" />
<Switch label="Allow icmp packets" checked={settings.allow_icmp} onChange={v => setSettings({...settings, allow_icmp:v.target.checked})}/> <Switch label="Allow icmp packets" checked={settings.allow_icmp} onChange={v => setSettings({...settings, allow_icmp:v.target.checked})}/>
<Space h="md" />
<Switch label="Allow multicast DNS" checked={settings.multicast_dns} onChange={v => setSettings({...settings, multicast_dns:v.target.checked})}/>
<Space h="md" />
<Switch label="Allow UPnP protocol" checked={settings.allow_upnp} onChange={v => setSettings({...settings, allow_upnp:v.target.checked})}/>
<Group position="right" mt="md"> <Group position="right" mt="md">
<Button loading={submitLoading} onClick={submitRequest}>Save Setting</Button> <Button loading={submitLoading} onClick={submitRequest}>Save Setting</Button>