From 337584d2a16c3a22551ab31c6eff7beb1c942815 Mon Sep 17 00:00:00 2001 From: Ted Trask Date: Thu, 26 Jun 2008 19:16:25 +0000 Subject: Rewrite of DNScache. git-svn-id: svn://svn.alpinelinux.org/acf/dnscache/trunk@1262 ab2d0c66-481e-0410-8bed-d214d4d58bed --- dnscache-config-html.lsp | 23 +++ dnscache-controller.lua | 181 ++++++++++----------- dnscache-createdomain-html.lsp | 17 ++ dnscache-editdomain-html.lsp | 17 ++ dnscache-editips-html.lsp | 15 ++ dnscache-expert-html.lsp | 72 ++++----- dnscache-listdomains-html.lsp | 34 ++++ dnscache-logfile-html.lsp | 31 ---- dnscache-model.lua | 349 ++++++++++++++++++++++++++--------------- dnscache-startstop-html.lsp | 26 +++ dnscache-status-html.lsp | 44 +----- dnscache.menu | 4 +- dnscache.roles | 4 +- 13 files changed, 483 insertions(+), 334 deletions(-) create mode 100644 dnscache-config-html.lsp create mode 100644 dnscache-createdomain-html.lsp create mode 100644 dnscache-editdomain-html.lsp create mode 100644 dnscache-editips-html.lsp create mode 100644 dnscache-listdomains-html.lsp delete mode 100644 dnscache-logfile-html.lsp create mode 100644 dnscache-startstop-html.lsp diff --git a/dnscache-config-html.lsp b/dnscache-config-html.lsp new file mode 100644 index 0000000..d1e414d --- /dev/null +++ b/dnscache-config-html.lsp @@ -0,0 +1,23 @@ + +DEBUGGING

DEBUG INFO: CFE

") +io.write(html.cfe_unpack(form)) +io.write("
") +--]] +?> + + + +

Config

