diff --git a/.dockerignore b/.dockerignore index 4cc0169..a9d1337 100755 --- a/.dockerignore +++ b/.dockerignore @@ -3,7 +3,7 @@ docker-compose.yml **/*.pyc **/__pycache__/ -/.vscode/ +**/.vscode/** #Node filters diff --git a/.gitignore b/.gitignore index 05a3e38..9593618 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ **/*.pyc **/__pycache__/ -/.vscode/** +**/.vscode/** /.mypy_cache/** **/node_modules diff --git a/backend/.vscode/settings.json b/backend/.vscode/settings.json deleted file mode 100644 index a1aef15..0000000 --- a/backend/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "python.linting.pylintEnabled": false, - "python.linting.mypyEnabled": true, - "python.linting.enabled": true -} \ No newline at end of file diff --git a/backend/modules/firegex.py b/backend/modules/firegex.py index 2880008..64453df 100644 --- a/backend/modules/firegex.py +++ b/backend/modules/firegex.py @@ -71,7 +71,7 @@ class FiregexTables(IPTables): def add_output(self, queue_range, proto = None, port = None, ip_int = None): init, end = queue_range if init > end: init, end = end, init - self.append_rule(FilterTypes.OUTPUT,"NFQUEUE" + self.append_rule(FilterTypes.OUTPUT,"NFQUEUE", * (["-p", str(proto)] if proto else []), * (["-s", str(ip_int)] if ip_int else []), * (["--sport", str(port)] if port else []), @@ -92,8 +92,9 @@ class FiregexTables(IPTables): def get(self) -> List[FiregexFilter]: res = [] + iptables_filters = self.list() for filter_type in [FilterTypes.INPUT, FilterTypes.OUTPUT]: - for filter in self.list()[filter_type]: + for filter in iptables_filters[filter_type]: port = filter.sport() if filter_type == FilterTypes.OUTPUT else filter.dport() queue = filter.nfqueue() if queue and port: @@ -133,13 +134,13 @@ class FiregexInterceptor: def func_wrap(ll_data, ll_proto_id, data, ctx, *args): pkt_parsed = ip6.IP6(data) if self.ipv6 else ip.IP(data) try: - data = None + pkt_data = None if not pkt_parsed[tcp.TCP] is None: - data = pkt_parsed[tcp.TCP].body_bytes - if not pkt_parsed[tcp.TCP] is None: - data = pkt_parsed[udp.UDP].body_bytes - if data: - if func(data): + pkt_data = pkt_parsed[tcp.TCP].body_bytes + elif not pkt_parsed[udp.UDP] is None: + pkt_data = pkt_parsed[udp.UDP].body_bytes + if pkt_data: + if func(pkt_data): return data, interceptor.NF_ACCEPT elif pkt_parsed[tcp.TCP]: pkt_parsed[tcp.TCP].flags &= 0x00 diff --git a/backend/modules/firewall.py b/backend/modules/firewall.py index 8a0e376..3a76673 100644 --- a/backend/modules/firewall.py +++ b/backend/modules/firewall.py @@ -45,7 +45,7 @@ class FirewallManager: continue self.proxy_table[srv.id] = ServiceManager(srv, self.db) - await self.proxy_table[srv.id].next(srv["status"]) + await self.proxy_table[srv.id].next(srv.status) async def _stats_updater(self, callback): try: @@ -111,7 +111,7 @@ class ServiceManager: def __init__(self, srv: Service, db): self.srv = srv self.db = db - self.iptables = FiregexTables(self.srv.ipv6) + self.firegextable = FiregexTables(self.srv.ipv6) self.status = STATUS.STOP self.filters: Dict[int, FiregexFilter] = {} self._update_filters_from_db() @@ -137,22 +137,19 @@ class ServiceManager: for f in new_filters: if not f in old_filters: filter = [ele for ele in regexes if ele.id == f][0] - self.filters[f] = FiregexFilter.from_regex(filter) + self.filters[f] = RegexFilter.from_regex(filter) def __update_status_db(self, status): - self.db.query("UPDATE services SET status = ? WHERE service_id = ?;", status, self.srv["service_id"]) + self.db.query("UPDATE services SET status = ? WHERE service_id = ?;", status, self.srv.id) async def next(self,to): async with self.lock: - return self._next(to) - - def _next(self, to): - if (self.status, to) == (STATUS.ACTIVE, STATUS.STOP): - self.proxy.stop() - self._set_status(to) - # PAUSE -> ACTIVE - elif (self.status, to) == (STATUS.STOP, STATUS.ACTIVE): - self.proxy.restart() + if (self.status, to) == (STATUS.ACTIVE, STATUS.STOP): + self.stop() + self._set_status(to) + # PAUSE -> ACTIVE + elif (self.status, to) == (STATUS.STOP, STATUS.ACTIVE): + self.restart() def _stats_updater(self,filter:RegexFilter): self.db.query("UPDATE regexes SET blocked_packets = ? WHERE regex_id = ?;", filter.blocked, filter.id) @@ -167,7 +164,7 @@ class ServiceManager: def start(self): if not self.interceptor: - self.iptables.delete_by_srv(self.srv) + self.firegextable.delete_by_srv(self.srv) def regex_filter(pkt, by_client): try: for filter in self.filters.values(): @@ -178,11 +175,11 @@ class ServiceManager: return False except IndexError: pass return True - self.interceptor = self.iptables.add(self.srv["proto"], self.srv["port"], self.srv["ip_int"], regex_filter) + self.interceptor = self.firegextable.add(FiregexFilter(self.srv.proto,self.srv.port, self.srv.ip_int, func=regex_filter)) self._set_status(STATUS.ACTIVE) def stop(self): - self.iptables.delete_by_srv(self.srv) + self.firegextable.delete_by_srv(self.srv) if self.interceptor: self.interceptor.stop() self.interceptor = None diff --git a/backend/modules/iptables.py b/backend/modules/iptables.py index edeea5b..0eb7f76 100644 --- a/backend/modules/iptables.py +++ b/backend/modules/iptables.py @@ -12,6 +12,9 @@ class Rule(): self.destination = destination self.details = details + def __repr__(self) -> str: + return f"Rule {self.id} : {self.target}, {self.prot}, {self.opt}, {self.source}, {self.destination}, {self.details}" + def dport(self) -> Union[int, None]: port = re.findall(r"dpt:([0-9]+)", self.details) return int(port[0]) if port else None @@ -49,7 +52,7 @@ class IPTables: if line.startswith("Chain"): chain_name = line.split()[1] res[chain_name] = [] - elif line.split()[0].isnumeric(): + elif line and line.split()[0].isnumeric(): parsed = re.findall(r"([^ ]*)[ ]{,10}([^ ]*)[ ]{,5}([^ ]*)[ ]{,5}([^ ]*)[ ]{,5}([^ ]*)[ ]+([^ ]*)[ ]+(.*)", line) if len(parsed) > 0: parsed = parsed[0] @@ -60,7 +63,7 @@ class IPTables: opt=parsed[3].strip(), source=parsed[4].strip(), destination=parsed[5].strip(), - details=" ".join(parsed[6:]).strip() if len(parsed[0]) >= 7 else "" + details=" ".join(parsed[6:]).strip() if len(parsed) >= 7 else "" )) return res diff --git a/backend/modules/sqlite.py b/backend/modules/sqlite.py index 80d690f..f0fbf93 100644 --- a/backend/modules/sqlite.py +++ b/backend/modules/sqlite.py @@ -1,6 +1,7 @@ from typing import Union import json, sqlite3, os from hashlib import md5 +import base64 class SQLite(): def __init__(self, db_name: str) -> None: @@ -116,7 +117,7 @@ class Service: class Regex: def __init__(self, id: int, regex: str, mode: str, service_id: str, is_blacklist: bool, blocked_packets: int, is_case_sensitive: bool, active: bool): - self.regex = regex + self.regex = base64.b64decode(regex) self.mode = mode self.service_id = service_id self.is_blacklist = is_blacklist diff --git a/tests/firegexapi.py b/tests/firegexapi.py index 4b521bc..8ac35ef 100644 --- a/tests/firegexapi.py +++ b/tests/firegexapi.py @@ -75,10 +75,6 @@ class FiregexAPI: req = self.s.get(f"{self.address}api/service/{service_id}/start") return req.json()["status"] == "ok" - def pause(self,service_id): - req = self.s.get(f"{self.address}api/service/{service_id}/pause") - return req.json()["status"] == "ok" - def stop(self,service_id): req = self.s.get(f"{self.address}api/service/{service_id}/stop") return req.json()["status"] == "ok" diff --git a/tests/test.py b/tests/test.py index 66e32cc..4685a57 100755 --- a/tests/test.py +++ b/tests/test.py @@ -58,11 +58,11 @@ else: puts(f"Test Failed: Couldn't create service ✗", color=colors.red); exit( #Delete the Service and exit def exit_test(status_code=0): - #if service_created: - # if(firegex.delete(service)): - # puts(f"Sucessfully delete service with id {service} ✔", color=colors.green) - # else: - # puts(f"Test Failed: Couldn't delete service ✗", color=colors.red); exit(1) + if service_created: + if(firegex.delete(service)): + puts(f"Sucessfully delete service with id {service} ✔", color=colors.green) + else: + puts(f"Test Failed: Couldn't delete service ✗", color=colors.red); exit(1) sep() server.terminate() exit(status_code) @@ -120,6 +120,7 @@ def checkRegex(regex): if not sendCheckData(secrets.token_bytes(200) + secret + secrets.token_bytes(200)): puts(f"The malicious request was successfully blocked ✔", color=colors.green) n_blocked += 1 + sleep(10) if firegex.get_regex(r["id"])["n_packets"] == n_blocked: puts(f"The packed was reported as blocked ✔", color=colors.green) else: @@ -132,7 +133,7 @@ def checkRegex(regex): checkRegex(regex) #Pause the proxy -if(firegex.pause(service)): puts(f"Sucessfully paused service with id {service} ✔", color=colors.green) +if(firegex.stop(service)): puts(f"Sucessfully paused service with id {service} ✔", color=colors.green) else: puts(f"Test Failed: Coulnd't pause the service ✗", color=colors.red); exit_test(1) #Check if it's actually paused @@ -140,49 +141,8 @@ if sendCheckData(secrets.token_bytes(200) + secret + secrets.token_bytes(200)): puts(f"The request wasn't blocked ✔", color=colors.green) else: puts(f"Test Failed: The request was blocked when it shouldn't have", color=colors.red) -#Stop the proxy -if(firegex.stop(service)): puts(f"Sucessfully stopped service with id {service} ✔", color=colors.green) -else: puts(f"Test Failed: Coulnd't stop the service ✗", color=colors.red); exit_test(1) -#Check if proxy is stopped and check if WAIT works -def bindForSeconds(port,delay=4): - try: - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) - sock.bind(('127.0.0.1', port)) - sock.listen() - puts(f"The test could bind to port {port} ✔", color=colors.green) - sleep(delay) - sock.close() - except Exception as e: - puts(f"The test couldn't bind to port {port} ✗", color=colors.red) - -bindingTest = Process(target=bindForSeconds, args=[args.service_port]) -bindingTest.start() -sleep(1) - -#Restart it -if(firegex.pause(service)): puts(f"Sucessfully started in pause mode ✔", color=colors.green) -else: puts(f"Test Failed: Coulnd't start the service ✗", color=colors.red); exit_test(1) -if firegex.get_service(service)["status"] == "wait": - puts(f"Service started in WAIT mode ✔", color=colors.green) -else: - puts(f"Service started but it's not WAIT mode ✗", color=colors.red); exit_test(1) - -bindingTest.join() -sleep(1) -#Check if service started in pause mode successfully -if firegex.get_service(service)["status"] == "pause": - puts(f"Service started in PAUSE mode ✔", color=colors.green) -else: - puts(f"Service is not in PAUSE mode ✗", color=colors.red); exit_test(1) - -if sendCheckData(secrets.token_bytes(200) + secret + secrets.token_bytes(200)): - puts(f"The request wasn't blocked ✔", color=colors.green) -else: - puts(f"Test Failed: The request was blocked when it shouldn't have", color=colors.red) - -#Restart it and check +#Start firewall if(firegex.start(service)): puts(f"Sucessfully started service with id {service} ✔", color=colors.green) else: puts(f"Test Failed: Coulnd't start the service ✗", color=colors.red); exit_test(1)