diff --git a/backend/modules/firewall/nftables.py b/backend/modules/firewall/nftables.py index b44bc0f..3a01ef9 100644 --- a/backend/modules/firewall/nftables.py +++ b/backend/modules/firewall/nftables.py @@ -1,5 +1,5 @@ from modules.firewall.models import Rule -from utils import nftables_int_to_json, ip_parse, ip_family, NFTableManager, nftables_json_to_int +from utils import nftables_int_to_json, ip_parse, ip_family, NFTableManager class FiregexHijackRule(): @@ -80,6 +80,13 @@ class FiregexTables(NFTableManager): for ele in srvs[::-1]: self.add(ele) def add(self, srv:Rule): + ip_filters = [] + if srv.ip_src.lower() != "any" and srv.ip_dst.lower() != "any": + ip_filters = [ + {'match': {'left': {'payload': {'protocol': ip_family(srv.ip_src), 'field': 'saddr'}}, 'op': '==', 'right': nftables_int_to_json(srv.ip_src)}}, + {'match': {'left': {'payload': {'protocol': ip_family(srv.ip_dst), 'field': 'daddr'}}, 'op': '==', 'right': nftables_int_to_json(srv.ip_dst)}}, + ] + port_filters = [] if srv.proto != "any": if srv.port_src_from != 1 or srv.port_src_to != 65535: #Any Port @@ -90,15 +97,13 @@ class FiregexTables(NFTableManager): port_filters.append({'match': {'left': {'payload': {'protocol': str(srv.proto), 'field': 'dport'}}, 'op': '<=', 'right': int(srv.port_dst_to)}}) if len(port_filters) == 0: port_filters.append({'match': {'left': {'payload': {'protocol': str(srv.proto), 'field': 'sport'}}, 'op': '!=', 'right': 0}}) #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}] + self.cmd({ "insert":{ "rule": { "family": "inet", "table": self.table_name, "chain": self.rules_chain_out if srv.output_mode else self.rules_chain_in, - "expr": [ - {'match': {'left': {'payload': {'protocol': ip_family(srv.ip_src), 'field': 'saddr'}}, 'op': '==', 'right': nftables_int_to_json(srv.ip_src)}}, - {'match': {'left': {'payload': {'protocol': ip_family(srv.ip_dst), 'field': 'daddr'}}, 'op': '==', 'right': nftables_int_to_json(srv.ip_dst)}}, - ] + port_filters + - [{'accept': None} if srv.action == "accept" else {'reject': {}} if (srv.action == "reject" and not srv.output_mode) else {'drop': None}] + "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 }}}) \ No newline at end of file diff --git a/backend/routers/firewall.py b/backend/routers/firewall.py index 3c835ae..e415c21 100644 --- a/backend/routers/firewall.py +++ b/backend/routers/firewall.py @@ -108,42 +108,16 @@ async def disable_firewall(): db.set("ENABLED", "0") return await apply_changes() -@app.get('/rule/{rule_id}/disable', response_model=StatusMessageModel) -async def service_disable(rule_id: str): - """Request disabling a specific rule""" - if len(db.query('SELECT 1 FROM rules WHERE rule_id = ?;', rule_id)) == 0: - return {'status': 'Rule not found'} - db.query('UPDATE rules SET active = 0 WHERE rule_id = ?;', rule_id) - return await apply_changes() - -@app.get('/rule/{rule_id}/enable', response_model=StatusMessageModel) -async def service_start(rule_id: str): - """Request the enabling a specific rule""" - if len(db.query('SELECT 1 FROM rules WHERE rule_id = ?;', rule_id)) == 0: - return {'status': 'Rule not found'} - db.query('UPDATE rules SET active = 1 WHERE rule_id = ?;', rule_id) - return await apply_changes() - -@app.post('/service/{rule_id}/rename', response_model=StatusMessageModel) -async def service_rename(rule_id: str, form: RenameForm): - """Request to change the name of a specific service""" - if len(db.query('SELECT 1 FROM rules WHERE rule_id = ?;', rule_id)) == 0: - return {'status': 'Rule not found'} - form.name = refactor_name(form.name) - if not form.name: return {'status': 'The name cannot be empty!'} - try: - db.query('UPDATE rules SET name=? WHERE rule_id = ?;', form.name, rule_id) - except sqlite3.IntegrityError: - return {'status': 'This name is already used'} - await refresh_frontend() - return {'status': 'ok'} - def parse_and_check_rule(rule:RuleModel): - try: - rule.ip_src = ip_parse(rule.ip_src) - rule.ip_dst = ip_parse(rule.ip_dst) - except ValueError: - return {"status":"Invalid address"} + + if rule.ip_src.lower().strip() == "any" or rule.ip_dst.lower().split() == "any": + rule.ip_dst = rule.ip_src = "any" + else: + try: + rule.ip_src = ip_parse(rule.ip_src) + rule.ip_dst = ip_parse(rule.ip_dst) + except ValueError: + return {"status":"Invalid address"} rule.port_dst_from, rule.port_dst_to = min(rule.port_dst_from, rule.port_dst_to), max(rule.port_dst_from, rule.port_dst_to) rule.port_src_from, rule.port_src_to = min(rule.port_src_from, rule.port_src_to), max(rule.port_src_from, rule.port_src_to) @@ -155,7 +129,6 @@ def parse_and_check_rule(rule:RuleModel): if rule.action not in ["accept", "drop", "reject"]: return {"status":"Invalid action"} return rule - @app.post('/rules/set', response_model=RuleAddResponse) async def add_new_service(form: RuleFormAdd):