Browse Source

nfqws: fix reasm seq handling

pull/193/head
bol-van 12 months ago
parent
commit
7d789f79d0
  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. 22
      nfq/conntrack.c
  11. 4
      nfq/conntrack.h
  12. 18
      nfq/desync.c
  13. 2
      nfq/protocol.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.

22
nfq/conntrack.c

@ -142,13 +142,13 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
if (tcp_syn_segment(tcphdr)) if (tcp_syn_segment(tcphdr))
{ {
if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry
t->seq0 = htonl(tcphdr->th_seq); t->seq0 = ntohl(tcphdr->th_seq);
} }
else if (tcp_synack_segment(tcphdr)) else if (tcp_synack_segment(tcphdr))
{ {
if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry if (t->state!=SYN) ConntrackReInitTrack(t); // erase current entry
if (!t->seq0) t->seq0 = htonl(tcphdr->th_ack)-1; if (!t->seq0) t->seq0 = ntohl(tcphdr->th_ack)-1;
t->ack0 = htonl(tcphdr->th_seq); t->ack0 = ntohl(tcphdr->th_seq);
} }
else if (tcphdr->th_flags & (TH_FIN|TH_RST)) else if (tcphdr->th_flags & (TH_FIN|TH_RST))
{ {
@ -159,25 +159,25 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
if (t->state==SYN) if (t->state==SYN)
{ {
t->state=ESTABLISHED; t->state=ESTABLISHED;
if (!bReverse && !t->ack0) t->ack0 = htonl(tcphdr->th_ack)-1; if (!bReverse && !t->ack0) t->ack0 = ntohl(tcphdr->th_ack)-1;
} }
} }
scale = tcp_find_scale_factor(tcphdr); scale = tcp_find_scale_factor(tcphdr);
if (bReverse) if (bReverse)
{ {
t->pos_orig = t->seq_last = htonl(tcphdr->th_ack); t->pos_orig = t->seq_last = ntohl(tcphdr->th_ack);
t->ack_last = htonl(tcphdr->th_seq); t->ack_last = ntohl(tcphdr->th_seq);
t->pos_reply = t->ack_last + len_payload; t->pos_reply = t->ack_last + len_payload;
t->winsize_reply = htons(tcphdr->th_win); t->winsize_reply = ntohs(tcphdr->th_win);
if (scale!=SCALE_NONE) t->scale_reply = scale; if (scale!=SCALE_NONE) t->scale_reply = scale;
} }
else else
{ {
t->seq_last = htonl(tcphdr->th_seq); t->seq_last = ntohl(tcphdr->th_seq);
t->pos_orig = t->seq_last + len_payload; t->pos_orig = t->seq_last + len_payload;
t->pos_reply = t->ack_last = htonl(tcphdr->th_ack); t->pos_reply = t->ack_last = ntohl(tcphdr->th_ack);
t->winsize_orig = htons(tcphdr->th_win); t->winsize_orig = ntohs(tcphdr->th_win);
if (scale!=SCALE_NONE) t->scale_orig = scale; if (scale!=SCALE_NONE) t->scale_orig = scale;
} }
} }
@ -387,7 +387,7 @@ bool ReasmResize(t_reassemble *reasm, size_t new_size)
if (reasm->size_present > new_size) reasm->size_present = new_size; if (reasm->size_present > new_size) reasm->size_present = new_size;
return true; return true;
} }
bool ReasmFeed(t_reassemble *reasm, size_t seq, const void *payload, size_t len) bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len)
{ {
if (reasm->seq!=seq) return false; // fail session if out of sequence if (reasm->seq!=seq) return false; // fail session if out of sequence

4
nfq/conntrack.h

@ -39,7 +39,7 @@ typedef struct
// this structure helps to reassemble continuous packets streams. it does not support out-of-orders // this structure helps to reassemble continuous packets streams. it does not support out-of-orders
typedef struct { typedef struct {
uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size. uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size.
size_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session. uint32_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; // 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' size_t size_present; // how many bytes already stored in 'packet'
} t_reassemble; } t_reassemble;
@ -109,7 +109,7 @@ bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start);
bool ReasmResize(t_reassemble *reasm, size_t new_size); bool ReasmResize(t_reassemble *reasm, size_t new_size);
void ReasmClear(t_reassemble *reasm); void ReasmClear(t_reassemble *reasm);
// false means reassemble session has failed and we should ReasmClear() it // false means reassemble session has failed and we should ReasmClear() it
bool ReasmFeed(t_reassemble *reasm, size_t seq, const void *payload, size_t len); bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len);
// check if it has enough space to buffer 'len' bytes // check if it has enough space to buffer 'len' bytes
bool ReasmHasSpace(t_reassemble *reasm, size_t len); bool ReasmHasSpace(t_reassemble *reasm, size_t len);
inline static bool ReasmIsEmpty(t_reassemble *reasm) {return !reasm->size;} inline static bool ReasmIsEmpty(t_reassemble *reasm) {return !reasm->size;}

