From 9e57fbb2c3f9c44cdf0a57e6fb9c1df32c84d52b Mon Sep 17 00:00:00 2001 From: Jo-Philipp Wich Date: Sun, 3 Nov 2019 20:34:57 +0100 Subject: [PATCH] luci-base, luci-app-firewall: port custom rules to client side view Signed-off-by: Jo-Philipp Wich --- .../resources/view/firewall/custom.js | 31 ++ .../luasrc/controller/firewall.lua | 3 +- .../luasrc/model/cbi/firewall/custom.lua | 31 -- .../luasrc/tools/firewall.lua | 289 ------------------ .../root/usr/share/rpcd/acl.d/luci-base.json | 7 + 5 files changed, 39 insertions(+), 322 deletions(-) create mode 100644 applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js delete mode 100644 applications/luci-app-firewall/luasrc/model/cbi/firewall/custom.lua delete mode 100644 applications/luci-app-firewall/luasrc/tools/firewall.lua diff --git a/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js new file mode 100644 index 000000000..4b4b14008 --- /dev/null +++ b/applications/luci-app-firewall/htdocs/luci-static/resources/view/firewall/custom.js @@ -0,0 +1,31 @@ +'use strict'; +'require fs'; + +return L.view.extend({ + load: function() { + return L.resolveDefault(fs.read('/etc/firewall.user'), ''); + }, + + handleSave: function(ev) { + var value = (document.querySelector('textarea').value || '').trim().replace(/\r\n/g, '\n') + '\n'; + + return fs.write('/etc/firewall.user', value).then(function(rc) { + document.querySelector('textarea').value = value; + L.ui.addNotification(null, E('p', _('Contents have been saved.')), 'info'); + fs.exec('/etc/init.d/firewall', ['restart']); + }).catch(function(e) { + L.ui.addNotification(null, E('p', _('Unable to save contents: %s').format(e.message))); + }); + }, + + render: function(fwuser) { + return E([ + E('h2', _('Firewall - Custom Rules')), + E('p', {}, _('Custom rules allow you to execute arbitrary iptables commands which are not otherwise covered by the firewall framework. The commands are executed after each firewall restart, right after the default ruleset has been loaded.')), + E('p', {}, E('textarea', { 'style': 'width:100%', 'rows': 10 }, [ fwuser != null ? fwuser : '' ])) + ]); + }, + + handleSaveApply: null, + handleReset: null +}); diff --git a/applications/luci-app-firewall/luasrc/controller/firewall.lua b/applications/luci-app-firewall/luasrc/controller/firewall.lua index 58a44c601..5f8cb6ef3 100644 --- a/applications/luci-app-firewall/luasrc/controller/firewall.lua +++ b/applications/luci-app-firewall/luasrc/controller/firewall.lua @@ -15,6 +15,5 @@ function index() view("firewall/rules"), _("Traffic Rules"), 30) entry({"admin", "network", "firewall", "custom"}, - form("firewall/custom"), - _("Custom Rules"), 40).leaf = true + view("firewall/custom"), _("Custom Rules"), 40).leaf = true end diff --git a/applications/luci-app-firewall/luasrc/model/cbi/firewall/custom.lua b/applications/luci-app-firewall/luasrc/model/cbi/firewall/custom.lua deleted file mode 100644 index 21a1b2796..000000000 --- a/applications/luci-app-firewall/luasrc/model/cbi/firewall/custom.lua +++ /dev/null @@ -1,31 +0,0 @@ --- Copyright 2011 Jo-Philipp Wich --- Licensed to the public under the Apache License 2.0. - -local fs = require "nixio.fs" - -local f = SimpleForm("firewall", - translate("Firewall - Custom Rules"), - translate("Custom rules allow you to execute arbitrary iptables commands \ - which are not otherwise covered by the firewall framework. \ - The commands are executed after each firewall restart, right after \ - the default ruleset has been loaded.")) - -local o = f:field(Value, "_custom") - -o.template = "cbi/tvalue" -o.rows = 20 - -function o.cfgvalue(self, section) - return fs.readfile("/etc/firewall.user") -end - -function o.write(self, section, value) - value = value:gsub("\r\n?", "\n") - fs.writefile("/etc/firewall.user", value) - require("luci.sys").call("/etc/init.d/firewall restart >/dev/null 2<&1") - require("nixio").syslog('info', 'Restarting firewall on custom /etc/firewall.user change') -end - -f.submit = translate("Restart Firewall") - -return f diff --git a/applications/luci-app-firewall/luasrc/tools/firewall.lua b/applications/luci-app-firewall/luasrc/tools/firewall.lua deleted file mode 100644 index 055342bfb..000000000 --- a/applications/luci-app-firewall/luasrc/tools/firewall.lua +++ /dev/null @@ -1,289 +0,0 @@ --- Copyright 2011-2012 Jo-Philipp Wich --- Licensed to the public under the Apache License 2.0. - -module("luci.tools.firewall", package.seeall) - -local ut = require "luci.util" -local ip = require "luci.ip" -local nx = require "nixio" - -local translate, translatef = luci.i18n.translate, luci.i18n.translatef - -local function _(...) - return tostring(translate(...)) -end - -function fmt_neg(x) - if type(x) == "string" then - local v, neg = x:gsub("^ *! *", "") - if neg > 0 then - return v, "%s " % _("not") - else - return x, "" - end - end - return x, "" -end - -function fmt_mac(x) - if x and #x > 0 then - local m, n - local l = { _("MAC"), " " } - for m in ut.imatch(x) do - m, n = fmt_neg(m) - l[#l+1] = "%s%s" %{ n, m } - l[#l+1] = ", " - end - if #l > 1 then - l[#l] = nil - if #l > 3 then - l[1] = _("MACs") - end - return table.concat(l, "") - end - end -end - -function fmt_port(x, d) - if x and #x > 0 then - local p, n - local l = { _("port"), " " } - for p in ut.imatch(x) do - p, n = fmt_neg(p) - local a, b = p:match("(%d+)%D+(%d+)") - if a and b then - l[1] = _("ports") - l[#l+1] = "%s%d-%d" %{ n, a, b } - else - l[#l+1] = "%s%d" %{ n, p } - end - l[#l+1] = ", " - end - if #l > 1 then - l[#l] = nil - if #l > 3 then - l[1] = _("ports") - end - return table.concat(l, "") - end - end - return d and "%s" % d -end - -function fmt_ip(x, d) - if x and #x > 0 then - local l = { _("IP"), " " } - local v, a, n - for v in ut.imatch(x) do - v, n = fmt_neg(v) - a, m = v:match("(%S+)/(%d+%.%S+)") - a = a or v - a = a:match(":") and ip.IPv6(a, m) or ip.IPv4(a, m) - if a and (a:is6() and a:prefix() < 128 or a:prefix() < 32) then - l[1] = _("IP range") - l[#l+1] = "%s%s" %{ - a:minhost():string(), - a:maxhost():string(), - n, a:string() - } - else - l[#l+1] = "%s%s" %{ - n, - a and a:string() or v - } - end - l[#l+1] = ", " - end - if #l > 1 then - l[#l] = nil - if #l > 3 then - l[1] = _("IPs") - end - return table.concat(l, "") - end - end - return d and "%s" % d -end - -function fmt_zone(x, d) - if x == "*" then - return "%s" % _("any zone") - elseif x and #x > 0 then - return "%s" % x - elseif d then - return "%s" % d - end -end - -function fmt_icmp_type(x) - if x and #x > 0 then - local t, v, n - local l = { _("type"), " " } - for v in ut.imatch(x) do - v, n = fmt_neg(v) - l[#l+1] = "%s%s" %{ n, v } - l[#l+1] = ", " - end - if #l > 1 then - l[#l] = nil - if #l > 3 then - l[1] = _("types") - end - return table.concat(l, "") - end - end -end - -function fmt_proto(x, icmp_types) - if x and #x > 0 then - local v, n - local l = { } - local t = fmt_icmp_type(icmp_types) - for v in ut.imatch(x) do - v, n = fmt_neg(v) - if v == "tcpudp" then - l[#l+1] = "TCP" - l[#l+1] = ", " - l[#l+1] = "UDP" - l[#l+1] = ", " - elseif v ~= "all" then - local p = nx.getproto(v) - if p then - -- ICMP - if (p.proto == 1 or p.proto == 58) and t then - l[#l+1] = translatef( - "%s%s with %s", - n, p.aliases[1] or p.name, t - ) - else - l[#l+1] = "%s%s" %{ - n, - p.aliases[1] or p.name - } - end - l[#l+1] = ", " - end - end - end - if #l > 0 then - l[#l] = nil - return table.concat(l, "") - end - end -end - -function fmt_limit(limit, burst) - burst = tonumber(burst) - if limit and #limit > 0 then - local l, u = limit:match("(%d+)/(%w+)") - l = tonumber(l or limit) - u = u or "second" - if l then - if u:match("^s") then - u = _("second") - elseif u:match("^m") then - u = _("minute") - elseif u:match("^h") then - u = _("hour") - elseif u:match("^d") then - u = _("day") - end - if burst and burst > 0 then - return translatef("%d pkts. per %s, \ - burst %d pkts.", l, u, burst) - else - return translatef("%d pkts. per %s", l, u) - end - end - end -end - -function fmt_target(x, src, dest) - if not src or #src == 0 then - if x == "ACCEPT" then - return _("Accept output") - elseif x == "REJECT" then - return _("Refuse output") - elseif x == "NOTRACK" then - return _("Do not track output") - else --if x == "DROP" then - return _("Discard output") - end - elseif dest and #dest > 0 then - if x == "ACCEPT" then - return _("Accept forward") - elseif x == "REJECT" then - return _("Refuse forward") - elseif x == "NOTRACK" then - return _("Do not track forward") - else --if x == "DROP" then - return _("Discard forward") - end - else - if x == "ACCEPT" then - return _("Accept input") - elseif x == "REJECT" then - return _("Refuse input") - elseif x == "NOTRACK" then - return _("Do not track input") - else --if x == "DROP" then - return _("Discard input") - end - end -end - - -function opt_enabled(s, t, ...) - if t == luci.cbi.Button then - local o = s:option(t, "__enabled") - function o.render(self, section) - if self.map:get(section, "enabled") ~= "0" then - self.title = _("Rule is enabled") - self.inputtitle = _("Disable") - self.inputstyle = "reset" - else - self.title = _("Rule is disabled") - self.inputtitle = _("Enable") - self.inputstyle = "apply" - end - t.render(self, section) - end - function o.write(self, section, value) - if self.map:get(section, "enabled") ~= "0" then - self.map:set(section, "enabled", "0") - else - self.map:del(section, "enabled") - end - end - return o - else - local o = s:option(t, "enabled", ...) - o.default = "1" - return o - end -end - -function opt_name(s, t, ...) - local o = s:option(t, "name", ...) - - function o.cfgvalue(self, section) - return self.map:get(section, "name") or - self.map:get(section, "_name") or "-" - end - - function o.write(self, section, value) - if value ~= "-" then - self.map:set(section, "name", value) - self.map:del(section, "_name") - else - self:remove(section) - end - end - - function o.remove(self, section) - self.map:del(section, "name") - self.map:del(section, "_name") - end - - return o -end diff --git a/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json b/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json index a60c432bc..321817302 100644 --- a/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json +++ b/modules/luci-base/root/usr/share/rpcd/acl.d/luci-base.json @@ -88,12 +88,19 @@ "luci-app-firewall": { "description": "Grant access to firewall procedures", "read": { + "file": { + "/etc/firewall.user": [ "read" ] + }, "ubus": { "luci": [ "getConntrackHelpers" ] }, "uci": [ "firewall" ] }, "write": { + "file": { + "/etc/firewall.user": [ "write" ], + "/etc/init.d/firewall": [ "exec" ] + }, "uci": [ "firewall" ] } } -- 2.25.1