]>
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 | ||
ca404e94 RG |
47 | static void validateQuery(const char * packet, size_t packetSize) |
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); | |
56 | BOOST_CHECK_EQUAL(mdp.d_header.arcount, 1); | |
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 | { | |
74 | string largerPacket; | |
75 | bool ednsAdded = false; | |
ff73f02b | 76 | bool ecsAdded = false; |
ca404e94 RG |
77 | ComboAddress remote; |
78 | DNSName name("www.powerdns.com."); | |
79 | ||
80 | vector<uint8_t> query; | |
7b146b98 | 81 | DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); |
ca404e94 | 82 | pw.getHeader()->rd = 1; |
ac688aff | 83 | uint16_t len = query.size(); |
7b146b98 | 84 | |
ca404e94 RG |
85 | /* large enough packet */ |
86 | char packet[1500]; | |
87 | memcpy(packet, query.data(), query.size()); | |
88 | ||
89 | unsigned int consumed = 0; | |
90 | uint16_t qtype; | |
91 | DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
92 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 RG |
93 | BOOST_CHECK(qtype == QType::A); |
94 | ||
ff0902ec | 95 | handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6); |
ca404e94 RG |
96 | BOOST_CHECK((size_t) len > query.size()); |
97 | BOOST_CHECK_EQUAL(largerPacket.size(), 0); | |
98 | BOOST_CHECK_EQUAL(ednsAdded, true); | |
ff73f02b | 99 | BOOST_CHECK_EQUAL(ecsAdded, false); |
ca404e94 | 100 | validateQuery(packet, len); |
7b146b98 | 101 | |
24c48018 | 102 | /* not large enough packet */ |
ca404e94 RG |
103 | consumed = 0; |
104 | len = query.size(); | |
105 | qname = DNSName((char*) query.data(), len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
106 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 RG |
107 | BOOST_CHECK(qtype == QType::A); |
108 | ||
ff0902ec | 109 | handleEDNSClientSubnet((char*) query.data(), query.size(), consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6); |
ca404e94 RG |
110 | BOOST_CHECK_EQUAL((size_t) len, query.size()); |
111 | BOOST_CHECK(largerPacket.size() > query.size()); | |
112 | BOOST_CHECK_EQUAL(ednsAdded, true); | |
ff73f02b | 113 | BOOST_CHECK_EQUAL(ecsAdded, false); |
ca404e94 RG |
114 | validateQuery(largerPacket.c_str(), largerPacket.size()); |
115 | } | |
116 | ||
117 | BOOST_AUTO_TEST_CASE(addECSWithEDNSNoECS) { | |
118 | string largerPacket; | |
119 | bool ednsAdded = false; | |
ff73f02b | 120 | bool ecsAdded = false; |
ca404e94 | 121 | ComboAddress remote; |
7b146b98 | 122 | DNSName name("www.powerdns.com."); |
ca404e94 RG |
123 | |
124 | vector<uint8_t> query; | |
7b146b98 | 125 | DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); |
ca404e94 RG |
126 | pw.getHeader()->rd = 1; |
127 | pw.addOpt(512, 0, 0); | |
128 | pw.commit(); | |
ac688aff | 129 | uint16_t len = query.size(); |
7b146b98 | 130 | |
ca404e94 RG |
131 | /* large enough packet */ |
132 | char packet[1500]; | |
133 | memcpy(packet, query.data(), query.size()); | |
134 | ||
135 | unsigned int consumed = 0; | |
136 | uint16_t qtype; | |
137 | DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
138 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 RG |
139 | BOOST_CHECK(qtype == QType::A); |
140 | ||
ff0902ec | 141 | handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6); |
ca404e94 RG |
142 | BOOST_CHECK((size_t) len > query.size()); |
143 | BOOST_CHECK_EQUAL(largerPacket.size(), 0); | |
144 | BOOST_CHECK_EQUAL(ednsAdded, false); | |
ff73f02b | 145 | BOOST_CHECK_EQUAL(ecsAdded, true); |
ca404e94 | 146 | validateQuery(packet, len); |
7b146b98 | 147 | |
24c48018 | 148 | /* not large enough packet */ |
ca404e94 RG |
149 | consumed = 0; |
150 | len = query.size(); | |
151 | qname = DNSName((char*) query.data(), len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
152 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 RG |
153 | BOOST_CHECK(qtype == QType::A); |
154 | ||
ff0902ec | 155 | handleEDNSClientSubnet((char*) query.data(), query.size(), consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, false, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6); |
ca404e94 RG |
156 | BOOST_CHECK_EQUAL((size_t) len, query.size()); |
157 | BOOST_CHECK(largerPacket.size() > query.size()); | |
158 | BOOST_CHECK_EQUAL(ednsAdded, false); | |
ff73f02b | 159 | BOOST_CHECK_EQUAL(ecsAdded, true); |
ca404e94 RG |
160 | validateQuery(largerPacket.c_str(), largerPacket.size()); |
161 | } | |
162 | ||
163 | BOOST_AUTO_TEST_CASE(replaceECSWithSameSize) { | |
164 | string largerPacket; | |
165 | bool ednsAdded = false; | |
ff73f02b | 166 | bool ecsAdded = false; |
ca404e94 | 167 | ComboAddress remote("192.168.1.25"); |
7b146b98 | 168 | DNSName name("www.powerdns.com."); |
ca404e94 RG |
169 | ComboAddress origRemote("127.0.0.1"); |
170 | ||
171 | vector<uint8_t> query; | |
7b146b98 | 172 | DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); |
ca404e94 RG |
173 | pw.getHeader()->rd = 1; |
174 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 175 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ca404e94 RG |
176 | string origECSOption = makeEDNSSubnetOptsString(ecsOpts); |
177 | DNSPacketWriter::optvect_t opts; | |
5c3b5e7f | 178 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption)); |
ca404e94 RG |
179 | pw.addOpt(512, 0, 0, opts); |
180 | pw.commit(); | |
ac688aff | 181 | uint16_t len = query.size(); |
7b146b98 | 182 | |
ca404e94 RG |
183 | /* large enough packet */ |
184 | char packet[1500]; | |
185 | memcpy(packet, query.data(), query.size()); | |
186 | ||
187 | unsigned int consumed = 0; | |
188 | uint16_t qtype; | |
189 | DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
190 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 | 191 | BOOST_CHECK(qtype == QType::A); |
ca404e94 | 192 | |
ff0902ec | 193 | handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6); |
ca404e94 RG |
194 | BOOST_CHECK_EQUAL((size_t) len, query.size()); |
195 | BOOST_CHECK_EQUAL(largerPacket.size(), 0); | |
196 | BOOST_CHECK_EQUAL(ednsAdded, false); | |
ff73f02b | 197 | BOOST_CHECK_EQUAL(ecsAdded, false); |
ca404e94 RG |
198 | validateQuery(packet, len); |
199 | } | |
200 | ||
201 | BOOST_AUTO_TEST_CASE(replaceECSWithSmaller) { | |
202 | string largerPacket; | |
203 | bool ednsAdded = false; | |
ff73f02b | 204 | bool ecsAdded = false; |
ca404e94 | 205 | ComboAddress remote("192.168.1.25"); |
7b146b98 | 206 | DNSName name("www.powerdns.com."); |
ca404e94 RG |
207 | ComboAddress origRemote("127.0.0.1"); |
208 | ||
209 | vector<uint8_t> query; | |
7b146b98 | 210 | DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); |
ca404e94 RG |
211 | pw.getHeader()->rd = 1; |
212 | EDNSSubnetOpts ecsOpts; | |
213 | ecsOpts.source = Netmask(origRemote, 32); | |
214 | string origECSOption = makeEDNSSubnetOptsString(ecsOpts); | |
215 | DNSPacketWriter::optvect_t opts; | |
5c3b5e7f | 216 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption)); |
ca404e94 RG |
217 | pw.addOpt(512, 0, 0, opts); |
218 | pw.commit(); | |
ac688aff | 219 | uint16_t len = query.size(); |
7b146b98 | 220 | |
ca404e94 RG |
221 | /* large enough packet */ |
222 | char packet[1500]; | |
223 | memcpy(packet, query.data(), query.size()); | |
224 | ||
225 | unsigned int consumed = 0; | |
226 | uint16_t qtype; | |
227 | DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
228 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 | 229 | BOOST_CHECK(qtype == QType::A); |
ca404e94 | 230 | |
ff0902ec | 231 | handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6); |
ca404e94 RG |
232 | BOOST_CHECK((size_t) len < query.size()); |
233 | BOOST_CHECK_EQUAL(largerPacket.size(), 0); | |
234 | BOOST_CHECK_EQUAL(ednsAdded, false); | |
ff73f02b | 235 | BOOST_CHECK_EQUAL(ecsAdded, false); |
ca404e94 RG |
236 | validateQuery(packet, len); |
237 | } | |
238 | ||
239 | BOOST_AUTO_TEST_CASE(replaceECSWithLarger) { | |
240 | string largerPacket; | |
241 | bool ednsAdded = false; | |
ff73f02b | 242 | bool ecsAdded = false; |
ca404e94 | 243 | ComboAddress remote("192.168.1.25"); |
7b146b98 | 244 | DNSName name("www.powerdns.com."); |
ca404e94 RG |
245 | ComboAddress origRemote("127.0.0.1"); |
246 | ||
247 | vector<uint8_t> query; | |
7b146b98 | 248 | DNSPacketWriter pw(query, name, QType::A, QClass::IN, 0); |
ca404e94 RG |
249 | pw.getHeader()->rd = 1; |
250 | EDNSSubnetOpts ecsOpts; | |
251 | ecsOpts.source = Netmask(origRemote, 8); | |
252 | string origECSOption = makeEDNSSubnetOptsString(ecsOpts); | |
253 | DNSPacketWriter::optvect_t opts; | |
5c3b5e7f | 254 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOption)); |
ca404e94 RG |
255 | pw.addOpt(512, 0, 0, opts); |
256 | pw.commit(); | |
ac688aff | 257 | uint16_t len = query.size(); |
7b146b98 | 258 | |
ca404e94 RG |
259 | /* large enough packet */ |
260 | char packet[1500]; | |
261 | memcpy(packet, query.data(), query.size()); | |
262 | ||
263 | unsigned int consumed = 0; | |
264 | uint16_t qtype; | |
265 | DNSName qname(packet, len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
266 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 | 267 | BOOST_CHECK(qtype == QType::A); |
ca404e94 | 268 | |
ff0902ec | 269 | handleEDNSClientSubnet(packet, sizeof packet, consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6); |
ca404e94 RG |
270 | BOOST_CHECK((size_t) len > query.size()); |
271 | BOOST_CHECK_EQUAL(largerPacket.size(), 0); | |
272 | BOOST_CHECK_EQUAL(ednsAdded, false); | |
ff73f02b | 273 | BOOST_CHECK_EQUAL(ecsAdded, false); |
ca404e94 RG |
274 | validateQuery(packet, len); |
275 | ||
24c48018 | 276 | /* not large enough packet */ |
ca404e94 RG |
277 | consumed = 0; |
278 | len = query.size(); | |
279 | qname = DNSName((char*) query.data(), len, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
280 | BOOST_CHECK_EQUAL(qname, name); | |
7b146b98 RG |
281 | BOOST_CHECK(qtype == QType::A); |
282 | ||
ff0902ec | 283 | handleEDNSClientSubnet((char*) query.data(), query.size(), consumed, &len, largerPacket, &ednsAdded, &ecsAdded, remote, true, remote.sin4.sin_family == AF_INET ? ECSSourcePrefixV4 : ECSSourcePrefixV6); |
ca404e94 RG |
284 | BOOST_CHECK_EQUAL((size_t) len, query.size()); |
285 | BOOST_CHECK(largerPacket.size() > query.size()); | |
286 | BOOST_CHECK_EQUAL(ednsAdded, false); | |
ff73f02b | 287 | BOOST_CHECK_EQUAL(ecsAdded, false); |
ca404e94 RG |
288 | validateQuery(largerPacket.c_str(), largerPacket.size()); |
289 | } | |
290 | ||
ff73f02b | 291 | BOOST_AUTO_TEST_CASE(removeEDNSWhenFirst) { |
7b146b98 RG |
292 | DNSName name("www.powerdns.com."); |
293 | ||
294 | vector<uint8_t> response; | |
295 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
296 | pw.getHeader()->qr = 1; | |
297 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
298 | pw.xfr32BitInt(0x01020304); | |
299 | pw.addOpt(512, 0, 0); | |
300 | pw.commit(); | |
ff73f02b RG |
301 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); |
302 | pw.xfr32BitInt(0x01020304); | |
303 | pw.commit(); | |
7b146b98 RG |
304 | |
305 | vector<uint8_t> newResponse; | |
306 | int res = rewriteResponseWithoutEDNS((const char *) response.data(), response.size(), newResponse); | |
ff73f02b RG |
307 | BOOST_CHECK_EQUAL(res, 0); |
308 | ||
309 | unsigned int consumed = 0; | |
310 | uint16_t qtype; | |
311 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
312 | BOOST_CHECK_EQUAL(qname, name); | |
313 | BOOST_CHECK(qtype == QType::A); | |
314 | size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */; | |
315 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize); | |
316 | ||
317 | validateResponse((const char *) newResponse.data(), newResponse.size(), false, 1); | |
318 | } | |
319 | ||
320 | BOOST_AUTO_TEST_CASE(removeEDNSWhenIntermediary) { | |
321 | DNSName name("www.powerdns.com."); | |
322 | ||
323 | vector<uint8_t> response; | |
324 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
325 | pw.getHeader()->qr = 1; | |
326 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
327 | pw.xfr32BitInt(0x01020304); | |
328 | pw.startRecord(DNSName("other.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
329 | pw.xfr32BitInt(0x01020304); | |
330 | pw.commit(); | |
331 | pw.addOpt(512, 0, 0); | |
332 | pw.commit(); | |
333 | pw.startRecord(DNSName("yetanother.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
334 | pw.xfr32BitInt(0x01020304); | |
335 | pw.commit(); | |
7b146b98 | 336 | |
ff73f02b RG |
337 | vector<uint8_t> newResponse; |
338 | int res = rewriteResponseWithoutEDNS((const char *) response.data(), response.size(), newResponse); | |
7b146b98 RG |
339 | BOOST_CHECK_EQUAL(res, 0); |
340 | ||
341 | unsigned int consumed = 0; | |
342 | uint16_t qtype; | |
343 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
344 | BOOST_CHECK_EQUAL(qname, name); | |
345 | BOOST_CHECK(qtype == QType::A); | |
346 | size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */; | |
347 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize); | |
348 | ||
ff73f02b RG |
349 | validateResponse((const char *) newResponse.data(), newResponse.size(), false, 2); |
350 | } | |
351 | ||
352 | BOOST_AUTO_TEST_CASE(removeEDNSWhenLast) { | |
353 | DNSName name("www.powerdns.com."); | |
354 | ||
355 | vector<uint8_t> response; | |
356 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
357 | pw.getHeader()->qr = 1; | |
358 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
359 | pw.xfr32BitInt(0x01020304); | |
360 | pw.commit(); | |
361 | pw.startRecord(DNSName("other.powerdns.com."), QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
362 | pw.xfr32BitInt(0x01020304); | |
363 | pw.commit(); | |
364 | pw.addOpt(512, 0, 0); | |
365 | pw.commit(); | |
366 | ||
367 | vector<uint8_t> newResponse; | |
368 | int res = rewriteResponseWithoutEDNS((const char *) response.data(), response.size(), newResponse); | |
369 | ||
370 | BOOST_CHECK_EQUAL(res, 0); | |
371 | ||
372 | unsigned int consumed = 0; | |
373 | uint16_t qtype; | |
374 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
375 | BOOST_CHECK_EQUAL(qname, name); | |
376 | BOOST_CHECK(qtype == QType::A); | |
377 | size_t const ednsOptRRSize = sizeof(struct dnsrecordheader) + 1 /* root in OPT RR */; | |
378 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - ednsOptRRSize); | |
379 | ||
380 | validateResponse((const char *) newResponse.data(), newResponse.size(), false, 1); | |
381 | } | |
382 | ||
383 | BOOST_AUTO_TEST_CASE(removeECSWhenOnlyOption) { | |
384 | DNSName name("www.powerdns.com."); | |
385 | ComboAddress origRemote("127.0.0.1"); | |
386 | ||
387 | vector<uint8_t> response; | |
388 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
389 | pw.getHeader()->qr = 1; | |
390 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
391 | pw.xfr32BitInt(0x01020304); | |
392 | ||
393 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
394 | pw.xfr32BitInt(0x01020304); | |
395 | pw.commit(); | |
396 | ||
397 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 398 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
399 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
400 | DNSPacketWriter::optvect_t opts; | |
401 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
402 | pw.addOpt(512, 0, 0, opts); | |
403 | pw.commit(); | |
404 | ||
405 | char * optStart = NULL; | |
406 | size_t optLen = 0; | |
407 | bool last = false; | |
408 | ||
409 | int res = locateEDNSOptRR((char *) response.data(), response.size(), &optStart, &optLen, &last); | |
410 | BOOST_CHECK_EQUAL(res, 0); | |
411 | BOOST_CHECK_EQUAL(last, true); | |
412 | ||
413 | size_t responseLen = response.size(); | |
414 | size_t existingOptLen = optLen; | |
415 | BOOST_CHECK(existingOptLen < responseLen); | |
416 | res = removeEDNSOptionFromOPT(optStart, &optLen, EDNSOptionCode::ECS); | |
417 | BOOST_CHECK_EQUAL(res, 0); | |
418 | BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4)); | |
419 | responseLen -= (existingOptLen - optLen); | |
420 | ||
421 | unsigned int consumed = 0; | |
422 | uint16_t qtype; | |
423 | DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
424 | BOOST_CHECK_EQUAL(qname, name); | |
425 | BOOST_CHECK(qtype == QType::A); | |
426 | ||
427 | validateResponse((const char *) response.data(), responseLen, true, 1); | |
428 | } | |
429 | ||
430 | BOOST_AUTO_TEST_CASE(removeECSWhenFirstOption) { | |
431 | DNSName name("www.powerdns.com."); | |
432 | ComboAddress origRemote("127.0.0.1"); | |
433 | ||
434 | vector<uint8_t> response; | |
435 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
436 | pw.getHeader()->qr = 1; | |
437 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
438 | pw.xfr32BitInt(0x01020304); | |
439 | ||
440 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
441 | pw.xfr32BitInt(0x01020304); | |
442 | pw.commit(); | |
443 | ||
444 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 445 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV6); |
ff73f02b RG |
446 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
447 | EDNSCookiesOpt cookiesOpt; | |
448 | cookiesOpt.client = string("deadbeef"); | |
449 | cookiesOpt.server = string("deadbeef"); | |
450 | string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt); | |
451 | DNSPacketWriter::optvect_t opts; | |
452 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
453 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr)); | |
454 | pw.addOpt(512, 0, 0, opts); | |
455 | pw.commit(); | |
456 | ||
457 | char * optStart = NULL; | |
458 | size_t optLen = 0; | |
459 | bool last = false; | |
460 | ||
461 | int res = locateEDNSOptRR((char *) response.data(), response.size(), &optStart, &optLen, &last); | |
462 | BOOST_CHECK_EQUAL(res, 0); | |
463 | BOOST_CHECK_EQUAL(last, true); | |
464 | ||
465 | size_t responseLen = response.size(); | |
466 | size_t existingOptLen = optLen; | |
467 | BOOST_CHECK(existingOptLen < responseLen); | |
468 | res = removeEDNSOptionFromOPT(optStart, &optLen, EDNSOptionCode::ECS); | |
469 | BOOST_CHECK_EQUAL(res, 0); | |
470 | BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4)); | |
471 | responseLen -= (existingOptLen - optLen); | |
472 | ||
473 | unsigned int consumed = 0; | |
474 | uint16_t qtype; | |
475 | DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
476 | BOOST_CHECK_EQUAL(qname, name); | |
477 | BOOST_CHECK(qtype == QType::A); | |
478 | ||
479 | validateResponse((const char *) response.data(), responseLen, true, 1); | |
480 | } | |
481 | ||
482 | BOOST_AUTO_TEST_CASE(removeECSWhenIntermediaryOption) { | |
483 | DNSName name("www.powerdns.com."); | |
484 | ComboAddress origRemote("127.0.0.1"); | |
485 | ||
486 | vector<uint8_t> response; | |
487 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
488 | pw.getHeader()->qr = 1; | |
489 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
490 | pw.xfr32BitInt(0x01020304); | |
491 | ||
492 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
493 | pw.xfr32BitInt(0x01020304); | |
494 | pw.commit(); | |
495 | ||
496 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 497 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
498 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
499 | ||
500 | EDNSCookiesOpt cookiesOpt; | |
501 | cookiesOpt.client = string("deadbeef"); | |
502 | cookiesOpt.server = string("deadbeef"); | |
503 | string cookiesOptionStr1 = makeEDNSCookiesOptString(cookiesOpt); | |
504 | string cookiesOptionStr2 = makeEDNSCookiesOptString(cookiesOpt); | |
505 | ||
506 | DNSPacketWriter::optvect_t opts; | |
507 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr1)); | |
508 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
509 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr2)); | |
510 | pw.addOpt(512, 0, 0, opts); | |
511 | pw.commit(); | |
512 | ||
513 | char * optStart = NULL; | |
514 | size_t optLen = 0; | |
515 | bool last = false; | |
516 | ||
517 | int res = locateEDNSOptRR((char *) response.data(), response.size(), &optStart, &optLen, &last); | |
518 | BOOST_CHECK_EQUAL(res, 0); | |
519 | BOOST_CHECK_EQUAL(last, true); | |
520 | ||
521 | size_t responseLen = response.size(); | |
522 | size_t existingOptLen = optLen; | |
523 | BOOST_CHECK(existingOptLen < responseLen); | |
524 | res = removeEDNSOptionFromOPT(optStart, &optLen, EDNSOptionCode::ECS); | |
525 | BOOST_CHECK_EQUAL(res, 0); | |
526 | BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4)); | |
527 | responseLen -= (existingOptLen - optLen); | |
528 | ||
529 | unsigned int consumed = 0; | |
530 | uint16_t qtype; | |
531 | DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
532 | BOOST_CHECK_EQUAL(qname, name); | |
533 | BOOST_CHECK(qtype == QType::A); | |
534 | ||
535 | validateResponse((const char *) response.data(), responseLen, true, 1); | |
536 | } | |
537 | ||
538 | BOOST_AUTO_TEST_CASE(removeECSWhenLastOption) { | |
539 | DNSName name("www.powerdns.com."); | |
540 | ComboAddress origRemote("127.0.0.1"); | |
541 | ||
542 | vector<uint8_t> response; | |
543 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
544 | pw.getHeader()->qr = 1; | |
545 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
546 | pw.xfr32BitInt(0x01020304); | |
547 | ||
548 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
549 | pw.xfr32BitInt(0x01020304); | |
550 | pw.commit(); | |
551 | ||
552 | EDNSCookiesOpt cookiesOpt; | |
553 | cookiesOpt.client = string("deadbeef"); | |
554 | cookiesOpt.server = string("deadbeef"); | |
555 | string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt); | |
556 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 557 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
558 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
559 | DNSPacketWriter::optvect_t opts; | |
560 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr)); | |
561 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
562 | pw.addOpt(512, 0, 0, opts); | |
563 | pw.commit(); | |
564 | ||
565 | char * optStart = NULL; | |
566 | size_t optLen = 0; | |
567 | bool last = false; | |
568 | ||
569 | int res = locateEDNSOptRR((char *) response.data(), response.size(), &optStart, &optLen, &last); | |
570 | BOOST_CHECK_EQUAL(res, 0); | |
571 | BOOST_CHECK_EQUAL(last, true); | |
572 | ||
573 | size_t responseLen = response.size(); | |
574 | size_t existingOptLen = optLen; | |
575 | BOOST_CHECK(existingOptLen < responseLen); | |
576 | res = removeEDNSOptionFromOPT(optStart, &optLen, EDNSOptionCode::ECS); | |
577 | BOOST_CHECK_EQUAL(res, 0); | |
578 | BOOST_CHECK_EQUAL(optLen, existingOptLen - (origECSOptionStr.size() + 4)); | |
579 | responseLen -= (existingOptLen - optLen); | |
580 | ||
581 | unsigned int consumed = 0; | |
582 | uint16_t qtype; | |
583 | DNSName qname((const char*) response.data(), responseLen, sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
584 | BOOST_CHECK_EQUAL(qname, name); | |
585 | BOOST_CHECK(qtype == QType::A); | |
586 | ||
587 | validateResponse((const char *) response.data(), responseLen, true, 1); | |
588 | } | |
589 | ||
590 | BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenOnlyOption) { | |
591 | DNSName name("www.powerdns.com."); | |
592 | ComboAddress origRemote("127.0.0.1"); | |
593 | ||
594 | vector<uint8_t> response; | |
595 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
596 | pw.getHeader()->qr = 1; | |
597 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
598 | pw.xfr32BitInt(0x01020304); | |
599 | ||
600 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 601 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
602 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
603 | DNSPacketWriter::optvect_t opts; | |
604 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
605 | pw.addOpt(512, 0, 0, opts); | |
606 | pw.commit(); | |
607 | ||
608 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
609 | pw.xfr32BitInt(0x01020304); | |
610 | pw.commit(); | |
611 | ||
612 | vector<uint8_t> newResponse; | |
613 | int res = rewriteResponseWithoutEDNSOption((const char *) response.data(), response.size(), EDNSOptionCode::ECS, newResponse); | |
614 | BOOST_CHECK_EQUAL(res, 0); | |
615 | ||
616 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4)); | |
617 | ||
618 | unsigned int consumed = 0; | |
619 | uint16_t qtype; | |
620 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
621 | BOOST_CHECK_EQUAL(qname, name); | |
622 | BOOST_CHECK(qtype == QType::A); | |
623 | ||
624 | validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1); | |
625 | } | |
626 | ||
627 | BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenFirstOption) { | |
628 | DNSName name("www.powerdns.com."); | |
629 | ComboAddress origRemote("127.0.0.1"); | |
630 | ||
631 | vector<uint8_t> response; | |
632 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
633 | pw.getHeader()->qr = 1; | |
634 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
635 | pw.xfr32BitInt(0x01020304); | |
636 | ||
637 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 638 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
639 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
640 | EDNSCookiesOpt cookiesOpt; | |
641 | cookiesOpt.client = string("deadbeef"); | |
642 | cookiesOpt.server = string("deadbeef"); | |
643 | string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt); | |
644 | DNSPacketWriter::optvect_t opts; | |
645 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
646 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr)); | |
647 | pw.addOpt(512, 0, 0, opts); | |
648 | pw.commit(); | |
649 | ||
650 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
651 | pw.xfr32BitInt(0x01020304); | |
652 | pw.commit(); | |
653 | ||
654 | vector<uint8_t> newResponse; | |
655 | int res = rewriteResponseWithoutEDNSOption((const char *) response.data(), response.size(), EDNSOptionCode::ECS, newResponse); | |
656 | BOOST_CHECK_EQUAL(res, 0); | |
657 | ||
658 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4)); | |
659 | ||
660 | unsigned int consumed = 0; | |
661 | uint16_t qtype; | |
662 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
663 | BOOST_CHECK_EQUAL(qname, name); | |
664 | BOOST_CHECK(qtype == QType::A); | |
665 | ||
666 | validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1); | |
667 | } | |
668 | ||
669 | BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenIntermediaryOption) { | |
670 | DNSName name("www.powerdns.com."); | |
671 | ComboAddress origRemote("127.0.0.1"); | |
672 | ||
673 | vector<uint8_t> response; | |
674 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
675 | pw.getHeader()->qr = 1; | |
676 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
677 | pw.xfr32BitInt(0x01020304); | |
678 | ||
679 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 680 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
681 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
682 | EDNSCookiesOpt cookiesOpt; | |
683 | cookiesOpt.client = string("deadbeef"); | |
684 | cookiesOpt.server = string("deadbeef"); | |
685 | string cookiesOptionStr1 = makeEDNSCookiesOptString(cookiesOpt); | |
686 | string cookiesOptionStr2 = makeEDNSCookiesOptString(cookiesOpt); | |
687 | DNSPacketWriter::optvect_t opts; | |
688 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr1)); | |
689 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
690 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr2)); | |
691 | pw.addOpt(512, 0, 0, opts); | |
692 | pw.commit(); | |
693 | ||
694 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
695 | pw.xfr32BitInt(0x01020304); | |
696 | pw.commit(); | |
697 | ||
698 | vector<uint8_t> newResponse; | |
699 | int res = rewriteResponseWithoutEDNSOption((const char *) response.data(), response.size(), EDNSOptionCode::ECS, newResponse); | |
700 | BOOST_CHECK_EQUAL(res, 0); | |
701 | ||
702 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4)); | |
703 | ||
704 | unsigned int consumed = 0; | |
705 | uint16_t qtype; | |
706 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
707 | BOOST_CHECK_EQUAL(qname, name); | |
708 | BOOST_CHECK(qtype == QType::A); | |
709 | ||
710 | validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1); | |
711 | } | |
712 | ||
713 | BOOST_AUTO_TEST_CASE(rewritingWithoutECSWhenLastOption) { | |
714 | DNSName name("www.powerdns.com."); | |
715 | ComboAddress origRemote("127.0.0.1"); | |
716 | ||
717 | vector<uint8_t> response; | |
718 | DNSPacketWriter pw(response, name, QType::A, QClass::IN, 0); | |
719 | pw.getHeader()->qr = 1; | |
720 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER, true); | |
721 | pw.xfr32BitInt(0x01020304); | |
722 | ||
723 | EDNSSubnetOpts ecsOpts; | |
ff0902ec | 724 | ecsOpts.source = Netmask(origRemote, ECSSourcePrefixV4); |
ff73f02b RG |
725 | string origECSOptionStr = makeEDNSSubnetOptsString(ecsOpts); |
726 | EDNSCookiesOpt cookiesOpt; | |
727 | cookiesOpt.client = string("deadbeef"); | |
728 | cookiesOpt.server = string("deadbeef"); | |
729 | string cookiesOptionStr = makeEDNSCookiesOptString(cookiesOpt); | |
730 | DNSPacketWriter::optvect_t opts; | |
731 | opts.push_back(make_pair(EDNSOptionCode::COOKIE, cookiesOptionStr)); | |
732 | opts.push_back(make_pair(EDNSOptionCode::ECS, origECSOptionStr)); | |
733 | pw.addOpt(512, 0, 0, opts); | |
734 | pw.commit(); | |
735 | ||
736 | pw.startRecord(name, QType::A, 3600, QClass::IN, DNSResourceRecord::ADDITIONAL, true); | |
737 | pw.xfr32BitInt(0x01020304); | |
738 | pw.commit(); | |
739 | ||
740 | vector<uint8_t> newResponse; | |
741 | int res = rewriteResponseWithoutEDNSOption((const char *) response.data(), response.size(), EDNSOptionCode::ECS, newResponse); | |
742 | BOOST_CHECK_EQUAL(res, 0); | |
743 | ||
744 | BOOST_CHECK_EQUAL(newResponse.size(), response.size() - (origECSOptionStr.size() + 4)); | |
745 | ||
746 | unsigned int consumed = 0; | |
747 | uint16_t qtype; | |
748 | DNSName qname((const char*) newResponse.data(), newResponse.size(), sizeof(dnsheader), false, &qtype, NULL, &consumed); | |
749 | BOOST_CHECK_EQUAL(qname, name); | |
750 | BOOST_CHECK(qtype == QType::A); | |
751 | ||
752 | validateResponse((const char *) newResponse.data(), newResponse.size(), true, 1); | |
7b146b98 RG |
753 | } |
754 | ||
ca404e94 | 755 | BOOST_AUTO_TEST_SUITE_END(); |