nfqws: ipfrag

This commit is contained in:
bol-van 2022-01-03 12:38:18 +03:00
parent 44175a5e2d
commit 690d458ec7
20 changed files with 340 additions and 88 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.

View File

@ -27,6 +27,7 @@ ipfw add 100 fwd ::1,988 tcp from any to any 80,443 proto ip6 recv em1
ipfw delete 100 ipfw delete 100
ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted not sockarg xmit em0 ipfw add 100 divert 989 tcp from any to any 80,443 out not diverted not sockarg xmit em0
ipfw add 100 divert 989 udp from any to any 443 out not diverted not sockarg xmit em0
ipfw delete 100 ipfw delete 100
ipfw add 100 allow tcp from me to table\(nozapret\) 80,443 ipfw add 100 allow tcp from me to table\(nozapret\) 80,443

View File

@ -210,3 +210,7 @@ blockcheck.sh
v43 v43
nfqws: UDP desync with conntrack support (any-protocol only for now) nfqws: UDP desync with conntrack support (any-protocol only for now)
v44
nfqws: ipfrag

View File

@ -5,13 +5,14 @@ iptables -t mangle -I PREROUTING -p tcp --sport 80 --tcp-flags SYN,ACK SYN,ACK -
For outgoing data manipulation ("Host:" case changing) : For outgoing data manipulation ("Host:" case changing) :
iptables -t mangle -I POSTROUTING -p tcp --dport 80 -j NFQUEUE --queue-num 200 --queue-bypass
iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m set --match-set zapret dst -j NFQUEUE --queue-num 200 --queue-bypass
iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m set --match-set zapret dst -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:5 -j NFQUEUE --queue-num 200 --queue-bypass iptables -t mangle -I POSTROUTING -p tcp --dport 80 -m set --match-set zapret dst -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 1:5 -j NFQUEUE --queue-num 200 --queue-bypass
For dpi desync attack : For dpi desync attack :
iptables -t mangle -I POSTROUTING -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 2:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass iptables -t mangle -I POSTROUTING -p tcp -m multiport --dports 80,443 -m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes 2:4 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
iptables -t mangle -I POSTROUTING -p tcp --dport 443 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
iptables -t mangle -I POSTROUTING -p udp --dport 443 -m mark ! --mark 0x40000000/0x40000000 -j NFQUEUE --queue-num 200 --queue-bypass
For TPROXY : For TPROXY :

View File

@ -139,7 +139,7 @@ nfqws takes the following parameters:
--pidfile=<filename> ; write pid to file --pidfile=<filename> ; write pid to file
--user=<username> ; drop root privs --user=<username> ; drop root privs
--uid=uid[:gid] ; drop root privs --uid=uid[:gid] ; drop root privs
--dpi-desync=[<mode0,]<mode>[,<mode2>] ; desync dpi state. modes : synack fake rst rstack disorder disorder2 split split2 --dpi-desync=[<mode0,]<mode>[,<mode2>] ; desync dpi state. modes : synack fake rst rstack disorder disorder2 split split2 ipfrag2
--dpi-desync-fwmark=<int|0xHEX> ; override fwmark for desync packet. default = 0x40000000 --dpi-desync-fwmark=<int|0xHEX> ; override fwmark for desync packet. default = 0x40000000
--dpi-desync-ttl=<int> ; set ttl for desync packet --dpi-desync-ttl=<int> ; set ttl for desync packet
--dpi-desync-ttl6=<int> ; set ipv6 hop limit for desync packet. by default ttl value is used --dpi-desync-ttl6=<int> ; set ipv6 hop limit for desync packet. by default ttl value is used
@ -148,6 +148,8 @@ nfqws takes the following parameters:
--dpi-desync-repeats=<N> ; send every desync packet N times --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-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-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-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment. default -10000 --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-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 --dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet
@ -391,6 +393,14 @@ parameter of `--ctrack-timeouts`.
Fake attack is useful only for stateful DPI and useless for stateless dealing with each packet independently. Fake attack is useful only for stateful DPI and useless for stateless dealing with each packet independently.
By default fake payload is 64 zeroes. Can be overriden using `--dpi-desync-fake-unknown-udp`. By default fake payload is 64 zeroes. Can be overriden using `--dpi-desync-fake-unknown-udp`.
### IP fragmentation
Modern network is very hostile to IP fragmentation. Fragmented packets are often not delivered or refragmented/reassembled
on the way. Linux always reassembles forwarded fragmented ipv6 if possible and it cannot be disablled.
But Linux can send fragments.
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.
## tpws ## tpws

View File

