From 6f1d9b6140f0ec39eccbf976f4a7ad15bd9378c7 Mon Sep 17 00:00:00 2001 From: Vladimír Čunát Date: Fri, 19 May 2023 09:09:06 +0200 Subject: lib/rules: implement forwarding Typical use cases should work now, briefly tested: - forwarding all to a resolver - forwarding a subtree downgraded to insecure (to resolver or auth) - forwarding a subtree to auth without changing DNSSEC chain (atypical) In some places we need to repeat kr_make_query() The issue is that some of its inputs (e.g. STUB/FORWARD, zone cut) are now not known at the beginning of PRODUCE yet. Also, checking that QNAME matches is useless on a cached reply. --- modules/policy/policy.lua | 52 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) (limited to 'modules') diff --git a/modules/policy/policy.lua b/modules/policy/policy.lua index cc77e487..b4030375 100644 --- a/modules/policy/policy.lua +++ b/modules/policy/policy.lua @@ -856,6 +856,58 @@ function policy.TAGS_ASSIGN(names) return 'policy.tags_assign_bitmap(' .. tostring(bitmap) .. ')' end +--[[ Insert a forwarding rule, i.e. override upstream for one DNS subtree. + +Throws lua exceptions when detecting something fishy. + +\param subtree plain string +\param options + .auth targets are authoritative (false by default = resolver) + .tls use DoT (false by default, only for resolvers) + .dnssec if overridden to false, don't validate DNSSEC locally + - for resolvers we still do *not* send CD=1 upstream, + i.e. we trust their DNSSEC validation. + - for auths this inserts a negative trust anchor + Beware that setting .set_insecure() *later* would override that. +\param targets same format as policy.TLS_FORWARD() +--]] +function policy.rule_forward_add(subtree, options, targets) + local port_default = 53 + if options.tls or false then + port_default = 853 + -- lots of code; easiest to just call it this way; checks and throws + policy.TLS_FORWARD(targets) + end + + local targets_2 = {} + for _, target in ipairs(targets) do + -- this also throws on failure + local sock = addr2sock(target[1], port_default) + if options.auth then + local port = ffi.C.kr_inaddr_port(sock) + assert(not options.tls and port == port_default) + end + table.insert(targets_2, sock) + end + local targets_3 = ffi.new('const struct sockaddr * [?]', #targets_2 + 1, targets_2) + targets_3[#targets_2] = nil + + local subtree_dname = todname(subtree) + assert(ffi.C.kr_rule_forward(subtree_dname, + { is_tcp = options.tls + , is_nods = options.dnssec == false + , is_auth = options.auth + }, + targets_3 + ) == 0) + + -- Probably the best way to turn off DNSSEC validation for auth is negative TA. + if options.auth and options.dnssec == false then + local ntas = kres.context().negative_anchors + assert(ffi.C.kr_ta_add(ntas, subtree_dname, kres.type.DS, 0, nil, 0) == 0) + end +end + local view_action_buf = ffi.new('knot_db_val_t[1]') -- cgit v1.2.3