diff options
author | Ted Trask <ttrask01@yahoo.com> | 2008-11-03 21:30:32 +0000 |
---|---|---|
committer | Ted Trask <ttrask01@yahoo.com> | 2008-11-03 21:30:32 +0000 |
commit | fc670b19af9f6dd4027dcec0fc6cc0035860f9e2 (patch) | |
tree | b86af704ba7bbef308e28014f3c0162bf2fea627 | |
download | acf-iptables-fc670b19af9f6dd4027dcec0fc6cc0035860f9e2.tar.bz2 acf-iptables-fc670b19af9f6dd4027dcec0fc6cc0035860f9e2.tar.xz |
Created iptables ACF to directly view / edit rules. Status, view, and expert work. Form to edit / create rules not functional yet.
git-svn-id: svn://svn.alpinelinux.org/acf/iptables/trunk@1575 ab2d0c66-481e-0410-8bed-d214d4d58bed
-rw-r--r-- | Makefile | 44 | ||||
-rw-r--r-- | README | 1 | ||||
-rw-r--r-- | config.mk | 10 | ||||
-rw-r--r-- | iptables-controller.lua | 64 | ||||
l--------- | iptables-createchain-html.lsp | 1 | ||||
l--------- | iptables-createrule-html.lsp | 1 | ||||
-rw-r--r-- | iptables-details-html.lsp | 21 | ||||
-rw-r--r-- | iptables-editchain-html.lsp | 15 | ||||
-rw-r--r-- | iptables-editrule-html.lsp | 35 | ||||
l--------- | iptables-expert-html.lsp | 1 | ||||
-rw-r--r-- | iptables-html.lsp | 35 | ||||
-rw-r--r-- | iptables-model.lua | 268 | ||||
-rw-r--r-- | iptables-startstop-html.lsp | 25 | ||||
l--------- | iptables-status-html.lsp | 1 | ||||
-rw-r--r-- | iptables.menu | 6 | ||||
-rw-r--r-- | iptables.roles | 4 |
16 files changed, 532 insertions, 0 deletions
diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..d0b3ed1 --- /dev/null +++ b/Makefile @@ -0,0 +1,44 @@ +APP_NAME=iptables +PACKAGE=acf-$(APP_NAME) +VERSION=0.0.1 + +APP_DIST=\ + iptables* \ + + +EXTRA_DIST=README Makefile config.mk + +DISTFILES=$(APP_DIST) $(EXTRA_DIST) + +TAR=tar + +P=$(PACKAGE)-$(VERSION) +tarball=$(P).tar.bz2 +install_dir=$(DESTDIR)/$(appdir)/$(APP_NAME) + +all: +clean: + rm -rf $(tarball) $(P) + +dist: $(tarball) + +install: + mkdir -p "$(install_dir)" + cp -a $(APP_DIST) "$(install_dir)" + +$(tarball): $(DISTFILES) + rm -rf $(P) + mkdir -p $(P) + cp -a $(DISTFILES) $(P) + $(TAR) -jcf $@ $(P) + rm -rf $(P) + +# target that creates a tar package, unpacks is and install from package +dist-install: $(tarball) + $(TAR) -jxf $(tarball) + $(MAKE) -C $(P) install DESTDIR=$(DESTDIR) + rm -rf $(P) + +include config.mk + +.PHONY: all clean dist install dist-install @@ -0,0 +1 @@ +ACF for iptables diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..45f4d21 --- /dev/null +++ b/config.mk @@ -0,0 +1,10 @@ +prefix=/usr +datadir=${prefix}/share +sysconfdir=${prefix}/etc +localstatedir=${prefix}/var +acfdir=${datadir}/acf +wwwdir=${acfdir}/www +cgibindir=${acfdir}/cgi-bin +appdir=${acfdir}/app +acflibdir=${acfdir}/lib +sessionsdir=${localstatedir}/lib/acf/sessions diff --git a/iptables-controller.lua b/iptables-controller.lua new file mode 100644 index 0000000..16fac32 --- /dev/null +++ b/iptables-controller.lua @@ -0,0 +1,64 @@ +module(..., package.seeall) + +-- Load libraries +require("controllerfunctions") + +-- ################################################################################ +-- LOCAL FUNCTIONS + +-- ################################################################################ +-- PUBLIC FUNCTIONS + +default_action = "status" + +function status(self) + return self.model.getstatus() +end + +function details(self) + return self.model.getstatusdetails() +end + +function filterrules(self) + return self.model.getrules("filter") +end + +function natrules(self) + return self.model.getrules("nat") +end + +function manglerules(self) + return self.model.getrules("mangle") +end + +function editchain(self) + return controllerfunctions.handle_form(self, function() return self.model.read_chain(self.clientdata.table, self.clientdata.chain or "") end, self.model.update_chain, self.clientdata, "Save", "Edit Chain", "Chain saved") +end + +function createchain(self) + return controllerfunctions.handle_form(self, function() return self.model.read_chain(self.clientdata.table) end, self.model.create_chain, self.clientdata, "Create", "Create New Chain", "Chain created") +end + +function deletechain(self) + return self:redirect_to_referrer(self.model.delete_chain(self.clientdata.table, self.clientdata.chain)) +end + +function editrule(self) + return controllerfunctions.handle_form(self, function() return self.model.read_rule(self.clientdata.table, self.clientdata.chain or "", self.clientdata.position or "") end, self.model.update_rule, self.clientdata, "Save", "Edit Rule", "Rule saved") +end + +function createrule(self) + return controllerfunctions.handle_form(self, function() return self.model.read_rule(self.clientdata.table, self.clientdata.chain, self.clientdata.position) end, self.model.create_rule, self.clientdata, "Create", "Create New Rule", "Rule created") +end + +function deleterule(self) + return self:redirect_to_referrer(self.model.delete_rule(self.clientdata.table, self.clientdata.chain, self.clientdata.position)) +end + +function expert(self) + return controllerfunctions.handle_form(self, self.model.readrulesfile, self.model.updaterulesfile, self.clientdata, "Save", "Edit Rules File", "Rules File Saved") +end + +function startstop(self) + return controllerfunctions.handle_startstop(self, self.model.startstop_service, self.model.getstatus, self.clientdata) +end diff --git a/iptables-createchain-html.lsp b/iptables-createchain-html.lsp new file mode 120000 index 0000000..4ff1163 --- /dev/null +++ b/iptables-createchain-html.lsp @@ -0,0 +1 @@ +iptables-editchain-html.lsp
\ No newline at end of file diff --git a/iptables-createrule-html.lsp b/iptables-createrule-html.lsp new file mode 120000 index 0000000..9a0fb9c --- /dev/null +++ b/iptables-createrule-html.lsp @@ -0,0 +1 @@ +iptables-editrule-html.lsp
\ No newline at end of file diff --git a/iptables-details-html.lsp b/iptables-details-html.lsp new file mode 100644 index 0000000..bbdbd9a --- /dev/null +++ b/iptables-details-html.lsp @@ -0,0 +1,21 @@ +<% local data, viewlibrary = ... +require("viewfunctions") +--[[ DEBUG INFORMATION +io.write("<H1>DEBUGGING</H1><span style='color:red'><H2>DEBUG INFO: CFE</H2>") +io.write(html.cfe_unpack(data)) +io.write("</span>") +--]] +%> + +<% viewlibrary.dispatch_component("status") %> + +<H2><%= data.label %></H2> +<DL> +<% for i,tab in ipairs({"filter", "nat", "mangle"}) do %> + <H3><%= tab %></H3> + <TABLE> + <TR><%= data.value[tab].chains %> Chains</TR> + <TR><%= data.value[tab].rules %> Rules</TR> + </TABLE> +<% end %> +</DL> diff --git a/iptables-editchain-html.lsp b/iptables-editchain-html.lsp new file mode 100644 index 0000000..eaa1bfb --- /dev/null +++ b/iptables-editchain-html.lsp @@ -0,0 +1,15 @@ +<% 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 == "editchain" then + form.value.table.contenteditable = false + form.value.table.type = "text" + form.value.chain.contenteditable = false + end + local order = {"table", "chain", "policy"} + displayform(form, order) +%> diff --git a/iptables-editrule-html.lsp b/iptables-editrule-html.lsp new file mode 100644 index 0000000..7a7ad3c --- /dev/null +++ b/iptables-editrule-html.lsp @@ -0,0 +1,35 @@ +<% local form, viewlibrary, page_info = ... +require("viewfunctions") +%> + +<H1><%= form.label %></H1> +<% +for name,val in pairs(form.value) do val.name = name end +form.value.table.contenteditable = false +form.value.table.type = "text" +form.value.chain.contenteditable = false +form.value.position.contenteditable = false +form.action = page_info.script .. page_info.prefix .. page_info.controller .. "/" .. page_info.action +displayformstart(form) +%> + +<H2>Rule Identification</H2><DL> +<% +displayformitem(form.value.table) +displayformitem(form.value.chain) +displayformitem(form.value.position) +%> +</DL><H2>Basic Parameters</H2><DL> +<% +displayformitem(form.value.protocol) +displayformitem(form.value.source) +displayformitem(form.value.destination) +displayformitem(form.value.jump) +displayformitem(form.value.goto) +displayformitem(form.value.in_interface) +displayformitem(form.value.out_interface) +displayformitem(form.value.fragment) +displayformitem(form.value.set_counters) +%> +</DL><H2>Save</H2> +<% displayformend(form) %> diff --git a/iptables-expert-html.lsp b/iptables-expert-html.lsp new file mode 120000 index 0000000..207f324 --- /dev/null +++ b/iptables-expert-html.lsp @@ -0,0 +1 @@ +../expert-html.lsp
\ No newline at end of file diff --git a/iptables-html.lsp b/iptables-html.lsp new file mode 100644 index 0000000..d9600e1 --- /dev/null +++ b/iptables-html.lsp @@ -0,0 +1,35 @@ +<% local data, viewlibrary, page_info, session = ... %> +<% require("viewfunctions") %> + +<% displaycommandresults({"editchain", "deletechain", "createrule", "deleterule", "editrule", "createchain"}, session) %> + +<H1><%= data.label %></H1> +<DL> + <TABLE> + <% local tab = data.value.table %> + <% for j,chain in ipairs(data.value) do %> + <TR><TD> + <% if chain.policy then %> + <a href="<%= page_info.script..page_info.prefix..page_info.controller.."/editchain?chain="..chain.name.."&table="..tab.."&redir="..page_info.orig_action %>"><IMG SRC='/skins/static/tango/16x16/actions/document-properties.png' width='16' height='16' title="Edit Chain"></a> + <% else %> + <a href="<%= page_info.script..page_info.prefix..page_info.controller.."/deletechain?chain="..chain.name.."&table="..tab.."&redir="..page_info.orig_action %>"><IMG SRC='/skins/static/tango/16x16/actions/list-remove.png' width='16' height='16' title="Delete Chain"></a> + <% end %> + <%= chain.name %> + <% if chain.policy then io.write(" ("..chain.policy..")\n") end %> + <% if chain.references then io.write(" ("..chain.references.." references)\n") end %> + </TD></TR> + <% for j,line in ipairs(chain) do %> + <TR><TD STYLE='padding-left:40px'> + <a href="<%= page_info.script..page_info.prefix..page_info.controller.."/createrule?table="..tab.."&chain="..chain.name.."&position="..j.."&redir="..page_info.orig_action %>"><IMG SRC='/skins/static/tango/16x16/actions/list-add.png' width='16' height='16' title="Insert Rule"></a> + <a href="<%= page_info.script..page_info.prefix..page_info.controller.."/deleterule?table="..tab.."&chain="..chain.name.."&position="..j.."&redir="..page_info.orig_action %>"><IMG SRC='/skins/static/tango/16x16/actions/list-remove.png' width='16' height='16' title="Delete Rule"></a> + <a href="<%= page_info.script..page_info.prefix..page_info.controller.."/editrule?table="..tab.."&chain="..chain.name.."&position="..j.."&redir="..page_info.orig_action %>"><IMG SRC='/skins/static/tango/16x16/actions/document-properties.png' width='16' height='16' title="Edit Rule"></a> + </TD><TD><%= line %></TD> + </TR> + <% end %> + <TR><TD STYLE='padding-left:40px'> + <a href="<%= page_info.script..page_info.prefix..page_info.controller.."/createrule?table="..tab.."&chain="..chain.name.."&redir="..page_info.orig_action %>"><IMG SRC='/skins/static/tango/16x16/actions/list-add.png' width='16' height='16' title="Append Rule"></a> + </TD></TR> + <% end %> + <TR><TD><a href="<%= page_info.script..page_info.prefix..page_info.controller.."/createchain?table="..tab.."&redir="..page_info.orig_action %>"><IMG SRC='/skins/static/tango/16x16/actions/list-add.png' width='16' height='16' title="Create Chain"></a></TD></TR> + </TABLE> +</DL> diff --git a/iptables-model.lua b/iptables-model.lua new file mode 100644 index 0000000..3f55965 --- /dev/null +++ b/iptables-model.lua @@ -0,0 +1,268 @@ +module(..., package.seeall) + +-- Load libraries +require("modelfunctions") +require("fs") +require("format") + +-- Set variables +local packagename = "iptables" +local servicename = "iptables" +local rulesfile = "/var/lib/iptables/rules-save" + +local path = "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin " +local tables = {"filter", "nat", "mangle"} +local details + +-- ################################################################################ +-- LOCAL FUNCTIONS + +local getdetails = function() + if not details then + details = {} + local cmd = path .. "iptables -t filter -n -L" + for i,tab in ipairs(tables) do + local f = io.popen( (string.gsub(cmd, "filter", tab)) ) + details[tab] = {table=tab} + local file = f:read("*a") + f:close() + for line in string.gmatch(file, "([^\n]+)") do + if string.match(line, "^Chain") then + local name = string.match(line, "^%w+%s+(%S+)") + local policy = string.match(line, "policy (%w+)") + local references = string.match(line, "(%d+) references") + table.insert(details[tab], {name=name, policy=policy, references=references}) + elseif not string.match(line, "^target%s+prot") then + table.insert(details[tab][#details[tab]], line) + elseif not details[tab].header then + details[tab].header = line + end + end + end + end +end + +local find_chain = function(tab, chain) + getdetails() + if details[tab] then + for i,chn in ipairs(details[tab]) do + if chain == chn.name then + return chn + end + end + end + return nil +end + +local save = function() + local cmd = path .. "/etc/init.d/"..servicename.." save 2>&1" + local f = io.popen( cmd ) + f:close() + details = nil +end + +-- ################################################################################ +-- PUBLIC FUNCTIONS + +function getstatus() + local status = {} + + local value, errtxt = processinfo.package_version(packagename) + status.version = cfe({ + label="Program version", + value=value, + errtxt=errtxt, + }) + + return cfe({ type="group", value=status, label="IPtables Status" }) +end + +function getstatusdetails() + getdetails() + local retval = {} + for i,tab in ipairs(tables) do + local chains = 0 + local rules = 0 + for i,chain in ipairs(details[tab]) do + chains = chains + 1 + rules = rules + #chain + end + retval[tab] = {chains=chains, rules=rules} + end + + return cfe({ type="structure", value=retval, label="IPtables Status Details" }) +end + +function getrules(tab) + getdetails() + tab = tab or "filter" + + return cfe({ type="structure", value=details[tab] or {}, label=string.gsub(tab, "^.", string.upper).." Rules" }) +end + +function read_chain(tab, chain) + local retval = {} + retval.table = cfe({ type="select", value=tab or "filter", label="Table", option=tables }) + retval.chain = cfe({ value=chain or "", label="Chain" }) + getdetails() + if tab and not details[tab] then + retval.table.errtxt = "Invalid table" + end + if chain then + local chn = find_chain(retval.table.value, chain) + if not chn then + retval.chain.errtxt = "Cannot find chain" + elseif chn.policy then + -- only built-in chains can have policies, and the target can only be DROP or ACCEPT + retval.policy = cfe({ type="select", value=chn.policy, label="Policy", option={"DROP", "ACCEPT"} }) + end + end + return cfe({ type="group", value=retval, label="Chain" }) +end + +function update_chain(chain) + local success = true + getdetails() + if not details[chain.value.table.value] then + chain.value.table.errtxt = "Invalid table" + success = false + elseif not find_chain(chain.value.table.value, chain.value.chain.value) then + chain.value.chain.errtxt = "Invalid chain" + success = false + end + + if success then + if chain.value.policy then + local cmd = path .. "iptables -t "..chain.value.table.value.." -P "..chain.value.chain.value.." "..chain.value.policy.value.." 2>&1" + local f = io.popen(cmd) + local errtxt = f:read("*a") + f:close() + if errtxt ~= "" then + chain.errtxt = errtxt + end + save() + end + else + chain.errtxt = "Failed to update chain" + end + + return chain +end + +function create_chain(chain) + local success = true + getdetails() + if not details[chain.value.table.value] then + chain.value.table.errtxt = "Invalid table" + success = false + elseif find_chain(chain.value.table.value, chain.value.chain.value) then + chain.value.chain.errtxt = "Chain already exists" + success = false + end + if string.find(chain.value.chain.value, "[%s\'\"]") then + chain.value.chain.errtxt = "Chain cannot contain spaces or quotes" + success = false + end + + if success then + local cmd = path .. "iptables -t "..chain.value.table.value.." -N "..chain.value.chain.value.." 2>&1" + local f = io.popen(cmd) + local errtxt = f:read("*a") + if errtxt ~= "" then + chain.errtxt = errtxt + end + f:close() + save() + else + chain.errtxt = "Failed to create chain" + end + + return chain +end + +function delete_chain(tab, chain) + local retval = cfe({ label="Delete Chain result" }) + tab = tab or "filter" + local chn = find_chain(tab, chain) + if not chn then + retval.errtxt = "Could not find chain" + elseif chn.policy then + retval.errtxt = "Cannot delete built-in chain" + elseif chn.references and tonumber(chn.references) > 0 then + retval.errtxt = "Cannot delete chain with references" + else + local cmd = path .. "iptables -t "..tab.." -X "..chain.." 2>&1" + local f = io.popen(cmd) + local errtxt = f:read("*a") + if errtxt ~= "" then + retval.errtxt = errtxt + else + retval.value = "Deleted Chain" + end + save() + end + + return retval +end + +function read_rule(tab, chain, pos) + local retval = {} + retval.table = cfe({ type="select", value=tab or "filter", label="Table", option=tables }) + retval.chain = cfe({ value=chain or "", label="Chain" }) + retval.position = cfe({ value=pos or "", label="Position" }) + retval.protocol = cfe({ value="all", label="Protocol", descr="One of tcp, udp, icmp, or all, or a numeric value representing a protocol, or a protocol name from /etc/protocols. A '!' before the protocol inverts the test." }) + retval.source = cfe({ label="Source", descr="A network name or IP address (may have mask of type /xxx.xxx.xxx.xxx or /xx). A '!' before the address spcification inverts the sense of the address." }) + retval.destination = cfe({ label="Destination", descr="A network name or IP address (may have mask of type /xxx.xxx.xxx.xxx or /xx). A '!' before the address spcification inverts the sense of the address." }) + retval.jump = cfe({ label="Target", descr="Specify the target of the rule - one of ACCEPT, DROP, QUEUE, or RETURN, or the name of a user-defined chain." }) + retval.goto = cfe({ label="Goto", descr="Processing should continue in the specified chain" }) + retval.in_interface = cfe({ label="In Interface", descr="Name of an interface via which a packet was received. A '!' before the interface inverts the sense. A '+' ending the interface will match any interface that begins with this name." }) + retval.out_interface = cfe({ label="Out Interface", descr="Name of an interface via which a packet is going to be sent. A '!' before the interface inverts the sense. A '+' ending the interface will match any interface that begins with this name." }) + retval.fragment = cfe({ label="Fragment", descr="A '+' specifies the second and further packets of fragmented packets. A '!' specifies only head fragments or unfragmented packets." }) + retval.set_counters = cfe({ label="Set Counters", descr="'Number, number' to initialize the packet and byte counters."}) + + getdetails() + if tab and not details[tab] then + retval.table.errtxt = "Invalid table" + end + local chn + if chain then + chn = find_chain(retval.table.value, chain) + if not chn then + retval.chain.errtxt = "Cannot find chain" + end + end + if pos and chn then + if not chn[tonumber(pos)] then + retval.position.errtxt = "Cannot find rule" + else + -- We found the rule, update the settings + end + end + return cfe({ type="group", value=retval, label="Rule" }) +end + +function readrulesfile() + return modelfunctions.getfiledetails(rulesfile) +end + +function updaterulesfile(filedetails) + return modelfunctions.setfiledetails(filedetails, {rulesfile}) +end + +-- local implementation to add save, reload, and panic actions +function startstop_service(action) + local cmdresult = cfe({ label="Start/Stop result" }) + + if (string.lower(action) == "start") or (string.lower(action) == "stop") or (string.lower(action) == "restart") or (string.lower(action) == "save") or (string.lower(action) == "reload") or (string.lower(action) == "panic") then + local file = io.popen( "PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin /etc/init.d/" .. + servicename .. " " .. string.lower(action) .. " 2>&1" ) + if file ~= nil then + cmdresult.value = file:read( "*a" ) + file:close() + end + posix.sleep(2) -- Wait for the process to start|stop + else + cmdresult.errtxt = "Unknown command!" + end + return cmdresult +end diff --git a/iptables-startstop-html.lsp b/iptables-startstop-html.lsp new file mode 100644 index 0000000..caa0b96 --- /dev/null +++ b/iptables-startstop-html.lsp @@ -0,0 +1,25 @@ +<% local data, viewlibrary, page_info = ... %> + +<H1>Management</H1> +<DL> +<form action="<%= page_info.script .. page_info.prefix .. page_info.controller .. "/" .. page_info.action %>" method="POST"> +<DT>Load rules from rules file</DT> +<DD> +<input class="submit" type="submit" name="action" value="Reload"> +</DD> +<DT>Save current rules to rules file</DT> +<DD> +<input class="submit" type="submit" name="action" value="Save"> +</DD> +</form> + +<% if data.value.result then %> +<DT>Previous action result</DT> +<DD> +<% if data.value.result.value ~= "" then %> +<P CLASS='descr'><%= string.gsub(data.value.result.value, "\n", "<BR>") %></P> +<% end if data.value.result.errtxt then %> +<P CLASS='error'><%= string.gsub(data.value.result.errtxt, "\n", "<BR>") %></P> +<% end end %> +</DD> +</DL> diff --git a/iptables-status-html.lsp b/iptables-status-html.lsp new file mode 120000 index 0000000..b2f8480 --- /dev/null +++ b/iptables-status-html.lsp @@ -0,0 +1 @@ +../status-html.lsp
\ No newline at end of file diff --git a/iptables.menu b/iptables.menu new file mode 100644 index 0000000..b047869 --- /dev/null +++ b/iptables.menu @@ -0,0 +1,6 @@ +#CAT GROUP/DESC TAB ACTION +Networking 45IPtables Status details +Networking 45IPtables Filter_Rules filterrules +Networking 45IPtables Nat_Rules natrules +Networking 45IPtables Mangle_Rules manglerules +Networking 45IPtables Expert expert diff --git a/iptables.roles b/iptables.roles new file mode 100644 index 0000000..f32fc56 --- /dev/null +++ b/iptables.roles @@ -0,0 +1,4 @@ +USER=iptables:status,iptables:details,iptables:startstop +EDITOR=iptables:filterrules,iptables:natrules,iptables:manglerules,iptables:editchain,iptables:createchain,iptables:deletechain,iptables:editrule,iptables:createrule,iptables:deleterule +EXPERT=iptables:expert +ADMIN=iptables:status,iptables:details,iptables:startstop,iptables:filterrules,iptables:natrules,iptables:manglerules,iptables:editchain,iptables:createchain,iptables:deletechain,iptables:editrule,iptables:createrule,iptables:deleterule,iptables:expert |