diff options
author | Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi> | 2012-04-12 05:44:22 +0000 |
---|---|---|
committer | Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi> | 2012-04-12 05:44:22 +0000 |
commit | 9ca4e2d6969579fd73f66c556f7e7b785de7144a (patch) | |
tree | 636d0aef41065f3653e3cbca092ec0f3facb8484 | |
parent | 80c370796ccc7b5906aa6d79d3ce972ffdef8c7c (diff) | |
download | awall-9ca4e2d6969579fd73f66c556f7e7b785de7144a.tar.bz2 awall-9ca4e2d6969579fd73f66c556f7e7b785de7144a.tar.xz |
dnat option for filter rules
-rw-r--r-- | awall/model.lua | 8 | ||||
-rw-r--r-- | awall/modules/filter.lua | 65 |
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 |