]> git.ipfire.org Git - thirdparty/pdns.git/blame - regression-tests.dnsdist/test_TCPKeepAlive.py
Merge pull request #8713 from rgacogne/auth-strict-caches-size
[thirdparty/pdns.git] / regression-tests.dnsdist / test_TCPKeepAlive.py
CommitLineData
dcacff17
RG
1#!/usr/bin/env python
2import struct
3import time
4import dns
06b0e003
RG
5from dnsdisttests import DNSDistTest
6
7try:
f0d9b6b7 8 range = xrange
06b0e003 9except NameError:
f0d9b6b7 10 pass
dcacff17
RG
11
12class TestTCPKeepAlive(DNSDistTest):
13 """
14 These tests make sure that dnsdist keeps the TCP connection alive
15 in various cases, like cache hits, self-generated answer, and
16 that it doesn't in error cases (Drop, invalid queries...)
17 """
18
19 _tcpIdleTimeout = 20
20 _maxTCPQueriesPerConn = 99
f0d9b6b7 21 _maxTCPConnsPerClient = 100
dcacff17
RG
22 _maxTCPConnDuration = 99
23 _config_template = """
24 newServer{address="127.0.0.1:%s"}
25 setTCPRecvTimeout(%s)
26 setMaxTCPQueriesPerConnection(%s)
27 setMaxTCPConnectionsPerClient(%s)
28 setMaxTCPConnectionDuration(%s)
7d294573 29 pc = newPacketCache(100, {maxTTL=86400, minTTL=1})
dcacff17 30 getPool(""):setCache(pc)
f0d9b6b7 31 addAction("largernumberofconnections.tcpka.tests.powerdns.com.", SkipCacheAction())
d3ec24f9 32 addAction("refused.tcpka.tests.powerdns.com.", RCodeAction(DNSRCode.REFUSED))
dcacff17
RG
33 addAction("dropped.tcpka.tests.powerdns.com.", DropAction())
34 addResponseAction("dropped-response.tcpka.tests.powerdns.com.", DropResponseAction())
35 -- create the pool named "nosuchpool"
36 getPool("nosuchpool")
37 addAction("nodownstream-servfail.tcpka.tests.powerdns.com.", PoolAction("nosuchpool"))
38 setServFailWhenNoServer(true)
39 """
40 _config_params = ['_testServerPort', '_tcpIdleTimeout', '_maxTCPQueriesPerConn', '_maxTCPConnsPerClient', '_maxTCPConnDuration']
41
42 def testTCPKaSelfGenerated(self):
43 """
44 TCP KeepAlive: Self-generated answer
45 """
46 name = 'refused.tcpka.tests.powerdns.com.'
47 query = dns.message.make_query(name, 'A', 'IN')
7af22479 48 query.flags &= ~dns.flags.RD
dcacff17
RG
49 expectedResponse = dns.message.make_response(query)
50 expectedResponse.set_rcode(dns.rcode.REFUSED)
51
52 conn = self.openTCPConnection()
53
54 count = 0
b4f23783 55 for idx in range(5):
dcacff17
RG
56 try:
57 self.sendTCPQueryOverConnection(conn, query)
58 response = self.recvTCPResponseOverConnection(conn)
59 if response is None:
60 break
61 self.assertEquals(expectedResponse, response)
62 count = count + 1
63 except:
64 pass
65
66 conn.close()
67 self.assertEqual(count, 5)
68
69 def testTCPKaCacheHit(self):
70 """
71 TCP KeepAlive: Cache Hit
72 """
73 name = 'cachehit.tcpka.tests.powerdns.com.'
74 query = dns.message.make_query(name, 'A', 'IN')
75 expectedResponse = dns.message.make_response(query)
76 rrset = dns.rrset.from_text(name,
77 3600,
78 dns.rdataclass.IN,
79 dns.rdatatype.A,
80 '192.0.2.1')
81 expectedResponse.answer.append(rrset)
82
83 # first query to fill the cache
84 (receivedQuery, receivedResponse) = self.sendTCPQuery(query, expectedResponse)
85 self.assertTrue(receivedQuery)
86 self.assertTrue(receivedResponse)
87 receivedQuery.id = query.id
88 self.assertEquals(query, receivedQuery)
89 self.assertEquals(receivedResponse, expectedResponse)
90
91 conn = self.openTCPConnection()
92
93 count = 0
b4f23783 94 for idx in range(5):
dcacff17
RG
95 try:
96 self.sendTCPQueryOverConnection(conn, query)
97 response = self.recvTCPResponseOverConnection(conn)
98 if response is None:
99 break
100 self.assertEquals(expectedResponse, response)
101 count = count + 1
102 except:
103 pass
104
105 conn.close()
106 self.assertEqual(count, 5)
107
108 def testTCPKaNoDownstreamServFail(self):
109 """
110 TCP KeepAlive: No downstream ServFail
111
112 The query is routed to a pool that has no server,
113 and dnsdist is configured to send a ServFail when
114 that happens. We should keep the TCP connection open.
115 """
116 name = 'nodownstream-servfail.tcpka.tests.powerdns.com.'
117 query = dns.message.make_query(name, 'A', 'IN')
118 expectedResponse = dns.message.make_response(query)
119 expectedResponse.set_rcode(dns.rcode.SERVFAIL)
120
121 conn = self.openTCPConnection()
122
123 count = 0
b4f23783 124 for idx in range(5):
dcacff17
RG
125 try:
126 self.sendTCPQueryOverConnection(conn, query)
127 response = self.recvTCPResponseOverConnection(conn)
128 if response is None:
129 break
130 self.assertEquals(expectedResponse, response)
131 count = count + 1
132 except:
133 pass
134
135 conn.close()
136 self.assertEqual(count, 5)
137
138 def testTCPKaQRBitSet(self):
139 """
140 TCP KeepAlive: QR bit set in question
141 """
142 name = 'qrset.tcpka.tests.powerdns.com.'
143 query = dns.message.make_query(name, 'A', 'IN')
144 query.flags |= dns.flags.QR
145
146 conn = self.openTCPConnection()
147
148 count = 0
b4f23783 149 for idx in range(5):
dcacff17
RG
150 try:
151 self.sendTCPQueryOverConnection(conn, query)
152 response = self.recvTCPResponseOverConnection(conn)
153 if response is None:
154 break
155 count = count + 1
156 except:
157 pass
158
159 conn.close()
160 self.assertEqual(count, 0)
161
162 def testTCPKaDrop(self):
163 """
164 TCP KeepAlive: Drop
165 """
166 name = 'dropped.tcpka.tests.powerdns.com.'
167 query = dns.message.make_query(name, 'A', 'IN')
168 query.flags |= dns.flags.QR
169
170 conn = self.openTCPConnection()
171
172 count = 0
b4f23783 173 for idx in range(5):
dcacff17
RG
174 try:
175 self.sendTCPQueryOverConnection(conn, query)
176 response = self.recvTCPResponseOverConnection(conn)
177 if response is None:
178 break
179 count = count + 1
180 except:
181 pass
182
183 conn.close()
184 self.assertEqual(count, 0)
185
186 def testTCPKaDropResponse(self):
187 """
188 TCP KeepAlive: Drop Response
189 """
190 name = 'dropped-response.tcpka.tests.powerdns.com.'
191 query = dns.message.make_query(name, 'A', 'IN')
192
193 conn = self.openTCPConnection()
194
195 count = 0
b4f23783 196 for idx in range(5):
dcacff17
RG
197 try:
198 self.sendTCPQueryOverConnection(conn, query)
199 response = self.recvTCPResponseOverConnection(conn)
200 if response is None:
201 break
202 count = count + 1
203 except:
204 pass
205
206 conn.close()
207 self.assertEqual(count, 0)
208
f0d9b6b7
RG
209 def testTCPKaLargeNumberOfConnections(self):
210 """
211 TCP KeepAlive: Large number of connections
212 """
213 name = 'largernumberofconnections.tcpka.tests.powerdns.com.'
214 query = dns.message.make_query(name, 'A', 'IN')
215 expectedResponse = dns.message.make_response(query)
216 #expectedResponse.set_rcode(dns.rcode.SERVFAIL)
217 rrset = dns.rrset.from_text(name,
218 3600,
219 dns.rdataclass.IN,
220 dns.rdatatype.A,
221 '192.0.2.1')
222 expectedResponse.answer.append(rrset)
223
224 # number of connections
225 numConns = 50
226 # number of queries per connections
227 numQueriesPerConn = 4
228
229 conns = []
230 start = time.time()
231 for idx in range(numConns):
232 conns.append(self.openTCPConnection())
233
234 count = 0
235 for idx in range(numConns * numQueriesPerConn):
236 try:
237 conn = conns[idx % numConns]
238 self.sendTCPQueryOverConnection(conn, query, response=expectedResponse)
239 response = self.recvTCPResponseOverConnection(conn)
240 if response is None:
241 break
242 self.assertEquals(expectedResponse, response)
243 count = count + 1
244 except:
245 pass
246
247 for con in conns:
248 conn.close()
249
250 self.assertEqual(count, numConns * numQueriesPerConn)
251
dcacff17
RG
252class TestTCPKeepAliveNoDownstreamDrop(DNSDistTest):
253 """
254 This test makes sure that dnsdist drops the TCP connection
255 if no downstream server is available and setServFailWhenNoServer()
256 is not set.
257 """
258
259 _tcpIdleTimeout = 20
260 _maxTCPQueriesPerConn = 99
261 _maxTCPConnsPerClient = 3
262 _maxTCPConnDuration = 99
263 _config_template = """
264 newServer{address="127.0.0.1:%s"}
265 setTCPRecvTimeout(%s)
266 setMaxTCPQueriesPerConnection(%s)
267 setMaxTCPConnectionsPerClient(%s)
268 setMaxTCPConnectionDuration(%s)
269 -- create the pool named "nosuchpool"
270 getPool("nosuchpool")
271 addAction("nodownstream-drop.tcpka.tests.powerdns.com.", PoolAction("nosuchpool"))
272 """
273 _config_params = ['_testServerPort', '_tcpIdleTimeout', '_maxTCPQueriesPerConn', '_maxTCPConnsPerClient', '_maxTCPConnDuration']
274
275 def testTCPKaNoDownstreamDrop(self):
276 """
277 TCP KeepAlive: No downstream Drop
278
279 The query is routed to a pool that has no server,
280 and dnsdist is configured to drop the query when
281 that happens. We should close the TCP connection right away.
282 """
283 name = 'nodownstream-drop.tcpka.tests.powerdns.com.'
284 query = dns.message.make_query(name, 'A', 'IN')
285
286 conn = self.openTCPConnection()
287
288 count = 0
b4f23783 289 for idx in range(5):
dcacff17
RG
290 try:
291 self.sendTCPQueryOverConnection(conn, query)
292 response = self.recvTCPResponseOverConnection(conn)
293 if response is None:
294 break
295 count = count + 1
296 except:
297 pass
298
299 conn.close()
300 self.assertEqual(count, 0)