13 Commits
v69 ... v69.1

Author SHA1 Message Date
bol-van
46284938ce tpws: fix socks-hostname hostlist checks 2024-11-22 12:42:33 +03:00
bol-van
09378553b9 keenetic script check disable ipv4 2024-11-21 20:35:27 +03:00
bol-van
6b85884cdf update keentic fix script 2024-11-21 20:30:23 +03:00
bol-van
1b14a8210c readme: more precise marker definition 2024-11-21 15:44:18 +03:00
bol-van
182fe850db makefiles: use lto 2024-11-21 15:25:19 +03:00
bol-van
62b081e9fb doc works 2024-11-21 10:47:11 +03:00
bol-van
e3e7449d74 doc works 2024-11-21 10:44:52 +03:00
bol-van
669f1978a3 doc works 2024-11-21 10:02:32 +03:00
bol-van
57c4b1a2b2 fix grep in default_route_interfaces6 2024-11-20 17:21:16 +03:00
bol-van
ac7385391e 10-keenetic-udp-fix: auto discover wan interfaces 2024-11-19 22:09:40 +03:00
bol-van
50a52d79ec default_route_interfaces helpers 2024-11-19 22:08:48 +03:00
bol-van
d77a1c8cd6 init.d: keenetic udp fix script 2024-11-19 19:54:21 +03:00
bol-van
395b9480c5 nfqws: fix wrong printf format 2024-11-19 19:27:36 +03:00
12 changed files with 96 additions and 58 deletions

View File

@@ -125,3 +125,13 @@ resolve_lower_devices()
}
}
}
default_route_interfaces6()
{
sed -nre 's/^00000000000000000000000000000000 00 [0-9a-f]{32} [0-9a-f]{2} [0-9a-f]{32} [0-9a-f]{8} [0-9a-f]{8} [0-9a-f]{8} [0-9a-f]{8} +(.*)$/\1/p' /proc/net/ipv6_route | grep -v '^lo$' | sort -u | xargs
}
default_route_interfaces4()
{
sed -nre 's/^([^\t]+)\t00000000\t[0-9A-F]{8}\t[0-9A-F]{4}\t[0-9]+\t[0-9]+\t[0-9]+\t00000000.*$/\1/p' /proc/net/route | sort -u | xargs
}

View File

