tpws: --mss

This commit is contained in:
bol-van 2024-03-27 17:48:37 +03:00
parent ed69120539
commit e0250e44af
17 changed files with 121 additions and 5 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -591,6 +591,8 @@ tpws is transparent proxy.
--unixeol ; replace 0D0A to 0A --unixeol ; replace 0D0A to 0A
--tlsrec=sni ; make 2 TLS records. split at SNI. don't split if SNI is not present. --tlsrec=sni ; make 2 TLS records. split at SNI. don't split if SNI is not present.
--tlsrec-pos=<pos> ; make 2 TLS records. split at specified pos --tlsrec-pos=<pos> ; make 2 TLS records. split at specified pos
--mss=<int> ; set client MSS. forces server to split messages but significantly decreases speed !
--mss-pf=[~]port1[-port2] ; MSS port filter. ~ means negation
--tamper-start=[n]<pos> ; start tampering only from specified outbound stream position. byte pos or block number ('n'). default is 0. --tamper-start=[n]<pos> ; start tampering only from specified outbound stream position. byte pos or block number ('n'). default is 0.
--tamper-cutoff=[n]<pos> ; do not tamper anymore after specified outbound stream position. byte pos or block number ('n'). default is unlimited. --tamper-cutoff=[n]<pos> ; do not tamper anymore after specified outbound stream position. byte pos or block number ('n'). default is unlimited.
--daemon ; daemonize --daemon ; daemonize
@ -664,6 +666,15 @@ This works fine in Linux and MacOS but unexpectedly in FreeBSD and OpenBSD
but middleboxes such as CDNs and ddos guards - not always. but middleboxes such as CDNs and ddos guards - not always.
Use of `--tlsrec` without filters is discouraged. Use of `--tlsrec` without filters is discouraged.
`--mss` sets TCP_MAXSEG socket option. Client sets this value in MSS TCP option in the SYN packet.
Server replies with it's own MSS in SYN,ACK packet. Usually servers lower their packet sizes but they still don't
fit to supplied MSS. The greater MSS client sets the bigger server's packets will be.
If it's enough to split TLS 1.2 ServerHello, it may fool DPI that checks certificate domain name.
This scheme may significantly lower speed. Hostlist and TLS version filters are not possible.
`--mss-pf` sets port filter for MSS. Use `mss-pf=443` to apply MSS only for https.
Likely not required for TLS1.3. If TLS1.3 is negotiable then MSS make things only worse.
Use only if nothing better is available. Works only in Linux, not BSD or MacOS.
## Ways to get a list of blocked IP ## Ways to get a list of blocked IP

View File

@ -672,6 +672,8 @@ tpws - это transparent proxy.
--unixeol ; конвертировать 0D0A в 0A и использовать везде 0A --unixeol ; конвертировать 0D0A в 0A и использовать везде 0A
--tlsrec=sni ; разбивка TLS ClientHello на 2 TLS records. режем между 1 и 2 символами hostname в SNI. Если SNI нет - отмена. --tlsrec=sni ; разбивка TLS ClientHello на 2 TLS records. режем между 1 и 2 символами hostname в SNI. Если SNI нет - отмена.
--tlsrec-pos=<pos> ; разбивка TLS ClientHello на 2 TLS records. режем на указанной позиции, если длина слишком мелкая - на позиции 1. --tlsrec-pos=<pos> ; разбивка TLS ClientHello на 2 TLS records. режем на указанной позиции, если длина слишком мелкая - на позиции 1.
--mss=<int> ; установить MSS для клиента. может заставить сервер разбивать ответы, но существенно снижает скорость
--mss-pf=[~]port1[-port2] ; применять MSS только к портам назначения, подпадающим под фильтр. ~ означает инверсию
--tamper-start=[n]<pos> ; начинать дурение только с указанной байтовой позиции или номера блока исходяшего потока (считается позиция начала принятого блока) --tamper-start=[n]<pos> ; начинать дурение только с указанной байтовой позиции или номера блока исходяшего потока (считается позиция начала принятого блока)
--tamper-cutoff=[n]<pos> ; закончить дурение на указанной байтовой позиции или номере блока исходящего потока (считается позиция начала принятого блока) --tamper-cutoff=[n]<pos> ; закончить дурение на указанной байтовой позиции или номере блока исходящего потока (считается позиция начала принятого блока)
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются. --hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются.
@ -790,6 +792,21 @@ tpws полностью работает на асинхронных сокет
Работает только с TLS 1.3, поскольку там эта информация шифруется. Работает только с TLS 1.3, поскольку там эта информация шифруется.
Впрочем, сейчас сайтов, не поддерживающих TLS 1.3, осталось немного. Впрочем, сейчас сайтов, не поддерживающих TLS 1.3, осталось немного.
--mss устанавливает опцию сокета TCP_MAXSEG. Клиент выдает это значение в tcp опциях SYN пакета.
Сервер в ответ в SYN,ACK выдает свой MSS. На практике сервера обычно снижают размеры отсылаемых ими пакетов, но они
все равно не вписываются в низкий MSS, указанный клиентом. Обычно чем больше указал клиент, тем больше
шлет сервер. На TLS 1.2 если сервер разбил заброс так, чтобы домен из сертификата не попал в первый пакет,
это может обмануть DPI, секущий ответ сервера.
Схема может значительно снизить скорость и сработать не на всех сайтах.
Несовместимо с фильтром по hostlist. Невозможен фильтр по версии TLS.
Взамен имеется фильтр по портам --mss-pf. --mss-pf=443 применяет дурение только к https.
Применяя данную опцию к сайтам TLS1.3, если броузер тоже поддерживает TLS1.3, то вы делаете только хуже.
Но нет способа автоматически узнать когда надо применять, когда нет, поскольку MSS идет только в
3-way handshake еще до обмены данными, а версию TLS можно узнать только по ответу сервера, который
может привести к реакции DPI.
Использовать только когда нет ничего лучше или для отдельных ресурсов.
Работает только на linux, не работает на BSD и MacOS.
--skip-nodelay может быть полезен, чтобы привести MTU к MTU системы, на которой работает tpws. --skip-nodelay может быть полезен, чтобы привести MTU к MTU системы, на которой работает tpws.
Это может быть полезно для скрытия факта использования VPN. Пониженный MTU - 1 из способов обнаружения Это может быть полезно для скрытия факта использования VPN. Пониженный MTU - 1 из способов обнаружения
подозрительного подключения. С tcp proxy ваши соединения неотличимы от тех, что сделал бы сам шлюз. подозрительного подключения. С tcp proxy ваши соединения неотличимы от тех, что сделал бы сам шлюз.

