|
@ -1,5 +1,8 @@ |
|
|
#define _GNU_SOURCE |
|
|
#define _GNU_SOURCE |
|
|
|
|
|
|
|
|
|
|
|
#include <string.h> |
|
|
|
|
|
#include <errno.h> |
|
|
|
|
|
|
|
|
#include "desync.h" |
|
|
#include "desync.h" |
|
|
#include "protocol.h" |
|
|
#include "protocol.h" |
|
|
#include "params.h" |
|
|
#include "params.h" |
|
@ -8,9 +11,6 @@ |
|
|
#include "ipset.h" |
|
|
#include "ipset.h" |
|
|
#include "conntrack.h" |
|
|
#include "conntrack.h" |
|
|
|
|
|
|
|
|
#include <string.h> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char *fake_http_request_default = "GET / HTTP/1.1\r\nHost: www.iana.org\r\n" |
|
|
const char *fake_http_request_default = "GET / HTTP/1.1\r\nHost: www.iana.org\r\n" |
|
|
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0\r\n" |
|
|
"User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/109.0\r\n" |
|
|
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n" |
|
|
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8\r\n" |
|
@ -1273,22 +1273,62 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint |
|
|
case DESYNC_MULTISPLIT: |
|
|
case DESYNC_MULTISPLIT: |
|
|
if (multisplit_count) |
|
|
if (multisplit_count) |
|
|
{ |
|
|
{ |
|
|
size_t from,to; |
|
|
uint8_t ovlseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg; |
|
|
|
|
|
size_t seg_len,from,to; |
|
|
|
|
|
unsigned int seqovl; |
|
|
for (i=0,from=0 ; i<=multisplit_count ; i++) |
|
|
for (i=0,from=0 ; i<=multisplit_count ; i++) |
|
|
{ |
|
|
{ |
|
|
to = i==multisplit_count ? dis->len_payload : multisplit_pos[i]; |
|
|
to = i==multisplit_count ? dis->len_payload : multisplit_pos[i]; |
|
|
|
|
|
|
|
|
pkt1_len = sizeof(pkt1); |
|
|
seqovl = dp->desync_seqovl; |
|
|
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, |
|
|
#ifdef __linux__ |
|
|
net32_add(dis->tcp->th_seq,from), dis->tcp->th_ack, |
|
|
// only linux return error if MTU is exceeded
|
|
|
dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), |
|
|
for(;;seqovl=0) |
|
|
fooling_orig,0,0, |
|
|
{ |
|
|
dis->data_payload+from, to-from, pkt1, &pkt1_len)) |
|
|
#endif |
|
|
return verdict; |
|
|
if (seqovl) |
|
|
DLOG("sending multisplit part %d %zu-%zu len=%zu : ",i+1,from,to-1,to-from); |
|
|
{ |
|
|
hexdump_limited_dlog(dis->data_payload+from,to-from,PKTDATA_MAXDUMP); DLOG("\n"); |
|
|
seg_len = to-from+seqovl; |
|
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) |
|
|
if (seg_len>sizeof(ovlseg)) |
|
|
return verdict; |
|
|
{ |
|
|
|
|
|
DLOG("seqovl is too large"); |
|
|
|
|
|
return verdict; |
|
|
|
|
|
} |
|
|
|
|
|
fill_pattern(ovlseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); |
|
|
|
|
|
memcpy(ovlseg+seqovl,dis->data_payload+from,to-from); |
|
|
|
|
|
seg = ovlseg; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
seqovl = 0; |
|
|
|
|
|
seg = dis->data_payload+from; |
|
|
|
|
|
seg_len = to-from; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pkt1_len = sizeof(pkt1); |
|
|
|
|
|
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, |
|
|
|
|
|
net32_add(dis->tcp->th_seq,from-seqovl), dis->tcp->th_ack, |
|
|
|
|
|
dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), |
|
|
|
|
|
fooling_orig,0,0, |
|
|
|
|
|
seg, seg_len, pkt1, &pkt1_len)) |
|
|
|
|
|
return verdict; |
|
|
|
|
|
DLOG("sending multisplit part %d %zu-%zu len=%zu seqovl=%u : ",i+1,from,to-1,to-from,seqovl); |
|
|
|
|
|
hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); |
|
|
|
|
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) |
|
|
|
|
|
{ |
|
|
|
|
|
#ifdef __linux__ |
|
|
|
|
|
if (errno==EMSGSIZE && seqovl) |
|
|
|
|
|
{ |
|
|
|
|
|
DLOG("MTU exceeded. cancelling seqovl.\n"); |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
return verdict; |
|
|
|
|
|
} |
|
|
|
|
|
#ifdef __linux__ |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
|
|
|
|
|
|
from = to; |
|
|
from = to; |
|
|
} |
|
|
} |
|
@ -1298,20 +1338,44 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint |
|
|
case DESYNC_MULTIDISORDER: |
|
|
case DESYNC_MULTIDISORDER: |
|
|
if (multisplit_count) |
|
|
if (multisplit_count) |
|
|
{ |
|
|
{ |
|
|
size_t from,to; |
|
|
uint8_t ovlseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg; |
|
|
|
|
|
size_t seg_len,from,to; |
|
|
|
|
|
unsigned int seqovl; |
|
|
for (i=multisplit_count-1,to=dis->len_payload ; i>=-1 ; i--) |
|
|
for (i=multisplit_count-1,to=dis->len_payload ; i>=-1 ; i--) |
|
|
{ |
|
|
{ |
|
|
from = i>=0 ? multisplit_pos[i] : 0; |
|
|
from = i>=0 ? multisplit_pos[i] : 0; |
|
|
|
|
|
|
|
|
|
|
|
seg = dis->data_payload+from; |
|
|
|
|
|
seg_len = to-from; |
|
|
|
|
|
seqovl = 0; |
|
|
|
|
|
if (i>=0 && dp->desync_seqovl) |
|
|
|
|
|
{ |
|
|
|
|
|
if (dp->desync_seqovl>=from) |
|
|
|
|
|
DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl for part %d.\n",dp->desync_seqovl,from,i+2); |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
seqovl = dp->desync_seqovl; |
|
|
|
|
|
seg_len = to-from+seqovl; |
|
|
|
|
|
if (seg_len>sizeof(ovlseg)) |
|
|
|
|
|
{ |
|
|
|
|
|
DLOG("seqovl is too large"); |
|
|
|
|
|
return verdict; |
|
|
|
|
|
} |
|
|
|
|
|
fill_pattern(ovlseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); |
|
|
|
|
|
memcpy(ovlseg+seqovl,dis->data_payload+from,to-from); |
|
|
|
|
|
seg = ovlseg; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
pkt1_len = sizeof(pkt1); |
|
|
pkt1_len = sizeof(pkt1); |
|
|
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, |
|
|
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, |
|
|
net32_add(dis->tcp->th_seq,from), dis->tcp->th_ack, |
|
|
net32_add(dis->tcp->th_seq,from-seqovl), dis->tcp->th_ack, |
|
|
dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), |
|
|
dis->tcp->th_win, scale_factor, timestamps,ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), |
|
|
fooling_orig,0,0, |
|
|
fooling_orig,0,0, |
|
|
dis->data_payload+from, to-from, pkt1, &pkt1_len)) |
|
|
seg, seg_len, pkt1, &pkt1_len)) |
|
|
return verdict; |
|
|
return verdict; |
|
|
DLOG("sending multisplit part %d %zu-%zu len=%zu : ",i+2,from,to-1,to-from); |
|
|
DLOG("sending multisplit part %d %zu-%zu len=%zu seqovl=%u : ",i+2,from,to-1,to-from,seqovl); |
|
|
hexdump_limited_dlog(dis->data_payload+from,to-from,PKTDATA_MAXDUMP); DLOG("\n"); |
|
|
hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); |
|
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) |
|
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) |
|
|
return verdict; |
|
|
return verdict; |
|
|
|
|
|
|
|
@ -1423,34 +1487,53 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint |
|
|
return verdict; |
|
|
return verdict; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if (dp->desync_seqovl) |
|
|
unsigned int seqovl = dp->desync_seqovl; |
|
|
|
|
|
#ifdef __linux__ |
|
|
|
|
|
// only linux return error if MTU is exceeded
|
|
|
|
|
|
for(;;seqovl=0) |
|
|
{ |
|
|
{ |
|
|
seg_len = split_pos+dp->desync_seqovl; |
|
|
#endif |
|
|
if (seg_len>sizeof(ovlseg)) |
|
|
if (seqovl) |
|
|
|
|
|
{ |
|
|
|
|
|
seg_len = split_pos+seqovl; |
|
|
|
|
|
if (seg_len>sizeof(ovlseg)) |
|
|
|
|
|
{ |
|
|
|
|
|
DLOG("seqovl is too large"); |
|
|
|
|
|
return verdict; |
|
|
|
|
|
} |
|
|
|
|
|
fill_pattern(ovlseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); |
|
|
|
|
|
memcpy(ovlseg+seqovl,dis->data_payload,split_pos); |
|
|
|
|
|
seg = ovlseg; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
seg = dis->data_payload; |
|
|
|
|
|
seg_len = split_pos; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pkt1_len = sizeof(pkt1); |
|
|
|
|
|
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,-seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, |
|
|
|
|
|
ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), |
|
|
|
|
|
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, |
|
|
|
|
|
seg, seg_len, pkt1, &pkt1_len)) |
|
|
|
|
|
return verdict; |
|
|
|
|
|
DLOG("sending 1st tcp segment 0-%zu len=%zu seqovl=%u : ",split_pos-1, split_pos, seqovl); |
|
|
|
|
|
hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); |
|
|
|
|
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) |
|
|
{ |
|
|
{ |
|
|
DLOG("seqovl is too large"); |
|
|
#ifdef __linux__ |
|
|
|
|
|
if (errno==EMSGSIZE && seqovl) |
|
|
|
|
|
{ |
|
|
|
|
|
DLOG("MTU exceeded. cancelling seqovl.\n"); |
|
|
|
|
|
continue; |
|
|
|
|
|
} |
|
|
|
|
|
#endif |
|
|
return verdict; |
|
|
return verdict; |
|
|
} |
|
|
} |
|
|
fill_pattern(ovlseg,dp->desync_seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); |
|
|
#ifdef __linux__ |
|
|
memcpy(ovlseg+dp->desync_seqovl,dis->data_payload,split_pos); |
|
|
break; |
|
|
seg = ovlseg; |
|
|
|
|
|
} |
|
|
|
|
|
else |
|
|
|
|
|
{ |
|
|
|
|
|
seg = dis->data_payload; |
|
|
|
|
|
seg_len = split_pos; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
#endif |
|
|
pkt1_len = sizeof(pkt1); |
|
|
|
|
|
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq,-dp->desync_seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, |
|
|
|
|
|
ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), |
|
|
|
|
|
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, |
|
|
|
|
|
seg, seg_len, pkt1, &pkt1_len)) |
|
|
|
|
|
return verdict; |
|
|
|
|
|
DLOG("sending 1st tcp segment 0-%zu len=%zu seqovl=%u : ",split_pos-1, split_pos, dp->desync_seqovl); |
|
|
|
|
|
hexdump_limited_dlog(seg,seg_len,PKTDATA_MAXDUMP); DLOG("\n"); |
|
|
|
|
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) |
|
|
|
|
|
return verdict; |
|
|
|
|
|
|
|
|
|
|
|
if (desync_mode==DESYNC_FAKEDSPLIT) |
|
|
if (desync_mode==DESYNC_FAKEDSPLIT) |
|
|
{ |
|
|
{ |
|
@ -1524,6 +1607,8 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint |
|
|
|
|
|
|
|
|
if (bFake) |
|
|
if (bFake) |
|
|
{ |
|
|
{ |
|
|
|
|
|
// if we are here original message was not sent in any form
|
|
|
|
|
|
// allowing system to pass the message to queue can result in unpredicted send order
|
|
|
DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", dis->len_pkt, dis->len_payload); |
|
|
DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", dis->len_pkt, dis->len_payload); |
|
|
verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6); |
|
|
verdict_tcp_csum_fix(verdict, dis->tcp, dis->transport_len, dis->ip, dis->ip6); |
|
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , dis->data_pkt, dis->len_pkt)) |
|
|
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , dis->data_pkt, dis->len_pkt)) |
|
|