diff options
author | Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi> | 2013-02-19 11:27:36 +0000 |
---|---|---|
committer | Kaarle Ritvanen <kaarle.ritvanen@datakunkku.fi> | 2013-02-19 11:27:36 +0000 |
commit | 2f489cc65e7b57d9ee5a222ef821cd8016cfbfff (patch) | |
tree | d1c97ecb938ccea7c61c889b251e17d9966b9545 | |
parent | 24baf0b3c1093b917bb155c200db785b47dbe7de (diff) | |
download | awall-2f489cc65e7b57d9ee5a222ef821cd8016cfbfff.tar.bz2 awall-2f489cc65e7b57d9ee5a222ef821cd8016cfbfff.tar.xz |
secure use of connection tracking helpersv0.3.0
enable connection tracking helpers when required, fixes #1540
service-specific RELATED rules
-rw-r--r-- | awall/modules/filter.lua | 120 | ||||
-rw-r--r-- | json/services.json | 10 |
2 files changed, 106 insertions, 24 deletions
diff --git a/awall/modules/filter.lua b/awall/modules/filter.lua index fdf851d..f01b586 100644 --- a/awall/modules/filter.lua +++ b/awall/modules/filter.lua @@ -13,10 +13,29 @@ local combinations = require('awall.optfrag').combinations local util = require('awall.util') local extend = util.extend +local listpairs = util.listpairs local RECENT_MAX_COUNT = 20 +local RelatedRule = model.class(model.Rule) + +function RelatedRule:servoptfrags() + local helpers = {} + for i, serv in listpairs(self.service) do + for i, sdef in listpairs(serv) do + local helper = sdef['ct-helper'] + if helper then + helpers[helper] = { + opts='-m conntrack --ctstate RELATED --helper '..helper + } + end + end + end + return util.values(helpers) +end + + local Filter = model.class(model.Rule) function Filter:init(...) @@ -54,11 +73,13 @@ end function Filter:trules() local res = {} - local function extrarules(cls, extra) + local function extrarules(cls, extra, src) + if not src then src = self end local params = {} - for i, attr in ipairs({'in', 'out', 'src', 'dest', - 'ipset', 'ipsec', 'service'}) do - params[attr] = self[attr] + for i, attr in ipairs( + {'in', 'out', 'src', 'dest', 'ipset', 'ipsec', 'service'} + ) do + params[attr] = src[attr] end util.update(params, extra) return extend(res, self:create(cls, params):trules()) @@ -105,9 +126,31 @@ function Filter:trules() extend(res, model.Rule.trules(self)) - if self['no-track'] and self.action == 'accept' then - extrarules('no-track', {reverse=true}) - extrarules('filter', {reverse=true, action='accept', log=false}) + if self.action == 'accept' then + local nr = #res + + if self.related then + for i, rule in listpairs(self.related) do + extrarules( + RelatedRule, + {service=self.service, action='accept'}, + rule + ) + end + else + -- TODO avoid creating unnecessary RELATED rules by introducing + -- helper direction attributes to service definitions + extrarules(RelatedRule, {action='accept'}) + extrarules(RelatedRule, {reverse=true, action='accept'}) + end + + if self['no-track'] then + if #res > nr then + self:error('Tracking required by service') + end + extrarules('no-track', {reverse=true}) + extrarules('filter', {reverse=true, action='accept', log=false}) + end end return res @@ -205,18 +248,57 @@ function Policy:servoptfrags() return nil end local fchains = {{chain='FORWARD'}, {chain='INPUT'}, {chain='OUTPUT'}} -local dar = combinations(fchains, - {{opts='-m conntrack --ctstate RELATED,ESTABLISHED'}}) -for i, chain in ipairs({'INPUT', 'OUTPUT'}) do - table.insert(dar, - {chain=chain, - opts='-'..string.lower(string.sub(chain, 1, 1))..' lo'}) +function stateful(config) + local res = {} + + local families = {{family='inet'}, {family='inet6'}} + + local er = combinations( + fchains, + {{opts='-m conntrack --ctstate ESTABLISHED'}} + ) + for i, chain in ipairs({'INPUT', 'OUTPUT'}) do + table.insert( + er, + { + chain=chain, + opts='-'..string.lower(string.sub(chain, 1, 1))..' lo' + } + ) + end + extend(res, combinations(families, er, {{table='filter', target='ACCEPT'}})) + + -- TODO avoid creating unnecessary CT rules by inspecting the + -- filter rules' target families and chains + local visited = {} + local ofrags = {} + for i, rule in listpairs(config.filter) do + for i, serv in listpairs(rule.service) do + if not visited[serv] then + for i, sdef in listpairs(serv) do + if sdef['ct-helper'] then + local of = model.Rule.morph({service={sdef}}):servoptfrags() + assert(#of == 1) + of[1].target = 'CT --helper '..sdef['ct-helper'] + table.insert(ofrags, of[1]) + end + end + visited[serv] = true + end + end + end + extend( + res, + combinations( + families, + {{table='raw'}}, + {{chain='PREROUTING'}, {chain='OUTPUT'}}, + ofrags + ) + ) + + return res end -dar = combinations( - dar, - {{table='filter', target='ACCEPT'}}, - {{family='inet'}, {family='inet6'}} -) local icmp = {{family='inet', table='filter', opts='-p icmp'}} local icmp6 = {{family='inet6', table='filter', opts='-p icmpv6'}} @@ -245,7 +327,7 @@ icmprules(icmp6, 'icmpv6-type', {1, 2, 3, 4}) export = { filter={class=Filter, before={'dnat', 'no-track'}}, policy={class=Policy, after='%filter-after'}, - ['%filter-before']={rules=dar, before='filter'}, + ['%filter-before']={rules=stateful, before='filter'}, ['%filter-after']={rules=ir, after='filter'} } diff --git a/json/services.json b/json/services.json index 25216af..4570528 100644 --- a/json/services.json +++ b/json/services.json @@ -16,7 +16,7 @@ { "proto": "tcp", "port": 135 }, { "proto": "udp", "port": 135 } ], - "ftp": { "proto": "tcp", "port": 21 }, + "ftp": { "proto": "tcp", "port": 21, "ct-helper": "ftp" }, "gre": { "proto": "gre" }, "hp-pdl": { "proto": "tcp", "port": 9100 }, "http": { "proto": "tcp", "port": 80 }, @@ -30,7 +30,7 @@ { "proto": "esp" }, { "proto": "udp", "port": [ 500, 4500 ] } ], - "irc": { "proto": "tcp", "port": 6667 }, + "irc": { "proto": "tcp", "port": 6667, "ct-helper": "irc" }, "kerberos": [ { "proto": "tcp", "port": 88 }, { "proto": "udp", "port": 88 } @@ -67,7 +67,7 @@ ], "netbios-ns": [ { "proto": "tcp", "port": 137 }, - { "proto": "udp", "port": 137 } + { "proto": "udp", "port": 137, "ct-helper": "netbios_ns" } ], "netbios-ssn": [ { "proto": "tcp", "port": 139 }, @@ -90,8 +90,8 @@ ], "rdp": { "proto": "tcp", "port": 3389 }, "sip": [ - { "proto": "udp", "port": 5060 }, - { "proto": "tcp", "port": 5060 } + { "proto": "udp", "port": 5060, "ct-helper": "sip" }, + { "proto": "tcp", "port": 5060, "ct-helper": "sip" } ], "sip-tls": [ { "proto": "udp", "port": 5061 }, |