mirror of
https://github.com/bol-van/zapret.git
synced 2024-11-26 20:20:53 +03:00
Compare commits
No commits in common. "9b3bbb72851a0e240c336bba6d55369785958163" and "656c549113d060eb756c1f2b7b7144430d7dcc41" have entirely different histories.
9b3bbb7285
...
656c549113
@ -213,7 +213,7 @@
|
|||||||
> Если используются методы нулевой фазы десинхронизации (`--mss`,
|
> Если используются методы нулевой фазы десинхронизации (`--mss`,
|
||||||
> `--wssize`, `--dpi-desync=syndata`) и режим фильтрации `hostlist`, то все
|
> `--wssize`, `--dpi-desync=syndata`) и режим фильтрации `hostlist`, то все
|
||||||
> параметры, относящиеся к этим методам, следует помещать в отдельные
|
> параметры, относящиеся к этим методам, следует помещать в отдельные
|
||||||
> профили мультистратегии, которые получат управление до определения имени
|
> профили мульистратегии, которые получат управление до определения имени
|
||||||
> хоста. Необходимо понимать алгоритм работы мультистратегий. Самым надежным
|
> хоста. Необходимо понимать алгоритм работы мультистратегий. Самым надежным
|
||||||
> вариантом будет дублирование этих параметров на 2 профиля. Какой-нибудь
|
> вариантом будет дублирование этих параметров на 2 профиля. Какой-нибудь
|
||||||
> сработает в зависимости от параметра `MODE_FILTER`.
|
> сработает в зависимости от параметра `MODE_FILTER`.
|
||||||
|
@ -12,6 +12,29 @@ static void ut_oom_recover(void *elem)
|
|||||||
oom = true;
|
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 const char *connstate_s[]={"SYN","ESTABLISHED","FIN"};
|
||||||
|
|
||||||
static void connswap(const t_conn *c, t_conn *c2)
|
static void connswap(const t_conn *c, t_conn *c2)
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
// this conntrack is not bullet-proof
|
// this conntrack is not bullet-proof
|
||||||
// its designed to satisfy dpi desync needs only
|
// its designed to satisfy dpi desync needs only
|
||||||
|
|
||||||
|
#include "packet_queue.h"
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -17,8 +19,6 @@
|
|||||||
#include <netinet/tcp.h>
|
#include <netinet/tcp.h>
|
||||||
#include <netinet/udp.h>
|
#include <netinet/udp.h>
|
||||||
|
|
||||||
#include "packet_queue.h"
|
|
||||||
#include "protocol.h"
|
|
||||||
|
|
||||||
//#define HASH_BLOOM 20
|
//#define HASH_BLOOM 20
|
||||||
#define HASH_NONFATAL_OOM 1
|
#define HASH_NONFATAL_OOM 1
|
||||||
@ -53,6 +53,16 @@ typedef struct {
|
|||||||
// FIN - FIN or RST received
|
// FIN - FIN or RST received
|
||||||
typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate;
|
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
|
typedef struct
|
||||||
{
|
{
|
||||||
bool bCheckDone, bCheckResult, bCheckExcluded; // hostlist check result cache
|
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)
|
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_MULTISPLIT || mode==DESYNC_MULTIDISORDER || 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_IPFRAG2 || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER;
|
||||||
}
|
}
|
||||||
bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode)
|
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_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2;
|
return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2;
|
||||||
}
|
}
|
||||||
bool desync_valid_second_stage_udp(enum dpi_desync_mode mode)
|
bool desync_valid_second_stage_udp(enum dpi_desync_mode mode)
|
||||||
{
|
{
|
||||||
@ -131,10 +131,6 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
|
|||||||
return DESYNC_SPLIT;
|
return DESYNC_SPLIT;
|
||||||
else if (!strcmp(s,"split2"))
|
else if (!strcmp(s,"split2"))
|
||||||
return DESYNC_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"))
|
else if (!strcmp(s,"ipfrag2"))
|
||||||
return DESYNC_IPFRAG2;
|
return DESYNC_IPFRAG2;
|
||||||
else if (!strcmp(s,"hopbyhop"))
|
else if (!strcmp(s,"hopbyhop"))
|
||||||
@ -586,7 +582,22 @@ 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)
|
static size_t pos_normalize(size_t split_pos, size_t reasm_offset, size_t len_payload)
|
||||||
{
|
{
|
||||||
return (split_pos>reasm_offset && (split_pos-reasm_offset)<len_payload) ? split_pos-reasm_offset : 0;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void autottl_discover(t_ctrack *ctrack, bool bIpv6)
|
static void autottl_discover(t_ctrack *ctrack, bool bIpv6)
|
||||||
@ -845,9 +856,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
const uint8_t *rdata_payload = dis->data_payload;
|
const uint8_t *rdata_payload = dis->data_payload;
|
||||||
size_t rlen_payload = dis->len_payload;
|
size_t rlen_payload = dis->len_payload;
|
||||||
size_t split_pos;
|
size_t split_pos;
|
||||||
size_t multisplit_pos[MAX_SPLITS];
|
|
||||||
int multisplit_count;
|
|
||||||
int i;
|
|
||||||
t_l7proto l7proto = UNKNOWN;
|
t_l7proto l7proto = UNKNOWN;
|
||||||
|
|
||||||
if (replay)
|
if (replay)
|
||||||
@ -1057,12 +1065,35 @@ 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 (l7proto==UNKNOWN)
|
||||||
{
|
{
|
||||||
if (!dp->desync_any_proto)
|
if (!dp->desync_any_proto)
|
||||||
{
|
{
|
||||||
DLOG("not applying tampering to unknown protocol\n");
|
DLOG("not applying tampering to unknown protocol\n");
|
||||||
reasm_orig_cancel(ctrack);
|
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
DLOG("applying tampering to unknown protocol\n");
|
DLOG("applying tampering to unknown protocol\n");
|
||||||
@ -1104,63 +1135,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dp->desync_mode==DESYNC_NONE)
|
if (dp->desync_mode==DESYNC_NONE) return verdict;
|
||||||
{
|
|
||||||
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)
|
if (params.debug)
|
||||||
{
|
{
|
||||||
@ -1172,42 +1147,24 @@ 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;
|
if (!split_pos || split_pos>rlen_payload) split_pos=1;
|
||||||
split_pos=pos_normalize(split_pos,reasm_offset,dis->len_payload);
|
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;
|
uint32_t fooling_orig = FOOL_NONE;
|
||||||
bool bFake = false;
|
bool b;
|
||||||
pkt1_len = sizeof(pkt1);
|
pkt1_len = sizeof(pkt1);
|
||||||
switch(dp->desync_mode)
|
b = false;
|
||||||
|
switch(desync_mode)
|
||||||
{
|
{
|
||||||
case DESYNC_FAKE_KNOWN:
|
case DESYNC_FAKE_KNOWN:
|
||||||
if (reasm_offset) break;
|
if (reasm_offset)
|
||||||
|
{
|
||||||
|
desync_mode = dp->desync_mode2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
if (l7proto==UNKNOWN)
|
if (l7proto==UNKNOWN)
|
||||||
{
|
{
|
||||||
DLOG("not applying fake because of unknown protocol\n");
|
DLOG("not applying fake because of unknown protocol\n");
|
||||||
|
desync_mode = dp->desync_mode2;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DESYNC_FAKE:
|
case DESYNC_FAKE:
|
||||||
@ -1219,14 +1176,14 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
{
|
{
|
||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
DLOG("sending fake : ");
|
DLOG("sending fake request : ");
|
||||||
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
|
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
|
||||||
bFake = true;
|
b = true;
|
||||||
break;
|
break;
|
||||||
case DESYNC_RST:
|
case DESYNC_RST:
|
||||||
case DESYNC_RSTACK:
|
case DESYNC_RSTACK:
|
||||||
if (reasm_offset) break;
|
if (reasm_offset) break;
|
||||||
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,
|
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,
|
||||||
ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
||||||
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
||||||
NULL, 0, pkt1, &pkt1_len))
|
NULL, 0, pkt1, &pkt1_len))
|
||||||
@ -1234,15 +1191,15 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
return verdict;
|
return verdict;
|
||||||
}
|
}
|
||||||
DLOG("sending fake RST/RSTACK\n");
|
DLOG("sending fake RST/RSTACK\n");
|
||||||
bFake = true;
|
b = true;
|
||||||
break;
|
break;
|
||||||
case DESYNC_HOPBYHOP:
|
case DESYNC_HOPBYHOP:
|
||||||
case DESYNC_DESTOPT:
|
case DESYNC_DESTOPT:
|
||||||
case DESYNC_IPFRAG1:
|
case DESYNC_IPFRAG1:
|
||||||
fooling_orig = (dp->desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
|
fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
|
||||||
if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(dp->desync_mode2) ||
|
desync_mode = 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)) ||
|
if (dis->ip6 && (desync_mode==DESYNC_NONE || !desync_valid_second_stage_tcp(desync_mode) ||
|
||||||
(!multisplit_count && (dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER))))
|
(!split_pos && (desync_mode==DESYNC_SPLIT || desync_mode==DESYNC_SPLIT2 || desync_mode==DESYNC_DISORDER || desync_mode==DESYNC_DISORDER2))))
|
||||||
{
|
{
|
||||||
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,
|
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),
|
ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
||||||
@ -1262,65 +1219,24 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (bFake)
|
if (b)
|
||||||
{
|
{
|
||||||
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
|
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
|
||||||
return verdict;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum dpi_desync_mode desync_mode = dp->desync_mode2==DESYNC_NONE ? dp->desync_mode : dp->desync_mode2;
|
pkt1_len = sizeof(pkt1);
|
||||||
switch(desync_mode)
|
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_DISORDER:
|
||||||
case DESYNC_DISORDER2:
|
case DESYNC_DISORDER2:
|
||||||
if (split_pos)
|
if (split_pos)
|
||||||
@ -1354,7 +1270,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
seg_len = dis->len_payload-split_pos;
|
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,
|
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),
|
ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
||||||
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
||||||
@ -1442,7 +1357,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
seg_len = split_pos;
|
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,
|
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),
|
ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
|
||||||
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
|
||||||
@ -1523,14 +1437,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
break;
|
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;
|
return verdict;
|
||||||
@ -1927,7 +1833,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
|
|||||||
case DESYNC_FAKE:
|
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))
|
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;
|
return verdict;
|
||||||
DLOG("sending fake : ");
|
DLOG("sending fake request : ");
|
||||||
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
|
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))
|
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
|
||||||
return verdict;
|
return verdict;
|
||||||
@ -2090,7 +1996,7 @@ static void packet_debug(bool replay, const struct dissect *dis)
|
|||||||
char s[80];
|
char s[80];
|
||||||
str_tcphdr(s,sizeof(s),dis->tcp);
|
str_tcphdr(s,sizeof(s),dis->tcp);
|
||||||
DLOG(" %s\n",s);
|
DLOG(" %s\n",s);
|
||||||
if (dis->len_payload) { DLOG("TCP: len=%zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); }
|
if (dis->len_payload) { DLOG("TCP: "); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); }
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (dis->udp)
|
else if (dis->udp)
|
||||||
@ -2098,7 +2004,7 @@ static void packet_debug(bool replay, const struct dissect *dis)
|
|||||||
char s[30];
|
char s[30];
|
||||||
str_udphdr(s,sizeof(s),dis->udp);
|
str_udphdr(s,sizeof(s),dis->udp);
|
||||||
DLOG(" %s\n",s);
|
DLOG(" %s\n",s);
|
||||||
if (dis->len_payload) { DLOG("UDP: len=%zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); }
|
if (dis->len_payload) { DLOG("UDP: "); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); }
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DLOG("\n");
|
DLOG("\n");
|
||||||
|
@ -32,8 +32,6 @@ enum dpi_desync_mode {
|
|||||||
DESYNC_DISORDER2,
|
DESYNC_DISORDER2,
|
||||||
DESYNC_SPLIT,
|
DESYNC_SPLIT,
|
||||||
DESYNC_SPLIT2,
|
DESYNC_SPLIT2,
|
||||||
DESYNC_MULTISPLIT,
|
|
||||||
DESYNC_MULTIDISORDER,
|
|
||||||
DESYNC_IPFRAG2,
|
DESYNC_IPFRAG2,
|
||||||
DESYNC_HOPBYHOP,
|
DESYNC_HOPBYHOP,
|
||||||
DESYNC_DESTOPT,
|
DESYNC_DESTOPT,
|
||||||
|
@ -11,27 +11,6 @@
|
|||||||
|
|
||||||
#include "params.h"
|
#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)
|
void rtrim(char *s)
|
||||||
{
|
{
|
||||||
if (s)
|
if (s)
|
||||||
|
@ -17,9 +17,6 @@ typedef union
|
|||||||
char _align[32]; // force 16-byte alignment for ip6_and int128 ops
|
char _align[32]; // force 16-byte alignment for ip6_and int128 ops
|
||||||
} sockaddr_in46;
|
} 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 rtrim(char *s);
|
||||||
void replace_char(char *s, char from, char to);
|
void replace_char(char *s, char from, char to);
|
||||||
char *strncasestr(const char *s,const char *find, size_t slen);
|
char *strncasestr(const char *s,const char *find, size_t slen);
|
||||||
|
237
nfq/nfqws.c
237
nfq/nfqws.c
@ -673,7 +673,10 @@ static bool parse_l7_list(char *opt, uint32_t *l7)
|
|||||||
*l7 |= L7_PROTO_UNKNOWN;
|
*l7 |= L7_PROTO_UNKNOWN;
|
||||||
else return false;
|
else return false;
|
||||||
|
|
||||||
if (e) *e++=c;
|
if (e)
|
||||||
|
{
|
||||||
|
*e++=c;
|
||||||
|
}
|
||||||
p = e;
|
p = e;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -720,173 +723,15 @@ static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6)
|
|||||||
*ipv6 = true;
|
*ipv6 = true;
|
||||||
else return false;
|
else return false;
|
||||||
|
|
||||||
if (e) *e++=c;
|
if (e)
|
||||||
|
{
|
||||||
|
*e++=c;
|
||||||
|
}
|
||||||
p = e;
|
p = e;
|
||||||
}
|
}
|
||||||
return true;
|
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__
|
#ifdef __CYGWIN__
|
||||||
static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *buf, size_t len)
|
static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *buf, size_t len)
|
||||||
{
|
{
|
||||||
@ -912,7 +757,10 @@ static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *bu
|
|||||||
if (n) strncat(buf," or ",len-strlen(buf)-1);
|
if (n) strncat(buf," or ",len-strlen(buf)-1);
|
||||||
strncat(buf, s1, len-strlen(buf)-1);
|
strncat(buf, s1, len-strlen(buf)-1);
|
||||||
|
|
||||||
if (e) *e++=c;
|
if (e)
|
||||||
|
{
|
||||||
|
*e++=c;
|
||||||
|
}
|
||||||
p = e;
|
p = e;
|
||||||
}
|
}
|
||||||
strncat(buf, ")", len-strlen(buf)-1);
|
strncat(buf, ")", len-strlen(buf)-1);
|
||||||
@ -1064,9 +912,7 @@ static void exithelp(void)
|
|||||||
" --hostspell\t\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n"
|
" --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"
|
" --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"
|
" --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 :\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"
|
||||||
"\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__
|
#ifdef __linux__
|
||||||
" --dpi-desync-fwmark=<int|0xHEX>\t\t; override fwmark for desync packet. default = 0x%08X (%u)\n"
|
" --dpi-desync-fwmark=<int|0xHEX>\t\t; override fwmark for desync packet. default = 0x%08X (%u)\n"
|
||||||
#elif defined(SO_USER_COOKIE)
|
#elif defined(SO_USER_COOKIE)
|
||||||
@ -1079,9 +925,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-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-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-skip-nosni=0|1\t\t\t; 1(default)=do not act on ClientHello without SNI (ESNI ?)\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"
|
" --dpi-desync-split-pos=<1..%u>\t\t; data payload split position\n"
|
||||||
"\t\t\t\t\t\t; full list is only used by multisplit and multidisorder\n"
|
" --dpi-desync-split-http-req=method|host\t; split at specified logical part of plain http request\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-tls=sni|sniext|snisld\t; split at specified logical part of TLS ClientHello\n"
|
||||||
" --dpi-desync-split-seqovl=<int>\t\t; use sequence overlap before first sent original split segment\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-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"
|
" --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
|
||||||
@ -1107,6 +953,7 @@ static void exithelp(void)
|
|||||||
DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT,
|
DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT,
|
||||||
#endif
|
#endif
|
||||||
AUTOTTL_DEFAULT_DELTA,AUTOTTL_DEFAULT_MIN,AUTOTTL_DEFAULT_MAX,
|
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_UDP_DEFAULT,
|
||||||
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT,
|
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT,
|
||||||
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT,
|
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT,
|
||||||
@ -1120,6 +967,29 @@ static void exithelp_clean(void)
|
|||||||
exithelp();
|
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__
|
#ifndef __OpenBSD__
|
||||||
// no static to not allow optimizer to inline this func (save stack)
|
// no static to not allow optimizer to inline this func (save stack)
|
||||||
void config_from_file(const char *filename)
|
void config_from_file(const char *filename)
|
||||||
@ -1577,27 +1447,21 @@ int main(int argc, char **argv)
|
|||||||
dp->desync_skip_nosni = !optarg || atoi(optarg);
|
dp->desync_skip_nosni = !optarg || atoi(optarg);
|
||||||
break;
|
break;
|
||||||
case 23: /* dpi-desync-split-pos */
|
case 23: /* dpi-desync-split-pos */
|
||||||
|
if (sscanf(optarg,"%u",&dp->desync_split_pos)<1 || dp->desync_split_pos<1)
|
||||||
{
|
{
|
||||||
int ct;
|
DLOG_ERR("dpi-desync-split-pos is not valid\n");
|
||||||
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);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
dp->split_count += ct;
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
case 24: /* dpi-desync-split-http-req */
|
case 24: /* dpi-desync-split-http-req */
|
||||||
// obsolete arg
|
if (!parse_httpreqpos(optarg, &dp->desync_split_http_req))
|
||||||
if (!parse_httpreqpos(optarg, &dp->split_http))
|
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for dpi-desync-split-http-req\n");
|
DLOG_ERR("Invalid argument for dpi-desync-split-http-req\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 25: /* dpi-desync-split-tls */
|
case 25: /* dpi-desync-split-tls */
|
||||||
// obsolete arg
|
if (!parse_tlspos(optarg, &dp->desync_split_tls))
|
||||||
if (!parse_tlspos(optarg, &dp->split_tls))
|
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for dpi-desync-split-tls\n");
|
DLOG_ERR("Invalid argument for dpi-desync-split-tls\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
@ -2048,13 +1912,6 @@ int main(int argc, char **argv)
|
|||||||
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
||||||
{
|
{
|
||||||
dp = &dpl->dp;
|
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
|
// not specified - use desync_ttl value instead
|
||||||
if (dp->desync_ttl6 == 0xFF) dp->desync_ttl6=dp->desync_ttl;
|
if (dp->desync_ttl6 == 0xFF) dp->desync_ttl6=dp->desync_ttl;
|
||||||
if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl;
|
if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl;
|
||||||
@ -2062,7 +1919,8 @@ 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);
|
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))
|
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);
|
DLOG("[profile %d] autottl ipv6 %u:%u-%u\n",dp->n,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max);
|
||||||
split_compat(dp);
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!LoadAllHostLists())
|
if (!LoadAllHostLists())
|
||||||
@ -2079,9 +1937,6 @@ int main(int argc, char **argv)
|
|||||||
DLOG("\nlists summary:\n");
|
DLOG("\nlists summary:\n");
|
||||||
HostlistsDebug();
|
HostlistsDebug();
|
||||||
IpsetsDebug();
|
IpsetsDebug();
|
||||||
|
|
||||||
DLOG("\nsplits summary:\n");
|
|
||||||
SplitDebug();
|
|
||||||
DLOG("\n");
|
DLOG("\n");
|
||||||
|
|
||||||
if (daemon) daemonize();
|
if (daemon) daemonize();
|
||||||
|
@ -169,6 +169,7 @@ struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
|
|||||||
|
|
||||||
memcpy(entry->dp.hostspell, "host", 4); // default hostspell
|
memcpy(entry->dp.hostspell, "host", 4); // default hostspell
|
||||||
entry->dp.desync_skip_nosni = true;
|
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_udp = IPFRAG_UDP_DEFAULT;
|
||||||
entry->dp.desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT;
|
entry->dp.desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT;
|
||||||
entry->dp.desync_repeats = 1;
|
entry->dp.desync_repeats = 1;
|
||||||
|
13
nfq/params.h
13
nfq/params.h
@ -38,8 +38,6 @@
|
|||||||
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
|
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
|
||||||
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3
|
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3
|
||||||
|
|
||||||
#define MAX_SPLITS 64
|
|
||||||
|
|
||||||
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
|
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
|
||||||
|
|
||||||
struct desync_profile
|
struct desync_profile
|
||||||
@ -55,14 +53,9 @@ struct desync_profile
|
|||||||
char hostspell[4];
|
char hostspell[4];
|
||||||
enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2;
|
enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2;
|
||||||
bool desync_retrans,desync_skip_nosni,desync_any_proto;
|
bool desync_retrans,desync_skip_nosni,desync_any_proto;
|
||||||
unsigned int desync_repeats,desync_seqovl,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp;
|
unsigned int desync_repeats,desync_split_pos,desync_seqovl,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp;
|
||||||
|
enum httpreqpos desync_split_http_req;
|
||||||
// multisplit
|
enum tlspos desync_split_tls;
|
||||||
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
|
char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence
|
||||||
unsigned int desync_start, desync_cutoff;
|
unsigned int desync_start, desync_cutoff;
|
||||||
uint8_t desync_ttl, desync_ttl6;
|
uint8_t desync_ttl, desync_ttl6;
|
||||||
|
234
nfq/protocol.c
234
nfq/protocol.c
@ -24,133 +24,6 @@ static bool FindNLD(const uint8_t *dom, size_t dlen, int level, const uint8_t **
|
|||||||
return true;
|
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 *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
|
||||||
const char *HttpMethod(const uint8_t *data, size_t len)
|
const char *HttpMethod(const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
@ -297,49 +170,39 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
|
|||||||
// compare 2nd level domains
|
// compare 2nd level domains
|
||||||
return strcasecmp(dhost, drhost)!=0;
|
return strcasecmp(dhost, drhost)!=0;
|
||||||
}
|
}
|
||||||
size_t HttpPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
|
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
|
||||||
{
|
{
|
||||||
const uint8_t *method, *host=NULL, *p;
|
const uint8_t *method, *host=NULL;
|
||||||
size_t offset_host,len_host;
|
|
||||||
ssize_t offset;
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
switch(posmarker)
|
switch(tpos_type)
|
||||||
{
|
{
|
||||||
case PM_HTTP_METHOD:
|
case httpreqpos_method:
|
||||||
// recognize some tpws pre-applied hacks
|
// recognize some tpws pre-applied hacks
|
||||||
method=data;
|
method=http;
|
||||||
if (sz<10) break;
|
if (sz<10) break;
|
||||||
if (*method=='\n' || *method=='\r') method++;
|
if (*method=='\n' || *method=='\r') method++;
|
||||||
if (*method=='\n' || *method=='\r') method++;
|
if (*method=='\n' || *method=='\r') method++;
|
||||||
for (p=method,i=0;i<7;i++) if (*p>='A' && *p<='Z') p++;
|
for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++;
|
||||||
if (i<3 || *p!=' ') break;
|
if (i<3 || *method!=' ') break;
|
||||||
return CheckPos(sz,method-data+pos);
|
return method-http-1;
|
||||||
case PM_HOST:
|
case httpreqpos_host:
|
||||||
case PM_HOST_END:
|
if (HttpFindHostConst(&host,http,sz) && (host-http+7)<sz)
|
||||||
case PM_HOST_SLD:
|
|
||||||
case PM_HOST_MIDSLD:
|
|
||||||
case PM_HOST_ENDSLD:
|
|
||||||
if (HttpFindHostConst(&host,data,sz) && (host-data+7)<sz)
|
|
||||||
{
|
{
|
||||||
host+=5;
|
host+=5;
|
||||||
if (*host==' ' || *host=='\t') host++;
|
if (*host==' ') host++;
|
||||||
offset_host = host-data;
|
return host-http;
|
||||||
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;
|
break;
|
||||||
|
case httpreqpos_pos:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return AnyProtoPos(posmarker,pos,data,sz);
|
|
||||||
}
|
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
return hpos_pos<sz ? hpos_pos : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint16_t TLSRecordDataLen(const uint8_t *data)
|
uint16_t TLSRecordDataLen(const uint8_t *data)
|
||||||
{
|
{
|
||||||
return pntoh16(data + 3);
|
return pntoh16(data + 3);
|
||||||
@ -492,40 +355,45 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
|
|||||||
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
return TLSExtractHostFromExt(ext, elen, host, len_host);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t TLSPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
|
// 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 elen;
|
size_t elen;
|
||||||
const uint8_t *ext, *p;
|
const uint8_t *ext, *p;
|
||||||
size_t offset_host,len_host;
|
switch(tpos_type)
|
||||||
ssize_t offset;
|
|
||||||
|
|
||||||
switch(posmarker)
|
|
||||||
{
|
{
|
||||||
case PM_HOST:
|
case tlspos_sni:
|
||||||
case PM_HOST_END:
|
case tlspos_sniext:
|
||||||
case PM_HOST_SLD:
|
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
||||||
case PM_HOST_MIDSLD:
|
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1;
|
||||||
case PM_HOST_ENDSLD:
|
break;
|
||||||
case PM_SNI_EXT:
|
case tlspos_snisld:
|
||||||
if (TLSFindExt(data,sz,0,&ext,&elen,false))
|
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
||||||
{
|
if (TLSHelloFindMiddleOfSLDInSNI(ext,elen,&p))
|
||||||
if (posmarker==PM_SNI_EXT)
|
return p-tls;
|
||||||
{
|
break;
|
||||||
offset = ext-data+1+pos;
|
case tlspos_pos:
|
||||||
return (offset>=0 && offset<sz) ? offset : 0;
|
break;
|
||||||
}
|
|
||||||
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:
|
default:
|
||||||
return AnyProtoPos(posmarker,pos,data,sz);
|
return 0;
|
||||||
}
|
}
|
||||||
|
return tpos_pos<sz ? tpos_pos : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -871,7 +739,6 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
|
|||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (bIsCryptoHello) *bIsCryptoHello=false;
|
if (bIsCryptoHello) *bIsCryptoHello=false;
|
||||||
@ -891,9 +758,8 @@ bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host
|
|||||||
if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len)) return false;
|
if (!IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len)) return false;
|
||||||
if (bIsCryptoHello) *bIsCryptoHello=true;
|
if (bIsCryptoHello) *bIsCryptoHello=true;
|
||||||
|
|
||||||
return TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, len_host, NULL, true);
|
return TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, len_host, true);
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
bool IsQUICInitial(const uint8_t *data, size_t len)
|
bool IsQUICInitial(const uint8_t *data, size_t len)
|
||||||
{
|
{
|
||||||
|
@ -7,39 +7,6 @@
|
|||||||
#include "crypto/aes-gcm.h"
|
#include "crypto/aes-gcm.h"
|
||||||
#include "helpers.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];
|
extern const char *http_methods[9];
|
||||||
const char *HttpMethod(const uint8_t *data, size_t len);
|
const char *HttpMethod(const uint8_t *data, size_t len);
|
||||||
bool IsHttp(const uint8_t *data, size_t len);
|
bool IsHttp(const uint8_t *data, size_t len);
|
||||||
@ -54,6 +21,8 @@ const char *HttpFind2ndLevelDomain(const char *host);
|
|||||||
int HttpReplyCode(const uint8_t *data, size_t len);
|
int HttpReplyCode(const uint8_t *data, size_t len);
|
||||||
// must be pre-checked by IsHttpReply
|
// must be pre-checked by IsHttpReply
|
||||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
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);
|
uint16_t TLSRecordDataLen(const uint8_t *data);
|
||||||
size_t TLSRecordLen(const uint8_t *data);
|
size_t TLSRecordLen(const uint8_t *data);
|
||||||
@ -66,6 +35,8 @@ 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 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 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);
|
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 IsWireguardHandshakeInitiation(const uint8_t *data, size_t len);
|
||||||
bool IsDhtD1(const uint8_t *data, size_t len);
|
bool IsDhtD1(const uint8_t *data, size_t len);
|
||||||
@ -85,4 +56,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 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 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