16 Commits
v70.4 ... v70.5

Author SHA1 Message Date
bol-van
a2ffa3455d nfqws: minor beautify text 2025-03-24 11:20:51 +03:00
bol-van
60b97dbed0 nfqws: remove debug printfs 2025-03-24 11:14:38 +03:00
bol-van
e56e4f5f35 update changes 2025-03-24 10:32:02 +03:00
bol-van
5305ea83c8 fakes: GGC kyber with inter-packet CRYPTO frag 2025-03-24 09:44:50 +03:00
bol-van
14b3dd459b nfqws: define reasm buffer sizes 2025-03-24 09:34:37 +03:00
bol-van
66fda2c33d nfqws: support QUIC multi packet CRYPTO fragmentation 2025-03-23 23:29:16 +03:00
bol-van
77df43b9cb nfqws: minor optimize 2025-03-22 13:03:31 +03:00
bol-van
85f2b37c88 update docs 2025-03-21 21:00:47 +03:00
bol-van
e2d600fcc6 update docs 2025-03-21 20:58:53 +03:00
bol-van
37eda0ad98 nfqws: mod skipped DLOG_ERR -> DLOG 2025-03-21 19:40:25 +03:00
bol-van
770be21e1c nfqws: fix custom tls fake fallback logic 2025-03-21 19:09:37 +03:00
bol-van
1b880d42f9 nfqws,tpws: missing va_end 2025-03-21 17:33:57 +03:00
bol-van
6387315c0b nfqws: multiple fakes 2025-03-21 17:12:36 +03:00
bol-van
3d4b395bfe ignore windivert files in nfq 2025-03-21 14:23:19 +03:00
bol-van
55950ed7d0 remove bad files 2025-03-21 14:22:28 +03:00
bol-van
f2b0341484 blockcheck: add dupsid to tls-mod 2025-03-20 18:14:35 +03:00
18 changed files with 514 additions and 194 deletions

1
.gitignore vendored
View File

@@ -4,6 +4,7 @@ mdig/mdig
nfq/dvtws
nfq/nfqws
nfq/winws.exe
nfq/WinDivert*
tpws/tpws
binaries/my/
ipset/zapret-ip*.txt

View File

@@ -1168,7 +1168,7 @@ pktws_curl_test_update_vary()
[ "$sec" = 0 ] || proto=tls
test_has_fake $desync && {
zerofake="--dpi-desync-fake-$proto=0x00000000"
[ "$sec" = 0 ] || tlsmod="--dpi-desync-fake-tls-mod=rnd,rndsni,padencap"
[ "$sec" = 0 ] || tlsmod="--dpi-desync-fake-tls-mod=rnd,dupsid,rndsni,padencap"
}
if test_has_fakedsplit $desync ; then
splits="method+2 midsld"

View File

@@ -466,3 +466,8 @@ nfqws,tpws: optional systemd notify support. compile using 'make systemd'
nfqws,tpws: systemd instance templates for nfqws and tpws
nfqws,tpws: separate droproot from dropcaps
tpws: detect WSL 1 and warn about non-working options
v70.5
nfqws: multiple --dpi-desync-fake-xxx
nfqws: support of inter-packet fragmented QUIC CRYPTO

View File

@@ -1,4 +1,4 @@
# zapret v70.4
# zapret v70.5
# SCAMMER WARNING
@@ -265,6 +265,12 @@ Fakes are separate generated by nfqws packets carrying false information for DPI
`--dpi-desync-fooling` takes multiple comma separated values.
Multiple parameters `--dpi-desync-fake-???` are supported except for the `--dpi-desync-fake-syndata`.
Fakes are sent in the specified order. `--dpi-desync-repeats` resends each fake.
Resulting order would be : `fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake3 .....`
### FAKE mods
**nfqws** has built-in TLS fake. It can be customized with `--dpi-desync-fake-tls` option.
@@ -282,6 +288,10 @@ It's possible to use TLS Client Hello with any fingerprint and any SNI.
By default if custom fake is not defined `rnd,rndsni,dupsid` mods are applied. If defined - `none`.
This behaviour is compatible with previous versions with addition of `dupsid`.
If TLS mod is enabled and there're multiple TLS fakes, all valid TLS Client Hello fakes are modified.
If there's no TLS Client Hello program exits with error.
### TCP segmentation
* `multisplit`. split request at specified in `--dpi-desync-split-pos` positions

View File

