Merge branch 'bol-van:master' into master

This commit is contained in:
allkatran 2024-11-15 12:46:44 +07:00 committed by GitHub
commit 2c2eb10b08
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
24 changed files with 788 additions and 410 deletions

View File

@ -55,7 +55,7 @@ TPPORT_SOCKS=987
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
TPWS_SOCKS_OPT="
--filter-tcp=80 --methodeol <HOSTLIST> --new
--filter-tcp=443 --split-tls=sni --disorder <HOSTLIST>
--filter-tcp=443 --split-pos=1,midsld --disorder <HOSTLIST>
"
TPWS_ENABLE=0
@ -65,7 +65,7 @@ TPWS_PORTS=80,443
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
TPWS_OPT="
--filter-tcp=80 --methodeol <HOSTLIST> --new
--filter-tcp=443 --split-tls=sni --disorder <HOSTLIST>
--filter-tcp=443 --split-pos=1,midsld --disorder <HOSTLIST>
"
NFQWS_ENABLE=0
@ -89,8 +89,8 @@ NFQWS_UDP_PKT_IN=0
# hostlist markers are replaced to empty string if MODE_FILTER does not satisfy
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
NFQWS_OPT="
--filter-tcp=80 --dpi-desync=fake,split2 --dpi-desync-fooling=md5sig <HOSTLIST> --new
--filter-tcp=443 --dpi-desync=fake,disorder2 --dpi-desync-fooling=md5sig <HOSTLIST> --new
--filter-tcp=80 --dpi-desync=fake,multisplit --dpi-desync-split-pos=method+2 --dpi-desync-fooling=md5sig <HOSTLIST> --new
--filter-tcp=443 --dpi-desync=fake,multidisorder --dpi-desync-split-pos=1,midsld --dpi-desync-fooling=badseq,md5sig <HOSTLIST> --new
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=6 <HOSTLIST_NOAUTO>
"

View File

@ -169,20 +169,16 @@ run_daemon()
local DAEMONBASE="$(basename "$2")"
local PIDFILE=$PIDDIR/$DAEMONBASE$1.pid
echo "Starting daemon $1: $2 $3"
if exists start-stop-daemon ; then
start-stop-daemon -S -p "$PIDFILE" -m -b -x "$2" -- $3
if [ -f "$PIDFILE" ] && pgrep -F "$PIDFILE" "$DAEMONBASE" >/dev/null; then
echo already running
else
if [ -f "$PIDFILE" ] && pgrep -F "$PIDFILE" "$DAEMONBASE" >/dev/null; then
echo already running
"$2" $3 >/dev/null &
PID=$!
if [ -n "$PID" ]; then
echo $PID >$PIDFILE
else
"$2" $3 >/dev/null 2>/dev/null &
PID=$!
if [ -n "$PID" ]; then
echo $PID >$PIDFILE
else
echo could not start daemon $1 : $2 $3
false
fi
echo could not start daemon $1 : $2 $3
false
fi
fi
}

View File

@ -5,7 +5,7 @@ CFLAGS_MAC = -mmacosx-version-min=10.8
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz
LIBS_BSD = -lz
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32 -luuid
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32
LIBS_CYGWIN32 = -lwindivert32
LIBS_CYGWIN64 = -lwindivert64
RES_CYGWIN32 = windows/res/32/winmanifest.o windows/res/32/winicon.o

View File

@ -1871,3 +1871,34 @@ void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transpo
udp_fix_checksum(udphdr,transport_len,ip,ip6hdr);
}
}
void dbgprint_socket_buffers(int fd)
{
if (params.debug)
{
int v;
socklen_t sz;
sz = sizeof(int);
if (!getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &v, &sz))
DLOG("fd=%d SO_RCVBUF=%d\n", fd, v);
sz = sizeof(int);
if (!getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &v, &sz))
DLOG("fd=%d SO_SNDBUF=%d\n", fd, v);
}
}
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf)
{
DLOG("set_socket_buffers fd=%d rcvbuf=%d sndbuf=%d\n", fd, rcvbuf, sndbuf);
if (rcvbuf && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) < 0)
{
DLOG_PERROR("setsockopt (SO_RCVBUF)");
return false;
}
if (sndbuf && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) < 0)
{
DLOG_PERROR("setsockopt (SO_SNDBUF)");
return false;
}
dbgprint_socket_buffers(fd);
return true;
}

View File

