]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
Add test, only clear cache if the notify wasn't for an RPZ
authorOtto Moerbeek <otto.moerbeek@open-xchange.com>
Fri, 12 Jan 2024 08:50:00 +0000 (09:50 +0100)
committerOtto Moerbeek <otto.moerbeek@open-xchange.com>
Fri, 12 Jan 2024 08:54:10 +0000 (09:54 +0100)
pdns/recursordist/pdns_recursor.cc
pdns/recursordist/rpzloader.cc
regression-tests.recursor-dnssec/test_RPZ.py

index ad6c83c70cabdfa1b4518fd74d4045e10fcf09e1..e31cd7d31b24609a5c707b5b3d588d1d5ca3a8c5 100644 (file)
@@ -2318,8 +2318,10 @@ static string* doProcessUDPQuestion(const std::string& question, const ComboAddr
       SLOG(g_log << Logger::Notice << RecThreadInfo::id() << " got NOTIFY for " << qname.toLogString() << " from " << source.toStringWithPort() << (source != fromaddr ? " (via " + fromaddr.toStringWithPort() + ")" : "") << endl,
            g_slogudpin->info(Logr::Notice, "Got NOTIFY", "source", Logging::Loggable(source), "remote", Logging::Loggable(fromaddr), "qname", Logging::Loggable(qname)));
     }
-    notifyRPZTracker(qname);
-    requestWipeCaches(qname);
+    if (!notifyRPZTracker(qname)) {
+      // It wasn't an RPZ
+      requestWipeCaches(qname);
+    }
 
     // the operation will now be treated as a Query, generating
     // a normal response, as the rest of the code does not