@@ -1,4 +1,4 @@
# zapret v70.4
# zapret v70.5
# ВНИМАНИЕ, остерегайтесь мошенников
@@ -320,6 +320,10 @@ dvtws, собираемый из тех же исходников (см. [док
Режимы дурения могут сочетаться в любых комбинациях. `--dpi-desync-fooling` берет множество значений через запятую.
Возможно задание множества фейков через повторение парамеров `--dpi-desync-fake-???`, кроме `--dpi-desync-fake-syndata`.
Фейки будут отосланы в указанном порядке. `--dpi-desync-repeats` повторяет каждый отосланный фейк.
Итоговый порядок будет такой : `fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake3 .....`
### МОДИФИКАЦИЯ ФЕЙКОВ
В nfqws зашит базовый вариант фейка для TLS. Его можно переопределить опцией `--dpi-desync-fake-tls`.
@@ -339,6 +343,9 @@ dvtws, собираемый из тех же исходников (см. [док
По умолчанию если не задан собственный фейк для TLS используются модификации `rnd,rndsni,dupsid`. Если фейк задан, используется `none`.
Это соответствует поведению программы более старых версий с добавлением функции `dupsid`.
Если задан режим модификации и имеется множество TLS фейков, модифицируются все фейки, являющиеся TLS Client Hello.
Если нет ни одного TLS Client Hello фейка, программа завершается с ошибкой.
### TCP СЕГМЕНТАЦИЯ
* `multisplit`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях.

Binary file not shown.

Binary file not shown.

View File

@@ -66,6 +66,9 @@ const uint8_t fake_tls_clienthello_default[648] = {
#define PKTDATA_MAXDUMP 32
#define IP_MAXDUMP 80
#define TCP_MAX_REASM 16384
#define UDP_MAX_REASM 16384
bool desync_valid_zero_stage(enum dpi_desync_mode mode)
{
return mode==DESYNC_SYNACK || mode==DESYNC_SYNDATA;
@@ -606,45 +609,48 @@ static uint16_t IP4_IP_ID_FIX(const struct ip *ip)
// fake_mod buffer must at least sizeof(desync_profile->fake_tls)
// size does not change
// return : true - altered, false - not altered
static bool runtime_tls_mod(const struct desync_profile *dp, uint8_t *fake_mod, const uint8_t *payload, size_t payload_len)
static bool runtime_tls_mod(int fake_n,const struct fake_tls_mod_cache *modcache, uint8_t fake_tls_mod, const uint8_t *fake_data, size_t fake_data_size, const uint8_t *payload, size_t payload_len, uint8_t *fake_mod)
{
bool b=false;
if (dp->fake_tls_mod & FAKE_TLS_MOD_PADENCAP)
if (modcache) // it's filled only if it's TLS
{
size_t sz_rec = pntoh16(dp->fake_tls+3) + payload_len;
size_t sz_handshake = pntoh24(dp->fake_tls+6) + payload_len;
size_t sz_ext = pntoh16(dp->fake_tls+dp->fake_tls_extlen_offset) + payload_len;
size_t sz_pad = pntoh16(dp->fake_tls+dp->fake_tls_padlen_offset) + payload_len;
if ((sz_rec & ~0xFFFF) || (sz_handshake & ~0xFFFFFF) || (sz_ext & ~0xFFFF) || (sz_pad & ~0xFFFF))
DLOG("cannot apply padencap tls mod. length overflow.\n");
else
if (fake_tls_mod & FAKE_TLS_MOD_PADENCAP)
{
memcpy(fake_mod,dp->fake_tls,dp->fake_tls_size);
phton16(fake_mod+3,(uint16_t)sz_rec);
phton24(fake_mod+6,(uint32_t)sz_handshake);
phton16(fake_mod+dp->fake_tls_extlen_offset,(uint16_t)sz_ext);
phton16(fake_mod+dp->fake_tls_padlen_offset,(uint16_t)sz_pad);
size_t sz_rec = pntoh16(fake_data+3) + payload_len;
size_t sz_handshake = pntoh24(fake_data+6) + payload_len;
size_t sz_ext = pntoh16(fake_data+modcache->extlen_offset) + payload_len;
size_t sz_pad = pntoh16(fake_data+modcache->padlen_offset) + payload_len;
if ((sz_rec & ~0xFFFF) || (sz_handshake & ~0xFFFFFF) || (sz_ext & ~0xFFFF) || (sz_pad & ~0xFFFF))
DLOG("fake[%d] cannot apply padencap tls mod. length overflow.\n", fake_n);
else
{
memcpy(fake_mod,fake_data,fake_data_size);
phton16(fake_mod+3,(uint16_t)sz_rec);
phton24(fake_mod+6,(uint32_t)sz_handshake);
phton16(fake_mod+modcache->extlen_offset,(uint16_t)sz_ext);
phton16(fake_mod+modcache->padlen_offset,(uint16_t)sz_pad);
b=true;
}
}
if (fake_tls_mod & FAKE_TLS_MOD_RND)
{
if (!b) memcpy(fake_mod,fake_data,fake_data_size);
fill_random_bytes(fake_mod+11,32); // random
fill_random_bytes(fake_mod+44,fake_mod[43]); // session id
b=true;
}
}
if (dp->fake_tls_mod & FAKE_TLS_MOD_RND)
{
if (!b) memcpy(fake_mod,dp->fake_tls,dp->fake_tls_size);
fill_random_bytes(fake_mod+11,32); // random
fill_random_bytes(fake_mod+44,fake_mod[43]); // session id
b=true;
}
if (dp->fake_tls_mod & FAKE_TLS_MOD_DUP_SID)
{
if (dp->fake_tls[43]!=payload[43])
DLOG("cannot apply dupsid tls mod. fake and orig session id length mismatch.\n");
else if (payload_len<(44+payload[43]))
DLOG("cannot apply dupsid tls mod. data payload is not valid.\n");
else
if (fake_tls_mod & FAKE_TLS_MOD_DUP_SID)
{
if (!b) memcpy(fake_mod,dp->fake_tls,dp->fake_tls_size);
memcpy(fake_mod+44,payload+44,fake_mod[43]); // session id
b=true;
if (fake_data[43]!=payload[43])
DLOG("fake[%d] cannot apply dupsid tls mod. fake and orig session id length mismatch.\n",fake_n);
else if (payload_len<(44+payload[43]))
DLOG("fake[%d] cannot apply dupsid tls mod. data payload is not valid.\n",fake_n);
else
{
if (!b) memcpy(fake_mod,fake_data,fake_data_size);
memcpy(fake_mod+44,payload+44,fake_mod[43]); // session id
b=true;
}
}
}
return b;
@@ -880,8 +886,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (!(dis->tcp->th_flags & TH_SYN) && dis->len_payload)
{
const uint8_t *fake;
size_t fake_size;
struct blob_collection_head *fake;
char host[256];
bool bHaveHost=false;
uint8_t *p, *phost=NULL;
@@ -893,7 +899,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
int i;
uint16_t ip_id;
t_l7proto l7proto = UNKNOWN;
uint8_t fake_mod[sizeof(dp->fake_tls)];
if (replay)
{
@@ -952,7 +957,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
!(ctrack->req_seq_finalized && seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end)))
{
// do not reconstruct unexpected large payload (they are feeding garbage ?)
if (!reasm_orig_start(ctrack,IPPROTO_TCP,TLSRecordLen(dis->data_payload),16384,dis->data_payload,dis->len_payload))
if (!reasm_orig_start(ctrack,IPPROTO_TCP,TLSRecordLen(dis->data_payload),TCP_MAX_REASM,dis->data_payload,dis->len_payload))
{
reasm_orig_cancel(ctrack);
return verdict;
@@ -1183,16 +1188,13 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
switch(l7proto)
{
case HTTP:
fake = dp->fake_http;
fake_size = dp->fake_http_size;
fake = &dp->fake_http;
break;
case TLS:
fake = runtime_tls_mod(dp,fake_mod,rdata_payload,rlen_payload) ? fake_mod : dp->fake_tls;
fake_size = dp->fake_tls_size;
fake = &dp->fake_tls;
break;
default:
fake = dp->fake_unknown;
fake_size = dp->fake_unknown_size;
fake = &dp->fake_unknown;
break;
}
if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)
@@ -1273,13 +1275,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
else
seqovl_pos = 0;
// we do not need reasm buffer anymore
reasm_orig_cancel(ctrack);
rdata_payload=NULL;
uint32_t fooling_orig = FOOL_NONE;
bool bFake = false;
pkt1_len = sizeof(pkt1);
switch(dp->desync_mode)
{
case DESYNC_FAKE_KNOWN:
@@ -1291,28 +1288,69 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
}
case DESYNC_FAKE:
if (reasm_offset) break;
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_fake,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
fake, fake_size, pkt1, &pkt1_len))
{
return verdict;
struct blob_item *fake_item;
uint8_t *fake_data;
uint8_t fake_data_buf[FAKE_MAX_TCP];
int n=0;
ip_id = IP4_IP_ID_FIX(dis->ip);
LIST_FOREACH(fake_item, fake, next)
{
n++;
switch(l7proto)
{
case TLS:
if ((fake_item->size <= sizeof(fake_data_buf)) &&
runtime_tls_mod(n,(struct fake_tls_mod_cache *)fake_item->extra, dp->fake_tls_mod, fake_item->data, fake_item->size, rdata_payload, rlen_payload, fake_data_buf))
{
fake_data = fake_data_buf;
break;
}
default:
fake_data = fake_item->data;
}
pkt1_len = sizeof(pkt1);
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_fake,IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
fake_data, fake_item->size, pkt1, &pkt1_len))
{
reasm_orig_cancel(ctrack);
return verdict;
}
DLOG("sending fake[%d] : ", n);
hexdump_limited_dlog(fake_data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
{
reasm_orig_cancel(ctrack);
return verdict;
}
ip_id=IP4_IP_ID_NEXT(ip_id);
}
}
DLOG("sending fake : ");
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
bFake = true;
break;
case DESYNC_RST:
case DESYNC_RSTACK:
if (reasm_offset) break;
pkt1_len = sizeof(pkt1);
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),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
NULL, 0, pkt1, &pkt1_len))
{
reasm_orig_cancel(ctrack);
return verdict;
}
DLOG("sending fake RST/RSTACK\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
{
reasm_orig_cancel(ctrack);
return verdict;
}
bFake = true;
break;
case DESYNC_HOPBYHOP:
@@ -1323,8 +1361,12 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
(!split_pos && (dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER)) ||
(!multisplit_count && (dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER))))
{
reasm_orig_cancel(ctrack);
rdata_payload=NULL;
pkt1_len = sizeof(pkt1);
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),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
ttl_orig,0,0,IP6_FLOW(dis->ip6),
fooling_orig,0,0,
dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
{
@@ -1341,11 +1383,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
break;
}
if (bFake)
{
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return verdict;
}
// we do not need reasm buffer anymore
reasm_orig_cancel(ctrack);
rdata_payload=NULL;
enum dpi_desync_mode desync_mode = dp->desync_mode2==DESYNC_NONE ? dp->desync_mode : dp->desync_mode2;
switch(desync_mode)
@@ -1875,8 +1915,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
if (dis->len_payload)
{
const uint8_t *fake;
size_t fake_size;
struct blob_collection_head *fake;
char host[256];
bool bHaveHost=false;
uint16_t ip_id;
@@ -1917,29 +1956,82 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
return verdict; // cannot be first packet
}
}
uint8_t defrag[16384];
uint8_t defrag[UDP_MAX_REASM];
size_t hello_offset, hello_len, defrag_len = sizeof(defrag);
if (QUICDefragCrypto(pclean,clean_len,defrag,&defrag_len))
bool bFull;
if (QUICDefragCrypto(pclean,clean_len,defrag,&defrag_len,&bFull))
{
bool bIsHello = IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len);
bool bReqFull = bIsHello ? IsTLSHandshakeFull(defrag+hello_offset,hello_len) : false;
DLOG(bIsHello ? bReqFull ? "packet contains full TLS ClientHello\n" : "packet contains partial TLS ClientHello\n" : "packet does not contain TLS ClientHello\n");
if (ctrack)
if (bFull)
{
if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig))
DLOG("QUIC initial contains CRYPTO with full fragment coverage\n");
bool bIsHello = IsQUICCryptoHello(defrag, defrag_len, &hello_offset, &hello_len);
bool bReqFull = bIsHello ? IsTLSHandshakeFull(defrag+hello_offset,hello_len) : false;
DLOG(bIsHello ? bReqFull ? "packet contains full TLS ClientHello\n" : "packet contains partial TLS ClientHello\n" : "packet does not contain TLS ClientHello\n");
if (ctrack)
{
// preallocate max buffer to avoid reallocs that cause memory copy
if (!reasm_orig_start(ctrack,IPPROTO_UDP,16384,16384,clean,clean_len))
if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig))
{
// preallocate max buffer to avoid reallocs that cause memory copy
if (!reasm_orig_start(ctrack,IPPROTO_UDP,UDP_MAX_REASM,UDP_MAX_REASM,clean,clean_len))
{
reasm_orig_cancel(ctrack);
return verdict;
}
}
if (!ReasmIsEmpty(&ctrack->reasm_orig))
{
verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6);
if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload))
{
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
}
else
{
DLOG_ERR("rawpacket_queue failed !\n");
reasm_orig_cancel(ctrack);
return verdict;
}
if (bReqFull)
{
replay_queue(&ctrack->delayed);
reasm_orig_fin(ctrack);
}
return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt);
}
}
if (bIsHello)
{
bHaveHost = TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, sizeof(host), TLS_PARTIALS_ENABLE);
if (!bHaveHost && dp->desync_skip_nosni)
{
reasm_orig_cancel(ctrack);
DLOG("not applying tampering to QUIC ClientHello without hostname in the SNI\n");
return verdict;
}
}
if (!ReasmIsEmpty(&ctrack->reasm_orig))
else
{
if (!quic_reasm_cancel(ctrack,"QUIC initial without ClientHello")) return verdict;
}
}
else
{
DLOG("QUIC initial contains CRYPTO with partial fragment coverage\n");
if (ctrack)
{
if (ReasmIsEmpty(&ctrack->reasm_orig))
{
// preallocate max buffer to avoid reallocs that cause memory copy
if (!reasm_orig_start(ctrack,IPPROTO_UDP,UDP_MAX_REASM,UDP_MAX_REASM,clean,clean_len))
{
reasm_orig_cancel(ctrack);
return verdict;
}
}
verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6);
if (rawpacket_queue(&ctrack->delayed, &dst, desync_fwmark, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload))
{
@@ -1951,28 +2043,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
reasm_orig_cancel(ctrack);
return verdict;
}
if (bReqFull)
{
replay_queue(&ctrack->delayed);
reasm_orig_fin(ctrack);
}
return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt);
}
}
if (bIsHello)
{
bHaveHost = TLSHelloExtractHostFromHandshake(defrag + hello_offset, hello_len, host, sizeof(host), TLS_PARTIALS_ENABLE);
if (!bHaveHost && dp->desync_skip_nosni)
{
reasm_orig_cancel(ctrack);
DLOG("not applying tampering to QUIC ClientHello without hostname in the SNI\n");
return verdict;
}
}
else
{
if (!quic_reasm_cancel(ctrack,"QUIC initial without ClientHello")) return verdict;
if (!quic_reasm_cancel(ctrack,"QUIC initial fragmented CRYPTO")) return verdict;
}
}
else
@@ -1991,7 +2064,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
{
// received payload without host. it means we are out of the request retransmission phase. stop counter
ctrack_stop_retrans_counter(ctrack);
reasm_orig_cancel(ctrack);
if (IsWireguardHandshakeInitiation(dis->data_payload,dis->len_payload))
@@ -2110,20 +2183,16 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
switch(l7proto)
{
case QUIC:
fake = dp->fake_quic;
fake_size = dp->fake_quic_size;
fake = &dp->fake_quic;
break;
case WIREGUARD:
fake = dp->fake_wg;
fake_size = dp->fake_wg_size;
fake = &dp->fake_wg;
break;
case DHT:
fake = dp->fake_dht;
fake_size = dp->fake_dht_size;
fake = &dp->fake_dht;
break;
default:
fake = dp->fake_unknown_udp;
fake_size = dp->fake_unknown_udp_size;
fake = &dp->fake_unknown_udp;
break;
}
@@ -2140,7 +2209,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
}
bool bFake = false;
pkt1_len = sizeof(pkt1);
switch(dp->desync_mode)
{
case DESYNC_FAKE_KNOWN:
@@ -2150,12 +2218,30 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
break;
}
case DESYNC_FAKE:
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len))
return verdict;
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;
{
struct blob_item *fake_item;
int n=0;
ip_id = IP4_IP_ID_FIX(dis->ip);
LIST_FOREACH(fake_item, fake, next)
{
n++;
pkt1_len = sizeof(pkt1);
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
ttl_fake, IP4_TOS(dis->ip),ip_id,IP6_FLOW(dis->ip6),
dp->desync_fooling_mode, NULL, 0, 0,
fake_item->data, fake_item->size, pkt1, &pkt1_len))
{
return verdict;
}
DLOG("sending fake[%d] : ", n);
hexdump_limited_dlog(fake_item->data,fake_item->size,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return verdict;
ip_id=IP4_IP_ID_NEXT(ip_id);
}
}
bFake = true;
break;
case DESYNC_HOPBYHOP:
@@ -2164,9 +2250,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
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_udp(dp->desync_mode2)))
{
pkt1_len = sizeof(pkt1);
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
ttl_orig,IP4_TOS(dis->ip),IP4_IP_ID_FIX(dis->ip),IP6_FLOW(dis->ip6),
fooling_orig,NULL,0,0,
ttl_orig,0,0,IP6_FLOW(dis->ip6),fooling_orig,NULL,0,0,
dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
{
return verdict;

View File

@@ -1007,74 +1007,67 @@ static void SplitDebug(void)
}
static const char * tld[]={"com","org","net","edu","gov","biz"};
static void onetime_tls_mod(struct desync_profile *dp)
static bool onetime_tls_mod_blob(int profile_n, int fake_n, uint8_t fake_tls_mod, uint8_t *fake_tls, size_t *fake_tls_size, size_t fake_tls_buf_size, struct fake_tls_mod_cache *modcache)
{
const uint8_t *ext;
size_t extlen, slen;
if (dp->n && !(dp->fake_tls_mod & (FAKE_TLS_MOD_SET|FAKE_TLS_MOD_CUSTOM_FAKE)))
dp->fake_tls_mod |= FAKE_TLS_MOD_RND|FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_DUP_SID; // old behavior compat + dup_sid
if (!(dp->fake_tls_mod & ~FAKE_TLS_MOD_SAVE_MASK))
return; // nothing to do
if (!IsTLSClientHello(dp->fake_tls,dp->fake_tls_size,false) || (dp->fake_tls_size<(44+dp->fake_tls[43]))) // has session id ?
modcache->extlen_offset = modcache->padlen_offset = 0;
if (fake_tls_mod & FAKE_TLS_MOD_PADENCAP)
{
DLOG_ERR("profile %d tls mod set but tls fake structure invalid\n", dp->n);
exit_clean(1);
}
if (dp->fake_tls_mod & FAKE_TLS_MOD_PADENCAP)
{
if (!TLSFindExtLen(dp->fake_tls,dp->fake_tls_size,&dp->fake_tls_extlen_offset))
if (!TLSFindExtLen(fake_tls,*fake_tls_size,&modcache->extlen_offset))
{
DLOG_ERR("profile %d padencap set but tls fake structure invalid\n", dp->n);
exit_clean(1);
DLOG_ERR("profile %d fake[%d] padencap set but tls fake structure invalid\n", profile_n, fake_n);
return false;
}
DLOG("profile %d fake tls extensions length offset : %zu\n", dp->n, dp->fake_tls_extlen_offset);
if (TLSFindExt(dp->fake_tls,dp->fake_tls_size,21,&ext,&extlen,false))
DLOG("profile %d fake[%d] tls extensions length offset : %zu\n", profile_n, fake_n, modcache->extlen_offset);
if (TLSFindExt(fake_tls,*fake_tls_size,21,&ext,&extlen,false))
{
if ((ext-dp->fake_tls+extlen)!=dp->fake_tls_size)
if ((ext-fake_tls+extlen)!=*fake_tls_size)
{
DLOG_ERR("profile %d fake tls padding ext is present but it's not at the end. padding ext offset %zu, padding ext size %zu, fake size %zu\n", dp->n, ext-dp->fake_tls, extlen, dp->fake_tls_size);
exit_clean(1);
DLOG_ERR("profile %d fake[%d] tls padding ext is present but it's not at the end. padding ext offset %zu, padding ext size %zu, fake size %zu\n", profile_n, fake_n, ext-fake_tls, extlen, *fake_tls_size);
return false;
}
dp->fake_tls_padlen_offset = ext-dp->fake_tls-2;
DLOG("profile %d fake tls padding ext is present, padding length offset %zu\n", dp->n, dp->fake_tls_padlen_offset);
modcache->padlen_offset = ext-fake_tls-2;
DLOG("profile %d fake[%d] tls padding ext is present, padding length offset %zu\n", profile_n, fake_n, modcache->padlen_offset);
}
else
{
if ((dp->fake_tls_size+4)>sizeof(dp->fake_tls))
if ((*fake_tls_size+4)>fake_tls_buf_size)
{
DLOG_ERR("profile %d fake tls padding is absent and there's not space to add it\n", dp->n);
exit_clean(1);
DLOG_ERR("profile %d fake[%d] tls padding is absent and there's no space to add it\n", profile_n, fake_n);
return false;
}
phton16(dp->fake_tls+dp->fake_tls_size,21);
dp->fake_tls_size+=2;
dp->fake_tls_padlen_offset=dp->fake_tls_size;
phton16(dp->fake_tls+dp->fake_tls_size,0);
dp->fake_tls_size+=2;
phton16(dp->fake_tls+dp->fake_tls_extlen_offset,pntoh16(dp->fake_tls+dp->fake_tls_extlen_offset)+4);
phton16(dp->fake_tls+3,pntoh16(dp->fake_tls+3)+4); // increase tls record len
phton24(dp->fake_tls+6,pntoh24(dp->fake_tls+6)+4); // increase tls handshake len
DLOG("profile %d fake tls padding is absent. added. padding ledgth offset %zu\n", dp->n, dp->fake_tls_padlen_offset);
phton16(fake_tls+*fake_tls_size,21);
*fake_tls_size+=2;
modcache->padlen_offset=*fake_tls_size;
phton16(fake_tls+*fake_tls_size,0);
*fake_tls_size+=2;
phton16(fake_tls+modcache->extlen_offset,pntoh16(fake_tls+modcache->extlen_offset)+4);
phton16(fake_tls+3,pntoh16(fake_tls+3)+4); // increase tls record len
phton24(fake_tls+6,pntoh24(fake_tls+6)+4); // increase tls handshake len
DLOG("profile %d fake[%d] tls padding is absent. added. padding length offset %zu\n", profile_n, fake_n, modcache->padlen_offset);
}
}
if (dp->fake_tls_mod & FAKE_TLS_MOD_RND_SNI)
if (fake_tls_mod & FAKE_TLS_MOD_RND_SNI)
{
if (!TLSFindExt(dp->fake_tls,dp->fake_tls_size,0,&ext,&extlen,false))
if (!TLSFindExt(fake_tls,*fake_tls_size,0,&ext,&extlen,false))
{
DLOG_ERR("profile %d rndsni set but tls fake does not have SNI\n", dp->n);
exit_clean(1);
DLOG_ERR("profile %d fake[%d] rndsni set but tls fake does not have SNI\n", profile_n, fake_n);
return false;
}
if (!TLSAdvanceToHostInSNI(&ext,&extlen,&slen))
{
DLOG_ERR("profile %d rndsni set but tls fake has invalid SNI structure\n", dp->n);
exit_clean(1);
DLOG_ERR("profile %d fake[%d] rndsni set but tls fake has invalid SNI structure\n", profile_n, fake_n);
return false;
}
if (!slen)
{
DLOG_ERR("profile %d rndsni set but tls fake has zero sized SNI\n", dp->n);
exit_clean(1);
DLOG_ERR("profile %d fake[%d] rndsni set but tls fake has zero sized SNI\n", profile_n, fake_n);
return false;
}
uint8_t *sni = dp->fake_tls + (ext - dp->fake_tls);
uint8_t *sni = fake_tls + (ext - fake_tls);
char *s1=NULL, *s2=NULL;
if (params.debug)
@@ -1100,11 +1093,66 @@ static void onetime_tls_mod(struct desync_profile *dp)
if (s1 && (s2 = malloc(slen+1)))
{
memcpy(s2,sni,slen); s2[slen]=0;
DLOG("profile %d generated random SNI : %s -> %s\n",dp->n,s1,s2);
DLOG("profile %d fake[%d] generated random SNI : %s -> %s\n",profile_n,fake_n,s1,s2);
}
free(s1); free(s2);
}
}
return true;
}
static bool onetime_tls_mod(struct desync_profile *dp)
{
if (dp->n && !(dp->fake_tls_mod & (FAKE_TLS_MOD_SET|FAKE_TLS_MOD_CUSTOM_FAKE)))
dp->fake_tls_mod |= FAKE_TLS_MOD_RND|FAKE_TLS_MOD_RND_SNI|FAKE_TLS_MOD_DUP_SID; // old behavior compat + dup_sid
if (!(dp->fake_tls_mod & ~FAKE_TLS_MOD_SAVE_MASK))
return true; // nothing to do
struct blob_item *fake_tls;
int n=0;
bool bMod=false;
LIST_FOREACH(fake_tls, &dp->fake_tls, next)
{
++n;
if (!IsTLSClientHello(fake_tls->data,fake_tls->size,false) || (fake_tls->size < (44+fake_tls->data[43]))) // has session id ?
{
DLOG("profile %d fake[%d] tls mod set but tls fake structure invalid. mod skipped.\n", dp->n, n);
continue;
}
bMod = true;
if (!fake_tls->extra)
{
fake_tls->extra = malloc(sizeof(struct fake_tls_mod_cache));
if (!fake_tls->extra) return false;
}
if (!onetime_tls_mod_blob(dp->n,n,dp->fake_tls_mod,fake_tls->data,&fake_tls->size,fake_tls->size_buf,(struct fake_tls_mod_cache*)fake_tls->extra))
return false;
}
if (!bMod)
DLOG_ERR("profile %d tls fake list does not have any valid TLS ClientHello\n", dp->n);
return bMod;
}
static void load_blob_to_collection(const char *filename, struct blob_collection_head *blobs, size_t max_size, size_t size_reserve)
{
struct blob_item *blob = blob_collection_add(blobs);
uint8_t *p;
if (!blob || (!(blob->data = malloc(max_size+size_reserve))))
{
DLOG_ERR("out of memory\n");
exit_clean(1);
}
blob->size = max_size;
load_file_or_exit(filename,blob->data,&blob->size);
p = realloc(blob->data,blob->size+size_reserve);
if (!p)
{
DLOG_ERR("out of memory\n");
exit_clean(1);
}
blob->data = p;
blob->size_buf = blob->size+size_reserve;
}
@@ -1992,12 +2040,10 @@ int main(int argc, char **argv)
dp->desync_any_proto = !optarg || atoi(optarg);
break;
case 38: /* dpi-desync-fake-http */
dp->fake_http_size = sizeof(dp->fake_http);
load_file_or_exit(optarg,dp->fake_http,&dp->fake_http_size);
load_blob_to_collection(optarg, &dp->fake_http, FAKE_MAX_TCP,0);
break;
case 39: /* dpi-desync-fake-tls */
dp->fake_tls_size = sizeof(dp->fake_tls);
load_file_or_exit(optarg,dp->fake_tls,&dp->fake_tls_size);
load_blob_to_collection(optarg, &dp->fake_tls, FAKE_MAX_TCP,4);
dp->fake_tls_mod |= FAKE_TLS_MOD_CUSTOM_FAKE;
break;
case 40: /* dpi-desync-fake-tls-mod */
@@ -2008,28 +2054,23 @@ int main(int argc, char **argv)
}
break;
case 41: /* dpi-desync-fake-unknown */
dp->fake_unknown_size = sizeof(dp->fake_unknown);
load_file_or_exit(optarg,dp->fake_unknown,&dp->fake_unknown_size);
load_blob_to_collection(optarg, &dp->fake_unknown, FAKE_MAX_TCP, 0);
break;
case 42: /* dpi-desync-fake-syndata */
dp->fake_syndata_size = sizeof(dp->fake_syndata);
load_file_or_exit(optarg,dp->fake_syndata,&dp->fake_syndata_size);
break;
case 43: /* dpi-desync-fake-quic */
dp->fake_quic_size = sizeof(dp->fake_quic);
load_file_or_exit(optarg,dp->fake_quic,&dp->fake_quic_size);
load_blob_to_collection(optarg, &dp->fake_quic, FAKE_MAX_UDP, 0);
break;
case 44: /* dpi-desync-fake-wireguard */
dp->fake_wg_size = sizeof(dp->fake_wg);
load_file_or_exit(optarg,dp->fake_wg,&dp->fake_wg_size);
load_blob_to_collection(optarg, &dp->fake_wg, FAKE_MAX_UDP, 0);
break;
case 45: /* dpi-desync-fake-dht */
dp->fake_dht_size = sizeof(dp->fake_dht);
load_file_or_exit(optarg,dp->fake_dht,&dp->fake_dht_size);
load_blob_to_collection(optarg, &dp->fake_dht, FAKE_MAX_UDP, 0);
break;
case 46: /* dpi-desync-fake-unknown-udp */
dp->fake_unknown_udp_size = sizeof(dp->fake_unknown_udp);
load_file_or_exit(optarg,dp->fake_unknown_udp,&dp->fake_unknown_udp_size);
load_blob_to_collection(optarg, &dp->fake_unknown_udp, FAKE_MAX_UDP, 0);
break;
case 47: /* dpi-desync-udplen-increment */
if (sscanf(optarg,"%d",&dp->udplen_increment)<1 || dp->udplen_increment>0x7FFF || dp->udplen_increment<-0x8000)
@@ -2475,7 +2516,16 @@ int main(int argc, char **argv)
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);
split_compat(dp);
onetime_tls_mod(dp);
if (!dp_fake_defaults(dp))
{
DLOG_ERR("could not fill fake defaults\n");
exit_clean(1);
}
if (!onetime_tls_mod(dp))
{
DLOG_ERR("could not mod tls\n");
exit_clean(1);
}
#ifndef __CYGWIN__
if (params.droproot && dp->hostlist_auto && chown(dp->hostlist_auto->filename, params.uid, -1))
DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", dp->hostlist_auto->filename);

