firegex/backend/modules/porthijack/firewall.py
2026-07-23 13:39:01 +02:00

85 lines
2.6 KiB
Python

import asyncio
from modules.porthijack.nftables import FiregexTables
from modules.porthijack.models import Service
from utils.sqlite import SQLite
nft = FiregexTables()
class ServiceNotFoundException(Exception):
pass
class ServiceManager:
def __init__(self, srv: Service, db):
self.srv = srv
self.db = db
self.active = False
self.lock = asyncio.Lock()
async def enable(self):
if not self.active:
async with self.lock:
nft.delete(self.srv)
nft.add(self.srv)
self._set_status(True)
async def disable(self,persist:bool=True):
if self.active:
async with self.lock:
nft.delete(self.srv)
self._set_status(False,persist=persist)
async def refresh(self, srv:Service):
self.srv = srv
if self.active:
await self.restart()
def _set_status(self,active,persist:bool=True):
self.active = active
if persist:
self.db.query("UPDATE services SET active = ? WHERE service_id = ?;", active, self.srv.service_id)
async def restart(self):
await self.disable()
await self.enable()
class FirewallManager:
def __init__(self, db:SQLite):
self.db = db
self.service_table: dict[str, ServiceManager] = {}
self.lock = asyncio.Lock()
async def close(self):
for key in list(self.service_table.keys()):
try:
await self.remove(key, persist=False)
except Exception:
# Don't let one broken service block shutdown of the others
self.service_table.pop(key, None)
async def remove(self,srv_id,persist:bool=True):
async with self.lock:
if srv_id in self.service_table:
await self.service_table[srv_id].disable(persist=persist)
del self.service_table[srv_id]
async def init(self):
nft.init()
await self.reload()
async def reload(self):
async with self.lock:
for srv in self.db.query('SELECT * FROM services;'):
srv = Service.from_dict(srv)
if srv.service_id in self.service_table:
continue
self.service_table[srv.service_id] = ServiceManager(srv, self.db)
if srv.active:
await self.service_table[srv.service_id].enable()
def get(self,srv_id) -> ServiceManager:
if srv_id in self.service_table:
return self.service_table[srv_id]
else:
raise ServiceNotFoundException()