module(..., package.seeall) -- Load libraries require("fs") require("procps") require("getopts") require("format") require("daemoncontrol") require("validator") require("processinfo") -- Set variables local configfile = "/etc/shorewall/shorewall.conf" local processname = "shorewall" local packagename = "shorewall" local baseurl = "/etc/shorewall/" local config = {} -- ################################################################################ -- LOCAL FUNCTIONS local function getloglevels() local loglevels = {} for i=1,8 do table.insert(loglevels,i) end return loglevels end local function getdetails() local f,error = io.popen("/sbin/shorewall status") local fake = f:read("*l") local fake = f:read("*l") local programstatus = f:read("*l") or "" local programstate = f:read("*l") or "" f:close() local f,error = io.popen("/sbin/shorewall version") local programversion = "shorewall-" .. f:read("*l") f:close() return programversion,programstatus,programstate end local function read_config(file) local path = baseurl .. file if not (fs.is_file(path)) then return {} end local filecontent = fs.read_file_as_array(path) local output = {} for k,v in pairs(filecontent) do if not string.find ( v, "^[;#].*" ) and not (string.find (v, "^%s*$")) then table.insert(output, v) end end return output end ---[[ local function addremove_config( addremove, file, value, orgvalue ) filepath = baseurl .. file local cmdoutput -- Check if we are about to change a valid filename local isvalidfile for k,v in pairs(getfilelist()) do isvalidfile = true if (v.value == filepath) then break end isvalidfile = false end if not (fs.is_file(filepath)) or not (isvalidfile) then return false, cfe({ name="model:addremove_config()", errtxt="'" .. filepath .. "' is not a valid file!", }) end if not (type(value) == "table") then return false, cfe({ name="model:addremove_config()", errtxt="Value should come as an array!", }) end local filecontentarray = fs.read_file_as_array(filepath) if (addremove == "delete" ) then local modifyrow local orgrecordtable = {} for word in string.gmatch(orgvalue, "%S+") do table.insert(orgrecordtable, word) end for i=1, #filecontentarray do local recordtable = {} for word in string.gmatch(filecontentarray[i], "%S+") do table.insert(recordtable, word) end if (table.concat(recordtable) == table.concat(orgrecordtable)) then modifyrow = i end end if (tonumber(modifyrow)) then table.remove(filecontentarray, modifyrow) fs.write_file(filepath, table.concat(filecontentarray, "\n")) return true, cfe({ name="model:addremove_config()", descr="* Record was successfully deleted!", }) else return false, cfe({ name="model:addremove_config()", errtxt="Record was not deleted!", }) end elseif (addremove == "add" ) then --Check if such record already exists for k,v in pairs(filecontentarray) do if not string.find ( v, "^[;#].*" ) then local recordtable = {} for word in string.gmatch(v, "%S+") do table.insert(recordtable, word) end if (table.concat(recordtable) == table.concat(value)) then return false, cfe({ name="model:addremove_config()", errtxt="The config already holds this kind of config!", }) end end end table.insert(filecontentarray, (#filecontentarray), table.concat(value, "\t")) fs.write_file(filepath, table.concat(filecontentarray, "\n")) return true, cfe({ name="model:addremove_config()", descr="* Record was successfully added!", }) elseif (addremove == "modify" ) then local modifyrow local orgrecordtable = {} for word in string.gmatch(orgvalue, "%S+") do table.insert(orgrecordtable, word) end for i=1, #filecontentarray do local recordtable = {} for word in string.gmatch(filecontentarray[i], "%S+") do table.insert(recordtable, word) end if (table.concat(recordtable) == table.concat(orgrecordtable)) then modifyrow = i end end if (tonumber(modifyrow)) then table.remove(filecontentarray, modifyrow) table.insert(filecontentarray, modifyrow, table.concat(value, "\t")) fs.write_file(filepath, table.concat(filecontentarray, "\n")) return true, cfe({ name="model:addremove_config()", descr="* Record was successfully modified!", }) else return false, cfe({ name="model:addremove_config()", errtxt="Record was not modified!", }) end else return false, cfe({ name="model:addremove_config()", errtxt="Wrong usage of this function! Available options are [add|delete|modify]. You chose '" .. addremove .. "'", }) end return false, cfe({ name="model:addremove_config()", errtxt="Something went wrong!", debug=value, }) end --]] -- ################################################################################ -- PUBLIC FUNCTIONS function modify_config(self, addremove, file, value, orgvalue ) return addremove_config(addremove, file, value, orgvalue ) end -- action should be a CFE function startstop_service ( self, action ) local cmd = action.value local cmdresult,cmdmessage,cmderror,cmdaction = daemoncontrol.daemoncontrol(processname, cmd) action.descr=cmdmessage action.errtxt=cmderror -- Reporting back (true|false, the original acition) return cmdresult,action end function getconfig() local config = {} config.params = cfe({ name = "params", label="List of parameters", type="select", option=read_config("params"), }) config.params.size=#config.params.option + 1 config.interfaces = cfe({ name = "interfaces", label="List of interfaces", type="select", option=read_config("interfaces"), }) config.interfaces.size=#config.interfaces.option + 1 config.zones = cfe({ name = "zones", label="List of zones", type="select", option=read_config("zones"), }) config.zones.size=#config.zones.option + 1 config.policy = cfe({ name = "policy", label="List of policy", type="select", option=read_config("policy"), }) config.policy.size=#config.policy.option + 1 config.rules = cfe({ name = "rules", label="List of rules", type="select", option=read_config("rules"), }) config.rules.size=#config.rules.option + 1 return config end function getstatus() local status = {} local value, errtxt = processinfo.package_version(packagename) status.version = cfe({ name = "version", label="Program version", value=value, errtxt=errtxt, }) local programversion,programstatus,programstate = getdetails() status.status = cfe({ name="status", label="Program status", value=programstatus, }) status.state = cfe({ name="state", label="Program reports", value=programstate, }) local autostart_sequense, autostart_errtxt = processinfo.process_botsequence(processname) status.autostart = cfe({ name="autostart", label="Autostart sequence", value=autostart_sequense, errtxt=autostart_errtxt, }) return status end function configcheck () local check = {} local f,err = io.popen("/bin/echo -n '>> Check starts at: ';/bin/date; /bin/echo; /etc/init.d/shorewall check; /bin/echo; /bin/echo -n '>> Check stops at: '; /bin/date;") local checkresult = f:read("*a") f:close() check.checkresult = cfe({ name = "checkresult", type="longtext", label="Result of checking config", value=checkresult, }) return check end function get_defined_zones () local output = {} for k,v in pairs(read_config("zones")) do table.insert(output, string.match(v, "^%s*(%S*)")) end return output end function getlogfile () local logfile = {} local logfilepath = getopts.getoptsfromfile(configfile,"LOGFILE") local cmdaction = "grep Shorewall " .. logfilepath.LOGFILE local f, error = io.popen(cmdaction ,r) local checkresult = f:read("*a") f:close() logfile.checkresult = cfe({ name = "checkresult", type="longtext", label="Result of logfiles", value=checkresult, }) logfile.filename = cfe({ name="filename", label="File name", value=cmdaction, }) return logfile end function getfilelist () local filepath = baseurl local listed_files = {} local k,v for name in posix.files(filepath) do if not string.match(name, "^%.") and not string.match(name, "^Makefile") then local filedetails = fs.stat(filepath .. name) table.insert ( listed_files , cfe({name=name, value=filepath .. name, mtime=filedetails.mtime, size=filedetails.size,}) ) end end table.sort(listed_files, function (a,b) return (a.name < b.name) end ) return listed_files end function getfiledetails(self,search) local file = {} local path = nil --Validate filename local available_files = getfilelist() for k,v in pairs(available_files) do if ( tostring(available_files[k]["value"]) == tostring(search.value) ) then path = tostring(search.value) end end if not (path) or (path == "") then file["filename"] = search file["filename"]["label"] = "File name" file["filename"]["errtxt"] = "Invalid path!" return file end local filedetails = fs.stat(path) file["filename"] = cfe({ name="filename", label="File name", value=path, }) file["filesize"] = cfe({ name="filesize", label="File size", value=filedetails.size, }) file["mtime"] = cfe({ name="mtime", label="File name", value=filedetails.mtime, }) file["filecontent"] = cfe({ type="longtext", name="filecontent", label="File content", value=fs.read_file(path), }) return file end -- modifications should be a CFE function updatefilecontent (self, filetochange) local path = nil --Validate filename local available_files = getfilelist() for k,v in pairs(available_files) do if ( tostring(available_files[k]["value"]) == tostring(filetochange.name) ) then path = tostring(filetochange.name) end end if not (path) then filetochange.errtxt = "Invalid path!" return filetochange end local file_result,err = fs.write_file(path, format.dostounix(filetochange.value)) return file_result, err end