nfqws: deprecate single split modes, optimize code

This commit is contained in:
bol-van 2024-11-13 11:54:40 +03:00
parent 8bc74333b8
commit 14e9fc4d43
5 changed files with 110 additions and 153 deletions

View File

@ -97,11 +97,11 @@ bool desync_only_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_FAKEDDISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_FAKEDSPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2 || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER; return mode==DESYNC_NONE || mode==DESYNC_FAKEDDISORDER || mode==DESYNC_FAKEDSPLIT || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2 || mode==DESYNC_UDPLEN || mode==DESYNC_TAMPER;
} }
bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode) bool desync_valid_second_stage_tcp(enum dpi_desync_mode mode)
{ {
return mode==DESYNC_NONE || mode==DESYNC_FAKEDDISORDER || mode==DESYNC_DISORDER2 || mode==DESYNC_FAKEDSPLIT || mode==DESYNC_SPLIT2 || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2; return mode==DESYNC_NONE || mode==DESYNC_FAKEDDISORDER || mode==DESYNC_FAKEDSPLIT || mode==DESYNC_MULTISPLIT || mode==DESYNC_MULTIDISORDER || mode==DESYNC_IPFRAG2;
} }
bool desync_valid_second_stage_udp(enum dpi_desync_mode mode) bool desync_valid_second_stage_udp(enum dpi_desync_mode mode)
{ {
@ -125,15 +125,11 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
return DESYNC_SYNDATA; return DESYNC_SYNDATA;
else if (!strcmp(s,"fakeddisorder") || !strcmp(s,"disorder")) else if (!strcmp(s,"fakeddisorder") || !strcmp(s,"disorder"))
return DESYNC_FAKEDDISORDER; return DESYNC_FAKEDDISORDER;
else if (!strcmp(s,"disorder2"))
return DESYNC_DISORDER2;
else if (!strcmp(s,"fakedsplit") || !strcmp(s,"split")) else if (!strcmp(s,"fakedsplit") || !strcmp(s,"split"))
return DESYNC_FAKEDSPLIT; return DESYNC_FAKEDSPLIT;
else if (!strcmp(s,"split2")) else if (!strcmp(s,"multisplit") || !strcmp(s,"split2"))
return DESYNC_SPLIT2;
else if (!strcmp(s,"multisplit"))
return DESYNC_MULTISPLIT; return DESYNC_MULTISPLIT;
else if (!strcmp(s,"multidisorder")) else if (!strcmp(s,"multidisorder") || !strcmp(s,"disorder2"))
return DESYNC_MULTIDISORDER; return DESYNC_MULTIDISORDER;
else if (!strcmp(s,"ipfrag2")) else if (!strcmp(s,"ipfrag2"))
return DESYNC_IPFRAG2; return DESYNC_IPFRAG2;
@ -1118,29 +1114,32 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("dpi desync src=%s dst=%s\n",s1,s2); DLOG("dpi desync src=%s dst=%s\n",s1,s2);
} }
const struct proto_pos *spos;
switch(l7proto) switch(l7proto)
{ {
case HTTP: case HTTP:
fake = dp->fake_http; fake = dp->fake_http;
fake_size = dp->fake_http_size; fake_size = dp->fake_http_size;
spos = &dp->split_http;
break; break;
case TLS: case TLS:
fake = dp->fake_tls; fake = dp->fake_tls;
fake_size = dp->fake_tls_size; fake_size = dp->fake_tls_size;
spos = &dp->split_tls;
break; break;
default: default:
fake = dp->fake_unknown; fake = dp->fake_unknown;
fake_size = dp->fake_unknown_size; fake_size = dp->fake_unknown_size;
spos = &dp->split_unknown;
break; break;
} }
const struct proto_pos defpos={marker:PM_ABS,pos:2};
if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER) if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)
{ {
split_pos=0; split_pos=0;
ResolveMultiPos(rdata_payload, rlen_payload, l7proto, dp->splits, dp->split_count, multisplit_pos, &multisplit_count); ResolveMultiPos(rdata_payload, rlen_payload, l7proto, dp->splits, dp->split_count, multisplit_pos, &multisplit_count);
if (!multisplit_count)
{
multisplit_pos[multisplit_count] = ResolvePos(rdata_payload, rlen_payload, l7proto, &defpos);
if (!multisplit_pos[multisplit_count]) multisplit_pos[multisplit_count] = 1;
multisplit_count++;
}
if (params.debug) if (params.debug)
{ {
if (multisplit_count) if (multisplit_count)
@ -1174,12 +1173,20 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
} }
} }
} }
else if (dp->desync_mode==DESYNC_FAKEDSPLIT || dp->desync_mode==DESYNC_SPLIT2 || dp->desync_mode==DESYNC_FAKEDDISORDER || dp->desync_mode==DESYNC_DISORDER2 || else if (dp->desync_mode==DESYNC_FAKEDSPLIT || dp->desync_mode==DESYNC_FAKEDDISORDER || dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER)
dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_SPLIT2 || dp->desync_mode2==DESYNC_FAKEDDISORDER || dp->desync_mode2==DESYNC_DISORDER2)
{ {
multisplit_count=0; multisplit_count=0;
split_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, spos); // first look for non-abs split
if (!split_pos) split_pos = dp->split_unknown.pos; for(i=0,split_pos=0;i<dp->split_count && !split_pos;i++)
if (dp->splits[i].marker!=PM_ABS)
split_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, dp->splits+i);
// second look for abs split
if (!split_pos)
for(i=0,split_pos=0;i<dp->split_count && !split_pos;i++)
if (dp->splits[i].marker==PM_ABS)
split_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, dp->splits+i);
if (!split_pos) split_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, &defpos);
if (!split_pos) split_pos = 1;
DLOG("regular split pos: %zu\n",split_pos); DLOG("regular split pos: %zu\n",split_pos);
if (!split_pos || split_pos>rlen_payload) split_pos=1; if (!split_pos || split_pos>rlen_payload) split_pos=1;
split_pos=pos_normalize(split_pos,reasm_offset,dis->len_payload); split_pos=pos_normalize(split_pos,reasm_offset,dis->len_payload);
@ -1241,7 +1248,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
case DESYNC_IPFRAG1: case DESYNC_IPFRAG1:
fooling_orig = (dp->desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1; fooling_orig = (dp->desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(dp->desync_mode2) || if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_tcp(dp->desync_mode2) ||
(!split_pos && (dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_SPLIT2 || dp->desync_mode2==DESYNC_FAKEDDISORDER || dp->desync_mode2==DESYNC_DISORDER2)) || (!split_pos && (dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER)) ||
(!multisplit_count && (dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)))) (!multisplit_count && (dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER))))
{ {
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
@ -1352,10 +1359,13 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
seg = dis->data_payload+from; seg = dis->data_payload+from;
seg_len = to-from; seg_len = to-from;
seqovl = 0; seqovl = 0;
if (i>=0 && dp->desync_seqovl) // do seqovl only to the second packet
// otherwise sequence overlap becomes problematic. overlap algorithm is not too obvious.
// real observations revealed that server can receive overlap junk instead of real data
if (i==0)
{ {
if (dp->desync_seqovl>=from) if (dp->desync_seqovl>=from)
DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl for part %d.\n",dp->desync_seqovl,from,i+2); DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl for part %d.\n",seqovl,from,i+2);
else else
{ {
seqovl = dp->desync_seqovl; seqovl = dp->desync_seqovl;
@ -1389,30 +1399,32 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
} }
break; break;
case DESYNC_FAKEDDISORDER: case DESYNC_FAKEDDISORDER:
case DESYNC_DISORDER2:
if (split_pos) if (split_pos)
{ {
uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg; uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg;
size_t seg_len; size_t seg_len;
unsigned int seqovl;
if (dp->desync_seqovl>=split_pos) if (dp->desync_seqovl>=split_pos)
{ {
DLOG("seqovl>=split_pos. desync is not possible.\n"); DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl.\n",dp->desync_seqovl,split_pos);
return verdict; seqovl = 0;
} }
else
seqovl = dp->desync_seqovl;
if (split_pos<dis->len_payload) if (split_pos<dis->len_payload)
{ {
if (dp->desync_seqovl) if (seqovl)
{ {
seg_len = dis->len_payload-split_pos+dp->desync_seqovl; seg_len = dis->len_payload-split_pos+seqovl;
if (seg_len>sizeof(fakeseg)) if (seg_len>sizeof(fakeseg))
{ {
DLOG("seqovl is too large\n"); DLOG("seqovl is too large\n");
return verdict; return verdict;
} }
fill_pattern(fakeseg,dp->desync_seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern)); fill_pattern(fakeseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern));
memcpy(fakeseg+dp->desync_seqovl,dis->data_payload+split_pos,dis->len_payload-split_pos); memcpy(fakeseg+seqovl,dis->data_payload+split_pos,dis->len_payload-split_pos);
seg = fakeseg; seg = fakeseg;
} }
else else
@ -1422,31 +1434,27 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
} }
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq , split_pos - dp->desync_seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, net32_add(dis->tcp->th_seq , split_pos - seqovl), dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
seg, seg_len, pkt1, &pkt1_len)) seg, seg_len, pkt1, &pkt1_len))
return verdict; return verdict;
DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu seqovl=%u : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos, dp->desync_seqovl); DLOG("sending 2nd out-of-order tcp segment %zu-%zu len=%zu seqovl=%u : ",split_pos,dis->len_payload-1, dis->len_payload-split_pos, seqovl);
hexdump_limited_dlog(seg,seg_len,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;
} }
seg_len = sizeof(fakeseg);
if (desync_mode==DESYNC_FAKEDDISORDER) if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
{ ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
seg_len = sizeof(fakeseg); dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, zeropkt, split_pos, fakeseg, &seg_len))
ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), return verdict;
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos);
zeropkt, split_pos, fakeseg, &seg_len)) hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
return verdict; if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len))
DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); return verdict;
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len))
return verdict;
}
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
@ -1459,37 +1467,30 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
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;
if (desync_mode==DESYNC_FAKEDDISORDER) 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,PKTDATA_MAXDUMP); DLOG("\n");
DLOG("sending fake(2) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len))
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); return verdict;
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len))
return verdict;
}
return VERDICT_DROP; return VERDICT_DROP;
} }
break; break;
case DESYNC_FAKEDSPLIT: case DESYNC_FAKEDSPLIT:
case DESYNC_SPLIT2:
if (split_pos) if (split_pos)
{ {
uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100],ovlseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg; uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100],ovlseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg;
size_t fakeseg_len,seg_len; size_t fakeseg_len,seg_len;
if (desync_mode==DESYNC_FAKEDSPLIT) fakeseg_len = sizeof(fakeseg);
{ if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps,
fakeseg_len = sizeof(fakeseg); ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
if (!prepare_tcp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, flags_orig, dis->tcp->th_seq, dis->tcp->th_ack, dis->tcp->th_win, scale_factor, timestamps, dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), zeropkt, split_pos, fakeseg, &fakeseg_len))
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment, return verdict;
zeropkt, split_pos, fakeseg, &fakeseg_len)) DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos);
return verdict; hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); return verdict;
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return verdict;
}
unsigned int seqovl = dp->desync_seqovl; unsigned int seqovl = dp->desync_seqovl;
#ifdef __linux__ #ifdef __linux__
@ -1539,13 +1540,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
} }
#endif #endif
if (desync_mode==DESYNC_FAKEDSPLIT) DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos);
{ hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
DLOG("sending fake(2) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos); if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n"); return verdict;
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return verdict;
}
if (split_pos<dis->len_payload) if (split_pos<dis->len_payload)
{ {
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
@ -1738,7 +1737,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
{ {
const uint8_t *fake; const uint8_t *fake;
size_t fake_size; size_t fake_size;
bool b;
char host[256]; char host[256];
bool bHaveHost=false; bool bHaveHost=false;
@ -1990,7 +1988,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
ttl_fake = (ctrack_replay && ctrack_replay->autottl) ? ctrack_replay->autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig)); ttl_fake = (ctrack_replay && ctrack_replay->autottl) ? ctrack_replay->autottl : (dis->ip6 ? (dp->desync_ttl6 ? dp->desync_ttl6 : ttl_orig) : (dp->desync_ttl ? dp->desync_ttl : ttl_orig));
enum dpi_desync_mode desync_mode = dp->desync_mode;
uint32_t fooling_orig = FOOL_NONE; uint32_t fooling_orig = FOOL_NONE;
if (params.debug) if (params.debug)
@ -2001,15 +1998,14 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("dpi desync src=%s dst=%s\n",s1,s2); DLOG("dpi desync src=%s dst=%s\n",s1,s2);
} }
bool bFake = false;
pkt1_len = sizeof(pkt1); pkt1_len = sizeof(pkt1);
b = false; switch(dp->desync_mode)
switch(desync_mode)
{ {
case DESYNC_FAKE_KNOWN: case DESYNC_FAKE_KNOWN:
if (l7proto==UNKNOWN) if (l7proto==UNKNOWN)
{ {
DLOG("not applying fake because of unknown protocol\n"); DLOG("not applying fake because of unknown protocol\n");
desync_mode = dp->desync_mode2;
break; break;
} }
case DESYNC_FAKE: case DESYNC_FAKE:
@ -2019,12 +2015,12 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n"); hexdump_limited_dlog(fake,fake_size,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return verdict; return verdict;
b = true; bFake = true;
break; break;
case DESYNC_HOPBYHOP: case DESYNC_HOPBYHOP:
case DESYNC_DESTOPT: case DESYNC_DESTOPT:
case DESYNC_IPFRAG1: case DESYNC_IPFRAG1:
fooling_orig = (desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1; fooling_orig = (dp->desync_mode==DESYNC_HOPBYHOP) ? FOOL_HOPBYHOP : (dp->desync_mode==DESYNC_DESTOPT) ? FOOL_DESTOPT : FOOL_IPFRAG1;
if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(dp->desync_mode2))) if (dis->ip6 && (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(dp->desync_mode2)))
{ {
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
@ -2040,26 +2036,13 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
// this mode is final, no other options available // this mode is final, no other options available
return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt); return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt);
} }
desync_mode = dp->desync_mode2;
break; break;
default: default:
pkt1_len=0; pkt1_len=0;
break; break;
} }
if (b) enum dpi_desync_mode desync_mode = dp->desync_mode2==DESYNC_NONE ? dp->desync_mode : dp->desync_mode2;
{
if (dp->desync_mode2==DESYNC_NONE || !desync_valid_second_stage_udp(dp->desync_mode2))
{
DLOG("reinjecting original packet. len=%zu len_payload=%zu\n", dis->len_pkt, dis->len_payload);
verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6);
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , dis->data_pkt, dis->len_pkt))
return verdict;
return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt);
}
desync_mode = dp->desync_mode2;
}
switch(desync_mode) switch(desync_mode)
{ {
case DESYNC_UDPLEN: case DESYNC_UDPLEN:
@ -2067,7 +2050,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), fooling_orig, dp->udplen_pattern, sizeof(dp->udplen_pattern), dp->udplen_increment, dis->data_payload, dis->len_payload, pkt1, &pkt1_len)) if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), fooling_orig, dp->udplen_pattern, sizeof(dp->udplen_pattern), dp->udplen_increment, dis->data_payload, dis->len_payload, pkt1, &pkt1_len))
{ {
DLOG("could not construct packet with modified length. too large ?\n"); DLOG("could not construct packet with modified length. too large ?\n");
return verdict; break;
} }
DLOG("resending original packet with increased by %d length\n", dp->udplen_increment); DLOG("resending original packet with increased by %d length\n", dp->udplen_increment);
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
@ -2084,7 +2067,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
if (szcopy>szbuf) if (szcopy>szbuf)
{ {
DLOG("packet is too long to tamper"); DLOG("packet is too long to tamper");
return verdict; break;
} }
memcpy(pkt2+pkt2_len,dis->data_payload+1,szcopy); memcpy(pkt2+pkt2_len,dis->data_payload+1,szcopy);
pkt2_len+=szcopy; pkt2_len+=szcopy;
@ -2092,7 +2075,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), fooling_orig, NULL, 0 , 0, pkt2, pkt2_len, pkt1, &pkt1_len)) if (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst, ttl_orig,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6), fooling_orig, NULL, 0 , 0, pkt2, pkt2_len, pkt1, &pkt1_len))
{ {
DLOG("could not construct packet with modified length. too large ?\n"); DLOG("could not construct packet with modified length. too large ?\n");
return verdict; break;
} }
DLOG("resending tampered DHT\n"); DLOG("resending tampered DHT\n");
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len)) if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
@ -2102,7 +2085,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
else else
{ {
DLOG("payload is not tamperable\n"); DLOG("payload is not tamperable\n");
return verdict; break;
} }
case DESYNC_IPFRAG2: case DESYNC_IPFRAG2:
{ {
@ -2150,6 +2133,16 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
break; break;
} }
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);
verdict_udp_csum_fix(verdict, dis->udp, dis->transport_len, dis->ip, dis->ip6);
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , dis->data_pkt, dis->len_pkt))
return verdict;
return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt);
}
} }
return verdict; return verdict;

