Commit 940c970d authored by Kaarle Ritvanen's avatar Kaarle Ritvanen

prepend object identifier and file name to error messages

parent 563a3fc1
...@@ -11,17 +11,17 @@ local familypatterns = {inet='%d[%.%d/]+', ...@@ -11,17 +11,17 @@ local familypatterns = {inet='%d[%.%d/]+',
inet6='[:%x/]+', inet6='[:%x/]+',
domain='[%a-][%.%w-]*'} domain='[%a-][%.%w-]*'}
local function getfamily(addr) local function getfamily(addr, context)
for k, v in pairs(familypatterns) do for k, v in pairs(familypatterns) do
if string.match(addr, '^'..v..'$') then return k end if string.match(addr, '^'..v..'$') then return k end
end end
error('Malformed host specification: '..addr) context:error('Malformed host specification: '..addr)
end end
local dnscache = {} local dnscache = {}
function resolve(host) function resolve(host, context)
local family = getfamily(host) local family = getfamily(host, context)
if family == 'domain' then if family == 'domain' then
if not dnscache[host] then if not dnscache[host] then
...@@ -36,12 +36,14 @@ function resolve(host) ...@@ -36,12 +36,14 @@ function resolve(host)
else family = nil end else family = nil end
if family then if family then
assert(getfamily(addr) == family) assert(getfamily(addr, context) == family)
table.insert(dnscache[host], {family, addr}) table.insert(dnscache[host], {family, addr})
end end
end end
end end
if not dnscache[host][1] then error('Invalid host name: '..host) end if not dnscache[host][1] then
context:error('Invalid host name: '..host)
end
end end
return dnscache[host] return dnscache[host]
......
...@@ -64,6 +64,17 @@ function Config:init(policyconfig) ...@@ -64,6 +64,17 @@ function Config:init(policyconfig)
self.input = policyconfig:expand() self.input = policyconfig:expand()
self.iptables = iptables.IPTables.new() self.iptables = iptables.IPTables.new()
local function morph(path, cls)
local objs = self.input[path]
if objs then
for k, v in pairs(objs) do
objs[k] = cls.morph(v,
self,
path..' '..k..' ('..policyconfig.source[path][k]..')')
end
end
end
local function insertrules(trules) local function insertrules(trules)
for i, trule in ipairs(trules) do for i, trule in ipairs(trules) do
local t = self.iptables.config[trule.family][trule.table][trule.chain] local t = self.iptables.config[trule.family][trule.table][trule.chain]
...@@ -79,12 +90,7 @@ function Config:init(policyconfig) ...@@ -79,12 +90,7 @@ function Config:init(policyconfig)
if defrules[phase] then insertrules(defrules[phase]) end if defrules[phase] then insertrules(defrules[phase]) end
end end
for i, path in ipairs(procorder) do for i, path in ipairs(procorder) do morph(path, classmap[path]) end
if self.input[path] then
util.map(self.input[path],
function(obj) return classmap[path].morph(obj, self) end)
end
end
insertdefrules('pre') insertdefrules('pre')
...@@ -97,6 +103,7 @@ function Config:init(policyconfig) ...@@ -97,6 +103,7 @@ function Config:init(policyconfig)
insertdefrules('post-'..path) insertdefrules('post-'..path)
end end
morph('ipset', awall.model.ConfigObject)
self.ipset = ipset.IPSet.new(self.input.ipset) self.ipset = ipset.IPSet.new(self.input.ipset)
end end
......
...@@ -16,11 +16,11 @@ function IPSet:init(config) self.config = config end ...@@ -16,11 +16,11 @@ function IPSet:init(config) self.config = config end
function IPSet:commands() function IPSet:commands()
local res = {} local res = {}
if self.config then if self.config then
for name, params in pairs(self.config) do for name, ipset in pairs(self.config) do
if not params.type then error('Type not defined for set '..name) end if not ipset.type then ipset:error('Type not defined') end
if not params.family then error('Family not defined for set '..name) end if not ipset.family then ipset:error('Family not defined') end
table.insert(res, table.insert(res,
'create '..name..' '..params.type..' family '..params.family..'\n') 'create '..name..' '..ipset.type..' family '..ipset.family..'\n')
end end
end end
return res return res
......
...@@ -21,13 +21,20 @@ class = awall.object.class ...@@ -21,13 +21,20 @@ class = awall.object.class
ConfigObject = class(awall.object.Object) ConfigObject = class(awall.object.Object)
function ConfigObject:init(context) function ConfigObject:init(context, location)
if context then if context then
self.context = context self.context = context
self.root = context.input self.root = context.input
end end
self.location = location
end end
function ConfigObject:create(cls, params)
return cls.morph(params, self.context, self.location)
end
function ConfigObject:error(msg) error(self.location..': '..msg) end
function ConfigObject:trules() return {} end function ConfigObject:trules() return {} end
...@@ -45,7 +52,7 @@ function Zone:optfrags(dir) ...@@ -45,7 +52,7 @@ function Zone:optfrags(dir)
if self.addr then if self.addr then
aopts = {} aopts = {}
for i, hostdef in util.listpairs(self.addr) do for i, hostdef in util.listpairs(self.addr) do
for i, addr in ipairs(awall.host.resolve(hostdef)) do for i, addr in ipairs(awall.host.resolve(hostdef, self)) do
table.insert(aopts, table.insert(aopts,
{family=addr[1], {family=addr[1],
[aprop]=addr[2], [aprop]=addr[2],
...@@ -69,8 +76,8 @@ fwzone = Zone.new() ...@@ -69,8 +76,8 @@ fwzone = Zone.new()
Rule = class(ConfigObject) Rule = class(ConfigObject)
function Rule:init(context) function Rule:init(...)
ConfigObject.init(self, context) ConfigObject.init(self, unpack(arg))
for i, prop in ipairs({'in', 'out'}) do for i, prop in ipairs({'in', 'out'}) do
self[prop] = self[prop] and util.maplist(self[prop], self[prop] = self[prop] and util.maplist(self[prop],
...@@ -78,7 +85,7 @@ function Rule:init(context) ...@@ -78,7 +85,7 @@ function Rule:init(context)
if type(z) ~= 'string' then return z end if type(z) ~= 'string' then return z end
return z == '_fw' and fwzone or return z == '_fw' and fwzone or
self.root.zone[z] or self.root.zone[z] or
error('Invalid zone: '..z) self:error('Invalid zone: '..z)
end) or self:defaultzones() end) or self:defaultzones()
end end
...@@ -87,7 +94,7 @@ function Rule:init(context) ...@@ -87,7 +94,7 @@ function Rule:init(context)
self.service = util.maplist(self.service, self.service = util.maplist(self.service,
function(s) function(s)
if type(s) ~= 'string' then return s end if type(s) ~= 'string' then return s end
return self.root.service[s] or error('Invalid service: '..s) return self.root.service[s] or self:error('Invalid service: '..s)
end) end)
end end
end end
...@@ -161,7 +168,7 @@ function Rule:servoptfrags() ...@@ -161,7 +168,7 @@ function Rule:servoptfrags()
for i, serv in ipairs(self.service) do for i, serv in ipairs(self.service) do
for i, sdef in util.listpairs(serv) do for i, sdef in util.listpairs(serv) do
if not sdef.proto then error('Protocol not defined') end if not sdef.proto then self:error('Protocol not defined') end
if util.contains({6, 'tcp', 17, 'udp'}, sdef.proto) then if util.contains({6, 'tcp', 17, 'udp'}, sdef.proto) then
local new = not containskey(ports, sdef.proto) local new = not containskey(ports, sdef.proto)
...@@ -187,7 +194,7 @@ function Rule:servoptfrags() ...@@ -187,7 +194,7 @@ function Rule:servoptfrags()
family = 'inet6' family = 'inet6'
oname = 'icmpv6-type' oname = 'icmpv6-type'
elseif sdef.type then elseif sdef.type then
error('Type specification not valid with '..sdef.proto) self:error('Type specification not valid with '..sdef.proto)
end end
if sdef.type then opts = opts..' --'..oname..' '..sdef.type end if sdef.type then opts = opts..' --'..oname..' '..sdef.type end
...@@ -217,7 +224,7 @@ function Rule:servoptfrags() ...@@ -217,7 +224,7 @@ function Rule:servoptfrags()
end end
function Rule:destoptfrags() function Rule:destoptfrags()
return Zone.morph({addr=self.dest}):optfrags('out') return self:create(Zone, {addr=self.dest}):optfrags('out')
end end
function Rule:table() return 'filter' end function Rule:table() return 'filter' end
...@@ -227,7 +234,7 @@ function Rule:chain() return nil end ...@@ -227,7 +234,7 @@ function Rule:chain() return nil end
function Rule:position() return 'append' end function Rule:position() return 'append' end
function Rule:target() function Rule:target()
if not self.action then error('Action not defined') end if not self.action then self:error('Action not defined') end
return string.upper(self.action) return string.upper(self.action)
end end
...@@ -276,13 +283,13 @@ function Rule:trules() ...@@ -276,13 +283,13 @@ function Rule:trules()
if self.ipset then if self.ipset then
local ipsetofrags = {} local ipsetofrags = {}
for i, ipset in util.listpairs(self.ipset) do for i, ipset in util.listpairs(self.ipset) do
if not ipset.name then error('Set name not defined') end if not ipset.name then self:error('Set name not defined') end
local setdef = self.root.ipset and self.root.ipset[ipset.name] local setdef = self.root.ipset and self.root.ipset[ipset.name]
if not setdef then error('Invalid set name') end if not setdef then self:error('Invalid set name') end
if not ipset.args then if not ipset.args then
error('Set direction arguments not defined') self:error('Set direction arguments not defined')
end end
local setopts = '-m set --match-set '..ipset.name..' ' local setopts = '-m set --match-set '..ipset.name..' '
...@@ -290,7 +297,7 @@ function Rule:trules() ...@@ -290,7 +297,7 @@ function Rule:trules()
if i > 1 then setopts = setopts..',' end if i > 1 then setopts = setopts..',' end
if arg == 'in' then setopts = setopts..'src' if arg == 'in' then setopts = setopts..'src'
elseif arg == 'out' then setopts = setopts..'dst' elseif arg == 'out' then setopts = setopts..'dst'
else error('Invalid set direction argument') end else self:error('Invalid set direction argument') end
end end
table.insert(ipsetofrags, {family=setdef.family, opts=setopts}) table.insert(ipsetofrags, {family=setdef.family, opts=setopts})
end end
...@@ -306,7 +313,7 @@ function Rule:trules() ...@@ -306,7 +313,7 @@ function Rule:trules()
setfamilies(res) setfamilies(res)
tag(res, 'chain', self:chain()) tag(res, 'chain', self:chain())
local addrofrags = combinations(Zone.morph({addr=self.src}):optfrags('in'), local addrofrags = combinations(self:create(Zone, {addr=self.src}):optfrags('in'),
self:destoptfrags()) self:destoptfrags())
if addrofrags then if addrofrags then
......
...@@ -26,7 +26,7 @@ function Filter:destoptfrags() ...@@ -26,7 +26,7 @@ function Filter:destoptfrags()
if not self.dnat then return ofrags end if not self.dnat then return ofrags end
ofrags = awall.optfrag.combinations(ofrags, {{family='inet6'}}) ofrags = awall.optfrag.combinations(ofrags, {{family='inet6'}})
local natof = model.Zone.morph({addr=self.dnat}):optfrags('out') local natof = self:create(model.Zone, {addr=self.dnat}):optfrags('out')
assert(#natof == 1) assert(#natof == 1)
table.insert(ofrags, natof[1]) table.insert(ofrags, natof[1])
return ofrags return ofrags
...@@ -37,28 +37,28 @@ function Filter:trules() ...@@ -37,28 +37,28 @@ function Filter:trules()
if self.dnat then if self.dnat then
if not self.dest then if not self.dest then
error('Destination address must be specified with DNAT') self:error('Destination address must be specified with DNAT')
end end
if string.find(self.dnat, '/') then if string.find(self.dnat, '/') then
error('DNAT target cannot be a network address') self:error('DNAT target cannot be a network address')
end end
for i, attr in ipairs({'ipsec', 'ipset'}) do for i, attr in ipairs({'ipsec', 'ipset'}) do
if self[attr] then if self[attr] then
error('dnat and '..attr..' options cannot be used simultaneously') self:error('dnat and '..attr..' options cannot be used simultaneously')
end end
end end
local dnataddr local dnataddr
for i, addr in ipairs(awall.host.resolve(self.dnat)) do for i, addr in ipairs(awall.host.resolve(self.dnat, self)) do
if addr[1] == 'inet' then if addr[1] == 'inet' then
if dnataddr then if dnataddr then
error(self.dnat..' resolves to multiple IPv4 addresses') self:error(self.dnat..' resolves to multiple IPv4 addresses')
end end
dnataddr = addr[2] dnataddr = addr[2]
end end
end end
if not dnataddr then if not dnataddr then
error(self.dnat..' does not resolve to any IPv4 address') self:error(self.dnat..' does not resolve to any IPv4 address')
end end
local dnat = {['ip-range']=dnataddr} local dnat = {['ip-range']=dnataddr}
...@@ -66,10 +66,9 @@ function Filter:trules() ...@@ -66,10 +66,9 @@ function Filter:trules()
dnat[attr] = self[attr] dnat[attr] = self[attr]
end end
if not awall.classmap.dnat then error('NAT module not installed') end if not awall.classmap.dnat then self:error('NAT module not installed') end
awall.util.extend(res, awall.classmap.dnat.morph(dnat, awall.util.extend(res, self:create(awall.classmap.dnat, dnat):trules())
self.context):trules())
end end
awall.util.extend(res, model.Rule.trules(self)) awall.util.extend(res, model.Rule.trules(self))
...@@ -82,7 +81,7 @@ function Filter:limit() ...@@ -82,7 +81,7 @@ function Filter:limit()
for i, limit in ipairs({'conn-limit', 'flow-limit'}) do for i, limit in ipairs({'conn-limit', 'flow-limit'}) do
if self[limit] then if self[limit] then
if res then if res then
error('Cannot specify multiple limits for a single filter rule') self:error('Cannot specify multiple limits for a single filter rule')
end end
res = limit res = limit
end end
...@@ -105,7 +104,7 @@ function Filter:extraoptfrags() ...@@ -105,7 +104,7 @@ function Filter:extraoptfrags()
local limit = self:limit() local limit = self:limit()
if limit then if limit then
if self.action ~= 'accept' then if self.action ~= 'accept' then
error('Cannot specify limit for '..self.action..' filter') self:error('Cannot specify limit for '..self.action..' filter')
end end
local optbase = '-m recent --name '..self:target() local optbase = '-m recent --name '..self:target()
table.insert(res, {chain=self:target(), table.insert(res, {chain=self:target(),
......
...@@ -15,11 +15,11 @@ local model = awall.model ...@@ -15,11 +15,11 @@ local model = awall.model
local NATRule = model.class(model.Rule) local NATRule = model.class(model.Rule)
function NATRule:init(context) function NATRule:init(...)
model.Rule.init(self, context) model.Rule.init(self, unpack(arg))
for i, dir in ipairs({'in', 'out'}) do for i, dir in ipairs({'in', 'out'}) do
if awall.util.contains(self[dir], model.fwzone) then if awall.util.contains(self[dir], model.fwzone) then
error('NAT rules not allowed for firewall zone') self:error('NAT rules not allowed for firewall zone')
end end
end end
end end
...@@ -28,7 +28,7 @@ function NATRule:defaultzones() return {nil} end ...@@ -28,7 +28,7 @@ function NATRule:defaultzones() return {nil} end
function NATRule:checkzoneoptfrag(ofrag) function NATRule:checkzoneoptfrag(ofrag)
if ofrag[self.params.forbidif] then if ofrag[self.params.forbidif] then
error('Cannot specify '..self.params.forbidif..'bound interface for '..self.params.target..' rule') self:error('Cannot specify '..self.params.forbidif..'bound interface for '..self.params.target..' rule')
end end
end end
...@@ -46,7 +46,7 @@ function NATRule:chain() return self.params.chain end ...@@ -46,7 +46,7 @@ function NATRule:chain() return self.params.chain end
function NATRule:target() function NATRule:target()
if self.action then return model.Rule.target(self) end if self.action then return model.Rule.target(self) end
if not self['ip-range'] then error('IP range not defined for NAT rule') end if not self['ip-range'] then self:error('IP range not defined for NAT rule') end
local target = self.params.target..' --to-'..self.params.subject..' '..self['ip-range'] local target = self.params.target..' --to-'..self.params.subject..' '..self['ip-range']
if self['port-range'] then target = target..':'..self['port-range'] end if self['port-range'] then target = target..':'..self['port-range'] end
return target return target
...@@ -55,8 +55,8 @@ end ...@@ -55,8 +55,8 @@ end
local DNATRule = model.class(NATRule) local DNATRule = model.class(NATRule)
function DNATRule:init(context) function DNATRule:init(...)
NATRule.init(self, context) NATRule.init(self, unpack(arg))
self.params = {forbidif='out', subject='destination', self.params = {forbidif='out', subject='destination',
chain='PREROUTING', target='DNAT'} chain='PREROUTING', target='DNAT'}
end end
...@@ -64,8 +64,8 @@ end ...@@ -64,8 +64,8 @@ end
local SNATRule = model.class(NATRule) local SNATRule = model.class(NATRule)
function SNATRule:init(context) function SNATRule:init(...)
NATRule.init(self, context) NATRule.init(self, unpack(arg))
self.params = {forbidif='in', subject='source', self.params = {forbidif='in', subject='source',
chain='POSTROUTING', target='SNAT'} chain='POSTROUTING', target='SNAT'}
end end
......
...@@ -15,11 +15,11 @@ local model = awall.model ...@@ -15,11 +15,11 @@ local model = awall.model
local NoTrackRule = model.class(model.Rule) local NoTrackRule = model.class(model.Rule)
function NoTrackRule:init(context) function NoTrackRule:init(...)
model.Rule.init(self, context) model.Rule.init(self, unpack(arg))
for i, dir in ipairs({'in', 'out'}) do for i, dir in ipairs({'in', 'out'}) do
if awall.util.contains(self[dir], model.fwzone) then if awall.util.contains(self[dir], model.fwzone) then
error('Connection tracking bypass rules not allowed for firewall zone') self:error('Connection tracking bypass rules not allowed for firewall zone')
end end
end end
end end
...@@ -28,7 +28,7 @@ function NoTrackRule:defaultzones() return {nil} end ...@@ -28,7 +28,7 @@ function NoTrackRule:defaultzones() return {nil} end
function NoTrackRule:checkzoneoptfrag(ofrag) function NoTrackRule:checkzoneoptfrag(ofrag)
if ofrag.out then if ofrag.out then
error('Cannot specify outbound interface for connection tracking bypass rule') self:error('Cannot specify outbound interface for connection tracking bypass rule')
end end
end end
......
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