summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--dhcp-controller.lua280
-rw-r--r--dhcp-createnet-html.lsp76
l---------dhcp-createsubnet-html.lsp1
-rw-r--r--dhcp-delnet-html.lsp30
-rw-r--r--dhcp-dep-html.lsp14
-rw-r--r--dhcp-editnet-html.lsp96
-rw-r--r--dhcp-editspc-html.lsp40
-rw-r--r--dhcp-editsubnet-html.lsp13
l---------dhcp-expert-html.lsp1
-rw-r--r--dhcp-help-html.lsp22
-rw-r--r--dhcp-home-html.lsp113
-rw-r--r--dhcp-listsubnets-html.lsp27
-rw-r--r--dhcp-model.lua1327
-rw-r--r--dhcp-settings-html.lsp42
l---------dhcp-startstop-html.lsp1
l---------[-rw-r--r--]dhcp-status-html.lsp37
-rw-r--r--dhcp-viewconfig-html.lsp12
l---------[-rw-r--r--]dhcp-viewleases-html.lsp13
-rw-r--r--dhcp.menu3
-rw-r--r--dhcp.roles8
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 .. "&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
-
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
diff --git a/dhcp.menu b/dhcp.menu
index 567e7bd..a3ad3b9 100644
--- a/dhcp.menu
+++ b/dhcp.menu
@@ -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
diff --git a/dhcp.roles b/dhcp.roles
index 511cd36..66cd536 100644
--- a/dhcp.roles
+++ b/dhcp.roles
@@ -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