mirror of
https://github.com/bol-van/zapret.git
synced 2024-11-26 20:20:53 +03:00
nfqws: allow hopbyhop with 2nd phase desync
This commit is contained in:
parent
f0a9246fd9
commit
707e86bd90
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.
@ -575,7 +575,6 @@ pktws_check_domain_bypass()
|
||||
pktws_curl_test_update $1 $3 --dpi-desync=$desync $e
|
||||
done
|
||||
}
|
||||
[ "$IPV" = 6 ] && pktws_curl_test_update $1 $3 --dpi-desync=hopbyhop $e
|
||||
for desync in $tests; do
|
||||
s="--dpi-desync=$desync"
|
||||
for ttl in $ttls; do
|
||||
@ -588,13 +587,22 @@ pktws_check_domain_bypass()
|
||||
echo 'WARNING ! although md5sig fooling worked it will not work on all sites. it typically works only on linux servers.'
|
||||
done
|
||||
done
|
||||
[ "$IPV" = 6 ] && {
|
||||
for desync in hopbyhop hopbyhop,split2 hopbyhop,disorder2; do
|
||||
pktws_curl_test_update $1 $3 --dpi-desync=$desync $e
|
||||
done
|
||||
}
|
||||
# do not do wssize test for http. it's useless
|
||||
[ "$sec" = 1 ] || break
|
||||
done
|
||||
|
||||
[ "$IPV" = 4 -o -n "$IP6_DEFRAG_DISABLE" ] && {
|
||||
for frag in 24 32 40 64 80 104; do
|
||||
pktws_curl_test_update $1 $3 --dpi-desync=ipfrag2 --dpi-desync-ipfrag-pos-tcp=$frag
|
||||
tests="ipfrag2"
|
||||
[ "$IPV" = 6 ] && tests="$tests hopbyhop,ipfrag2"
|
||||
for desync in $tests; do
|
||||
pktws_curl_test_update $1 $3 --dpi-desync=$desync --dpi-desync-ipfrag-pos-tcp=$frag
|
||||
done
|
||||
done
|
||||
}
|
||||
|
||||
|
@ -245,7 +245,9 @@ Extra header increases packet size and can't be applied to the maximum size pack
|
||||
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 cannot be used with second phase modes.
|
||||
`hopbyhop` mode 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`.
|
||||
|
||||
There are DPIs that analyze responses from the server, particularly the certificate from the ServerHello
|
||||
that contain domain name(s). The ClientHello delivery confirmation is an ACK packet from the server
|
||||
|
@ -301,7 +301,9 @@ disorder2 и split2 не предполагают отсылку фейк пак
|
||||
Расчет идет на то, что DPI увидит 0 в поле next header основного заголовка ipv6 и не будет скакать по
|
||||
extension хедерам в поисках транспортного хедера. Таким образом не поймет, что это tcp или udp, и пропустит пакет
|
||||
без анализа. Возможно, какие-то DPI на это купятся.
|
||||
hopbyhop исключает применение режимов 2-й фазы.
|
||||
Может сочетаться с любыми режимами 2-й фазы.
|
||||
Например, "hopbyhop,split2" означает разбить tcp пакет на 2 сегмента, в каждый из них добавить hop-by-hop.
|
||||
При "hopbyhop,ipfrag2" последовательность хедеров будет : ipv6,hop-by-hop,fragment,tcp/udp.
|
||||
|
||||
Есть DPI, которые анализируют ответы от сервера, в частности сертификат из ServerHello, где прописаны домены.
|
||||
Подтверждением доставки ClientHello является ACK пакет от сервера с номером ACK sequence, соответствующим длине ClientHello+1.
|
||||
|
@ -16,6 +16,10 @@ uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment)
|
||||
{
|
||||
return htonl(ntohl(netorder_value)+cpuorder_increment);
|
||||
}
|
||||
uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment)
|
||||
{
|
||||
return htons(ntohs(netorder_value)+cpuorder_increment);
|
||||
}
|
||||
|
||||
uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind)
|
||||
{
|
||||
@ -346,7 +350,23 @@ bool prepare_udp_segment(
|
||||
false;
|
||||
}
|
||||
|
||||
|
||||
bool ip6_insert_hopbyhop(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);
|
||||
*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;
|
||||
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;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// split ipv4 packet into 2 fragments at data payload position frag_pos
|
||||
bool ip_frag4(
|
||||
|
@ -13,6 +13,7 @@
|
||||
|
||||
// returns netorder value
|
||||
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment);
|
||||
uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
|
||||
|
||||
#define FOOL_NONE 0x00
|
||||
#define FOOL_MD5SIG 0x01
|
||||
@ -85,6 +86,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);
|
||||
|
||||
// ipv4: ident==-1 - copy ip_id from original ipv4 packet
|
||||
bool ip_frag4(
|
||||
|
75
nfq/desync.c
75
nfq/desync.c
@ -51,7 +51,7 @@ const uint8_t fake_tls_clienthello_default[517] = {
|
||||
};
|
||||
|
||||
#define PKTDATA_MAXDUMP 32
|
||||
#define IP_MAXDUMP 64
|
||||
#define IP_MAXDUMP 80
|
||||
|
||||
static uint8_t zeropkt[DPI_DESYNC_MAX_FAKE_LEN];
|
||||
|
||||
@ -71,7 +71,7 @@ bool desync_valid_first_stage(enum dpi_desync_mode mode)
|
||||
}
|
||||
bool desync_only_first_stage(enum dpi_desync_mode mode)
|
||||
{
|
||||
return mode==DESYNC_HOPBYHOP;
|
||||
return false;
|
||||
}
|
||||
bool desync_valid_second_stage(enum dpi_desync_mode mode)
|
||||
{
|
||||
@ -356,6 +356,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
}
|
||||
|
||||
enum dpi_desync_mode desync_mode = params.desync_mode;
|
||||
uint8_t fooling_orig = FOOL_NONE;
|
||||
bool b;
|
||||
|
||||
pkt1_len = sizeof(pkt1);
|
||||
@ -385,7 +386,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
b = true;
|
||||
break;
|
||||
case DESYNC_HOPBYHOP:
|
||||
if (ip6hdr)
|
||||
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,
|
||||
@ -399,7 +400,8 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
// this mode is final, no other options available
|
||||
return drop;
|
||||
}
|
||||
return res;
|
||||
fooling_orig = FOOL_HOPBYHOP;
|
||||
desync_mode = params.desync_mode2;
|
||||
}
|
||||
|
||||
if (b)
|
||||
@ -444,7 +446,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
if (split_pos<len_payload)
|
||||
{
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(tcphdr->th_seq,split_pos), tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
|
||||
ttl_orig,FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
|
||||
ttl_orig,fooling_orig,params.desync_badseq_increment,params.desync_badseq_ack_increment,
|
||||
data_payload+split_pos, len_payload-split_pos, pkt1, &pkt1_len))
|
||||
return res;
|
||||
DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu : ",split_pos,len_payload-1, len_payload-split_pos)
|
||||
@ -470,7 +472,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
|
||||
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,FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
|
||||
ttl_orig,fooling_orig,params.desync_badseq_increment,params.desync_badseq_ack_increment,
|
||||
data_payload, split_pos, pkt1, &pkt1_len))
|
||||
return res;
|
||||
DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos)
|
||||
@ -510,7 +512,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
|
||||
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,FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
|
||||
ttl_orig,fooling_orig,params.desync_badseq_increment,params.desync_badseq_ack_increment,
|
||||
data_payload, split_pos, pkt1, &pkt1_len))
|
||||
return res;
|
||||
DLOG("sending 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos)
|
||||
@ -530,7 +532,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
{
|
||||
pkt1_len = sizeof(pkt1);
|
||||
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(tcphdr->th_seq,split_pos), tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
|
||||
ttl_orig,FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
|
||||
ttl_orig,fooling_orig,params.desync_badseq_increment,params.desync_badseq_ack_increment,
|
||||
data_payload+split_pos, len_payload-split_pos, pkt1, &pkt1_len))
|
||||
return res;
|
||||
DLOG("sending 2nd tcp segment %zu-%zu len=%zu : ",split_pos,len_payload-1, len_payload-split_pos)
|
||||
@ -546,9 +548,15 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
{
|
||||
#ifdef __FreeBSD__
|
||||
// FreeBSD tend to pass ipv6 frames with wrong checksum
|
||||
if (ip6hdr)
|
||||
tcp_fix_checksum(tcphdr,len_tcp,ip,ip6hdr);
|
||||
if (res==modify || ip6hdr)
|
||||
#else
|
||||
// if original packet was tampered earlier it needs checksum fixed
|
||||
if (res==modify)
|
||||
#endif
|
||||
tcp_fix_checksum(tcphdr,len_tcp,ip,ip6hdr);
|
||||
|
||||
uint8_t pkt3[DPI_DESYNC_MAX_FAKE_LEN+100], *pkt_orig;
|
||||
size_t pkt_orig_len;
|
||||
|
||||
size_t ipfrag_pos = (params.desync_ipfrag_pos_tcp && params.desync_ipfrag_pos_tcp<len_tcp) ? params.desync_ipfrag_pos_tcp : 24;
|
||||
uint32_t ident = ip ? ip->ip_id ? ip->ip_id : htons(1+random()%0xFFFF) : htonl(1+random()&0xFFFFFFFF);
|
||||
@ -556,7 +564,20 @@ 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 (!ip_frag(data_pkt, len_pkt, ipfrag_pos, ident, pkt1, &pkt1_len, pkt2, &pkt2_len))
|
||||
if (ip6hdr && fooling_orig==FOOL_HOPBYHOP)
|
||||
{
|
||||
pkt_orig_len = sizeof(pkt3);
|
||||
if (!ip6_insert_hopbyhop(data_pkt, len_pkt, pkt3, &pkt_orig_len))
|
||||
return res;
|
||||
pkt_orig = pkt3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pkt_orig = data_pkt;
|
||||
pkt_orig_len = len_pkt;
|
||||
}
|
||||
|
||||
if (!ip_frag(pkt_orig, pkt_orig_len, ipfrag_pos, ident, pkt1, &pkt1_len, pkt2, &pkt2_len))
|
||||
return res;
|
||||
|
||||
DLOG("sending 1st ip fragment 0-%zu len=%zu : ", ipfrag_pos-1, ipfrag_pos)
|
||||
@ -633,6 +654,7 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
DLOG("applying tampering to unknown protocol\n")
|
||||
|
||||
enum dpi_desync_mode desync_mode = params.desync_mode;
|
||||
uint8_t fooling_orig = FOOL_NONE;
|
||||
|
||||
ttl_orig = ip ? ip->ip_ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim;
|
||||
if (ip6hdr) ttl_fake = params.desync_ttl6 ? params.desync_ttl6 : ttl_orig;
|
||||
@ -653,6 +675,7 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
|
||||
pkt1_len = sizeof(pkt1);
|
||||
b = false;
|
||||
|
||||
switch(desync_mode)
|
||||
{
|
||||
case DESYNC_FAKE:
|
||||
@ -663,7 +686,7 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
b = true;
|
||||
break;
|
||||
case DESYNC_HOPBYHOP:
|
||||
if (ip6hdr)
|
||||
if (ip6hdr && params.desync_mode2==DESYNC_NONE)
|
||||
{
|
||||
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
|
||||
ttl_orig,FOOL_HOPBYHOP,
|
||||
@ -677,7 +700,8 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
// this mode is final, no other options available
|
||||
return drop;
|
||||
}
|
||||
return res;
|
||||
fooling_orig = FOOL_HOPBYHOP;
|
||||
desync_mode = params.desync_mode2;
|
||||
}
|
||||
|
||||
if (b)
|
||||
@ -709,9 +733,15 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
|
||||
|
||||
#ifdef __FreeBSD__
|
||||
// FreeBSD tend to pass ipv6 frames with wrong checksum
|
||||
if (ip6hdr)
|
||||
udp_fix_checksum(udphdr,sizeof(struct udphdr)+len_payload,ip,ip6hdr);
|
||||
if (res==modify || ip6hdr)
|
||||
#else
|
||||
// if original packet was tampered earlier it needs checksum fixed
|
||||
if (res==modify)
|
||||
#endif
|
||||
udp_fix_checksum(udphdr,sizeof(struct udphdr)+len_payload,ip,ip6hdr);
|
||||
|
||||
uint8_t pkt3[DPI_DESYNC_MAX_FAKE_LEN+100], *pkt_orig;
|
||||
size_t pkt_orig_len;
|
||||
|
||||
size_t len_transport = len_payload + sizeof(struct udphdr);
|
||||
size_t ipfrag_pos = (params.desync_ipfrag_pos_udp && params.desync_ipfrag_pos_udp<len_transport) ? params.desync_ipfrag_pos_udp : sizeof(struct udphdr);
|
||||
@ -721,7 +751,20 @@ 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 (!ip_frag(data_pkt, len_pkt, ipfrag_pos, ident, pkt1, &pkt1_len, pkt2, &pkt2_len))
|
||||
if (ip6hdr && fooling_orig==FOOL_HOPBYHOP)
|
||||
{
|
||||
pkt_orig_len = sizeof(pkt3);
|
||||
if (!ip6_insert_hopbyhop(data_pkt, len_pkt, pkt3, &pkt_orig_len))
|
||||
return res;
|
||||
pkt_orig = pkt3;
|
||||
}
|
||||
else
|
||||
{
|
||||
pkt_orig = data_pkt;
|
||||
pkt_orig_len = len_pkt;
|
||||
}
|
||||
|
||||
if (!ip_frag(pkt_orig, pkt_orig_len, ipfrag_pos, ident, pkt1, &pkt1_len, pkt2, &pkt2_len))
|
||||
return res;
|
||||
|
||||
DLOG("sending 1st ip fragment 0-%zu len=%zu : ", ipfrag_pos-1, ipfrag_pos)
|
||||
|
Loading…
Reference in New Issue
Block a user