]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rec: dump right SOA into dumpFile and report non-relative SOA for includeSOA=true 14471/head
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Mon, 15 Jul 2024 09:41:38 +0000 (11:41 +0200)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Mon, 15 Jul 2024 10:03:56 +0000 (12:03 +0200)
pdns/recursordist/filterpo.cc
pdns/recursordist/rpzloader.cc
regression-tests.recursor-dnssec/test_RPZ.py

index bfcbbc71e6a88a89a3cb51ffe570f5a56db5ae45..75f3106b4938845e5e39897e893165ef2b951003 100644 (file)
@@ -799,9 +799,14 @@ void DNSFilterEngine::Zone::dumpAddrPolicy(FILE* filePtr, const Netmask& netmask
 
 void DNSFilterEngine::Zone::dump(FILE* filePtr) const
 {
-  /* fake the SOA record */
-  auto soa = DNSRecordContent::make(QType::SOA, QClass::IN, "fake.RPZ. hostmaster.fake.RPZ. " + std::to_string(d_serial) + " " + std::to_string(d_refresh) + " 600 3600000 604800");
-  fprintf(filePtr, "%s IN SOA %s\n", d_domain.toString().c_str(), soa->getZoneRepresentation().c_str());
+  if (DNSRecord soa = d_zoneData->d_soa; !soa.d_name.empty()) {
+    fprintf(filePtr, "%s IN SOA %s\n", soa.d_name.toString().c_str(), soa.getContent()->getZoneRepresentation().c_str());
+  }
+  else {
+    /* fake the SOA record */
+    auto soarr = DNSRecordContent::make(QType::SOA, QClass::IN, "fake.RPZ. hostmaster.fake.RPZ. " + std::to_string(d_serial) + " " + std::to_string(d_refresh) + " 600 3600000 604800");
+    fprintf(filePtr, "%s IN SOA %s\n", d_domain.toString().c_str(), soarr->getZoneRepresentation().c_str());
+  }
 
   for (const auto& pair : d_qpolName) {
     dumpNamedPolicy(filePtr, pair.first + d_domain, pair.second);
index 486019d776ab065bd5fa4b72aaec713ade5f013e..a7471d64cabf4176939241837cdb1fdc626b381b 100644 (file)
@@ -269,10 +269,13 @@ static shared_ptr<const SOARecordContent> loadRPZFromServer(Logr::log_t plogger,
         continue;
       }
 
+      // We want the full name in the SOA record
+      if (dnsRecord.d_type == QType::SOA) {
+        zone->setSOA(dnsRecord);
+      }
       dnsRecord.d_name.makeUsRelative(zoneName);
       if (dnsRecord.d_type == QType::SOA) {
         soaRecordContent = getRR<SOARecordContent>(dnsRecord);
-        zone->setSOA(dnsRecord);
         continue;
       }
 
index ca7292d39c750292665df1216081247b490ce307..3ac9f0683ef0b9e981fd587efbd3fe5506f6f499 100644 (file)
@@ -261,20 +261,20 @@ log-rpz-changes=yes
         self.assertEqual(res.opcode(), 4)
         self.assertEqual(res.question[0].to_text(), 'zone.rpz. IN SOA')
 
-    def assertAdditionalHasSOA(self, msg):
+    def assertAdditionalHasSOA(self, msg, name):
         if not isinstance(msg, dns.message.Message):
             raise TypeError("msg is not a dns.message.Message but a %s" % type(msg))
 
         found = False
         for rrset in msg.additional:
-            if rrset.rdtype == dns.rdatatype.SOA:
+            if rrset.rdtype == dns.rdatatype.SOA and str(rrset.name) == name:
                 found = True
                 break
 
         if not found:
-            raise AssertionError("No SOA record found in the authority section:\n%s" % msg.to_text())
+            raise AssertionError("No %s SOA record found in the additional section:\n%s" % (name, msg.to_text()))
 
-    def checkBlocked(self, name, shouldBeBlocked=True, adQuery=False, singleCheck=False, soa=False):
+    def checkBlocked(self, name, shouldBeBlocked=True, adQuery=False, singleCheck=False, soa=None):
         query = dns.message.make_query(name, 'A', want_dnssec=True)
         query.flags |= dns.flags.CD
         if adQuery:
@@ -291,14 +291,14 @@ log-rpz-changes=yes
 
             self.assertRRsetInAnswer(res, expected)
             if soa:
-                self.assertAdditionalHasSOA(res)
+                self.assertAdditionalHasSOA(res, soa)
             if singleCheck:
                 break
 
     def checkNotBlocked(self, name, adQuery=False, singleCheck=False):
         self.checkBlocked(name, False, adQuery, singleCheck)
 
-    def checkCustom(self, qname, qtype, expected, soa=False):
+    def checkCustom(self, qname, qtype, expected, soa=None):
         query = dns.message.make_query(qname, qtype, want_dnssec=True)
         query.flags |= dns.flags.CD
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -307,9 +307,9 @@ log-rpz-changes=yes
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertRRsetInAnswer(res, expected)
             if soa:
-                self.assertAdditionalHasSOA(res)
+                self.assertAdditionalHasSOA(res, soa)
 
-    def checkNoData(self, qname, qtype, soa=False):
+    def checkNoData(self, qname, qtype, soa=None):
         query = dns.message.make_query(qname, qtype, want_dnssec=True)
         query.flags |= dns.flags.CD
         for method in ("sendUDPQuery", "sendTCPQuery"):
@@ -318,7 +318,7 @@ log-rpz-changes=yes
             self.assertRcodeEqual(res, dns.rcode.NOERROR)
             self.assertEqual(len(res.answer), 0)
             if soa:
-                self.assertAdditionalHasSOA(res)
+                self.assertAdditionalHasSOA(res, soa)
 
     def checkNXD(self, qname, qtype='A'):
         query = dns.message.make_query(qname, qtype, want_dnssec=True)
@@ -330,7 +330,7 @@ log-rpz-changes=yes
             self.assertEqual(len(res.answer), 0)
             self.assertEqual(len(res.authority), 1)
 
-    def checkTruncated(self, qname, qtype='A', soa=False):
+    def checkTruncated(self, qname, qtype='A', soa=None):
         query = dns.message.make_query(qname, qtype, want_dnssec=True)
         query.flags |= dns.flags.CD
         res = self.sendUDPQuery(query)
@@ -339,7 +339,7 @@ log-rpz-changes=yes
         self.assertEqual(len(res.answer), 0)
         self.assertEqual(len(res.authority), 0)
         if soa:
-            self.assertAdditionalHasSOA(res)
+            self.assertAdditionalHasSOA(res, soa)
 
         res = self.sendTCPQuery(query)
         self.assertRcodeEqual(res, dns.rcode.NXDOMAIN)
@@ -444,7 +444,7 @@ e 3600 IN A 192.0.2.42
         # first zone, only a should be blocked
         self.waitUntilCorrectSerialIsLoaded(1)
         self.checkRPZStats(1, 1, 1, self._xfrDone)
-        self.checkBlocked('a.example.', soa=True)
+        self.checkBlocked('a.example.', soa='zone.rpz.')
         self.checkNotBlocked('b.example.')
         self.checkNotBlocked('c.example.')
 
@@ -452,8 +452,8 @@ e 3600 IN A 192.0.2.42
         self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(2)
         self.checkRPZStats(2, 2, 1, self._xfrDone)
-        self.checkBlocked('a.example.', soa=True)
-        self.checkBlocked('b.example.', soa=True)
+        self.checkBlocked('a.example.', soa='zone.rpz.')
+        self.checkBlocked('b.example.', soa='zone.rpz.')
         self.checkNotBlocked('c.example.')
 
         # third zone, only b should be blocked
@@ -461,7 +461,7 @@ e 3600 IN A 192.0.2.42
         self.waitUntilCorrectSerialIsLoaded(3)
         self.checkRPZStats(3, 1, 1, self._xfrDone)
         self.checkNotBlocked('a.example.')
-        self.checkBlocked('b.example.', soa=True)
+        self.checkBlocked('b.example.', soa='zone.rpz.')
         self.checkNotBlocked('c.example.')
 
         # fourth zone, only c should be blocked
@@ -470,7 +470,7 @@ e 3600 IN A 192.0.2.42
         self.checkRPZStats(4, 1, 1, self._xfrDone)
         self.checkNotBlocked('a.example.')
         self.checkNotBlocked('b.example.')
-        self.checkBlocked('c.example.', soa=True)
+        self.checkBlocked('c.example.', soa='zone.rpz.')
 
         # fifth zone, we should get a full AXFR this time, and only d should be blocked
         self.sendNotify()
@@ -479,7 +479,7 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('a.example.')
         self.checkNotBlocked('b.example.')
         self.checkNotBlocked('c.example.')
-        self.checkBlocked('d.example.', soa=True)
+        self.checkBlocked('d.example.', soa='zone.rpz.')
 
         # sixth zone, only e should be blocked, f is a local data record
         self.sendNotify()
@@ -489,10 +489,10 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('b.example.')
         self.checkNotBlocked('c.example.')
         self.checkNotBlocked('d.example.')
-        self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1', '192.0.2.2'), soa=True)
+        self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.1', '192.0.2.2'), soa='zone.rpz.')
         self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'))
-        self.checkNoData('e.example.', 'AAAA', soa=True)
-        self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa=True)
+        self.checkNoData('e.example.', 'AAAA', soa='zone.rpz.')
+        self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa='zone.rpz.')
 
         # seventh zone, e should only have one A
         self.sendNotify()
@@ -502,14 +502,14 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('b.example.')
         self.checkNotBlocked('c.example.')
         self.checkNotBlocked('d.example.')
-        self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2'), soa=True)
-        self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'), soa=True)
-        self.checkNoData('e.example.', 'AAAA', soa=True)
-        self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa=True)
+        self.checkCustom('e.example.', 'A', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.2'), soa='zone.rpz.')
+        self.checkCustom('e.example.', 'MX', dns.rrset.from_text('e.example.', 0, dns.rdataclass.IN, 'MX', '10 mx.example.'), soa='zone.rpz.')
+        self.checkNoData('e.example.', 'AAAA', soa='zone.rpz.')
+        self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa='zone.rpz.')
         # check that the policy is disabled for AD=1 queries
         self.checkNotBlocked('e.example.', True)
         # check non-custom policies