@ -1,4 +1,4 @@
zapret v.43 zapret v.44
English English
------- -------
@ -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 disorder disorder2 split split2 --dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack fake rst rstack 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
@ -418,13 +418,20 @@ window size итоговый размер окна стал максимальн
ПОДДЕРЖКА UDP ПОДДЕРЖКА UDP
Атаки на udp более ограничены в возможностях. udp нельзя фрагментировать иначе, чем на уровне ip. Атаки на udp более ограничены в возможностях. udp нельзя фрагментировать иначе, чем на уровне ip.
ip фрагментация на данный момент не реализована.
Пока что реализован только метод десинхронизации fake в режиме --dpi-desync-any-protocol. Пока что реализован только метод десинхронизации fake в режиме --dpi-desync-any-protocol.
Реализован conntrack для udp. Можно пользоваться --dpi-desync-cutoff. Таймаут conntrack для udp Реализован conntrack для udp. Можно пользоваться --dpi-desync-cutoff. Таймаут conntrack для udp
можно изменить 4-м параметром в --ctrack-timeouts. можно изменить 4-м параметром в --ctrack-timeouts.
Атака fake полезна только для stateful DPI, она бесполезна для анализа на уровне отдельных пакетов. Атака fake полезна только для stateful DPI, она бесполезна для анализа на уровне отдельных пакетов.
По умолчанию fake наполнение - 64 нуля. Можно указать файл в --dpi-desync-fake-unknown-udp. По умолчанию fake наполнение - 64 нуля. Можно указать файл в --dpi-desync-fake-unknown-udp.
IP ФРАГМЕНТАЦИЯ
В современной сети с этом все очень плохо. Фрагментированные пакеты застревают по пути, часто отбрасываются.
Иногда доходят. Иногда то доходят, то не доходят. Может зависеть от версии ipv4/ipv6.
Роутеры на базе linux и freebsd могут самопроизвольно собирать или перефрагментировать пакеты.
Linux всегда собирает проходящие ipv6 фрагменты, и это неотключаемо, но может отсылать фрагменты сам.
Позиция фрагментации задается отдельно для tcp и udp. По умолчанию 24 и 8 соответственно, должна быть кратна 8.
Смещение считается с заголовка, следующего за ip. В большинство случаев это транспортный заголовок.
tpws tpws
----- -----

View File

@ -307,6 +307,100 @@ bool prepare_udp_segment(
// split ipv4 packet into 2 fragments at data payload position frag_pos
bool ip_frag4(
const uint8_t *pkt, size_t pkt_size,
size_t frag_pos, uint32_t ident,
uint8_t *pkt1, size_t *pkt1_size,
uint8_t *pkt2, size_t *pkt2_size)
{
uint16_t hdrlen, payload_len;
// frag_pos must be 8-byte aligned
if (frag_pos & 7 || pkt_size < sizeof(struct ip)) return false;
payload_len = htons(((struct ip *)pkt)->ip_len);
hdrlen = ((struct ip *)pkt)->ip_hl<<2;
if (payload_len>pkt_size || hdrlen>pkt_size || hdrlen>payload_len) return false;
payload_len -= hdrlen;
if (frag_pos>=payload_len || *pkt1_size<(hdrlen+frag_pos) || *pkt2_size<(hdrlen+payload_len-frag_pos)) return false;
memcpy(pkt1, pkt, hdrlen+frag_pos);
((struct ip*)pkt1)->ip_off = htons(IP_MF);
((struct ip*)pkt1)->ip_len = htons(hdrlen+frag_pos);
if (ident!=(uint32_t)-1) ((struct ip*)pkt1)->ip_id = (uint16_t)ident;
*pkt1_size=hdrlen+frag_pos;
ip4_fix_checksum((struct ip *)pkt1);
memcpy(pkt2, pkt, hdrlen);
memcpy(pkt2+hdrlen, pkt+hdrlen+frag_pos, payload_len-frag_pos);
((struct ip*)pkt2)->ip_off = htons((uint16_t)frag_pos>>3 & IP_OFFMASK);
((struct ip*)pkt2)->ip_len = htons(hdrlen+payload_len-frag_pos);
if (ident!=(uint32_t)-1) ((struct ip*)pkt2)->ip_id = (uint16_t)ident;
*pkt2_size=hdrlen+payload_len-frag_pos;
ip4_fix_checksum((struct ip *)pkt2);
return true;
}
bool ip_frag6(
const uint8_t *pkt, size_t pkt_size,
size_t frag_pos, uint32_t ident,
uint8_t *pkt1, size_t *pkt1_size,
uint8_t *pkt2, size_t *pkt2_size)
{
uint16_t payload_len;
uint8_t proto;
struct ip6_frag *frag;
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))
{
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);
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(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);
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;
return true;
}
bool ip_frag(
const uint8_t *pkt, size_t pkt_size,
size_t frag_pos, uint32_t ident,
uint8_t *pkt1, size_t *pkt1_size,
uint8_t *pkt2, size_t *pkt2_size)
{
if (proto_check_ipv4(pkt,pkt_size))
return ip_frag4(pkt,pkt_size,frag_pos,ident,pkt1,pkt1_size,pkt2,pkt2_size);
else if (proto_check_ipv6(pkt,pkt_size))
return ip_frag6(pkt,pkt_size,frag_pos,ident,pkt1,pkt1_size,pkt2,pkt2_size);
else
return false;
}
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport) void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport)
{ {
if (sport) *sport = htons(tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0); if (sport) *sport = htons(tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0);

View File

@ -84,6 +84,24 @@ bool prepare_udp_segment(
uint8_t *buf, size_t *buflen); uint8_t *buf, size_t *buflen);
// ipv4: ident==-1 - copy ip_id from original ipv4 packet
bool ip_frag4(
const uint8_t *pkt, size_t pkt_size,
size_t frag_pos, uint32_t ident,
uint8_t *pkt1, size_t *pkt1_size,
uint8_t *pkt2, size_t *pkt2_size);
bool ip_frag6(
const uint8_t *pkt, size_t pkt_size,
size_t frag_pos, uint32_t ident,
uint8_t *pkt1, size_t *pkt1_size,
uint8_t *pkt2, size_t *pkt2_size);
bool ip_frag(
const uint8_t *pkt, size_t pkt_size,
size_t frag_pos, uint32_t ident,
uint8_t *pkt1, size_t *pkt1_size,
uint8_t *pkt2, size_t *pkt2_size);
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport); void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport);
void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr,const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst); void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr,const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst);
uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind); uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind);

