2021-03-04 14:30:38 +03:00
# define _GNU_SOURCE
# include "desync.h"
# include "protocol.h"
# include "params.h"
# include "helpers.h"
# include "hostlist.h"
2021-03-18 17:21:25 +03:00
# include "conntrack.h"
2021-03-04 14:30:38 +03:00
# include <string.h>
2024-02-27 13:58:36 +03:00
const char * fake_http_request_default = " GET / HTTP/1.1 \r \n Host: www.iana.org \r \n "
2023-10-26 15:12:32 +03:00
" 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-Encoding: gzip, deflate, br \r \n \r \n " ;
2024-02-27 13:58:36 +03:00
2021-03-04 14:30:38 +03:00
const uint8_t fake_tls_clienthello_default [ 517 ] = {
2024-02-27 13:58:36 +03:00
0x16 , 0x03 , 0x01 , 0x02 , 0x00 , 0x01 , 0x00 , 0x01 , 0xfc , 0x03 , 0x03 , 0x65 , 0xcb , 0x3a , 0x7f , 0x66 , 0x07 , 0x5d , 0xf3 , 0x6a , 0x44 , 0x13 , 0xa5 , 0x51 ,
0x99 , 0xf6 , 0xeb , 0x4a , 0xf4 , 0xa3 , 0xe1 , 0xa7 , 0x92 , 0x32 , 0xd9 , 0x8b , 0xce , 0xf3 , 0xe1 , 0x2f , 0xe6 , 0xa5 , 0x31 , 0x20 , 0x61 , 0x5a , 0x25 , 0x75 ,
0xc9 , 0x6f , 0x59 , 0xe8 , 0x44 , 0xe1 , 0x2c , 0xf8 , 0x74 , 0x6c , 0xab , 0x84 , 0x36 , 0xb0 , 0x38 , 0xe1 , 0xc8 , 0xc4 , 0x56 , 0x04 , 0xab , 0x76 , 0x81 , 0xd1 ,
0x3c , 0x7b , 0x12 , 0xa4 , 0x00 , 0x20 , 0xca , 0xca , 0x13 , 0x01 , 0x13 , 0x02 , 0x13 , 0x03 , 0xc0 , 0x2b , 0xc0 , 0x2f , 0xc0 , 0x2c , 0xc0 , 0x30 , 0xcc , 0xa9 ,
0xcc , 0xa8 , 0xc0 , 0x13 , 0xc0 , 0x14 , 0x00 , 0x9c , 0x00 , 0x9d , 0x00 , 0x2f , 0x00 , 0x35 , 0x01 , 0x00 , 0x01 , 0x93 , 0xfa , 0xfa , 0x00 , 0x00 , 0xff , 0x01 ,
0x00 , 0x01 , 0x00 , 0x00 , 0x0d , 0x00 , 0x12 , 0x00 , 0x10 , 0x04 , 0x03 , 0x08 , 0x04 , 0x04 , 0x01 , 0x05 , 0x03 , 0x08 , 0x05 , 0x05 , 0x01 , 0x08 , 0x06 , 0x06 ,
0x01 , 0x00 , 0x33 , 0x00 , 0x2b , 0x00 , 0x29 , 0x3a , 0x3a , 0x00 , 0x01 , 0x00 , 0x00 , 0x1d , 0x00 , 0x20 , 0x2d , 0x92 , 0x42 , 0x0c , 0xd5 , 0xad , 0x05 , 0xa1 ,
0x9c , 0x9f , 0x47 , 0xf7 , 0x12 , 0xed , 0x21 , 0xfb , 0xd2 , 0x1a , 0xdf , 0x47 , 0x10 , 0x75 , 0xac , 0x21 , 0x97 , 0x32 , 0x40 , 0x8c , 0xf1 , 0x44 , 0x87 , 0x08 ,
0x00 , 0x23 , 0x00 , 0x00 , 0x00 , 0x1b , 0x00 , 0x03 , 0x02 , 0x00 , 0x02 , 0x00 , 0x10 , 0x00 , 0x0e , 0x00 , 0x0c , 0x02 , 0x68 , 0x32 , 0x08 , 0x68 , 0x74 , 0x74 ,
0x70 , 0x2f , 0x31 , 0x2e , 0x31 , 0x00 , 0x0b , 0x00 , 0x02 , 0x01 , 0x00 , 0x00 , 0x2b , 0x00 , 0x07 , 0x06 , 0xda , 0xda , 0x03 , 0x04 , 0x03 , 0x03 , 0x00 , 0x2d ,
0x00 , 0x02 , 0x01 , 0x01 , 0x00 , 0x17 , 0x00 , 0x00 , 0x00 , 0x05 , 0x00 , 0x05 , 0x01 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x11 , 0x00 , 0x0f , 0x00 ,
0x00 , 0x0c , 0x77 , 0x77 , 0x77 , 0x2e , 0x69 , 0x61 , 0x6e , 0x61 , 0x2e , 0x6f , 0x72 , 0x67 , 0x00 , 0x12 , 0x00 , 0x00 , 0x44 , 0x69 , 0x00 , 0x05 , 0x00 , 0x03 ,
0x02 , 0x68 , 0x32 , 0x00 , 0x0a , 0x00 , 0x0a , 0x00 , 0x08 , 0x3a , 0x3a , 0x00 , 0x1d , 0x00 , 0x17 , 0x00 , 0x18 , 0xea , 0xea , 0x00 , 0x01 , 0x00 , 0x00 , 0x15 ,
0x00 , 0xcb , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 ,
0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00 , 0x00
2021-03-04 14:30:38 +03:00
} ;
2022-01-03 12:38:18 +03:00
# define PKTDATA_MAXDUMP 32
2022-02-02 15:18:35 +03:00
# define IP_MAXDUMP 80
2021-03-04 14:30:38 +03:00
static uint8_t zeropkt [ DPI_DESYNC_MAX_FAKE_LEN ] ;
2023-10-13 20:10:46 +03:00
void desync_init ( void )
2021-03-04 14:30:38 +03:00
{
memset ( zeropkt , 0 , sizeof ( zeropkt ) ) ;
}
2021-04-07 12:13:46 +03:00
bool desync_valid_zero_stage ( enum dpi_desync_mode mode )
{
2024-03-19 13:50:20 +03:00
return mode = = DESYNC_SYNACK | | mode = = DESYNC_SYNDATA ;
2021-04-07 12:13:46 +03:00
}
2021-03-04 14:30:38 +03:00
bool desync_valid_first_stage ( enum dpi_desync_mode mode )
{
2022-04-12 15:52:06 +03:00
return mode = = DESYNC_FAKE | | mode = = DESYNC_FAKE_KNOWN | | mode = = DESYNC_RST | | mode = = DESYNC_RSTACK | | mode = = DESYNC_HOPBYHOP | | mode = = DESYNC_DESTOPT | | mode = = DESYNC_IPFRAG1 ;
2022-02-01 20:35:52 +03:00
}
bool desync_only_first_stage ( enum dpi_desync_mode mode )
{
2022-02-02 15:18:35 +03:00
return false ;
2021-03-04 14:30:38 +03:00
}
bool desync_valid_second_stage ( enum dpi_desync_mode mode )
2022-04-12 15:52:06 +03:00
{
2023-09-07 19:03:37 +03:00
return mode = = DESYNC_NONE | | mode = = DESYNC_DISORDER | | mode = = DESYNC_DISORDER2 | | mode = = DESYNC_SPLIT | | mode = = DESYNC_SPLIT2 | | mode = = DESYNC_IPFRAG2 | | mode = = DESYNC_UDPLEN | | mode = = DESYNC_TAMPER ;
2022-04-12 15:52:06 +03:00
}
bool desync_valid_second_stage_tcp ( enum dpi_desync_mode mode )
2021-03-04 14:30:38 +03:00
{
2022-01-03 12:38:18 +03:00
return mode = = DESYNC_NONE | | mode = = DESYNC_DISORDER | | mode = = DESYNC_DISORDER2 | | mode = = DESYNC_SPLIT | | mode = = DESYNC_SPLIT2 | | mode = = DESYNC_IPFRAG2 ;
2021-03-04 14:30:38 +03:00
}
2022-04-12 15:52:06 +03:00
bool desync_valid_second_stage_udp ( enum dpi_desync_mode mode )
{
2023-09-07 19:03:37 +03:00
return mode = = DESYNC_NONE | | mode = = DESYNC_UDPLEN | | mode = = DESYNC_TAMPER | | mode = = DESYNC_IPFRAG2 ;
2022-04-12 15:52:06 +03:00
}
2021-03-04 14:30:38 +03:00
enum dpi_desync_mode desync_mode_from_string ( const char * s )
{
if ( ! s )
return DESYNC_NONE ;
else if ( ! strcmp ( s , " fake " ) )
return DESYNC_FAKE ;
2022-04-12 15:52:06 +03:00
else if ( ! strcmp ( s , " fakeknown " ) )
return DESYNC_FAKE_KNOWN ;
2021-03-04 14:30:38 +03:00
else if ( ! strcmp ( s , " rst " ) )
return DESYNC_RST ;
else if ( ! strcmp ( s , " rstack " ) )
return DESYNC_RSTACK ;
2021-04-07 12:13:46 +03:00
else if ( ! strcmp ( s , " synack " ) )
return DESYNC_SYNACK ;
2024-03-19 13:50:20 +03:00
else if ( ! strcmp ( s , " syndata " ) )
return DESYNC_SYNDATA ;
2021-03-04 14:30:38 +03:00
else if ( ! strcmp ( s , " disorder " ) )
return DESYNC_DISORDER ;
else if ( ! strcmp ( s , " disorder2 " ) )
return DESYNC_DISORDER2 ;
else if ( ! strcmp ( s , " split " ) )
return DESYNC_SPLIT ;
else if ( ! strcmp ( s , " split2 " ) )
return DESYNC_SPLIT2 ;
2022-01-03 12:38:18 +03:00
else if ( ! strcmp ( s , " ipfrag2 " ) )
return DESYNC_IPFRAG2 ;
2022-02-01 20:35:52 +03:00
else if ( ! strcmp ( s , " hopbyhop " ) )
return DESYNC_HOPBYHOP ;
2022-02-05 13:36:03 +03:00
else if ( ! strcmp ( s , " destopt " ) )
return DESYNC_DESTOPT ;
2022-02-05 15:41:46 +03:00
else if ( ! strcmp ( s , " ipfrag1 " ) )
return DESYNC_IPFRAG1 ;
2022-04-12 15:52:06 +03:00
else if ( ! strcmp ( s , " udplen " ) )
return DESYNC_UDPLEN ;
2023-09-07 19:03:37 +03:00
else if ( ! strcmp ( s , " tamper " ) )
return DESYNC_TAMPER ;
2021-03-04 14:30:38 +03:00
return DESYNC_INVALID ;
}
// auto creates internal socket and uses it for subsequent calls
2022-05-15 15:54:35 +03:00
static bool rawsend_rep ( const struct sockaddr * dst , uint32_t fwmark , const char * ifout , const void * data , size_t len )
2021-03-04 14:30:38 +03:00
{
for ( int i = 0 ; i < params . desync_repeats ; i + + )
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( dst , fwmark , ifout , data , len ) )
2021-03-04 14:30:38 +03:00
return false ;
return true ;
}
2021-12-27 16:51:30 +03:00
static uint64_t cutoff_get_limit ( t_ctrack * ctrack , char mode )
{
switch ( mode )
{
case ' n ' : return ctrack - > pcounter_orig ;
case ' d ' : return ctrack - > pdcounter_orig ;
case ' s ' : return ctrack - > seq_last - ctrack - > seq0 ;
default : return 0 ;
}
}
static bool cutoff_test ( t_ctrack * ctrack , uint64_t cutoff , char mode )
{
return cutoff & & cutoff_get_limit ( ctrack , mode ) > = cutoff ;
}
2022-01-01 20:22:04 +03:00
static void maybe_cutoff ( t_ctrack * ctrack , uint8_t proto )
2021-03-21 21:55:26 +03:00
{
if ( ctrack )
{
2022-01-01 20:22:04 +03:00
if ( proto = = IPPROTO_TCP )
ctrack - > b_wssize_cutoff | = cutoff_test ( ctrack , params . wssize_cutoff , params . wssize_cutoff_mode ) ;
2021-12-27 16:51:30 +03:00
ctrack - > b_desync_cutoff | = cutoff_test ( ctrack , params . desync_cutoff , params . desync_cutoff_mode ) ;
2023-11-15 19:36:34 +03:00
// we do not need conntrack entry anymore if all cutoff conditions are either not defined or reached
// do not drop udp entry because it will be recreated when next packet arrives
2022-01-01 20:22:04 +03:00
if ( proto = = IPPROTO_TCP )
2023-10-26 15:12:32 +03:00
ctrack - > b_cutoff | = \
( ! params . wssize | | ctrack - > b_wssize_cutoff ) & &
( ! params . desync_cutoff | | ctrack - > b_desync_cutoff ) & &
2023-11-15 19:36:34 +03:00
( ! * params . hostlist_auto_filename | | ctrack - > req_retrans_counter = = RETRANS_COUNTER_STOP ) & &
ReasmIsEmpty ( & ctrack - > reasm_orig ) ;
2021-03-21 21:55:26 +03:00
}
}
static void wssize_cutoff ( t_ctrack * ctrack )
{
if ( ctrack )
{
ctrack - > b_wssize_cutoff = true ;
2022-01-01 20:22:04 +03:00
maybe_cutoff ( ctrack , IPPROTO_TCP ) ;
2021-03-21 21:55:26 +03:00
}
}
2023-11-15 19:36:34 +03:00
static void forced_wssize_cutoff ( t_ctrack * ctrack )
{
if ( ctrack & & params . wssize & & ! ctrack - > b_wssize_cutoff )
{
DLOG ( " forced wssize-cutoff \n " ) ;
wssize_cutoff ( ctrack ) ;
}
}
2023-10-26 15:12:32 +03:00
2023-11-15 19:36:34 +03:00
static void ctrack_stop_retrans_counter ( t_ctrack * ctrack )
2023-10-26 15:12:32 +03:00
{
2023-11-09 12:08:09 +03:00
if ( ctrack & & * params . hostlist_auto_filename )
{
ctrack - > req_retrans_counter = RETRANS_COUNTER_STOP ;
maybe_cutoff ( ctrack , IPPROTO_TCP ) ;
}
2023-10-26 15:12:32 +03:00
}
// return true if retrans trigger fires
static bool auto_hostlist_retrans ( t_ctrack * ctrack , uint8_t l4proto , int threshold )
{
if ( * params . hostlist_auto_filename & & ctrack & & ctrack - > req_retrans_counter ! = RETRANS_COUNTER_STOP )
{
2023-11-15 19:36:34 +03:00
if ( l4proto = = IPPROTO_TCP )
{
if ( ! ctrack - > req_seq_present )
return false ;
if ( ! seq_within ( ctrack - > seq_last , ctrack - > req_seq_start , ctrack - > req_seq_end ) )
{
DLOG ( " req retrans : tcp seq %u not within the req range %u-%u. stop tracking. \n " , ctrack - > seq_last , ctrack - > req_seq_start , ctrack - > req_seq_end ) ;
ctrack_stop_retrans_counter ( ctrack ) ;
ctrack - > req_seq_present = false ;
return false ;
}
}
2023-10-26 15:12:32 +03:00
ctrack - > req_retrans_counter + + ;
if ( ctrack - > req_retrans_counter > = threshold )
{
2023-11-15 19:36:34 +03:00
DLOG ( " req retrans threshold reached : %u/%u \n " , ctrack - > req_retrans_counter , threshold ) ;
ctrack_stop_retrans_counter ( ctrack ) ;
2023-10-26 15:12:32 +03:00
return true ;
}
2023-11-15 19:36:34 +03:00
DLOG ( " req retrans counter : %u/%u \n " , ctrack - > req_retrans_counter , threshold ) ;
2023-10-26 15:12:32 +03:00
}
return false ;
}
static void auto_hostlist_failed ( const char * hostname )
{
hostfail_pool * fail_counter ;
fail_counter = HostFailPoolFind ( params . hostlist_auto_fail_counters , hostname ) ;
if ( ! fail_counter )
{
fail_counter = HostFailPoolAdd ( & params . hostlist_auto_fail_counters , hostname , params . hostlist_auto_fail_time ) ;
if ( ! fail_counter )
{
fprintf ( stderr , " HostFailPoolAdd: out of memory \n " ) ;
return ;
}
}
fail_counter - > counter + + ;
DLOG ( " auto hostlist : %s : fail counter %d/%d \n " , hostname , fail_counter - > counter , params . hostlist_auto_fail_threshold ) ;
2023-11-09 12:08:09 +03:00
HOSTLIST_DEBUGLOG_APPEND ( " %s : fail counter %d/%d " , hostname , fail_counter - > counter , params . hostlist_auto_fail_threshold ) ;
2023-10-26 15:12:32 +03:00
if ( fail_counter - > counter > = params . hostlist_auto_fail_threshold )
{
2023-11-15 19:36:34 +03:00
DLOG ( " auto hostlist : fail threshold reached. about to add %s to auto hostlist \n " , hostname ) ;
2023-10-26 15:12:32 +03:00
HostFailPoolDel ( & params . hostlist_auto_fail_counters , fail_counter ) ;
2023-10-26 16:27:52 +03:00
DLOG ( " auto hostlist : rechecking %s to avoid duplicates \n " , hostname ) ;
bool bExcluded = false ;
if ( ! HostlistCheck ( params . hostlist , params . hostlist_exclude , hostname , & bExcluded ) & & ! bExcluded )
2023-10-26 15:12:32 +03:00
{
2023-10-26 16:27:52 +03:00
DLOG ( " auto hostlist : adding %s \n " , hostname ) ;
2023-11-09 12:08:09 +03:00
HOSTLIST_DEBUGLOG_APPEND ( " %s : adding " , hostname ) ;
2023-10-26 16:27:52 +03:00
if ( ! StrPoolAddStr ( & params . hostlist , hostname ) )
{
fprintf ( stderr , " StrPoolAddStr out of memory \n " ) ;
return ;
}
if ( ! append_to_list_file ( params . hostlist_auto_filename , hostname ) )
{
perror ( " write to auto hostlist: " ) ;
return ;
}
2023-10-26 15:12:32 +03:00
}
2023-10-26 16:27:52 +03:00
else
2023-11-09 12:08:09 +03:00
{
2023-10-26 16:27:52 +03:00
DLOG ( " auto hostlist : NOT adding %s \n " , hostname ) ;
2023-11-09 12:08:09 +03:00
HOSTLIST_DEBUGLOG_APPEND ( " %s : NOT adding, duplicate detected " , hostname ) ;
}
2023-10-26 15:12:32 +03:00
}
}
2023-11-15 19:36:34 +03:00
static void process_retrans_fail ( t_ctrack * ctrack , uint8_t proto )
{
if ( ctrack & & ctrack - > hostname & & auto_hostlist_retrans ( ctrack , proto , params . hostlist_auto_retrans_threshold ) )
{
HOSTLIST_DEBUGLOG_APPEND ( " %s : tcp retrans threshold reached " , ctrack - > hostname ) ;
auto_hostlist_failed ( ctrack - > hostname ) ;
}
}
static bool reasm_start ( t_ctrack * ctrack , t_reassemble * reasm , size_t sz , size_t szMax , const uint8_t * data_payload , size_t len_payload )
{
ReasmClear ( reasm ) ;
if ( sz < = szMax )
{
if ( ReasmInit ( reasm , sz , ctrack - > seq_last ) )
{
ReasmFeed ( reasm , ctrack - > seq_last , data_payload , len_payload ) ;
DLOG ( " starting reassemble. now we have %zu/%zu \n " , reasm - > size_present , reasm - > size ) ;
return true ;
}
else
DLOG ( " reassemble init failed. out of memory \n " ) ;
}
else
DLOG ( " unexpected large payload for reassemble: size=%zu \n " , sz ) ;
return false ;
}
static bool reasm_orig_start ( t_ctrack * ctrack , size_t sz , size_t szMax , const uint8_t * data_payload , size_t len_payload )
{
return reasm_start ( ctrack , & ctrack - > reasm_orig , sz , szMax , data_payload , len_payload ) ;
}
static bool reasm_feed ( t_ctrack * ctrack , t_reassemble * reasm , const uint8_t * data_payload , size_t len_payload )
{
if ( ctrack & & ! ReasmIsEmpty ( reasm ) )
{
if ( ReasmFeed ( reasm , ctrack - > seq_last , data_payload , len_payload ) )
{
DLOG ( " reassemble : feeding data payload size=%zu. now we have %zu/%zu \n " , len_payload , reasm - > size_present , reasm - > size )
return true ;
}
else
{
ReasmClear ( reasm ) ;
DLOG ( " reassemble session failed \n " )
}
}
return false ;
}
static bool reasm_orig_feed ( t_ctrack * ctrack , const uint8_t * data_payload , size_t len_payload )
{
return reasm_feed ( ctrack , & ctrack - > reasm_orig , data_payload , len_payload ) ;
}
static void reasm_orig_fin ( t_ctrack * ctrack )
{
if ( ctrack & & ReasmIsFull ( & ctrack - > reasm_orig ) )
{
DLOG ( " reassemble session finished \n " ) ;
ReasmClear ( & ctrack - > reasm_orig ) ;
}
}
2021-03-04 14:30:38 +03:00
// result : true - drop original packet, false = dont drop
2022-05-15 15:54:35 +03:00
packet_process_result dpi_desync_tcp_packet ( uint32_t fwmark , const char * ifout , uint8_t * data_pkt , size_t len_pkt , struct ip * ip , struct ip6_hdr * ip6hdr , struct tcphdr * tcphdr , size_t len_tcp , uint8_t * data_payload , size_t len_payload )
2021-03-04 14:30:38 +03:00
{
packet_process_result res = pass ;
2021-03-18 17:21:25 +03:00
t_ctrack * ctrack = NULL ;
bool bReverse = false ;
2021-03-04 14:30:38 +03:00
2021-04-07 12:13:46 +03:00
struct sockaddr_storage src , dst ;
2022-01-03 12:38:18 +03:00
uint8_t pkt1 [ DPI_DESYNC_MAX_FAKE_LEN + 100 ] , pkt2 [ DPI_DESYNC_MAX_FAKE_LEN + 100 ] ;
size_t pkt1_len , pkt2_len ;
2021-04-07 12:13:46 +03:00
uint8_t ttl_orig , ttl_fake , flags_orig , scale_factor ;
uint32_t * timestamps ;
2021-03-04 14:30:38 +03:00
if ( ! ! ip = = ! ! ip6hdr ) return res ; // one and only one must be present
2024-03-02 17:53:37 +03:00
ttl_orig = ip ? ip - > ip_ttl : ip6hdr - > ip6_ctlun . ip6_un1 . ip6_un1_hlim ;
2021-03-12 14:33:48 +03:00
2023-11-15 19:36:34 +03:00
ConntrackPoolPurge ( & params . conntrack ) ;
if ( ConntrackPoolFeed ( & params . conntrack , ip , ip6hdr , tcphdr , NULL , len_payload , & ctrack , & bReverse ) )
maybe_cutoff ( ctrack , IPPROTO_TCP ) ;
HostFailPoolPurgeRateLimited ( & params . hostlist_auto_fail_counters ) ;
2021-12-27 16:51:30 +03:00
//ConntrackPoolDump(¶ms.conntrack);
2021-03-12 14:33:48 +03:00
if ( params . wsize & & tcp_synack_segment ( tcphdr ) )
{
tcp_rewrite_winsize ( tcphdr , params . wsize , params . wscale ) ;
res = modify ;
}
2023-10-26 15:12:32 +03:00
if ( bReverse )
{
2024-03-02 17:53:37 +03:00
if ( ctrack & & ! ctrack - > autottl & & ctrack - > pcounter_reply = = 1 )
{
autottl * attl = ip ? & params . desync_autottl : & params . desync_autottl6 ;
if ( AUTOTTL_ENABLED ( * attl ) )
{
ctrack - > autottl = autottl_guess ( ttl_orig , attl ) ;
if ( ctrack - > autottl )
DLOG ( " autottl: guessed %u \n " , ctrack - > autottl )
else
DLOG ( " autottl: could not guess \n " )
}
}
2023-10-26 15:12:32 +03:00
// process reply packets for auto hostlist mode
2023-11-15 19:36:34 +03:00
// by looking at RSTs or HTTP replies we decide whether original request looks like DPI blocked
// we only process first-sequence replies. do not react to subsequent redirects or RSTs
if ( * params . hostlist_auto_filename & & ctrack & & ctrack - > hostname & & ( ctrack - > ack_last - ctrack - > ack0 ) = = 1 )
2023-10-26 15:12:32 +03:00
{
2023-11-15 19:36:34 +03:00
bool bFail = false ;
2023-10-26 15:12:32 +03:00
if ( tcphdr - > th_flags & TH_RST )
{
DLOG ( " incoming RST detected for hostname %s \n " , ctrack - > hostname ) ;
2023-11-09 12:08:09 +03:00
HOSTLIST_DEBUGLOG_APPEND ( " %s : incoming RST " , ctrack - > hostname ) ;
2023-11-15 19:36:34 +03:00
bFail = true ;
2023-10-26 15:12:32 +03:00
}
else if ( len_payload & & ctrack - > l7proto = = HTTP )
{
if ( IsHttpReply ( data_payload , len_payload ) )
{
DLOG ( " incoming HTTP reply detected for hostname %s \n " , ctrack - > hostname ) ;
bFail = HttpReplyLooksLikeDPIRedirect ( data_payload , len_payload , ctrack - > hostname ) ;
if ( bFail )
2023-11-09 12:08:09 +03:00
{
2023-10-26 15:12:32 +03:00
DLOG ( " redirect to another domain detected. possibly DPI redirect. \n " )
2023-11-09 12:08:09 +03:00
HOSTLIST_DEBUGLOG_APPEND ( " %s : redirect to another domain " , ctrack - > hostname ) ;
}
2023-10-26 15:12:32 +03:00
else
DLOG ( " local or in-domain redirect detected. it's not a DPI redirect. \n " )
}
else
{
// received not http reply. do not monitor this connection anymore
DLOG ( " incoming unknown HTTP data detected for hostname %s \n " , ctrack - > hostname ) ;
}
}
if ( bFail )
auto_hostlist_failed ( ctrack - > hostname ) ;
2023-11-15 19:36:34 +03:00
if ( tcphdr - > th_flags & TH_RST )
ConntrackClearHostname ( ctrack ) ; // do not react to further dup RSTs
2023-10-26 15:12:32 +03:00
}
return res ; // nothing to do. do not waste cpu
}
2021-04-07 12:13:46 +03:00
2022-05-15 15:54:35 +03:00
uint32_t desync_fwmark = fwmark | params . desync_fwmark ;
2023-10-26 15:12:32 +03:00
2021-12-27 16:51:30 +03:00
if ( params . wssize )
2021-03-12 14:33:48 +03:00
{
2021-12-27 16:51:30 +03:00
if ( ctrack )
{
if ( ctrack - > b_wssize_cutoff )
{
DLOG ( " not changing wssize. wssize-cutoff reached \n " ) ;
}
else
{
if ( params . wssize_cutoff ) DLOG ( " wssize-cutoff not reached (mode %c): %llu/%u \n " , params . wssize_cutoff_mode , ( unsigned long long ) cutoff_get_limit ( ctrack , params . wssize_cutoff_mode ) , params . wssize_cutoff ) ;
tcp_rewrite_winsize ( tcphdr , params . wssize , params . wsscale ) ;
res = modify ;
}
}
else
{
DLOG ( " not changing wssize. wssize is set but conntrack entry is missing \n " ) ;
}
2021-03-12 14:33:48 +03:00
}
2021-04-07 12:13:46 +03:00
if ( params . desync_mode0 ! = DESYNC_NONE | | params . desync_mode ! = DESYNC_NONE ) // save some cpu
{
2024-03-02 17:53:37 +03:00
ttl_fake = ( ctrack & & ctrack - > autottl ) ? ctrack - > autottl : ( ip6hdr ? ( params . desync_ttl6 ? params . desync_ttl6 : ttl_orig ) : ( params . desync_ttl ? params . desync_ttl : ttl_orig ) ) ;
2021-04-07 12:13:46 +03:00
flags_orig = * ( ( uint8_t * ) tcphdr + 13 ) ;
scale_factor = tcp_find_scale_factor ( tcphdr ) ;
timestamps = tcp_find_timestamps ( tcphdr ) ;
2022-01-01 20:22:04 +03:00
extract_endpoints ( ip , ip6hdr , tcphdr , NULL , & src , & dst ) ;
2021-04-07 12:13:46 +03:00
}
2024-03-19 13:50:20 +03:00
if ( tcp_syn_segment ( tcphdr ) )
2021-04-07 12:13:46 +03:00
{
2024-03-19 13:50:20 +03:00
switch ( params . desync_mode0 )
2021-04-07 12:13:46 +03:00
{
2024-03-19 13:50:20 +03:00
case DESYNC_SYNACK :
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 ,
ttl_fake , params . desync_fooling_mode , params . desync_badseq_increment , params . desync_badseq_ack_increment ,
NULL , 0 , pkt1 , & pkt1_len ) )
{
return res ;
}
DLOG ( " sending fake SYNACK \n " ) ;
if ( ! rawsend_rep ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
return res ;
break ;
case DESYNC_SYNDATA :
2024-03-19 21:58:53 +03:00
// make sure we are not breaking TCP fast open
if ( tcp_has_fastopen ( tcphdr ) )
{
DLOG ( " received SYN with TCP fast open option. syndata desync is not applied. \n " ) ;
break ;
}
if ( len_payload )
{
DLOG ( " received SYN with data payload. syndata desync is not applied. \n " ) ;
break ;
}
2024-03-19 13:50:20 +03:00
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 , 0 , 0 , 0 , params . fake_syndata , params . fake_syndata_size , pkt1 , & pkt1_len ) )
{
return res ;
}
DLOG ( " sending SYN with fake data : " ) ;
hexdump_limited_dlog ( params . fake_syndata , params . fake_syndata_size , PKTDATA_MAXDUMP ) ; DLOG ( " \n " )
if ( ! rawsend_rep ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
return res ;
# ifdef __linux__
// if used in postnat chain, dropping SYN will cause conntrack connection teardown
// so we need to workaround this.
// we can't use low ttl because TCP/IP stack listens to ttl expired ICMPs in response to SYN and reset connection
// we also can't use TCP fooling because DPI would accept fooled packets
if ( ip )
{
// routers will drop IP frames with invalid checksum
ip - > ip_sum ^ = htons ( 0xBEAF ) ;
res = modify ;
}
else
// ipv6 does not have checksum
// consider we are free of NAT in ipv6 case. just drop
res = drop ;
# else
res = drop ;
# endif
break ;
2021-04-07 12:13:46 +03:00
}
}
2021-12-27 16:51:30 +03:00
if ( params . desync_cutoff )
{
if ( ctrack )
{
if ( ctrack - > b_desync_cutoff )
{
DLOG ( " not desyncing. desync-cutoff reached (mode %c): %llu/%u \n " , params . desync_cutoff_mode , ( unsigned long long ) cutoff_get_limit ( ctrack , params . desync_cutoff_mode ) , params . desync_cutoff ) ;
return res ;
}
DLOG ( " desync-cutoff not reached (mode %c): %llu/%u \n " , params . desync_cutoff_mode , ( unsigned long long ) cutoff_get_limit ( ctrack , params . desync_cutoff_mode ) , params . desync_cutoff ) ;
}
else
{
DLOG ( " not desyncing. desync-cutoff is set but conntrack entry is missing \n " ) ;
return res ;
}
}
2023-10-26 15:12:32 +03:00
if ( ! params . wssize & & params . desync_mode = = DESYNC_NONE & & ! params . hostcase & & ! params . hostnospace & & ! params . domcase & & ! * params . hostlist_auto_filename ) return res ; // nothing to do. do not waste cpu
2021-03-04 14:30:38 +03:00
if ( ! ( tcphdr - > th_flags & TH_SYN ) & & len_payload )
{
const uint8_t * fake ;
size_t fake_size ;
char host [ 256 ] ;
bool bHaveHost = false ;
bool bIsHttp ;
2022-04-12 15:52:06 +03:00
bool bKnownProtocol = false ;
2021-03-04 14:30:38 +03:00
uint8_t * p , * phost ;
2023-11-15 19:36:34 +03:00
const uint8_t * rdata_payload = data_payload ;
size_t rlen_payload = len_payload ;
if ( reasm_orig_feed ( ctrack , data_payload , len_payload ) )
{
rdata_payload = ctrack - > reasm_orig . packet ;
rlen_payload = ctrack - > reasm_orig . size_present ;
}
if ( ( bIsHttp = IsHttp ( rdata_payload , rlen_payload ) ) )
2021-03-04 14:30:38 +03:00
{
DLOG ( " packet contains HTTP request \n " )
2023-10-26 15:12:32 +03:00
if ( ctrack & & ! ctrack - > l7proto ) ctrack - > l7proto = HTTP ;
2023-11-15 19:36:34 +03:00
forced_wssize_cutoff ( ctrack ) ;
2021-03-04 14:30:38 +03:00
fake = params . fake_http ;
fake_size = params . fake_http_size ;
2023-11-15 19:36:34 +03:00
if ( params . hostlist | | params . hostlist_exclude )
2021-03-04 14:30:38 +03:00
{
2023-11-15 19:36:34 +03:00
bHaveHost = HttpExtractHost ( rdata_payload , rlen_payload , host , sizeof ( host ) ) ;
if ( ! bHaveHost )
{
DLOG ( " not applying tampering to HTTP without Host: \n " )
process_retrans_fail ( ctrack , IPPROTO_TCP ) ;
reasm_orig_fin ( ctrack ) ;
return res ;
}
}
if ( ctrack )
{
// we do not reassemble http
if ( ! ctrack - > req_seq_present )
{
ctrack - > req_seq_start = ctrack - > seq_last ;
ctrack - > req_seq_end = ctrack - > pos_orig - 1 ;
ctrack - > req_seq_start_present = ctrack - > req_seq_present = true ;
DLOG ( " req retrans : tcp seq interval %u-%u \n " , ctrack - > req_seq_start , ctrack - > req_seq_end ) ;
}
2021-03-04 14:30:38 +03:00
}
2022-04-12 15:52:06 +03:00
bKnownProtocol = true ;
2021-03-04 14:30:38 +03:00
}
2023-11-15 19:36:34 +03:00
else if ( IsTLSClientHello ( rdata_payload , rlen_payload , TLS_PARTIALS_ENABLE ) )
2021-03-04 14:30:38 +03:00
{
2023-11-15 19:36:34 +03:00
bool bReqFull = IsTLSRecordFull ( rdata_payload , rlen_payload ) ;
DLOG ( bReqFull ? " packet contains full TLS ClientHello \n " : " packet contains partial TLS ClientHello \n " )
2021-03-04 14:30:38 +03:00
fake = params . fake_tls ;
fake_size = params . fake_tls_size ;
2023-11-15 19:36:34 +03:00
bHaveHost = TLSHelloExtractHost ( rdata_payload , rlen_payload , host , sizeof ( host ) , TLS_PARTIALS_ENABLE ) ;
if ( ctrack )
2021-03-04 14:30:38 +03:00
{
2023-11-15 19:36:34 +03:00
if ( ! ctrack - > l7proto ) ctrack - > l7proto = TLS ;
if ( ! bReqFull & & ReasmIsEmpty ( & ctrack - > reasm_orig ) )
// do not reconstruct unexpected large payload (they are feeding garbage ?)
reasm_orig_start ( ctrack , TLSRecordLen ( data_payload ) , 4096 , data_payload , len_payload ) ;
if ( ! ctrack - > req_seq_start_present )
2021-03-04 14:30:38 +03:00
{
2023-11-15 19:36:34 +03:00
// lower bound of request seq interval
ctrack - > req_seq_start = ctrack - > seq_last ;
ctrack - > req_seq_start_present = true ;
2021-03-04 14:30:38 +03:00
}
2023-11-15 19:36:34 +03:00
if ( ! ctrack - > req_seq_present & & bReqFull )
{
// upper bound of request seq interval
ctrack - > req_seq_end = ctrack - > pos_orig - 1 ;
ctrack - > req_seq_present = ctrack - > req_seq_start_present ;
DLOG ( " req retrans : seq interval %u-%u \n " , ctrack - > req_seq_start , ctrack - > req_seq_end ) ;
}
}
if ( bReqFull | | ! ctrack | | ReasmIsEmpty ( & ctrack - > reasm_orig ) ) forced_wssize_cutoff ( ctrack ) ;
if ( params . desync_skip_nosni & & ! bHaveHost )
{
DLOG ( " not applying tampering to TLS ClientHello without hostname in the SNI \n " )
process_retrans_fail ( ctrack , IPPROTO_TCP ) ;
reasm_orig_fin ( ctrack ) ;
return res ;
2021-03-04 14:30:38 +03:00
}
2022-04-12 15:52:06 +03:00
bKnownProtocol = true ;
2021-03-04 14:30:38 +03:00
}
2023-11-15 19:36:34 +03:00
reasm_orig_fin ( ctrack ) ;
rdata_payload = NULL ;
2021-03-04 14:30:38 +03:00
if ( bHaveHost )
{
2023-10-26 15:12:32 +03:00
bool bExcluded ;
2023-11-15 19:36:34 +03:00
DLOG ( " hostname: %s \n " , host )
2023-10-26 15:12:32 +03:00
if ( ( params . hostlist | | params . hostlist_exclude ) & & ! HostlistCheck ( params . hostlist , params . hostlist_exclude , host , & bExcluded ) )
2021-03-04 14:30:38 +03:00
{
DLOG ( " not applying tampering to this request \n " )
2023-11-15 19:36:34 +03:00
if ( ctrack )
2023-10-26 15:12:32 +03:00
{
2023-11-15 19:36:34 +03:00
if ( ! bExcluded & & * params . hostlist_auto_filename )
2023-11-09 12:08:09 +03:00
{
2023-11-15 19:36:34 +03:00
if ( ! ctrack - > hostname ) ctrack - > hostname = strdup ( host ) ;
process_retrans_fail ( ctrack , IPPROTO_TCP ) ;
2023-11-09 12:08:09 +03:00
}
2023-11-15 19:36:34 +03:00
else
ctrack_stop_retrans_counter ( ctrack ) ;
2023-10-26 15:12:32 +03:00
}
2021-03-04 14:30:38 +03:00
return res ;
}
2023-11-15 19:36:34 +03:00
ctrack_stop_retrans_counter ( ctrack ) ;
}
process_retrans_fail ( ctrack , IPPROTO_TCP ) ;
if ( ! bKnownProtocol )
{
if ( ! params . desync_any_proto ) return res ;
DLOG ( " applying tampering to unknown protocol \n " )
fake = params . fake_unknown ;
fake_size = params . fake_unknown_size ;
2021-03-04 14:30:38 +03:00
}
if ( bIsHttp & & ( params . hostcase | | params . hostnospace | | params . domcase ) & & ( phost = ( uint8_t * ) memmem ( data_payload , len_payload , " \r \n Host: " , 8 ) ) )
{
if ( params . hostcase )
{
DLOG ( " modifying Host: => %c%c%c%c: \n " , params . hostspell [ 0 ] , params . hostspell [ 1 ] , params . hostspell [ 2 ] , params . hostspell [ 3 ] )
memcpy ( phost + 2 , params . hostspell , 4 ) ;
res = modify ;
}
if ( params . domcase )
{
DLOG ( " mixing domain case \n " ) ;
for ( p = phost + 7 ; p < ( data_payload + len_payload ) & & * p ! = ' \r ' & & * p ! = ' \n ' ; p + + )
* p = ( ( ( size_t ) p ) & 1 ) ? tolower ( * p ) : toupper ( * p ) ;
res = modify ;
}
uint8_t * pua ;
if ( params . hostnospace & &
( pua = ( uint8_t * ) memmem ( data_payload , len_payload , " \r \n User-Agent: " , 14 ) ) & &
( pua = ( uint8_t * ) memmem ( pua + 1 , len_payload - ( pua - data_payload ) - 1 , " \r \n " , 2 ) ) )
{
DLOG ( " removing space after Host: and adding it to User-Agent: \n " )
if ( pua > phost )
{
memmove ( phost + 7 , phost + 8 , pua - phost - 8 ) ;
phost [ pua - phost - 1 ] = ' ' ;
}
else
{
memmove ( pua + 1 , pua , phost - pua + 7 ) ;
* pua = ' ' ;
}
res = modify ;
}
}
if ( params . desync_mode = = DESYNC_NONE ) return res ;
if ( params . debug )
{
printf ( " dpi desync src= " ) ;
print_sockaddr ( ( struct sockaddr * ) & src ) ;
printf ( " dst= " ) ;
print_sockaddr ( ( struct sockaddr * ) & dst ) ;
printf ( " \n " ) ;
}
enum dpi_desync_mode desync_mode = params . desync_mode ;
2024-03-02 17:53:37 +03:00
uint32_t fooling_orig = FOOL_NONE ;
2021-03-04 14:30:38 +03:00
bool b ;
2022-01-03 12:38:18 +03:00
pkt1_len = sizeof ( pkt1 ) ;
2021-03-04 14:30:38 +03:00
b = false ;
switch ( desync_mode )
{
2022-04-12 15:52:06 +03:00
case DESYNC_FAKE_KNOWN :
if ( ! bKnownProtocol )
{
DLOG ( " not applying fake because of unknown protocol \n " ) ;
desync_mode = params . desync_mode2 ;
break ;
}
2021-03-04 14:30:38 +03:00
case DESYNC_FAKE :
2021-03-19 15:39:32 +03:00
if ( ! prepare_tcp_segment ( ( struct sockaddr * ) & src , ( struct sockaddr * ) & dst , flags_orig , tcphdr - > th_seq , tcphdr - > th_ack , tcphdr - > th_win , scale_factor , timestamps ,
2022-01-01 20:22:04 +03:00
ttl_fake , params . desync_fooling_mode , params . desync_badseq_increment , params . desync_badseq_ack_increment ,
2022-01-03 12:38:18 +03:00
fake , fake_size , pkt1 , & pkt1_len ) )
2021-03-04 14:30:38 +03:00
{
return res ;
}
DLOG ( " sending fake request : " ) ;
2022-01-03 12:38:18 +03:00
hexdump_limited_dlog ( fake , fake_size , PKTDATA_MAXDUMP ) ; DLOG ( " \n " )
2021-03-04 14:30:38 +03:00
b = true ;
break ;
case DESYNC_RST :
case DESYNC_RSTACK :
2021-03-19 15:39:32 +03:00
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 ,
2022-01-01 20:22:04 +03:00
ttl_fake , params . desync_fooling_mode , params . desync_badseq_increment , params . desync_badseq_ack_increment ,
2022-01-03 12:38:18 +03:00
NULL , 0 , pkt1 , & pkt1_len ) )
2021-03-04 14:30:38 +03:00
{
return res ;
}
DLOG ( " sending fake RST/RSTACK \n " ) ;
b = true ;
break ;
2022-02-01 20:35:52 +03:00
case DESYNC_HOPBYHOP :
2022-02-05 13:36:03 +03:00
case DESYNC_DESTOPT :
2022-02-05 15:41:46 +03:00
case DESYNC_IPFRAG1 :
fooling_orig = ( desync_mode = = DESYNC_HOPBYHOP ) ? FOOL_HOPBYHOP : ( desync_mode = = DESYNC_DESTOPT ) ? FOOL_DESTOPT : FOOL_IPFRAG1 ;
2022-04-12 15:52:06 +03:00
if ( ip6hdr & & ( params . desync_mode2 = = DESYNC_NONE | | ! desync_valid_second_stage_tcp ( params . desync_mode2 ) ) )
2022-02-01 20:35:52 +03:00
{
if ( ! prepare_tcp_segment ( ( struct sockaddr * ) & src , ( struct sockaddr * ) & dst , flags_orig , tcphdr - > th_seq , tcphdr - > th_ack , tcphdr - > th_win , scale_factor , timestamps ,
2022-02-05 13:36:03 +03:00
ttl_orig , fooling_orig , 0 , 0 ,
2022-02-01 20:35:52 +03:00
data_payload , len_payload , pkt1 , & pkt1_len ) )
{
return res ;
}
2022-02-05 13:36:03 +03:00
DLOG ( " resending original packet with extension header \n " ) ;
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
2022-02-01 20:35:52 +03:00
return res ;
2022-02-02 09:39:48 +03:00
// this mode is final, no other options available
return drop ;
2022-02-01 20:35:52 +03:00
}
2022-02-02 15:18:35 +03:00
desync_mode = params . desync_mode2 ;
2021-03-04 14:30:38 +03:00
}
if ( b )
{
2022-05-15 15:54:35 +03:00
if ( ! rawsend_rep ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
2021-03-04 14:30:38 +03:00
return res ;
2022-04-12 15:52:06 +03:00
if ( params . desync_mode2 = = DESYNC_NONE | | ! desync_valid_second_stage_tcp ( params . desync_mode2 ) )
2021-03-04 14:30:38 +03:00
{
if ( params . desync_retrans )
{
DLOG ( " dropping original packet to force retransmission. len=%zu len_payload=%zu \n " , len_pkt , len_payload )
}
else
{
DLOG ( " reinjecting original packet. len=%zu len_payload=%zu \n " , len_pkt , len_payload )
# ifdef __FreeBSD__
// FreeBSD tend to pass ipv6 frames with wrong checksum
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 ) ;
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , data_pkt , len_pkt ) )
2021-03-04 14:30:38 +03:00
return res ;
}
return drop ;
}
desync_mode = params . desync_mode2 ;
}
2022-01-03 12:38:18 +03:00
size_t split_pos = len_payload > params . desync_split_pos ? params . desync_split_pos : 1 ;
pkt1_len = sizeof ( pkt1 ) ;
2021-03-04 14:30:38 +03:00
switch ( desync_mode )
{
case DESYNC_DISORDER :
case DESYNC_DISORDER2 :
{
uint8_t fakeseg [ DPI_DESYNC_MAX_FAKE_LEN + 100 ] ;
size_t fakeseg_len ;
if ( split_pos < len_payload )
{
2021-03-19 15:39:32 +03:00
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 ,
2022-02-02 15:18:35 +03:00
ttl_orig , fooling_orig , params . desync_badseq_increment , params . desync_badseq_ack_increment ,
2022-01-03 12:38:18 +03:00
data_payload + split_pos , len_payload - split_pos , pkt1 , & pkt1_len ) )
2021-03-04 14:30:38 +03:00
return res ;
DLOG ( " sending 2nd out-of-order tcp segment %zu-%zu len=%zu : " , split_pos , len_payload - 1 , len_payload - split_pos )
2022-01-03 12:38:18 +03:00
hexdump_limited_dlog ( data_payload + split_pos , len_payload - split_pos , PKTDATA_MAXDUMP ) ; DLOG ( " \n " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
2021-03-04 14:30:38 +03:00
return res ;
}
if ( desync_mode = = DESYNC_DISORDER )
{
fakeseg_len = sizeof ( fakeseg ) ;
2021-03-19 15:39:32 +03:00
if ( ! prepare_tcp_segment ( ( struct sockaddr * ) & src , ( struct sockaddr * ) & dst , flags_orig , tcphdr - > th_seq , tcphdr - > th_ack , tcphdr - > th_win , scale_factor , timestamps ,
2022-01-01 20:22:04 +03:00
ttl_fake , params . desync_fooling_mode , params . desync_badseq_increment , params . desync_badseq_ack_increment ,
2021-03-04 14:30:38 +03:00
zeropkt , split_pos , fakeseg , & fakeseg_len ) )
return res ;
DLOG ( " sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : " , split_pos - 1 , split_pos )
2022-01-03 12:38:18 +03:00
hexdump_limited_dlog ( zeropkt , split_pos , PKTDATA_MAXDUMP ) ; DLOG ( " \n " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend_rep ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , fakeseg , fakeseg_len ) )
2021-03-04 14:30:38 +03:00
return res ;
}
2022-01-03 12:38:18 +03:00
pkt1_len = sizeof ( pkt1 ) ;
2021-03-19 15:39:32 +03:00
if ( ! prepare_tcp_segment ( ( struct sockaddr * ) & src , ( struct sockaddr * ) & dst , flags_orig , tcphdr - > th_seq , tcphdr - > th_ack , tcphdr - > th_win , scale_factor , timestamps ,
2022-02-02 15:18:35 +03:00
ttl_orig , fooling_orig , params . desync_badseq_increment , params . desync_badseq_ack_increment ,
2022-01-03 12:38:18 +03:00
data_payload , split_pos , pkt1 , & pkt1_len ) )
2021-03-04 14:30:38 +03:00
return res ;
DLOG ( " sending 1st out-of-order tcp segment 0-%zu len=%zu : " , split_pos - 1 , split_pos )
2022-01-03 12:38:18 +03:00
hexdump_limited_dlog ( data_payload , split_pos , PKTDATA_MAXDUMP ) ; DLOG ( " \n " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
2021-03-04 14:30:38 +03:00
return res ;
if ( desync_mode = = DESYNC_DISORDER )
{
DLOG ( " sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu : " , split_pos - 1 , split_pos )
2022-01-03 12:38:18 +03:00
hexdump_limited_dlog ( zeropkt , split_pos , PKTDATA_MAXDUMP ) ; DLOG ( " \n " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend_rep ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , fakeseg , fakeseg_len ) )
2021-03-04 14:30:38 +03:00
return res ;
}
return drop ;
}
break ;
case DESYNC_SPLIT :
case DESYNC_SPLIT2 :
{
uint8_t fakeseg [ DPI_DESYNC_MAX_FAKE_LEN + 100 ] ;
size_t fakeseg_len ;
if ( desync_mode = = DESYNC_SPLIT )
{
fakeseg_len = sizeof ( fakeseg ) ;
2021-03-19 15:39:32 +03:00
if ( ! prepare_tcp_segment ( ( struct sockaddr * ) & src , ( struct sockaddr * ) & dst , flags_orig , tcphdr - > th_seq , tcphdr - > th_ack , tcphdr - > th_win , scale_factor , timestamps ,
2022-01-01 20:22:04 +03:00
ttl_fake , params . desync_fooling_mode , params . desync_badseq_increment , params . desync_badseq_ack_increment ,
2021-03-04 14:30:38 +03:00
zeropkt , split_pos , fakeseg , & fakeseg_len ) )
return res ;
DLOG ( " sending fake(1) 1st tcp segment 0-%zu len=%zu : " , split_pos - 1 , split_pos )
2022-01-03 12:38:18 +03:00
hexdump_limited_dlog ( zeropkt , split_pos , PKTDATA_MAXDUMP ) ; DLOG ( " \n " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend_rep ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , fakeseg , fakeseg_len ) )
2021-03-04 14:30:38 +03:00
return res ;
}
2022-01-03 12:38:18 +03:00
pkt1_len = sizeof ( pkt1 ) ;
2021-03-19 15:39:32 +03:00
if ( ! prepare_tcp_segment ( ( struct sockaddr * ) & src , ( struct sockaddr * ) & dst , flags_orig , tcphdr - > th_seq , tcphdr - > th_ack , tcphdr - > th_win , scale_factor , timestamps ,
2022-02-02 15:18:35 +03:00
ttl_orig , fooling_orig , params . desync_badseq_increment , params . desync_badseq_ack_increment ,
2022-01-03 12:38:18 +03:00
data_payload , split_pos , pkt1 , & pkt1_len ) )
2021-03-04 14:30:38 +03:00
return res ;
DLOG ( " sending 1st tcp segment 0-%zu len=%zu : " , split_pos - 1 , split_pos )
2022-01-03 12:38:18 +03:00
hexdump_limited_dlog ( data_payload , split_pos , PKTDATA_MAXDUMP ) ; DLOG ( " \n " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
2021-03-04 14:30:38 +03:00
return res ;
if ( desync_mode = = DESYNC_SPLIT )
{
DLOG ( " sending fake(2) 1st tcp segment 0-%zu len=%zu : " , split_pos - 1 , split_pos )
2022-01-03 12:38:18 +03:00
hexdump_limited_dlog ( zeropkt , split_pos , PKTDATA_MAXDUMP ) ; DLOG ( " \n " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend_rep ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , fakeseg , fakeseg_len ) )
2021-03-04 14:30:38 +03:00
return res ;
}
if ( split_pos < len_payload )
{
2022-01-03 12:38:18 +03:00
pkt1_len = sizeof ( pkt1 ) ;
2021-03-19 15:39:32 +03:00
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 ,
2022-02-02 15:18:35 +03:00
ttl_orig , fooling_orig , params . desync_badseq_increment , params . desync_badseq_ack_increment ,
2022-01-03 12:38:18 +03:00
data_payload + split_pos , len_payload - split_pos , pkt1 , & pkt1_len ) )
2021-03-04 14:30:38 +03:00
return res ;
DLOG ( " sending 2nd tcp segment %zu-%zu len=%zu : " , split_pos , len_payload - 1 , len_payload - split_pos )
2022-01-03 12:38:18 +03:00
hexdump_limited_dlog ( data_payload + split_pos , len_payload - split_pos , PKTDATA_MAXDUMP ) ; DLOG ( " \n " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
2021-03-04 14:30:38 +03:00
return res ;
}
return drop ;
}
break ;
2022-01-03 12:38:18 +03:00
case DESYNC_IPFRAG2 :
{
# ifdef __FreeBSD__
// FreeBSD tend to pass ipv6 frames with wrong checksum
2022-02-02 15:18:35 +03:00
if ( res = = modify | | ip6hdr )
# else
// if original packet was tampered earlier it needs checksum fixed
if ( res = = modify )
2022-01-03 12:38:18 +03:00
# endif
2022-02-02 15:18:35 +03:00
tcp_fix_checksum ( tcphdr , len_tcp , ip , ip6hdr ) ;
uint8_t pkt3 [ DPI_DESYNC_MAX_FAKE_LEN + 100 ] , * pkt_orig ;
size_t pkt_orig_len ;
2022-01-03 12:38:18 +03:00
size_t ipfrag_pos = ( params . desync_ipfrag_pos_tcp & & params . desync_ipfrag_pos_tcp < len_tcp ) ? params . desync_ipfrag_pos_tcp : 24 ;
2022-02-05 15:41:46 +03:00
uint32_t ident = ip ? ip - > ip_id ? ip - > ip_id : htons ( 1 + random ( ) % 0xFFFF ) : htonl ( 1 + random ( ) % 0xFFFFFFFF ) ;
2022-01-03 12:38:18 +03:00
pkt1_len = sizeof ( pkt1 ) ;
pkt2_len = sizeof ( pkt2 ) ;
2022-02-05 15:41:46 +03:00
if ( ip6hdr & & ( fooling_orig = = FOOL_HOPBYHOP | | fooling_orig = = FOOL_DESTOPT ) )
2022-02-02 15:18:35 +03:00
{
pkt_orig_len = sizeof ( pkt3 ) ;
2022-02-05 15:41:46 +03:00
if ( ! ip6_insert_simple_hdr ( fooling_orig = = FOOL_HOPBYHOP ? IPPROTO_HOPOPTS : IPPROTO_DSTOPTS , data_pkt , len_pkt , pkt3 , & pkt_orig_len ) )
2022-02-02 15:18:35 +03:00
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 ) )
2022-01-03 12:38:18 +03:00
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 " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt2 , pkt2_len ) )
2022-01-03 12:38:18 +03:00
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 " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
2022-01-03 12:38:18 +03:00
return res ;
return frag ;
}
2021-03-04 14:30:38 +03:00
}
2023-11-15 19:36:34 +03:00
2022-01-01 20:22:04 +03:00
}
return res ;
}
2022-05-15 15:54:35 +03:00
packet_process_result dpi_desync_udp_packet ( uint32_t fwmark , const char * ifout , uint8_t * data_pkt , size_t len_pkt , struct ip * ip , struct ip6_hdr * ip6hdr , struct udphdr * udphdr , uint8_t * data_payload , size_t len_payload )
2022-01-01 20:22:04 +03:00
{
packet_process_result res = pass ;
t_ctrack * ctrack = NULL ;
bool bReverse = false ;
struct sockaddr_storage src , dst ;
2022-01-03 12:38:18 +03:00
uint8_t pkt1 [ DPI_DESYNC_MAX_FAKE_LEN + 100 ] , pkt2 [ DPI_DESYNC_MAX_FAKE_LEN + 100 ] ;
size_t pkt1_len , pkt2_len ;
2022-01-01 20:22:04 +03:00
uint8_t ttl_orig , ttl_fake ;
if ( ! ! ip = = ! ! ip6hdr ) return res ; // one and only one must be present
2023-11-15 19:36:34 +03:00
ConntrackPoolPurge ( & params . conntrack ) ;
if ( ConntrackPoolFeed ( & params . conntrack , ip , ip6hdr , NULL , udphdr , len_payload , & ctrack , & bReverse ) )
maybe_cutoff ( ctrack , IPPROTO_UDP ) ;
HostFailPoolPurgeRateLimited ( & params . hostlist_auto_fail_counters ) ;
2022-01-01 20:22:04 +03:00
//ConntrackPoolDump(¶ms.conntrack);
if ( bReverse ) return res ; // nothing to do. do not waste cpu
2023-10-26 15:12:32 +03:00
2022-01-01 20:22:04 +03:00
if ( params . desync_cutoff )
{
if ( ctrack )
{
if ( ctrack - > b_desync_cutoff )
{
DLOG ( " not desyncing. desync-cutoff reached (mode %c): %llu/%u \n " , params . desync_cutoff_mode , ( unsigned long long ) cutoff_get_limit ( ctrack , params . desync_cutoff_mode ) , params . desync_cutoff ) ;
return res ;
}
DLOG ( " desync-cutoff not reached (mode %c): %llu/%u \n " , params . desync_cutoff_mode , ( unsigned long long ) cutoff_get_limit ( ctrack , params . desync_cutoff_mode ) , params . desync_cutoff ) ;
}
else
{
DLOG ( " not desyncing. desync-cutoff is set but conntrack entry is missing \n " ) ;
return res ;
}
}
2023-10-26 15:12:32 +03:00
if ( params . desync_mode = = DESYNC_NONE & & ! * params . hostlist_auto_filename ) return res ; // do not waste cpu
2022-01-01 20:22:04 +03:00
if ( len_payload )
{
const uint8_t * fake ;
size_t fake_size ;
bool b ;
2022-03-25 16:59:58 +03:00
char host [ 256 ] ;
bool bHaveHost = false ;
2022-04-12 15:52:06 +03:00
bool bKnownProtocol = false ;
2022-01-01 20:22:04 +03:00
2022-03-20 20:46:39 +03:00
if ( IsQUICInitial ( data_payload , len_payload ) )
{
DLOG ( " packet contains QUIC initial \n " )
2023-10-26 15:12:32 +03:00
if ( ctrack & & ! ctrack - > l7proto ) ctrack - > l7proto = QUIC ;
2022-03-20 20:46:39 +03:00
fake = params . fake_quic ;
fake_size = params . fake_quic_size ;
2022-03-25 16:59:58 +03:00
2022-03-25 22:34:37 +03:00
bool bIsCryptoHello , bDecryptOK ;
bHaveHost = QUICExtractHostFromInitial ( data_payload , len_payload , host , sizeof ( host ) , & bDecryptOK , & bIsCryptoHello ) ;
2022-03-25 16:59:58 +03:00
if ( bIsCryptoHello )
{
2022-03-25 22:34:37 +03:00
// decrypted and payload is ClientHello
2022-03-25 16:59:58 +03:00
if ( params . desync_skip_nosni & & ! bHaveHost )
{
DLOG ( " not applying tampering to QUIC ClientHello without hostname in the SNI \n " )
return res ;
}
}
2022-03-25 22:34:37 +03:00
else if ( ! bDecryptOK )
{
// could not decrypt
if ( params . desync_skip_nosni )
{
DLOG ( " not applying tampering to QUIC initial that could not be decrypted \n " )
return res ;
}
else
// consider this case the same way as absence of the SNI. DPI also might not be able to decrypt this and get SNI
DLOG ( " QUIC initial decryption failed. still applying tampering because desync_skip_nosni is not set \n " )
}
2022-03-25 16:59:58 +03:00
else
{
2022-03-25 22:34:37 +03:00
// decrypted and payload is not ClientHello
2022-03-25 16:59:58 +03:00
if ( params . desync_any_proto )
{
DLOG ( " QUIC initial without CRYPTO frame. applying tampering because desync_any_proto is set \n " )
}
else
{
DLOG ( " not applying tampering to QUIC initial without CRYPTO frame \n " )
return res ;
}
}
2022-04-12 15:52:06 +03:00
bKnownProtocol = true ;
2022-03-20 20:46:39 +03:00
}
else
{
2023-11-09 12:08:09 +03:00
// received payload without host. it means we are out of the request retransmission phase. stop counter
2023-11-15 19:36:34 +03:00
ctrack_stop_retrans_counter ( ctrack ) ;
2023-11-09 12:08:09 +03:00
if ( IsWireguardHandshakeInitiation ( data_payload , len_payload ) )
{
DLOG ( " packet contains wireguard handshake initiation \n " )
if ( ctrack & & ! ctrack - > l7proto ) ctrack - > l7proto = WIREGUARD ;
fake = params . fake_wg ;
fake_size = params . fake_wg_size ;
bKnownProtocol = true ;
}
else if ( IsDhtD1 ( data_payload , len_payload ) )
{
DLOG ( " packet contains DHT d1...e \n " )
if ( ctrack & & ! ctrack - > l7proto ) ctrack - > l7proto = DHT ;
fake = params . fake_dht ;
fake_size = params . fake_dht_size ;
bKnownProtocol = true ;
}
else
{
if ( ! params . desync_any_proto ) return res ;
DLOG ( " applying tampering to unknown protocol \n " )
fake = params . fake_unknown_udp ;
fake_size = params . fake_unknown_udp_size ;
}
2022-03-20 20:46:39 +03:00
}
2022-01-01 20:22:04 +03:00
2022-03-25 16:59:58 +03:00
if ( bHaveHost )
{
DLOG ( " hostname: %s \n " , host )
2023-10-26 15:12:32 +03:00
bool bExcluded ;
if ( ( params . hostlist | | params . hostlist_exclude ) & & ! HostlistCheck ( params . hostlist , params . hostlist_exclude , host , & bExcluded ) )
2022-03-25 16:59:58 +03:00
{
DLOG ( " not applying tampering to this request \n " )
2023-11-09 12:08:09 +03:00
if ( ! bExcluded & & * params . hostlist_auto_filename & & ctrack )
2023-10-26 15:12:32 +03:00
{
2023-11-09 12:08:09 +03:00
if ( ! ctrack - > hostname ) ctrack - > hostname = strdup ( host ) ;
2023-11-15 19:36:34 +03:00
process_retrans_fail ( ctrack , IPPROTO_UDP ) ;
2023-10-26 15:12:32 +03:00
}
2022-03-25 16:59:58 +03:00
return res ;
}
}
2022-01-03 12:38:18 +03:00
enum dpi_desync_mode desync_mode = params . desync_mode ;
2024-03-02 17:53:37 +03:00
uint32_t fooling_orig = FOOL_NONE ;
2022-01-03 12:38:18 +03:00
2022-01-01 21:12:47 +03:00
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 ;
else ttl_fake = params . desync_ttl ? params . desync_ttl : ttl_orig ;
extract_endpoints ( ip , ip6hdr , NULL , udphdr , & src , & dst ) ;
2022-01-01 20:22:04 +03:00
if ( params . debug )
{
printf ( " dpi desync src= " ) ;
print_sockaddr ( ( struct sockaddr * ) & src ) ;
printf ( " dst= " ) ;
print_sockaddr ( ( struct sockaddr * ) & dst ) ;
printf ( " \n " ) ;
}
2022-05-15 15:54:35 +03:00
uint32_t desync_fwmark = fwmark | params . desync_fwmark ;
2022-01-03 12:38:18 +03:00
pkt1_len = sizeof ( pkt1 ) ;
2022-01-01 20:22:04 +03:00
b = false ;
2022-01-03 12:38:18 +03:00
switch ( desync_mode )
2022-01-01 20:22:04 +03:00
{
2022-04-12 15:52:06 +03:00
case DESYNC_FAKE_KNOWN :
if ( ! bKnownProtocol )
{
DLOG ( " not applying fake because of unknown protocol \n " ) ;
desync_mode = params . desync_mode2 ;
break ;
}
2022-01-01 20:22:04 +03:00
case DESYNC_FAKE :
2023-09-07 13:41:25 +03:00
if ( ! prepare_udp_segment ( ( struct sockaddr * ) & src , ( struct sockaddr * ) & dst , ttl_fake , params . desync_fooling_mode , NULL , 0 , 0 , fake , fake_size , pkt1 , & pkt1_len ) )
2022-01-01 20:22:04 +03:00
return res ;
DLOG ( " sending fake request : " ) ;
2022-01-03 12:38:18 +03:00
hexdump_limited_dlog ( fake , fake_size , PKTDATA_MAXDUMP ) ; DLOG ( " \n " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend_rep ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
2022-04-12 15:52:06 +03:00
return res ;
2022-01-01 20:22:04 +03:00
b = true ;
break ;
2022-02-01 20:35:52 +03:00
case DESYNC_HOPBYHOP :
2022-02-05 13:36:03 +03:00
case DESYNC_DESTOPT :
2022-02-05 15:41:46 +03:00
case DESYNC_IPFRAG1 :
fooling_orig = ( desync_mode = = DESYNC_HOPBYHOP ) ? FOOL_HOPBYHOP : ( desync_mode = = DESYNC_DESTOPT ) ? FOOL_DESTOPT : FOOL_IPFRAG1 ;
2022-04-12 15:52:06 +03:00
if ( ip6hdr & & ( params . desync_mode2 = = DESYNC_NONE | | ! desync_valid_second_stage_udp ( params . desync_mode2 ) ) )
2022-02-01 20:35:52 +03:00
{
if ( ! prepare_udp_segment ( ( struct sockaddr * ) & src , ( struct sockaddr * ) & dst ,
2023-09-07 13:41:25 +03:00
ttl_orig , fooling_orig , NULL , 0 , 0 ,
2022-02-01 20:35:52 +03:00
data_payload , len_payload , pkt1 , & pkt1_len ) )
{
return res ;
}
2022-02-05 13:36:03 +03:00
DLOG ( " resending original packet with extension header \n " ) ;
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
2022-02-01 20:35:52 +03:00
return res ;
2022-02-02 09:39:48 +03:00
// this mode is final, no other options available
return drop ;
2022-02-01 20:35:52 +03:00
}
2022-02-02 15:18:35 +03:00
desync_mode = params . desync_mode2 ;
2022-04-12 15:52:06 +03:00
break ;
2022-01-01 20:22:04 +03:00
}
if ( b )
{
2022-04-12 15:52:06 +03:00
if ( params . desync_mode2 = = DESYNC_NONE | | ! desync_valid_second_stage_udp ( params . desync_mode2 ) )
2022-01-03 12:38:18 +03:00
{
DLOG ( " reinjecting original packet. len=%zu len_payload=%zu \n " , len_pkt , len_payload )
# ifdef __FreeBSD__
// FreeBSD tend to pass ipv6 frames with wrong checksum
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 ) ;
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , data_pkt , len_pkt ) )
2022-01-03 12:38:18 +03:00
return res ;
return drop ;
}
desync_mode = params . desync_mode2 ;
2022-01-01 20:22:04 +03:00
}
2022-01-03 12:38:18 +03:00
switch ( desync_mode )
{
2022-04-12 15:52:06 +03:00
case DESYNC_UDPLEN :
pkt1_len = sizeof ( pkt1 ) ;
2023-09-07 13:41:25 +03:00
if ( ! prepare_udp_segment ( ( struct sockaddr * ) & src , ( struct sockaddr * ) & dst , ttl_orig , fooling_orig , params . udplen_pattern , sizeof ( params . udplen_pattern ) , params . udplen_increment , data_payload , len_payload , pkt1 , & pkt1_len ) )
2022-07-27 12:00:36 +03:00
{
DLOG ( " could not construct packet with modified length. too large ? \n " ) ;
2022-04-12 15:52:06 +03:00
return res ;
2022-07-27 12:00:36 +03:00
}
DLOG ( " resending original packet with increased by %d length \n " , params . udplen_increment ) ;
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
2022-04-12 15:52:06 +03:00
return res ;
return drop ;
2023-09-07 19:03:37 +03:00
case DESYNC_TAMPER :
if ( IsDhtD1 ( data_payload , len_payload ) )
{
size_t szbuf , szcopy ;
2023-09-07 21:02:29 +03:00
memcpy ( pkt2 , " d2:001:x " , 8 ) ;
2023-09-07 19:03:37 +03:00
pkt2_len = 8 ;
szbuf = sizeof ( pkt2 ) - pkt2_len ;
szcopy = len_payload - 1 ;
if ( szcopy > szbuf )
{
DLOG ( " packet is too long to tamper " ) ;
return res ;
}
memcpy ( pkt2 + pkt2_len , data_payload + 1 , szcopy ) ;
pkt2_len + = szcopy ;
pkt1_len = sizeof ( pkt1 ) ;
if ( ! prepare_udp_segment ( ( struct sockaddr * ) & src , ( struct sockaddr * ) & dst , ttl_orig , fooling_orig , NULL , 0 , 0 , pkt2 , pkt2_len , pkt1 , & pkt1_len ) )
{
DLOG ( " could not construct packet with modified length. too large ? \n " ) ;
return res ;
}
DLOG ( " resending tampered DHT \n " ) ;
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
return res ;
return drop ;
}
else
{
DLOG ( " payload is not tamperable \n " ) ;
return res ;
}
2022-01-03 12:38:18 +03:00
case DESYNC_IPFRAG2 :
{
# ifdef __FreeBSD__
// FreeBSD tend to pass ipv6 frames with wrong checksum
2022-02-02 15:18:35 +03:00
if ( res = = modify | | ip6hdr )
# else
// if original packet was tampered earlier it needs checksum fixed
if ( res = = modify )
2022-01-03 12:38:18 +03:00
# endif
2022-02-02 15:18:35 +03:00
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 ;
2022-01-03 12:38:18 +03:00
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
2022-02-05 15:41:46 +03:00
uint32_t ident = ip ? ip - > ip_id ? ip - > ip_id : htons ( 1 + random ( ) % 0xFFFF ) : htonl ( 1 + random ( ) % 0xFFFFFFFF ) ;
2022-01-03 12:38:18 +03:00
pkt1_len = sizeof ( pkt1 ) ;
pkt2_len = sizeof ( pkt2 ) ;
2022-02-05 15:41:46 +03:00
if ( ip6hdr & & ( fooling_orig = = FOOL_HOPBYHOP | | fooling_orig = = FOOL_DESTOPT ) )
2022-02-02 15:18:35 +03:00
{
pkt_orig_len = sizeof ( pkt3 ) ;
2022-02-05 15:41:46 +03:00
if ( ! ip6_insert_simple_hdr ( fooling_orig = = FOOL_HOPBYHOP ? IPPROTO_HOPOPTS : IPPROTO_DSTOPTS , data_pkt , len_pkt , pkt3 , & pkt_orig_len ) )
2022-02-02 15:18:35 +03:00
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 ) )
2022-01-03 12:38:18 +03:00
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 " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt2 , pkt2_len ) )
2022-01-03 12:38:18 +03:00
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 " )
2022-05-15 15:54:35 +03:00
if ( ! rawsend ( ( struct sockaddr * ) & dst , desync_fwmark , ifout , pkt1 , pkt1_len ) )
2022-01-03 12:38:18 +03:00
return res ;
return frag ;
}
}
2021-03-04 14:30:38 +03:00
}
return res ;
}