From: Vladimír Čunát Date: Mon, 12 Aug 2019 14:08:37 +0000 (+0200) Subject: modules/policy: optimize special domain processing X-Git-Tag: v4.3.0~4^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=073b6f11c2f6550e65b67e512dbde899279dea79;p=thirdparty%2Fknot-resolver.git modules/policy: optimize special domain processing Running the full special-domain checks is relatively expensive. --- diff --git a/modules/policy/policy.lua b/modules/policy/policy.lua index d78e0f0ac..af958ce69 100644 --- a/modules/policy/policy.lua +++ b/modules/policy/policy.lua @@ -577,28 +577,6 @@ function policy.evaluate(rules, req, query, state) return end --- Top-down policy list walk until we hit a match --- the caller is responsible for reordering policy list --- from most specific to least specific. --- Some rules may be chained, in this case they are evaluated --- as a dependency chain, e.g. r1,r2,r3 -> r3(r2(r1(state))) -policy.layer = { - begin = function(state, req) - -- Don't act on "resolved" cases. - if bit.band(state, bit.bor(kres.FAIL, kres.DONE)) ~= 0 then return state end - return policy.evaluate(policy.rules, req, req:current(), state) or - policy.evaluate(policy.special_names, req, req:current(), state) or - state - end, - finish = function(state, req) - -- Optimization for the typical case - if #policy.postrules == 0 then return state end - -- Don't act on "resolved" cases. - if bit.band(state, bit.bor(kres.FAIL, kres.DONE)) ~= 0 then return state end - return policy.evaluate(policy.postrules, req, req:current(), state) or state - end -} - -- Add rule to policy list function policy.add(rule, postrule) -- Compatibility with 1.0.0 API @@ -755,6 +733,7 @@ policy.todnames(private_zones) policy.rules = {} policy.postrules = {} policy.special_names = { + -- XXX: beware of special_names_optim() when modifying these filters { cb=policy.suffix_common(policy.DENY_MSG( 'Blocking is mandated by standards, see references on ' @@ -789,4 +768,44 @@ policy.special_names = { }, } +-- Return boolean; false = no special name may apply, true = some might apply. +-- The point is to *efficiently* filter almost all QNAMEs that do not apply. +local function special_names_optim(req, sname) + local qname_size = req.qsource.packet.qname_size + if qname_size < 9 then return true end -- don't want to special-case bad array access + local root = sname + qname_size - 1 + return + -- .a???. or .t???. + (root[-5] == 4 and (root[-4] == 97 or root[-4] == 116)) + -- .on???. or .in?????. or lo???. or *ost. + or (root[-6] == 5 and root[-5] == 111 and root[-4] == 110) + or (root[-8] == 7 and root[-7] == 105 and root[-6] == 110) + or (root[-6] == 5 and root[-5] == 108 and root[-4] == 111) + or (root[-3] == 111 and root[-2] == 115 and root[-1] == 116) +end + +-- Top-down policy list walk until we hit a match +-- the caller is responsible for reordering policy list +-- from most specific to least specific. +-- Some rules may be chained, in this case they are evaluated +-- as a dependency chain, e.g. r1,r2,r3 -> r3(r2(r1(state))) +policy.layer = { + begin = function(state, req) + -- Don't act on "resolved" cases. + if bit.band(state, bit.bor(kres.FAIL, kres.DONE)) ~= 0 then return state end + local qry = req:current() + return policy.evaluate(policy.rules, req, qry, state) + or (special_names_optim(req, qry.sname) + and policy.evaluate(policy.special_names, req, qry, state)) + or state + end, + finish = function(state, req) + -- Optimization for the typical case + if #policy.postrules == 0 then return state end + -- Don't act on "resolved" cases. + if bit.band(state, bit.bor(kres.FAIL, kres.DONE)) ~= 0 then return state end + return policy.evaluate(policy.postrules, req, req:current(), state) or state + end +} + return policy