-        self.checkTruncated('tc.example.', soa=True)
+        self.checkTruncated('tc.example.', soa='zone.rpz.')
         self.checkDropped('drop.example.')
 
         # eighth zone, all entries should be gone
@@ -538,7 +538,7 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('c.example.')
         self.checkNotBlocked('d.example.')
         self.checkNotBlocked('e.example.')
-        self.checkBlocked('f.example.', soa=True)
+        self.checkBlocked('f.example.', soa='zone.rpz.')
         self.checkNXD('tc.example.')
         self.checkNXD('drop.example.')
 
@@ -555,7 +555,7 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('d.example.')
         self.checkNotBlocked('e.example.')
         self.checkNXD('f.example.')
-        self.checkBlocked('g.example.', soa=True)
+        self.checkBlocked('g.example.', soa='zone.rpz.')
         self.checkNXD('tc.example.')
         self.checkNXD('drop.example.')
 
@@ -602,7 +602,7 @@ tc.example.zone.rpz. 60 IN CNAME rpz-tcp-only.
     def testRPZ(self):
         self.checkCustom('a.example.', 'A', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'A', '192.0.2.42', '192.0.2.43'))
         self.checkCustom('a.example.', 'TXT', dns.rrset.from_text('a.example.', 0, dns.rdataclass.IN, 'TXT', '"some text"'))
-        self.checkBlocked('z.example.', soa=True)
+        self.checkBlocked('z.example.', soa='zone.rpz.')
         self.checkNotBlocked('b.example.')
         self.checkNotBlocked('c.example.')
         self.checkNotBlocked('d.example.')
@@ -610,7 +610,7 @@ tc.example.zone.rpz. 60 IN CNAME rpz-tcp-only.
         # check that the policy is disabled for AD=1 queries
         self.checkNotBlocked('z.example.', True)
         # check non-custom policies
-        self.checkTruncated('tc.example.', soa=True)
+        self.checkTruncated('tc.example.', soa='zone.rpz.')
         self.checkDropped('drop.example.')
 
 class RPZFileDefaultPolRecursorTest(RPZRecursorTest):