mirror of
https://github.com/bol-van/zapret.git
synced 2024-11-26 12:10:53 +03:00
Compare commits
3 Commits
ef9f9ae428
...
36cd8ca3b2
Author | SHA1 | Date | |
---|---|---|---|
|
36cd8ca3b2 | ||
|
9ec2d685e3 | ||
|
46d31003e2 |
@ -55,7 +55,7 @@ TPPORT_SOCKS=987
|
|||||||
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
|
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
|
||||||
TPWS_SOCKS_OPT="
|
TPWS_SOCKS_OPT="
|
||||||
--filter-tcp=80 --methodeol <HOSTLIST> --new
|
--filter-tcp=80 --methodeol <HOSTLIST> --new
|
||||||
--filter-tcp=443 --split-tls=sni --disorder <HOSTLIST>
|
--filter-tcp=443 --split-pos=midsld --disorder <HOSTLIST>
|
||||||
"
|
"
|
||||||
|
|
||||||
TPWS_ENABLE=0
|
TPWS_ENABLE=0
|
||||||
@ -65,7 +65,7 @@ TPWS_PORTS=80,443
|
|||||||
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
|
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
|
||||||
TPWS_OPT="
|
TPWS_OPT="
|
||||||
--filter-tcp=80 --methodeol <HOSTLIST> --new
|
--filter-tcp=80 --methodeol <HOSTLIST> --new
|
||||||
--filter-tcp=443 --split-tls=sni --disorder <HOSTLIST>
|
--filter-tcp=443 --split-pos=midsld --disorder <HOSTLIST>
|
||||||
"
|
"
|
||||||
|
|
||||||
NFQWS_ENABLE=0
|
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 markers are replaced to empty string if MODE_FILTER does not satisfy
|
||||||
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
|
# <HOSTLIST_NOAUTO> appends ipset/zapret-hosts-auto.txt as normal list
|
||||||
NFQWS_OPT="
|
NFQWS_OPT="
|
||||||
--filter-tcp=80 --dpi-desync=fake,split2 --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,disorder2 --dpi-desync-fooling=md5sig <HOSTLIST> --new
|
--filter-tcp=443 --dpi-desync=fake,multidisorder --dpi-desync-split-pos=midsld --dpi-desync-fooling=md5sig <HOSTLIST> --new
|
||||||
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=6 <HOSTLIST_NOAUTO>
|
--filter-udp=443 --dpi-desync=fake --dpi-desync-repeats=6 <HOSTLIST_NOAUTO>
|
||||||
"
|
"
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ CFLAGS_MAC = -mmacosx-version-min=10.8
|
|||||||
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
|
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
|
||||||
LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz
|
LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz
|
||||||
LIBS_BSD = -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_CYGWIN32 = -lwindivert32
|
||||||
LIBS_CYGWIN64 = -lwindivert64
|
LIBS_CYGWIN64 = -lwindivert64
|
||||||
RES_CYGWIN32 = windows/res/32/winmanifest.o windows/res/32/winicon.o
|
RES_CYGWIN32 = windows/res/32/winmanifest.o windows/res/32/winicon.o
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __CYGWIN__
|
#ifdef __CYGWIN__
|
||||||
|
#define INITGUID
|
||||||
#include "windivert/windivert.h"
|
#include "windivert/windivert.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
|
|
||||||
#include "helpers.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
@ -11,6 +11,29 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.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)
|
void rtrim(char *s)
|
||||||
{
|
{
|
||||||
if (s)
|
if (s)
|
||||||
|
@ -15,6 +15,9 @@ typedef union
|
|||||||
struct sockaddr_in6 sa6; // size 28
|
struct sockaddr_in6 sa6; // size 28
|
||||||
} sockaddr_in46;
|
} 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 rtrim(char *s);
|
||||||
void replace_char(char *s, char from, char to);
|
void replace_char(char *s, char from, char to);
|
||||||
char *strncasestr(const char *s,const char *find, size_t slen);
|
char *strncasestr(const char *s,const char *find, size_t slen);
|
||||||
|
@ -139,6 +139,22 @@ int HOSTLIST_DEBUGLOG_APPEND(const char *format, ...)
|
|||||||
return 0;
|
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)
|
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;
|
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 };
|
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
|
||||||
|
|
||||||
struct desync_profile
|
struct desync_profile
|
||||||
@ -38,16 +40,16 @@ struct desync_profile
|
|||||||
bool hostcase, hostdot, hosttab, hostnospace, methodspace, methodeol, unixeol, domcase;
|
bool hostcase, hostdot, hosttab, hostnospace, methodspace, methodeol, unixeol, domcase;
|
||||||
int hostpad;
|
int hostpad;
|
||||||
char hostspell[4];
|
char hostspell[4];
|
||||||
enum httpreqpos split_http_req;
|
|
||||||
enum tlspos tlsrec;
|
|
||||||
int tlsrec_pos;
|
|
||||||
enum tlspos split_tls;
|
|
||||||
bool split_any_protocol;
|
bool split_any_protocol;
|
||||||
int split_pos;
|
|
||||||
bool disorder, disorder_http, disorder_tls;
|
bool disorder, disorder_http, disorder_tls;
|
||||||
bool oob, oob_http, oob_tls;
|
bool oob, oob_http, oob_tls;
|
||||||
uint8_t oob_byte;
|
uint8_t oob_byte;
|
||||||
|
|
||||||
|
// multisplit
|
||||||
|
struct proto_pos splits[MAX_SPLITS];
|
||||||
|
int split_count;
|
||||||
|
struct proto_pos tlsrec;
|
||||||
|
|
||||||
int mss;
|
int mss;
|
||||||
|
|
||||||
bool tamper_start_n,tamper_cutoff_n;
|
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_ERR(const char *format, ...);
|
||||||
int DLOG_PERROR(const char *s);
|
int DLOG_PERROR(const char *s);
|
||||||
int HOSTLIST_DEBUGLOG_APPEND(const char *format, ...);
|
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 VPRINT(format, ...) DLOG(format, 1, ##__VA_ARGS__)
|
||||||
#define DBGPRINT(format, ...) DLOG(format, 2, ##__VA_ARGS__)
|
#define DBGPRINT(format, ...) DLOG(format, 2, ##__VA_ARGS__)
|
||||||
|
213
tpws/protocol.c
213
tpws/protocol.c
@ -24,6 +24,133 @@ static bool FindNLD(const uint8_t *dom, size_t dlen, int level, const uint8_t **
|
|||||||
return true;
|
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 *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
|
||||||
const char *HttpMethod(const uint8_t *data, size_t len)
|
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
|
// compare 2nd level domains
|
||||||
return strcasecmp(dhost, drhost)!=0;
|
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;
|
int i;
|
||||||
|
|
||||||
switch(tpos_type)
|
switch(posmarker)
|
||||||
{
|
{
|
||||||
case httpreqpos_method:
|
case PM_HTTP_METHOD:
|
||||||
// recognize some tpws pre-applied hacks
|
// recognize some tpws pre-applied hacks
|
||||||
method=http;
|
method=data;
|
||||||
if (sz<10) break;
|
if (sz<10) break;
|
||||||
if (*method=='\n' || *method=='\r') method++;
|
if (*method=='\n' || *method=='\r') method++;
|
||||||
if (*method=='\n' || *method=='\r') method++;
|
if (*method=='\n' || *method=='\r') method++;
|
||||||
for (i=0;i<7;i++) if (*method>='A' && *method<='Z') method++;
|
for (p=method,i=0;i<7;i++) if (*p>='A' && *p<='Z') p++;
|
||||||
if (i<3 || *method!=' ') break;
|
if (i<3 || *p!=' ') break;
|
||||||
return method-http-1;
|
return CheckPos(sz,method-data+pos);
|
||||||
case httpreqpos_host:
|
case PM_HOST:
|
||||||
if (HttpFindHostConst(&host,http,sz) && (host-http+7)<sz)
|
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;
|
host+=5;
|
||||||
if (*host==' ') host++;
|
if (*host==' ' || *host=='\t') host++;
|
||||||
return host-http;
|
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;
|
break;
|
||||||
case httpreqpos_pos:
|
|
||||||
break;
|
|
||||||
default:
|
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;
|
*p = (len==1) ? *p+1 : *p+len/2;
|
||||||
return true;
|
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;
|
size_t elen;
|
||||||
const uint8_t *ext, *p;
|
const uint8_t *ext, *p;
|
||||||
switch(tpos_type)
|
size_t offset_host,len_host;
|
||||||
|
ssize_t offset;
|
||||||
|
|
||||||
|
switch(posmarker)
|
||||||
{
|
{
|
||||||
case tlspos_sni:
|
case PM_HOST:
|
||||||
case tlspos_sniext:
|
case PM_HOST_END:
|
||||||
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
case PM_HOST_SLD:
|
||||||
return (tpos_type==tlspos_sni) ? ext-tls+6 : ext-tls+1;
|
case PM_HOST_MIDSLD:
|
||||||
break;
|
case PM_HOST_ENDSLD:
|
||||||
case tlspos_snisld:
|
case PM_SNI_EXT:
|
||||||
if (TLSFindExt(tls,sz,0,&ext,&elen,false))
|
if (TLSFindExt(data,sz,0,&ext,&elen,false))
|
||||||
if (TLSHelloFindMiddleOfSLDInSNI(ext,elen,&p))
|
{
|
||||||
return p-tls;
|
if (posmarker==PM_SNI_EXT)
|
||||||
break;
|
{
|
||||||
case tlspos_pos:
|
return CheckPos(sz,ext-data+pos);
|
||||||
break;
|
}
|
||||||
default:
|
else
|
||||||
return 0;
|
{
|
||||||
|
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 <stdint.h>
|
||||||
#include <stdbool.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];
|
extern const char *http_methods[9];
|
||||||
const char *HttpMethod(const uint8_t *data, size_t len);
|
const char *HttpMethod(const uint8_t *data, size_t len);
|
||||||
bool IsHttp(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);
|
int HttpReplyCode(const uint8_t *data, size_t len);
|
||||||
// must be pre-checked by IsHttpReply
|
// must be pre-checked by IsHttpReply
|
||||||
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
|
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);
|
uint16_t TLSRecordDataLen(const uint8_t *data);
|
||||||
size_t TLSRecordLen(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 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 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);
|
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;
|
if (pthread_attr_init(&attr)) goto ex;
|
||||||
// set minimum thread stack size
|
// 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);
|
pthread_attr_destroy(&attr);
|
||||||
goto ex;
|
goto ex;
|
||||||
|
@ -8,22 +8,6 @@
|
|||||||
#include "protocol.h"
|
#include "protocol.h"
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
const char *l7proto_str(t_l7proto l7)
|
|
||||||
{
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
|
static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
|
||||||
{
|
{
|
||||||
bool bHostlistsEmpty;
|
bool bHostlistsEmpty;
|
||||||
@ -87,11 +71,10 @@ void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest)
|
|||||||
|
|
||||||
|
|
||||||
// segment buffer has at least 5 extra bytes to extend data block
|
// 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;
|
uint8_t *p, *pp, *pHost = NULL;
|
||||||
size_t method_len = 0, pos;
|
size_t method_len = 0, pos, tpos, orig_size=*size;
|
||||||
size_t tpos, spos;
|
|
||||||
const char *method;
|
const char *method;
|
||||||
bool bHaveHost = false;
|
bool bHaveHost = false;
|
||||||
char *pc, Host[256];
|
char *pc, Host[256];
|
||||||
@ -116,8 +99,8 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*split_pos=0;
|
if (multisplit_count) *multisplit_count=0;
|
||||||
*split_flags=0;
|
if (split_flags) *split_flags=0;
|
||||||
|
|
||||||
if ((method = HttpMethod(segment,*size)))
|
if ((method = HttpMethod(segment,*size)))
|
||||||
{
|
{
|
||||||
@ -193,7 +176,6 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(l7proto)
|
switch(l7proto)
|
||||||
{
|
{
|
||||||
case HTTP:
|
case HTTP:
|
||||||
@ -325,22 +307,26 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
|
|||||||
pHost = NULL; // invalidate
|
pHost = NULL; // invalidate
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*split_pos = HttpPos(ctrack->dp->split_http_req, ctrack->dp->split_pos, segment, *size);
|
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->disorder_http) *split_flags |= SPLIT_FLAG_DISORDER;
|
||||||
if (ctrack->dp->oob_http) *split_flags |= SPLIT_FLAG_OOB;
|
if (ctrack->dp->oob_http) *split_flags |= SPLIT_FLAG_OOB;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TLS:
|
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)
|
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)
|
if (tpos>5)
|
||||||
{
|
{
|
||||||
// construct 2 TLS records from one
|
// construct 2 TLS records from one
|
||||||
uint16_t l = pntoh16(segment+3); // length
|
uint16_t l = pntoh16(segment+3); // length
|
||||||
if (l>=2)
|
if (l>=2)
|
||||||
{
|
{
|
||||||
|
int i;
|
||||||
// length is checked in IsTLSClientHello and cannot exceed buffer size
|
// length is checked in IsTLSClientHello and cannot exceed buffer size
|
||||||
if ((tpos-5)>=l) tpos=5+1;
|
if ((tpos-5)>=l) tpos=5+1;
|
||||||
VPRINT("making 2 TLS records at pos %zu\n",tpos);
|
VPRINT("making 2 TLS records at pos %zu\n",tpos);
|
||||||
@ -351,27 +337,40 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
|
|||||||
phton16(segment+tpos+3,l-(tpos-5));
|
phton16(segment+tpos+3,l-(tpos-5));
|
||||||
phton16(segment+3,tpos-5);
|
phton16(segment+3,tpos-5);
|
||||||
*size += 5;
|
*size += 5;
|
||||||
// split pos present and it is not before tlsrec split. increase split pos by tlsrec header size (5 bytes)
|
// fix split positions after tlsrec. increase split pos by tlsrec header size (5 bytes)
|
||||||
if (spos && spos>=tpos) spos+=5;
|
if (multisplit_pos)
|
||||||
|
for(i=0;i<*multisplit_count;i++)
|
||||||
|
if (multisplit_pos[i]>tpos) multisplit_pos[i]+=5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (split_flags)
|
||||||
if (spos && spos < *size)
|
{
|
||||||
*split_pos = spos;
|
|
||||||
|
|
||||||
if (ctrack->dp->disorder_tls) *split_flags |= SPLIT_FLAG_DISORDER;
|
if (ctrack->dp->disorder_tls) *split_flags |= SPLIT_FLAG_DISORDER;
|
||||||
if (ctrack->dp->oob_tls) *split_flags |= SPLIT_FLAG_OOB;
|
if (ctrack->dp->oob_tls) *split_flags |= SPLIT_FLAG_OOB;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
if (ctrack->dp->split_any_protocol && ctrack->dp->split_pos < *size)
|
if (multisplit_pos && ctrack->dp->split_any_protocol)
|
||||||
*split_pos = ctrack->dp->split_pos;
|
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->disorder) *split_flags |= SPLIT_FLAG_DISORDER;
|
||||||
if (ctrack->dp->oob) *split_flags |= SPLIT_FLAG_OOB;
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const char *hostname, const char *client_ip_port, t_l7proto l7proto)
|
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_DISORDER 0x01
|
||||||
#define SPLIT_FLAG_OOB 0x02
|
#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
|
typedef struct
|
||||||
{
|
{
|
||||||
// common state
|
// common state
|
||||||
@ -28,7 +22,7 @@ typedef struct
|
|||||||
|
|
||||||
void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest);
|
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);
|
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
|
// connection reset by remote leg
|
||||||
void rst_in(t_ctrack *ctrack, const struct sockaddr *client);
|
void rst_in(t_ctrack *ctrack, const struct sockaddr *client);
|
||||||
|
185
tpws/tpws.c
185
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-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"
|
" --hostlist-auto-debug=<logfile>\t; debug auto hostlist positives\n"
|
||||||
"\nTAMPER:\n"
|
"\nTAMPER:\n"
|
||||||
" --split-http-req=method|host\t\t; split at specified logical part of plain http request\n"
|
" --split-pos=N|-N|marker+N|marker-N\t; comma separated list of split positions\n"
|
||||||
" --split-tls=sni|sniext|snisld\t\t; split at specified logical part of TLS ClientHello\n"
|
"\t\t\t\t\t; markers: method,host,endhost,sld,endsld,midsld,sniext\n"
|
||||||
" --split-pos=<numeric_offset>\t\t; split at specified pos. split-http-req or split-tls take precedence for http.\n"
|
|
||||||
" --split-any-protocol\t\t\t; split not only http and https\n"
|
" --split-any-protocol\t\t\t; split not only http and https\n"
|
||||||
#if defined(BSD) && !defined(__APPLE__)
|
#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"
|
" --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"
|
" --methodspace\t\t\t\t; add extra space after method\n"
|
||||||
" --methodeol\t\t\t\t; add end-of-line before method\n"
|
" --methodeol\t\t\t\t; add end-of-line before method\n"
|
||||||
" --unixeol\t\t\t\t; replace 0D0A to 0A\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=N|-N|marker+N|marker-N\t; make 2 TLS records. split records at specified position.\n"
|
||||||
" --tlsrec-pos=<pos>\t\t\t; make 2 TLS records. split at specified pos\n"
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
" --mss=<int>\t\t\t\t; set client MSS. forces server to split messages but significantly decreases speed !\n"
|
" --mss=<int>\t\t\t\t; set client MSS. forces server to split messages but significantly decreases speed !\n"
|
||||||
#endif
|
#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"))
|
if (!strcmp(s, "method"))
|
||||||
*pos = httpreqpos_method;
|
{
|
||||||
|
sp->marker = PM_HTTP_METHOD;
|
||||||
|
sp->pos=2;
|
||||||
|
}
|
||||||
else if (!strcmp(s, "host"))
|
else if (!strcmp(s, "host"))
|
||||||
*pos = httpreqpos_host;
|
{
|
||||||
|
sp->marker = PM_HOST;
|
||||||
|
sp->pos=1;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
return true;
|
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"))
|
if (!strcmp(s, "sni"))
|
||||||
*pos = tlspos_sni;
|
{
|
||||||
|
sp->marker = PM_HOST;
|
||||||
|
sp->pos=1;
|
||||||
|
}
|
||||||
else if (!strcmp(s, "sniext"))
|
else if (!strcmp(s, "sniext"))
|
||||||
*pos = tlspos_sniext;
|
{
|
||||||
|
sp->marker = PM_SNI_EXT;
|
||||||
|
sp->pos=1;
|
||||||
|
}
|
||||||
else if (!strcmp(s, "snisld"))
|
else if (!strcmp(s, "snisld"))
|
||||||
*pos = tlspos_snisld;
|
{
|
||||||
|
sp->marker = PM_HOST_MIDSLD;
|
||||||
|
sp->pos=0;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
return true;
|
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)
|
static bool wf_make_l3(char *opt, bool *ipv4, bool *ipv6)
|
||||||
{
|
{
|
||||||
char *e,*p,c;
|
char *e,*p,c;
|
||||||
@ -682,30 +782,46 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 23: /* split-http-req */
|
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");
|
DLOG_ERR("Invalid argument for split-http-req\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
|
dp->split_count++;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 24: /* split-tls */
|
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");
|
DLOG_ERR("Invalid argument for split-tls\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
|
dp->split_count++;
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 25: /* split-pos */
|
case 25: /* split-pos */
|
||||||
i = atoi(optarg);
|
|
||||||
if (i>0)
|
|
||||||
dp->split_pos = i;
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
DLOG_ERR("Invalid argument for split-pos\n");
|
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);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
|
dp->split_count += ct;
|
||||||
|
}
|
||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 26: /* split-any-protocol */
|
case 26: /* split-any-protocol */
|
||||||
@ -724,7 +840,6 @@ void parse_params(int argc, char *argv[])
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
dp->disorder = true;
|
dp->disorder = true;
|
||||||
save_default_ttl();
|
|
||||||
break;
|
break;
|
||||||
case 28: /* oob */
|
case 28: /* oob */
|
||||||
if (optarg)
|
if (optarg)
|
||||||
@ -770,7 +885,7 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 34: /* tlsrec */
|
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");
|
DLOG_ERR("Invalid argument for tlsrec\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
@ -778,9 +893,11 @@ void parse_params(int argc, char *argv[])
|
|||||||
params.tamper = true;
|
params.tamper = true;
|
||||||
break;
|
break;
|
||||||
case 35: /* tlsrec-pos */
|
case 35: /* tlsrec-pos */
|
||||||
if ((dp->tlsrec_pos = atoi(optarg))>0)
|
// obsolete arg
|
||||||
dp->tlsrec = tlspos_pos;
|
i = atoi(optarg);
|
||||||
else
|
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");
|
DLOG_ERR("Invalid argument for tlsrec-pos\n");
|
||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
@ -823,8 +940,6 @@ void parse_params(int argc, char *argv[])
|
|||||||
DLOG_ERR("gzipped auto hostlists are not supported\n");
|
DLOG_ERR("gzipped auto hostlists are not supported\n");
|
||||||
exit_clean(1);
|
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)))
|
if (!(dp->hostlist_auto=RegisterHostlist(dp, false, optarg)))
|
||||||
{
|
{
|
||||||
@ -858,8 +973,6 @@ void parse_params(int argc, char *argv[])
|
|||||||
exit_clean(1);
|
exit_clean(1);
|
||||||
}
|
}
|
||||||
fclose(F);
|
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));
|
strncpy(params.hostlist_auto_debuglog, optarg, sizeof(params.hostlist_auto_debuglog));
|
||||||
params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0';
|
params.hostlist_auto_debuglog[sizeof(params.hostlist_auto_debuglog) - 1] = '\0';
|
||||||
}
|
}
|
||||||
@ -881,8 +994,6 @@ void parse_params(int argc, char *argv[])
|
|||||||
fprintf(stderr, "cannot create %s\n", params.debug_logfile);
|
fprintf(stderr, "cannot create %s\n", params.debug_logfile);
|
||||||
exit_clean(1);
|
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;
|
if (!params.debug) params.debug = 1;
|
||||||
params.debug_target = LOG_TARGET_FILE;
|
params.debug_target = LOG_TARGET_FILE;
|
||||||
}
|
}
|
||||||
@ -1117,16 +1228,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);
|
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)
|
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
||||||
{
|
{
|
||||||
dp = &dpl->dp;
|
dp = &dpl->dp;
|
||||||
if (dp->split_tls==tlspos_none && dp->split_pos) dp->split_tls=tlspos_pos;
|
if (params.skip_nodelay && dp->split_count)
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
DLOG_ERR("Cannot split with --skip-nodelay\n");
|
DLOG_ERR("Cannot split with --skip-nodelay\n");
|
||||||
exit_clean(1);
|
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())
|
if (!LoadAllHostLists())
|
||||||
@ -1143,6 +1259,9 @@ void parse_params(int argc, char *argv[])
|
|||||||
VPRINT("\nlists summary:\n");
|
VPRINT("\nlists summary:\n");
|
||||||
HostlistsDebug();
|
HostlistsDebug();
|
||||||
IpsetsDebug();
|
IpsetsDebug();
|
||||||
|
|
||||||
|
VPRINT("\nsplits summary:\n");
|
||||||
|
SplitDebug();
|
||||||
VPRINT("\n");
|
VPRINT("\n");
|
||||||
|
|
||||||
#ifndef __OpenBSD__
|
#ifndef __OpenBSD__
|
||||||
|
106
tpws/tpws_conn.c
106
tpws/tpws_conn.c
@ -24,6 +24,7 @@
|
|||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "hostlist.h"
|
#include "hostlist.h"
|
||||||
|
|
||||||
|
#define PKTDATA_MAXDUMP 32
|
||||||
|
|
||||||
// keep separate legs counter. counting every time thousands of legs can consume cpu
|
// keep separate legs counter. counting every time thousands of legs can consume cpu
|
||||||
static int legs_local, legs_remote;
|
static int legs_local, legs_remote;
|
||||||
@ -92,26 +93,43 @@ static bool socks_send_rep_errno(uint8_t ver, int fd, int errn)
|
|||||||
return ver==5 ? socks5_send_rep_errno(fd,errn) : socks4_send_rep_errno(fd, errn);
|
return ver==5 ? socks5_send_rep_errno(fd,errn) : socks4_send_rep_errno(fd, errn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void packet_debug(const uint8_t *data, size_t sz)
|
||||||
|
{
|
||||||
|
hexdump_limited_dlog(data, sz, PKTDATA_MAXDUMP); VPRINT("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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 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);
|
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,fd);
|
DLOG_ERR("could not set ttl %d to fd=%d\n",ttl_apply,fd);
|
||||||
|
cork(fd,true);
|
||||||
}
|
}
|
||||||
wr = send(fd, buf, len, flags);
|
wr = send(fd, buf, len, flags);
|
||||||
if (ttl)
|
if (!params.skip_nodelay)
|
||||||
{
|
cork(fd,false);
|
||||||
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;
|
|
||||||
}
|
|
||||||
return wr;
|
return wr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,19 +326,18 @@ bool set_socket_buffers(int fd, int rcvbuf, int sndbuf)
|
|||||||
if (rcvbuf && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) <0)
|
if (rcvbuf && setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf, sizeof(int)) <0)
|
||||||
{
|
{
|
||||||
DLOG_PERROR("setsockopt (SO_RCVBUF)");
|
DLOG_PERROR("setsockopt (SO_RCVBUF)");
|
||||||
close(fd);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (sndbuf && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) <0)
|
if (sndbuf && setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf, sizeof(int)) <0)
|
||||||
{
|
{
|
||||||
DLOG_PERROR("setsockopt (SO_SNDBUF)");
|
DLOG_PERROR("setsockopt (SO_SNDBUF)");
|
||||||
close(fd);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
dbgprint_socket_buffers(fd);
|
dbgprint_socket_buffers(fd);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static bool proxy_remote_conn_ack(tproxy_conn_t *conn, int sock_err)
|
static bool proxy_remote_conn_ack(tproxy_conn_t *conn, int sock_err)
|
||||||
{
|
{
|
||||||
// if proxy mode acknowledge connection request
|
// if proxy mode acknowledge connection request
|
||||||
@ -393,7 +410,10 @@ static int connect_remote(const struct sockaddr *remote_addr, int mss)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!set_socket_buffers(remote_fd, params.remote_rcvbuf, params.remote_sndbuf))
|
if (!set_socket_buffers(remote_fd, params.remote_rcvbuf, params.remote_sndbuf))
|
||||||
|
{
|
||||||
|
close(remote_fd);
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
if (!set_keepalive(remote_fd))
|
if (!set_keepalive(remote_fd))
|
||||||
{
|
{
|
||||||
DLOG_PERROR("set_keepalive");
|
DLOG_PERROR("set_keepalive");
|
||||||
@ -1068,9 +1088,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 (params.tamper)
|
||||||
{
|
{
|
||||||
if (conn->remote)
|
if (conn->remote)
|
||||||
@ -1081,26 +1101,26 @@ static void tamper(tproxy_conn_t *conn, uint8_t *segment, size_t segment_buffer_
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (in_tamper_out_range(conn))
|
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
|
// 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;
|
ssize_t wr;
|
||||||
if (oob)
|
if (oob)
|
||||||
{
|
{
|
||||||
VPRINT("Sending OOB byte %02X\n", oob_byte);
|
|
||||||
uint8_t oob_save;
|
uint8_t oob_save;
|
||||||
oob_save = buf[len];
|
oob_save = buf[len];
|
||||||
buf[len] = oob_byte;
|
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;
|
buf[len] = oob_save;
|
||||||
|
if (wr<0 && errno==EAGAIN) wr=0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
wr = send_or_buffer(sb, fd, buf, len, 0, ttl);
|
wr = send_with_ttl(fd, buf, len, 0, ttl);
|
||||||
return wr;
|
return wr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1186,36 +1206,53 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
|
|||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
// incoming data from local leg
|
// 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);
|
rd = recv(conn->fd, buf, RD_BLOCK_SIZE, MSG_DONTWAIT);
|
||||||
DBGPRINT("recv fd=%d rd=%zd err=%d\n",conn->fd, rd,errno);
|
DBGPRINT("recv fd=%d rd=%zd err=%d\n",conn->fd, rd,errno);
|
||||||
if (rd<0 && errno==EAGAIN) rd=0;
|
if (rd<0 && errno==EAGAIN) rd=0;
|
||||||
if (rd>0)
|
if (rd>0)
|
||||||
{
|
{
|
||||||
size_t split_pos;
|
size_t multisplit_pos[MAX_SPLITS];
|
||||||
|
int multisplit_count;
|
||||||
|
|
||||||
uint8_t split_flags;
|
uint8_t split_flags;
|
||||||
|
|
||||||
bs = rd;
|
bs = rd;
|
||||||
|
|
||||||
// tamper needs to know stream position of the block start
|
// 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
|
// increase after tamper
|
||||||
conn->tnrd++;
|
conn->tnrd++;
|
||||||
conn->trd+=rd;
|
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" : "");
|
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];
|
||||||
|
|
||||||
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);
|
bApplyDisorder = !(i & 1) && i<multisplit_count && (split_flags & SPLIT_FLAG_DISORDER);
|
||||||
DBGPRINT("send_or_buffer(1) fd=%d wr=%zd err=%d\n",conn->partner->fd,wr,errno);
|
bApplyOOB = i==0 && (split_flags & SPLIT_FLAG_OOB);
|
||||||
if (wr >= 0)
|
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;
|
conn->partner->twr += wr;
|
||||||
wr = send_or_buffer(conn->partner->wr_buf + 1, conn->partner->fd, buf + split_pos, bs - split_pos, 0, 0);
|
if (wr<len)
|
||||||
DBGPRINT("send_or_buffer(2) fd=%d wr=%zd err=%d\n",conn->partner->fd,wr,errno);
|
{
|
||||||
|
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;
|
if (wr>0) conn->partner->twr += wr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
from = to;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1279,7 +1316,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);
|
DBGPRINT("read_all_and_buffer(%d) numbytes=%d\n",buffer_number,numbytes);
|
||||||
if (numbytes>0)
|
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);
|
ssize_t rd = recv(conn->fd, conn->partner->wr_buf[buffer_number].data, numbytes, MSG_DONTWAIT);
|
||||||
if (rd>0)
|
if (rd>0)
|
||||||
@ -1289,10 +1326,7 @@ static bool read_all_and_buffer(tproxy_conn_t *conn, int buffer_number)
|
|||||||
|
|
||||||
conn->partner->bFlowOut = true;
|
conn->partner->bFlowOut = true;
|
||||||
|
|
||||||
size_t split_pos;
|
tamper(conn, conn->partner->wr_buf[buffer_number].data, numbytes+6, &conn->partner->wr_buf[buffer_number].len, NULL, NULL, NULL);
|
||||||
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);
|
|
||||||
|
|
||||||
if (epoll_update_flow(conn->partner))
|
if (epoll_update_flow(conn->partner))
|
||||||
return true;
|
return true;
|
||||||
@ -1369,7 +1403,7 @@ static bool handle_resolve_pipe(tproxy_conn_t **conn, struct tailhead *conn_list
|
|||||||
else if (rd!=sizeof(void*))
|
else if (rd!=sizeof(void*))
|
||||||
{
|
{
|
||||||
// partial pointer read is FATAL. in any case it will cause pointer corruption and coredump
|
// 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);
|
exit(1000);
|
||||||
}
|
}
|
||||||
b = resolve_complete(ri, conn_list);
|
b = resolve_complete(ri, conn_list);
|
||||||
|
Loading…
Reference in New Issue
Block a user