]>
Commit | Line | Data |
---|---|---|
046a03e9 RG |
1 | #!/usr/bin/env python |
2 | import base64 | |
3 | import time | |
4 | import dns | |
5 | from dnsdisttests import DNSDistTest, pickAvailablePort | |
6 | ||
7 | class TestCacheMissSelfAnswered(DNSDistTest): | |
8 | _consoleKey = DNSDistTest.generateConsoleKey() | |
9 | _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii') | |
10 | _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort'] | |
11 | ||
12 | _config_template = """ | |
13 | setKey("%s") | |
14 | controlSocket("127.0.0.1:%d") | |
15 | newServer{address="127.0.0.1:%d"} | |
16 | ||
17 | pc = newPacketCache(100, {maxTTL=86400, minTTL=1}) | |
18 | getPool(""):setCache(pc) | |
19 | -- this does not really make sense on its own, but we might want | |
20 | -- to refuse queries for a domain under attack if the anwer is not cached | |
21 | addCacheMissAction(SuffixMatchNodeRule("refused.cache-miss.tests.powerdns.com."), RCodeAction(DNSRCode.REFUSED), {name="myFirstRule"}) | |
22 | """ | |
23 | ||
24 | def testRefusedWhenNotCached(self): | |
25 | """ | |
26 | CacheMiss: Refused when not in cache | |
27 | """ | |
28 | # check that the rule is in place | |
29 | lines = self.sendConsoleCommand('showCacheMissRules()').splitlines() | |
30 | self.assertEqual(len(lines), 2) | |
31 | self.assertIn('myFirstRule', lines[1]) | |
32 | ||
33 | name = 'refused.cache-miss.tests.powerdns.com.' | |
34 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
35 | # dnsdist set RA = RD for spoofed responses | |
36 | query.flags &= ~dns.flags.RD | |
37 | expectedResponse = dns.message.make_response(query) | |
38 | expectedResponse.set_rcode(dns.rcode.REFUSED) | |
39 | ||
40 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
41 | self.assertTrue(receivedResponse) | |
42 | self.assertEqual(receivedResponse, expectedResponse) | |
43 | ||
44 | # now we remove the rule | |
45 | self.sendConsoleCommand('clearCacheMissRules()') | |
46 | lines = self.sendConsoleCommand('showCacheMissRules()').splitlines() | |
47 | self.assertEqual(len(lines), 1) | |
48 | ||
49 | # get a response inserted into the cache | |
50 | response = dns.message.make_response(query) | |
51 | rrset = dns.rrset.from_text(name, | |
52 | 60, | |
53 | dns.rdataclass.IN, | |
54 | dns.rdatatype.AAAA, | |
55 | '2001:db8::1') | |
56 | response.answer.append(rrset) | |
57 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response=response) | |
58 | self.assertTrue(receivedQuery) | |
59 | self.assertTrue(receivedResponse) | |
60 | receivedQuery.id = query.id | |
61 | self.assertEqual(receivedQuery, query) | |
62 | self.assertEqual(receivedResponse, response) | |
63 | ||
64 | # add the rule back | |
65 | self.sendConsoleCommand('addCacheMissAction(SuffixMatchNodeRule("refused.cache-miss.tests.powerdns.com."), RCodeAction(DNSRCode.REFUSED), {name="myFirstRule"})') | |
66 | lines = self.sendConsoleCommand('showCacheMissRules()').splitlines() | |
67 | self.assertEqual(len(lines), 2) | |
68 | self.assertIn('myFirstRule', lines[1]) | |
69 | ||
70 | # and check that we do get the cached response | |
71 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
72 | self.assertTrue(receivedResponse) | |
73 | self.assertEqual(receivedResponse, response) | |
74 | ||
75 | class TestCacheMissGoToADifferentPool(DNSDistTest): | |
76 | _consoleKey = DNSDistTest.generateConsoleKey() | |
77 | _consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii') | |
78 | _testServer2Port = pickAvailablePort() | |
79 | _config_params = ['_consoleKeyB64', '_consolePort', '_testServerPort', '_testServer2Port'] | |
80 | ||
81 | _config_template = """ | |
82 | setKey("%s") | |
83 | controlSocket("127.0.0.1:%d") | |
84 | ||
85 | newServer{address="127.0.0.1:%d", pool="slow", name="slow"} | |
86 | newServer{address="127.0.0.1:%d", pool="initial", name="initial"} | |
87 | ||
88 | pc = newPacketCache(100, {maxTTL=86400, minTTL=1}) | |
89 | getPool("initial"):setCache(pc) | |
90 | getPool("slow"):setCache(pc) | |
91 | ||
92 | addAction(AllRule(), PoolAction("initial")) | |
93 | -- this does not really make sense on its own, but we might want | |
94 | -- to route queries for a domain under attack to a different pool | |
95 | -- of 'best-effort' servers if the anwer is not cached | |
96 | addCacheMissAction(SuffixMatchNodeRule("routed-to-slow.cache-miss.tests.powerdns.com."), PoolAction("slow")) | |
97 | """ | |
98 | ||
99 | def testRoutedToSlowWhenNotCached(self): | |
100 | """ | |
101 | CacheMiss: Routed to a different pool when not in cache | |
102 | """ | |
103 | name = 'routed-to-slow.cache-miss.tests.powerdns.com.' | |
104 | query = dns.message.make_query(name, 'AAAA', 'IN') | |
105 | response = dns.message.make_response(query) | |
106 | rrset = dns.rrset.from_text(name, | |
107 | 60, | |
108 | dns.rdataclass.IN, | |
109 | dns.rdatatype.AAAA, | |
110 | '2001:db8::1') | |
111 | response.answer.append(rrset) | |
112 | ||
113 | # first query goes to the 'slow' server | |
114 | (receivedQuery, receivedResponse) = self.sendUDPQuery(query, response=response) | |
115 | self.assertTrue(receivedQuery) | |
116 | self.assertTrue(receivedResponse) | |
117 | receivedQuery.id = query.id | |
118 | self.assertEqual(receivedQuery, query) | |
119 | self.assertEqual(receivedResponse, response) | |
120 | ||
121 | # the second one is a cache-hit | |
122 | (_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False) | |
123 | self.assertTrue(receivedResponse) | |
124 | self.assertEqual(receivedResponse, response) | |
125 | ||
126 | backendLines = self.sendConsoleCommand('showServers()').splitlines(False) | |
127 | self.assertEqual(len(backendLines), 4) | |
128 | for line in backendLines: | |
129 | if line.startswith('#') or line.startswith('All'): | |
130 | continue | |
131 | tokens = line.split() | |
132 | self.assertEqual(len(tokens), 15) | |
133 | pool = tokens[13] | |
134 | queries = int(tokens[9]) | |
135 | if pool == 'slow': | |
136 | self.assertEqual(queries, 1) | |
137 | else: | |
138 | self.assertEqual(queries, 0) |