18
nfq/desync.c

@ -269,14 +269,15 @@ static bool send_delayed(t_ctrack *ctrack)
} }
static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload) static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload)
{ {
ReasmClear(reasm); ReasmClear(reasm);
if (sz<=szMax) if (sz<=szMax)
{ {
if (ReasmInit(reasm,sz,ctrack->seq_last)) uint32_t seq = (proto==IPPROTO_TCP) ? ctrack->seq_last : 0;
if (ReasmInit(reasm,sz,seq))
{ {
ReasmFeed(reasm,ctrack->seq_last,data_payload,len_payload); ReasmFeed(reasm,seq,data_payload,len_payload);
DLOG("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; return true;
} }
@ -287,15 +288,16 @@ static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, size_t sz, size_t
DLOG("unexpected large payload for reassemble: size=%zu\n",sz); DLOG("unexpected large payload for reassemble: size=%zu\n",sz);
return false; return false;
} }
static bool reasm_orig_start(t_ctrack *ctrack, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload) static bool reasm_orig_start(t_ctrack *ctrack, uint8_t proto, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload)
{ {
return reasm_start(ctrack,&ctrack->reasm_orig,sz,szMax,data_payload,len_payload); return reasm_start(ctrack,&ctrack->reasm_orig,proto,sz,szMax,data_payload,len_payload);
} }
static bool reasm_feed(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, const uint8_t *data_payload, size_t len_payload) static bool reasm_feed(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, const uint8_t *data_payload, size_t len_payload)
{ {
if (ctrack && !ReasmIsEmpty(reasm)) if (ctrack && !ReasmIsEmpty(reasm))
{ {
if (ReasmFeed(reasm,proto==IPPROTO_TCP ? (size_t)ctrack->seq_last : reasm->size_present, data_payload, len_payload)) uint32_t seq = (proto==IPPROTO_TCP) ? ctrack->seq_last : (uint32_t)reasm->size_present;
if (ReasmFeed(reasm, seq, data_payload, len_payload))
{ {
DLOG("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; return true;
@ -698,7 +700,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
!(ctrack->req_seq_finalized && seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end))) !(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 ?) // do not reconstruct unexpected large payload (they are feeding garbage ?)
if (!reasm_orig_start(ctrack,TLSRecordLen(data_payload),16384,data_payload,len_payload)) if (!reasm_orig_start(ctrack,IPPROTO_TCP,TLSRecordLen(data_payload),16384,data_payload,len_payload))
{ {
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
return verdict; return verdict;
@ -1189,7 +1191,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const ch
if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig)) if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig))
{ {
// preallocate max buffer to avoid reallocs that cause memory copy // preallocate max buffer to avoid reallocs that cause memory copy
if (!reasm_orig_start(ctrack,16384,16384,clean,clean_len)) if (!reasm_orig_start(ctrack,IPPROTO_UDP,16384,16384,clean,clean_len))
{ {
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
return verdict; return verdict;

2
nfq/protocol.c

@ -131,7 +131,7 @@ size_t TLSHandshakeLen(const uint8_t *data)
} }
bool IsTLSHandshakeClientHello(const uint8_t *data, size_t len) bool IsTLSHandshakeClientHello(const uint8_t *data, size_t len)
{ {
return len>=4 && data[0]==0x01; return len>=4 && data[0]==0x01 && TLSHandshakeLen(data)>0;
} }
bool IsTLSHandshakeFull(const uint8_t *data, size_t len) bool IsTLSHandshakeFull(const uint8_t *data, size_t len)
{ {

Loading…
Cancel
Save