archy/core/openwrt/src/tollgate/nodogsplash.rs

51 lines
2.5 KiB
Rust
Raw Normal View History

fix(tollgate): install and configure NoDogSplash for real client gating tollgate-wrt has no firewall/netfilter code of its own (confirmed via strings on the binary and the upstream Go source) — it delegates all MAC authorization and gate open/close to NoDogSplash via ndsctl. Upstream's package declares +nodogsplash as a hard dependency, but neither of our install paths pull it in: the opkg fast path only resolves deps against a real feed, and the raw .ipk-extraction fallback (used whenever the package isn't in a feed, and always on ApkNative) skips dependency resolution entirely. Result: tollgate-wrt ran, accepted payments, and tracked balances, but never actually blocked unpaid clients — the static firewall zone just forwarded everyone to WAN unconditionally. Also fixes the config.json mismatch: tollgate-wrt reads /etc/tollgate/config.json exclusively, never the tollgate.main.* UCI keys we were writing — so mint/price changes through this project's UI silently had no effect on what the daemon actually advertised. - tollgate/nodogsplash.rs: install nodogsplash, configure it to gate the dedicated br-tollgate bridge, open the pre-auth walled-garden ports (2121 payment, 2050 portal). - tollgate/wifi.rs: bind network.tollgate to a stable br-tollgate bridge device (NoDogSplash needs a known interface name — the driver-assigned name of a bare wifi vif isn't guaranteed); disable IPv6 RA/DHCPv6 on it (NoDogSplash only manages IPv4 iptables, so IPv6 would let clients bypass the portal entirely). - tollgate/config.rs: apply_daemon_config() merges pricing/mint into the real config.json instead of (only) UCI. - opkg.rs: generic install_package() for standard feed packages under either PkgManager mode. - router.rs: upload_file() (SCP) for non-UCI config files.
2026-07-02 17:23:12 +00:00
use anyhow::{Context, Result};
use crate::opkg::PkgManager;
use crate::tollgate::TollGateConfig;
use crate::Router;
/// Install and configure NoDogSplash — the captive-portal engine that
/// `tollgate-wrt` delegates all MAC authorization and gate open/close to via
/// `ndsctl`. `tollgate-wrt` contains no firewall/netfilter code of its own
/// (confirmed: its binary has no `nft`/`ipset`/`iptables` calls at all); the
/// upstream package therefore hard-depends on `+nodogsplash` and its postinst
/// restarts it. Without NoDogSplash actually running, nothing blocks
/// unauthenticated clients from reaching the internet, regardless of what
/// TollGate itself is configured to charge.
///
/// Gates the dedicated `br-tollgate` bridge (see `wifi::provision_network`),
/// not `br-lan` — the paid SSID here lives on its own isolated network/subnet
/// rather than the canonical upstream layout where it's bridged into `lan`.
pub fn provision(router: &Router, pkg_mgr: PkgManager, cfg: &TollGateConfig) -> Result<()> {
router
.install_package(pkg_mgr, "nodogsplash")
.context("install nodogsplash — required by tollgate-wrt for client gating")?;
router.run_ok("touch /etc/config/nodogsplash")?;
router.uci_set("nodogsplash.main", "nodogsplash")?;
router.uci_set("nodogsplash.main.enabled", "1")?;
router.uci_set("nodogsplash.main.gatewayinterface", "br-tollgate")?;
router.uci_set("nodogsplash.main.gatewayname", &format!("{} Portal", cfg.ssid))?;
router.uci_set("nodogsplash.main.gatewaydomainname", "TollGate.lan")?;
router.uci_set("nodogsplash.main.gatewayport", "2050")?;
// Pre-auth "walled garden": unauthenticated clients must still be able to
// reach the TollGate payment endpoint (2121) and the splash portal itself
// (2050) — everything else is blocked by NoDogSplash until ndsctl
// authorizes their MAC. Rebuild the list each run rather than trying to
// dedupe, so repeated provisioning stays idempotent.
let _ = router.uci_delete("nodogsplash.main.users_to_router");
router.uci_add_list("nodogsplash.main.users_to_router", "allow tcp port 2121")?;
router.uci_add_list("nodogsplash.main.users_to_router", "allow tcp port 2050")?;
router.uci_commit(Some("nodogsplash"))?;
Ok(())
}
/// (Re)start the nodogsplash service so config changes and gate state take effect.
pub fn restart(router: &Router) -> Result<()> {
router.run_ok("/etc/init.d/nodogsplash enable")?;
router.run_ok("/etc/init.d/nodogsplash restart || /etc/init.d/nodogsplash start")?;
Ok(())
}