View File

@@ -65,6 +65,7 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, va_list
{
va_copy(args2,args);
DLOG_CON(format,syslog_priority,args2);
va_end(args2);
}
if (params.debug)
{
@@ -184,18 +185,8 @@ void dp_init(struct desync_profile *dp)
dp->desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT;
dp->desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT;
dp->desync_repeats = 1;
dp->fake_tls_size = sizeof(fake_tls_clienthello_default);
memcpy(dp->fake_tls,fake_tls_clienthello_default,dp->fake_tls_size);
dp->fake_tls_mod = 0;
dp->fake_http_size = strlen(fake_http_request_default);
memcpy(dp->fake_http,fake_http_request_default,dp->fake_http_size);
dp->fake_quic_size = 620; // must be 601+ for TSPU hack
dp->fake_quic[0] = 0x40; // russian TSPU QUIC short header fake
dp->fake_wg_size = 64;
dp->fake_dht_size = 64;
dp->fake_unknown_size = 256;
dp->fake_syndata_size = 16;
dp->fake_unknown_udp_size = 64;
dp->wscale=-1; // default - dont change scale factor (client)
dp->desync_ttl6 = 0xFF; // unused
dp->desync_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
@@ -207,11 +198,55 @@ void dp_init(struct desync_profile *dp)
dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT;
dp->filter_ipv4 = dp->filter_ipv6 = true;
}
bool dp_fake_defaults(struct desync_profile *dp)
{
struct blob_item *item;
if (blob_collection_empty(&dp->fake_http))
if (!blob_collection_add_blob(&dp->fake_http,fake_http_request_default,strlen(fake_http_request_default),0))
return false;
if (blob_collection_empty(&dp->fake_tls))
{
if (!blob_collection_add_blob(&dp->fake_tls,fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),4))
return false;
}
if (blob_collection_empty(&dp->fake_unknown))
{
if (!(item=blob_collection_add_blob(&dp->fake_unknown,NULL,256,0)))
return false;
memset(item->data,0,item->size);
}
if (blob_collection_empty(&dp->fake_quic))
{
if (!(item=blob_collection_add_blob(&dp->fake_quic,NULL,620,0)))
return false;
memset(item->data,0,item->size);
item->data[0] = 0x40;
}
if (blob_collection_empty(&dp->fake_wg))
{
if (!(item=blob_collection_add_blob(&dp->fake_wg,NULL,64,0)))
return false;
memset(item->data,0,item->size);
}
if (blob_collection_empty(&dp->fake_dht))
{
if (!(item=blob_collection_add_blob(&dp->fake_dht,NULL,64,0)))
return false;
memset(item->data,0,item->size);
}
if (blob_collection_empty(&dp->fake_unknown_udp))
{
if (!(item=blob_collection_add_blob(&dp->fake_unknown_udp,NULL,64,0)))
return false;
memset(item->data,0,item->size);
}
return true;
}
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
{
struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list));
if (!entry) return NULL;
dp_init(&entry->dp);
// add to the tail
@@ -234,6 +269,13 @@ static void dp_clear_dynamic(struct desync_profile *dp)
ipset_collection_destroy(&dp->ips_collection_exclude);
port_filters_destroy(&dp->pf_tcp);
port_filters_destroy(&dp->pf_udp);
blob_collection_destroy(&dp->fake_http);
blob_collection_destroy(&dp->fake_tls);
blob_collection_destroy(&dp->fake_unknown);
blob_collection_destroy(&dp->fake_unknown_udp);
blob_collection_destroy(&dp->fake_quic);
blob_collection_destroy(&dp->fake_wg);
blob_collection_destroy(&dp->fake_dht);
HostFailPoolDestroy(&dp->hostlist_auto_fail_counters);
}
void dp_clear(struct desync_profile *dp)

