aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--README.md12
-rw-r--r--awall/modules/filter.lua78
2 files changed, 76 insertions, 14 deletions
diff --git a/README.md b/README.md
index c8edb0b..d9e7488 100644
--- a/README.md
+++ b/README.md
@@ -436,6 +436,18 @@ limit object may have an attribute named **log**. It defines how the
dropped packets should be logged and is semantically similar to the
**log** attribute of rule objects.
+Filter objects may have an attribute named **update-limit**. This
+causes the packet flow or new connection attempts matching the filter
+to be included in the total rate of a named limit without any packets
+being dropped. When defined as a string, it is interpreted as the name
+of the limit. It can also be defined as an object with a **name**
+attribute and additional attributes. The **measure** attribute is used
+to select whether to measure the packet flow (**flow**) or connection
+attempts (**conn**, default). The **addr** attribute is used to select
+whether to consider the source (**src**, default) or destination
+(**dest**) address. When **update-limit** is defined, **action**
+defaults to **pass** and cannot be set to any other value.
+
Filter objects may have an attribute named **dnat**, the value of
which is an IPv4 address. If defined, this enables destination NAT for
all IPv4 packets matching the rule, such that the specified address
diff --git a/awall/modules/filter.lua b/awall/modules/filter.lua
index 963e93e..436fbfa 100644
--- a/awall/modules/filter.lua
+++ b/awall/modules/filter.lua
@@ -18,6 +18,19 @@ local util = require('awall.util')
local contains = util.contains
local extend = util.extend
local listpairs = util.listpairs
+local setdefault = util.setdefault
+
+
+local function initmask(obj)
+ for _, attr in ipairs{'src-mask', 'dest-mask'} do
+ if obj[attr] then
+ obj:error('Attribute not allowed with a named limit: '..attr)
+ end
+ end
+
+ local limits = obj.root.limit
+ obj[(obj.addr or 'src')..'-mask'] = limits and limits[obj.name] or true
+end
local RECENT_MAX_COUNT = 20
@@ -25,16 +38,7 @@ local RECENT_MAX_COUNT = 20
local FilterLimit = class(model.Limit)
function FilterLimit:initmask()
- if self.name then
- for _, attr in ipairs{'src-mask', 'dest-mask'} do
- if self[attr] then
- self:error('Attribute not allowed with a named limit: '..attr)
- end
- end
-
- local limits = self.root.limit
- self[(self.addr or 'src')..'-mask'] = limits and limits[self.name] or true
-
+ if self.name then initmask(self)
elseif self.update ~= nil then
self:error('Attribute allowed only with named limits: update')
end
@@ -72,6 +76,24 @@ function FilterLimit:recentofrags(name)
end
+local LimitReference = class(model.Maskable)
+
+function LimitReference:initmask()
+ if not self.name then
+ if not self[1] then self:error('Limit name not defined') end
+ self.name = self[1]
+ end
+ initmask(self)
+
+ LimitReference.super(self):initmask()
+end
+
+function LimitReference:recentofrags()
+ local ofs = self:recentmask()
+ return ofs and combinations(ofs, {{match='--set'}}) or self:error(MASK_ERROR)
+end
+
+
local TranslatingRule = class(Rule)
function TranslatingRule:init(...)
@@ -129,7 +151,7 @@ local LoggingRule = class(TranslatingRule)
function LoggingRule:init(...)
LoggingRule.super(self):init(...)
- util.setdefault(self, 'action', 'accept')
+ setdefault(self, 'action', 'accept')
local custom = self:customtarget()
if type(self.log) ~= 'table' then
@@ -188,6 +210,9 @@ function RelatedRule:target() return 'ACCEPT' end
local Filter = class(LoggingRule)
function Filter:init(...)
+ local ul = self['update-limit']
+ if ul then setdefault(self, 'action', 'pass') end
+
Filter.super(self):init(...)
-- alpine v2.4 compatibility
@@ -206,6 +231,21 @@ function Filter:init(...)
end
self[limit].log = loadclass('log').get(self, self[limit].log, true)
end
+
+ if ul then
+ if self.action ~= 'pass' then
+ self:error('Cannot specify action with update-limit')
+ end
+
+ if not contains({'conn', 'flow'}, setdefault(ul, 'measure', 'conn')) then
+ self:error('Invalid value for measure: '..ul.measure)
+ end
+ if self['no-track'] and ul.measure == 'conn' then
+ self:error('Tracking required when measuring connection rate')
+ end
+
+ self:create(LimitReference, ul, 'update-limit')
+ end
end
function Filter:extratrules()
@@ -309,8 +349,11 @@ function Filter:limit()
end
function Filter:position()
- return not self['no-track'] and self:limit() == 'flow-limit'
- and 'prepend' or 'append'
+ return not self['no-track'] and (
+ self:limit() == 'flow-limit' or (
+ self['update-limit'] and self['update-limit'].measure == 'flow'
+ )
+ ) and 'prepend' or 'append'
end
function Filter:logdefault()
@@ -327,12 +370,19 @@ end
function Filter:mangleoptfrags(ofrags)
local limit = self:limit()
- if not limit then return Filter.super(self):mangleoptfrags(ofrags) end
+ if not limit then
+ if self['update-limit'] then
+ ofrags = self:combine(ofrags, self['update-limit']:recentofrags())
+ end
+ return Filter.super(self):mangleoptfrags(ofrags)
+ end
local function incompatible(item)
self:error('Limit incompatible with '..item)
end
+ if self['update-limit'] then incompatible('update-limit') end
+
if self:customtarget() or self:logdefault() then
incompatible('action: '..self.action)
end