From: Petr Špaček Date: Fri, 21 Jun 2019 12:01:02 +0000 (+0200) Subject: dns64: workaround for broken auths which fail on AAAA query X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=refs%2Fheads%2F483-dns64-aaaa-failures-fix;p=thirdparty%2Fknot-resolver.git dns64: workaround for broken auths which fail on AAAA query Some auths return weird stuff on AAAA query and RFC 6147 section-5.1.2 mandates workarounds for these cases. This is only partial fix. In some cases all servers return answers so weird that iterator refuses to accept them and fails with "no NS" condition, which in turn does not call consume phase and skips dns64 module. Fixing this particular case will require changes to module logic and such change is not suitable to minor release. Related: #483 --- diff --git a/NEWS b/NEWS index 8c1360ddb..8286b7841 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,11 @@ +Knot Resolver 4.2.2 (2019-09-2?) +================================ + +Bugfixes +-------- +- DNS64 module works around broken auth servers as mandated + by RFC 6147 section 5.1.2 (#483) + Knot Resolver 4.2.1 (2019-09-26) ================================ diff --git a/modules/dns64/dns64.lua b/modules/dns64/dns64.lua index 0ee40e089..fd555f529 100644 --- a/modules/dns64/dns64.lua +++ b/modules/dns64/dns64.lua @@ -26,20 +26,44 @@ end -- Layers M.layer = { } function M.layer.consume(state, req, pkt) - if state == kres.FAIL then return state end - local qry = req:current() - -- Observe only final answers in IN class where request has no CD flag. - if M.proxy == nil or not qry.flags.RESOLVED - or pkt:qclass() ~= kres.class.IN or req.answer:cd() then + if M.proxy == nil then -- no configuration return state end - -- Synthetic AAAA from marked A responses - local answer = pkt:section(kres.section.ANSWER) + local rcode = pkt:rcode() + if (pkt:qclass() ~= kres.class.IN -- RFC 6147 section 5.1 + or rcode == kres.rcode.NXDOMAIN -- RFC 6147 section 5.1.2. + or (req.answer:cd() and req.answer:dobit()) -- RFC 6147 section 5.5 + -- optimization + or (pkt:qtype() ~= kres.type.AAAA and pkt:qtype() ~= kres.type.A)) then + return state + end + + local qry = req:current() + if bit.band(state, kres.FAIL) ~= 0 and not qry.flags.RESOLVED then + -- resolution is not finished yet + return state + end -- Observe final AAAA NODATA responses to the current SNAME. - local is_nodata = pkt:rcode() == kres.rcode.NOERROR and #answer == 0 - if pkt:qtype() == kres.type.AAAA and is_nodata and pkt:qname() == qry:name() - and qry.flags.RESOLVED and not qry.flags.CNAME and qry.parent == nil then + local aaaapresent = false + -- workaround for auths which break on AAAA query + if bit.band(state, kres.DONE) and rcode == kres.rcode.NOERROR and req.answ_selected.len > 0 then + -- NOERROR might be NODATA, look for AAAA in answer + for idx = 0, tonumber(req.answ_selected.len - 1) do + if (req.answ_selected.at[idx].to_wire == true + and req.answ_selected.at[idx].rr.type == kres.type.AAAA) + then + aaaapresent = true + break + end + end + end + if pkt:qtype() == kres.type.AAAA and pkt:qname() == qry:name() + and not qry.flags.CNAME and qry.parent == nil + and aaaapresent == false then + if verbose() then + ffi.C.kr_log_qverbose_impl(qry, 'dns64', 'no AAAA found, querying for A\n') + end -- Start a *marked* corresponding A sub-query. local extraFlags = kres.mk_qflags({}) extraFlags.DNSSEC_WANT = qry.flags.DNSSEC_WANT @@ -49,7 +73,7 @@ function M.layer.consume(state, req, pkt) return state end - + -- Synthetic AAAA from marked A responses -- Observe answer to the marked sub-query, and convert all A records in ANSWER -- to corresponding AAAA records to be put into the request's answer. if not qry.flags.DNS64_MARK then return state end