View File

@@ -46,8 +46,16 @@
#define FAKE_TLS_MOD_RND_SNI 0x40
#define FAKE_TLS_MOD_PADENCAP 0x80
#define FAKE_MAX_TCP 1460
#define FAKE_MAX_UDP 1472
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
struct fake_tls_mod_cache
{
size_t extlen_offset, padlen_offset;
};
struct desync_profile
{
int n; // number of the profile
@@ -74,12 +82,12 @@ struct desync_profile
autottl desync_autottl, desync_autottl6;
uint32_t desync_fooling_mode;
uint32_t desync_badseq_increment, desync_badseq_ack_increment;
uint8_t fake_http[1460],fake_unknown[1460],fake_syndata[1460],seqovl_pattern[1460],fsplit_pattern[1460];
uint8_t fake_unknown_udp[1472],udplen_pattern[1472],fake_quic[1472],fake_wg[1472],fake_dht[1472];
size_t fake_http_size,fake_quic_size,fake_wg_size,fake_dht_size,fake_unknown_size,fake_syndata_size,fake_unknown_udp_size;
uint8_t fake_tls[1460],fake_tls_mod;
size_t fake_tls_size, fake_tls_extlen_offset, fake_tls_padlen_offset;
struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht;
uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],fsplit_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP];
size_t fake_syndata_size;
uint8_t fake_tls_mod;
int udplen_increment;
@@ -113,6 +121,7 @@ void dp_entry_destroy(struct desync_profile_list *entry);
void dp_list_destroy(struct desync_profile_list_head *head);
bool dp_list_have_autohostlist(struct desync_profile_list_head *head);
void dp_init(struct desync_profile *dp);
bool dp_fake_defaults(struct desync_profile *dp);
void dp_clear(struct desync_profile *dp);
struct params_s

