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
[ "$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

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.
`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`.

View File

@ -187,7 +187,7 @@ nfqws
--hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--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-ttl=<int> ; установить ttl для десинхронизирующих пакетов
--dpi-desync-ttl6=<int> ; установить 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" во все пакеты, попадающие под десинхронизацию.
Здесь надо обязательно понимать, что добавление хедера увеличивает размер пакета, потому не может быть применено
к пакетам максимального размера. Это имеет место при передаче больших сообщений.
В случае невозможности отослать пакет дурение будет отменено, пакет будет выслан в оригинале.

View File

@ -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;

View File

@ -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(

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)
{
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;
}

View File

@ -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;

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"
" --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=[<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__
" --dpi-desync-fwmark=<int|0xHEX>\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;