libs/core: add luci.model.firewall, oop abstraction for uci firewall
authorJo-Philipp Wich <jow@openwrt.org>
Thu, 8 Oct 2009 00:14:07 +0000 (00:14 +0000)
committerJo-Philipp Wich <jow@openwrt.org>
Thu, 8 Oct 2009 00:14:07 +0000 (00:14 +0000)
libs/core/luasrc/model/firewall.lua [new file with mode: 0644]

diff --git a/libs/core/luasrc/model/firewall.lua b/libs/core/luasrc/model/firewall.lua
new file mode 100644 (file)
index 0000000..c1a8a45
--- /dev/null
@@ -0,0 +1,309 @@
+--[[
+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 lmo = require "lmo"
+local utl = require "luci.util"
+local uct = require "luci.model.uci.bind"
+
+module "luci.model.firewall"
+
+
+local ub = uct.bind("firewall")
+
+function init(cursor)
+       if cursor then
+               cursor:unload("firewall")
+               cursor:load("firewall")
+               ub:init(cursor)
+       end
+end
+
+function add_zone(n)
+       if n then
+               local z = ub.uci:section("firewall", "zone", nil, {
+                       name    = n,
+                       network = " ",
+                       input   = defaults:input()   or "DROP",
+                       forward = defaults:forward() or "DROP",
+                       output  = defaults:output()  or "DROP"
+               })
+
+               return z and zone(z)
+       end
+end
+
+function get_zone(n)
+       local z
+       ub.uci: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
+
+function get_zones()
+       local zones = { }
+       ub.uci:foreach("firewall", "zone",
+               function(s)
+                       if s.name then
+                               zones[#zones+1] = zone(s['.name'])
+                       end
+               end)
+       return zones
+end
+
+function get_zones_by_network(net)
+       local zones = { }
+       ub.uci:foreach("firewall", "zone",
+               function(s)
+                       if s.name then
+                               local n
+                               for _, n in ipairs(ub:list(s.network or s.name)) do
+                                       if n == net then
+                                               zones[#zones+1] = zone(s['.name'])
+                                               return true
+                                       end
+                               end
+                       end
+               end)
+       return zones
+end
+
+function del_zone(n)
+       local r = false
+       ub.uci:foreach("firewall", "zone",
+               function(s)
+                       if n and s.name == n then
+                               r = ub.uci:delete("firewall", s['.name'])
+                               return false
+                       end
+               end)
+       if r then
+               ub.uci:foreach("firewall", "rule",
+                       function(s)
+                               if s.src == n or s.dest == n then
+                                       ub.uci:delete("firewall", s['.name'])
+                               end
+                       end)
+               ub.uci:foreach("firewall", "redirect",
+                       function(s)
+                               if s.src == n then
+                                       ub.uci:delete("firewall", s['.name'])
+                               end
+                       end)
+               ub.uci:foreach("firewall", "forwarding",
+                       function(s)
+                               if s.src == n then
+                                       ub.uci:delete("firewall", s['.name'])
+                               end
+                       end)
+       end
+       return r
+end
+
+function del_network(net)
+       local z
+       if net then
+               for _, z in ipairs(get_zones()) do
+                       z:del_network(net)
+               end
+       end
+end
+
+
+defaults = ub:usection("defaults")
+defaults:property_bool("syn_flood")
+defaults:property_bool("drop_invalid")
+defaults:property("input")
+defaults:property("forward")
+defaults:property("output")
+
+
+zone = ub:section("zone")
+zone:property_bool("masq")
+zone:property("name")
+zone:property("network")
+zone:property("input")
+zone:property("forward")
+zone:property("output")
+
+function zone.add_network(self, net)
+       if ub.uci:get("network", net) == "interface" then
+               local networks = ub:list(self:network() or self:name(), net)
+               if #networks > 0 then
+                       self:network(table.concat(networks, " "))
+               else
+                       self:network(" ")
+               end
+       end
+end
+
+function zone.del_network(self, net)
+       local networks = ub:list(self:network() or self:name(), nil, net)
+       if #networks > 0 then
+               self:network(table.concat(networks, " "))
+       else
+               self:network(" ")
+       end
+end
+
+function zone.get_networks(self)
+       return ub:list(self:network() or self:name())
+end
+
+function zone.get_forwardings_by(self, what)
+       local name = self:name()
+       local forwards = { }
+       ub.uci: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, with_mtu_fix)
+       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() then
+               local s = ub.uci:section("firewall", "forwarding", nil, {
+                       src     = self:name(),
+                       dest    = dest,
+                       mtu_fix = with_mtu_fix and true or false
+               })
+               return s and forwarding(s)
+       end
+end
+
+function zone.add_forwarding_from(self, src, with_mtu_fix)
+       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() then
+               local s = ub.uci:section("firewall", "forwarding", nil, {
+                       src     = src,
+                       dest    = self:name(),
+                       mtu_fix = with_mtu_fix and true or false
+               })
+               return s and forwarding(s)
+       end
+end
+
+function zone.add_redirect(self, options)
+       options = options or { }
+       options.src = self:name()
+       local s = ub.uci: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 = ub.uci: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(lmo.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 = ub:section("forwarding")
+forwarding:property_bool("mtu_fix")
+forwarding:property("src")
+forwarding:property("dest")
+
+function forwarding.src_zone(self)
+       return zone(self:src())
+end
+
+function forwarding.dest_zone(self)
+       return zone(self:dest())
+end
+
+
+rule = ub:section("rule")
+rule:property("src")
+rule:property("src_ip")
+rule:property("src_mac")
+rule:property("src_port")
+rule:property("dest")
+rule:property("dest_ip")
+rule:property("dest_port")
+rule:property("proto")
+rule:property("target")
+
+function rule.src_zone(self)
+       return zone(self:src())
+end
+
+
+redirect = ub:section("redirect")
+redirect:property("src")
+redirect:property("src_ip")
+redirect:property("src_mac")
+redirect:property("src_port")
+redirect:property("src_dport")
+redirect:property("dest_ip")
+redirect:property("dest_port")
+redirect:property("proto")
+
+function redirect.src_zone(self)
+       return zone(self:src())
+end
+