From 33b22a174c074c49da0f0e36b1fa3c50e1d30593 Mon Sep 17 00:00:00 2001 From: Domingo Dirutigliano Date: Sat, 12 Apr 2025 16:51:42 +0200 Subject: [PATCH] using also bridge table on network hooking --- backend/binsrc/classes/nfqueue.cpp | 4 +- backend/modules/nfproxy/nftables.py | 48 +++++++++++++----------- backend/modules/nfregex/nftables.py | 38 ++++++++++--------- backend/modules/porthijack/nftables.py | 38 ++++++++++--------- backend/utils/__init__.py | 2 +- frontend/src/components/NFProxy/utils.ts | 2 +- tests/utils/tcpserver.py | 2 +- 7 files changed, 71 insertions(+), 63 deletions(-) diff --git a/backend/binsrc/classes/nfqueue.cpp b/backend/binsrc/classes/nfqueue.cpp index 9a60271..04ee946 100644 --- a/backend/binsrc/classes/nfqueue.cpp +++ b/backend/binsrc/classes/nfqueue.cpp @@ -295,7 +295,7 @@ class PktRequest { if (tcp){ //If the packet has data, we have to remove it set_data(nullptr, 0); - //For the first matched data or only for data packets, we set FIN bit + //For the first matched data or only for data packets, we set RST bit //This only for client packets, because this will trigger server to close the connection //Packets will be filtered anyway also if client don't send packets if (_data_original_size != 0){ @@ -585,4 +585,4 @@ uint32_t hash_stream_id(const stream_id &sid) { } }} -#endif // NFQUEUE_CLASS_CPP \ No newline at end of file +#endif // NFQUEUE_CLASS_CPP diff --git a/backend/modules/nfproxy/nftables.py b/backend/modules/nfproxy/nftables.py index 046d98d..473e8cc 100644 --- a/backend/modules/nfproxy/nftables.py +++ b/backend/modules/nfproxy/nftables.py @@ -10,7 +10,8 @@ def convert_protocol_to_l4(proto:str): raise Exception("Invalid protocol") class FiregexFilter: - def __init__(self, proto:str, port:int, ip_int:str, target:str, id:int): + def __init__(self, proto:str, port:int, ip_int:str, target:str, id:int, family:str): + self.family = family self.id = id self.target = target self.proto = proto @@ -28,29 +29,30 @@ class FiregexTables(NFTableManager): def __init__(self): super().__init__([ - {"add":{"chain":{ #Input chain attached before conntrack see it - "family":"inet", + + *[{"add":{"chain":{ #Input chain attached before conntrack see it + "family":fam, "table":self.table_name, "name":self.input_chain, "type":"filter", "hook":"prerouting", "prio":-310, "policy":"accept" - }}}, - {"add":{"chain":{ #Output chain attached after conntrack saw it - "family":"inet", + }}} for fam in ("inet", "bridge")], + *[{"add":{"chain":{ #Output chain attached after conntrack saw it + "family":fam, "table":self.table_name, "name":self.output_chain, "type":"filter", "hook":"postrouting", "prio":-310, "policy":"accept" - }}} + }}} for fam in ("inet", "bridge")], ],[ - {"flush":{"chain":{"table":self.table_name,"family":"inet", "name":self.input_chain}}}, - {"delete":{"chain":{"table":self.table_name,"family":"inet", "name":self.input_chain}}}, - {"flush":{"chain":{"table":self.table_name,"family":"inet", "name":self.output_chain}}}, - {"delete":{"chain":{"table":self.table_name,"family":"inet", "name":self.output_chain}}}, + *[{"flush":{"chain":{"table":self.table_name,"family":fam, "name":self.input_chain}}} for fam in ("inet", "bridge")], + *[{"delete":{"chain":{"table":self.table_name,"family":fam, "name":self.input_chain}}} for fam in ("inet", "bridge")], + *[{"flush":{"chain":{"table":self.table_name,"family":fam, "name":self.output_chain}}} for fam in ("inet", "bridge")], + *[{"delete":{"chain":{"table":self.table_name,"family":fam, "name":self.output_chain}}} for fam in ("inet", "bridge")], ]) def add(self, srv:Service, queue_range): @@ -63,8 +65,8 @@ class FiregexTables(NFTableManager): if init > end: init, end = end, init self.cmd( - { "insert":{ "rule": { - "family": "inet", + *[{ "insert":{ "rule": { + "family": fam, "table": self.table_name, "chain": self.output_chain, "expr": [ @@ -73,9 +75,9 @@ class FiregexTables(NFTableManager): {"mangle": {"key": {"meta": {"key": "mark"}},"value": 0x1338}}, {"queue": {"num": str(init) if init == end else {"range":[init, end] }, "flags": ["bypass"]}} ] - }}}, - {"insert":{"rule":{ - "family": "inet", + }}} for fam in ("inet", "bridge")], + *[{"insert":{"rule":{ + "family": fam, "table": self.table_name, "chain": self.input_chain, "expr": [ @@ -84,7 +86,7 @@ class FiregexTables(NFTableManager): {"mangle": {"key": {"meta": {"key": "mark"}},"value": 0x1337}}, {"queue": {"num": str(init) if init == end else {"range":[init, end] }, "flags": ["bypass"]}} ] - }}} + }}} for fam in ("inet", "bridge")] ) @@ -99,6 +101,7 @@ class FiregexTables(NFTableManager): res.append(FiregexFilter( target=filter["chain"], id=int(filter["handle"]), + family=filter["family"], proto=filter["expr"][1]["match"]["left"]["payload"]["protocol"], port=filter["expr"][1]["match"]["right"], ip_int=ip_int @@ -109,9 +112,10 @@ class FiregexTables(NFTableManager): for filter in self.get(): if filter.__eq__(srv): self.cmd({ "delete":{ "rule": { - "family": "inet", - "table": self.table_name, - "chain": filter.target, - "handle": filter.id - }}}) + "family": filter.family, + "table": self.table_name, + "chain": filter.target, + "handle": filter.id + }}} + ) \ No newline at end of file diff --git a/backend/modules/nfregex/nftables.py b/backend/modules/nfregex/nftables.py index c352226..fe8601d 100644 --- a/backend/modules/nfregex/nftables.py +++ b/backend/modules/nfregex/nftables.py @@ -2,7 +2,8 @@ from modules.nfregex.models import Service from utils import ip_parse, ip_family, NFTableManager, nftables_int_to_json class FiregexFilter: - def __init__(self, proto:str, port:int, ip_int:str, target:str, id:int): + def __init__(self, proto:str, port:int, ip_int:str, target:str, id:int, family:str): + self.family = family self.id = id self.target = target self.proto = proto @@ -20,29 +21,29 @@ class FiregexTables(NFTableManager): def __init__(self): super().__init__([ - {"add":{"chain":{ - "family":"inet", + *[{"add":{"chain":{ + "family":fam, "table":self.table_name, "name":self.input_chain, "type":"filter", "hook":"prerouting", "prio":-301, "policy":"accept" - }}}, - {"add":{"chain":{ - "family":"inet", + }}} for fam in ("inet", "bridge")], + *[{"add":{"chain":{ + "family":fam, "table":self.table_name, "name":self.output_chain, "type":"filter", "hook":"postrouting", "prio":-301, "policy":"accept" - }}} + }}} for fam in ("inet", "bridge")] ],[ - {"flush":{"chain":{"table":self.table_name,"family":"inet", "name":self.input_chain}}}, - {"delete":{"chain":{"table":self.table_name,"family":"inet", "name":self.input_chain}}}, - {"flush":{"chain":{"table":self.table_name,"family":"inet", "name":self.output_chain}}}, - {"delete":{"chain":{"table":self.table_name,"family":"inet", "name":self.output_chain}}}, + *[{"flush":{"chain":{"table":self.table_name,"family":fam, "name":self.input_chain}}} for fam in ("inet", "bridge")], + *[{"delete":{"chain":{"table":self.table_name,"family":fam, "name":self.input_chain}}} for fam in ("inet", "bridge")], + *[{"flush":{"chain":{"table":self.table_name,"family":fam, "name":self.output_chain}}} for fam in ("inet", "bridge")], + *[{"delete":{"chain":{"table":self.table_name,"family":fam, "name":self.output_chain}}} for fam in ("inet", "bridge")], ]) def add(self, srv:Service, queue_range): @@ -55,8 +56,8 @@ class FiregexTables(NFTableManager): if init > end: init, end = end, init self.cmd( - { "insert":{ "rule": { - "family": "inet", + *[{ "insert":{ "rule": { + "family": fam, "table": self.table_name, "chain": self.output_chain, "expr": [ @@ -65,9 +66,9 @@ class FiregexTables(NFTableManager): {"mangle": {"key": {"meta": {"key": "mark"}},"value": 0x1338}}, {"queue": {"num": str(init) if init == end else {"range":[init, end] }, "flags": ["bypass"]}} ] - }}}, - {"insert":{"rule":{ - "family": "inet", + }}} for fam in ("inet", "bridge")], + *[{"insert":{"rule":{ + "family": fam, "table": self.table_name, "chain": self.input_chain, "expr": [ @@ -76,7 +77,7 @@ class FiregexTables(NFTableManager): {"mangle": {"key": {"meta": {"key": "mark"}},"value": 0x1337}}, {"queue": {"num": str(init) if init == end else {"range":[init, end] }, "flags": ["bypass"]}} ] - }}} + }}} for fam in ("inet", "bridge")] ) @@ -91,6 +92,7 @@ class FiregexTables(NFTableManager): res.append(FiregexFilter( target=filter["chain"], id=int(filter["handle"]), + family=filter["family"], proto=filter["expr"][1]["match"]["left"]["payload"]["protocol"], port=filter["expr"][1]["match"]["right"], ip_int=ip_int @@ -101,7 +103,7 @@ class FiregexTables(NFTableManager): for filter in self.get(): if filter.__eq__(srv): self.cmd({ "delete":{ "rule": { - "family": "inet", + "family": filter.family, "table": self.table_name, "chain": filter.target, "handle": filter.id diff --git a/backend/modules/porthijack/nftables.py b/backend/modules/porthijack/nftables.py index 0590b2f..fee2cd6 100644 --- a/backend/modules/porthijack/nftables.py +++ b/backend/modules/porthijack/nftables.py @@ -2,8 +2,9 @@ from modules.porthijack.models import Service from utils import addr_parse, ip_parse, ip_family, NFTableManager, nftables_json_to_int class FiregexHijackRule(): - def __init__(self, proto:str, public_port:int,proxy_port:int, ip_src:str, ip_dst:str, target:str, id:int): + def __init__(self, proto:str, public_port:int,proxy_port:int, ip_src:str, ip_dst:str, target:str, id:int, family:str): self.id = id + self.family = family self.target = target self.proto = proto self.public_port = public_port @@ -22,29 +23,29 @@ class FiregexTables(NFTableManager): def __init__(self): super().__init__([ - {"add":{"chain":{ - "family":"inet", + *[{"add":{"chain":{ + "family":fam, "table":self.table_name, "name":self.prerouting_porthijack, "type":"filter", "hook":"prerouting", "prio":-310, "policy":"accept" - }}}, - {"add":{"chain":{ - "family":"inet", + }}} for fam in ("inet", "bridge")], + *[{"add":{"chain":{ + "family":fam, "table":self.table_name, "name":self.postrouting_porthijack, "type":"filter", "hook":"postrouting", "prio":-310, "policy":"accept" - }}} + }}} for fam in ("inet", "bridge")] ],[ - {"flush":{"chain":{"table":self.table_name,"family":"inet", "name":self.prerouting_porthijack}}}, - {"delete":{"chain":{"table":self.table_name,"family":"inet", "name":self.prerouting_porthijack}}}, - {"flush":{"chain":{"table":self.table_name,"family":"inet", "name":self.postrouting_porthijack}}}, - {"delete":{"chain":{"table":self.table_name,"family":"inet", "name":self.postrouting_porthijack}}} + *[{"flush":{"chain":{"table":self.table_name,"family":fam, "name":self.prerouting_porthijack}}} for fam in ("inet", "bridge")], + *[{"delete":{"chain":{"table":self.table_name,"family":fam, "name":self.prerouting_porthijack}}} for fam in ("inet", "bridge")], + *[{"flush":{"chain":{"table":self.table_name,"family":fam, "name":self.postrouting_porthijack}}} for fam in ("inet", "bridge")], + *[{"delete":{"chain":{"table":self.table_name,"family":fam, "name":self.postrouting_porthijack}}} for fam in ("inet", "bridge")] ]) def add(self, srv:Service): @@ -53,8 +54,8 @@ class FiregexTables(NFTableManager): if ele.__eq__(srv): return - self.cmd({ "insert":{ "rule": { - "family": "inet", + self.cmd(*[{ "insert":{ "rule": { + "family": fam, "table": self.table_name, "chain": self.prerouting_porthijack, "expr": [ @@ -63,9 +64,9 @@ class FiregexTables(NFTableManager): {'mangle': {'key': {'payload': {'protocol': str(srv.proto), 'field': 'dport'}}, 'value': int(srv.proxy_port)}}, {'mangle': {'key': {'payload': {'protocol': ip_family(srv.ip_src), 'field': 'daddr'}}, 'value': addr_parse(srv.ip_dst)}} ] - }}}) - self.cmd({ "insert":{ "rule": { - "family": "inet", + }}} for fam in ("inet", "bridge")]) + self.cmd(*[{ "insert":{ "rule": { + "family": fam, "table": self.table_name, "chain": self.postrouting_porthijack, "expr": [ @@ -74,7 +75,7 @@ class FiregexTables(NFTableManager): {'mangle': {'key': {'payload': {'protocol': str(srv.proto), 'field': 'sport'}}, 'value': int(srv.public_port)}}, {'mangle': {'key': {'payload': {'protocol': ip_family(srv.ip_dst), 'field': 'saddr'}}, 'value': addr_parse(srv.ip_src)}} ] - }}}) + }}} for fam in ("inet", "bridge")]) def get(self) -> list[FiregexHijackRule]: @@ -83,6 +84,7 @@ class FiregexTables(NFTableManager): res.append(FiregexHijackRule( target=filter["chain"], id=int(filter["handle"]), + family=filter["family"], proto=filter["expr"][1]["match"]["left"]["payload"]["protocol"], public_port=filter["expr"][1]["match"]["right"] if filter["chain"] == self.prerouting_porthijack else filter["expr"][2]["mangle"]["value"], proxy_port=filter["expr"][1]["match"]["right"] if filter["chain"] == self.postrouting_porthijack else filter["expr"][2]["mangle"]["value"], @@ -95,7 +97,7 @@ class FiregexTables(NFTableManager): for filter in self.get(): if filter.__eq__(srv): self.cmd({ "delete":{ "rule": { - "family": "inet", + "family": filter.family, "table": self.table_name, "chain": filter.target, "handle": filter.id diff --git a/backend/utils/__init__.py b/backend/utils/__init__.py index b18b80f..eeb6b1a 100644 --- a/backend/utils/__init__.py +++ b/backend/utils/__init__.py @@ -143,7 +143,7 @@ class NFTableManager(Singleton): def init(self): self.reset() - self.raw_cmd({"add":{"table":{"name":self.table_name,"family":"inet"}}}) + self.raw_cmd(*[{"add":{"table":{"name":self.table_name,"family":fam}}} for fam in ("inet", "bridge")]) self.cmd(*self.__init_cmds) def reset(self): diff --git a/frontend/src/components/NFProxy/utils.ts b/frontend/src/components/NFProxy/utils.ts index 8c53f1b..3ce66de 100644 --- a/frontend/src/components/NFProxy/utils.ts +++ b/frontend/src/components/NFProxy/utils.ts @@ -117,7 +117,7 @@ from firegex.nfproxy import pyfilter from firegex.nfproxy import REJECT, ACCEPT, UNSTABLE_MANGLE, DROP # - The filter must return one of the following values: # - ACCEPT: The packet will be accepted -# - REJECT: The packet will be rejected (will be activated a mechanism to send a FIN packet and drop all data in the stream) +# - REJECT: The packet will be rejected (will be activated a mechanism to send a RST packet and drop all data in the stream) # - UNSTABLE_MANGLE: The packet will be mangled and accepted # - DROP: All the packets in this stream will be easly dropped diff --git a/tests/utils/tcpserver.py b/tests/utils/tcpserver.py index 519ab5e..0483022 100644 --- a/tests/utils/tcpserver.py +++ b/tests/utils/tcpserver.py @@ -64,7 +64,7 @@ class TcpServer: def recv_packet(self): try: return self.client_sock.recv(4096) - except TimeoutError: + except (TimeoutError, ConnectionResetError): if self.verbose: traceback.print_exc() return False