push: code changes x2

This commit is contained in:
Domingo Dirutigliano
2025-02-28 21:14:09 +01:00
parent 6a11dd0d16
commit 8ae533e8f7
31 changed files with 544 additions and 397 deletions

View File

@@ -7,6 +7,7 @@
#include <tins/tcp_ip/stream_identifier.h>
#include <libmnl/libmnl.h>
#include <tins/tins.h>
#include <map>
using namespace std;
@@ -17,7 +18,17 @@ enum class FilterAction{ DROP, ACCEPT, MANGLE, NOACTION };
enum class L4Proto { TCP, UDP, RAW };
typedef Tins::TCPIP::StreamIdentifier stream_id;
//TODO DUBBIO: I PACCHETTI INVIATI A PYTHON SONO GIA' FIXATI?
struct tcp_ack_seq_ctx{
int64_t in = 0;
int64_t out = 0;
tcp_ack_seq_ctx(){}
void reset(){
in = 0;
out = 0;
}
};
typedef map<stream_id, tcp_ack_seq_ctx*> tcp_ack_map;
template<typename T>
class PktRequest {
@@ -28,6 +39,7 @@ class PktRequest {
uint32_t packet_id;
size_t _original_size;
size_t _data_original_size;
size_t _header_size;
bool need_tcp_fixing = false;
public:
bool is_ipv6;
@@ -39,18 +51,15 @@ class PktRequest {
bool is_input;
string packet;
char* data;
size_t data_size;
stream_id sid;
int64_t* tcp_in_offset = nullptr;
int64_t* tcp_out_offset = nullptr;
tcp_ack_seq_ctx* ack_seq_offset = nullptr;
T* ctx;
T* ctx = nullptr;
private:
static size_t inner_data_size(Tins::PDU* pdu){
static inline size_t inner_data_size(Tins::PDU* pdu){
if (pdu == nullptr){
return 0;
}
@@ -61,9 +70,9 @@ class PktRequest {
return inner->size();
}
inline void fetch_data_size(Tins::PDU* pdu){
data_size = inner_data_size(pdu);
_data_original_size = data_size;
inline void __internal_fetch_data_size(Tins::PDU* pdu){
_data_original_size = inner_data_size(pdu);
_header_size = _original_size - _data_original_size;
}
L4Proto fill_l4_info(){
@@ -72,14 +81,14 @@ class PktRequest {
if (tcp == nullptr){
udp = ipv6->find_pdu<Tins::UDP>();
if (udp == nullptr){
fetch_data_size(ipv6);
__internal_fetch_data_size(ipv6);
return L4Proto::RAW;
}else{
fetch_data_size(udp);
__internal_fetch_data_size(udp);
return L4Proto::UDP;
}
}else{
fetch_data_size(tcp);
__internal_fetch_data_size(tcp);
return L4Proto::TCP;
}
}else{
@@ -87,73 +96,23 @@ class PktRequest {
if (tcp == nullptr){
udp = ipv4->find_pdu<Tins::UDP>();
if (udp == nullptr){
fetch_data_size(ipv4);
__internal_fetch_data_size(ipv4);
return L4Proto::RAW;
}else{
fetch_data_size(udp);
__internal_fetch_data_size(udp);
return L4Proto::UDP;
}
}else{
fetch_data_size(tcp);
__internal_fetch_data_size(tcp);
return L4Proto::TCP;
}
}
}
bool need_tcp_fix(){
return (tcp_in_offset != nullptr && *tcp_in_offset != 0) || (tcp_out_offset != nullptr && *tcp_out_offset != 0);
return tcp && ack_seq_offset != nullptr && (ack_seq_offset->in != 0 || ack_seq_offset->out != 0);
}
Tins::PDU::serialization_type reserialize_raw_data(const uint8_t* data, const size_t& data_size){
if (is_ipv6){
Tins::IPv6 ipv6_new = Tins::IPv6(data, data_size);
if (tcp){
Tins::TCP* tcp_new = ipv6_new.find_pdu<Tins::TCP>();
}
return ipv6_new.serialize();
}else{
Tins::IP ipv4_new = Tins::IP(data, data_size);
if (tcp){
Tins::TCP* tcp_new = ipv4_new.find_pdu<Tins::TCP>();
}
return ipv4_new.serialize();
}
}
void _fix_ack_seq_tcp(Tins::TCP* this_tcp){
need_tcp_fixing = need_tcp_fix();
#ifdef DEBUG
if (need_tcp_fixing){
cerr << "[DEBUG] Fixing ack_seq with offsets " << *tcp_in_offset << " " << *tcp_out_offset << endl;
}
#endif
if(this_tcp == nullptr){
return;
}
if (is_input){
if (tcp_in_offset != nullptr){
this_tcp->seq(this_tcp->seq() + *tcp_in_offset);
}
if (tcp_out_offset != nullptr){
this_tcp->ack_seq(this_tcp->ack_seq() - *tcp_out_offset);
}
}else{
if (tcp_in_offset != nullptr){
this_tcp->ack_seq(this_tcp->ack_seq() - *tcp_in_offset);
}
if (tcp_out_offset != nullptr){
this_tcp->seq(this_tcp->seq() + *tcp_out_offset);
}
}
#ifdef DEBUG
if (need_tcp_fixing){
size_t new_size = inner_data_size(this_tcp);
cerr << "[DEBUG] FIXED PKT " << (is_input?"-> IN ":"<- OUT") << " [SEQ: " << this_tcp->seq() << "] \t[ACK: " << this_tcp->ack_seq() << "] \t[SIZE: " << new_size << "]" << endl;
}
#endif
}
public:
PktRequest(const char* payload, size_t plen, T* ctx, mnl_socket* nl, nfgenmsg *nfg, nfqnl_msg_packet_hdr *ph, bool is_input):
@@ -168,22 +127,129 @@ class PktRequest {
sid = stream_id::make_identifier(*ipv6);
_original_size = ipv6->size();
}else{
ipv4 = new Tins::IP((uint8_t*)packet.data(), plen);
ipv4 = new Tins::IP((uint8_t*)packet.c_str(), plen);
sid = stream_id::make_identifier(*ipv4);
_original_size = ipv4->size();
}
l4_proto = fill_l4_info();
data = packet.data()+(plen-data_size);
#ifdef DEBUG
if (tcp){
cerr << "[DEBUG] NEW_PACKET " << (is_input?"-> IN ":"<- OUT") << " [SEQ: " << tcp->seq() << "] \t[ACK: " << tcp->ack_seq() << "] \t[SIZE: " << data_size << "]" << endl;
cerr << "[DEBUG] NEW_PACKET " << (is_input?"-> IN ":"<- OUT") << " [SEQ: " << tcp->seq() << "] \t[ACK: " << tcp->ack_seq() << "] \t[SIZE: " << data_size() << "]" << endl;
}
#endif
}
void fix_tcp_ack(){
inline size_t header_size(){
return _header_size;
}
char* data(){
return packet.data()+_header_size;
}
size_t data_size(){
return packet.size()-_header_size;
}
size_t data_original_size(){
return _data_original_size;
}
void reserialize(){
auto data = serialize();
packet.resize(data.size());
memcpy(packet.data(), data.data(), data.size());
}
void set_data(const char* data, const size_t& data_size){
auto bef_raw = before_raw_pdu_ptr();
if (bef_raw){
delete before_raw_pdu_ptr()->release_inner_pdu();
if (data_size > 0){
before_raw_pdu_ptr() /= move(Tins::RawPDU((uint8_t*)data, data_size));
}
}
}
Tins::PDU* before_raw_pdu_ptr(){
if (tcp){
_fix_ack_seq_tcp(tcp);
return tcp;
}else if (udp){
return udp;
}else if (ipv4){
return ipv4;
}else if (ipv6){
return ipv6;
}
return nullptr;
}
void set_packet(const char* data, size_t data_size){
// Parsing only the header with libtins
Tins::PDU *data_pdu = nullptr;
size_t total_size;
if (is_ipv6){
delete ipv6;
ipv6 = new Tins::IPv6((uint8_t*)data, data_size);
if (tcp){
tcp = ipv6->find_pdu<Tins::TCP>();
data_pdu = tcp;
}else if (udp){
udp = ipv6->find_pdu<Tins::UDP>();
data_pdu = udp;
}else{
data_pdu = ipv6;
}
total_size = ipv6->size();
}else{
delete ipv4;
ipv4 = new Tins::IP((uint8_t*)data, data_size);
if (tcp){
tcp = ipv4->find_pdu<Tins::TCP>();
data_pdu = tcp;
}else if(udp){
udp = ipv4->find_pdu<Tins::UDP>();
data_pdu = udp;
}else{
data_pdu = ipv4;
}
total_size = ipv4->size();
}
_header_size = total_size - inner_data_size(data_pdu);
// Libtins can skip data if the lenght is changed to a bigger len (due to ip header total lenght), so we need to specify the data section manually
set_data(data+_header_size, data_size-_header_size);
}
void fix_tcp_ack(){
need_tcp_fixing = need_tcp_fix();
if(!need_tcp_fixing){
return;
}
#ifdef DEBUG
cerr << "[DEBUG] Fixing ack_seq with offsets " << ((int32_t)ack_seq_offset->in) << " " << ((int32_t)ack_seq_offset->out) << endl;
#endif
if (is_input){
tcp->seq(tcp->seq() + ack_seq_offset->in);
tcp->ack_seq(tcp->ack_seq() - ack_seq_offset->out);
}else{
tcp->ack_seq(tcp->ack_seq() - ack_seq_offset->in);
tcp->seq(tcp->seq() + ack_seq_offset->out);
}
#ifdef DEBUG
size_t new_size = inner_data_size(tcp);
cerr << "[DEBUG] FIXED PKT " << (is_input?"-> IN ":"<- OUT") << " [SEQ: " << tcp->seq() << "] \t[ACK: " << tcp->ack_seq() << "] \t[SIZE: " << new_size << "]" << endl;
#endif
}
void fix_data_payload(){
//Stream follower move the payload data, so we need to reinizialize RawPDU
auto bef_raw = before_raw_pdu_ptr();
if (bef_raw){
delete bef_raw->release_inner_pdu();
auto new_data_size = packet.size()-_header_size;
if (new_data_size > 0){
bef_raw /= move(Tins::RawPDU((uint8_t*)packet.data()+_header_size, new_data_size));
}
}
}
@@ -196,10 +262,6 @@ class PktRequest {
}
}
size_t data_original_size(){
return _data_original_size;
}
size_t original_size(){
return _original_size;
}
@@ -225,11 +287,11 @@ class PktRequest {
void reject(){
if (tcp){
//If the packet has data, we have to remove it
delete tcp->release_inner_pdu();
set_data(nullptr, 0);
//For the first matched data or only for data packets, we set FIN 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 && is_input){
if (_data_original_size != 0){
tcp->set_flag(Tins::TCP::FIN,1);
tcp->set_flag(Tins::TCP::ACK,1);
tcp->set_flag(Tins::TCP::SYN,0);
@@ -241,10 +303,16 @@ class PktRequest {
}
}
void mangle_custom_pkt(uint8_t* pkt, const size_t& pkt_size){
void mangle_custom_pkt(const char* raw_pkt, size_t raw_pkt_size){
if (action == FilterAction::NOACTION){
action = FilterAction::MANGLE;
perfrom_action(pkt, pkt_size);
try{
set_packet(raw_pkt, raw_pkt_size);
reserialize();
action = FilterAction::MANGLE;
}catch(...){
action = FilterAction::DROP;
}
perfrom_action(false);
}else{
throw invalid_argument("Cannot mangle a packet that has already been accepted or dropped");
}
@@ -259,7 +327,7 @@ class PktRequest {
delete ipv6;
}
inline Tins::PDU::serialization_type serialize(){
Tins::PDU::serialization_type serialize(){
if (is_ipv6){
return ipv6->serialize();
}else{
@@ -268,15 +336,17 @@ class PktRequest {
}
private:
void perfrom_action(uint8_t* custom_data = nullptr, size_t custom_data_size = 0){
void perfrom_action(bool do_serialize = true){
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh_verdict = nfq_nlmsg_put(buf, NFQNL_MSG_VERDICT, ntohs(res_id));
switch (action)
{
case FilterAction::ACCEPT:
if (need_tcp_fixing){
Tins::PDU::serialization_type data = serialize();
nfq_nlmsg_verdict_put_pkt(nlh_verdict, data.data(), data.size());
if (do_serialize){
reserialize();
}
nfq_nlmsg_verdict_put_pkt(nlh_verdict, packet.data(), packet.size());
}
nfq_nlmsg_verdict_put(nlh_verdict, ntohl(packet_id), NF_ACCEPT );
break;
@@ -285,32 +355,20 @@ class PktRequest {
break;
case FilterAction::MANGLE:{
//If not custom data, use the data in the packets
Tins::PDU::serialization_type data;
if (custom_data == nullptr){
data = serialize();
}else{
try{
data = reserialize_raw_data(custom_data, custom_data_size);
}catch(...){
nfq_nlmsg_verdict_put(nlh_verdict, ntohl(packet_id), NF_DROP );
action = FilterAction::DROP;
break;
}
if(do_serialize){
reserialize();
}
nfq_nlmsg_verdict_put_pkt(nlh_verdict, packet.data(), packet.size());
#ifdef DEBUG
size_t new_size = _data_original_size+((int64_t)custom_data_size) - ((int64_t)_original_size);
cerr << "[DEBUG] MANGLEDPKT " << (is_input?"-> IN ":"<- OUT") << " [SIZE: " << new_size << "]" << endl;
cerr << "[DEBUG] MANGLEDPKT " << (is_input?"-> IN ":"<- OUT") << " [SIZE: " << packet.size()-header_size() << "]" << endl;
#endif
if (tcp && custom_data_size != _original_size){
int64_t delta = ((int64_t)custom_data_size) - ((int64_t)_original_size);
if (is_input && tcp_in_offset != nullptr){
*tcp_in_offset += delta;
}else if (!is_input && tcp_out_offset != nullptr){
*tcp_out_offset += delta;
if (tcp && ack_seq_offset && packet.size() != _original_size){
if (is_input){
ack_seq_offset->in += packet.size() - _original_size;
}else{
ack_seq_offset->out += packet.size() - _original_size;
}
}
nfq_nlmsg_verdict_put_pkt(nlh_verdict, data.data(), data.size());
nfq_nlmsg_verdict_put(nlh_verdict, ntohl(packet_id), NF_ACCEPT );
break;
}