]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: support trustanchor.server CH TXT queries
authorPieter Lexis <pieter.lexis@powerdns.com>
Mon, 2 Oct 2017 11:20:38 +0000 (13:20 +0200)
committerPieter Lexis <pieter.lexis@powerdns.com>
Mon, 2 Oct 2017 12:26:21 +0000 (14:26 +0200)
pdns/pdns_recursor.cc
pdns/recursordist/docs/dnssec.rst
pdns/recursordist/docs/settings.rst
pdns/syncres.cc
regression-tests.recursor-dnssec/test_TrustAnchors.py [new file with mode: 0644]

index 9be65868727e10a4dfd6b60684b622b111a190ad..671307dad4c24be8c599b708f3e22acb38f6bfe3 100644 (file)
@@ -3305,6 +3305,7 @@ int main(int argc, char **argv)
     ::arg().set("single-socket", "If set, only use a single socket for outgoing queries")="off";
     ::arg().set("auth-zones", "Zones for which we have authoritative data, comma separated domain=file pairs ")="";
     ::arg().set("lua-config-file", "More powerful configuration options")="";
+    ::arg().setSwitch("allow-trust-anchor-query", "Allow queries for trustanchor.server CH TXT")="yes";
 
     ::arg().set("forward-zones", "Zones for which we forward queries, comma separated domain=ip pairs")="";
     ::arg().set("forward-zones-recurse", "Zones for which we forward queries with recursion bit, comma separated domain=ip pairs")="";
index 110a8204137c67144e1089807865f9e38a893932..028cdaaee059314d3c4f4b7bbcd34b95b23a2779 100644 (file)
@@ -74,6 +74,9 @@ Trust Anchor Management
 In the PowerDNS Recursor, both positive and negative trust anchors can be configured during startup (from a persistent configuration file) and at runtime (which is volatile).
 However, all trust anchors are configurable.
 
+Current trust anchors can be queried from the recursor by sending a query for "trustanchor.server CH TXT".
+This query will (if :ref:`setting-allow-trust-anchor-query` is enabled) return a TXT record per trust-anchor in the format ``"DOMAIN KEYTAG [KEYTAG]..."``.
+
 Trust Anchors
 ^^^^^^^^^^^^^
 The PowerDNS Recursor ships with the DNSSEC Root key built-in.
index 1ae0d71c1fcfe23e22356d06ee38d0ee52c174b9..5a9aeac718fa3f4939b8d63037738e817cfe6c31 100644 (file)
@@ -54,6 +54,17 @@ Overrides the `allow-from`_ setting. To use this feature, supply one netmask per
 Answer questions for the ANY type on UDP with a truncated packet that refers the remote server to TCP.
 Useful for mitigating ANY reflection attacks.
 
+.. _setting-allow-trust-anchor-query:
+
+``allow-trust-anchor-query``
+----------------------------
+.. versionadded:: 4.1.0
+
+-  Boolean
+-  Default: yes
+
+Allow ``trustanchor.server CH TXT`` queries to view the configured :doc:`DNSSEC <dnssec>` trust anchors.
+
 .. _setting-api-config-dir:
 
 ``api-config-dir``
index c75c21901f73d7969c940447cbd6632a99397088..6888ec90410df9d345171e484d996a5549bac5f6 100644 (file)
@@ -159,11 +159,12 @@ int SyncRes::beginResolve(const DNSName &qname, const QType &qtype, uint16_t qcl
  * - version.bind. CH TXT
  * - version.pdns. CH TXT
  * - id.server. CH TXT
+ * - trustanchor.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.");
+    localhost("localhost."), versionbind("version.bind."), idserver("id.server."), versionpdns("version.pdns."), trustanchorserver("trustanchor.server.");
 
   bool handled = false;
   vector<pair<QType::typeenum, string> > answers;
@@ -195,6 +196,25 @@ bool SyncRes::doSpecialNamesResolve(const DNSName &qname, const QType &qtype, co
     }
   }
 
+  if (qname == trustanchorserver && 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 &dsAnchor : luaLocal->dsAnchors) {
+        ostringstream ans;
+        ans<<"\"";
+        ans<<dsAnchor.first.toString(); // Explicit toString to have a trailing dot
+        for (auto const &dsRecord : dsAnchor.second) {
+          ans<<" ";
+          ans<<dsRecord.d_tag;
+        }
+        ans << "\"";
+        answers.push_back({QType::TXT, ans.str()});
+      }
+    }
+  }
+
   if (handled && !answers.empty()) {
     ret.clear();
     d_wasOutOfBand=true;
diff --git a/regression-tests.recursor-dnssec/test_TrustAnchors.py b/regression-tests.recursor-dnssec/test_TrustAnchors.py
new file mode 100644 (file)
index 0000000..bb761ef
--- /dev/null
@@ -0,0 +1,46 @@
+import dns
+from recursortests import RecursorTest
+
+
+class testTrustAnchorsEnabled(RecursorTest):
+    """This test will do a query for "trustanchor.server CH TXT" and hopes to get
+    a proper answer"""
+
+    _auth_zones = None
+    _confdir = 'TrustAnchorsEnabled'
+    _roothints = None
+    _root_DS = None
+    _lua_config_file = """
+addDS("powerdns.com", "44030 8 1 B763646757DF621DD1204AD3BFA0675B49BE3279")
+"""
+
+    def testTrustanchorDotServer(self):
+        expected = dns.rrset.from_text_list(
+            'trustanchor.server.', 86400, dns.rdataclass.CH, 'TXT',
+            ['". 19036 20326"', '"powerdns.com. 44030"'])
+        query = dns.message.make_query('trustanchor.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
+    a proper answer"""
+
+    _auth_zones = None
+    _confdir = 'TrustAnchorsDisabled'
+    _roothints = None
+    _root_DS = None
+    _config_template = """
+    allow-trust-anchor-query=no
+"""
+
+    def testTrustanchorDotServer(self):
+        query = dns.message.make_query('trustanchor.server', 'TXT',
+                                       dns.rdataclass.CH)
+        result = self.sendUDPQuery(query)
+
+        self.assertRcodeEqual(result, dns.rcode.SERVFAIL)