View File

@@ -517,3 +517,64 @@ bool port_filters_deny_if_empty(struct port_filters_head *head)
if (LIST_FIRST(head)) return true;
return pf_parse("0",&pf) && port_filter_add(head,&pf);
}
struct blob_item *blob_collection_add(struct blob_collection_head *head)
{
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
if (entry)
{
// insert to the end
struct blob_item *itemc,*iteml=LIST_FIRST(head);
if (iteml)
{
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
LIST_INSERT_AFTER(iteml, entry, next);
}
else
LIST_INSERT_HEAD(head, entry, next);
}
return entry;
}
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve)
{
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
if (!entry) return NULL;
if (!(entry->data = malloc(size+size_reserve)))
{
free(entry);
return NULL;
}
if (data) memcpy(entry->data,data,size);
entry->size = size;
entry->size_buf = size+size_reserve;
// insert to the end
struct blob_item *itemc,*iteml=LIST_FIRST(head);
if (iteml)
{
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
LIST_INSERT_AFTER(iteml, entry, next);
}
else
LIST_INSERT_HEAD(head, entry, next);
return entry;
}
void blob_collection_destroy(struct blob_collection_head *head)
{
struct blob_item *entry;
while ((entry = LIST_FIRST(head)))
{
LIST_REMOVE(entry, next);
free(entry->extra);
free(entry->data);
free(entry);
}
}
bool blob_collection_empty(const struct blob_collection_head *head)
{
return !LIST_FIRST(head);
}

