summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2012-04-12 05:44:22 +0000
committerKaarle Ritvanen <kaarle.ritvanen@datakunkku.fi>2012-04-12 05:44:22 +0000
commit9ca4e2d6969579fd73f66c556f7e7b785de7144a (patch)
tree636d0aef41065f3653e3cbca092ec0f3facb8484
parent80c370796ccc7b5906aa6d79d3ce972ffdef8c7c (diff)
downloadawall-9ca4e2d6969579fd73f66c556f7e7b785de7144a.tar.bz2
awall-9ca4e2d6969579fd73f66c556f7e7b785de7144a.tar.xz
dnat option for filter rules
-rw-r--r--awall/model.lua8
-rw-r--r--awall/modules/filter.lua65
2 files changed, 72 insertions, 1 deletions
diff --git a/awall/model.lua b/awall/model.lua
index 381bd04..c6df76d 100644
--- a/awall/model.lua
+++ b/awall/model.lua
@@ -73,6 +73,7 @@ function Rule:init(context)
for i, prop in ipairs({'in', 'out'}) do
self[prop] = self[prop] and util.maplist(self[prop],
function(z)
+ if type(z) ~= 'string' then return z end
return z == '_fw' and fwzone or
self.root.zone[z] or
error('Invalid zone: '..z)
@@ -83,6 +84,7 @@ function Rule:init(context)
if type(self.service) == 'string' then self.label = self.service end
self.service = util.maplist(self.service,
function(s)
+ if type(s) ~= 'string' then return s end
return self.root.service[s] or error('Invalid service: '..s)
end)
end
@@ -212,6 +214,10 @@ function Rule:servoptfrags()
return res
end
+function Rule:destoptfrags()
+ return Zone.morph({addr=self.dest}):optfrags('out')
+end
+
function Rule:table() return 'filter' end
function Rule:chain() return nil end
@@ -299,7 +305,7 @@ function Rule:trules()
tag(res, 'chain', self:chain())
local addrofrags = combinations(Zone.morph({addr=self.src}):optfrags('in'),
- Zone.morph({addr=self.dest}):optfrags('out'))
+ self:destoptfrags())
if addrofrags then
addrofrags = ffilter(addrofrags)
diff --git a/awall/modules/filter.lua b/awall/modules/filter.lua
index c335cd3..ac03813 100644
--- a/awall/modules/filter.lua
+++ b/awall/modules/filter.lua
@@ -7,11 +7,76 @@ Licensed under the terms of GPL2
module(..., package.seeall)
+require 'awall'
+require 'awall.host'
require 'awall.model'
+require 'awall.optfrag'
+require 'awall.util'
+
local model = awall.model
local Filter = model.class(model.Rule)
+function Filter:defaultzones()
+ return self.dnat and {nil} or model.Rule.defaultzones(self)
+end
+
+function Filter:destoptfrags()
+ local ofrags = model.Rule.destoptfrags(self)
+ if not self.dnat then return ofrags end
+
+ ofrags = awall.optfrag.combinations(ofrags, {{family='inet6'}}) or {}
+ local natof = model.Zone.morph({addr=self.dnat}):optfrags('out')
+ assert(#natof == 1)
+ table.insert(ofrags, natof[1])
+ return ofrags
+end
+
+function Filter:trules()
+ local res = {}
+
+ if self.dnat then
+ if not self.dest then
+ error('Destination address must be specified with DNAT')
+ end
+ if string.find(self.dnat, '/') then
+ error('DNAT target cannot be a network address')
+ end
+ for i, attr in ipairs({'ipsec', 'ipset'}) do
+ if self[attr] then
+ error('dnat and '..attr..' options cannot be used simultaneously')
+ end
+ end
+
+ local dnataddr
+ for i, addr in ipairs(awall.host.resolve(self.dnat)) do
+ if addr[1] == 'inet' then
+ if dnataddr then
+ error(self.dnat..' resolves to multiple IPv4 addresses')
+ end
+ dnataddr = addr[2]
+ end
+ end
+ if not dnataddr then
+ error(self.dnat..' does not resolve to any IPv4 address')
+ end
+
+ local dnat = {['ip-range']=dnataddr}
+ for i, attr in ipairs({'in', 'src', 'dest', 'service'}) do
+ dnat[attr] = self[attr]
+ end
+
+ if not awall.classmap.dnat then error('NAT module not installed') end
+
+ awall.util.extend(res, awall.classmap.dnat.morph(dnat,
+ self.context):trules())
+ end
+
+ awall.util.extend(res, model.Rule.trules(self))
+
+ return res
+end
+
function Filter:limit()
local res
for i, limit in ipairs({'conn-limit', 'flow-limit'}) do