View File

@ -50,7 +50,8 @@ const uint8_t fake_tls_clienthello_default[517] = {
0x00, 0x00, 0x00, 0x00, 0x00 0x00, 0x00, 0x00, 0x00, 0x00
}; };
#define PKT_MAXDUMP 32 #define PKTDATA_MAXDUMP 32
#define IP_MAXDUMP 64
static uint8_t zeropkt[DPI_DESYNC_MAX_FAKE_LEN]; static uint8_t zeropkt[DPI_DESYNC_MAX_FAKE_LEN];
@ -70,7 +71,7 @@ bool desync_valid_first_stage(enum dpi_desync_mode mode)
} }
bool desync_valid_second_stage(enum dpi_desync_mode mode) bool desync_valid_second_stage(enum dpi_desync_mode mode)
{ {
return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2; return mode==DESYNC_NONE || mode==DESYNC_DISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_SPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_IPFRAG2;
} }
enum dpi_desync_mode desync_mode_from_string(const char *s) enum dpi_desync_mode desync_mode_from_string(const char *s)
{ {
@ -92,6 +93,8 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
return DESYNC_SPLIT; return DESYNC_SPLIT;
else if (!strcmp(s,"split2")) else if (!strcmp(s,"split2"))
return DESYNC_SPLIT2; return DESYNC_SPLIT2;
else if (!strcmp(s,"ipfrag2"))
return DESYNC_IPFRAG2;
return DESYNC_INVALID; return DESYNC_INVALID;
} }
@ -151,8 +154,8 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
bool bReverse=false; bool bReverse=false;
struct sockaddr_storage src, dst; struct sockaddr_storage src, dst;
uint8_t newdata[DPI_DESYNC_MAX_FAKE_LEN+100]; uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN+100], pkt2[DPI_DESYNC_MAX_FAKE_LEN+100];
size_t newlen; size_t pkt1_len, pkt2_len;
uint8_t ttl_orig,ttl_fake,flags_orig,scale_factor; uint8_t ttl_orig,ttl_fake,flags_orig,scale_factor;
uint32_t *timestamps; uint32_t *timestamps;
@ -210,15 +213,15 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
if (params.desync_mode0==DESYNC_SYNACK && tcp_syn_segment(tcphdr)) if (params.desync_mode0==DESYNC_SYNACK && tcp_syn_segment(tcphdr))
{ {
newlen = sizeof(newdata); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN|TH_ACK, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_SYN|TH_ACK, tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment, ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
NULL, 0, newdata, &newlen)) NULL, 0, pkt1, &pkt1_len))
{ {
return res; return res;
} }
DLOG("sending fake SYNACK\n"); DLOG("sending fake SYNACK\n");
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen)) if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res; return res;
} }
@ -349,26 +352,26 @@ 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; enum dpi_desync_mode desync_mode = params.desync_mode;
bool b; bool b;
newlen = sizeof(newdata); pkt1_len = sizeof(pkt1);
b = false; b = false;
switch(desync_mode) switch(desync_mode)
{ {
case DESYNC_FAKE: case DESYNC_FAKE:
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_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment, ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
fake, fake_size, newdata, &newlen)) fake, fake_size, pkt1, &pkt1_len))
{ {
return res; return res;
} }
DLOG("sending fake request : "); DLOG("sending fake request : ");
hexdump_limited_dlog(fake,fake_size,PKT_MAXDUMP); DLOG("\n") hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n")
b = true; b = true;
break; break;
case DESYNC_RST: case DESYNC_RST:
case DESYNC_RSTACK: case DESYNC_RSTACK:
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (desync_mode==DESYNC_RSTACK ? TH_ACK:0), tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, TH_RST | (desync_mode==DESYNC_RSTACK ? TH_ACK:0), tcphdr->th_seq, tcphdr->th_ack, tcphdr->th_win, scale_factor, timestamps,
ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment, ttl_fake,params.desync_fooling_mode,params.desync_badseq_increment,params.desync_badseq_ack_increment,
NULL, 0, newdata, &newlen)) NULL, 0, pkt1, &pkt1_len))
{ {
return res; return res;
} }
@ -379,7 +382,7 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
if (b) if (b)
{ {
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen)) if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res; return res;
if (params.desync_mode2==DESYNC_NONE) if (params.desync_mode2==DESYNC_NONE)
{ {
@ -406,13 +409,13 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
desync_mode = params.desync_mode2; desync_mode = params.desync_mode2;
} }
newlen = sizeof(newdata); size_t split_pos=len_payload>params.desync_split_pos ? params.desync_split_pos : 1;
pkt1_len = sizeof(pkt1);
switch(desync_mode) switch(desync_mode)
{ {
case DESYNC_DISORDER: case DESYNC_DISORDER:
case DESYNC_DISORDER2: case DESYNC_DISORDER2:
{ {
size_t split_pos=len_payload>params.desync_split_pos ? params.desync_split_pos : 1;
uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100]; uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100];
size_t fakeseg_len; size_t fakeseg_len;
@ -420,11 +423,11 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
{ {
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, 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,FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
data_payload+split_pos, len_payload-split_pos, newdata, &newlen)) data_payload+split_pos, len_payload-split_pos, pkt1, &pkt1_len))
return res; return res;
DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu : ",split_pos,len_payload-1, len_payload-split_pos) DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu : ",split_pos,len_payload-1, len_payload-split_pos)
hexdump_limited_dlog(data_payload+split_pos,len_payload-split_pos,PKT_MAXDUMP); DLOG("\n") hexdump_limited_dlog(data_payload+split_pos,len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n")
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen)) if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res; return res;
} }
@ -437,26 +440,26 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
zeropkt, split_pos, fakeseg, &fakeseg_len)) zeropkt, split_pos, fakeseg, &fakeseg_len))
return res; return res;
DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos) DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos)
hexdump_limited_dlog(zeropkt,split_pos,PKT_MAXDUMP); DLOG("\n") hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n")
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len)) if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
return res; return res;
} }
newlen = sizeof(newdata); 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, 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,FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
data_payload, split_pos, newdata, &newlen)) data_payload, split_pos, pkt1, &pkt1_len))
return res; return res;
DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos) DLOG("sending 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos)
hexdump_limited_dlog(data_payload,split_pos,PKT_MAXDUMP); DLOG("\n") hexdump_limited_dlog(data_payload,split_pos,PKTDATA_MAXDUMP); DLOG("\n")
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen)) if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res; return res;
if (desync_mode==DESYNC_DISORDER) if (desync_mode==DESYNC_DISORDER)
{ {
DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos) DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos)
hexdump_limited_dlog(zeropkt,split_pos,PKT_MAXDUMP); DLOG("\n") hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n")
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len)) if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
return res; return res;
} }
@ -467,7 +470,6 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
case DESYNC_SPLIT: case DESYNC_SPLIT:
case DESYNC_SPLIT2: case DESYNC_SPLIT2:
{ {
size_t split_pos=len_payload>params.desync_split_pos ? params.desync_split_pos : 1;
uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100]; uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100];
size_t fakeseg_len; size_t fakeseg_len;
@ -479,45 +481,74 @@ packet_process_result dpi_desync_tcp_packet(uint8_t *data_pkt, size_t len_pkt, s
zeropkt, split_pos, fakeseg, &fakeseg_len)) zeropkt, split_pos, fakeseg, &fakeseg_len))
return res; return res;
DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos) DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos)
hexdump_limited_dlog(zeropkt,split_pos,PKT_MAXDUMP); DLOG("\n") hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n")
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len)) if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
return res; return res;
} }
newlen = sizeof(newdata); 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, 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,FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
data_payload, split_pos, newdata, &newlen)) data_payload, split_pos, pkt1, &pkt1_len))
return res; return res;
DLOG("sending 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos) DLOG("sending 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos)
hexdump_limited_dlog(data_payload,split_pos,PKT_MAXDUMP); DLOG("\n") hexdump_limited_dlog(data_payload,split_pos,PKTDATA_MAXDUMP); DLOG("\n")
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen)) if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res; return res;
if (desync_mode==DESYNC_SPLIT) if (desync_mode==DESYNC_SPLIT)
{ {
DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos) DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos)
hexdump_limited_dlog(zeropkt,split_pos,PKT_MAXDUMP); DLOG("\n") hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n")
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len)) if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, fakeseg, fakeseg_len))
return res; return res;
} }
if (split_pos<len_payload) if (split_pos<len_payload)
{ {
newlen = sizeof(newdata); 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, 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,FOOL_NONE,params.desync_badseq_increment,params.desync_badseq_ack_increment,
data_payload+split_pos, len_payload-split_pos, newdata, &newlen)) data_payload+split_pos, len_payload-split_pos, pkt1, &pkt1_len))
return res; return res;
DLOG("sending 2nd tcp segment %zu-%zu len=%zu : ",split_pos,len_payload-1, len_payload-split_pos) DLOG("sending 2nd tcp segment %zu-%zu len=%zu : ",split_pos,len_payload-1, len_payload-split_pos)
hexdump_limited_dlog(data_payload+split_pos,len_payload-split_pos,PKT_MAXDUMP); DLOG("\n") hexdump_limited_dlog(data_payload+split_pos,len_payload-split_pos,PKTDATA_MAXDUMP); DLOG("\n")
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen)) if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res; return res;
} }
return drop; return drop;
} }
break; break;
case DESYNC_IPFRAG2:
{
#ifdef __FreeBSD__
// FreeBSD tend to pass ipv6 frames with wrong checksum
if (ip6hdr)
tcp_fix_checksum(tcphdr,len_tcp,ip,ip6hdr);
#endif
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);
pkt1_len = sizeof(pkt1);
pkt2_len = sizeof(pkt2);
if (!ip_frag(data_pkt, len_pkt, 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)
hexdump_limited_dlog(pkt1,pkt1_len,IP_MAXDUMP); DLOG("\n")
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt2, pkt2_len))
return res;
DLOG("sending 2nd ip fragment %zu-%zu len=%zu : ", ipfrag_pos, len_tcp-1, len_tcp-ipfrag_pos)
hexdump_limited_dlog(pkt2,pkt2_len,IP_MAXDUMP); DLOG("\n")
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res;
return frag;
}
} }
} }
@ -533,8 +564,8 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
bool bReverse=false; bool bReverse=false;
struct sockaddr_storage src, dst; struct sockaddr_storage src, dst;
uint8_t newdata[DPI_DESYNC_MAX_FAKE_LEN+100]; uint8_t pkt1[DPI_DESYNC_MAX_FAKE_LEN+100], pkt2[DPI_DESYNC_MAX_FAKE_LEN+100];
size_t newlen; size_t pkt1_len, pkt2_len;
uint8_t ttl_orig,ttl_fake; uint8_t ttl_orig,ttl_fake;
if (!!ip == !!ip6hdr) return res; // one and only one must be present if (!!ip == !!ip6hdr) return res; // one and only one must be present
@ -579,6 +610,8 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
if (!params.desync_any_proto) return res; if (!params.desync_any_proto) return res;
DLOG("applying tampering to unknown protocol\n") DLOG("applying tampering to unknown protocol\n")
enum dpi_desync_mode desync_mode = params.desync_mode;
ttl_orig = ip ? ip->ip_ttl : ip6hdr->ip6_ctlun.ip6_un1.ip6_un1_hlim; 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; if (ip6hdr) ttl_fake = params.desync_ttl6 ? params.desync_ttl6 : ttl_orig;
else ttl_fake = params.desync_ttl ? params.desync_ttl : ttl_orig; else ttl_fake = params.desync_ttl ? params.desync_ttl : ttl_orig;
@ -596,36 +629,77 @@ packet_process_result dpi_desync_udp_packet(uint8_t *data_pkt, size_t len_pkt, s
printf("\n"); printf("\n");
} }
newlen = sizeof(newdata); pkt1_len = sizeof(pkt1);
b = false; b = false;
switch(params.desync_mode) switch(desync_mode)
{ {
case DESYNC_FAKE: case DESYNC_FAKE:
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, params.desync_fooling_mode, fake, fake_size, newdata, &newlen)) if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_fake, params.desync_fooling_mode, fake, fake_size, pkt1, &pkt1_len))
return res; return res;
DLOG("sending fake request : "); DLOG("sending fake request : ");
hexdump_limited_dlog(fake,fake_size,PKT_MAXDUMP); DLOG("\n") hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n")
b = true; b = true;
break; break;
} }
if (b) if (b)
{ {
if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, newdata, newlen)) if (params.desync_mode2==DESYNC_NONE)
return res; {
DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", len_pkt, len_payload) if (!rawsend_rep((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
#ifdef __FreeBSD__ return res;
// FreeBSD tend to pass ipv6 frames with wrong checksum DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", len_pkt, len_payload)
if (res==modify || ip6hdr) #ifdef __FreeBSD__
#else // FreeBSD tend to pass ipv6 frames with wrong checksum
// if original packet was tampered earlier it needs checksum fixed if (res==modify || ip6hdr)
if (res==modify) #else
#endif // if original packet was tampered earlier it needs checksum fixed
udp_fix_checksum(udphdr,sizeof(struct udphdr)+len_payload,ip,ip6hdr); if (res==modify)
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, data_pkt, len_pkt)) #endif
return res; udp_fix_checksum(udphdr,sizeof(struct udphdr)+len_payload,ip,ip6hdr);
return drop; if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, data_pkt, len_pkt))
return res;
return drop;
}
desync_mode = params.desync_mode2;
} }
switch(desync_mode)
{
case DESYNC_IPFRAG2:
{
#ifdef __FreeBSD__
// FreeBSD tend to pass ipv6 frames with wrong checksum
if (ip6hdr)
udp_fix_checksum(udphdr,sizeof(struct udphdr)+len_payload,ip,ip6hdr);
#endif
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);
// freebsd do not set ip.id
uint32_t ident = ip ? ip->ip_id ? ip->ip_id : htons(1+random()%0xFFFF) : htonl(1+random()&0xFFFFFFFF);
pkt1_len = sizeof(pkt1);
pkt2_len = sizeof(pkt2);
if (!ip_frag(data_pkt, len_pkt, 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)
hexdump_limited_dlog(pkt1,pkt1_len,IP_MAXDUMP); DLOG("\n")
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt2, pkt2_len))
return res;
DLOG("sending 2nd ip fragment %zu-%zu len=%zu : ", ipfrag_pos, len_transport-1, len_transport-ipfrag_pos)
hexdump_limited_dlog(pkt2,pkt2_len,IP_MAXDUMP); DLOG("\n")
if (!rawsend((struct sockaddr *)&dst, params.desync_fwmark, pkt1, pkt1_len))
return res;
return frag;
}
}
} }
return res; return res;

