14 KiB
title, created, updated, tags
| title | created | updated | tags | ||||||
|---|---|---|---|---|---|---|---|---|---|
| Rasputin OpenWrt router | 2026-07-22 | 2026-07-22 |
|
Rasputin R5S OpenWrt router
Status as of 2026-07-22: 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 MaccloudflaredQUIC traffic.
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 is currently represented by both eth0 and usb0 in the wan firewall zone. At capture time, eth0 had no carrier, while usb0 was up and had the default route.
Current default route:
default via 10.252.240.133 dev usb0 src 10.252.240.230
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,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:
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
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 -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:
/etc/xray/config.json
Structure:
{
"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": "<redacted-vless-user-id>",
"flow": "xtls-rprx-vision",
"encryption": "none"
}
]
}
]
},
"streamSettings": {
"network": "tcp",
"security": "reality",
"realitySettings": {
"serverName": "node3.sysnx.net",
"publicKey": "<redacted-reality-public-key>",
"shortId": "<redacted-reality-short-id>",
"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:
/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:
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.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. - 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
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
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'
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
Other LAN traffic -> vpn routing table -> tun0 -> Xray/VLESS
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
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
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. eth0was down at the 2026-07-22 capture;usb0was active and part of thewanfirewall zone.- Secrets are redacted here intentionally. Consult the live router files only when the actual VLESS or Cloudflare credentials are needed.