feat: kit-busrouter v2.0 — complete Synology + GL fleet router platform

Includes:
- package/ GL-XE3000 kit-busrouter (opkg)
- scripts/provision.sh (GL) and provision-synology.sh (Synology)
- syno-balance/ — new WAN balancer replacing aiwanbal (SmartWAN adapter)
- kit-connect/ — unified connectivity SPK (Tailscale + reverse SSH)
- docs/deployment/synology-rt2600ac-checklist.md — 62-point checklist
- docs/provisioning/device-identity.md — fleet identity spec
- docs/pilot/checklist.md — field pilot validation
- x4078_20260721.dss — reference config backup

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-22 00:07:14 +00:00
commit f15ac69925
41 changed files with 5083 additions and 0 deletions
+183
View File
@@ -0,0 +1,183 @@
# Pioneer Bus Router — Device Identity & Provisioning
**Last updated:** 2026-07-01
**Target hardware:** GL.iNet GL-XE3000 (Puli AX), OpenWrt 21.02-SNAPSHOT, ARMv8
---
## 1. Fleet-wide constants
| Parameter | Value |
|-----------|-------|
| WiFi SSID (2.4 + 5 GHz) | `<DEVICE_ID>` — the plan spec's `X0000` shorthand means SSID = device ID (e.g. `B0042`) |
| WiFi password | `Pioneer123` |
| Admin username (logical) | `pioadmin` |
| Admin password | `Pioneer321!` |
| Admin SSH user (OpenWrt) | `root` (GL-XE3000 uses root for all admin; pioadmin is the logical name) |
| Timezone | `UTC` |
| Cellular APN | `fast.t-mobile.com` (T-Mobile 5G, Quectel RM520N-GL, bus `1-1.2`) |
| WireGuard hub endpoint | `167.172.237.162:51820` |
| WireGuard hub IP | `10.88.0.1/24` |
| WireGuard tunnel subnet | `10.88.0.0/24` |
| WireGuard keepalive | `25 s` |
| WireGuard MTU | `1280` |
| WG mwan3 fix rule | priority `99`, dest `10.88.0.0/24`, lookup `1001` (required — see §4) |
| mwan3 balance mode | `balanced` (weight-based, 50/50 default; daemon adjusts live weights) |
**Hub WireGuard public key:** `REPLACE_WITH_HUB_WG_PUBKEY`
(Retrieve with `wg pubkey < /etc/wireguard/hub.key` on the hub at `167.172.237.162`)
---
## 2. Per-device parameters
Each bus unit gets a unique identity. Fill in this table for each device:
| DEVICE_ID | WG tunnel IP | WG public key | SIM 1 ICCID | SIM 2 ICCID | Notes |
|-----------|-------------|---------------|-------------|-------------|-------|
| `bus01` | `10.88.0.2` | *(see recon)* | `8901260417776090740F` | — | bench unit; ATT Fiber on eth0 in lab |
| `B0001` | `10.88.0.3` | *(generate)* | — | — | *(first production unit)* |
**Column format:**
- `DEVICE_ID`: `B` + 4-digit zero-padded bus number (e.g. `B0042`)
- `WG tunnel IP`: `10.88.0.X` (assigned by hub admin, no DHCP; range 10.88.0.210.88.0.254)
- `WG private key`: base64, generated per device, never stored in this doc (keep in secrets store)
- `SIM ICCID`: printed on SIM card tray
### Generating a keypair for a new device
```sh
# On any Linux machine with wireguard-tools:
PRIVKEY=$(wg genkey)
PUBKEY=$(echo "$PRIVKEY" | wg pubkey)
echo "Private: $PRIVKEY"
echo "Public: $PUBKEY"
```
Register the public key + assigned IP at the hub:
```sh
# On hub (167.172.237.162):
wg set wg0 peer <DEVICE_PUBKEY> allowed-ips 10.88.0.X/32 persistent-keepalive 25
# Persist (choose ONE based on how the hub manages wg0):
wg-quick save wg0 # if hub uses wg-quick
# OR: edit /etc/wireguard/wg0.conf manually and run: wg addconf wg0 <(diff)
# Verify hub persistence method before using wg-quick save — it overwrites the file.
```
---
## 3. Provisioning procedure
### Prerequisites
- Physical or LAN access to the router at `192.168.8.1`
- Cellular SIM installed in slot 1 (provides internet for opkg)
- `kit-busrouter.ipk` copied to `/tmp/kit-busrouter.ipk` on the router
- Device keypair generated and hub-side peer registered (§2)
### Steps
```sh
# 1. Copy provision.sh and package to the router
scp scripts/provision.sh root@192.168.8.1:/tmp/provision.sh
scp kit-busrouter_*.ipk root@192.168.8.1:/tmp/kit-busrouter.ipk
# 2. SSH in and run
ssh root@192.168.8.1
chmod +x /tmp/provision.sh
/tmp/provision.sh B0042 "<WG_PRIVKEY>" "10.88.0.42"
# Device reboots automatically after ~5 s.
# 3. Post-reboot verification (from hub 10.88.0.1 over WireGuard)
ssh root@10.88.0.42
mwan3 status # both modem_0001 and wan should appear (wan offline if no dish)
cat /etc/busrouter/device-id # B0042
wg show # wgclient1 peer handshake recent
```
### Expected WiFi after provisioning
- SSID: `B0042` (same on 2.4 + 5 GHz)
- Password: `Pioneer123`
- LAN IP: `192.168.8.1`
### Expected admin access
- SSH: `ssh root@192.168.8.1` → password `Pioneer321!`
- Web UI: `http://192.168.8.1` → root / `Pioneer321!`
- WG path: `ssh root@10.88.0.42` (from hub, or via WG client)
---
## 4. mwan3 + WireGuard tunnel coexistence fix
**Critical — must be applied or in-tunnel SSH drops silently.**
Root cause: mwan3 adds all directly-connected networks (including wgclient1's 10.88.0.0/24) to
its `mwan3_connected` ipset and marks matching packets with `0x3f00`. The ip rule
`9000: not from all fwmark 0/0xf000 lookup main` then routes replies via main table, which has
no route for 10.88.0.0/24 (wgclient1 routes live in table 1001). Packets are silently dropped.
Fix: add an ip rule at priority 99 (before mwan3's mark-based rules) routing to 10.88.0.0/24
via table 1001. `provision.sh` does this automatically:
```sh
# Runtime:
ip rule add to 10.88.0.0/24 priority 99 lookup 1001
# Persisted via UCI (recreated by netifd on boot):
uci add network rule
uci set network.@rule[-1].lookup='1001'
uci set network.@rule[-1].dest='10.88.0.0/24'
uci set network.@rule[-1].priority='99'
uci commit network
```
Also required: `net.ipv4.conf.wgclient1.rp_filter=2` (written to /etc/sysctl.conf by provision.sh
and re-asserted on WAN flap via /etc/hotplug.d/iface/99-busrouter-rpfilter).
---
## 5. GL-XE3000 hardware notes
| Detail | Value |
|--------|-------|
| Modem | Quectel RM520N-GL (5G NR SA) |
| Modem transport | MHI/PCIe (NOT USB-CDC; no `/dev/cdc-wdm*`) |
| Modem bus for gl_modem | `1-1.2` (verify per unit: `ls /sys/bus/usb/devices/ | grep -v ':' | sort`) |
| Signal read | `ubus call modem.signal get_signals '{"time":1}'` (primary); `gl_modem -B 1-1.2 AT AT+QCSQ` (fallback) |
| GPS enable | `gl_modem -B 1-1.2 AT AT+QGPS=1` (OFF by default; provision.sh writes to /etc/rc.local) |
| GPS read | `gl_modem -B 1-1.2 AT AT+QGPSLOC=2` (returns error 505/516 until first fix after GNSS enable) |
| SIM switch | `gl_modem -B 1-1.2 AT AT+QUIMSLOT=<1|2>` |
| SIM query | `gl_modem -B 1-1.2 AT AT+QUIMSLOT?` |
| kmwan (GL multiwan) | Disabled by provision.sh — do NOT re-enable; mwan3 owns routing |
| grpcurl | NOT installed; Phase 3 (Starlink) must bundle static arm64 binary in the .ipk |
| setsid / nohup | ABSENT on this firmware; use `start-stop-daemon -S -b -x <prog>` for background procs |
| WG firewall zone | `wgclient1` (NOT `wan`); SSH allow rule: `src=wgclient1 src_ip=10.88.0.0/24 dest_port=22` |
---
## 6. Bench unit `bus01` — specific config
| Field | Value |
|-------|-------|
| DEVICE_ID | `bus01` (rename to fleet format `B0001` for production) |
| LAN IP | `192.168.8.1` |
| WG tunnel IP | `10.88.0.2` |
| Cellular (WAN1) | `rmnet_mhi0`, UCI `modem_0001`, T-Mobile CGNAT |
| Starlink (WAN2) | `eth0`, UCI `wan` — no dish on bench unit; ATT Fiber used as stand-in |
| WG underlay | Rides `eth0` when fiber is attached (do NOT down eth0 for bench tests) |
| Access via hub | `ssh root@10.88.0.2` (from hub `10.88.0.1`) |
---
## 7. Checklist — new device before field deployment
- [ ] Device ID assigned and recorded in fleet registry
- [ ] WG keypair generated; public key registered at hub with assigned IP
- [ ] SIM installed; APN = `fast.t-mobile.com`; cellular data confirmed
- [ ] `provision.sh` run end-to-end; device rebooted cleanly
- [ ] WiFi visible as `<DEVICE_ID>`, password `Pioneer123`
- [ ] SSH to `root@192.168.8.1` succeeds with `Pioneer321!`
- [ ] `mwan3 status` shows both interfaces (wan offline is OK if no dish yet)
- [ ] WG tunnel up: `wg show` shows handshake < 60 s ago
- [ ] Hub can SSH to `root@10.88.0.WG_IP`
- [ ] `/etc/busrouter/device-id` contains correct DEVICE_ID
- [ ] `busrouter` daemon running: `ps | grep daemon.sh`
- [ ] Status page accessible: `http://192.168.8.1/busrouter/`