@ -22,6 +22,7 @@
#endif
#ifdef __CYGWIN__
#define INITGUID
#include "windivert/windivert.h"
#endif
@ -247,3 +248,6 @@ void do_nat(bool bOutbound, struct ip *ip, struct ip6_hdr *ip6, struct tcphdr *t
void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr);
void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transport_len, struct ip *ip, struct ip6_hdr *ip6hdr);
void dbgprint_socket_buffers(int fd);
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf);

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)
{
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)
{
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)
{
@ -125,15 +125,11 @@ enum dpi_desync_mode desync_mode_from_string(const char *s)
return DESYNC_SYNDATA;
else if (!strcmp(s,"fakeddisorder") || !strcmp(s,"disorder"))
return DESYNC_FAKEDDISORDER;
else if (!strcmp(s,"disorder2"))
return DESYNC_DISORDER2;
else if (!strcmp(s,"fakedsplit") || !strcmp(s,"split"))
return DESYNC_FAKEDSPLIT;
else if (!strcmp(s,"split2"))
return DESYNC_SPLIT2;
else if (!strcmp(s,"multisplit"))
else if (!strcmp(s,"multisplit") || !strcmp(s,"split2"))
return DESYNC_MULTISPLIT;
else if (!strcmp(s,"multidisorder"))
else if (!strcmp(s,"multidisorder") || !strcmp(s,"disorder2"))
return DESYNC_MULTIDISORDER;
else if (!strcmp(s,"ipfrag2"))
return DESYNC_IPFRAG2;
@ -844,7 +840,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
uint8_t *p, *phost=NULL;
const uint8_t *rdata_payload = dis->data_payload;
size_t rlen_payload = dis->len_payload;
size_t split_pos;
size_t split_pos, seqovl_pos;
size_t multisplit_pos[MAX_SPLITS];
int multisplit_count;
int i;
@ -1118,23 +1114,19 @@ 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);
}
const struct proto_pos *spos;
switch(l7proto)
{
case HTTP:
fake = dp->fake_http;
fake_size = dp->fake_http_size;
spos = &dp->split_http;
break;
case TLS:
fake = dp->fake_tls;
fake_size = dp->fake_tls_size;
spos = &dp->split_tls;
break;
default:
fake = dp->fake_unknown;
fake_size = dp->fake_unknown_size;
spos = &dp->split_unknown;
break;
}
if (dp->desync_mode==DESYNC_MULTISPLIT || dp->desync_mode==DESYNC_MULTIDISORDER || dp->desync_mode2==DESYNC_MULTISPLIT || dp->desync_mode2==DESYNC_MULTIDISORDER)
@ -1173,13 +1165,21 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("all multisplit pos are outside of this packet\n");
}
}
seqovl_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, &dp->seqovl);
}
else if (dp->desync_mode==DESYNC_FAKEDSPLIT || dp->desync_mode==DESYNC_SPLIT2 || dp->desync_mode==DESYNC_FAKEDDISORDER || dp->desync_mode==DESYNC_DISORDER2 ||
dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_SPLIT2 || dp->desync_mode2==DESYNC_FAKEDDISORDER || dp->desync_mode2==DESYNC_DISORDER2)
else if (dp->desync_mode==DESYNC_FAKEDSPLIT || dp->desync_mode==DESYNC_FAKEDDISORDER || dp->desync_mode2==DESYNC_FAKEDSPLIT || dp->desync_mode2==DESYNC_FAKEDDISORDER)
{
multisplit_count=0;
split_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, spos);
if (!split_pos) split_pos = dp->split_unknown.pos;
// first look for non-abs split
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 = 1;
DLOG("regular split pos: %zu\n",split_pos);
if (!split_pos || split_pos>rlen_payload) split_pos=1;
split_pos=pos_normalize(split_pos,reasm_offset,dis->len_payload);
@ -1187,12 +1187,15 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
DLOG("normalized regular split pos : %zu\n",split_pos);
else
DLOG("regular split pos is outside of this packet\n");
seqovl_pos = ResolvePos(rdata_payload, rlen_payload, l7proto, &dp->seqovl);
}
else
{
multisplit_count=0;
split_pos = 0;
split_pos = seqovl_pos = 0;
}
seqovl_pos = pos_normalize(seqovl_pos,reasm_offset,dis->len_payload);
if (seqovl_pos) DLOG("normalized seqovl pos : %zu\n",seqovl_pos);
// we do not need reasm buffer anymore
reasm_orig_cancel(ctrack);
@ -1241,7 +1244,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
case DESYNC_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) ||
(!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))))
{
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,
@ -1284,7 +1287,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
// do seqovl only to the first packet
// otherwise it's prone to race condition on server side
// what happens first : server pushes socket buffer to process or another packet with seqovl arrives
seqovl = i==0 ? dp->desync_seqovl : 0;
seqovl = i==0 ? seqovl_pos : 0;
#ifdef __linux__
// only linux return error if MTU is exceeded
for(;;seqovl=0)
@ -1352,13 +1355,16 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
seg = dis->data_payload+from;
seg_len = to-from;
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)
DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl for part %d.\n",dp->desync_seqovl,from,i+2);
if (seqovl_pos>=from)
DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl for part %d.\n",seqovl,from,i+2);
else
{
seqovl = dp->desync_seqovl;
seqovl = seqovl_pos;
seg_len = to-from+seqovl;
if (seg_len>sizeof(ovlseg))
{
@ -1389,30 +1395,32 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
}
break;
case DESYNC_FAKEDDISORDER:
case DESYNC_DISORDER2:
if (split_pos)
{
uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg;
size_t seg_len;
unsigned int seqovl;
if (dp->desync_seqovl>=split_pos)
if (seqovl_pos>=split_pos)
{
DLOG("seqovl>=split_pos. desync is not possible.\n");
return verdict;
DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl.\n",seqovl_pos,split_pos);
seqovl = 0;
}
else
seqovl = seqovl_pos;
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))
{
DLOG("seqovl is too large\n");
return verdict;
}
fill_pattern(fakeseg,dp->desync_seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern));
memcpy(fakeseg+dp->desync_seqovl,dis->data_payload+split_pos,dis->len_payload-split_pos);
fill_pattern(fakeseg,seqovl,dp->seqovl_pattern,sizeof(dp->seqovl_pattern));
memcpy(fakeseg+seqovl,dis->data_payload+split_pos,dis->len_payload-split_pos);
seg = fakeseg;
}
else
@ -1422,31 +1430,27 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
}
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),
fooling_orig,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
seg, seg_len, pkt1, &pkt1_len))
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");
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return verdict;
}
if (desync_mode==DESYNC_FAKEDDISORDER)
{
seg_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,
ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
zeropkt, split_pos, fakeseg, &seg_len))
return verdict;
DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos);
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len))
return verdict;
}
seg_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,
ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
zeropkt, split_pos, fakeseg, &seg_len))
return verdict;
DLOG("sending fake(1) 1st out-of-order tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos);
hexdump_limited_dlog(zeropkt,split_pos,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);
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,39 +1463,32 @@ 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))
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");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len))
return verdict;
}
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");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, seg_len))
return verdict;
return VERDICT_DROP;
}
break;
case DESYNC_FAKEDSPLIT:
case DESYNC_SPLIT2:
if (split_pos)
{
uint8_t fakeseg[DPI_DESYNC_MAX_FAKE_LEN+100],ovlseg[DPI_DESYNC_MAX_FAKE_LEN+100], *seg;
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,
ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
zeropkt, split_pos, fakeseg, &fakeseg_len))
return verdict;
DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos);
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return verdict;
}
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,
ttl_fake,IP4_TOS(dis->ip),IP6_FLOW(dis->ip6),
dp->desync_fooling_mode,dp->desync_badseq_increment,dp->desync_badseq_ack_increment,
zeropkt, split_pos, fakeseg, &fakeseg_len))
return verdict;
DLOG("sending fake(1) 1st tcp segment 0-%zu len=%zu : ",split_pos-1, split_pos);
hexdump_limited_dlog(zeropkt,split_pos,PKTDATA_MAXDUMP); DLOG("\n");
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 = seqovl_pos;
#ifdef __linux__
// only linux return error if MTU is exceeded
for(;;seqovl=0)
@ -1539,13 +1536,11 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
}
#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");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return verdict;
}
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");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , fakeseg, fakeseg_len))
return verdict;
if (split_pos<dis->len_payload)
{
pkt1_len = sizeof(pkt1);
@ -1738,7 +1733,6 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
{
const uint8_t *fake;
size_t fake_size;
bool b;
char host[256];
bool bHaveHost=false;
@ -1990,7 +1984,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));
enum dpi_desync_mode desync_mode = dp->desync_mode;
uint32_t fooling_orig = FOOL_NONE;
if (params.debug)
@ -2001,15 +1994,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);
}
bool bFake = false;
pkt1_len = sizeof(pkt1);
b = false;
switch(desync_mode)
switch(dp->desync_mode)
{
case DESYNC_FAKE_KNOWN:
if (l7proto==UNKNOWN)
{
DLOG("not applying fake because of unknown protocol\n");
desync_mode = dp->desync_mode2;
break;
}
case DESYNC_FAKE:
@ -2019,12 +2011,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");
if (!rawsend_rep(dp->desync_repeats,(struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
return verdict;
b = true;
bFake = true;
break;
case DESYNC_HOPBYHOP:
case DESYNC_DESTOPT:
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 (!prepare_udp_segment((struct sockaddr *)&src, (struct sockaddr *)&dst,
@ -2040,26 +2032,13 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
// this mode is final, no other options available
return ct_new_postnat_fix_udp(ctrack, dis->ip, dis->ip6, dis->udp, &dis->len_pkt);
}
desync_mode = dp->desync_mode2;
break;
default:
pkt1_len=0;
break;
}
if (b)
{
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;
}
enum dpi_desync_mode desync_mode = dp->desync_mode2==DESYNC_NONE ? dp->desync_mode : dp->desync_mode2;
switch(desync_mode)
{
case DESYNC_UDPLEN:
@ -2067,7 +2046,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))
{
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);
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
@ -2084,7 +2063,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
if (szcopy>szbuf)
{
DLOG("packet is too long to tamper");
return verdict;
break;
}
memcpy(pkt2+pkt2_len,dis->data_payload+1,szcopy);
pkt2_len+=szcopy;
@ -2092,7 +2071,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))
{
DLOG("could not construct packet with modified length. too large ?\n");
return verdict;
break;
}
DLOG("resending tampered DHT\n");
if (!rawsend((struct sockaddr *)&dst, desync_fwmark, ifout , pkt1, pkt1_len))
@ -2102,7 +2081,7 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
else
{
DLOG("payload is not tamperable\n");
return verdict;
break;
}
case DESYNC_IPFRAG2:
{
@ -2150,6 +2129,16 @@ static uint8_t dpi_desync_udp_packet_play(bool replay, size_t reasm_offset, uint
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;
@ -2178,7 +2167,7 @@ static void packet_debug(bool replay, const struct dissect *dis)
char s[80];
str_tcphdr(s,sizeof(s),dis->tcp);
DLOG(" %s\n",s);
if (dis->len_payload) { DLOG("TCP: len=%zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); }
if (dis->len_payload) { DLOG("TCP: len=%zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, PKTDATA_MAXDUMP); DLOG("\n"); }
}
else if (dis->udp)
@ -2186,7 +2175,7 @@ static void packet_debug(bool replay, const struct dissect *dis)
char s[30];
str_udphdr(s,sizeof(s),dis->udp);
DLOG(" %s\n",s);
if (dis->len_payload) { DLOG("UDP: len=%zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, 32); DLOG("\n"); }
if (dis->len_payload) { DLOG("UDP: len=%zu : ",dis->len_payload); hexdump_limited_dlog(dis->data_payload, dis->len_payload, PKTDATA_MAXDUMP); DLOG("\n"); }
}
else
DLOG("\n");

View File

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

View File

@ -5,12 +5,11 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/stat.h>
#include <libgen.h>
#include "params.h"
int unique_size_t(size_t *pu, int ct)
{
int i, j, u;
@ -64,22 +63,6 @@ char *strncasestr(const char *s, const char *find, size_t slen)
return (char *)s;
}
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
{
size_t k;
bool bcut = false;
if (size > limit)
{
size = limit;
bcut = true;
}
if (!size) return;
for (k = 0; k < size; k++) DLOG("%02X ", data[k]);
DLOG(bcut ? "... : " : ": ");
for (k = 0; k < size; k++) DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.');
if (bcut) DLOG(" ...");
}
bool load_file(const char *filename, void *buffer, size_t *buffer_size)
{
@ -220,38 +203,6 @@ uint16_t saport(const struct sockaddr *sa)
sa->sa_family==AF_INET6 ? ((struct sockaddr_in6*)sa)->sin6_port : 0);
}
void dbgprint_socket_buffers(int fd)
{
if (params.debug)
{
int v;
socklen_t sz;
sz = sizeof(int);
if (!getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &v, &sz))
DLOG("fd=%d SO_RCVBUF=%d\n", fd, v);
sz = sizeof(int);
if (!getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &v, &sz))
DLOG("fd=%d SO_SNDBUF=%d\n", fd, v);
}
}
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf)
{
DLOG("set_socket_buffers fd=%d rcvbuf=%d sndbuf=%d\n", fd, rcvbuf, sndbuf);
if (rcvbuf && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) < 0)
{
DLOG_PERROR("setsockopt (SO_RCVBUF)");
close(fd);
return false;
}
if (sndbuf && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) < 0)
{
DLOG_PERROR("setsockopt (SO_SNDBUF)");
close(fd);
return false;
}
dbgprint_socket_buffers(fd);
return true;
}
uint64_t pntoh64(const void *p)
{
@ -416,14 +367,14 @@ void fill_random_az09(uint8_t *p,size_t sz)
}
}
bool cd_to_exe_dir(const char *argv0)
bool set_env_exedir(const char *argv0)
{
char *s,*d;
bool bOK=false;
if ((s = strdup(argv0)))
{
if ((d = dirname(s)))
bOK = !chdir(d);
setenv("EXEDIR",s,1);
free(s);
}
return bOK;

View File

@ -24,7 +24,6 @@ void rtrim(char *s);
void replace_char(char *s, char from, char to);
char *strncasestr(const char *s,const char *find, size_t slen);
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit);
bool load_file(const char *filename,void *buffer,size_t *buffer_size);
bool load_file_nonempty(const char *filename,void *buffer,size_t *buffer_size);
bool save_file(const char *filename, const void *buffer, size_t buffer_size);
@ -40,9 +39,6 @@ uint16_t saport(const struct sockaddr *sa);
bool seq_within(uint32_t s, uint32_t s1, uint32_t s2);
void dbgprint_socket_buffers(int fd);
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf);
uint64_t pntoh64(const void *p);
void phton64(uint8_t *p, uint64_t v);
@ -79,7 +75,7 @@ void fill_random_bytes(uint8_t *p,size_t sz);
void fill_random_az(uint8_t *p,size_t sz);
void fill_random_az09(uint8_t *p,size_t sz);
bool cd_to_exe_dir(const char *argv0);
bool set_env_exedir(const char *argv0);
struct cidr4