@@ -325,9 +325,9 @@ dvtws, собираемый из тех же исходников (см. [док
* **method** - начало метода HTTP ('GET', 'POST', 'HEAD', ...). Метод обычно всегда находится на позиции 0, но поддерживается и нахождение метода после дурение методом `--methodeol` от tpws. Тогда позиция может стать 1 или 2.
* **host** - начало имени хоста в известном протоколе (http, TLS)
* **endhost** - конец имени хоста
* **endhost** - байт, следующий за последним байтом имени хоста
* **sld** - начало домена 2 уровня в имени хоста
* **endsld** - конец домена 2 уровня в имени хоста
* **endsld** - байт, следующий за последним байтом домена 2 уровня в имени хоста
* **midsld** - середина домена 2 уровня в имени хоста
* **sniext** - начало поля данных SNI extension в TLS. Любой extension состоит из 2-байтовых полей type и length, за ними идет поле данных.
@@ -381,7 +381,7 @@ Windows оставляет старые данные, поэтому disorder с
### СПЕЦИФИЧЕСКИЕ РЕЖИМЫ IPV6
Режимы десинхронизации `hopbyhop`, `destopt` и `ipfrag1` (не путать с fooling !) относятся только к `ipv6` и заключается
Режимы десинхронизации `hopbyhop`, `destopt` и `ipfrag1` (не путать с fooling !) относятся только к ipv6 и заключается
в добавлении хедера `hop-by-hop options`, `destination options` или `fragment` во все пакеты, попадающие под десинхронизацию.
Здесь надо обязательно понимать, что добавление хедера увеличивает размер пакета, потому не может быть применено
к пакетам максимального размера. Это имеет место при передаче больших сообщений.
@@ -398,7 +398,7 @@ extension хедерам в поисках транспортного хедер
В параметре dpi-desync можно указать до 3 режимов через запятую.
* 0 фаза - предполагает работу на этапе установления соединения : `synack`, `syndata` `--wsize`, `--wssize`. На эту фазу не действуют фильтры по [hostlist](((#множественные-стратегии))).
* 0 фаза - предполагает работу на этапе установления соединения : `synack`, `syndata`, `--wsize`, `--wssize`. На эту фазу не действуют фильтры по [hostlist](#множественные-стратегии).
* 1 фаза - отсылка чего-либо до оригинального пакета данных : `fake`, `rst`, `rstack`.
* 2 фаза - отсылка в модифицированном виде оригинального пакета данных (например, `fakedsplit` или `ipfrag2`).
@@ -424,29 +424,10 @@ DPI может отстать от потока, если ClientHello его у
В документации по geneva это называется "TCB turnaround". Попытка ввести DPI в заблуждение относительно
ролей клиента и сервера.
!!! Поскольку режим нарушает работу NAT, техника может сработать только если между атакующим устройством
Поскольку режим нарушает работу NAT, техника может сработать только если между атакующим устройством
и DPI нет NAT. Атака не сработает через NAT роутер, но может сработать с него.
Для реализации атаки в linux обязательно требуется отключить стандартное правило firewall,
дропающее инвалидные пакеты в цепочке OUTPUT. Например : `-A OUTPUT -m state --state INVALID -j DROP`
В openwrt можно отключить drop INVALID в OUTPUT и FORWARD через опцию в /etc/config/firewall:
```
config zone
option name 'wan'
.........
option masq_allow_invalid '1'
```
К сожалению, отключить только в OUTPUT таким образом нельзя. Но можно сделать иначе. Вписать в `/etc/firewall.user`:
```
iptables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT
ip6tables -D zone_wan_output -m comment --comment '!fw3' -j zone_wan_dest_ACCEPT
```
Лучше делать так, потому что отсутствие дропа INVALID в FORWARD может привести к нежелательным утечкам пакетов из LAN.
Если не принять эти меры, отсылка SYN,ACK сегмента вызовет ошибку и операция будет прервана.
Остальные режимы тоже не сработают. Если поймете, что вам synack не нужен, обязательно верните правило дропа INVALID.
Для реализации атаки на проходящий трафик требуются nftables и схема [POSTNAT](#nftables-для-nfqws).
### РЕЖИМ SYNDATA
@@ -480,7 +461,7 @@ conntrack - простенький, он не писался с учетом в
`--wssize` позволяет изменить с клиента размер tcp window для сервера, чтобы он послал следующие ответы разбитыми на части.
Чтобы это подействовало на все серверные ОС, необходимо менять window size в каждом исходящем с клиента пакете до отсылки сообщения,
ответ на который должен быть разбит (например, TLS ClientHello). Именно поэтому и необходим conntrack, чтобы
ответ на которое должен быть разбит (например, TLS ClientHello). Именно поэтому и необходим conntrack, чтобы
знать когда надо остановиться. Если не остановиться и все время устанавливать низкий wssize, скорость упадет катастрофически.
В linux это может быть купировано через connbytes, но в BSD системах такой возможности нет.
В случае http(s) останавливаемся сразу после отсылки первого http запроса или TLS ClientHello.
@@ -521,7 +502,7 @@ nfqws поддерживает реассемблинг некоторых ви
На текущий момент это TLS и QUIC ClientHello. Они бывает длинными, если в chrome включить пост-квантовую
криптографию tls-kyber, и занимают как правило 2 или 3 пакета. kyber включен по умолчанию, начиная с chromium 124.
chrome рандомизирует фингерпринт TLS. SNI может оказаться как в начале, так и в конце, то есть
попасть любой пакет. stateful DPI обычно реассемблирует запрос целиком, и только потом
попасть в любой пакет. stateful DPI обычно реассемблирует запрос целиком, и только потом
принимает решение о блокировке.
В случае получения TLS или QUIC пакета с частичным ClientHello начинается процесс сборки, а пакеты
задерживаются и не отсылаются до ее окончания. По окончании сборки пакеты проходит через десинхронизацию

View File

@@ -0,0 +1,22 @@
# This script fixes keenetic issue with nfqws generated udp packets
# Keenetic uses proprietary ndmmark and does not masquerade without this mark
# If not masqueraded packets go to WAN with LAN IP and get dropped by ISP
# It's advised to set IFACE_WAN in config
zapret_custom_firewall()
{
# $1 - 1 - add, 0 - stop
local wan wanif rule
[ "$DISABLE_IPV4" = "1" ] || {
# use IFACE_WAN if defined. if not - search for interfaces with default route.
wanif=${IFACE_WAN:-$(sed -nre 's/^([^\t]+)\t00000000\t[0-9A-F]{8}\t[0-9A-F]{4}\t[0-9]+\t[0-9]+\t[0-9]+\t00000000.*$/\1/p' /proc/net/route | sort -u | xargs)}
for wan in $wanif; do
rule="-o $wan -p udp -m mark --mark $DESYNC_MARK/$DESYNC_MARK"
ipt_print_op $1 "$rule" "keenetic udp fix"
ipt_add_del $1 POSTROUTING -t nat $rule -j MASQUERADE
done
}
}

View File

@@ -1,5 +1,5 @@
CC ?= gcc
CFLAGS += -std=gnu99 -Os
CFLAGS += -std=gnu99 -Os -flto=auto
CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_WIN = -static
LIBS =

View File

@@ -1,5 +1,5 @@
CC ?= cc
CFLAGS += -std=gnu99 -s -Os -Wno-address-of-packed-member
CFLAGS += -std=gnu99 -s -Os -Wno-address-of-packed-member -flto=auto
LIBS = -lz
SRC_FILES = *.c crypto/*.c

View File

@@ -1,7 +1,6 @@
CC ?= gcc
CFLAGS += -std=gnu99 -Os
CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_MAC = -mmacosx-version-min=10.8
CFLAGS_BSD = -Wno-address-of-packed-member -flto=auto
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz
LIBS_BSD = -lz

View File

@@ -1395,7 +1395,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (i==0)
{
if (seqovl_pos>=from)
DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl for part %d.\n",seqovl,from,i+2);
DLOG("seqovl>=split_pos (%zu>=%zu). cancelling seqovl for part %d.\n",seqovl,from,i+2);
else
{
seqovl = seqovl_pos;
@@ -1440,7 +1440,7 @@ static uint8_t dpi_desync_tcp_packet_play(bool replay, size_t reasm_offset, uint
if (seqovl_pos>=split_pos)
{
DLOG("seqovl>=split_pos (%u>=%zu). cancelling seqovl.\n",seqovl_pos,split_pos);
DLOG("seqovl>=split_pos (%zu>=%zu). cancelling seqovl.\n",seqovl_pos,split_pos);
seqovl = 0;
}
else

View File

@@ -1,5 +1,5 @@
CC ?= cc
CFLAGS += -std=gnu99 -s -Os
CFLAGS += -std=gnu99 -s -Os -flto=auto
LIBS = -lz -lpthread
SRC_FILES = *.c

View File

@@ -1,5 +1,5 @@
CC ?= gcc
CFLAGS += -std=gnu99 -Os
CFLAGS += -std=gnu99 -Os -flto=auto
CFLAGS_BSD = -Wno-address-of-packed-member
LIBS = -lz -lpthread
LIBS_ANDROID = -lz

View File

@@ -140,11 +140,6 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
if (bHaveHost)
VPRINT("request hostname: %s\n", Host);
if (ctrack->b_not_act)
{
VPRINT("Not acting on this request\n");
return;
}
bool bDiscoveredL7 = ctrack->l7proto==UNKNOWN && l7proto!=UNKNOWN;
if (bDiscoveredL7)
@@ -169,17 +164,25 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
struct desync_profile *dp_prev = ctrack->dp;
apply_desync_profile(ctrack, dest);
if (ctrack->dp!=dp_prev)
{
VPRINT("desync profile changed by revealed l7 protocol or hostname !\n");
ctrack->b_host_checked = ctrack->b_ah_check = false;
}
}
if (bDiscoveredHostname && ctrack->dp->hostlist_auto)
if (l7proto!=UNKNOWN && ctrack->dp->hostlist_auto)
{
bool bHostExcluded;
if (!HostlistCheck(ctrack->dp, Host, &bHostExcluded, false))
if (bHaveHost && !ctrack->b_host_checked)
{
bool bHostExcluded;
ctrack->b_host_matches = HostlistCheck(ctrack->dp, Host, &bHostExcluded, false);
ctrack->b_host_checked = true;
if (!ctrack->b_host_matches)
ctrack->b_ah_check = !bHostExcluded;
}
if (!ctrack->b_host_matches)
{
ctrack->b_ah_check = !bHostExcluded;
VPRINT("Not acting on this request\n");
ctrack->b_not_act = true;
return;
}
}

View File

@@ -14,8 +14,7 @@ typedef struct
// common state
t_l7proto l7proto;
bool bTamperInCutoff;
bool b_ah_check;
bool b_not_act;
bool b_host_checked,b_host_matches,b_ah_check;
char *hostname;
struct desync_profile *dp; // desync profile cache
} t_ctrack;

View File

@@ -479,6 +479,30 @@ static int connect_remote(const struct sockaddr *remote_addr, int mss)
return remote_fd;
}
static bool connect_remote_conn(tproxy_conn_t *conn)
{
int mss=0;
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
if (conn->track.dp)
{
mss = conn->track.dp->mss;
if (conn->track.dp->hostlist_auto)
{
if (conn->track.hostname)
{
bool bHostExcluded;
conn->track.b_host_matches = HostlistCheck(conn->track.dp, conn->track.hostname, &bHostExcluded, false);
conn->track.b_host_checked = true;
if (!conn->track.b_host_matches) conn->track.b_ah_check = !bHostExcluded;
if (!conn->track.b_host_matches) mss = 0;
}
}
}
return (conn->partner->fd = connect_remote((struct sockaddr *)&conn->dest, mss))>=0;
}
//Free resources occupied by this connection
static void free_conn(tproxy_conn_t *conn)
@@ -636,9 +660,7 @@ static tproxy_conn_t* add_tcp_connection(int efd, struct tailhead *conn_list,int
conn->partner->client = conn->client;
conn->partner->dest = conn->dest;
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
if ((conn->partner->fd = connect_remote((struct sockaddr *)&orig_dst, conn->track.dp ? conn->track.dp->mss : 0)) < 0)
if (!connect_remote_conn(conn))
{
DLOG_ERR("Failed to connect\n");
free_conn(conn->partner);
@@ -811,14 +833,7 @@ static bool proxy_mode_connect_remote(tproxy_conn_t *conn, struct tailhead *conn
return false;
}
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
if ((remote_fd = connect_remote((struct sockaddr *)&conn->dest, conn->track.dp ? conn->track.dp->mss : 0)) < 0)
{
DLOG_ERR("socks failed to connect (1) errno=%d\n", errno);
socks_send_rep_errno(conn->socks_ver, conn->fd, errno);
return false;
}
if (!(conn->partner = new_conn(remote_fd, true)))
{
close(remote_fd);
@@ -830,6 +845,15 @@ static bool proxy_mode_connect_remote(tproxy_conn_t *conn, struct tailhead *conn
conn->partner->efd = conn->efd;
conn->partner->client = conn->client;
conn->partner->dest = conn->dest;
if (!connect_remote_conn(conn))
{
free_conn(conn->partner); conn->partner = NULL;
DLOG_ERR("socks failed to connect (1) errno=%d\n", errno);
socks_send_rep_errno(conn->socks_ver, conn->fd, errno);
return false;
}
if (!epoll_set(conn->partner, EPOLLOUT))
{
DLOG_ERR("socks epoll_set error %d\n", errno);