Browse Source

nfqws: optimize autohostlist handling

pull/193/head
bol-van 12 months ago
parent
commit
21ce641ebf
  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. 3
      nfq/conntrack.h
  11. 124
      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.

3
nfq/conntrack.h

@ -65,7 +65,7 @@ typedef struct
uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none
uint8_t req_retrans_counter; // number of request retransmissions uint8_t req_retrans_counter; // number of request retransmissions
bool req_seq_present,req_seq_finalized; bool req_seq_present,req_seq_finalized,req_seq_abandoned;
uint32_t req_seq_start,req_seq_end; // sequence interval of the request (to track retransmissions) uint32_t req_seq_start,req_seq_end; // sequence interval of the request (to track retransmissions)
uint8_t autottl; uint8_t autottl;
@ -75,6 +75,7 @@ typedef struct
t_l7proto l7proto; t_l7proto l7proto;
char *hostname; char *hostname;
bool hostname_ah_check; // should perform autohostlist checks
t_reassemble reasm_orig; t_reassemble reasm_orig;
struct rawpacket_tailhead delayed; struct rawpacket_tailhead delayed;

124
nfq/desync.c

@ -144,7 +144,7 @@ static void maybe_cutoff(t_ctrack *ctrack, uint8_t proto)
ctrack->b_cutoff |= \ ctrack->b_cutoff |= \
(!params.wssize || ctrack->b_wssize_cutoff) && (!params.wssize || ctrack->b_wssize_cutoff) &&
(!params.desync_cutoff || ctrack->b_desync_cutoff) && (!params.desync_cutoff || ctrack->b_desync_cutoff) &&
(!*params.hostlist_auto_filename || ctrack->req_retrans_counter==RETRANS_COUNTER_STOP) && (!ctrack->hostname_ah_check || ctrack->req_retrans_counter==RETRANS_COUNTER_STOP) &&
ReasmIsEmpty(&ctrack->reasm_orig); ReasmIsEmpty(&ctrack->reasm_orig);
} }
} }
@ -167,7 +167,7 @@ static void forced_wssize_cutoff(t_ctrack *ctrack)
static void ctrack_stop_retrans_counter(t_ctrack *ctrack) static void ctrack_stop_retrans_counter(t_ctrack *ctrack)
{ {
if (ctrack && *params.hostlist_auto_filename) if (ctrack && ctrack->hostname_ah_check)
{ {
ctrack->req_retrans_counter = RETRANS_COUNTER_STOP; ctrack->req_retrans_counter = RETRANS_COUNTER_STOP;
maybe_cutoff(ctrack, IPPROTO_TCP); maybe_cutoff(ctrack, IPPROTO_TCP);
@ -177,11 +177,11 @@ static void ctrack_stop_retrans_counter(t_ctrack *ctrack)
// return true if retrans trigger fires // return true if retrans trigger fires
static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int threshold) static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int threshold)
{ {
if (*params.hostlist_auto_filename && ctrack && ctrack->req_retrans_counter!=RETRANS_COUNTER_STOP) if (ctrack && ctrack->hostname_ah_check && ctrack->req_retrans_counter!=RETRANS_COUNTER_STOP)
{ {
if (l4proto==IPPROTO_TCP) if (l4proto==IPPROTO_TCP)
{ {
if (!ctrack->req_seq_finalized) if (!ctrack->req_seq_finalized || ctrack->req_seq_abandoned)
return false; return false;
if (!seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end)) if (!seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end))
{ {
@ -441,14 +441,13 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
{ {
uint8_t verdict=VERDICT_PASS; uint8_t verdict=VERDICT_PASS;
t_ctrack *ctrack=NULL; t_ctrack *ctrack=NULL, *ctrack_replay=NULL;
const t_reassemble *reasm_replay=NULL;
bool bReverse=false; bool bReverse=false;
struct sockaddr_storage src, dst; struct sockaddr_storage src, dst;
uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN+100], pkt2[DPI_DESYNC_MAX_FAKE_LEN+100]; uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN+100], pkt2[DPI_DESYNC_MAX_FAKE_LEN+100];
size_t pkt1_len, pkt2_len; size_t pkt1_len, pkt2_len;
uint8_t ttl_orig,ttl_fake,ttl_auto=0,flags_orig,scale_factor; uint8_t ttl_orig,ttl_fake,flags_orig,scale_factor;
uint32_t *timestamps; uint32_t *timestamps;
ttl_orig = ip ? ip->ip_ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim; ttl_orig = ip ? ip->ip_ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim;
@ -456,24 +455,21 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
if (replay) if (replay)
{ {
t_ctrack *ctrack; // in replay mode conntrack_replay is not NULL and ctrack is NULL
bool bReverse;
//ConntrackPoolDump(&params.conntrack); //ConntrackPoolDump(&params.conntrack);
if (ConntrackPoolDoubleSearch(&params.conntrack, ip, ip6hdr, tcphdr, NULL, &ctrack, &bReverse) && !bReverse) if (!ConntrackPoolDoubleSearch(&params.conntrack, ip, ip6hdr, tcphdr, NULL, &ctrack_replay, &bReverse) || bReverse)
{
reasm_replay = &ctrack->reasm_orig;
ttl_auto = ctrack->autottl;
}
else
return verdict; return verdict;
} }
else else
{ {
// in real mode ctrack may be NULL or not NULL, conntrack_replay is equal to ctrack
ConntrackPoolPurge(&params.conntrack); ConntrackPoolPurge(&params.conntrack);
if (ConntrackPoolFeed(&params.conntrack, ip, ip6hdr, tcphdr, NULL, len_payload, &ctrack, &bReverse)) if (ConntrackPoolFeed(&params.conntrack, ip, ip6hdr, tcphdr, NULL, len_payload, &ctrack, &bReverse))
{ {
ctrack_replay = ctrack;
maybe_cutoff(ctrack, IPPROTO_TCP); maybe_cutoff(ctrack, IPPROTO_TCP);
ttl_auto = ctrack->autottl;
} }
HostFailPoolPurgeRateLimited(&params.hostlist_auto_fail_counters); HostFailPoolPurgeRateLimited(&params.hostlist_auto_fail_counters);
@ -503,7 +499,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
// process reply packets for auto hostlist mode // process reply packets for auto hostlist mode
// by looking at RSTs or HTTP replies we decide whether original request looks like DPI blocked // by looking at RSTs or HTTP replies we decide whether original request looks like DPI blocked
// we only process first-sequence replies. do not react to subsequent redirects or RSTs // we only process first-sequence replies. do not react to subsequent redirects or RSTs
if (*params.hostlist_auto_filename && ctrack && ctrack->hostname && (ctrack->ack_last-ctrack->ack0)==1) if (ctrack && ctrack->hostname && ctrack->hostname_ah_check && (ctrack->ack_last-ctrack->ack0)==1)
{ {
bool bFail=false; bool bFail=false;
if (tcphdr->th_flags & TH_RST) if (tcphdr->th_flags & TH_RST)
@ -566,7 +562,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
if (params.desync_mode0!=DESYNC_NONE || params.desync_mode!=DESYNC_NONE) // save some cpu if (params.desync_mode0!=DESYNC_NONE || params.desync_mode!=DESYNC_NONE) // save some cpu
{ {
ttl_fake = ttl_auto ? ttl_auto : (ip6hdr ? (params.desync_ttl6 ? params.desync_ttl6 : ttl_orig) : (params.desync_ttl ? params.desync_ttl : ttl_orig)); ttl_fake = (ctrack_replay && ctrack_replay->autottl) ? ctrack_replay->autottl : (ip6hdr ? (params.desync_ttl6 ? params.desync_ttl6 : ttl_orig) : (params.desync_ttl ? params.desync_ttl : ttl_orig));
flags_orig = *((uint8_t*)tcphdr+13); flags_orig = *((uint8_t*)tcphdr+13);
scale_factor = tcp_find_scale_factor(tcphdr); scale_factor = tcp_find_scale_factor(tcphdr);
timestamps = tcp_find_timestamps(tcphdr); timestamps = tcp_find_timestamps(tcphdr);
@ -639,10 +635,10 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
const uint8_t *rdata_payload = data_payload; const uint8_t *rdata_payload = data_payload;
size_t rlen_payload = len_payload; size_t rlen_payload = len_payload;
if (reasm_replay) if (replay)
{ {
rdata_payload = reasm_replay->packet; rdata_payload = ctrack_replay->reasm_orig.packet;
rlen_payload = reasm_replay->size_present; rlen_payload = ctrack_replay->reasm_orig.size_present;
} }
else if (reasm_orig_feed(ctrack,IPPROTO_TCP,data_payload,len_payload)) else if (reasm_orig_feed(ctrack,IPPROTO_TCP,data_payload,len_payload))
{ {
@ -696,7 +692,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
{ {
if (!ctrack->l7proto) ctrack->l7proto = TLS; if (!ctrack->l7proto) ctrack->l7proto = TLS;
// do not reasm retransmissions // do not reasm retransmissions
if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_orig) && if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_orig) && !ctrack->req_seq_abandoned &&
!(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 ?)
@ -741,7 +737,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
replay_queue(&ctrack->delayed); replay_queue(&ctrack->delayed);
reasm_orig_fin(ctrack); reasm_orig_fin(ctrack);
} }
if (!ctrack->hostname && bHaveHost) ctrack->hostname=strdup(host);
return VERDICT_DROP; return VERDICT_DROP;
} }
} }
@ -761,25 +756,37 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, uint32_t fwmark, const ch
reasm_orig_cancel(ctrack); reasm_orig_cancel(ctrack);
rdata_payload=NULL; rdata_payload=NULL;
if (ctrack && ctrack->req_seq_finalized)
{
uint32_t dseq = ctrack->seq_last - ctrack->req_seq_end;
// do not react to 32-bit overflowed sequence numbers. allow 16 Mb grace window then cutoff.
if (dseq>=0x1000000 && !(dseq & 0x80000000)) ctrack->req_seq_abandoned=true;
}
if (bHaveHost) if (bHaveHost)
{ {
bool bExcluded;
DLOG("hostname: %s\n",host) DLOG("hostname: %s\n",host)
if ((params.hostlist || params.hostlist_exclude) && !HostlistCheck(host, &bExcluded)) if (params.hostlist || params.hostlist_exclude)
{ {
DLOG("not applying tampering to this request\n") bool bBypass;
if (ctrack) if (HostlistCheck(host, &bBypass))
ctrack_stop_retrans_counter(ctrack_replay);
else
{ {
if (!bExcluded && *params.hostlist_auto_filename) if (ctrack_replay)
{ {
if (!ctrack->hostname) ctrack->hostname=strdup(host); ctrack_replay->hostname_ah_check = *params.hostlist_auto_filename && !bBypass;
if (ctrack_replay->hostname_ah_check)
{
if (!ctrack_replay->hostname) ctrack_replay->hostname=strdup(host);
}
else
ctrack_stop_retrans_counter(ctrack_replay);
} }
else DLOG("not applying tampering to this request\n")
ctrack_stop_retrans_counter(ctrack); return verdict;
} }
return verdict;
} }
ctrack_stop_retrans_counter(ctrack);
} }
if (!bKnownProtocol) if (!bKnownProtocol)
@ -1088,7 +1095,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const ch
{ {
uint8_t verdict=VERDICT_PASS; uint8_t verdict=VERDICT_PASS;
t_ctrack *ctrack=NULL; t_ctrack *ctrack=NULL, *ctrack_replay=NULL;
bool bReverse=false; bool bReverse=false;
struct sockaddr_storage src, dst; struct sockaddr_storage src, dst;
@ -1096,23 +1103,24 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const ch
size_t pkt1_len, pkt2_len; size_t pkt1_len, pkt2_len;
uint8_t ttl_orig,ttl_fake; uint8_t ttl_orig,ttl_fake;
t_reassemble *reasm_replay = NULL;
if (replay) if (replay)
{ {
t_ctrack *ctrack; // in replay mode conntrack_replay is not NULL and ctrack is NULL
bool bReverse;
//ConntrackPoolDump(&params.conntrack); //ConntrackPoolDump(&params.conntrack);
if (ConntrackPoolDoubleSearch(&params.conntrack, ip, ip6hdr, NULL, udphdr, &ctrack, &bReverse) && !bReverse) if (!ConntrackPoolDoubleSearch(&params.conntrack, ip, ip6hdr, NULL, udphdr, &ctrack_replay, &bReverse) || bReverse)
reasm_replay = &ctrack->reasm_orig;
else
return verdict; return verdict;
} }
else else
{ {
// in real mode ctrack may be NULL or not NULL, conntrack_replay is equal to ctrack
ConntrackPoolPurge(&params.conntrack); ConntrackPoolPurge(&params.conntrack);
if (ConntrackPoolFeed(&params.conntrack, ip, ip6hdr, NULL, udphdr, len_payload, &ctrack, &bReverse)) if (ConntrackPoolFeed(&params.conntrack, ip, ip6hdr, NULL, udphdr, len_payload, &ctrack, &bReverse))
{
ctrack_replay = ctrack;
maybe_cutoff(ctrack, IPPROTO_UDP); maybe_cutoff(ctrack, IPPROTO_UDP);
}
HostFailPoolPurgeRateLimited(&params.hostlist_auto_fail_counters); HostFailPoolPurgeRateLimited(&params.hostlist_auto_fail_counters);
//ConntrackPoolDump(&params.conntrack); //ConntrackPoolDump(&params.conntrack);
} }
@ -1142,17 +1150,16 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const ch
if (IsQUICInitial(data_payload,len_payload)) if (IsQUICInitial(data_payload,len_payload))
{ {
DLOG("packet contains QUIC initial\n") DLOG("packet contains QUIC initial\n")
if (ctrack && !ctrack->l7proto) ctrack->l7proto = QUIC; if (ctrack && !ctrack->l7proto) ctrack->l7proto = QUIC;
uint8_t clean[16384], *pclean; uint8_t clean[16384], *pclean;
size_t clean_len; size_t clean_len;
bool bIsHello = false; bool bIsHello = false;
if (reasm_replay) if (replay)
{ {
clean_len = reasm_replay->size_present; clean_len = ctrack_replay->reasm_orig.size_present;
pclean = reasm_replay->packet; pclean = ctrack_replay->reasm_orig.packet;
} }
else else
{ {
@ -1285,19 +1292,26 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const ch
if (bHaveHost) if (bHaveHost)
{ {
DLOG("hostname: %s\n",host) DLOG("hostname: %s\n",host)
bool bExcluded; if (params.hostlist || params.hostlist_exclude)
if ((params.hostlist || params.hostlist_exclude) && !HostlistCheck(host, &bExcluded))
{ {
DLOG("not applying tampering to this request\n") bool bBypass;
if (!bExcluded && *params.hostlist_auto_filename && ctrack) if (!HostlistCheck(host, &bBypass))
{ {
if (!ctrack->hostname) if (ctrack_replay)
// first request is not retrans {
ctrack->hostname=strdup(host); ctrack_replay->hostname_ah_check = *params.hostlist_auto_filename && !bBypass;
else if (ctrack_replay->hostname_ah_check)
process_retrans_fail(ctrack, IPPROTO_UDP); {
// first request is not retrans
if (ctrack_replay->hostname)
process_retrans_fail(ctrack_replay, IPPROTO_UDP);
else
ctrack_replay->hostname=strdup(host);
}
}
DLOG("not applying tampering to this request\n")
return verdict;
} }
return verdict;
} }
} }

Loading…
Cancel
Save