mirror of
https://github.com/bol-van/zapret.git
synced 2025-05-24 22:32:58 +03:00
nfqws: combine desync and tamper logic
This commit is contained in:
@@ -119,7 +119,7 @@ uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8
|
||||
}
|
||||
|
||||
|
||||
void tcp_fix_checksum(struct tcphdr *tcp,int len, in_addr_t src_addr, in_addr_t dest_addr)
|
||||
void tcp4_fix_checksum(struct tcphdr *tcp,int len, in_addr_t src_addr, in_addr_t dest_addr)
|
||||
{
|
||||
tcp->check = 0;
|
||||
tcp->check = csum_tcpudp_magic(src_addr,dest_addr,len,IPPROTO_TCP,csum_partial(tcp, len));
|
||||
@@ -129,3 +129,10 @@ void tcp6_fix_checksum(struct tcphdr *tcp,int len, const struct in6_addr *src_ad
|
||||
tcp->check = 0;
|
||||
tcp->check = csum_ipv6_magic(src_addr,dest_addr,len,IPPROTO_TCP,csum_partial(tcp, len));
|
||||
}
|
||||
void tcp_fix_checksum(struct tcphdr *tcp,int len,const struct iphdr *iphdr,const struct ip6_hdr *ip6hdr)
|
||||
{
|
||||
if (iphdr)
|
||||
tcp4_fix_checksum(tcp, len, iphdr->saddr, iphdr->daddr);
|
||||
else if (ip6hdr)
|
||||
tcp6_fix_checksum(tcp, len, &ip6hdr->ip6_src, &ip6hdr->ip6_dst);
|
||||
}
|
||||
|
@@ -12,5 +12,6 @@ uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8
|
||||
uint16_t ip4_compute_csum(const void *buff, size_t len);
|
||||
void ip4_fix_checksum(struct iphdr *ip);
|
||||
|
||||
void tcp_fix_checksum(struct tcphdr *tcp,int len, in_addr_t src_addr, in_addr_t dest_addr);
|
||||
void tcp4_fix_checksum(struct tcphdr *tcp,int len, in_addr_t src_addr, in_addr_t dest_addr);
|
||||
void tcp6_fix_checksum(struct tcphdr *tcp,int len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
|
||||
void tcp_fix_checksum(struct tcphdr *tcp,int len,const struct iphdr *iphdr,const struct ip6_hdr *ip6hdr);
|
||||
|
@@ -192,7 +192,7 @@ bool prepare_tcp_segment4(
|
||||
fill_tcphdr(tcp,tcp_flags,seq,ack_seq,fooling,src->sin_port,dst->sin_port,wsize,timestamps);
|
||||
|
||||
memcpy((char*)tcp+sizeof(struct tcphdr)+tcpoptlen,data,len);
|
||||
tcp_fix_checksum(tcp,sizeof(struct tcphdr)+tcpoptlen+len,ip->saddr,ip->daddr);
|
||||
tcp4_fix_checksum(tcp,sizeof(struct tcphdr)+tcpoptlen+len,ip->saddr,ip->daddr);
|
||||
if (fooling & TCP_FOOL_BADSUM) tcp->check^=0xBEAF;
|
||||
|
||||
*buflen = pktlen;
|
||||
|
@@ -1,5 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "checksum.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <netinet/ip.h>
|
||||
@@ -7,7 +9,7 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/in.h>
|
||||
#include <sys/socket.h>
|
||||
#include "checksum.h"
|
||||
|
||||
|
||||
// returns netorder value
|
||||
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment);
|
||||
|
94
nfq/desync.c
94
nfq/desync.c
@@ -58,9 +58,12 @@ void desync_init()
|
||||
|
||||
|
||||
// result : true - drop original packet, false = dont drop
|
||||
bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *iphdr, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, uint8_t *data_payload, size_t len_payload)
|
||||
packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struct iphdr *iphdr, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload)
|
||||
{
|
||||
if (!!iphdr == !!ip6hdr) return false; // one and only one must be present
|
||||
packet_process_result res=pass;
|
||||
|
||||
if (!!iphdr == !!ip6hdr) return res; // one and only one must be present
|
||||
if (params.desync_mode==DESYNC_NONE && !params.hostcase && !params.hostnospace) return res; // nothing to do. do not waste cpu
|
||||
|
||||
if (!tcphdr->syn && len_payload)
|
||||
{
|
||||
@@ -69,8 +72,9 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
|
||||
size_t fake_size;
|
||||
char host[256];
|
||||
bool bHaveHost=false;
|
||||
bool bIsHttp;
|
||||
|
||||
if (IsHttp(data_payload,len_payload))
|
||||
if (bIsHttp = IsHttp(data_payload,len_payload))
|
||||
{
|
||||
DLOG("packet contains HTTP request\n")
|
||||
fake = (uint8_t*)fake_http_request;
|
||||
@@ -78,8 +82,8 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
|
||||
if (params.hostlist || params.debug) bHaveHost=HttpExtractHost(data_payload,len_payload,host,sizeof(host));
|
||||
if (params.hostlist && !bHaveHost)
|
||||
{
|
||||
DLOG("not applying dpi-desync to HTTP without Host:\n")
|
||||
return false;
|
||||
DLOG("not applying tampering to HTTP without Host:\n")
|
||||
return res;
|
||||
}
|
||||
}
|
||||
else if (IsTLSClientHello(data_payload,len_payload))
|
||||
@@ -92,16 +96,15 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
|
||||
bHaveHost=TLSHelloExtractHost(data_payload,len_payload,host,sizeof(host));
|
||||
if (params.desync_skip_nosni && !bHaveHost)
|
||||
{
|
||||
DLOG("not applying dpi-desync to TLS ClientHello without hostname in the SNI\n")
|
||||
return false;
|
||||
DLOG("not applying tampering to TLS ClientHello without hostname in the SNI\n")
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!params.desync_any_proto) return false;
|
||||
DLOG("applying dpi-desync to unknown protocol\n")
|
||||
if (!params.desync_any_proto) return res;
|
||||
DLOG("applying tampering to unknown protocol\n")
|
||||
fake = zeropkt;
|
||||
fake_size = 256;
|
||||
}
|
||||
@@ -111,11 +114,42 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
|
||||
DLOG("hostname: %s\n",host)
|
||||
if (params.hostlist && !SearchHostList(params.hostlist,host,params.debug))
|
||||
{
|
||||
DLOG("not applying dpi-desync to this request\n")
|
||||
return false;
|
||||
DLOG("not applying tampering to this request\n")
|
||||
return res;
|
||||
}
|
||||
|
||||
uint8_t *phost;
|
||||
if (bIsHttp && (params.hostcase || params.hostnospace) && (phost = (uint8_t*)memmem(data_payload, len_payload, "\r\nHost: ", 8)))
|
||||
{
|
||||
if (params.hostcase)
|
||||
{
|
||||
DLOG("modifying Host: => %c%c%c%c:\n", params.hostspell[0], params.hostspell[1], params.hostspell[2], params.hostspell[3])
|
||||
memcpy(phost + 2, params.hostspell, 4);
|
||||
res=modify;
|
||||
}
|
||||
uint8_t *pua;
|
||||
if (params.hostnospace &&
|
||||
(pua = (uint8_t*)memmem(data_payload, len_payload, "\r\nUser-Agent: ", 14)) &&
|
||||
(pua = (uint8_t*)memmem(pua + 1, len_payload - (pua - data_payload) - 1, "\r\n", 2)))
|
||||
{
|
||||
DLOG("removing space after Host: and adding it to User-Agent:\n")
|
||||
if (pua > phost)
|
||||
{
|
||||
memmove(phost + 7, phost + 8, pua - phost - 8);
|
||||
phost[pua - phost - 1] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove(pua + 1, pua, phost - pua + 7);
|
||||
*pua = ' ';
|
||||
}
|
||||
res=modify;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (params.desync_mode==DESYNC_NONE) return res;
|
||||
|
||||
extract_endpoints(iphdr, ip6hdr, tcphdr, &src, &dst);
|
||||
if (params.debug)
|
||||
{
|
||||
@@ -150,7 +184,7 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
|
||||
data_payload+split_pos, len_payload-split_pos, newdata, &newlen) ||
|
||||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
|
||||
{
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -164,7 +198,7 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
|
||||
zeropkt, split_pos, fakeseg, &fakeseg_len) ||
|
||||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
|
||||
{
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,17 +210,17 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
|
||||
data_payload, split_pos, newdata, &newlen) ||
|
||||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
|
||||
{
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (params.desync_mode==DESYNC_DISORDER)
|
||||
{
|
||||
DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu\n",split_pos-1, split_pos)
|
||||
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
|
||||
return true;
|
||||
return drop;
|
||||
}
|
||||
break;
|
||||
case DESYNC_SPLIT:
|
||||
@@ -205,7 +239,7 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
|
||||
zeropkt, split_pos, fakeseg, &fakeseg_len) ||
|
||||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
|
||||
{
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -216,14 +250,14 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
|
||||
data_payload, split_pos, newdata, &newlen) ||
|
||||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
|
||||
{
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (params.desync_mode==DESYNC_SPLIT)
|
||||
{
|
||||
DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu\n",split_pos-1, split_pos)
|
||||
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (split_pos<len_payload)
|
||||
@@ -235,11 +269,11 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
|
||||
data_payload+split_pos, len_payload-split_pos, newdata, &newlen) ||
|
||||
!rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
|
||||
{
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
return drop;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -248,7 +282,7 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
|
||||
ttl_fake,params.desync_tcp_fooling_mode,
|
||||
fake, fake_size, newdata, &newlen))
|
||||
{
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
case DESYNC_RST:
|
||||
@@ -257,27 +291,29 @@ bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *ip
|
||||
ttl_fake,params.desync_tcp_fooling_mode,
|
||||
NULL, 0, newdata, &newlen))
|
||||
{
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
|
||||
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen))
|
||||
return false;
|
||||
return res;
|
||||
|
||||
if (params.desync_retrans)
|
||||
DLOG("dropping packet to force retransmission. len=%zu len_payload=%zu\n", len_pkt, len_payload)
|
||||
else
|
||||
{
|
||||
DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", len_pkt, len_payload)
|
||||
// if original packet was tampered earlier it needs checksum fixed
|
||||
if (res==modify) tcp_fix_checksum(tcphdr,len_tcp,iphdr,ip6hdr);
|
||||
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, data_pkt, len_pkt))
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
return true;
|
||||
return drop;
|
||||
}
|
||||
|
||||
return false;
|
||||
return res;
|
||||
}
|
||||
|
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "darkmagic.h"
|
||||
#include "nfqws.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
@@ -24,4 +25,4 @@ enum dpi_desync_mode {
|
||||
};
|
||||
|
||||
void desync_init();
|
||||
bool dpi_desync_packet(const uint8_t *data_pkt, size_t len_pkt, struct iphdr *iphdr, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, uint8_t *data_payload, size_t len_payload);
|
||||
packet_process_result dpi_desync_packet(uint8_t *data_pkt, size_t len_pkt, struct iphdr *iphdr, struct ip6_hdr *ip6hdr, struct tcphdr *tcphdr, size_t len_tcp, uint8_t *data_payload, size_t len_payload);
|
||||
|
98
nfq/nfqws.c
98
nfq/nfqws.c
@@ -1,5 +1,6 @@
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include "nfqws.h"
|
||||
#include "sec.h"
|
||||
#include "desync.h"
|
||||
#include "helpers.h"
|
||||
@@ -138,17 +139,6 @@ static inline bool tcp_synack_segment(const struct tcphdr *tcphdr)
|
||||
tcphdr->syn == 1 &&
|
||||
tcphdr->fin == 0;
|
||||
}
|
||||
static inline bool tcp_ack_segment(const struct tcphdr *tcphdr)
|
||||
{
|
||||
/* check for set bits in TCP hdr */
|
||||
return tcphdr->urg == 0 &&
|
||||
tcphdr->ack == 1 &&
|
||||
tcphdr->rst == 0 &&
|
||||
tcphdr->syn == 0 &&
|
||||
tcphdr->fin == 0;
|
||||
}
|
||||
|
||||
|
||||
static void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize)
|
||||
{
|
||||
uint16_t winsize_old;
|
||||
@@ -157,77 +147,19 @@ static void tcp_rewrite_winsize(struct tcphdr *tcp, uint16_t winsize)
|
||||
DLOG("Window size change %u => %u\n", winsize_old, winsize)
|
||||
}
|
||||
|
||||
|
||||
// data/len points to data payload
|
||||
static bool modify_tcp_packet(uint8_t *data, size_t len, struct tcphdr *tcphdr)
|
||||
{
|
||||
const char **method;
|
||||
size_t method_len = 0;
|
||||
uint8_t *phost, *pua;
|
||||
bool bRet = false;
|
||||
|
||||
if (tcp_synack_segment(tcphdr))
|
||||
if (tcp_synack_segment(tcphdr) && params.wsize)
|
||||
{
|
||||
if (params.wsize)
|
||||
{
|
||||
tcp_rewrite_winsize(tcphdr, (uint16_t)params.wsize);
|
||||
bRet = true;
|
||||
}
|
||||
tcp_rewrite_winsize(tcphdr, (uint16_t)params.wsize);
|
||||
return true;
|
||||
}
|
||||
else if ((params.hostcase || params.hostnospace) && IsHttp(data,len))
|
||||
{
|
||||
if (params.hostlist)
|
||||
{
|
||||
char host[256];
|
||||
if (HttpExtractHost(data,len,host,sizeof(host)))
|
||||
{
|
||||
DLOG("hostname: %s\n",host)
|
||||
if (!SearchHostList(params.hostlist,host,params.debug))
|
||||
{
|
||||
DLOG("not applying tampering to this request\n")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG("could not extract host from http request. not applying tampering\n")
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (phost = (uint8_t*)memmem(data, len, "\r\nHost: ", 8))
|
||||
{
|
||||
if (params.hostcase)
|
||||
{
|
||||
DLOG("modifying Host: => %c%c%c%c:\n", params.hostspell[0], params.hostspell[1], params.hostspell[2], params.hostspell[3])
|
||||
memcpy(phost + 2, params.hostspell, 4);
|
||||
bRet = true;
|
||||
}
|
||||
if (params.hostnospace && (pua = (uint8_t*)memmem(data, len, "\r\nUser-Agent: ", 14)) && (pua = (uint8_t*)memmem(pua + 1, len - (pua - data) - 1, "\r\n", 2)))
|
||||
{
|
||||
DLOG("removing space after Host: and adding it to User-Agent:\n")
|
||||
if (pua > phost)
|
||||
{
|
||||
memmove(phost + 7, phost + 8, pua - phost - 8);
|
||||
phost[pua - phost - 1] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
memmove(pua + 1, pua, phost - pua + 7);
|
||||
*pua = ' ';
|
||||
}
|
||||
bRet = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return bRet;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
pass = 0, modify, drop
|
||||
} packet_process_result;
|
||||
static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt, uint32_t *mark)
|
||||
{
|
||||
struct iphdr *iphdr = NULL;
|
||||
@@ -235,7 +167,7 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
|
||||
struct tcphdr *tcphdr = NULL;
|
||||
size_t len = len_pkt, len_tcp;
|
||||
uint8_t *data = data_pkt;
|
||||
packet_process_result res = pass;
|
||||
packet_process_result res = pass, res2;
|
||||
uint8_t proto;
|
||||
|
||||
if (*mark & params.desync_fwmark) return res;
|
||||
@@ -266,18 +198,10 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
|
||||
|
||||
if (modify_tcp_packet(data, len, tcphdr))
|
||||
res = modify;
|
||||
if (params.desync_mode!=DESYNC_NONE)
|
||||
{
|
||||
if (dpi_desync_packet(data_pkt, len_pkt, iphdr, ip6hdr, tcphdr, data, len))
|
||||
res = drop;
|
||||
}
|
||||
if (res==modify)
|
||||
{
|
||||
if (iphdr)
|
||||
tcp_fix_checksum(tcphdr, len_tcp, iphdr->saddr, iphdr->daddr);
|
||||
else
|
||||
tcp6_fix_checksum(tcphdr, len_tcp, &ip6hdr->ip6_src, &ip6hdr->ip6_dst);
|
||||
}
|
||||
|
||||
res2 = dpi_desync_packet(data_pkt, len_pkt, iphdr, ip6hdr, tcphdr, len_tcp, data, len);
|
||||
res = (res2==pass && res==modify) ? modify : res2;
|
||||
if (res==modify) tcp_fix_checksum(tcphdr,len_tcp,iphdr,ip6hdr);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
@@ -320,7 +244,7 @@ static void exithelp()
|
||||
" --pidfile=<filename>\t\t\t; write pid to file\n"
|
||||
" --user=<username>\t\t\t; drop root privs\n"
|
||||
" --uid=uid[:gid]\t\t\t; drop root privs\n"
|
||||
" --wsize=<window_size>\t\t\t; set window size. 0 = do not modify\n"
|
||||
" --wsize=<window_size>\t\t\t; set window size. 0 = do not modify. OBSOLETE !\n"
|
||||
" --hostcase\t\t\t\t; change Host: => host:\n"
|
||||
" --hostspell\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n"
|
||||
" --hostnospace\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n"
|
||||
|
6
nfq/nfqws.h
Normal file
6
nfq/nfqws.h
Normal file
@@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum
|
||||
{
|
||||
pass = 0, modify, drop
|
||||
} packet_process_result;
|
Reference in New Issue
Block a user