summaryrefslogtreecommitdiffstats
path: root/dhcp-model.lua
diff options
context:
space:
mode:
Diffstat (limited to 'dhcp-model.lua')
-rw-r--r--dhcp-model.lua1327
1 files changed, 470 insertions, 857 deletions
diff --git a/dhcp-model.lua b/dhcp-model.lua
index 2dd0831..11c0228 100644
--- a/dhcp-model.lua
+++ b/dhcp-model.lua
@@ -3,975 +3,588 @@
module (..., package.seeall)
--- get additional libraries
-require("procps")
+require("modelfunctions")
require("validator")
-require("daemoncontrol")
-require("procps")
-require("processinfo")
local subnet = {}
-local cfgdir = "/etc/dhcp/"
+local configfile = "/etc/dhcp/dhcpd.conf"
local processname = "dhcpd"
local packagename = "dhcp"
+local leasefile = "/var/lib/dhcp/dhcpd.leases"
+local config
-- ################################################################################
-- LOCAL FUNCTIONS
-function process_status_text(procname)
- local t = procps.pidof(procname)
- if (t) and (#t > 0) then
- return "Enabled"
- else
- return "Disabled"
- end
-end
--- ################################################################################
--- PUBLIC FUNCTIONS
-
-function getstatus ()
- local status = {}
-
- local value, errtxt = processinfo.package_version(packagename)
- status.version = cfe({ name = "version",
- label="Program version",
- value=value,
- errtxt=errtxt,
- })
-
- status.status = cfe({ name="status",
- label="Program status",
- value=process_status_text(processname),
- })
-
- 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
+local replacemagiccharacters = function(str)
+ return string.gsub(str, "[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%1")
end
---- the tokenizer functions - must be dislocated into a library later
-tokenizer = {}
-
-tokenizer.new = function( str, delim )
- local token = {}
- token.value = str;
- token.delim = delim;
- token.pos = 1
- return token
-end
-
-tokenizer.pos = function( value, substr, pos )
- local retval = pos
- local done = false
- while not done and retval <= #value do
- if string.sub( value, retval, retval ) == substr then
- done = true
- else
- retval = retval + 1
- end
- end
-
- return retval
-end
-
-tokenizer.next = function( token )
- if token.pos > #token.value then
- return token, nil
- end
-
- local strpos = tokenizer.pos( token.value, token.delim, token.pos )
- retval = string.sub(token.value, token.pos, strpos-1)
- if retval == token.delim then
- retval = ""
- token.pos = token.pos + 1
- else
- token.pos = strpos + 1
- end
-
- return token, retval
+local replaceentry = function(file, configentry, newstring)
+ if newstring then
+ return string.gsub(file, string.gsub(replacemagiccharacters(table.concat(configentry, "\n")), "\n", "%%s+"), replacemagiccharacters(newstring), 1)
+ else
+ return string.gsub(file, string.gsub(replacemagiccharacters(table.concat(configentry, "\n")), "\n", "%%s+").."%s*;%s*\n?", "", 1)
+ end
end
----
-dep_check = function ()
-
- icode = 0
- retval = {}
-
- lpos = require "posix"
- ptr, msg, code = lpos.access("/etc/dhcp")
- if ptr == nil then
- table.insert(retval, "/etc/dhcp")
- icode = icode + 1
- end
-
- ptr, msg, code = lpos.access("/usr/sbin/dhcpd")
- if ptr == nil then
- table.insert(retval, "/usr/sbin/dhcpd")
- icode = icode + 1
+local parseconfigfile = function(file)
+ -- first, remove all comments
+ file = file or ""
+ lines = {}
+ for line in string.gmatch(file, "([^\n]*)\n?") do
+ lines[#lines+1] = string.gsub(line, "#.*$", "")
end
+ file = table.concat(lines, " ")
- ptr, msg, code = lpos.access("/etc/init.d/dhcpd")
- if ptr == nil then
- table.insert(retval, "/etc/init.d/dhcpd")
- icode = icode + 1
+ -- each line either ends with ';' or with '{'...'}'
+ -- build an array with one entry per statement, each entry having an array of elements, and possibly a subarray
+ local config = {}
+ local stack = {config}
+ local entry
+ for word in string.gmatch(file, "(%S+)") do
+ if word == "{" then
+ if not entry then
+ entry = {}
+ table.insert(stack[#stack], entry)
+ end
+ entry.sub = {}
+ stack[#stack+1] = entry.sub
+ entry = nil
+ elseif word == "}" then
+ stack[#stack] = nil
+ else
+ if not entry then
+ entry = {}
+ table.insert(stack[#stack], entry)
+ entry[1] = word
+ else
+ entry[#entry+1] = word
+ end
+ if string.find(word, ";$") then
+ entry[#entry] = string.sub(word, 1, -2)
+ entry = nil
+ end
+ end
end
-
- if icode == 0 then
- retval = nil
- end
-
- return retval
+ return config
end
-config_generate = function()
+local validate_host = function( host )
+ -- FIXME
+-- hostname
+-- ip
+-- mac
+ return true, host
+end
- msg = ""
- tmpfilename = os.tmpname()
-
- -- create tmp config file
- local tmpfile = io.open( tmpfilename, "w+" )
-
- -- get, validate and write global settings to tmp config file
- settings = read_settings()
- s_msg, s_fields = validate_settings( settings )
- if #s_msg > 0 then
- tmpfile:close()
- os.remove( tmpfilename )
- msg = "Configuration Generation Failed!\n\n" ..
- "Reason: Error in Global Settings\n"
- return msg
+local validate_subnet = function( net )
+ local success = true
+ if net.value.subnet.value == "" or string.find(net.value.subnet.value, "[^%w.-]") then
+ net.value.subnet.errtxt = "Invalid domain name / IPv4 address"
+ success = false
end
-
- tmpfile:write( "authoritative;\n" )
- tmpfile:write( "ddns-update-style none;\n\n" )
- tmpfile:write( "option local-wpad-server code 252 = text;\n\n" )
-
- tmpfile:write( "include \"/etc/dhcp/dhcpd.preconfig\";\n" )
-
- if #settings.domainname.value > 0 then
- tmpfile:write( "option domain-name \"" .. settings.domainname.value .. "\";\n" )
+ if not validator.is_ipv4(net.value.netmask.value) then
+ net.value.netmask.errtxt = "Invalid IPv4 address"
+ success = false
end
- tmpfile:write( "default-lease-time " .. settings.defleasetime.value .. ";\n" )
- tmpfile:write( "max-lease-time " .. settings.maxleasetime.value .. ";\n\n" )
-
- -- get, validate and write subnet configurations to tmp config file
- tmpfile:write( "###### SUBNET CONFIG BEGIN ######\n\n" )
- subnets = get_subnets()
- local numnetworks = 0
- for k,v in ipairs(subnets) do
- numnetworks = numnetworks + 1
- net = subnet_read( v )
- sn_msg, sn_fields = validate_network( net )
- if #sn_msg > 0 then
- tmpfile:close()
- os.remove( tmpfilename )
- msg = "Configuration Generation Failed!\n\n" ..
- "Reason: Error in Subnet '" .. v .. "'\n"
- return msg
- end
-
- tmpfile:write( "# " .. net.name.value .. "\n" )
- tmpfile:write( "subnet " .. net.subnet.value .. " netmask " .. net.netmask.value .. " {\n" )
- if #net.defleasetime.value > 0 then
- tmpfile:write( " default-lease-time " .. net.defleasetime.value .. ";\n" )
- end
- if #net.maxleasetime.value > 0 then
- tmpfile:write( " max-lease-time " .. net.maxleasetime.value .. ";\n" )
- end
- tmpfile:write( " option routers " .. net.gateway.value .. ";\n" )
- dnssrvrs = ""
- if #net.dnssrv1.value > 0 then
- dnssrvrs = net.dnssrv1.value
- end
- if #net.dnssrv2.value > 0 then
- if #dnssrvrs > 0 then
- dnssrvrs = dnssrvrs .. ", " .. net.dnssrv2.value
- else
- dnssrvrs = net.dnssrv2.value
- end
- end
- if #dnssrvrs > 0 then
- tmpfile:write( " option domain-name-servers " .. dnssrvrs .. ";\n" )
- end
- if #net.domainname.value > 0 then
- tmpfile:write( " option domain-name \"" .. net.domainname.value .. "\";\n" )
- end
- if #net.wpad.value > 0 then
- tmpfile:write( " option local-wpad-server \"" .. net.wpad.value .. "\\n\";\n" )
- end
- spec2_msg = generate_pool( tmpfile, tmpfilename, net )
- if #spec2_msg > 0 then
- tmpfile:close()
- os.remove( tmpfilename )
- msg = "Configuration Generation Failed!\n\n" .. spec2_msg
- return msg
- end
- --- generate advanced part / drop in
- advancedfile = io.open( cfgdir .. net.name.value .. ".advanced", "r" )
- if advancedfile ~= nil then
- nxtline = advancedfile:read( "*l" )
- while nxtline ~= nil do
- tmpfile:write( " " .. nxtline .. "\n" )
- nxtline = advancedfile:read( "*l" )
- end
- advancedfile:close()
- end
- ---
-
- tmpfile:write( "}\n\n" )
+ if net.value.defleasetime.value ~= "" and not validator.is_integer_in_range(net.value.defleasetime.value, 1800, 86400) then
+ net.value.defleasetime.errtxt = "Lease time must be: 1800 < x < 86400"
+ success = false
end
- tmpfile:write( "###### SUBNET CONFIG END ######\n\n" )
-
- if numnetworks <= 0 then
- tmpfile:close()
- os.remove( tmpfilename )
- msg = "Configuration Generation Failed!\n\n" ..
- "Reason: No Subnets defined!\n"
- return msg
+ if net.value.maxleasetime.value ~= "" and not validator.is_integer_in_range(net.value.maxleasetime.value, 1800, 86400) then
+ net.value.maxleasetime.errtxt = "Lease time must be: 1800 < x < 86400"
+ success = false
end
-
- msg = generate_hosts( tmpfile )
- if #msg > 0 then
- tmpfile:close()
- os.remove( tmpfilename )
- return msg
+ if net.value.routers.value ~= "" then
+ for router in string.gmatch(net.value.routers.value, "([^,%s]+),?%s*") do
+ if string.find(router, "[^%w.-]") then
+ net.value.routers.errtxt = "Invalid domain name / IPv4 address"
+ success = false
+ break
+ end
+ end
end
-
- tmpfile:write( "include \"/etc/dhcp/dhcpd.postconfig\";\n" )
-
- tmpfile:close()
- os.rename( tmpfilename, "/etc/dhcp/dhcpd.conf" )
-
- -- make sure the master pre/post config files are present
- local precfg
- local postcfg
- precfg = io.open( "/etc/dhcp/dhcpd.preconfig", "r" )
- postcfg = io.open( "/etc/dhcp/dhcpd.postconfig", "r" )
-
- if precfg == nil then
- precfg = io.open( "/etc/dhcp/dhcpd.preconfig", "w+" )
+ if string.find(net.value.domainname.value, "[^%w.-]") then
+ net.value.domainname.errtxt = "Invalid domain name"
+ success = false
end
- precfg:close()
-
- if postcfg == nil then
- postcfg = io.open( "/etc/dhcp/dhcpd.postconfig", "w+" )
+ if net.value.domainnameservers.value ~= "" then
+ for server in string.gmatch(net.value.domainnameservers.value, "([^,%s]+),?%s*") do
+ if string.find(server, "[^%w.-]") then
+ net.value.domainnameservers.errtxt = "Invalid domain name / IPv4 address"
+ success = false
+ end
+ end
end
- postcfg:close()
-
- return "Configuration Generation Successful!\n"
-end
-
-generate_pool = function( tmpfile, tmpfilename, net )
- if not validator.is_ipv4( net.leaserangestart.value ) or
- not validator.is_ipv4( net.leaserangeend.value ) then
- if net.unknownclients.value == "allow" then
- msg = "Reason: permitted unknown clients but failed to define lease range!\n"
- return msg
- end
-
- return ""
- end
-
- --- pool header
- tmpfile:write( " pool {\n" )
- if net.unknownclients.value == "allow" then
- tmpfile:write( " allow known-clients;\n" )
- tmpfile:write( " allow unknown-clients;\n" )
- else
- tmpfile:write( " allow known-clients;\n" )
- tmpfile:write( " deny unknown-clients;\n" )
+ if net.value.leaserangestart.value ~= "" and not validator.is_ipv4(net.value.leaserangestart.value) then
+ net.value.leaserangestart.errtxt = "Invalid IPv4 address"
+ success = false
end
- tmpfile:write( " range " .. net.leaserangestart.value .. " " .. net.leaserangeend.value .. ";\n" )
- tmpfile:write( " }\n" )
-
- return ""
-end
-
-generate_hosts = function( outfile )
-
- local retval = ""
-
- outfile:write( "\n####### STATIC HOSTS BEGIN ######\n\n" )
-
- snets = get_subnets()
- for k,v in ipairs(snets) do
- msg = generate_hosts_persubnet( outfile, v )
- if #msg > 0 then
- return msg
+ if net.value.leaserangeend.value ~= "" then
+ if not validator.is_ipv4(net.value.leaserangeend.value) then
+ net.value.leaserangeend.errtxt = "Invalid IPv4 address"
+ success = false
+ elseif net.value.leaserangestart.value == "" then
+ net.value.leaserangeend.errtxt = "Cannot define range end without range start"
+ success = false
end
end
-
- outfile:write( "###### STATIC HOSTS END ######\n" )
-
- retval = generate_hosts_dynamic( outfile )
+ success = success and modelfunctions.validateselect(net.value.unknownclients)
- return retval
+ return success, net
end
-generate_hosts_persubnet = function( outfile, netname )
-
- local retval = ""
-
- local hostsfile = io.open( cfgdir .. netname .. ".static", "r" )
- if hostsfile ~= nil then
- local hostsdata = hostsfile:read( "*a" )
- hostsfile:close()
- if hostsdata ~= nil then
- if #hostsdata <= 0 then
- return retval
- end
- outfile:write( "# " .. netname .. "\n" )
- outfile:write( "group {\n" )
- local done = false
- local hosttoken = tokenizer.new( hostsdata, "\n" )
- while not done do
- hosttoken, nexthost = tokenizer.next( hosttoken )
- if nexthost ~= nil then
- if string.sub( nexthost, 1, 1) ~= "#" then
- local spectoken = tokenizer.new( nexthost, ";" )
- spectoken, hostname = tokenizer.next( spectoken )
- spectoken, ip = tokenizer.next( spectoken )
- spectoken, mac = tokenizer.next( spectoken )
- spectoken, comment = tokenizer.next( spectoken )
- outfile:write(" host " .. hostname .. " {\n")
- outfile:write(" hardware ethernet " .. mac .. ";\n")
- outfile:write(" fixed-address " .. ip .. ";\n")
- outfile:write(" }\n")
- end
- else
- done = true
- end
+local validate_settings = function ( settings )
+ local success = true
+ if settings.value.defleasetime.value ~= "" and not validator.is_integer_in_range(settings.value.defleasetime.value, 1800, 86400) then
+ settings.value.defleasetime.errtxt = "Out of range 1800 < x < 86400 or not integer"
+ success = false
+ end
+ if settings.value.maxleasetime.value ~= "" and not validator.is_integer_in_range(settings.value.maxleasetime.value, 1800, 86400) then
+ settings.value.maxleasetime.errtxt = "Out of range 1800 < x < 86400 or not integer"
+ success = false
+ end
+ if string.find(settings.value.domainname.value, "[^%w.-]") then
+ settings.value.domainname.errtxt = "Invalid domain name"
+ success = false
+ end
+ if settings.value.domainnameservers.value ~= "" then
+ for server in string.gmatch(settings.value.domainnameservers.value, "([^,%s]+),?%s*") do
+ if string.find(server, "[^%w.-]") then
+ settings.value.domainnameservers.errtxt = "Invalid domain name / IPv4 address"
+ success = false
end
- outfile:write( "}\n\n" )
- else
- retval = "Configuration Generation Failed: Failed to read data from subnet static hosts file for " .. netname
end
end
- return retval
+ return success, settings
end
-generate_hosts_dynamic = function( outfile )
-
- local retval = ""
-
- local hostsfile = io.open( cfgdir .. "dhcpd.dynamic", "r" )
- if hostsfile ~= nil then
- local hostsdata = hostsfile:read( "*a" )
- hostsfile:close()
- if hostsdata ~= nil then
- if #hostsdata <= 0 then
- return retval
- end
- outfile:write( "group {\n" )
- local done = false
- local hosttoken = tokenizer.new( hostsdata, "\n" )
- while not done do
- hosttoken, nexthost = tokenizer.next( hosttoken )
- if nexthost ~= nil then
- if string.sub( nexthost, 1, 1) ~= "#" then
- local spectoken = tokenizer.new( nexthost, ";" )
- spectoken, hostname = tokenizer.next( spectoken )
- spectoken, mac = tokenizer.next( spectoken )
- spectoken, comment = tokenizer.next( spectoken )
- outfile:write(" host " .. hostname .. " {\n")
- outfile:write(" hardware ethernet " .. mac .. ";\n")
- outfile:write(" }\n")
- end
- else
- done = true
- end
- end
- outfile:write( "}\n" )
- else
- retval = "Configuration Generation Failed: Failed to read data from dynamic hosts file!"
+-- Give it the string and the position of the { and it will find the corresponding }
+local find_section_end = function(file, section_start)
+ local i = section_start+1
+ local indent = 1
+ while indent > 0 and i <= #file do
+ local char = string.sub(file, i, i)
+ if char == "}" then indent = indent-1
+ elseif char == "{" then indent = indent+1
+ elseif char == "#" then i = string.find(file, "\n", i)
+ elseif char == "'" then i = string.find(file, "'", i)
+ elseif char == '"' then i = string.find(file, '"', i)
end
+ i=i+1;
end
-
- return retval
+ return i-1
end
-subnet_delete = function( name )
-
- local msg = ""
+local subnet_write = function(net)
+ local file = fs.read_file(configfile)
+ config = config or parseconfigfile(file)
- local filename = cfgdir .. name
- os.remove( filename .. ".subnet" )
- os.remove( filename .. ".static" )
- os.remove( filename .. ".dynamic" )
-
- return msg
-end
-
-advglobal_read = function()
+ -- First, add or update the submet line
+ local subnetline = "subnet "..net.value.subnet.value.." netmask "..net.value.netmask.value
+ local found = false
+ for i,value in ipairs(config or {}) do
+ if value[1] == "subnet" and value[2] == net.value.subnet.value then
+ file = replaceentry(file, value, subnetline)
+ found = true
+ end
+ end
+ if not found then file = file.."\n"..subnetline.." {\n}" end
- preconfig = ""
- postconfig = ""
- dynamic = ""
+ -- Now, find the subnet section
+ local subnet_start = select(2, string.find(file, replacemagiccharacters(subnetline).."%s*{"))
+ local subnet_end = find_section_end(file, subnet_start) - 1
+ subnet_start = string.find(file, "\n", subnet_start) + 1
+ local subnetcontent = string.sub(file, subnet_start, subnet_end)
- file = io.open( cfgdir .. "dhcpd.preconfig", "r" )
- if file ~= nil then
- preconfig = file:read( "*a" )
- if preconfig == nil then
- preconfig = ""
- end
- file:close()
+ -- Update the subnet data
+ if net.value.defleasetime.value ~= "" then
+ net.value.defleasetime.replace = "default-lease-time "..net.value.defleasetime.value
end
-
- file = io.open( cfgdir .. "dhcpd.postconfig", "r" )
- if file ~= nil then
- postconfig = file:read( "*a" )
- if postconfig == nil then
- postconfig = ""
- end
- file:close()
+ if net.value.maxleasetime.value ~= "" then
+ net.value.maxleasetime.replace = "max-lease-time "..net.value.maxleasetime.value
end
-
- file = io.open( cfgdir .. "dhcpd.dynamic", "r" )
- if file ~= nil then
- dynamic = file:read( "*a" )
- if dynamic == nil then
- dynamic = ""
- end
- file:close()
+ if net.value.routers.value ~= "" then
+ net.value.routers.replace = "option routers "..net.value.routers.value
end
-
- return cfe({ preconfig = preconfig, postconfig = postconfig, dynamic = dynamic })
-end
-
-advglobal_update = function( preconfig, postconfig, dynamic )
-
- file = io.open( cfgdir .. "dhcpd.preconfig", "wb+" )
- if file ~= nil then
- file:write( preconfig )
- file:close()
+ if net.value.domainname.value ~= "" then
+ net.value.domainname.replace = 'option domain-name "'..net.value.domainname.value..'"'
end
-
- file = io.open( cfgdir .. "dhcpd.postconfig", "wb+" )
- if file ~= nil then
- file:write( postconfig )
- file:close()
+ if net.value.domainnameservers.value ~= "" then
+ net.value.domainnameservers.replace = "option domain-name-servers "..net.value.domainnameservers.value
end
-
- file = io.open( cfgdir .. "dhcpd.dynamic", "wb+" )
- if file ~= nil then
- file:write( dynamic )
- file:close()
+ if net.value.leaserangestart.value ~= "" then
+ net.value.leaserangestart.replace = "range "..net.value.leaserangestart.value
end
-
- return cfe({ preconfig = preconfig, postconfig = postconfig, dynamic = dynamic })
-end
-
-subnet_read = function( name )
- local filename = cfgdir .. name .. ".subnet"
- local net = create_new_net( name, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil )
-
- for line in io.lines(filename) do
- if (string.sub(line, 1, 15) == "def-lease-time:") then
- net.defleasetime.value = string.sub(line, 17)
- elseif (string.sub(line, 1, 15) == "max-lease-time:") then
- net.maxleasetime.value = string.sub(line, 17)
- elseif (string.sub(line, 1, 8) == "gateway:") then
- net.gateway.value = string.sub(line, 10)
- elseif (string.sub(line, 1, 12) == "domain-name:") then
- net.domainname.value = string.sub(line, 14)
- elseif (string.sub(line, 1, 10) == "dns-srv-1:") then
- net.dnssrv1.value = string.sub(line, 12)
- elseif (string.sub(line, 1, 10) == "dns-srv-2:") then
- net.dnssrv2.value = string.sub(line, 12)
- elseif (string.sub(line, 1, 7) == "subnet:") then
- net.subnet.value = string.sub(line, 9)
- elseif (string.sub(line, 1, 8) == "netmask:") then
- net.netmask.value = string.sub(line, 10)
- elseif (string.sub(line, 1, 18) == "lease-range-start:") then
- net.leaserangestart.value = string.sub(line, 20)
- elseif (string.sub(line, 1, 16) == "lease-range-end:") then
- net.leaserangeend.value = string.sub(line, 18)
- elseif (string.sub(line, 1, 5) == "wpad:") then
- net.wpad.value = string.sub(line, 7)
- elseif (string.sub(line, 1, 16) == "unknown-clients:") then
- net.unknownclients.value = string.sub(line, 18)
- end
+ if net.value.leaserangeend.value ~= "" then
+ net.value.leaserangestart.replace = net.value.leaserangestart.replace.." "..net.value.leaserangeend.value
end
- if net.unknownclients.value ~= "allow" then
- net.unknownclients.value = "deny"
+ if net.value.unknownclients.value ~= "" then
+ net.value.unknownclients.replace = net.value.unknownclients.value.." unknown-clients"
end
-
- net.statichosts.value = subnet_get_spechosts( name, "static" )
- net.advanced.value = subnet_get_spechosts( name, "advanced" )
-
- return net
-end
-subnet_get_spechosts = function( name, suffix )
- local retval = ""
- local filename = cfgdir .. name .. "." .. suffix
- if file_exists( filename ) then
- local file = io.open( filename, "r" )
- if file ~= nil then
- msg = file:read( "*a" )
- if msg ~= nil then
- retval = msg
+ local subnetconfig = parseconfigfile(subnetcontent)
+ for i,value in ipairs(subnetconfig or {}) do
+ if value[1] == "default-lease-time" then
+ subnetcontent = replaceentry(subnetcontent, value, net.value.defleasetime.replace)
+ net.value.defleasetime.replace = nil
+ elseif value[1] == "max-lease-time" then
+ subnetcontent = replaceentry(subnetcontent, value, net.value.maxleasetime.replace)
+ net.value.maxleasetime.replace = nil
+ elseif value[1] == "option" then
+ if value[2] == "routers" then
+ subnetcontent = replaceentry(subnetcontent, value, net.value.routers.replace)
+ net.value.routers.replace = nil
+ elseif value[2] == "domain-name" then
+ subnetcontent = replaceentry(subnetcontent, value, net.value.domainname.replace)
+ net.value.domainname.replace = nil
+ elseif value[2] == "domain-name-servers" then
+ subnetcontent = replaceentry(subnetcontent, value, net.value.domainnameservers.replace)
+ net.value.domainnameservers.replace = nil
+ end
+ elseif value[1] == "range" then
+ -- We need to steal the dynamic-bootp status
+ if value[2] == "dynamic-bootp" and net.value.leaserangestart.replace then
+ net.value.leaserangestart.replace = string.gsub(net.value.leaserangestart.replace, "range", "%1 "..value[2])
+ end
+ -- Need to use a pool if unknownclients defined
+ if net.value.unknownclients.replace then
+ subnetcontent = replaceentry(subnetcontent, value)
+ else
+ subnetcontent = replaceentry(subnetcontent, value, net.value.leaserangestart.replace)
+ net.value.leaserangestart.replace = nil
+ end
+ -- We only support one pool per subnet
+ elseif value[1] == "pool" then
+ for x,y in ipairs(value.sub or {}) do
+ if y[2] == "unknown-clients" then
+ subnetcontent = replaceentry(subnetcontent, y, net.value.unknownclients.replace)
+ net.value.unknownclients.replace = nil
+ elseif y[1] == "range" then
+ -- We need to steal the dynamic-bootp status
+ if y[2] == "dynamic-bootp" and net.value.leaserangestart.replace then
+ net.value.leaserangestart.replace = string.gsub(net.value.leaserangestart.replace, "range", "%1 "..y[2])
+ end
+ subnetcontent = replaceentry(subnetcontent, y, net.value.leaserangestart.replace)
+ net.value.leaserangestart.replace = nil
+ end
+ end
+ if net.value.leaserangestart.replace then
+ subnetcontent = string.gsub(subnetcontent, "(pool%s*{%s*\n)", "%1"..replacemagiccharacters(net.value.leaserangestart.replace)..";\n")
+ net.value.leaserangestart.replace = nil
+ end
+ if net.value.unknownclients.replace then
+ subnetcontent = string.gsub(subnetcontent, "(pool%s*{%s*\n)", "%1"..replacemagiccharacters(net.value.unknownclients.replace)..";\n")
+ net.value.unknownclients.replace = nil
end
- file:close()
end
end
-
- return retval
-end
-subnet_update_statichosts = function( name, statichosts )
- local msg = "";
- local filename = cfgdir .. name .. ".static"
-
- file, errmsg = io.open( filename, "wb+" )
- if file == nil then
- msg = "Error: Failed to open " .. filename .. "(" .. errmsg .. ")!"
- else
- file:write( statichosts )
- file:close()
+ -- add in new lines at the top if they didn't exist
+ local newlines = {}
+ newlines[#newlines+1] = net.value.defleasetime.replace
+ net.value.defleasetime.replace = nil
+ newlines[#newlines+1] = net.value.maxleasetime.replace
+ net.value.maxleasetime.replace = nil
+ newlines[#newlines+1] = net.value.routers.replace
+ net.value.routers.replace = nil
+ newlines[#newlines+1] = net.value.domainname.replace
+ net.value.domainname.replace = nil
+ newlines[#newlines+1] = net.value.domainnameservers.replace
+ net.value.domainnameservers.replace = nil
+ if net.value.leaserangestart.replace and not net.value.unknownclients.replace then
+ newlines[#newlines+1] = net.value.leaserangestart.replace
+ net.value.leaserangestart.replace = nil
end
-
- return msg
-end
-
-subnet_update_advanced = function( name, advanced )
- local msg = "";
- local filename = cfgdir .. name .. ".advanced"
-
- file, errmsg = io.open( filename, "wb+" )
- if file == nil then
- msg = "Error: Failed to open " .. filename .. "(" .. errmsg .. ")!"
- else
- file:write( advanced )
- file:close()
+ if #newlines > 0 then
+ for i,line in ipairs(newlines) do newlines[i] = " "..line end
+ newlines[#newlines+1] = subnetcontent
+ subnetcontent = table.concat(newlines, ";\n")
end
-
- return msg
-end
-
-read_settings = function()
- local filename = cfgdir .. "globalsettings.conf"
- local settings = create_new_settings( nil, nil, nil )
- if file_exists( filename ) then
- for line in io.lines(filename) do
- if (string.sub(line, 1, 15) == "def-lease-time:") then
- settings.defleasetime.value = string.sub(line, 17)
- elseif (string.sub(line, 1, 15) == "max-lease-time:") then
- settings.maxleasetime.value = string.sub(line, 17)
- elseif (string.sub(line, 1, 12) == "domain-name:") then
- settings.domainname.value = string.sub(line, 14)
- end
+ if net.value.unknownclients.replace then
+ local temp = " pool {\n "..net.value.unknownclients.replace..";\n"
+ net.value.unknownclients.replace = nil
+ if net.value.leaserangestart.replace then
+ temp = temp .. " " .. net.value.leaserangestart.replace .. ";\n"
+ net.value.leaserangestart.replace = nil
end
+ subnetcontent = subnetcontent .. temp .. " }\n"
end
-
- return settings
+
+ -- The subnet is updated, put it into the file
+ file = string.sub(file, 1, subnet_start-1) .. subnetcontent .. string.sub(file, subnet_end+1, -1)
+
+ -- Finally, write out the new file
+ fs.write_file(configfile, string.gsub(file, "\n*$", ""))
+ config = nil
end
-subnet_write = function( net )
- msg, fields = validate_network( net )
- if #msg > 0 then
- return cfe({ msg = msg, fields = fields }), net
- end
- local filename = cfgdir .. net.name.value .. ".subnet"
- local file = io.open( filename, "w+" )
- file:write( "def-lease-time: " .. net.defleasetime.value .. "\n" )
- file:write( "max-lease-time: " .. net.maxleasetime.value .. "\n" )
- file:write( "gateway: " .. net.gateway.value .. "\n" )
- file:write( "domain-name: " .. net.domainname.value .. "\n" )
- file:write( "dns-srv-1: " .. net.dnssrv1.value .. "\n" )
- file:write( "dns-srv-2: " .. net.dnssrv2.value .. "\n" )
- file:write( "subnet: " .. net.subnet.value .. "\n" )
- file:write( "netmask: " .. net.netmask.value .. "\n" )
- file:write( "lease-range-start: " .. net.leaserangestart.value .. "\n" )
- file:write( "lease-range-end: " .. net.leaserangeend.value .. "\n" )
- file:write( "wpad: " .. net.wpad.value .. "\n" )
- file:write( "unknown-clients: " .. net.unknownclients.value .. "\n" )
- file:close()
-
- spec_msg = validate_statichosts( net.statichosts.value )
- if #spec_msg == 0 then
- spec_msg = subnet_update_statichosts( net.name.value, net.statichosts.value )
- if #spec_msg > 0 then
- msg = spec_msg
- table.insert( fields, "statichosts" )
- end
- else
- msg = spec_msg
- table.insert( fields, "statichosts" )
- end
+-- ################################################################################
+-- PUBLIC FUNCTIONS
- spec_msg = subnet_update_advanced( net.name.value, net.advanced.value )
- if #spec_msg > 0 then
- msg = spec_msg
- table.insert( fields, "advanced" )
- end
-
- return cfe({ msg = msg, fields = {}}), net
+function startstop_service(action)
+ return modelfunctions.startstop_service(processname, action)
end
-validate_statichosts = function( statichosts )
- local line = 1
- local msg = ""
- local done = false
- hosttoken = tokenizer.new( statichosts, "\n")
- while not done do
- hosttoken, nexthost = tokenizer.next( hosttoken )
- if nexthost ~= nil then
- if string.sub(nexthost, 1, 1) ~= "#" then
- fieldtoken = tokenizer.new( nexthost, ";")
- fieldtoken, hostname = tokenizer.next( fieldtoken )
- fieldtoken, ip = tokenizer.next( fieldtoken )
- fieldtoken, mac = tokenizer.next( fieldtoken )
- fieldtoken, comment = tokenizer.next( fieldtoken )
- if hostname == nil then
- msg = msg .. "Static Hosts: hostname missing on line " .. line .. "!\n"
- else
- if not is_valid_hostname( hostname ) then
- msg = msg .. "Static Hosts: Invalid hostname on line " .. line .. "!\n"
+
+function getstatus ()
+ return modelfunctions.getstatus(processname, packagename, "DHCP Status")
+end
+
+create_new_subnet = function()
+ net = {
+ subnet = cfe({ label="Subnet" }),
+ netmask = cfe({ label="Netmask" }),
+ defleasetime = cfe({ label="Default Lease Time" }),
+ maxleasetime = cfe({ label="Maximum Lease Time" }),
+ routers = cfe({ label="Routers", descr="Comma-separated addresses" }),
+ domainname = cfe({ label="Domainname" }),
+ domainnameservers = cfe({ label="Domain Name Servers", descr="Comma-separated addresses" }),
+ --wpad = cfe({ label="Web Proxy Auto Discovery" }),
+ leaserangestart = cfe({ label="Lease Range Start" }),
+ leaserangeend = cfe({ label="Lease Range End" }),
+ unknownclients = cfe({ type="select", label="Unknown Clients", option={"", "allow", "deny"} }),
+ }
+
+ return cfe({ type="group", value=net, label="Subnet" })
+end
+
+subnet_read = function( name )
+ config = config or parseconfigfile(fs.read_file(configfile))
+ local net = create_new_subnet()
+ net.value.subnet.value = name
+ local pools = 0
+ local ranges = 0
+
+ for j,k in ipairs(config) do
+ if k[1] == "subnet" and k[2] == name then
+ net.value.netmask.value = k[4] or ""
+ for i,value in ipairs(k.sub or {}) do
+ if value[1] == "default-lease-time" then
+ net.value.defleasetime.value = value[2] or ""
+ elseif value[1] == "max-lease-time" then
+ net.value.maxleasetime.value = value[2] or ""
+ elseif value[1] == "option" then
+ if value[2] == "routers" then
+ net.value.routers.value = table.concat(value, " ", 3)
+ elseif value[2] == "domain-name" then
+ net.value.domainname.value = string.sub(value[3] or "", 2, -2)
+ elseif value[2] == "domain-name-servers" then
+ net.value.domainnameservers.value = table.concat(value, " ", 3)
+ --elseif value[2] == "local-wpad-server" then
+ -- net.value.wpad.value = string.sub(value[3] or "", 2, -2)
end
- end
- if ip == nil then
- msg = msg .. "Static Hosts: ip missing on line " .. line .. "!\n"
- else
- if not validator.is_ipv4( ip ) then
- msg = msg .. "Static Hosts: Invalid ip on line " .. line .. "!\n"
+ elseif value[1] == "range" then
+ ranges = ranges + 1
+ if value[2] == "dynamic-bootp" then
+ net.value.leaserangestart.value = value[3] or ""
+ net.value.leaserangeend.value = value[4] or ""
+ else
+ net.value.leaserangestart.value = value[2] or ""
+ net.value.leaserangeend.value = value[3] or ""
end
- end
- if mac == nil then
- msg = msg .. "Static Hosts: mac missing on line " .. line .. "!\n"
- else
- if not validator.is_mac( mac ) then
- msg = msg .. "Static Hosts: Invalid mac on line " .. line .. "!\n"
+ -- We only support one pool per subnet
+ elseif value[1] == "pool" then
+ pools = pools + 1
+ for x,y in ipairs(value.sub or {}) do
+ if y[2] == "unknown-clients" then
+ net.value.unknownclients.value = y[1]
+ elseif y[1] == "range" then
+ ranges = ranges + 1
+ if y[2] == "dynamic-bootp" then
+ net.value.leaserangestart.value = y[3] or ""
+ net.value.leaserangeend.value = y[4] or ""
+ else
+ net.value.leaserangestart.value = y[2] or ""
+ net.value.leaserangeend.value = y[3] or ""
+ end
+ end
end
end
end
- line = line + 1
- else
- done = true
+ break
end
end
+
+ if pools > 1 or ranges > 1 then
+ net.value.subnet.errtxt = "Warning! This subnet contains multiple pool/range definitions. This is not supported by ACF. Saving may break functionality!"
+ end
- return msg
+ return net
end
-validate_dynamichosts = function( dynamichosts )
- local line = 1
- msg = ""
- local done = false
- hosttoken = tokenizer.new( dynamichosts, "\n")
- while not done do
- hosttoken, nexthost = tokenizer.next( hosttoken )
- if nexthost ~= nil then
- if string.sub(nexthost, 1, 1) ~= "#" then
- fieldtoken = tokenizer.new( nexthost, ";")
- fieldtoken, hostname = tokenizer.next( fieldtoken )
- fieldtoken, mac = tokenizer.next( fieldtoken )
- fieldtoken, comment = tokenizer.next( fieldtoken )
- if hostname == nil then
- msg = msg .. "Dynamic Hosts: hostname missing on line " .. line .. "!\n"
- else
- if not is_valid_hostname( hostname ) then
- msg = msg .. "Dynamic Hosts: Invalid hostname on line " .. line .. "!\n"
- end
- end
- if mac == nil then
- msg = msg .. "Dynamic Hosts: mac missing on line " .. line .. "!\n"
- else
- if not validator.is_mac( mac ) then
- msg = msg .. "Dynamic Hosts: Invalid mac on line " .. line .. "!\n"
- end
- end
+subnet_update = function( net )
+ local success, net = validate_subnet( net )
+ if not net.value.subnet.errtxt then
+ local previous_success = success
+ success = false
+ net.value.subnet.errtxt = "This subnet does not exist"
+ local subnets = get_subnets()
+ for i,subnet in ipairs(subnets.value) do
+ if subnet == net.value.subnet.value then
+ success = previous_success
+ net.value.subnet.errtxt = nil
+ break
end
- line = line + 1
- else
- done = true
end
end
-
- return msg
-end
-
-update_settings = function ( settings )
-
- msg, fields = validate_settings ( settings )
- if #msg > 0 then
- return cfe({ msg = msg, fields = fields }), settings
+ if success then
+ subnet_write(net)
+ else
+ net.errtxt = "Failed to update subnet"
end
- local filename = cfgdir .. "globalsettings.conf"
- local file = io.open( filename, "w+" )
- file:write( "def-lease-time: " .. settings.defleasetime.value .. "\n" )
- file:write( "max-lease-time: " .. settings.maxleasetime.value .. "\n" )
- file:write( "domain-name: " .. settings.domainname.value .. "\n" )
- return cfe({ msg = "", fields = {}}), settings
+
+ return net
end
-
subnet_create = function( net )
- if file_exists( cfgdir .. net.name.value .. ".subnet" ) then
- return cfe({ msg = "This subnet already exists!", fields = {}}), net
- end
- retcode, net = subnet_write( net )
- return retcode, net
-end
-
-_tonumber = function( value )
- ret = tonumber( value )
- if (ret == nil) then
- ret = 0
- end
- return ret
-end
-
-validate_network = function( net )
- fields = {}
- msg = ""
- if #net.name.value < 3 then
- table.insert(fields, "name")
- msg = msg .. "Minimum network name length is 3 characters!\n"
- end
- if not is_valid_netname( net.name.value ) then
- table.insert( fields, "name" )
- msg = msg .. "Invalid network name: allowed characters are: 'a..z', '0..9', '-'\n"
- end
- if net.name.value == "<new>" then
- table.insert(fields, "name")
- msg = msg .. "&lt;new&gt; is not a valid network name!\n"
- end
- if #net.defleasetime.value > 0 then
- if not validator.is_integer_in_range(_tonumber(net.defleasetime.value), 1800, 86400) then
- table.insert(fields, "defleasetime")
- msg = msg .. "Default-Lease-Time must be: 1800 < x < 86400\n"
- end
- end
- if #net.maxleasetime.value > 0 then
- if not validator.is_integer_in_range(_tonumber(net.maxleasetime.value), 1800, 86400) then
- table.insert(fields, "maxleasetime")
- msg = msg .. "Maximum-Lease-Time must be: 1800 < x < 86400\n"
- end
- end
- if not validator.is_ipv4(net.gateway.value) then
- table.insert(fields, "gateway")
- msg = msg .. "Gateway: invalid IPv4 address!\n"
- end
- if #net.dnssrv1.value > 0 then
- if not validator.is_ipv4(net.dnssrv1.value) then
- table.insert(fields, "dnssrv1")
- msg = msg .. "DNS Server 1: invalid IPv4 address!\n"
- end
- end
- if not validator.is_ipv4(net.dnssrv2.value) then
- if #net.dnssrv2.value > 0 then
- table.insert(fields, "dnssrv2")
- msg = msg .. "DNS Server 2: invalid IPv4 address!\n"
- end
- end
- if not validator.is_ipv4(net.subnet.value) then
- table.insert(fields, "subnet")
- msg = msg .. "Subnet: invalid IPv4 address!\n"
- end
- if not validator.is_ipv4(net.netmask.value) then
- table.insert(fields, "netmask")
- msg = msg .. "Netmask: invalid IPv4 address!\n"
- end
- if #net.leaserangestart.value > 0 then
- if not validator.is_ipv4(net.leaserangestart.value) then
- table.insert(fields, "leaserangestart")
- msg = msg .. "Lease-Range-Start: invalid IPv4 address!\n"
+ local success, net = validate_subnet(net)
+ if not net.value.subnet.errtxt then
+ local subnets = get_subnets()
+ for i,subnet in ipairs(subnets.value) do
+ if subnet == net.value.subnet.value then
+ success = false
+ net.value.subnet.errtxt = "This subnet already exists"
+ break
+ end
end
end
- if #net.leaserangeend.value > 0 then
- if not validator.is_ipv4(net.leaserangeend.value) then
- table.insert(fields, "leaserangeend")
- msg = msg .. "Lease-Range-End: invalid IPv4 address!\n"
- end
+ if success then
+ subnet_write(net)
+ else
+ net.errtxt = "Failed to create subnet"
end
- return msg, fields
-end
-
-file_exists = function( filename )
- retval = false
- lpos = require "posix"
- ptr, msg, code = lpos.access( filename )
- if ptr ~= nil then
- retval = true
- end
- return retval
+ return net
end
-read_file = function ( filename )
- local contents = ""
- local line = ""
- local file = io.open( filename, "r" )
- if file ~= nil then
- line = file:read( "*l" )
- while line ~= nil do
- contents = contents .. "\n" .. line
- line = file:read( "*l" )
+subnet_delete = function(name)
+ local file = fs.read_file(configfile)
+ config = config or parseconfigfile(file)
+ local cmdresult = cfe({ value="Failed to delete subnet - not found", label="Delete subnet result" })
+ local subnets = get_subnets()
+ for i,subnet in ipairs(subnets.value) do
+ if subnet == name then
+ local start, endd = string.find(file, "subnet%s*"..replacemagiccharacters(name).."%s*netmask[^{]*{")
+ endd = find_section_end(file, endd)
+ endd = string.find(file, "\n", endd)
+ file = string.sub(file, 1, start-1) .. string.sub(file, endd+1, -1)
+ fs.write_file(configfile, string.gsub(file, "\n*$", ""))
+ config = nil
end
- file:close()
- else
- contents = "\n Error: File not found!\n\n"
end
- return contents
+ return cmdresult
end
-is_running = function( process )
- return procps.pidof(process) ~= nil
-end
-
-get_dhcpd_version = function()
- local retval = "dhcpd"
- local file = io.popen("/usr/sbin/dhcpd --version 2>&1")
- if file ~= nil then
- local line = file:read( "*a" )
- if #line > 0 then
- retval = line
+get_subnets = function ()
+ config = config or parseconfigfile(fs.read_file(configfile))
+ local retval = {}
+ for i,entry in ipairs(config) do
+ if string.lower(entry[1] or "") == "subnet" then
+ table.insert(retval, entry[2])
end
- file:close()
end
- return retval
+ return cfe({ type="list", value=retval, label="Subnet list" })
end
-service_control = function ( command )
-
- local retval = ""
- local code = false
- local x
- local y
-
- code, retval, x, y = daemoncontrol.daemoncontrol ( "dhcpd", command )
-
- return retval
-end
-
-function nonil( value )
- local retval = ""
- if value ~= nil then
- retval = value
- end
-
- return retval
-end
-
-get_subnets = function ()
-
- local retval = {}
-
- lpos = require "posix"
- files = lpos.dir( "/etc/dhcp" )
- for k,v in ipairs(files) do
- if string.sub(v, -7) == ".subnet" then
- table.insert(retval, string.sub(v, 1, -8))
+read_settings = function()
+ config = config or parseconfigfile(fs.read_file(configfile))
+ local domainname = cfe({ label="Domain Name" })
+ local domainnameservers = cfe({ label="Domain Name Servers", descr="Comma-separated addresses" })
+ local defleasetime = cfe({ label="Default Lease Time" })
+ local maxleasetime = cfe({ label="Maximum Lease Time" })
+ for i,value in ipairs(config) do
+ if value[1] == "option" then
+ if value[2] == "domain-name" then
+ domainname.value = string.sub(value[3] or "", 2, -2)
+ elseif value[2] == "domain-name-servers" then
+ domainnameservers.value = table.concat(value, " ", 3)
+ end
+ elseif value[1] == "default-lease-time" then
+ defleasetime.value = value[2] or ""
+ elseif value[1] == "max-lease-time" then
+ maxleasetime.value = value[2] or ""
end
end
- return retval
+ return cfe({ type="group", value={domainname=domainname, domainnameservers=domainnameservers, defleasetime=defleasetime, maxleasetime=maxleasetime}, label = "Global settings" })
end
-create_new_net = function( name, defleasetime, maxleasetime, gateway, domainname, dnssrv1, dnssrv2, subnet, netmask, leaserangestart, leaserangeend, wpad, statichosts, unknownclients, dynamichosts, advanced, useadvanced )
- net = { name = { label="Name", value=nonil(name), type="message" },
- defleasetime = { label="Default Lease Time", value=nonil(defleasetime), type="text" },
- maxleasetime = { label="Maximum Lease Time", value=nonil(maxleasetime), type="text" },
- gateway = { label="Gateway", value=nonil(gateway), type="text" },
- domainname = { label="Domainname", value=nonil(domainname), type="text" },
- dnssrv1 = { label="DNS Server 1", value=nonil(dnssrv1), type="text" },
- dnssrv2 = { label="DNS Server 2", value=nonil(dnssrv2), type="text" },
- subnet = { label="Subnet", value=nonil(subnet), type="text" },
- netmask = { label="Netmask", value=nonil(netmask), type="text" },
- leaserangestart = { label="Lease Range Start", value=nonil(leaserangestart), type="text" },
- leaserangeend = { label="Lease Range End", value=nonil(leaserangeend), type="text" },
- wpad = { label="Web Proxy Auto Discovery", value=nonil(wpad), type="text" },
- statichosts = { label="Static Hosts", value=nonil(statichosts), type="text" },
- dynamichosts = { label="Dynamic Hosts", value=nonil(dynamichosts), type="text" },
- unknownclients = { label="Unknown Clients", value=nonil(unknownclients), type="text" },
- advanced = { label="Advanced", value=nonil(advanced), type="text" },
- useadvanced = { label="Use Advanced", value=nonil(useadvanced), type="text" }
- }
- if net.unknownclients.value ~= "allow" then
- net.unknownclients.value = "deny"
+update_settings = function ( settings )
+ success, settings = validate_settings(settings)
+ if success then
+ local file = fs.read_file(configfile)
+ config = config or parseconfigfile(file)
+
+ -- set up the lines we want to enter
+ if settings.value.domainname.value ~= "" then
+ settings.value.domainname.replace = 'option domain-name "'..settings.value.domainname.value..'"'
+ end
+ if settings.value.domainnameservers.value ~= "" then
+ settings.value.domainnameservers.replace = "option domain-name-servers "..settings.value.domainnameservers.value
+ end
+ if settings.value.defleasetime.value ~= "" then
+ settings.value.defleasetime.replace = "default-lease-time "..settings.value.defleasetime.value
+ end
+ if settings.value.maxleasetime.value ~= "" then
+ settings.value.maxleasetime.replace = "max-lease-time "..settings.value.maxleasetime.value
+ end
+
+ -- replace existing lines
+ for i,value in ipairs(config) do
+ if value[1] == "option" then
+ if value[2] == "domain-name" then
+ file = replaceentry(file, value, settings.value.domainname.replace)
+ settings.value.domainname.replace = nil
+ elseif value[2] == "domain-name-servers" then
+ file = replaceentry(file, value, settings.value.domainnameservers.replace)
+ settings.value.domainnameservers.replace = nil
+ end
+ elseif value[1] == "default-lease-time" then
+ file = replaceentry(file, value, settings.value.defleasetime.replace)
+ settings.value.defleasetime.replace = nil
+ elseif value[1] == "max-lease-time" then
+ file = replaceentry(file, value, settings.value.maxleasetime.replace)
+ settings.value.maxleasetime.replace = nil
+ end
+ end
+
+ -- add in new lines at the top if they didn't exist
+ local newlines = {}
+ newlines[#newlines+1] = settings.value.domainname.replace
+ settings.value.domainname.replace = nil
+ newlines[#newlines+1] = settings.value.domainnameservers.replace
+ settings.value.domainnameservers.replace = nil
+ newlines[#newlines+1] = settings.value.defleasetime.replace
+ settings.value.defleasetime.replace = nil
+ newlines[#newlines+1] = settings.value.maxleasetime.replace
+ settings.value.maxleasetime.replace = nil
+ if #newlines > 0 then
+ newlines[#newlines+1] = file
+ file = table.concat(newlines, ";\n")
+ end
+ fs.write_file(configfile, string.gsub(file, "\n*$", ""))
+ config = nil
+ else
+ settings.errtxt = "Failed to update global settings"
end
-
- return net
-end
-create_new_settings = function( defleasetime, maxleasetime, domainname )
- settings = { domainname = { label="Domainname", type="text", value=nonil(domainname) },
- defleasetime = { label="Default Lease Time", type="text", value=nonil(defleasetime) },
- maxleasetime = { label="Maximum Lease Time", type="text", value=nonil(maxleasetime) }
- }
return settings
end
-validate_settings = function ( settings )
-
- msg = ""
- fields = {}
-
- if not validator.is_integer_in_range(_tonumber(settings.defleasetime.value), 1800, 86400) then
- msg = msg .. "Default Lease Time: Out of range 1800 < x < 86400 or not integer\n"
- table.insert( fields, "defleasetime" )
- end
- if not validator.is_integer_in_range(_tonumber(settings.maxleasetime.value), 1800, 86400) then
- msg = msg .. "Maximum Lease Time: Out of range 1800 < x < 86400 or not integer\n"
- table.insert( fields, "maxleasetime" )
- end
- if not is_valid_hostname( settings.domainname.value ) then
- if #settings.domainname.value > 0 then
- msg = msg .. "Invalid domainname: valid chars are 'a..z', '0..9', '.', '-'\n"
- table.insert( fields, "domainname" )
- end
- end
-
- return msg, fields
+getconfigfile = function()
+ return modelfunctions.getfiledetails(configfile)
end
-is_valid_hostname = function ( hostname )
-
- local retval = true
-
- name = string.lower( hostname )
- lap = 1
- while lap <= #name do
- chr = string.sub(name, lap, lap)
- if (chr >= "a" and chr <= "z") or
- (chr >= "0" and chr <= "9") or
- (chr == ".") or (chr == "-") then
-
- else
- retval = false
- end
- lap = lap + 1
- end
-
- return retval
+setconfigfile = function(filedetails)
+ filedetails.value.filename.value = configfile
+ return modelfunctions.setfiledetails(filedetails)
end
-is_valid_netname = function ( netname )
-
- local retval = true
-
- name = string.lower( netname )
- lap = 1
- while lap <= #name do
- chr = string.sub( name, lap, lap )
- if (chr >= "a" and chr <= "z") or
- (chr >= "0" and chr <= "9") or
- (chr == "-") then
-
- else
- retval = false
- end
- lap = lap + 1
- end
-
- return retval
+getleases = function()
+ return modelfunctions.getfiledetails(leasefile)
end
-