--- title: Rasputin OpenWrt router created: '2026-07-22' updated: '2026-09-17' tags: - openwrt - router - rasputin - networking - vless - cloudflared --- # Rasputin R5S OpenWrt router > Status as of 2026-09-17: Rasputin is the OpenWrt edge/LAN router, routing normal LAN traffic through a VLESS/Xray tunnel via `tun0`, with explicit direct-WAN exceptions for upstream LAN access and Mac `cloudflared` QUIC traffic. ⚠️ **WAN переехал на `eth0` (`192.168.2.157/24`, gw `192.168.2.2`)** — см. раздел «WAN-интерфейс изменился» ниже. Транзит в GPON-сегмент `192.168.0.0/24` **сломан** — см. одноимённый раздел. ## 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 ```text 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 devices are `eth0` and `usb0` in the `wan` firewall zone. **As of 2026-09-17 `eth0` is the active WAN** (it carries the default route); `usb0` is idle. At the 2026-07-22 capture this was inverted — `eth0` had no carrier and `usb0` held the default route. Default route at the 2026-07-22 capture (historical, no longer active): ```text default via 10.252.240.133 dev usb0 src 10.252.240.230 ``` Current default route (2026-09-17): ```text default via 192.168.2.2 dev eth0 proto static src 192.168.2.157 ``` That is, Rasputin gets `192.168.2.157/24` from the upstream router `192.168.2.2` and reaches the internet through it; `192.168.2.2` in turn sits behind GPON `192.168.0.1`. VPN table: ```text default dev tun0 scope link ``` ## Interfaces ### LAN `br-lan` bridges: ```text eth1 eth2 phy0-ap0 ``` LAN config: ```text 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`: ```text network.wan=interface network.wan.device='eth0' network.wan.proto='dhcp' network.wan.peerdns='0' network.wan.type='bridge' ``` `usb0`: ```text network.usbwan=interface network.usbwan.proto='dhcp' network.usbwan.device='usb0' ``` Firewall `wan` zone includes: ```text wan wan6 wwan usbwan ``` ### VPN `tun0` is declared as an unmanaged interface: ```text 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: ```text dhcp.lan=dhcp dhcp.lan.interface='lan' dhcp.lan.start='100' dhcp.lan.limit='150' dhcp.lan.leasetime='12h' dhcp.lan.dhcp_option='6,1.1.1.1,1.0.0.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: ```text 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: ```text /etc/config/dhcp.bak.20260714-195408 ``` ## VLESS / Xray Stack Packages present include: ```text badvpn xray-core v2ray-core v2ray-extra v2ray-geoip v2ray-geosite v2raya luci-app-v2raya sing-box nftables-json iptables-nft ``` Runtime processes: ```text 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 -confdir /etc/xray -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 File: ```text /etc/xray/config.json ``` Structure: ```json { "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": "188.239.191.235", "port": 443, "users": [ { "id": "", "flow": "xtls-rprx-vision", "encryption": "none" } ] } ] }, "streamSettings": { "network": "tcp", "security": "reality", "realitySettings": { "serverName": "node3.sysnx.net", "publicKey": "", "shortId": "", "fingerprint": "qq" } } } ], "routing": { "rules": [ { "type": "field", "outboundTag": "proxy", "network": "tcp,udp" } ] } } ``` Secrets are intentionally redacted in this note. The live file on the router contains the actual VLESS UUID and REALITY parameters. ## `tunvpn` Service File: ```text /etc/init.d/tunvpn ``` Purpose: - Start `badvpn-tun2socks`. - Populate routing table `vpn` with default route through `tun0`. - Add policy rules so LAN traffic uses the VPN table. - Add explicit Cloudflare Tunnel QUIC bypass rules for the Mac. Current script: ```sh #!/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: ```text /etc/init.d/tunvpn.bak.20260714-195530 ``` ## Policy Routing Current rules: ```text 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 ``` Meaning: - Mac Wi-Fi `192.168.6.173` UDP/7844 goes direct through `main`. - Mac Ethernet `192.168.6.104` UDP/7844 goes direct through `main`. - Traffic to upstream LAN `192.168.2.0/24` goes direct through `main`. - 🔴 Traffic to the GPON segment `192.168.0.0/24` is **NOT** covered by rule `100` (2026-09-17) → falls through to rule `101` → `table vpn` → `tun0`. Доступ к GPON-сегменту из LAN `192.168.6.0/24` не работает. See the «🔴 Транзит Rasputin → 192.168.0.0/24» section. - All other traffic entering from LAN bridge `br-lan` uses `table vpn`. - `table vpn` sends default traffic through `tun0`. `/etc/rc.local` adds the upstream-LAN bypass: ```sh # 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: ```text input: REJECT output: ACCEPT forward: REJECT ``` Zones: ### `lan` ```text name='lan' input='ACCEPT' output='ACCEPT' forward='REJECT' masq='1' network='lan' ``` ### `wan` ```text name='wan' input='REJECT' output='ACCEPT' forward='REJECT' masq='1' mtu_fix='1' network='wan' 'wan6' 'wwan' 'usbwan' ``` ### `vpn` ```text name='vpn' input='ACCEPT' output='ACCEPT' forward='ACCEPT' masq='1' network='vpn' ``` Forwarding: ```text 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: ```text 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: ```text 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: ```text counter packets 19 bytes 27636 ``` This confirms that Mac `cloudflared` QUIC traffic was hitting the direct-WAN exception. ### Upstream LAN Bypass (`Allow-upstream-LAN`) ```text 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`**: ```text 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`) при пинге выключенного хоста верхнего сегмента: ```text $ /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` | хост не ответил | ```text /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`), при том что с самого Rasputin `192.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): ```text 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-сегмента: ```text 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) Ранее (capture 2026-07-22) WAN был `usb0` с адресом `10.252.240.230`. Сейчас **WAN = `eth0`**: ```text inet 192.168.2.157/24 scope global eth0 default via 192.168.2.2 dev eth0 proto static src 192.168.2.157 ``` То есть Rasputin получает адрес `192.168.2.157` **от роутера `192.168.2.2`** и выходит в интернет через него, а `192.168.2.2` — через GPON `192.168.0.1`. Топология запроса подтверждена: `rasputin → 192.168.2.2 → 192.168.0.1 (GPON) → 192.168.0.50`. ### ✅ ЧТО СДЕЛАНО (2026-09-17) — правило `ip rule` добавлено и работает Применено и **проверено Alex руками** (80 порт на `192.168.0.50` открылся): ```sh # на живом роутере ip rule add to 192.168.0.0/24 lookup main priority 100 # и то же записано в /etc/rc.local (чтобы выжило ребут) ``` Бэкап до правки: `/etc/rc.local.bak.20260917-132639` Правила после правки (две строки priority 100 — это нормально): ```text 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`. Следующие два пункта **не трогались**: 1. **NAT/masq для `192.168.0.0/24`** — нет. Пакет уходит с source `192.168.6.x`. Проверка показала, что 80 порт всё равно отвечает (GPON, судя по всему, маршрутизирует обратно), поэтому это **не блокер**, но и не гарантия. 2. **ICMP** — `Allow-upstream-LAN` в nft по-прежнему только `tcp`+`udp`, без `icmp`. Значит **пинг из LAN в `192.168.0.0/24` не работает до сих пор**, хотя TCP/UDP проходит. Не путать «не пингуется» с «не работает». ### План ремонта (исходный, для истории) ```sh # 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 ```text 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 ```text 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: ```text 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: ```text /etc/config/firewall.bak.20260714-195530 ``` ## Port Forwarding There is a port-forward named `LocalSend-to-mbp-black-eth`: ```text 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 `cloudflared` for `zulip.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: 1. Mac `cloudflared` should use QUIC, not HTTP/2. 2. Cloudflare Tunnel QUIC is UDP destination port `7844`. 3. Router sends only Mac UDP/7844 through `main` table. 4. Firewall allows only Mac UDP/7844 from LAN to WAN before the KillSwitch. Mac-side LaunchDaemon observed earlier: ```text /Library/LaunchDaemons/com.cloudflare.cloudflared.plist ``` Original args observed before the change: ```text cloudflared tunnel --protocol http2 run --token ``` Target Mac-side args: ```text cloudflared tunnel --protocol quic run --token ``` Manual Mac commands provided for that change: ```sh 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: ```sh plutil -p /Library/LaunchDaemons/com.cloudflare.cloudflared.plist tail -50 /Library/Logs/com.cloudflare.cloudflared.err.log ``` Expected log clue: ```text protocol=quic ``` Router-side counters can verify traffic is hitting the bypass: ```sh nft list chain inet fw4 forward_lan ``` Look for increasing counters on: ```text Allow-Mac-cloudflared-QUIC-direct ``` ## Current Effective Traffic Behavior ```text 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 Other LAN traffic -> vpn routing table -> tun0 -> Xray/VLESS LAN -> WAN not explicitly allowed -> rejected by KillSwitch ``` ## Operational Commands Restart VPN tunnel policy: ```sh /etc/init.d/tunvpn restart ``` Restart firewall: ```sh /etc/init.d/firewall restart ``` Show policy routing: ```sh ip rule show ip route show table vpn ip route show table all ``` Show Cloudflare direct firewall counter: ```sh nft list chain inet fw4 forward_lan ``` Show Xray logs: ```sh tail -100 /tmp/xray-access.log tail -100 /tmp/xray-error.log ``` Show active proxy processes: ```sh ps w | grep -Ei 'xray|badvpn|tun2socks' | grep -v grep ``` Show current DHCP static leases: ```sh 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: ```text /etc/config/dhcp.bak.20260714-195408 ``` Routing service backup from Cloudflare direct-bypass change: ```text /etc/init.d/tunvpn.bak.20260714-195530 ``` Firewall backup from Cloudflare direct-bypass change: ```text /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: ```sh 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: ```sh cp /etc/config/dhcp.bak.20260714-195408 /etc/config/dhcp uci commit dhcp /etc/init.d/dnsmasq restart ``` Rollback GPON-транзита (2026-09-17): ```sh # живая система 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 `cloudflared` using 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 rule` can match `ipproto udp dport 7844` on 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 `101` sends LAN ingress to `table vpn`. The direct `ip rule`s at priorities `98` and `99` must remain before priority `101`. - Rule order in `forward_lan` matters: Cloudflare direct allow must stay above `KillSwitch`. - `eth0` is the **active** WAN as of 2026-09-17 (`192.168.2.157/24`, gw `192.168.2.2`); `usb0` is idle. At the 2026-07-22 capture this was inverted (`eth0` down, `usb0` carrying the default route). Do not trust the old banner — re-read `ip route` before 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.x` host returns `Destination Port Unreachable` from `rasputin.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. Use `arp (incomplete)` + `100% packet loss` as the liveness signal. Confirmed 2026-09-15 (see the dedicated section above). - Liveness of `192.168.2.0/24` hosts 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 '`). Если роутер видит хост, а 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.