summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTed Trask <ttrask01@yahoo.com>2008-11-03 21:30:32 +0000
committerTed Trask <ttrask01@yahoo.com>2008-11-03 21:30:32 +0000
commitfc670b19af9f6dd4027dcec0fc6cc0035860f9e2 (patch)
treeb86af704ba7bbef308e28014f3c0162bf2fea627
downloadacf-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--Makefile44
-rw-r--r--README1
-rw-r--r--config.mk10
-rw-r--r--iptables-controller.lua64
l---------iptables-createchain-html.lsp1
l---------iptables-createrule-html.lsp1
-rw-r--r--iptables-details-html.lsp21
-rw-r--r--iptables-editchain-html.lsp15
-rw-r--r--iptables-editrule-html.lsp35
l---------iptables-expert-html.lsp1
-rw-r--r--iptables-html.lsp35
-rw-r--r--iptables-model.lua268
-rw-r--r--iptables-startstop-html.lsp25
l---------iptables-status-html.lsp1
-rw-r--r--iptables.menu6
-rw-r--r--iptables.roles4
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
diff --git a/README b/README
new file mode 100644
index 0000000..8790399
--- /dev/null
+++ b/README
@@ -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