View File

@ -28,8 +28,6 @@ enum dpi_desync_mode {
DESYNC_RSTACK, DESYNC_RSTACK,
DESYNC_SYNACK, DESYNC_SYNACK,
DESYNC_SYNDATA, DESYNC_SYNDATA,
DESYNC_SPLIT2,
DESYNC_DISORDER2,
DESYNC_FAKEDSPLIT, DESYNC_FAKEDSPLIT,
DESYNC_FAKEDDISORDER, DESYNC_FAKEDDISORDER,
DESYNC_MULTISPLIT, DESYNC_MULTISPLIT,

View File

@ -752,7 +752,7 @@ static bool parse_tlspos(const char *s, struct proto_pos *sp)
else if (!strcmp(s, "sniext")) else if (!strcmp(s, "sniext"))
{ {
sp->marker = PM_SNI_EXT; sp->marker = PM_SNI_EXT;
sp->pos=0; sp->pos=1;
} }
else if (!strcmp(s, "snisld")) else if (!strcmp(s, "snisld"))
{ {
@ -836,41 +836,6 @@ static bool parse_split_pos_list(char *opt, struct proto_pos *splits, int splits
if (p) return false; // too much splits if (p) return false; // too much splits
return true; return true;
} }
static void split_compat(struct desync_profile *dp)
{
// make it mostly compatible with old versions
int i;
dp->split_unknown.marker=PM_ABS;
dp->split_unknown.pos=2;
for (i=0;i<dp->split_count;i++)
{
if (dp->splits[i].marker==PM_ABS)
{
dp->split_unknown.pos=dp->splits[i].pos;
break;
}
}
if (PROTO_POS_EMPTY(&dp->split_http))
{
dp->split_http=dp->split_unknown;
for (i=0;i<dp->split_count;i++)
if (IsHostMarker(dp->splits[i].marker) || dp->splits[i].marker==PM_HTTP_METHOD)
{
dp->split_http = dp->splits[i];
break;
}
}
if (PROTO_POS_EMPTY(&dp->split_tls))
{
dp->split_tls=dp->split_unknown;
for (i=0;i<dp->split_count;i++)
if (IsHostMarker(dp->splits[i].marker) || dp->splits[i].marker==PM_SNI_EXT)
{
dp->split_tls = dp->splits[i];
break;
}
}
}
static void SplitDebug(void) static void SplitDebug(void)
{ {
struct desync_profile_list *dpl; struct desync_profile_list *dpl;
@ -878,9 +843,6 @@ static void SplitDebug(void)
LIST_FOREACH(dpl, &params.desync_profiles, next) LIST_FOREACH(dpl, &params.desync_profiles, next)
{ {
dp = &dpl->dp; dp = &dpl->dp;
DLOG("profile %d split_http %s %d\n",dp->n,posmarker_name(dp->split_http.marker),dp->split_http.pos);
DLOG("profile %d split_tls %s %d\n",dp->n,posmarker_name(dp->split_tls.marker),dp->split_tls.pos);
DLOG("profile %d split_unknown %s %d\n",dp->n,posmarker_name(dp->split_unknown.marker),dp->split_unknown.pos);
for(int x=0;x<dp->split_count;x++) for(int x=0;x<dp->split_count;x++)
DLOG("profile %d multisplit %s %d\n",dp->n,posmarker_name(dp->splits[x].marker),dp->splits[x].pos); DLOG("profile %d multisplit %s %d\n",dp->n,posmarker_name(dp->splits[x].marker),dp->splits[x].pos);
} }
@ -1066,7 +1028,7 @@ static void exithelp(void)
" --domcase\t\t\t\t\t; mix domain case : Host: TeSt.cOm\n" " --domcase\t\t\t\t\t; mix domain case : Host: TeSt.cOm\n"
" --dpi-desync=[<mode0>,]<mode>[,<mode2>]\t; try to desync dpi state. modes :\n" " --dpi-desync=[<mode0>,]<mode>[,<mode2>]\t; try to desync dpi state. modes :\n"
"\t\t\t\t\t\t; synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1\n" "\t\t\t\t\t\t; synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1\n"
"\t\t\t\t\t\t; disorder2 split2 multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper\n" "\t\t\t\t\t\t; multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper\n"
#ifdef __linux__ #ifdef __linux__
" --dpi-desync-fwmark=<int|0xHEX>\t\t; override fwmark for desync packet. default = 0x%08X (%u)\n" " --dpi-desync-fwmark=<int|0xHEX>\t\t; override fwmark for desync packet. default = 0x%08X (%u)\n"
#elif defined(SO_USER_COOKIE) #elif defined(SO_USER_COOKIE)
@ -1079,9 +1041,10 @@ static void exithelp(void)
" --dpi-desync-fooling=<mode>[,<mode>]\t\t; can use multiple comma separated values. modes : none md5sig ts badseq badsum datanoack hopbyhop hopbyhop2\n" " --dpi-desync-fooling=<mode>[,<mode>]\t\t; can use multiple comma separated values. modes : none md5sig ts badseq badsum datanoack hopbyhop hopbyhop2\n"
" --dpi-desync-repeats=<N>\t\t\t; send every desync packet N times\n" " --dpi-desync-repeats=<N>\t\t\t; send every desync packet N times\n"
" --dpi-desync-skip-nosni=0|1\t\t\t; 1(default)=do not act on ClientHello without SNI (ESNI ?)\n" " --dpi-desync-skip-nosni=0|1\t\t\t; 1(default)=do not act on ClientHello without SNI (ESNI ?)\n"
" --dpi-desync-split-pos=N|-N|marker+N|marker-N\t; comma separated list of split positions. markers: method,host,endhost,sld,endsld,midsld,sniext\n" " --dpi-desync-split-pos=N|-N|marker+N|marker-N\t; comma separated list of split positions\n"
"\t\t\t\t\t\t; markers: method,host,endhost,sld,endsld,midsld,sniext\n"
"\t\t\t\t\t\t; full list is only used by multisplit and multidisorder\n" "\t\t\t\t\t\t; full list is only used by multisplit and multidisorder\n"
"\t\t\t\t\t\t; single split takes first l7-protocol-compatible parameter if present, first abs value otherwise\n" "\t\t\t\t\t\t; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise\n"
" --dpi-desync-split-seqovl=<int>\t\t; use sequence overlap before first sent original split segment\n" " --dpi-desync-split-seqovl=<int>\t\t; use sequence overlap before first sent original split segment\n"
" --dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; pattern for the fake part of overlap\n" " --dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; pattern for the fake part of overlap\n"
" --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n" " --dpi-desync-ipfrag-pos-tcp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
@ -1589,19 +1552,33 @@ int main(int argc, char **argv)
break; break;
case 24: /* dpi-desync-split-http-req */ case 24: /* dpi-desync-split-http-req */
// obsolete arg // obsolete arg
if (!parse_httpreqpos(optarg, &dp->split_http)) DLOG_CONDUP("WARNING ! --dpi-desync-split-http-req is deprecated. use --dpi-desync-split-pos with markers.\n",MAX_SPLITS);
if (dp->split_count>=MAX_SPLITS)
{
DLOG_ERR("Too much splits. max splits: %u\n",MAX_SPLITS);
exit_clean(1);
}
if (!parse_httpreqpos(optarg, dp->splits + dp->split_count))
{ {
DLOG_ERR("Invalid argument for dpi-desync-split-http-req\n"); DLOG_ERR("Invalid argument for dpi-desync-split-http-req\n");
exit_clean(1); exit_clean(1);
} }
dp->split_count++;
break; break;
case 25: /* dpi-desync-split-tls */ case 25: /* dpi-desync-split-tls */
// obsolete arg // obsolete arg
if (!parse_tlspos(optarg, &dp->split_tls)) DLOG_CONDUP("WARNING ! --dpi-desync-split-tls is deprecated. use --dpi-desync-split-pos with markers.\n",MAX_SPLITS);
if (dp->split_count>=MAX_SPLITS)
{
DLOG_ERR("Too much splits. max splits: %u\n",MAX_SPLITS);
exit_clean(1);
}
if (!parse_tlspos(optarg, dp->splits + dp->split_count))
{ {
DLOG_ERR("Invalid argument for dpi-desync-split-tls\n"); DLOG_ERR("Invalid argument for dpi-desync-split-tls\n");
exit_clean(1); exit_clean(1);
} }
dp->split_count++;
break; break;
case 26: /* dpi-desync-split-seqovl */ case 26: /* dpi-desync-split-seqovl */
if (sscanf(optarg,"%u",&dp->desync_seqovl)<1) if (sscanf(optarg,"%u",&dp->desync_seqovl)<1)
@ -2048,13 +2025,6 @@ int main(int argc, char **argv)
LIST_FOREACH(dpl, &params.desync_profiles, next) LIST_FOREACH(dpl, &params.desync_profiles, next)
{ {
dp = &dpl->dp; dp = &dpl->dp;
if (!dp->split_count && (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER))
{
DLOG_ERR("multisplit requires explicit split pos\n");
exit_clean(1);
}
// not specified - use desync_ttl value instead // not specified - use desync_ttl value instead
if (dp->desync_ttl6 == 0xFF) dp->desync_ttl6=dp->desync_ttl; if (dp->desync_ttl6 == 0xFF) dp->desync_ttl6=dp->desync_ttl;
if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl; if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl;
@ -2062,7 +2032,6 @@ int main(int argc, char **argv)
DLOG("[profile %d] autottl ipv4 %u:%u-%u\n",dp->n,dp->desync_autottl.delta,dp->desync_autottl.min,dp->desync_autottl.max); DLOG("[profile %d] autottl ipv4 %u:%u-%u\n",dp->n,dp->desync_autottl.delta,dp->desync_autottl.min,dp->desync_autottl.max);
if (AUTOTTL_ENABLED(dp->desync_autottl6)) if (AUTOTTL_ENABLED(dp->desync_autottl6))
DLOG("[profile %d] autottl ipv6 %u:%u-%u\n",dp->n,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max); DLOG("[profile %d] autottl ipv6 %u:%u-%u\n",dp->n,dp->desync_autottl6.delta,dp->desync_autottl6.min,dp->desync_autottl6.max);
split_compat(dp);
} }
if (!LoadAllHostLists()) if (!LoadAllHostLists())

View File

@ -60,8 +60,6 @@ struct desync_profile
// multisplit // multisplit
struct proto_pos splits[MAX_SPLITS]; struct proto_pos splits[MAX_SPLITS];
int split_count; int split_count;
// single split pos cache
struct proto_pos split_http,split_tls,split_unknown;
char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int desync_start, desync_cutoff; unsigned int desync_start, desync_cutoff;

View File

@ -511,8 +511,7 @@ size_t TLSPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
{ {
if (posmarker==PM_SNI_EXT) if (posmarker==PM_SNI_EXT)
{ {
offset = ext-data+1+pos; return CheckPos(sz,ext-data+pos);
return (offset>=0 && offset<sz) ? offset : 0;
} }
else else
{ {