Skip to content
Snippets Groups Projects
Select Git revision
  • master
  • nrb/dev protected
2 results

0002-add-patch-to-remove-fastd-random-delay-on-inital-han.patch

Blame
  • 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