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