View File

@@ -146,3 +146,17 @@ bool port_filter_add(struct port_filters_head *head, const port_filter *pf);
void port_filters_destroy(struct port_filters_head *head);
bool port_filters_in_range(const struct port_filters_head *head, uint16_t port);
bool port_filters_deny_if_empty(struct port_filters_head *head);
struct blob_item {
uint8_t *data; // main data blob
size_t size; // main data blob size
size_t size_buf;// main data blob allocated size
void *extra; // any data without size
LIST_ENTRY(blob_item) next;
};
LIST_HEAD(blob_collection_head, blob_item);
struct blob_item *blob_collection_add(struct blob_collection_head *head);
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve);
void blob_collection_destroy(struct blob_collection_head *head);
bool blob_collection_empty(const struct blob_collection_head *head);

View File

@@ -844,7 +844,16 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
return !memcmp(data + pn_offset + pkn_len + cryptlen, atag, 16);
}
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len)
struct range64
{
uint64_t offset,len;
};
#define MAX_DEFRAG_PIECES 128
static int cmp_range64(const void * a, const void * b)
{
return (((struct range64*)a)->offset < ((struct range64*)b)->offset) ? -1 : (((struct range64*)a)->offset > ((struct range64*)b)->offset) ? 1 : 0;
}
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len, bool *bFull)
{
// Crypto frame can be split into multiple chunks
// chromium randomly splits it and pads with zero/one bytes to force support the standard
@@ -853,13 +862,15 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
if (*defrag_len<10) return false;
uint8_t *defrag_data = defrag+10;
size_t defrag_data_len = *defrag_len-10;
uint8_t ft;
uint64_t offset,sz,szmax=0,zeropos=0,pos=0;
bool found=false;
struct range64 ranges[MAX_DEFRAG_PIECES];
int i,range=0;
while(pos<clean_len)
{
// frame type
ft = clean[pos];
pos++;
if (ft>1) // 00 - padding, 01 - ping
@@ -867,6 +878,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
if (ft!=6) return false; // dont want to know all possible frame type formats
if (pos>=clean_len) return false;
if (range>=MAX_DEFRAG_PIECES) return false;
if ((pos+tvb_get_size(clean[pos])>=clean_len)) return false;
pos += tvb_get_varint(clean+pos, &offset);
@@ -875,7 +887,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
pos += tvb_get_varint(clean+pos, &sz);
if ((pos+sz)>clean_len) return false;
if ((offset+sz)>defrag_data_len) return false;
if ((offset+sz)>defrag_data_len) return false; // defrag buf overflow
if (zeropos < offset)
// make sure no uninitialized gaps exist in case of not full fragment coverage
memset(defrag_data+zeropos,0,offset-zeropos);
@@ -886,6 +898,10 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
found=true;
pos+=sz;
ranges[range].offset = offset;
ranges[range].len = sz;
range++;
}
}
if (found)
@@ -897,6 +913,23 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
phton64(defrag+2,szmax);
defrag[2] |= 0xC0; // 64 bit value
*defrag_len = (size_t)(szmax+10);
qsort(ranges, range, sizeof(*ranges), cmp_range64);
//for(i=0 ; i<range ; i++)
// printf("RANGE %zu len %zu\n",ranges[i].offset,ranges[i].len);
for(i=0,offset=0,*bFull=true ; i<range ; i++)
{
if (ranges[i].offset!=offset)
{
*bFull = false;
break;
}
offset += ranges[i].len;
}
//printf("bFull=%u\n",*bFull);
}
return found;
}

View File

@@ -87,5 +87,6 @@ uint8_t QUICDraftVersion(uint32_t version);
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);
// returns true if crypto frames were found . bFull = true if crypto frame fragments have full coverage
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len, bool *bFull);
//bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host, size_t len_host, bool *bDecryptOK, bool *bIsCryptoHello);

View File

@@ -50,6 +50,7 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, int lev
{
va_copy(args2,args);
DLOG_CON(format,syslog_priority,args2);
va_end(args2);
}
if (params.debug>=level)
{