View File

@ -24,6 +24,12 @@ 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;
}; };
typedef struct
{
uint16_t from,to;
bool neg;
} port_filter;
struct params_s struct params_s
{ {
struct bind_s binds[MAX_BINDS]; struct bind_s binds[MAX_BINDS];
@ -55,6 +61,9 @@ struct params_s
uint8_t oob_byte; uint8_t oob_byte;
int ttl_default; int ttl_default;
int mss;
port_filter mss_pf;
char pidfile[256]; char pidfile[256];
strpool *hostlist, *hostlist_exclude; strpool *hostlist, *hostlist_exclude;

View File

@ -189,6 +189,10 @@ static void exithelp(void)
" --unixeol\t\t\t\t; replace 0D0A to 0A\n" " --unixeol\t\t\t\t; replace 0D0A to 0A\n"
" --tlsrec=sni\t\t\t\t; make 2 TLS records. split at SNI. don't split if SNI is not present\n" " --tlsrec=sni\t\t\t\t; make 2 TLS records. split at SNI. 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-pos=<pos>\t\t\t; make 2 TLS records. split at specified pos\n"
#ifdef __linux__
" --mss=<int>\t\t\t\t; set client MSS. forces server to split messages but significantly decreases speed !\n"
" --mss-pf=[~]port1[-port2]\t\t; MSS port filter. ~ means negation\n"
#endif
" --tamper-start=[n]<pos>\t\t; start tampering only from specified outbound stream position. default is 0. 'n' means data block number.\n" " --tamper-start=[n]<pos>\t\t; start tampering only from specified outbound stream position. default is 0. 'n' means data block number.\n"
" --tamper-cutoff=[n]<pos>\t\t; do not tamper anymore after specified outbound stream position. default is unlimited.\n", " --tamper-cutoff=[n]<pos>\t\t; do not tamper anymore after specified outbound stream position. default is unlimited.\n",
HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT
@ -324,6 +328,9 @@ void parse_params(int argc, char *argv[])
{ "tamper-cutoff",required_argument,0,0 },// optidx=51 { "tamper-cutoff",required_argument,0,0 },// optidx=51
#if defined(BSD) && !defined(__OpenBSD__) && !defined(__APPLE__) #if defined(BSD) && !defined(__OpenBSD__) && !defined(__APPLE__)
{ "enable-pf",no_argument,0,0 },// optidx=52 { "enable-pf",no_argument,0,0 },// optidx=52
#elif defined(__linux__)
{ "mss",required_argument,0,0 },// optidx=52
{ "mss-pf",required_argument,0,0 },// optidx=53
#endif #endif
{ "hostlist-auto-retrans-threshold",optional_argument,0,0}, // ignored. for nfqws command line compatibility { "hostlist-auto-retrans-threshold",optional_argument,0,0}, // ignored. for nfqws command line compatibility
{ NULL,0,NULL,0 } { NULL,0,NULL,0 }
@ -723,6 +730,23 @@ void parse_params(int argc, char *argv[])
case 52: /* enable-pf */ case 52: /* enable-pf */
params.pf_enable = true; params.pf_enable = true;
break; break;
#elif defined(__linux__)
case 52: /* mss */
// this option does not work in any BSD and MacOS. OS may accept but it changes nothing
params.mss = atoi(optarg);
if (params.mss<88 || params.mss>32767)
{
fprintf(stderr, "Invalid value for MSS. Linux accepts MSS 88-32767.\n");
exit_clean(1);
}
break;
case 53: /* mss-pf */
if (!pf_parse(optarg,&params.mss_pf))
{
fprintf(stderr, "Invalid MSS port filter.\n");
exit_clean(1);
}
break;
#endif #endif
} }
} }

