]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsdist-ecs.cc
dnsdist: Fix signedness issue in isEDNSOptionInOpt()
[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(static_cast<uint16_t>(optRData.length()));
261 res.reserve(sizeof(name) + sizeof(dh) + optRData.length());
262 res.assign(reinterpret_cast<const char *>(&name), sizeof name);
263 res.append(reinterpret_cast<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 if (*optLen < optRecordMinimumSize) {
468 return EINVAL;
469 }
470 const unsigned char* end = (const unsigned char*) optStart + *optLen;
471 unsigned char* p = (unsigned char*) optStart + 9;
472 unsigned char* rdLenPtr = p;
473 uint16_t rdLen = (0x100*p[0] + p[1]);
474 p += sizeof(rdLen);
475 if (p + rdLen != end) {
476 return EINVAL;
477 }
478 uint16_t newRdLen = 0;
479 int res = removeEDNSOptionFromOptions(p, rdLen, optionCodeToRemove, &newRdLen);
480 if (res != 0) {
481 return res;
482 }
483 *optLen -= (rdLen - newRdLen);
484 rdLenPtr[0] = newRdLen / 0x100;
485 rdLenPtr[1] = newRdLen % 0x100;
486 return 0;
487 }
488
489 bool isEDNSOptionInOpt(const std::string& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart, uint16_t* optContentLen)
490 {
491 if (optLen < optRecordMinimumSize) {
492 return false;
493 }
494 size_t p = optStart + 9;
495 uint16_t rdLen = (0x100*static_cast<unsigned char>(packet.at(p)) + static_cast<unsigned char>(packet.at(p+1)));
496 p += sizeof(rdLen);
497 if (rdLen > (optLen - optRecordMinimumSize)) {
498 return false;
499 }
500
501 size_t rdEnd = p + rdLen;
502 while ((p + 4) <= rdEnd) {
503 const uint16_t optionCode = 0x100*static_cast<unsigned char>(packet.at(p)) + static_cast<unsigned char>(packet.at(p+1));
504 p += sizeof(optionCode);
505 const uint16_t optionLen = 0x100*static_cast<unsigned char>(packet.at(p)) + static_cast<unsigned char>(packet.at(p+1));
506 p += sizeof(optionLen);
507
508 if ((p + optionLen) > rdEnd) {
509 return false;
510 }
511
512 if (optionCode == optionCodeToFind) {
513 if (optContentStart != nullptr) {
514 *optContentStart = p;
515 }
516
517 if (optContentLen != nullptr) {
518 *optContentLen = optionLen;
519 }
520
521 return true;
522 }
523 p += optionLen;
524 }
525 return false;
526 }
527
528 int rewriteResponseWithoutEDNSOption(const std::string& initialPacket, const uint16_t optionCodeToSkip, vector<uint8_t>& newContent)
529 {
530 assert(initialPacket.size() >= sizeof(dnsheader));
531 const struct dnsheader* dh = reinterpret_cast<const struct dnsheader*>(initialPacket.data());
532
533 if (ntohs(dh->arcount) == 0)
534 return ENOENT;
535
536 if (ntohs(dh->qdcount) == 0)
537 return ENOENT;
538
539 PacketReader pr(initialPacket);
540
541 size_t idx = 0;
542 DNSName rrname;
543 uint16_t qdcount = ntohs(dh->qdcount);
544 uint16_t ancount = ntohs(dh->ancount);
545 uint16_t nscount = ntohs(dh->nscount);
546 uint16_t arcount = ntohs(dh->arcount);
547 uint16_t rrtype;
548 uint16_t rrclass;
549 string blob;
550 struct dnsrecordheader ah;
551
552 rrname = pr.getName();
553 rrtype = pr.get16BitInt();
554 rrclass = pr.get16BitInt();
555
556 DNSPacketWriter pw(newContent, rrname, rrtype, rrclass, dh->opcode);
557 pw.getHeader()->id=dh->id;
558 pw.getHeader()->qr=dh->qr;
559 pw.getHeader()->aa=dh->aa;
560 pw.getHeader()->tc=dh->tc;
561 pw.getHeader()->rd=dh->rd;
562 pw.getHeader()->ra=dh->ra;
563 pw.getHeader()->ad=dh->ad;
564 pw.getHeader()->cd=dh->cd;
565 pw.getHeader()->rcode=dh->rcode;
566
567 /* consume remaining qd if any */
568 if (qdcount > 1) {
569 for(idx = 1; idx < qdcount; idx++) {
570 rrname = pr.getName();
571 rrtype = pr.get16BitInt();
572 rrclass = pr.get16BitInt();
573 (void) rrtype;
574 (void) rrclass;
575 }
576 }
577
578 /* copy AN and NS */
579 for (idx = 0; idx < ancount; idx++) {
580 rrname = pr.getName();
581 pr.getDnsrecordheader(ah);
582
583 pw.startRecord(rrname, ah.d_type, ah.d_ttl, ah.d_class, DNSResourceRecord::ANSWER, true);
584 pr.xfrBlob(blob);
585 pw.xfrBlob(blob);
586 }
587
588 for (idx = 0; idx < nscount; idx++) {
589 rrname = pr.getName();
590 pr.getDnsrecordheader(ah);
591
592 pw.startRecord(rrname, ah.d_type, ah.d_ttl, ah.d_class, DNSResourceRecord::AUTHORITY, true);
593 pr.xfrBlob(blob);
594 pw.xfrBlob(blob);
595 }
596
597 /* consume AR, looking for OPT */
598 for (idx = 0; idx < arcount; idx++) {
599 rrname = pr.getName();
600 pr.getDnsrecordheader(ah);
601
602 if (ah.d_type != QType::OPT) {
603 pw.startRecord(rrname, ah.d_type, ah.d_ttl, ah.d_class, DNSResourceRecord::ADDITIONAL, true);
604 pr.xfrBlob(blob);
605 pw.xfrBlob(blob);
606 } else {
607 pw.startRecord(rrname, ah.d_type, ah.d_ttl, ah.d_class, DNSResourceRecord::ADDITIONAL, false);
608 pr.xfrBlob(blob);
609 uint16_t rdLen = blob.length();
610 removeEDNSOptionFromOptions((unsigned char*)blob.c_str(), rdLen, optionCodeToSkip, &rdLen);
611 /* xfrBlob(string, size) completely ignores size.. */
612 if (rdLen > 0) {
613 blob.resize((size_t)rdLen);
614 pw.xfrBlob(blob);
615 } else {
616 pw.commit();
617 }
618 }
619 }
620 pw.commit();
621
622 return 0;
623 }
624
625 bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode)
626 {
627 if (dh->arcount != 0) {
628 return false;
629 }
630
631 std::string optRecord;
632 generateOptRR(std::string(), optRecord, payloadSize, ednsrcode, dnssecOK);
633
634 if (optRecord.size() >= size || (size - optRecord.size()) < len) {
635 return false;
636 }
637
638 char * optPtr = reinterpret_cast<char*>(dh) + len;
639 memcpy(optPtr, optRecord.data(), optRecord.size());
640 len += optRecord.size();
641 dh->arcount = htons(1);
642
643 return true;
644 }
645
646 bool addEDNSToQueryTurnedResponse(DNSQuestion& dq)
647 {
648 uint16_t optRDPosition;
649 /* remaining is at least the size of the rdlen + the options if any + the following records if any */
650 size_t remaining = 0;
651
652 int res = getEDNSOptionsStart(reinterpret_cast<char*>(dq.dh), dq.consumed, dq.len, &optRDPosition, &remaining);
653
654 if (res != 0) {
655 /* if the initial query did not have EDNS0, we are done */
656 return true;
657 }
658
659 const size_t existingOptLen = /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + /* Z */ 2 + remaining;
660 if (existingOptLen >= dq.len) {
661 /* something is wrong, bail out */
662 return false;
663 }
664
665 char* optRDLen = reinterpret_cast<char*>(dq.dh) + optRDPosition;
666 char * optPtr = (optRDLen - (/* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + /* Z */ 2));
667
668 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;
669 uint16_t z = 0x100 * (*zPtr) + *(zPtr + 1);
670 bool dnssecOK = z & EDNS_HEADER_FLAG_DO;
671
672 /* remove the existing OPT record, and everything else that follows (any SIG or TSIG would be useless anyway) */
673 dq.len -= existingOptLen;
674 dq.dh->arcount = 0;
675
676 if (g_addEDNSToSelfGeneratedResponses) {
677 /* now we need to add a new OPT record */
678 return addEDNS(dq.dh, dq.len, dq.size, dnssecOK, g_PayloadSizeSelfGenAnswers, dq.ednsRCode);
679 }
680
681 /* otherwise we are just fine */
682 return true;
683 }
684
685 // goal in life - if you send us a reasonably normal packet, we'll get Z for you, otherwise 0
686 int getEDNSZ(const DNSQuestion& dq)
687 try
688 {
689 if (ntohs(dq.dh->qdcount) != 1 || dq.dh->ancount != 0 || ntohs(dq.dh->arcount) != 1 || dq.dh->nscount != 0) {
690 return 0;
691 }
692
693 if (dq.len <= sizeof(dnsheader)) {
694 return 0;
695 }
696
697 size_t pos = sizeof(dnsheader) + dq.consumed + DNS_TYPE_SIZE + DNS_CLASS_SIZE;
698
699 if (dq.len <= (pos + /* root */ 1 + DNS_TYPE_SIZE + DNS_CLASS_SIZE)) {
700 return 0;
701 }
702
703 const char* packet = reinterpret_cast<const char*>(dq.dh);
704
705 if (packet[pos] != 0) {
706 /* not root, so not a valid OPT record */
707 return 0;
708 }
709
710 pos++;
711
712 uint16_t qtype = (reinterpret_cast<const unsigned char*>(packet)[pos])*256 + reinterpret_cast<const unsigned char*>(packet)[pos+1];
713 pos += DNS_TYPE_SIZE;
714 pos += DNS_CLASS_SIZE;
715
716 if (qtype != QType::OPT || (pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE + 1) >= dq.len) {
717 return 0;
718 }
719
720 const uint8_t* z = reinterpret_cast<const uint8_t*>(packet) + pos + EDNS_EXTENDED_RCODE_SIZE + EDNS_VERSION_SIZE;
721 return 0x100 * (*z) + *(z+1);
722 }
723 catch(...)
724 {
725 return 0;
726 }
727
728 bool queryHasEDNS(const DNSQuestion& dq)
729 {
730 uint16_t optRDPosition;
731 size_t ecsRemaining = 0;
732
733 int res = getEDNSOptionsStart(reinterpret_cast<char*>(dq.dh), dq.consumed, dq.len, &optRDPosition, &ecsRemaining);
734 if (res == 0) {
735 return true;
736 }
737
738 return false;
739 }
740
741 bool getEDNS0Record(const DNSQuestion& dq, EDNS0Record& edns0)
742 {
743 uint16_t optStart;
744 size_t optLen = 0;
745 bool last = false;
746 const char * packet = reinterpret_cast<const char*>(dq.dh);
747 std::string packetStr(packet, dq.len);
748 int res = locateEDNSOptRR(packetStr, &optStart, &optLen, &last);
749 if (res != 0) {
750 // no EDNS OPT RR
751 return false;
752 }
753
754 if (optLen < optRecordMinimumSize) {
755 return false;
756 }
757
758 if (optStart < dq.len && packetStr.at(optStart) != 0) {
759 // OPT RR Name != '.'
760 return false;
761 }
762
763 static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t) AKA RR TTL size");
764 // copy out 4-byte "ttl" (really the EDNS0 record), after root label (1) + type (2) + class (2).
765 memcpy(&edns0, packet + optStart + 5, sizeof edns0);
766 return true;
767 }