View File

@ -752,12 +752,12 @@ static bool parse_tlspos(const char *s, struct proto_pos *sp)
else if (!strcmp(s, "sniext"))
{
sp->marker = PM_SNI_EXT;
sp->pos=0;
sp->pos=1;
}
else if (!strcmp(s, "snisld"))
{
sp->marker = PM_HOST_MIDSLD;
sp->pos=1;
sp->pos=0;
}
else
return false;
@ -838,39 +838,14 @@ static bool parse_split_pos_list(char *opt, struct proto_pos *splits, int splits
}
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->split_count)
{
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;
}
dp->splits[dp->split_count].marker = PM_ABS;
dp->splits[dp->split_count].pos = 2;
dp->split_count++;
}
}
static void SplitDebug(void)
{
struct desync_profile_list *dpl;
@ -878,11 +853,9 @@ static void SplitDebug(void)
LIST_FOREACH(dpl, &params.desync_profiles, next)
{
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++)
DLOG("profile %d multisplit %s %d\n",dp->n,posmarker_name(dp->splits[x].marker),dp->splits[x].pos);
if (!PROTO_POS_EMPTY(&dp->seqovl)) DLOG("profile %d seqovl %s %d\n",dp->n,posmarker_name(dp->seqovl.marker),dp->seqovl.pos);
}
}
@ -1066,7 +1039,7 @@ static void exithelp(void)
" --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"
"\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__
" --dpi-desync-fwmark=<int|0xHEX>\t\t; override fwmark for desync packet. default = 0x%08X (%u)\n"
#elif defined(SO_USER_COOKIE)
@ -1078,11 +1051,12 @@ static void exithelp(void)
" --dpi-desync-autottl6=[<delta>[:<min>[-<max>]]] ; overrides --dpi-desync-autottl for ipv6 only\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-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-skip-nosni=0|1\t\t\t; 1(default)=do not act on ClientHello without SNI\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; single split takes 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"
"\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=N|-N|marker+N|marker-N ; 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-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-udp=<8..%u>\t\t; ip frag position starting from the transport header. multiple of 8, default %u.\n"
@ -1149,6 +1123,8 @@ void config_from_file(const char *filename)
int main(int argc, char **argv)
{
set_env_exedir(argv[0]);
#ifdef __CYGWIN__
if (service_run(argc, argv))
{
@ -1332,10 +1308,6 @@ int main(int argc, char **argv)
fprintf(stderr, "cannot create %s\n", params.debug_logfile);
exit_clean(1);
}
#ifndef __CYGWIN__
if (params.droproot && chown(params.debug_logfile, params.uid, -1))
fprintf(stderr, "could not chown %s. log file may not be writable after privilege drop\n", params.debug_logfile);
#endif
params.debug = true;
params.debug_target = LOG_TARGET_FILE;
}
@ -1589,24 +1561,38 @@ int main(int argc, char **argv)
break;
case 24: /* dpi-desync-split-http-req */
// 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");
exit_clean(1);
}
dp->split_count++;
break;
case 25: /* dpi-desync-split-tls */
// 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");
exit_clean(1);
}
dp->split_count++;
break;
case 26: /* dpi-desync-split-seqovl */
if (sscanf(optarg,"%u",&dp->desync_seqovl)<1)
if (!parse_split_pos(optarg, &dp->seqovl))
{
DLOG_ERR("dpi-desync-split-seqovl is not valid\n");
DLOG_ERR("Invalid argument for dpi-desync-split-seqovl\n");
exit_clean(1);
}
break;
@ -1754,10 +1740,6 @@ int main(int argc, char **argv)
DLOG_ERR("gzipped auto hostlists are not supported\n");
exit_clean(1);
}
#ifndef __CYGWIN__
if (params.droproot && chown(optarg, params.uid, -1))
DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", optarg);
#endif
}
if (!(dp->hostlist_auto=RegisterHostlist(dp, false, optarg)))
{
@ -1798,10 +1780,6 @@ int main(int argc, char **argv)
exit_clean(1);
}
fclose(F);
#ifndef __CYGWIN__
if (params.droproot && chown(optarg, params.uid, -1))
DLOG_ERR("could not chown %s. auto hostlist debug log may not be writable after privilege drop\n", optarg);
#endif
strncpy(params.hostlist_auto_debuglog, optarg, sizeof(params.hostlist_auto_debuglog));
params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0';
}
@ -2045,16 +2023,15 @@ int main(int argc, char **argv)
DLOG_CONDUP("we have %d user defined desync profile(s) and default low priority profile 0\n",desync_profile_count);
#ifndef __CYGWIN__
if (params.debug_target == LOG_TARGET_FILE && params.droproot && chown(params.debug_logfile, params.uid, -1))
fprintf(stderr, "could not chown %s. log file may not be writable after privilege drop\n", params.debug_logfile);
if (params.droproot && *params.hostlist_auto_debuglog && chown(params.hostlist_auto_debuglog, params.uid, -1))
DLOG_ERR("could not chown %s. auto hostlist debug log may not be writable after privilege drop\n", params.hostlist_auto_debuglog);
#endif
LIST_FOREACH(dpl, &params.desync_profiles, next)
{
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
if (dp->desync_ttl6 == 0xFF) dp->desync_ttl6=dp->desync_ttl;
if (!AUTOTTL_ENABLED(dp->desync_autottl6)) dp->desync_autottl6 = dp->desync_autottl;
@ -2063,6 +2040,10 @@ int main(int argc, char **argv)
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);
split_compat(dp);
#ifndef __CYGWIN__
if (params.droproot && dp->hostlist_auto && chown(dp->hostlist_auto->filename, params.uid, -1))
DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", dp->hostlist_auto->filename);
#endif
}
if (!LoadAllHostLists())

View File

