From 2dd8533fb5671fc37d7ce7847564ed150e4ee36d Mon Sep 17 00:00:00 2001 From: bol-van Date: Wed, 10 Dec 2025 19:36:31 +0300 Subject: [PATCH] nfqws2,zapret-lib.lua,zapret-auto.lua: restructure conntrack record --- docs/changes.txt | 3 +- docs/changes_compat.txt | 4 + lua/zapret-auto.lua | 4 +- lua/zapret-lib.lua | 43 +++++++--- nfq2/conntrack.c | 134 ++++++++++++++---------------- nfq2/conntrack.h | 6 +- nfq2/conntrack_base.h | 35 ++++---- nfq2/desync.c | 180 ++++++++++++++++++++-------------------- nfq2/helpers.c | 2 +- nfq2/lua.c | 92 ++++++++++++-------- nfq2/lua.h | 5 +- nfq2/nfqws.c | 4 +- nfq2/nfqws.h | 2 +- nfq2/packet_queue.c | 10 +-- nfq2/packet_queue.h | 6 +- nfq2/params.h | 2 +- 16 files changed, 293 insertions(+), 239 deletions(-) diff --git a/docs/changes.txt b/docs/changes.txt index d63531e..c50a3d1 100644 --- a/docs/changes.txt +++ b/docs/changes.txt @@ -81,6 +81,7 @@ v0.6.1 * zapret-lib: detect_payload_str - sample lua payload detector * blockcheck2: unterminated string fix -v0.6.2 +v0.7 * nfqws2, zapret-lib : fix non-working % and # arg substitution under orchestrator +* nfqws2, zapret-lib : structure conntrack in/out positions. pass in desync.track.pos.{client,server,direct,reverse} position tables diff --git a/docs/changes_compat.txt b/docs/changes_compat.txt index 1692b54..6e828d0 100644 --- a/docs/changes_compat.txt +++ b/docs/changes_compat.txt @@ -5,3 +5,7 @@ v2 * removed "stun_binding_req" specialized payload. replaced with common "stun" - any stun packets, not only binding request. every LUA relying on desync.l7payload should be revised. nfqws2 --payload option and init.d custom scripts must be updated. + +v3 +* restructured desync.track. pass positions in desync.track.pos.{client,server,direct,reverse} +code relying on conntrack counters and sequence numbers must be rewritten diff --git a/lua/zapret-auto.lua b/lua/zapret-auto.lua index edab9ac..f98f771 100644 --- a/lua/zapret-auto.lua +++ b/lua/zapret-auto.lua @@ -141,11 +141,11 @@ function standard_failure_detector(desync, crec, arg) if desync.outgoing then if udp_out then local udp_in = udp_in or 0 - trigger = desync.track.pcounter_orig>=udp_out and desync.track.pcounter_reply<=udp_in + trigger = desync.track.pos.direct.pcounter>=udp_out and desync.track.pos.reverse.pcounter<=udp_in if trigger then crec.nocheck = true if b_debug then - DLOG("standard_failure_detector: udp_out "..desync.track.pcounter_orig..">="..udp_out.." udp_in "..desync.track.pcounter_reply.."<="..udp_in) + DLOG("standard_failure_detector: udp_out "..desync.track.pos.direct.pcounter..">="..udp_out.." udp_in "..desync.track.pos.reverse.pcounter.."<="..udp_in) end end end diff --git a/lua/zapret-lib.lua b/lua/zapret-lib.lua index 922d5b0..52ad395 100644 --- a/lua/zapret-lib.lua +++ b/lua/zapret-lib.lua @@ -37,16 +37,24 @@ function pktdebug(ctx, desync) end -- basic desync function -- prints function args -function argdebug(ctx,desync) +function argdebug(ctx, desync) var_debug(desync.arg) end -- basic desync function -- prints conntrack positions to DLOG -function posdebug(ctx,desync) - local s="posdebug:" - for i,pos in pairs({'n','d','b','s'}) do - s=s.." "..pos..pos_get(desync,pos) +function posdebug(ctx, desync) + if not desync.track then + DLOG("posdebug: no track") + return + end + local s="posdebug: "..(desync.outgoing and "out" or "in").." time +"..desync.track.pos.dt.."s direct" + for i,pos in pairs({'n','d','b','s','p'}) do + s=s.." "..pos..pos_get(desync, pos, false) + end + s=s.." reverse" + for i,pos in pairs({'n','d','b','s','p'}) do + s=s.." "..pos..pos_get(desync, pos, true) end s=s.." payload "..#desync.dis.payload if desync.reasm_data then @@ -231,20 +239,31 @@ end -- pos is {mode,pos} -- range is {from={mode,pos}, to={mode,pos}, upper_cutoff} -- upper_cutoff = true means non-inclusive upper boundary -function pos_get(desync, mode) - if desync.track then +function pos_get_pos(track_pos, mode) + if track_pos then if mode=='n' then - return desync.outgoing and desync.track.pcounter_orig or desync.track.pcounter_reply + return track_pos.pcounter elseif mode=='d' then - return desync.outgoing and desync.track.pdcounter_orig or desync.track.pdcounter_reply + return track_pos.pdcounter elseif mode=='b' then - return desync.outgoing and desync.track.pbcounter_orig or desync.track.pbcounter_reply - elseif mode=='s' and desync.track.tcp then - return desync.outgoing and u32add(desync.track.tcp.seq, -desync.track.tcp.seq0) or u32add(desync.track.tcp.ack, -desync.track.tcp.ack0) + return track_pos.pbcounter + elseif track_pos.tcp then + if mode=='s' then + return track_pos.tcp.rseq + elseif mode=='p' then + return track_pos.tcp.pos + end end end return 0 end +function pos_get(desync, mode, reverse) + if desync.track then + local track_pos = reverse and desync.track.pos.reverse or desync.track.pos.direct + return pos_get_pos(track_pos,mode) + end + return 0 +end function pos_check_from(desync, range) if range.from.mode == 'x' then return false end if range.from.mode ~= 'a' then diff --git a/nfq2/conntrack.c b/nfq2/conntrack.c index 4428fe0..f586978 100644 --- a/nfq2/conntrack.c +++ b/nfq2/conntrack.c @@ -37,7 +37,7 @@ void ConntrackClearHostname(t_ctrack *track) static void ConntrackClearTrack(t_ctrack *track) { ConntrackClearHostname(track); - ReasmClear(&track->reasm_orig); + ReasmClear(&track->reasm_client); rawpacket_queue_destroy(&track->delayed); luaL_unref(params.L, LUA_REGISTRYINDEX, track->lua_state); luaL_unref(params.L, LUA_REGISTRYINDEX, track->lua_instance_cutoff); @@ -102,8 +102,8 @@ static void ConntrackInitTrack(t_ctrack *t) { memset(t, 0, sizeof(*t)); t->l7proto = L7_UNKNOWN; - t->pos.scale_orig = t->pos.scale_reply = SCALE_NONE; - time(&t->pos.t_start); + t->pos.client.scale = t->pos.server.scale = SCALE_NONE; + time(&t->t_start); rawpacket_queue_init(&t->delayed); lua_newtable(params.L); t->lua_state = luaL_ref(params.L, LUA_REGISTRYINDEX); @@ -128,6 +128,36 @@ static t_conntrack_pool *ConntrackNew(t_conntrack_pool **pp, const t_conn *c) return ctnew; } +static void ConntrackApplyPos(const struct tcphdr *tcp, t_ctrack *t, bool bReverse, uint32_t len_payload) +{ + uint8_t scale; + uint16_t mss; + t_ctrack_position *direct, *reverse; + + direct = bReverse ? &t->pos.server : &t->pos.client; + reverse = bReverse ? &t->pos.client : &t->pos.server; + + scale = tcp_find_scale_factor(tcp); + mss = ntohs(tcp_find_mss(tcp)); + + direct->seq_last = ntohl(tcp->th_seq); + direct->pos = direct->seq_last + len_payload; + reverse->pos = reverse->seq_last = ntohl(tcp->th_ack); + if (t->pos.state == SYN) + direct->uppos_prev = direct->uppos = direct->pos; + else if (len_payload) + { + direct->uppos_prev = direct->uppos; + if (!((direct->pos - direct->uppos) & 0x80000000)) + direct->uppos = direct->pos; + } + direct->winsize = ntohs(tcp->th_win); + direct->winsize_calc = direct->winsize; + if (direct->scale != SCALE_NONE) direct->winsize_calc <<= direct->scale; + if (mss && !direct->mss) direct->mss = mss; + if (scale != SCALE_NONE) direct->scale = scale; +} + // non-tcp packets are passed with tcphdr=NULL but len_payload filled static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr *tcphdr, uint32_t len_payload) { @@ -136,16 +166,16 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr if (bReverse) { - t->pos.pcounter_reply++; - t->pos.pdcounter_reply += !!len_payload; - t->pos.pbcounter_reply += len_payload; + t->pos.server.pcounter++; + t->pos.server.pdcounter += !!len_payload; + t->pos.server.pbcounter += len_payload; } else { - t->pos.pcounter_orig++; - t->pos.pdcounter_orig += !!len_payload; - t->pos.pbcounter_orig += len_payload; + t->pos.client.pcounter++; + t->pos.client.pdcounter += !!len_payload; + t->pos.client.pbcounter += len_payload; } if (tcphdr) @@ -153,16 +183,16 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr if (tcp_syn_segment(tcphdr)) { if (t->pos.state != SYN) ConntrackReInitTrack(t); // erase current entry - t->pos.seq0 = ntohl(tcphdr->th_seq); + t->pos.client.seq0 = ntohl(tcphdr->th_seq); } else if (tcp_synack_segment(tcphdr)) { // ignore SA dups uint32_t seq0 = ntohl(tcphdr->th_ack) - 1; - if (t->pos.state != SYN && t->pos.seq0 != seq0) + if (t->pos.state != SYN && t->pos.client.seq0 != seq0) ConntrackReInitTrack(t); // erase current entry - if (!t->pos.seq0) t->pos.seq0 = seq0; - t->pos.ack0 = ntohl(tcphdr->th_seq); + if (!t->pos.client.seq0) t->pos.client.seq0 = seq0; + t->pos.server.seq0 = ntohl(tcphdr->th_seq); } else if (tcphdr->th_flags & (TH_FIN | TH_RST)) { @@ -173,61 +203,23 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr if (t->pos.state == SYN) { t->pos.state = ESTABLISHED; - if (!bReverse && !t->pos.ack0) t->pos.ack0 = ntohl(tcphdr->th_ack) - 1; + if (!bReverse && !t->pos.server.seq0) t->pos.server.seq0 = ntohl(tcphdr->th_ack) - 1; } } - scale = tcp_find_scale_factor(tcphdr); - mss = ntohs(tcp_find_mss(tcphdr)); - if (bReverse) - { - t->pos.ack_last = ntohl(tcphdr->th_seq); - t->pos.pos_orig = t->pos.seq_last = ntohl(tcphdr->th_ack); - t->pos.pos_reply = t->pos.ack_last + len_payload; - if (t->pos.state == SYN) - t->pos.uppos_reply_prev = t->pos.uppos_reply = t->pos.pos_reply; - else if (len_payload) - { - t->pos.uppos_reply_prev = t->pos.uppos_reply; - if (!((t->pos.pos_reply - t->pos.uppos_reply) & 0x80000000)) - t->pos.uppos_reply = t->pos.pos_reply; - } - t->pos.winsize_reply = ntohs(tcphdr->th_win); - t->pos.winsize_reply_calc = t->pos.winsize_reply; - if (t->pos.scale_reply != SCALE_NONE) t->pos.winsize_reply_calc <<= t->pos.scale_reply; - if (mss && !t->pos.mss_reply) t->pos.mss_reply = mss; - if (scale != SCALE_NONE) t->pos.scale_reply = scale; - } - else - { - t->pos.seq_last = ntohl(tcphdr->th_seq); - t->pos.pos_orig = t->pos.seq_last + len_payload; - t->pos.pos_reply = t->pos.ack_last = ntohl(tcphdr->th_ack); - if (t->pos.state == SYN) - t->pos.uppos_orig_prev = t->pos.uppos_orig = t->pos.pos_orig; - else if (len_payload) - { - t->pos.uppos_orig_prev = t->pos.uppos_orig; - if (!((t->pos.pos_orig - t->pos.uppos_orig) & 0x80000000)) - t->pos.uppos_orig = t->pos.pos_orig; - } - t->pos.winsize_orig = ntohs(tcphdr->th_win); - t->pos.winsize_orig_calc = t->pos.winsize_orig; - if (t->pos.scale_orig != SCALE_NONE) t->pos.winsize_orig_calc <<= t->pos.scale_orig; - if (mss && !t->pos.mss_reply) t->pos.mss_orig = mss; - if (scale != SCALE_NONE) t->pos.scale_orig = scale; - } + + ConntrackApplyPos(tcphdr, t, bReverse, len_payload); } else { if (bReverse) { - t->pos.ack_last = t->pos.pos_reply; - t->pos.pos_reply += len_payload; + t->pos.server.seq_last = t->pos.server.pos; + t->pos.server.pos += len_payload; } else { - t->pos.seq_last = t->pos.pos_orig; - t->pos.pos_orig += len_payload; + t->pos.client.seq_last = t->pos.client.pos; + t->pos.client.pos += len_payload; } } @@ -362,24 +354,24 @@ void ConntrackPoolDump(const t_conntrack *p) HASH_ITER(hh, p->pool, t, tmp) { taddr2str(t->conn.l3proto, &t->conn.src, sa1, sizeof(sa1)); taddr2str(t->conn.l3proto, &t->conn.dst, sa2, sizeof(sa2)); - printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu orig=d%llu/n%llu/b%llu reply=d%llu/n%llu/b%lld ", + printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu client=d%llu/n%llu/b%llu server=d%llu/n%llu/b%lld ", proto_name(t->conn.l4proto), sa1, t->conn.sport, sa2, t->conn.dport, t->conn.l4proto == IPPROTO_TCP ? connstate_s[t->track.pos.state] : "-", - (unsigned long long)t->track.pos.t_start, (unsigned long long)(t->track.pos.t_last - t->track.pos.t_start), (unsigned long long)(tnow - t->track.pos.t_last), - (unsigned long long)t->track.pos.pdcounter_orig, (unsigned long long)t->track.pos.pcounter_orig, (unsigned long long)t->track.pos.pbcounter_orig, - (unsigned long long)t->track.pos.pdcounter_reply, (unsigned long long)t->track.pos.pcounter_reply, (unsigned long long)t->track.pos.pbcounter_reply); + (unsigned long long)t->track.t_start, (unsigned long long)(t->track.pos.t_last - t->track.t_start), (unsigned long long)(tnow - t->track.pos.t_last), + (unsigned long long)t->track.pos.client.pdcounter, (unsigned long long)t->track.pos.client.pcounter, (unsigned long long)t->track.pos.client.pbcounter, + (unsigned long long)t->track.pos.server.pdcounter, (unsigned long long)t->track.pos.server.pcounter, (unsigned long long)t->track.pos.server.pbcounter); if (t->conn.l4proto == IPPROTO_TCP) - printf("seq0=%u rseq=%u pos_orig=%u ack0=%u rack=%u pos_reply=%u mss_orig=%u mss_reply=%u wsize_orig=%u:%d wsize_reply=%u:%d", - t->track.pos.seq0, t->track.pos.seq_last - t->track.pos.seq0, t->track.pos.pos_orig - t->track.pos.seq0, - t->track.pos.ack0, t->track.pos.ack_last - t->track.pos.ack0, t->track.pos.pos_reply - t->track.pos.ack0, - t->track.pos.mss_orig, t->track.pos.mss_reply, - t->track.pos.winsize_orig, t->track.pos.scale_orig == SCALE_NONE ? -1 : t->track.pos.scale_orig, - t->track.pos.winsize_reply, t->track.pos.scale_reply == SCALE_NONE ? -1 : t->track.pos.scale_reply); + printf("seq0=%u rseq=%u client.pos=%u ack0=%u rack=%u server.pos=%u client.mss=%u server.mss=%u client.wsize=%u:%d server.wsize=%u:%d", + t->track.pos.client.seq0, t->track.pos.client.seq_last - t->track.pos.client.seq0, t->track.pos.client.pos - t->track.pos.client.seq0, + t->track.pos.server.seq0, t->track.pos.server.seq_last - t->track.pos.server.seq0, t->track.pos.server.pos - t->track.pos.server.seq0, + t->track.pos.client.mss, t->track.pos.server.mss, + t->track.pos.client.winsize, t->track.pos.client.scale == SCALE_NONE ? -1 : t->track.pos.client.scale, + t->track.pos.server.winsize, t->track.pos.server.scale == SCALE_NONE ? -1 : t->track.pos.server.scale); else - printf("rseq=%u pos_orig=%u rack=%u pos_reply=%u", - t->track.pos.seq_last, t->track.pos.pos_orig, - t->track.pos.ack_last, t->track.pos.pos_reply); + printf("rseq=%u client.pos=%u rack=%u server.pos=%u", + t->track.pos.client.seq_last, t->track.pos.client.pos, + t->track.pos.server.seq_last, t->track.pos.server.pos); printf(" req_retrans=%u cutoff=%u lua_in_cutoff=%u lua_out_cutoff=%u hostname=%s l7proto=%s\n", t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_lua_in_cutoff, t->track.b_lua_out_cutoff, t->track.hostname, l7proto_str(t->track.l7proto)); }; diff --git a/nfq2/conntrack.h b/nfq2/conntrack.h index aeb3392..ba8e606 100644 --- a/nfq2/conntrack.h +++ b/nfq2/conntrack.h @@ -54,8 +54,10 @@ typedef struct bool bCheckDone, bCheckResult, bCheckExcluded; // hostlist check result cache uint8_t ipproto; + time_t t_start; + // this block of data can change between delayed (queued) packets. need to remeber this data for each packet for further replay - t_ctrack_position pos; + t_ctrack_positions pos; struct desync_profile *dp; // desync profile cache bool dp_search_complete; @@ -78,7 +80,7 @@ typedef struct int lua_state; // registry index of associated LUA object int lua_instance_cutoff; // registry index of per connection function instance cutoff table - t_reassemble reasm_orig; + t_reassemble reasm_client; struct rawpacket_tailhead delayed; } t_ctrack; diff --git a/nfq2/conntrack_base.h b/nfq2/conntrack_base.h index 68883d2..ec7f64d 100644 --- a/nfq2/conntrack_base.h +++ b/nfq2/conntrack_base.h @@ -14,21 +14,26 @@ typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate; typedef struct { - time_t t_last, t_start; - - uint64_t pcounter_orig, pcounter_reply; // packet counter - uint64_t pdcounter_orig, pdcounter_reply; // data packet counter (with payload) - uint64_t pbcounter_orig, pbcounter_reply; // transferred byte counter. includes retransmissions. it's not the same as relative seq. - uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current - uint32_t uppos_orig, uppos_reply; // max seen position. useful to detect retransmissions - uint32_t uppos_orig_prev, uppos_reply_prev; // previous max seen position. useful to detect retransmissions - uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current + uint64_t pcounter; // packet counter + uint64_t pdcounter; // data packet counter (with payload) + uint64_t pbcounter; // transferred byte counter. includes retransmissions. it's not the same as relative seq. + uint32_t pos; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current + uint32_t uppos; // max seen position. useful to detect retransmissions + uint32_t uppos_prev; // previous max seen position. useful to detect retransmissions + uint32_t seq_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current // tcp only state, not used in udp - t_connstate state; - uint32_t seq0, ack0; // starting seq and ack - uint16_t winsize_orig, winsize_reply; // last seen window size - uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none - uint32_t winsize_orig_calc, winsize_reply_calc; // calculated window size - uint16_t mss_orig, mss_reply; + uint32_t seq0; // starting seq and ack + uint16_t winsize; // last seen window size + uint8_t scale; // last seen window scale factor. SCALE_NONE if none + uint32_t winsize_calc; // calculated window size + uint16_t mss; } t_ctrack_position; + +typedef struct +{ + time_t t_last; + t_connstate state; + t_ctrack_position client, server; +} +t_ctrack_positions; diff --git a/nfq2/desync.c b/nfq2/desync.c index 610bcc5..5c6009a 100644 --- a/nfq2/desync.c +++ b/nfq2/desync.c @@ -240,9 +240,9 @@ static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const ch } } -static bool is_retransmission(const t_ctrack *ctrack) +static bool is_retransmission(const t_ctrack_position *pos) { - return !((ctrack->pos.uppos_orig_prev - ctrack->pos.pos_orig) & 0x80000000); + return !((pos->uppos_prev - pos->pos) & 0x80000000); } // return true if retrans trigger fires @@ -254,15 +254,15 @@ static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int thresho { if (ctrack->retrans_detect_finalized) return false; - if (!seq_within(ctrack->pos.seq_last, ctrack->pos.seq0, ctrack->pos.seq0 + ctrack->dp->hostlist_auto_retrans_maxseq)) + if (!seq_within(ctrack->pos.client.seq_last, ctrack->pos.client.seq0, ctrack->pos.client.seq0 + ctrack->dp->hostlist_auto_retrans_maxseq)) { ctrack->retrans_detect_finalized = true; - DLOG("retrans : tcp seq %u not within the req range %u-%u. stop tracking.\n", ctrack->pos.seq_last, ctrack->pos.seq0, ctrack->pos.seq0 + ctrack->dp->hostlist_auto_retrans_maxseq); + DLOG("retrans : tcp seq %u not within the req range %u-%u. stop tracking.\n", ctrack->pos.client.seq_last, ctrack->pos.client.seq0, ctrack->pos.client.seq0 + ctrack->dp->hostlist_auto_retrans_maxseq); ctrack_stop_retrans_counter(ctrack); auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname, client_ip_port, l7proto); return false; } - if (!is_retransmission(ctrack)) + if (!is_retransmission(&ctrack->pos.client)) return false; } ctrack->req_retrans_counter++; @@ -353,23 +353,22 @@ static bool send_delayed(t_ctrack *ctrack) return true; } -static bool rawpacket_queue_csum_fix(struct rawpacket_tailhead *q, const struct dissect *dis, const t_ctrack_position *pos, const struct sockaddr_storage* dst, uint32_t fwmark, uint32_t desync_fwmark, const char *ifin, const char *ifout) +static bool rawpacket_queue_csum_fix(struct rawpacket_tailhead *q, const struct dissect *dis, const t_ctrack_positions *tpos, const struct sockaddr_storage* dst, uint32_t fwmark, uint32_t desync_fwmark, const char *ifin, const char *ifout) { // this breaks const pointer to l4 header if (dis->tcp) verdict_tcp_csum_fix(VERDICT_PASS, (struct tcphdr *)dis->tcp, dis->transport_len, dis->ip, dis->ip6); else if (dis->udp) verdict_udp_csum_fix(VERDICT_PASS, (struct udphdr *)dis->udp, dis->transport_len, dis->ip, dis->ip6); - return rawpacket_queue(q, dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, pos); + return rawpacket_queue(q, dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, tpos); } -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) +static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, uint32_t seq, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload) { ReasmClear(reasm); if (sz <= szMax) { - uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->pos.seq_last : 0; if (ReasmInit(reasm, sz, seq)) { ReasmFeed(reasm, seq, data_payload, len_payload); @@ -383,15 +382,15 @@ static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, si DLOG("unexpected large payload for reassemble: size=%zu\n", sz); return false; } -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) +static bool reasm_client_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, proto, sz, szMax, data_payload, len_payload); + if (!ctrack) return false; + return reasm_start(ctrack, &ctrack->reasm_client, proto, (proto == IPPROTO_TCP) ? ctrack->pos.client.seq_last : 0, 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, uint32_t seq, const uint8_t *data_payload, size_t len_payload) { if (ctrack && !ReasmIsEmpty(reasm)) { - uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->pos.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); @@ -406,29 +405,30 @@ static bool reasm_feed(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, con } return false; } -static bool reasm_orig_feed(t_ctrack *ctrack, uint8_t proto, const uint8_t *data_payload, size_t len_payload) +static bool reasm_client_feed(t_ctrack *ctrack, uint8_t proto, const uint8_t *data_payload, size_t len_payload) { - return reasm_feed(ctrack, &ctrack->reasm_orig, proto, data_payload, len_payload); + if (!ctrack) return false; + return reasm_feed(ctrack, &ctrack->reasm_client, proto, (proto == IPPROTO_TCP) ? ctrack->pos.client.seq_last : (uint32_t)ctrack->reasm_client.size_present, data_payload, len_payload); } -static void reasm_orig_stop(t_ctrack *ctrack, const char *dlog_msg) +static void reasm_client_stop(t_ctrack *ctrack, const char *dlog_msg) { if (ctrack) { - if (!ReasmIsEmpty(&ctrack->reasm_orig)) + if (!ReasmIsEmpty(&ctrack->reasm_client)) { DLOG("%s", dlog_msg); - ReasmClear(&ctrack->reasm_orig); + ReasmClear(&ctrack->reasm_client); } send_delayed(ctrack); } } -static void reasm_orig_cancel(t_ctrack *ctrack) +static void reasm_client_cancel(t_ctrack *ctrack) { - reasm_orig_stop(ctrack, "reassemble session cancelled\n"); + reasm_client_stop(ctrack, "reassemble session cancelled\n"); } -static void reasm_orig_fin(t_ctrack *ctrack) +static void reasm_client_fin(t_ctrack *ctrack) { - reasm_orig_stop(ctrack, "reassemble session finished\n"); + reasm_client_stop(ctrack, "reassemble session finished\n"); } @@ -438,7 +438,7 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, const struct dissect * // if used in postnat chain, dropping initial packet will cause conntrack connection teardown // so we need to workaround this. // SYN and SYN,ACK checks are for conntrack-less mode - if (ctrack && (params.server ? ctrack->pos.pcounter_reply : ctrack->pos.pcounter_orig) == 1 || dis->tcp && (tcp_syn_segment(dis->tcp) || tcp_synack_segment(dis->tcp))) + if (ctrack && (params.server ? ctrack->pos.server.pcounter : ctrack->pos.client.pcounter) == 1 || dis->tcp && (tcp_syn_segment(dis->tcp) || tcp_synack_segment(dis->tcp))) { if (dis->len_pkt > *len_mod_pkt) DLOG_ERR("linux postnat conntrack workaround cannot be applied\n"); @@ -467,21 +467,22 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, const struct dissect * } -static uint64_t pos_get(const t_ctrack_position *pos, char mode, bool bReply) +static uint64_t pos_get(const t_ctrack_position *pos, char mode) { if (pos) { switch (mode) { - case 'n': return bReply ? pos->pcounter_reply : pos->pcounter_orig; - case 'd': return bReply ? pos->pdcounter_reply : pos->pdcounter_orig; - case 's': return bReply ? (pos->ack_last - pos->ack0) : (pos->seq_last - pos->seq0); - case 'b': return bReply ? pos->pbcounter_reply : pos->pbcounter_orig; + case 'n': return pos->pcounter; + case 'd': return pos->pdcounter; + case 's': return pos->seq_last - pos->seq0; + case 'p': return pos->pos - pos->seq0; + case 'b': return pos->pbcounter; } } return 0; } -static bool check_pos_from(const t_ctrack_position *pos, bool bReply, const struct packet_range *range) +static bool check_pos_from(const t_ctrack_position *pos, const struct packet_range *range) { uint64_t ps; if (range->from.mode == 'x') return false; @@ -489,7 +490,7 @@ static bool check_pos_from(const t_ctrack_position *pos, bool bReply, const stru { if (pos) { - ps = pos_get(pos, range->from.mode, bReply); + ps = pos_get(pos, range->from.mode); return ps >= range->from.pos; } else @@ -497,7 +498,7 @@ static bool check_pos_from(const t_ctrack_position *pos, bool bReply, const stru } return true; } -static bool check_pos_to(const t_ctrack_position *pos, bool bReply, const struct packet_range *range) +static bool check_pos_to(const t_ctrack_position *pos, const struct packet_range *range) { uint64_t ps; if (range->to.mode == 'x') return false; @@ -505,7 +506,7 @@ static bool check_pos_to(const t_ctrack_position *pos, bool bReply, const struct { if (pos) { - ps = pos_get(pos, range->to.mode, bReply); + ps = pos_get(pos, range->to.mode); return (ps < range->to.pos) || !range->upper_cutoff && (ps == range->to.pos); } else @@ -513,14 +514,14 @@ static bool check_pos_to(const t_ctrack_position *pos, bool bReply, const struct } return true; } -static bool check_pos_cutoff(const t_ctrack_position *pos, bool bReply, const struct packet_range *range) +static bool check_pos_cutoff(const t_ctrack_position *pos, const struct packet_range *range) { - bool bto = check_pos_to(pos, bReply, range); - return pos ? !bto : (!bto || !check_pos_from(pos, bReply, range)); + bool bto = check_pos_to(pos, range); + return pos ? !bto : (!bto || !check_pos_from(pos, range)); } -static bool check_pos_range(const t_ctrack_position *pos, bool bReply, const struct packet_range *range) +static bool check_pos_range(const t_ctrack_position *pos, const struct packet_range *range) { - return check_pos_from(pos, bReply, range) && check_pos_to(pos, bReply, range); + return check_pos_from(pos, range) && check_pos_to(pos, range); } @@ -654,7 +655,7 @@ static uint8_t desync( const char *ifout, bool bIncoming, t_ctrack *ctrack, - const t_ctrack_position *pos, + const t_ctrack_positions *tpos, t_l7payload l7payload, t_l7proto l7proto, const struct dissect *dis, @@ -672,6 +673,7 @@ static uint8_t desync( struct packet_range *range; size_t l; char instance[256]; + const t_ctrack_position *pos, *rpos; if (ctrack) { @@ -686,8 +688,10 @@ static uint8_t desync( DLOG("lua out cutoff\n"); return verdict; } - if (!pos) pos = &ctrack->pos; + if (!tpos) tpos = &ctrack->pos; } + pos = tpos ? (bIncoming ^ params.server) ? &tpos->server : &tpos->client : NULL; + rpos = tpos ? (bIncoming ^ params.server) ? &tpos->client : &tpos->server : NULL; LUA_STACK_GUARD_ENTER(params.L) @@ -709,12 +713,12 @@ static uint8_t desync( { if (lua_instance_cutoff_check(&ctx, bIncoming)) DLOG("* lua '%s' : voluntary cutoff\n", instance); - else if (check_pos_cutoff(pos, bIncoming, range)) + else if (check_pos_cutoff(pos, range)) { DLOG("* lua '%s' : %s pos %c%llu %c%llu is beyond range %c%u%c%c%u (ctrack %s)\n", instance, sDirection, - range->from.mode, pos_get(pos, range->from.mode, bIncoming), - range->to.mode, pos_get(pos, range->to.mode, bIncoming), + range->from.mode, pos_get(pos, range->from.mode), + range->to.mode, pos_get(pos, range->to.mode), range->from.mode, range->from.pos, range->upper_cutoff ? '<' : '-', range->to.mode, range->to.pos, @@ -737,7 +741,7 @@ static uint8_t desync( // create arg table that persists across multiple desync function calls lua_newtable(params.L); lua_pushf_dissect(dis); - lua_pushf_ctrack(ctrack, pos); + lua_pushf_ctrack(ctrack, tpos, bIncoming); lua_pushf_int("profile_n", dp->n); if (dp->name) lua_pushf_str("profile_name", dp->name); if (dp->n_tpl) lua_pushf_int("template_n", dp->n_tpl); @@ -769,8 +773,8 @@ static uint8_t desync( if (dis->tcp) { // recommended mss value for generated packets - if (pos && pos->mss_orig) - lua_pushf_int("tcp_mss", pos->mss_orig); + if (rpos && rpos->mss) + lua_pushf_int("tcp_mss", rpos->mss); else lua_pushf_global("tcp_mss", "DEFAULT_MSS"); } @@ -786,12 +790,12 @@ static uint8_t desync( if (!lua_instance_cutoff_check(&ctx, bIncoming)) { range = bIncoming ? &func->range_in : &func->range_out; - if (check_pos_range(pos, bIncoming, range)) + if (check_pos_range(pos, range)) { DLOG("* lua '%s' : %s pos %c%llu %c%llu in range %c%u%c%c%u\n", instance, sDirection, - range->from.mode, pos_get(pos, range->from.mode, bIncoming), - range->to.mode, pos_get(pos, range->to.mode, bIncoming), + range->from.mode, pos_get(pos, range->from.mode), + range->to.mode, pos_get(pos, range->to.mode), range->from.mode, range->from.pos, range->upper_cutoff ? '<' : '-', range->to.mode, range->to.pos); @@ -836,8 +840,8 @@ static uint8_t desync( else DLOG("* lua '%s' : %s pos %c%llu %c%llu out of range %c%u%c%c%u\n", instance, sDirection, - range->from.mode, pos_get(pos, range->from.mode, bIncoming), - range->to.mode, pos_get(pos, range->to.mode, bIncoming), + range->from.mode, pos_get(pos, range->from.mode), + range->to.mode, pos_get(pos, range->to.mode), range->from.mode, range->from.pos, range->upper_cutoff ? '<' : '-', range->to.mode, range->to.pos); @@ -936,7 +940,7 @@ static uint8_t dpi_desync_tcp_packet_play( unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, - const t_ctrack_position *pos, + const t_ctrack_positions *tpos, const struct dissect *dis, uint8_t *mod_pkt, size_t *len_mod_pkt) { @@ -1093,7 +1097,7 @@ static uint8_t dpi_desync_tcp_packet_play( // process reply packets for auto hostlist mode // 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 - if (!params.server && ctrack && ctrack->hostname && ctrack->hostname_ah_check && (ctrack->pos.ack_last - ctrack->pos.ack0) == 1) + if (!params.server && ctrack && ctrack->hostname && ctrack->hostname_ah_check && (ctrack->pos.server.seq_last - ctrack->pos.server.seq0) == 1) { bool bFail = false; @@ -1149,13 +1153,13 @@ static uint8_t dpi_desync_tcp_packet_play( if (replay_piece_count) { - rdata_payload = ctrack_replay->reasm_orig.packet; - rlen_payload = ctrack_replay->reasm_orig.size_present; + rdata_payload = ctrack_replay->reasm_client.packet; + rlen_payload = ctrack_replay->reasm_client.size_present; } - else if (reasm_orig_feed(ctrack, IPPROTO_TCP, dis->data_payload, dis->len_payload)) + else if (reasm_client_feed(ctrack, IPPROTO_TCP, dis->data_payload, dis->len_payload)) { - rdata_payload = ctrack->reasm_orig.packet; - rlen_payload = ctrack->reasm_orig.size_present; + rdata_payload = ctrack->reasm_client.packet; + rlen_payload = ctrack->reasm_client.size_present; } process_retrans_fail(ctrack, IPPROTO_TCP, (struct sockaddr*)&src); @@ -1170,7 +1174,7 @@ static uint8_t dpi_desync_tcp_packet_play( } // we do not reassemble http - reasm_orig_cancel(ctrack); + reasm_client_cancel(ctrack); bHaveHost = HttpExtractHost(rdata_payload, rlen_payload, host, sizeof(host)); if (!bHaveHost) @@ -1196,14 +1200,14 @@ static uint8_t dpi_desync_tcp_packet_play( if (ctrack && !(params.reasm_payload_disable && l7_payload_match(l7payload, params.reasm_payload_disable))) { // do not reasm retransmissions - if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_orig) && !is_retransmission(ctrack)) + if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_client) && !is_retransmission(&ctrack->pos.client)) { // do not reconstruct unexpected large payload (they are feeding garbage ?) - if (!reasm_orig_start(ctrack, IPPROTO_TCP, TLSRecordLen(dis->data_payload), TCP_MAX_REASM, dis->data_payload, dis->len_payload)) + if (!reasm_client_start(ctrack, IPPROTO_TCP, TLSRecordLen(dis->data_payload), TCP_MAX_REASM, dis->data_payload, dis->len_payload)) goto pass_reasm_cancel; } - if (!ReasmIsEmpty(&ctrack->reasm_orig)) + if (!ReasmIsEmpty(&ctrack->reasm_client)) { if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout)) { @@ -1214,16 +1218,16 @@ static uint8_t dpi_desync_tcp_packet_play( DLOG_ERR("rawpacket_queue failed !\n"); goto pass_reasm_cancel; } - if (ReasmIsFull(&ctrack->reasm_orig)) + if (ReasmIsFull(&ctrack->reasm_client)) { replay_queue(&ctrack->delayed); - reasm_orig_fin(ctrack); + reasm_client_fin(ctrack); } return VERDICT_DROP; } } } - else if (ctrack && (ctrack->pos.seq_last - ctrack->pos.seq0)==1 && IsMTProto(dis->data_payload, dis->len_payload)) + else if (ctrack && (ctrack->pos.client.seq_last - ctrack->pos.client.seq0)==1 && IsMTProto(dis->data_payload, dis->len_payload)) { DLOG("packet contains telegram mtproto2 initial\n"); // mtproto detection requires aes. react only on the first tcp data packet. do not detect if ctrack unavailable. @@ -1343,19 +1347,19 @@ static uint8_t dpi_desync_tcp_packet_play( ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2)); DLOG("dpi desync src=%s dst=%s track_direction=%s fixed_direction=%s connection_proto=%s payload_type=%s\n", s1, s2, bReverse ? "in" : "out", bReverseFixed ? "in" : "out", l7proto_str(l7proto), l7payload_str(l7payload)); } - verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, pos, l7payload, l7proto, dis, sdip4, sdip6, sdport, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, rdata_payload, rlen_payload, NULL, 0); + verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, tpos, l7payload, l7proto, dis, sdip4, sdip6, sdport, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, rdata_payload, rlen_payload, NULL, 0); pass: return (!bReverseFixed && (verdict & VERDICT_MASK) == VERDICT_DROP) ? ct_new_postnat_fix(ctrack, dis, mod_pkt, len_mod_pkt) : verdict; pass_reasm_cancel: - reasm_orig_cancel(ctrack); + reasm_client_cancel(ctrack); goto pass; } // return : true - should continue, false - should stop with verdict static void quic_reasm_cancel(t_ctrack *ctrack, const char *reason) { - reasm_orig_cancel(ctrack); + reasm_client_cancel(ctrack); DLOG("%s\n", reason); } @@ -1364,7 +1368,7 @@ static uint8_t dpi_desync_udp_packet_play( unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, - const t_ctrack_position *pos, + const t_ctrack_positions *tpos, const struct dissect *dis, uint8_t *mod_pkt, size_t *len_mod_pkt) { @@ -1550,8 +1554,8 @@ static uint8_t dpi_desync_udp_packet_play( if (replay_piece_count) { - clean_len = ctrack_replay->reasm_orig.size_present; - pclean = ctrack_replay->reasm_orig.packet; + clean_len = ctrack_replay->reasm_client.size_present; + pclean = ctrack_replay->reasm_client.packet; } else { @@ -1561,13 +1565,13 @@ static uint8_t dpi_desync_udp_packet_play( if (pclean) { bool reasm_disable = params.reasm_payload_disable && l7_payload_match(l7payload, params.reasm_payload_disable); - if (ctrack && !reasm_disable && !ReasmIsEmpty(&ctrack->reasm_orig)) + if (ctrack && !reasm_disable && !ReasmIsEmpty(&ctrack->reasm_client)) { - if (ReasmHasSpace(&ctrack->reasm_orig, clean_len)) + if (ReasmHasSpace(&ctrack->reasm_client, clean_len)) { - reasm_orig_feed(ctrack, IPPROTO_UDP, clean, clean_len); - pclean = ctrack->reasm_orig.packet; - clean_len = ctrack->reasm_orig.size_present; + reasm_client_feed(ctrack, IPPROTO_UDP, clean, clean_len); + pclean = ctrack->reasm_client.packet; + clean_len = ctrack->reasm_client.size_present; } else { @@ -1592,13 +1596,13 @@ static uint8_t dpi_desync_udp_packet_play( if (ctrack && !reasm_disable) { - if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig)) + if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_client)) { // preallocate max buffer to avoid reallocs that cause memory copy - if (!reasm_orig_start(ctrack, IPPROTO_UDP, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len)) + if (!reasm_client_start(ctrack, IPPROTO_UDP, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len)) goto pass_reasm_cancel; } - if (!ReasmIsEmpty(&ctrack->reasm_orig)) + if (!ReasmIsEmpty(&ctrack->reasm_client)) { if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout)) { @@ -1612,7 +1616,7 @@ static uint8_t dpi_desync_udp_packet_play( if (bReqFull) { replay_queue(&ctrack->delayed); - reasm_orig_fin(ctrack); + reasm_client_fin(ctrack); } return ct_new_postnat_fix(ctrack, dis, mod_pkt, len_mod_pkt); } @@ -1634,10 +1638,10 @@ static uint8_t dpi_desync_udp_packet_play( DLOG("QUIC initial contains CRYPTO with partial fragment coverage\n"); if (ctrack && !reasm_disable) { - if (ReasmIsEmpty(&ctrack->reasm_orig)) + if (ReasmIsEmpty(&ctrack->reasm_client)) { // preallocate max buffer to avoid reallocs that cause memory copy - if (!reasm_orig_start(ctrack, IPPROTO_UDP, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len)) + if (!reasm_client_start(ctrack, IPPROTO_UDP, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len)) goto pass_reasm_cancel; } if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout)) @@ -1671,7 +1675,7 @@ static uint8_t dpi_desync_udp_packet_play( // received payload without host. it means we are out of the request retransmission phase. stop counter ctrack_stop_retrans_counter(ctrack); - reasm_orig_cancel(ctrack); + reasm_client_cancel(ctrack); t_protocol_probe testers[] = { {L7P_DISCORD_IP_DISCOVERY,L7_DISCORD,IsDiscordIpDiscoveryRequest,false}, @@ -1799,12 +1803,12 @@ static uint8_t dpi_desync_udp_packet_play( ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2)); DLOG("dpi desync src=%s dst=%s track_direction=%s fixed_direction=%s connection_proto=%s payload_type=%s\n", s1, s2, bReverse ? "in" : "out", bReverseFixed ? "in" : "out", l7proto_str(l7proto), l7payload_str(l7payload)); } - verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, pos, l7payload, l7proto, dis, sdip4, sdip6, sdport, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, NULL, 0, data_decrypt, len_decrypt); + verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, tpos, l7payload, l7proto, dis, sdip4, sdip6, sdport, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, NULL, 0, data_decrypt, len_decrypt); pass: return (!bReverse && (verdict & VERDICT_MASK) == VERDICT_DROP) ? ct_new_postnat_fix(ctrack, dis, mod_pkt, len_mod_pkt) : verdict; pass_reasm_cancel: - reasm_orig_cancel(ctrack); + reasm_client_cancel(ctrack); goto pass; } @@ -1848,7 +1852,7 @@ static void packet_debug(bool replay, const struct dissect *dis) static uint8_t dpi_desync_packet_play( unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, - const t_ctrack_position *pos, + const t_ctrack_positions *tpos, const uint8_t *data_pkt, size_t len_pkt, uint8_t *mod_pkt, size_t *len_mod_pkt) { @@ -1864,7 +1868,7 @@ static uint8_t dpi_desync_packet_play( case IPPROTO_TCP: if (dis.tcp) { - verdict = dpi_desync_tcp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, pos, &dis, mod_pkt, len_mod_pkt); + verdict = dpi_desync_tcp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, tpos, &dis, mod_pkt, len_mod_pkt); // we fix csum before pushing to replay queue if (!replay_piece_count) verdict_tcp_csum_fix(verdict, (struct tcphdr *)dis.tcp, dis.transport_len, dis.ip, dis.ip6); } @@ -1872,7 +1876,7 @@ static uint8_t dpi_desync_packet_play( case IPPROTO_UDP: if (dis.udp) { - verdict = dpi_desync_udp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, pos, &dis, mod_pkt, len_mod_pkt); + verdict = dpi_desync_udp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, tpos, &dis, mod_pkt, len_mod_pkt); // we fix csum before pushing to replay queue if (!replay_piece_count) verdict_udp_csum_fix(verdict, (struct udphdr *)dis.udp, dis.transport_len, dis.ip, dis.ip6); } @@ -1902,7 +1906,7 @@ static bool replay_queue(struct rawpacket_tailhead *q) { DLOG("REPLAYING delayed packet #%u offset %zu\n", i+1, offset); modlen = sizeof(mod); - uint8_t verdict = dpi_desync_packet_play(i, count, offset, rp->fwmark_orig, rp->ifin, rp->ifout, rp->pos_present ? &rp->pos : NULL, rp->packet, rp->len, mod, &modlen); + uint8_t verdict = dpi_desync_packet_play(i, count, offset, rp->fwmark_orig, rp->ifin, rp->ifout, rp->tpos_present ? &rp->tpos : NULL, rp->packet, rp->len, mod, &modlen); switch (verdict & VERDICT_MASK) { case VERDICT_MODIFY: diff --git a/nfq2/helpers.c b/nfq2/helpers.c index e2eff2e..f98b97a 100644 --- a/nfq2/helpers.c +++ b/nfq2/helpers.c @@ -514,7 +514,7 @@ bool pf_is_empty(const port_filter *pf) bool packet_pos_parse(const char *s, struct packet_pos *pos) { - if (*s!='n' && *s!='d' && *s!='s' && *s!='b' && *s!='x' && *s!='a') return false; + if (*s!='n' && *s!='d' && *s!='s' && *s!='p' && *s!='b' && *s!='x' && *s!='a') return false; pos->mode=*s; if (pos->mode=='x' || pos->mode=='a') { diff --git a/nfq2/lua.c b/nfq2/lua.c index 3fab0a9..8ed2258 100644 --- a/nfq2/lua.c +++ b/nfq2/lua.c @@ -1260,23 +1260,44 @@ void lua_pushf_dissect(const struct dissect *dis) lua_rawset(params.L,-3); } -void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_position *pos) +void lua_pushf_ctrack_pos(const t_ctrack *ctrack, const t_ctrack_position *pos) { LUA_STACK_GUARD_ENTER(params.L) - if (!pos) pos = &ctrack->pos; + lua_pushf_lint("pcounter", pos->pcounter); + lua_pushf_lint("pdcounter", pos->pdcounter); + lua_pushf_lint("pbcounter", pos->pbcounter); + if (ctrack->ipproto == IPPROTO_TCP) + { + lua_pushliteral(params.L, "tcp"); + lua_createtable(params.L, 0, 10); + lua_pushf_lint("seq0", pos->seq0); + lua_pushf_lint("seq", pos->seq_last); + lua_pushf_lint("rseq", pos->seq_last - pos->seq0); + lua_pushf_int("pos", pos->pos - pos->seq0); + lua_pushf_int("uppos", pos->uppos - pos->seq0); + lua_pushf_int("uppos_prev", pos->uppos_prev - pos->seq0); + lua_pushf_int("winsize", pos->winsize); + lua_pushf_int("winsize_calc", pos->winsize_calc); + lua_pushf_int("scale", pos->scale); + lua_pushf_int("mss", pos->mss); + lua_rawset(params.L,-3); + } + + LUA_STACK_GUARD_LEAVE(params.L, 0) +} + +void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_positions *tpos, bool bIncoming) +{ + LUA_STACK_GUARD_ENTER(params.L) + + if (!tpos) tpos = &ctrack->pos; lua_pushliteral(params.L, "track"); if (ctrack) { - lua_createtable(params.L, 0, 13 + (ctrack->ipproto == IPPROTO_TCP)); + lua_createtable(params.L, 0, 9); - lua_pushf_lint("pcounter_orig", pos->pcounter_orig); - lua_pushf_lint("pdcounter_orig", pos->pdcounter_orig); - lua_pushf_lint("pbcounter_orig", pos->pbcounter_orig); - lua_pushf_lint("pcounter_reply", pos->pcounter_reply); - lua_pushf_lint("pdcounter_reply", pos->pdcounter_reply); - lua_pushf_lint("pbcounter_reply", pos->pbcounter_reply); if (ctrack->incoming_ttl) lua_pushf_int("incoming_ttl", ctrack->incoming_ttl); else @@ -1287,31 +1308,36 @@ void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_position *pos) lua_pushf_reg("lua_state", ctrack->lua_state); lua_pushf_bool("lua_in_cutoff", ctrack->b_lua_in_cutoff); lua_pushf_bool("lua_out_cutoff", ctrack->b_lua_out_cutoff); + lua_pushf_lint("t_start", ctrack->t_start); - if (ctrack->ipproto == IPPROTO_TCP) - { - lua_pushliteral(params.L, "tcp"); - lua_createtable(params.L, 0, 18); - lua_pushf_lint("seq0", pos->seq0); - lua_pushf_lint("seq", pos->seq_last); - lua_pushf_lint("ack0", pos->ack0); - lua_pushf_lint("ack", pos->ack_last); - lua_pushf_int("pos_orig", pos->pos_orig - pos->seq0); - lua_pushf_int("uppos_orig", pos->uppos_orig - pos->seq0); - lua_pushf_int("uppos_orig_prev", pos->uppos_orig_prev - pos->seq0); - lua_pushf_int("winsize_orig", pos->winsize_orig); - lua_pushf_int("winsize_orig_calc", pos->winsize_orig_calc); - lua_pushf_int("scale_orig", pos->scale_orig); - lua_pushf_int("mss_orig", pos->mss_orig); - lua_pushf_int("pos_reply", pos->pos_reply - pos->ack0); - lua_pushf_int("uppos_reply", pos->uppos_reply - pos->ack0); - lua_pushf_int("uppos_reply_prev", pos->uppos_reply_prev - pos->ack0); - lua_pushf_int("winsize_reply", pos->winsize_reply); - lua_pushf_int("winsize_reply_calc", pos->winsize_reply_calc); - lua_pushf_int("scale_reply", pos->scale_reply); - lua_pushf_int("mss_reply", pos->mss_reply); - lua_rawset(params.L,-3); - } + lua_pushliteral(params.L, "pos"); + lua_createtable(params.L, 0, 5); + + // orig, reply related to connection logical direction + // for tcp orig is client (who connects), reply is server (who listens). + // for orig is the first seen party, reply is another party + lua_pushf_lint("dt", tpos->t_last - ctrack->t_start); + + lua_pushliteral(params.L, "client"); + lua_newtable(params.L); + lua_pushf_ctrack_pos(ctrack, &tpos->client); + lua_rawset(params.L,-3); + + lua_pushliteral(params.L, "server"); + lua_newtable(params.L); + lua_pushf_ctrack_pos(ctrack, &tpos->server); + lua_rawset(params.L,-3); + + // direct and reverse are adjusted for server mode. in server mode orig and reply are exchanged. + lua_pushliteral(params.L, "direct"); + lua_getfield(params.L, -2, (params.server ^ bIncoming) ? "server" : "client"); + lua_rawset(params.L,-3); + + lua_pushliteral(params.L, "reverse"); + lua_getfield(params.L, -2, (params.server ^ bIncoming) ? "client" : "server"); + lua_rawset(params.L,-3); + + lua_rawset(params.L,-3); } else lua_pushnil(params.L); diff --git a/nfq2/lua.h b/nfq2/lua.h index ec62d0b..4aa1685 100644 --- a/nfq2/lua.h +++ b/nfq2/lua.h @@ -34,6 +34,7 @@ #endif // pushing and not popping inside luacall cause memory leak +// these macros ensure correct stack position or throw error if not #define LUA_STACK_GUARD_ENTER(L) int _lsg=lua_gettop(L); #define LUA_STACK_GUARD_LEAVE(L,N) if ((_lsg+N)!=lua_gettop(L)) luaL_error(L,"stack guard failure"); #define LUA_STACK_GUARD_RETURN(L,N) LUA_STACK_GUARD_LEAVE(L,N); return N; @@ -86,8 +87,8 @@ void lua_pushf_iphdr(const struct ip *ip, size_t len); void lua_pushf_ip6hdr(const struct ip6_hdr *ip6, size_t len); void lua_push_dissect(const struct dissect *dis); void lua_pushf_dissect(const struct dissect *dis); -void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_position *pos); -void lua_pushf_args(const struct str2_list_head *args, int idx_desync); +void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_positions *tpos, bool bIncoming); +void lua_pushf_args(const struct str2_list_head *args, int idx_desync, bool subst_prefix); void lua_pushf_pos(const char *name, const struct packet_pos *pos); void lua_pushf_range(const char *name, const struct packet_range *range); void lua_pushf_global(const char *field, const char *global); diff --git a/nfq2/nfqws.c b/nfq2/nfqws.c index 235e70f..5c4cfcf 100644 --- a/nfq2/nfqws.c +++ b/nfq2/nfqws.c @@ -1438,8 +1438,8 @@ static void exithelp(void) " --hostlist-auto-debug=\t\t\t; debug auto hostlist positives (global parameter)\n" "\nLUA PACKET PASS MODE:\n" " --payload=type[,type]\t\t\t\t\t; set payload types following LUA functions should process : %s\n" - " --out-range=[(n|a|d|s)](-|<)[(n|a|d|s)]\t; set outgoing packet range for following LUA functions. '-' - include end pos, '<' - not include. prefix meaning : n - packet number, d - data packet number, s - relative sequence, b - byte count, x - never, a - always\n" - " --in-range=[(n|a|d|s)](-|<)[(n|a|d|s)]\t; set incoming packet range for following LUA functions. '-' - include end pos, '<' - not include. prefix meaning : n - packet number, d - data packet number, s - relative sequence, b - byte count, x - never, a - always\n" + " --out-range=[(n|a|d|s|p)](-|<)[(n|a|d|s|p)]\t; set outgoing packet range for following LUA functions. '-' - include end pos, '<' - not include. prefix meaning : n - packet number, d - data packet number, s - relative sequence, p - data position relative sequence, b - byte count, x - never, a - always\n" + " --in-range=[(n|a|d|s|p)](-|<)[(n|a|d|s|p)]\t; set incoming packet range for following LUA functions. '-' - include end pos, '<' - not include. prefix meaning : n - packet number, d - data packet number, s - relative sequence, p - data position relative sequence, b - byte count, x - never, a - always\n" "\nLUA DESYNC ACTION:\n" " --lua-desync=[:param1=val1[:param2=val2]]\t; call LUA function when packet received\n", #if defined(__linux__) || defined(SO_USER_COOKIE) diff --git a/nfq2/nfqws.h b/nfq2/nfqws.h index ce69646..ab4fc8b 100644 --- a/nfq2/nfqws.h +++ b/nfq2/nfqws.h @@ -12,4 +12,4 @@ extern bool bQuit; int main(int argc, char *argv[]); // when something changes that can break LUA compatibility this version should be increased -#define LUA_COMPAT_VER 2 +#define LUA_COMPAT_VER 3 diff --git a/nfq2/packet_queue.c b/nfq2/packet_queue.c index 7a7a3ec..a6e428e 100644 --- a/nfq2/packet_queue.c +++ b/nfq2/packet_queue.c @@ -26,7 +26,7 @@ void rawpacket_queue_destroy(struct rawpacket_tailhead *q) while((rp = rawpacket_dequeue(q))) rawpacket_free(rp); } -struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark_orig,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload,const t_ctrack_position *pos) +struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark_orig,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload,const t_ctrack_positions *tpos) { struct rawpacket *rp = malloc(sizeof(struct rawpacket)); if (!rp) return NULL; @@ -54,13 +54,13 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock rp->len_payload=len_payload; // make a copy for replay - if (pos) + if (tpos) { - rp->pos = *pos; - rp->pos_present = true; + rp->tpos = *tpos; + rp->tpos_present = true; } else - rp->pos_present = false; + rp->tpos_present = false; TAILQ_INSERT_TAIL(q, rp, next); diff --git a/nfq2/packet_queue.h b/nfq2/packet_queue.h index 92484e4..bcde1b7 100644 --- a/nfq2/packet_queue.h +++ b/nfq2/packet_queue.h @@ -16,8 +16,8 @@ struct rawpacket uint32_t fwmark; size_t len, len_payload; uint8_t *packet; - t_ctrack_position pos; - bool pos_present; + t_ctrack_positions tpos; + bool tpos_present; TAILQ_ENTRY(rawpacket) next; }; TAILQ_HEAD(rawpacket_tailhead, rawpacket); @@ -26,6 +26,6 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q); void rawpacket_queue_destroy(struct rawpacket_tailhead *q); bool rawpacket_queue_empty(const struct rawpacket_tailhead *q); unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q); -struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark_orig,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload,const t_ctrack_position *pos); +struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark_orig,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload,const t_ctrack_positions *tpos); struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q); void rawpacket_free(struct rawpacket *rp); diff --git a/nfq2/params.h b/nfq2/params.h index 71320ca..6a17904 100644 --- a/nfq2/params.h +++ b/nfq2/params.h @@ -40,7 +40,7 @@ #define BLOB_EXTRA_BYTES 128 // this MSS is used for ipv6 in windows and linux -#define DEFAULT_MSS 1360 +#define DEFAULT_MSS 1220 #define RECONSTRUCT_MAX_SIZE 16384