+ + + diff --git a/dnscache-controller.lua b/dnscache-controller.lua index 0cc4d92..d50fb63 100644 --- a/dnscache-controller.lua +++ b/dnscache-controller.lua @@ -3,115 +3,108 @@ module(..., package.seeall) -- Load libraries require("format") --- Set variables -local newrecordtxt = "[New]" - --- ################################################################################ --- LOCAL FUNCTIONS - -local function displaycmdmanagement(pidofstatus) - -- Add a management buttons - local management = {} - management.start = cfe({ name="cmdmanagement", - label="Program control-panel", - value="Start", - type="submit", - }) - management.stop = cfe({ name="cmdmanagement", - label="Program control-panel", - value="Stop", - type="submit", - }) - management.restart = cfe({ name="cmdmanagement", - label="Program control-panel", - value="Restart", - type="submit", - }) - -- next CFE can be used to present the result of the previous action - management.actionresult = cfe({ name="actionresult", - label="Previous action result", - }) - - -- Disable management buttons based on if the process is running or not - if (pidofstatus) then - management.start.disabled = "yes" - else - management.stop.disabled = "yes" - management.restart.disabled = "yes" +local function handle_form(getFunction, setFunction, clientdata, option, label, descr) + local form = getFunction() + + if clientdata[option] then + form.errtxt = nil + for name,value in pairs(form.value) do + value.errtxt = nil + if value.type == "boolean" then + value.value = (clientdata[name] ~= nil) + elseif value.type == "list" then + value.value = {} + if clientdata[name] and clientdata[name] ~= "" then + for ip in string.gmatch(clientdata[name].."\n", "%s*(%S[^\n]*%S)%s*\n") do + table.insert(value.value, ip) + end + end + else + value.value = clientdata[name] or value.value + end + end + form = setFunction(form) + if not form.errtxt then + form.descr = descr + end end - return management -end + form.type = "form" + form.option = option + form.label = label --- ################################################################################ --- PUBLIC FUNCTIONS + return form +end default_action = "status" function status(self) - return { status=self.model.getstatus() } + return self.model.getstatus() end -function expert(self) - local modifications = self.clientdata.filecontent or "" - if ( self.clientdata.cmdsave ) then - modifications = self.model:update_filecontent(modifications) +function startstop(self) + local result + if self.clientdata.action then + result = self.model.startstop_service(self.clientdata.action) + self.sessiondata.dnscachestartstopresult = result + self.redirect_to_referrer(self) end - local url = self.conf.script .. self.conf.prefix .. self.conf.controller - - -- Start/Stop/Restart process - local cmdmanagement, actionresult - if ( self.clientdata.cmdmanagement) then - cmdmanagement = cfe({ - name="cmdmanagement", - label="Previous action result", - action=cfe({ - name="cmdmanagement", - value=string.lower(self.clientdata.cmdmanagement), -- This row contains start/stop/restart (one of these commands) - }), - }) - actionresult, cmdmanagement = self.model:startstop_service( cmdmanagement.action ) + + local status = self.model.getstatus() + status = status.value.status + if self.sessiondata.dnscachestartstopresult then + result = self.sessiondata.dnscachestartstopresult + self.sessiondata.dnscachestartstopresult = nil end - local status=self.model.getstatus() - local file = self.model:get_filedetails() - - -- Add buttons - file.cmdsave = cfe ({ - name="cmdsave", - label="Apply settings", - value="Apply", - type="submit", - }) - if (self.clientdata.cmdsave) then - file.cmdsave.descr="* Changes has been saved!" - end - - -- Management buttons (Hide/show buttons - local pidofstatus - if (string.lower(status.status.value) == "enabled" ) then pidofstatus = true end - management = displaycmdmanagement(pidofstatus) - if (actionresult) then - management.actionresult.descr=cmdmanagement.descr - management.actionresult.errtxt=cmdmanagement.errtxt + return cfe({ type="group", value={status=status, result=result} }) +end + +function config(self) + return handle_form(self.model.getconfig, self.model.setconfig, self.clientdata, "Save", "Edit Config", "Configuration Set") +end + +function expert(self) + local filedetails + if self.clientdata.Save then + filedetails = self.model.setconfigfile(self.clientdata.filecontent) + if not filedetails.errtxt then + filedetails.descr = "Config file set" + end + else + filedetails = self.model.getconfigfile() end - - return ( { - status = status, - file = file, - modifications = modifications, - management = management, - url = url, } ) + + filedetails.type = "form" + filedetails.option = "Save" + filedetails.label = "Set config file" + + return filedetails +end + +function editips(self) + return handle_form(self.model.getIPs, self.model.setIPs, self.clientdata, "Save", "Edit IP List", "IP List Set") end -function logfile(self) +function listdomains(self) + return self.model.getDomains() +end - local status=self.model.getstatus() - local logfile = self.model:get_logfile() +function createdomain(self) + local cmdresult = handle_form(self.model.getNewDomain, self.model.setNewDomain, self.clientdata, "Create", "Create new domain", "New domain created") + if cmdresult.descr then + redirect_to_referrer(self) + end + return cmdresult +end + +function editdomain(self) + return handle_form(function(form) return self.model.getDomain(self.clientdata.domain) end, + self.model.setDomain, self.clientdata, "Save", "Edit domain entry", "Domain saved") +end - return ({ - status = status, - logfile = logfile, - url = url, - }) +function deletedomain(self) + local cmdresult = self.model.deleteDomain(self.clientdata.domain) + redirect_to_referrer(self) + return cmdresult end diff --git a/dnscache-createdomain-html.lsp b/dnscache-createdomain-html.lsp new file mode 100644 index 0000000..4347fc0 --- /dev/null +++ b/dnscache-createdomain-html.lsp @@ -0,0 +1,17 @@ + +DEBUGGING

DEBUG INFO: CFE

") +io.write(html.cfe_unpack(form)) +io.write("
") +--]] +?> + +

+ diff --git a/dnscache-editdomain-html.lsp b/dnscache-editdomain-html.lsp new file mode 100644 index 0000000..34ba902 --- /dev/null +++ b/dnscache-editdomain-html.lsp @@ -0,0 +1,17 @@ + +DEBUGGING

DEBUG INFO: CFE

") +io.write(html.cfe_unpack(form)) +io.write("
") +--]] +?> + +

+ diff --git a/dnscache-editips-html.lsp b/dnscache-editips-html.lsp new file mode 100644 index 0000000..b88e2c4 --- /dev/null +++ b/dnscache-editips-html.lsp @@ -0,0 +1,15 @@ + +DEBUGGING

