mirror of
https://github.com/bol-van/zapret.git
synced 2025-05-24 22:32:58 +03:00
nfqws: quic fix retrans counter, optimize reasm
This commit is contained in:
@@ -387,9 +387,9 @@ bool ReasmResize(t_reassemble *reasm, size_t new_size)
|
||||
if (reasm->size_present > new_size) reasm->size_present = new_size;
|
||||
return true;
|
||||
}
|
||||
bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len)
|
||||
bool ReasmFeed(t_reassemble *reasm, size_t seq, const void *payload, size_t len)
|
||||
{
|
||||
if (seq!=-1 && reasm->seq!=seq) return false; // fail session if out of sequence
|
||||
if (reasm->seq!=seq) return false; // fail session if out of sequence
|
||||
|
||||
size_t szcopy;
|
||||
szcopy = reasm->size - reasm->size_present;
|
||||
@@ -400,3 +400,7 @@ bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t le
|
||||
|
||||
return true;
|
||||
}
|
||||
bool ReasmHasSpace(t_reassemble *reasm, size_t len)
|
||||
{
|
||||
return (reasm->size_present+len)<=reasm->size;
|
||||
}
|
||||
|
@@ -39,7 +39,7 @@ typedef struct
|
||||
// this structure helps to reassemble continuous packets streams. it does not support out-of-orders
|
||||
typedef struct {
|
||||
uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size.
|
||||
uint32_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session.
|
||||
size_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session.
|
||||
size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet'
|
||||
size_t size_present; // how many bytes already stored in 'packet'
|
||||
} t_reassemble;
|
||||
@@ -109,6 +109,8 @@ bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start);
|
||||
bool ReasmResize(t_reassemble *reasm, size_t new_size);
|
||||
void ReasmClear(t_reassemble *reasm);
|
||||
// false means reassemble session has failed and we should ReasmClear() it
|
||||
bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len);
|
||||
bool ReasmFeed(t_reassemble *reasm, size_t seq, const void *payload, size_t len);
|
||||
// check if it has enough space to buffer 'len' bytes
|
||||
bool ReasmHasSpace(t_reassemble *reasm, size_t len);
|
||||
inline static bool ReasmIsEmpty(t_reassemble *reasm) {return !reasm->size;}
|
||||
inline static bool ReasmIsFull(t_reassemble *reasm) {return !ReasmIsEmpty(reasm) && (reasm->size==reasm->size_present);}
|
||||
|
103
nfq/desync.c
103
nfq/desync.c
@@ -277,7 +277,7 @@ static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, size_t sz, size_t
|
||||
if (ReasmInit(reasm,sz,ctrack->seq_last))
|
||||
{
|
||||
ReasmFeed(reasm,ctrack->seq_last,data_payload,len_payload);
|
||||
DLOG(reasm->size_present==reasm->size ? "starting reassemble. now we have %zu\n" : "starting reassemble. now we have %zu/%zu\n",reasm->size_present,reasm->size);
|
||||
DLOG("starting reassemble. now we have %zu/%zu\n",reasm->size_present,reasm->size);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -295,9 +295,9 @@ static bool reasm_feed(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, con
|
||||
{
|
||||
if (ctrack && !ReasmIsEmpty(reasm))
|
||||
{
|
||||
if (ReasmFeed(reasm,proto==IPPROTO_TCP ? ctrack->seq_last : -1,data_payload,len_payload))
|
||||
if (ReasmFeed(reasm,proto==IPPROTO_TCP ? (size_t)ctrack->seq_last : reasm->size_present, data_payload, len_payload))
|
||||
{
|
||||
DLOG(reasm->size_present==reasm->size ? "reassemble : feeding data payload size=%zu. now we have %zu\n" : "reassemble : feeding data payload size=%zu. now we have %zu/%zu\n", len_payload,reasm->size_present,reasm->size)
|
||||
DLOG("reassemble : feeding data payload size=%zu. now we have %zu/%zu\n", len_payload,reasm->size_present,reasm->size)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -313,27 +313,26 @@ static bool reasm_orig_feed(t_ctrack *ctrack, uint8_t proto, const uint8_t *data
|
||||
{
|
||||
return reasm_feed(ctrack, &ctrack->reasm_orig, proto, data_payload, len_payload);
|
||||
}
|
||||
static void reasm_orig_fin(t_ctrack *ctrack)
|
||||
{
|
||||
if (ctrack && ReasmIsFull(&ctrack->reasm_orig))
|
||||
{
|
||||
DLOG("reassemble session finished\n");
|
||||
ReasmClear(&ctrack->reasm_orig);
|
||||
send_delayed(ctrack);
|
||||
}
|
||||
}
|
||||
static void reasm_orig_cancel(t_ctrack *ctrack)
|
||||
static void reasm_orig_stop(t_ctrack *ctrack, const char *dlog_msg)
|
||||
{
|
||||
if (ctrack)
|
||||
{
|
||||
if (!ReasmIsEmpty(&ctrack->reasm_orig))
|
||||
{
|
||||
DLOG("reassemble session cancelled\n");
|
||||
DLOG("%s",dlog_msg);
|
||||
ReasmClear(&ctrack->reasm_orig);
|
||||
}
|
||||
send_delayed(ctrack);
|
||||
}
|
||||
}
|
||||
static void reasm_orig_cancel(t_ctrack *ctrack)
|
||||
{
|
||||
reasm_orig_stop(ctrack, "reassemble session cancelled\n");
|
||||
}
|
||||
static void reasm_orig_fin(t_ctrack *ctrack)
|
||||
{
|
||||
reasm_orig_stop(ctrack, "reassemble session finished\n");
|
||||
}
|
||||
|
||||
|
||||
static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, struct ip *ip, struct ip6_hdr *ip6, uint8_t proto, struct udphdr *udp, struct tcphdr *tcp, size_t *len_pkt)
|
||||
@@ -655,6 +654,10 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
|
||||
{
|
||||
DLOG("packet contains HTTP request\n")
|
||||
if (ctrack && !ctrack->l7proto) ctrack->l7proto = HTTP;
|
||||
|
||||
// we do not reassemble http
|
||||
reasm_orig_cancel(ctrack);
|
||||
|
||||
forced_wssize_cutoff(ctrack);
|
||||
fake = params.fake_http;
|
||||
fake_size = params.fake_http_size;
|
||||
@@ -664,7 +667,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
|
||||
if (!bHaveHost)
|
||||
{
|
||||
DLOG("not applying tampering to HTTP without Host:\n")
|
||||
reasm_orig_fin(ctrack);
|
||||
return verdict;
|
||||
}
|
||||
}
|
||||
@@ -698,7 +700,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
|
||||
// do not reconstruct unexpected large payload (they are feeding garbage ?)
|
||||
if (!reasm_orig_start(ctrack,TLSRecordLen(data_payload),16384,data_payload,len_payload))
|
||||
{
|
||||
fprintf(stderr, "reasm start failed ! out of memory.\n");
|
||||
reasm_orig_cancel(ctrack);
|
||||
return verdict;
|
||||
}
|
||||
@@ -746,7 +747,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
|
||||
if (params.desync_skip_nosni && !bHaveHost)
|
||||
{
|
||||
DLOG("not applying tampering to TLS ClientHello without hostname in the SNI\n")
|
||||
reasm_orig_fin(ctrack);
|
||||
reasm_orig_cancel(ctrack);
|
||||
return verdict;
|
||||
}
|
||||
|
||||
@@ -755,7 +756,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
|
||||
bKnownProtocol = true;
|
||||
}
|
||||
|
||||
reasm_orig_fin(ctrack);
|
||||
reasm_orig_cancel(ctrack);
|
||||
rdata_payload=NULL;
|
||||
|
||||
if (bHaveHost)
|
||||
@@ -1065,6 +1066,21 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
|
||||
return verdict;
|
||||
}
|
||||
|
||||
// return : true - should continue, false - should stop with verdict
|
||||
static bool quic_reasm_cancel(t_ctrack *ctrack, const char *reason)
|
||||
{
|
||||
reasm_orig_cancel(ctrack);
|
||||
if (params.desync_any_proto)
|
||||
{
|
||||
DLOG("%s. applying tampering because desync_any_proto is set\n",reason)
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
DLOG("%s. not applying tampering because desync_any_proto is not set\n",reason)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const char *ifout, uint8_t *data_pkt, size_t *len_pkt, struct ip *ip, struct ip6_hdr *ip6hdr, struct udphdr *udphdr, size_t transport_len, uint8_t *data_payload, size_t len_payload)
|
||||
{
|
||||
@@ -1127,7 +1143,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const ch
|
||||
|
||||
if (ctrack && !ctrack->l7proto) ctrack->l7proto = QUIC;
|
||||
|
||||
uint8_t clean[9000], *pclean;
|
||||
uint8_t clean[16384], *pclean;
|
||||
size_t clean_len;
|
||||
bool bIsHello = false;
|
||||
|
||||
@@ -1145,14 +1161,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const ch
|
||||
{
|
||||
if (ctrack && !ReasmIsEmpty(&ctrack->reasm_orig))
|
||||
{
|
||||
size_t newlen = ctrack->reasm_orig.size_present + clean_len;
|
||||
if (newlen>16384)
|
||||
{
|
||||
DLOG("QUIC reasm is too long. cancelling.\n");
|
||||
reasm_orig_cancel(ctrack);
|
||||
return verdict; // cannot be first packet
|
||||
}
|
||||
if (ReasmResize(&ctrack->reasm_orig, newlen))
|
||||
if (ReasmHasSpace(&ctrack->reasm_orig, clean_len))
|
||||
{
|
||||
reasm_orig_feed(ctrack,IPPROTO_UDP,clean,clean_len);
|
||||
pclean = ctrack->reasm_orig.packet;
|
||||
@@ -1160,7 +1169,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const ch
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "reasm update failed ! out of memory.\n");
|
||||
DLOG("QUIC reasm is too long. cancelling.\n");
|
||||
reasm_orig_cancel(ctrack);
|
||||
return verdict; // cannot be first packet
|
||||
}
|
||||
@@ -1179,9 +1188,9 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const ch
|
||||
{
|
||||
if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig))
|
||||
{
|
||||
if (!reasm_orig_start(ctrack,clean_len,clean_len,clean,clean_len))
|
||||
// preallocate max buffer to avoid reallocs that cause memory copy
|
||||
if (!reasm_orig_start(ctrack,16384,16384,clean,clean_len))
|
||||
{
|
||||
fprintf(stderr, "reasm start failed ! out of memory.\n");
|
||||
reasm_orig_cancel(ctrack);
|
||||
return verdict;
|
||||
}
|
||||
@@ -1220,40 +1229,19 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const ch
|
||||
}
|
||||
else
|
||||
{
|
||||
reasm_orig_cancel(ctrack);
|
||||
if (params.desync_any_proto)
|
||||
DLOG("QUIC initial without ClientHello. applying tampering because desync_any_proto is set\n")
|
||||
else
|
||||
{
|
||||
DLOG("not applying tampering to QUIC initial without ClientHello\n")
|
||||
return verdict;
|
||||
}
|
||||
if (!quic_reasm_cancel(ctrack,"QUIC initial without ClientHello")) return verdict;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// defrag failed
|
||||
reasm_orig_cancel(ctrack);
|
||||
if (params.desync_any_proto)
|
||||
DLOG("QUIC initial without CRYPTO frame. applying tampering because desync_any_proto is set\n")
|
||||
else
|
||||
{
|
||||
DLOG("not applying tampering to QUIC initial without CRYPTO frame\n")
|
||||
return verdict;
|
||||
}
|
||||
if (!quic_reasm_cancel(ctrack,"QUIC initial defrag CRYPTO failed")) return verdict;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// decrypt failed
|
||||
reasm_orig_cancel(ctrack);
|
||||
if (params.desync_any_proto)
|
||||
DLOG("QUIC initial decryption failed. applying tampering because desync_any_proto is set\n")
|
||||
else
|
||||
{
|
||||
DLOG("not applying tampering to QUIC initial that could not be decrypted\n")
|
||||
return verdict;
|
||||
}
|
||||
if (!quic_reasm_cancel(ctrack,"QUIC initial decryption failed")) return verdict;
|
||||
}
|
||||
|
||||
fake = params.fake_quic;
|
||||
@@ -1301,8 +1289,11 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const ch
|
||||
DLOG("not applying tampering to this request\n")
|
||||
if (!bExcluded && *params.hostlist_auto_filename && ctrack)
|
||||
{
|
||||
if (!ctrack->hostname) ctrack->hostname=strdup(host);
|
||||
process_retrans_fail(ctrack, IPPROTO_UDP);
|
||||
if (!ctrack->hostname)
|
||||
// first request is not retrans
|
||||
ctrack->hostname=strdup(host);
|
||||
else
|
||||
process_retrans_fail(ctrack, IPPROTO_UDP);
|
||||
}
|
||||
return verdict;
|
||||
}
|
||||
|
Reference in New Issue
Block a user