Skip to content

Commit 8f33ac1

Browse files
authored
Merge pull request #16102 from rgacogne/ddist20-backport-16065
dnsdist-2.0.x: Backport 16065 - Test that the configuration is correctly reloaded in various cases
2 parents 696955c + 0c7c9bb commit 8f33ac1

File tree

2 files changed

+248
-2
lines changed

2 files changed

+248
-2
lines changed

pdns/dnsdistdist/dnsdist.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -792,8 +792,6 @@ void responderThread(std::shared_ptr<DownstreamState> dss)
792792
break;
793793
}
794794

795-
dnsdist::configuration::refreshLocalRuntimeConfiguration();
796-
797795
for (const auto& sockDesc : sockets) {
798796
/* allocate one more byte so we can detect truncation */
799797
// NOLINTNEXTLINE(bugprone-use-after-move): resizing a vector has no preconditions so it is valid to do so after moving it
@@ -822,6 +820,7 @@ void responderThread(std::shared_ptr<DownstreamState> dss)
822820
continue;
823821
}
824822

823+
dnsdist::configuration::refreshLocalRuntimeConfiguration();
825824
if (processResponderPacket(dss, response, std::move(*ids)) && ids->isXSK() && ids->cs->xskInfoResponder) {
826825
#ifdef HAVE_XSK
827826
auto& xskInfo = ids->cs->xskInfoResponder;
Lines changed: 247 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,247 @@
1+
#!/usr/bin/env python
2+
import base64
3+
import dns
4+
import time
5+
from dnsdisttests import DNSDistTest, pickAvailablePort
6+
import extendederrors
7+
8+
class TestConfigurationUpdates(DNSDistTest):
9+
_yaml_config_template = """---
10+
console:
11+
listen_address: "127.0.0.1:%d"
12+
key: "%s"
13+
acl:
14+
- 127.0.0.0/8
15+
16+
binds:
17+
- listen_address: "127.0.0.1:%d"
18+
protocol: Do53
19+
- listen_address: "127.0.0.1:%d"
20+
protocol: "DoT"
21+
tls:
22+
certificates:
23+
- certificate: "%s"
24+
key: "%s"
25+
provider: "openssl"
26+
- listen_address: "127.0.0.1:%d"
27+
protocol: "DoH"
28+
tls:
29+
certificates:
30+
- certificate: "%s"
31+
key: "%s"
32+
doh:
33+
provider: "nghttp2"
34+
paths:
35+
- "/"
36+
- listen_address: "127.0.0.1:%d"
37+
protocol: "DoQ"
38+
tls:
39+
certificates:
40+
- certificate: "%s"
41+
key: "%s"
42+
- listen_address: "127.0.0.1:%d"
43+
protocol: "DoH3"
44+
tls:
45+
certificates:
46+
- certificate: "%s"
47+
key: "%s"
48+
49+
backends:
50+
- address: "127.0.0.1:%d"
51+
protocol: Do53
52+
- address: "127.0.0.1:%d"
53+
protocol: Do53
54+
tcp_only: true
55+
pools:
56+
- "tcp-pool"
57+
58+
query_rules:
59+
- name: "route TCP response test to the TCP-only pool"
60+
selector:
61+
type: "QName"
62+
qname: "TCP-response.config-updates.test.powerdns.com."
63+
action:
64+
type: "Pool"
65+
pool_name: "tcp-pool"
66+
"""
67+
_dnsDistPort = pickAvailablePort()
68+
_tlsServerPort = pickAvailablePort()
69+
_dohWithNGHTTP2ServerPort = pickAvailablePort()
70+
_doqServerPort = pickAvailablePort()
71+
_doh3ServerPort = pickAvailablePort()
72+
_serverKey = 'server.key'
73+
_serverCert = 'server.chain'
74+
_serverName = 'tls.tests.dnsdist.org'
75+
_dohWithNGHTTP2BaseURL = ("https://%s:%d/" % (_serverName, _dohWithNGHTTP2ServerPort))
76+
_dohBaseURL = ("https://%s:%d/" % (_serverName, _doh3ServerPort))
77+
_caCert = 'ca.pem'
78+
_consoleKey = DNSDistTest.generateConsoleKey()
79+
_consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
80+
_consolePort = pickAvailablePort()
81+
_testServerPort = pickAvailablePort()
82+
_yaml_config_params = ['_consolePort', '_consoleKeyB64', '_dnsDistPort', '_tlsServerPort', '_serverCert', '_serverKey', '_dohWithNGHTTP2ServerPort', '_serverCert', '_serverKey', '_doqServerPort','_serverCert', '_serverKey', '_doh3ServerPort', '_serverCert', '_serverKey', '_testServerPort', '_testServerPort']
83+
_config_params = []
84+
_checkConfigExpectedOutput = b"DNS over HTTPS configured\nConfiguration 'configs/dnsdist_TestConfigurationUpdates.yml' OK!\n"
85+
86+
def testRegular(self):
87+
"""
88+
Configuration updates: regular
89+
"""
90+
for protocol in ['UDP', 'TCP', 'DOT', 'DOH', 'DOQ', 'DOH3']:
91+
name = f'regular-{protocol}.config-updates.test.powerdns.com.'
92+
query = dns.message.make_query(name, 'A', 'IN')
93+
query.flags &= ~dns.flags.RD
94+
response = dns.message.make_response(query)
95+
rrset = dns.rrset.from_text(name,
96+
60,
97+
dns.rdataclass.IN,
98+
dns.rdatatype.A,
99+
'127.0.0.1')
100+
101+
response.answer.append(rrset)
102+
103+
method = f'send{protocol}Query'
104+
if not protocol in ['UDP', 'TCP']:
105+
if protocol == 'DOH':
106+
method = 'sendDOHWithNGHTTP2QueryWrapper'
107+
else:
108+
method += 'Wrapper'
109+
sender = getattr(self, method)
110+
111+
(receivedQuery, receivedResponse) = sender(query, response=response)
112+
receivedQuery.id = query.id
113+
self.assertEqual(receivedQuery, query)
114+
self.assertEqual(receivedResponse, response)
115+
116+
self.sendConsoleCommand(f'addAction(QNameRule("{name}"), RCodeAction(DNSRCode.REFUSED))')
117+
118+
# the configuration should have been updated
119+
response = dns.message.make_response(query)
120+
response.set_rcode(dns.rcode.REFUSED)
121+
(_, receivedResponse) = sender(query, response=None, useQueue=False)
122+
self.assertEqual(receivedResponse, response)
123+
124+
def testResponseRule(self):
125+
"""
126+
Configuration updates: response
127+
"""
128+
for protocol in ['UDP', 'TCP']:
129+
name = f'{protocol}-response.config-updates.test.powerdns.com.'
130+
query = dns.message.make_query(name, 'A', 'IN')
131+
query.flags &= ~dns.flags.RD
132+
response = dns.message.make_response(query)
133+
rrset = dns.rrset.from_text(name,
134+
60,
135+
dns.rdataclass.IN,
136+
dns.rdatatype.A,
137+
'127.0.0.1')
138+
139+
response.answer.append(rrset)
140+
141+
method = f'send{protocol}Query'
142+
sender = getattr(self, method)
143+
144+
(receivedQuery, receivedResponse) = sender(query, response=response)
145+
receivedQuery.id = query.id
146+
self.assertEqual(receivedQuery, query)
147+
self.assertEqual(receivedResponse, response)
148+
149+
self.sendConsoleCommand(f'addResponseAction(QNameRule("{name}"), SetExtendedDNSErrorResponseAction(15))')
150+
if protocol == 'TCP':
151+
time.sleep(1)
152+
153+
# the configuration should have been updated
154+
expectedResponse = dns.message.make_response(query)
155+
ede = extendederrors.ExtendedErrorOption(15, b'')
156+
expectedResponse.use_edns(edns=True, payload=4096, options=[ede])
157+
expectedResponse.answer.append(rrset)
158+
(_, receivedResponse) = sender(query, response=response)
159+
self.assertEqual(receivedResponse, expectedResponse)
160+
161+
class TestConfigurationUpdatesRecvMMSG(DNSDistTest):
162+
_yaml_config_template = """---
163+
console:
164+
listen_address: "127.0.0.1:%d"
165+
key: "%s"
166+
acl:
167+
- 127.0.0.0/8
168+
169+
binds:
170+
- listen_address: "127.0.0.1:%d"
171+
protocol: Do53
172+
173+
backends:
174+
- address: "127.0.0.1:%d"
175+
protocol: Do53
176+
177+
tuning:
178+
udp:
179+
messages_per_round: 10
180+
"""
181+
_dnsDistPort = pickAvailablePort()
182+
_consoleKey = DNSDistTest.generateConsoleKey()
183+
_consoleKeyB64 = base64.b64encode(_consoleKey).decode('ascii')
184+
_consolePort = pickAvailablePort()
185+
_testServerPort = pickAvailablePort()
186+
_yaml_config_params = ['_consolePort', '_consoleKeyB64', '_dnsDistPort', '_testServerPort']
187+
_config_params = []
188+
189+
def testRecvMMSGUDP(self):
190+
"""
191+
Configuration updates: recvmmsg UDP
192+
"""
193+
name = 'recvmmsg-udp.config-updates.test.powerdns.com.'
194+
query = dns.message.make_query(name, 'A', 'IN')
195+
query.flags &= ~dns.flags.RD
196+
response = dns.message.make_response(query)
197+
rrset = dns.rrset.from_text(name,
198+
60,
199+
dns.rdataclass.IN,
200+
dns.rdatatype.A,
201+
'127.0.0.1')
202+
203+
response.answer.append(rrset)
204+
205+
(receivedQuery, receivedResponse) = self.sendUDPQuery(query, response=response)
206+
receivedQuery.id = query.id
207+
self.assertEqual(receivedQuery, query)
208+
self.assertEqual(receivedResponse, response)
209+
210+
self.sendConsoleCommand(f'addAction(QNameRule("{name}"), RCodeAction(DNSRCode.REFUSED))')
211+
212+
# the configuration should have been updated
213+
response = dns.message.make_response(query)
214+
response.set_rcode(dns.rcode.REFUSED)
215+
(_, receivedResponse) = self.sendUDPQuery(query, response=None, useQueue=False)
216+
self.assertEqual(receivedResponse, response)
217+
218+
def testUDPResponseRule(self):
219+
"""
220+
Configuration updates: UDP response
221+
"""
222+
name = 'recvmmsg-udp-response.config-updates.test.powerdns.com.'
223+
query = dns.message.make_query(name, 'A', 'IN')
224+
query.flags &= ~dns.flags.RD
225+
response = dns.message.make_response(query)
226+
rrset = dns.rrset.from_text(name,
227+
60,
228+
dns.rdataclass.IN,
229+
dns.rdatatype.A,
230+
'127.0.0.1')
231+
232+
response.answer.append(rrset)
233+
234+
(receivedQuery, receivedResponse) = self.sendUDPQuery(query, response=response)
235+
receivedQuery.id = query.id
236+
self.assertEqual(receivedQuery, query)
237+
self.assertEqual(receivedResponse, response)
238+
239+
self.sendConsoleCommand(f'addResponseAction(QNameRule("{name}"), SetExtendedDNSErrorResponseAction(15))')
240+
241+
# the configuration should have been updated
242+
expectedResponse = dns.message.make_response(query)
243+
ede = extendederrors.ExtendedErrorOption(15, b'')
244+
expectedResponse.use_edns(edns=True, payload=4096, options=[ede])
245+
expectedResponse.answer.append(rrset)
246+
(_, receivedResponse) = self.sendUDPQuery(query, response=response)
247+
self.assertEqual(receivedResponse, expectedResponse)

0 commit comments

Comments
 (0)