Commit c1488f91 authored by chrissi^'s avatar chrissi^

Add autoupdater-fallback-package

The autoupdater-fallback-package is used to recover nodes that have lost
their uplink. If the loss of uplink is caused by a new configuration
(e.g. changed mesh-config) a recovery as WiFi client can be useful.

This change adds a fork of the Freifunk Hochstift
autoupdater-fallback-package and ports it forward to Gluon v2018.2.
Signed-off-by: chrissi^'s avatarChrissi^ <chris@tinyhost.de>
parent b19f4a06
include $(TOPDIR)/rules.mk
PKG_NAME:=gluon-ffbs-autoupdater-wifi-fallback
PKG_VERSION:=1
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
include $(INCLUDE_DIR)/package.mk
define Package/gluon-ffbs-autoupdater-wifi-fallback
SECTION:=gluon
CATEGORY:=Gluon
TITLE:=Implements switching to fallback mode if we are cut off from the mesh
DEPENDS:=+gluon-autoupdater +libiwinfo-lua +iw
endef
define Package/gluon-fffd-autokey/description
fastd automatic key upload:
this package makes use of an on-up-script for fastd
to upload the public key of fastd to a web application
endef
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
endef
define Build/Configure
endef
define Build/Compile
endef
define Package/gluon-ffbs-autoupdater-wifi-fallback/install
$(CP) ./files/* $(1)/
$(CP) ./luasrc/* $(1)/
endef
$(eval $(call BuildPackage,gluon-ffbs-autoupdater-wifi-fallback))
gluon-ffbs-autoupdater-fallback
===============================
If a node has no connection to the mesh, neither via wlan-mesh nor via
mesh-vpn, it ist not possible to update this node via `autoupdater`. Therefor
the *wifi-fallback* was developed. It checks hourly whether the node is part of
a fully operative mesh or not. Else the node connects to a visible "Freifunknetz"
and tries downloads an update as wlan-client via executing `autoupdater -f`.
Actually this needs `iw connect` patched into `iw`.
This patch is included in our site.
#config autoupdater-wifi-fallback settings
# option enabled 1
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
local autil = require 'autoupdater-wifi-fallback.util'
local enabled
if uci:get('autoupdater-wifi-fallback', 'settings') then
enabled = uci:get_bool('autoupdater-wifi-fallback', 'settings', 'enabled')
uci:delete('autoupdater-wifi-fallback', 'settings')
else
enabled = uci:get_bool('autoupdater', 'settings', 'enabled')
end
uci:section('autoupdater-wifi-fallback', 'autoupdater-wifi-fallback', 'settings',{
enabled = enabled,
})
uci:delete('wireless', 'fallback')
uci:delete('network', 'fallback')
uci:delete('network', 'fallback6')
uci:section('network', 'interface', 'fallback',{
proto = 'dhcp',
peerdns = true,
sourcefilter = false,
})
uci:section('network', 'interface', 'fallback6',{
ifname = '@fallback',
proto = 'dhcpv6',
peerdns = true,
sourcefilter = false,
})
uci:save('autoupdater-wifi-fallback')
uci:save('network')
uci:save('wireless')
local minute = tonumber(autil.read_file('/usr/lib/micron.d/autoupdater'):match('^([0-9][0-9]?)%s'))
minute = (minute + 10) % 60
local f = io.open('/usr/lib/micron.d/autoupdater-wifi-fallback', 'w')
f:write(string.format('%i * * * * /usr/sbin/autoupdater-wifi-fallback\n', minute))
f:close()
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
local iwinfo = require 'iwinfo'
util = {}
function util.get_available_wifi_networks()
local radios = {}
uci:foreach('wireless', 'wifi-device',
function(s)
radios[s['.name']] = {}
end
)
for radio, _ in pairs(radios) do
local wifitype = iwinfo.type(radio)
local iw = iwinfo[wifitype]
if not iw then
return null
end
local tmplist = iw.scanlist(radio)
for _, net in ipairs(tmplist) do
if net.ssid and net.bssid and net.ssid:match('.*[Ff][Rr][Ee][Ii][Ff][Uu][Nn][Kk].*') then
table.insert (radios[radio], net)
end
end
end
return radios
end
function util.get_update_hosts(branch)
local hosts = {}
local mirrors = uci:get_list('autoupdater', branch, 'mirror')
for _, mirror in ipairs(mirrors) do
local host = mirror:match('://%[?([a-zA-Z0-9\:\.-]+)%]?/')
table.insert(hosts, 1, host)
end
return hosts
end
function util.read_file(path)
local file = io.open(path, "rb") -- r read mode and b binary mode
if not file then return nil end
local content = file:read "*a" -- *a or *all reads the whole file
file:close()
return content
end
return util
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
local autil = require 'autoupdater-wifi-fallback.util'
local util = require 'gluon.util'
local configname = 'autoupdater-wifi-fallback'
local force = false
local min_uptime_secs = 3600
local branch_name = uci:get('autoupdater', 'settings', 'branch')
local function parse_args()
local i = 1
while arg[i] do
if arg[i] == '-f' then
force = true
elseif arg[i] == '-b' then
i=i+1
if not arg[i] then
io.stderr:write('Error parsing command line: expected branch name\n')
os.exit(1)
end
branch_name = arg[i]
else
io.stderr:write("Error parsing command line: unexpected argument '" .. arg[i] .. "'\n")
os.exit(1)
end
i = i+1
end
end
local function preflight_check()
if not uci:get_bool(configname, 'settings', 'enabled') then
return false
end
if not uci:get_bool('autoupdater', 'settings', 'enabled') then
return false
end
if tonumber(autil.read_file('/proc/uptime'):match('^([^ ]+) ')) < min_uptime_secs then
return false
end
return true
end
local function connectivity_check()
-- connectivity check against updateserver
for _, host in ipairs(autil.get_update_hosts(branch_name)) do
if os.execute('ping -w2 -c1 ' .. host .. ' > /dev/null 2>&1') == 0 then
return true
end
end
io.popen('logger -s -t autoupdater-wifi-fallback -p local0.info "connectivity check failed"')
return false
end
local function run_autoupdater()
io.popen('logger -s -t autoupdater-wifi-fallback -p local0.info "execute the autoupdater"')
os.execute('/usr/sbin/autoupdater -f -b ' .. branch_name)
end
local function switch_to_fallback_mode(radio, ssid, bssid)
io.popen('logger -s -t autoupdater-wifi-fallback -p local0.info "connect to ' .. radio .. ' ' .. ssid .. ' ' .. bssid .. '"')
uci:delete_all('wireless', 'wifi-iface')
uci:section('wireless', 'wifi-iface', 'fallback', {
device = radio,
network = 'fallback',
mode = 'sta',
disabled = false,
macaddr = util.generate_mac(3, 10),
bssid = bssid,
ssid = ssid,
ifname = 'fallback',
encryption = 'none',
})
uci:set('wireless', radio, 'disabled', false)
uci:save('wireless')
os.execute('wifi')
os.execute('sleep 5')
uci:revert('wireless')
os.execute('sleep 20')
os.execute('ip r del 10.38.0.0/16 dev br-client')
os.execute('ip r del 10.38.0.0/16 dev local-node')
os.execute('ip l set dev br-client down')
end
local function revert_to_standard_mode()
io.popen('logger -s -t autoupdater-wifi-fallback -p local0.info "going back to standard mode"')
os.execute('ip r add 10.38.0.0/16 dev br-client')
os.execute('ip r add 10.38.0.0/16 dev local-node')
os.execute('ip l set dev br-client up')
os.execute('/etc/init.d/network restart')
os.execute('sleep 30')
end
parse_args()
if not uci:get('autoupdater', branch_name) then
io.stderr:write("Can't find configuration for branch '" .. branch_name .. "'\n")
os.exit(1)
end
if (force or preflight_check()) and not connectivity_check() then
local offset = 2 * 3600
local unreachable_since = os.time()
if not uci:get('autoupdater-wifi-fallback', 'settings', 'unreachable_since') then
uci:set(configname, 'settings', 'unreachable_since', unreachable_since)
else
uci:set(configname, 'settings', 'last_run', unreachable_since)
unreachable_since = uci:get(configname, 'settings', 'unreachable_since')
end
uci:save(configname)
if force or tonumber(unreachable_since) + offset < os.time() then
io.popen('logger -s -t autoupdater-wifi-fallback -p local0.info "going to fallback mode"')
for radio, netlist in pairs(autil.get_available_wifi_networks()) do
for _, net in ipairs(netlist) do
switch_to_fallback_mode(radio, net.ssid, net.bssid)
if run_autoupdater() == 0 then
break
end
end
end
-- this is only reached if no updated happened
revert_to_standard_mode()
end
else
uci:delete(configname, 'settings', 'unreachable_since')
uci:delete(configname, 'settings', 'last_run')
uci:save(configname)
end
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
local ifnames = {}
uci:foreach('wireless', 'wifi-iface',
function(s)
table.insert(ifnames, s['.name'])
end
)
for _, ifname in ipairs(ifnames) do
local iface = uci:get_all('wireless', ifname)
if not uci:get_bool('wireless', ifname, 'disabled') and iface.mode == 'sta' and iface.ifname and iface.device and iface.ssid then
local command = 'iw dev ' .. iface.ifname .. ' connect -w ' .. iface.ssid
if iface.bssid then
command = command .. ' ' .. iface.bssid
end
os.execute(command)
end
end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment