nfqws: destopt desync mode

This commit is contained in:
bol-van 2022-02-05 13:36:03 +03:00
parent 3ee381aff6
commit 6151afe727
17 changed files with 62 additions and 35 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -589,7 +589,7 @@ pktws_check_domain_bypass()
done done
done done
[ "$IPV" = 6 ] && { [ "$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 pktws_curl_test_update $1 $3 --dpi-desync=$desync $e
done done
} }
@ -600,7 +600,7 @@ pktws_check_domain_bypass()
[ "$IPV" = 4 -o -n "$IP6_DEFRAG_DISABLE" ] && { [ "$IPV" = 4 -o -n "$IP6_DEFRAG_DISABLE" ] && {
for frag in 24 32 40 64 80 104; do for frag in 24 32 40 64 80 104; do
tests="ipfrag2" tests="ipfrag2"
[ "$IPV" = 6 ] && tests="$tests hopbyhop,ipfrag2" [ "$IPV" = 6 ] && tests="$tests hopbyhop,ipfrag2 destopt,ipfrag2"
for desync in $tests; do for desync in $tests; do
pktws_curl_test_update $1 $3 --dpi-desync=$desync --dpi-desync-ipfrag-pos-tcp=$frag pktws_curl_test_update $1 $3 --dpi-desync=$desync --dpi-desync-ipfrag-pos-tcp=$frag
done done

View File

@ -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. 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 `hopbyhop` and `destopt` desync modes (it's not the same as `hopbyhop` fooling !) are ipv6 only. One `hop-by-hop` or
is added to all desynced packets. `destination options` header is added to all desynced packets.
Extra header increases packet size and can't be applied to the maximum size 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. 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 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. 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. 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`. With `hopbyhop,ipfrag2` header sequence will be : `ipv6,hop-by-hop,fragment,tcp/udp`.

View File

@ -187,7 +187,7 @@ nfqws
--hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета --hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase --hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--domcase ; домен после Host: сделать таким : TeSt.cOm --domcase ; домен после Host: сделать таким : TeSt.cOm
--dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack fake rst rstack hopbyhop disorder disorder2 split split2 ipfrag2 --dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack fake rst rstack hopbyhop destopt disorder disorder2 split split2 ipfrag2
--dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000 --dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
--dpi-desync-ttl=<int> ; установить ttl для десинхронизирующих пакетов --dpi-desync-ttl=<int> ; установить ttl для десинхронизирующих пакетов
--dpi-desync-ttl6=<int> ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение ttl --dpi-desync-ttl6=<int> ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение ttl
@ -293,8 +293,8 @@ nfqws
disorder2 и split2 не предполагают отсылку фейк пакетов, поэтому опции ttl и fooling неактуальны. disorder2 и split2 не предполагают отсылку фейк пакетов, поэтому опции ttl и fooling неактуальны.
Режим десинхронизации hopbyhop (не путать с fooling !) относится только к ipv6 и заключается в добавлении Режимы десинхронизации hopbyhop и destopt (не путать с fooling !) относятся только к ipv6 и заключается в добавлении
хедера "hop-by-hop options" во все пакеты, попадающие под десинхронизацию. хедера "hop-by-hop options" или "destination options" во все пакеты, попадающие под десинхронизацию.
Здесь надо обязательно понимать, что добавление хедера увеличивает размер пакета, потому не может быть применено Здесь надо обязательно понимать, что добавление хедера увеличивает размер пакета, потому не может быть применено
к пакетам максимального размера. Это имеет место при передаче больших сообщений. к пакетам максимального размера. Это имеет место при передаче больших сообщений.
В случае невозможности отослать пакет дурение будет отменено, пакет будет выслан в оригинале. В случае невозможности отослать пакет дурение будет отменено, пакет будет выслан в оригинале.

View File

@ -205,13 +205,13 @@ bool prepare_tcp_segment6(
{ {
uint16_t tcpoptlen = tcpopt_len(fooling,timestamps,scale_factor); uint16_t tcpoptlen = tcpopt_len(fooling,timestamps,scale_factor);
uint16_t transport_payload_len = sizeof(struct tcphdr) + tcpoptlen + len; 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; uint16_t pktlen = sizeof(struct ip6_hdr) + ip_payload_len;
if (pktlen>*buflen) return false; if (pktlen>*buflen) return false;
struct ip6_hdr *ip6 = (struct ip6_hdr*)buf; struct ip6_hdr *ip6 = (struct ip6_hdr*)buf;
struct tcphdr *tcp = (struct tcphdr*)(ip6+1); struct tcphdr *tcp = (struct tcphdr*)(ip6+1);
uint8_t proto; uint8_t proto = IPPROTO_TCP, *nexttype = NULL;
if (fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2)) if (fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))
{ {
@ -226,10 +226,20 @@ bool prepare_tcp_segment6(
memset(hbh,0,8); memset(hbh,0,8);
} }
hbh->ip6h_nxt = IPPROTO_TCP; hbh->ip6h_nxt = IPPROTO_TCP;
nexttype = &hbh->ip6h_nxt;
proto = 0; // hop by hop options proto = 0; // hop by hop options
} }
else if (fooling & FOOL_DESTOPT)
proto = IPPROTO_TCP; {
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; uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen;
@ -299,13 +309,13 @@ bool prepare_udp_segment6(
uint8_t *buf, size_t *buflen) uint8_t *buf, size_t *buflen)
{ {
uint16_t transport_payload_len = sizeof(struct udphdr) + len; 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; uint16_t pktlen = sizeof(struct ip6_hdr) + ip_payload_len;
if (pktlen>*buflen) return false; if (pktlen>*buflen) return false;
struct ip6_hdr *ip6 = (struct ip6_hdr*)buf; struct ip6_hdr *ip6 = (struct ip6_hdr*)buf;
struct udphdr *udp = (struct udphdr*)(ip6+1); struct udphdr *udp = (struct udphdr*)(ip6+1);
uint8_t proto; uint8_t proto = IPPROTO_UDP, *nexttype = NULL;
if (fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2)) if (fooling & (FOOL_HOPBYHOP|FOOL_HOPBYHOP2))
{ {
@ -320,10 +330,21 @@ bool prepare_udp_segment6(
memset(hbh,0,8); memset(hbh,0,8);
} }
hbh->ip6h_nxt = IPPROTO_UDP; hbh->ip6h_nxt = IPPROTO_UDP;
nexttype = &hbh->ip6h_nxt;
proto = 0; // hop by hop options proto = 0; // hop by hop options
} }
else if (fooling & FOOL_DESTOPT)
proto = IPPROTO_UDP; {
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); uint8_t *payload = (uint8_t*)(udp+1);
fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl); fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl);
@ -350,17 +371,17 @@ bool prepare_udp_segment(
false; 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)) if ((len_pkt+8)<=*buflen && len_pkt>=sizeof(struct ip6_hdr))
{ {
struct ip6_hdr *ip6 = (struct ip6_hdr *)buf; 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; *ip6 = *(struct ip6_hdr*)data_pkt;
memset(hbh,0,8); memset(hbh,0,8);
memcpy((uint8_t*)hbh+8, data_pkt+sizeof(struct ip6_hdr), len_pkt-sizeof(struct ip6_hdr)); 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; hbh->ip6e_nxt = ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt = 0; 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); ip6->ip6_ctlun.ip6_un1.ip6_un1_plen = net16_add(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen, 8);
*buflen = len_pkt + 8; *buflen = len_pkt + 8;
return true; return true;

View File

@ -22,6 +22,7 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
#define FOOL_BADSEQ 0x08 #define FOOL_BADSEQ 0x08
#define FOOL_HOPBYHOP 0x10 #define FOOL_HOPBYHOP 0x10
#define FOOL_HOPBYHOP2 0x20 #define FOOL_HOPBYHOP2 0x20
#define FOOL_DESTOPT 0x40
#define SCALE_NONE ((uint8_t)-1) #define SCALE_NONE ((uint8_t)-1)
@ -86,7 +87,7 @@ bool prepare_udp_segment(
const void *data, uint16_t len, const void *data, uint16_t len,
uint8_t *buf, size_t *buflen); 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 // ipv4: ident==-1 - copy ip_id from original ipv4 packet
bool ip_frag4( bool ip_frag4(

View File

@ -67,7 +67,7 @@ bool desync_valid_zero_stage(enum dpi_desync_mode mode)
} }
bool desync_valid_first_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) 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; return DESYNC_IPFRAG2;
else if (!strcmp(s,"hopbyhop")) else if (!strcmp(s,"hopbyhop"))
return DESYNC_HOPBYHOP; return DESYNC_HOPBYHOP;
else if (!strcmp(s,"destopt"))
return DESYNC_DESTOPT;
return DESYNC_INVALID; 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; b = true;
break; break;
case DESYNC_HOPBYHOP: case DESYNC_HOPBYHOP:
case DESYNC_DESTOPT:
fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : FOOL_DESTOPT;
if (ip6hdr && params.desync_mode2==DESYNC_NONE) 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, 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)) data_payload, len_payload, pkt1, &pkt1_len))
{ {
return res; 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)) if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res; return res;
// this mode is final, no other options available // this mode is final, no other options available
return drop; return drop;
} }
fooling_orig = FOOL_HOPBYHOP;
desync_mode = params.desync_mode2; 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); pkt1_len = sizeof(pkt1);
pkt2_len = sizeof(pkt2); pkt2_len = sizeof(pkt2);
if (ip6hdr && fooling_orig==FOOL_HOPBYHOP) if (ip6hdr && fooling_orig!=FOOL_NONE)
{ {
pkt_orig_len = sizeof(pkt3); 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; return res;
pkt_orig = pkt3; 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; b = true;
break; break;
case DESYNC_HOPBYHOP: case DESYNC_HOPBYHOP:
case DESYNC_DESTOPT:
fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : FOOL_DESTOPT;
if (ip6hdr && params.desync_mode2==DESYNC_NONE) if (ip6hdr && params.desync_mode2==DESYNC_NONE)
{ {
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, 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)) data_payload, len_payload, pkt1, &pkt1_len))
{ {
return res; 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)) if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res; return res;
// this mode is final, no other options available // this mode is final, no other options available
return drop; return drop;
} }
fooling_orig = FOOL_HOPBYHOP;
desync_mode = params.desync_mode2; 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); pkt1_len = sizeof(pkt1);
pkt2_len = sizeof(pkt2); pkt2_len = sizeof(pkt2);
if (ip6hdr && fooling_orig==FOOL_HOPBYHOP) if (ip6hdr && fooling_orig!=FOOL_NONE)
{ {
pkt_orig_len = sizeof(pkt3); 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; return res;
pkt_orig = pkt3; pkt_orig = pkt3;
} }