DEBUG INFO: CFE

") +io.write(html.cfe_unpack(form)) +io.write("
") +--]] +?> + +

+ diff --git a/dnscache-expert-html.lsp b/dnscache-expert-html.lsp index 4f77e5e..c4ad955 100644 --- a/dnscache-expert-html.lsp +++ b/dnscache-expert-html.lsp @@ -1,6 +1,5 @@ - + + DEBUGGING

DEBUG INFO: CFE

") @@ -9,50 +8,43 @@ io.write("
") --]] ?> -

SYSTEM INFO

-
- -
+ + + -
-

CONFIGURATION

-

Expert config

-

File details

+

Configuration

+

Expert Configuration

+

File Details

-

FILE CONTENT

- +

File Content

+

") ?>

+

") ?>

+ + +

") ?>

-

SAVE AND APPLY ABOVE SETTINGS

-
- -
+
+
+ + MANAGEMENT\n
") - displaymanagement(myform,tags) - io.write("
") -end +--[[ DEBUG INFORMATION +io.write("

DEBUGGING

DEBUG INFO: CFE

") +io.write(html.cfe_unpack(form)) +io.write("
") +--]] ?> - - diff --git a/dnscache-listdomains-html.lsp b/dnscache-listdomains-html.lsp new file mode 100644 index 0000000..9c7ba20 --- /dev/null +++ b/dnscache-listdomains-html.lsp @@ -0,0 +1,34 @@ + +DEBUGGING

DEBUG INFO: CFE

") +io.write(html.cfe_unpack(data)) +io.write("
") +--]] +?> + +

Configuration

+

Edit/View DNS server entries

+ + + + + + + + + + + +
ActionDomain
+ + +
+ + diff --git a/dnscache-logfile-html.lsp b/dnscache-logfile-html.lsp deleted file mode 100644 index aa0b6e5..0000000 --- a/dnscache-logfile-html.lsp +++ /dev/null @@ -1,31 +0,0 @@ - - - -

SYSTEM INFO

-
- -
- -
-

LOGFILE

-

Details

-
- -
- -

FILE CONTENT