View File

@ -28,7 +28,8 @@ enum dpi_desync_mode {
DESYNC_DISORDER, DESYNC_DISORDER,
DESYNC_DISORDER2, DESYNC_DISORDER2,
DESYNC_SPLIT, DESYNC_SPLIT,
DESYNC_SPLIT2 DESYNC_SPLIT2,
DESYNC_IPFRAG2
}; };
extern const char *fake_http_request_default; extern const char *fake_http_request_default;

View File

@ -148,7 +148,7 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
// ipv6 packets were with incorrect checksum // ipv6 packets were with incorrect checksum
#ifdef __FreeBSD__ #ifdef __FreeBSD__
// FreeBSD tend to pass ipv6 frames with wrong checksum // FreeBSD tend to pass ipv6 frames with wrong checksum
if (res==modify || ip6hdr) if (res==modify || res!=frag && ip6hdr)
#else #else
if (res==modify) if (res==modify)
#endif #endif
@ -171,7 +171,7 @@ static packet_process_result processPacketData(uint8_t *data_pkt, size_t len_pkt
res = dpi_desync_udp_packet(data_pkt, len_pkt, ip, ip6hdr, udphdr, data, len); res = dpi_desync_udp_packet(data_pkt, len_pkt, ip, ip6hdr, udphdr, data, len);
#ifdef __FreeBSD__ #ifdef __FreeBSD__
// FreeBSD tend to pass ipv6 frames with wrong checksum // FreeBSD tend to pass ipv6 frames with wrong checksum
if (res==modify || ip6hdr) if (res==modify || res!=frag && ip6hdr)
#else #else
if (res==modify) if (res==modify)
#endif #endif
@ -209,6 +209,7 @@ static int nfq_cb(struct nfq_q_handle *qh, struct nfgenmsg *nfmsg,
DLOG("packet: id=%d pass modified\n", id); DLOG("packet: id=%d pass modified\n", id);
return nfq_set_verdict2(qh, id, NF_ACCEPT, mark, len, data); return nfq_set_verdict2(qh, id, NF_ACCEPT, mark, len, data);
case drop: case drop:
case frag:
DLOG("packet: id=%d drop\n", id); DLOG("packet: id=%d drop\n", id);
return nfq_set_verdict2(qh, id, NF_DROP, mark, 0, NULL); return nfq_set_verdict2(qh, id, NF_DROP, mark, 0, NULL);
} }
@ -504,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 disorder disorder2 split split2\n" " --dpi-desync=[<mode0>,]<mode>[,<mode2>] ; try to desync dpi state. modes : synack fake rst rstack 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)
@ -518,7 +519,9 @@ static void exithelp()
#endif #endif
" --dpi-desync-repeats=<N>\t\t; send every desync packet N times\n" " --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-skip-nosni=0|1\t\t; 1(default)=do not act on ClientHello without SNI (ESNI ?)\n"
" --dpi-desync-split-pos=<1..%u>\t; TCP packet split position\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-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment. default %d\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-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" " --dpi-desync-any-protocol=0|1\t\t; 0(default)=desync only http and tls 1=desync any nonempty data packet\n"
@ -533,6 +536,8 @@ static void exithelp()
DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT, DPI_DESYNC_FWMARK_DEFAULT,DPI_DESYNC_FWMARK_DEFAULT,
#endif #endif
DPI_DESYNC_MAX_FAKE_LEN, DPI_DESYNC_MAX_FAKE_LEN,
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_UDP_DEFAULT,
DPI_DESYNC_MAX_FAKE_LEN, IPFRAG_TCP_DEFAULT,
BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT BADSEQ_INCREMENT_DEFAULT, BADSEQ_ACK_INCREMENT_DEFAULT
); );
exit(1); exit(1);
@ -602,6 +607,8 @@ int main(int argc, char **argv)
params.desync_fwmark = DPI_DESYNC_FWMARK_DEFAULT; params.desync_fwmark = DPI_DESYNC_FWMARK_DEFAULT;
params.desync_skip_nosni = true; params.desync_skip_nosni = true;
params.desync_split_pos = 2; params.desync_split_pos = 2;
params.desync_ipfrag_pos_udp = IPFRAG_UDP_DEFAULT;
params.desync_ipfrag_pos_tcp = IPFRAG_TCP_DEFAULT;
params.desync_repeats = 1; params.desync_repeats = 1;
params.fake_tls_size = sizeof(fake_tls_clienthello_default); params.fake_tls_size = sizeof(fake_tls_clienthello_default);
memcpy(params.fake_tls,fake_tls_clienthello_default,params.fake_tls_size); memcpy(params.fake_tls,fake_tls_clienthello_default,params.fake_tls_size);
@ -661,15 +668,17 @@ int main(int argc, char **argv)
{"dpi-desync-repeats",required_argument,0,0}, // optidx=20 {"dpi-desync-repeats",required_argument,0,0}, // optidx=20
{"dpi-desync-skip-nosni",optional_argument,0,0},// optidx=21 {"dpi-desync-skip-nosni",optional_argument,0,0},// optidx=21
{"dpi-desync-split-pos",required_argument,0,0},// optidx=22 {"dpi-desync-split-pos",required_argument,0,0},// optidx=22
{"dpi-desync-badseq-increment",required_argument,0,0},// optidx=23 {"dpi-desync-ipfrag-pos-tcp",required_argument,0,0},// optidx=24
{"dpi-desync-badack-increment",required_argument,0,0},// optidx=24 {"dpi-desync-ipfrag-pos-udp",required_argument,0,0},// optidx=25
{"dpi-desync-any-protocol",optional_argument,0,0},// optidx=25 {"dpi-desync-badseq-increment",required_argument,0,0},// optidx=26
{"dpi-desync-fake-http",required_argument,0,0},// optidx=26 {"dpi-desync-badack-increment",required_argument,0,0},// optidx=27
{"dpi-desync-fake-tls",required_argument,0,0},// optidx=27 {"dpi-desync-any-protocol",optional_argument,0,0},// optidx=28
{"dpi-desync-fake-unknown",required_argument,0,0},// optidx=28 {"dpi-desync-fake-http",required_argument,0,0},// optidx=29
{"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=29 {"dpi-desync-fake-tls",required_argument,0,0},// optidx=30
{"dpi-desync-cutoff",required_argument,0,0},// optidx=30 {"dpi-desync-fake-unknown",required_argument,0,0},// optidx=31
{"hostlist",required_argument,0,0}, // optidx=31 {"dpi-desync-fake-unknown-udp",required_argument,0,0},// optidx=32
{"dpi-desync-cutoff",required_argument,0,0},// optidx=33
{"hostlist",required_argument,0,0}, // optidx=34
{NULL,0,NULL,0} {NULL,0,NULL,0}
}; };
if (argc < 2) exithelp(); if (argc < 2) exithelp();
@ -806,6 +815,13 @@ int main(int argc, char **argv)
fprintf(stderr, "invalid desync combo : %s+%s\n", mode,mode2); fprintf(stderr, "invalid desync combo : %s+%s\n", mode,mode2);
exit_clean(1); exit_clean(1);
} }
#if defined(__OpenBSD__)
if (params.desync_mode==DESYNC_IPFRAG2 || params.desync_mode2==DESYNC_IPFRAG2)
{
fprintf(stderr, "OpenBSD has checksum issues with fragmented packets. ipfrag disabled.\n");
exit_clean(1);
}
#endif
} }
break; break;
case 15: /* dpi-desync-fwmark/dpi-desync-sockarg */ case 15: /* dpi-desync-fwmark/dpi-desync-sockarg */
@ -866,8 +882,7 @@ int main(int argc, char **argv)
#endif #endif
break; break;
case 20: /* dpi-desync-repeats */ case 20: /* dpi-desync-repeats */
params.desync_repeats = atoi(optarg); if (sscanf(optarg,"%u",&params.desync_repeats)<1 || params.desync_repeats<=0 || params.desync_repeats>20)
if (params.desync_repeats<=0 || params.desync_repeats>20)
{ {
fprintf(stderr, "dpi-desync-repeats must be within 1..20\n"); fprintf(stderr, "dpi-desync-repeats must be within 1..20\n");
exit_clean(1); exit_clean(1);
@ -877,54 +892,77 @@ int main(int argc, char **argv)
params.desync_skip_nosni = !optarg || atoi(optarg); params.desync_skip_nosni = !optarg || atoi(optarg);
break; break;
case 22: /* dpi-desync-split-pos */ case 22: /* dpi-desync-split-pos */
params.desync_split_pos = atoi(optarg); if (sscanf(optarg,"%u",&params.desync_split_pos)<1 || params.desync_split_pos<1 || params.desync_split_pos>DPI_DESYNC_MAX_FAKE_LEN)
if (params.desync_split_pos<1 || params.desync_split_pos>DPI_DESYNC_MAX_FAKE_LEN)
{ {
fprintf(stderr, "dpi-desync-split-pos must be within 1..%u range\n",DPI_DESYNC_MAX_FAKE_LEN); fprintf(stderr, "dpi-desync-split-pos must be within 1..%u range\n",DPI_DESYNC_MAX_FAKE_LEN);
exit_clean(1); exit_clean(1);
} }
break; break;
case 23: /* dpi-desync-badseq-increments */ case 23: /* dpi-desync-ipfrag-pos-tcp */
if (sscanf(optarg,"%u",&params.desync_ipfrag_pos_tcp)<1 || params.desync_ipfrag_pos_tcp<1 || params.desync_ipfrag_pos_tcp>DPI_DESYNC_MAX_FAKE_LEN)
{
fprintf(stderr, "dpi-desync-ipfrag-pos-tcp must be within 1..%u range\n",DPI_DESYNC_MAX_FAKE_LEN);
exit_clean(1);
}
if (params.desync_ipfrag_pos_tcp & 7)
{
fprintf(stderr, "dpi-desync-ipfrag-pos-tcp must be multiple of 8\n");
exit_clean(1);
}
break;
case 24: /* dpi-desync-ipfrag-pos-udp */
if (sscanf(optarg,"%u",&params.desync_ipfrag_pos_udp)<1 || params.desync_ipfrag_pos_udp<1 || params.desync_ipfrag_pos_udp>DPI_DESYNC_MAX_FAKE_LEN)
{
fprintf(stderr, "dpi-desync-ipfrag-pos-udp must be within 1..%u range\n",DPI_DESYNC_MAX_FAKE_LEN);
exit_clean(1);
}
if (params.desync_ipfrag_pos_udp & 7)
{
fprintf(stderr, "dpi-desync-ipfrag-pos-udp must be multiple of 8\n");
exit_clean(1);
}
break;
case 25: /* dpi-desync-badseq-increments */
if (!parse_badseq_increment(optarg,&params.desync_badseq_increment)) if (!parse_badseq_increment(optarg,&params.desync_badseq_increment))
{ {
fprintf(stderr, "dpi-desync-badseq-increment should be signed decimal or signed 0xHEX\n"); fprintf(stderr, "dpi-desync-badseq-increment should be signed decimal or signed 0xHEX\n");
exit_clean(1); exit_clean(1);
} }
break; break;
case 24: /* dpi-desync-badack-increment */ case 26: /* dpi-desync-badack-increment */
if (!parse_badseq_increment(optarg,&params.desync_badseq_ack_increment)) if (!parse_badseq_increment(optarg,&params.desync_badseq_ack_increment))
{ {
fprintf(stderr, "dpi-desync-badack-increment should be signed decimal or signed 0xHEX\n"); fprintf(stderr, "dpi-desync-badack-increment should be signed decimal or signed 0xHEX\n");
exit_clean(1); exit_clean(1);
} }
break; break;
case 25: /* dpi-desync-any-protocol */ case 27: /* dpi-desync-any-protocol */
params.desync_any_proto = !optarg || atoi(optarg); params.desync_any_proto = !optarg || atoi(optarg);
break; break;
case 26: /* dpi-desync-fake-http */ case 28: /* dpi-desync-fake-http */
params.fake_http_size = sizeof(params.fake_http); params.fake_http_size = sizeof(params.fake_http);
load_file_or_exit(optarg,params.fake_http,&params.fake_http_size); load_file_or_exit(optarg,params.fake_http,&params.fake_http_size);
break; break;
case 27: /* dpi-desync-fake-tls */ case 29: /* dpi-desync-fake-tls */
params.fake_tls_size = sizeof(params.fake_tls); params.fake_tls_size = sizeof(params.fake_tls);
load_file_or_exit(optarg,params.fake_tls,&params.fake_tls_size); load_file_or_exit(optarg,params.fake_tls,&params.fake_tls_size);
break; break;
case 28: /* dpi-desync-fake-unknown */ case 30: /* dpi-desync-fake-unknown */
params.fake_unknown_size = sizeof(params.fake_unknown); params.fake_unknown_size = sizeof(params.fake_unknown);
load_file_or_exit(optarg,params.fake_unknown,&params.fake_unknown_size); load_file_or_exit(optarg,params.fake_unknown,&params.fake_unknown_size);
break; break;
case 29: /* dpi-desync-fake-unknown-udp */ case 31: /* dpi-desync-fake-unknown-udp */
params.fake_unknown_udp_size = sizeof(params.fake_unknown_udp); params.fake_unknown_udp_size = sizeof(params.fake_unknown_udp);
load_file_or_exit(optarg,params.fake_unknown_udp,&params.fake_unknown_udp_size); load_file_or_exit(optarg,params.fake_unknown_udp,&params.fake_unknown_udp_size);
break; break;
case 30: /* desync-cutoff */ case 32: /* desync-cutoff */
if (!parse_cutoff(optarg, &params.desync_cutoff, &params.desync_cutoff_mode)) if (!parse_cutoff(optarg, &params.desync_cutoff, &params.desync_cutoff_mode))
{ {
fprintf(stderr, "invalid desync-cutoff value\n"); fprintf(stderr, "invalid desync-cutoff value\n");
exit_clean(1); exit_clean(1);
} }
break; break;
case 31: /* hostlist */ case 33: /* hostlist */
if (!LoadHostList(&params.hostlist, optarg)) if (!LoadHostList(&params.hostlist, optarg))
exit_clean(1); exit_clean(1);
strncpy(params.hostfile,optarg,sizeof(params.hostfile)); strncpy(params.hostfile,optarg,sizeof(params.hostfile));

View File

@ -2,5 +2,6 @@
typedef enum typedef enum
{ {
pass = 0, modify, drop // frag=drop but do not fix checksum
pass = 0, modify, drop, frag
} packet_process_result; } packet_process_result;

View File

@ -20,6 +20,9 @@
#define BADSEQ_INCREMENT_DEFAULT -10000 #define BADSEQ_INCREMENT_DEFAULT -10000
#define BADSEQ_ACK_INCREMENT_DEFAULT -66000 #define BADSEQ_ACK_INCREMENT_DEFAULT -66000
#define IPFRAG_UDP_DEFAULT 8
#define IPFRAG_TCP_DEFAULT 32
struct params_s struct params_s
{ {
bool debug; bool debug;
@ -36,7 +39,7 @@ struct params_s
char hostspell[4]; char hostspell[4];
enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2; enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2;
bool desync_retrans,desync_skip_nosni,desync_any_proto; bool desync_retrans,desync_skip_nosni,desync_any_proto;
int desync_repeats,desync_split_pos; unsigned int desync_repeats,desync_split_pos,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp;
char desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence char desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int desync_cutoff; unsigned int desync_cutoff;
uint8_t desync_ttl, desync_ttl6; uint8_t desync_ttl, desync_ttl6;