]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdist-ecs.cc
Merge pull request #7484 from omoerbeek/no-utility-random
[thirdparty/pdns.git] / pdns / dnsdist-ecs.cc
1 /*
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 */
22 #include "dolog.hh"
23 #include "dnsdist.hh"
24 #include "dnsdist-ecs.hh"
25 #include "dnsparser.hh"
26 #include "dnswriter.hh"
27 #include "ednsoptions.hh"
28 #include "ednssubnet.hh"
29
30 /* when we add EDNS to a query, we don't want to advertise
31 a large buffer size */
32 size_t g_EdnsUDPPayloadSize = 512;
33 uint16_t g_PayloadSizeSelfGenAnswers{s_udpIncomingBufferSize};
34
35 /* draft-ietf-dnsop-edns-client-subnet-04 "11.1. Privacy" */
36 uint16_t g_ECSSourcePrefixV4 = 24;
37 uint16_t g_ECSSourcePrefixV6 = 56;
38
39 bool g_ECSOverride{false};
40 bool g_addEDNSToSelfGeneratedResponses{true};
41
42 int rewriteResponseWithoutEDNS(const std::string& initialPacket, vector<uint8_t>& newContent)
43 {
44 assert(initialPacket.size() >= sizeof(dnsheader));
45 const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
46
47 if (ntohs(dh->arcount) == 0)
48 return ENOENT;
49
50 if (ntohs(dh->qdcount) == 0)
51 return ENOENT;
52
53 PacketReader pr(initialPacket);
54
55 size_t idx = 0;
56 DNSName rrname;
57 uint16_t qdcount = ntohs(dh->qdcount);
58 uint16_t ancount = ntohs(dh->ancount);
59 uint16_t nscount = ntohs(dh->nscount);
60 uint16_t arcount = ntohs(dh->arcount);
61 uint16_t rrtype;
62 uint16_t rrclass;
63 string blob;
64 struct dnsrecordheader ah;
65
66 rrname = pr.getName();
67 rrtype = pr.get16BitInt();
68 rrclass = pr.get16BitInt();
69
70 DNSPacketWriter pw(newContent, rrname, rrtype, rrclass, dh->opcode);
71 pw.getHeader()->id=dh->id;
72 pw.getHeader()->qr=dh->qr;
73 pw.getHeader()->aa=dh->aa;
74 pw.getHeader()->tc=dh->tc;
75 pw.getHeader()->rd=dh->rd;
76 pw.getHeader()->ra=dh->ra;
77 pw.getHeader()->ad=dh->ad;
78 pw.getHeader()->cd=dh->cd;
79 pw.getHeader()->rcode=dh->rcode;
80
81 /* consume remaining qd if any */
82 if (qdcount > 1) {
83 for(idx = 1; idx < qdcount; idx++) {
84 rrname = pr.getName();
85 rrtype = pr.get16BitInt();
86 rrclass = pr.get16BitInt();
87 (void) rrtype;
88 (void) rrclass;
89 }
90 }
91
92 /* copy AN and NS */
93 for (idx = 0; idx < ancount; idx++) {
94 rrname = pr.getName();
95 pr.getDnsrecordheader(ah);
96
97 pw.startRecord(rrname, ah.d_type, ah.d_ttl, ah.d_class, DNSResourceRecord::ANSWER, true);
98 pr.xfrBlob(blob);
99 pw.xfrBlob(blob);
100 }
101
102 for (idx = 0; idx < nscount; idx++) {
103 rrname = pr.getName();
104 pr.getDnsrecordheader(ah);
105
106 pw.startRecord(rrname, ah.d_type, ah.d_ttl, ah.d_class, DNSResourceRecord::AUTHORITY, true);
107 pr.xfrBlob(blob);
108 pw.xfrBlob(blob);
109 }
110 /* consume AR, looking for OPT */
111 for (idx = 0; idx < arcount; idx++) {
112 rrname = pr.getName();
113 pr.getDnsrecordheader(ah);
114
115 if (ah.d_type != QType::OPT) {
116 pw.startRecord(rrname, ah.d_type, ah.d_ttl, ah.d_class, DNSResourceRecord::ADDITIONAL, true);
117 pr.xfrBlob(blob);
118 pw.xfrBlob(blob);
119 } else {
120 pr.skip(ah.d_clen);
121 }
122 }
123 pw.commit();
124
125 return 0;
126 }
127
128 int locateEDNSOptRR(const std::string& packet, uint16_t * optStart, size_t * optLen, bool * last)
129 {
130 assert(optStart != NULL);
131 assert(optLen != NULL);
132 assert(last != NULL);
133 const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet.data());
134
135 if (ntohs(dh->arcount) == 0)
136 return ENOENT;
137
138 PacketReader pr(packet);
139 size_t idx = 0;
140 DNSName rrname;
141 uint16_t qdcount = ntohs(dh->qdcount);
142 uint16_t ancount = ntohs(dh->ancount);
143 uint16_t nscount = ntohs(dh->nscount);
144 uint16_t arcount = ntohs(dh->arcount);
145 uint16_t rrtype;
146 uint16_t rrclass;
147 struct dnsrecordheader ah;
148
149 /* consume qd */
150 for(idx = 0; idx < qdcount; idx++) {
151 rrname = pr.getName();
152 rrtype = pr.get16BitInt();
153 rrclass = pr.get16BitInt();
154 (void) rrtype;
155 (void) rrclass;
156 }
157
158 /* consume AN and NS */
159 for (idx = 0; idx < ancount + nscount; idx++) {
160 rrname = pr.getName();
161 pr.getDnsrecordheader(ah);
162 pr.skip(ah.d_clen);
163 }
164
165 /* consume AR, looking for OPT */
166 for (idx = 0; idx < arcount; idx++) {
167 uint16_t start = pr.getPosition();
168 rrname = pr.getName();
169 pr.getDnsrecordheader(ah);
170
171 if (ah.d_type == QType::OPT) {
172 *optStart = start;
173 *optLen = (pr.getPosition() - start) + ah.d_clen;
174
175 if (packet.size() < (*optStart + *optLen)) {
176 throw std::range_error("Opt record overflow");
177 }
178
179 if (idx == ((size_t) arcount - 1)) {
180 *last = true;
181 }
182 else {
183 *last = false;
184 }
185 return 0;
186 }
187 pr.skip(ah.d_clen);
188 }
189
190 return ENOENT;
191 }
192
193 /* extract the start of the OPT RR in a QUERY packet if any */
194 int getEDNSOptionsStart(const char* packet, const size_t offset, const size_t len, uint16_t* optRDPosition, size_t * remaining)
195 {
196 assert(packet != nullptr);
197 assert(optRDPosition != nullptr);
198 assert(remaining != nullptr);
199 const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(packet);
200
201 if (offset >= len) {
202 return ENOENT;
203 }
204
205 if (ntohs(dh->qdcount) != 1 || ntohs(dh->ancount) != 0 || ntohs(dh->arcount) != 1 || ntohs(dh->nscount) != 0)
206 return ENOENT;
207
208 size_t pos = sizeof(dnsheader) + offset;
209 pos += DNS_TYPE_SIZE + DNS_CLASS_SIZE;
210
211 if (pos >= len)
212 return ENOENT;
213
214 if ((pos + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE) >= len) {
215 return ENOENT;
216 }
217
218 if (packet[pos] != 0) {
219 /* not the root so not an OPT record */
220 return ENOENT;
221 }
222 pos += 1;
223
224 uint16_t qtype = (reinterpret_cast<const unsigned char*>(packet)[pos])*256 + reinterpret_cast<const unsigned char*>(packet)[pos+1];
225 pos += DNS_TYPE_SIZE;
226 pos += DNS_CLASS_SIZE;
227
228 if(qtype != QType::OPT || (len - pos) < (DNS_TTL_SIZE + DNS_RDLENGTH_SIZE))
229 return ENOENT;
230
231 pos += DNS_TTL_SIZE;
232 *optRDPosition = pos;
233 *remaining = len - pos;
234
235 return 0;
236 }
237
238 void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPrefixLength)
239 {
240 Netmask sourceNetmask(source, ECSPrefixLength);
241 EDNSSubnetOpts ecsOpts;
242 ecsOpts.source = sourceNetmask;
243 string payload = makeEDNSSubnetOptsString(ecsOpts);
244 generateEDNSOption(EDNSOptionCode::ECS, payload, res);
245 }
246
247 void generateOptRR(const std::string& optRData, string& res, uint16_t udpPayloadSize, uint8_t ednsrcode, bool dnssecOK)
248 {
249 const uint8_t name = 0;
250 dnsrecordheader dh;
251 EDNS0Record edns0;
252 edns0.extRCode = ednsrcode;
253 edns0.version = 0;
254 edns0.extFlags = dnssecOK ? htons(EDNS_HEADER_FLAG_DO) : 0;
255
256 dh.d_type = htons(QType::OPT);
257 dh.d_class = htons(udpPayloadSize);
258 static_assert(sizeof(EDNS0Record) == sizeof(dh.d_ttl), "sizeof(EDNS0Record) must match sizeof(dnsrecordheader.d_ttl)");
259 memcpy(&dh.d_ttl, &edns0, sizeof edns0);
260 dh.d_clen = htons((uint16_t) optRData.length());
261 res.reserve(sizeof(name) + sizeof(dh) + optRData.length());
262 res.assign((const char *) &name, sizeof name);
263 res.append((const char *) &dh, sizeof dh);
264 res.append(optRData.c_str(), optRData.length());
265 }
266
267 static bool replaceEDNSClientSubnetOption(char * const packet, const size_t packetSize, uint16_t * const len, char * const oldEcsOptionStart, size_t const oldEcsOptionSize, unsigned char * const optRDLen, const string& newECSOption)
268 {
269 assert(packet != NULL);
270 assert(len != NULL);
271 assert(oldEcsOptionStart != NULL);
272 assert(optRDLen != NULL);
273
274 if (newECSOption.size() == oldEcsOptionSize) {
275 /* same size as the existing option */
276 memcpy(oldEcsOptionStart, newECSOption.c_str(), oldEcsOptionSize);
277 }
278 else {
279 /* different size than the existing option */
280 const unsigned int newPacketLen = *len + (newECSOption.length() - oldEcsOptionSize);
281 const size_t beforeOptionLen = oldEcsOptionStart - packet;
282 const size_t dataBehindSize = *len - beforeOptionLen - oldEcsOptionSize;
283
284 /* check that it fits in the existing buffer */
285 if (newPacketLen > packetSize) {
286 return false;
287 }
288
289 /* fix the size of ECS Option RDLen */
290 uint16_t newRDLen = (optRDLen[0] * 256) + optRDLen[1];
291 newRDLen += (newECSOption.size() - oldEcsOptionSize);
292 optRDLen[0] = newRDLen / 256;
293 optRDLen[1] = newRDLen % 256;
294
295 if (dataBehindSize > 0) {
296 memmove(oldEcsOptionStart, oldEcsOptionStart + oldEcsOptionSize, dataBehindSize);
297 }
298 memcpy(oldEcsOptionStart + dataBehindSize, newECSOption.c_str(), newECSOption.size());
299 *len = newPacketLen;
300 }
301
302 return true;
303 }
304
305 /* This function looks for an OPT RR, return true if a valid one was found (even if there was no options)
306 and false otherwise. */
307 bool parseEDNSOptions(DNSQuestion& dq)
308 {
309 assert(dq.dh != nullptr);
310 assert(dq.consumed <= dq.len);
311 assert(dq.len <= dq.size);
312
313 if (dq.ednsOptions != nullptr) {
314 return true;
315 }
316
317 dq.ednsOptions = std::make_shared<std::map<uint16_t, EDNSOptionView> >();
318 const char* packet = reinterpret_cast<const char*>(dq.dh);
319
320 size_t remaining = 0;
321 uint16_t optRDPosition;
322 int res = getEDNSOptionsStart(packet, dq.consumed, dq.len, &optRDPosition, &remaining);
323
324 if (res == 0) {
325 res = getEDNSOptions(packet + optRDPosition, remaining, *dq.ednsOptions);
326 return (res == 0);
327 }
328
329 return false;
330 }
331
332 static bool addECSToExistingOPT(char* const packet, size_t const packetSize, uint16_t* const len, const string& newECSOption, unsigned char* optRDLen, bool* const ecsAdded)
333 {
334 /* we need to add one EDNS0 ECS option, fixing the size of EDNS0 RDLENGTH */
335 /* getEDNSOptionsStart has already checked that there is exactly one AR,
336 no NS and no AN */
337
338 /* check if the existing buffer is large enough */
339 const size_t newECSOptionSize = newECSOption.size();
340 if (packetSize - *len <= newECSOptionSize) {
341 return false;
342 }
343
344 uint16_t newRDLen = (optRDLen[0] * 256) + optRDLen[1];
345 newRDLen += newECSOptionSize;
346 optRDLen[0] = newRDLen / 256;
347 optRDLen[1] = newRDLen % 256;
348
349 memcpy(packet + *len, newECSOption.c_str(), newECSOptionSize);
350 *len += newECSOptionSize;
351 *ecsAdded = true;
352
353 return true;
354 }
355
356 static bool addEDNSWithECS(char* const packet, size_t const packetSize, uint16_t* const len, const string& newECSOption, bool* const ednsAdded, bool preserveTrailingData)
357 {
358 /* we need to add a EDNS0 RR with one EDNS0 ECS option, fixing the AR count */
359 string EDNSRR;
360 struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(packet);
361 generateOptRR(newECSOption, EDNSRR, g_EdnsUDPPayloadSize, 0, false);
362
363 /* does it fit in the existing buffer? */
364 if (packetSize - *len <= EDNSRR.size()) {
365 return false;
366 }
367
368 uint32_t realPacketLen = getDNSPacketLength(packet, *len);
369 if (realPacketLen < *len && preserveTrailingData) {
370 size_t toMove = *len - realPacketLen;
371 memmove(packet + realPacketLen + EDNSRR.size(), packet + realPacketLen, toMove);
372 *len += EDNSRR.size();
373 }
374 else {
375 *len = realPacketLen + EDNSRR.size();
376 }
377
378 uint16_t arcount = ntohs(dh->arcount);
379 arcount++;
380 dh->arcount = htons(arcount);
381 *ednsAdded = true;
382
383 memcpy(packet + realPacketLen, EDNSRR.c_str(), EDNSRR.size());
384
385 return true;
386 }
387
388 bool handleEDNSClientSubnet(char* const packet, const size_t packetSize, const unsigned int consumed, uint16_t* const len, bool* const ednsAdded, bool* const ecsAdded, bool overrideExisting, const string& newECSOption, bool preserveTrailingData)
389 {
390 assert(packet != nullptr);
391 assert(len != nullptr);
392 assert(consumed <= (size_t) *len);
393 assert(ednsAdded != nullptr);
394 assert(ecsAdded != nullptr);
395 uint16_t optRDPosition = 0;
396 size_t remaining = 0;
397
398 int res = getEDNSOptionsStart(packet, consumed, *len, &optRDPosition, &remaining);
399
400 if (res != 0) {
401 return addEDNSWithECS(packet, packetSize, len, newECSOption, ednsAdded, preserveTrailingData);
402 }
403
404 unsigned char* optRDLen = reinterpret_cast<unsigned char*>(packet) + optRDPosition;
405 char * ecsOptionStart = nullptr;
406 size_t ecsOptionSize = 0;
407
408 res = getEDNSOption(reinterpret_cast<char*>(optRDLen), remaining, EDNSOptionCode::ECS, &ecsOptionStart, &ecsOptionSize);
409
410 if (res == 0) {
411 /* there is already an ECS value */
412 if (!overrideExisting) {
413 return true;
414 }
415
416 return replaceEDNSClientSubnetOption(packet, packetSize, len, ecsOptionStart, ecsOptionSize, optRDLen, newECSOption);
417 } else {
418 /* we have an EDNS OPT RR but no existing ECS option */
419 return addECSToExistingOPT(packet, packetSize, len, newECSOption, optRDLen, ecsAdded);
420 }
421
422 return true;
423 }
424
425 bool handleEDNSClientSubnet(DNSQuestion& dq, bool* ednsAdded, bool* ecsAdded, bool preserveTrailingData)
426 {
427 assert(dq.remote != nullptr);
428 string newECSOption;
429 generateECSOption(dq.ecsSet ? dq.ecs.getNetwork() : *dq.remote, newECSOption, dq.ecsSet ? dq.ecs.getBits() : dq.ecsPrefixLength);
430 char* packet = reinterpret_cast<char*>(dq.dh);
431
432 return handleEDNSClientSubnet(packet, dq.size, dq.consumed, &dq.len, ednsAdded, ecsAdded, dq.ecsOverride, newECSOption, preserveTrailingData);
433 }
434
435 static int removeEDNSOptionFromOptions(unsigned char* optionsStart, const uint16_t optionsLen, const uint16_t optionCodeToRemove, uint16_t* newOptionsLen)
436 {
437 unsigned char* p = optionsStart;
438 size_t pos = 0;
439 while ((pos + 4) <= optionsLen) {
440 unsigned char* optionBegin = p;
441 const uint16_t optionCode = 0x100*p[0] + p[1];
442 p += sizeof(optionCode);
443 pos += sizeof(optionCode);
444 const uint16_t optionLen = 0x100*p[0] + p[1];
445 p += sizeof(optionLen);
446 pos += sizeof(optionLen);
447 if ((pos + optionLen) > optionsLen) {
448 return EINVAL;
449 }
450 if (optionCode == optionCodeToRemove) {
451 if (pos + optionLen < optionsLen) {
452 /* move remaining options over the removed one,
453 if any */
454 memmove(optionBegin, p + optionLen, optionsLen - (pos + optionLen));
455 }
456 *newOptionsLen = optionsLen - (sizeof(optionCode) + sizeof(optionLen) + optionLen);
457 return 0;
458 }
459 p += optionLen;
460 pos += optionLen;
461 }
462 return ENOENT;
463 }
464
465 int removeEDNSOptionFromOPT(char* optStart, size_t* optLen, const uint16_t optionCodeToRemove)
466 {
467 /* we need at least:
468 root label (1), type (2), class (2), ttl (4) + rdlen (2)*/
469 if (*optLen < 11) {
470 return EINVAL;
471 }
472 const unsigned char* end = (const unsigned char*) optStart + *optLen;
473 unsigned char* p = (unsigned char*) optStart + 9;
474 unsigned char* rdLenPtr = p;
475 uint16_t rdLen = (0x100*p[0] + p[1]);
476 p += sizeof(rdLen);
477 if (p + rdLen != end) {
478 return EINVAL;
479 }
480 uint16_t newRdLen = 0;
481 int res = removeEDNSOptionFromOptions(p, rdLen, optionCodeToRemove, &newRdLen);
482 if (res != 0) {
483 return res;
484 }
485 *optLen -= (rdLen - newRdLen);
486 rdLenPtr[0] = newRdLen / 0x100;
487 rdLenPtr[1] = newRdLen % 0x100;
488 return 0;
489 }
490
491 bool isEDNSOptionInOpt(const std::string& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart, uint16_t* optContentLen)
492 {
493 /* we need at least:
494 root label (1), type (2), class (2), ttl (4) + rdlen (2)*/
495 if (optLen < 11) {
496 return false;
497 }
498 size_t p = optStart + 9;
499 uint16_t rdLen = (0x100*packet.at(p) + packet.at(p+1));
500 p += sizeof(rdLen);
501 if (rdLen > (optLen - 11)) {
502 return false;
503 }
504
505 size_t rdEnd = p + rdLen;
506 while ((p + 4) <= rdEnd) {
507 const uint16_t optionCode = 0x100*packet.at(p) + packet.at(p+1);
508 p += sizeof(optionCode);
509 const uint16_t optionLen = 0x100*packet.at(p) + packet.at(p+1);
510 p += sizeof(optionLen);
511
512 if ((p + optionLen) > rdEnd) {
513 return false;
514 }
515
516 if (optionCode == optionCodeToFind) {
517 if (optContentStart != nullptr) {
518 *optContentStart = p;
519 }
520
521 if (optContentLen != nullptr) {
522 *optContentLen = optionLen;
523 }
524
525 return true;
526 }
527 p += optionLen;
528 }
529 return false;
530 }
531
532 int rewriteResponseWithoutEDNSOption(const std::string& initialPacket, const uint16_t optionCodeToSkip, vector<uint8_t>& newContent)
533 {
534 assert(initialPacket.size() >= sizeof(dnsheader));
535 const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
536
537 if (ntohs(dh->arcount) == 0)
538 return ENOENT;
539
540 if (ntohs(dh->qdcount) == 0)
541 return ENOENT;
542
543 PacketReader pr(initialPacket);
544
545 size_t idx = 0;
546 DNSName rrname;
547 uint16_t qdcount = ntohs(dh->qdcount);
548 uint16_t ancount = ntohs(dh->ancount);
549 uint16_t nscount = ntohs(dh->nscount);
550 uint16_t arcount = ntohs(dh->arcount);
551 uint16_t rrtype;
552 uint16_t rrclass;
553 string blob;
554 struct dnsrecordheader ah;
555
556 rrname = pr.getName();
557 rrtype = pr.get16BitInt();
558 rrclass = pr.get16BitInt();
559
560 DNSPacketWriter pw(newContent, rrname, rrtype, rrclass, dh->opcode);
561 pw.getHeader()->id=dh->id;
562 pw.getHeader()->qr=dh->qr;
563 pw.getHeader()->aa=dh->aa;
564 pw.getHeader()->tc=dh->tc;
565 pw.getHeader()->rd=dh->rd;
566 pw.getHeader()->ra=dh->ra;
567 pw.getHeader()->ad=dh->ad;
568 pw.getHeader()->cd=dh->cd;
569 pw.getHeader()->rcode=dh->rcode;
570
571 /* consume remaining qd if any */
572 if (qdcount > 1) {
573 for(idx = 1; idx < qdcount; idx++) {
574 rrname = pr.getName();
575 rrtype = pr.get16BitInt();
576 rrclass = pr.get16BitInt();
577 (void) rrtype;
578 (void) rrclass;
579 }
580 }
581
582 /* copy AN and NS */
583 for (idx = 0; idx < ancount; idx++) {
584 rrname = pr.getName();
585 pr.getDnsrecordheader(ah);
586
587 pw.startRecord(rrname, ah.d_type, ah.d_ttl, ah.d_class, DNSResourceRecord::ANSWER, true);
588 pr.xfrBlob(blob);
589 pw.xfrBlob(blob);
590 }
591
592 for (idx = 0; idx < nscount; idx++) {
593 rrname = pr.getName();
594 pr.getDnsrecordheader(ah);
595
596 pw.startRecord(rrname, ah.d_type, ah.d_ttl, ah.d_class, DNSResourceRecord::AUTHORITY, true);
597 pr.xfrBlob(blob);
598 pw.xfrBlob(blob);
599 }
600
601 /* consume AR, looking for OPT */
602 for (idx = 0; idx < arcount; idx++) {
603 rrname = pr.getName();
604 pr.getDnsrecordheader(ah);
605
606 if (ah.d_type != QType::OPT) {
607 pw.startRecord(rrname, ah.d_type, ah.d_ttl, ah.d_class, DNSResourceRecord::ADDITIONAL, true);
608 pr.xfrBlob(blob);
609 pw.xfrBlob(blob);
610 } else {
611 pw.startRecord(rrname, ah.d_type, ah.d_ttl, ah.d_class, DNSResourceRecord::ADDITIONAL, false);
612 pr.xfrBlob(blob);
613 uint16_t rdLen = blob.length();
614 removeEDNSOptionFromOptions((unsigned char*)blob.c_str(), rdLen, optionCodeToSkip, &rdLen);
615 /* xfrBlob(string, size) completely ignores size.. */
616 if (rdLen > 0) {
617 blob.resize((size_t)rdLen);
618 pw.xfrBlob(blob);
619 } else {
620 pw.commit();
621 }
622 }
623 }
624 pw.commit();
625
626 return 0;
627 }
628
629 bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode)
630 {
631 if (dh->arcount != 0) {
632 return false;
633 }
634
635 std::string optRecord;
636 generateOptRR(std::string(), optRecord, payloadSize, ednsrcode, dnssecOK);
637
638 if (optRecord.size() >= size || (size - optRecord.size()) < len) {
639 return false;
640 }
641
642 char * optPtr = reinterpret_cast<char*>(dh) + len;
643 memcpy(optPtr, optRecord.data(), optRecord.size());
644 len += optRecord.size();
645 dh->arcount = htons(1);
646
647 return true;
648 }
649
650 bool addEDNSToQueryTurnedResponse(DNSQuestion& dq)
651 {
652 uint16_t optRDPosition;
653 /* remaining is at least the size of the rdlen + the options if any + the following records if any */
654 size_t remaining = 0;
655
656 int res = getEDNSOptionsStart(reinterpret_cast<char*>(dq.dh), dq.consumed, dq.len, &optRDPosition, &remaining);
657
658 if (res != 0) {
659 /* if the initial query did not have EDNS0, we are done */
660 return true;
661 }
662
663 const size_t existingOptLen = /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + /* Z */ 2 + remaining;
664 if (existingOptLen >= dq.len) {
665 /* something is wrong, bail out */
666 return false;
667 }
668
669 char* optRDLen = reinterpret_cast<char*>(dq.dh) + optRDPosition;
670 char * optPtr = (optRDLen - (/* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + /* Z */ 2));
671
672 const uint8_t* zPtr = reinterpret_cast<const uint8_t*>(optPtr) + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE;
673 uint16_t z = 0x100 * (*zPtr) + *(zPtr + 1);
674 bool dnssecOK = z & EDNS_HEADER_FLAG_DO;
675
676 /* remove the existing OPT record, and everything else that follows (any SIG or TSIG would be useless anyway) */
677 dq.len -= existingOptLen;
678 dq.dh->arcount = 0;
679
680 if (g_addEDNSToSelfGeneratedResponses) {
681 /* now we need to add a new OPT record */
682 return addEDNS(dq.dh, dq.len, dq.size, dnssecOK, g_PayloadSizeSelfGenAnswers, dq.ednsRCode);
683 }
684
685 /* otherwise we are just fine */
686 return true;
687 }
688
689 // goal in life - if you send us a reasonably normal packet, we'll get Z for you, otherwise 0
690 int getEDNSZ(const DNSQuestion& dq)
691 try
692 {
693 if (ntohs(dq.dh->qdcount) != 1 || dq.dh->ancount != 0 || ntohs(dq.dh->arcount) != 1 || dq.dh->nscount != 0) {
694 return 0;
695 }
696
697 if (dq.len <= sizeof(dnsheader)) {
698 return 0;
699 }
700
701 size_t pos = sizeof(dnsheader) + dq.consumed + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
702
703 if (dq.len <= (pos + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE)) {
704 return 0;
705 }
706
707 const char* packet = reinterpret_cast<const char*>(dq.dh);
708
709 if (packet[pos] != 0) {
710 /* not root, so not a valid OPT record */
711 return 0;
712 }
713
714 pos++;
715
716 uint16_t qtype = (reinterpret_cast<const unsigned char*>(packet)[pos])*256 + reinterpret_cast<const unsigned char*>(packet)[pos+1];
717 pos += DNS_TYPE_SIZE;
718 pos += DNS_CLASS_SIZE;
719
720 if (qtype != QType::OPT || (pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + 1) >= dq.len) {
721 return 0;
722 }
723
724 const uint8_t* z = reinterpret_cast<const uint8_t*>(packet) + pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE;
725 return 0x100 * (*z) + *(z+1);
726 }
727 catch(...)
728 {
729 return 0;
730 }
731
732 bool queryHasEDNS(const DNSQuestion& dq)
733 {
734 uint16_t optRDPosition;
735 size_t ecsRemaining = 0;
736
737 int res = getEDNSOptionsStart(reinterpret_cast<char*>(dq.dh), dq.consumed, dq.len, &optRDPosition, &ecsRemaining);
738 if (res == 0) {
739 return true;
740 }
741
742 return false;
743 }