@ -154,6 +154,21 @@ int HOSTLIST_DEBUGLOG_APPEND(const char *format, ...)
return 0;
}
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
{
size_t k;
bool bcut = false;
if (size > limit)
{
size = limit;
bcut = true;
}
if (!size) return;
for (k = 0; k < size; k++) DLOG("%02X ", data[k]);
DLOG(bcut ? "... : " : ": ");
for (k = 0; k < size; k++) DLOG("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.');
if (bcut) DLOG(" ...");
}
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
{

View File

@ -55,13 +55,12 @@ struct desync_profile
char hostspell[4];
enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2;
bool desync_retrans,desync_skip_nosni,desync_any_proto;
unsigned int desync_repeats,desync_seqovl,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp;
unsigned int desync_repeats,desync_ipfrag_pos_tcp,desync_ipfrag_pos_udp;
// multisplit
struct proto_pos splits[MAX_SPLITS];
int split_count;
// single split pos cache
struct proto_pos split_http,split_tls,split_unknown;
struct proto_pos seqovl;
char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int desync_start, desync_cutoff;
@ -150,3 +149,4 @@ int DLOG_ERR(const char *format, ...);
int DLOG_PERROR(const char *s);
int DLOG_CONDUP(const char *format, ...);
int HOSTLIST_DEBUGLOG_APPEND(const char *format, ...);
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit);

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)
{
offset = ext-data+1+pos;
return (offset>=0 && offset<sz) ? offset : 0;
return CheckPos(sz,ext-data+pos);
}
else
{

View File

@ -1,8 +1,8 @@
#define _GNU_SOURCE
#include "helpers.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#include <sys/socket.h>
@ -10,6 +10,30 @@
#include <ifaddrs.h>
#include <time.h>
#include <sys/stat.h>
#include <libgen.h>
#include "helpers.h"
int unique_size_t(size_t *pu, int ct)
{
int i, j, u;
for (i = j = 0; j < ct; i++)
{
u = pu[j++];
for (; j < ct && pu[j] == u; j++);
pu[i] = u;
}
return i;
}
static int cmp_size_t(const void * a, const void * b)
{
return *(size_t*)a < *(size_t*)b ? -1 : *(size_t*)a > *(size_t*)b;
}
void qsort_size_t(size_t *array,size_t ct)
{
qsort(array,ct,sizeof(*array),cmp_size_t);
}
void rtrim(char *s)
{
@ -326,6 +350,20 @@ bool pf_is_empty(const port_filter *pf)
}
bool set_env_exedir(const char *argv0)
{
char *s,*d;
bool bOK=false;
if ((s = strdup(argv0)))
{
if ((d = dirname(s)))
setenv("EXEDIR",s,1);
free(s);
}
return bOK;
}
static void mask_from_preflen6_make(uint8_t plen, struct in6_addr *a)
{
if (plen >= 128)

View File

@ -15,6 +15,9 @@ typedef union
struct sockaddr_in6 sa6; // size 28
} sockaddr_in46;
int unique_size_t(size_t *pu, int ct);
void qsort_size_t(size_t *array,size_t ct);
void rtrim(char *s);
void replace_char(char *s, char from, char to);
char *strncasestr(const char *s,const char *find, size_t slen);
@ -70,6 +73,8 @@ bool pf_in_range(uint16_t port, const port_filter *pf);
bool pf_parse(const char *s, port_filter *pf);
bool pf_is_empty(const port_filter *pf);
bool set_env_exedir(const char *argv0);
#ifndef IN_LOOPBACK
#define IN_LOOPBACK(a) ((((uint32_t) (a)) & 0xff000000) == 0x7f000000)
#endif

View File

@ -139,6 +139,22 @@ int HOSTLIST_DEBUGLOG_APPEND(const char *format, ...)
return 0;
}
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
{
size_t k;
bool bcut = false;
if (size > limit)
{
size = limit;
bcut = true;
}
if (!size) return;
for (k = 0; k < size; k++) VPRINT("%02X ", data[k]);
VPRINT(bcut ? "... : " : ": ");
for (k = 0; k < size; k++) VPRINT("%c", data[k] >= 0x20 && data[k] <= 0x7F ? (char)data[k] : '.');
if (bcut) VPRINT(" ...");
}
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
{

View File

@ -29,6 +29,8 @@ struct bind_s
int bind_wait_ifup,bind_wait_ip,bind_wait_ip_ll;
};
#define MAX_SPLITS 16
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
struct desync_profile
@ -38,16 +40,16 @@ struct desync_profile
bool hostcase, hostdot, hosttab, hostnospace, methodspace, methodeol, unixeol, domcase;
int hostpad;
char hostspell[4];
enum httpreqpos split_http_req;
enum tlspos tlsrec;
int tlsrec_pos;
enum tlspos split_tls;
bool split_any_protocol;
int split_pos;
bool disorder, disorder_http, disorder_tls;
bool oob, oob_http, oob_tls;
uint8_t oob_byte;
// multisplit
struct proto_pos splits[MAX_SPLITS];
int split_count;
struct proto_pos tlsrec;
int mss;
bool tamper_start_n,tamper_cutoff_n;
@ -140,6 +142,7 @@ int DLOG_CONDUP(const char *format, ...);
int DLOG_ERR(const char *format, ...);
int DLOG_PERROR(const char *s);
int HOSTLIST_DEBUGLOG_APPEND(const char *format, ...);
void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit);
#define VPRINT(format, ...) DLOG(format, 1, ##__VA_ARGS__)
#define DBGPRINT(format, ...) DLOG(format, 2, ##__VA_ARGS__)

View File

@ -24,6 +24,133 @@ static bool FindNLD(const uint8_t *dom, size_t dlen, int level, const uint8_t **
return true;
}
const char *l7proto_str(t_l7proto l7)
{
switch(l7)
{
case HTTP: return "http";
case TLS: return "tls";
case QUIC: return "quic";
case WIREGUARD: return "wireguard";
case DHT: return "dht";
default: return "unknown";
}
}
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
{
return (l7proto==UNKNOWN && (filter_l7 & L7_PROTO_UNKNOWN)) ||
(l7proto==HTTP && (filter_l7 & L7_PROTO_HTTP)) ||
(l7proto==TLS && (filter_l7 & L7_PROTO_TLS)) ||
(l7proto==QUIC && (filter_l7 & L7_PROTO_QUIC)) ||
(l7proto==WIREGUARD && (filter_l7 & L7_PROTO_WIREGUARD)) ||
(l7proto==DHT && (filter_l7 & L7_PROTO_DHT));
}
#define PM_ABS 0
#define PM_HOST 1
#define PM_HOST_END 2
#define PM_HOST_SLD 3
#define PM_HOST_MIDSLD 4
#define PM_HOST_ENDSLD 5
#define PM_HTTP_METHOD 6
#define PM_SNI_EXT 7
bool IsHostMarker(uint8_t posmarker)
{
switch(posmarker)
{
case PM_HOST:
case PM_HOST_END:
case PM_HOST_SLD:
case PM_HOST_MIDSLD:
case PM_HOST_ENDSLD:
return true;
default:
return false;
}
}
const char *posmarker_name(uint8_t posmarker)
{
switch(posmarker)
{
case PM_ABS: return "abs";
case PM_HOST: return "host";
case PM_HOST_END: return "endhost";
case PM_HOST_SLD: return "sld";
case PM_HOST_MIDSLD: return "midsld";
case PM_HOST_ENDSLD: return "endsld";
case PM_HTTP_METHOD: return "method";
case PM_SNI_EXT: return "sniext";
default: return "?";
}
}
static size_t CheckPos(size_t sz, ssize_t offset)
{
return (offset>=0 && offset<sz) ? offset : 0;
}
size_t AnyProtoPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
{
ssize_t offset;
switch(posmarker)
{
case PM_ABS:
offset = (pos<0) ? sz+pos : pos;
return CheckPos(sz,offset);
default:
return 0;
}
}
static size_t HostPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz, size_t offset_host, size_t len_host)
{
ssize_t offset;
const uint8_t *p;
size_t slen;
switch(posmarker)
{
case PM_HOST:
offset = offset_host+pos;
break;
case PM_HOST_END:
offset = offset_host+len_host+pos;
break;
case PM_HOST_SLD:
case PM_HOST_MIDSLD:
case PM_HOST_ENDSLD:
if (((offset_host+len_host)<=sz) && FindNLD(data+offset_host,len_host,2,&p,&slen))
offset = (posmarker==PM_HOST_SLD ? p-data : posmarker==PM_HOST_ENDSLD ? p-data+slen : slen==1 ? p+1-data : p+slen/2-data) + pos;
else
offset = 0;
break;
}
return CheckPos(sz,offset);
}
size_t ResolvePos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct proto_pos *sp)
{
switch(l7proto)
{
case HTTP:
return HttpPos(sp->marker, sp->pos, data, sz);
case TLS:
return TLSPos(sp->marker, sp->pos, data, sz);
default:
return AnyProtoPos(sp->marker, sp->pos, data, sz);
}
}
void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct proto_pos *splits, int split_count, size_t *pos, int *pos_count)
{
int i,j;
for(i=j=0;i<split_count;i++)
{
pos[j] = ResolvePos(data,sz,l7proto,splits+i);
if (pos[j]) j++;
}
qsort_size_t(pos, j);
j=unique_size_t(pos, j);
*pos_count=j;
}
const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
const char *HttpMethod(const uint8_t *data, size_t len)
{
@ -169,36 +296,45 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
// compare 2nd level domains
return strcasecmp(dhost, drhost)!=0;
}
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz)
size_t HttpPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
{
const uint8_t *method, *host=NULL;
const uint8_t *method, *host=NULL, *p;
size_t offset_host,len_host;
ssize_t offset;
int i;
switch(tpos_type)
switch(posmarker)
{
case httpreqpos_method:
case PM_HTTP_METHOD:
// recognize some tpws pre-applied hacks
method=http;
method=data;
if (sz<10) break;
if (*method=='\n' || *method=='\r') method++;
if (*method=='\n' || *method=='\r') method++;
for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++;
if (i<3 || *method!=' ') break;
return method-http-1;
case httpreqpos_host:
if (HttpFindHostConst(&host,http,sz) && (host-http+7)<sz)
for (p=method,i=0;i<7;i++) if (*p>='A' && *p<='Z') p++;
if (i<3 || *p!=' ') break;
return CheckPos(sz,method-data+pos);
case PM_HOST:
case PM_HOST_END:
case PM_HOST_SLD:
case PM_HOST_MIDSLD:
case PM_HOST_ENDSLD:
if (HttpFindHostConst(&host,data,sz) && (host-data+7)<sz)
{
host+=5;
if (*host==' ') host++;
return host-http;
if (*host==' ' || *host=='\t') host++;
offset_host = host-data;
if (posmarker!=PM_HOST)
for (len_host=0; (offset_host+len_host)<sz && data[offset_host+len_host]!='\r' && data[offset_host+len_host]!='\n'; len_host++);
else
len_host = 0;
return HostPos(posmarker,pos,data,sz,offset_host,len_host);
}
break;
case httpreqpos_pos:
break;
default:
return 0;
return AnyProtoPos(posmarker,pos,data,sz);
}
return hpos_pos<sz ? hpos_pos : 0;
return 0;
}
@ -361,26 +497,37 @@ static bool TLSHelloFindMiddleOfSLDInSNI(const uint8_t *ext, size_t elen, const
*p = (len==1) ? *p+1 : *p+len/2;
return true;
}
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type)
size_t TLSPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
{
size_t elen;
const uint8_t *ext, *p;
switch(tpos_type)
size_t offset_host,len_host;
ssize_t offset;
switch(posmarker)
{
case tlspos_sni:
case tlspos_sniext:
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1;
break;
case tlspos_snisld:
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
if (TLSHelloFindMiddleOfSLDInSNI(ext,elen,&p))
return p-tls;
break;
case tlspos_pos:
break;
default:
case PM_HOST:
case PM_HOST_END:
case PM_HOST_SLD:
case PM_HOST_MIDSLD:
case PM_HOST_ENDSLD:
case PM_SNI_EXT:
if (TLSFindExt(data,sz,0,&ext,&elen,false))
{
if (posmarker==PM_SNI_EXT)
{
return CheckPos(sz,ext-data+pos);
}
else
{
if (!TLSAdvanceToHostInSNI(&ext,&elen,&len_host))
return 0;
offset_host = ext-data;
return HostPos(posmarker,pos,data,sz,offset_host,len_host);
}
}
return 0;
default:
return AnyProtoPos(posmarker,pos,data,sz);
}
return tpos_pos<sz ? tpos_pos : 0;
}

