nfqws: optimize autohostlist handling

This commit is contained in:
bol-van 2024-04-24 17:03:18 +03:00
parent 7d789f79d0
commit 21ce641ebf
11 changed files with 73 additions and 58 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

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

View File

@ -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
{ {
@ -1185,7 +1192,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, uint32_t fwmark, const ch
bool bReqFull = bIsHello ? IsTLSHandshakeFull(defrag+hello_offset,hello_len) : false; 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") 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 (ctrack)
{ {
if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig)) if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig))
@ -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;
} }
} }