]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/test-packetcache_hh.cc
Merge pull request #7537 from andreydomas/dnsnameset
[thirdparty/pdns.git] / pdns / test-packetcache_hh.cc
1 #define BOOST_TEST_DYN_LINK
2 #define BOOST_TEST_NO_MAIN
3
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
7 #include <boost/test/unit_test.hpp>
8
9 #include "dnswriter.hh"
10 #include "dnsrecords.hh"
11 #include "ednscookies.hh"
12 #include "ednssubnet.hh"
13 #include "packetcache.hh"
14
15 BOOST_AUTO_TEST_SUITE(packetcache_hh)
16
17 BOOST_AUTO_TEST_CASE(test_PacketCacheAuthCollision) {
18
19 /* auth version (ECS is not processed, we just hash the whole query except for the ID, while lowercasing the qname) */
20 const DNSName qname("www.powerdns.com.");
21 uint16_t qtype = QType::AAAA;
22 EDNSSubnetOpts opt;
23 DNSPacketWriter::optvect_t ednsOptions;
24
25 {
26 /* same query, different IDs */
27 vector<uint8_t> packet;
28 DNSPacketWriter pw1(packet, qname, qtype);
29 pw1.getHeader()->rd = true;
30 pw1.getHeader()->qr = false;
31 pw1.getHeader()->id = 0x42;
32 string spacket1((const char*)&packet[0], packet.size());
33 auto hash1 = PacketCache::canHashPacket(spacket1);
34
35 packet.clear();
36 DNSPacketWriter pw2(packet, qname, qtype);
37 pw2.getHeader()->rd = true;
38 pw2.getHeader()->qr = false;
39 pw2.getHeader()->id = 0x84;
40 string spacket2((const char*)&packet[0], packet.size());
41 auto hash2 = PacketCache::canHashPacket(spacket2);
42
43 BOOST_CHECK_EQUAL(hash1, hash2);
44 BOOST_CHECK(PacketCache::queryMatches(spacket1, spacket2, qname));
45 }
46
47 {
48 /* same query, different IDs, different ECS, still hashes to the same value */
49 vector<uint8_t> packet;
50 DNSPacketWriter pw1(packet, qname, qtype);
51 pw1.getHeader()->rd = true;
52 pw1.getHeader()->qr = false;
53 pw1.getHeader()->id = 0x42;
54 opt.source = Netmask("10.0.18.199/32");
55 ednsOptions.clear();
56 ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
57 pw1.addOpt(512, 0, 0, ednsOptions);
58 pw1.commit();
59
60 string spacket1((const char*)&packet[0], packet.size());
61 auto hash1 = PacketCache::canHashPacket(spacket1);
62
63 packet.clear();
64 DNSPacketWriter pw2(packet, qname, qtype);
65 pw2.getHeader()->rd = true;
66 pw2.getHeader()->qr = false;
67 pw2.getHeader()->id = 0x84;
68 opt.source = Netmask("10.0.131.66/32");
69 ednsOptions.clear();
70 ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
71 pw2.addOpt(512, 0, 0, ednsOptions);
72 pw2.commit();
73
74 string spacket2((const char*)&packet[0], packet.size());
75 auto hash2 = PacketCache::canHashPacket(spacket2);
76
77 BOOST_CHECK_EQUAL(hash1, hash2);
78 /* the hash is the same but we should _not_ match */
79 BOOST_CHECK(!PacketCache::queryMatches(spacket1, spacket2, qname));
80 }
81
82 {
83 /* same query but one has DNSSECOK, not the other, different IDs, different ECS, still hashes to the same value */
84 vector<uint8_t> packet;
85 DNSPacketWriter pw1(packet, qname, qtype);
86 pw1.getHeader()->rd = true;
87 pw1.getHeader()->qr = false;
88 pw1.getHeader()->id = 0x42;
89 opt.source = Netmask("47.8.0.0/32");
90 ednsOptions.clear();
91 ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
92 pw1.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
93 pw1.commit();
94
95 string spacket1((const char*)&packet[0], packet.size());
96 auto hash1 = PacketCache::canHashPacket(spacket1);
97
98 packet.clear();
99 DNSPacketWriter pw2(packet, qname, qtype);
100 pw2.getHeader()->rd = true;
101 pw2.getHeader()->qr = false;
102 pw2.getHeader()->id = 0x84;
103 opt.source = Netmask("18.43.1.0/32");
104 ednsOptions.clear();
105 ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
106 /* no EDNSOpts::DNSSECOK !! */
107 pw2.addOpt(512, 0, 0, ednsOptions);
108 pw2.commit();
109
110 string spacket2((const char*)&packet[0], packet.size());
111 auto hash2 = PacketCache::canHashPacket(spacket2);
112
113 BOOST_CHECK_EQUAL(hash1, hash2);
114 /* the hash is the same but we should _not_ match */
115 BOOST_CHECK(!PacketCache::queryMatches(spacket1, spacket2, qname));
116 }
117
118 {
119 /* same query but different cookies, still hashes to the same value */
120 vector<uint8_t> packet;
121 DNSPacketWriter pw1(packet, qname, qtype);
122 pw1.getHeader()->rd = true;
123 pw1.getHeader()->qr = false;
124 pw1.getHeader()->id = 0x42;
125 opt.source = Netmask("192.0.2.1/32");
126 ednsOptions.clear();
127 ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
128 EDNSCookiesOpt cookiesOpt;
129 cookiesOpt.client = string("deadbeef");
130 cookiesOpt.server = string("deadbeef");
131 cookiesOpt.server[4] = -42;
132 cookiesOpt.server[5] = -6;
133 cookiesOpt.server[6] = 1;
134 cookiesOpt.server[7] = 0;
135 ednsOptions.push_back(std::make_pair(EDNSOptionCode::COOKIE, makeEDNSCookiesOptString(cookiesOpt)));
136 pw1.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
137 pw1.commit();
138
139 string spacket1((const char*)&packet[0], packet.size());
140 auto hash1 = PacketCache::canHashPacket(spacket1);
141
142 packet.clear();
143 DNSPacketWriter pw2(packet, qname, qtype);
144 pw2.getHeader()->rd = true;
145 pw2.getHeader()->qr = false;
146 pw2.getHeader()->id = 0x84;
147 opt.source = Netmask("192.0.2.1/32");
148 ednsOptions.clear();
149 ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
150 cookiesOpt.client = string("deadbeef");
151 cookiesOpt.server = string("deadbeef");
152 cookiesOpt.server[4] = 29;
153 cookiesOpt.server[5] = -79;
154 cookiesOpt.server[6] = 1;
155 cookiesOpt.server[7] = 0;
156 ednsOptions.push_back(std::make_pair(EDNSOptionCode::COOKIE, makeEDNSCookiesOptString(cookiesOpt)));
157 pw2.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
158 pw2.commit();
159
160 string spacket2((const char*)&packet[0], packet.size());
161 auto hash2 = PacketCache::canHashPacket(spacket2);
162
163 BOOST_CHECK_EQUAL(hash1, hash2);
164 /* the hash is the same but we should _not_ match */
165 BOOST_CHECK(!PacketCache::queryMatches(spacket1, spacket2, qname));
166 }
167 }
168
169 BOOST_AUTO_TEST_CASE(test_PacketCacheRecSimple) {
170
171 const DNSName qname("www.powerdns.com.");
172 uint16_t qtype = QType::AAAA;
173 EDNSSubnetOpts opt;
174 DNSPacketWriter::optvect_t ednsOptions;
175 uint16_t ecsBegin;
176 uint16_t ecsEnd;
177
178 {
179 vector<uint8_t> packet;
180 DNSPacketWriter pw1(packet, qname, qtype);
181 pw1.getHeader()->rd = true;
182 pw1.getHeader()->qr = false;
183 pw1.getHeader()->id = 0x42;
184 pw1.addOpt(512, 0, 0);
185 pw1.commit();
186
187 string spacket1((const char*)&packet[0], packet.size());
188 /* set the RD length to a large value */
189 unsigned char* ptr = reinterpret_cast<unsigned char*>(&spacket1.at(sizeof(dnsheader) + qname.wirelength() + /* qtype and qclass */ 4 + /* OPT root label (1), type (2), class (2) and ttl (4) */ 9));
190 *ptr = 255;
191 *(ptr + 1) = 255;
192 /* truncate the end of the OPT header to try to trigger an out of bounds read */
193 spacket1.resize(spacket1.size() - 6);
194 PacketCache::canHashPacket(spacket1, &ecsBegin, &ecsEnd);
195 /* no ECS */
196 BOOST_CHECK_EQUAL(ecsBegin, 0);
197 BOOST_CHECK_EQUAL(ecsEnd, 0);
198 }
199 }
200
201 BOOST_AUTO_TEST_CASE(test_PacketCacheRecCollision) {
202
203 /* rec version (ECS is processed, we hash the whole query except for the ID and the ECS value, while lowercasing the qname) */
204 const DNSName qname("www.powerdns.com.");
205 uint16_t qtype = QType::AAAA;
206 EDNSSubnetOpts opt;
207 DNSPacketWriter::optvect_t ednsOptions;
208 uint16_t ecsBegin;
209 uint16_t ecsEnd;
210
211 {
212 /* same query, different IDs */
213 vector<uint8_t> packet;
214 DNSPacketWriter pw1(packet, qname, qtype);
215 pw1.getHeader()->rd = true;
216 pw1.getHeader()->qr = false;
217 pw1.getHeader()->id = 0x42;
218 string spacket1((const char*)&packet[0], packet.size());
219 auto hash1 = PacketCache::canHashPacket(spacket1, &ecsBegin, &ecsEnd);
220 /* no ECS */
221 BOOST_CHECK_EQUAL(ecsBegin, 0);
222 BOOST_CHECK_EQUAL(ecsEnd, 0);
223
224 packet.clear();
225 DNSPacketWriter pw2(packet, qname, qtype);
226 pw2.getHeader()->rd = true;
227 pw2.getHeader()->qr = false;
228 pw2.getHeader()->id = 0x84;
229 string spacket2((const char*)&packet[0], packet.size());
230 auto hash2 = PacketCache::canHashPacket(spacket2, &ecsBegin, &ecsEnd);
231 /* no ECS */
232 BOOST_CHECK_EQUAL(ecsBegin, 0);
233 BOOST_CHECK_EQUAL(ecsEnd, 0);
234
235 BOOST_CHECK_EQUAL(hash1, hash2);
236 BOOST_CHECK(PacketCache::queryMatches(spacket1, spacket2, qname, ecsBegin, ecsEnd));
237 }
238
239 {
240 /* same query, different IDs, different ECS, still hashes to the same value */
241 vector<uint8_t> packet;
242 DNSPacketWriter pw1(packet, qname, qtype);
243 pw1.getHeader()->rd = true;
244 pw1.getHeader()->qr = false;
245 pw1.getHeader()->id = 0x42;
246 opt.source = Netmask("10.0.18.199/32");
247 ednsOptions.clear();
248 ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
249 pw1.addOpt(512, 0, 0, ednsOptions);
250 pw1.commit();
251
252 string spacket1((const char*)&packet[0], packet.size());
253 auto hash1 = PacketCache::canHashPacket(spacket1, &ecsBegin, &ecsEnd);
254 /* ECS value */
255 BOOST_CHECK_EQUAL(ecsBegin, sizeof(dnsheader) + qname.wirelength() + ( 2 * sizeof(uint16_t)) /* qtype */ + (2 * sizeof(uint16_t)) /* qclass */ + /* OPT root label */ 1 + sizeof(uint32_t) /* TTL */ + DNS_RDLENGTH_SIZE);
256 BOOST_CHECK_EQUAL(ecsEnd, ecsBegin + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE + 2 /* family */ + 1 /* scope length */ + 1 /* source length */ + 4 /* IPv4 */);
257
258 packet.clear();
259 DNSPacketWriter pw2(packet, qname, qtype);
260 pw2.getHeader()->rd = true;
261 pw2.getHeader()->qr = false;
262 pw2.getHeader()->id = 0x84;
263 opt.source = Netmask("10.0.131.66/32");
264 ednsOptions.clear();
265 ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
266 pw2.addOpt(512, 0, 0, ednsOptions);
267 pw2.commit();
268
269 string spacket2((const char*)&packet[0], packet.size());
270 auto hash2 = PacketCache::canHashPacket(spacket2, &ecsBegin, &ecsEnd);
271 /* ECS value */
272 BOOST_CHECK_EQUAL(ecsBegin, sizeof(dnsheader) + qname.wirelength() + ( 2 * sizeof(uint16_t)) /* qtype */ + (2 * sizeof(uint16_t)) /* qclass */ + /* OPT root label */ 1 + sizeof(uint32_t) /* TTL */ + DNS_RDLENGTH_SIZE);
273 BOOST_CHECK_EQUAL(ecsEnd, ecsBegin + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE + 2 /* family */ + 1 /* scope length */ + 1 /* source length */ + 4 /* IPv4 */);
274
275 BOOST_CHECK_EQUAL(hash1, hash2);
276 /* the hash is the same and we don't hash the ECS so we should match */
277 BOOST_CHECK(PacketCache::queryMatches(spacket1, spacket2, qname, ecsBegin, ecsEnd));
278 }
279
280 {
281 /* same query but different cookies, still hashes to the same value */
282 vector<uint8_t> packet;
283 DNSPacketWriter pw1(packet, qname, qtype);
284 pw1.getHeader()->rd = true;
285 pw1.getHeader()->qr = false;
286 pw1.getHeader()->id = 0x42;
287 opt.source = Netmask("192.0.2.1/32");
288 ednsOptions.clear();
289 ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
290 EDNSCookiesOpt cookiesOpt;
291 cookiesOpt.client = string("deadbeef");
292 cookiesOpt.server = string("deadbeef");
293 cookiesOpt.server[4] = -20;
294 cookiesOpt.server[5] = -114;
295 cookiesOpt.server[6] = 0;
296 cookiesOpt.server[7] = 0;
297 ednsOptions.push_back(std::make_pair(EDNSOptionCode::COOKIE, makeEDNSCookiesOptString(cookiesOpt)));
298 pw1.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
299 pw1.commit();
300
301 string spacket1((const char*)&packet[0], packet.size());
302 auto hash1 = PacketCache::canHashPacket(spacket1, &ecsBegin, &ecsEnd);
303 /* ECS value */
304 BOOST_CHECK_EQUAL(ecsBegin, sizeof(dnsheader) + qname.wirelength() + ( 2 * sizeof(uint16_t)) /* qtype */ + (2 * sizeof(uint16_t)) /* qclass */ + /* OPT root label */ 1 + sizeof(uint32_t) /* TTL */ + DNS_RDLENGTH_SIZE);
305 BOOST_CHECK_EQUAL(ecsEnd, ecsBegin + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE + 2 /* family */ + 1 /* scope length */ + 1 /* source length */ + 4 /* IPv4 */);
306
307 packet.clear();
308 DNSPacketWriter pw2(packet, qname, qtype);
309 pw2.getHeader()->rd = true;
310 pw2.getHeader()->qr = false;
311 pw2.getHeader()->id = 0x84;
312 opt.source = Netmask("192.0.2.1/32");
313 ednsOptions.clear();
314 ednsOptions.push_back(std::make_pair(EDNSOptionCode::ECS, makeEDNSSubnetOptsString(opt)));
315 cookiesOpt.client = string("deadbeef");
316 cookiesOpt.server = string("deadbeef");
317 cookiesOpt.server[4] = 103;
318 cookiesOpt.server[5] = 68;
319 cookiesOpt.server[6] = 0;
320 cookiesOpt.server[7] = 0;
321 ednsOptions.push_back(std::make_pair(EDNSOptionCode::COOKIE, makeEDNSCookiesOptString(cookiesOpt)));
322 pw2.addOpt(512, 0, EDNSOpts::DNSSECOK, ednsOptions);
323 pw2.commit();
324
325 string spacket2((const char*)&packet[0], packet.size());
326 auto hash2 = PacketCache::canHashPacket(spacket2, &ecsBegin, &ecsEnd);
327 /* ECS value */
328 BOOST_CHECK_EQUAL(ecsBegin, sizeof(dnsheader) + qname.wirelength() + ( 2 * sizeof(uint16_t)) /* qtype */ + (2 * sizeof(uint16_t)) /* qclass */ + /* OPT root label */ 1 + sizeof(uint32_t) /* TTL */ + DNS_RDLENGTH_SIZE);
329 BOOST_CHECK_EQUAL(ecsEnd, ecsBegin + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE + 2 /* family */ + 1 /* scope length */ + 1 /* source length */ + 4 /* IPv4 */);
330
331 BOOST_CHECK_EQUAL(hash1, hash2);
332 /* the hash is the same but we should _not_ match, even though we skip the ECS part, because the cookies are different */
333 BOOST_CHECK(!PacketCache::queryMatches(spacket1, spacket2, qname, ecsBegin, ecsEnd));
334 }
335 }
336
337 BOOST_AUTO_TEST_SUITE_END()