View File

@ -4,6 +4,40 @@
#include <stdint.h>
#include <stdbool.h>
typedef enum {UNKNOWN=0, HTTP, TLS, QUIC, WIREGUARD, DHT} t_l7proto;
#define L7_PROTO_HTTP 0x00000001
#define L7_PROTO_TLS 0x00000002
#define L7_PROTO_QUIC 0x00000004
#define L7_PROTO_WIREGUARD 0x00000008
#define L7_PROTO_DHT 0x00000010
#define L7_PROTO_UNKNOWN 0x80000000
const char *l7proto_str(t_l7proto l7);
bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7);
// pos markers
#define PM_ABS 0
#define PM_HOST 1
#define PM_HOST_END 2
#define PM_HOST_SLD 3
#define PM_HOST_MIDSLD 4
#define PM_HOST_ENDSLD 5
#define PM_HTTP_METHOD 6
#define PM_SNI_EXT 7
struct proto_pos
{
int16_t pos;
uint8_t marker;
};
#define PROTO_POS_EMPTY(sp) ((sp)->marker==PM_ABS && (sp)->pos==0)
bool IsHostMarker(uint8_t posmarker);
const char *posmarker_name(uint8_t posmarker);
size_t AnyProtoPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz);
size_t HttpPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz);
size_t TLSPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz);
size_t ResolvePos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct proto_pos *sp);
void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7proto l7proto, const struct proto_pos *splits, int split_count, size_t *pos, int *pos_count);
extern const char *http_methods[9];
const char *HttpMethod(const uint8_t *data, size_t len);
bool IsHttp(const uint8_t *data, size_t len);
@ -18,8 +52,6 @@ const char *HttpFind2ndLevelDomain(const char *host);
int HttpReplyCode(const uint8_t *data, size_t len);
// must be pre-checked by IsHttpReply
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
enum httpreqpos { httpreqpos_none = 0, httpreqpos_method, httpreqpos_host, httpreqpos_pos };
size_t HttpPos(enum httpreqpos tpos_type, size_t hpos_pos, const uint8_t *http, size_t sz);
uint16_t TLSRecordDataLen(const uint8_t *data);
size_t TLSRecordLen(const uint8_t *data);
@ -29,5 +61,3 @@ bool TLSFindExt(const uint8_t *data, size_t len, uint16_t type, const uint8_t **
bool TLSFindExtInHandshake(const uint8_t *data, size_t len, uint16_t type, const uint8_t **ext, size_t *len_ext, bool bPartialIsOK);
bool TLSHelloExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *host, size_t len_host, bool bPartialIsOK);
enum tlspos { tlspos_none = 0, tlspos_sni, tlspos_sniext, tlspos_snisld, tlspos_pos };
size_t TLSPos(enum tlspos tpos_type, size_t tpos_pos, const uint8_t *tls, size_t sz, uint8_t type);

View File

@ -221,7 +221,7 @@ bool resolver_init(int threads, int fd_signal_pipe)
if (pthread_attr_init(&attr)) goto ex;
// set minimum thread stack size
if (pthread_attr_setstacksize(&attr,PTHREAD_STACK_MIN>20480 ? PTHREAD_STACK_MIN : 20480))
if (pthread_attr_setstacksize(&attr,PTHREAD_STACK_MIN>32768 ? PTHREAD_STACK_MIN : 32768))
{
pthread_attr_destroy(&attr);
goto ex;

View File

@ -8,20 +8,11 @@
#include "protocol.h"
#include "helpers.h"
const char *l7proto_str(t_l7proto l7)
#define PKTDATA_MAXDUMP 32
void packet_debug(const uint8_t *data, size_t sz)
{
switch(l7)
{
case HTTP: return "http";
case TLS: return "tls";
default: return "unknown";
}
}
static bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
{
return (l7proto==UNKNOWN && (filter_l7 & L7_PROTO_UNKNOWN)) ||
(l7proto==HTTP && (filter_l7 & L7_PROTO_HTTP)) ||
(l7proto==TLS && (filter_l7 & L7_PROTO_TLS));
hexdump_limited_dlog(data, sz, PKTDATA_MAXDUMP); VPRINT("\n");
}
static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
@ -87,11 +78,10 @@ void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest)
// segment buffer has at least 5 extra bytes to extend data block
void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags)
void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *multisplit_pos, int *multisplit_count, uint8_t *split_flags)
{
uint8_t *p, *pp, *pHost = NULL;
size_t method_len = 0, pos;
size_t tpos, spos;
size_t method_len = 0, pos, tpos, orig_size=*size;
const char *method;
bool bHaveHost = false;
char *pc, Host[256];
@ -116,8 +106,8 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
return;
}
*split_pos=0;
*split_flags=0;
if (multisplit_count) *multisplit_count=0;
if (split_flags) *split_flags=0;
if ((method = HttpMethod(segment,*size)))
{
@ -193,7 +183,6 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
return;
}
}
switch(l7proto)
{
case HTTP:
@ -325,22 +314,27 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
pHost = NULL; // invalidate
}
}
*split_pos = HttpPos(ctrack->dp->split_http_req, ctrack->dp->split_pos, segment, *size);
if (ctrack->dp->disorder_http) *split_flags |= SPLIT_FLAG_DISORDER;
if (ctrack->dp->oob_http) *split_flags |= SPLIT_FLAG_OOB;
if (multisplit_pos) ResolveMultiPos(segment, *size, l7proto, ctrack->dp->splits, ctrack->dp->split_count, multisplit_pos, multisplit_count);
if (split_flags)
{
if (ctrack->dp->disorder_http) *split_flags |= SPLIT_FLAG_DISORDER;
if (ctrack->dp->oob_http) *split_flags |= SPLIT_FLAG_OOB;
}
break;
case TLS:
spos = TLSPos(ctrack->dp->split_tls, ctrack->dp->split_pos, segment, *size, 0);
if (multisplit_pos) ResolveMultiPos(segment, *size, l7proto, ctrack->dp->splits, ctrack->dp->split_count, multisplit_pos, multisplit_count);
if ((5+*size)<=segment_buffer_size)
{
tpos = TLSPos(ctrack->dp->tlsrec, ctrack->dp->tlsrec_pos+5, segment, *size, 0);
tpos = ResolvePos(segment, *size, l7proto, &ctrack->dp->tlsrec);
if (tpos>5)
{
// construct 2 TLS records from one
uint16_t l = pntoh16(segment+3); // length
if (l>=2)
{
int i;
size_t dlen;
// length is checked in IsTLSClientHello and cannot exceed buffer size
if ((tpos-5)>=l) tpos=5+1;
VPRINT("making 2 TLS records at pos %zu\n",tpos);
@ -351,27 +345,45 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
phton16(segment+tpos+3,l-(tpos-5));
phton16(segment+3,tpos-5);
*size += 5;
// split pos present and it is not before tlsrec split. increase split pos by tlsrec header size (5 bytes)
if (spos && spos>=tpos) spos+=5;
VPRINT("-2nd TLS record: ");
dlen = tpos<16 ? tpos : 16;
packet_debug(segment+tpos-dlen,dlen);
VPRINT("+2nd TLS record: ");
packet_debug(segment+tpos,*size-tpos);
// fix split positions after tlsrec. increase split pos by tlsrec header size (5 bytes)
if (multisplit_pos)
for(i=0;i<*multisplit_count;i++)
if (multisplit_pos[i]>tpos) multisplit_pos[i]+=5;
}
}
}
if (spos && spos < *size)
*split_pos = spos;
if (ctrack->dp->disorder_tls) *split_flags |= SPLIT_FLAG_DISORDER;
if (ctrack->dp->oob_tls) *split_flags |= SPLIT_FLAG_OOB;
if (split_flags)
{
if (ctrack->dp->disorder_tls) *split_flags |= SPLIT_FLAG_DISORDER;
if (ctrack->dp->oob_tls) *split_flags |= SPLIT_FLAG_OOB;
}
break;
default:
if (ctrack->dp->split_any_protocol && ctrack->dp->split_pos < *size)
*split_pos = ctrack->dp->split_pos;
if (multisplit_pos && ctrack->dp->split_any_protocol)
ResolveMultiPos(segment, *size, l7proto, ctrack->dp->splits, ctrack->dp->split_count, multisplit_pos, multisplit_count);
}
if (split_flags)
{
if (ctrack->dp->disorder) *split_flags |= SPLIT_FLAG_DISORDER;
if (ctrack->dp->oob) *split_flags |= SPLIT_FLAG_OOB;
}
if (orig_size!=*size)
{
VPRINT("segment size changed: %zu -> %zu\n", orig_size, *size);
}
if (params.debug && multisplit_count && *multisplit_count)
{
VPRINT("multisplit pos: ");
for (int i=0;i<*multisplit_count;i++) VPRINT("%zu ",multisplit_pos[i]);
VPRINT("\n");
}
if (ctrack->dp->disorder) *split_flags |= SPLIT_FLAG_DISORDER;
if (ctrack->dp->oob) *split_flags |= SPLIT_FLAG_OOB;
}
static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const char *hostname, const char *client_ip_port, t_l7proto l7proto)

