This can be done when e.g. a TLD or high-traffic zone goes bogus.
Note that it is good practice to verify that this is indeed the case and not because of malicious actions.
+Current trust anchors can be queried from the recursor by sending a query for "negativetrustanchor.server CH TXT".
+This query will (if :ref:`setting-allow-trust-anchor-query` is enabled) return a TXT record per negative trust-anchor in the format ``"DOMAIN [REASON]"``.
+
To configure a negative trust anchor, use the ``addNTA()`` function in the :ref:`setting-lua-config-file` and restart the recursor.
This function requires the name of the zone and an optional reason:
- Boolean
- Default: yes
-Allow ``trustanchor.server CH TXT`` queries to view the configured :doc:`DNSSEC <dnssec>` trust anchors.
+Allow ``trustanchor.server CH TXT`` and ``negativetrustanchor.server CH TXT`` queries to view the configured :doc:`DNSSEC <dnssec>` (negative) trust anchors.
.. _setting-api-config-dir:
* - version.pdns. CH TXT
* - id.server. CH TXT
* - trustanchor.server CH TXT
+ * - negativetrustanchor.server CH TXT
*/
bool SyncRes::doSpecialNamesResolve(const DNSName &qname, const QType &qtype, const uint16_t qclass, vector<DNSRecord> &ret)
{
static const DNSName arpa("1.0.0.127.in-addr.arpa."), ip6_arpa("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa."),
- localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns."), trustanchorserver("trustanchor.server.");
+ localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns."), trustanchorserver("trustanchor.server."),
+ negativetrustanchorserver("negativetrustanchor.server.");
bool handled = false;
vector<pair<QType::typeenum, string> > answers;
}
}
+ if (qname == negativetrustanchorserver && qclass == QClass::CHAOS &&
+ ::arg().mustDo("allow-trust-anchor-query")) {
+ handled = true;
+ if (qtype == QType::TXT || qtype == QType::ANY) {
+ auto luaLocal = g_luaconfs.getLocal();
+ for (auto const &negAnchor : luaLocal->negAnchors) {
+ ostringstream ans;
+ ans<<"\"";
+ ans<<negAnchor.first.toString(); // Explicit toString to have a trailing dot
+ if (negAnchor.second.length())
+ ans<<" "<<negAnchor.second;
+ ans << "\"";
+ answers.push_back({QType::TXT, ans.str()});
+ }
+ }
+ }
+
if (handled && !answers.empty()) {
ret.clear();
d_wasOutOfBand=true;
_root_DS = None
_lua_config_file = """
addDS("powerdns.com", "44030 8 1 B763646757DF621DD1204AD3BFA0675B49BE3279")
+addNTA("example")
+addNTA("example.com", "some reason")
"""
def testTrustanchorDotServer(self):
self.assertRcodeEqual(result, dns.rcode.NOERROR)
self.assertRRsetInAnswer(result, expected)
+ def testNegativerustanchorDotServer(self):
+ expected = dns.rrset.from_text_list(
+ 'negativetrustanchor.server.', 86400, dns.rdataclass.CH, 'TXT',
+ ['"example."', '"example.com. some reason"'])
+ query = dns.message.make_query('negativetrustanchor.server', 'TXT',
+ dns.rdataclass.CH)
+ result = self.sendUDPQuery(query)
+
+ self.assertRcodeEqual(result, dns.rcode.NOERROR)
+ self.assertRRsetInAnswer(result, expected)
+
class testTrustAnchorsDisabled(RecursorTest):
"""This test will do a query for "trustanchor.server CH TXT" and hopes to get
result = self.sendUDPQuery(query)
self.assertRcodeEqual(result, dns.rcode.SERVFAIL)
+
+ def testNegativerustanchorDotServer(self):
+ query = dns.message.make_query('negativetrustanchor.server', 'TXT',
+ dns.rdataclass.CH)
+ result = self.sendUDPQuery(query)
+
+ self.assertRcodeEqual(result, dns.rcode.SERVFAIL)