Проверено на живом стенде: 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), сниппеты и таблицы приведены в соответствие.
74 lines
3.8 KiB
Plaintext
74 lines
3.8 KiB
Plaintext
#!/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
|
||
}
|
||
} |