From f524a6f6edf59eaf6e20043d4e54fe866f7f1357 Mon Sep 17 00:00:00 2001 From: Ted Trask Date: Fri, 9 Jan 2009 22:00:23 +0000 Subject: Virtual rewrite of opennhrp to change config to listinterfaces and editinterface. Modified expert to allow writing of file with errors. git-svn-id: svn://svn.alpinelinux.org/acf/opennhrp/trunk@1673 ab2d0c66-481e-0410-8bed-d214d4d58bed --- opennhrp-config-html.lsp | 27 ---- opennhrp-controller.lua | 8 +- opennhrp-editinterface-html.lsp | 10 ++ opennhrp-listinterfaces-html.lsp | 25 +++ opennhrp-model.lua | 341 +++++++++++++++++++++++++-------------- opennhrp.menu | 2 +- opennhrp.roles | 4 +- 7 files changed, 261 insertions(+), 156 deletions(-) delete mode 100644 opennhrp-config-html.lsp create mode 100644 opennhrp-editinterface-html.lsp create mode 100644 opennhrp-listinterfaces-html.lsp diff --git a/opennhrp-config-html.lsp b/opennhrp-config-html.lsp deleted file mode 100644 index 75c98ce..0000000 --- a/opennhrp-config-html.lsp +++ /dev/null @@ -1,27 +0,0 @@ -<% local form, viewlibrary, page_info, session = ... -require("viewfunctions") -%> -<% ---[[ DEBUG INFORMATION -io.write("

DEBUGGING

DEBUG INFO: CFE

") -io.write(html.cfe_unpack(form)) -io.write("
") ---]] -%> - -<% displaycommandresults({"startstop"}, session) %> - -<% if viewlibrary and viewlibrary.dispatch_component then - viewlibrary.dispatch_component("status") -end %> - -

Config

-<% - form.action = page_info.script .. page_info.prefix .. page_info.controller .. "/" .. page_info.action - local order = {"outgoinginterface", "peers", "publishedinterfaces"} - displayform(form, order) -%> - -<% if viewlibrary and viewlibrary.dispatch_component then - viewlibrary.dispatch_component("startstop") -end %> diff --git a/opennhrp-controller.lua b/opennhrp-controller.lua index aab365d..94ea3eb 100644 --- a/opennhrp-controller.lua +++ b/opennhrp-controller.lua @@ -16,8 +16,12 @@ function startstop(self) return controllerfunctions.handle_startstop(self, self.model.startstop_service, self.model.getstatus, self.clientdata) end -function config(self) - return controllerfunctions.handle_form(self, function() return self.model:getconfig() end, function(value) return self.model:setconfig(value) end, self.clientdata, "Save", "Edit Config", "Configuration Set") +function listinterfaces(self) + return self.model.listinterfaces(self) +end + +function editinterface(self) + return controllerfunctions.handle_form(self, function() return self.model.getinterfacedetails(self.clientdata.interface) end, self.model.updateinterfacedetails, self.clientdata, "Save", "Edit Interface Config", "Interface Configuration Set") end function expert (self) diff --git a/opennhrp-editinterface-html.lsp b/opennhrp-editinterface-html.lsp new file mode 100644 index 0000000..73af9ab --- /dev/null +++ b/opennhrp-editinterface-html.lsp @@ -0,0 +1,10 @@ +<% local form, viewlibrary, page_info = ... +require("viewfunctions") +%> + +

<%= form.label %>

+<% + form.value.interface.contenteditable = false + local option = {"interface", "type", "map"} + displayform(form, option, nil, page_info) +%> diff --git a/opennhrp-listinterfaces-html.lsp b/opennhrp-listinterfaces-html.lsp new file mode 100644 index 0000000..ca3fdb6 --- /dev/null +++ b/opennhrp-listinterfaces-html.lsp @@ -0,0 +1,25 @@ +<% local view, viewlibrary, page_info, session = ... +require("viewfunctions") +%> + +<% displaycommandresults({"editinterface"}, session) %> + +

<%= view.label %>

+ + + + + + + +<% for i,intf in ipairs(view.value) do %> + + + + + + +<% end %> +
ActionInterfaceTypeComment
+ <% io.write(html.link{value = "editinterface?interface="..intf.interface.."&redir="..page_info.orig_action, label="Edit " }) %> + <%= intf.interface %><%= intf.type %>

<%= string.gsub(intf.errtxt or "", "\n", "
") %>

diff --git a/opennhrp-model.lua b/opennhrp-model.lua index 2601655..ef9c69a 100644 --- a/opennhrp-model.lua +++ b/opennhrp-model.lua @@ -9,6 +9,9 @@ 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", @@ -28,7 +31,130 @@ local descr = { -- ################################################################################ -- LOCAL FUNCTIONS -local function opennhrpctl_show() +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 = {} + for word in configfilecontent:gmatch("%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" @@ -58,151 +184,118 @@ local function opennhrpctl_show() 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) +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 - -- 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() + return cfe({ type="group", value=details, label="OpenNHRP Interface Configuration" }) +end - 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] +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 - elseif word == "shortcut-destination" then - publishedinterfaces.value[#publishedinterfaces.value + 1] = currentinterface + else + lines[1] = string.gsub(configfilecontent or "", "\n+$", "") end - end - return cfe({ type="group", value={outgoinginterface=outgoinginterface, peers=peers, publishedinterfaces=publishedinterfaces}, label="OpenNHRP Config" }) -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 -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] = "" + 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 table.concat(filelines, "\n") + return interfacedetails 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 +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 - 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 + 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 - 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") + for i,name in ipairs(interfaceslist) do + if not config[name] then + table.insert(interfaces, {interface=name, type="Unused"}) 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 + return cfe({ type="structure", value=interfaces, label="OpenNHRP Interfaces" }) end function getconfigfile(self) - return modelfunctions.getfiledetails(configfile, nil, function(filedetails) return validateconfigfile(self, filedetails)end) + return validateconfigfile(self, modelfunctions.getfiledetails(configfile)) end function setconfigfile(self, filedetails) - return modelfunctions.setfiledetails(filedetails, {configfile}, function(filedetails) return validateconfigfile(self, filedetails)end) + filedetails = modelfunctions.setfiledetails(filedetails, {configfile}) + if not filedetails.errtxt then + configfilecontent = nil + config = nil + end + return validateconfigfile(self, filedetails) end diff --git a/opennhrp.menu b/opennhrp.menu index c8ce6cb..65dc1ee 100644 --- a/opennhrp.menu +++ b/opennhrp.menu @@ -1,4 +1,4 @@ #CAT GROUP/DESC TAB ACTION Networking 45NHRP Status show -Networking 45NHRP Config config +Networking 45NHRP Config listinterfaces Networking 45NHRP Expert expert diff --git a/opennhrp.roles b/opennhrp.roles index 2d16b10..b55dedf 100644 --- a/opennhrp.roles +++ b/opennhrp.roles @@ -1,4 +1,4 @@ USER=opennhrp:status,opennhrp:show,opennhrp:startstop -EDITOR=opennhrp:config +EDITOR=opennhrp:listinterfaces,opennhrp:editinterface EXPERT=opennhrp:expert -ADMIN=opennhrp:status,opennhrp:show,opennhrp:startstop,opennhrp:config,opennhrp:expert +ADMIN=opennhrp:status,opennhrp:show,opennhrp:startstop,opennhrp:listinterfaces,opennhrp:editinterface,opennhrp:expert -- cgit v1.2.3