diff options
Diffstat (limited to 'modules/luci-base/luasrc/model/firewall.lua')
-rw-r--r-- | modules/luci-base/luasrc/model/firewall.lua | 582 |
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 |