From cae8264fbf855a722629a1e0402cd1cca9083fe2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 14 Feb 2026 20:44:47 +0000 Subject: [PATCH] Add random range support for dpi-desync-ts-increment Co-authored-by: vemneyy <78843201+vemneyy@users.noreply.github.com> --- docs/readme.en.md | 2 +- docs/readme.md | 2 +- nfq/desync.c | 34 ++++++++++++++++++++------------ nfq/nfqws.c | 49 ++++++++++++++++++++++++++++++++++++++++++++--- nfq/params.h | 2 ++ 5 files changed, 72 insertions(+), 17 deletions(-) diff --git a/docs/readme.en.md b/docs/readme.en.md index a921c645..22742bb7 100644 --- a/docs/readme.en.md +++ b/docs/readme.en.md @@ -209,7 +209,7 @@ nfqws takes the following parameters: --dpi-desync-hostfakesplit-mod=mod[,mod] ; can be none, host=, altorder=0|1 --dpi-desync-ipfrag-pos-tcp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 32. --dpi-desync-ipfrag-pos-udp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 8. - --dpi-desync-ts-increment= ; ts fooling TSval signed increment. default -600000 + --dpi-desync-ts-increment= ; ts fooling TSval signed increment or per-fake random value from range. default -600000 --dpi-desync-badseq-increment= ; badseq fooling seq signed increment. default -10000 --dpi-desync-badack-increment= ; badseq fooling ackseq signed increment. default -66000 --dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet diff --git a/docs/readme.md b/docs/readme.md index 10eb2b09..378c4ccd 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -239,7 +239,7 @@ dvtws, собираемый из тех же исходников (см. [док --dpi-desync-hostfakesplit-mod=mod[,mod] ; может быть none, host=, altorder=0|1 --dpi-desync-ipfrag-pos-tcp=<8..9216> ; позиция ip фрагментации tcp, начиная с транспортного заголовка. должно быть кратно 8, по умолчанию - 32. --dpi-desync-ipfrag-pos-udp=<8..9216> ; позиция ip фрагментации udp, начиная с транспортного заголовка. должно быть кратно 8, по умолчанию - 8. ---dpi-desync-ts-increment= ; инкремент TSval для ts. по умолчанию -600000 +--dpi-desync-ts-increment= ; инкремент TSval для ts или случайное значение из диапазона для каждого фейка. по умолчанию -600000 --dpi-desync-badseq-increment= ; инкремент sequence number для badseq. по умолчанию -10000 --dpi-desync-badack-increment= ; инкремент ack sequence number для badseq. по умолчанию -66000 --dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных diff --git a/nfq/desync.c b/nfq/desync.c index 7d5950b7..a9d35d0f 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -876,6 +876,16 @@ static uint16_t IP4_IP_ID_ADD(uint16_t ip_id, uint16_t inc, t_ip_id_mode mode) #define IP4_IP_ID_NEXT(ip_id,mode) IP4_IP_ID_ADD(ip_id,+1,mode) #define IP4_IP_ID_PREV(ip_id,mode) IP4_IP_ID_ADD(ip_id,-1,mode) +static uint32_t desync_ts_increment(const struct desync_profile *dp) +{ + if (!dp->desync_ts_increment_random) + return dp->desync_ts_increment; + + int64_t span = (int64_t)dp->desync_ts_increment_max - dp->desync_ts_increment_min + 1; + int32_t value = dp->desync_ts_increment_min + (int32_t)(random() % span); + return (uint32_t)value; +} + // fake_mod buffer must at least sizeof(desync_profile->fake_tls) // return : true - altered, false - not altered @@ -1531,7 +1541,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN | TH_ACK, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), - dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, + dp->desync_fooling_mode, desync_ts_increment(dp), dp->desync_badseq_increment, dp->desync_badseq_ack_increment, NULL, 0, pkt1, &pkt1_len)) { goto send_orig; @@ -2085,7 +2095,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_fake, false, 0, htonl(sequence), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), - dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, + dp->desync_fooling_mode, desync_ts_increment(dp), dp->desync_badseq_increment, dp->desync_badseq_ack_increment, fake_data, fake_size, pkt1, &pkt1_len)) { reasm_orig_cancel(ctrack); @@ -2110,7 +2120,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode == DESYNC_RSTACK ? TH_ACK : 0), false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), - dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, + dp->desync_fooling_mode, desync_ts_increment(dp), dp->desync_badseq_increment, dp->desync_badseq_ack_increment, NULL, 0, pkt1, &pkt1_len)) { reasm_orig_cancel(ctrack); @@ -2244,7 +2254,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_fake, false, 0, net32_add(dis->tcp->th_seq, pos_host), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), - dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, + dp->desync_fooling_mode, desync_ts_increment(dp), dp->desync_badseq_increment, dp->desync_badseq_ack_increment, fakehost, host_size, pkt2, &pkt2_len)) goto send_orig_clean; if (dp->ip_id_mode!=IPID_SEQ_GROUP) ip_id = IP4_IP_ID_NEXT(ip_id,dp->ip_id_mode); @@ -2538,7 +2548,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint fakeseg2_len = sizeof(fakeseg2); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_fake, false, 0, net32_add(dis->tcp->th_seq, split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), - dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, + dp->desync_fooling_mode, desync_ts_increment(dp), dp->desync_badseq_increment, dp->desync_badseq_ack_increment, pat + split_pos, dis->len_payload - split_pos, fakeseg2, &fakeseg2_len)) goto send_orig; @@ -2554,7 +2564,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq, split_pos - seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_orig, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), - fooling_orig, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, + fooling_orig, desync_ts_increment(dp), dp->desync_badseq_increment, dp->desync_badseq_ack_increment, seg, seg_len, pkt1, &pkt1_len)) goto send_orig; ip_id = IP4_IP_ID_NEXT(ip_id,dp->ip_id_mode); @@ -2581,7 +2591,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint seg_len = sizeof(fakeseg); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_fake, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), - dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, + dp->desync_fooling_mode, desync_ts_increment(dp), dp->desync_badseq_increment, dp->desync_badseq_ack_increment, pat, split_pos, fakeseg, &seg_len)) goto send_orig; if (dp->ip_id_mode!=IPID_SEQ_GROUP) ip_id = IP4_IP_ID_NEXT(ip_id,dp->ip_id_mode); @@ -2593,7 +2603,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_orig, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), - fooling_orig, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, + fooling_orig, desync_ts_increment(dp), dp->desync_badseq_increment, dp->desync_badseq_ack_increment, dis->data_payload, split_pos, pkt1, &pkt1_len)) goto send_orig; ip_id = IP4_IP_ID_NEXT(ip_id,dp->ip_id_mode); @@ -2650,7 +2660,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint fakeseg_len = sizeof(fakeseg); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_fake, false, 0, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), - dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, + dp->desync_fooling_mode, desync_ts_increment(dp), dp->desync_badseq_increment, dp->desync_badseq_ack_increment, pat, split_pos, fakeseg, &fakeseg_len)) goto send_orig; @@ -2690,7 +2700,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq, -seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_orig, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), - fooling_orig, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, + fooling_orig, desync_ts_increment(dp), dp->desync_badseq_increment, dp->desync_badseq_ack_increment, seg, seg_len, pkt1, &pkt1_len)) goto send_orig; ip_id = IP4_IP_ID_NEXT(ip_id,dp->ip_id_mode); @@ -2729,7 +2739,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint fakeseg_len = sizeof(fakeseg); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_fake, false, 0, net32_add(dis->tcp->th_seq, split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_fake, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), - dp->desync_fooling_mode, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, + dp->desync_fooling_mode, desync_ts_increment(dp), dp->desync_badseq_increment, dp->desync_badseq_ack_increment, pat + split_pos, dis->len_payload - split_pos, fakeseg, &fakeseg_len)) goto send_orig; if (dp->ip_id_mode!=IPID_SEQ_GROUP) ip_id = IP4_IP_ID_NEXT(ip_id,dp->ip_id_mode); @@ -2741,7 +2751,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, false, 0, net32_add(dis->tcp->th_seq, split_pos), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, DF, ttl_orig, IP4_TOS(dis->ip), ip_id, IP6_FLOW(dis->ip6), - fooling_orig, dp->desync_ts_increment, dp->desync_badseq_increment, dp->desync_badseq_ack_increment, + fooling_orig, desync_ts_increment(dp), dp->desync_badseq_increment, dp->desync_badseq_ack_increment, dis->data_payload + split_pos, dis->len_payload - split_pos, pkt1, &pkt1_len)) goto send_orig; ip_id = IP4_IP_ID_NEXT(ip_id,dp->ip_id_mode); diff --git a/nfq/nfqws.c b/nfq/nfqws.c index b648958c..7a2eb463 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -866,6 +867,48 @@ static bool parse_net32_signed(const char *opt, uint32_t *value) return sscanf(opt, "%d", (int32_t*)value) > 0; } } +static bool parse_desync_ts_increment(const char *opt, struct desync_profile *dp) +{ + int sign = 1; + const char *s = opt; + if (*s == '+' || *s == '-') + { + sign = (*s == '-') ? -1 : 1; + s++; + } + bool with_brackets = *s == '('; + if (with_brackets) s++; + + const char *dash = strchr(s, '-'); + if (dash && dash > s && dash[1]) + { + char *e; + long long v0 = strtoll(s, &e, 10); + if (e != dash) return false; + long long v1 = strtoll(dash + 1, &e, 10); + if (with_brackets) + { + if (*e != ')') return false; + e++; + } + if (*e || v0 < 0 || v1 < 0 || v0 > v1 || v1 > INT_MAX) return false; + + dp->desync_ts_increment_random = true; + dp->desync_ts_increment_min = (int32_t)(sign * v0); + dp->desync_ts_increment_max = (int32_t)(sign * v1); + if (dp->desync_ts_increment_min > dp->desync_ts_increment_max) + { + int32_t t = dp->desync_ts_increment_min; + dp->desync_ts_increment_min = dp->desync_ts_increment_max; + dp->desync_ts_increment_max = t; + } + return true; + } + + if (with_brackets) return false; + dp->desync_ts_increment_random = false; + return parse_net32_signed(opt, &dp->desync_ts_increment); +} static void load_file_or_exit(const char *filename, void *buf, size_t *size, size_t *offset) { size_t ofs; @@ -2016,7 +2059,7 @@ static void exithelp(void) " --dpi-desync-hostfakesplit-mod=mod[,mod]\t\t; mods can be none,host=,altorder=0|1\n" " --dpi-desync-ipfrag-pos-udp=<8..%u>\t\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n" " --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n" - " --dpi-desync-ts-increment=\t\t\t; ts fooling TSval signed increment. default %d\n" + " --dpi-desync-ts-increment=\t; ts fooling TSval signed increment or random range per fake. default %d\n" " --dpi-desync-badseq-increment=\t\t; badseq fooling seq signed increment. default %d\n" " --dpi-desync-badack-increment=\t\t; badseq fooling ackseq signed increment. default %d\n" " --dpi-desync-any-protocol=0|1\t\t\t\t; 0(default)=desync only http and tls 1=desync any nonempty data packet\n" @@ -3117,9 +3160,9 @@ int main(int argc, char **argv) } break; case IDX_DPI_DESYNC_TS_INCREMENT: - if (!parse_net32_signed(optarg, &dp->desync_ts_increment)) + if (!parse_desync_ts_increment(optarg, dp)) { - DLOG_ERR("dpi-desync-ts-increment should be signed decimal or signed 0xHEX\n"); + DLOG_ERR("dpi-desync-ts-increment should be signed decimal, signed 0xHEX, [+-](N-M) or N-M\n"); exit_clean(1); } break; diff --git a/nfq/params.h b/nfq/params.h index dd2f1ccb..66391f4b 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -156,6 +156,8 @@ struct desync_profile autottl desync_autottl, desync_autottl6; uint32_t desync_fooling_mode; uint32_t desync_ts_increment, desync_badseq_increment, desync_badseq_ack_increment; + bool desync_ts_increment_random; + int32_t desync_ts_increment_min, desync_ts_increment_max; uint16_t desync_tcp_flags_set, desync_tcp_flags_unset; struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht,fake_discord,fake_stun;