data handler improves, written test for nfproxy, new option on parsing fail

This commit is contained in:
Domingo Dirutigliano
2025-03-09 22:14:34 +01:00
parent 9dfe229a26
commit 73c40d2f5d
21 changed files with 1077 additions and 306 deletions

View File

@@ -75,12 +75,9 @@ def handle_packet(glob: dict) -> None:
cache_call = {} # Cache of the data handler calls
cache_call[RawPacket] = internal_data.current_pkt
final_result = Action.ACCEPT
result = PacketHandlerResult(glob)
func_name = None
mangled_packet = None
for filter in internal_data.filter_call_info:
final_params = []
skip_call = False
@@ -116,24 +113,37 @@ def handle_packet(glob: dict) -> None:
if skip_call:
continue
res = context_call(glob, filter.func, *final_params)
if res is None:
continue #ACCEPTED
if not isinstance(res, Action):
raise Exception(f"Invalid return type {type(res)} for function {filter.name}")
if res == Action.MANGLE:
mangled_packet = internal_data.current_pkt.raw_packet
if res != Action.ACCEPT:
func_name = filter.name
final_result = res
break
# Create an iterator with all the calls to be done
def try_to_call(params:list):
is_base_call = True
for i in range(len(params)):
if isinstance(params[i], list):
new_params = params.copy()
for ele in params[i]:
new_params[i] = ele
for ele in try_to_call(new_params):
yield ele
is_base_call = False
break
if is_base_call:
yield context_call(glob, filter.func, *params)
for res in try_to_call(final_params):
if res is None:
continue #ACCEPTED
if not isinstance(res, Action):
raise Exception(f"Invalid return type {type(res)} for function {filter.name}")
if res == Action.MANGLE:
result.matched_by = filter.name
result.mangled_packet = internal_data.current_pkt.raw_packet
result.action = Action.MANGLE
elif res != Action.ACCEPT:
result.matched_by = filter.name
result.action = res
result.mangled_packet = None
return result.set_result()
result.action = final_result
result.matched_by = func_name
result.mangled_packet = mangled_packet
return result.set_result()
return result.set_result() # Will be MANGLE or ACCEPT
def compile(glob:dict) -> None:
@@ -148,13 +158,12 @@ def compile(glob:dict) -> None:
if "FGEX_STREAM_MAX_SIZE" in glob and int(glob["FGEX_STREAM_MAX_SIZE"]) > 0:
internal_data.stream_max_size = int(glob["FGEX_STREAM_MAX_SIZE"])
else:
internal_data.stream_max_size = 1*8e20 # 1MB default value
if "FGEX_FULL_STREAM_ACTION" in glob and isinstance(glob["FGEX_FULL_STREAM_ACTION"], FullStreamAction):
internal_data.full_stream_action = glob["FGEX_FULL_STREAM_ACTION"]
else:
internal_data.full_stream_action = FullStreamAction.FLUSH
if "FGEX_INVALID_ENCODING_ACTION" in glob and isinstance(glob["FGEX_INVALID_ENCODING_ACTION"], Action):
internal_data.invalid_encoding_action = glob["FGEX_INVALID_ENCODING_ACTION"]
PacketHandlerResult(glob).reset_result()

View File

@@ -1,5 +1,5 @@
from firegex.nfproxy.internals.models import FilterHandler
from firegex.nfproxy.internals.models import FullStreamAction
from firegex.nfproxy.internals.models import FullStreamAction, ExceptionAction
class RawPacket:
"class rapresentation of the nfqueue packet sent in python context by the c++ core"
@@ -120,23 +120,39 @@ class DataStreamCtx:
@property
def stream_max_size(self) -> int:
if "stream_max_size" not in self.__data.keys():
self.__data["stream_max_size"] = 1*8e20
self.__data["stream_max_size"] = 1*8e20 # 1MB default value
return self.__data.get("stream_max_size")
@stream_max_size.setter
def stream_max_size(self, v: int):
if not isinstance(v, int):
raise Exception("Invalid data type, data MUST be of type int")
self.__data["stream_max_size"] = v
@property
def full_stream_action(self) -> FullStreamAction:
if "full_stream_action" not in self.__data.keys():
self.__data["full_stream_action"] = "flush"
self.__data["full_stream_action"] = FullStreamAction.FLUSH
return self.__data.get("full_stream_action")
@full_stream_action.setter
def full_stream_action(self, v: FullStreamAction):
if not isinstance(v, FullStreamAction):
raise Exception("Invalid data type, data MUST be of type FullStreamAction")
self.__data["full_stream_action"] = v
@property
def invalid_encoding_action(self) -> ExceptionAction:
if "invalid_encoding_action" not in self.__data.keys():
self.__data["invalid_encoding_action"] = ExceptionAction.REJECT
return self.__data.get("invalid_encoding_action")
@invalid_encoding_action.setter
def invalid_encoding_action(self, v: ExceptionAction):
if not isinstance(v, ExceptionAction):
raise Exception("Invalid data type, data MUST be of type ExceptionAction")
self.__data["invalid_encoding_action"] = v
@property
def data_handler_context(self) -> dict:
if "data_handler_context" not in self.__data.keys():

View File

@@ -13,3 +13,4 @@ class RejectConnection(Exception):
class StreamFullReject(Exception):
"raise this exception if you want to reject the connection due to full stream"

View File

@@ -8,6 +8,13 @@ class Action(Enum):
REJECT = 2
MANGLE = 3
class ExceptionAction(Enum):
"""Action to be taken by the filter when an exception occurs (used in some cases)"""
ACCEPT = 0
DROP = 1
REJECT = 2
NOACTION = 3
class FullStreamAction(Enum):
"""Action to be taken by the filter when the stream is full"""
FLUSH = 0
@@ -40,5 +47,3 @@ class PacketHandlerResult:
def reset_result(self) -> None:
self.glob["__firegex_pyfilter_result"] = None