mirror of
https://github.com/bol-van/zapret.git
synced 2024-12-02 06:30:53 +03:00
tpws: --tlsrec
This commit is contained in:
parent
2456aae8ad
commit
6dc413d0c9
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.
@ -645,6 +645,9 @@ tpws_check_domain_bypass()
|
||||
tpws_curl_test_update $1 $3 $s $s2 && break
|
||||
done
|
||||
done
|
||||
for s2 in '--tlsrec=sni' '--tlsrec=sni --split-pos=10' '--tlsrec=sni --split-pos=10 --disorder'; do
|
||||
tpws_curl_test_update $1 $3 $s2 && [ "$FORCE" != 1 ] && break
|
||||
done
|
||||
fi
|
||||
report_strategy $1 $3 tpws
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
Поддерживаемые версии
|
||||
Поддерживаемые версии
|
||||
---------------------
|
||||
|
||||
FreeBSD 11.x+ , OpenBSD 6.x+, частично MacOS Sierra+
|
||||
|
@ -243,3 +243,7 @@ v50
|
||||
DHT protocol support.
|
||||
DPI desync mode 'tamper' for DHT.
|
||||
HEX string support in addition to binary files.
|
||||
|
||||
v51
|
||||
|
||||
tpws --tlsrec attack.
|
@ -1,4 +1,4 @@
|
||||
nftables - это технология, пришедшая на замену iptables.
|
||||
nftables - это технология, пришедшая на замену iptables.
|
||||
В ней собрали все, что относилось к различным iptables. А их немало. iptables, ip6tables, ebtables, arptables, ipset.
|
||||
Весь код из разрозненных, но похожих компонент, собрали в одно целое с единым синтаксисом.
|
||||
Добавили различные конструкции языка, позволяющие писать правила более лаконично, не повторяя одни и те же команды с небольшими различиями.
|
||||
|
@ -1,4 +1,4 @@
|
||||
Специально для тех, кто хочет побыстрее начать, но не хочет слишком углубляться в простыню readme.txt.
|
||||
Специально для тех, кто хочет побыстрее начать, но не хочет слишком углубляться в простыню readme.txt.
|
||||
|
||||
Предупреждение : не пишите в issue вопросы типа "как скопировать файл", "как скачать", "как запустить", ...
|
||||
То есть все , что касается базовых навыков обращения с ОС linux. Эти вопросы буду закрывать сразу.
|
||||
|
1380
docs/readme.eng.md
1380
docs/readme.eng.md
File diff suppressed because it is too large
Load Diff
@ -1,4 +1,4 @@
|
||||
zapret v.50
|
||||
zapret v.51
|
||||
|
||||
English
|
||||
-------
|
||||
@ -592,6 +592,8 @@ tpws - это transparent proxy.
|
||||
--methodspace ; добавить пробел после метода : "GET /" => "GET /"
|
||||
--methodeol ; добавить перевод строки перед методом : "GET /" => "\r\nGET /"
|
||||
--unixeol ; конвертировать 0D0A в 0A и использовать везде 0A
|
||||
--tlsrec=sni ; разбивка TLS ClientHello на 2 TLS records. режем между 1 и 2 символами hostname в SNI. Если SNI нет - отмена.
|
||||
--tlsrec-pos=<pos> ; разбивка TLS ClientHello на 2 TLS records. режем на указанной позиции, если длина слишком мелкая - на позиции 1.
|
||||
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются.
|
||||
; в файле должен быть хост на каждой строке.
|
||||
; список читается 1 раз при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
|
||||
@ -691,6 +693,19 @@ tpws полностью работает на асинхронных сокет
|
||||
а потом полный запрос без сплита. На него может отреагировать DPI штатным образом.
|
||||
--disorder является дополнительным флагом к любому сплиту. Сам по себе он не делает ничего.
|
||||
|
||||
--tlsrec и --tlsrec-pos позволяют внутри одного tcp сегмента разрезать TLS ClientHello на 2 TLS records.
|
||||
--tlsrec=sni режет между 1 и 2 символами hostname в SNI, делая невозможным бинарный поиск паттерна без анализа структуры данных.
|
||||
В случае отсутствия SNI разбиение отменяется.
|
||||
--tlsrec-pos режет на указанной позиции. Если длина блока данных TLS меньше указанной позиции, режем на позиции 1.
|
||||
Параметр сочетается с --split-pos. В этом случае происходит сначала разделение на уровне TLS record layer, потом на уровне TCP.
|
||||
Самая изорщенная атака --tslrec, --split-pos и --disorder вместе.
|
||||
--tlsrec ломает значительное количество сайтов. Криптобиблиотеки (openssl, ...) на оконечных http серверах без проблем
|
||||
принимают разделенные tls сегменты, но мидлбоксы - не всегда. К мидлбоксам можно отнести CDN или системы ddos-защиты.
|
||||
Поэтому применение --tlsrec без ограничителей вряд ли целесообразно.
|
||||
В РФ --tlsrec обычно не работает с TLS 1.2, потому что цензор парсит сертификат сервера из ServerHello.
|
||||
Работает только с TLS 1.3, поскольку там эта информация шифруется.
|
||||
Впрочем, сейчас сайтов, не поддерживающих TLS 1.3, осталось немного.
|
||||
|
||||
--skip-nodelay может быть полезен, чтобы привести MTU к MTU системы, на которой работает tpws.
|
||||
Это может быть полезно для скрытия факта использования VPN. Пониженный MTU - 1 из способов обнаружения
|
||||
подозрительного подключения. С tcp proxy ваши соединения неотличимы от тех, что сделал бы сам шлюз.
|
||||
|
@ -1,4 +1,4 @@
|
||||
Данный мануал пишется не как копипастная инструкция, а как помощь уже соображающему.
|
||||
Данный мануал пишется не как копипастная инструкция, а как помощь уже соображающему.
|
||||
Если вы не знаете основ сетей, linux, openwrt, а пытаетесь что-то скопипастить отсюда без малейшего
|
||||
понимания смысла, то маловероятно, что у вас что-то заработает. Не тратье свое время напрасно.
|
||||
Цель - донести принципы как это настраивается вообще, а не указать какую буковку где вписать.
|
||||
|
@ -31,6 +31,11 @@ bool set_hl(int fd, int hl);
|
||||
bool set_ttl_hl(int fd, int ttl);
|
||||
int get_so_error(int fd);
|
||||
|
||||
// alignment-safe functions
|
||||
static inline uint16_t pntoh16(const uint8_t *p) {
|
||||
return ((uint16_t)p[0] << 8) | (uint16_t)p[1];
|
||||
}
|
||||
static inline void phton16(uint8_t *p, uint16_t v) {
|
||||
p[0] = (uint8_t)(v>>8);
|
||||
p[1] = (uint8_t)v;
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "strpool.h"
|
||||
|
||||
enum splithttpreq { split_none = 0, split_method, split_host };
|
||||
enum tlsrec { tlsrec_none = 0, tlsrec_sni, tlsrec_pos };
|
||||
enum bindll { unwanted=0, no, prefer, force };
|
||||
|
||||
#define MAX_BINDS 32
|
||||
@ -41,6 +42,8 @@ struct params_s
|
||||
int hostpad;
|
||||
char hostspell[4];
|
||||
enum splithttpreq split_http_req;
|
||||
enum tlsrec tlsrec;
|
||||
int tlsrec_pos;
|
||||
bool split_any_protocol;
|
||||
int split_pos;
|
||||
bool disorder;
|
||||
|
@ -4,11 +4,12 @@
|
||||
#include "params.h"
|
||||
#include "hostlist.h"
|
||||
#include "protocol.h"
|
||||
#include "helpers.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// pHost points to "Host: ..."
|
||||
bool find_host(char **pHost,char *buf,size_t bs)
|
||||
bool find_host(uint8_t **pHost,uint8_t *buf,size_t bs)
|
||||
{
|
||||
if (!*pHost)
|
||||
{
|
||||
@ -23,14 +24,15 @@ bool find_host(char **pHost,char *buf,size_t bs)
|
||||
}
|
||||
|
||||
static const char *http_methods[] = { "GET /","POST /","HEAD /","OPTIONS /","PUT /","DELETE /","CONNECT /","TRACE /",NULL };
|
||||
void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,size_t *split_pos)
|
||||
// segment buffer has at least 5 extra bytes to extend data block
|
||||
void modify_tcp_segment(uint8_t *segment,size_t segment_buffer_size,size_t *size,size_t *split_pos)
|
||||
{
|
||||
char *p, *pp, *pHost = NULL;
|
||||
uint8_t *p, *pp, *pHost = NULL;
|
||||
size_t method_len = 0, pos;
|
||||
const char **method;
|
||||
bool bIsHttp = false, bBypass = false;
|
||||
char bRemovedHostSpace = 0;
|
||||
char Host[128];
|
||||
char *pc, Host[128];
|
||||
|
||||
*split_pos=0;
|
||||
|
||||
@ -57,7 +59,7 @@ void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,si
|
||||
memcpy(Host, p, pp - p);
|
||||
Host[pp - p] = '\0';
|
||||
VPRINT("Requested Host is : %s", Host)
|
||||
for(p = Host; *p; p++) *p=tolower(*p);
|
||||
for(pc = Host; *pc; pc++) *pc=tolower(*pc);
|
||||
bBypass = !HostlistCheck(params.hostlist, params.hostlist_exclude, Host);
|
||||
}
|
||||
if (!bBypass)
|
||||
@ -208,13 +210,14 @@ void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,si
|
||||
{
|
||||
VPRINT("Not acting on this request")
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (params.split_pos && params.split_pos < *size)
|
||||
{
|
||||
// split-pos is the only parameter applicable to non-http block (may be https ?)
|
||||
if (IsTLSClientHello((uint8_t*)segment,*size))
|
||||
|
||||
if (IsTLSClientHello(segment,*size))
|
||||
{
|
||||
char host[256];
|
||||
size_t tpos=0,elen;
|
||||
const uint8_t *ext;
|
||||
|
||||
VPRINT("packet contains TLS ClientHello")
|
||||
// we need host only if hostlist is present
|
||||
@ -227,9 +230,42 @@ void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,si
|
||||
return;
|
||||
}
|
||||
}
|
||||
*split_pos = params.split_pos;
|
||||
switch(params.tlsrec)
|
||||
{
|
||||
case tlsrec_sni:
|
||||
if (TLSFindExt(segment,*size,0,&ext,&elen))
|
||||
tpos = ext-segment+1; // between typical 1st and 2nd char of hostname
|
||||
break;
|
||||
case tlsrec_pos:
|
||||
tpos = params.tlsrec_pos;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
else if (params.split_any_protocol)
|
||||
*split_pos = params.split_pos;
|
||||
if (tpos)
|
||||
{
|
||||
// construct 2 TLS records from one
|
||||
uint16_t l = pntoh16(segment+3); // length
|
||||
if (l>=2)
|
||||
{
|
||||
// length is checked in IsTLSClientHello and cannot exceed buffer size
|
||||
if (tpos>=l) tpos=1;
|
||||
VPRINT("making 2 TLS records at pos %zu",tpos)
|
||||
memmove(segment+5+tpos+5,segment+5+tpos,l-tpos);
|
||||
segment[5+tpos] = segment[0];
|
||||
segment[5+tpos+1] = segment[1];
|
||||
segment[5+tpos+2] = segment[2];
|
||||
phton16(segment+5+tpos+3,l-tpos);
|
||||
phton16(segment+3,tpos);
|
||||
*size += 5;
|
||||
}
|
||||
}
|
||||
|
||||
if (params.split_pos < *size)
|
||||
*split_pos = params.split_pos;
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.split_any_protocol && params.split_pos < *size)
|
||||
*split_pos = params.split_pos;
|
||||
}
|
||||
|
@ -1,7 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
bool find_host(char **pHost,char *buf,size_t bs);
|
||||
void modify_tcp_segment(char *segment,size_t segment_buffer_size,size_t *size,size_t *split_pos);
|
||||
bool find_host(uint8_t **pHost,uint8_t *buf,size_t bs);
|
||||
void modify_tcp_segment(uint8_t *segment,size_t segment_buffer_size,size_t *size,size_t *split_pos);
|
||||
|
74
tpws/tpws.c
74
tpws/tpws.c
@ -174,6 +174,8 @@ static void exithelp()
|
||||
" --methodspace\t\t\t; add extra space after method\n"
|
||||
" --methodeol\t\t\t; add end-of-line before method\n"
|
||||
" --unixeol\t\t\t; replace 0D0A to 0A\n"
|
||||
" --tlsrec=sni\t\t\t; make 2 TLS records. split at SNI. don't split if SNI is not present\n"
|
||||
" --tlsrec-pos=<pos>\t\t; make 2 TLS records. split at specified pos\n"
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
@ -288,19 +290,21 @@ void parse_params(int argc, char *argv[])
|
||||
{ "methodeol",no_argument,0,0 },// optidx=28
|
||||
{ "hosttab",no_argument,0,0 },// optidx=29
|
||||
{ "unixeol",no_argument,0,0 },// optidx=30
|
||||
{ "hostlist",required_argument,0,0 },// optidx=31
|
||||
{ "hostlist-exclude",required_argument,0,0 },// optidx=32
|
||||
{ "pidfile",required_argument,0,0 },// optidx=33
|
||||
{ "debug",optional_argument,0,0 },// optidx=34
|
||||
{ "local-rcvbuf",required_argument,0,0 },// optidx=35
|
||||
{ "local-sndbuf",required_argument,0,0 },// optidx=36
|
||||
{ "remote-rcvbuf",required_argument,0,0 },// optidx=37
|
||||
{ "remote-sndbuf",required_argument,0,0 },// optidx=38
|
||||
{ "socks",no_argument,0,0 },// optidx=39
|
||||
{ "no-resolve",no_argument,0,0 },// optidx=40
|
||||
{ "skip-nodelay",no_argument,0,0 },// optidx=41
|
||||
{ "tlsrec",required_argument,0,0 },// optidx=31
|
||||
{ "tlsrec-pos",required_argument,0,0 },// optidx=32
|
||||
{ "hostlist",required_argument,0,0 },// optidx=33
|
||||
{ "hostlist-exclude",required_argument,0,0 },// optidx=34
|
||||
{ "pidfile",required_argument,0,0 },// optidx=35
|
||||
{ "debug",optional_argument,0,0 },// optidx=36
|
||||
{ "local-rcvbuf",required_argument,0,0 },// optidx=37
|
||||
{ "local-sndbuf",required_argument,0,0 },// optidx=38
|
||||
{ "remote-rcvbuf",required_argument,0,0 },// optidx=39
|
||||
{ "remote-sndbuf",required_argument,0,0 },// optidx=40
|
||||
{ "socks",no_argument,0,0 },// optidx=41
|
||||
{ "no-resolve",no_argument,0,0 },// optidx=42
|
||||
{ "skip-nodelay",no_argument,0,0 },// optidx=43
|
||||
#if defined(BSD) && !defined(__OpenBSD__) && !defined(__APPLE__)
|
||||
{ "enable-pf",no_argument,0,0 },// optidx=42
|
||||
{ "enable-pf",no_argument,0,0 },// optidx=44
|
||||
#endif
|
||||
{ NULL,0,NULL,0 }
|
||||
};
|
||||
@ -472,7 +476,7 @@ void parse_params(int argc, char *argv[])
|
||||
break;
|
||||
case 24: /* split-pos */
|
||||
i = atoi(optarg);
|
||||
if (i)
|
||||
if (i>0)
|
||||
params.split_pos = i;
|
||||
else
|
||||
{
|
||||
@ -504,7 +508,27 @@ void parse_params(int argc, char *argv[])
|
||||
params.unixeol = true;
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 31: /* hostlist */
|
||||
case 31: /* tlsrec */
|
||||
if (!strcmp(optarg, "sni"))
|
||||
params.tlsrec = tlsrec_sni;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Invalid argument for tlsrec\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 32: /* tlsrec-pos */
|
||||
if ((params.tlsrec_pos = atoi(optarg))>0)
|
||||
params.tlsrec = tlsrec_pos;
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Invalid argument for tlsrec-pos\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 33: /* hostlist */
|
||||
if (!strlist_add(¶ms.hostlist_files, optarg))
|
||||
{
|
||||
fprintf(stderr, "strlist_add failed\n");
|
||||
@ -512,7 +536,7 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 32: /* hostlist-exclude */
|
||||
case 34: /* hostlist-exclude */
|
||||
if (!strlist_add(¶ms.hostlist_exclude_files, optarg))
|
||||
{
|
||||
fprintf(stderr, "strlist_add failed\n");
|
||||
@ -520,36 +544,36 @@ void parse_params(int argc, char *argv[])
|
||||
}
|
||||
params.tamper = true;
|
||||
break;
|
||||
case 33: /* pidfile */
|
||||
case 35: /* pidfile */
|
||||
strncpy(params.pidfile,optarg,sizeof(params.pidfile));
|
||||
params.pidfile[sizeof(params.pidfile)-1]='\0';
|
||||
break;
|
||||
case 34:
|
||||
case 36:
|
||||
params.debug = optarg ? atoi(optarg) : 1;
|
||||
break;
|
||||
case 35: /* local-rcvbuf */
|
||||
case 37: /* local-rcvbuf */
|
||||
params.local_rcvbuf = atoi(optarg)/2;
|
||||
break;
|
||||
case 36: /* local-sndbuf */
|
||||
case 38: /* local-sndbuf */
|
||||
params.local_sndbuf = atoi(optarg)/2;
|
||||
break;
|
||||
case 37: /* remote-rcvbuf */
|
||||
case 39: /* remote-rcvbuf */
|
||||
params.remote_rcvbuf = atoi(optarg)/2;
|
||||
break;
|
||||
case 38: /* remote-sndbuf */
|
||||
case 40: /* remote-sndbuf */
|
||||
params.remote_sndbuf = atoi(optarg)/2;
|
||||
break;
|
||||
case 39: /* socks */
|
||||
case 41: /* socks */
|
||||
params.proxy_type = CONN_TYPE_SOCKS;
|
||||
break;
|
||||
case 40: /* no-resolve */
|
||||
case 42: /* no-resolve */
|
||||
params.no_resolve = true;
|
||||
break;
|
||||
case 41: /* skip-nodelay */
|
||||
case 43: /* skip-nodelay */
|
||||
params.skip_nodelay = true;
|
||||
break;
|
||||
#if defined(BSD) && !defined(__OpenBSD__) && !defined(__APPLE__)
|
||||
case 42: /* enable-pf */
|
||||
case 44: /* enable-pf */
|
||||
params.pf_enable = true;
|
||||
break;
|
||||
#endif
|
||||
|
@ -133,7 +133,7 @@ ssize_t send_with_ttl(int fd, const void *buf, size_t len, int flags, int ttl)
|
||||
}
|
||||
|
||||
|
||||
static bool send_buffer_create(send_buffer_t *sb, char *data, size_t len, int ttl)
|
||||
static bool send_buffer_create(send_buffer_t *sb, const void *data, size_t len, int ttl)
|
||||
{
|
||||
if (sb->data)
|
||||
{
|
||||
@ -258,7 +258,7 @@ static bool conn_has_unsent_pair(tproxy_conn_t *conn)
|
||||
}
|
||||
|
||||
|
||||
static ssize_t send_or_buffer(send_buffer_t *sb, int fd, char *buf, size_t len, int ttl)
|
||||
static ssize_t send_or_buffer(send_buffer_t *sb, int fd, const void *buf, size_t len, int ttl)
|
||||
{
|
||||
ssize_t wr=0;
|
||||
if (len)
|
||||
@ -919,7 +919,7 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
|
||||
if (!conn_partner_alive(conn))
|
||||
{
|
||||
// throw it to a black hole
|
||||
char waste[65070];
|
||||
uint8_t waste[65070];
|
||||
ssize_t trd=0;
|
||||
|
||||
while((rd=recv(conn->fd, waste, sizeof(waste), MSG_DONTWAIT))>0 && trd<MAX_WASTE)
|
||||
@ -969,7 +969,7 @@ static bool handle_epoll(tproxy_conn_t *conn, struct tailhead *conn_list, uint32
|
||||
#endif
|
||||
{
|
||||
// incoming data from local leg
|
||||
char buf[RD_BLOCK_SIZE + 4];
|
||||
uint8_t buf[RD_BLOCK_SIZE + 5];
|
||||
|
||||
rd = recv(conn->fd, buf, RD_BLOCK_SIZE, MSG_DONTWAIT);
|
||||
DBGPRINT("recv fd=%d rd=%zd err=%d",conn->fd, rd,errno)
|
||||
|
Loading…
Reference in New Issue
Block a user