From 6f3af9b4b6a2891a6838c7cf0729a1ad47007f04 Mon Sep 17 00:00:00 2001 From: rubo77 Date: Thu, 14 Feb 2019 22:22:47 +0100 Subject: [PATCH] gluon-offline-ssid: add original gluon-ssid-changer package to automatically change the SSID when no Internet connection --- docs/package/gluon-ssid-changer.rst | 77 ++++++++ package/gluon-ssid-changer/Makefile | 36 ++++ package/gluon-ssid-changer/check_site.lua | 9 + .../files/etc/config/ssid-changer | 1 + .../files/usr/lib/micron.d/ssid-changer | 1 + package/gluon-ssid-changer/gluonShellDiet.sh | 5 + package/gluon-ssid-changer/i18n/de.po | 26 +++ .../i18n/gluon-ssid-changer.pot | 10 + .../controller/admin/ssid-changer.lua | 1 + .../config-mode/model/admin/ssid-changer.lua | 28 +++ .../luasrc/lib/gluon/upgrade/500-ssid-changer | 21 ++ .../gluon-ssid-changer/shsrc/ssid-changer.sh | 180 ++++++++++++++++++ 12 files changed, 395 insertions(+) create mode 100644 docs/package/gluon-ssid-changer.rst create mode 100644 package/gluon-ssid-changer/Makefile create mode 100644 package/gluon-ssid-changer/check_site.lua create mode 100644 package/gluon-ssid-changer/files/etc/config/ssid-changer create mode 100644 package/gluon-ssid-changer/files/usr/lib/micron.d/ssid-changer create mode 100755 package/gluon-ssid-changer/gluonShellDiet.sh create mode 100644 package/gluon-ssid-changer/i18n/de.po create mode 100644 package/gluon-ssid-changer/i18n/gluon-ssid-changer.pot create mode 100644 package/gluon-ssid-changer/luasrc/lib/gluon/config-mode/controller/admin/ssid-changer.lua create mode 100644 package/gluon-ssid-changer/luasrc/lib/gluon/config-mode/model/admin/ssid-changer.lua create mode 100755 package/gluon-ssid-changer/luasrc/lib/gluon/upgrade/500-ssid-changer create mode 100755 package/gluon-ssid-changer/shsrc/ssid-changer.sh diff --git a/docs/package/gluon-ssid-changer.rst b/docs/package/gluon-ssid-changer.rst new file mode 100644 index 00000000..10dc7a6d --- /dev/null +++ b/docs/package/gluon-ssid-changer.rst @@ -0,0 +1,77 @@ +gluon-ssid-changer +================== + +This package adds a script to change the SSID when there is no connection to any +gateway. This Offline-SSID can be generated from the node's hostname with the +first and last part of the node name or the MAC address allowing observers to +recognize which node does not have a connection to a gateway. This script is +called once every minute by ``micron.d`` and check gateway-connectivity. It will +change the SSID to the Offline-SSID after the node lost gateway connectivity for +several consecutive checks. As soon as the gateway-connectivity is back it +toggles back to the original SSID. + +You can enable/disable it in the config mode. + +It checks if a gateway is reachable in an interval. Different algorithms can be +selected to determine whether a gateway is reachable: + +- ``tq_limit_enabled=true``: (not working with BATMAN\_V) define an upper and + lower bound to toggle the SSID. As long as the TQ stays in-between those + bounds the SSID will not be changed. +- ``tq_limit_enabled=false``: there will be only checked, if the gateway is + reachable with: + + :: + + batctl gwl -H + +The SSID is always changed back to normal every minute as soon as the +gateway-connectivity is back, The parameter ``switch_timeframe`` defines how +long it will record the gateway-connectivity. **Only** if the gateway is not +reachable during at least half the checks within ``switch_timeframe`` minutes, +the SSID will be changed to "FF\_Offline\_$node\_hostname". + +The parameter ``first`` defines a learning phase after reboot (in minutes) +during which the SSID may be changed to the Offline-SSID **every minute**. + +site.conf +========= + +Adapt and add this block to your ``site.conf``: + +:: + + ssid_changer = { + enabled = true, + switch_timeframe = 30, -- only once every timeframe (in minutes) the SSID will change to the Offline-SSID + -- set to 1440 to change once a day + -- set to 1 minute to change every time the router gets offline + first = 5, -- the first few minutes directly after reboot within which an Offline-SSID may be + -- activated every minute (must be <= switch_timeframe) + prefix = 'FF_Offline_', -- use something short to leave space for the nodename (no '~' allowed!) + suffix = 'nodename', -- generate the SSID with either 'nodename', 'mac' or to use only the prefix: 'none' + + tq_limit_enabled = false, -- if false, the offline SSID will only be set if there is no gateway reacheable + -- upper and lower limit to turn the offline_ssid on and off + -- in-between these two values the SSID will never be changed to prevent it from + -- toggeling every minute. + tq_limit_max = 45, -- upper limit, above that the online SSID will be used + tq_limit_min = 35 -- lower limit, below that the offline SSID will be used + }, + +Commandline options +=================== + +You can configure the ssid-changer on the commandline with ``uci``, for example +disable it with: + +:: + + uci set ssid-changer.settings.enabled='0' + +Or set the timeframe to every three minutes with + +:: + + uci set ssid-changer.settings.switch_timeframe='3' + uci set ssid-changer.settings.first='3' diff --git a/package/gluon-ssid-changer/Makefile b/package/gluon-ssid-changer/Makefile new file mode 100644 index 00000000..bda435e1 --- /dev/null +++ b/package/gluon-ssid-changer/Makefile @@ -0,0 +1,36 @@ +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-ssid-changer +PKG_VERSION:=5 + +include $(TOPDIR)/../package/gluon.mk + +define Package/$(PKG_NAME) + TITLE:=changes the SSID to an Offline-SSID so clients don't connect to an offline WiFi + DEPENDS:=+gluon-core +micrond +endef + +define Package/$(PKG_NAME)/description + Script to change the SSID to an Offline-SSID when there is no connection to + any gateway. This SSID can be generated from the node's hostname with the + first and last part of the nodename or the mac address, to allow observers to + recognise which node is down. The script is called once a minute by micrond + and it will change from online to Offline-SSID once per definable timeframe at + most. +endef + + +define Build/Compile + $(call Gluon/Build/Compile) + ./gluonShellDiet.sh shsrc/ssid-changer.sh > $(PKG_BUILD_DIR)/ssid-changer.sh +endef + +define Package/$(PKG_NAME)/install + $(Gluon/Build/Install) + + $(INSTALL_DIR) $(1)/lib/gluon/ssid-changer + $(INSTALL_BIN) $(PKG_BUILD_DIR)/ssid-changer.sh $(1)/lib/gluon/ssid-changer/ +endef + + +$(eval $(call BuildPackageGluon,$(PKG_NAME))) diff --git a/package/gluon-ssid-changer/check_site.lua b/package/gluon-ssid-changer/check_site.lua new file mode 100644 index 00000000..ab4c2a62 --- /dev/null +++ b/package/gluon-ssid-changer/check_site.lua @@ -0,0 +1,9 @@ +need_boolean({'ssid_changer', 'enabled'}, false) +need_number({'ssid_changer', 'switch_timeframe'}, false) +need_number({'ssid_changer', 'first'}, false) +need_string({'ssid_changer', 'prefix'}, false) +need_one_of({'ssid_changer', 'suffix'}, {'nodename', 'mac', 'none'}, false) +if need_boolean({'ssid_changer','tq_limit_enabled'}, false) then + need_number({'ssid_changer', 'tq_limit_max'}, false) + need_number({'ssid_changer', 'tq_limit_min'}, false) +end diff --git a/package/gluon-ssid-changer/files/etc/config/ssid-changer b/package/gluon-ssid-changer/files/etc/config/ssid-changer new file mode 100644 index 00000000..c488b640 --- /dev/null +++ b/package/gluon-ssid-changer/files/etc/config/ssid-changer @@ -0,0 +1 @@ +config settings 'settings' diff --git a/package/gluon-ssid-changer/files/usr/lib/micron.d/ssid-changer b/package/gluon-ssid-changer/files/usr/lib/micron.d/ssid-changer new file mode 100644 index 00000000..e3a99fa4 --- /dev/null +++ b/package/gluon-ssid-changer/files/usr/lib/micron.d/ssid-changer @@ -0,0 +1 @@ +* * * * * /lib/gluon/ssid-changer/ssid-changer.sh diff --git a/package/gluon-ssid-changer/gluonShellDiet.sh b/package/gluon-ssid-changer/gluonShellDiet.sh new file mode 100755 index 00000000..1cb74ad6 --- /dev/null +++ b/package/gluon-ssid-changer/gluonShellDiet.sh @@ -0,0 +1,5 @@ +#!/bin/sh + +# This script requires a file as argument in which it will remove all comment lines that start with a hash '#' + +sed '/^\s*\#[^!].*/d; /^\s*\#$/d' $1 diff --git a/package/gluon-ssid-changer/i18n/de.po b/package/gluon-ssid-changer/i18n/de.po new file mode 100644 index 00000000..cc198764 --- /dev/null +++ b/package/gluon-ssid-changer/i18n/de.po @@ -0,0 +1,26 @@ +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"PO-Revision-Date: 2018-07-29 15:26+0200\n" +"Last-Translator: \n" +"Language-Team: German\n" +"Language: de\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +msgid "Enabled" +msgstr "Aktiviert" + +msgid "" +"Here you can enable to automatically change the SSID to the Offline-SSID " +"when the node has no connection to the selected Gateway." +msgstr "" +"Hier kannst du aktivieren, dass dein Knoten automatisch die SSID auf die " +"Offline-SSID ändert, wenn keine Verbindung zu Freifunk Servern besteht.

