Files
obsidian-vault/family/how-to/rasputin-router.md
T

14 KiB

title, created, updated, tags
title created updated tags
Rasputin OpenWrt router 2026-07-22 2026-07-22
openwrt
router
rasputin
networking
vless
cloudflared

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 Mac cloudflared QUIC 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 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:

#!/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.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.
  • 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:

# 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 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:

/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 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 rules at priorities 98 and 99 must remain before priority 101.
  • Rule order in forward_lan matters: Cloudflare direct allow must stay above KillSwitch.
  • eth0 was down at the 2026-07-22 capture; usb0 was active and part of the wan firewall zone.
  • Secrets are redacted here intentionally. Consult the live router files only when the actual VLESS or Cloudflare credentials are needed.