diff --git a/binaries/aarch64/nfqws b/binaries/aarch64/nfqws index 64885cb..06b82d9 100755 Binary files a/binaries/aarch64/nfqws and b/binaries/aarch64/nfqws differ diff --git a/binaries/arm/nfqws b/binaries/arm/nfqws index d26a419..6a370f2 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 5e4cfe7..ed55a48 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 fa30156..ab96a34 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 4f7363e..b792caf 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 2b7016c..b8cf2d6 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 1ca5e0b..f55e736 100755 Binary files a/binaries/ppc/nfqws and b/binaries/ppc/nfqws differ diff --git a/binaries/x86/nfqws b/binaries/x86/nfqws index 32dc195..ff4a55c 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 2502f62..65b27c9 100755 Binary files a/binaries/x86_64/nfqws and b/binaries/x86_64/nfqws differ diff --git a/blockcheck.sh b/blockcheck.sh index 7acee08..cf0a6ae 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 9595e58..9656f5b 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 b0c2470..7d5a2ac 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 a7f6be9..e167a4a 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 abb068a..cf02849 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 f8bebf4..236768d 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 98445f6..6be6160 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 f803518..4a45046 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;