mirror of
https://github.com/bol-van/zapret.git
synced 2025-04-15 11:32:58 +03:00
Merge branch 'bol-van:master' into master
This commit is contained in:
commit
2c2eb10b08
@ -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>
|
||||
"
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
197
nfq/desync.c
197
nfq/desync.c
@ -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");
|
||||
|
@ -28,8 +28,6 @@ enum dpi_desync_mode {
|
||||
DESYNC_RSTACK,
|
||||
DESYNC_SYNACK,
|
||||
DESYNC_SYNDATA,
|
||||
DESYNC_SPLIT2,
|
||||
DESYNC_DISORDER2,
|
||||
DESYNC_FAKEDSPLIT,
|
||||
DESYNC_FAKEDDISORDER,
|
||||
DESYNC_MULTISPLIT,
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
107
nfq/nfqws.c
107
nfq/nfqws.c
@ -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, ¶ms.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, ¶ms.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())
|
||||
|
15
nfq/params.c
15
nfq/params.c
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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__)
|
||||
|
211
tpws/protocol.c
211
tpws/protocol.c
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
214
tpws/tpws.c
214
tpws/tpws.c
@ -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, ¶ms.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, ¶ms.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();
|
||||
|
||||
|
105
tpws/tpws_conn.c
105
tpws/tpws_conn.c
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user