From 656c549113d060eb756c1f2b7b7144430d7dcc41 Mon Sep 17 00:00:00 2001 From: bol-van Date: Mon, 11 Nov 2024 12:39:33 +0300 Subject: [PATCH 01/10] quick_start: uninstall --- docs/quick_start.md | 5 +++++ docs/quick_start_windows.md | 8 ++++++++ 2 files changed, 13 insertions(+) diff --git a/docs/quick_start.md b/docs/quick_start.md index d4699d2..d34a2c2 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -237,6 +237,11 @@ 9. Удалите директорию из /tmp, откуда производилась установка. +## Полное удаление + +1. Прогоните `/opt/zapret/uninstall_easy.sh`. +2. Cогласитесь на удаление зависимостей в openwrt. +3. Удалите каталог `/opt/zapret`. ## Итог Это минимальная инструкция, чтобы быстро сориентироваться с чего начать. diff --git a/docs/quick_start_windows.md b/docs/quick_start_windows.md index ef42a04..6443f2d 100644 --- a/docs/quick_start_windows.md +++ b/docs/quick_start_windows.md @@ -47,6 +47,14 @@ _"Совсем ничего не могу, все очень сложно, да Не помогла _"таблетка"_ ? Это вовсе не значит, что ничего не получится. Но придется делать по нормальному. +## НЕ ПОМОГЛО, КАК ТЕПЕРЬ ЭТО УДАЛИТЬ + +Если вы не устанавливали zapret как службу или запланированную задачу (а это требует редактирования cmd файлов), +достаточно закрыть окно с winws и запустить windivert_delete.cmd. +Альтернатива - перезагрузить компьютер. +После чего можно удалить папку с zapret. На этом деинсталляция закончена. +Если же вы устанавливали zapret как службу, то вы наверняка знаете как ее удалить. + ## РЕШЕНИЕ "КАК ПОЛОЖЕНО" 1) Скачайте и распакуйте архив https://github.com/bol-van/zapret-win-bundle/archive/refs/heads/master.zip. From 1c7080ca6863e0230353458631d81d685d770bfe Mon Sep 17 00:00:00 2001 From: bol-van Date: Mon, 11 Nov 2024 14:52:30 +0300 Subject: [PATCH 02/10] quick_start.md: typo --- docs/quick_start.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/docs/quick_start.md b/docs/quick_start.md index d34a2c2..7c7d5c7 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -213,7 +213,7 @@ > Если используются методы нулевой фазы десинхронизации (`--mss`, > `--wssize`, `--dpi-desync=syndata`) и режим фильтрации `hostlist`, то все > параметры, относящиеся к этим методам, следует помещать в отдельные - > профили мульистратегии, которые получат управление до определения имени + > профили мультистратегии, которые получат управление до определения имени > хоста. Необходимо понимать алгоритм работы мультистратегий. Самым надежным > вариантом будет дублирование этих параметров на 2 профиля. Какой-нибудь > сработает в зависимости от параметра `MODE_FILTER`. @@ -237,11 +237,6 @@ 9. Удалите директорию из /tmp, откуда производилась установка. -## Полное удаление - -1. Прогоните `/opt/zapret/uninstall_easy.sh`. -2. Cогласитесь на удаление зависимостей в openwrt. -3. Удалите каталог `/opt/zapret`. ## Итог Это минимальная инструкция, чтобы быстро сориентироваться с чего начать. From 918d52c2e6828dddeb4c9c3f9f183e6d27432a11 Mon Sep 17 00:00:00 2001 From: bol-van Date: Mon, 11 Nov 2024 14:53:36 +0300 Subject: [PATCH 03/10] Revert "quick_start.md: typo" This reverts commit 1c7080ca6863e0230353458631d81d685d770bfe. --- docs/quick_start.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/quick_start.md b/docs/quick_start.md index 7c7d5c7..d34a2c2 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -213,7 +213,7 @@ > Если используются методы нулевой фазы десинхронизации (`--mss`, > `--wssize`, `--dpi-desync=syndata`) и режим фильтрации `hostlist`, то все > параметры, относящиеся к этим методам, следует помещать в отдельные - > профили мультистратегии, которые получат управление до определения имени + > профили мульистратегии, которые получат управление до определения имени > хоста. Необходимо понимать алгоритм работы мультистратегий. Самым надежным > вариантом будет дублирование этих параметров на 2 профиля. Какой-нибудь > сработает в зависимости от параметра `MODE_FILTER`. @@ -237,6 +237,11 @@ 9. Удалите директорию из /tmp, откуда производилась установка. +## Полное удаление + +1. Прогоните `/opt/zapret/uninstall_easy.sh`. +2. Cогласитесь на удаление зависимостей в openwrt. +3. Удалите каталог `/opt/zapret`. ## Итог Это минимальная инструкция, чтобы быстро сориентироваться с чего начать. From c1e670be23921d2afbbe994ad27fde4e8777aa02 Mon Sep 17 00:00:00 2001 From: bol-van Date: Mon, 11 Nov 2024 14:54:27 +0300 Subject: [PATCH 04/10] quick_start.md: typo --- docs/quick_start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/quick_start.md b/docs/quick_start.md index d34a2c2..d7679d3 100644 --- a/docs/quick_start.md +++ b/docs/quick_start.md @@ -213,7 +213,7 @@ > Если используются методы нулевой фазы десинхронизации (`--mss`, > `--wssize`, `--dpi-desync=syndata`) и режим фильтрации `hostlist`, то все > параметры, относящиеся к этим методам, следует помещать в отдельные - > профили мульистратегии, которые получат управление до определения имени + > профили мультистратегии, которые получат управление до определения имени > хоста. Необходимо понимать алгоритм работы мультистратегий. Самым надежным > вариантом будет дублирование этих параметров на 2 профиля. Какой-нибудь > сработает в зависимости от параметра `MODE_FILTER`. From a17e4908514f3f280d0d4a216f7d48b169d94ff8 Mon Sep 17 00:00:00 2001 From: bol-van Date: Mon, 11 Nov 2024 18:38:23 +0300 Subject: [PATCH 05/10] nfqws: multisplit --- nfq/desync.c | 275 +++++++++++++++++++++++++++++++++++-------------- nfq/desync.h | 2 + nfq/helpers.c | 21 ++++ nfq/helpers.h | 3 + nfq/nfqws.c | 232 ++++++++++++++++++++++++++++++++--------- nfq/params.c | 1 - nfq/params.h | 19 +++- nfq/protocol.c | 189 ++++++++++++++++++++++++--------- nfq/protocol.h | 21 +++- 9 files changed, 579 insertions(+), 184 deletions(-) diff --git a/nfq/desync.c b/nfq/desync.c index cf942e1..729ca29 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -97,11 +97,11 @@ bool desync_only_first_stage(enum dpi_desync_mode mode) } bool desync_valid_second_stage(enum dpi_desync_mode mode) { - return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2 || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER; + return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2 || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER; } bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode) { - return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2; + return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2; } bool desync_valid_second_stage_udp(enum dpi_desync_mode mode) { @@ -131,6 +131,10 @@ enum dpi_desync_mode desync_mode_from_string(const char *s) return DESYNC_SPLIT; else if (!strcmp(s,"split2")) return DESYNC_SPLIT2; + else if (!strcmp(s,"multisplit")) + return DESYNC_MULTISPLIT; + else if (!strcmp(s,"multidisorder")) + return DESYNC_MULTIDISORDER; else if (!strcmp(s,"ipfrag2")) return DESYNC_IPFRAG2; else if (!strcmp(s,"hopbyhop")) @@ -582,22 +586,7 @@ static bool replay_queue(struct rawpacket_tailhead *q); static size_t pos_normalize(size_t split_pos, size_t reasm_offset, size_t len_payload) { - size_t rsplit_pos = split_pos; - // normalize split pos to current packet - split_pos=(split_pos>reasm_offset && (split_pos-reasm_offset) %zu\n",rsplit_pos,split_pos); - else - DLOG("split pos %zu is outside of this packet %zu-%zu\n",rsplit_pos,reasm_offset,reasm_offset+len_payload); - } - } - return split_pos; + return (split_pos>reasm_offset && (split_pos-reasm_offset)marker, sp->pos, data, sz); + case TLS: + return TLSPos(sp->marker, sp->pos, data, sz); + default: + return AnyProtoPos(sp->marker, sp->pos, data, sz); + } +} +static void resolve_multisplit(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct desync_profile *dp, size_t *pos, int *pos_count) +{ + int i,j; + for(i=j=0;isplit_count;i++) + { + pos[j] = resolve_split(data,sz,l7proto,dp->splits+i); + if (pos[j]) j++; + } + qsort_size_t(pos, j); + j=unique_size_t(pos, j); + *pos_count=j; +} + static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, struct dissect *dis) { uint8_t verdict=VERDICT_PASS; @@ -845,7 +859,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } } // !replay - + if (!(dis->tcp->th_flags & TH_SYN) && dis->len_payload) { const uint8_t *fake; @@ -856,6 +870,9 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint const uint8_t *rdata_payload = dis->data_payload; size_t rlen_payload = dis->len_payload; size_t split_pos; + size_t multisplit_pos[MAX_SPLITS]; + int multisplit_count; + int i; t_l7proto l7proto = UNKNOWN; if (replay) @@ -1065,35 +1082,12 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } } - // desync profile may have changed after hostname was revealed - switch(l7proto) - { - case HTTP: - fake = dp->fake_http; - fake_size = dp->fake_http_size; - split_pos = HttpPos(dp->desync_split_http_req, dp->desync_split_pos, rdata_payload, rlen_payload); - break; - case TLS: - fake = dp->fake_tls; - fake_size = dp->fake_tls_size; - split_pos = TLSPos(dp->desync_split_tls, dp->desync_split_pos, rdata_payload, rlen_payload, 0); - break; - default: - fake = dp->fake_unknown; - fake_size = dp->fake_unknown_size; - split_pos=dp->desync_split_pos; - break; - } - - // we do not need reasm buffer anymore - reasm_orig_cancel(ctrack); - rdata_payload=NULL; - if (l7proto==UNKNOWN) { if (!dp->desync_any_proto) { DLOG("not applying tampering to unknown protocol\n"); + reasm_orig_cancel(ctrack); return verdict; } DLOG("applying tampering to unknown protocol\n"); @@ -1135,7 +1129,63 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint } } - if (dp->desync_mode==DESYNC_NONE) return verdict; + if (dp->desync_mode==DESYNC_NONE) + { + reasm_orig_cancel(ctrack); + return verdict; + } + + const struct split_pos *spos; + switch(l7proto) + { + case HTTP: + fake = dp->fake_http; + fake_size = dp->fake_http_size; + spos = &dp->split_http; + break; + case TLS: + fake = dp->fake_tls; + fake_size = dp->fake_tls_size; + spos = &dp->split_tls; + break; + default: + fake = dp->fake_unknown; + fake_size = dp->fake_unknown_size; + spos = &dp->split_unknown; + break; + } + if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER) + { + split_pos=0; + resolve_multisplit(rdata_payload, rlen_payload, l7proto, dp, multisplit_pos, &multisplit_count); + if (params.debug) + { + if (multisplit_count) + { + DLOG("multisplit pos: "); + for (i=0;idesync_mode==DESYNC_SPLIT || dp->desync_mode==DESYNC_SPLIT2 || dp->desync_mode==DESYNC_DISORDER || dp->desync_mode==DESYNC_DISORDER2 || + dp->desync_mode2==DESYNC_SPLIT || dp->desync_mode2==DESYNC_SPLIT2 || dp->desync_mode2==DESYNC_DISORDER || dp->desync_mode2==DESYNC_DISORDER2) + { + multisplit_count=0; + split_pos = resolve_split(rdata_payload, rlen_payload, l7proto, spos); + DLOG("regular split pos: %zu\n",split_pos); + } + else + { + multisplit_count=0; + split_pos = 0; + } + + // we do not need reasm buffer anymore + reasm_orig_cancel(ctrack); + rdata_payload=NULL; if (params.debug) { @@ -1144,27 +1194,45 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2)); DLOG("dpi desync src=%s dst=%s\n",s1,s2); } - + if (!split_pos || split_pos>rlen_payload) split_pos=1; split_pos=pos_normalize(split_pos,reasm_offset,dis->len_payload); + if (split_pos) + DLOG("normalized regular split pos : %zu\n",split_pos); + else + DLOG("regular split pos is outside of this packet\n"); + if (multisplit_count) + { + int j; + for (i=j=0;ilen_payload); + if (multisplit_pos[j]) j++; + } + multisplit_count=j; + if (params.debug) + { + if (multisplit_count) + { + DLOG("normalized multisplit pos: "); + for (i=0;idesync_mode; uint32_t fooling_orig = FOOL_NONE; - bool b; + bool bFake = false; pkt1_len = sizeof(pkt1); - b = false; - switch(desync_mode) + switch(dp->desync_mode) { case DESYNC_FAKE_KNOWN: - if (reasm_offset) - { - desync_mode = dp->desync_mode2; - break; - } + if (reasm_offset) break; if (l7proto==UNKNOWN) { DLOG("not applying fake because of unknown protocol\n"); - desync_mode = dp->desync_mode2; break; } case DESYNC_FAKE: @@ -1176,14 +1244,14 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint { return verdict; } - DLOG("sending fake request : "); + DLOG("sending fake : "); hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n"); - b = true; + bFake = true; break; case DESYNC_RST: case DESYNC_RSTACK: if (reasm_offset) break; - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (desync_mode==DESYNC_RSTACK ? TH_ACK:0), dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (dp->desync_mode==DESYNC_RSTACK ? TH_ACK:0), dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, NULL, 0, pkt1, &pkt1_len)) @@ -1191,15 +1259,15 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint return verdict; } DLOG("sending fake RST/RSTACK\n"); - b = true; + bFake = true; break; case DESYNC_HOPBYHOP: case DESYNC_DESTOPT: case DESYNC_IPFRAG1: - fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1; - desync_mode = dp->desync_mode2; - if (dis->ip6 && (desync_mode==DESYNC_NONE || !desync_valid_second_stage_tcp(desync_mode) || - (!split_pos && (desync_mode==DESYNC_SPLIT || desync_mode==DESYNC_SPLIT2 || desync_mode==DESYNC_DISORDER || desync_mode==DESYNC_DISORDER2)))) + fooling_orig = (dp->desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1; + if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(dp->desync_mode2) || + (!split_pos && (dp->desync_mode2==DESYNC_SPLIT || dp->desync_mode2==DESYNC_SPLIT2 || dp->desync_mode2==DESYNC_DISORDER || dp->desync_mode2==DESYNC_DISORDER2)) || + (!multisplit_count && (dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)))) { if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), @@ -1219,24 +1287,65 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint break; } - if (b) + if (bFake) { if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) return verdict; - if (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(dp->desync_mode2)) - { - DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", dis->len_pkt, dis->len_payload); - verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6); - if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , dis->data_pkt, dis->len_pkt)) - return verdict; - return VERDICT_DROP; - } - desync_mode = dp->desync_mode2; } - pkt1_len = sizeof(pkt1); + enum dpi_desync_mode desync_mode = dp->desync_mode2==DESYNC_NONE ? dp->desync_mode : dp->desync_mode2; switch(desync_mode) { + case DESYNC_MULTISPLIT: + if (multisplit_count) + { + size_t from,to; + for (i=0,from=0 ; i<=multisplit_count ; i++) + { + to = i==multisplit_count ? dis->len_payload : multisplit_pos[i]; + + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, + net32_add(dis->tcp->th_seq,from), dis->tcp->th_ack, + dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + fooling_orig,0,0, + dis->data_payload+from, to-from, pkt1, &pkt1_len)) + return verdict; + DLOG("sending multisplit part %d %zu-%zu len=%zu : ",i+1,from,to-1,to-from); + hexdump_limited_dlog(dis->data_payload+from,to-from,PKTDATA_MAXDUMP); DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + return verdict; + + from = to; + } + return VERDICT_DROP; + } + break; + case DESYNC_MULTIDISORDER: + if (multisplit_count) + { + size_t from,to; + for (i=multisplit_count-1,to=dis->len_payload ; i>=-1 ; i--) + { + from = i>=0 ? multisplit_pos[i] : 0; + + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, + net32_add(dis->tcp->th_seq,from), dis->tcp->th_ack, + dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), + fooling_orig,0,0, + dis->data_payload+from, to-from, pkt1, &pkt1_len)) + return verdict; + DLOG("sending multisplit part %d %zu-%zu len=%zu : ",i+2,from,to-1,to-from); + hexdump_limited_dlog(dis->data_payload+from,to-from,PKTDATA_MAXDUMP); DLOG("\n"); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + return verdict; + + to = from; + } + return VERDICT_DROP; + } + break; case DESYNC_DISORDER: case DESYNC_DISORDER2: if (split_pos) @@ -1270,6 +1379,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint seg_len = dis->len_payload-split_pos; } + pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq , split_pos - dp->desync_seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, @@ -1357,6 +1467,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint seg_len = split_pos; } + pkt1_len = sizeof(pkt1); if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,-dp->desync_seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, @@ -1436,7 +1547,15 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint default: break; } - + + if (bFake) + { + DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", dis->len_pkt, dis->len_payload); + verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6); + if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , dis->data_pkt, dis->len_pkt)) + return verdict; + return VERDICT_DROP; + } } return verdict; @@ -1833,7 +1952,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint case DESYNC_FAKE: if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), dp->desync_fooling_mode, NULL, 0, 0, fake, fake_size, pkt1, &pkt1_len)) return verdict; - DLOG("sending fake request : "); + DLOG("sending fake : "); hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n"); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) return verdict; @@ -1996,7 +2115,7 @@ static void packet_debug(bool replay, const struct dissect *dis) char s[80]; str_tcphdr(s,sizeof(s),dis->tcp); DLOG(" %s\n",s); - if (dis->len_payload) { DLOG("TCP: "); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); } + if (dis->len_payload) { DLOG("TCP: len %zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); } } else if (dis->udp) @@ -2004,7 +2123,7 @@ static void packet_debug(bool replay, const struct dissect *dis) char s[30]; str_udphdr(s,sizeof(s),dis->udp); DLOG(" %s\n",s); - if (dis->len_payload) { DLOG("UDP: "); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); } + if (dis->len_payload) { DLOG("UDP: len %zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); } } else DLOG("\n"); diff --git a/nfq/desync.h b/nfq/desync.h index 4aa42aa..4250f5c 100644 --- a/nfq/desync.h +++ b/nfq/desync.h @@ -32,6 +32,8 @@ enum dpi_desync_mode { DESYNC_DISORDER2, DESYNC_SPLIT, DESYNC_SPLIT2, + DESYNC_MULTISPLIT, + DESYNC_MULTIDISORDER, DESYNC_IPFRAG2, DESYNC_HOPBYHOP, DESYNC_DESTOPT, diff --git a/nfq/helpers.c b/nfq/helpers.c index 2d2d320..90c0452 100644 --- a/nfq/helpers.c +++ b/nfq/helpers.c @@ -11,6 +11,27 @@ #include "params.h" +int unique_size_t(size_t *pu, int ct) +{ + int i, j, u; + for (i = j = 0; j < ct; i++) + { + u = pu[j++]; + for (; j < ct && pu[j] == u; j++); + pu[i] = u; + } + return i; +} +static int cmp_size_t(const void * a, const void * b) +{ + return *(size_t*)a < *(size_t*)b ? -1 : *(size_t*)a > *(size_t*)b; +} +void qsort_size_t(size_t *array,size_t ct) +{ + qsort(array,ct,sizeof(*array),cmp_size_t); +} + + void rtrim(char *s) { if (s) diff --git a/nfq/helpers.h b/nfq/helpers.h index c06862e..58051a7 100644 --- a/nfq/helpers.h +++ b/nfq/helpers.h @@ -17,6 +17,9 @@ typedef union char _align[32]; // force 16-byte alignment for ip6_and int128 ops } sockaddr_in46; +int unique_size_t(size_t *pu, int ct); +void qsort_size_t(size_t *array,size_t ct); + void rtrim(char *s); void replace_char(char *s, char from, char to); char *strncasestr(const char *s,const char *find, size_t slen); diff --git a/nfq/nfqws.c b/nfq/nfqws.c index e07054f..c9f18ed 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -673,10 +673,7 @@ static bool parse_l7_list(char *opt, uint32_t *l7) *l7 |= L7_PROTO_UNKNOWN; else return false; - if (e) - { - *e++=c; - } + if (e) *e++=c; p = e; } return true; @@ -723,15 +720,173 @@ static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6) *ipv6 = true; else return false; - if (e) - { - *e++=c; - } + if (e) *e++=c; p = e; } return true; } +static bool parse_httpreqpos(const char *s, struct split_pos *sp) +{ + if (!strcmp(s, "method")) + { + sp->marker = PM_HTTP_METHOD; + sp->pos=2; + } + else if (!strcmp(s, "host")) + { + sp->marker = PM_HOST; + sp->pos=1; + } + else + return false; + return true; +} +static bool parse_tlspos(const char *s, struct split_pos *sp) +{ + if (!strcmp(s, "sni")) + { + sp->marker = PM_HOST; + sp->pos=1; + } + else if (!strcmp(s, "sniext")) + { + sp->marker = PM_SNI_EXT; + sp->pos=0; + } + else if (!strcmp(s, "snisld")) + { + sp->marker = PM_HOST_MIDSLD; + sp->pos=1; + } + else + return false; + return true; +} + +static bool parse_int16(const char *p, int16_t *v) +{ + if (*p=='+' || *p=='-' || *p>='0' && *p<='9') + { + int i = atoi(p); + *v = (int16_t)i; + return *v==i; // check overflow + } + return false; +} +static bool parse_posmarker(const char *opt, uint8_t *posmarker) +{ + if (!strcmp(opt,"host")) + *posmarker = PM_HOST; + else if (!strcmp(opt,"endhost")) + *posmarker = PM_HOST_END; + else if (!strcmp(opt,"sld")) + *posmarker = PM_HOST_SLD; + else if (!strcmp(opt,"midsld")) + *posmarker = PM_HOST_MIDSLD; + else if (!strcmp(opt,"endsld")) + *posmarker = PM_HOST_ENDSLD; + else if (!strcmp(opt,"method")) + *posmarker = PM_HTTP_METHOD; + else if (!strcmp(opt,"sniext")) + *posmarker = PM_SNI_EXT; + else + return false; + return true; +} +static bool parse_split_pos(char *opt, struct split_pos *split) +{ + if (parse_int16(opt,&split->pos)) + { + split->marker = PM_ABS; + return !!split->pos; + } + else + { + char c,*p=opt; + bool b; + + for (; *opt && *opt!='+' && *opt!='-'; opt++); + c=*opt; *opt=0; + b=parse_posmarker(p,&split->marker); + *opt=c; + if (!b) return false; + if (*opt) + return parse_int16(opt,&split->pos); + else + split->pos = 0; + } + return true; +} +static bool parse_split_pos_list(char *opt, struct split_pos *splits, int splits_size, int *split_count) +{ + char c,*e,*p; + + for (p=opt, *split_count=0 ; p && *split_countsplit_unknown.marker=PM_ABS; + dp->split_unknown.pos=2; + for (i=0;isplit_count;i++) + { + if (dp->splits[i].marker==PM_ABS) + { + dp->split_unknown.pos=dp->splits[i].pos; + break; + } + } + if (SPLIT_POS_EMPTY(&dp->split_http)) + { + dp->split_http=dp->split_unknown; + for (i=0;isplit_count;i++) + if (IsHostMarker(dp->splits[i].marker) || dp->splits[i].marker==PM_HTTP_METHOD) + { + dp->split_http = dp->splits[i]; + break; + } + } + if (SPLIT_POS_EMPTY(&dp->split_tls)) + { + dp->split_tls=dp->split_unknown; + for (i=0;isplit_count;i++) + if (IsHostMarker(dp->splits[i].marker) || dp->splits[i].marker==PM_SNI_EXT) + { + dp->split_tls = dp->splits[i]; + break; + } + } +} +static void SplitDebug(void) +{ + struct desync_profile_list *dpl; + const struct desync_profile *dp; + LIST_FOREACH(dpl, ¶ms.desync_profiles, next) + { + dp = &dpl->dp; + DLOG("profile %d split_http %s %d\n",dp->n,posmarker_name(dp->split_http.marker),dp->split_http.pos); + DLOG("profile %d split_tls %s %d\n",dp->n,posmarker_name(dp->split_tls.marker),dp->split_tls.pos); + DLOG("profile %d split_unknown %s %d\n",dp->n,posmarker_name(dp->split_unknown.marker),dp->split_unknown.pos); + for(int x=0;xsplit_count;x++) + DLOG("profile %d multisplit %s %d\n",dp->n,posmarker_name(dp->splits[x].marker),dp->splits[x].pos); + } +} + + #ifdef __CYGWIN__ static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *buf, size_t len) { @@ -757,10 +912,7 @@ static bool wf_make_pf(char *opt, const char *l4, const char *portname, char *bu if (n) strncat(buf," or ",len-strlen(buf)-1); strncat(buf, s1, len-strlen(buf)-1); - if (e) - { - *e++=c; - } + if (e) *e++=c; p = e; } strncat(buf, ")", len-strlen(buf)-1); @@ -912,7 +1064,9 @@ static void exithelp(void) " --hostspell\t\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n" " --hostnospace\t\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n" " --domcase\t\t\t\t\t; mix domain case : Host: TeSt.cOm\n" - " --dpi-desync=[,][,]\t; try to desync dpi state. modes : synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen tamper\n" + " --dpi-desync=[,][,]\t; try to desync dpi state. modes :\n" + "\t\t\t\t\t\t; synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1\n" + "\t\t\t\t\t\t; disorder disorder2 split split2 multisplit multidisorder ipfrag2 udplen tamper\n" #ifdef __linux__ " --dpi-desync-fwmark=\t\t; override fwmark for desync packet. default = 0x%08X (%u)\n" #elif defined(SO_USER_COOKIE) @@ -925,9 +1079,9 @@ static void exithelp(void) " --dpi-desync-fooling=[,]\t\t; can use multiple comma separated values. modes : none md5sig ts badseq badsum datanoack hopbyhop hopbyhop2\n" " --dpi-desync-repeats=\t\t\t; send every desync packet N times\n" " --dpi-desync-skip-nosni=0|1\t\t\t; 1(default)=do not act on ClientHello without SNI (ESNI ?)\n" - " --dpi-desync-split-pos=<1..%u>\t\t; data payload split position\n" - " --dpi-desync-split-http-req=method|host\t; split at specified logical part of plain http request\n" - " --dpi-desync-split-tls=sni|sniext|snisld\t; split at specified logical part of TLS ClientHello\n" + " --dpi-desync-split-pos=N|-N|marker+N|marker-N\t; comma separated list of split positions. markers: method,host,endhost,sld,endsld,midsld,sniext\n" + "\t\t\t\t\t\t; full list is only used by multisplit and multidisorder\n" + "\t\t\t\t\t\t; single split takes first l7-protocol-compatible parameter if present, first abs value otherwise\n" " --dpi-desync-split-seqovl=\t\t; use sequence overlap before first sent original split segment\n" " --dpi-desync-split-seqovl-pattern=|0xHEX ; pattern for the fake part of overlap\n" " --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n" @@ -953,7 +1107,6 @@ static void exithelp(void) DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT, #endif AUTOTTL_DEFAULT_DELTA,AUTOTTL_DEFAULT_MIN,AUTOTTL_DEFAULT_MAX, - DPI_DESYNC_MAX_FAKE_LEN, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT, DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT, BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT, @@ -967,29 +1120,6 @@ static void exithelp_clean(void) exithelp(); } -bool parse_httpreqpos(const char *s, enum httpreqpos *pos) -{ - if (!strcmp(s, "method")) - *pos = httpreqpos_method; - else if (!strcmp(s, "host")) - *pos = httpreqpos_host; - else - return false; - return true; -} -bool parse_tlspos(const char *s, enum tlspos *pos) -{ - if (!strcmp(s, "sni")) - *pos = tlspos_sni; - else if (!strcmp(s, "sniext")) - *pos = tlspos_sniext; - else if (!strcmp(s, "snisld")) - *pos = tlspos_snisld; - else - return false; - return true; -} - #ifndef __OpenBSD__ // no static to not allow optimizer to inline this func (save stack) void config_from_file(const char *filename) @@ -1447,21 +1577,27 @@ int main(int argc, char **argv) dp->desync_skip_nosni = !optarg || atoi(optarg); break; case 23: /* dpi-desync-split-pos */ - if (sscanf(optarg,"%u",&dp->desync_split_pos)<1 || dp->desync_split_pos<1) { - DLOG_ERR("dpi-desync-split-pos is not valid\n"); - exit_clean(1); + int ct; + if (!parse_split_pos_list(optarg,dp->splits+dp->split_count,MAX_SPLITS-dp->split_count,&ct)) + { + DLOG_ERR("could not parse split pos list or too much positions (before parsing - %u, max - %u) : %s\n",dp->split_count,MAX_SPLITS,optarg); + exit_clean(1); + } + dp->split_count += ct; } break; case 24: /* dpi-desync-split-http-req */ - if (!parse_httpreqpos(optarg, &dp->desync_split_http_req)) + // obsolete arg + if (!parse_httpreqpos(optarg, &dp->split_http)) { DLOG_ERR("Invalid argument for dpi-desync-split-http-req\n"); exit_clean(1); } break; case 25: /* dpi-desync-split-tls */ - if (!parse_tlspos(optarg, &dp->desync_split_tls)) + // obsolete arg + if (!parse_tlspos(optarg, &dp->split_tls)) { DLOG_ERR("Invalid argument for dpi-desync-split-tls\n"); exit_clean(1); @@ -1919,8 +2055,7 @@ int main(int argc, char **argv) DLOG("[profile %d] autottl ipv4 %u:%u-%u\n",dp->n,dp->desync_autottl.delta,dp->desync_autottl.min,dp->desync_autottl.max); if (AUTOTTL_ENABLED(dp->desync_autottl6)) DLOG("[profile %d] autottl ipv6 %u:%u-%u\n",dp->n,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max); - if (dp->desync_split_tls==tlspos_none && dp->desync_split_pos) dp->desync_split_tls=tlspos_pos; - if (dp->desync_split_http_req==httpreqpos_none && dp->desync_split_pos) dp->desync_split_http_req=httpreqpos_pos; + split_compat(dp); } if (!LoadAllHostLists()) @@ -1937,6 +2072,9 @@ int main(int argc, char **argv) DLOG("\nlists summary:\n"); HostlistsDebug(); IpsetsDebug(); + + DLOG("\nsplits summary:\n"); + SplitDebug(); DLOG("\n"); if (daemon) daemonize(); diff --git a/nfq/params.c b/nfq/params.c index 3cece72..8a7702c 100644 --- a/nfq/params.c +++ b/nfq/params.c @@ -169,7 +169,6 @@ struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head) memcpy(entry->dp.hostspell, "host", 4); // default hostspell entry->dp.desync_skip_nosni = true; - entry->dp.desync_split_pos = 2; entry->dp.desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT; entry->dp.desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT; entry->dp.desync_repeats = 1; diff --git a/nfq/params.h b/nfq/params.h index 7af45c6..4fff9dc 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -40,6 +40,14 @@ enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; +struct split_pos +{ + int16_t pos; + uint8_t marker; +}; +#define SPLIT_POS_EMPTY(sp) ((sp)->marker==PM_ABS && (sp)->pos==0) +#define MAX_SPLITS 64 + struct desync_profile { int n; // number of the profile @@ -53,9 +61,14 @@ struct desync_profile char hostspell[4]; enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2; bool desync_retrans,desync_skip_nosni,desync_any_proto; - unsigned int desync_repeats,desync_split_pos,desync_seqovl,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp; - enum httpreqpos desync_split_http_req; - enum tlspos desync_split_tls; + unsigned int desync_repeats,desync_seqovl,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp; + + // multisplit + struct split_pos splits[MAX_SPLITS]; + int split_count; + // single split pos cache + struct split_pos split_http,split_tls,split_unknown; + char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence unsigned int desync_start, desync_cutoff; uint8_t desync_ttl, desync_ttl6; diff --git a/nfq/protocol.c b/nfq/protocol.c index bec8362..1283e2c 100644 --- a/nfq/protocol.c +++ b/nfq/protocol.c @@ -24,6 +24,88 @@ static bool FindNLD(const uint8_t *dom, size_t dlen, int level, const uint8_t ** return true; } + +#define PM_ABS 0 +#define PM_HOST 1 +#define PM_HOST_END 2 +#define PM_HOST_SLD 3 +#define PM_HOST_MIDSLD 4 +#define PM_HOST_ENDSLD 5 +#define PM_HTTP_METHOD 6 +#define PM_SNI_EXT 7 +bool IsHostMarker(uint8_t posmarker) +{ + switch(posmarker) + { + case PM_HOST: + case PM_HOST_END: + case PM_HOST_SLD: + case PM_HOST_MIDSLD: + case PM_HOST_ENDSLD: + return true; + default: + return false; + } +} +const char *posmarker_name(uint8_t posmarker) +{ + switch(posmarker) + { + case PM_ABS: return "abs"; + case PM_HOST: return "host"; + case PM_HOST_END: return "endhost"; + case PM_HOST_SLD: return "sld"; + case PM_HOST_MIDSLD: return "midsld"; + case PM_HOST_ENDSLD: return "endsld"; + case PM_HTTP_METHOD: return "method"; + case PM_SNI_EXT: return "sniext"; + default: return "?"; + } +} + +static size_t CheckPos(size_t sz, ssize_t offset) +{ + return (offset>=0 && offset='A' && *method<='Z') method++; - if (i<3 || *method!=' ') break; - return method-http-1; - case httpreqpos_host: - if (HttpFindHostConst(&host,http,sz) && (host-http+7)='A' && *p<='Z') p++; + if (i<3 || *p!=' ') break; + return CheckPos(sz,method-data+pos); + case PM_HOST: + case PM_HOST_END: + case PM_HOST_SLD: + case PM_HOST_MIDSLD: + case PM_HOST_ENDSLD: + if (HttpFindHostConst(&host,data,sz) && (host-data+7) aka.ru -// return false if SNI ext is bad or SLD is not found -static bool TLSHelloFindMiddleOfSLDInSNI(const uint8_t *ext, size_t elen, const uint8_t **p) -{ - size_t len; - if (!TLSHelloFindNLDInSNI(ext,elen,2,p,&len)) - return false; - // in case of one letter SLD (x.com) we split at '.' to prevent appearance of the whole SLD - *p = (len==1) ? *p+1 : *p+len/2; - return true; -} -size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type) +size_t TLSPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz) { size_t elen; const uint8_t *ext, *p; - switch(tpos_type) + size_t offset_host,len_host; + ssize_t offset; + + switch(posmarker) { - case tlspos_sni: - case tlspos_sniext: - if (TLSFindExt(tls,sz,0,&ext,&elen,false)) - return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1; - break; - case tlspos_snisld: - if (TLSFindExt(tls,sz,0,&ext,&elen,false)) - if (TLSHelloFindMiddleOfSLDInSNI(ext,elen,&p)) - return p-tls; - break; - case tlspos_pos: - break; - default: + case PM_HOST: + case PM_HOST_END: + case PM_HOST_SLD: + case PM_HOST_MIDSLD: + case PM_HOST_ENDSLD: + case PM_SNI_EXT: + if (TLSFindExt(data,sz,0,&ext,&elen,false)) + { + if (posmarker==PM_SNI_EXT) + { + offset = ext-data+1+pos; + return (offset>=0 && offset Date: Mon, 11 Nov 2024 19:48:47 +0300 Subject: [PATCH 06/10] nfqws: move code --- nfq/conntrack.c | 23 ----------------------- nfq/conntrack.h | 14 ++------------ nfq/desync.c | 29 ++--------------------------- nfq/nfqws.c | 7 +++++++ nfq/params.h | 10 ++-------- nfq/protocol.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ nfq/protocol.h | 18 ++++++++++++++++++ 7 files changed, 76 insertions(+), 70 deletions(-) diff --git a/nfq/conntrack.c b/nfq/conntrack.c index 1f1fd7c..22b82dd 100644 --- a/nfq/conntrack.c +++ b/nfq/conntrack.c @@ -12,29 +12,6 @@ static void ut_oom_recover(void *elem) oom = true; } -const char *l7proto_str(t_l7proto l7) -{ - switch(l7) - { - case HTTP: return "http"; - case TLS: return "tls"; - case QUIC: return "quic"; - case WIREGUARD: return "wireguard"; - case DHT: return "dht"; - default: return "unknown"; - } -} -bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7) -{ - return (l7proto==UNKNOWN && (filter_l7 & L7_PROTO_UNKNOWN)) || - (l7proto==HTTP && (filter_l7 & L7_PROTO_HTTP)) || - (l7proto==TLS && (filter_l7 & L7_PROTO_TLS)) || - (l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) || - (l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) || - (l7proto==DHT && (filter_l7 & L7_PROTO_DHT)); -} - - static const char *connstate_s[]={"SYN","ESTABLISHED","FIN"}; static void connswap(const t_conn *c, t_conn *c2) diff --git a/nfq/conntrack.h b/nfq/conntrack.h index 415c533..ffe5270 100644 --- a/nfq/conntrack.h +++ b/nfq/conntrack.h @@ -4,8 +4,6 @@ // this conntrack is not bullet-proof // its designed to satisfy dpi desync needs only -#include "packet_queue.h" - #include #include #include @@ -19,6 +17,8 @@ #include #include +#include "packet_queue.h" +#include "protocol.h" //#define HASH_BLOOM 20 #define HASH_NONFATAL_OOM 1 @@ -53,16 +53,6 @@ typedef struct { // FIN - FIN or RST received typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate; -typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto; -#define L7_PROTO_HTTP 0x00000001 -#define L7_PROTO_TLS 0x00000002 -#define L7_PROTO_QUIC 0x00000004 -#define L7_PROTO_WIREGUARD 0x00000008 -#define L7_PROTO_DHT 0x00000010 -#define L7_PROTO_UNKNOWN 0x80000000 -const char *l7proto_str(t_l7proto l7); -bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7); - typedef struct { bool bCheckDone, bCheckResult, bCheckExcluded; // hostlist check result cache diff --git a/nfq/desync.c b/nfq/desync.c index 729ca29..2391b42 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -607,31 +607,6 @@ static void autottl_discover(t_ctrack *ctrack, bool bIpv6) } } -static size_t resolve_split(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *sp) -{ - switch(l7proto) - { - case HTTP: - return HttpPos(sp->marker, sp->pos, data, sz); - case TLS: - return TLSPos(sp->marker, sp->pos, data, sz); - default: - return AnyProtoPos(sp->marker, sp->pos, data, sz); - } -} -static void resolve_multisplit(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct desync_profile *dp, size_t *pos, int *pos_count) -{ - int i,j; - for(i=j=0;isplit_count;i++) - { - pos[j] = resolve_split(data,sz,l7proto,dp->splits+i); - if (pos[j]) j++; - } - qsort_size_t(pos, j); - j=unique_size_t(pos, j); - *pos_count=j; -} - static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint32_t fwmark, const char *ifout, struct dissect *dis) { uint8_t verdict=VERDICT_PASS; @@ -1157,7 +1132,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER) { split_pos=0; - resolve_multisplit(rdata_payload, rlen_payload, l7proto, dp, multisplit_pos, &multisplit_count); + ResolveMultiPos(rdata_payload, rlen_payload, l7proto, dp->splits, dp->split_count, multisplit_pos, &multisplit_count); if (params.debug) { if (multisplit_count) @@ -1174,7 +1149,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint dp->desync_mode2==DESYNC_SPLIT || dp->desync_mode2==DESYNC_SPLIT2 || dp->desync_mode2==DESYNC_DISORDER || dp->desync_mode2==DESYNC_DISORDER2) { multisplit_count=0; - split_pos = resolve_split(rdata_payload, rlen_payload, l7proto, spos); + split_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, spos); DLOG("regular split pos: %zu\n",split_pos); } else diff --git a/nfq/nfqws.c b/nfq/nfqws.c index c9f18ed..317a5ad 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -2048,6 +2048,13 @@ int main(int argc, char **argv) LIST_FOREACH(dpl, ¶ms.desync_profiles, next) { dp = &dpl->dp; + + if (!dp->split_count && (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)) + { + DLOG_ERR("multisplit requires explicit split pos\n"); + exit_clean(1); + } + // not specified - use desync_ttl value instead if (dp->desync_ttl6 == 0xFF) dp->desync_ttl6=dp->desync_ttl; if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl; diff --git a/nfq/params.h b/nfq/params.h index 4fff9dc..a224ae0 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -38,16 +38,10 @@ #define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60 #define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3 -enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; - -struct split_pos -{ - int16_t pos; - uint8_t marker; -}; -#define SPLIT_POS_EMPTY(sp) ((sp)->marker==PM_ABS && (sp)->pos==0) #define MAX_SPLITS 64 +enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG }; + struct desync_profile { int n; // number of the profile diff --git a/nfq/protocol.c b/nfq/protocol.c index 1283e2c..67a0ff9 100644 --- a/nfq/protocol.c +++ b/nfq/protocol.c @@ -24,6 +24,27 @@ static bool FindNLD(const uint8_t *dom, size_t dlen, int level, const uint8_t ** return true; } +const char *l7proto_str(t_l7proto l7) +{ + switch(l7) + { + case HTTP: return "http"; + case TLS: return "tls"; + case QUIC: return "quic"; + case WIREGUARD: return "wireguard"; + case DHT: return "dht"; + default: return "unknown"; + } +} +bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7) +{ + return (l7proto==UNKNOWN && (filter_l7 & L7_PROTO_UNKNOWN)) || + (l7proto==HTTP && (filter_l7 & L7_PROTO_HTTP)) || + (l7proto==TLS && (filter_l7 & L7_PROTO_TLS)) || + (l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) || + (l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) || + (l7proto==DHT && (filter_l7 & L7_PROTO_DHT)); +} #define PM_ABS 0 #define PM_HOST 1 @@ -104,6 +125,30 @@ static size_t HostPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_ } return CheckPos(sz,offset); } +size_t ResolvePos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *sp) +{ + switch(l7proto) + { + case HTTP: + return HttpPos(sp->marker, sp->pos, data, sz); + case TLS: + return TLSPos(sp->marker, sp->pos, data, sz); + default: + return AnyProtoPos(sp->marker, sp->pos, data, sz); + } +} +void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *splits, int split_count, size_t *pos, int *pos_count) +{ + int i,j; + for(i=j=0;imarker==PM_ABS && (sp)->pos==0) bool IsHostMarker(uint8_t posmarker); const char *posmarker_name(uint8_t posmarker); size_t AnyProtoPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz); size_t HttpPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz); size_t TLSPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz); +size_t ResolvePos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *sp); +void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *splits, int split_count, size_t *pos, int *pos_count); extern const char *http_methods[9]; const char *HttpMethod(const uint8_t *data, size_t len); From 9b3bbb72851a0e240c336bba6d55369785958163 Mon Sep 17 00:00:00 2001 From: bol-van Date: Mon, 11 Nov 2024 20:35:48 +0300 Subject: [PATCH 07/10] nfqws: minor beautify --- nfq/desync.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nfq/desync.c b/nfq/desync.c index 2391b42..88d3039 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -2090,7 +2090,7 @@ static void packet_debug(bool replay, const struct dissect *dis) char s[80]; str_tcphdr(s,sizeof(s),dis->tcp); DLOG(" %s\n",s); - if (dis->len_payload) { DLOG("TCP: len %zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); } + if (dis->len_payload) { DLOG("TCP: len=%zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); } } else if (dis->udp) @@ -2098,7 +2098,7 @@ static void packet_debug(bool replay, const struct dissect *dis) char s[30]; str_udphdr(s,sizeof(s),dis->udp); DLOG(" %s\n",s); - if (dis->len_payload) { DLOG("UDP: len %zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); } + if (dis->len_payload) { DLOG("UDP: len=%zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); } } else DLOG("\n"); From f973a6f3a6a775f502b43b618428702b536aa6ae Mon Sep 17 00:00:00 2001 From: bol-van Date: Mon, 11 Nov 2024 21:58:00 +0300 Subject: [PATCH 08/10] nfqws: beautify --- nfq/desync.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/nfq/desync.c b/nfq/desync.c index 88d3039..1129ef9 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -1110,6 +1110,14 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint return verdict; } + if (params.debug) + { + char s1[48],s2[48]; + ntop46_port((struct sockaddr *)&src, s1, sizeof(s1)); + ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2)); + DLOG("dpi desync src=%s dst=%s\n",s1,s2); + } + const struct split_pos *spos; switch(l7proto) { @@ -1162,14 +1170,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint reasm_orig_cancel(ctrack); rdata_payload=NULL; - if (params.debug) - { - char s1[48],s2[48]; - ntop46_port((struct sockaddr *)&src, s1, sizeof(s1)); - ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2)); - DLOG("dpi desync src=%s dst=%s\n",s1,s2); - } - if (!split_pos || split_pos>rlen_payload) split_pos=1; split_pos=pos_normalize(split_pos,reasm_offset,dis->len_payload); if (split_pos) From f8b3dca6f542474772a61b8650794a661641e875 Mon Sep 17 00:00:00 2001 From: bol-van Date: Tue, 12 Nov 2024 10:23:42 +0300 Subject: [PATCH 09/10] nfqws: optimize code --- nfq/desync.c | 57 +++++++++++++++++++++++++------------------------- nfq/nfqws.c | 12 +++++------ nfq/params.h | 4 ++-- nfq/protocol.c | 4 ++-- nfq/protocol.h | 8 +++---- 5 files changed, 42 insertions(+), 43 deletions(-) diff --git a/nfq/desync.c b/nfq/desync.c index 1129ef9..f54d6eb 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -1118,7 +1118,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint DLOG("dpi desync src=%s dst=%s\n",s1,s2); } - const struct split_pos *spos; + const struct proto_pos *spos; switch(l7proto) { case HTTP: @@ -1152,6 +1152,27 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint else DLOG("all multisplit pos are outside of this packet\n"); } + if (multisplit_count) + { + int j; + for (i=j=0;ilen_payload); + if (multisplit_pos[j]) j++; + } + multisplit_count=j; + if (params.debug) + { + if (multisplit_count) + { + DLOG("normalized multisplit pos: "); + for (i=0;idesync_mode==DESYNC_SPLIT || dp->desync_mode==DESYNC_SPLIT2 || dp->desync_mode==DESYNC_DISORDER || dp->desync_mode==DESYNC_DISORDER2 || dp->desync_mode2==DESYNC_SPLIT || dp->desync_mode2==DESYNC_SPLIT2 || dp->desync_mode2==DESYNC_DISORDER || dp->desync_mode2==DESYNC_DISORDER2) @@ -1159,6 +1180,12 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint multisplit_count=0; split_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, spos); DLOG("regular split pos: %zu\n",split_pos); + if (!split_pos || split_pos>rlen_payload) split_pos=1; + split_pos=pos_normalize(split_pos,reasm_offset,dis->len_payload); + if (split_pos) + DLOG("normalized regular split pos : %zu\n",split_pos); + else + DLOG("regular split pos is outside of this packet\n"); } else { @@ -1170,34 +1197,6 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint reasm_orig_cancel(ctrack); rdata_payload=NULL; - if (!split_pos || split_pos>rlen_payload) split_pos=1; - split_pos=pos_normalize(split_pos,reasm_offset,dis->len_payload); - if (split_pos) - DLOG("normalized regular split pos : %zu\n",split_pos); - else - DLOG("regular split pos is outside of this packet\n"); - if (multisplit_count) - { - int j; - for (i=j=0;ilen_payload); - if (multisplit_pos[j]) j++; - } - multisplit_count=j; - if (params.debug) - { - if (multisplit_count) - { - DLOG("normalized multisplit pos: "); - for (i=0;ipos)) { @@ -818,7 +818,7 @@ static bool parse_split_pos(char *opt, struct split_pos *split) } return true; } -static bool parse_split_pos_list(char *opt, struct split_pos *splits, int splits_size, int *split_count) +static bool parse_split_pos_list(char *opt, struct proto_pos *splits, int splits_size, int *split_count) { char c,*e,*p; @@ -850,7 +850,7 @@ static void split_compat(struct desync_profile *dp) break; } } - if (SPLIT_POS_EMPTY(&dp->split_http)) + if (PROTO_POS_EMPTY(&dp->split_http)) { dp->split_http=dp->split_unknown; for (i=0;isplit_count;i++) @@ -860,7 +860,7 @@ static void split_compat(struct desync_profile *dp) break; } } - if (SPLIT_POS_EMPTY(&dp->split_tls)) + if (PROTO_POS_EMPTY(&dp->split_tls)) { dp->split_tls=dp->split_unknown; for (i=0;isplit_count;i++) diff --git a/nfq/params.h b/nfq/params.h index a224ae0..8f5151d 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -58,10 +58,10 @@ struct desync_profile unsigned int desync_repeats,desync_seqovl,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp; // multisplit - struct split_pos splits[MAX_SPLITS]; + struct proto_pos splits[MAX_SPLITS]; int split_count; // single split pos cache - struct split_pos split_http,split_tls,split_unknown; + struct proto_pos split_http,split_tls,split_unknown; char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence unsigned int desync_start, desync_cutoff; diff --git a/nfq/protocol.c b/nfq/protocol.c index 67a0ff9..fd280f4 100644 --- a/nfq/protocol.c +++ b/nfq/protocol.c @@ -125,7 +125,7 @@ static size_t HostPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_ } return CheckPos(sz,offset); } -size_t ResolvePos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *sp) +size_t ResolvePos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct proto_pos *sp) { switch(l7proto) { @@ -137,7 +137,7 @@ size_t ResolvePos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struc return AnyProtoPos(sp->marker, sp->pos, data, sz); } } -void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *splits, int split_count, size_t *pos, int *pos_count) +void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct proto_pos *splits, int split_count, size_t *pos, int *pos_count) { int i,j; for(i=j=0;imarker==PM_ABS && (sp)->pos==0) +#define PROTO_POS_EMPTY(sp) ((sp)->marker==PM_ABS && (sp)->pos==0) bool IsHostMarker(uint8_t posmarker); const char *posmarker_name(uint8_t posmarker); size_t AnyProtoPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz); size_t HttpPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz); size_t TLSPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz); -size_t ResolvePos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *sp); -void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct split_pos *splits, int split_count, size_t *pos, int *pos_count); +size_t ResolvePos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct proto_pos *sp); +void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct proto_pos *splits, int split_count, size_t *pos, int *pos_count); extern const char *http_methods[9]; const char *HttpMethod(const uint8_t *data, size_t len); From 200cd9caf2ec17960d79c7f38d6963d39f12661c Mon Sep 17 00:00:00 2001 From: bol-van Date: Tue, 12 Nov 2024 10:29:29 +0300 Subject: [PATCH 10/10] mdig: enlarge dns reply buffer --- mdig/mdig.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mdig/mdig.c b/mdig/mdig.c index 6521f5f..4b9bfc7 100644 --- a/mdig/mdig.c +++ b/mdig/mdig.c @@ -424,7 +424,7 @@ bool dns_parse_print(const uint8_t *a, size_t len) } int dns_parse_query() { - uint8_t a[1500]; + uint8_t a[8192]; size_t l; #ifdef _WIN32 _setmode(_fileno(stdin), _O_BINARY);