" +"Das verhindert, dass Client-Geräte sich mit einem Knoten verbinden, an dem es " +"derzeit keine nutzbare Interverbindung gibt.
" +"Wenn in dieser Firmware der Suffix auf 'nodename' gestellt ist, dann kann man " +"leichter anhand der dann gesendeten Offline-SSID nach einem fehlerhaften Gerät " +"suchen." diff --git a/package/gluon-ssid-changer/i18n/gluon-ssid-changer.pot b/package/gluon-ssid-changer/i18n/gluon-ssid-changer.pot new file mode 100644 index 00000000..16db87db --- /dev/null +++ b/package/gluon-ssid-changer/i18n/gluon-ssid-changer.pot @@ -0,0 +1,10 @@ +msgid "" +msgstr "Content-Type: text/plain; charset=UTF-8" + +msgid "Enabled" +msgstr "" + +msgid "" +"Here you can enable to automatically change the SSID to the Offline-SSID " +"when the node has no connection to the selected Gateway." +msgstr "" diff --git a/package/gluon-ssid-changer/luasrc/lib/gluon/config-mode/controller/admin/ssid-changer.lua b/package/gluon-ssid-changer/luasrc/lib/gluon/config-mode/controller/admin/ssid-changer.lua new file mode 100644 index 00000000..d84d3cef --- /dev/null +++ b/package/gluon-ssid-changer/luasrc/lib/gluon/config-mode/controller/admin/ssid-changer.lua @@ -0,0 +1 @@ +entry({"admin", "ssid-changer"}, model("admin/ssid-changer"), _("Offline-SSID"), 35) diff --git a/package/gluon-ssid-changer/luasrc/lib/gluon/config-mode/model/admin/ssid-changer.lua b/package/gluon-ssid-changer/luasrc/lib/gluon/config-mode/model/admin/ssid-changer.lua new file mode 100644 index 00000000..282164c1 --- /dev/null +++ b/package/gluon-ssid-changer/luasrc/lib/gluon/config-mode/model/admin/ssid-changer.lua @@ -0,0 +1,28 @@ +local uci = require('simple-uci').cursor() +local util = require 'gluon.util' + +local pkg_i18n = i18n 'gluon-ssid-changer' + +local f = Form(pkg_i18n.translate('Offline-SSID')) + +local s = f:section(Section, nil, pkg_i18n.translate( + 'Here you can enable to automatically change the SSID to the Offline-SSID ' + .. 'when the node has no connection to the selected Gateway.' +)) + +local enabled = s:option(Flag, 'enabled', pkg_i18n.translate('Enabled')) +enabled.default = uci:get_bool('ssid-changer', 'settings', 'enabled') + +function f:write() + if enabled.data then + uci:section('ssid-changer', 'settings', 'settings', { + enabled = '1' + }) + else + uci:set('ssid-changer', 'settings', 'enabled', '0') + end + + uci:commit('ssid-changer') +end + +return f diff --git a/package/gluon-ssid-changer/luasrc/lib/gluon/upgrade/500-ssid-changer b/package/gluon-ssid-changer/luasrc/lib/gluon/upgrade/500-ssid-changer new file mode 100755 index 00000000..34db9649 --- /dev/null +++ b/package/gluon-ssid-changer/luasrc/lib/gluon/upgrade/500-ssid-changer @@ -0,0 +1,21 @@ +#!/usr/bin/lua + +local site = require 'gluon.site' + +local uci = require('simple-uci').cursor() + +if site.ssid_changer ~= nil then + local site_enabled = site.ssid_changer.enabled() or '1' + + uci:section('ssid-changer', 'settings', 'settings', { + enabled = uci:get('ssid-changer', 'settings', 'enabled') or site_enabled, + switch_timeframe = site.ssid_changer.switch_timeframe() or '30', + first = site.ssid_changer.first() or '5', + prefix = site.ssid_changer.prefix() or 'FF_Offline_', + suffix = site.ssid_changer.suffix() or 'nodename', + tq_limit_enabled = site.ssid_changer.tq_limit_enabled() or false, + tq_limit_max = site.ssid_changer.tq_limit_max() or 45, + tq_limit_min = site.ssid_changer.tq_limit_min() or 35, + }) + uci:save('ssid-changer') +end diff --git a/package/gluon-ssid-changer/shsrc/ssid-changer.sh b/package/gluon-ssid-changer/shsrc/ssid-changer.sh new file mode 100755 index 00000000..cf0f73dd --- /dev/null +++ b/package/gluon-ssid-changer/shsrc/ssid-changer.sh @@ -0,0 +1,180 @@ +#!/bin/sh + +################# +# safety checks # +################# +safety_exit() { + echo $1, exiting with error code 2 + exit 2 +} +pgrep -f autoupdater >/dev/null && safety_exit 'autoupdater running' +UT=$(sed 's/\..*//g' /proc/uptime) +[ $UT -gt 60 ] || safety_exit 'less than one minute' +[ $(find /var/run -name hostapd-phy* | wc -l) -gt 0 ] || safety_exit 'no hostapd-phy*' + +# only once every timeframe minutes the SSID will change to the Offline-SSID +# (set to 1 minute to change immediately every time the router gets offline) +MINUTES="$(uci -q get ssid-changer.settings.switch_timeframe)" +: ${MINUTES:=30} + +# the first few minutes directly after reboot within which an Offline-SSID always may be activated +# (must be <= switch_timeframe) +FIRST="$(uci -q get ssid-changer.settings.first)" +: ${FIRST:=5} + +# the Offline-SSID will start with this prefix use something short to leave space for the nodename +# (no '~' allowed!) +PREFIX="$(uci -q get ssid-changer.settings.prefix)" +: ${PREFIX:='FF_Offline_'} + +if [ "$(uci -q get ssid-changer.settings.enabled)" = '0' ]; then + DISABLED='1' +else + DISABLED='0' +fi + +# generate the ssid with either 'nodename', 'mac' or to use only the prefix set to 'none' +SETTINGS_SUFFIX="$(uci -q get ssid-changer.settings.suffix)" +: ${SETTINGS_SUFFIX:='nodename'} + +if [ $SETTINGS_SUFFIX = 'nodename' ]; then + SUFFIX="$(uname -n)" + # 32 would be possible as well + if [ ${#SUFFIX} -gt $((30 - ${#PREFIX})) ]; then + # calculate the length of the first part of the node identifier in the offline-ssid + HALF=$(( (28 - ${#PREFIX} ) / 2 )) + # jump to this charakter for the last part of the name + SKIP=$(( ${#SUFFIX} - $HALF )) + # use the first and last part of the nodename for nodes with long name + SUFFIX=${SUFFIX:0:$HALF}...${SUFFIX:$SKIP:${#SUFFIX}} + fi +elif [ $SETTINGS_SUFFIX = 'mac' ]; then + SUFFIX="$(uci -q get network.bat0.macaddr | /bin/sed 's/://g')" +else + # 'none' + SUFFIX='' +fi + +OFFLINE_SSID="$PREFIX$SUFFIX" + +# get all SSIDs (replace \' with TICX and back to keep a possible tic in an SSID) +ONLINE_SSIDs="$(uci show | grep wireless.client_radio[0-9]\. | grep ssid | awk -F '=' '{print $2}' | sed "s/\\\'/TICX/g" | tr \' \~ | sed "s/TICX/\\\'/g" ) " +# if for whatever reason ONLINE_SSIDs is NULL: +: ${ONLINE_SSIDs:="~FREIFUNK~"} + +# temp file to count the offline incidents during switch_timeframe +TMP=/tmp/ssid-changer-count +if [ ! -f $TMP ]; then echo "0">$TMP; fi +OFF_COUNT=$(cat $TMP) + +TQ_LIMIT_ENABLED="$(uci -q get ssid-changer.settings.tq_limit_enabled)" +# if true, the offline ssid will only be set if there is no gateway reacheable +# upper and lower limit to turn the offline_ssid on and off +# in-between these two values the SSID will never be changed to preven it from toggeling every Minute. +: ${TQ_LIMIT_ENABLED:='0'} + +if [ $TQ_LIMIT_ENABLED = 1 ]; then + TQ_LIMIT_MAX="$(uci -q get ssid-changer.settings.tq_limit_max)" + # upper limit, above that the online SSID will be used + : ${TQ_LIMIT_MAX:='45'} + TQ_LIMIT_MIN="$(uci -q get ssid-changer.settings.tq_limit_min)" + # lower limit, below that the offline SSID will be used + : ${TQ_LIMIT_MIN:='35'} + # grep the connection quality of the currently used gateway + GATEWAY_TQ=$(batctl gwl | grep -e "^=>" -e "^\*" | awk -F '[('')]' '{print $2}' | tr -d " ") + if [ ! $GATEWAY_TQ ]; then + # there is no gateway + GATEWAY_TQ=0 + fi + + MSG="TQ is $GATEWAY_TQ, " + + if [ $GATEWAY_TQ -ge $TQ_LIMIT_MAX ]; then + CHECK=1 + elif [ $GATEWAY_TQ -lt $TQ_LIMIT_MIN ]; then + CHECK=0 + else + # this is just get a clean run if we are in-between the grace periode + echo "TQ is $GATEWAY_TQ, do nothing" + exit 0 + fi +else + MSG="" + CHECK="$(batctl gwl -H|grep -v "gateways in range"|wc -l)" +fi + +UP=$(($UT / 60)) +M=$(($UP % $MINUTES)) + +HUP_NEEDED=0 +if [ "$CHECK" -gt 0 ] || [ "$DISABLED" = '1' ]; then + echo "node is online" + LOOP=1 + # check status for all physical devices + for HOSTAPD in $(ls /var/run/hostapd-phy*); do + ONLINE_SSID="$(echo $ONLINE_SSIDs | awk -F '~' -v l=$((LOOP*2)) '{print $l}')" + LOOP=$((LOOP+1)) + CURRENT_SSID="$(grep "^ssid=$ONLINE_SSID" $HOSTAPD | cut -d"=" -f2)" + if [ "$CURRENT_SSID" = "$ONLINE_SSID" ]; then + echo "SSID $CURRENT_SSID is correct, nothing to do" + break + fi + CURRENT_SSID="$(grep "^ssid=$OFFLINE_SSID" $HOSTAPD | cut -d"=" -f2)" + if [ "$CURRENT_SSID" = "$OFFLINE_SSID" ]; then + # set online + logger -s -t "gluon-ssid-changer" -p 5 $MSG"SSID is $CURRENT_SSID, change to $ONLINE_SSID" + sed -i "s~^ssid=$CURRENT_SSID~ssid=$ONLINE_SSID~" $HOSTAPD + # HUP here would be to early for dualband devices + HUP_NEEDED=1 + else + logger -s -t "gluon-ssid-changer" -p 5 "could not set to online state: did neither find SSID '$ONLINE_SSID' nor '$OFFLINE_SSID'. Please reboot" + fi + done +elif [ "$CHECK" -eq 0 ]; then + echo "node is considered offline" + if [ $UP -lt $FIRST ] || [ $M -eq 0 ]; then + # set SSID offline, only if uptime is less than FIRST or exactly a multiplicative of switch_timeframe + if [ $UP -lt $FIRST ]; then + T=$FIRST + else + T=$MINUTES + fi + #echo minute $M, check if $OFF_COUNT is more than half of $T + if [ $OFF_COUNT -ge $(($T / 2)) ]; then + # node was offline more times than half of switch_timeframe (or than $FIRST) + LOOP=1 + for HOSTAPD in $(ls /var/run/hostapd-phy*); do + ONLINE_SSID="$(echo $ONLINE_SSIDs | awk -F '~' -v l=$((LOOP*2)) '{print $l}')" + LOOP=$((LOOP+1)) + CURRENT_SSID="$(grep "^ssid=$OFFLINE_SSID" $HOSTAPD | cut -d"=" -f2)" + if [ "$CURRENT_SSID" = "$OFFLINE_SSID" ]; then + echo "SSID $CURRENT_SSID is correct, nothing to do" + break + fi + CURRENT_SSID="$(grep "^ssid=$ONLINE_SSID" $HOSTAPD | cut -d"=" -f2)" + if [ "$CURRENT_SSID" = "$ONLINE_SSID" ]; then + # set offline + logger -s -t "gluon-ssid-changer" -p 5 $MSG"$OFF_COUNT times offline, SSID is $CURRENT_SSID, change to $OFFLINE_SSID" + sed -i "s~^ssid=$ONLINE_SSID~ssid=$OFFLINE_SSID~" $HOSTAPD + HUP_NEEDED=1 + else + logger -s -t "gluon-ssid-changer" -p 5 "could not set to offline state: did neither find SSID '$ONLINE_SSID' nor '$OFFLINE_SSID'. Please reboot" + fi + done + fi + #else echo minute $M, just count $OFF_COUNT + fi + echo "$(($OFF_COUNT + 1))">$TMP +fi + +if [ $HUP_NEEDED = 1 ]; then + # send HUP to all hostapd to load the new SSID + killall -HUP hostapd + HUP_NEEDED=0 + echo "HUP!" +fi + +if [ $M -eq 0 ]; then + # set counter to 0 if the timeframe is over + echo "0">$TMP +fi