From 684869e54f544e4467bdad62756e11c3c3098701 Mon Sep 17 00:00:00 2001 From: bol-van Date: Tue, 19 Mar 2024 13:50:20 +0300 Subject: [PATCH] syndata desync mode --- blockcheck.sh | 6 ++-- nfq/darkmagic.c | 6 ++++ nfq/darkmagic.h | 3 +- nfq/desync.c | 58 ++++++++++++++++++++++++++++++++------- nfq/desync.h | 1 + nfq/nfqws.c | 73 +++++++++++++++++++++++++++---------------------- nfq/params.h | 5 ++-- 7 files changed, 103 insertions(+), 49 deletions(-) diff --git a/blockcheck.sh b/blockcheck.sh index bbb6440..78c8b78 100755 --- a/blockcheck.sh +++ b/blockcheck.sh @@ -477,7 +477,7 @@ curl_test_https_tls12() # $2 - domain name # do not use tls 1.3 to make sure server certificate is not encrypted - curl_with_dig $1 $2 -ISs -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.2 $TLSMAX12 "https://$2" -o /dev/null 2>&1 + curl_with_dig $1 $2 -ISs -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.2 $TLSMAX12 "https://$2" -o /dev/null 2>&1 } curl_test_https_tls13() { @@ -485,7 +485,7 @@ curl_test_https_tls13() # $2 - domain name # force TLS1.3 mode - curl_with_dig $1 $2 -ISs -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.3 $TLSMAX13 "https://$2" -o /dev/null 2>&1 + curl_with_dig $1 $2 -ISs -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.3 $TLSMAX13 "https://$2" -o /dev/null 2>&1 } curl_test_http3() @@ -494,7 +494,7 @@ curl_test_http3() # $2 - domain name # force TLS1.3 mode - curl_with_dig $1 $2 -ISs -A "$USER_AGENT" --max-time $CURL_MAX_TIME --http3-only $CURL_OPT "https://$2" -o /dev/null 2>&1 + curl_with_dig $1 $2 -ISs -A "$USER_AGENT" --max-time $CURL_MAX_TIME --http3-only $CURL_OPT "https://$2" -o /dev/null 2>&1 } ipt_scheme() diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index ff6b298..5af8ead 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -560,6 +560,12 @@ bool ip_frag( return false; } +void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl) +{ + if (ip) ip->ip_ttl = ttl; + if (ip6) ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim = ttl; +} + void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport) { diff --git a/nfq/darkmagic.h b/nfq/darkmagic.h index 3defd24..a538cf0 100644 --- a/nfq/darkmagic.h +++ b/nfq/darkmagic.h @@ -124,7 +124,8 @@ bool ip_frag( size_t frag_pos, uint32_t ident, uint8_t *pkt1, size_t *pkt1_size, uint8_t *pkt2, size_t *pkt2_size); - + +void rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl); void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport); void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr,const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst); diff --git a/nfq/desync.c b/nfq/desync.c index b1f36e2..120e092 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -53,7 +53,7 @@ void desync_init(void) bool desync_valid_zero_stage(enum dpi_desync_mode mode) { - return mode==DESYNC_SYNACK; + return mode==DESYNC_SYNACK || mode==DESYNC_SYNDATA; } bool desync_valid_first_stage(enum dpi_desync_mode mode) { @@ -89,6 +89,8 @@ enum dpi_desync_mode desync_mode_from_string(const char *s) return DESYNC_RSTACK; else if (!strcmp(s,"synack")) return DESYNC_SYNACK; + else if (!strcmp(s,"syndata")) + return DESYNC_SYNDATA; else if (!strcmp(s,"disorder")) return DESYNC_DISORDER; else if (!strcmp(s,"disorder2")) @@ -437,18 +439,54 @@ packet_process_result dpi_desync_tcp_packet(uint32_t fwmark, const char *ifout, extract_endpoints(ip, ip6hdr, tcphdr, NULL, &src, &dst); } - if (params.desync_mode0==DESYNC_SYNACK && tcp_syn_segment(tcphdr)) + if (tcp_syn_segment(tcphdr)) { - pkt1_len = sizeof(pkt1); - if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN|TH_ACK, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, - ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment, - NULL, 0, pkt1, &pkt1_len)) + switch (params.desync_mode0) { - return res; + case DESYNC_SYNACK: + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN|TH_ACK, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment, + NULL, 0, pkt1, &pkt1_len)) + { + return res; + } + DLOG("sending fake SYNACK\n"); + if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + return res; + break; + case DESYNC_SYNDATA: + pkt1_len = sizeof(pkt1); + if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, + ttl_orig,0,0,0, params.fake_syndata,params.fake_syndata_size, pkt1,&pkt1_len)) + { + return res; + } + DLOG("sending SYN with fake data : "); + hexdump_limited_dlog(params.fake_syndata,params.fake_syndata_size,PKTDATA_MAXDUMP); DLOG("\n") + if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) + return res; + + #ifdef __linux__ + // if used in postnat chain, dropping SYN will cause conntrack connection teardown + // so we need to workaround this. + // we can't use low ttl because TCP/IP stack listens to ttl expired ICMPs in response to SYN and reset connection + // we also can't use TCP fooling because DPI would accept fooled packets + if (ip) + { + // routers will drop IP frames with invalid checksum + ip->ip_sum ^= htons(0xBEAF); + res=modify; + } + else + // ipv6 does not have checksum + // consider we are free of NAT in ipv6 case. just drop + res=drop; + #else + res=drop; + #endif + break; } - DLOG("sending fake SYNACK\n"); - if (!rawsend_rep((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) - return res; } if (params.desync_cutoff) diff --git a/nfq/desync.h b/nfq/desync.h index 4e8ca33..e77745d 100644 --- a/nfq/desync.h +++ b/nfq/desync.h @@ -26,6 +26,7 @@ enum dpi_desync_mode { DESYNC_RST, DESYNC_RSTACK, DESYNC_SYNACK, + DESYNC_SYNDATA, DESYNC_DISORDER, DESYNC_DISORDER2, DESYNC_SPLIT, diff --git a/nfq/nfqws.c b/nfq/nfqws.c index bd3772d..8c97e73 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -528,7 +528,7 @@ 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 fake fakeknown rst rstack hopbyhop destopt ipfrag1 disorder disorder2 split split2 ipfrag2 udplen tamper\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" #ifdef __linux__ " --dpi-desync-fwmark=\t\t; override fwmark for desync packet. default = 0x%08X (%u)\n" #elif defined(SO_USER_COOKIE) @@ -553,6 +553,7 @@ static void exithelp(void) " --dpi-desync-fake-http=|0xHEX\t; file containing fake http request\n" " --dpi-desync-fake-tls=|0xHEX\t\t; file containing fake TLS ClientHello (for https)\n" " --dpi-desync-fake-unknown=|0xHEX\t; file containing unknown protocol fake payload\n" + " --dpi-desync-fake-syndata=|0xHEX\t; file containing SYN data payload\n" " --dpi-desync-fake-quic=|0xHEX\t; file containing fake QUIC Initial\n" " --dpi-desync-fake-wireguard=|0xHEX\t; file containing fake wireguard handshake initiation\n" " --dpi-desync-fake-dht=|0xHEX\t\t; file containing DHT protocol fake payload (d1...e)\n" @@ -696,6 +697,7 @@ int main(int argc, char **argv) params.fake_wg_size = 64; params.fake_dht_size = 64; params.fake_unknown_size = 256; + params.fake_syndata_size = 16; params.fake_unknown_udp_size = 64; params.wscale=-1; // default - dont change scale factor (client) params.ctrack_t_syn = CTRACK_T_SYN; @@ -766,24 +768,25 @@ int main(int argc, char **argv) {"dpi-desync-fake-http",required_argument,0,0},// optidx=30 {"dpi-desync-fake-tls",required_argument,0,0},// optidx=31 {"dpi-desync-fake-unknown",required_argument,0,0},// optidx=32 - {"dpi-desync-fake-quic",required_argument,0,0},// optidx=33 - {"dpi-desync-fake-wireguard",required_argument,0,0},// optidx=34 - {"dpi-desync-fake-dht",required_argument,0,0},// optidx=35 - {"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=36 - {"dpi-desync-udplen-increment",required_argument,0,0},// optidx=37 - {"dpi-desync-udplen-pattern",required_argument,0,0},// optidx=38 - {"dpi-desync-cutoff",required_argument,0,0},// optidx=39 - {"hostlist",required_argument,0,0}, // optidx=40 - {"hostlist-exclude",required_argument,0,0}, // optidx=41 - {"hostlist-auto",required_argument,0,0}, // optidx=42 - {"hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=43 - {"hostlist-auto-fail-time",required_argument,0,0}, // optidx=44 - {"hostlist-auto-retrans-threshold",required_argument,0,0}, // optidx=45 - {"hostlist-auto-debug",required_argument,0,0}, // optidx=46 + {"dpi-desync-fake-syndata",required_argument,0,0},// optidx=33 + {"dpi-desync-fake-quic",required_argument,0,0},// optidx=34 + {"dpi-desync-fake-wireguard",required_argument,0,0},// optidx=35 + {"dpi-desync-fake-dht",required_argument,0,0},// optidx=36 + {"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=37 + {"dpi-desync-udplen-increment",required_argument,0,0},// optidx=38 + {"dpi-desync-udplen-pattern",required_argument,0,0},// optidx=39 + {"dpi-desync-cutoff",required_argument,0,0},// optidx=40 + {"hostlist",required_argument,0,0}, // optidx=41 + {"hostlist-exclude",required_argument,0,0}, // optidx=42 + {"hostlist-auto",required_argument,0,0}, // optidx=43 + {"hostlist-auto-fail-threshold",required_argument,0,0}, // optidx=44 + {"hostlist-auto-fail-time",required_argument,0,0}, // optidx=45 + {"hostlist-auto-retrans-threshold",required_argument,0,0}, // optidx=46 + {"hostlist-auto-debug",required_argument,0,0}, // optidx=47 #ifdef __linux__ - {"bind-fix4",no_argument,0,0}, // optidx=47 - {"bind-fix6",no_argument,0,0}, // optidx=48 + {"bind-fix4",no_argument,0,0}, // optidx=48 + {"bind-fix6",no_argument,0,0}, // optidx=49 #endif {NULL,0,NULL,0} }; @@ -1077,30 +1080,34 @@ int main(int argc, char **argv) params.fake_unknown_size = sizeof(params.fake_unknown); load_file_or_exit(optarg,params.fake_unknown,¶ms.fake_unknown_size); break; - case 33: /* dpi-desync-fake-quic */ + case 33: /* dpi-desync-fake-syndata */ + params.fake_syndata_size = sizeof(params.fake_syndata); + load_file_or_exit(optarg,params.fake_syndata,¶ms.fake_syndata_size); + break; + case 34: /* dpi-desync-fake-quic */ params.fake_quic_size = sizeof(params.fake_quic); load_file_or_exit(optarg,params.fake_quic,¶ms.fake_quic_size); break; - case 34: /* dpi-desync-fake-wireguard */ + case 35: /* dpi-desync-fake-wireguard */ params.fake_wg_size = sizeof(params.fake_wg); load_file_or_exit(optarg,params.fake_wg,¶ms.fake_wg_size); break; - case 35: /* dpi-desync-fake-dht */ + case 36: /* dpi-desync-fake-dht */ params.fake_dht_size = sizeof(params.fake_dht); load_file_or_exit(optarg,params.fake_dht,¶ms.fake_dht_size); break; - case 36: /* dpi-desync-fake-unknown-udp */ + case 37: /* dpi-desync-fake-unknown-udp */ params.fake_unknown_udp_size = sizeof(params.fake_unknown_udp); load_file_or_exit(optarg,params.fake_unknown_udp,¶ms.fake_unknown_udp_size); break; - case 37: /* dpi-desync-udplen-increment */ + case 38: /* dpi-desync-udplen-increment */ if (sscanf(optarg,"%d",¶ms.udplen_increment)<1 || params.udplen_increment>0x7FFF || params.udplen_increment<-0x8000) { fprintf(stderr, "dpi-desync-udplen-increment must be integer within -32768..32767 range\n"); exit_clean(1); } break; - case 38: /* dpi-desync-udplen-pattern */ + case 39: /* dpi-desync-udplen-pattern */ { char buf[sizeof(params.udplen_pattern)]; size_t sz=sizeof(buf); @@ -1108,28 +1115,28 @@ int main(int argc, char **argv) fill_pattern(params.udplen_pattern,sizeof(params.udplen_pattern),buf,sz); } break; - case 39: /* desync-cutoff */ + case 40: /* desync-cutoff */ if (!parse_cutoff(optarg, ¶ms.desync_cutoff, ¶ms.desync_cutoff_mode)) { fprintf(stderr, "invalid desync-cutoff value\n"); exit_clean(1); } break; - case 40: /* hostlist */ + case 41: /* hostlist */ if (!strlist_add(¶ms.hostlist_files, optarg)) { fprintf(stderr, "strlist_add failed\n"); exit_clean(1); } break; - case 41: /* hostlist-exclude */ + case 42: /* hostlist-exclude */ if (!strlist_add(¶ms.hostlist_exclude_files, optarg)) { fprintf(stderr, "strlist_add failed\n"); exit_clean(1); } break; - case 42: /* hostlist-auto */ + case 43: /* hostlist-auto */ if (*params.hostlist_auto_filename) { fprintf(stderr, "only one auto hostlist is supported\n"); @@ -1160,7 +1167,7 @@ int main(int argc, char **argv) strncpy(params.hostlist_auto_filename, optarg, sizeof(params.hostlist_auto_filename)); params.hostlist_auto_filename[sizeof(params.hostlist_auto_filename) - 1] = '\0'; break; - case 43: /* hostlist-auto-fail-threshold */ + case 44: /* hostlist-auto-fail-threshold */ params.hostlist_auto_fail_threshold = (uint8_t)atoi(optarg); if (params.hostlist_auto_fail_threshold<1 || params.hostlist_auto_fail_threshold>20) { @@ -1168,7 +1175,7 @@ int main(int argc, char **argv) exit_clean(1); } break; - case 44: /* hostlist-auto-fail-time */ + case 45: /* hostlist-auto-fail-time */ params.hostlist_auto_fail_time = (uint8_t)atoi(optarg); if (params.hostlist_auto_fail_time<1) { @@ -1176,7 +1183,7 @@ int main(int argc, char **argv) exit_clean(1); } break; - case 45: /* hostlist-auto-retrans-threshold */ + case 46: /* hostlist-auto-retrans-threshold */ params.hostlist_auto_retrans_threshold = (uint8_t)atoi(optarg); if (params.hostlist_auto_retrans_threshold<2 || params.hostlist_auto_retrans_threshold>10) { @@ -1184,7 +1191,7 @@ int main(int argc, char **argv) exit_clean(1); } break; - case 46: /* hostlist-auto-debug */ + case 47: /* hostlist-auto-debug */ { FILE *F = fopen(optarg,"a+t"); if (!F) @@ -1200,10 +1207,10 @@ int main(int argc, char **argv) } break; #ifdef __linux__ - case 47: /* bind-fix4 */ + case 48: /* bind-fix4 */ params.bind_fix4 = true; break; - case 48: /* bind-fix6 */ + case 49: /* bind-fix6 */ params.bind_fix6 = true; break; #endif diff --git a/nfq/params.h b/nfq/params.h index 5da1cd6..cc01667 100644 --- a/nfq/params.h +++ b/nfq/params.h @@ -56,8 +56,9 @@ struct params_s uint32_t desync_fooling_mode; uint32_t desync_fwmark; // unused in BSD uint32_t desync_badseq_increment, desync_badseq_ack_increment; - uint8_t fake_http[1432],fake_tls[1432],fake_quic[1472],fake_wg[1472],fake_dht[1472],fake_unknown[1432],fake_unknown_udp[1472], udplen_pattern[1472]; - size_t fake_http_size,fake_tls_size,fake_quic_size,fake_wg_size,fake_dht_size,fake_unknown_size,fake_unknown_udp_size; + uint8_t fake_http[1460],fake_tls[1460],fake_unknown[1460],fake_syndata[1460]; + uint8_t fake_unknown_udp[1472],udplen_pattern[1472],fake_quic[1472],fake_wg[1472],fake_dht[1472]; + size_t fake_http_size,fake_tls_size,fake_quic_size,fake_wg_size,fake_dht_size,fake_unknown_size,fake_syndata_size,fake_unknown_udp_size; int udplen_increment; bool droproot; uid_t uid;