module(..., package.seeall) -- Load libraries require("modelfunctions") require("validator") -- Set variables local configfile = "/etc/opennhrp/opennhrp.conf" local processname = "opennhrp" local packagename = "opennhrp" local interfaceslist, reverseinterfaceslist local config, configfilecontent 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 list_interfaces(self) if not interfaceslist then -- Get the list of available interfaces local interfaces = self:new("alpine-baselayout/interfaces") local availableinterfaces = interfaces:read() interfaceslist = {} reverseinterfaceslist = {} for i,int in ipairs(availableinterfaces.value) do interfaceslist[#interfaceslist + 1] = int.value.name.value reverseinterfaceslist[int.value.name.value] = #interfaceslist end interfaces:destroy() end return interfaceslist, reverseinterfaceslist end local function parseconfigfile(configfilecontent) local config = {} local currentinterface local words = {} -- remove comments, and then parse word-by-word for word in string.gmatch(string.gsub(configfilecontent, "#[^\n]*", ""), "%S+") do words[#words + 1] = word end local i=1 while i <= table.maxn(words) do local word = words[i] if not currentinterface and word ~= "interface" then currentinterface = "" config[""].errtxt = "Syntax error - undefined interface" end if word == "interface" then i = i+1 currentinterface = words[i] if config[currentinterface] then config[currentinterface].errtxt = "Syntax error - interface defined multiple times" else config[currentinterface] = {} end elseif word == "map" then -- there may be more than one map statement if not config[currentinterface].map then config[currentinterface].map = {} end local temp = {words[i+1], words[i+2]} i = i+2 if words[i+1] == "register" then temp[3] = words[i+1] i = i+1 end table.insert(config[currentinterface].map, temp) elseif word == "cisco-authentication" then config[currentinterface]["cisco-authentication"] = {words[i+1]} i = i+1 elseif word == "redirect" or word == "shortcut" or word == "non-caching" or word == "shortcut-destination" then config[currentinterface][word] = {} else table.insert(config[currentinterface], word) end i = i+1 end -- Check interfaces for errors for interf,val in pairs(config) do if val[1] then local errtxt = "Syntax error - unrecognized keyword" if val.errtxt then val.errtxt = val.errtxt .. "\n" .. errtxt else val.errtxt = errtxt end end end return config end local function validateconfigfile(self, configfile) local config = parseconfigfile(configfile.value.filecontent.value) list_interfaces(self) local errtxt = {} for name,value in pairs(config) do if name ~= "" and not reverseinterfaceslist[name] then errtxt[#errtxt + 1] = name .. " - Nonexistant interface" end if value.errtxt then errtxt[#errtxt + 1] = name .. " - " .. string.gsub(value.errtxt, "\n", "\n"..name.." - ") end end if #errtxt then configfile.value.filecontent.errtxt = table.concat(errtxt, "\n") end return configfile end local function validateinterfacedetails(interfacedetails) local success = modelfunctions.validateselect(interfacedetails.value.type) for i,map in ipairs(interfacedetails.value.map.value) do local words = {} for word in string.gmatch(map, "%S+") do words[#words+1] = word end if not words[1] or not words[2] or (words[3] and words[3] ~= "register") or words[4] then interfacedetails.value.map.errtxt = "Syntax error on line "..i success = false break end end if not interfacedetails.value.interface.value or string.find(interfacedetails.value.interface.value, "%s") then interfacedetails.value.interface.errtxt = "Invalid interface name" success = false end return success, interfacedetails 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() 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 function getinterfacedetails(interface) local details = {} details.interface = cfe({ value=interface, label="Interface" }) details.type = cfe({ type="select", value="Unused", label="Interface type", option={"Unused", "NHRP Enabled", "Shortcut Destination"} }) details.map = cfe({ type="list", value={}, label="Static Peers", descr="List of static peer mappings of protocol-address to nbma-address. Optional 'register' parameter specifies Registration Request sent to this peer on startup. (protocol-address[/prefix] nbma-address [register])" }) configfilecontent = configfilecontent or fs.read_file(configfile) config = config or parseconfigfile(configfilecontent) if config and config[interface] then if config[interface]["shortcut-destination"] then details.type.value = "Shortcut Destination" else details.type.value = "NHRP Enabled" end for i,map in ipairs(config[interface].map or {}) do table.insert(details.map.value, table.concat(map, " ")) end details.interface.errtxt = config[interface].errtxt end return cfe({ type="group", value=details, label="OpenNHRP Interface Configuration" }) end function updateinterfacedetails(interfacedetails) local success, interfacedetails = validateinterfacedetails(interfacedetails) if success then configfilecontent = configfilecontent or fs.read_file(configfile) local startchar = string.find(configfilecontent or "", "interface%s+"..interfacedetails.value.interface.value) local lines = {} if startchar then lines[1] = string.gsub(string.sub(configfilecontent, 1, startchar-1), "\n+$", "") startchar = string.find(configfilecontent, "interface", startchar+1) if startchar then lines[2] = string.sub(configfilecontent, startchar, -1) end else lines[1] = string.gsub(configfilecontent or "", "\n+$", "") end if interfacedetails.value.type.value ~= "Unused" then local intflines = {"interface "..interfacedetails.value.interface.value} if interfacedetails.value.type.value == "Shortcut Destination" then intflines[2] = "\tshortcut-destination" else for i,map in ipairs(interfacedetails.value.map.value) do table.insert(intflines, "\tmap "..map) end config = config or parseconfigfile(configfilecontent) local intfconfig = config[interfacedetails.value.interface.value] or {} intfconfig.map = nil intfconfig["shortcut-destination"] = nil for name,arr in pairs(intfconfig) do APP.logevent(name) if type(name) ~= "number" and name ~= "errtxt" then table.insert(intflines, "\t"..name.." "..table.concat(arr, " ")) end end end table.insert(lines, 2, table.concat(intflines, "\n")) end fs.write_file(configfile, table.concat(lines, "\n")) configfilecontent = nil config = nil else interfacedetails.errtxt = "Failed to save Interface Details" end return interfacedetails end function listinterfaces(self) local interfaces = {} list_interfaces(self) configfilecontent = configfilecontent or fs.read_file(configfile) config = config or parseconfigfile(configfilecontent) for name,intf in pairs(config) do temp = {interface=name, type="NHRP Enabled", errtxt=intf.errtxt} if intf["shortcut-destination"] then temp.type = "Shortcut Destination" end if not reverseinterfaceslist[name] then local errtxt = "Nonexistant interface" if temp.errtxt then temp.errtxt = temp.errtxt .. "\n" .. errtxt else temp.errtxt = errtxt end end table.insert(interfaces, temp) end for i,name in ipairs(interfaceslist) do if not config[name] then table.insert(interfaces, {interface=name, type="Unused"}) end end return cfe({ type="structure", value=interfaces, label="OpenNHRP Interfaces" }) end function getconfigfile(self) return validateconfigfile(self, modelfunctions.getfiledetails(configfile)) end function setconfigfile(self, filedetails) filedetails = modelfunctions.setfiledetails(filedetails, {configfile}) if not filedetails.errtxt then configfilecontent = nil config = nil end return validateconfigfile(self, filedetails) end