diff --git a/binaries/aarch64/nfqws b/binaries/aarch64/nfqws index 64885cb2..06b82d94 100755 Binary files a/binaries/aarch64/nfqws and b/binaries/aarch64/nfqws differ diff --git a/binaries/arm/nfqws b/binaries/arm/nfqws index d26a4198..6a370f20 100755 Binary files a/binaries/arm/nfqws and b/binaries/arm/nfqws differ diff --git a/binaries/freebsd-x64/dvtws b/binaries/freebsd-x64/dvtws index 5e4cfe71..ed55a483 100755 Binary files a/binaries/freebsd-x64/dvtws and b/binaries/freebsd-x64/dvtws differ diff --git a/binaries/mips32r1-lsb/nfqws b/binaries/mips32r1-lsb/nfqws index fa301564..ab96a349 100755 Binary files a/binaries/mips32r1-lsb/nfqws and b/binaries/mips32r1-lsb/nfqws differ diff --git a/binaries/mips32r1-msb/nfqws b/binaries/mips32r1-msb/nfqws index 4f7363e2..b792caf7 100755 Binary files a/binaries/mips32r1-msb/nfqws and b/binaries/mips32r1-msb/nfqws differ diff --git a/binaries/mips64r2-msb/nfqws b/binaries/mips64r2-msb/nfqws index 2b7016c1..b8cf2d69 100755 Binary files a/binaries/mips64r2-msb/nfqws and b/binaries/mips64r2-msb/nfqws differ diff --git a/binaries/ppc/nfqws b/binaries/ppc/nfqws index 1ca5e0b0..f55e7364 100755 Binary files a/binaries/ppc/nfqws and b/binaries/ppc/nfqws differ diff --git a/binaries/x86/nfqws b/binaries/x86/nfqws index 32dc195b..ff4a55c9 100755 Binary files a/binaries/x86/nfqws and b/binaries/x86/nfqws differ diff --git a/binaries/x86_64/nfqws b/binaries/x86_64/nfqws index 2502f62f..65b27c90 100755 Binary files a/binaries/x86_64/nfqws and b/binaries/x86_64/nfqws differ diff --git a/blockcheck.sh b/blockcheck.sh index 7acee081..cf0a6ae2 100755 --- a/blockcheck.sh +++ b/blockcheck.sh @@ -589,7 +589,7 @@ pktws_check_domain_bypass() done done [ "$IPV" = 6 ] && { - for desync in hopbyhop hopbyhop,split2 hopbyhop,disorder2; do + for desync in hopbyhop hopbyhop,split2 hopbyhop,disorder2 destopt destopt,split2 destopt,disorder2; do pktws_curl_test_update $1 $3 --dpi-desync=$desync $e done } @@ -600,7 +600,7 @@ pktws_check_domain_bypass() [ "$IPV" = 4 -o -n "$IP6_DEFRAG_DISABLE" ] && { for frag in 24 32 40 64 80 104; do tests="ipfrag2" - [ "$IPV" = 6 ] && tests="$tests hopbyhop,ipfrag2" + [ "$IPV" = 6 ] && tests="$tests hopbyhop,ipfrag2 destopt,ipfrag2" for desync in $tests; do pktws_curl_test_update $1 $3 --dpi-desync=$desync --dpi-desync-ipfrag-pos-tcp=$frag done diff --git a/docs/readme.eng.md b/docs/readme.eng.md index 9595e58c..9656f5b6 100644 --- a/docs/readme.eng.md +++ b/docs/readme.eng.md @@ -239,13 +239,13 @@ Mode `split2` disables sending of fake segments. It can be used as a faster alte In `disorder2` and 'split2` modes no fake packets are sent, so ttl and fooling options are not required. -`hopbyhop` desync mode (it's not the same as `hopbyhop` fooling !) is ipv6 only. One hop-by-hop header -is added to all desynced packets. +`hopbyhop` and `destopt` desync modes (it's not the same as `hopbyhop` fooling !) are ipv6 only. One `hop-by-hop` or +`destination options` header is added to all desynced packets. Extra header increases packet size and can't be applied to the maximum size packets. If it's not possible to send modified packet original one will be sent. The idea here is that DPI sees 0 in the next header field of the main ipv6 header and does not walk through the extension header chain until transport header is found. -`hopbyhop` mode can be used with any second phase mode. +`hopbyhop` and `destopt` modes can be used with any second phase mode. For example, `hopbyhop,split2` means split original tcp packet into 2 pieces and add hop-by-hop header to both. With `hopbyhop,ipfrag2` header sequence will be : `ipv6,hop-by-hop,fragment,tcp/udp`. diff --git a/docs/readme.txt b/docs/readme.txt index b0c2470a..7d5a2ac4 100644 --- a/docs/readme.txt +++ b/docs/readme.txt @@ -187,7 +187,7 @@ nfqws --hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета --hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase --domcase ; домен после Host: сделать таким : TeSt.cOm - --dpi-desync=[,][,,][, ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000 --dpi-desync-ttl= ; установить ttl для десинхронизирующих пакетов --dpi-desync-ttl6= ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение ttl @@ -293,8 +293,8 @@ nfqws disorder2 и split2 не предполагают отсылку фейк пакетов, поэтому опции ttl и fooling неактуальны. -Режим десинхронизации hopbyhop (не путать с fooling !) относится только к ipv6 и заключается в добавлении -хедера "hop-by-hop options" во все пакеты, попадающие под десинхронизацию. +Режимы десинхронизации hopbyhop и destopt (не путать с fooling !) относятся только к ipv6 и заключается в добавлении +хедера "hop-by-hop options" или "destination options" во все пакеты, попадающие под десинхронизацию. Здесь надо обязательно понимать, что добавление хедера увеличивает размер пакета, потому не может быть применено к пакетам максимального размера. Это имеет место при передаче больших сообщений. В случае невозможности отослать пакет дурение будет отменено, пакет будет выслан в оригинале. diff --git a/nfq/darkmagic.c b/nfq/darkmagic.c index a7f6be93..e167a4a1 100644 --- a/nfq/darkmagic.c +++ b/nfq/darkmagic.c @@ -205,13 +205,13 @@ bool prepare_tcp_segment6( { uint16_t tcpoptlen = tcpopt_len(fooling,timestamps,scale_factor); uint16_t transport_payload_len = sizeof(struct tcphdr) + tcpoptlen + len; - uint16_t ip_payload_len = transport_payload_len + 8*!!((fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))==FOOL_HOPBYHOP) + 16*!!(fooling & FOOL_HOPBYHOP2); + uint16_t ip_payload_len = transport_payload_len + 8*!!((fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))==FOOL_HOPBYHOP) + 16*!!(fooling & FOOL_HOPBYHOP2) + 8*!!(fooling & FOOL_DESTOPT); uint16_t pktlen = sizeof(struct ip6_hdr) + ip_payload_len; if (pktlen>*buflen) return false; struct ip6_hdr *ip6 = (struct ip6_hdr*)buf; struct tcphdr *tcp = (struct tcphdr*)(ip6+1); - uint8_t proto; + uint8_t proto = IPPROTO_TCP, *nexttype = NULL; if (fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2)) { @@ -226,10 +226,20 @@ bool prepare_tcp_segment6( memset(hbh,0,8); } hbh->ip6h_nxt = IPPROTO_TCP; + nexttype = &hbh->ip6h_nxt; proto = 0; // hop by hop options } - else - proto = IPPROTO_TCP; + if (fooling & FOOL_DESTOPT) + { + struct ip6_dest *dest = (struct ip6_dest*)tcp; + tcp = (struct tcphdr*)((uint8_t*)tcp+8); + memset(dest,0,8); + dest->ip6d_nxt = IPPROTO_TCP; + if (nexttype) + *nexttype = 60; // destination options + else + proto = 60; + } uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen; @@ -299,13 +309,13 @@ bool prepare_udp_segment6( uint8_t *buf, size_t *buflen) { uint16_t transport_payload_len = sizeof(struct udphdr) + len; - uint16_t ip_payload_len = transport_payload_len + 8*!!((fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))==FOOL_HOPBYHOP) + 16*!!(fooling & FOOL_HOPBYHOP2); + uint16_t ip_payload_len = transport_payload_len + 8*!!((fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))==FOOL_HOPBYHOP) + 16*!!(fooling & FOOL_HOPBYHOP2) + 8*!!(fooling & FOOL_DESTOPT) ; uint16_t pktlen = sizeof(struct ip6_hdr) + ip_payload_len; if (pktlen>*buflen) return false; struct ip6_hdr *ip6 = (struct ip6_hdr*)buf; struct udphdr *udp = (struct udphdr*)(ip6+1); - uint8_t proto; + uint8_t proto = IPPROTO_UDP, *nexttype = NULL; if (fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2)) { @@ -320,10 +330,21 @@ bool prepare_udp_segment6( memset(hbh,0,8); } hbh->ip6h_nxt = IPPROTO_UDP; + nexttype = &hbh->ip6h_nxt; proto = 0; // hop by hop options } - else - proto = IPPROTO_UDP; + if (fooling & FOOL_DESTOPT) + { + struct ip6_dest *dest = (struct ip6_dest*)udp; + udp = (struct udphdr*)((uint8_t*)udp+8); + memset(dest,0,8); + dest->ip6d_nxt = IPPROTO_UDP; + if (nexttype) + *nexttype = 60; // destination options + else + proto = 60; + } + uint8_t *payload = (uint8_t*)(udp+1); fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl); @@ -350,17 +371,17 @@ bool prepare_udp_segment( false; } -bool ip6_insert_hopbyhop(uint8_t *data_pkt, size_t len_pkt, uint8_t *buf, size_t *buflen) +bool ip6_insert_simple_hdr(uint8_t type, uint8_t *data_pkt, size_t len_pkt, uint8_t *buf, size_t *buflen) { if ((len_pkt+8)<=*buflen && len_pkt>=sizeof(struct ip6_hdr)) { struct ip6_hdr *ip6 = (struct ip6_hdr *)buf; - struct ip6_hbh *hbh = (struct ip6_hbh*)(ip6+1); + struct ip6_ext *hbh = (struct ip6_ext*)(ip6+1); *ip6 = *(struct ip6_hdr*)data_pkt; memset(hbh,0,8); memcpy((uint8_t*)hbh+8, data_pkt+sizeof(struct ip6_hdr), len_pkt-sizeof(struct ip6_hdr)); - hbh->ip6h_nxt = ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt; - ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt = 0; + hbh->ip6e_nxt = ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt; + ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt = type; ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = net16_add(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen, 8); *buflen = len_pkt + 8; return true; diff --git a/nfq/darkmagic.h b/nfq/darkmagic.h index abb068a8..cf028499 100644 --- a/nfq/darkmagic.h +++ b/nfq/darkmagic.h @@ -22,6 +22,7 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment); #define FOOL_BADSEQ 0x08 #define FOOL_HOPBYHOP 0x10 #define FOOL_HOPBYHOP2 0x20 +#define FOOL_DESTOPT 0x40 #define SCALE_NONE ((uint8_t)-1) @@ -86,7 +87,7 @@ bool prepare_udp_segment( const void *data, uint16_t len, uint8_t *buf, size_t *buflen); -bool ip6_insert_hopbyhop(uint8_t *data_pkt, size_t len_pkt, uint8_t *buf, size_t *buflen); +bool ip6_insert_simple_hdr(uint8_t type, uint8_t *data_pkt, size_t len_pkt, uint8_t *buf, size_t *buflen); // ipv4: ident==-1 - copy ip_id from original ipv4 packet bool ip_frag4( diff --git a/nfq/desync.c b/nfq/desync.c index f8bebf44..236768d4 100644 --- a/nfq/desync.c +++ b/nfq/desync.c @@ -67,7 +67,7 @@ bool desync_valid_zero_stage(enum dpi_desync_mode mode) } bool desync_valid_first_stage(enum dpi_desync_mode mode) { - return mode==DESYNC_FAKE || mode==DESYNC_RST || mode==DESYNC_RSTACK || mode==DESYNC_HOPBYHOP; + return mode==DESYNC_FAKE || mode==DESYNC_RST || mode==DESYNC_RSTACK || mode==DESYNC_HOPBYHOP || mode==DESYNC_DESTOPT; } bool desync_only_first_stage(enum dpi_desync_mode mode) { @@ -101,6 +101,8 @@ enum dpi_desync_mode desync_mode_from_string(const char *s) return DESYNC_IPFRAG2; else if (!strcmp(s,"hopbyhop")) return DESYNC_HOPBYHOP; + else if (!strcmp(s,"destopt")) + return DESYNC_DESTOPT; return DESYNC_INVALID; } @@ -386,21 +388,22 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s b = true; break; case DESYNC_HOPBYHOP: + case DESYNC_DESTOPT: + fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : FOOL_DESTOPT; if (ip6hdr && params.desync_mode2==DESYNC_NONE) { 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,FOOL_HOPBYHOP,0,0, + ttl_orig,fooling_orig,0,0, data_payload, len_payload, pkt1, &pkt1_len)) { return res; } - DLOG("resending original packet with hop-by-hop options\n"); + DLOG("resending original packet with extension header\n"); if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len)) return res; // this mode is final, no other options available return drop; } - fooling_orig = FOOL_HOPBYHOP; desync_mode = params.desync_mode2; } @@ -564,10 +567,10 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s pkt1_len = sizeof(pkt1); pkt2_len = sizeof(pkt2); - if (ip6hdr && fooling_orig==FOOL_HOPBYHOP) + if (ip6hdr && fooling_orig!=FOOL_NONE) { pkt_orig_len = sizeof(pkt3); - if (!ip6_insert_hopbyhop(data_pkt, len_pkt, pkt3, &pkt_orig_len)) + if (!ip6_insert_simple_hdr(fooling_orig==FOOL_HOPBYHOP ? 0 : 60, data_pkt, len_pkt, pkt3, &pkt_orig_len)) return res; pkt_orig = pkt3; } @@ -686,21 +689,22 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s b = true; break; case DESYNC_HOPBYHOP: + case DESYNC_DESTOPT: + fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : FOOL_DESTOPT; if (ip6hdr && params.desync_mode2==DESYNC_NONE) { if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, - ttl_orig,FOOL_HOPBYHOP, + ttl_orig,fooling_orig, data_payload, len_payload, pkt1, &pkt1_len)) { return res; } - DLOG("resending original packet with hop-by-hop options\n"); + DLOG("resending original packet with extension header\n"); if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len)) return res; // this mode is final, no other options available return drop; } - fooling_orig = FOOL_HOPBYHOP; desync_mode = params.desync_mode2; } @@ -751,10 +755,10 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s pkt1_len = sizeof(pkt1); pkt2_len = sizeof(pkt2); - if (ip6hdr && fooling_orig==FOOL_HOPBYHOP) + if (ip6hdr && fooling_orig!=FOOL_NONE) { pkt_orig_len = sizeof(pkt3); - if (!ip6_insert_hopbyhop(data_pkt, len_pkt, pkt3, &pkt_orig_len)) + if (!ip6_insert_simple_hdr(fooling_orig==FOOL_HOPBYHOP ? 0 : 60, data_pkt, len_pkt, pkt3, &pkt_orig_len)) return res; pkt_orig = pkt3; } diff --git a/nfq/desync.h b/nfq/desync.h index 98445f6e..6be6160d 100644 --- a/nfq/desync.h +++ b/nfq/desync.h @@ -30,7 +30,8 @@ enum dpi_desync_mode { DESYNC_SPLIT, DESYNC_SPLIT2, DESYNC_IPFRAG2, - DESYNC_HOPBYHOP + DESYNC_HOPBYHOP, + DESYNC_DESTOPT }; extern const char *fake_http_request_default; diff --git a/nfq/nfqws.c b/nfq/nfqws.c index f803518b..4a450460 100644 --- a/nfq/nfqws.c +++ b/nfq/nfqws.c @@ -505,7 +505,7 @@ static void exithelp() " --hostspell\t\t\t\t; exact spelling of \"Host\" header. must be 4 chars. default is \"host\"\n" " --hostnospace\t\t\t\t; remove space after Host: and add it to User-Agent: to preserve packet size\n" " --domcase\t\t\t\t; mix domain case : Host: TeSt.cOm\n" - " --dpi-desync=[,][,] ; try to desync dpi state. modes : synack fake rst rstack hopbyhop disorder disorder2 split split2 ipfrag2\n" + " --dpi-desync=[,][,] ; try to desync dpi state. modes : synack fake rst rstack hopbyhop destopt disorder disorder2 split split2 ipfrag2\n" #ifdef __linux__ " --dpi-desync-fwmark=\t; override fwmark for desync packet. default = 0x%08X (%u)\n" #elif defined(SO_USER_COOKIE) @@ -870,7 +870,7 @@ int main(int argc, char **argv) params.desync_fooling_mode |= FOOL_HOPBYHOP2; else if (strcmp(p,"none")) { - fprintf(stderr, "dpi-desync-fooling allowed values : none,md5sig,ts,badseq,badsum\n"); + fprintf(stderr, "dpi-desync-fooling allowed values : none,md5sig,ts,badseq,badsum,hopbyhop,hopbyhop2\n"); exit_clean(1); } p = e;