diff options
-rw-r--r-- | awall/model.lua | 43 | ||||
-rw-r--r-- | awall/modules/filter.lua | 42 |
2 files changed, 58 insertions, 27 deletions
diff --git a/awall/model.lua b/awall/model.lua index c49daa5..fcc1ee8 100644 --- a/awall/model.lua +++ b/awall/model.lua @@ -29,6 +29,9 @@ local maplist = util.maplist local startswith = require('stringy').startswith +local RECENT_MAX_COUNT = 20 + + local function join(a, b) local comps = {} local function add(s) if s and s > '' then table.insert(comps, s) end end @@ -67,6 +70,7 @@ function M.ConfigObject:create(cls, params, label, index) end end + if type(params) ~= 'table' then params = {params} end params.label = join(self.label, label) local obj = cls.morph(params, self.context, self.location) @@ -572,6 +576,45 @@ end function M.Rule:extraoptfrags() return {} end +M.Limit = M.class(M.ConfigObject) + +function M.Limit:init(...) + M.Limit.super(self):init(...) + + if not self.count then + if not self[1] then + self:error('Packet count not defined for limit') + end + self.count = self[1] + end + + if not self.interval then self.interval = 1 end +end + +function M.Limit:rate() return math.ceil(self.count / self.interval) end + +function M.Limit:recentopts() + local count = self.count + local interval = self.interval + + if count > RECENT_MAX_COUNT then + count = self:rate() + interval = 1 + end + + if count <= RECENT_MAX_COUNT then + return '--update --hitcount '..count..' --seconds '..interval + end +end + +function M.Limit:limitopts(name) + local rate = self:rate() + return '-m hashlimit --hashlimit-upto '..rate.. + '/second --hashlimit-burst '..rate.. + ' --hashlimit-mode srcip --hashlimit-name '..(name or self:uniqueid()) +end + + M.export = {zone={class=M.Zone}, ipset={class=IPSet, before='%modules'}} return M diff --git a/awall/modules/filter.lua b/awall/modules/filter.lua index 1c78dda..dd12132 100644 --- a/awall/modules/filter.lua +++ b/awall/modules/filter.lua @@ -19,8 +19,6 @@ local contains = util.contains local extend = util.extend local listpairs = util.listpairs -local RECENT_MAX_COUNT = 20 - local TranslatingRule = class(Rule) @@ -240,48 +238,38 @@ function Filter:extraoptfrags() local limitchain = self:uniqueid('limit') local limitlog = self[limit].log - local count = self[limit].count - local interval = self[limit].interval or 1 - - if count > RECENT_MAX_COUNT then - count = math.ceil(count / interval) - interval = 1 - end + local limitobj = self:create(model.Limit, self[limit], 'limit') local ofrags = {} local logch, limitofs local accept = self:position() == 'append' - if count > RECENT_MAX_COUNT then - if accept then - ofrags, logch = self:logchain(self.log, 'accept', 'ACCEPT') - else logch = 'RETURN' end - - limitofs = { - { - opts='-m hashlimit --hashlimit-upto '..count..'/second --hashlimit-burst '..count..' --hashlimit-mode srcip --hashlimit-name '..limitchain, - target=logch - }, - {target='DROP'} - } - if limitlog then table.insert(limitofs, 2, limitlog:optfrag()) end + local recentopts = limitobj:recentopts() - else + if recentopts then ofrags, logch = self:logchain(limitlog, 'drop', 'DROP') limitofs = combinations( {{opts='-m recent --name '..limitchain}}, { - { - opts='--update --hitcount '..count..' --seconds '..interval, - target=logch - }, + {opts=recentopts, target=logch}, {opts='--set', target=accept and 'ACCEPT' or nil} } ) if accept and self.log then table.insert(limitofs, 2, self.log:optfrag()) end + + else + if accept then + ofrags, logch = self:logchain(self.log, 'accept', 'ACCEPT') + else logch = 'RETURN' end + + limitofs = { + {opts=limitobj:limitopts(limitchain), target=logch}, + {target='DROP'} + } + if limitlog then table.insert(limitofs, 2, limitlog:optfrag()) end end extend(ofrags, combinations({{chain=limitchain}}, limitofs)) |