]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - pdns/dnsdist-ecs.cc
Merge pull request #8223 from PowerDNS/omoerbeek-patch-1
[thirdparty/pdns.git] / pdns / dnsdist-ecs.cc
index dbb6cad589d85d2c0fa0e8a8bb7e94d6e3fd418a..67fc5733728184d442c8793e3a91e35a5da3ced2 100644 (file)
@@ -244,12 +244,12 @@ void generateECSOption(const ComboAddress& source, string& res, uint16_t ECSPref
   generateEDNSOption(EDNSOptionCode::ECS, payload, res);
 }
 
-void generateOptRR(const std::string& optRData, string& res, uint16_t udpPayloadSize, bool dnssecOK)
+void generateOptRR(const std::string& optRData, string& res, uint16_t udpPayloadSize, uint8_t ednsrcode, bool dnssecOK)
 {
   const uint8_t name = 0;
   dnsrecordheader dh;
   EDNS0Record edns0;
-  edns0.extRCode = 0;
+  edns0.extRCode = ednsrcode;
   edns0.version = 0;
   edns0.extFlags = dnssecOK ? htons(EDNS_HEADER_FLAG_DO) : 0;
 
@@ -257,10 +257,10 @@ void generateOptRR(const std::string& optRData, string& res, uint16_t udpPayload
   dh.d_class = htons(udpPayloadSize);
   static_assert(sizeof(EDNS0Record) == sizeof(dh.d_ttl), "sizeof(EDNS0Record) must match sizeof(dnsrecordheader.d_ttl)");
   memcpy(&dh.d_ttl, &edns0, sizeof edns0);
-  dh.d_clen = htons((uint16_t) optRData.length());
+  dh.d_clen = htons(static_cast<uint16_t>(optRData.length()));
   res.reserve(sizeof(name) + sizeof(dh) + optRData.length());
-  res.assign((const char *) &name, sizeof name);
-  res.append((const char *) &dh, sizeof dh);
+  res.assign(reinterpret_cast<const char *>(&name), sizeof name);
+  res.append(reinterpret_cast<const char *>(&dh), sizeof(dh));
   res.append(optRData.c_str(), optRData.length());
 }
 
@@ -358,7 +358,7 @@ static bool addEDNSWithECS(char* const packet, size_t const packetSize, uint16_t
   /* we need to add a EDNS0 RR with one EDNS0 ECS option, fixing the AR count */
   string EDNSRR;
   struct dnsheader* dh = reinterpret_cast<struct dnsheader*>(packet);
-  generateOptRR(newECSOption, EDNSRR, g_EdnsUDPPayloadSize, false);
+  generateOptRR(newECSOption, EDNSRR, g_EdnsUDPPayloadSize, 0, false);
 
   /* does it fit in the existing buffer? */
   if (packetSize - *len <= EDNSRR.size()) {
@@ -464,9 +464,7 @@ static int removeEDNSOptionFromOptions(unsigned char* optionsStart, const uint16
 
 int removeEDNSOptionFromOPT(char* optStart, size_t* optLen, const uint16_t optionCodeToRemove)
 {
-  /* we need at least:
-     root label (1), type (2), class (2), ttl (4) + rdlen (2)*/
-  if (*optLen < 11) {
+  if (*optLen < optRecordMinimumSize) {
     return EINVAL;
   }
   const unsigned char* end = (const unsigned char*) optStart + *optLen;
@@ -490,23 +488,21 @@ int removeEDNSOptionFromOPT(char* optStart, size_t* optLen, const uint16_t optio
 
 bool isEDNSOptionInOpt(const std::string& packet, const size_t optStart, const size_t optLen, const uint16_t optionCodeToFind, size_t* optContentStart, uint16_t* optContentLen)
 {
-  /* we need at least:
-   root label (1), type (2), class (2), ttl (4) + rdlen (2)*/
-  if (optLen < 11) {
+  if (optLen < optRecordMinimumSize) {
     return false;
   }
   size_t p = optStart + 9;
-  uint16_t rdLen = (0x100*packet.at(p) + packet.at(p+1));
+  uint16_t rdLen = (0x100*static_cast<unsigned char>(packet.at(p)) + static_cast<unsigned char>(packet.at(p+1)));
   p += sizeof(rdLen);
-  if (rdLen > (optLen - 11)) {
+  if (rdLen > (optLen - optRecordMinimumSize)) {
     return false;
   }
 
   size_t rdEnd = p + rdLen;
   while ((p + 4) <= rdEnd) {
-    const uint16_t optionCode = 0x100*packet.at(p) + packet.at(p+1);
+    const uint16_t optionCode = 0x100*static_cast<unsigned char>(packet.at(p)) + static_cast<unsigned char>(packet.at(p+1));
     p += sizeof(optionCode);
-    const uint16_t optionLen = 0x100*packet.at(p) + packet.at(p+1);
+    const uint16_t optionLen = 0x100*static_cast<unsigned char>(packet.at(p)) + static_cast<unsigned char>(packet.at(p+1));
     p += sizeof(optionLen);
 
     if ((p + optionLen) > rdEnd) {
@@ -626,14 +622,14 @@ int rewriteResponseWithoutEDNSOption(const std::string& initialPacket, const uin
   return 0;
 }
 
-bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize)
+bool addEDNS(dnsheader* dh, uint16_t& len, const size_t size, bool dnssecOK, uint16_t payloadSize, uint8_t ednsrcode)
 {
   if (dh->arcount != 0) {
     return false;
   }
 
   std::string optRecord;
-  generateOptRR(std::string(), optRecord, payloadSize, dnssecOK);
+  generateOptRR(std::string(), optRecord, payloadSize, ednsrcode, dnssecOK);
 
   if (optRecord.size() >= size || (size - optRecord.size()) < len) {
     return false;
@@ -679,7 +675,7 @@ bool addEDNSToQueryTurnedResponse(DNSQuestion& dq)
 
   if (g_addEDNSToSelfGeneratedResponses) {
     /* now we need to add a new OPT record */
-    return addEDNS(dq.dh, dq.len, dq.size, dnssecOK, g_PayloadSizeSelfGenAnswers);
+    return addEDNS(dq.dh, dq.len, dq.size, dnssecOK, g_PayloadSizeSelfGenAnswers, dq.ednsRCode);
   }
 
   /* otherwise we are just fine */
@@ -741,3 +737,31 @@ bool queryHasEDNS(const DNSQuestion& dq)
 
   return false;
 }
+
+bool getEDNS0Record(const DNSQuestion& dq, EDNS0Record& edns0)
+{
+  uint16_t optStart;
+  size_t optLen = 0;
+  bool last = false;
+  const char * packet = reinterpret_cast<const char*>(dq.dh);
+  std::string packetStr(packet, dq.len);
+  int res = locateEDNSOptRR(packetStr, &optStart, &optLen, &last);
+  if (res != 0) {
+    // no EDNS OPT RR
+    return false;
+  }
+
+  if (optLen < optRecordMinimumSize) {
+    return false;
+  }
+
+  if (optStart < dq.len && packetStr.at(optStart) != 0) {
+    // OPT RR Name != '.'
+    return false;
+  }
+
+  static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t) AKA RR TTL size");
+  // copy out 4-byte "ttl" (really the EDNS0 record), after root label (1) + type (2) + class (2).
+  memcpy(&edns0, packet + optStart + 5, sizeof edns0);
+  return true;
+}