nfproxy module writing: written part of the firegex lib, frontend refactored and improved, c++ improves
This commit is contained in:
@@ -1,18 +1,87 @@
|
||||
#define PY_SSIZE_T_CLEAN
|
||||
#include <Python.h>
|
||||
|
||||
#include "proxytun/settings.cpp"
|
||||
#include "proxytun/proxytun.cpp"
|
||||
#include "pyproxy/settings.cpp"
|
||||
#include "pyproxy/pyproxy.cpp"
|
||||
#include "classes/netfilter.cpp"
|
||||
#include <syncstream>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <cstdlib>
|
||||
#include <endian.h>
|
||||
|
||||
using namespace std;
|
||||
using namespace Firegex::PyProxy;
|
||||
using Firegex::NfQueue::MultiThreadQueue;
|
||||
|
||||
/*
|
||||
|
||||
How python code is handles:
|
||||
|
||||
User code example:
|
||||
```python
|
||||
|
||||
from firegex.nfproxy import DROP, ACCEPT, pyfilter
|
||||
|
||||
@pyfilter
|
||||
def invalid_curl_agent(http):
|
||||
if "curl" in http.headers.get("User-Agent", ""):
|
||||
return DROP
|
||||
return ACCEPT
|
||||
|
||||
```
|
||||
|
||||
The code is now edited adding an intestation and a end statement:
|
||||
```python
|
||||
global __firegex_pyfilter_enabled, __firegex_proto
|
||||
__firegex_pyfilter_enabled = ["invalid_curl_agent", "func3"] # This list is dynamically generated by firegex backend
|
||||
__firegex_proto = "http"
|
||||
import firegex.nfproxy.internals
|
||||
<user_code>
|
||||
firegex.nfproxy.internals.compile() # This function can save other global variables, to use by the packet handler and is used generally to check and optimize the code
|
||||
````
|
||||
|
||||
This code will be executed only once, and is needed to build the global and local context to use
|
||||
The globals and locals generated here are copied for each connection, and are used to handle the packets
|
||||
|
||||
Using C API will be injected in global context the following informations:
|
||||
|
||||
__firegex_packet_info = {
|
||||
"data" = b"raw data found on L4",
|
||||
"raw_packet" = b"raw packet",
|
||||
"is_input" = True, # If the packet is incoming from a client
|
||||
"is_ipv6" = False, # If the packet is ipv6
|
||||
"is_tcp" = True, # If the packet is tcp
|
||||
}
|
||||
|
||||
As result the packet handler is responsible to return a dictionary in the global context with the following dictionary:
|
||||
__firegex_pyfilter_result = {
|
||||
"action": REJECT, # One of PyFilterResponse
|
||||
"matched_by": "invalid_curl_agent", # The function that matched the packet (used if action = DROP or REJECT or MANGLE)
|
||||
"mangled_packet": b"new packet" # The new packet to send to the kernel (used if action = MANGLE)
|
||||
}
|
||||
|
||||
PyFilterResponse {
|
||||
ACCEPT = 0,
|
||||
DROP = 1,
|
||||
REJECT = 2,
|
||||
MANGLE = 3,
|
||||
EXCEPTION = 4,
|
||||
INVALID = 5
|
||||
};
|
||||
|
||||
Every time a packet is received, the packet handler will execute the following code:
|
||||
```python
|
||||
firegex.nfproxy.internals.handle_packet()
|
||||
````
|
||||
|
||||
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
|
||||
So firegex handle_packet has to implement a way to limit memory usage, this dipends on what methods you choose to use to filter packets
|
||||
firegex lib will give you all the needed possibilities to do this is many ways
|
||||
|
||||
Final note: is not raccomanded to use variables that starts with __firegex_ in your code, because they may break the nfproxy
|
||||
*/
|
||||
|
||||
ssize_t read_check(int __fd, void *__buf, size_t __nbytes){
|
||||
ssize_t bytes = read(__fd, __buf, __nbytes);
|
||||
if (bytes == 0){
|
||||
@@ -30,7 +99,10 @@ void config_updater (){
|
||||
while (true){
|
||||
uint32_t code_size;
|
||||
read_check(STDIN_FILENO, &code_size, 4);
|
||||
vector<uint8_t> code(code_size);
|
||||
//Python will send number always in little endian
|
||||
code_size = le32toh(code_size);
|
||||
string code;
|
||||
code.resize(code_size);
|
||||
read_check(STDIN_FILENO, code.data(), code_size);
|
||||
cerr << "[info] [updater] Updating configuration" << endl;
|
||||
try{
|
||||
@@ -44,10 +116,12 @@ void config_updater (){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char *argv[]){
|
||||
|
||||
Py_Initialize();
|
||||
atexit(Py_Finalize);
|
||||
init_handle_packet_code(); //Compile the static code used to handle packets
|
||||
|
||||
if (freopen(nullptr, "rb", stdin) == nullptr){ // We need to read from stdin binary data
|
||||
cerr << "[fatal] [main] Failed to reopen stdin in binary mode" << endl;
|
||||
|
||||
Reference in New Issue
Block a user