Browse Source

nfqws: quic fix retrans counter, optimize reasm

pull/193/head
bol-van 12 months ago
parent
commit
0f14f2e71b
  1. BIN
      binaries/aarch64/nfqws
  2. BIN
      binaries/arm/nfqws
  3. BIN
      binaries/freebsd-x64/dvtws
  4. BIN
      binaries/mips32r1-lsb/nfqws
  5. BIN
      binaries/mips32r1-msb/nfqws
  6. BIN
      binaries/mips64r2-msb/nfqws
  7. BIN
      binaries/ppc/nfqws
  8. BIN
      binaries/x86/nfqws
  9. BIN
      binaries/x86_64/nfqws
  10. 8
      nfq/conntrack.c
  11. 6
      nfq/conntrack.h
  12. 103
      nfq/desync.c

BIN
binaries/aarch64/nfqws

Binary file not shown.

BIN
binaries/arm/nfqws

Binary file not shown.

BIN
binaries/freebsd-x64/dvtws

Binary file not shown.

BIN
binaries/mips32r1-lsb/nfqws

Binary file not shown.

BIN
binaries/mips32r1-msb/nfqws

Binary file not shown.

BIN
binaries/mips64r2-msb/nfqws

Binary file not shown.

BIN
binaries/ppc/nfqws

Binary file not shown.

BIN
binaries/x86/nfqws

Binary file not shown.

BIN
binaries/x86_64/nfqws

Binary file not shown.

8
nfq/conntrack.c

@ -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;
}

6
nfq/conntrack.h

@ -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

@ -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;
}

Loading…
Cancel
Save