47 KiB
Executable File
title, created, updated, tags
| title | created | updated | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|
| Rasputin OpenWrt router | 2026-07-22 | 2026-10-30 |
|
Rasputin R5S OpenWrt router
Rasputin — LAN-роутер OpenWrt: 192.168.6.1/24, WAN eth0 — 192.168.2.157/24, шлюз 192.168.2.2. Клиентский TCP-трафик идёт через tun0 → badvpn-tun2socks → SOCKS Xray → TrueNAS → reverse-туннель → Kraken → интернет. Для локальных сетей аплинка и Mac cloudflared QUIC действуют прямые исключения.
DNS клиентов обслуживает отдельная служба clientdns через тот же туннель. Системный dnsmasq и DNS самого роутера работают отдельно. SSH: ssh root@192.168.6.1.
Identity
| Field | Value |
|---|---|
| Hostname | Rasputin |
| Hardware | FriendlyElec NanoPi R5S |
| Board | friendlyarm,nanopi-r5s |
| CPU | ARMv8 Processor rev 0 |
| OpenWrt | 24.10.2, revision r28739-d9340319c6 |
| Target | rockchip/armv8 |
| Kernel | 6.6.93 |
| Rootfs | squashfs |
| LAN IP | 192.168.6.1/24 |
| IPv6 ULA prefix | fd3b:153e:9be9::/48 |
Network Topology
LAN clients
-> br-lan / 192.168.6.0/24
-> policy routing
-> most LAN traffic: table vpn -> tun0 -> badvpn-tun2socks -> Xray SOCKS -> VLESS
-> selected exceptions: table main -> WAN device
В зоне wan находятся eth0 и usb0; активный аплинк — eth0.
default via 192.168.2.2 dev eth0 proto static src 192.168.2.157
Аплинк: Rasputin → 192.168.2.2 → GPON 192.168.0.1. Туннель подключается к TrueNAS 192.168.2.197:8443 через локальную сеть аплинка.
VPN table:
default dev tun0 scope link
Interfaces
LAN
br-lan bridges:
eth1
eth2
phy0-ap0
LAN config:
network.lan=interface
network.lan.device='br-lan'
network.lan.proto='static'
network.lan.ipaddr='192.168.6.1'
network.lan.netmask='255.255.255.0'
network.lan.ip6assign='60'
network.lan.dns='8.8.8.8'
WAN
eth0:
network.wan=interface
network.wan.device='eth0'
network.wan.proto='dhcp'
network.wan.peerdns='0'
network.wan.type='bridge'
usb0:
network.usbwan=interface
network.usbwan.proto='dhcp'
network.usbwan.device='usb0'
Firewall wan zone includes:
wan
wan6
wwan
usbwan
VPN
tun0 is declared as an unmanaged interface:
network.vpn=interface
network.vpn.proto='none'
network.vpn.device='tun0'
tun0 is created/used by badvpn-tun2socks, launched from /etc/init.d/tunvpn.
DHCP And Static Leases
DHCP server:
dhcp.lan=dhcp
dhcp.lan.interface='lan'
dhcp.lan.start='100'
dhcp.lan.limit='150'
dhcp.lan.leasetime='12h'
dhcp.lan.dhcp_option='6,192.168.6.1'
dhcp.lan.dhcpv4='server'
dhcp.lan.dhcpv6='server'
dhcp.lan.ra='server'
dhcp.lan.ra_slaac='1'
dhcp.lan.ra_flags='managed-config' 'other-config'
Static DHCP reservations added 2026-07-14 for the Mac:
dhcp.@host[0].name='mbp-black-eth'
dhcp.@host[0].mac='00:e0:4c:68:04:88'
dhcp.@host[0].ip='192.168.6.104'
dhcp.@host[1].name='mbp-black-wifi'
dhcp.@host[1].mac='66:02:b1:8b:2f:94'
dhcp.@host[1].ip='192.168.6.173'
Backup made before this change:
/etc/config/dhcp.bak.20260714-195408
Клиентский DNS через туннель
DHCP выдаёт клиентам 192.168.6.1:
dhcp.lan.dhcp_option='6,192.168.6.1'
LAN-клиент → адрес Rasputin:53 (UDP/TCP)
→ firewall dstnat_lan → redirect :1053
→ отдельный dnsmasq службы clientdns
→ локальные имена: системный dnsmasq 127.0.0.1:53
→ внешний DNS: отдельный Xray 127.0.0.1:1054
→ SOCKS основного Xray 127.0.0.1:1080
→ VLESS → TrueNAS → reverse-туннель → Kraken
→ Cloudflare: A/AAAA через DoH; другие типы через DNS-over-TCP
clientdns не меняет upstream системного dnsmasq и встроенный DNS основного Xray. Системный dnsmasq слушает порт 53 и использует 8.8.8.8 из /tmp/resolv.conf.d/resolv.conf.auto; запросы самого роутера не перенаправляются. DNS аплинка 192.168.2.2 настроен на 1.1.1.1 и полученный по WAN 192.168.0.1.
Обрабатываются только входящие из LAN TCP/UDP-запросы к DNS-адресам Rasputin: 192.168.6.1, fd3b:153e:9be9::1 и fe80::34ae:87ff:fe04:8dd. Запросы к произвольным внешним DNS-адресам это правило не перехватывает. При смене LAN IPv6-адресов нужно обновить /etc/clientdns/redirect.nft.
Общая передача клиентского UDP через текущий tun2socks не настроена. Для DNS это не требуется: клиентский UDP заканчивается на Rasputin, а дальше запрос идёт по TCP через прокси. При недоступности основного Xray/reverse-туннеля внешний клиентский DNS также недоступен; прямого fallback через WAN нет.
Файлы и параметры clientdns
/etc/init.d/clientdns — отдельная служба procd с двумя экземплярами: doh (Xray) и resolver (dnsmasq). Автозапуск включён, START=99, STOP=10; для обоих процессов настроен respawn 3600 5 5. Ссылки автозапуска: /etc/rc.d/S99clientdns и /etc/rc.d/K10clientdns. После загрузки внешний клиентский DNS становится доступен, когда основной Xray и reverse-туннель готовы принимать запросы. Параметры и правила firewall сохранены в /etc; проверка enable/disable выполняется без остановки процессов.
/etc/clientdns/dnsmasq.conf:
# Dedicated client resolver; the system dnsmasq remains on port 53.
port=1053
interface=br-lan
interface=lo
bind-dynamic
no-resolv
no-poll
no-hosts
cache-size=1000
edns-packet-max=1232
server=127.0.0.1#1054
# Preserve the existing router's local name service.
server=/lan/local/127.0.0.1#53
server=//127.0.0.1#53
server=/6.168.192.in-addr.arpa/ip6.arpa/127.0.0.1#53
user=dnsmasq
group=dnsmasq
log-facility=/tmp/clientdns-dnsmasq.log
Локальные домены lan, local, имена без доменной части, обратные запросы для 192.168.6.0/24 и ip6.arpa передаются прежнему dnsmasq. Клиентский экземпляр не раздаёт DHCP.
/etc/clientdns/xray.json:
{
"log": {
"loglevel": "warning",
"access": "/tmp/clientdns-xray-access.log",
"error": "/tmp/clientdns-xray-error.log"
},
"inbounds": [
{
"tag": "clientdns-in",
"listen": "127.0.0.1",
"port": 1054,
"protocol": "dokodemo-door",
"settings": {
"address": "1.1.1.1",
"port": 53,
"network": "tcp,udp"
}
}
],
"outbounds": [
{
"tag": "tunnel",
"protocol": "socks",
"settings": {
"servers": [
{
"address": "127.0.0.1",
"port": 1080
}
]
}
},
{
"tag": "dns-out",
"protocol": "dns",
"settings": {
"network": "tcp",
"address": "1.1.1.1",
"port": 53,
"nonIPQuery": "skip"
},
"proxySettings": {
"tag": "tunnel"
}
}
],
"routing": {
"domainStrategy": "AsIs",
"rules": [
{
"type": "field",
"inboundTag": [
"clientdns-in"
],
"outboundTag": "dns-out"
},
{
"type": "field",
"inboundTag": [
"clientdns-upstream"
],
"outboundTag": "tunnel"
}
]
},
"dns": {
"servers": [
"https://1.1.1.1/dns-query"
],
"queryStrategy": "UseIP",
"tag": "clientdns-upstream"
}
}
У отдельного Xray нет собственного VLESS-подключения: он использует существующий SOCKS 127.0.0.1:1080. A/AAAA разрешаются через https://1.1.1.1/dns-query; остальные типы (MX, TXT, HTTPS и другие) передаются к 1.1.1.1:53 по TCP через тот же SOCKS. UseIP относится только к отдельному DNS-процессу; основной Xray сохраняет UseIPv4.
Подключение правил в /etc/config/firewall:
config include 'clientdns_redirect'
option type 'nftables'
option path '/etc/clientdns/redirect.nft'
option chain 'dstnat_lan'
option position 'chain-prepend'
/etc/clientdns/redirect.nft:
ip daddr 192.168.6.1 meta l4proto { tcp, udp } th dport 53 counter redirect to :1053 comment "clientdns-v4"
ip6 daddr { fd3b:153e:9be9::1, fe80::34ae:87ff:fe04:8dd } meta l4proto { tcp, udp } th dport 53 counter redirect to :1053 comment "clientdns-v6"
Управление и диагностика clientdns
На роутере:
/etc/init.d/clientdns status
/etc/init.d/clientdns enabled
ubus call service list '{"name":"clientdns"}'
/usr/bin/xray run -test -config /etc/clientdns/xray.json < /dev/null
/usr/sbin/dnsmasq --test -C /etc/clientdns/dnsmasq.conf
netstat -lnp | grep -E ':(1053|1054) '
uci show firewall.clientdns_redirect
nft list chain inet fw4 dstnat_lan
Оба экземпляра procd должны быть running; при клиентских запросах растут счётчики clientdns-v4/clientdns-v6.
Проверка обработчика на роутере и отдельной маршрутизации локальных имён:
nslookup www.youtube.com 127.0.0.1:1053
nslookup rasputin.lan 127.0.0.1:1053
Проверка с LAN-клиента через стандартный DNS-порт:
dig @192.168.6.1 www.youtube.com A
dig +tcp @192.168.6.1 www.youtube.com A
dig @192.168.6.1 rasputin.lan A
dig @192.168.6.1 gmail.com MX
dig @192.168.6.1 cloudflare.com TYPE65
curl -4 -fsS -o /dev/null --max-time 20 -w 'HTTP %{http_code}\n' https://www.youtube.com
TYPE65 — запись HTTPS; такой синтаксис подходит для штатного macOS dig. Ожидаются ответы DNS и HTTP 200. Запрос на роутере к 127.0.0.1:53 проверяет системный DNS, а не клиентский путь.
Логи отдельной службы:
tail -100 /tmp/clientdns-dnsmasq.log
tail -100 /tmp/clientdns-xray-error.log
tail -100 /tmp/clientdns-xray-access.log
grep '1.1.1.1:443' /tmp/xray-access.log | tail -10
Перезапуск только клиентского DNS:
/etc/init.d/clientdns restart
Отключение и откат clientdns
Подключиться по IP: ssh root@192.168.6.1. На роутере выполнить:
sh /etc/clientdns/rollback.sh
Эквивалентные ручные команды:
uci -q delete firewall.clientdns_redirect
uci commit firewall
/etc/init.d/firewall reload
/etc/init.d/clientdns stop
/etc/init.d/clientdns disable
После этого клиентские запросы снова обрабатывает исходный dnsmasq на порту 53. Менять DHCP или настройки клиентов не нужно. Возвращается обычный DNS через WAN, вместе с его ограничениями.
Копия скрипта отката и исходные конфиги находятся на роутере в /root/clientdns-backup-20261030-134826/: rollback.sh, firewall, firewall.uci, dhcp, xray-config.json. Для отключения clientdns достаточно удалить его отдельный блок firewall; восстановление всего firewall из копии может затереть другие последующие изменения.
При полном удалении сначала выполнить откат, затем удалить /etc/init.d/clientdns и /etc/clientdns/. Нельзя удалять redirect.nft, пока на него ссылается включённый блок firewall.
VLESS / Xray Stack
Packages present include:
badvpn
xray-core
v2ray-core
v2ray-extra
v2ray-geoip
v2ray-geosite
v2raya
luci-app-v2raya
sing-box
nftables-json
iptables-nft
Runtime processes:
badvpn-tun2socks --tundev tun0 --netif-ipaddr 10.99.0.2 --netif-netmask 255.255.255.252 --socks-server-addr 127.0.0.1:1080 --loglevel none
/usr/bin/xray run -config /etc/xray/config.json -format json
v2raya is installed, but the observed UCI service config previously had enabled='0'. The active traffic path is the custom tunvpn service plus direct Xray config.
Xray Config
Основной Xray управляется OpenWrt procd через /etc/init.d/xray. Конфиг: /etc/xray/config.json; UCI: /etc/config/xray; ресурсы: /usr/share/xray. Автозапуск включён.
xray.enabled.enabled='1'
xray.config.conffiles='/etc/xray/config.json'
xray.config.datadir='/usr/share/xray'
xray.config.format='json'
SOCKS-вход: 127.0.0.1:1080. Выход: VLESS поверх WebSocket/TLS к TrueNAS 192.168.2.197:8443, SNI/Host vpn.mallexxx.duckdns.org, путь /vless. UUID в документации скрыт; брать его из действующего конфига.
{
"log": {
"loglevel": "debug",
"access": "/tmp/xray-access.log",
"error": "/tmp/xray-error.log"
},
"inbounds": [
{
"tag": "socks-in",
"listen": "127.0.0.1",
"port": 1080,
"protocol": "socks"
}
],
"outbounds": [
{
"tag": "proxy",
"protocol": "vless",
"settings": {
"vnext": [
{
"address": "192.168.2.197",
"port": 8443,
"users": [
{
"id": "<VLESS_UUID>",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "ws",
"security": "tls",
"tlsSettings": {
"serverName": "vpn.mallexxx.duckdns.org"
},
"wsSettings": {
"path": "/vless",
"headers": {
"Host": "vpn.mallexxx.duckdns.org"
}
}
}
},
{
"tag": "direct",
"protocol": "freedom"
},
{
"tag": "block",
"protocol": "blackhole"
}
],
"routing": {
"domainStrategy": "IPIfNonMatch",
"rules": [
{
"type": "field",
"protocol": [
"bittorrent"
],
"outboundTag": "block"
}
]
},
"dns": {
"servers": [
{
"address": "223.5.5.5",
"port": 53
},
{
"address": "8.8.8.8",
"port": 53
}
],
"queryStrategy": "UseIPv4"
}
}
Перезапуск и диагностика Xray
Команды выполняются на Rasputin после ssh root@192.168.6.1.
Проверить конфиг перед перезапуском; успешный результат — Configuration OK.:
/usr/bin/xray run -test -config /etc/xray/config.json < /dev/null
Перезапустить только основную службу Xray:
/etc/init.d/xray restart
/etc/init.d/xray status
Проверить автозапуск и состояние процесса под procd:
/etc/init.d/xray enabled
ubus call service list '{"name":"xray"}'
uci show xray
netstat -lnp | grep '127.0.0.1:1080'
status должен выводить running; enabled завершается с кодом 0, если автозапуск включён. В ответе ubus у экземпляра xray должно быть "running": true; TCP-порт 127.0.0.1:1080 должен слушаться.
Логи:
tail -100 /tmp/xray-error.log
tail -100 /tmp/xray-access.log
logread -e xray
Файлы в /tmp очищаются при перезагрузке. В access-log [socks-in >> proxy] означает передачу запроса в основной VLESS-выход.
Сквозная проверка основного прокси с удалённым разрешением имени:
curl -4 -fsS --max-time 20 --socks5-hostname 127.0.0.1:1080 https://api.ipify.org
curl -4 -fsS -o /dev/null --max-time 20 --socks5-hostname 127.0.0.1:1080 -w 'HTTP %{http_code}\n' https://www.youtube.com
Первый запрос должен показать текущий внешний IP Kraken, второй — HTTP 200. IP Kraken динамический; для сравнения получить его непосредственно на Kraken.
xray, tunvpn и clientdns — разные службы. Перезапуск xray не пересоздаёт tun0 и policy routing; для их проверки использовать ip rule show, ip route show table vpn и ip link show tun0. Команда /etc/init.d/tunvpn restart перезапускает tun2socks и маршрутизацию. Клиентский DNS перезапускается через /etc/init.d/clientdns restart. Не использовать killall xray: он остановит также отдельный процесс Xray службы clientdns.
tunvpn Service
File:
/etc/init.d/tunvpn
Purpose:
- Start
badvpn-tun2socks. - Populate routing table
vpnwith default route throughtun0. - Add policy rules so LAN traffic uses the VPN table.
- Add explicit Cloudflare Tunnel QUIC bypass rules for the Mac.
Current script:
#!/bin/sh /etc/rc.common
START=95
STOP=10
start() {
badvpn-tun2socks --tundev tun0 --netif-ipaddr 10.99.0.2 --netif-netmask 255.255.255.252 --socks-server-addr 127.0.0.1:1080 --loglevel none &
sleep 2
ip route replace default dev tun0 table vpn
# cloudflared QUIC direct bypass for Mac Ethernet/Wi-Fi
ip rule add priority 98 from 192.168.6.173 ipproto udp dport 7844 lookup main 2>/dev/null
ip rule add priority 99 from 192.168.6.104 ipproto udp dport 7844 lookup main 2>/dev/null
ip rule add iif br-lan lookup vpn priority 101
}
stop() {
killall badvpn-tun2socks
ip rule del priority 98 2>/dev/null
ip rule del priority 99 2>/dev/null
ip rule del iif br-lan lookup vpn 2>/dev/null
ip route flush table vpn
}
Backup made before the Cloudflare direct-bypass update:
/etc/init.d/tunvpn.bak.20260714-195530
Policy Routing
Current rules (снято 2026-09-22, живая система):
0: from all lookup local
98: from 192.168.6.173 ipproto udp dport 7844 lookup main
99: from 192.168.6.104 ipproto udp dport 7844 lookup main
100: from all to 192.168.2.0/24 lookup main
100: from all to 192.168.0.0/24 lookup main
101: from all iif br-lan lookup vpn
32766: from all lookup main
32767: from all lookup default
Две строки с priority 100 — это нормально (обе добавлены вручную, 192.168.0.0/24 — 2026-09-17).
Meaning:
- Mac Wi-Fi
192.168.6.173UDP/7844 goes direct throughmain. - Mac Ethernet
192.168.6.104UDP/7844 goes direct throughmain. - Traffic to upstream LAN
192.168.2.0/24goes direct throughmain. - Traffic to GPON
192.168.0.0/24goes direct throughmain(исправлено 2026-09-17). - 🔴 Traffic to
192.168.1.0/24(Кра́кен, ТВ, ASUS) is NOT covered by any rule100(2026-09-22) → falls through to rule101→table vpn→tun0. Доступ к Кра́кену/ТВ из LAN192.168.6.0/24не работает. См. раздел «🔴 Транзит из LAN в 192.168.1.0/24». - All other traffic entering from LAN bridge
br-lanusestable vpn. table vpnsends default traffic throughtun0.
/etc/rc.local adds the upstream-LAN bypass:
# Put your custom commands here that should be executed once
# the system init finished. By default this file does nothing.
ip rule add to 192.168.2.0/24 lookup main priority 100
exit 0
⚠️ Здесь только 192.168.2.0/24. Строки для 192.168.0.0/24 нет — это и есть корневая причина сломанного транзита в GPON-сегмент. После ребута текущий ip rule 100 пересоздаётся именно из этого файла.
Firewall Model
Default firewall policy:
input: REJECT
output: ACCEPT
forward: REJECT
Zones:
lan
name='lan'
input='ACCEPT'
output='ACCEPT'
forward='REJECT'
masq='1'
network='lan'
wan
name='wan'
input='REJECT'
output='ACCEPT'
forward='REJECT'
masq='1'
mtu_fix='1'
network='wan' 'wan6' 'wwan' 'usbwan'
vpn
name='vpn'
input='ACCEPT'
output='ACCEPT'
forward='ACCEPT'
masq='1'
network='vpn'
Forwarding:
lan -> vpn
There is no general lan -> wan forwarding. Instead, selected lan -> wan traffic is allowed before a LAN-to-WAN killswitch.
Important Firewall Rules
Cloudflare Tunnel QUIC Direct Bypass
Added 2026-07-14:
firewall.@rule[8].name='Allow-Mac-cloudflared-QUIC-direct'
firewall.@rule[8].src='lan'
firewall.@rule[8].dest='wan'
firewall.@rule[8].src_ip='192.168.6.104' '192.168.6.173'
firewall.@rule[8].proto='udp'
firewall.@rule[8].dest_port='7844'
firewall.@rule[8].target='ACCEPT'
The nft realization appears in forward_lan before the killswitch:
ip saddr { 192.168.6.104, 192.168.6.173 } udp dport 7844 jump accept_to_wan comment "!fw4: Allow-Mac-cloudflared-QUIC-direct"
At capture time, this rule had matched traffic:
counter packets 19 bytes 27636
This confirms that Mac cloudflared QUIC traffic was hitting the direct-WAN exception.
Upstream LAN Bypass (Allow-upstream-LAN)
firewall.@rule[10].name='Allow-upstream-LAN'
firewall.@rule[10].src='lan'
firewall.@rule[10].dest='wan'
firewall.@rule[10].target='ACCEPT'
firewall.@rule[10].dest_ip='192.168.2.0/24' '192.168.0.1'
⚠️ Порядковый номер изменился (2026-09-17). Актуальное правило — firewall.@rule[0].name='Allow-upstream-LAN', и dest_ip расширен до GPON-сегмента. Его nft-реализация в forward_lan — две отдельные строки, tcp и udp, без icmp:
meta l4proto tcp ip daddr { 192.168.0.1, 192.168.0.50, 192.168.2.0/24 } counter packets 19 bytes 1216 jump accept_to_wan comment "!fw4: Allow-upstream-LAN"
meta l4proto udp ip daddr { 192.168.0.1, 192.168.0.50, 192.168.2.0/24 } counter packets 0 bytes 0 jump accept_to_wan comment "!fw4: Allow-upstream-LAN"
Практическое следствие: forward в GPON-сегмент разрешён, но без NAT ответ не вернётся, а ICMP вообще не проходит. Полный разбор — в разделе «🔴 Транзит Rasputin → 192.168.0.0/24» ниже.
🔴 ICMP к недоступному хосту в 192.168.2.0/24 отдаёт Destination Port Unreachable от САМОГО роутера
Наблюдение 2026-09-15 (подтверждено дважды в одной сессии). С Mac (192.168.6.104) при пинге выключенного хоста верхнего сегмента:
$ /sbin/ping -c 3 192.168.2.176
92 bytes from rasputin.lan (192.168.6.1): Destination Port Unreachable
Vr HL TOS Len ID Flg off TTL Pro cks Src Dst
4 5 00 5400 a0a3 0 0000 3f 01 509d 192.168.6.104 192.168.2.176
--- 192.168.2.176 ping statistics ---
3 packets transmitted, 0 packets received, 100.0% packet loss
Как это читать (и как НЕ читать):
| Признак | Значение |
|---|---|
Request timeout for icmp_seq N |
нормальный признак «хост выключен» |
Destination Port Unreachable от rasputin.lan (192.168.6.1) |
это роутер отбивает попытку, а не ответ хоста |
Полный дамп IP-заголовка (Vr HL TOS … Src/Dst) |
ответ сгенерирован ICMP-модулем роутера, а не удалённой машиной |
100.0% packet loss |
хост не ответил |
/usr/sbin/arp -an | grep 176
? (192.168.6.176) at (incomplete) on en8 ifscope [ethernet]
(incomplete) = ARP-запрос ушёл, ответа нет → L2-ответа нет вообще, хост мёртв или вне сети. Это правильный признак для вывода «машина недоступна».
⚠️ ПИТФОЛЛ ДИАГНОСТИКИ: строка
Destination Port Unreachableот роутера легко читается как «порт закрыт, машина жива». Это НЕВЕРНО. Она одинаково выглядит и для хоста, который выключен, и для хоста, который висит в kernel lockup без сетевого стека. Опираться нужно наarp (incomplete)+ 100% loss, а не на текст ICMP-ошибки.
⚠️ Проверять достижимость узлов
192.168.2.0/24из192.168.6.0/24надёжнее всего тем же каналом, которым потом будете работать: SSH по ключу.ssh -o ConnectTimeout=10 -o BatchMode=yes root@192.168.2.176 'uptime'— если отвечает, хост жив, и всё дальнейшее снимается через него. Пинг/веб-порты могут врать (см.Reject to LANниже), SSH — нет.
🔴 Проверка 2026-09-17: 5 из 5 ICMP-попыток к
192.168.2.2отбиты роутером (Destination Port Unreachableот192.168.6.1), при том что с самого Rasputin192.168.2.2пингуется 0% loss, 0.75–0.84 ms. То есть эхо-запрос из LAN до шлюза не доходит вообще — отбой происходит локально. Практический вывод: отсутствие пинга к192.168.2.xНЕ говорит о том, что хост/шлюз недоступен. Единственный вывод — «ICMP из LAN до этого адреса зарезан». Никогда не строить на пинге вывод о состоянии аплинка; проверять TCP-каналом, которым будете работать.
⚠️ Ещё один контр-пример к пингу как индикатору (2026-09-17,
192.168.0.50): с Мака — 100% loss и безDestination Port Unreachable(обычный timeout), а с Rasputin — 0% loss. Здесь пинг отражает реальную поломку policy routing, но не показывает, жив ли хост. Различить «хост мёртв» и «транзит сломан» можно одним дешёвым шагом: пингануть ту же цель с самого Rasputin. Роутер видит, клиент — нет ⇒ проблема в транзите, не в хосте.
Границы прав внутри сегментов (напоминание):
- Router transit
192.168.6.0/24 ↔ 192.168.2.0/24— разрешён правилами выше. - Между сегментами есть санитарный
Reject to LANвforward_lan→ произвольные порты не пройдут, ICMP-эхо тоже. - Порты HA (
8123) и SSH (22) через транзит роутера не проверять как индикатор живости — индикатор это сам факт ответа SSH-сессии.
🔴 Транзит Rasputin → 192.168.0.0/24 (GPON-сегмент) НЕ РАБОТАЕТ
Наблюдение 2026-09-17. Симптом: с Мака (LAN 192.168.6.0/24) трафик на 192.168.0.50 и 192.168.0.1 (80 порт) не проходит.
Что подтверждено фактами
| Тест | Результат |
|---|---|
ping -c2 192.168.0.50 с Мака (192.168.6.173, en8) |
100% loss |
ping -c2 192.168.0.50 с самого Rasputin |
✅ 0% loss, 2.11–2.79 ms, ttl=63 |
ping -c2 192.168.2.2 с Мака |
100% loss + Destination Port Unreachable от 192.168.6.1 |
Вывод из таблицы: L2/L3 от Rasputin до 192.168.0.50 живой (ttl=63 — один хоп). Ломается только транзит из LAN 192.168.6.0/24.
Три причины
1. ip rule 100 покрывает только 192.168.2.0/24.
Фактические правила на роутере (2026-09-17):
0: from all lookup local
98: from 192.168.6.173 ipproto udp dport 7844 lookup main
99: from 192.168.6.104 ipproto udp dport 7844 lookup main
100: from all to 192.168.2.0/24 lookup main
101: from all iif br-lan lookup vpn
32766: from all lookup main
32767: from all lookup default
Для 192.168.0.50 правило 100 не матчится → пакет попадает в 101 → table vpn → tun0 (VLESS). Трафик уходит в туннель вместо WAN.
2. NAT/masq для зоны wan не покрывает 192.168.0.0/24.
Правило firewall уже расширено до GPON-сегмента:
meta l4proto tcp ip daddr { 192.168.0.1, 192.168.0.50, 192.168.2.0/24 } counter packets 19 bytes 1216 jump accept_to_wan comment "!fw4: Allow-upstream-LAN"
meta l4proto udp ip daddr { 192.168.0.1, 192.168.0.50, 192.168.2.0/24 } counter packets 0 bytes 0 jump accept_to_wan comment "!fw4: Allow-upstream-LAN"
То есть forward разрешён, но пакет уходит с source 192.168.6.x, а GPON-сегмент не знает обратного маршрута в 192.168.6.0/24. Ответ вернуться не может. В forward_lan нет NAT-правила для этого направления.
3. ICMP зарезан отдельно.
Allow-upstream-LAN в nft создан в двух вариантах — tcp и udp, без icmp — и стоит выше KillSwitch. Остальной ICMP из LAN падает в KillSwitch (packets 71 bytes 6192). Отсюда Destination Port Unreachable от самого роутера (см. раздел про ICMP ниже).
⚠️ Из-за п.3 пинг не является индикатором доступности
192.168.0.0/24из LAN. Проверять только тем каналом, которым будете работать (SSH/TCP).
WAN-интерфейс изменился ДВАЖДЫ (2026-09-17 → 2026-09-22)
Текущее состояние (2026-09-22, проверено вживую):
eth0: 192.168.1.50/24, MAC 36:ae:87:04:08:dc, link 1000/full
br-lan: 192.168.6.1/24
default: via 192.168.1.1 dev eth0 proto static src 192.168.1.50
🔴 Распутин теперь воткнут в сегмент 192.168.1.0/24 — тот же, где Кра́кен (.14/.15), ТВ (.70) и Mac (.57/.69). Прежний 192.168.2.157/24 (gw 192.168.2.2) больше не активен.
Доступ: ssh root@192.168.6.1 (LAN-адрес бранча, работает с Mac, хотя Mac в другом сегменте — через 192.168.1.50).
Историческая хронология WAN:
| Дата | WAN-интерфейс | Адрес | GW |
|---|---|---|---|
| 2026-07-22 | usb0 |
10.252.240.230 |
10.252.240.133 |
| 2026-09-17 | eth0 |
192.168.2.157/24 |
192.168.2.2 |
| 2026-09-22 | eth0 |
192.168.1.50/24 |
192.168.1.1 |
Топология запроса (2026-09-17): rasputin → 192.168.2.2 → 192.168.0.1 (GPON) → 192.168.0.50. После переезда 2026-09-22 цепочка аплинка изменилась — 192.168.2.2 из пути выпал.
Измерения Rasputin → Кра́кен (2026-09-22)
Rasputin → 192.168.1.14: 0.499 / 0.639 / 0.897 ms 10/10, 0% loss
Rasputin → 192.168.1.15: 0.444 / 0.641 / 1.037 ms 10/10, 0% loss
ARP на Rasputin: и .14, и .15 резолвятся в один lladdr 2c:cf:67:64:03:f3 (eth0 Кра́кена).
⚠️ На OpenWrt ping -i 0.3 не поддерживается — busybox-ping отдаёт ping: invalid number '0.3'. Использовать ping -c N без -i или с целым числом.
🔴 Пропускная способность не измерена (2026-09-22). iperf3 установлен на Распутине (opkg install iperf3 → 3.17.1, /usr/bin/iperf3) и на Кра́кене (3.12, apt-get install iperf3). Замер не сделан, потому что sshd на Распутине отказал (Connection refused при живом пинге, см. ниже).
⚠️ На OpenWrt в комплекте уже были libiperf3 (3.17.1-r4) и python3-iperf3 — это библиотеки, не бинарь. which iperf3 до установки пакета пусто. Проверять which, а не opkg list-installed | grep iperf.
Замер, когда sshd вернётся:
# на Кра́кене
nohup iperf3 -s -p 5201 > /tmp/iperf3s.log 2>&1 &
# на Распутине
iperf3 -c 192.168.1.14 -p 5201 -t 10
⚠️ 1000FD в robocfg/ethtool — это link speed, НЕ throughput. Реальные Мбит/с даёт только iperf3. Гигабит физически даёт максимум ~940–950 Мбит/с (оверход Ethernet); на NanoPi R5S потолок может быть ниже — упрётся в CPU.
⚠️ sshd на Распутине отказывает (2026-09-22, НЕ закрыто)
Симптом: ssh root@192.168.6.1 → Connection refused, при этом ping 192.168.6.1 идёт 0% loss (4.4–7.6 ms), и nc -z 192.168.6.1 22 → CLOSED.
То есть сеть до роутера жива, но sshd не слушает. В начале той же сессии SSH работал. Не выяснено: упал ли sshd, кончились ли ресурсы, сработала ли защита, или дело в watchdog/перезагрузке.
Диагностика на месте (когда будет доступ):
service dropbear status # OpenWrt: dropbear, НЕ openssh
logread | grep -i dropbear
netstat -tlnp | grep :22
⚠️ Это второй случай нестабильного SSH за сессию: ASUS (192.168.1.1) тоже начал отдавать Connection closed by 192.168.1.1 port 22 без причины (порт 22 при этом nc -z → succeeded). При недоступности роутера по SSH — сначала ping + nc -z, чтобы развести «сеть легла» и «демон отказал».
✅ ЧТО СДЕЛАНО (2026-09-17) — правило ip rule добавлено и работает
Применено и проверено Alex руками (80 порт на 192.168.0.50 открылся):
# на живом роутере
ip rule add to 192.168.0.0/24 lookup main priority 100
# и то же записано в /etc/rc.local (чтобы выжило ребут)
Бэкап до правки: /etc/rc.local.bak.20260917-132639
Правила после правки (две строки priority 100 — это нормально):
100: from all to 192.168.2.0/24 lookup main
100: from all to 192.168.0.0/24 lookup main
101: from all iif br-lan lookup vpn
🔴 Правка файлов на роутере — через скачивание → локальную правку → заливку.
sed -iпо живому конфигу запрещён (и был заблокирован в этой сессии). Порядок:scpвниз →patchлокально →scpнаверх →catдля проверки.
⚠️ Что ОСТАЛОСЬ не сделано (осознанно, по объёму команды «ip rule»)
Alex дал команду только на ip rule. Следующие два пункта не трогались:
- NAT/masq для
192.168.0.0/24— нет. Пакет уходит с source192.168.6.x. Проверка показала, что 80 порт всё равно отвечает (GPON, судя по всему, маршрутизирует обратно), поэтому это не блокер, но и не гарантия. - ICMP —
Allow-upstream-LANв nft по-прежнему толькоtcp+udp, безicmp. Значит пинг из LAN в192.168.0.0/24не работает до сих пор, хотя TCP/UDP проходит. Не путать «не пингуется» с «не работает».
План ремонта (исходный, для истории)
# 1. ip rule — расширить bypass на GPON-сегмент ← СДЕЛАНО
ip rule add to 192.168.0.0/24 lookup main priority 100
# 2. та же строка в /etc/rc.local ← СДЕЛАНО
# 3. firewall: Allow-upstream-LAN dest_ip += 192.168.0.0/24, добавить proto icmp ← НЕ сделано
# 4. проверить, что masq зоны wan покрывает 192.168.0.0/24 ← НЕ сделано
Порядок работ по боевому конфигу: коммит ДО → правка → заливка → проверка Алекса руками → коммит ПОСЛЕ.
Downstream LAN Access
firewall.@rule[11].name='Allow-downstream-LAN'
firewall.@rule[11].src='wan'
firewall.@rule[11].dest='lan'
firewall.@rule[11].target='ACCEPT'
firewall.@rule[11].src_ip='192.168.2.0/24' '192.168.0.1'
KillSwitch
firewall.@rule[12].name='KillSwitch'
firewall.@rule[12].src='lan'
firewall.@rule[12].dest='wan'
firewall.@rule[12].proto='all'
firewall.@rule[12].target='REJECT'
In nft forward_lan, ordering is important:
1. Allow-Mac-cloudflared-QUIC-direct
2. Allow-upstream-LAN
3. KillSwitch
4. Accept lan to vpn forwarding
5. Accept DNAT port forwards
6. Reject to LAN
This ordering means only explicit lan -> wan exceptions escape; everything else either goes through VPN routing or is rejected from WAN.
Backup made before the Cloudflare firewall change:
/etc/config/firewall.bak.20260714-195530
Port Forwarding
There is a port-forward named LocalSend-to-mbp-black-eth:
firewall.@redirect[0].name='LocalSend-to-mbp-black-eth'
firewall.@redirect[0].src='wan'
firewall.@redirect[0].dest='lan'
firewall.@redirect[0].src_ip='192.168.2.0/24'
firewall.@redirect[0].proto='tcp udp'
firewall.@redirect[0].src_dport='53317'
firewall.@redirect[0].dest_ip='192.168.6.104'
firewall.@redirect[0].dest_port='53317'
firewall.@redirect[0].target='DNAT'
Reflection rules exist for LAN clients hitting the router WAN IP on port 53317, redirecting to 192.168.6.104:53317.
Cloudflare Tunnel / Mac Bypass Context
Problem addressed:
- Mac runs
cloudflaredforzulip.qentra.top. - Router routes normal LAN traffic through VLESS via
tun0. - Cloudflare Tunnel connector traffic should go direct to WAN rather than through VLESS.
Chosen solution:
- Mac
cloudflaredshould use QUIC, not HTTP/2. - Cloudflare Tunnel QUIC is UDP destination port
7844. - Router sends only Mac UDP/7844 through
maintable. - Firewall allows only Mac UDP/7844 from LAN to WAN before the KillSwitch.
Mac-side LaunchDaemon observed earlier:
/Library/LaunchDaemons/com.cloudflare.cloudflared.plist
Original args observed before the change:
cloudflared tunnel --protocol http2 run --token <redacted-cloudflare-tunnel-token>
Target Mac-side args:
cloudflared tunnel --protocol quic run --token <redacted-cloudflare-tunnel-token>
Manual Mac commands provided for that change:
sudo cp /Library/LaunchDaemons/com.cloudflare.cloudflared.plist \
/Library/LaunchDaemons/com.cloudflare.cloudflared.plist.bak.$(date +%Y%m%d-%H%M%S)
sudo /usr/libexec/PlistBuddy \
-c "Set :ProgramArguments:3 quic" \
/Library/LaunchDaemons/com.cloudflare.cloudflared.plist
sudo launchctl bootout system /Library/LaunchDaemons/com.cloudflare.cloudflared.plist
sudo launchctl bootstrap system /Library/LaunchDaemons/com.cloudflare.cloudflared.plist
Verify on Mac:
plutil -p /Library/LaunchDaemons/com.cloudflare.cloudflared.plist
tail -50 /Library/Logs/com.cloudflare.cloudflared.err.log
Expected log clue:
protocol=quic
Router-side counters can verify traffic is hitting the bypass:
nft list chain inet fw4 forward_lan
Look for increasing counters on:
Allow-Mac-cloudflared-QUIC-direct
Current Effective Traffic Behavior
Mac 192.168.6.104 UDP/7844 -> main routing table -> WAN direct
Mac 192.168.6.173 UDP/7844 -> main routing table -> WAN direct
Any LAN client -> 192.168.2.0/24 -> main routing table -> WAN/upstream LAN
LAN DNS to Rasputin:53 -> clientdns -> SOCKS/Xray -> TrueNAS -> Kraken
Other LAN TCP traffic -> vpn routing table -> tun0 -> Xray/VLESS
General client UDP via tun2socks -> not configured
LAN -> WAN not explicitly allowed -> rejected by KillSwitch
Operational Commands
Restart VPN tunnel policy:
/etc/init.d/tunvpn restart
Restart firewall:
/etc/init.d/firewall restart
Show policy routing:
ip rule show
ip route show table vpn
ip route show table all
Show Cloudflare direct firewall counter:
nft list chain inet fw4 forward_lan
Show Xray logs:
tail -100 /tmp/xray-access.log
tail -100 /tmp/xray-error.log
Show active proxy processes:
ps w | grep -Ei 'xray|badvpn|tun2socks' | grep -v grep
Show current DHCP static leases:
uci show dhcp | grep -E 'mbp-black|192.168.6.104|192.168.6.173|00:e0:4c:68:04:88|66:02:b1:8b:2f:94'
Recovery / Rollback
DHCP backup from Mac static lease change:
/etc/config/dhcp.bak.20260714-195408
Routing service backup from Cloudflare direct-bypass change:
/etc/init.d/tunvpn.bak.20260714-195530
Firewall backup from Cloudflare direct-bypass change:
/etc/config/firewall.bak.20260714-195530
Роутинг через туннель (tunvpn) — 2026-07-14.
Firewall/Cloudflare bypass — 2026-07-14.
GPON-транзит (ip rule на 192.168.0.0/24) — 2026-09-17.
Rollback example:
cp /etc/init.d/tunvpn.bak.20260714-195530 /etc/init.d/tunvpn
chmod +x /etc/init.d/tunvpn
cp /etc/config/firewall.bak.20260714-195530 /etc/config/firewall
/etc/init.d/tunvpn restart
/etc/init.d/firewall restart
Rollback DHCP static leases:
cp /etc/config/dhcp.bak.20260714-195408 /etc/config/dhcp
uci commit dhcp
/etc/init.d/dnsmasq restart
Rollback GPON-транзита (2026-09-17):
# живая система
ip rule del to 192.168.0.0/24 lookup main priority 100
# постоянство
cp /etc/rc.local.bak.20260917-132639 /etc/rc.local
⚠️ Правки
/etc/rc.localна роутере делать только черезscp-вниз →patchлокально →scp-наверх.sed -iпо живому конфигу запрещён.
Notes And Pitfalls
- The Cloudflare bypass depends on Mac
cloudflaredusing QUIC. If the Mac falls back to HTTP/2/TCP/443, the router exception will not match. - There are two Mac source IPs because the Mac can use Ethernet or Wi-Fi.
- Both Mac IPs are now static DHCP reservations on Rasputin.
ip rulecan matchipproto udp dport 7844on this OpenWrt build; this was tested and confirmed before making the persistent change.- The firewall allow alone would not be sufficient, because policy routing rule
101sends LAN ingress totable vpn. The directip rules at priorities98and99must remain before priority101. - Rule order in
forward_lanmatters: Cloudflare direct allow must stay aboveKillSwitch. eth0is the active WAN as of 2026-09-17 (192.168.2.157/24, gw192.168.2.2);usb0is idle. At the 2026-07-22 capture this was inverted (eth0down,usb0carrying the default route). Do not trust the old banner — re-readip routebefore assuming which WAN is live.- 🔴 Транзит из LAN
192.168.6.0/24в GPON-сегмент192.168.0.0/24— ЧАСТИЧНО ПОЧИНЕН (2026-09-17).ip ruleдобавлено (живая система +/etc/rc.local), Alex проверил 80 порт на192.168.0.50— работает. Было три причины:ip rule 100не покрывал192.168.0.0/24(✅ исправлено); нет NAT/masq для этого направления (❌ не сделано, не блокер); ICMP не разрешён вAllow-upstream-LAN(❌ не сделано). Подробности — в разделе «Транзит Rasputin → 192.168.0.0/24». - 🔴 ICMP по-прежнему не индикатор доступности
192.168.0.0/24.Allow-upstream-LANсоздан только дляtcp+udp, поэтому эхо-запросы из LAN падают вKillSwitchи роутер отвечаетDestination Port Unreachableот себя. Пинг в GPON-сегмент не работает даже после починкиip rule— TCP/UDP при этом проходит. Проверять TCP-портом (nc -zv 192.168.0.50 80) или SSH. - Различай два похожих симптома:
Destination Port Unreachableот роутера192.168.6.1= локальное отбивание ICMP/firewall-ом, а не закрытый порт на хосте. Признак живости — ответ на TCP/SSH, а не текст ICMP-ошибки. - 🔴 Ping from Mac to an unreachable
192.168.2.xhost returnsDestination Port Unreachablefromrasputin.lan (192.168.6.1), NOT a plain timeout. This is the router rejecting the attempt — it does not mean the host is up with a closed port. Usearp (incomplete)+100% packet lossas the liveness signal. Confirmed 2026-09-15 (see the dedicated section above). - Liveness of
192.168.2.0/24hosts is best verified with the channel you intend to work through: key-based SSH (ssh -o BatchMode=yes root@192.168.2.176 'uptime'). Ping and web ports can mislead; an answered SSH session cannot. - Дешёвый способ развести «хост мёртв» и «транзит сломан»: пингануть цель с самого Rasputin (
ssh root@192.168.6.1 'ping -c2 <target>'). Если роутер видит хост, а LAN-клиент — нет, проблема в policy routing/firewall, а не в хосте. Именно так 2026-09-17 локализовали GPON-проблему. - Secrets are redacted here intentionally. Consult the live router files only when the actual VLESS or Cloudflare credentials are needed.