summaryrefslogtreecommitdiffhomepage
path: root/modules/luci-base/luasrc/model/firewall.lua
diff options
context:
space:
mode:
Diffstat (limited to 'modules/luci-base/luasrc/model/firewall.lua')
-rw-r--r--modules/luci-base/luasrc/model/firewall.lua582
1 files changed, 582 insertions, 0 deletions
diff --git a/modules/luci-base/luasrc/model/firewall.lua b/modules/luci-base/luasrc/model/firewall.lua
new file mode 100644
index 000000000..a9f6fdb7f
--- /dev/null
+++ b/modules/luci-base/luasrc/model/firewall.lua
@@ -0,0 +1,582 @@
+--[[
+LuCI - Firewall model
+
+Copyright 2009 Jo-Philipp Wich <xm@subsignal.org>
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+]]--
+
+local type, pairs, ipairs, table, luci, math
+ = type, pairs, ipairs, table, luci, math
+
+local tpl = require "luci.template.parser"
+local utl = require "luci.util"
+local uci = require "luci.model.uci"
+
+module "luci.model.firewall"
+
+
+local uci_r, uci_s
+
+function _valid_id(x)
+ return (x and #x > 0 and x:match("^[a-zA-Z0-9_]+$"))
+end
+
+function _get(c, s, o)
+ return uci_r:get(c, s, o)
+end
+
+function _set(c, s, o, v)
+ if v ~= nil then
+ if type(v) == "boolean" then v = v and "1" or "0" end
+ return uci_r:set(c, s, o, v)
+ else
+ return uci_r:delete(c, s, o)
+ end
+end
+
+
+function init(cursor)
+ uci_r = cursor or uci_r or uci.cursor()
+ uci_s = uci_r:substate()
+
+ return _M
+end
+
+function save(self, ...)
+ uci_r:save(...)
+ uci_r:load(...)
+end
+
+function commit(self, ...)
+ uci_r:commit(...)
+ uci_r:load(...)
+end
+
+function get_defaults()
+ return defaults()
+end
+
+function new_zone(self)
+ local name = "newzone"
+ local count = 1
+
+ while self:get_zone(name) do
+ count = count + 1
+ name = "newzone%d" % count
+ end
+
+ return self:add_zone(name)
+end
+
+function add_zone(self, n)
+ if _valid_id(n) and not self:get_zone(n) then
+ local d = defaults()
+ local z = uci_r:section("firewall", "zone", nil, {
+ name = n,
+ network = " ",
+ input = d:input() or "DROP",
+ forward = d:forward() or "DROP",
+ output = d:output() or "DROP"
+ })
+
+ return z and zone(z)
+ end
+end
+
+function get_zone(self, n)
+ if uci_r:get("firewall", n) == "zone" then
+ return zone(n)
+ else
+ local z
+ uci_r:foreach("firewall", "zone",
+ function(s)
+ if n and s.name == n then
+ z = s['.name']
+ return false
+ end
+ end)
+ return z and zone(z)
+ end
+end
+
+function get_zones(self)
+ local zones = { }
+ local znl = { }
+
+ uci_r:foreach("firewall", "zone",
+ function(s)
+ if s.name then
+ znl[s.name] = zone(s['.name'])
+ end
+ end)
+
+ local z
+ for z in utl.kspairs(znl) do
+ zones[#zones+1] = znl[z]
+ end
+
+ return zones
+end
+
+function get_zone_by_network(self, net)
+ local z
+
+ uci_r:foreach("firewall", "zone",
+ function(s)
+ if s.name and net then
+ local n
+ for n in utl.imatch(s.network or s.name) do
+ if n == net then
+ z = s['.name']
+ return false
+ end
+ end
+ end
+ end)
+
+ return z and zone(z)
+end
+
+function del_zone(self, n)
+ local r = false
+
+ if uci_r:get("firewall", n) == "zone" then
+ local z = uci_r:get("firewall", n, "name")
+ r = uci_r:delete("firewall", n)
+ n = z
+ else
+ uci_r:foreach("firewall", "zone",
+ function(s)
+ if n and s.name == n then
+ r = uci_r:delete("firewall", s['.name'])
+ return false
+ end
+ end)
+ end
+
+ if r then
+ uci_r:foreach("firewall", "rule",
+ function(s)
+ if s.src == n or s.dest == n then
+ uci_r:delete("firewall", s['.name'])
+ end
+ end)
+
+ uci_r:foreach("firewall", "redirect",
+ function(s)
+ if s.src == n or s.dest == n then
+ uci_r:delete("firewall", s['.name'])
+ end
+ end)
+
+ uci_r:foreach("firewall", "forwarding",
+ function(s)
+ if s.src == n or s.dest == n then
+ uci_r:delete("firewall", s['.name'])
+ end
+ end)
+ end
+
+ return r
+end
+
+function rename_zone(self, old, new)
+ local r = false
+
+ if _valid_id(new) and not self:get_zone(new) then
+ uci_r:foreach("firewall", "zone",
+ function(s)
+ if old and s.name == old then
+ if not s.network then
+ uci_r:set("firewall", s['.name'], "network", old)
+ end
+ uci_r:set("firewall", s['.name'], "name", new)
+ r = true
+ return false
+ end
+ end)
+
+ if r then
+ uci_r:foreach("firewall", "rule",
+ function(s)
+ if s.src == old then
+ uci_r:set("firewall", s['.name'], "src", new)
+ end
+ if s.dest == old then
+ uci_r:set("firewall", s['.name'], "dest", new)
+ end
+ end)
+
+ uci_r:foreach("firewall", "redirect",
+ function(s)
+ if s.src == old then
+ uci_r:set("firewall", s['.name'], "src", new)
+ end
+ if s.dest == old then
+ uci_r:set("firewall", s['.name'], "dest", new)
+ end
+ end)
+
+ uci_r:foreach("firewall", "forwarding",
+ function(s)
+ if s.src == old then
+ uci_r:set("firewall", s['.name'], "src", new)
+ end
+ if s.dest == old then
+ uci_r:set("firewall", s['.name'], "dest", new)
+ end
+ end)
+ end
+ end
+
+ return r
+end
+
+function del_network(self, net)
+ local z
+ if net then
+ for _, z in ipairs(self:get_zones()) do
+ z:del_network(net)
+ end
+ end
+end
+
+
+defaults = utl.class()
+function defaults.__init__(self)
+ uci_r:foreach("firewall", "defaults",
+ function(s)
+ self.sid = s['.name']
+ return false
+ end)
+
+ self.sid = self.sid or uci_r:section("firewall", "defaults", nil, { })
+end
+
+function defaults.get(self, opt)
+ return _get("firewall", self.sid, opt)
+end
+
+function defaults.set(self, opt, val)
+ return _set("firewall", self.sid, opt, val)
+end
+
+function defaults.syn_flood(self)
+ return (self:get("syn_flood") == "1")
+end
+
+function defaults.drop_invalid(self)
+ return (self:get("drop_invalid") == "1")
+end
+
+function defaults.input(self)
+ return self:get("input") or "DROP"
+end
+
+function defaults.forward(self)
+ return self:get("forward") or "DROP"
+end
+
+function defaults.output(self)
+ return self:get("output") or "DROP"
+end
+
+
+zone = utl.class()
+function zone.__init__(self, z)
+ if uci_r:get("firewall", z) == "zone" then
+ self.sid = z
+ self.data = uci_r:get_all("firewall", z)
+ else
+ uci_r:foreach("firewall", "zone",
+ function(s)
+ if s.name == z then
+ self.sid = s['.name']
+ self.data = s
+ return false
+ end
+ end)
+ end
+end
+
+function zone.get(self, opt)
+ return _get("firewall", self.sid, opt)
+end
+
+function zone.set(self, opt, val)
+ return _set("firewall", self.sid, opt, val)
+end
+
+function zone.masq(self)
+ return (self:get("masq") == "1")
+end
+
+function zone.name(self)
+ return self:get("name")
+end
+
+function zone.network(self)
+ return self:get("network")
+end
+
+function zone.input(self)
+ return self:get("input") or defaults():input() or "DROP"
+end
+
+function zone.forward(self)
+ return self:get("forward") or defaults():forward() or "DROP"
+end
+
+function zone.output(self)
+ return self:get("output") or defaults():output() or "DROP"
+end
+
+function zone.add_network(self, net)
+ if uci_r:get("network", net) == "interface" then
+ local nets = { }
+
+ local n
+ for n in utl.imatch(self:get("network") or self:get("name")) do
+ if n ~= net then
+ nets[#nets+1] = n
+ end
+ end
+
+ nets[#nets+1] = net
+
+ _M:del_network(net)
+ self:set("network", table.concat(nets, " "))
+ end
+end
+
+function zone.del_network(self, net)
+ local nets = { }
+
+ local n
+ for n in utl.imatch(self:get("network") or self:get("name")) do
+ if n ~= net then
+ nets[#nets+1] = n
+ end
+ end
+
+ if #nets > 0 then
+ self:set("network", table.concat(nets, " "))
+ else
+ self:set("network", " ")
+ end
+end
+
+function zone.get_networks(self)
+ local nets = { }
+
+ local n
+ for n in utl.imatch(self:get("network") or self:get("name")) do
+ nets[#nets+1] = n
+ end
+
+ return nets
+end
+
+function zone.clear_networks(self)
+ self:set("network", " ")
+end
+
+function zone.get_forwardings_by(self, what)
+ local name = self:name()
+ local forwards = { }
+
+ uci_r:foreach("firewall", "forwarding",
+ function(s)
+ if s.src and s.dest and s[what] == name then
+ forwards[#forwards+1] = forwarding(s['.name'])
+ end
+ end)
+
+ return forwards
+end
+
+function zone.add_forwarding_to(self, dest)
+ local exist, forward
+
+ for _, forward in ipairs(self:get_forwardings_by('src')) do
+ if forward:dest() == dest then
+ exist = true
+ break
+ end
+ end
+
+ if not exist and dest ~= self:name() and _valid_id(dest) then
+ local s = uci_r:section("firewall", "forwarding", nil, {
+ src = self:name(),
+ dest = dest
+ })
+
+ return s and forwarding(s)
+ end
+end
+
+function zone.add_forwarding_from(self, src)
+ local exist, forward
+
+ for _, forward in ipairs(self:get_forwardings_by('dest')) do
+ if forward:src() == src then
+ exist = true
+ break
+ end
+ end
+
+ if not exist and src ~= self:name() and _valid_id(src) then
+ local s = uci_r:section("firewall", "forwarding", nil, {
+ src = src,
+ dest = self:name()
+ })
+
+ return s and forwarding(s)
+ end
+end
+
+function zone.del_forwardings_by(self, what)
+ local name = self:name()
+
+ uci_r:delete_all("firewall", "forwarding",
+ function(s)
+ return (s.src and s.dest and s[what] == name)
+ end)
+end
+
+function zone.add_redirect(self, options)
+ options = options or { }
+ options.src = self:name()
+
+ local s = uci_r:section("firewall", "redirect", nil, options)
+ return s and redirect(s)
+end
+
+function zone.add_rule(self, options)
+ options = options or { }
+ options.src = self:name()
+
+ local s = uci_r:section("firewall", "rule", nil, options)
+ return s and rule(s)
+end
+
+function zone.get_color(self)
+ if self and self:name() == "lan" then
+ return "#90f090"
+ elseif self and self:name() == "wan" then
+ return "#f09090"
+ elseif self then
+ math.randomseed(tpl.hash(self:name()))
+
+ local r = math.random(128)
+ local g = math.random(128)
+ local min = 0
+ local max = 128
+
+ if ( r + g ) < 128 then
+ min = 128 - r - g
+ else
+ max = 255 - r - g
+ end
+
+ local b = min + math.floor( math.random() * ( max - min ) )
+
+ return "#%02x%02x%02x" % { 0xFF - r, 0xFF - g, 0xFF - b }
+ else
+ return "#eeeeee"
+ end
+end
+
+
+forwarding = utl.class()
+function forwarding.__init__(self, f)
+ self.sid = f
+end
+
+function forwarding.src(self)
+ return uci_r:get("firewall", self.sid, "src")
+end
+
+function forwarding.dest(self)
+ return uci_r:get("firewall", self.sid, "dest")
+end
+
+function forwarding.src_zone(self)
+ return zone(self:src())
+end
+
+function forwarding.dest_zone(self)
+ return zone(self:dest())
+end
+
+
+rule = utl.class()
+function rule.__init__(self, f)
+ self.sid = f
+end
+
+function rule.get(self, opt)
+ return _get("firewall", self.sid, opt)
+end
+
+function rule.set(self, opt, val)
+ return _set("firewall", self.sid, opt, val)
+end
+
+function rule.src(self)
+ return uci_r:get("firewall", self.sid, "src")
+end
+
+function rule.dest(self)
+ return uci_r:get("firewall", self.sid, "dest")
+end
+
+function rule.src_zone(self)
+ return zone(self:src())
+end
+
+function rule.dest_zone(self)
+ return zone(self:dest())
+end
+
+
+redirect = utl.class()
+function redirect.__init__(self, f)
+ self.sid = f
+end
+
+function redirect.get(self, opt)
+ return _get("firewall", self.sid, opt)
+end
+
+function redirect.set(self, opt, val)
+ return _set("firewall", self.sid, opt, val)
+end
+
+function redirect.src(self)
+ return uci_r:get("firewall", self.sid, "src")
+end
+
+function redirect.dest(self)
+ return uci_r:get("firewall", self.sid, "dest")
+end
+
+function redirect.src_zone(self)
+ return zone(self:src())
+end
+
+function redirect.dest_zone(self)
+ return zone(self:dest())
+end