Commit 9ca4e2d6 authored by Kaarle Ritvanen's avatar Kaarle Ritvanen

dnat option for filter rules

parent 80c37079
......@@ -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)
......
......@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment