conwrt Device Support Matrix

Auto-generated from models/*.json — the authoritative single source of truth.

tested Verified on real hardware
defined Model defined, not yet tested
blocked Known to not work

Flash Methods

Vendor Device SoC RAM Flash oem
http
sysupgrade recovery
http
uboot
http
dlink
hnap
edgeos
kernel
swap
tftp serial
tftp
openwrt
mtd
write
zycast Caps
ASUS Lyra MAP-AC2200 tri-band WiFi mesh node (IPQ4019 + QCA9886)
asus-lyra-map-ac2200
Qualcomm IPQ4019 (quad-core Cortex-A7) @ 717MHz 256MB DDR3 (Nanya NT5CC128M16IP-DI) NAND 128MB (Macronix) defined ethernet wifi
D-Link COVR-X1860 A1 mesh WiFi
dlink-covr-x1860-a1
MT7621AT 256MB NAND 128MB tested tested blocked ethernet wifi
Extreme Networks WS-AP3915i / AP391x Qualcomm IPQ4029 access point — no-serial TFTP flash via rdwr_boot_cfg
extreme-networks-ws-ap3915i
Qualcomm IPQ4029 (4x Cortex-A7 @ 717 MHz) 512MB DDR3 SPI-NOR 32MB (Macronix MX25L25635E, verified from DTS and hardware) defined defined ethernet
GL.iNet AR150 Mini Router (all variants)
glinet-gl-ar150
AR9331 (MIPS 24Kc) @ 400MHz 64MB DDR2 NOR 16MB defined ethernet wifi usb
GL.iNet AR300M-Lite / AR300M16 / AR300M16-Ext (NOR only, no switch, no NAND)
glinet-gl-ar300m-lite
QCA9533 v2 (MIPS 24Kc) @ 650MHz 128MB DDR2 NOR 16MB (Winbond W25Q128) only — no NAND defined defined ethernet wifi usb
GL.iNet AR300M / AR300M-Ext / AR300MD (NAND boot, switch LEFT)
glinet-gl-ar300m-nand
QCA9533 v2 (MIPS 24Kc) @ 650MHz 128MB DDR2 NAND 128MB (GigaDevice SPI NAND) + NOR 16MB (Winbond W25Q128) defined tested ethernet wifi usb
GL.iNet AR300M / AR300M-Ext (NOR boot). NOT recommended for general use — NAND is 128MB vs NOR's 16MB. NOR is useful as automatic failsafe recovery partition. NOR boot via switch RIGHT (bootm 0x9f050000) or bootcount method (fw_setenv bootcount 3). Switch-based NOR boot may not work on all U-Boot versions.
glinet-gl-ar300m-nor
QCA9533 v2 (MIPS 24Kc) @ 650MHz 128MB DDR2 NAND 128MB (GigaDevice SPI NAND) + NOR 16MB (Winbond W25Q128) defined defined ethernet wifi usb
GL.iNet Beryl AX (GL-MT3000) WiFi 6 travel router
glinet-mt3000
MT7981B (Filogic 820) dual-core Cortex-A53 @ 1.3GHz 512MB DDR4 NAND 256MB tested tested ethernet wifi usb
Linksys Velop AX4200 WiFi 6 System V1 — CVE-2019-16340 auth bypass for initial flash
linksys-mx4200-v1
IPQ8174 (quad-core Cortex-A53) @ 1.0GHz 512MB DDR3 NAND 256MB defined ethernet wifi
Linksys Velop Tri-Band V1 (WHW03) — U-Boot HTTP recovery signatures needed
linksys-whw03-v1
IPQ4019 (quad-core Cortex-A7) @ 716MHz 512MB DDR3 eMMC 4GB defined ethernet wifi
Linksys Velop Tri-Band V2 (WHW03 V2) — U-Boot HTTP recovery signatures needed
linksys-whw03-v2
IPQ4019 (quad-core Cortex-A7) @ 716MHz 512MB DDR3 NAND 512MB defined ethernet wifi
Ubiquiti EdgeRouter 6P (ER-e300) — Cavium Octeon III, 5x GbE + SFP, no WiFi
ubnt-edgerouter-6p
Cavium CN7130 (Octeon III) 1024MB eMMC 4GB + SPI NOR 8MB defined tested defined ethernet usb
Ubiquiti EdgeRouter X (ER-X) — MediaTek MT7621A, 5x GbE, no WiFi
ubnt-edgerouter-x
MediaTek MT7621A (MIPS) 256MB DDR3 256MB SPI NAND defined ethernet
Zyxel EX5700 (Telenor) — MediaTek MT7986B, WiFi 6 tri-band
zyxel-ex5700-telenor
MT7986B (Filogic 830) quad-core Cortex-A53 1GB DDR3 SPI NAND ~486MB (UBI) defined ethernet wifi
Zyxel GS1900-24E 24-port managed gigabit switch, Realtek RTL8382M
zyxel-gs1900-24e
Realtek RTL8382M MIPS 4KEc @ 500MHz 128 MiB DDR2 SDRAM 16 MiB SPI NOR (Macronix MX25L12835F) tested
bbaf09c
tested
bbaf09c
defined tested
bbaf09c
ethernet
Zyxel GS1900-8HP A1 (formerly v2) 8-port PoE+ managed gigabit switch, Realtek RTL8380M, 70W PoE budget
zyxel-gs1900-8hp-a1
Realtek RTL8380M MIPS 4KEc @ 500MHz 128 MiB DDR3 SDRAM (Samsung K4B1G0846G) 16 MiB SPI NOR (Macronix MX25L12835F) tested tested defined defined ethernet
Zyxel GS1900-8HP B1 (formerly v1) 8-port PoE+ managed gigabit switch, Realtek RTL8380M, 70W PoE budget
zyxel-gs1900-8hp-b1
Realtek RTL8380M MIPS 4KEc @ 500MHz 128 MiB DDR2 SDRAM (Nanya NT5TU128M8HE-AC) 16 MiB SPI NOR (Macronix MX25L12835F) defined defined defined defined ethernet
Zyxel GS1920-24 24-port managed gigabit switch (non-PoE), Realtek RTL8392M
zyxel-gs1920-24
Realtek RTL8392M MIPS 4KEc @ 500MHz 128 MiB DDR2 SDRAM 16 MiB SPI NOR (dual-slot, 8 MiB per slot) defined defined ethernet
Zyxel NR7101 — 5G/NR outdoor router, MediaTek MT7621
zyxel-nr7101
MT7621A (MediaTek) dual-core MIPS 1004Kc @ 880MHz 256MB DDR3 SPI NAND 256MB tested
5b45579
tested ethernet cellular
Zyxel WX5600-T0 (AX6000) — Altibox/Lyse ISP build, MediaTek MT7986B
zyxel-wx5600-t0
MT7986B (Filogic 830) quad-core Cortex-A53 @ 1.6GHz 512MB DDR3 SPI NAND 512MB (Micron MT29F4G01ABAFD, NMBM enabled) defined defined ethernet wifi

Device Testing Log

Per-device tested capabilities with commit links.

Vendor Device Tested Capabilities
ASUS Lyra MAP-AC2200 tri-band WiFi mesh node (IPQ4019 + QCA9886)
asus-lyra-map-ac2200
stock-ssh-mtd-batch1 tested 2026-05-26
stock-ssh-mtd-batch2 tested 2026-05-27
D-Link COVR-X1860 A1 mesh WiFi
dlink-covr-x1860-a1
recovery-http tested 2026-05-24
dlink-hnap defined
sysupgrade tested 2026-05-18
wifi_sta_ap tested 2026-05-15
Extreme Networks WS-AP3915i / AP391x Qualcomm IPQ4029 access point — no-serial TFTP flash via rdwr_boot_cfg
extreme-networks-ws-ap3915i
extreme-rdwr-tftp-initramfs tested 2026-05-23
GL.iNet AR300M / AR300M-Ext / AR300MD (NAND boot, switch LEFT)
glinet-gl-ar300m-nand
recovery-http tested 2026-05-16
nand_boot tested 2026-05-17
nor_setup tested 2026-05-17
nor_boot_switch_method tested 2026-05-17
nor_boot_bootcount_method tested 2026-05-17
nand_boot_after_nor tested 2026-05-17
tether-android-adb tested 2026-05-17
sqm tested 2026-05-17
GL.iNet AR300M / AR300M-Ext (NOR boot). NOT recommended for general use — NAND is 128MB vs NOR's 16MB. NOR is useful as automatic failsafe recovery partition. NOR boot via switch RIGHT (bootm 0x9f050000) or bootcount method (fw_setenv bootcount 3). Switch-based NOR boot may not work on all U-Boot versions.
glinet-gl-ar300m-nor
nor_boot_bootcount tested 2026-05-17
nor_boot_switch tested 2026-05-17
nand_boot_after_nor tested 2026-05-17
GL.iNet Beryl AX (GL-MT3000) WiFi 6 travel router
glinet-mt3000
uboot-http tested 2026-05-16
sysupgrade tested 2026-05-16
usb_tether_android tested 2026-05-16
Ubiquiti EdgeRouter 6P (ER-e300) — Cavium Octeon III, 5x GbE + SFP, no WiFi
ubnt-edgerouter-6p
edgeos-kernel-swap tested 2026-05-19
Zyxel GS1900-24E 24-port managed gigabit switch, Realtek RTL8382M
zyxel-gs1900-24e
oem-http tested @bbaf09c Uploaded initramfs via Playwright, device booted into OpenWrt initramfs in ~90s 2026-05-18
sysupgrade tested @bbaf09c sysupgrade -n completed, SSH access after ~120s boot 2026-05-18
mtd-write tested @bbaf09c mtd -r write succeeded, device booted into 25.12.1 initramfs 2026-05-18
serial-tftp-openwrt defined
uboot_env_modification tested @bbaf09c fw_setenv + fw_printenv confirmed serverip change 2026-05-18
Zyxel GS1900-8HP A1 (formerly v2) 8-port PoE+ managed gigabit switch, Realtek RTL8380M, 70W PoE budget
zyxel-gs1900-8hp-a1
oem-stock-upgrade tested V2.00(AAHI.2) → V2.90(AAHI.0) via Playwright HTTP upload, cmd=5903, partition=0 (Active) 2026-05-21
oem-http tested Uploaded OpenWrt 25.12.1 initramfs via OEM HTTP to V2.90 OEM firmware, device booted into initramfs in ~24s 2026-05-21
sysupgrade tested sysupgrade -n from 25.12.1 initramfs to 25.12.1 squashfs permanent install, SSH access after ~105s boot 2026-05-21
serial-tftp-openwrt defined
Zyxel NR7101 — 5G/NR outdoor router, MediaTek MT7621
zyxel-nr7101
sysupgrade tested @5b45579 sysupgrade -n 24.10.5→25.12.4, SSH key auth after ~60s boot 2026-05-19
zycast tested Go zycast binary on MIPS OpenWrt switch, NR7101 Telenor (MAC 78:c5:7d:13:91:9c), PoE power cycle, initramfs-recovery image 2026-05-26
modem_inventory tested @5b45579 AT commands on /dev/ttyUSB2: ATI, AT+GMR, AT+QCCID all responded 2026-05-19
cellular_data tested @b68de06 SIM card (ice+), ping 8.8.8.8 via LTE, 56Mbps down, 43ms latency 2026-05-19

Use Case Presets

Name Description Status Requires Packages Commands
adguard Network-wide ad blocking via AdGuard Home (post-flash setup) tested
ops characterization + transport parity
none adguardhome, luci-app-adguardhome
auto-sqm Auto-measure WAN speed and configure SQM to eliminate bufferbloat experimental
not validated on hardware
none sqm-scripts, luci-app-sqm, jsonfilter, iperf3
doh DNS-over-HTTPS via https-dns-proxy for encrypted DNS resolution tested
ops characterization + transport parity
none https-dns-proxy, luci-app-https-dns-proxy
fips-bluetooth-rfcomm FIPS mesh networking over Bluetooth RFCOMM (star topology with TUN) experimental
ASUS Lyra MAP-AC2200, star topology, RFCOMM transport
bluetooth bluez-libs, bluez-utils, bluez-utils-extra, kmod-tun
guest-wifi Isolated guest WiFi network with separate subnet, DHCP, and firewall zone tested
ops characterization + transport parity
wifi
mesh11sd 802.11s mesh networking with auto-config via mesh11sd tested
ops characterization + transport parity
wifi mesh11sd, ip-full, kmod-nft-bridge, vxlan requires configuration
mwan3 Multi-WAN failover or load balancing via mwan3 tested
ops characterization + transport parity
none mwan3
openclash Transparent proxy via Clash/Mihomo for censorship bypass (post-flash config) tested
ops characterization + transport parity
none luci-app-openclash, coreutils-nohup, bash, iptables, dnsmasq-full +4 more
sqm Smart Queue Management with CAKE to eliminate bufferbloat experimental
uci from OpenWrt wiki
none sqm-scripts, luci-app-sqm
ssh-hardening Optional Dropbear hardening: disable password auth, idle timeout, rate limit tested
ops unit tests, UciSet validation
none
tether Auto-detect Android or iPhone USB WAN. For Android, includes ADB auto-enable. tested
GL.iNet MT3000, Android RNDIS
usb kmod-usb-net, kmod-usb-net-rndis, kmod-usb-net-cdc-ether, kmod-usb2, usbutils +8 more
tether-android USB WAN from Android phone. Enable tethering manually on the phone. tested
GL.iNet MT3000
usb kmod-usb-net, kmod-usb-net-rndis, kmod-usb-net-cdc-ether, kmod-usb2, usbutils
tether-android-adb USB WAN from Android phone with ADB auto-enable. Confirm on phone, tethering activates automatically. tested
GL.iNet MT3000
usb kmod-usb-net, kmod-usb-net-rndis, kmod-usb-net-cdc-ether, kmod-usb2, usbutils +1 more
tether-ios USB WAN from iPhone. Enable Personal Hotspot manually on the phone. experimental
wiki-based; needs hardware validation
usb kmod-usb-net, kmod-usb-net-ipheth, kmod-usb-net-cdc-ether, usbmuxd, libimobiledevice +2 more
tollgate OpenTollGate Bitcoin/Lightning payment gateway. Downloads ipk via nostr (Blossom) with GitHub CI fallback, deploys post-flash via SCP + opkg. tested
ops characterization + resolve tests + transport parity
none nodogsplash, libustream-wolfssl, ca-bundle, ca-certificates
travelmate Travel router auto-connect for captive portal WiFi (hotels, airports) experimental
wiki-based
wifi travelmate, luci-app-travelmate, ca-bundle, ca-certificates
wireguard-client WireGuard VPN client — route traffic through a VPN tunnel tested
D-Link COVR-X1860 A1
none wireguard-tools, luci-proto-wireguard
wireguard-server WireGuard VPN server — remote access to home network tested
ops characterization + transport parity
none wireguard-tools, luci-proto-wireguard, qrencode
# --- AdGuard Home --- uci set adguardhome.adguardhome=adguardhome uci set adguardhome.adguardhome.enabled='1' uci set adguardhome.adguardhome.http_address='0.0.0.0:3000' uci set adguardhome.adguardhome.dns_port='5353' uci commit adguardhome /etc/init.d/adguardhome enable /etc/init.d/adguardhome start uci set dhcp.@dnsmasq[0].noresolv='1' uci add_list dhcp.@dnsmasq[0].server='127.0.0.1#5353' uci commit dhcp /etc/init.d/dnsmasq restart echo "AdGuard Home configured: DNS on port 5353, web UI at 0.0.0.0:3000"
# --- Auto-SQM --- touch /etc/config/auto_sqm uci set auto_sqm.config=auto_sqm uci set auto_sqm.config.mode='static' uci set auto_sqm.config.interface='wan' uci set auto_sqm.config.device='eth0' uci set auto_sqm.config.target_percent='90' uci set auto_sqm.config.qdisc='cake' uci set auto_sqm.config.script='piece_of_cake.qos' uci set auto_sqm.config.measurement_mode='wget' uci set auto_sqm.config.iperf3_host='' uci set auto_sqm.config.iperf3_port='5201' uci set auto_sqm.config.test_url='http://speedtest.tele2.net/10MB.zip' uci set auto_sqm.config.download_kbps='0' uci set auto_sqm.config.upload_kbps='0' uci set auto_sqm.config.upload_fallback_kbps='5000' uci set auto_sqm.config.hysteresis_percent='10' uci set auto_sqm.config.dynamic_interval_hours='4' uci commit auto_sqm cat <<'AUTO_SQM_EOF' > /usr/sbin/auto-sqm #!/bin/sh # auto-sqm — measure WAN link speed and configure SQM MODE=$(uci -q get auto_sqm.config.mode || echo "static") INTERFACE=$(uci -q get auto_sqm.config.interface || echo "wan") DEVICE=$(uci -q get auto_sqm.config.device || echo "eth0") TARGET_PCT=$(uci -q get auto_sqm.config.target_percent || echo "90") QDISC=$(uci -q get auto_sqm.config.qdisc || echo "cake") QOS_SCRIPT=$(uci -q get auto_sqm.config.script || echo "piece_of_cake.qos") MEAS_MODE=$(uci -q get auto_sqm.config.measurement_mode || echo "wget") IPERF3_HOST=$(uci -q get auto_sqm.config.iperf3_host || echo "") IPERF3_PORT=$(uci -q get auto_sqm.config.iperf3_port || echo "5201") TEST_URL=$(uci -q get auto_sqm.config.test_url || echo "") UPLOAD_FALLBACK=$(uci -q get auto_sqm.config.upload_fallback_kbps || echo "5000") HYSTERESIS=$(uci -q get auto_sqm.config.hysteresis_percent || echo "10") DL_SPEED=0 UL_SPEED=0 measure_wget() { [ -z "$DEVICE" ] && return 1 [ -z "$TEST_URL" ] && return 1 bytes_before=$(cat /sys/class/net/"$DEVICE"/statistics/rx_bytes 2>/dev/null) || return 1 t1=$(date +%s) wget -O /dev/null -T 30 "$TEST_URL" 2>/dev/null || return 1 t2=$(date +%s) bytes_after=$(cat /sys/class/net/"$DEVICE"/statistics/rx_bytes 2>/dev/null) || return 1 elapsed=$((t2 - t1)) [ "$elapsed" -eq 0 ] && elapsed=1 speed_bps=$(( (bytes_after - bytes_before) * 8 / elapsed )) DL_SPEED=$((speed_bps / 1000)) DL_SPEED=$((DL_SPEED * TARGET_PCT / 100)) } measure_iperf3() { [ -z "$IPERF3_HOST" ] && return 1 command -v iperf3 >/dev/null 2>&1 || return 1 json_out=$(iperf3 -c "$IPERF3_HOST" -p "$IPERF3_PORT" -t 5 -J 2>/dev/null) || return 1 speed_bps=$(echo "$json_out" | jsonfilter -e "@.end.sum_received.bits_per_second" 2>/dev/null) || return 1 speed_bps=$(echo "$speed_bps" | cut -d. -f1) DL_SPEED=$((speed_bps / 1000)) DL_SPEED=$((DL_SPEED * TARGET_PCT / 100)) } apply_sqm() { dl=$1 ul=$2 [ "$dl" -eq 0 ] && return 1 cur_dl=$(uci -q get sqm."$INTERFACE".download || echo "0") cur_ul=$(uci -q get sqm."$INTERFACE".upload || echo "0") if [ "$cur_dl" -gt 0 ] && [ "$cur_ul" -gt 0 ]; then lo=$((100 - HYSTERESIS)) hi=$((100 + HYSTERESIS)) pct_dl=$((cur_dl * 100 / dl)) pct_ul=$((cur_ul * 100 / ul)) if [ "$pct_dl" -ge "$lo" ] && [ "$pct_dl" -le "$hi" ] && [ "$pct_ul" -ge "$lo" ] && [ "$pct_ul" -le "$hi" ]; then echo "auto-sqm: change within hysteresis, skipping" return 0 fi fi touch /etc/config/sqm uci set sqm.$INTERFACE=queue uci set sqm.$INTERFACE.interface="$INTERFACE" uci set sqm.$INTERFACE.enabled='1' uci set sqm.$INTERFACE.script="$QOS_SCRIPT" uci set sqm.$INTERFACE.qdisc="$QDISC" uci set sqm.$INTERFACE.linklayer='none' uci set sqm.$INTERFACE.overhead='0' uci set sqm.$INTERFACE.linklayer_adaptation_mechanism='default' uci set sqm.$INTERFACE.debug_logging='0' uci set sqm.$INTERFACE.verbosity='5' uci set sqm.$INTERFACE.download="$dl" uci set sqm.$INTERFACE.upload="$ul" uci commit sqm /etc/init.d/sqm enable /etc/init.d/sqm restart 2>/dev/null || true echo "auto-sqm: SQM applied ${dl}/${ul} kbit/s (${QDISC})" } STATIC_DL=$(uci -q get auto_sqm.config.download_kbps || echo "0") STATIC_UL=$(uci -q get auto_sqm.config.upload_kbps || echo "0") if [ "$MODE" = "static" ] && [ "$STATIC_DL" -gt 0 ]; then DL_SPEED=$((STATIC_DL * TARGET_PCT / 100)) if [ "$STATIC_UL" -gt 0 ]; then UL_SPEED=$((STATIC_UL * TARGET_PCT / 100)) else UL_SPEED=$UPLOAD_FALLBACK fi else if [ "$MEAS_MODE" = "iperf3" ] && [ -n "$IPERF3_HOST" ]; then measure_iperf3 || measure_wget else measure_wget || measure_iperf3 fi if [ "$DL_SPEED" -eq 0 ]; then echo "auto-sqm: measurement failed, will retry on next trigger" >&2 exit 1 fi if [ "$STATIC_UL" -gt 0 ]; then UL_SPEED=$((STATIC_UL * TARGET_PCT / 100)) else UL_SPEED=$UPLOAD_FALLBACK fi fi apply_sqm "$DL_SPEED" "$UL_SPEED" AUTO_SQM_EOF chmod +x /usr/sbin/auto-sqm mkdir -p /etc/hotplug.d/iface cat <<'HOTPLUG_EOF' > /etc/hotplug.d/iface/10-sqm-autotune #!/bin/sh [ "$ACTION" = "ifup" ] && [ "$INTERFACE" = "wan" ] && /usr/sbin/auto-sqm & HOTPLUG_EOF chmod +x /etc/hotplug.d/iface/10-sqm-autotune echo 'auto-sqm: will measure and configure on WAN ifup' echo 'Auto-SQM configured'
# --- DNS-over-HTTPS (cloudflare) --- uci -q delete https-dns-proxy >/dev/null 2>&1 || true uci set https-dns-proxy.main=https_dns_proxy uci set https-dns-proxy.main.bootstrap_dns='1.1.1.1,8.8.8.8' uci set https-dns-proxy.main.listen_addr='127.0.0.1' uci set https-dns-proxy.main.listen_port='5053' uci set https-dns-proxy.main.resolver_url='https://cloudflare-dns.com/dns-query' uci commit https-dns-proxy /etc/init.d/https-dns-proxy enable /etc/init.d/https-dns-proxy restart # --- Point dnsmasq to DoH proxy on port 5053 --- uci set dhcp.@dnsmasq[0].noresolv='1' uci delete dhcp.@dnsmasq[0].server uci add_list dhcp.@dnsmasq[0].server='127.0.0.1#5053' uci commit dhcp /etc/init.d/dnsmasq restart echo "DoH configured: cloudflare on port 5053"
mkdir -p /etc/fips echo 'node:' > /etc/fips/fips.yaml echo ' identity:' >> /etc/fips/fips.yaml echo ' persistent: true' >> /etc/fips/fips.yaml echo '' >> /etc/fips/fips.yaml echo 'tun:' >> /etc/fips/fips.yaml echo ' enabled: true' >> /etc/fips/fips.yaml echo '' >> /etc/fips/fips.yaml echo 'dns:' >> /etc/fips/fips.yaml echo ' enabled: true' >> /etc/fips/fips.yaml echo '' >> /etc/fips/fips.yaml echo 'transports:' >> /etc/fips/fips.yaml echo ' rfcomm:' >> /etc/fips/fips.yaml echo ' mode: "client"' >> /etc/fips/fips.yaml echo ' channel: 1' >> /etc/fips/fips.yaml echo ' mtu: 1000' >> /etc/fips/fips.yaml echo ' auto_connect: true' >> /etc/fips/fips.yaml echo '' >> /etc/fips/fips.yaml echo 'peers: []' >> /etc/fips/fips.yaml echo '' >> /etc/fips/fips.yaml echo 'gateway:' >> /etc/fips/fips.yaml echo ' enabled: true' >> /etc/fips/fips.yaml echo ' pool: "fd01::/112"' >> /etc/fips/fips.yaml echo ' lan_interface: "br-lan"' >> /etc/fips/fips.yaml echo ' dns:' >> /etc/fips/fips.yaml echo ' listen: "[::1]:5353"' >> /etc/fips/fips.yaml echo ' upstream: "[::1]:5354"' >> /etc/fips/fips.yaml echo ' ttl: 60' >> /etc/fips/fips.yaml echo '0000' > /etc/fips/bt-pin echo '#!/bin/sh /etc/rc.common' > /etc/init.d/bt-agent echo 'START=98' >> /etc/init.d/bt-agent echo 'STOP=10' >> /etc/init.d/bt-agent echo 'start() {' >> /etc/init.d/bt-agent echo ' hciconfig hci0 up' >> /etc/init.d/bt-agent echo ' command -v bt-agent >/dev/null 2>&1 && bt-agent -c NoInputNoOutput -p /etc/fips/bt-pin &' >> /etc/init.d/bt-agent echo '}' >> /etc/init.d/bt-agent echo 'stop() {' >> /etc/init.d/bt-agent echo ' killall bt-agent 2>/dev/null' >> /etc/init.d/bt-agent echo '}' >> /etc/init.d/bt-agent chmod +x /etc/init.d/bt-agent /etc/init.d/bt-agent enable echo '#!/bin/sh /etc/rc.common' > /etc/init.d/fips echo 'START=99' >> /etc/init.d/fips echo 'STOP=10' >> /etc/init.d/fips echo 'start() {' >> /etc/init.d/fips echo ' fips -c /etc/fips/fips.yaml &' >> /etc/init.d/fips echo '}' >> /etc/init.d/fips echo 'stop() {' >> /etc/init.d/fips echo ' killall fips 2>/dev/null' >> /etc/init.d/fips echo '}' >> /etc/init.d/fips chmod +x /etc/init.d/fips /etc/init.d/fips enable echo 'FIPS Bluetooth RFCOMM configured (client, channel 1, 0 peer(s))'
# --- Guest WiFi: 'Guest' --- uci set network.guest=interface uci set network.guest.proto='static' uci set network.guest.ipaddr='192.168.4.1' uci set network.guest.netmask='255.255.255.0' uci commit network uci set dhcp.guest=dhcp uci set dhcp.guest.interface='guest' uci set dhcp.guest.start='100' uci set dhcp.guest.limit='50' uci set dhcp.guest.leasetime='1h' uci commit dhcp uci set firewall.guest=zone uci set firewall.guest.name='guest' uci set firewall.guest.network='guest' uci set firewall.guest.input='REJECT' uci set firewall.guest.output='ACCEPT' uci set firewall.guest.forward='REJECT' uci set firewall.guest_fwd=forwarding uci set firewall.guest_fwd.src='guest' uci set firewall.guest_fwd.dest='wan' uci set firewall.guest_dns=rule uci set firewall.guest_dns.name='Allow-DNS-guest' uci set firewall.guest_dns.src='guest' uci set firewall.guest_dns.dest_port='53' uci set firewall.guest_dns.proto='tcpudp' uci set firewall.guest_dns.target='ACCEPT' uci set firewall.guest_dhcp=rule uci set firewall.guest_dhcp.name='Allow-DHCP-guest' uci set firewall.guest_dhcp.src='guest' uci set firewall.guest_dhcp.dest_port='67-68' uci set firewall.guest_dhcp.proto='udp' uci set firewall.guest_dhcp.target='ACCEPT' uci commit firewall while uci show wireless 2>/dev/null | grep -q "network='guest'"; do _s=$(uci show wireless 2>/dev/null | grep "network='guest'" | head -1 | cut -d. -f2 | cut -d= -f1); uci delete "wireless.$_s" 2>/dev/null; done; true _radio=""; for _r in radio0 radio1 radio2 radio3; do _b=$(uci get wireless.${_r}.band 2>/dev/null); if [ "$_b" = "2g" ]; then _radio=$_r; break; fi; done; if [ -n "$_radio" ]; then uci add wireless wifi-iface; uci set wireless.@wifi-iface[-1].device=$_radio; uci set wireless.@wifi-iface[-1].mode=ap; uci set wireless.@wifi-iface[-1].ssid='Guest'; uci set wireless.@wifi-iface[-1].encryption=psk2; uci set wireless.@wifi-iface[-1].network=guest; uci set wireless.@wifi-iface[-1].isolate=1; fi uci commit wireless /etc/init.d/network restart /etc/init.d/firewall restart echo "Guest WiFi configured: SSID='Guest' network=guest isolated=1"
# --- mwan3 multi-WAN --- uci -q delete mwan3 >/dev/null 2>&1 || true uci set mwan3.wan=interface uci set mwan3.wan.enabled='1' list track_ip '1.0.0.1' list track_ip '1.1.1.1' list track_ip '8.8.8.8' list track_ip '8.8.4.4' uci set mwan3.wan.family='ipv4' uci set mwan3.wan.reliability='1' uci set mwan3.wan.count='1' uci set mwan3.wan.timeout='2' uci set mwan3.wan.interval='5' uci set mwan3.wan.down='3' uci set mwan3.wan.up='8' uci set mwan3.usbwan=interface uci set mwan3.usbwan.enabled='1' list track_ip '1.0.0.1' list track_ip '1.1.1.1' list track_ip '8.8.8.8' list track_ip '8.8.4.4' uci set mwan3.usbwan.family='ipv4' uci set mwan3.usbwan.reliability='1' uci set mwan3.usbwan.count='1' uci set mwan3.usbwan.timeout='2' uci set mwan3.usbwan.interval='5' uci set mwan3.usbwan.down='3' uci set mwan3.usbwan.up='8' uci set mwan3.wan_m1_w1=member uci set mwan3.wan_m1_w1.interface='wan' uci set mwan3.wan_m1_w1.metric='1' uci set mwan3.wan_m1_w1.weight='1' uci set mwan3.usbwan_m2_w1=member uci set mwan3.usbwan_m2_w1.interface='usbwan' uci set mwan3.usbwan_m2_w1.metric='2' uci set mwan3.usbwan_m2_w1.weight='1' uci set mwan3.wan_policy=policy uci add_list mwan3.wan_policy.use_member='wan_m1_w1' uci add_list mwan3.wan_policy.use_member='usbwan_m2_w1' uci set mwan3.wan_policy.last_resort='default' uci set mwan3.default_rule_v4=rule uci set mwan3.default_rule_v4.dest_ip='0.0.0.0/0' uci set mwan3.default_rule_v4.use_policy='wan_policy' uci set mwan3.default_rule_v4.family='ipv4' uci set mwan3.https_rule=rule uci set mwan3.https_rule.dest_port='443' uci set mwan3.https_rule.proto='tcp' uci set mwan3.https_rule.sticky='1' uci set mwan3.https_rule.use_policy='wan_policy' uci commit mwan3 /etc/init.d/mwan3 restart echo "mwan3 configured: wan (primary) + usbwan (failover)"
# --- OpenClash transparent proxy --- mkdir -p /etc/openclash/config uci set openclash.config.enable='1' uci set openclash.config.config_path='/etc/openclash/config/config.yaml' uci set openclash.config.proxy_type='ss' uci set openclash.config.core_type='Meta' uci set openclash.config.dashboard_type='Official' uci set openclash.config.dns_mode='redir-host' uci set openclash.config.operation_mode='redir-host' uci commit openclash /etc/init.d/openclash enable echo "OpenClash configured: Meta core, ss proxy" echo "Post-flash: import your subscription config via the LuCI web UI"
# --- SQM Smart Queue Management --- for _s in $(uci -q show sqm 2>/dev/null | grep '=queue' | cut -d. -f2 | cut -d= -f1); do uci -q delete sqm.$_s; done; true _sqm_dev=$(uci get network.wan.device 2>/dev/null); if [ -z "$_sqm_dev" ] || ! ip addr show "$_sqm_dev" 2>/dev/null | grep -q "inet "; then _sqm_dev=$(ip route show default 0.0.0.0/0 2>/dev/null | awk '{print $5}' | head -1); fi; if [ -z "$_sqm_dev" ]; then _sqm_dev=wan; fi uci set sqm.wan=queue uci set sqm.wan.interface="$_sqm_dev" uci set sqm.wan.enabled='1' uci set sqm.wan.script='piece_of_cake.qos' uci set sqm.wan.qdisc='cake' uci set sqm.wan.linklayer='none' uci set sqm.wan.overhead='0' uci set sqm.wan.download='10000' uci set sqm.wan.upload='5000' uci set sqm.wan.linklayer_adaptation_mechanism='default' uci set sqm.wan.debug_logging='0' uci set sqm.wan.verbosity='5' uci commit sqm /etc/init.d/sqm enable /etc/init.d/sqm restart echo "SQM configured: 10000/5000 kbit/s (cake) on $_sqm_dev"
# --- SSH hardening --- uci set dropbear.@dropbear[0].PasswordAuth='off' uci set dropbear.@dropbear[0].RootPasswordAuth='off' uci set dropbear.@dropbear[0].Port='22' uci set dropbear.@dropbear[0].IdleTimeout='300' uci set dropbear.@dropbear[0].MaxAuthTries='3' uci set dropbear.@dropbear[0].GatewayPorts='no' uci commit dropbear /etc/init.d/dropbear restart echo "SSH hardened: password_auth=off idle=300s max_tries=3 port=22"
# --- USB tethering (auto-detect) --- /usr/sbin/usbmuxd -v -U -f >/dev/null 2>&1 & USB_DEV="" for _ in $(seq 1 45); do for dev in /sys/class/net/*; do name=$(basename "$dev") case "$name" in lo|br-lan|eth0|wlan*) continue ;; esac driver=$(readlink "$dev/device/driver" 2>/dev/null || true) if echo "$driver" | grep -qi "rndis\|cdc_ether\|usbnet\|ipheth"; then USB_DEV="$name" break 2 fi iface_desc="" [ -e "$dev/device/interface" ] && iface_desc=$(cat "$dev/device/interface" 2>/dev/null || true) if echo "$iface_desc" | grep -qi "apple\|iphone"; then USB_DEV="$name" break 2 fi done sleep 1 done if [ -z "$USB_DEV" ]; then for cand in usb0 usb1; do [ -e "/sys/class/net/$cand" ] && USB_DEV="$cand" && break done fi if [ -n "$USB_DEV" ]; then uci set network.usbwan=interface uci set network.usbwan.proto='dhcp' uci set network.usbwan.device="$USB_DEV" uci set network.usbwan.metric='20' for _z in $(uci show firewall 2>/dev/null | grep '=zone' | cut -d. -f2 | cut -d= -f1 || true); do [ "$(uci -q get firewall.$_z.name)" = 'wan' ] && uci del_list firewall.$_z.network='usbwan' 2>/dev/null; uci add_list firewall.$_z.network='usbwan'; break; done uci commit network uci commit firewall ifup usbwan 2>/dev/null || true echo "USB tethering enabled on $USB_DEV -> usbwan" else echo "USB tethering: no USB network device found, skipping" >&2 fi mkdir -p /etc/hotplug.d/usb cat > /etc/hotplug.d/usb/99-usb-tether-adb << 'HOTPLUG_EOF' [ "$ACTION" = "bind" ] || exit 0 [ "$PRODUCT" ] || exit 0 ( HOME=/root export HOME command -v adb >/dev/null 2>&1 || exit 0 DELAY=1 for attempt in 1 2 3 4 5 6 7; do sleep $DELAY if ip addr show usb0 2>/dev/null | grep -q "inet "; then exit 0 fi STATE=$(adb get-state 2>/dev/null) if [ "$STATE" = "device" ]; then adb shell svc usb setFunctions rndis 2>/dev/null sleep 3 if ip addr show usb0 2>/dev/null | grep -q "inet "; then logger -t usb-tether "ADB enabled tethering (attempt $attempt)" exit 0 fi fi DELAY=$((DELAY * 2)) done logger -t usb-tether "ADB tethering gave up after $attempt attempts" ) & HOTPLUG_EOF
# --- Android USB tethering (manual) --- USB_DEV="" for _ in $(seq 1 45); do for dev in /sys/class/net/*; do name=$(basename "$dev") case "$name" in lo|br-lan|eth0|wlan*) continue ;; esac driver=$(readlink "$dev/device/driver" 2>/dev/null || true) if echo "$driver" | grep -qi "rndis\|cdc_ether\|usbnet"; then USB_DEV="$name" break 2 fi done sleep 1 done if [ -z "$USB_DEV" ]; then for cand in usb0 usb1; do [ -e "/sys/class/net/$cand" ] && USB_DEV="$cand" && break done fi if [ -n "$USB_DEV" ]; then uci set network.usbwan=interface uci set network.usbwan.proto='dhcp' uci set network.usbwan.device="$USB_DEV" uci set network.usbwan.metric='20' for _z in $(uci show firewall 2>/dev/null | grep '=zone' | cut -d. -f2 | cut -d= -f1 || true); do [ "$(uci -q get firewall.$_z.name)" = 'wan' ] && uci del_list firewall.$_z.network='usbwan' 2>/dev/null; uci add_list firewall.$_z.network='usbwan'; break; done uci commit network uci commit firewall ifup usbwan 2>/dev/null || true echo "USB tethering enabled on $USB_DEV -> usbwan" else echo "USB tethering: no USB network device found, skipping" >&2 fi
# --- Android USB tethering (ADB auto-enable) --- USB_DEV="" for _ in $(seq 1 45); do for dev in /sys/class/net/*; do name=$(basename "$dev") case "$name" in lo|br-lan|eth0|wlan*) continue ;; esac driver=$(readlink "$dev/device/driver" 2>/dev/null || true) if echo "$driver" | grep -qi "rndis\|cdc_ether\|usbnet"; then USB_DEV="$name" break 2 fi done sleep 1 done if [ -z "$USB_DEV" ]; then for cand in usb0 usb1; do [ -e "/sys/class/net/$cand" ] && USB_DEV="$cand" && break done fi if [ -n "$USB_DEV" ]; then uci set network.usbwan=interface uci set network.usbwan.proto='dhcp' uci set network.usbwan.device="$USB_DEV" uci set network.usbwan.metric='20' for _z in $(uci show firewall 2>/dev/null | grep '=zone' | cut -d. -f2 | cut -d= -f1 || true); do [ "$(uci -q get firewall.$_z.name)" = 'wan' ] && uci del_list firewall.$_z.network='usbwan' 2>/dev/null; uci add_list firewall.$_z.network='usbwan'; break; done uci commit network uci commit firewall ifup usbwan 2>/dev/null || true echo "USB tethering enabled on $USB_DEV -> usbwan" else echo "USB tethering: no USB network device found, skipping" >&2 fi mkdir -p /etc/hotplug.d/usb cat > /etc/hotplug.d/usb/99-usb-tether-adb << 'HOTPLUG_EOF' [ "$ACTION" = "bind" ] || exit 0 [ "$PRODUCT" ] || exit 0 ( HOME=/root export HOME command -v adb >/dev/null 2>&1 || exit 0 DELAY=1 for attempt in 1 2 3 4 5 6 7; do sleep $DELAY if ip addr show usb0 2>/dev/null | grep -q "inet "; then exit 0 fi STATE=$(adb get-state 2>/dev/null) if [ "$STATE" = "device" ]; then adb shell svc usb setFunctions rndis 2>/dev/null sleep 3 if ip addr show usb0 2>/dev/null | grep -q "inet "; then logger -t usb-tether "ADB enabled tethering (attempt $attempt)" exit 0 fi fi DELAY=$((DELAY * 2)) done logger -t usb-tether "ADB tethering gave up after $attempt attempts" ) & HOTPLUG_EOF
# --- iPhone USB tethering --- /usr/sbin/usbmuxd -v -U -f >/dev/null 2>&1 & USB_DEV="" for _ in $(seq 1 45); do for dev in /sys/class/net/*; do name=$(basename "$dev") case "$name" in lo|br-lan|eth0|wlan*) continue ;; esac driver=$(readlink "$dev/device/driver" 2>/dev/null || true) if echo "$driver" | grep -qi "ipheth"; then USB_DEV="$name" break 2 fi iface_desc="" [ -e "$dev/device/interface" ] && iface_desc=$(cat "$dev/device/interface" 2>/dev/null || true) if echo "$iface_desc" | grep -qi "apple\|iphone"; then USB_DEV="$name" break 2 fi done sleep 1 done if [ -z "$USB_DEV" ]; then for cand in usb0 usb1; do [ -e "/sys/class/net/$cand" ] && USB_DEV="$cand" && break done fi if [ -n "$USB_DEV" ]; then uci set network.usbwan=interface uci set network.usbwan.proto='dhcp' uci set network.usbwan.device="$USB_DEV" uci set network.usbwan.metric='20' for _z in $(uci show firewall 2>/dev/null | grep '=zone' | cut -d. -f2 | cut -d= -f1 || true); do [ "$(uci -q get firewall.$_z.name)" = 'wan' ] && uci del_list firewall.$_z.network='usbwan' 2>/dev/null; uci add_list firewall.$_z.network='usbwan'; break; done uci commit network uci commit firewall ifup usbwan 2>/dev/null || true echo "USB tethering enabled on $USB_DEV -> usbwan" else echo "USB tethering: no USB network device found, skipping" >&2 fi
# --- TollGate: nodogsplash captive portal --- uci set nodogsplash.@nodogsplash[0].enabled='1' uci commit nodogsplash /etc/init.d/nodogsplash enable /etc/init.d/nodogsplash restart # --- TollGate: ipk installed separately via deploy_tollgate_post_flash() ---
# --- Travelmate travel router --- uci set travelmate.global.trm_enabled='1' uci set travelmate.global.trm_automatic='1' uci set travelmate.global.trm_captive='1' uci set travelmate.global.trm_timeout='60' uci set travelmate.global.trm_retry='5' uci set travelmate.global.trm_radio='radio0' uci commit travelmate /etc/init.d/travelmate enable /etc/init.d/travelmate restart echo "Travelmate configured: auto-connect on radio0"
# --- WireGuard VPN client --- uci set network.wg0=interface uci set network.wg0.proto='wireguard' uci set network.wg0.private_key='generate' uci set network.wg0.addresses='10.67.0.2/32' uci set network.wg0_peer=wireguard_wg0 uci set network.wg0_peer.public_key='' uci set network.wg0_peer.endpoint_host='' uci set network.wg0_peer.endpoint_port='51820' uci set network.wg0_peer.allowed_ips='0.0.0.0/0, ::/0' uci set network.wg0_peer.route_allowed_ips='1' uci set network.wg0_peer.persistent_keepalive='25' # --- Cleanup stale anonymous WireGuard firewall sections --- while uci show firewall 2>/dev/null | grep -q "name='vpn'"; do _s=$(uci show firewall 2>/dev/null | grep "name='vpn'" | head -1 | cut -d. -f2 | cut -d= -f1); uci delete "firewall.$_s" 2>/dev/null; done; true while uci show firewall 2>/dev/null | grep -q "dest='vpn'"; do _s=$(uci show firewall 2>/dev/null | grep "dest='vpn'" | head -1 | cut -d. -f2 | cut -d= -f1); uci delete "firewall.$_s" 2>/dev/null; done; true while uci show firewall 2>/dev/null | grep -q "name='KillSwitch-Reject-NonVPN'"; do _s=$(uci show firewall 2>/dev/null | grep "name='KillSwitch-Reject-NonVPN'" | head -1 | cut -d. -f2 | cut -d= -f1); uci delete "firewall.$_s" 2>/dev/null; done; true # --- WireGuard firewall zone + forwarding --- uci set firewall.wg_client_vpn=zone uci set firewall.wg_client_vpn.name='vpn' uci set firewall.wg_client_vpn.input='REJECT' uci set firewall.wg_client_vpn.output='ACCEPT' uci set firewall.wg_client_vpn.forward='REJECT' uci set firewall.wg_client_vpn.masq='1' uci set firewall.wg_client_vpn.mtu_fix='1' uci set firewall.wg_client_vpn.network='wg0' uci set firewall.wg_client_fwd=forwarding uci set firewall.wg_client_fwd.src='lan' uci set firewall.wg_client_fwd.dest='vpn' uci set firewall.wg_client_killswitch=rule uci set firewall.wg_client_killswitch.name='KillSwitch-Reject-NonVPN' uci set firewall.wg_client_killswitch.src='lan' uci set firewall.wg_client_killswitch.dest='wan' uci set firewall.wg_client_killswitch.proto='all' uci set firewall.wg_client_killswitch.target='REJECT' uci commit network uci commit firewall /etc/init.d/network restart echo 'WireGuard client configured: :51820' i=0; while [ $i -lt 30 ]; do if wg show wg0 2>/dev/null | grep -q 'latest handshake'; then echo 'WG kill-switch: tunnel verified'; exit 0; fi; sleep 1; i=$((i+1)); done; echo 'WG kill-switch: tunnel failed — removing kill switch to restore WAN'; uci delete firewall.wg_client_killswitch; uci commit firewall; fw4 restart
# --- WireGuard VPN server --- uci set network.wg0=interface uci set network.wg0.proto='wireguard' uci set network.wg0.private_key='' uci set network.wg0.listen_port='51820' uci add_list network.wg0.addresses='10.1.99.1/24' while uci show firewall 2>/dev/null | grep -q "name='vpn'"; do _s=$(uci show firewall 2>/dev/null | grep "name='vpn'" | head -1 | cut -d. -f2 | cut -d= -f1); uci delete "firewall.$_s" 2>/dev/null; done; true while uci show firewall 2>/dev/null | grep -q "name='Allow-WireGuard'"; do _s=$(uci show firewall 2>/dev/null | grep "name='Allow-WireGuard'" | head -1 | cut -d. -f2 | cut -d= -f1); uci delete "firewall.$_s" 2>/dev/null; done; true uci set firewall.wg_server_vpn=zone uci set firewall.wg_server_vpn.name='vpn' uci set firewall.wg_server_vpn.input='ACCEPT' uci set firewall.wg_server_vpn.output='ACCEPT' uci set firewall.wg_server_vpn.forward='REJECT' uci set firewall.wg_server_vpn.masq='1' uci set firewall.wg_server_vpn.mtu_fix='1' uci set firewall.wg_server_vpn.network='wg0' uci set firewall.wg_server_fwd_lan=forwarding uci set firewall.wg_server_fwd_lan.src='vpn' uci set firewall.wg_server_fwd_lan.dest='lan' uci set firewall.wg_server_fwd_wan=forwarding uci set firewall.wg_server_fwd_wan.src='vpn' uci set firewall.wg_server_fwd_wan.dest='wan' uci set firewall.wg_server_allow=rule uci set firewall.wg_server_allow.name='Allow-WireGuard' uci set firewall.wg_server_allow.src='wan' uci set firewall.wg_server_allow.dest_port='51820' uci set firewall.wg_server_allow.proto='udp' uci set firewall.wg_server_allow.target='ACCEPT' uci commit network uci commit firewall /etc/init.d/network restart echo "WireGuard server configured: port 51820, subnet 10.1.99.1/24"