module(..., package.seeall) -- Load libraries require("modelfunctions") require("validator") -- Set variables local configfile = "/etc/opennhrp/opennhrp.conf" local processname = "opennhrp" local packagename = "opennhrp" local descr = { Type = { ['incomplete']="The protocol address is being resolved", ['negative']="This protocol address is not available", ['cached']="Protocol address was resolved successfully", ['route']="This is a dynamic shortcut", ['dynamic']="This entry is from a node that connected to us", ['local']="Local interface address", ['static']="Static mapping from configuration file (e.g. address of core)", }, Flags= { -- ['up']="Connection is fully usable", ['lower-up']="ipsec connections is up, but registration is not yet done", }, } -- ################################################################################ -- LOCAL FUNCTIONS local function opennhrpctl_show() local peers_list = cfe({ type="structure", value={}, label="Peers" }) local opennhrpstatus = cfe({ value="Show report not available", label="Status" }) local cmd = "/usr/sbin/opennhrpctl show 2>/dev/null" local f = io.popen( cmd ) local content = f:read("*a") f:close() local current for line in string.gmatch(content, "([^\n]*)\n?") do if string.find(line, "^Status:") then opennhrpstatus.value = string.match(line, ":%s*(%w+)") elseif string.find(line,"^Interface:") then local intf = string.match(line, ":%s*(%w+)") current = {} peers_list.value[intf] = peers_list.value[intf] or {} table.insert(peers_list.value[intf], current) elseif ( current ) and (line ~= "") then local name,val = string.match(line,"^(.-):%s?(.*)") if name and val then current[name] = cfe({value=val, label=name}) if (type(descr[name]) == "table") then current[name].descr = descr[name][val] end end end end return cfe({ type="group", value={peers_list=peers_list, status=opennhrpstatus}, label="OpenNHRP Show Report" }) end local function parseconfigfile(self, configfile) if fs.is_file(configfile) then configfile = fs.read_file(configfile) end -- Get the list of available interfaces local interfaces = self:new("alpine-baselayout/interfaces") local availableinterfaces = interfaces:read() local listinterfaces = {} local reverseinterfaces = {} for i,int in ipairs(availableinterfaces.value) do listinterfaces[#listinterfaces + 1] = int.value.name.value reverseinterfaces[int.value.name.value] = #listinterfaces end interfaces:destroy() local outgoinginterface = cfe({ type="select", label="Outgoing Interface", option=listinterfaces }) local publishedinterfaces = cfe({ type="multi", value={}, label="Published Interfaces", option=listinterfaces }) local peers = cfe({ type="list", value={}, label="Registered Peers", descr="protocol-address[/prefix] nbma-address" }) local currentinterface = "" local words = {} for word in configfile:gmatch("%S+") do words[#words + 1] = word end for i,word in ipairs(words) do if word == "interface" then currentinterface = words[i+1] elseif word == "map" then if outgoinginterface.value ~= "" and outgoinginterface.value ~= currentinterface then outgoinginterface.errtxt = "Multiple outgoing interfaces not supported" else outgoinginterface.value = currentinterface peers.value[#peers.value + 1] = words[i+1] .. " " .. words[i+2] end elseif word == "shortcut-destination" then publishedinterfaces.value[#publishedinterfaces.value + 1] = currentinterface end end return cfe({ type="group", value={outgoinginterface=outgoinginterface, peers=peers, publishedinterfaces=publishedinterfaces}, label="OpenNHRP Config" }) end local function generateconfigfile(config) local filelines = {} filelines[#filelines + 1] = "interface " .. config.value.outgoinginterface.value for i,value in ipairs(config.value.peers.value) do filelines[#filelines + 1] = " map " .. value .. " register" end filelines[#filelines + 1] = " shortcut" filelines[#filelines + 1] = " redirect" filelines[#filelines + 1] = " non-caching" filelines[#filelines + 1] = "" for i,value in ipairs(config.value.publishedinterfaces.value) do filelines[#filelines + 1] = "interface " .. value filelines[#filelines + 1] = " shortcut-destination" filelines[#filelines + 1] = "" end return table.concat(filelines, "\n") end local function validateconfig(config) local success = true if not modelfunctions.validateselect(config.value.outgoinginterface) then success = false end if not modelfunctions.validatemulti(config.value.publishedinterfaces) then success = false end -- make sure don't try to publish the outgoing interface for i,value in ipairs(config.value.publishedinterfaces.value) do if value == config.value.outgoinginterface.value then success = false config.value.publishedinterfaces.errtxt = "Cannot publish outgoing interface" break end end for i,value in ipairs(config.value.peers.value) do if not validator.is_ipv4(value:match("[^%s/]+")) then success = false config.value.peers.errtxt = "Syntax error - invalid ip address" break elseif value:match("/(%d*)") and not validator.is_integer_in_range(value:match("/(%d*)"), 1, 31) then success = false config.value.peers.errtxt = "Syntax error - invalid prefix" break elseif string.find(value:match("%s(%S+)"), "[^%w.-]") then success = false config.value.peers.errtxt = "Syntax error - invalid domain name" break end end return success, config end local function validateconfigfile(self, configfile) local config = parseconfigfile(self, configfile.value.filecontent.value) local success, config = validateconfig(config) if not success then local errtxt = {} for name,value in pairs(config.value) do if value.errtxt then errtxt[#errtxt + 1] = name .. " - " .. value.errtxt end end if #errtxt then configfile.value.filecontent.errtxt = table.concat(errtxt, "\n") end end return success, configfile end -- ################################################################################ -- PUBLIC FUNCTIONS function startstop_service(action) return modelfunctions.startstop_service(processname, action) end function getstatus() return modelfunctions.getstatus(processname, packagename, "Opennhrp Status") end function getshowreport() return opennhrpctl_show() end function getconfig(self) local config = parseconfigfile(self, configfile) local result, config = validateconfig(config) return config end function setconfig(self, config) local success, config = validateconfig(config) if success then fs.write_file(configfile, generateconfigfile(config)) else config.errtxt = "Failed to set configuration" end return config end function getconfigfile(self) return modelfunctions.getfiledetails(configfile, nil, function(filedetails) return validateconfigfile(self, filedetails)end) end function setconfigfile(self, filedetails) return modelfunctions.setfiledetails(filedetails, {configfile}, function(filedetails) return validateconfigfile(self, filedetails)end) end