View File

@ -9,12 +9,6 @@
#define SPLIT_FLAG_DISORDER 0x01
#define SPLIT_FLAG_OOB 0x02
typedef enum {UNKNOWN=0, HTTP, TLS} t_l7proto;
#define L7_PROTO_HTTP 1
#define L7_PROTO_TLS 2
#define L7_PROTO_UNKNOWN 0x80000000
const char *l7proto_str(t_l7proto l7);
typedef struct
{
// common state
@ -28,9 +22,11 @@ typedef struct
void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest);
void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *split_pos, uint8_t *split_flags);
void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *multisplit_pos, int *multisplit_count, uint8_t *split_flags);
void tamper_in(t_ctrack *ctrack, const struct sockaddr *client, uint8_t *segment,size_t segment_buffer_size,size_t *size);
// connection reset by remote leg
void rst_in(t_ctrack *ctrack, const struct sockaddr *client);
// local leg closed connection (timeout waiting response ?)
void hup_out(t_ctrack *ctrack, const struct sockaddr *client);
void packet_debug(const uint8_t *data, size_t sz);

View File

@ -182,9 +182,8 @@ static void exithelp(void)
" --hostlist-auto-fail-time=<int>\t; all failed attemps must be within these seconds (default : %d)\n"
" --hostlist-auto-debug=<logfile>\t; debug auto hostlist positives\n"
"\nTAMPER:\n"
" --split-http-req=method|host\t\t; split at specified logical part of plain http request\n"
" --split-tls=sni|sniext|snisld\t\t; split at specified logical part of TLS ClientHello\n"
" --split-pos=<numeric_offset>\t\t; split at specified pos. split-http-req or split-tls take precedence for http.\n"
" --split-pos=N|-N|marker+N|marker-N\t; comma separated list of split positions\n"
"\t\t\t\t\t; markers: method,host,endhost,sld,endsld,midsld,sniext\n"
" --split-any-protocol\t\t\t; split not only http and https\n"
#if defined(BSD) && !defined(__APPLE__)
" --disorder[=http|tls]\t\t\t; when splitting simulate sending second fragment first (BSD sends entire message instead of first fragment, this is not good)\n"
@ -203,8 +202,7 @@ static void exithelp(void)
" --methodspace\t\t\t\t; add extra space after method\n"
" --methodeol\t\t\t\t; add end-of-line before method\n"
" --unixeol\t\t\t\t; replace 0D0A to 0A\n"
" --tlsrec=sni|sniext|snisld\t\t; make 2 TLS records. split at specified logical part. don't split if SNI is not present\n"
" --tlsrec-pos=<pos>\t\t\t; make 2 TLS records. split at specified pos\n"
" --tlsrec=N|-N|marker+N|marker-N\t; make 2 TLS records. split records at specified position.\n"
#ifdef __linux__
" --mss=<int>\t\t\t\t; set client MSS. forces server to split messages but significantly decreases speed !\n"
#endif
@ -276,29 +274,131 @@ void save_default_ttl(void)
}
}
bool parse_httpreqpos(const char *s, enum httpreqpos *pos)
static bool parse_httpreqpos(const char *s, struct proto_pos *sp)
{
if (!strcmp(s, "method"))
*pos = httpreqpos_method;
{
sp->marker = PM_HTTP_METHOD;
sp->pos=2;
}
else if (!strcmp(s, "host"))
*pos = httpreqpos_host;
{
sp->marker = PM_HOST;
sp->pos=1;
}
else
return false;
return true;
}
bool parse_tlspos(const char *s, enum tlspos *pos)
static bool parse_tlspos(const char *s, struct proto_pos *sp)
{
if (!strcmp(s, "sni"))
*pos = tlspos_sni;
{
sp->marker = PM_HOST;
sp->pos=1;
}
else if (!strcmp(s, "sniext"))
*pos = tlspos_sniext;
{
sp->marker = PM_SNI_EXT;
sp->pos=1;
}
else if (!strcmp(s, "snisld"))
*pos = tlspos_snisld;
{
sp->marker = PM_HOST_MIDSLD;
sp->pos=0;
}
else
return false;
return true;
}
static bool parse_int16(const char *p, int16_t *v)
{
if (*p=='+' || *p=='-' || *p>='0' && *p<='9')
{
int i = atoi(p);
*v = (int16_t)i;
return *v==i; // check overflow
}
return false;
}
static bool parse_posmarker(const char *opt, uint8_t *posmarker)
{
if (!strcmp(opt,"host"))
*posmarker = PM_HOST;
else if (!strcmp(opt,"endhost"))
*posmarker = PM_HOST_END;
else if (!strcmp(opt,"sld"))
*posmarker = PM_HOST_SLD;
else if (!strcmp(opt,"midsld"))
*posmarker = PM_HOST_MIDSLD;
else if (!strcmp(opt,"endsld"))
*posmarker = PM_HOST_ENDSLD;
else if (!strcmp(opt,"method"))
*posmarker = PM_HTTP_METHOD;
else if (!strcmp(opt,"sniext"))
*posmarker = PM_SNI_EXT;
else
return false;
return true;
}
static bool parse_split_pos(char *opt, struct proto_pos *split)
{
if (parse_int16(opt,&split->pos))
{
split->marker = PM_ABS;
return !!split->pos;
}
else
{
char c,*p=opt;
bool b;
for (; *opt && *opt!='+' && *opt!='-'; opt++);
c=*opt; *opt=0;
b=parse_posmarker(p,&split->marker);
*opt=c;
if (!b) return false;
if (*opt)
return parse_int16(opt,&split->pos);
else
split->pos = 0;
}
return true;
}
static bool parse_split_pos_list(char *opt, struct proto_pos *splits, int splits_size, int *split_count)
{
char c,*e,*p;
for (p=opt, *split_count=0 ; p && *split_count<splits_size ; (*split_count)++)
{
if ((e = strchr(p,',')))
{
c=*e;
*e=0;
}
if (!parse_split_pos(p,splits+*split_count)) return false;
if (e) *e++=c;
p = e;
}
if (p) return false; // too much splits
return true;
}
static void SplitDebug(void)
{
struct desync_profile_list *dpl;
const struct desync_profile *dp;
int x;
LIST_FOREACH(dpl, &params.desync_profiles, next)
{
dp = &dpl->dp;
for(x=0;x<dp->split_count;x++)
VPRINT("profile %d multisplit %s %d\n",dp->n,posmarker_name(dp->splits[x].marker),dp->splits[x].pos);
if (!PROTO_POS_EMPTY(&dp->tlsrec))
VPRINT("profile %d tlsrec %s %d\n",dp->n,posmarker_name(dp->tlsrec.marker),dp->tlsrec.pos);
}
}
static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6)
{
char *e,*p,c;
@ -399,6 +499,16 @@ void config_from_file(const char *filename)
}
#endif
#ifndef __linux__
static bool check_oob_disorder(const struct desync_profile *dp)
{
return !(
dp->oob && (dp->disorder || dp->disorder_http || dp->disorder_tls) ||
dp->oob_http && (dp->disorder || dp->disorder_http) ||
dp->oob_tls && (dp->disorder || dp->disorder_tls));
}
#endif
void parse_params(int argc, char *argv[])
{
int option_index = 0;
@ -682,29 +792,45 @@ void parse_params(int argc, char *argv[])
params.tamper = true;
break;
case 23: /* split-http-req */
if (!parse_httpreqpos(optarg, &dp->split_http_req))
DLOG_CONDUP("WARNING ! --split-http-req is deprecated. use --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 split-http-req\n");
exit_clean(1);
}
dp->split_count++;
params.tamper = true;
break;
case 24: /* split-tls */
if (!parse_tlspos(optarg, &dp->split_tls))
// obsolete arg
DLOG_CONDUP("WARNING ! --split-tls is deprecated. use --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 split-tls\n");
exit_clean(1);
}
dp->split_count++;
params.tamper = true;
break;
case 25: /* split-pos */
i = atoi(optarg);
if (i>0)
dp->split_pos = i;
else
{
DLOG_ERR("Invalid argument for split-pos\n");
exit_clean(1);
int ct;
if (!parse_split_pos_list(optarg,dp->splits+dp->split_count,MAX_SPLITS-dp->split_count,&ct))
{
DLOG_ERR("could not parse split pos list or too much positions (before parsing - %u, max - %u) : %s\n",dp->split_count,MAX_SPLITS,optarg);
exit_clean(1);
}
dp->split_count += ct;
}
params.tamper = true;
break;
@ -724,7 +850,13 @@ void parse_params(int argc, char *argv[])
}
else
dp->disorder = true;
save_default_ttl();
#ifndef __linux__
if (!check_oob_disorder(dp))
{
DLOG_ERR("--oob and --disorder work simultaneously only in linux. in this system it's guaranteed to fail.\n");
exit_clean(1);
}
#endif
break;
case 28: /* oob */
if (optarg)
@ -739,6 +871,13 @@ void parse_params(int argc, char *argv[])
}
else
dp->oob = true;
#ifndef __linux__
if (!check_oob_disorder(dp))
{
DLOG_ERR("--oob and --disorder work simultaneously only in linux. in this system it's guaranteed to fail.\n");
exit_clean(1);
}
#endif
break;
case 29: /* oob-data */
{
@ -770,7 +909,7 @@ void parse_params(int argc, char *argv[])
params.tamper = true;
break;
case 34: /* tlsrec */
if (!parse_tlspos(optarg, &dp->tlsrec))
if (!parse_split_pos(optarg, &dp->tlsrec) && !parse_tlspos(optarg, &dp->tlsrec))
{
DLOG_ERR("Invalid argument for tlsrec\n");
exit_clean(1);
@ -778,9 +917,11 @@ void parse_params(int argc, char *argv[])
params.tamper = true;
break;
case 35: /* tlsrec-pos */
if ((dp->tlsrec_pos = atoi(optarg))>0)
dp->tlsrec = tlspos_pos;
else
// obsolete arg
i = atoi(optarg);
dp->tlsrec.marker = PM_ABS;
dp->tlsrec.pos = (int16_t)i;
if (!dp->tlsrec.pos || i!=dp->tlsrec.pos)
{
DLOG_ERR("Invalid argument for tlsrec-pos\n");
exit_clean(1);
@ -823,8 +964,6 @@ void parse_params(int argc, char *argv[])
DLOG_ERR("gzipped auto hostlists are not supported\n");
exit_clean(1);
}
if (params.droproot && chown(optarg, params.uid, -1))
DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", optarg);
}
if (!(dp->hostlist_auto=RegisterHostlist(dp, false, optarg)))
{
@ -858,8 +997,6 @@ void parse_params(int argc, char *argv[])
exit_clean(1);
}
fclose(F);
if (params.droproot && chown(optarg, params.uid, -1))
DLOG_ERR("could not chown %s. auto hostlist debug log may not be writable after privilege drop\n", optarg);
strncpy(params.hostlist_auto_debuglog, optarg, sizeof(params.hostlist_auto_debuglog));
params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0';
}
@ -881,8 +1018,6 @@ void parse_params(int argc, char *argv[])
fprintf(stderr, "cannot create %s\n", params.debug_logfile);
exit_clean(1);
}
if (params.droproot && chown(params.debug_logfile, params.uid, -1))
fprintf(stderr, "could not chown %s. log file may not be writable after privilege drop\n", params.debug_logfile);
if (!params.debug) params.debug = 1;
params.debug_target = LOG_TARGET_FILE;
}
@ -1054,7 +1189,7 @@ void parse_params(int argc, char *argv[])
}
params.tamper = true;
break;
#if defined(__FreeBSD__)
case 62: /* enable-pf */
params.pf_enable = true;
@ -1117,16 +1252,21 @@ void parse_params(int argc, char *argv[])
DLOG_CONDUP("we have %d user defined desync profile(s) and default low priority profile 0\n",desync_profile_count);
save_default_ttl();
if (params.debug_target == LOG_TARGET_FILE && params.droproot && chown(params.debug_logfile, params.uid, -1))
fprintf(stderr, "could not chown %s. log file may not be writable after privilege drop\n", params.debug_logfile);
if (params.droproot && *params.hostlist_auto_debuglog && chown(params.hostlist_auto_debuglog, params.uid, -1))
DLOG_ERR("could not chown %s. auto hostlist debug log may not be writable after privilege drop\n", params.hostlist_auto_debuglog);
LIST_FOREACH(dpl, &params.desync_profiles, next)
{
dp = &dpl->dp;
if (dp->split_tls==tlspos_none && dp->split_pos) dp->split_tls=tlspos_pos;
if (dp->split_http_req==httpreqpos_none && dp->split_pos) dp->split_http_req=httpreqpos_pos;
if (params.skip_nodelay && (dp->split_tls || dp->split_http_req || dp->split_pos))
if (params.skip_nodelay && dp->split_count)
{
DLOG_ERR("Cannot split with --skip-nodelay\n");
exit_clean(1);
}
if (params.droproot && dp->hostlist_auto && chown(dp->hostlist_auto->filename, params.uid, -1))
DLOG_ERR("could not chown %s. auto hostlist file may not be writable after privilege drop\n", dp->hostlist_auto->filename);
}
if (!LoadAllHostLists())
@ -1143,6 +1283,9 @@ void parse_params(int argc, char *argv[])
VPRINT("\nlists summary:\n");
HostlistsDebug();
IpsetsDebug();
VPRINT("\nsplits summary:\n");
SplitDebug();
VPRINT("\n");
#ifndef __OpenBSD__
@ -1304,6 +1447,7 @@ int main(int argc, char *argv[])
struct salisten_s list[MAX_BINDS];
char ip_port[48];
set_env_exedir(argv[0]);
srand(time(NULL));
mask_from_preflen6_prepare();