- - -
diff --git a/dnscache-model.lua b/dnscache-model.lua index 649fcc5..fc41cc6 100644 --- a/dnscache-model.lua +++ b/dnscache-model.lua @@ -30,180 +30,271 @@ local function process_status_text(procname) end end -local function humanreadable(value) - local myvalue = tonumber(value) - if not (myvalue) then - return false - end - if ( myvalue > 1073741824 ) then - myvalue=((myvalue/1073741824) - (myvalue/1073741824%0.1)) .. "G" - elseif ( myvalue > 1048576 ) then - myvalue=((myvalue/1048576) - (myvalue/1048576%0.1)) .. "M" - elseif ( myvalue > 1024 ) then - myvalue=((myvalue/1024) - (myvalue/1024%0.1)) .. "k" - end - return myvalue -end - -local function list_servers() - local serverlist = {} - local serverdetails = {} - for k,v in pairs(posix.dir(baseurl .. "servers")) do - if not string.match(v, "^%.") then - if (fs.is_file(baseurl .. "servers/" .. v)) then - table.insert(serverlist, v) - serverdetails[v] = fs.read_file_as_array(baseurl .. "servers/" .. v) - end +local function validateconfig(config) + local success = true + if config.value.IPSEND and not validator.is_ipv4(config.value.IPSEND.value) then + config.value.IPSEND.errtxt = "Invalid IP address" + success = false + end + if config.value.CACHESIZE and not validator.is_integer(config.value.CACHESIZE.value) then + config.value.CACHESIZE.errtxt = "Must be an integer" + success = false + end + if config.value.IP and not validator.is_ipv4(config.value.IP.value) then + config.value.IP.errtxt = "Invalid IP address" + success = false + end + return success, config +end + +local function getfiledetails(file) + local filename = cfe({ value=file, label="File name" }) + local filecontent = cfe({ type="longtext", label="File content" }) + local filesize = cfe({ value="0", label="File size" }) + local mtime = cfe({ value="---", label="File date" }) + if fs.is_file(file) then + local filedetails = fs.stat(file) + filecontent.value = fs.read_file(file) + filesize.value = filedetails.size + mtime.value = filedetails.mtime + else + filename.errtxt = "File not found" + end + return cfe({ type="group", value={filename=filename, filecontent=filecontent, filesize=filesize, mtime=mtime}, label="Config file details" }) +end + +local function validatedomain(domain) + local success = false + local domains = getDomains() + domain.value.domain.errtxt = "Invalid domain" + for i,name in ipairs(domains.value) do + if name == domain.value.domain.value then + domain.value.domain.errtxt = nil + success = true + break + end + end + for i,name in ipairs(domain.value.iplist.value) do + if not validator.is_ipv4(name) then + domain.value.iplist.errtxt = "Invalid IP address" + success = false + break end end - return serverlist, serverdetails + return success, domain end + -- ################################################################################ -- PUBLIC FUNCTIONS -function startstop_service ( self, action ) - local cmd = action.value - local cmdresult,cmdmessage,cmderror,cmdaction = daemoncontrol.daemoncontrol(processname, cmd) - action.descr=cmdmessage - action.errtxt=cmderror - return cmdresult,action +function startstop_service(action) + -- action is validated in daemoncontrol + local cmdresult,cmdmessage,cmderror,cmdaction = daemoncontrol.daemoncontrol(processname, action) + return cfe({ type="boolean", value=cmdresult, descr=cmdmessage, errtxt=cmderror, label="Start/Stop result" }) end function getstatus() local status = {} - local config = getconfig() + local value, errtxt = processinfo.package_version(packagename) - status.version = cfe({ name = "version", + status.version = cfe({ label="Program version", value=value, errtxt=errtxt, }) - status.status = cfe({ name="status", + status.status = cfe({ label="Program status", value=process_status_text(processname), }) local autostart_sequense, autostart_errtxt = processinfo.process_botsequence(processname) - status.autostart = cfe({ name="autostart", + status.autostart = cfe({ label="Autostart sequence", value=autostart_sequense, errtxt=autostart_errtxt, }) + + return cfe({ type="group", value=status, label="DNS Cache Status" }) +end - status.ip = cfe({ name="ip", - label="Listening on", - value=config.IP or "", - }) +function getconfig() + local conf = getopts.getoptsfromfile(configfile, "") or {} + local output = {} + output.IPSEND = cfe({ value = conf.IPSEND or "", label="IP address for requests", + descr="Use 0.0.0.0 for default address" }) + output.CACHESIZE = cfe({ value=conf.CACHESIZE or "0", label="Cache size" }) + output.IP = cfe({ value=conf.IP or "", label="IP address to listen on" }) + output.FORWARDONLY = cfe({ type="boolean", value=(conf.FORWARDONLY and conf.FORWARDONLY ~= ""), + label="Forward only", descr="Servers are parent caches, not root servers" }) + return cfe({ type="group", value=output, label="DNS Cache Config" }) +end - status.cachesize = cfe({ name="cachesize", - label="Cache size", - value=humanreadable(config.CACHESIZE or ""), - }) +function setconfig(config) + local success, config = validateconfig(config) - local serverlist, serverdetails = list_servers() - status.servers = cfe({ name="servers", - label="Configured DNS-servers", - value=serverlist, - option=serverdetails, - }) + if success then + local file = fs.read_file(configfile) + getopts.setoptsinfile(file,"","IPSEND",config.value.IPSEND.value) + getopts.setoptsinfile(file,"","CACHESIZE",config.value.CACHESIZE.value) + getopts.setoptsinfile(file,"","IP",config.value.IP.value) + if config.value.IPSEND.value then + getopts.setoptsinfile(file,"","FORWARDONLY",config.value.IPSEND.value) + else + getopts.setoptsinfile(file,"","FORWARDONLY","") + end + fs.write_file(configfile, file) + else + config.errtxt = "Failed to set config" + end - return status + return config end -function get_logfile () - local file = {} - local cmdtxt = "grep ".. processname .. " /var/log/messages" - local cmd, error = io.popen(cmdtxt ,r) - local cmdoutput = cmd:read("*a") - cmd:close() +function getconfigfile() + local config = getfiledetails(configfile) + return config +end - file["filename"] = cfe({ - name="filename", - label="File name", - value=cmdtxt, - }) +function setconfigfile(modifications) + local configcontent = string.gsub(format.dostounix(modifications), "\n*$", "") + local config + if fs.is_file(configfile) then + fs.write_file(configfile, configcontent) + config = getfile(configfile) + else + config = getfile(configfile) + config.value.filecontent.value = configcontent + config.errtxt = "Failed to set config" + end - file["filecontent"] = cfe({ - type="longtext", - name="filecontent", - label="File content", - value=cmdoutput, - }) + return config +end + +function getIPs() + local ipdir = baseurl.."ip" + local iplist = cfe({ type="list", value={}, label="IPs to listen for" }) + if fs.is_dir(ipdir) then + for i,name in ipairs(posix.dir(ipdir)) do + if not string.match(name, "^%.") then + if (fs.is_file(ipdir.."/"..name)) then + table.insert(iplist.value, name) + end + end + end + end + return cfe({ type="group", value={iplist=iplist} }) +end - return file +function setIPs(iplist) + local reverseIPs = {} + for i,name in ipairs(iplist.value.iplist.value) do + -- check if a valid (or partial) ip + if not validator.is_partial_ipv4(name) then + iplist.value.iplist.errtxt = "Invalid IP address" + iplist.errtxt = "Failed to set IP list" + break + end + reverseIPs[name] = i + end + if not iplist.errtxt then + local currentIPlist = getIPs() + for i,name in ipairs(currentIPlist.value.iplist.value) do + if reverseIPs[name] then + reverseIPs[name] = nil + else + -- need to delete the file + local f = io.popen("rm "..baseurl.."ip/"..name) + f:close() + end + end + for name in pairs(reverseIPs) do + -- need to create the file + local f = io.popen("touch "..baseurl.."ip/"..name) + f:close() + end + end + return iplist end -function getconfig() - if (fs.is_file(configfile)) then - return getopts.getoptsfromfile(configfile, "") or {} +function getDomains() + local domaindir = baseurl.."servers" + local domainlist = cfe({ type="list", value={}, label="DNS Server Domains" }) + if fs.is_dir(domaindir) then + for i,name in ipairs(posix.dir(domaindir)) do + if not string.match(name, "^%.") then + if (fs.is_file(domaindir.."/"..name)) then + table.insert(domainlist.value, name) + end + end + end end - return {} + return domainlist end -function get_filedetails(self,num) - local path - if (num == "2") then - path = configfile2 - else - path = configfile - end - local file = {} - local filedetails = {} - local config = {} - local filenameerrtxt - if (path) and (fs.is_file(path)) then - filedetails = fs.stat(path) - config = getconfig(path) +function getNewDomain() + local domain = cfe({ label="Domain" }) + return cfe({ type="group", value={domain=domain} }) +end + +function setNewDomain(domain) + if "" ~= string.gsub(domain.value.domain.value..".", "%w+%.", "") then + domain.value.domain.errtxt = "Invalid domain" + domain.errtxt = "Failed to create domain" + elseif fs.is_file(baseurl.."servers/"..domain.value.domain.value) then + domain.value.domain.errtxt = "Domain already exists" + domain.errtxt = "Failed to create domain" else - config = {} - config.filename = {} - config["filename"]["errtxt"]="Config file '".. path .. "' is missing!" + local f = io.popen("touch "..baseurl.."servers/"..domain.value.domain.value) + f:close() + domain.descr = "Created domain" end + return domain +end - file["filename" .. (num or "")] = cfe({ - name="filename" .. (num or ""), - label="File name", - value=path, - errtxt=filenameerrtxt - }) - file["filesize" .. (num or "")] = cfe({ - name="filesize" .. (num or ""), - label="File size", - value=filedetails.size or 0, - }) - file["mtime" .. (num or "")] = cfe({ - name="mtime" .. (num or ""), - label="File date", - value=filedetails.mtime or "---", - }) - file["filecontent" .. (num or "")] = cfe({ - type="longtext", - name="filecontent" .. (num or ""), - label="File content", - value=fs.read_file(path), - }) - - -- Sum all errors into one cfe - local sumerrors = "" - for k,v in pairs(config) do - if (config[k]) and (config[k]["errtxt"]) and (config[k]["errtxt"] ~= "") then - sumerrors = sumerrors .. config[k]["errtxt"] .. "\n" +function getDomain(getdomainname) + local domain = cfe({ value=getdomainname, label="Domain", errtxt="Invalid domain" }) + local iplist = cfe({ type="list", value={}, label="List of DNS servers" }) + local domains = getDomains() + for i,name in ipairs(domains.value) do + if name == getdomainname then + domain.errtxt = nil + break end end - if (sumerrors ~= "") then - file["sumerrors" .. (num or "")] = cfe ({ - name="sumerrors" .. (num or ""), - label = "Configuration errors", - errtxt = string.match(sumerrors, "(.-)\n$"), - }) + if not domain.errtxt then + local content = fs.read_file(baseurl.."servers/"..getdomainname) + for name in string.gmatch(content.."\n", "([^\n]+)\n") do + table.insert(iplist.value, name) + end end - - return file + return cfe({ type="group", value={domain=domain, iplist=iplist} }) end -function update_filecontent (self, modifications) - local path = configfile - local file_result,err = fs.write_file(path, format.dostounix(modifications)) - return file_result + +function setDomain(domain) + local success, domain = validatedomain(domain) + if success then + fs.write_file(baseurl.."servers/"..domain.value.domain.value, + table.concat(domain.value.iplist.value, "\n") ) + end + return domain end +function deleteDomain(domainname) + local cmdresult = cfe({ value="Domain not deleted", label="Delete domain result", errtxt="Invalid domain" }) + local domains = getDomains() + if domainname == "@" then + cmdresult.errtxt = "Cannot delete root domain" + else + for i,name in ipairs(domains.value) do + if name == domainname then + local f = io.popen("rm "..baseurl.."servers/"..name) + f:close() + cmdresult.errtxt = nil + cmdresult.value = "Domain deleted" + break + end + end + end + return cmdresult +end diff --git a/dnscache-startstop-html.lsp b/dnscache-startstop-html.lsp new file mode 100644 index 0000000..f963d3b --- /dev/null +++ b/dnscache-startstop-html.lsp @@ -0,0 +1,26 @@ + + + +

