Files
vpn-raspberry/client/nftables.conf
Maxim 538414f2c8 Стабильная работа туннеля: anti-RST, --fix-gro, QUIC-блок, автозагрузка
Проверено на живом стенде: 0% потерь на 10.66.66.1 и 8.8.8.8, выход через
сервер (curl -> 95.174.102.77).

Транспорт (устранение разрывов faketcp):
- anti-RST вписан в конфиги вместо хрупкого -a+flush:
  клиент — первой строкой chain input (ip saddr 95.174.102.77 tcp sport 25565 drop),
  сервер — в таблице wgfwd (ip daddr 192.168.31.163 tcp dport 25565 drop, переживает ufw reload).
  Причина: RST от ядра убивал CGNAT-маппинг оператора -> direction timeout и смена порта.
- --fix-gro на обоих концах: чинит дроп GRO «супер-пакетов» (huge packet > max_data_len).

Клиент:
- nftables.conf: flush ruleset (убирает дубли), reject QUIC/UDP 443 (откат браузера на TCP).
- udp2raw-client.service: After=nftables.service (anti-RST применяется до старта udp2raw).

Автозагрузка/порядок (обе службы udp2raw):
- After=network-online.target, Before=wg-quick@wg0.service.

README: раздел 5 «Известные нюансы» (anti-RST vs flush, CGNAT/RST, GRO),
сниппеты и таблицы приведены в соответствие.
2026-07-08 11:35:46 +03:00

74 lines
3.8 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/sbin/nft -f
# RASPBERRY PI 4: /etc/nftables.conf
# flush обязателен: без него повторный `nft -f` накапливает дубли правил.
flush ruleset
table ip nat {
chain postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.77.0/24 oifname "usbnet" masquerade
ip saddr 192.168.77.0/24 oifname "wg0" masquerade
}
}
table inet filter {
chain input {
type filter hook input priority filter; policy drop;
# udp2raw faketcp anti-RST (КРИТИЧНО, должно стоять ПЕРВЫМ — выше ct-accept):
# обратный faketcp от сервера попадает под ct established и доходит до TCP-стека
# ядра, а тот шлёт RST на «левый» TCP -> шторм RST -> туннель встаёт, но данные
# не идут. Прячем эти пакеты от стека; udp2raw читает их через AF_PACKET (до
# netfilter), поэтому drop ему не мешает. Аналог правила, которое ставит флаг -a.
# Держим правило ЗДЕСЬ (а не через -a), чтобы flush ruleset его не стирал.
ip saddr 95.174.102.77 tcp sport 25565 drop
ct state established,related accept
iifname "lo" accept
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
tcp dport 22 accept
iifname "wlan0" udp dport { 67, 68 } accept
iifname "wlan0" udp dport 53 accept
tcp dport 8080 accept
iifname "wg0" accept
}
chain forward {
type filter hook forward priority filter; policy drop;
iifname "wlan0" oifname "usbnet" accept
iifname "usbnet" oifname "wlan0" ct state established,related accept
# Блокируем QUIC/HTTP-3 (UDP 443) в туннель: он НЕ подчиняется MSS-clamp,
# крупные датаграммы теряются при MTU 1200 и сайты «висят».
# reject (а не drop) → браузер сразу откатывается на TCP/HTTPS. Ставить ДО accept.
iifname "wlan0" oifname "wg0" udp dport 443 reject
iifname "wlan0" oifname "wg0" accept
iifname "wg0" oifname "wlan0" ct state established,related accept
# MSS-clamp: клиенты 192.168.77.0/24 имеют MTU 1500 и не знают про туннель 1200.
# Без этого крупные TCP-сессии (сайты, загрузки) залипают при заблокированном PMTUD.
iifname "wlan0" oifname "wg0" tcp flags syn tcp option maxseg size set rt mtu
}
chain output {
type filter hook output priority filter; policy accept;
}
}
table ip nm-shared-wlan0 {
chain nat_postrouting {
type nat hook postrouting priority srcnat; policy accept;
ip saddr 192.168.77.0/24 ip daddr != 192.168.77.0/24 masquerade
}
chain filter_forward {
type filter hook forward priority filter; policy accept;
ip daddr 192.168.77.0/24 oifname "wlan0" ct state { established, related } accept
ip saddr 192.168.77.0/24 iifname "wlan0" accept
iifname "wlan0" oifname "wlan0" accept
iifname "wlan0" reject
oifname "wlan0" reject
}
}