View File

@ -20,7 +20,6 @@
#include "tpws_conn.h" #include "tpws_conn.h"
#include "redirect.h" #include "redirect.h"
#include "tamper.h" #include "tamper.h"
#include "params.h"
#include "socks.h" #include "socks.h"
#include "helpers.h" #include "helpers.h"
@ -336,7 +335,7 @@ static bool proxy_remote_conn_ack(tproxy_conn_t *conn, int sock_err)
//Returns -1 if something fails, >0 on success (socket fd). //Returns -1 if something fails, >0 on success (socket fd).
static int connect_remote(const struct sockaddr *remote_addr) static int connect_remote(const struct sockaddr *remote_addr)
{ {
int remote_fd = 0, yes = 1, no = 0; int remote_fd = 0, yes = 1, no = 0, v;
if((remote_fd = socket(remote_addr->sa_family, SOCK_STREAM, 0)) < 0) if((remote_fd = socket(remote_addr->sa_family, SOCK_STREAM, 0)) < 0)
@ -368,10 +367,28 @@ static int connect_remote(const struct sockaddr *remote_addr)
} }
if (setsockopt(remote_fd, IPPROTO_TCP, TCP_NODELAY, params.skip_nodelay ? &no : &yes, sizeof(int)) <0) if (setsockopt(remote_fd, IPPROTO_TCP, TCP_NODELAY, params.skip_nodelay ? &no : &yes, sizeof(int)) <0)
{ {
perror("setsockopt (SO_NODELAY, connect_remote)"); perror("setsockopt (TCP_NODELAY, connect_remote)");
close(remote_fd); close(remote_fd);
return -1; return -1;
} }
if (params.mss)
{
uint16_t port = saport(remote_addr);
if (pf_in_range(port,&params.mss_pf))
{
VPRINT("Setting MSS %d",params.mss)
if (setsockopt(remote_fd, IPPROTO_TCP, TCP_MAXSEG, &params.mss, sizeof(int)) <0)
{
perror("setsockopt (TCP_MAXSEG, connect_remote)");
close(remote_fd);
return -1;
}
}
else
{
VPRINT("Not setting MSS. Port %u is out of MSS port range.",port)
}
}
if(connect(remote_fd, remote_addr, remote_addr->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) < 0) if(connect(remote_fd, remote_addr, remote_addr->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)) < 0)
{ {
if(errno != EINPROGRESS) if(errno != EINPROGRESS)
@ -1043,7 +1060,7 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
if (split_pos) if (split_pos)
{ {
VPRINT("Splitting at pos %zu%s", split_pos, (split_flags & SPLIT_FLAG_DISORDER) ? " with disorder" : "") VPRINT("Splitting at pos %zu%s", split_pos, (split_flags & SPLIT_FLAG_DISORDER) ? " with disorder" : "")
if (split_flags && SPLIT_FLAG_OOB) if (split_flags & SPLIT_FLAG_OOB)
{ {
VPRINT("Sending OOB byte %02X", params.oob_byte) VPRINT("Sending OOB byte %02X", params.oob_byte)
uint8_t oob_save; uint8_t oob_save;
@ -1394,3 +1411,37 @@ ex:
if (listen_conn) free(listen_conn); if (listen_conn) free(listen_conn);
return retval; return retval;
} }
bool pf_in_range(uint16_t port, const port_filter *pf)
{
return port && ((!pf->from && !pf->to || port>=pf->from && port<=pf->to) ^ pf->neg);
}
bool pf_parse(const char *s, port_filter *pf)
{
unsigned int v1,v2;
if (!s) return false;
if (*s=='~')
{
pf->neg=true;
s++;
}
else
pf->neg=false;
if (sscanf(s,"%u-%u",&v1,&v2)==2)
{
if (!v1 || v1>65535 || v2>65535 || v1>v2) return false;
pf->from=(uint16_t)v1;
pf->to=(uint16_t)v2;
}
else if (sscanf(s,"%u",&v1)==1)
{
if (!v1 || v1>65535) return false;
pf->to=pf->from=(uint16_t)v1;
}
else
return false;
return true;
}

View File

@ -5,6 +5,7 @@
#include <sys/queue.h> #include <sys/queue.h>
#include <time.h> #include <time.h>
#include "tamper.h" #include "tamper.h"
#include "params.h"
#define BACKLOG 10 #define BACKLOG 10
#define MAX_EPOLL_EVENTS 64 #define MAX_EPOLL_EVENTS 64
@ -99,3 +100,6 @@ TAILQ_HEAD(tailhead, tproxy_conn);
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf); bool set_socket_buffers(int fd, int rcvbuf, int sndbuf);
bool pf_in_range(uint16_t port, const port_filter *pf);
bool pf_parse(const char *s, port_filter *pf);