mirror of
https://github.com/bol-van/zapret.git
synced 2024-11-26 12:10:53 +03:00
Compare commits
6 Commits
656c549113
...
9b3bbb7285
Author | SHA1 | Date | |
---|---|---|---|
|
9b3bbb7285 | ||
|
284f911785 | ||
|
a17e490851 | ||
|
c1e670be23 | ||
|
918d52c2e6 | ||
|
1c7080ca68 |
@ -213,7 +213,7 @@
|
||||
> Если используются методы нулевой фазы десинхронизации (`--mss`,
|
||||
> `--wssize`, `--dpi-desync=syndata`) и режим фильтрации `hostlist`, то все
|
||||
> параметры, относящиеся к этим методам, следует помещать в отдельные
|
||||
> профили мульистратегии, которые получат управление до определения имени
|
||||
> профили мультистратегии, которые получат управление до определения имени
|
||||
> хоста. Необходимо понимать алгоритм работы мультистратегий. Самым надежным
|
||||
> вариантом будет дублирование этих параметров на 2 профиля. Какой-нибудь
|
||||
> сработает в зависимости от параметра `MODE_FILTER`.
|
||||
|
@ -12,29 +12,6 @@ static void ut_oom_recover(void *elem)
|
||||
oom = true;
|
||||
}
|
||||
|
||||
const char *l7proto_str(t_l7proto l7)
|
||||
{
|
||||
switch(l7)
|
||||
{
|
||||
case HTTP: return "http";
|
||||
case TLS: return "tls";
|
||||
case QUIC: return "quic";
|
||||
case WIREGUARD: return "wireguard";
|
||||
case DHT: return "dht";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
|
||||
{
|
||||
return (l7proto==UNKNOWN && (filter_l7 & L7_PROTO_UNKNOWN)) ||
|
||||
(l7proto==HTTP && (filter_l7 & L7_PROTO_HTTP)) ||
|
||||
(l7proto==TLS && (filter_l7 & L7_PROTO_TLS)) ||
|
||||
(l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) ||
|
||||
(l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) ||
|
||||
(l7proto==DHT && (filter_l7 & L7_PROTO_DHT));
|
||||
}
|
||||
|
||||
|
||||
static const char *connstate_s[]={"SYN","ESTABLISHED","FIN"};
|
||||
|
||||
static void connswap(const t_conn *c, t_conn *c2)
|
||||
|
@ -4,8 +4,6 @@
|
||||
// this conntrack is not bullet-proof
|
||||
// its designed to satisfy dpi desync needs only
|
||||
|
||||
#include "packet_queue.h"
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
@ -19,6 +17,8 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/udp.h>
|
||||
|
||||
#include "packet_queue.h"
|
||||
#include "protocol.h"
|
||||
|
||||
//#define HASH_BLOOM 20
|
||||
#define HASH_NONFATAL_OOM 1
|
||||
@ -53,16 +53,6 @@ typedef struct {
|
||||
// FIN - FIN or RST received
|
||||
typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate;
|
||||
|
||||
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto;
|
||||
#define L7_PROTO_HTTP 0x00000001
|
||||
#define L7_PROTO_TLS 0x00000002
|
||||
#define L7_PROTO_QUIC 0x00000004
|
||||
#define L7_PROTO_WIREGUARD 0x00000008
|
||||
#define L7_PROTO_DHT 0x00000010
|
||||
#define L7_PROTO_UNKNOWN 0x80000000
|
||||
const char *l7proto_str(t_l7proto l7);
|
||||
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool bCheckDone, bCheckResult, bCheckExcluded; // hostlist check result cache
|
||||
|
244
nfq/desync.c
244
nfq/desync.c
@ -97,11 +97,11 @@ bool desync_only_first_stage(enum dpi_desync_mode mode)
|
||||
}
|
||||
bool desync_valid_second_stage(enum dpi_desync_mode mode)
|
||||
{
|
||||
return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2 || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER;
|
||||
return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2 || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER;
|
||||
}
|
||||
bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode)
|
||||
{
|
||||
return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2;
|
||||
return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2;
|
||||
}
|
||||
bool desync_valid_second_stage_udp(enum dpi_desync_mode mode)
|
||||
{
|
||||
@ -131,6 +131,10 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
|
||||
return DESYNC_SPLIT;
|
||||
else if (!strcmp(s,"split2"))
|
||||
return DESYNC_SPLIT2;
|
||||
else if (!strcmp(s,"multisplit"))
|
||||
return DESYNC_MULTISPLIT;
|
||||
else if (!strcmp(s,"multidisorder"))
|
||||
return DESYNC_MULTIDISORDER;
|
||||
else if (!strcmp(s,"ipfrag2"))
|
||||
return DESYNC_IPFRAG2;
|
||||
else if (!strcmp(s,"hopbyhop"))
|
||||
@ -582,22 +586,7 @@ static bool replay_queue(struct rawpacket_tailhead *q);
|
||||
|
||||
static size_t pos_normalize(size_t split_pos, size_t reasm_offset, size_t len_payload)
|
||||
{
|
||||
size_t rsplit_pos = split_pos;
|
||||
// normalize split pos to current packet
|
||||
split_pos=(split_pos>reasm_offset && (split_pos-reasm_offset)<len_payload) ? split_pos-reasm_offset : 0;
|
||||
if (rsplit_pos)
|
||||
{
|
||||
if (split_pos==rsplit_pos)
|
||||
DLOG("split pos %zu\n",split_pos);
|
||||
else
|
||||
{
|
||||
if (split_pos)
|
||||
DLOG("split pos was normalized to packet data offset : %zu -> %zu\n",rsplit_pos,split_pos);
|
||||
else
|
||||
DLOG("split pos %zu is outside of this packet %zu-%zu\n",rsplit_pos,reasm_offset,reasm_offset+len_payload);
|
||||
}
|
||||
}
|
||||
return split_pos;
|
||||
return (split_pos>reasm_offset && (split_pos-reasm_offset)<len_payload) ? split_pos-reasm_offset : 0;
|
||||
}
|
||||
|
||||
static void autottl_discover(t_ctrack *ctrack, bool bIpv6)
|
||||
@ -856,6 +845,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
const uint8_t *rdata_payload = dis->data_payload;
|
||||
size_t rlen_payload = dis->len_payload;
|
||||
size_t split_pos;
|
||||
size_t multisplit_pos[MAX_SPLITS];
|
||||
int multisplit_count;
|
||||
int i;
|
||||
t_l7proto l7proto = UNKNOWN;
|
||||
|
||||
if (replay)
|
||||
@ -1065,35 +1057,12 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
}
|
||||
}
|
||||
|
||||
// desync profile may have changed after hostname was revealed
|
||||
switch(l7proto)
|
||||
{
|
||||
case HTTP:
|
||||
fake = dp->fake_http;
|
||||
fake_size = dp->fake_http_size;
|
||||
split_pos = HttpPos(dp->desync_split_http_req, dp->desync_split_pos, rdata_payload, rlen_payload);
|
||||
break;
|
||||
case TLS:
|
||||
fake = dp->fake_tls;
|
||||
fake_size = dp->fake_tls_size;
|
||||
split_pos = TLSPos(dp->desync_split_tls, dp->desync_split_pos, rdata_payload, rlen_payload, 0);
|
||||
break;
|
||||
default:
|
||||
fake = dp->fake_unknown;
|
||||
fake_size = dp->fake_unknown_size;
|
||||
split_pos=dp->desync_split_pos;
|
||||
break;
|
||||
}
|
||||
|
||||
// we do not need reasm buffer anymore
|
||||
reasm_orig_cancel(ctrack);
|
||||
rdata_payload=NULL;
|
||||
|
||||
if (l7proto==UNKNOWN)
|
||||
{
|
||||
if (!dp->desync_any_proto)
|
||||
{
|
||||
DLOG("not applying tampering to unknown protocol\n");
|
||||
reasm_orig_cancel(ctrack);
|
||||
return verdict;
|
||||
}
|
||||
DLOG("applying tampering to unknown protocol\n");
|
||||
@ -1135,7 +1104,63 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
}
|
||||
}
|
||||
|
||||
if (dp->desync_mode==DESYNC_NONE) return verdict;
|
||||
if (dp->desync_mode==DESYNC_NONE)
|
||||
{
|
||||
reasm_orig_cancel(ctrack);
|
||||
return verdict;
|
||||
}
|
||||
|
||||
const struct split_pos *spos;
|
||||
switch(l7proto)
|
||||
{
|
||||
case HTTP:
|
||||
fake = dp->fake_http;
|
||||
fake_size = dp->fake_http_size;
|
||||
spos = &dp->split_http;
|
||||
break;
|
||||
case TLS:
|
||||
fake = dp->fake_tls;
|
||||
fake_size = dp->fake_tls_size;
|
||||
spos = &dp->split_tls;
|
||||
break;
|
||||
default:
|
||||
fake = dp->fake_unknown;
|
||||
fake_size = dp->fake_unknown_size;
|
||||
spos = &dp->split_unknown;
|
||||
break;
|
||||
}
|
||||
if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)
|
||||
{
|
||||
split_pos=0;
|
||||
ResolveMultiPos(rdata_payload, rlen_payload, l7proto, dp->splits, dp->split_count, multisplit_pos, &multisplit_count);
|
||||
if (params.debug)
|
||||
{
|
||||
if (multisplit_count)
|
||||
{
|
||||
DLOG("multisplit pos: ");
|
||||
for (i=0;i<multisplit_count;i++) DLOG("%zu ",multisplit_pos[i]);
|
||||
DLOG("\n");
|
||||
}
|
||||
else
|
||||
DLOG("all multisplit pos are outside of this packet\n");
|
||||
}
|
||||
}
|
||||
else if (dp->desync_mode==DESYNC_SPLIT || dp->desync_mode==DESYNC_SPLIT2 || dp->desync_mode==DESYNC_DISORDER || dp->desync_mode==DESYNC_DISORDER2 ||
|
||||
dp->desync_mode2==DESYNC_SPLIT || dp->desync_mode2==DESYNC_SPLIT2 || dp->desync_mode2==DESYNC_DISORDER || dp->desync_mode2==DESYNC_DISORDER2)
|
||||
{
|
||||
multisplit_count=0;
|
||||
split_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, spos);
|
||||
DLOG("regular split pos: %zu\n",split_pos);
|
||||
}
|
||||
else
|
||||
{
|
||||
multisplit_count=0;
|
||||
split_pos = 0;
|
||||
}
|
||||
|
||||
// we do not need reasm buffer anymore
|
||||
reasm_orig_cancel(ctrack);
|
||||
rdata_payload=NULL;
|
||||
|
||||
if (params.debug)
|
||||
{
|
||||
@ -1147,24 +1172,42 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
|
||||
if (!split_pos || split_pos>rlen_payload) split_pos=1;
|
||||
split_pos=pos_normalize(split_pos,reasm_offset,dis->len_payload);
|
||||
if (split_pos)
|
||||
DLOG("normalized regular split pos : %zu\n",split_pos);
|
||||
else
|
||||
DLOG("regular split pos is outside of this packet\n");
|
||||
if (multisplit_count)
|
||||
{
|
||||
int j;
|
||||
for (i=j=0;i<multisplit_count;i++)
|
||||
{
|
||||
multisplit_pos[j]=pos_normalize(multisplit_pos[i],reasm_offset,dis->len_payload);
|
||||
if (multisplit_pos[j]) j++;
|
||||
}
|
||||
multisplit_count=j;
|
||||
if (params.debug)
|
||||
{
|
||||
if (multisplit_count)
|
||||
{
|
||||
DLOG("normalized multisplit pos: ");
|
||||
for (i=0;i<multisplit_count;i++) DLOG("%zu ",multisplit_pos[i]);
|
||||
DLOG("\n");
|
||||
}
|
||||
else
|
||||
DLOG("all multisplit pos are outside of this packet\n");
|
||||
}
|
||||
}
|
||||
|
||||
enum dpi_desync_mode desync_mode = dp->desync_mode;
|
||||
uint32_t fooling_orig = FOOL_NONE;
|
||||
bool b;
|
||||
bool bFake = false;
|
||||
pkt1_len = sizeof(pkt1);
|
||||
b = false;
|
||||
switch(desync_mode)
|
||||
switch(dp->desync_mode)
|
||||
{
|
||||
case DESYNC_FAKE_KNOWN:
|
||||
if (reasm_offset)
|
||||
{
|
||||
desync_mode = dp->desync_mode2;
|
||||
break;
|
||||
}
|
||||
if (reasm_offset) break;
|
||||
if (l7proto==UNKNOWN)
|
||||
{
|
||||
DLOG("not applying fake because of unknown protocol\n");
|
||||
desync_mode = dp->desync_mode2;
|
||||
break;
|
||||
}
|
||||
case DESYNC_FAKE:
|
||||
@ -1176,14 +1219,14 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
{
|
||||
return verdict;
|
||||
}
|
||||
DLOG("sending fake request : ");
|
||||
DLOG("sending fake : ");
|
||||
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
|
||||
b = true;
|
||||
bFake = true;
|
||||
break;
|
||||
case DESYNC_RST:
|
||||
case DESYNC_RSTACK:
|
||||
if (reasm_offset) break;
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (desync_mode==DESYNC_RSTACK ? TH_ACK:0), dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode==DESYNC_RSTACK ? TH_ACK:0), dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
||||
ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
||||
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
||||
NULL, 0, pkt1, &pkt1_len))
|
||||
@ -1191,15 +1234,15 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
return verdict;
|
||||
}
|
||||
DLOG("sending fake RST/RSTACK\n");
|
||||
b = true;
|
||||
bFake = true;
|
||||
break;
|
||||
case DESYNC_HOPBYHOP:
|
||||
case DESYNC_DESTOPT:
|
||||
case DESYNC_IPFRAG1:
|
||||
fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
|
||||
desync_mode = dp->desync_mode2;
|
||||
if (dis->ip6 && (desync_mode==DESYNC_NONE || !desync_valid_second_stage_tcp(desync_mode) ||
|
||||
(!split_pos && (desync_mode==DESYNC_SPLIT || desync_mode==DESYNC_SPLIT2 || desync_mode==DESYNC_DISORDER || desync_mode==DESYNC_DISORDER2))))
|
||||
fooling_orig = (dp->desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
|
||||
if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(dp->desync_mode2) ||
|
||||
(!split_pos && (dp->desync_mode2==DESYNC_SPLIT || dp->desync_mode2==DESYNC_SPLIT2 || dp->desync_mode2==DESYNC_DISORDER || dp->desync_mode2==DESYNC_DISORDER2)) ||
|
||||
(!multisplit_count && (dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER))))
|
||||
{
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
||||
ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
||||
@ -1219,24 +1262,65 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
break;
|
||||
}
|
||||
|
||||
if (b)
|
||||
if (bFake)
|
||||
{
|
||||
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
|
||||
return verdict;
|
||||
if (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(dp->desync_mode2))
|
||||
{
|
||||
DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", dis->len_pkt, dis->len_payload);
|
||||
verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6);
|
||||
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , dis->data_pkt, dis->len_pkt))
|
||||
return verdict;
|
||||
return VERDICT_DROP;
|
||||
}
|
||||
desync_mode = dp->desync_mode2;
|
||||
}
|
||||
|
||||
pkt1_len = sizeof(pkt1);
|
||||
enum dpi_desync_mode desync_mode = dp->desync_mode2==DESYNC_NONE ? dp->desync_mode : dp->desync_mode2;
|
||||
switch(desync_mode)
|
||||
{
|
||||
case DESYNC_MULTISPLIT:
|
||||
if (multisplit_count)
|
||||
{
|
||||
size_t from,to;
|
||||
for (i=0,from=0 ; i<=multisplit_count ; i++)
|
||||
{
|
||||
to = i==multisplit_count ? dis->len_payload : multisplit_pos[i];
|
||||
|
||||
pkt1_len = sizeof(pkt1);
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig,
|
||||
net32_add(dis->tcp->th_seq,from), dis->tcp->th_ack,
|
||||
dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
||||
fooling_orig,0,0,
|
||||
dis->data_payload+from, to-from, pkt1, &pkt1_len))
|
||||
return verdict;
|
||||
DLOG("sending multisplit part %d %zu-%zu len=%zu : ",i+1,from,to-1,to-from);
|
||||
hexdump_limited_dlog(dis->data_payload+from,to-from,PKTDATA_MAXDUMP); DLOG("\n");
|
||||
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
|
||||
return verdict;
|
||||
|
||||
from = to;
|
||||
}
|
||||
return VERDICT_DROP;
|
||||
}
|
||||
break;
|
||||
case DESYNC_MULTIDISORDER:
|
||||
if (multisplit_count)
|
||||
{
|
||||
size_t from,to;
|
||||
for (i=multisplit_count-1,to=dis->len_payload ; i>=-1 ; i--)
|
||||
{
|
||||
from = i>=0 ? multisplit_pos[i] : 0;
|
||||
|
||||
pkt1_len = sizeof(pkt1);
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig,
|
||||
net32_add(dis->tcp->th_seq,from), dis->tcp->th_ack,
|
||||
dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
||||
fooling_orig,0,0,
|
||||
dis->data_payload+from, to-from, pkt1, &pkt1_len))
|
||||
return verdict;
|
||||
DLOG("sending multisplit part %d %zu-%zu len=%zu : ",i+2,from,to-1,to-from);
|
||||
hexdump_limited_dlog(dis->data_payload+from,to-from,PKTDATA_MAXDUMP); DLOG("\n");
|
||||
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
|
||||
return verdict;
|
||||
|
||||
to = from;
|
||||
}
|
||||
return VERDICT_DROP;
|
||||
}
|
||||
break;
|
||||
case DESYNC_DISORDER:
|
||||
case DESYNC_DISORDER2:
|
||||
if (split_pos)
|
||||
@ -1270,6 +1354,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
seg_len = dis->len_payload-split_pos;
|
||||
}
|
||||
|
||||
pkt1_len = sizeof(pkt1);
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq , split_pos - dp->desync_seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
||||
ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
||||
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
||||
@ -1357,6 +1442,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
seg_len = split_pos;
|
||||
}
|
||||
|
||||
pkt1_len = sizeof(pkt1);
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,-dp->desync_seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
|
||||
ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
||||
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
||||
@ -1437,6 +1523,14 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
break;
|
||||
}
|
||||
|
||||
if (bFake)
|
||||
{
|
||||
DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", dis->len_pkt, dis->len_payload);
|
||||
verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6);
|
||||
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , dis->data_pkt, dis->len_pkt))
|
||||
return verdict;
|
||||
return VERDICT_DROP;
|
||||
}
|
||||
}
|
||||
|
||||
return verdict;
|
||||
@ -1833,7 +1927,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
||||
case DESYNC_FAKE:
|
||||
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len))
|
||||
return verdict;
|
||||
DLOG("sending fake request : ");
|
||||
DLOG("sending fake : ");
|
||||
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
|
||||
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
|
||||
return verdict;
|
||||
@ -1996,7 +2090,7 @@ static void packet_debug(bool replay, const struct dissect *dis)
|
||||
char s[80];
|
||||
str_tcphdr(s,sizeof(s),dis->tcp);
|
||||
DLOG(" %s\n",s);
|
||||
if (dis->len_payload) { DLOG("TCP: "); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); }
|
||||
if (dis->len_payload) { DLOG("TCP: len=%zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); }
|
||||
|
||||
}
|
||||
else if (dis->udp)
|
||||
@ -2004,7 +2098,7 @@ static void packet_debug(bool replay, const struct dissect *dis)
|
||||
char s[30];
|
||||
str_udphdr(s,sizeof(s),dis->udp);
|
||||
DLOG(" %s\n",s);
|
||||
if (dis->len_payload) { DLOG("UDP: "); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); }
|
||||
if (dis->len_payload) { DLOG("UDP: len=%zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); }
|
||||
}
|
||||
else
|
||||
DLOG("\n");
|
||||
|
@ -32,6 +32,8 @@ enum dpi_desync_mode {
|
||||
DESYNC_DISORDER2,
|
||||
DESYNC_SPLIT,
|
||||
DESYNC_SPLIT2,
|
||||
DESYNC_MULTISPLIT,
|
||||
DESYNC_MULTIDISORDER,
|
||||
DESYNC_IPFRAG2,
|
||||
DESYNC_HOPBYHOP,
|
||||
DESYNC_DESTOPT,
|
||||
|
@ -11,6 +11,27 @@
|
||||
|
||||
#include "params.h"
|
||||
|
||||
int unique_size_t(size_t *pu, int ct)
|
||||
{
|
||||
int i, j, u;
|
||||
for (i = j = 0; j < ct; i++)
|
||||
{
|
||||
u = pu[j++];
|
||||
for (; j < ct && pu[j] == u; j++);
|
||||
pu[i] = u;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
static int cmp_size_t(const void * a, const void * b)
|
||||
{
|
||||
return *(size_t*)a < *(size_t*)b ? -1 : *(size_t*)a > *(size_t*)b;
|
||||
}
|
||||
void qsort_size_t(size_t *array,size_t ct)
|
||||
{
|
||||
qsort(array,ct,sizeof(*array),cmp_size_t);
|
||||
}
|
||||
|
||||
|
||||
void rtrim(char *s)
|
||||
{
|
||||
if (s)
|
||||
|
@ -17,6 +17,9 @@ typedef union
|
||||
char _align[32]; // force 16-byte alignment for ip6_and int128 ops
|
||||
} sockaddr_in46;
|
||||
|
||||
int unique_size_t(size_t *pu, int ct);
|
||||
void qsort_size_t(size_t *array,size_t ct);
|
||||
|
||||
void rtrim(char *s);
|
||||
void replace_char(char *s, char from, char to);
|
||||
char *strncasestr(const char *s,const char *find, size_t slen);
|
||||
|
237
nfq/nfqws.c
237
nfq/nfqws.c
@ -673,10 +673,7 @@ static bool parse_l7_list(char *opt, uint32_t *l7)
|
||||
*l7 |= L7_PROTO_UNKNOWN;
|
||||
else return false;
|
||||
|
||||
if (e)
|
||||
{
|
||||
*e++=c;
|
||||
}
|
||||
if (e) *e++=c;
|
||||
p = e;
|
||||
}
|
||||
return true;
|
||||
@ -723,15 +720,173 @@ static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6)
|
||||
*ipv6 = true;
|
||||
else return false;
|
||||
|
||||
if (e)
|
||||
{
|
||||
*e++=c;
|
||||
}
|
||||
if (e) *e++=c;
|
||||
p = e;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_httpreqpos(const char *s, struct split_pos *sp)
|
||||
{
|
||||
if (!strcmp(s, "method"))
|
||||
{
|
||||
sp->marker = PM_HTTP_METHOD;
|
||||
sp->pos=2;
|
||||
}
|
||||
else if (!strcmp(s, "host"))
|
||||
{
|
||||
sp->marker = PM_HOST;
|
||||
sp->pos=1;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
static bool parse_tlspos(const char *s, struct split_pos *sp)
|
||||
{
|
||||
if (!strcmp(s, "sni"))
|
||||
{
|
||||
sp->marker = PM_HOST;
|
||||
sp->pos=1;
|
||||
}
|
||||
else if (!strcmp(s, "sniext"))
|
||||
{
|
||||
sp->marker = PM_SNI_EXT;
|
||||
sp->pos=0;
|
||||
}
|
||||
else if (!strcmp(s, "snisld"))
|
||||
{
|
||||
sp->marker = PM_HOST_MIDSLD;
|
||||
sp->pos=1;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool parse_int16(const char *p, int16_t *v)
|
||||
{
|
||||
if (*p=='+' || *p=='-' || *p>='0' && *p<='9')
|
||||
{
|
||||
int i = atoi(p);
|
||||
*v = (int16_t)i;
|
||||
return *v==i; // check overflow
|
||||
}
|
||||
return false;
|
||||
}
|
||||
static bool parse_posmarker(const char *opt, uint8_t *posmarker)
|
||||
{
|
||||
if (!strcmp(opt,"host"))
|
||||
*posmarker = PM_HOST;
|
||||
else if (!strcmp(opt,"endhost"))
|
||||
*posmarker = PM_HOST_END;
|
||||
else if (!strcmp(opt,"sld"))
|
||||
*posmarker = PM_HOST_SLD;
|
||||
else if (!strcmp(opt,"midsld"))
|
||||
*posmarker = PM_HOST_MIDSLD;
|
||||
else if (!strcmp(opt,"endsld"))
|
||||
*posmarker = PM_HOST_ENDSLD;
|
||||
else if (!strcmp(opt,"method"))
|
||||
*posmarker = PM_HTTP_METHOD;
|
||||
else if (!strcmp(opt,"sniext"))
|
||||
*posmarker = PM_SNI_EXT;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
static bool parse_split_pos(char *opt, struct split_pos *split)
|
||||
{
|
||||
if (parse_int16(opt,&split->pos))
|
||||
{
|
||||
split->marker = PM_ABS;
|
||||
return !!split->pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
char c,*p=opt;
|
||||
bool b;
|
||||
|
||||
for (; *opt && *opt!='+' && *opt!='-'; opt++);
|
||||
c=*opt; *opt=0;
|
||||
b=parse_posmarker(p,&split->marker);
|
||||
*opt=c;
|
||||
if (!b) return false;
|
||||
if (*opt)
|
||||
return parse_int16(opt,&split->pos);
|
||||
else
|
||||
split->pos = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static bool parse_split_pos_list(char *opt, struct split_pos *splits, int splits_size, int *split_count)
|
||||
{
|
||||
char c,*e,*p;
|
||||
|
||||
for (p=opt, *split_count=0 ; p && *split_count<splits_size ; (*split_count)++)
|
||||
{
|
||||
if ((e = strchr(p,',')))
|
||||
{
|
||||
c=*e;
|
||||
*e=0;
|
||||
}
|
||||
if (!parse_split_pos(p,splits+*split_count)) return false;
|
||||
if (e) *e++=c;
|
||||
p = e;
|
||||
}
|
||||
if (p) return false; // too much splits
|
||||
return true;
|
||||
}
|
||||
static void split_compat(struct desync_profile *dp)
|
||||
{
|
||||
// make it mostly compatible with old versions
|
||||
int i;
|
||||
dp->split_unknown.marker=PM_ABS;
|
||||
dp->split_unknown.pos=2;
|
||||
for (i=0;i<dp->split_count;i++)
|
||||
{
|
||||
if (dp->splits[i].marker==PM_ABS)
|
||||
{
|
||||
dp->split_unknown.pos=dp->splits[i].pos;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (SPLIT_POS_EMPTY(&dp->split_http))
|
||||
{
|
||||
dp->split_http=dp->split_unknown;
|
||||
for (i=0;i<dp->split_count;i++)
|
||||
if (IsHostMarker(dp->splits[i].marker) || dp->splits[i].marker==PM_HTTP_METHOD)
|
||||
{
|
||||
dp->split_http = dp->splits[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (SPLIT_POS_EMPTY(&dp->split_tls))
|
||||
{
|
||||
dp->split_tls=dp->split_unknown;
|
||||
for (i=0;i<dp->split_count;i++)
|
||||
if (IsHostMarker(dp->splits[i].marker) || dp->splits[i].marker==PM_SNI_EXT)
|
||||
{
|
||||
dp->split_tls = dp->splits[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void SplitDebug(void)
|
||||
{
|
||||
struct desync_profile_list *dpl;
|
||||
const struct desync_profile *dp;
|
||||
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
||||
{
|
||||
dp = &dpl->dp;
|
||||
DLOG("profile %d split_http %s %d\n",dp->n,posmarker_name(dp->split_http.marker),dp->split_http.pos);
|
||||
DLOG("profile %d split_tls %s %d\n",dp->n,posmarker_name(dp->split_tls.marker),dp->split_tls.pos);
|
||||
DLOG("profile %d split_unknown %s %d\n",dp->n,posmarker_name(dp->split_unknown.marker),dp->split_unknown.pos);
|
||||
for(int x=0;x<dp->split_count;x++)
|
||||
DLOG("profile %d multisplit %s %d\n",dp->n,posmarker_name(dp->splits[x].marker),dp->splits[x].pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *buf, size_t len)
|
||||
{
|
||||
@ -757,10 +912,7 @@ static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *bu
|
||||
if (n) strncat(buf," or ",len-strlen(buf)-1);
|
||||
strncat(buf, s1, len-strlen(buf)-1);
|
||||
|
||||
if (e)
|
||||
{
|
||||
*e++=c;
|
||||
}
|
||||
if (e) *e++=c;
|
||||
p = e;
|
||||
}
|
||||
strncat(buf, ")", len-strlen(buf)-1);
|
||||
@ -912,7 +1064,9 @@ static void exithelp(void)
|
||||
" --hostspell\t\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n"
|
||||
" --hostnospace\t\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n"
|
||||
" --domcase\t\t\t\t\t; mix domain case : Host: TeSt.cOm\n"
|
||||
" --dpi-desync=[<mode0>,]<mode>[,<mode2>]\t; try to desync dpi state. modes : synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen tamper\n"
|
||||
" --dpi-desync=[<mode0>,]<mode>[,<mode2>]\t; try to desync dpi state. modes :\n"
|
||||
"\t\t\t\t\t\t; synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1\n"
|
||||
"\t\t\t\t\t\t; disorder disorder2 split split2 multisplit multidisorder ipfrag2 udplen tamper\n"
|
||||
#ifdef __linux__
|
||||
" --dpi-desync-fwmark=<int|0xHEX>\t\t; override fwmark for desync packet. default = 0x%08X (%u)\n"
|
||||
#elif defined(SO_USER_COOKIE)
|
||||
@ -925,9 +1079,9 @@ static void exithelp(void)
|
||||
" --dpi-desync-fooling=<mode>[,<mode>]\t\t; can use multiple comma separated values. modes : none md5sig ts badseq badsum datanoack hopbyhop hopbyhop2\n"
|
||||
" --dpi-desync-repeats=<N>\t\t\t; send every desync packet N times\n"
|
||||
" --dpi-desync-skip-nosni=0|1\t\t\t; 1(default)=do not act on ClientHello without SNI (ESNI ?)\n"
|
||||
" --dpi-desync-split-pos=<1..%u>\t\t; data payload split position\n"
|
||||
" --dpi-desync-split-http-req=method|host\t; split at specified logical part of plain http request\n"
|
||||
" --dpi-desync-split-tls=sni|sniext|snisld\t; split at specified logical part of TLS ClientHello\n"
|
||||
" --dpi-desync-split-pos=N|-N|marker+N|marker-N\t; comma separated list of split positions. markers: method,host,endhost,sld,endsld,midsld,sniext\n"
|
||||
"\t\t\t\t\t\t; full list is only used by multisplit and multidisorder\n"
|
||||
"\t\t\t\t\t\t; single split takes first l7-protocol-compatible parameter if present, first abs value otherwise\n"
|
||||
" --dpi-desync-split-seqovl=<int>\t\t; use sequence overlap before first sent original split segment\n"
|
||||
" --dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; pattern for the fake part of overlap\n"
|
||||
" --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
|
||||
@ -953,7 +1107,6 @@ static void exithelp(void)
|
||||
DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT,
|
||||
#endif
|
||||
AUTOTTL_DEFAULT_DELTA,AUTOTTL_DEFAULT_MIN,AUTOTTL_DEFAULT_MAX,
|
||||
DPI_DESYNC_MAX_FAKE_LEN,
|
||||
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT,
|
||||
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT,
|
||||
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT,
|
||||
@ -967,29 +1120,6 @@ static void exithelp_clean(void)
|
||||
exithelp();
|
||||
}
|
||||
|
||||
bool parse_httpreqpos(const char *s, enum httpreqpos *pos)
|
||||
{
|
||||
if (!strcmp(s, "method"))
|
||||
*pos = httpreqpos_method;
|
||||
else if (!strcmp(s, "host"))
|
||||
*pos = httpreqpos_host;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
bool parse_tlspos(const char *s, enum tlspos *pos)
|
||||
{
|
||||
if (!strcmp(s, "sni"))
|
||||
*pos = tlspos_sni;
|
||||
else if (!strcmp(s, "sniext"))
|
||||
*pos = tlspos_sniext;
|
||||
else if (!strcmp(s, "snisld"))
|
||||
*pos = tlspos_snisld;
|
||||
else
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef __OpenBSD__
|
||||
// no static to not allow optimizer to inline this func (save stack)
|
||||
void config_from_file(const char *filename)
|
||||
@ -1447,21 +1577,27 @@ int main(int argc, char **argv)
|
||||
dp->desync_skip_nosni = !optarg || atoi(optarg);
|
||||
break;
|
||||
case 23: /* dpi-desync-split-pos */
|
||||
if (sscanf(optarg,"%u",&dp->desync_split_pos)<1 || dp->desync_split_pos<1)
|
||||
{
|
||||
DLOG_ERR("dpi-desync-split-pos is not valid\n");
|
||||
int ct;
|
||||
if (!parse_split_pos_list(optarg,dp->splits+dp->split_count,MAX_SPLITS-dp->split_count,&ct))
|
||||
{
|
||||
DLOG_ERR("could not parse split pos list or too much positions (before parsing - %u, max - %u) : %s\n",dp->split_count,MAX_SPLITS,optarg);
|
||||
exit_clean(1);
|
||||
}
|
||||
dp->split_count += ct;
|
||||
}
|
||||
break;
|
||||
case 24: /* dpi-desync-split-http-req */
|
||||
if (!parse_httpreqpos(optarg, &dp->desync_split_http_req))
|
||||
// obsolete arg
|
||||
if (!parse_httpreqpos(optarg, &dp->split_http))
|
||||
{
|
||||
DLOG_ERR("Invalid argument for dpi-desync-split-http-req\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case 25: /* dpi-desync-split-tls */
|
||||
if (!parse_tlspos(optarg, &dp->desync_split_tls))
|
||||
// obsolete arg
|
||||
if (!parse_tlspos(optarg, &dp->split_tls))
|
||||
{
|
||||
DLOG_ERR("Invalid argument for dpi-desync-split-tls\n");
|
||||
exit_clean(1);
|
||||
@ -1912,6 +2048,13 @@ int main(int argc, char **argv)
|
||||
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
||||
{
|
||||
dp = &dpl->dp;
|
||||
|
||||
if (!dp->split_count && (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER))
|
||||
{
|
||||
DLOG_ERR("multisplit requires explicit split pos\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
|
||||
// not specified - use desync_ttl value instead
|
||||
if (dp->desync_ttl6 == 0xFF) dp->desync_ttl6=dp->desync_ttl;
|
||||
if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl;
|
||||
@ -1919,8 +2062,7 @@ int main(int argc, char **argv)
|
||||
DLOG("[profile %d] autottl ipv4 %u:%u-%u\n",dp->n,dp->desync_autottl.delta,dp->desync_autottl.min,dp->desync_autottl.max);
|
||||
if (AUTOTTL_ENABLED(dp->desync_autottl6))
|
||||
DLOG("[profile %d] autottl ipv6 %u:%u-%u\n",dp->n,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max);
|
||||
if (dp->desync_split_tls==tlspos_none && dp->desync_split_pos) dp->desync_split_tls=tlspos_pos;
|
||||
if (dp->desync_split_http_req==httpreqpos_none && dp->desync_split_pos) dp->desync_split_http_req=httpreqpos_pos;
|
||||
split_compat(dp);
|
||||
}
|
||||
|
||||
if (!LoadAllHostLists())
|
||||
@ -1937,6 +2079,9 @@ int main(int argc, char **argv)
|
||||
DLOG("\nlists summary:\n");
|
||||
HostlistsDebug();
|
||||
IpsetsDebug();
|
||||
|
||||
DLOG("\nsplits summary:\n");
|
||||
SplitDebug();
|
||||
DLOG("\n");
|
||||
|
||||
if (daemon) daemonize();
|
||||
|
@ -169,7 +169,6 @@ struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
|
||||
|
||||
memcpy(entry->dp.hostspell, "host", 4); // default hostspell
|
||||
entry->dp.desync_skip_nosni = true;
|
||||
entry->dp.desync_split_pos = 2;
|
||||
entry->dp.desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT;
|
||||
entry->dp.desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT;
|
||||
entry->dp.desync_repeats = 1;
|
||||
|
13
nfq/params.h
13
nfq/params.h
@ -38,6 +38,8 @@
|
||||
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
|
||||
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3
|
||||
|
||||
#define MAX_SPLITS 64
|
||||
|
||||
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
|
||||
|
||||
struct desync_profile
|
||||
@ -53,9 +55,14 @@ struct desync_profile
|
||||
char hostspell[4];
|
||||
enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2;
|
||||
bool desync_retrans,desync_skip_nosni,desync_any_proto;
|
||||
unsigned int desync_repeats,desync_split_pos,desync_seqovl,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp;
|
||||
enum httpreqpos desync_split_http_req;
|
||||
enum tlspos desync_split_tls;
|
||||
unsigned int desync_repeats,desync_seqovl,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp;
|
||||
|
||||
// multisplit
|
||||
struct split_pos splits[MAX_SPLITS];
|
||||
int split_count;
|
||||
// single split pos cache
|
||||
struct split_pos split_http,split_tls,split_unknown;
|
||||
|
||||
char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence
|
||||
unsigned int desync_start, desync_cutoff;
|
||||
uint8_t desync_ttl, desync_ttl6;
|
||||
|
236
nfq/protocol.c
236
nfq/protocol.c
@ -24,6 +24,133 @@ static bool FindNLD(const uint8_t *dom, size_t dlen, int level, const uint8_t **
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *l7proto_str(t_l7proto l7)
|
||||
{
|
||||
switch(l7)
|
||||
{
|
||||
case HTTP: return "http";
|
||||
case TLS: return "tls";
|
||||
case QUIC: return "quic";
|
||||
case WIREGUARD: return "wireguard";
|
||||
case DHT: return "dht";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
|
||||
{
|
||||
return (l7proto==UNKNOWN && (filter_l7 & L7_PROTO_UNKNOWN)) ||
|
||||
(l7proto==HTTP && (filter_l7 & L7_PROTO_HTTP)) ||
|
||||
(l7proto==TLS && (filter_l7 & L7_PROTO_TLS)) ||
|
||||
(l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) ||
|
||||
(l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) ||
|
||||
(l7proto==DHT && (filter_l7 & L7_PROTO_DHT));
|
||||
}
|
||||
|
||||
#define PM_ABS 0
|
||||
#define PM_HOST 1
|
||||
#define PM_HOST_END 2
|
||||
#define PM_HOST_SLD 3
|
||||
#define PM_HOST_MIDSLD 4
|
||||
#define PM_HOST_ENDSLD 5
|
||||
#define PM_HTTP_METHOD 6
|
||||
#define PM_SNI_EXT 7
|
||||
bool IsHostMarker(uint8_t posmarker)
|
||||
{
|
||||
switch(posmarker)
|
||||
{
|
||||
case PM_HOST:
|
||||
case PM_HOST_END:
|
||||
case PM_HOST_SLD:
|
||||
case PM_HOST_MIDSLD:
|
||||
case PM_HOST_ENDSLD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const char *posmarker_name(uint8_t posmarker)
|
||||
{
|
||||
switch(posmarker)
|
||||
{
|
||||
case PM_ABS: return "abs";
|
||||
case PM_HOST: return "host";
|
||||
case PM_HOST_END: return "endhost";
|
||||
case PM_HOST_SLD: return "sld";
|
||||
case PM_HOST_MIDSLD: return "midsld";
|
||||
case PM_HOST_ENDSLD: return "endsld";
|
||||
case PM_HTTP_METHOD: return "method";
|
||||
case PM_SNI_EXT: return "sniext";
|
||||
default: return "?";
|
||||
}
|
||||
}
|
||||
|
||||
static size_t CheckPos(size_t sz, ssize_t offset)
|
||||
{
|
||||
return (offset>=0 && offset<sz) ? offset : 0;
|
||||
}
|
||||
size_t AnyProtoPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
|
||||
{
|
||||
ssize_t offset;
|
||||
switch(posmarker)
|
||||
{
|
||||
case PM_ABS:
|
||||
offset = (pos<0) ? sz+pos : pos;
|
||||
return CheckPos(sz,offset);
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static size_t HostPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz, size_t offset_host, size_t len_host)
|
||||
{
|
||||
ssize_t offset;
|
||||
const uint8_t *p;
|
||||
size_t slen;
|
||||
|
||||
switch(posmarker)
|
||||
{
|
||||
case PM_HOST:
|
||||
offset = offset_host+pos;
|
||||
break;
|
||||
case PM_HOST_END:
|
||||
offset = offset_host+len_host+pos;
|
||||
break;
|
||||
case PM_HOST_SLD:
|
||||
case PM_HOST_MIDSLD:
|
||||
case PM_HOST_ENDSLD:
|
||||
if (((offset_host+len_host)<=sz) && FindNLD(data+offset_host,len_host,2,&p,&slen))
|
||||
offset = (posmarker==PM_HOST_SLD ? p-data : posmarker==PM_HOST_ENDSLD ? p-data+slen : slen==1 ? p+1-data : p+slen/2-data) + pos;
|
||||
else
|
||||
offset = 0;
|
||||
break;
|
||||
}
|
||||
return CheckPos(sz,offset);
|
||||
}
|
||||
size_t ResolvePos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *sp)
|
||||
{
|
||||
switch(l7proto)
|
||||
{
|
||||
case HTTP:
|
||||
return HttpPos(sp->marker, sp->pos, data, sz);
|
||||
case TLS:
|
||||
return TLSPos(sp->marker, sp->pos, data, sz);
|
||||
default:
|
||||
return AnyProtoPos(sp->marker, sp->pos, data, sz);
|
||||
}
|
||||
}
|
||||
void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *splits, int split_count, size_t *pos, int *pos_count)
|
||||
{
|
||||
int i,j;
|
||||
for(i=j=0;i<split_count;i++)
|
||||
{
|
||||
pos[j] = ResolvePos(data,sz,l7proto,splits+i);
|
||||
if (pos[j]) j++;
|
||||
}
|
||||
qsort_size_t(pos, j);
|
||||
j=unique_size_t(pos, j);
|
||||
*pos_count=j;
|
||||
}
|
||||
|
||||
|
||||
const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
|
||||
const char *HttpMethod(const uint8_t *data, size_t len)
|
||||
{
|
||||
@ -170,37 +297,47 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
|
||||
// compare 2nd level domains
|
||||
return strcasecmp(dhost, drhost)!=0;
|
||||
}
|
||||
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
|
||||
size_t HttpPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
|
||||
{
|
||||
const uint8_t *method, *host=NULL;
|
||||
const uint8_t *method, *host=NULL, *p;
|
||||
size_t offset_host,len_host;
|
||||
ssize_t offset;
|
||||
int i;
|
||||
|
||||
switch(tpos_type)
|
||||
switch(posmarker)
|
||||
{
|
||||
case httpreqpos_method:
|
||||
case PM_HTTP_METHOD:
|
||||
// recognize some tpws pre-applied hacks
|
||||
method=http;
|
||||
method=data;
|
||||
if (sz<10) break;
|
||||
if (*method=='\n' || *method=='\r') method++;
|
||||
if (*method=='\n' || *method=='\r') method++;
|
||||
for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++;
|
||||
if (i<3 || *method!=' ') break;
|
||||
return method-http-1;
|
||||
case httpreqpos_host:
|
||||
if (HttpFindHostConst(&host,http,sz) && (host-http+7)<sz)
|
||||
for (p=method,i=0;i<7;i++) if (*p>='A' && *p<='Z') p++;
|
||||
if (i<3 || *p!=' ') break;
|
||||
return CheckPos(sz,method-data+pos);
|
||||
case PM_HOST:
|
||||
case PM_HOST_END:
|
||||
case PM_HOST_SLD:
|
||||
case PM_HOST_MIDSLD:
|
||||
case PM_HOST_ENDSLD:
|
||||
if (HttpFindHostConst(&host,data,sz) && (host-data+7)<sz)
|
||||
{
|
||||
host+=5;
|
||||
if (*host==' ') host++;
|
||||
return host-http;
|
||||
if (*host==' ' || *host=='\t') host++;
|
||||
offset_host = host-data;
|
||||
if (posmarker!=PM_HOST)
|
||||
for (len_host=0; (offset_host+len_host)<sz && data[offset_host+len_host]!='\r' && data[offset_host+len_host]!='\n'; len_host++);
|
||||
else
|
||||
len_host = 0;
|
||||
return HostPos(posmarker,pos,data,sz,offset_host,len_host);
|
||||
}
|
||||
break;
|
||||
case httpreqpos_pos:
|
||||
break;
|
||||
default:
|
||||
return AnyProtoPos(posmarker,pos,data,sz);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return hpos_pos<sz ? hpos_pos : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
uint16_t TLSRecordDataLen(const uint8_t *data)
|
||||
@ -355,45 +492,40 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
|
||||
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
||||
}
|
||||
|
||||
// find N level domain in SNI
|
||||
static bool TLSHelloFindNLDInSNI(const uint8_t *ext, size_t elen, int level, const uint8_t **p, size_t *len)
|
||||
{
|
||||
size_t slen;
|
||||
return TLSAdvanceToHostInSNI(&ext,&elen,&slen) && FindNLD(ext,slen,level,p,len);
|
||||
}
|
||||
// find the middle of second level domain (SLD) in SNI ext : www.sobaka.ru => aka.ru
|
||||
// return false if SNI ext is bad or SLD is not found
|
||||
static bool TLSHelloFindMiddleOfSLDInSNI(const uint8_t *ext, size_t elen, const uint8_t **p)
|
||||
{
|
||||
size_t len;
|
||||
if (!TLSHelloFindNLDInSNI(ext,elen,2,p,&len))
|
||||
return false;
|
||||
// in case of one letter SLD (x.com) we split at '.' to prevent appearance of the whole SLD
|
||||
*p = (len==1) ? *p+1 : *p+len/2;
|
||||
return true;
|
||||
}
|
||||
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
|
||||
size_t TLSPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
|
||||
{
|
||||
size_t elen;
|
||||
const uint8_t *ext, *p;
|
||||
switch(tpos_type)
|
||||
size_t offset_host,len_host;
|
||||
ssize_t offset;
|
||||
|
||||
switch(posmarker)
|
||||
{
|
||||
case tlspos_sni:
|
||||
case tlspos_sniext:
|
||||
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
||||
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1;
|
||||
break;
|
||||
case tlspos_snisld:
|
||||
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
||||
if (TLSHelloFindMiddleOfSLDInSNI(ext,elen,&p))
|
||||
return p-tls;
|
||||
break;
|
||||
case tlspos_pos:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
case PM_HOST:
|
||||
case PM_HOST_END:
|
||||
case PM_HOST_SLD:
|
||||
case PM_HOST_MIDSLD:
|
||||
case PM_HOST_ENDSLD:
|
||||
case PM_SNI_EXT:
|
||||
if (TLSFindExt(data,sz,0,&ext,&elen,false))
|
||||
{
|
||||
if (posmarker==PM_SNI_EXT)
|
||||
{
|
||||
offset = ext-data+1+pos;
|
||||
return (offset>=0 && offset<sz) ? offset : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!TLSAdvanceToHostInSNI(&ext,&elen,&len_host))
|
||||
return 0;
|
||||
offset_host = ext-data;
|
||||
return HostPos(posmarker,pos,data,sz,offset_host,len_host);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
default:
|
||||
return AnyProtoPos(posmarker,pos,data,sz);
|
||||
}
|
||||
return tpos_pos<sz ? tpos_pos : 0;
|
||||
}
|
||||
|
||||
|
||||
@ -739,6 +871,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
||||
return found;
|
||||
}
|
||||
|
||||
/*
|
||||
bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello)
|
||||
{
|
||||
if (bIsCryptoHello) *bIsCryptoHello=false;
|
||||
@ -758,8 +891,9 @@ bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host
|
||||
if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len)) return false;
|
||||
if (bIsCryptoHello) *bIsCryptoHello=true;
|
||||
|
||||
return TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, len_host, true);
|
||||
return TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, len_host, NULL, true);
|
||||
}
|
||||
*/
|
||||
|
||||
bool IsQUICInitial(const uint8_t *data, size_t len)
|
||||
{
|
||||
|
@ -7,6 +7,39 @@
|
||||
#include "crypto/aes-gcm.h"
|
||||
#include "helpers.h"
|
||||
|
||||
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto;
|
||||
#define L7_PROTO_HTTP 0x00000001
|
||||
#define L7_PROTO_TLS 0x00000002
|
||||
#define L7_PROTO_QUIC 0x00000004
|
||||
#define L7_PROTO_WIREGUARD 0x00000008
|
||||
#define L7_PROTO_DHT 0x00000010
|
||||
#define L7_PROTO_UNKNOWN 0x80000000
|
||||
const char *l7proto_str(t_l7proto l7);
|
||||
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7);
|
||||
|
||||
// pos markers
|
||||
#define PM_ABS 0
|
||||
#define PM_HOST 1
|
||||
#define PM_HOST_END 2
|
||||
#define PM_HOST_SLD 3
|
||||
#define PM_HOST_MIDSLD 4
|
||||
#define PM_HOST_ENDSLD 5
|
||||
#define PM_HTTP_METHOD 6
|
||||
#define PM_SNI_EXT 7
|
||||
struct split_pos
|
||||
{
|
||||
int16_t pos;
|
||||
uint8_t marker;
|
||||
};
|
||||
#define SPLIT_POS_EMPTY(sp) ((sp)->marker==PM_ABS && (sp)->pos==0)
|
||||
bool IsHostMarker(uint8_t posmarker);
|
||||
const char *posmarker_name(uint8_t posmarker);
|
||||
size_t AnyProtoPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz);
|
||||
size_t HttpPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz);
|
||||
size_t TLSPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz);
|
||||
size_t ResolvePos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *sp);
|
||||
void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *splits, int split_count, size_t *pos, int *pos_count);
|
||||
|
||||
extern const char *http_methods[9];
|
||||
const char *HttpMethod(const uint8_t *data, size_t len);
|
||||
bool IsHttp(const uint8_t *data, size_t len);
|
||||
@ -21,8 +54,6 @@ const char *HttpFind2ndLevelDomain(const char *host);
|
||||
int HttpReplyCode(const uint8_t *data, size_t len);
|
||||
// must be pre-checked by IsHttpReply
|
||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
||||
enum httpreqpos { httpreqpos_none = 0, httpreqpos_method, httpreqpos_host, httpreqpos_pos };
|
||||
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz);
|
||||
|
||||
uint16_t TLSRecordDataLen(const uint8_t *data);
|
||||
size_t TLSRecordLen(const uint8_t *data);
|
||||
@ -35,8 +66,6 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
|
||||
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
|
||||
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
|
||||
enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_snisld, tlspos_pos };
|
||||
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);
|
||||
|
||||
bool IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
|
||||
bool IsDhtD1(const uint8_t *data, size_t len);
|
||||
@ -56,4 +85,4 @@ bool QUICExtractDCID(const uint8_t *data, size_t len, quic_cid_t *cid);
|
||||
|
||||
bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, size_t *clean_len);
|
||||
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len);
|
||||
bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello);
|
||||
//bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello);
|
||||
|
Loading…
Reference in New Issue
Block a user