travelmate: release 2.4.5-1

- added opt-in protection against access points with locally-administered (LAA) BSSIDs
- added a special trm_maxretry value '0', enabling unlimited connection retries
- removed obsolete connection-tracking functions (too many uci updates/flash wear)
- all runtime files now live under a single /var/run/travelmate/ directory
- various code cleanups & fixes
- LuCI: made the new UCI option 'trm_eviltwin' available
- LuCI: more cleanups
- readme update

Signed-off-by: Dirk Brenken <dev@brenken.org>
(cherry picked from commit 8722911295)
This commit is contained in:
Dirk Brenken
2026-05-09 21:38:20 +02:00
parent 957e9c41d7
commit 243c066cb0
7 changed files with 545 additions and 287 deletions
+2 -2
View File
@@ -6,8 +6,8 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=travelmate
PKG_VERSION:=2.4.0
PKG_RELEASE:=2
PKG_VERSION:=2.4.5
PKG_RELEASE:=1
PKG_LICENSE:=GPL-3.0-or-later
PKG_MAINTAINER:=Dirk Brenken <dev@brenken.org>
+7 -1
View File
@@ -8,8 +8,14 @@
trm_init="/etc/init.d/travelmate"
trm_funlib="/usr/lib/travelmate-functions.sh"
trm_ntplock="/var/lock/travelmate.ntp.lock"
trm_ntplock="/var/run/travelmate/travelmate.ntp.lock"
# ensure runtime directory exists
#
[ ! -d "${trm_ntplock%/*}" ] && mkdir -p "${trm_ntplock%/*}"
# check for ntp hotplug event and travelmate service autostart condition
#
if mkdir "${trm_ntplock}" 2>/dev/null; then
if [ "${ACTION}" = "stratum" ] && "${trm_init}" enabled; then
. "${trm_funlib}"
+9 -12
View File
@@ -36,11 +36,10 @@ automatically (re)connnects to configured APs/hotspots as they become available.
* VPN hook supports 'wireguard' or 'openvpn' client setups to handle VPN (re)connections automatically
* Email hook via 'msmtp' sends notification e-mails after every successful uplink connect
* Proactively scan and switch to a higher priority uplink, replacing an existing connection
* Connection tracking logs start and end date of an uplink connection
* Check router subnet vs. uplink subnet, to show conflicts with router LAN network
* Automatically disable the uplink after n minutes, e.g. for timed connections
* Automatically (re)enable the uplink after n minutes, e.g. after failed login attempts
* (Optional) Generate a random unicast MAC address for each uplink connection
* (Optional) Evil twin protection by skipping access points with locally-administered (LAA) BSSIDs
* Configurable retry limit per uplink, with optional unlimited retry mode
* NTP time sync before sending emails
* procd init and ntp-hotplug support
* Runtime information available via LuCI & via 'status' init command
@@ -100,8 +99,9 @@ automatically (re)connnects to configured APs/hotspots as they become available.
| trm_autoadd | 0, disabled | automatically add open uplinks like hotel captive portals to your wireless config |
| trm_ssidfilter | -, not set | list of SSID patterns for filtering/skipping specific open uplinks, e.g. 'Chromecast*' |
| trm_randomize | 0, disabled | generate a random unicast MAC address for each uplink connection |
| trm_eviltwin | 0, disabled | detect and skip access points with locally administered (LAA) BSSIDs to mitigate evil twin attacks |
| trm_triggerdelay | 2 | additional trigger delay in seconds before travelmate processing begins |
| trm_maxretry | 3 | retry limit to connect to an uplink |
| trm_maxretry | 3 | retry limit to connect to an uplink, set to '0' for unlimited retries |
| trm_minquality | 35 | minimum signal quality threshold as percent for conditional uplink (dis-) connections |
| trm_maxwait | 30 | how long should travelmate wait for a successful wlan uplink connection |
| trm_timeout | 60 | overall retry timeout in seconds |
@@ -123,17 +123,13 @@ automatically (re)connnects to configured APs/hotspots as they become available.
| Option | Default | Description/Valid Values |
| :----------------- | :--------------------------------- | :---------------------------------------------------------------------------------------------------- |
| enabled | 1, enabled | enable or disable the uplink, automatically set if the retry limit or the conn. expiry was reached |
| enabled | 1, enabled | enable or disable the uplink, automatically set if the retry limit was reached |
| device | -, not set | match the 'device' in the wireless config section |
| ssid | -, not set | match the 'ssid' in the wireless config section |
| bssid | -, not set | match the 'bssid' in the wireless config section |
| con_start | -, not set | connection start (will be automatically set after a successful ntp sync) |
| con_end | -, not set | connection end (will be automatically set after a successful ntp sync) |
| con_start_expiry | 0, disabled | automatically disable the uplink after n minutes, e.g. for timed connections |
| con_end_expiry | 0, disabled | automatically (re-)enable the uplink after n minutes, e.g. after failed login attempts |
| script | -, not set | reference to an external auto login script for captive portals |
| script_args | -, not set | optional runtime args for the auto login script |
| macaddr | -, not set | use a specified MAC address for the uplink
| macaddr | -, not set | use a specified MAC address for the uplink |
| vpn | 0, disabled | automatically handle VPN (re-) connections |
| vpnservice | -, not set | reference the already configured 'wireguard' or 'openvpn' client instance as vpn provider |
| vpniface | -, not set | the logical vpn interface, e.g. 'wg0' or 'tun0' |
@@ -196,7 +192,8 @@ Hopefully more scripts for different captive portals will be provided by the com
## Runtime information
**Receive Travelmate runtime information:**
Travelmate stores all runtime files (pid, scan results, status JSON, etc.) under `/var/run/travelmate/`. The runtime status is exposed both via the LuCI status panel and the init command:
<pre><code>
root@2go:~# /etc/init.d/travelmate status
::: travelmate runtime information
@@ -207,7 +204,7 @@ root@2go:~# /etc/init.d/travelmate status
+ station_mac : 42:40:45:EC:B3:D1
+ station_interfaces : wwan, -
+ station_subnet : 10.168.20.0 (lan: 10.200.1.0)
+ run_flags : scan: active, captive: ✔, proactive: ✔, netcheck: ✘, autoadd: ✘, randomize: ✔
+ run_flags : captive: ✔, proactive: ✔, netcheck: ✘, autoadd: ✘, randomize: ✔, eviltwin: ✘
+ ext_hooks : ntp: ✔, vpn: ✘, mail: ✔
+ last_run : 2025.12.11-09:08:24
+ system : Cudy TR3000 v1, mediatek/filogic, OpenWrt SNAPSHOT (r32287-1c7ec8ab19)
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -20,7 +20,7 @@ f_conf
while :; do
if [ "${trm_action}" = "stop" ]; then
if [ -s "${trm_pidfile}" ]; then
f_log "info" "travelmate instance stopped ::: action: ${trm_action}, pid: $(< ${trm_pidfile})"
f_log "info" "travelmate instance stopped ::: action: ${trm_action}, pid: $("${trm_catcmd}" "${trm_pidfile}")"
: >"${trm_rtfile}"
: >"${trm_pidfile}"
fi
+25 -17
View File
@@ -61,10 +61,14 @@ status_service() {
scan() {
local result radio="${1:-radio0}"
case "${radio}" in
*[!a-z0-9]*) return 1 ;;
esac
result="$(f_scan "${radio}" full)"
if [ -z "${result}" ]; then
: > "${trm_tmpfile}"
mv -f "${trm_tmpfile}" "${trm_scanfile}"
: >"${trm_tmpfile}"
mv -f "${trm_tmpfile}" "${trm_scanfile}"
return 0
fi
@@ -83,20 +87,20 @@ scan() {
sub(/[ \t]+$/, "", ssid)
printf "%3s %3s %17s %-12s %-10s %-10s %s\n",
quality, channel, bssid, rsn, cipher, auth, ssid
}' | "${trm_sortcmd}" -rn > "${trm_tmpfile}"
}' | "${trm_sortcmd}" -rn >"${trm_tmpfile}"
mv -f "${trm_tmpfile}" "${trm_scanfile}"
mv -f "${trm_tmpfile}" "${trm_scanfile}"
}
setup() {
local rc cnt net iface input="${1:-"trm_wwan"}" zone="${2:-"wan"}" metric="${3:-"100"}"
input="${input//[+*~%&\$@\"\' ]/}"
zone="${zone//[+*~%&\$@\"\' ]/}"
metric="${metric//[^0-9]/}"
input="${input//[!a-zA-Z0-9_]/}"
zone="${zone//[!a-zA-Z0-9_]/}"
metric="${metric//[!0-9]/}"
iface="$(uci_get travelmate global trm_iface)"
if [ -n "${iface}" ] && [ "${iface}" = "${input}" ]; then
if [ -z "${input}" ] || { [ -n "${iface}" ] && [ "${iface}" = "${input}" ]; }; then
return 1
fi
@@ -124,19 +128,23 @@ setup() {
fi
cnt="0"
while [ -n "$(uci_get firewall @zone[${cnt}] name)" ]; do
if [ "$(uci_get firewall @zone[${cnt}] name)" = "${zone}" ]; then
zone_name="$(uci_get firewall @zone[${cnt}] name)"
while [ -n "${zone_name}" ]; do
if [ "${zone_name}" = "${zone}" ]; then
net="$(uci_get firewall @zone[${cnt}] network)"
if ! printf "%s" "${net}" | grep -qw "${input}"; then
uci -q add_list firewall.@zone[${cnt}].network="${input}"
fi
if ! printf "%s" "${net}" | grep -qw "${input}6"; then
uci -q add_list firewall.@zone[${cnt}].network="${input}6"
fi
case " ${net} " in
*" ${input} "*) ;;
*) uci -q add_list firewall.@zone[${cnt}].network="${input}" ;;
esac
case " ${net} " in
*" ${input}6 "*) ;;
*) uci -q add_list firewall.@zone[${cnt}].network="${input}6" ;;
esac
[ -n "$(uci -q changes "firewall")" ] && uci_commit firewall
break
fi
cnt="$((cnt + 1))"
zone_name="$(uci_get firewall @zone[${cnt}] name)"
done
cnt="0"
+5 -4
View File
@@ -13,6 +13,7 @@ vpn_action="${2}"
vpn_service="${3}"
vpn_iface="${4}"
vpn_instance="${5}"
vpn_status=""
trm_funlib="/usr/lib/travelmate-functions.sh"
if [ -z "${trm_bver}" ]; then
. "${trm_funlib}"
@@ -21,7 +22,7 @@ fi
f_net() {
local json_rc
json_rc="$(${trm_fetchcmd} ${trm_fetchparm} --user-agent "${trm_useragent}" --header "Cache-Control: no-cache, no-store, must-revalidate, max-age=0" --write-out "%{response_code}" --output /dev/null "${trm_captiveurl}")"
json_rc="$("${trm_fetchcmd}" ${trm_fetchparm} --user-agent "${trm_useragent}" --header "Cache-Control: no-cache, no-store, must-revalidate, max-age=0" --write-out "%{response_code}" --output /dev/null "${trm_captiveurl}")"
if [ "${json_rc}" = "200" ] || [ "${json_rc}" = "204" ]; then
json_rc="net ok"
fi
@@ -49,7 +50,7 @@ if [ "${vpn}" = "1" ] && [ "${vpn_action%_*}" = "enable" ]; then
if ! "${trm_ubuscmd}" -t "$((trm_maxwait / 6))" wait_for network.interface."${vpn_iface}" >/dev/null 2>&1; then
f_log "info" "travelmate vpn interface '${vpn_iface}' does not appear on ubus on ifup event"
fi
cnt=0
cnt="0"
while :; do
vpn_status="$("${trm_ubuscmd}" -S call network.interface."${vpn_iface}" status 2>/dev/null | "${trm_jsoncmd}" -ql1 -e '@.up')"
if [ "${vpn_status}" = "true" ]; then
@@ -67,8 +68,8 @@ if [ "${vpn}" = "1" ] && [ "${vpn_action%_*}" = "enable" ]; then
/etc/init.d/openvpn stop "${vpn_instance}"
fi
rm -f "${trm_vpnfile}"
f_log "info" "${vpn_service} client connection can't be established '${vpn_iface}/${vpn_instance:-"-", rc: ${net_status:-"-"}}'"
return 1
f_log "info" "${vpn_service} client connection can't be established '${vpn_iface}/${vpn_instance:-"-"}, rc: ${net_status:-"-"}'"
exit 1
fi
cnt="$((cnt + 1))"
sleep 1