]>
Commit | Line | Data |
---|---|---|
ca404e94 | 1 | /* |
6edbf68a PL |
2 | * This file is part of PowerDNS or dnsdist. |
3 | * Copyright -- PowerDNS.COM B.V. and its contributors | |
4 | * | |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of version 2 of the GNU General Public License as | |
7 | * published by the Free Software Foundation. | |
8 | * | |
9 | * In addition, for the avoidance of any doubt, permission is granted to | |
10 | * link this program with OpenSSL and to (re)distribute the binaries | |
11 | * produced as the result of such linking. | |
12 | * | |
13 | * This program is distributed in the hope that it will be useful, | |
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
16 | * GNU General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU General Public License | |
19 | * along with this program; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | |
21 | */ | |
ca404e94 RG |
22 | #define BOOST_TEST_DYN_LINK |
23 | #define BOOST_TEST_NO_MAIN | |
24 | ||
25 | #include <boost/test/unit_test.hpp> | |
26 | ||
27 | #include "dnsdist.hh" | |
28 | #include "dnsdist-ecs.hh" | |
29 | #include "dolog.hh" | |
30 | #include "dnsname.hh" | |
31 | #include "dnsparser.hh" | |
32 | #include "dnswriter.hh" | |
5c3b5e7f | 33 | #include "ednsoptions.hh" |
ff73f02b | 34 | #include "ednscookies.hh" |
ca404e94 RG |
35 | #include "ednssubnet.hh" |
36 | #include <unistd.h> | |
37 | ||
38 | BOOST_AUTO_TEST_SUITE(dnsdist_cc) | |
39 | ||
40 | bool g_console{true}; | |
bbfaaa6f | 41 | bool g_syslog{true}; |
ca404e94 RG |
42 | bool g_verbose{true}; |
43 | ||
ff0902ec RG |
44 | static const uint16_t ECSSourcePrefixV4 = 24; |
45 | static const uint16_t ECSSourcePrefixV6 = 56; | |
46 | ||
0beaa5c8 | 47 | static void validateQuery(const char * packet, size_t packetSize, bool hasEdns=true) |
ca404e94 | 48 | { |
27c0050c | 49 | MOADNSParser mdp(true, packet, packetSize); |
7b146b98 | 50 | |
ca404e94 RG |
51 | BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com."); |
52 | ||
53 | BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1); | |
54 | BOOST_CHECK_EQUAL(mdp.d_header.ancount, 0); | |
55 | BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0); | |
0beaa5c8 | 56 | BOOST_CHECK_EQUAL(mdp.d_header.arcount, (hasEdns ? 1 : 0)); |
ca404e94 RG |
57 | } |
58 | ||
ff73f02b | 59 | static void validateResponse(const char * packet, size_t packetSize, bool hasEdns, uint8_t additionalCount=0) |
7b146b98 | 60 | { |
27c0050c | 61 | MOADNSParser mdp(false, packet, packetSize); |
7b146b98 RG |
62 | |
63 | BOOST_CHECK_EQUAL(mdp.d_qname.toString(), "www.powerdns.com."); | |
64 | ||
65 | BOOST_CHECK_EQUAL(mdp.d_header.qr, 1); | |
66 | BOOST_CHECK_EQUAL(mdp.d_header.qdcount, 1); | |
67 | BOOST_CHECK_EQUAL(mdp.d_header.ancount, 1); | |
68 | BOOST_CHECK_EQUAL(mdp.d_header.nscount, 0); | |
ff73f02b | 69 | BOOST_CHECK_EQUAL(mdp.d_header.arcount, (hasEdns ? 1 : 0) + additionalCount); |
7b146b98 RG |
70 | } |
71 | ||
ca404e94 RG |
72 | BOOST_AUTO_TEST_CASE(addECSWithoutEDNS) |
73 | { | |
ca404e94 | 74 | bool ednsAdded = false; |
ff73f02b | 75 | bool ecsAdded = false; |
ca404e94 RG |
76 | ComboAddress remote; |
77 | DNSName name("www.powerdns.com."); | |
78 | ||
79 | vector<uint8_t> query; | |
7b146b98 | 80 | DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); |
ca404e94 | 81 | pw.getHeader()->rd = 1; |
ac688aff | 82 | uint16_t len = query.size(); |
7b146b98 | 83 | |
ca404e94 RG |
84 | /* large enough packet */ |
85 | char packet[1500]; | |
86 | memcpy(packet, query.data(), query.size()); | |
87 | ||
88 | unsigned int consumed = 0; | |
89 | uint16_t qtype; | |
90 | DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
91 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 RG |
92 | BOOST_CHECK(qtype == QType::A); |
93 | ||
0beaa5c8 | 94 | BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6)); |
ca404e94 | 95 | BOOST_CHECK((size_t) len > query.size()); |
ca404e94 | 96 | BOOST_CHECK_EQUAL(ednsAdded, true); |
ff73f02b | 97 | BOOST_CHECK_EQUAL(ecsAdded, false); |
ca404e94 | 98 | validateQuery(packet, len); |
7b146b98 | 99 | |
24c48018 | 100 | /* not large enough packet */ |
0beaa5c8 RG |
101 | ednsAdded = false; |
102 | ecsAdded = false; | |
ca404e94 RG |
103 | consumed = 0; |
104 | len = query.size(); | |
0beaa5c8 | 105 | qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed); |
ca404e94 | 106 | BOOST_CHECK_EQUAL(qname, name); |
7b146b98 RG |
107 | BOOST_CHECK(qtype == QType::A); |
108 | ||
0beaa5c8 | 109 | BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6)); |
ca404e94 | 110 | BOOST_CHECK_EQUAL((size_t) len, query.size()); |
0beaa5c8 | 111 | BOOST_CHECK_EQUAL(ednsAdded, false); |
ff73f02b | 112 | BOOST_CHECK_EQUAL(ecsAdded, false); |
0beaa5c8 | 113 | validateQuery(reinterpret_cast<char*>(query.data()), len, false); |
ca404e94 RG |
114 | } |
115 | ||
116 | BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECS) { | |
ca404e94 | 117 | bool ednsAdded = false; |
ff73f02b | 118 | bool ecsAdded = false; |
ca404e94 | 119 | ComboAddress remote; |
7b146b98 | 120 | DNSName name("www.powerdns.com."); |
ca404e94 RG |
121 | |
122 | vector<uint8_t> query; | |
7b146b98 | 123 | DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); |
ca404e94 RG |
124 | pw.getHeader()->rd = 1; |
125 | pw.addOpt(512, 0, 0); | |
126 | pw.commit(); | |
ac688aff | 127 | uint16_t len = query.size(); |
7b146b98 | 128 | |
ca404e94 RG |
129 | /* large enough packet */ |
130 | char packet[1500]; | |
131 | memcpy(packet, query.data(), query.size()); | |
132 | ||
133 | unsigned int consumed = 0; | |
134 | uint16_t qtype; | |
135 | DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
136 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 RG |
137 | BOOST_CHECK(qtype == QType::A); |
138 | ||
0beaa5c8 | 139 | BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6)); |
ca404e94 | 140 | BOOST_CHECK((size_t) len > query.size()); |
ca404e94 | 141 | BOOST_CHECK_EQUAL(ednsAdded, false); |
ff73f02b | 142 | BOOST_CHECK_EQUAL(ecsAdded, true); |
ca404e94 | 143 | validateQuery(packet, len); |
7b146b98 | 144 | |
24c48018 | 145 | /* not large enough packet */ |
ca404e94 | 146 | consumed = 0; |
0beaa5c8 RG |
147 | ednsAdded = false; |
148 | ecsAdded = false; | |
ca404e94 | 149 | len = query.size(); |
0beaa5c8 | 150 | qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed); |
ca404e94 | 151 | BOOST_CHECK_EQUAL(qname, name); |
7b146b98 RG |
152 | BOOST_CHECK(qtype == QType::A); |
153 | ||
0beaa5c8 | 154 | BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6)); |
ca404e94 | 155 | BOOST_CHECK_EQUAL((size_t) len, query.size()); |
ca404e94 | 156 | BOOST_CHECK_EQUAL(ednsAdded, false); |
0beaa5c8 RG |
157 | BOOST_CHECK_EQUAL(ecsAdded, false); |
158 | validateQuery(reinterpret_cast<char*>(query.data()), len); | |
ca404e94 RG |
159 | } |
160 | ||
161 | BOOST_AUTO_TEST_CASE(replaceECSWithSameSize) { | |
ca404e94 | 162 | bool ednsAdded = false; |
ff73f02b | 163 | bool ecsAdded = false; |
ca404e94 | 164 | ComboAddress remote("192.168.1.25"); |
7b146b98 | 165 | DNSName name("www.powerdns.com."); |
ca404e94 RG |
166 | ComboAddress origRemote("127.0.0.1"); |
167 | ||
168 | vector<uint8_t> query; | |
7b146b98 | 169 | DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); |
ca404e94 RG |
170 | pw.getHeader()->rd = 1; |
171 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 172 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ca404e94 RG |
173 | string origECSOption = makeEDNSSubnetOptsString(ecsOpts); |
174 | DNSPacketWriter::optvect_t opts; | |
5c3b5e7f | 175 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption)); |
ca404e94 RG |
176 | pw.addOpt(512, 0, 0, opts); |
177 | pw.commit(); | |
ac688aff | 178 | uint16_t len = query.size(); |
7b146b98 | 179 | |
ca404e94 RG |
180 | /* large enough packet */ |
181 | char packet[1500]; | |
182 | memcpy(packet, query.data(), query.size()); | |
183 | ||
184 | unsigned int consumed = 0; | |
185 | uint16_t qtype; | |
186 | DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
187 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 | 188 | BOOST_CHECK(qtype == QType::A); |
ca404e94 | 189 | |
0beaa5c8 | 190 | BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6)); |
ca404e94 | 191 | BOOST_CHECK_EQUAL((size_t) len, query.size()); |
ca404e94 | 192 | BOOST_CHECK_EQUAL(ednsAdded, false); |
ff73f02b | 193 | BOOST_CHECK_EQUAL(ecsAdded, false); |
ca404e94 RG |
194 | validateQuery(packet, len); |
195 | } | |
196 | ||
197 | BOOST_AUTO_TEST_CASE(replaceECSWithSmaller) { | |
ca404e94 | 198 | bool ednsAdded = false; |
ff73f02b | 199 | bool ecsAdded = false; |
ca404e94 | 200 | ComboAddress remote("192.168.1.25"); |
7b146b98 | 201 | DNSName name("www.powerdns.com."); |
ca404e94 RG |
202 | ComboAddress origRemote("127.0.0.1"); |
203 | ||
204 | vector<uint8_t> query; | |
7b146b98 | 205 | DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); |
ca404e94 RG |
206 | pw.getHeader()->rd = 1; |
207 | EDNSSubnetOpts ecsOpts; | |
208 | ecsOpts.source = Netmask(origRemote, 32); | |
209 | string origECSOption = makeEDNSSubnetOptsString(ecsOpts); | |
210 | DNSPacketWriter::optvect_t opts; | |
5c3b5e7f | 211 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption)); |
ca404e94 RG |
212 | pw.addOpt(512, 0, 0, opts); |
213 | pw.commit(); | |
ac688aff | 214 | uint16_t len = query.size(); |
7b146b98 | 215 | |
ca404e94 RG |
216 | /* large enough packet */ |
217 | char packet[1500]; | |
218 | memcpy(packet, query.data(), query.size()); | |
219 | ||
220 | unsigned int consumed = 0; | |
221 | uint16_t qtype; | |
222 | DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
223 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 | 224 | BOOST_CHECK(qtype == QType::A); |
ca404e94 | 225 | |
0beaa5c8 | 226 | BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6)); |
ca404e94 | 227 | BOOST_CHECK((size_t) len < query.size()); |
ca404e94 | 228 | BOOST_CHECK_EQUAL(ednsAdded, false); |
ff73f02b | 229 | BOOST_CHECK_EQUAL(ecsAdded, false); |
ca404e94 RG |
230 | validateQuery(packet, len); |
231 | } | |
232 | ||
233 | BOOST_AUTO_TEST_CASE(replaceECSWithLarger) { | |
ca404e94 | 234 | bool ednsAdded = false; |
ff73f02b | 235 | bool ecsAdded = false; |
ca404e94 | 236 | ComboAddress remote("192.168.1.25"); |
7b146b98 | 237 | DNSName name("www.powerdns.com."); |
ca404e94 RG |
238 | ComboAddress origRemote("127.0.0.1"); |
239 | ||
240 | vector<uint8_t> query; | |
7b146b98 | 241 | DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); |
ca404e94 RG |
242 | pw.getHeader()->rd = 1; |
243 | EDNSSubnetOpts ecsOpts; | |
244 | ecsOpts.source = Netmask(origRemote, 8); | |
245 | string origECSOption = makeEDNSSubnetOptsString(ecsOpts); | |
246 | DNSPacketWriter::optvect_t opts; | |
5c3b5e7f | 247 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption)); |
ca404e94 RG |
248 | pw.addOpt(512, 0, 0, opts); |
249 | pw.commit(); | |
ac688aff | 250 | uint16_t len = query.size(); |
7b146b98 | 251 | |
ca404e94 RG |
252 | /* large enough packet */ |
253 | char packet[1500]; | |
254 | memcpy(packet, query.data(), query.size()); | |
255 | ||
256 | unsigned int consumed = 0; | |
257 | uint16_t qtype; | |
258 | DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
259 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 | 260 | BOOST_CHECK(qtype == QType::A); |
ca404e94 | 261 | |
0beaa5c8 | 262 | BOOST_CHECK(handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6)); |
ca404e94 | 263 | BOOST_CHECK((size_t) len > query.size()); |
ca404e94 | 264 | BOOST_CHECK_EQUAL(ednsAdded, false); |
ff73f02b | 265 | BOOST_CHECK_EQUAL(ecsAdded, false); |
ca404e94 RG |
266 | validateQuery(packet, len); |
267 | ||
24c48018 | 268 | /* not large enough packet */ |
0beaa5c8 RG |
269 | ednsAdded = false; |
270 | ecsAdded = false; | |
ca404e94 RG |
271 | consumed = 0; |
272 | len = query.size(); | |
0beaa5c8 | 273 | qname = DNSName(reinterpret_cast<char*>(query.data()), len, sizeof(dnsheader), false, &qtype, NULL, &consumed); |
ca404e94 | 274 | BOOST_CHECK_EQUAL(qname, name); |
7b146b98 RG |
275 | BOOST_CHECK(qtype == QType::A); |
276 | ||
0beaa5c8 | 277 | BOOST_CHECK(!handleEDNSClientSubnet(reinterpret_cast<char*>(query.data()), query.size(), consumed, &len, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6)); |
ca404e94 | 278 | BOOST_CHECK_EQUAL((size_t) len, query.size()); |
ca404e94 | 279 | BOOST_CHECK_EQUAL(ednsAdded, false); |
ff73f02b | 280 | BOOST_CHECK_EQUAL(ecsAdded, false); |
0beaa5c8 | 281 | validateQuery(reinterpret_cast<char*>(query.data()), len); |
ca404e94 RG |
282 | } |
283 | ||
ff73f02b | 284 | BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst) { |
7b146b98 RG |
285 | DNSName name("www.powerdns.com."); |
286 | ||
287 | vector<uint8_t> response; | |
288 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
289 | pw.getHeader()->qr = 1; | |
290 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
291 | pw.xfr32BitInt(0x01020304); | |
292 | pw.addOpt(512, 0, 0); | |
293 | pw.commit(); | |
ff73f02b RG |
294 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); |
295 | pw.xfr32BitInt(0x01020304); | |
296 | pw.commit(); | |
7b146b98 RG |
297 | |
298 | vector<uint8_t> newResponse; | |
299 | int res = rewriteResponseWithoutEDNS((const char *) response.data(), response.size(), newResponse); | |
ff73f02b RG |
300 | BOOST_CHECK_EQUAL(res, 0); |
301 | ||
302 | unsigned int consumed = 0; | |
303 | uint16_t qtype; | |
304 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
305 | BOOST_CHECK_EQUAL(qname, name); | |
306 | BOOST_CHECK(qtype == QType::A); | |
307 | size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */; | |
308 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize); | |
309 | ||
310 | validateResponse((const char *) newResponse.data(), newResponse.size(), false, 1); | |
311 | } | |
312 | ||
313 | BOOST_AUTO_TEST_CASE(removeEDNSWhenIntermediary) { | |
314 | DNSName name("www.powerdns.com."); | |
315 | ||
316 | vector<uint8_t> response; | |
317 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
318 | pw.getHeader()->qr = 1; | |
319 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
320 | pw.xfr32BitInt(0x01020304); | |
321 | pw.startRecord(DNSName("other.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
322 | pw.xfr32BitInt(0x01020304); | |
323 | pw.commit(); | |
324 | pw.addOpt(512, 0, 0); | |
325 | pw.commit(); | |
326 | pw.startRecord(DNSName("yetanother.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
327 | pw.xfr32BitInt(0x01020304); | |
328 | pw.commit(); | |
7b146b98 | 329 | |
ff73f02b RG |
330 | vector<uint8_t> newResponse; |
331 | int res = rewriteResponseWithoutEDNS((const char *) response.data(), response.size(), newResponse); | |
7b146b98 RG |
332 | BOOST_CHECK_EQUAL(res, 0); |
333 | ||
334 | unsigned int consumed = 0; | |
335 | uint16_t qtype; | |
336 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
337 | BOOST_CHECK_EQUAL(qname, name); | |
338 | BOOST_CHECK(qtype == QType::A); | |
339 | size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */; | |
340 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize); | |
341 | ||
ff73f02b RG |
342 | validateResponse((const char *) newResponse.data(), newResponse.size(), false, 2); |
343 | } | |
344 | ||
345 | BOOST_AUTO_TEST_CASE(removeEDNSWhenLast) { | |
346 | DNSName name("www.powerdns.com."); | |
347 | ||
348 | vector<uint8_t> response; | |
349 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
350 | pw.getHeader()->qr = 1; | |
351 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
352 | pw.xfr32BitInt(0x01020304); | |
353 | pw.commit(); | |
354 | pw.startRecord(DNSName("other.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
355 | pw.xfr32BitInt(0x01020304); | |
356 | pw.commit(); | |
357 | pw.addOpt(512, 0, 0); | |
358 | pw.commit(); | |
359 | ||
360 | vector<uint8_t> newResponse; | |
361 | int res = rewriteResponseWithoutEDNS((const char *) response.data(), response.size(), newResponse); | |
362 | ||
363 | BOOST_CHECK_EQUAL(res, 0); | |
364 | ||
365 | unsigned int consumed = 0; | |
366 | uint16_t qtype; | |
367 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
368 | BOOST_CHECK_EQUAL(qname, name); | |
369 | BOOST_CHECK(qtype == QType::A); | |
370 | size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */; | |
371 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize); | |
372 | ||
373 | validateResponse((const char *) newResponse.data(), newResponse.size(), false, 1); | |
374 | } | |
375 | ||
376 | BOOST_AUTO_TEST_CASE(removeECSWhenOnlyOption) { | |
377 | DNSName name("www.powerdns.com."); | |
378 | ComboAddress origRemote("127.0.0.1"); | |
379 | ||
380 | vector<uint8_t> response; | |
381 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
382 | pw.getHeader()->qr = 1; | |
383 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
384 | pw.xfr32BitInt(0x01020304); | |
385 | ||
386 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
387 | pw.xfr32BitInt(0x01020304); | |
388 | pw.commit(); | |
389 | ||
390 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 391 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
392 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
393 | DNSPacketWriter::optvect_t opts; | |
394 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
395 | pw.addOpt(512, 0, 0, opts); | |
396 | pw.commit(); | |
397 | ||
398 | char * optStart = NULL; | |
399 | size_t optLen = 0; | |
400 | bool last = false; | |
401 | ||
402 | int res = locateEDNSOptRR((char *) response.data(), response.size(), &optStart, &optLen, &last); | |
403 | BOOST_CHECK_EQUAL(res, 0); | |
404 | BOOST_CHECK_EQUAL(last, true); | |
405 | ||
406 | size_t responseLen = response.size(); | |
407 | size_t existingOptLen = optLen; | |
408 | BOOST_CHECK(existingOptLen < responseLen); | |
409 | res = removeEDNSOptionFromOPT(optStart, &optLen, EDNSOptionCode::ECS); | |
410 | BOOST_CHECK_EQUAL(res, 0); | |
411 | BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4)); | |
412 | responseLen -= (existingOptLen - optLen); | |
413 | ||
414 | unsigned int consumed = 0; | |
415 | uint16_t qtype; | |
416 | DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
417 | BOOST_CHECK_EQUAL(qname, name); | |
418 | BOOST_CHECK(qtype == QType::A); | |
419 | ||
420 | validateResponse((const char *) response.data(), responseLen, true, 1); | |
421 | } | |
422 | ||
423 | BOOST_AUTO_TEST_CASE(removeECSWhenFirstOption) { | |
424 | DNSName name("www.powerdns.com."); | |
425 | ComboAddress origRemote("127.0.0.1"); | |
426 | ||
427 | vector<uint8_t> response; | |
428 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
429 | pw.getHeader()->qr = 1; | |
430 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
431 | pw.xfr32BitInt(0x01020304); | |
432 | ||
433 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
434 | pw.xfr32BitInt(0x01020304); | |
435 | pw.commit(); | |
436 | ||
437 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 438 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV6); |
ff73f02b RG |
439 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
440 | EDNSCookiesOpt cookiesOpt; | |
441 | cookiesOpt.client = string("deadbeef"); | |
442 | cookiesOpt.server = string("deadbeef"); | |
443 | string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt); | |
444 | DNSPacketWriter::optvect_t opts; | |
445 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
446 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr)); | |
447 | pw.addOpt(512, 0, 0, opts); | |
448 | pw.commit(); | |
449 | ||
450 | char * optStart = NULL; | |
451 | size_t optLen = 0; | |
452 | bool last = false; | |
453 | ||
454 | int res = locateEDNSOptRR((char *) response.data(), response.size(), &optStart, &optLen, &last); | |
455 | BOOST_CHECK_EQUAL(res, 0); | |
456 | BOOST_CHECK_EQUAL(last, true); | |
457 | ||
458 | size_t responseLen = response.size(); | |
459 | size_t existingOptLen = optLen; | |
460 | BOOST_CHECK(existingOptLen < responseLen); | |
461 | res = removeEDNSOptionFromOPT(optStart, &optLen, EDNSOptionCode::ECS); | |
462 | BOOST_CHECK_EQUAL(res, 0); | |
463 | BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4)); | |
464 | responseLen -= (existingOptLen - optLen); | |
465 | ||
466 | unsigned int consumed = 0; | |
467 | uint16_t qtype; | |
468 | DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
469 | BOOST_CHECK_EQUAL(qname, name); | |
470 | BOOST_CHECK(qtype == QType::A); | |
471 | ||
472 | validateResponse((const char *) response.data(), responseLen, true, 1); | |
473 | } | |
474 | ||
475 | BOOST_AUTO_TEST_CASE(removeECSWhenIntermediaryOption) { | |
476 | DNSName name("www.powerdns.com."); | |
477 | ComboAddress origRemote("127.0.0.1"); | |
478 | ||
479 | vector<uint8_t> response; | |
480 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
481 | pw.getHeader()->qr = 1; | |
482 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
483 | pw.xfr32BitInt(0x01020304); | |
484 | ||
485 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
486 | pw.xfr32BitInt(0x01020304); | |
487 | pw.commit(); | |
488 | ||
489 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 490 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
491 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
492 | ||
493 | EDNSCookiesOpt cookiesOpt; | |
494 | cookiesOpt.client = string("deadbeef"); | |
495 | cookiesOpt.server = string("deadbeef"); | |
496 | string cookiesOptionStr1 = makeEDNSCookiesOptString(cookiesOpt); | |
497 | string cookiesOptionStr2 = makeEDNSCookiesOptString(cookiesOpt); | |
498 | ||
499 | DNSPacketWriter::optvect_t opts; | |
500 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr1)); | |
501 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
502 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr2)); | |
503 | pw.addOpt(512, 0, 0, opts); | |
504 | pw.commit(); | |
505 | ||
506 | char * optStart = NULL; | |
507 | size_t optLen = 0; | |
508 | bool last = false; | |
509 | ||
510 | int res = locateEDNSOptRR((char *) response.data(), response.size(), &optStart, &optLen, &last); | |
511 | BOOST_CHECK_EQUAL(res, 0); | |
512 | BOOST_CHECK_EQUAL(last, true); | |
513 | ||
514 | size_t responseLen = response.size(); | |
515 | size_t existingOptLen = optLen; | |
516 | BOOST_CHECK(existingOptLen < responseLen); | |
517 | res = removeEDNSOptionFromOPT(optStart, &optLen, EDNSOptionCode::ECS); | |
518 | BOOST_CHECK_EQUAL(res, 0); | |
519 | BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4)); | |
520 | responseLen -= (existingOptLen - optLen); | |
521 | ||
522 | unsigned int consumed = 0; | |
523 | uint16_t qtype; | |
524 | DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
525 | BOOST_CHECK_EQUAL(qname, name); | |
526 | BOOST_CHECK(qtype == QType::A); | |
527 | ||
528 | validateResponse((const char *) response.data(), responseLen, true, 1); | |
529 | } | |
530 | ||
531 | BOOST_AUTO_TEST_CASE(removeECSWhenLastOption) { | |
532 | DNSName name("www.powerdns.com."); | |
533 | ComboAddress origRemote("127.0.0.1"); | |
534 | ||
535 | vector<uint8_t> response; | |
536 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
537 | pw.getHeader()->qr = 1; | |
538 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
539 | pw.xfr32BitInt(0x01020304); | |
540 | ||
541 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
542 | pw.xfr32BitInt(0x01020304); | |
543 | pw.commit(); | |
544 | ||
545 | EDNSCookiesOpt cookiesOpt; | |
546 | cookiesOpt.client = string("deadbeef"); | |
547 | cookiesOpt.server = string("deadbeef"); | |
548 | string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt); | |
549 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 550 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
551 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
552 | DNSPacketWriter::optvect_t opts; | |
553 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr)); | |
554 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
555 | pw.addOpt(512, 0, 0, opts); | |
556 | pw.commit(); | |
557 | ||
558 | char * optStart = NULL; | |
559 | size_t optLen = 0; | |
560 | bool last = false; | |
561 | ||
562 | int res = locateEDNSOptRR((char *) response.data(), response.size(), &optStart, &optLen, &last); | |
563 | BOOST_CHECK_EQUAL(res, 0); | |
564 | BOOST_CHECK_EQUAL(last, true); | |
565 | ||
566 | size_t responseLen = response.size(); | |
567 | size_t existingOptLen = optLen; | |
568 | BOOST_CHECK(existingOptLen < responseLen); | |
569 | res = removeEDNSOptionFromOPT(optStart, &optLen, EDNSOptionCode::ECS); | |
570 | BOOST_CHECK_EQUAL(res, 0); | |
571 | BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4)); | |
572 | responseLen -= (existingOptLen - optLen); | |
573 | ||
574 | unsigned int consumed = 0; | |
575 | uint16_t qtype; | |
576 | DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
577 | BOOST_CHECK_EQUAL(qname, name); | |
578 | BOOST_CHECK(qtype == QType::A); | |
579 | ||
580 | validateResponse((const char *) response.data(), responseLen, true, 1); | |
581 | } | |
582 | ||
583 | BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenOnlyOption) { | |
584 | DNSName name("www.powerdns.com."); | |
585 | ComboAddress origRemote("127.0.0.1"); | |
586 | ||
587 | vector<uint8_t> response; | |
588 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
589 | pw.getHeader()->qr = 1; | |
590 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
591 | pw.xfr32BitInt(0x01020304); | |
592 | ||
593 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 594 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
595 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
596 | DNSPacketWriter::optvect_t opts; | |
597 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
598 | pw.addOpt(512, 0, 0, opts); | |
599 | pw.commit(); | |
600 | ||
601 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
602 | pw.xfr32BitInt(0x01020304); | |
603 | pw.commit(); | |
604 | ||
605 | vector<uint8_t> newResponse; | |
606 | int res = rewriteResponseWithoutEDNSOption((const char *) response.data(), response.size(), EDNSOptionCode::ECS, newResponse); | |
607 | BOOST_CHECK_EQUAL(res, 0); | |
608 | ||
609 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4)); | |
610 | ||
611 | unsigned int consumed = 0; | |
612 | uint16_t qtype; | |
613 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
614 | BOOST_CHECK_EQUAL(qname, name); | |
615 | BOOST_CHECK(qtype == QType::A); | |
616 | ||
617 | validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1); | |
618 | } | |
619 | ||
620 | BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenFirstOption) { | |
621 | DNSName name("www.powerdns.com."); | |
622 | ComboAddress origRemote("127.0.0.1"); | |
623 | ||
624 | vector<uint8_t> response; | |
625 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
626 | pw.getHeader()->qr = 1; | |
627 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
628 | pw.xfr32BitInt(0x01020304); | |
629 | ||
630 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 631 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
632 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
633 | EDNSCookiesOpt cookiesOpt; | |
634 | cookiesOpt.client = string("deadbeef"); | |
635 | cookiesOpt.server = string("deadbeef"); | |
636 | string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt); | |
637 | DNSPacketWriter::optvect_t opts; | |
638 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
639 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr)); | |
640 | pw.addOpt(512, 0, 0, opts); | |
641 | pw.commit(); | |
642 | ||
643 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
644 | pw.xfr32BitInt(0x01020304); | |
645 | pw.commit(); | |
646 | ||
647 | vector<uint8_t> newResponse; | |
648 | int res = rewriteResponseWithoutEDNSOption((const char *) response.data(), response.size(), EDNSOptionCode::ECS, newResponse); | |
649 | BOOST_CHECK_EQUAL(res, 0); | |
650 | ||
651 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4)); | |
652 | ||
653 | unsigned int consumed = 0; | |
654 | uint16_t qtype; | |
655 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
656 | BOOST_CHECK_EQUAL(qname, name); | |
657 | BOOST_CHECK(qtype == QType::A); | |
658 | ||
659 | validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1); | |
660 | } | |
661 | ||
662 | BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenIntermediaryOption) { | |
663 | DNSName name("www.powerdns.com."); | |
664 | ComboAddress origRemote("127.0.0.1"); | |
665 | ||
666 | vector<uint8_t> response; | |
667 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
668 | pw.getHeader()->qr = 1; | |
669 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
670 | pw.xfr32BitInt(0x01020304); | |
671 | ||
672 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 673 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
674 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
675 | EDNSCookiesOpt cookiesOpt; | |
676 | cookiesOpt.client = string("deadbeef"); | |
677 | cookiesOpt.server = string("deadbeef"); | |
678 | string cookiesOptionStr1 = makeEDNSCookiesOptString(cookiesOpt); | |
679 | string cookiesOptionStr2 = makeEDNSCookiesOptString(cookiesOpt); | |
680 | DNSPacketWriter::optvect_t opts; | |
681 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr1)); | |
682 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
683 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr2)); | |
684 | pw.addOpt(512, 0, 0, opts); | |
685 | pw.commit(); | |
686 | ||
687 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
688 | pw.xfr32BitInt(0x01020304); | |
689 | pw.commit(); | |
690 | ||
691 | vector<uint8_t> newResponse; | |
692 | int res = rewriteResponseWithoutEDNSOption((const char *) response.data(), response.size(), EDNSOptionCode::ECS, newResponse); | |
693 | BOOST_CHECK_EQUAL(res, 0); | |
694 | ||
695 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4)); | |
696 | ||
697 | unsigned int consumed = 0; | |
698 | uint16_t qtype; | |
699 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
700 | BOOST_CHECK_EQUAL(qname, name); | |
701 | BOOST_CHECK(qtype == QType::A); | |
702 | ||
703 | validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1); | |
704 | } | |
705 | ||
706 | BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption) { | |
707 | DNSName name("www.powerdns.com."); | |
708 | ComboAddress origRemote("127.0.0.1"); | |
709 | ||
710 | vector<uint8_t> response; | |
711 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
712 | pw.getHeader()->qr = 1; | |
713 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
714 | pw.xfr32BitInt(0x01020304); | |
715 | ||
716 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 717 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
718 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
719 | EDNSCookiesOpt cookiesOpt; | |
720 | cookiesOpt.client = string("deadbeef"); | |
721 | cookiesOpt.server = string("deadbeef"); | |
722 | string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt); | |
723 | DNSPacketWriter::optvect_t opts; | |
724 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr)); | |
725 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
726 | pw.addOpt(512, 0, 0, opts); | |
727 | pw.commit(); | |
728 | ||
729 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
730 | pw.xfr32BitInt(0x01020304); | |
731 | pw.commit(); | |
732 | ||
733 | vector<uint8_t> newResponse; | |
734 | int res = rewriteResponseWithoutEDNSOption((const char *) response.data(), response.size(), EDNSOptionCode::ECS, newResponse); | |
735 | BOOST_CHECK_EQUAL(res, 0); | |
736 | ||
737 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4)); | |
738 | ||
739 | unsigned int consumed = 0; | |
740 | uint16_t qtype; | |
741 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
742 | BOOST_CHECK_EQUAL(qname, name); | |
743 | BOOST_CHECK(qtype == QType::A); | |
744 | ||
745 | validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1); | |
7b146b98 RG |
746 | } |
747 | ||
ca404e94 | 748 | BOOST_AUTO_TEST_SUITE_END(); |