code push

This commit is contained in:
Domingo Dirutigliano
2025-03-03 20:25:36 +01:00
parent 8ae533e8f7
commit 072745cc06
22 changed files with 1020 additions and 206 deletions

View File

@@ -364,9 +364,9 @@ class PktRequest {
#endif
if (tcp && ack_seq_offset && packet.size() != _original_size){
if (is_input){
ack_seq_offset->in += packet.size() - _original_size;
ack_seq_offset->in += data_size() - _data_original_size;
}else{
ack_seq_offset->out += packet.size() - _original_size;
ack_seq_offset->out += data_size() - _data_original_size;
}
}
nfq_nlmsg_verdict_put(nlh_verdict, ntohl(packet_id), NF_ACCEPT );

View File

@@ -72,7 +72,7 @@ PyFilterResponse {
Every time a packet is received, the packet handler will execute the following code:
```python
firegex.nfproxy.internals.handle_packet()
firegex.nfproxy.internals.handle_packet(globals())
````
The TCP stream is sorted by libtins using c++ code, but the c++ code is not responsabile di buffer the stream, but only to sort those

View File

@@ -34,7 +34,7 @@ class PyProxyQueue: public NfQueue::ThreadNfQueue<PyProxyQueue> {
public:
stream_ctx sctx;
StreamFollower follower;
PyThreadState * gtstate = nullptr;
PyThreadState * tstate = nullptr;
PyInterpreterConfig py_thread_config = {
.use_main_obmalloc = 0,
@@ -45,15 +45,16 @@ class PyProxyQueue: public NfQueue::ThreadNfQueue<PyProxyQueue> {
.check_multi_interp_extensions = 1,
.gil = PyInterpreterConfig_OWN_GIL,
};
PyThreadState *tstate = NULL;
NfQueue::PktRequest<PyProxyQueue>* pkt;
NfQueue::tcp_ack_seq_ctx* current_tcp_ack = nullptr;
PyObject* handle_packet_code = nullptr;
void before_loop() override {
PyStatus pystatus;
// Create a new interpreter for the thread
gtstate = PyThreadState_New(PyInterpreterState_Main());
PyEval_AcquireThread(gtstate);
tstate = PyThreadState_New(PyInterpreterState_Main());
PyEval_AcquireThread(tstate);
pystatus = Py_NewInterpreterFromConfig(&tstate, &py_thread_config);
if(tstate == nullptr){
cerr << "[fatal] [main] Failed to create new interpreter" << endl;
@@ -64,6 +65,12 @@ class PyProxyQueue: public NfQueue::ThreadNfQueue<PyProxyQueue> {
Py_ExitStatusException(pystatus);
throw invalid_argument("Failed to create new interpreter (pystatus exc)");
}
if(!PyGC_IsEnabled()){
PyGC_Enable();
}
handle_packet_code = unmarshal_code(py_handle_packet_code);
// Setting callbacks for the stream follower
follower.new_stream_callback(bind(on_new_stream, placeholders::_1, this));
follower.stream_termination_callback(bind(on_stream_close, placeholders::_1, this));
@@ -100,11 +107,24 @@ class PyProxyQueue: public NfQueue::ThreadNfQueue<PyProxyQueue> {
if (compiled_code == nullptr){
stream.client_data_callback(nullptr);
stream.server_data_callback(nullptr);
stream.ignore_client_data();
stream.ignore_server_data();
return pkt->accept();
}else{
try{
stream_match = new pyfilter_ctx(compiled_code, handle_packet_code);
}catch(invalid_argument& e){
cerr << "[error] [filter_action] Failed to create the filter context" << endl;
print_exception_reason();
sctx.clean_stream_by_id(pkt->sid);
stream.client_data_callback(nullptr);
stream.server_data_callback(nullptr);
stream.ignore_client_data();
stream.ignore_server_data();
return pkt->accept();
}
sctx.streams_ctx.insert_or_assign(pkt->sid, stream_match);
}
stream_match = new pyfilter_ctx(compiled_code);
Py_DECREF(compiled_code);
sctx.streams_ctx.insert_or_assign(pkt->sid, stream_match);
}else{
stream_match = stream_search->second;
}
@@ -140,6 +160,8 @@ class PyProxyQueue: public NfQueue::ThreadNfQueue<PyProxyQueue> {
print_exception_reason();
sctx.clean_stream_by_id(pkt->sid);
//Free the packet data
stream.ignore_client_data();
stream.ignore_server_data();
stream.client_data_callback(nullptr);
stream.server_data_callback(nullptr);
return pkt->accept();
@@ -233,6 +255,7 @@ class PyProxyQueue: public NfQueue::ThreadNfQueue<PyProxyQueue> {
PyEval_ReleaseThread(tstate);
PyThreadState_Clear(tstate);
PyThreadState_Delete(tstate);
Py_DECREF(handle_packet_code);
sctx.clean();
}

View File

@@ -16,9 +16,13 @@ namespace PyProxy {
class PyCodeConfig;
shared_ptr<PyCodeConfig> config;
PyObject* py_handle_packet_code = nullptr;
UnixClientConnection control_socket;
PyObject* unmarshal_code(string encoded_code){
if (encoded_code.empty()) return nullptr;
return PyMarshal_ReadObjectFromString(encoded_code.c_str(), encoded_code.size());
}
class PyCodeConfig{
public:
string encoded_code;
@@ -32,22 +36,24 @@ class PyCodeConfig{
PyObject* glob = PyDict_New();
PyObject* result = PyEval_EvalCode(compiled_code, glob, glob);
Py_DECREF(glob);
if (!result){
if (PyErr_Occurred()){
PyErr_Print();
Py_DECREF(compiled_code);
std::cerr << "[fatal] [main] Failed to execute the code" << endl;
throw invalid_argument("Failed to execute the code, maybe an invalid filter code has been provided");
}
Py_DECREF(result);
Py_XDECREF(result);
PyObject* code_dump = PyMarshal_WriteObjectToString(compiled_code, 4);
Py_DECREF(compiled_code);
if (code_dump == nullptr){
PyErr_Print();
if (PyErr_Occurred())
PyErr_Print();
std::cerr << "[fatal] [main] Failed to dump the code" << endl;
throw invalid_argument("Failed to dump the code");
}
if (!PyBytes_Check(code_dump)){
std::cerr << "[fatal] [main] Failed to dump the code" << endl;
Py_DECREF(code_dump);
throw invalid_argument("Failed to dump the code");
}
encoded_code = string(PyBytes_AsString(code_dump), PyBytes_Size(code_dump));
@@ -55,8 +61,7 @@ class PyCodeConfig{
}
PyObject* compiled_code(){
if (encoded_code.empty()) return nullptr;
return PyMarshal_ReadObjectFromString(encoded_code.c_str(), encoded_code.size());
return unmarshal_code(encoded_code);
}
PyCodeConfig(){}
@@ -69,16 +74,27 @@ void init_control_socket(){
control_socket = UnixClientConnection(socket_path);
}
string py_handle_packet_code;
void init_handle_packet_code(){
py_handle_packet_code = Py_CompileStringExFlags(
"firegex.nfproxy.internals.handle_packet()\n", "<pyfilter>",
PyObject* compiled_code = Py_CompileStringExFlags(
"firegex.nfproxy.internals.handle_packet(globals())\n", "<pyfilter>",
Py_file_input, NULL, 2);
if (py_handle_packet_code == nullptr){
std::cerr << "[fatal] [main] Failed to compile the utility python code (strange behaviour, probably a bug)" << endl;
throw invalid_argument("Failed to compile the code");
PyObject* code_dump = PyMarshal_WriteObjectToString(compiled_code, 4);
Py_DECREF(compiled_code);
if (code_dump == nullptr){
if (PyErr_Occurred())
PyErr_Print();
std::cerr << "[fatal] [main] Failed to dump the code" << endl;
throw invalid_argument("Failed to dump the code");
}
if (!PyBytes_Check(code_dump)){
std::cerr << "[fatal] [main] Failed to dump the code" << endl;
Py_DECREF(code_dump);
throw invalid_argument("Failed to dump the code");
}
py_handle_packet_code = string(PyBytes_AsString(code_dump), PyBytes_Size(code_dump));
Py_DECREF(code_dump);
}
}}

View File

@@ -55,11 +55,15 @@ typedef Tins::TCPIP::StreamIdentifier stream_id;
struct pyfilter_ctx {
PyObject * glob = nullptr;
PyObject * py_handle_packet = nullptr;
pyfilter_ctx(PyObject * compiled_code){
pyfilter_ctx(PyObject * compiled_code, PyObject * handle_packet_code){
py_handle_packet = handle_packet_code;
Py_INCREF(py_handle_packet);
glob = PyDict_New();
PyObject* result = PyEval_EvalCode(compiled_code, glob, glob);
if (!result){
Py_XDECREF(compiled_code);
if (PyErr_Occurred()){
PyErr_Print();
Py_XDECREF(glob);
std::cerr << "[fatal] [main] Failed to compile the code" << endl;
@@ -69,7 +73,10 @@ struct pyfilter_ctx {
}
~pyfilter_ctx(){
cerr << "[info] [pyfilter_ctx] Cleaning pyfilter_ctx" << endl;
Py_DECREF(glob);
Py_DECREF(py_handle_packet);
PyGC_Collect();
}
inline void set_item_to_glob(const char* key, PyObject* value){
@@ -82,14 +89,16 @@ struct pyfilter_ctx {
void del_item_from_glob(const char* key){
if (PyDict_DelItemString(glob, key) != 0){
PyErr_Print();
if (PyErr_Occurred())
PyErr_Print();
throw invalid_argument("Failed to delete item from dict");
}
}
inline void set_item_to_dict(PyObject* dict, const char* key, PyObject* value){
if (PyDict_SetItemString(dict, key, value) != 0){
PyErr_Print();
if (PyErr_Occurred())
PyErr_Print();
throw invalid_argument("Failed to set item to dict");
}
Py_DECREF(value);
@@ -111,11 +120,18 @@ struct pyfilter_ctx {
// Set packet info to the global context
set_item_to_glob("__firegex_packet_info", packet_info);
PyObject * result = PyEval_EvalCode(py_handle_packet_code, glob, glob);
#ifdef DEBUG
cerr << "[DEBUG] [handle_packet] Calling python with a data of " << data.size() << endl;
#endif
PyObject * result = PyEval_EvalCode(py_handle_packet, glob, glob);
PyGC_Collect();
#ifdef DEBUG
cerr << "[DEBUG] [handle_packet] End of python call" << endl;
#endif
del_item_from_glob("__firegex_packet_info");
Py_DECREF(packet_info);
if (!result){
if (PyErr_Occurred()){
cerr << "[error] [handle_packet] Failed to execute the code " << result << endl;
PyErr_Print();
#ifdef DEBUG
cerr << "[DEBUG] [handle_packet] Exception raised" << endl;
@@ -134,7 +150,9 @@ struct pyfilter_ctx {
}
if (!PyDict_Check(result)){
PyErr_Print();
if (PyErr_Occurred()){
PyErr_Print();
}
#ifdef DEBUG
cerr << "[DEBUG] [handle_packet] Result is not a dict" << endl;
#endif

View File

@@ -78,7 +78,7 @@ class FiregexInterceptor:
await run_func(self.outstrem_function, self.srv.id, line)
async def _start_binary(self):
proxy_binary_path = os.path.join(os.path.dirname(os.path.abspath(__file__)),"../cpproxy")
proxy_binary_path = os.path.abspath(os.path.join(os.path.dirname(__file__), "../cpproxy"))
self.process = await asyncio.create_subprocess_exec(
proxy_binary_path, stdin=asyncio.subprocess.DEVNULL,
stdout=asyncio.subprocess.PIPE,