index 5f835969c61c029329b88646410332deed028a05..c5e1036a9e099c5aa280396317c2d0570047d69c 100644 (file)
@@ -564,7 +564,7 @@ static bool RPZTrackerIteration(RPZTrackerParams& params, const DNSName& zoneNam
         if (resourceRecord.d_type == QType::SOA) {
           auto oldsr = getRR<SOARecordContent>(resourceRecord);
           if (oldsr && oldsr->d_st.serial == currentSR->d_st.serial) {
-            //     cout<<"Got good removal of SOA serial "<<oldsr->d_st.serial<<endl;
+            // Got good removal of SOA serial, no work to be done
           }
           else {
             if (!oldsr) {
@@ -587,7 +587,6 @@ static bool RPZTrackerIteration(RPZTrackerParams& params, const DNSName& zoneNam
         }
         if (resourceRecord.d_type == QType::SOA) {
           auto tempSR = getRR<SOARecordContent>(resourceRecord);
-          //     g_log<<Logger::Info<<"New SOA serial for "<<zoneName<<": "<<currentSR->d_st.serial<<endl;
           if (tempSR) {
             currentSR = std::move(tempSR);
           }
index da865ea74cce43f1b8bd2bee2511a4debb87dc5c..d71953268d83f245ac851d111a3021a7d2262104 100644 (file)
@@ -17,7 +17,7 @@ class RPZServer(object):
         self._targetSerial = 1
         self._serverPort = port
         listener = threading.Thread(name='RPZ Listener', target=self._listener, args=[])
-        listener.setDaemon(True)
+        listener.daemon = True
         listener.start()
 
     def getCurrentSerial(self):
@@ -213,7 +213,7 @@ class RPZServer(object):
                 thread = threading.Thread(name='RPZ Connection Handler',
                                       target=self._connectionHandler,
                                       args=[conn])
-                thread.setDaemon(True)
+                thread.daemon = True
                 thread.start()
 
             except socket.error as e:
@@ -253,6 +253,14 @@ api-key=%s
 log-rpz-changes=yes
 """ % (_confdir, _wsPort, _wsPassword, _apiKey)
 
+    def sendNotify(self):
+        notify = dns.message.make_query('zone.rpz', 'SOA', want_dnssec=False)
+        notify.set_opcode(4) # notify
+        res = self.sendUDPQuery(notify)
+        self.assertRcodeEqual(res, dns.rcode.NOERROR)
+        self.assertEqual(res.opcode(), 4)
+        self.assertEqual(res.question[0].to_text(), 'zone.rpz. IN SOA')
+
     def assertAdditionalHasSOA(self, msg):
         if not isinstance(msg, dns.message.Message):
             raise TypeError("msg is not a dns.message.Message but a %s" % type(msg))
@@ -377,7 +385,7 @@ class RPZXFRRecursorTest(RPZRecursorTest):
     global rpzServerPort
     _lua_config_file = """
     -- The first server is a bogus one, to test that we correctly fail over to the second one
-    rpzMaster({'127.0.0.1:9999', '127.0.0.1:%d'}, 'zone.rpz.', { refresh=1, includeSOA=true})
+    rpzMaster({'127.0.0.1:9999', '127.0.0.1:%d'}, 'zone.rpz.', { refresh=3600, includeSOA=true})
     """ % (rpzServerPort)
     _confdir = 'RPZXFR'
     _wsPort = 8042
@@ -392,6 +400,8 @@ webserver-address=127.0.0.1
 webserver-password=%s
 api-key=%s
 disable-packetcache
+allow-notify-from=127.0.0.0/8
+allow-notify-for=zone.rpz
 """ % (_confdir, _wsPort, _wsPassword, _apiKey)
     _xfrDone = 0
 
@@ -429,6 +439,7 @@ e 3600 IN A 192.0.2.42
         raise AssertionError("Waited %d seconds for the serial to be updated to %d but the serial is still %d" % (timeout, serial, currentSerial))
 
     def testRPZ(self):
+        # Fresh RPZ does not need a notify
         self.waitForTCPSocket("127.0.0.1", self._wsPort)
         # first zone, only a should be blocked
         self.waitUntilCorrectSerialIsLoaded(1)
@@ -438,6 +449,7 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('c.example.')
 
         # second zone, a and b should be blocked
+        self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(2)
         self.checkRPZStats(2, 2, 1, self._xfrDone)
         self.checkBlocked('a.example.', soa=True)
@@ -445,6 +457,7 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('c.example.')
 
         # third zone, only b should be blocked
+        self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(3)
         self.checkRPZStats(3, 1, 1, self._xfrDone)
         self.checkNotBlocked('a.example.')
@@ -452,6 +465,7 @@ e 3600 IN A 192.0.2.42
         self.checkNotBlocked('c.example.')
 
         # fourth zone, only c should be blocked
+        self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(4)
         self.checkRPZStats(4, 1, 1, self._xfrDone)
         self.checkNotBlocked('a.example.')
@@ -459,6 +473,7 @@ e 3600 IN A 192.0.2.42
         self.checkBlocked('c.example.', soa=True)
 
         # fifth zone, we should get a full AXFR this time, and only d should be blocked
+        self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(5)
         self.checkRPZStats(5, 3, 2, self._xfrDone)
         self.checkNotBlocked('a.example.')
@@ -467,6 +482,7 @@ e 3600 IN A 192.0.2.42
         self.checkBlocked('d.example.', soa=True)
 
         # sixth zone, only e should be blocked, f is a local data record
+        self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(6)
         self.checkRPZStats(6, 2, 2, self._xfrDone)
         self.checkNotBlocked('a.example.')
@@ -479,6 +495,7 @@ e 3600 IN A 192.0.2.42
         self.checkCustom('f.example.', 'A', dns.rrset.from_text('f.example.', 0, dns.rdataclass.IN, 'CNAME', 'e.example.'), soa=True)
 
         # seventh zone, e should only have one A
+        self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(7)
         self.checkRPZStats(7, 4, 2, self._xfrDone)
         self.checkNotBlocked('a.example.')
@@ -496,6 +513,7 @@ e 3600 IN A 192.0.2.42
         self.checkDropped('drop.example.')
 
         # eighth zone, all entries should be gone
+        self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(8)
         self.checkRPZStats(8, 0, 3, self._xfrDone)
         self.checkNotBlocked('a.example.')
@@ -510,7 +528,9 @@ e 3600 IN A 192.0.2.42
         # 9th zone is a duplicate, it might get skipped
         global rpzServer
         rpzServer.moveToSerial(9)
+        self.sendNotify()
         time.sleep(3)
+        self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(10)
         self.checkRPZStats(10, 1, 4, self._xfrDone)
         self.checkNotBlocked('a.example.')
@@ -524,7 +544,9 @@ e 3600 IN A 192.0.2.42
 
         # the next update will update the zone twice
         rpzServer.moveToSerial(11)
+        self.sendNotify()
         time.sleep(3)
+        self.sendNotify()
         self.waitUntilCorrectSerialIsLoaded(12)
         self.checkRPZStats(12, 1, 4, self._xfrDone)
         self.checkNotBlocked('a.example.')
@@ -704,7 +726,7 @@ class RPZSimpleAuthServer(object):
     def __init__(self, port):
         self._serverPort = port
         listener = threading.Thread(name='RPZ Simple Auth Listener', target=self._listener, args=[])
-        listener.setDaemon(True)
+        listener.daemon = True
         listener.start()
 
     def _getAnswer(self, message):