Select Git revision
0002-add-patch-to-remove-fastd-random-delay-on-inital-han.patch
util.lua 4.98 KiB
#!/usr/bin/lua
local uci = require('simple-uci').cursor()
local util = require 'gluon.util'
local iwinfo = require 'iwinfo'
local json = require 'jsonc'
local bit = require 'bit32'
local log = require 'posix.syslog'
local M = {}
local fcntl = require 'posix.fcntl'
local unistd = require 'posix.unistd'
local sys_sock = require "posix.sys.socket"
local domains = {"stuttgart.freifunk.net", "freifunk-stuttgart.net"}
function M.log(dest, msg)
local prefix = 'ffs-set-segment: '
msg = prefix .. msg
if dest == 'out' then
io.stdout:write(msg .. '\n')
log.syslog(log.LOG_INFO, msg)
elseif dest == 'err' then
io.stderr:write(msg .. '\n')
log.syslog(log.LOG_CRIT, msg)
end
end
function M.fastd_public_key()
local key = util.trim(util.exec('/etc/init.d/fastd show_key mesh_vpn'))
if key == '' then key = nil end
return key
end
function M.lock(lockfilename)
local lockfd, err = fcntl.open(lockfilename, bit.bor(fcntl.O_WRONLY, fcntl.O_CREAT), 384) -- mode 0600
if not lockfd then
autil.log('err', err)
local err_verbose = string.format("Unable to get file descriptor for lock file %s .", lockfilename)
autil.log('err', err_verbose)
os.exit(1)
end
local ok, _ = fcntl.fcntl(lockfd, fcntl.F_SETLK, {
l_start = 0,
l_len = 0,
l_type = fcntl.F_WRLCK,
l_whence = unistd.SEEK_SET,
})
if not ok then
local err_msg = string.format("Unable to lock file %s. ", lockfilename) ..
"Make sure there is no other instance of this script running."
M.log('err', err_msg)
os.exit(1)
end
end
local function execute(command)
local f = io.popen(command)
if not f then
return nil
end
local data = f:read('*a')
f:close()
return data
end
function M.has_batman_gw()
local gwl_cmd = execute("batctl meshif bat0 gateways_json")
if not gwl_cmd then
M.log("err", "could not get gwl")
return false
end
local gwl = json.parse(gwl_cmd)
if not gwl then
return false
end
return true
end
local function _resp_try_v6(dnsrecords)
if not dnsrecords then
return nil
end
for i, record in ipairs(dnsrecords) do
local addr = record.addr
local segmentstr = addr:match("^2001:2:0:711::([0-9]+)")
if segmentstr then
local segment = tonumber(segmentstr, 10)
if not segment then
M.log("err", "Could not convert '"..segmentstr.."' to segment")
return nil
end
return segment
end
end
end
local function _resp_try_v4(dnsrecords)
if not dnsrecords then
return nil
end
for i, record in ipairs(dnsrecords) do
local addr = record.addr
local segmentstr = addr:match('^198.18.190.([0-9]+)')
if segmentstr then
local segment = tonumber(segmentstr, 10)
if segment == nil then
M.log("err", "Could not convert '"..addr.addr.."' to segment")
return nil
end
return segment
end
end
end
function M.get_segment_from_dns(nodeid, pubkey)
for i, domain in ipairs(domains) do
local dnsname = "ffs-" .. nodeid .. "-" .. pubkey .. ".segassign." .. domain
M.log("out", "DNS for "..dnsname)
--- todo: we need to specify to use WAN DNS servers somehow, current idea: just run us with gluon-wan always
local dnsres, errmsg, errno = sys_sock.getaddrinfo(dnsname)
if not dnsres then
M.log("err", "DNS for '"..dnsname.."' failed: "..errno.." "..errmsg)
else
local segment = _resp_try_v6(dnsres)
if not segment then
M.log("err", "Could not get segment based of AAAA records on '"..dnsname.."', trying fallback to A record")
segment = _resp_try_v4(dnsres)
if not segment then
M.log("err", "A record fallback failed for '"..dnsname.."'")
return nil
end
end
return segment
end
end
end
function M.get_segment_from_batman()
local gwl = json.parse(execute("batctl meshif bat0 gateways_json", "r"))
if not gwl then
return nil
end
for i, gw in ipairs(gwl) do
local gwmac = gw.orig_address
-- valid GW mac, byte index 4 is the segment
local batseg = gwmac:match("02:00:3[0-9a-fA-F]:([0-9a-fA-F]-):")
if not batseg then
return nil
end
return tonumber(batseg, 10)
end
end
local function is_in_table(haystack, needle)
for i, item in ipairs(haystack) do
if item == needle then
return true
end
end
return false
end
local function restart_fastd()
M.log("out", "Restarting fastd")
io.popen("/etc/init.d/fastd restart")
io.popen("/sbin/ip addr flush dev br-client scope global")
end
function M.set_fastd_remotes(port, segment)
local changed = false
for i=1,10 do
local gwid = string.format("gw%02d", i)
local current_peer_list = uci:get_list("fastd", "mesh_vpn_backbone_peer_" .. gwid, "remote")
local newpeers = {}
for _, domain in ipairs(domains) do
local peer = string.format("\"gw%02ds%02d.gw.%s\" port %d", i, segment, domain, port)
table.insert(newpeers, peer)
if not is_in_table(current_peer_list, peer) then
changed = true
end
end
if changed then
uci:set_list("fastd", "mesh_vpn_backbone_peer_" .. gwid, "remote", newpeers)
end
end
if changed then
uci:save('fastd')
restart_fastd()
else
M.log("out", "No changes")
end
end
return M