Management

+
+
+
Program control-panel
+
+> +> +> +
+
+ + +
Previous action result
+
+ +

") ?>

+ +

") ?>

+ +
+
diff --git a/dnscache-status-html.lsp b/dnscache-status-html.lsp index 40e4ee4..05b4a7a 100644 --- a/dnscache-status-html.lsp +++ b/dnscache-status-html.lsp @@ -1,49 +1,19 @@ - DEBUGGING

DEBUG INFO: CFE

") -io.write(html.cfe_unpack(form)) +io.write(html.cfe_unpack(data)) io.write("
") --]] ?> -

SYSTEM INFO

+

System Info

- -
- -

PROGRAM SPECIFIC OPTIONS/INFORMATION

-
- - -" .. myform.label .. "\n") -io.write("\t\t
\n") -for k,v in pairs(myform.value or {}) do - io.write("\t\t\t") - io.write("\n\t\t\t\n") - for k1,v1 in pairs(myform.option[v]) do - io.write("\n\t\t\t
" .. v .. "
"..v1) - end - - io.write("\t\t\t
") -end -io.write("\t\t
\n") + - -
- diff --git a/dnscache.menu b/dnscache.menu index c8a0d32..698225d 100644 --- a/dnscache.menu +++ b/dnscache.menu @@ -1,5 +1,7 @@ #CAT GROUP/DESC TAB ACTION Networking 11DNScache Status status +Networking 11DNScache Config config +Networking 11DNScache IPs editips +Networking 11DNScache DNS_Server_Entries listdomains Networking 11DNScache Expert expert -Networking 11DNScache Logfile logfile diff --git a/dnscache.roles b/dnscache.roles index 74c0431..a4f82fc 100644 --- a/dnscache.roles +++ b/dnscache.roles @@ -1,2 +1,2 @@ -READ=dnscache:status,dnscache:logfile -UPDATE=dnscache:expert +READ=dnscache:status +UPDATE=dnscache:config,dnscache:expert,dnscache:startstop,dnscache:editips,dnscache:listdomains,dnscache:createdomain,dnscache:editdomain,dnscache:deletedomain -- cgit v1.2.3