View File

@ -24,7 +24,6 @@
#include "helpers.h"
#include "hostlist.h"
// keep separate legs counter. counting every time thousands of legs can consume cpu
static int legs_local, legs_remote;
/*
@ -93,25 +92,37 @@ static bool socks_send_rep_errno(uint8_t ver, int fd, int errn)
}
static bool cork(int fd, int enable)
{
#ifdef __linux__
int e = errno;
if (setsockopt(fd, SOL_TCP, TCP_CORK, &enable, sizeof(enable))<0)
{
DLOG_PERROR("setsockopt (TCP_CORK)");
errno = e;
return false;
}
errno = e;
#endif
return true;
}
ssize_t send_with_ttl(int fd, const void *buf, size_t len, int flags, int ttl)
{
ssize_t wr;
ssize_t wr;
if (ttl)
if (!params.skip_nodelay)
{
int ttl_apply = ttl ? ttl : params.ttl_default;
DBGPRINT("send_with_ttl %d fd=%d\n",ttl,fd);
if (!set_ttl_hl(fd, ttl))
if (!set_ttl_hl(fd, ttl_apply))
//DLOG_ERR("could not set ttl %d to fd=%d\n",ttl,fd);
DLOG_ERR("could not set ttl %d to fd=%d\n",ttl,fd);
DLOG_ERR("could not set ttl %d to fd=%d\n",ttl_apply,fd);
cork(fd,true);
}
wr = send(fd, buf, len, flags);
if (ttl)
{
int e=errno;
if (!set_ttl_hl(fd, params.ttl_default))
DLOG_ERR("could not set ttl %d to fd=%d\n",params.ttl_default,fd);
errno=e;
}
if (!params.skip_nodelay)
cork(fd,false);
return wr;
}
@ -308,19 +319,18 @@ bool set_socket_buffers(int fd, int rcvbuf, int sndbuf)
if (rcvbuf && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) <0)
{
DLOG_PERROR("setsockopt (SO_RCVBUF)");
close(fd);
return false;
}
if (sndbuf && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) <0)
{
DLOG_PERROR("setsockopt (SO_SNDBUF)");
close(fd);
return false;
}
dbgprint_socket_buffers(fd);
return true;
}
static bool proxy_remote_conn_ack(tproxy_conn_t *conn, int sock_err)
{
// if proxy mode acknowledge connection request
@ -393,7 +403,10 @@ static int connect_remote(const struct sockaddr *remote_addr, int mss)
return -1;
}
if (!set_socket_buffers(remote_fd, params.remote_rcvbuf, params.remote_sndbuf))
{
close(remote_fd);
return -1;
}
if (!set_keepalive(remote_fd))
{
DLOG_PERROR("set_keepalive");
@ -1068,9 +1081,9 @@ static bool in_tamper_out_range(tproxy_conn_t *conn)
}
static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_size, size_t *segment_size, size_t *split_pos, uint8_t *split_flags)
static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_size, size_t *segment_size, size_t *multisplit_pos, int *multisplit_count, uint8_t *split_flags)
{
*split_pos=0;
if (multisplit_count) *multisplit_count=0;
if (params.tamper)
{
if (conn->remote)
@ -1081,26 +1094,26 @@ static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_
else
{
if (in_tamper_out_range(conn))
tamper_out(&conn->track,(struct sockaddr*)&conn->dest,segment,segment_buffer_size,segment_size,split_pos,split_flags);
tamper_out(&conn->track,(struct sockaddr*)&conn->dest,segment,segment_buffer_size,segment_size,multisplit_pos,multisplit_count,split_flags);
}
}
}
// buffer must have at least one extra byte for OOB
static ssize_t send_or_buffer_oob(send_buffer_t *sb, int fd, uint8_t *buf, size_t len, int ttl, bool oob, uint8_t oob_byte)
static ssize_t send_oob(int fd, uint8_t *buf, size_t len, int ttl, bool oob, uint8_t oob_byte)
{
ssize_t wr;
if (oob)
{
VPRINT("Sending OOB byte %02X\n", oob_byte);
uint8_t oob_save;
oob_save = buf[len];
buf[len] = oob_byte;
wr = send_or_buffer(sb, fd, buf, len+1, MSG_OOB, ttl);
wr = send_with_ttl(fd, buf, len+1, MSG_OOB, ttl);
buf[len] = oob_save;
if (wr<0 && errno==EAGAIN) wr=0;
}
else
wr = send_or_buffer(sb, fd, buf, len, 0, ttl);
wr = send_with_ttl(fd, buf, len, 0, ttl);
return wr;
}
@ -1186,36 +1199,53 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
#endif
{
// incoming data from local leg
uint8_t buf[RD_BLOCK_SIZE + 5];
uint8_t buf[RD_BLOCK_SIZE + 6];
rd = recv(conn->fd, buf, RD_BLOCK_SIZE, MSG_DONTWAIT);
DBGPRINT("recv fd=%d rd=%zd err=%d\n",conn->fd, rd,errno);
if (rd<0 && errno==EAGAIN) rd=0;
if (rd>0)
{
size_t split_pos;
size_t multisplit_pos[MAX_SPLITS];
int multisplit_count;
uint8_t split_flags;
bs = rd;
// tamper needs to know stream position of the block start
tamper(conn, buf, sizeof(buf), &bs, &split_pos, &split_flags);
tamper(conn, buf, sizeof(buf), &bs, multisplit_pos, &multisplit_count, &split_flags);
// increase after tamper
conn->tnrd++;
conn->trd+=rd;
if (split_pos && bs<sizeof(buf) && split_pos<sizeof(buf))
if (multisplit_count)
{
VPRINT("Splitting at pos %zu%s\n", split_pos, (split_flags & SPLIT_FLAG_DISORDER) ? " with disorder" : "");
wr = send_or_buffer_oob(conn->partner->wr_buf, conn->partner->fd, buf, split_pos, !!(split_flags & SPLIT_FLAG_DISORDER), !!(split_flags & SPLIT_FLAG_OOB), conn->track.dp ? conn->track.dp->oob_byte : 0);
DBGPRINT("send_or_buffer(1) fd=%d wr=%zd err=%d\n",conn->partner->fd,wr,errno);
if (wr >= 0)
ssize_t from,to,len;
int i;
bool bApplyDisorder, bApplyOOB;
for (i=0,from=0;i<=multisplit_count;i++)
{
to = i==multisplit_count ? bs : multisplit_pos[i];
bApplyDisorder = !(i & 1) && i<multisplit_count && (split_flags & SPLIT_FLAG_DISORDER);
bApplyOOB = i==0 && (split_flags & SPLIT_FLAG_OOB);
len = to-from;
VPRINT("Sending multisplit part %d %zd-%zd (len %zd)%s%s : ", i+1, from, to, len, bApplyDisorder ? " with disorder" : "", bApplyOOB ? " with OOB" : "");
packet_debug(buf+from,len);
wr = send_oob(conn->partner->fd, buf+from, len, bApplyDisorder, bApplyOOB, conn->track.dp ? conn->track.dp->oob_byte : 0);
if (wr<0) break;
conn->partner->twr += wr;
wr = send_or_buffer(conn->partner->wr_buf + 1, conn->partner->fd, buf + split_pos, bs - split_pos, 0, 0);
DBGPRINT("send_or_buffer(2) fd=%d wr=%zd err=%d\n",conn->partner->fd,wr,errno);
if (wr>0) conn->partner->twr += wr;
if (wr<len)
{
from+=wr;
VPRINT("Cannot send part %d immediately. only %zd bytes were sent (%zd left in segment). cancelling split.\n", i+1, wr, bs-from);
wr = send_or_buffer(conn->partner->wr_buf, conn->partner->fd, buf+from, bs-from, 0, 0);
if (wr>0) conn->partner->twr += wr;
break;
}
from = to;
}
}
else
@ -1279,7 +1309,7 @@ static bool read_all_and_buffer(tproxy_conn_t *conn, int buffer_number)
DBGPRINT("read_all_and_buffer(%d) numbytes=%d\n",buffer_number,numbytes);
if (numbytes>0)
{
if (send_buffer_create(conn->partner->wr_buf+buffer_number, NULL, numbytes, 5, 0, 0))
if (send_buffer_create(conn->partner->wr_buf+buffer_number, NULL, numbytes, 6, 0, 0))
{
ssize_t rd = recv(conn->fd, conn->partner->wr_buf[buffer_number].data, numbytes, MSG_DONTWAIT);
if (rd>0)
@ -1289,10 +1319,7 @@ static bool read_all_and_buffer(tproxy_conn_t *conn, int buffer_number)
conn->partner->bFlowOut = true;
size_t split_pos;
uint8_t split_flags;
tamper(conn, conn->partner->wr_buf[buffer_number].data, numbytes+5, &conn->partner->wr_buf[buffer_number].len, &split_pos, &split_flags);
tamper(conn, conn->partner->wr_buf[buffer_number].data, numbytes+6, &conn->partner->wr_buf[buffer_number].len, NULL, NULL, NULL);
if (epoll_update_flow(conn->partner))
return true;
@ -1369,7 +1396,7 @@ static bool handle_resolve_pipe(tproxy_conn_t **conn, struct tailhead *conn_list
else if (rd!=sizeof(void*))
{
// partial pointer read is FATAL. in any case it will cause pointer corruption and coredump
DLOG_ERR("resolve_pipe not full read %zu\n",rd);
DLOG_ERR("resolve_pipe not full read %zd\n",rd);
exit(1000);
}
b = resolve_complete(ri, conn_list);