View File

@ -30,7 +30,8 @@ enum dpi_desync_mode {
DESYNC_SPLIT, DESYNC_SPLIT,
DESYNC_SPLIT2, DESYNC_SPLIT2,
DESYNC_IPFRAG2, DESYNC_IPFRAG2,
DESYNC_HOPBYHOP DESYNC_HOPBYHOP,
DESYNC_DESTOPT
}; };
extern const char *fake_http_request_default; extern const char *fake_http_request_default;

View File

@ -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" " --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" " --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" " --domcase\t\t\t\t; mix domain case : Host: TeSt.cOm\n"
" --dpi-desync=[<mode0>,]<mode>[,<mode2>] ; try to desync dpi state. modes : synack fake rst rstack hopbyhop disorder disorder2 split split2 ipfrag2\n" " --dpi-desync=[<mode0>,]<mode>[,<mode2>] ; try to desync dpi state. modes : synack fake rst rstack hopbyhop destopt disorder disorder2 split split2 ipfrag2\n"
#ifdef __linux__ #ifdef __linux__
" --dpi-desync-fwmark=<int|0xHEX>\t; override fwmark for desync packet. default = 0x%08X (%u)\n" " --dpi-desync-fwmark=<int|0xHEX>\t; override fwmark for desync packet. default = 0x%08X (%u)\n"
#elif defined(SO_USER_COOKIE) #elif defined(SO_USER_COOKIE)
@ -870,7 +870,7 @@ int main(int argc, char **argv)
params.desync_fooling_mode |= FOOL_HOPBYHOP2; params.desync_fooling_mode |= FOOL_HOPBYHOP2;
else if (strcmp(p,"none")) 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); exit_clean(1);
} }
p = e; p = e;