diff options
-rw-r--r-- | dhcp-controller.lua | 280 | ||||
-rw-r--r-- | dhcp-createnet-html.lsp | 76 | ||||
l--------- | dhcp-createsubnet-html.lsp | 1 | ||||
-rw-r--r-- | dhcp-delnet-html.lsp | 30 | ||||
-rw-r--r-- | dhcp-dep-html.lsp | 14 | ||||
-rw-r--r-- | dhcp-editnet-html.lsp | 96 | ||||
-rw-r--r-- | dhcp-editspc-html.lsp | 40 | ||||
-rw-r--r-- | dhcp-editsubnet-html.lsp | 13 | ||||
l--------- | dhcp-expert-html.lsp | 1 | ||||
-rw-r--r-- | dhcp-help-html.lsp | 22 | ||||
-rw-r--r-- | dhcp-home-html.lsp | 113 | ||||
-rw-r--r-- | dhcp-listsubnets-html.lsp | 27 | ||||
-rw-r--r-- | dhcp-model.lua | 1327 | ||||
-rw-r--r-- | dhcp-settings-html.lsp | 42 | ||||
l--------- | dhcp-startstop-html.lsp | 1 | ||||
l---------[-rw-r--r--] | dhcp-status-html.lsp | 37 | ||||
-rw-r--r-- | dhcp-viewconfig-html.lsp | 12 | ||||
l---------[-rw-r--r--] | dhcp-viewleases-html.lsp | 13 | ||||
-rw-r--r-- | dhcp.menu | 3 | ||||
-rw-r--r-- | dhcp.roles | 8 |
20 files changed, 560 insertions, 1596 deletions
diff --git a/dhcp-controller.lua b/dhcp-controller.lua index b79c3dc..13639f0 100644 --- a/dhcp-controller.lua +++ b/dhcp-controller.lua @@ -1,286 +1,42 @@ -- the dhcpd controller - module (..., package.seeall) -default_action = "status" - -dep = function( self ) - - -- do the dependancy check - msg = self.model.dep_check() - - -- make sure nobody accidentally calls this action - if msg == nil then - redirect(self, "home") - end - - -- go ahead - return ( cfe ({ msg = msg }) ) -end +require("controllerfunctions") -help = function( self ) +default_action = "status" - return ( cfe ({ option = "" }) ) +status = function ( self ) + return self.model.getstatus() end -delnet = function( self ) - - local net = {} - - if not self.clientdata.cmd then - redirect(self) - end - if not self.clientdata.network then - redirect(self) - end - - local option = { script = self.conf.script, - prefix = self.conf.prefix, - controller = self.conf.controller, - action = self.conf.action, - extra = "" - } - - if self.clientdata.cmd == "delete" then - if self.clientdata.confirm == "yes" then - msg = self.model.subnet_delete( self.clientdata.network ) - redirect(self) - else - net = self.model.subnet_read( self.clientdata.network ); - return ( cfe({ option = option, value = net, msg = msg }) ) - end - end +startstop = function ( self ) + return controllerfunctions.handle_startstop(self, self.model.startstop_service, self.model.getstatus, self.clientdata) end settings = function( self ) - - if not self.clientdata.cmd then - redirect(self) - end - - local settings = {} - local option = { script = self.conf.script, - prefix = self.conf.prefix, - controller = self.conf.controller, - action = self.conf.action, - extra = "" - } - - if self.clientdata.cmd == "update" then - tmp = self.clientdata - settings = self.model.create_new_settings( tmp.defleasetime, tmp.maxleasetime, tmp.domainname ) - errcode, settings = self.model.update_settings( settings ) - return ( cfe ({ option = option, value = settings, errcode = errcode })) - else - settings = self.model.read_settings() - return ( cfe ({ option = option, value = settings, errcode = { msg = "", fields={} }}) ) - end -end - -editnet = function ( self ) - - if not self.clientdata.cmd then - redirect(self) - else - if self.clientdata.cmd == "back" then - redirect(self) - end - end - - local net = {} - local option = { script = self.conf.script, - prefix = self.conf.prefix, - controller = self.conf.controller, - action = self.conf.action, - extra = "" - } - - if self.clientdata.network then - if self.clientdata.network == "choose" then - redirect(self) - end - end - - if self.clientdata.cmd == "update" then - tmp = self.clientdata - dynamicx = tmp.dynamichosts - advancedx = tmp.advanced - if tmp.unknownclients == "allow" then - dynamicx = tmp.dynamicx - end - if tmp.useadvanced ~= "use" then - advancedx = tmp.advancedx - end - net = self.model.create_new_net( tmp.name, tmp.defleasetime, tmp.maxleasetime, tmp.gateway, - tmp.domainname, tmp.dnssrv1, tmp.dnssrv2, tmp.subnet, tmp.netmask, tmp.leaserangestart, - tmp.leaserangeend, tmp.wpad, tmp.statichosts, tmp.unknownclients, dynamicx, advancedx, tmp.useadvanced ) - errcode, net = self.model.subnet_write( net ) - return ( cfe({ option = option, value = net, errcode = errcode }) ) - end - - net = self.model.subnet_read( self.clientdata.network ); - return ( cfe({ option = option, value = net, errcode = { msg="", fields={} }}) ) + return controllerfunctions.handle_form(self, self.model.read_settings, self.model.update_settings, self.clientdata, "Save", "Update Global Settings", "Global Settings Updated") end -editspc = function ( self ) - if not self.clientdata.cmd then - redirect( self ) - end - - local option = { script = self.conf.script, - prefix = self.conf.prefix, - controller = self.conf.controller, - action = self.conf.action, - extra = "" - } - - if self.clientdata.cmd == "update" then - msg = "" - fields = {} - tmp = self.clientdata - errmsg = self.model.validate_dynamichosts( tmp.dynamic ) - if #errmsg > 0 then - msg = errmsg - table.insert(fields, "dynamichosts") - end - value = self.model.advglobal_update( tmp.preconfig, tmp.postconfig, tmp.dynamic ) - return ( cfe({ option = option, value = value, errcode = { msg=msg, fields=fields }}) ) - end - - value = self.model.advglobal_read() - return ( cfe({ option = option, value = value, errcode = { msg="", fields={} }}) ) +editsubnet = function ( self ) + return controllerfunctions.handle_form(self, function() return self.model.subnet_read(self.clientdata.subnet) end, self.model.subnet_update, self.clientdata, "Save", "Edit Subnet", "Subnet Settings Updated") end -createnet = function ( self ) - - if not self.clientdata.cmd then - redirect(self) - end - - local option = { script = self.conf.script, - prefix = self.conf.prefix, - controller = self.conf.controller, - action = self.conf.action, - extra = "" - } - - if self.clientdata.cmd == "new" then - net = self.model.create_new_net( "<new>", nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil ) - return ( cfe({ option = option, value = net, errcode = { msg = "", fields = nil }}) ) - elseif self.clientdata.cmd == "create" then - tmp = self.clientdata - net = self.model.create_new_net( tmp.name, tmp.defleasetime, tmp.maxleasetime, - tmp.gateway, tmp.domainname, tmp.dnssrv1, tmp.dnssrv2, tmp.subnet, - tmp.netmask, tmp.leaserangestart, tmp.leaserangeend, tmp.wpad, "", tmp.unknownclients, "", "", "" ) - errcode, net = self.model.subnet_create( net ) - if #errcode.msg == 0 then - redirect(self, "home") - else - return ( cfe({ option = option, value = net, errcode = errcode }) ) - end - end +createsubnet = function ( self ) + return controllerfunctions.handle_form(self, self.model.create_new_subnet, self.model.subnet_create, self.clientdata, "Create", "Create new subnet", "New subnet Created") end -status = function ( self ) - return cfe({ option = { script = self.conf.script, - prefix = self.conf.prefix, - controller = self.conf.controller, - action = self.conf.action, - extra = "", - }, - value = "", - genmsg = genmsg, - info = self.model.getstatus() }) +delsubnet = function(self) + return self:redirect_to_referrer(self.model.subnet_delete(self.clientdata.subnet)) end -home = function ( self ) - - -- dependancy check for neccessary libs/packages et al. - msg = self.model.dep_check() - if msg ~= nil then - redirect(self, "dep") - end - - local srvctrl = "" - if self.clientdata.srvcmd then - srvcmd = self.clientdata.srvcmd - if srvcmd == "start" or srvcmd == "stop" or srvcmd == "restart" then - srvctrl = self.model.service_control(self.clientdata.srvcmd) - end - end - - if self.clientdata.cmd == "generate" then - genmsg = self.model.config_generate() - end - - local option = { script = self.conf.script, - prefix = self.conf.prefix, - controller = self.conf.controller, - action = self.conf.action, - extra = "" - } - - local info = self.model.getstatus() - info.subnets = self.model.get_subnets() - - -- 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", - }) - -- Disable management buttons based on if the process is running or not - if (string.lower(info.status.value) == "enabled") then management.start.disabled = "yes" end - if (string.lower(info.status.value) == "disabled") then management.stop.disabled = "yes" end - if (string.lower(info.status.value) == "disabled") then management.restart.disabled = "yes" end - - return ( cfe({ option = option, value = "", genmsg = genmsg, info = info, management = management, }) ) +listsubnets = function ( self ) + return self.model.get_subnets() end viewleases = function ( self ) - - local filename = "/var/lib/dhcp/dhcpd.leases"; - - local option = { script = self.conf.script, - prefix = self.conf.prefix, - controller = self.conf.controller, - action = self.conf.action, - extra = "" - } - - local value = { filename = { value=filename }, - contents = { value=self.model.read_file(filename) } - } - - return ( cfe({ option = option, value = value }) ) + return self.model.getleases() end -viewconfig = function ( self ) - - local filename = "/etc/dhcp/dhcpd.conf" - - local option = { script = self.conf.script, - prefix = self.conf.prefix, - controller = self.conf.controller, - action = self.conf.action, - extra = "" - } - - local value = { filename = { value=filename }, - contents = { value=self.model.read_file(filename) } - } - - return ( cfe({ option = option, value = value }) ) +expert = function(self) + return controllerfunctions.handle_form(self, self.model.getconfigfile, self.model.setconfigfile, self.clientdata, "Save", "Edit Config", "Configuration Set") end - diff --git a/dhcp-createnet-html.lsp b/dhcp-createnet-html.lsp deleted file mode 100644 index 6cd62c2..0000000 --- a/dhcp-createnet-html.lsp +++ /dev/null @@ -1,76 +0,0 @@ -<% - local form = ... - local option = form.option; - local net = form.value -%> -<h1>Create New Subnet</h1> -<h2>Subnet: new</h2> - -<% - if #form.errcode.msg > 0 then - io.write("<p class='error'>" .. form.errcode.msg .. "</p>") - end -%> -<DL> -<form action="<% io.write(option.script .. option.prefix .. - option.controller .. "/" .. option.action .. option.extra) %>" method="POST"> - -<dt>Name</dt> -<dd><input type="text" class="text" name="name" value="<% io.write(net.name.value) %>"></dd> - -<dt>Subnet</dt> -<dd><input type="text" class="text" name="subnet" value="<% io.write(net.subnet.value) %>"></dd> - -<dt>Netmask</dt> -<dd><input type="text" class="text" name="netmask" value="<% io.write(net.netmask.value) %>"></dd> - -<dt>Gateway</dt> -<dd><input type="text" class="text" name="gateway" value="<% io.write(net.gateway.value) %>"></dd> - -<dt>DNS Server 1</dt> -<dd><input type="text" class="text" name="dnssrv1" value="<% io.write(net.dnssrv1.value) %>"></dd> - -<dt>DNS Server 2</dt> -<dd><input type="text" class="text" name="dnssrv2" value="<% io.write(net.dnssrv2.value) %>"></dd> - -<dt>Default Lease Time</dt> -<dd><input type="text" class="text" name="defleasetime" value="<% io.write(net.defleasetime.value) %>"></dd> - -<dt>Maximum Lease Time</dt> -<dd><input type="text" class="text" name="maxleasetime" value="<% io.write(net.maxleasetime.value) %>"></dd> - -<dt>Domain Name</dt> -<dd><input type="text" class="text" name="domainname" value="<% io.write(net.domainname.value) %>"></dd> - -<dt>WPAD</dt> -<dd><input type="text" class="text" name="wpad" value="<% io.write(net.wpad.value) %>"></dd> - -<dt>Lease Range Start</dt> -<dd><input type="text" class="text" name="leaserangestart" value="<% io.write(net.leaserangestart.value) %>"></dd> - -<dt>Lease Range End</dt> -<dd><input type="text" class="text" name="leaserangeend" value="<% io.write(net.leaserangeend.value) %>"></dd> - -<dt>Unknown Clients</dt> -<dd><select name="unknownclients" size="1"> -<% - if net.unknownclients.value == "allow" then - io.write(" <option selected>allow</option>\n"); - io.write(" <option>deny</option>\n"); - else - io.write(" <option>allow</option>\n"); - io.write(" <option selected>deny</option>\n"); - end -%> -</select></dd> - -<dt>Submit above settings</dt> -<dd><input type=submit name=cmd value="create" class="submit"></dd> - -</form> - -<dt>Cancel and go back</dt> -<dd><form action="<% io.write(option.script .. option.prefix .. option.controller .. "/home") %> method="POST"> -<input type=submit name="cmd" value="back" class="submit"></form></dd> -</DL> - diff --git a/dhcp-createsubnet-html.lsp b/dhcp-createsubnet-html.lsp new file mode 120000 index 0000000..48378d6 --- /dev/null +++ b/dhcp-createsubnet-html.lsp @@ -0,0 +1 @@ +dhcp-editsubnet-html.lsp
\ No newline at end of file diff --git a/dhcp-delnet-html.lsp b/dhcp-delnet-html.lsp deleted file mode 100644 index 6611d9a..0000000 --- a/dhcp-delnet-html.lsp +++ /dev/null @@ -1,30 +0,0 @@ -<% - local form = ... - local option = form.option; - local net = form.value - local msg = form.msg -%> -<h1>DHCPd Delete Subnet</h1> -<h2>Subnet: <% io.write(net.name.value) %></h2> -<br> -<h3>Do you really want to delete this subnet?</h3><br> - -<form action="<% io.write(option.script .. option.prefix .. - option.controller .. "/" .. option.action .. option.extra) %>" method="POST"> -<input type="hidden" name="name" value="<% io.write(net.name.value) %>"> -<input type="hidden" name="network" value="<% io.write(net.name.value) %>"> -<input type="hidden" name="confirm" value="yes"> -<table> - <tr><td><nobr>Subnet:</nobr></td><td>"<% io.write(net.subnet.value) %>"</td></tr> - <tr><td><nobr>Netmask:</nobr></td><td>"<% io.write(net.netmask.value) %>"</td></tr> - <tr><td><nobr>Gateway:</nobr></td><td>"<% io.write(net.gateway.value) %>"</td></tr> - <tr><td><nobr>DNS Server 1:</nobr></td><td>"<% io.write(net.dnssrv1.value) %>"</td></tr> - <tr><td><nobr>DNS Server 2:</nobr></td><td>"<% io.write(net.dnssrv2.value) %>"</td></tr> - <tr><td><nobr>Default Lease Time:</nobr></td><td>"<% io.write(net.defleasetime.value) %>"</td></tr> - <tr><td><nobr>Maximum Lease Time:</nobr></td><td>"<% io.write(net.maxleasetime.value) %>"</td></tr> - <tr><td><nobr>Domain Name:</nobr></td><td>"<% io.write(net.domainname.value) %>"</td></tr> - <tr><td><nobr>WPAD:</nobr></td><td>"<% io.write(net.wpad.value) %>"</td></tr> - <tr><td><nobr>Lease Range Start:</nobr></td><td>"<% io.write(net.leaserangestart.value) %>"</td></tr> - <tr><td><nobr>Lease Range End:</nobr></td><td>"<% io.write(net.leaserangeend.value) %>"</td></tr> - <tr><td></td><td><input type=submit name=cmd value="delete" style="width:100px"></form><form action="<% io.write(option.script .. option.prefix .. option.controller .. "/home") %>" method="POST"> -<input type=submit name="cmd" value="back" style="width:100px"></form></td></tr></table> diff --git a/dhcp-dep-html.lsp b/dhcp-dep-html.lsp deleted file mode 100644 index da5b292..0000000 --- a/dhcp-dep-html.lsp +++ /dev/null @@ -1,14 +0,0 @@ -<% - local form = ... - -%> -<h1>ACF DHCP - Dependancy Check Failure!</h1><br> -<b>The following package(s) are missing:</b><br> -<pre style="color: #ff2020"> -<% - for k,v in ipairs(form.msg) do - io.write(v .. "\n") - end -%> -</pre> - diff --git a/dhcp-editnet-html.lsp b/dhcp-editnet-html.lsp deleted file mode 100644 index 3461638..0000000 --- a/dhcp-editnet-html.lsp +++ /dev/null @@ -1,96 +0,0 @@ -<% - local form = ... - local option = form.option; - local net = form.value - local errcode = form.errcode -%> -<script language="JavaScript"> - - function handleAdvChg() { - if (document.myform.useadvanced.checked == true) { - document.getElementById('advanced').innerHTML = '<textarea name="advanced" style="width:600px">' + document.myform.advancedx.value + '</textarea>'; - } else { - document.getElementById('advanced').innerHTML = ''; - } - } - -</script> -<h1>Basic Configuration</h1> -<h2>Subnet: <% io.write(net.name.value) %></h2> - -<% - if #errcode.msg > 0 then - io.write("<p class='error'>" .. errcode.msg .. "</p>") - end -%> - -<form name="myform" action="<% io.write(option.script .. option.prefix .. - option.controller .. "/" .. option.action .. option.extra) %>" method="POST"> -<input type="hidden" name="name" value="<% io.write(net.name.value) %>"> -<input type="hidden" name="dynhost1" value=""> -<DL> - -<dt>Name</dt> -<dd><% io.write(net.name.value) %></dd> - -<dt>Subnet</dt> -<dd><input type="text" class="text" name="subnet" value="<% io.write(net.subnet.value) %>"></dd> - -<dt>Netmask</dt> -<dd><input type="text" class="text" name="netmask" value="<% io.write(net.netmask.value) %>"></dd> - -<dt>Gateway</dt> -<dd><input type="text" class="text" name="gateway" value="<% io.write(net.gateway.value) %>"></dd> - -<dt>DNS Server 1</dt> -<dd><input type="text" class="text" name="dnssrv1" value="<% io.write(net.dnssrv1.value) %>"></dd> - -<dt>DNS Server 2</dt> -<dd><input type="text" class="text" name="dnssrv2" value="<% io.write(net.dnssrv2.value) %>"></dd> - -<dt>Default Lease Time</dt> -<dd><input type="text" class="text" name="defleasetime" value="<% io.write(net.defleasetime.value) %>"></dd> - -<dt>Maximum Lease Time</dt> -<dd><input type="text" class="text" name="maxleasetime" value="<% io.write(net.maxleasetime.value) %>"></dd> - -<dt>Domain Name</dt> -<dd><input type="text" class="text" name="domainname" value="<% io.write(net.domainname.value) %>"></dd> - -<dt>WPAD</dt> -<dd><input type="text" class="text" name="wpad" value="<% io.write(net.wpad.value) %>"></dd> - -<dt>Lease Range Start</dt> -<dd><input type="text" class="text" name="leaserangestart" value="<% io.write(net.leaserangestart.value) %>"></dd> - -<dt>Lease Range End</dt> -<dd><input type="text" class="text" name="leaserangeend" value="<% io.write(net.leaserangeend.value) %>"></dd> - -<dt>Unknown Clients</dt> -<dd><select name="unknownclients" size="1" onChange="javascript:handleDynChg();"> -<% - if net.unknownclients.value == "allow" then - io.write(" <option selected>allow</option>\n"); - io.write(" <option>deny</option>\n"); - else - io.write(" <option>allow</option>\n"); - io.write(" <option selected>deny</option>\n"); - end -%> -</select></dd> -</dl> - -<h2>Submit/Cancel</h2> -<dl> -<dt>Submit above settings</dt> -<dd><input type="submit" name="cmd" value="update" class="submit"></dd> -<dt>Cancel and go back</dt><dd><input type=submit name="cmd" value="back" class="submit"></form></dd> -</DL> - -<h2>Static Hosts</h2> -<p> -Enter static hosts data, one per line <i>(e.g. hostname;192.168.xx.140;00:11:22:33:44:55;comment)</i> -</p> -<textarea name="statichosts"><% io.write( net.statichosts.value ) %></textarea> -</form> - diff --git a/dhcp-editspc-html.lsp b/dhcp-editspc-html.lsp deleted file mode 100644 index a4397d9..0000000 --- a/dhcp-editspc-html.lsp +++ /dev/null @@ -1,40 +0,0 @@ -<% - local form = ... - local option = form.option; - local errcode = form.errcode -%> -<h1>DHCPd - Advanced Global Configuration</h1> - -<form name="myform" action="<% io.write(option.script .. option.prefix .. - option.controller .. "/" .. option.action .. option.extra) %>" method="POST"> - -<pre style="color: #ff2020;"><% io.write( form.errcode.msg ) %></pre> - -<h2>DHCPd - Dynamic Hosts</h2> -<p> -Enter dynamic hosts data, one per line <i>(e.g. hostname;00:11:22:33:44:55)</i> -</p> -<textarea name="dynamic"><% io.write( form.value.dynamic ) %></textarea> - -<h2>DHCPd - Pre Main Configuration</h2> -<p> -These fields below are copied into the final dhcpd.conf on configuration generation without any validation check. Do not use -them unless you know what you are doing. -</p> -<textarea name="preconfig"><% io.write(form.value.preconfig) %></textarea> - -<h2>DHCPd - Post Main Configuration</h2> -<textarea name="postconfig"><% io.write(form.value.postconfig) %></textarea> - -<h2>Submit/Cancel</h2> -<DL> -<dt>Submit above settings</dt> -<dd><input type="submit" name="cmd" value="update" class="submit"></dd> - -<dt>Cancel and go back</dt> -<dd><form action="<% io.write(option.script .. option.prefix .. option.controller .. "/home") %>" method="POST"> -<input type=submit name="cmd" value="back" class="submit"></form></dd> -</form> -</DL> - - diff --git a/dhcp-editsubnet-html.lsp b/dhcp-editsubnet-html.lsp new file mode 100644 index 0000000..25b3882 --- /dev/null +++ b/dhcp-editsubnet-html.lsp @@ -0,0 +1,13 @@ +<% local form, viewlibrary, page_info = ... +require("viewfunctions") +%> + +<H1><%= form.label %></H1> +<% + form.action = page_info.script .. page_info.prefix .. page_info.controller .. "/" .. page_info.action + if page_info.action == "editsubnet" then + form.value.subnet.contenteditable = false + end + local order = {"subnet", "netmask", "leaserangestart", "leaserangeend", "unknownclients", "domainname", "domainnameservers", "routers", "defleasetime", "maxleasetime"} + displayform(form, order) +%> diff --git a/dhcp-expert-html.lsp b/dhcp-expert-html.lsp new file mode 120000 index 0000000..207f324 --- /dev/null +++ b/dhcp-expert-html.lsp @@ -0,0 +1 @@ +../expert-html.lsp
\ No newline at end of file diff --git a/dhcp-help-html.lsp b/dhcp-help-html.lsp deleted file mode 100644 index 5a6d35f..0000000 --- a/dhcp-help-html.lsp +++ /dev/null @@ -1,22 +0,0 @@ -<% - local form = ... -%> -<h1>DHCPd - Help</h1> -<h2>DHCPd - About</h2> -The acf-dhcp module serves as configuration frontend for the -isc-dhcp server. - -<h2>DHCPd - How to start</h2> -<b>Step by Step</b><br> -<ul> - <li>Edit 'Global Settings', fill in all mandatory fields</li> - <li>Add a new subnet by entering all neccessary fields or more if needed</li> - <li>If you want to add static/dynamic but specified hosts go to Edit Subnet</li> - <li>Generate Configuration File</li> - <li>Start service</li> -</ul> - -<h2>DHCPd - Special Configurations</h2> - -<h2>DHCPd - FAQs</h2> - diff --git a/dhcp-home-html.lsp b/dhcp-home-html.lsp index 7125145..1591f76 100644 --- a/dhcp-home-html.lsp +++ b/dhcp-home-html.lsp @@ -1,108 +1,27 @@ -<% - local form = ... - local data = form.option -%> +<% local view, viewlibrary, page_info, session = ... %> +<% require("viewfunctions") %> -<% -function displayinfo(myform,tags,viewonly) - for k,v in pairs(tags) do - if (myform[v]) and (myform[v]["value"]) then - local val = myform[v] - io.write("\t<DT") - if (val.errtxt) then - val.class = "error" - io.write(" class='error'") - end - io.write(">" .. val.label .. "</DT>\n") - if (viewonly) then - io.write("\t\t<DD>" .. val.value .. "\n") - else - io.write("\t\t<DD>" .. html.form[val.type](val) .. "\n") - end - if (val.descr) and (#val.descr > 0) then io.write("\t\t<P CLASS='descr'>" .. string.gsub(val.descr, "\n", "<BR>") .. "</P>\n") end - if (val.errtxt) then io.write("\t\t<P CLASS='error'>" .. string.gsub(val.errtxt, "\n", "<BR>") .. "</P>\n") end - io.write("\t\t</DD>\n") - end - end -end -%> - -<H1>SYSTEM INFO</H1> -<DL> -<% -local myform = form.info -local tags = { "status", "version", "autostart", } -displayinfo(myform,tags,"viewonly") -%> -</DL> - -<H2>Change/Generate settings</H2> +<% if viewlibrary and viewlibrary.dispatch_component then + viewlibrary.dispatch_component("status") +end %> -<H3>Global</H3> +<H1>Global Settings</H1> <DL> <dt>Edit global settings</dt> -<dd><form action="<% io.write(data.script .. data.prefix .. data.controller .. "/settings") %>" method="POST"> -<input type=submit name="cmd" value="edit" class="submit"> -</form></dd> - - -<dt>Global Config Pre/Post Code</dt> -<dd><form action="<% io.write(data.script .. data.prefix .. data.controller .. "/editspc") %>" method="POST"> -<input type=submit name="cmd" value="edit" class="submit"> +<dd><form action="<%= page_info.script .. page_info.prefix .. page_info.controller .. "/settings" %>" method="POST"> +<input type=submit value="Edit" class="submit"> </form></dd> </DL> -<H3>Subnet declarations</H3> - -<DL> -<dt>Edit subnet</dt> -<dd><form action="<% io.write(data.script .. data.prefix .. data.controller .. "/editnet") %>" method="POST"> -<select class="select" name="network" size="1"> - <option value="choose">-- Choose Network --</option> -<% - for k,v in ipairs(form.info.subnets) do - io.write("<option>" .. v .. "</option>") - end -%> -</select><input type=submit name="cmd" value="edit" class="submit"> -</form></dd> - -<dt>Add new subnet</dt> -<dd><form action="<% io.write(data.script .. data.prefix .. data.controller .. "/createnet") %>" method="POST"> -<input type=submit name="cmd" value="new" class="submit"> -</form></dd> -</DL> - -<h3>Generate config</h3> -<DL> -<dt>Generate Configuration File</dt> -<dd><form action="<% io.write(data.script .. data.prefix .. data.controller .. "/home") %>" method="POST"> -<input type=submit name="cmd" value="generate" class="submit"></form> -<% if form.genmsg ~= nil then io.write( "<p class='error'>" .. form.genmsg .. "</p>" ) end %></dd> -</DL> - -<% -- MANAGEMENT BUTTONS -local cmdform = form.management -local cmdresult = form.cmdmanagement -local tags = { "start", "stop", "restart" } -if (cmdform) and (cmdform[tags[1]]) then +<% if viewlibrary and viewlibrary.dispatch_component then + viewlibrary.dispatch_component("listsubnets") +end %> - io.write('<form name="management" action="" method="POST">') - io.write('<H1>MANAGEMENT</H1>') - io.write('<dl>') - io.write('<dt>' .. cmdform[tags[1]]["label"] .. '</dt>') - io.write('<dd>') - for k,v in pairs(tags) do - if (cmdform[v]) then - io.write(html.form[cmdform[v].type](cmdform[v])) - end - end - io.write('</dd>') +<% --[[if viewlibrary and viewlibrary.dispatch_component then + viewlibrary.dispatch_component("listhosts") +end --]] %> - if (cmdresult) and (cmdresult.action) and (#cmdresult.action.descr > 0) then - io.write('<dt>' .. cmdresult.label .. '</dt>') - io.write('<dd><pre>' .. cmdresult.action.descr .. '</pre></dd>') - end - io.write('</dl></form>') +<% if viewlibrary and viewlibrary.dispatch_component then + viewlibrary.dispatch_component("startstop") end %> diff --git a/dhcp-listsubnets-html.lsp b/dhcp-listsubnets-html.lsp new file mode 100644 index 0000000..4eb4285 --- /dev/null +++ b/dhcp-listsubnets-html.lsp @@ -0,0 +1,27 @@ +<% local view, viewlibrary, page_info, session = ... %> +<% require("viewfunctions") %> + +<H1>Subnet Declarations</H1> + +<DL> +<TABLE> + <TR style="background:#eee;font-weight:bold;"> + <TD style="padding-right:20px;white-space:nowrap;text-align:left;" class="header">Action</TD> + <TD style="white-space:nowrap;text-align:left;" class="header">Subnet</TD> + </TR> +<% for i,subnet in ipairs(view.value) do %> + <TR> + <TD style="padding-right:20px;white-space:nowrap;"> + <%= html.link{value=page_info.script..page_info.prefix..page_info.controller.."/editsubnet?subnet="..subnet, label="Edit "} %> + <%= html.link{value=page_info.script..page_info.prefix..page_info.controller.."/delsubnet?subnet="..subnet, label="Delete "} %> + </TD> + <TD style="white-space:nowrap;"><%= subnet %></TD> + </TR> +<% end %> +</TABLE> + +<dt>Add new subnet</dt> +<dd><form action="<%= page_info.script .. page_info.prefix .. page_info.controller .. "/createsubnet" %>" method="POST"> +<input type=submit value="New" class="submit"> +</form></dd> +</DL> 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 .. "<new> 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 - diff --git a/dhcp-settings-html.lsp b/dhcp-settings-html.lsp index 8a7019e..796f565 100644 --- a/dhcp-settings-html.lsp +++ b/dhcp-settings-html.lsp @@ -1,38 +1,8 @@ -<% - local form = ... - local option = form.option - local settings = form.value - local errcode = form.errcode -%> -<h1>Global Settings</h1> +<% local form = ... %> +<% require("viewfunctions") %> -<% - if #errcode.msg > 0 then - io.write("<pre style=\"color: #ff2020\">" .. errcode.msg .. "</pre><br>") - end +<h1><%= form.label %></h1> +<% + local order = {"domainname", "domainnameservers", "defleasetime", "maxleasetime"} + displayform(form, order) %> - -<DL> -<form action="<% io.write(option.script .. option.prefix .. - option.controller .. "/" .. option.action .. option.extra) %>" method="POST"> - -<dt>Default Lease Time</dt> -<dd><input type="text" name="defleasetime" class="text" value="<% io.write(settings.defleasetime.value) %>"></dd> - -<dt>Maximum Lease Time</dt> -<dd><input type="text" name="maxleasetime" class="text" value="<% io.write(settings.maxleasetime.value) %>"></dd> - -<dt>Domain Name</dt> -<dd><input type="text" name="domainname" class="text" value="<% io.write(settings.domainname.value) %>"></dd> - -<dt>Submit above settings</dt> -<dd><input type=submit name=cmd value="update" class="submit"></dd> - -</form> - -<dt>Cancel and go back</dt> -<dd><form action="<% io.write(option.script .. option.prefix .. option.controller .. "/home") %>" method="POST"> -<input type=submit name="cmd" value="back" class="submit"></form></dd> -</DL> - - diff --git a/dhcp-startstop-html.lsp b/dhcp-startstop-html.lsp new file mode 120000 index 0000000..0ea2627 --- /dev/null +++ b/dhcp-startstop-html.lsp @@ -0,0 +1 @@ +../startstop-html.lsp
\ No newline at end of file diff --git a/dhcp-status-html.lsp b/dhcp-status-html.lsp index e13dcda..b2f8480 100644..120000 --- a/dhcp-status-html.lsp +++ b/dhcp-status-html.lsp @@ -1,36 +1 @@ -<% local form = ... %> - -<% -function displayinfo(myform,tags,viewonly) - for k,v in pairs(tags) do - if (myform[v]) and (myform[v]["value"]) then - local val = myform[v] - io.write("\t<DT") - if (val.errtxt) then - val.class = "error" - io.write(" class='error'") - end - io.write(">" .. val.label .. "</DT>\n") - if (viewonly) then - io.write("\t\t<DD>" .. val.value .. "\n") - else - io.write("\t\t<DD>" .. html.form[val.type](val) .. "\n") - end - if (val.descr) and (#val.descr > 0) then io.write("\t\t<P CLASS='descr'>" .. string.gsub(val.descr, "\n", "<BR>") .. "</P>\n") end - if (val.errtxt) then io.write("\t\t<P CLASS='error'>" .. string.gsub(val.errtxt, "\n", "<BR>") .. "</P>\n") end - io.write("\t\t</DD>\n") - end - end -end -%> - -<H1>SYSTEM INFO</H1> -<DL> -<% -local myform = form.info -local tags = { "status", "version", "autostart", } -displayinfo(myform,tags,"viewonly") -%> -</DL> - - +../status-html.lsp
\ No newline at end of file diff --git a/dhcp-viewconfig-html.lsp b/dhcp-viewconfig-html.lsp deleted file mode 100644 index 9070330..0000000 --- a/dhcp-viewconfig-html.lsp +++ /dev/null @@ -1,12 +0,0 @@ -<% - local form = ... - local option = form.option - local value = form.value -%> -<h1>View <% io.write(value.filename.value) %></h1> - -<textarea name=""><% io.write(value.contents.value) %></textarea> -<form action="<% io.write(option.script .. option.prefix .. option.controller .. "/home") %>" method="POST"> - <input type=submit name="cmd" value="Back" class="submit"> -</form> - diff --git a/dhcp-viewleases-html.lsp b/dhcp-viewleases-html.lsp index 9070330..15b1930 100644..120000 --- a/dhcp-viewleases-html.lsp +++ b/dhcp-viewleases-html.lsp @@ -1,12 +1 @@ -<% - local form = ... - local option = form.option - local value = form.value -%> -<h1>View <% io.write(value.filename.value) %></h1> - -<textarea name=""><% io.write(value.contents.value) %></textarea> -<form action="<% io.write(option.script .. option.prefix .. option.controller .. "/home") %>" method="POST"> - <input type=submit name="cmd" value="Back" class="submit"> -</form> - +../filedetails-html.lsp
\ No newline at end of file @@ -3,5 +3,4 @@ Networking 10DHCP Status status Networking 10DHCP Config home Networking 10DHCP View_leases viewleases -Networking 10DHCP View_config viewconfig -Networking 10DHCP Help help +Networking 10DHCP Expert expert @@ -1,4 +1,4 @@ -CREATE=dhcp:createnet -READ=dhcp:home,dhcp:viewleases,dhcp:viewconfig,dhcp:status -UPDATE=dhcp:dep,dhcp:help,dhcp:settings,dhcp:editnet,dhcp:editspc -DELETE=dhcp:delnet +CREATE=dhcp:createsubnet,dhcp:createhost +READ=dhcp:home,dhcp:viewleases,dhcp:status,dhcp:listsubnets,dhcp:listhosts +UPDATE=dhcp:settings,dhcp:editsubnet,dhcp:edithost,dhcp:startstop,dhcp:expert +DELETE=dhcp:delsubnet,dhcp:delhost |