diff --git a/hoodselector/README.md b/hoodselector/README.md new file mode 100644 index 0000000000000000000000000000000000000000..193c1c1eb7d7b9984e4aafe578b8046dd184d84a --- /dev/null +++ b/hoodselector/README.md @@ -0,0 +1,18 @@ +# Hoodselector + +## Command Line Options + +### Enable the Hoodselector +``` +hoodselector enable +``` + +### Disable the Hoodselector +``` +hoodselector disable +``` +### Print Hoodfile Path +``` +hoodselector hoodfile +``` + diff --git a/hoodselector/files/etc/config/hoodselector b/hoodselector/files/etc/config/hoodselector new file mode 100644 index 0000000000000000000000000000000000000000..6f735b57adb56d3f964a381cc01e88f2cb26a264 --- /dev/null +++ b/hoodselector/files/etc/config/hoodselector @@ -0,0 +1,4 @@ +config settings 'hoodselector' + option hoodfile '/lib/ffnw/hoods/hoods.json' + option static '0' + option enabled '1' \ No newline at end of file diff --git a/hoodselector/luasrc/lib/gluon/upgrade/540-ffnw-hoodselector b/hoodselector/luasrc/lib/gluon/upgrade/540-ffnw-hoodselector new file mode 100755 index 0000000000000000000000000000000000000000..f7426b30b754204ac9710ac4ad9e11d7ae3b571a --- /dev/null +++ b/hoodselector/luasrc/lib/gluon/upgrade/540-ffnw-hoodselector @@ -0,0 +1,161 @@ +#!/usr/bin/lua + +local json = require ("luci.jsonc") +local uci = require('luci.model.uci').cursor() + +-- Read the full hoodfile. Return nil for wrong format or no such file +local function readHoodfile(file) + local jhood = io.open(file, 'r') + if not jhood then return nil end + local obj, _, err = json.parse (jhood:read('*a'), 1, nil) + if err then + return nil + else + return obj + end +end + +local function vpn_reconfigure(hood_serverlist,local_serverlist) + -- remove all servers + for config_index, _ in pairs(local_serverlist) do + uci:delete('fastd',config_index) + end + + -- add servers from hoodfile + local group = 'mesh_vpn_backbone' + for _,hood_server in pairs(hood_serverlist) do + uci:section('fastd', 'peer', group .. '_peer_' .. hood_server.host:split('.')[1]:gsub("%-", "%_") .. "_" .. hood_server.port, + { + enabled = 1, + net = 'mesh_vpn', + group = group, + key = hood_server.publickey, + remote = {'\"'..hood_server.host..'\"'..' port '..hood_server.port} + } + ) + end + + uci:save('fastd') +end + +-- Reconfigure wireless +local function wireless_reconfigure(radios, hood_bssid) + for _, radio in ipairs(radios) do + if not ( uci:get('wireless', 'ibss_' .. radio, 'bssid') == hood_bssid ) then + uci:section('wireless', 'wifi-iface', 'ibss_' .. radio, { + bssid = hood_bssid + }) + end + end + uci:save('wireless') +end + +-- Retun a table of current peers from /etc/config/fastd +local function getCurrentPeers() + local configPeers = {} + local err = uci:foreach('fastd', 'peer', + function(s) + if s['.name'] then + for prefix,peer in pairs(s) do + local tmpPeer = {} + if prefix:match(".name") then + if peer:match("mesh_vpn_backbone_peer_") then + -- val tmpRemote does not need uci exception check because its already include by "uci:foreach" + local tmpRemote = uci:get('fastd', peer, 'remote') + tmpRemote = tmpRemote[1]:split(" ") + local remote = {} + remote['host'] = tmpRemote[1] + remote[tmpRemote[2]] = tmpRemote[3] + -- uci:get does not need uci exception check because its already include by "uci:foreach" + tmpPeer['key'] = tostring(uci:get('fastd', peer, 'key')) + tmpPeer['remote'] = remote + configPeers[peer] = tmpPeer + end + end + end + end + end + ) + if not err then + os.exit(1) + end + return configPeers +end + +local function getHoodByName(jhood,hoodname) + for _, h in pairs(jhood) do + if h.name == hoodname then + return h + end + end + return nil +end + +-- Get a list of wifi devices return an emty table for no divices +local function getWifiDevices() + local radios = {} + uci:foreach('wireless', 'wifi-device', + function(s) + table.insert(radios, s['.name']) + end + ) + return radios +end + +local function getDefaultHood(jhood) + for _, h in pairs(jhood) do + if h.defaulthood then + return h + end + end + return nil +end + +-- START HERE + +local hoodfile = uci:get('hoodselector', 'hoodselector', 'hoodfile') +local hoodname = uci:get('hoodselector', 'hoodselector', 'hood') +local static = uci:get('hoodselector', 'hoodselector', 'static') +local enabled = uci:get('hoodselector', 'hoodselector', 'enabled') + +if hoodfile == nil then + os.exit(1) +end + +if static == nil then + static = '0' +end + +if enabled == nil then + enabled = '1' +end + +local jhood = readHoodfile(hoodfile) +if jhood == nil then + enabled = 0 +end + +if hoodname == nil then + if jhood ~= nil then + hoodname = (getDefaultHood(jhood)).name + end +end + +uci:section('hoodselector', 'settings', 'hoodselector', { + hood = hoodname, + hoodfile = hoodfile, + static = static, + enabled = enabled +}) +uci:save('hoodselector') + +local hood = getHoodByName(jhood,hoodname) +if hood == nil then + os.exit(1) +end + +local radios = getWifiDevices() +vpn_reconfigure(hood["servers"],getCurrentPeers()) +if radios ~= nil then + wireless_reconfigure(radios, hood["bssid"]) +end \ No newline at end of file diff --git a/hoodselector/luasrc/usr/sbin/hoodselector b/hoodselector/luasrc/usr/sbin/hoodselector index 21b6f3498d484f5a01e855c339593d66950e2fde..9822ad9d2c1aa36a34792894fd6ddaab4fcf53c6 100755 --- a/hoodselector/luasrc/usr/sbin/hoodselector +++ b/hoodselector/luasrc/usr/sbin/hoodselector @@ -58,6 +58,42 @@ local function log(msg) end end +if arg[1] ~= nil then + if arg[1] == 'enable' then + io.stderr:write("Hoodselector enabled\n") + uci:set('hoodselector', 'hoodselector', 'enabled' , 1) + uci:save('hoodselector') + uci:commit('hoodselector') + elseif arg[1] == 'disable' then + io.stderr:write('Hoodselector disabled\n') + uci:set('hoodselector', 'hoodselector', 'enabled' , 0) + uci:save('hoodselector') + uci:commit('hoodselector') + elseif arg[1] == 'hoodfile' then + if uci:get('hoodselector', 'hoodselector', 'hoodfile') == nil then + io.stderr:write("Hoodfile Path not in Config\n") + else + io.stderr:write("Hoodfile Path: " .. uci:get('hoodselector', 'hoodselector', 'hoodfile') .. "\n") + end + else + io.stderr:write( + "Hoodselector usage: \n\n" + .. "hoodselector \t\t runs the Hoodselector\n" + .. "hoodselector enable \t enable the Hoodselector\n" + .. "hoodselector disable \t disable the Hoodselector\n" + .. "hoodselector hoodfile \t shows the path of the Hoodfile\n") + end + os.exit(0) +end + +local hoodselectorenabled = uci:get('hoodselector', 'hoodselector', 'enabled') + +if hoodselectorenabled == '0' then + io.stderr:write("Hoodselector is disabled by UCI\n") + os.exit(0) +end + + if io.open(pidPath, "r") ~=nil then log("The hoodselector is still running.") os.exit(1) @@ -68,7 +104,15 @@ else end end -local FILE = '/lib/ffnw/hoods/hoods.json' + +local hoodstatic = 0 + +local FILE = uci:get('hoodselector', 'hoodselector', 'hoodfile') +if FILE == nil then + log("No hood file in config") + os.exit(1) +end + -- initialization done -- Read the full hoodfile. Return nil for wrong format or no such file @@ -563,6 +607,18 @@ local function wireless_reconfigure(radios, hood_bssid) uci:commit('wireless') end +-- Save selected hood to config to make a restore after a sysupgrade possible +local function saveHoodToConfig(hoodname) + uci:section('hoodselector', 'settings', 'hoodselector', { + hood = hoodname, + hoodfile = FILE, + static = hoodstatic, + enabled = hoodselectorenabled + }) + uci:save('hoodselector') + uci:commit('hoodselector') +end + -- This method sets a new hoodconfig and takes care that services are only -- stopped or restarted if reconfiguration is needed. -- Process: @@ -574,15 +630,18 @@ end -- * If fastd needed reconfiguration start fastd now local function set_hoodconfig(hood, radios) local local_serverlist = getCurrentPeers() + local config_changed = false -- Check if VPN needs reconfiguration because in case of reconfiguration we -- need to stop VPN before we can reconfigure any other connection. local vpn_reconf_needed = vpn_reconfiguration_needed(hood["servers"],local_serverlist); if(vpn_reconf_needed) then + config_changed = true vpn_stop() end -- reconfigure wireless if(wireless_reconfiguration_needed(radios, hood["bssid"])) then + config_changed = true wireless_reconfigure(radios, hood["bssid"]) wireless_restart() io.stderr:write('Wireless needed reconfiguration. Applied new settings and restarted.\n') @@ -600,6 +659,13 @@ local function set_hoodconfig(hood, radios) io.stderr:write("Set hood \""..hood["name"].."\"\n") molwmtable["hoodname"] = "\"" .. hood["name"] .. "\"" + if(uci:get('hoodselector', 'hoodselector' , 'hood') ~= hood["name"]) then + config_changed = true + end + + if config_changed then + saveHoodToConfig(hood["name"]) + end return true end @@ -641,13 +707,10 @@ end -- Return hood from hood file based on a peer address. nil if no matching hood could be found local function getCurrentHood(jhood) - for _, local_server in pairs(getCurrentPeers()) do - for _, h in pairs(jhood) do - for _, peer in pairs(h.servers) do - if ( peer["host"] == local_server.remote.host:gsub("\"", "") ) then - return h - end - end + local hoodname = uci:get('hoodselector', 'hoodselector', 'hood') + for _, h in pairs(jhood) do + if h.name == hoodname then + return h end end return nil