Skip to content

travelmate: feature request -- bare-mode service toggling for captive portal auth #28646

@SeanLF

Description

@SeanLF

Problem

When travelmate connects to a network with a captive portal, it correctly disables VPN (f_vpn "disable") before attempting portal authentication. However, other services that interfere with captive portal auth are not disabled:

  • Encrypted DNS (stubby, adguardhome, dnscrypt-proxy) -- upstream DNS encryption bypasses the portal's DNS redirect, so the portal detection URL resolves correctly but the device can't actually reach the portal login page through its normal DNS path
  • Tailscale -- routes traffic through the mesh, bypassing the portal
  • DNS-based ad-blocking -- can block resources loaded by portal login pages

This is a common failure mode for travel routers running travelmate alongside encrypted DNS or VPN mesh services. The portal is detected, but authentication fails because these services prevent the device from interacting with the portal normally.

Existing behaviour

  1. travelmate detects captive portal via f_net()
  2. VPN is disabled via f_vpn "disable"
  3. Portal domain is added to dnsmasq rebind whitelist
  4. Login script runs (if configured)
  5. f_net() verifies auth succeeded
  6. VPN re-enabled

Steps 2-3 are not sufficient when encrypted DNS or mesh VPN services are active, because DNS queries still bypass the portal's DNS interception.

Proposed solution

A new "bare-mode" callback, following the existing travelmate.vpn pattern:

  • New UCI options:
    option trm_baremode '0'
    option trm_baremode_services 'stubby adguardhome tailscale'
    
  • Optional per-uplink override:
    config uplink
        option ssid 'HotelWiFi'
        option baremode_services 'stubby adguardhome tailscale'
    
  • A callback script /etc/travelmate/travelmate.baremode called with "disable" before login and "enable" after successful auth
  • Falls back to global trm_baremode_services when per-uplink config is not set

The default callback would simply stop/start the configured init.d services.

Flow with bare-mode

  1. travelmate detects captive portal via f_net() (existing)
  2. VPN is disabled via f_vpn "disable" (existing)
  3. Bare-mode services disabled (new)
  4. Portal domain added to dnsmasq rebind whitelist (existing)
  5. Login script runs if configured (existing)
  6. f_net() verifies auth succeeded (existing)
  7. Bare-mode services re-enabled (new)
  8. VPN re-enabled (existing)

Prior art

GL.iNet's travel router firmware implements this pattern (their "bare mode") in their captive portal handler. The older implementation is available under GPL v3 at https://github.com/gl-inet/portal-detection. The approach is proven in production across their device range.

Implementation notes

  • I'm happy to submit a PR for this if the approach seems reasonable
  • The change is self-contained: a new function in travelmate-functions.sh, a default callback script, and UCI config additions
  • No new dependencies
  • Backwards compatible -- bare-mode is off by default

Would appreciate feedback on whether this fits with travelmate's direction, or if there's a preferred approach I'm not seeing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions