def testTCPQueriesPerConn(self): """ TCP Limits: Maximum number of queries """ name = 'maxqueriesperconn.tcp.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') conn = self.openTCPConnection() count = 0 for idx in range(self._maxTCPQueriesPerConn): try: self.sendTCPQueryOverConnection(conn, query) response = self.recvTCPResponseOverConnection(conn) self.assertTrue(response) count = count + 1 except: pass # this one should fail failed = False try: self.sendTCPQueryOverConnection(conn, query) response = self.recvTCPResponseOverConnection(conn) self.assertFalse(response) if not response: failed = True else: count = count + 1 except: failed = True conn.close() self.assertTrue(failed) self.assertEqual(count, self._maxTCPQueriesPerConn)
def testTCPConnsPerClient(self): """ TCP Limits: Maximum number of conns per client """ name = 'maxconnsperclient.tcp.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') conns = [] for idx in range(self._maxTCPConnsPerClient + 1): conns.append(self.openTCPConnection()) count = 0 failed = 0 for conn in conns: try: self.sendTCPQueryOverConnection(conn, query) response = self.recvTCPResponseOverConnection(conn) if response: count = count + 1 else: failed = failed + 1 except: failed = failed + 1 for conn in conns: conn.close() self.assertEqual(count, self._maxTCPConnsPerClient) self.assertEqual(failed, 1)
def testTCPKaSelfGenerated(self): """ TCP KeepAlive: Self-generated answer """ name = 'refused.tcpka.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') expectedResponse = dns.message.make_response(query) expectedResponse.set_rcode(dns.rcode.REFUSED) conn = self.openTCPConnection() count = 0 for idx in range(5): try: self.sendTCPQueryOverConnection(conn, query) response = self.recvTCPResponseOverConnection(conn) if response is None: break self.assertEquals(expectedResponse, response) count = count + 1 except: pass conn.close() self.assertEqual(count, 5)
def testTCPKaNoDownstreamServFail(self): """ TCP KeepAlive: No downstream ServFail The query is routed to a pool that has no server, and dnsdist is configured to send a ServFail when that happens. We should keep the TCP connection open. """ name = 'nodownstream-servfail.tcpka.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') expectedResponse = dns.message.make_response(query) expectedResponse.set_rcode(dns.rcode.SERVFAIL) conn = self.openTCPConnection() count = 0 for idx in range(5): try: self.sendTCPQueryOverConnection(conn, query) response = self.recvTCPResponseOverConnection(conn) if response is None: break self.assertEquals(expectedResponse, response) count = count + 1 except: pass conn.close() self.assertEqual(count, 5)
def testTCPKaNoDownstreamDrop(self): """ TCP KeepAlive: No downstream Drop The query is routed to a pool that has no server, and dnsdist is configured to drop the query when that happens. We should close the TCP connection right away. """ name = 'nodownstream-drop.tcpka.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') conn = self.openTCPConnection() count = 0 for idx in range(5): try: self.sendTCPQueryOverConnection(conn, query) response = self.recvTCPResponseOverConnection(conn) if response is None: break count = count + 1 except: pass conn.close() self.assertEqual(count, 0)
def testWhitelisted(self): """ Dyn Blocks: Whitelisted from the dynamic blocks """ name = 'whitelisted.dynblocks.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') response = dns.message.make_response(query) rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1') response.answer.append(rrset) allowed = 0 sent = 0 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = allowed + 1 else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # we should not have been blocked self.assertEqual(allowed, sent) # wait for the maintenance function to run time.sleep(2) # we should still not be blocked (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(receivedResponse, receivedResponse) # check that we would have been blocked without the whitelisting name = 'whitelisted-test.dynblocks.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') # dnsdist set RA = RD for spoofed responses query.flags &= ~dns.flags.RD expectedResponse = dns.message.make_response(query) rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.42') expectedResponse.answer.append(rrset) (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, expectedResponse)
def testWarning(self): """ Dyn Blocks (group) : Warning """ name = 'warning.group.dynblocks.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') response = dns.message.make_response(query) rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1') response.answer.append(rrset) allowed = 0 sent = 0 for _ in range((self._dynBlockWarningQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = allowed + 1 else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # a dynamic rule should have been inserted, but the queries should # still go on because we are still at warning level self.assertEqual(allowed, sent) # wait for the maintenance function to run time.sleep(2) # the rule should still be present, but the queries pass through anyway (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(receivedResponse, receivedResponse) # check that the rule has been inserted self.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', self._dynBlockDuration - 4, self._dynBlockDuration, 0, sent) self.doTestQRate(name)
def testExcluded(self): """ Dyn Blocks (group) : Excluded from the dynamic block rules """ name = 'excluded.group.dynblocks.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') response = dns.message.make_response(query) rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1') response.answer.append(rrset) allowed = 0 sent = 0 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = allowed + 1 else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # we should have been blocked self.assertEqual(allowed, sent) # wait for the maintenance function to run time.sleep(2) # we should still not be blocked (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(receivedResponse, receivedResponse)
def testExcluded(self): """ Dyn Blocks (group) : Excluded from the dynamic block rules """ name = 'excluded.group.dynblocks.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') response = dns.message.make_response(query) rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1') response.answer.append(rrset) allowed = 0 sent = 0 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = allowed + 1 else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # we should not have been blocked self.assertEqual(allowed, sent) # wait for the maintenance function to run time.sleep(2) # we should still not be blocked (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(receivedResponse, receivedResponse)
def testTCPKaDropResponse(self): """ TCP KeepAlive: Drop Response """ name = 'dropped-response.tcpka.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') conn = self.openTCPConnection() count = 0 for idx in range(5): try: self.sendTCPQueryOverConnection(conn, query) response = self.recvTCPResponseOverConnection(conn) if response is None: break count = count + 1 except: pass conn.close() self.assertEqual(count, 0)
def testTCPKaCacheHit(self): """ TCP KeepAlive: Cache Hit """ name = 'cachehit.tcpka.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') expectedResponse = dns.message.make_response(query) rrset = dns.rrset.from_text(name, 3600, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1') expectedResponse.answer.append(rrset) # first query to fill the cache (receivedQuery, receivedResponse) = self.sendTCPQuery(query, expectedResponse) self.assertTrue(receivedQuery) self.assertTrue(receivedResponse) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(receivedResponse, expectedResponse) conn = self.openTCPConnection() count = 0 for idx in range(5): try: self.sendTCPQueryOverConnection(conn, query) response = self.recvTCPResponseOverConnection(conn) if response is None: break self.assertEquals(expectedResponse, response) count = count + 1 except: pass conn.close() self.assertEqual(count, 5)
def testTCPKaQRBitSet(self): """ TCP KeepAlive: QR bit set in question """ name = 'qrset.tcpka.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') query.flags |= dns.flags.QR conn = self.openTCPConnection() count = 0 for idx in range(5): try: self.sendTCPQueryOverConnection(conn, query) response = self.recvTCPResponseOverConnection(conn) if response is None: break count = count + 1 except: pass conn.close() self.assertEqual(count, 0)
def testDynBlocksQRate(self): """ Dyn Blocks: QRate truncated (action) """ name = 'qrateactiontruncated.dynblocks.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') response = dns.message.make_response(query) rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1') response.answer.append(rrset) truncatedResponse = dns.message.make_response(query) truncatedResponse.flags |= dns.flags.TC allowed = 0 sent = 0 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(receivedResponse, response) allowed = allowed + 1 else: self.assertEquals(receivedResponse, truncatedResponse) # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # we might be already truncated, but we should have been able to send # at least self._dynBlockQPS queries self.assertGreaterEqual(allowed, self._dynBlockQPS) if allowed == sent: # wait for the maintenance function to run time.sleep(2) # we should now be 'truncated' for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, truncatedResponse) # check over TCP, which should not be truncated (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) self.assertEquals(query, receivedQuery) self.assertEquals(receivedResponse, response) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) # this one should succeed (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = 0 sent = 0 # again, over TCP this time, we should never get truncated! for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) sent = sent + 1 self.assertEquals(query, receivedQuery) self.assertEquals(receivedResponse, response) receivedQuery.id = query.id allowed = allowed + 1 self.assertEquals(allowed, sent)
def doTestQRate(self, name, testViaAPI=True): query = dns.message.make_query(name, 'A', 'IN') response = dns.message.make_response(query) rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1') response.answer.append(rrset) allowed = 0 sent = 0 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = allowed + 1 else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # we might be already blocked, but we should have been able to send # at least self._dynBlockQPS queries self.assertGreaterEqual(allowed, self._dynBlockQPS) if allowed == sent: # wait for the maintenance function to run time.sleep(2) # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, None) if testViaAPI: self.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', self._dynBlockDuration - 4, self._dynBlockDuration, (sent - allowed) + 1, (sent - allowed) + 1) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) # this one should succeed (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) # again, over TCP this time allowed = 0 sent = 0 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = allowed + 1 else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # we might be already blocked, but we should have been able to send # at least self._dynBlockQPS queries self.assertGreaterEqual(allowed, self._dynBlockQPS) if allowed == sent: # wait for the maintenance function to run time.sleep(2) # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, None) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) # this one should succeed (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse)
def doTestRCodeRate(self, name, rcode): query = dns.message.make_query(name, 'A', 'IN') response = dns.message.make_response(query) rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1') response.answer.append(rrset) expectedResponse = dns.message.make_response(query) expectedResponse.set_rcode(rcode) # start with normal responses for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) # wait for the maintenance function to run time.sleep(2) # we should NOT be dropped! (_, receivedResponse) = self.sendUDPQuery(query, response) self.assertEquals(receivedResponse, response) # now with rcode! sent = 0 allowed = 0 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, expectedResponse) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(expectedResponse, receivedResponse) allowed = allowed + 1 else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # we might be already blocked, but we should have been able to send # at least self._dynBlockQPS queries self.assertGreaterEqual(allowed, self._dynBlockQPS) if allowed == sent: # wait for the maintenance function to run time.sleep(2) # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, None) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) # this one should succeed (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) # again, over TCP this time # start with normal responses for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) # wait for the maintenance function to run time.sleep(2) # we should NOT be dropped! (_, receivedResponse) = self.sendUDPQuery(query, response) self.assertEquals(receivedResponse, response) # now with rcode! sent = 0 allowed = 0 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendTCPQuery(query, expectedResponse) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(expectedResponse, receivedResponse) allowed = allowed + 1 else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # we might be already blocked, but we should have been able to send # at least self._dynBlockQPS queries self.assertGreaterEqual(allowed, self._dynBlockQPS) if allowed == sent: # wait for the maintenance function to run time.sleep(2) # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, None) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) # this one should succeed (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse)
def doTestResponseByteRate(self, name): query = dns.message.make_query(name, 'A', 'IN') response = dns.message.make_response(query) response.answer.append( dns.rrset.from_text_list( name, 60, dns.rdataclass.IN, dns.rdatatype.A, ['192.0.2.1', '192.0.2.2', '192.0.2.3', '192.0.2.4'])) response.answer.append( dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:DB8::1')) allowed = 0 sent = 0 print(time.time()) for _ in range( int(self._dynBlockBytesPerSecond * 5 / len(response.to_wire()))): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) sent = sent + len(response.to_wire()) if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = allowed + len(response.to_wire()) else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # and stop right there, otherwise we might # wait for so long that the dynblock is gone # by the time we finished break # we might be already blocked, but we should have been able to send # at least self._dynBlockBytesPerSecond bytes print(allowed) print(sent) print(time.time()) self.assertGreaterEqual(allowed, self._dynBlockBytesPerSecond) print(self.sendConsoleCommand("showDynBlocks()")) print(self.sendConsoleCommand("grepq(\"\")")) print(time.time()) if allowed == sent: # wait for the maintenance function to run print("Waiting for the maintenance function to run") time.sleep(2) print(self.sendConsoleCommand("showDynBlocks()")) print(self.sendConsoleCommand("grepq(\"\")")) print(time.time()) # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, None) print(self.sendConsoleCommand("showDynBlocks()")) print(self.sendConsoleCommand("grepq(\"\")")) print(time.time()) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) print(self.sendConsoleCommand("showDynBlocks()")) print(self.sendConsoleCommand("grepq(\"\")")) print(time.time()) # this one should succeed (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) # again, over TCP this time allowed = 0 sent = 0 for _ in range( int(self._dynBlockBytesPerSecond * 5 / len(response.to_wire()))): (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) sent = sent + len(response.to_wire()) if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = allowed + len(response.to_wire()) else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # and stop right there, otherwise we might # wait for so long that the dynblock is gone # by the time we finished break # we might be already blocked, but we should have been able to send # at least self._dynBlockBytesPerSecond bytes self.assertGreaterEqual(allowed, self._dynBlockBytesPerSecond) if allowed == sent: # wait for the maintenance function to run time.sleep(2) # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, None) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) # this one should succeed (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse)
def testDynBlocksResponseByteRate(self): """ Dyn Blocks: Response Byte Rate """ name = 'responsebyterate.dynblocks.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') response = dns.message.make_response(query) response.answer.append(dns.rrset.from_text_list(name, 60, dns.rdataclass.IN, dns.rdatatype.A, ['192.0.2.1', '192.0.2.2', '192.0.2.3', '192.0.2.4'])) response.answer.append(dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.AAAA, '2001:DB8::1')) allowed = 0 sent = 0 print(time.time()) for _ in range(int(self._dynBlockBytesPerSecond * 5 / len(response.to_wire()))): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) sent = sent + len(response.to_wire()) if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = allowed + len(response.to_wire()) else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # and stop right there, otherwise we might # wait for so long that the dynblock is gone # by the time we finished break # we might be already blocked, but we should have been able to send # at least self._dynBlockBytesPerSecond bytes print(allowed) print(sent) print(time.time()) self.assertGreaterEqual(allowed, self._dynBlockBytesPerSecond) print(self.sendConsoleCommand("showDynBlocks()")) print(self.sendConsoleCommand("grepq(\"\")")) print(time.time()) if allowed == sent: # wait for the maintenance function to run print("Waiting for the maintenance function to run") time.sleep(2) print(self.sendConsoleCommand("showDynBlocks()")) print(self.sendConsoleCommand("grepq(\"\")")) print(time.time()) # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, None) print(self.sendConsoleCommand("showDynBlocks()")) print(self.sendConsoleCommand("grepq(\"\")")) print(time.time()) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) print(self.sendConsoleCommand("showDynBlocks()")) print(self.sendConsoleCommand("grepq(\"\")")) print(time.time()) # this one should succeed (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) # again, over TCP this time allowed = 0 sent = 0 for _ in range(int(self._dynBlockBytesPerSecond * 5 / len(response.to_wire()))): (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) sent = sent + len(response.to_wire()) if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = allowed + len(response.to_wire()) else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # and stop right there, otherwise we might # wait for so long that the dynblock is gone # by the time we finished break # we might be already blocked, but we should have been able to send # at least self._dynBlockBytesPerSecond bytes self.assertGreaterEqual(allowed, self._dynBlockBytesPerSecond) if allowed == sent: # wait for the maintenance function to run time.sleep(2) # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, None) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) # this one should succeed (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse)
def testDynBlocksServFailRate(self): """ Dyn Blocks: Server Failure Rate """ name = 'servfailrate.dynblocks.tests.powerdns.com.' query = dns.message.make_query(name, 'A', 'IN') response = dns.message.make_response(query) rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1') response.answer.append(rrset) servfailResponse = dns.message.make_response(query) servfailResponse.set_rcode(dns.rcode.SERVFAIL) # start with normal responses for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) # wait for the maintenance function to run time.sleep(2) # we should NOT be dropped! (_, receivedResponse) = self.sendUDPQuery(query, response) self.assertEquals(receivedResponse, response) # now with ServFail! sent = 0 allowed = 0 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, servfailResponse) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(servfailResponse, receivedResponse) allowed = allowed + 1 else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # we might be already blocked, but we should have been able to send # at least self._dynBlockQPS queries self.assertGreaterEqual(allowed, self._dynBlockQPS) if allowed == sent: # wait for the maintenance function to run time.sleep(2) # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, None) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) # this one should succeed (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) # again, over TCP this time # start with normal responses for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) # wait for the maintenance function to run time.sleep(2) # we should NOT be dropped! (_, receivedResponse) = self.sendUDPQuery(query, response) self.assertEquals(receivedResponse, response) # now with ServFail! sent = 0 allowed = 0 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendTCPQuery(query, servfailResponse) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(servfailResponse, receivedResponse) allowed = allowed + 1 else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # we might be already blocked, but we should have been able to send # at least self._dynBlockQPS queries self.assertGreaterEqual(allowed, self._dynBlockQPS) if allowed == sent: # wait for the maintenance function to run time.sleep(2) # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, None) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) # this one should succeed (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse)
def doTestQRate(self, name, testViaAPI=True): query = dns.message.make_query(name, 'A', 'IN') response = dns.message.make_response(query) rrset = dns.rrset.from_text(name, 60, dns.rdataclass.IN, dns.rdatatype.A, '192.0.2.1') response.answer.append(rrset) allowed = 0 sent = 0 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = allowed + 1 else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # we might be already blocked, but we should have been able to send # at least self._dynBlockQPS queries self.assertGreaterEqual(allowed, self._dynBlockQPS) if allowed == sent: # wait for the maintenance function to run time.sleep(2) # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, None) if testViaAPI: self.doTestDynBlockViaAPI('127.0.0.1/32', 'Exceeded query rate', self._dynBlockDuration - 4, self._dynBlockDuration, (sent-allowed)+1, (sent-allowed)+1) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) # this one should succeed (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) # again, over TCP this time allowed = 0 sent = 0 for _ in range((self._dynBlockQPS * self._dynBlockPeriod) + 1): (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) sent = sent + 1 if receivedQuery: receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse) allowed = allowed + 1 else: # the query has not reached the responder, # let's clear the response queue self.clearToResponderQueue() # we might be already blocked, but we should have been able to send # at least self._dynBlockQPS queries self.assertGreaterEqual(allowed, self._dynBlockQPS) if allowed == sent: # wait for the maintenance function to run time.sleep(2) # we should now be dropped for up to self._dynBlockDuration + self._dynBlockPeriod (_, receivedResponse) = self.sendTCPQuery(query, response=None, useQueue=False) self.assertEquals(receivedResponse, None) # wait until we are not blocked anymore time.sleep(self._dynBlockDuration + self._dynBlockPeriod) # this one should succeed (receivedQuery, receivedResponse) = self.sendTCPQuery(query, response) receivedQuery.id = query.id self.assertEquals(query, receivedQuery) self.assertEquals(response, receivedResponse)