mirror of
https://github.com/bol-van/zapret.git
synced 2024-11-26 20:20:53 +03:00
nfqws: ipv6 fragment at transport header
This commit is contained in:
parent
85517a3851
commit
6b39411454
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.
@ -148,8 +148,8 @@ nfqws takes the following parameters:
|
||||
--dpi-desync-repeats=<N> ; send every desync packet N times
|
||||
--dpi-desync-skip-nosni=0|1 ; 1(default)=do not apply desync to requests without hostname in the SNI
|
||||
--dpi-desync-split-pos=<1..1500> ; (for split* and disorder* only) split TCP packet at specified position
|
||||
--dpi-desync-ipfrag-pos-tcp=<8..9216> ; ip frag position starting from the second header (usually transport header). multiple of 8, default 8.
|
||||
--dpi-desync-ipfrag-pos-udp=<8..9216> ; ip frag position starting from the second header (usually transport header). multiple of 8, default 32.
|
||||
--dpi-desync-ipfrag-pos-tcp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 8.
|
||||
--dpi-desync-ipfrag-pos-udp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 32.
|
||||
--dpi-desync-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment. default -10000
|
||||
--dpi-desync-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment. default -66000
|
||||
--dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet
|
||||
@ -397,11 +397,11 @@ By default fake payload is 64 zeroes. Can be overriden using `--dpi-desync-fake-
|
||||
|
||||
Modern network is very hostile to IP fragmentation. Fragmented packets are often not delivered or refragmented/reassembled on the way.
|
||||
Frag position is set independently for tcp and udp. By default 24 and 8, must be multiple of 8.
|
||||
Offset starts from the header following ip header - transport header in most cases.
|
||||
Offset starts from the transport header.
|
||||
|
||||
There are important nuances when working with fragments in Linux.
|
||||
ipv4 : Linux allows to send ipv4 fragments but standard firewall rules in OUTPUT chain can drop them.
|
||||
ipv6 : There's no way for an application to reliably send fragments without defragmentation in conntrack.
|
||||
ipv4 : Linux allows to send ipv4 fragments but standard firewall rules in OUTPUT chain can cause raw send to fail.
|
||||
ipv6 : There's no way for an application to reliably send fragments without defragmentation by conntrack.
|
||||
Sometimes it works, sometimes system defragments packets.
|
||||
Looks like kernels <4.16 have no simple way to solve this problem. Unloading of nf_conntrack module
|
||||
and its dependency nf_defrag_ipv6 helps but this severely impacts functionality.
|
||||
|
@ -1,4 +1,4 @@
|
||||
zapret v.44
|
||||
zapret v.44
|
||||
|
||||
English
|
||||
-------
|
||||
@ -427,12 +427,12 @@ window size итоговый размер окна стал максимальн
|
||||
IP ФРАГМЕНТАЦИЯ
|
||||
В современной сети с этом все очень плохо. Фрагментированные пакеты застревают по пути, часто отбрасываются.
|
||||
Иногда доходят. Иногда то доходят, то не доходят. Может зависеть от версии ipv4/ipv6.
|
||||
Роутеры на базе linux и freebsd могут самопроизвольно собирать или перефрагментировать пакеты.
|
||||
Роутеры на базе linux могут самопроизвольно собирать или перефрагментировать пакеты.
|
||||
Позиция фрагментации задается отдельно для tcp и udp. По умолчанию 24 и 8 соответственно, должна быть кратна 8.
|
||||
Смещение считается с заголовка, следующего за ip. В большинство случаев это транспортный заголовок.
|
||||
Смещение считается с транспортного заголовка.
|
||||
|
||||
Существует ряд моментов вокруг работы с фрагментами на Linux, без понимания которых может ничего не получиться.
|
||||
ipv4 : Linux дает отсылать ipv4 фрагменты, но стандартные настройки iptables в цепочке OUTPUT могут их дропать.
|
||||
ipv4 : Linux дает отсылать ipv4 фрагменты, но стандартные настройки iptables в цепочке OUTPUT могут вызывать ошибки отправки.
|
||||
ipv6 : Нет способа для приложения гарантированно отослать фрагменты без дефрагментации в conntrack.
|
||||
На разных системах получается по-разному. Где-то нормально уходят, где-то пакеты дефрагментируются.
|
||||
Для ядер <4.16 похоже, что нет иного способа решить эту проблему, кроме как выгрузить модуль nf_conntrack,
|
||||
|
@ -346,42 +346,50 @@ bool ip_frag6(
|
||||
uint8_t *pkt1, size_t *pkt1_size,
|
||||
uint8_t *pkt2, size_t *pkt2_size)
|
||||
{
|
||||
uint16_t payload_len;
|
||||
size_t payload_len, unfragmentable;
|
||||
uint8_t *last_header_type;
|
||||
uint8_t proto;
|
||||
struct ip6_frag *frag;
|
||||
const uint8_t *payload;
|
||||
|
||||
if (frag_pos & 7 || pkt_size < sizeof(struct ip6_hdr)) return false;
|
||||
payload_len = htons(((struct ip6_hdr*)pkt)->ip6_ctlun.ip6_un1.ip6_un1_plen);
|
||||
if ((sizeof(struct ip6_hdr)+payload_len)>pkt_size || frag_pos>=payload_len ||
|
||||
*pkt1_size<(sizeof(struct ip6_hdr)+sizeof(struct ip6_frag)+frag_pos) ||
|
||||
*pkt2_size<(sizeof(struct ip6_hdr)+sizeof(struct ip6_frag)+payload_len-frag_pos))
|
||||
payload_len = sizeof(struct ip6_hdr) + htons(((struct ip6_hdr*)pkt)->ip6_ctlun.ip6_un1.ip6_un1_plen);
|
||||
if (pkt_size < payload_len) return false;
|
||||
|
||||
payload = pkt;
|
||||
proto_skip_ipv6((uint8_t**)&payload, &payload_len, &proto, &last_header_type);
|
||||
unfragmentable = payload - pkt;
|
||||
|
||||
//printf("pkt_size=%zu FRAG_POS=%zu payload_len=%zu unfragmentable=%zu dh=%zu\n",pkt_size,frag_pos,payload_len,unfragmentable,last_header_type - pkt);
|
||||
|
||||
if (frag_pos>=payload_len ||
|
||||
*pkt1_size<(unfragmentable + sizeof(struct ip6_frag) + frag_pos) ||
|
||||
*pkt2_size<(unfragmentable + sizeof(struct ip6_frag) + payload_len - frag_pos))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
proto = ((struct ip6_hdr*)pkt)->ip6_ctlun.ip6_un1.ip6_un1_nxt;
|
||||
|
||||
memcpy(pkt1, pkt, sizeof(struct ip6_hdr));
|
||||
((struct ip6_hdr*)pkt1)->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(sizeof(struct ip6_frag)+frag_pos);
|
||||
((struct ip6_hdr*)pkt1)->ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_FRAGMENT;
|
||||
frag = (struct ip6_frag*)(((struct ip6_hdr*)pkt1)+1);
|
||||
memcpy(pkt1, pkt, unfragmentable);
|
||||
((struct ip6_hdr*)pkt1)->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(unfragmentable - sizeof(struct ip6_hdr) + sizeof(struct ip6_frag) + frag_pos);
|
||||
pkt1[last_header_type - pkt] = IPPROTO_FRAGMENT;
|
||||
frag = (struct ip6_frag*)(pkt1 + unfragmentable);
|
||||
frag->ip6f_nxt = proto;
|
||||
frag->ip6f_reserved = 0;
|
||||
frag->ip6f_offlg = IP6F_MORE_FRAG;
|
||||
frag->ip6f_ident = ident;
|
||||
memcpy(frag+1, pkt+sizeof(struct ip6_hdr), frag_pos);
|
||||
*pkt1_size = sizeof(struct ip6_hdr)+sizeof(struct ip6_frag)+frag_pos;
|
||||
memcpy(frag+1, pkt + unfragmentable, frag_pos);
|
||||
*pkt1_size = unfragmentable + sizeof(struct ip6_frag) + frag_pos;
|
||||
|
||||
memcpy(pkt2, pkt, sizeof(struct ip6_hdr));
|
||||
((struct ip6_hdr*)pkt2)->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(sizeof(struct ip6_frag)+payload_len-frag_pos);
|
||||
((struct ip6_hdr*)pkt2)->ip6_ctlun.ip6_un1.ip6_un1_nxt = IPPROTO_FRAGMENT;
|
||||
frag = (struct ip6_frag*)(((struct ip6_hdr*)pkt2)+1);
|
||||
((struct ip6_hdr*)pkt2)->ip6_ctlun.ip6_un1.ip6_un1_plen = htons(unfragmentable - sizeof(struct ip6_hdr) + sizeof(struct ip6_frag) + payload_len - frag_pos);
|
||||
pkt2[last_header_type - pkt] = IPPROTO_FRAGMENT;
|
||||
frag = (struct ip6_frag*)(pkt2 + unfragmentable);
|
||||
frag->ip6f_nxt = proto;
|
||||
frag->ip6f_reserved = 0;
|
||||
frag->ip6f_offlg = htons(frag_pos);
|
||||
frag->ip6f_ident = ident;
|
||||
memcpy(frag+1, pkt+sizeof(struct ip6_hdr)+frag_pos, payload_len-frag_pos);
|
||||
*pkt2_size = sizeof(struct ip6_hdr)+sizeof(struct ip6_frag)+payload_len-frag_pos;
|
||||
memcpy(frag+1, pkt + unfragmentable + frag_pos, payload_len - frag_pos);
|
||||
*pkt2_size = unfragmentable + sizeof(struct ip6_frag) + payload_len - frag_pos;
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -619,7 +627,7 @@ bool proto_check_ipv6(const uint8_t *data, size_t len)
|
||||
}
|
||||
// move to transport protocol
|
||||
// proto_type = 0 => error
|
||||
void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type)
|
||||
void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type, uint8_t **last_header_type)
|
||||
{
|
||||
size_t hdrlen;
|
||||
uint8_t HeaderType;
|
||||
@ -627,6 +635,7 @@ void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type)
|
||||
if (proto_type) *proto_type = 0; // put error in advance
|
||||
|
||||
HeaderType = (*data)[6]; // NextHeader field
|
||||
if (last_header_type) *last_header_type = (*data)+6;
|
||||
*data += 40; *len -= 40; // skip ipv6 base header
|
||||
while (*len > 0) // need at least one byte for NextHeader field
|
||||
{
|
||||
@ -654,6 +663,7 @@ void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type)
|
||||
}
|
||||
if (*len < hdrlen) return; // error
|
||||
HeaderType = **data;
|
||||
if (last_header_type) *last_header_type = *data;
|
||||
// advance to the next header location
|
||||
*len -= hdrlen;
|
||||
*data += hdrlen;
|
||||
|
@ -125,7 +125,7 @@ void print_udphdr(const struct udphdr *udphdr);
|
||||
bool proto_check_ipv4(const uint8_t *data, size_t len);
|
||||
void proto_skip_ipv4(uint8_t **data, size_t *len);
|
||||
bool proto_check_ipv6(const uint8_t *data, size_t len);
|
||||
void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type);
|
||||
void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type, uint8_t **last_header_type);
|
||||
bool proto_check_tcp(const uint8_t *data, size_t len);
|
||||
void proto_skip_tcp(uint8_t **data, size_t *len);
|
||||
bool proto_check_udp(const uint8_t *data, size_t len);
|
||||
|
@ -115,7 +115,7 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
|
||||
else if (proto_check_ipv6(data, len))
|
||||
{
|
||||
ip6hdr = (struct ip6_hdr *) data;
|
||||
proto_skip_ipv6(&data, &len, &proto);
|
||||
proto_skip_ipv6(&data, &len, &proto, NULL);
|
||||
if (params.debug)
|
||||
{
|
||||
printf("IP6: ");
|
||||
@ -520,8 +520,8 @@ static void exithelp()
|
||||
" --dpi-desync-repeats=<N>\t\t; send every desync packet N times\n"
|
||||
" --dpi-desync-skip-nosni=0|1\t\t; 1(default)=do not act on ClientHello without SNI (ESNI ?)\n"
|
||||
" --dpi-desync-split-pos=<1..%u>\t; data payload split position\n"
|
||||
" --dpi-desync-ipfrag-pos-tcp=<8..%u>\t; ip frag position starting from the second header (usually transport header). multiple of 8, default %u.\n"
|
||||
" --dpi-desync-ipfrag-pos-udp=<8..%u>\t; ip frag position starting from the second header (usually transport header). multiple of 8, default %u.\n"
|
||||
" --dpi-desync-ipfrag-pos-tcp=<8..%u>\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
|
||||
" --dpi-desync-ipfrag-pos-udp=<8..%u>\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
|
||||
" --dpi-desync-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment. default %d\n"
|
||||
" --dpi-desync-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment. default %d\n"
|
||||
" --dpi-desync-any-protocol=0|1\t\t; 0(default)=desync only http and tls 1=desync any nonempty data packet\n"
|
||||
|
Loading…
Reference in New Issue
Block a user