]> git.ipfire.org Git - thirdparty/pdns.git/blobdiff - pdns/dnsname.cc
dnsdist: Add HTTPStatusAction to return a specific HTTP response
[thirdparty/pdns.git] / pdns / dnsname.cc
index c9dee777048ce09c761fdbd59706373d5e34b9cd..b2936ec757ea68834e33a287c5a5cb3387b70276 100644 (file)
@@ -22,6 +22,7 @@
 #include "dnsname.hh"
 #include <boost/format.hpp>
 #include <string>
+#include <cinttypes>
 
 #include "dnswriter.hh"
 #include "misc.hh"
@@ -165,15 +166,27 @@ std::string DNSName::toString(const std::string& separator, const bool trailing)
     throw std::out_of_range("Attempt to print an unset dnsname");
   }
 
- if(isRoot())
 if(isRoot())
     return trailing ? separator : "";
 
   std::string ret;
-  for(const auto& s : getRawLabels()) {
-    ret+= escapeLabel(s) + separator;
-  }
+  ret.reserve(d_storage.size());
+
+  {
+    // iterate over the raw labels
+    const char* p = d_storage.c_str();
+    const char* end = p + d_storage.size();
 
-  return ret.substr(0, ret.size()-!trailing);
+    while (p < end && *p) {
+      appendEscapedLabel(ret, p + 1, static_cast<size_t>(*p));
+      ret += separator;
+      p += *p + 1;
+    }
+  }
+  if (!trailing) {
+    ret.resize(ret.size() - separator.size());
+  }
+  return ret;
 }
 
 std::string DNSName::toLogString() const
@@ -338,9 +351,9 @@ bool DNSName::slowCanonCompare(const DNSName& rhs) const
   return std::lexicographical_compare(ours.rbegin(), ours.rend(), rhsLabels.rbegin(), rhsLabels.rend(), CIStringCompare());
 }
 
-vector<string> DNSName::getRawLabels() const
+vector<std::string> DNSName::getRawLabels() const
 {
-  vector<string> ret;
+  vector<std::string> ret;
   ret.reserve(countLabels());
   // 3www4ds9a2nl0
   for(const unsigned char* p = (const unsigned char*) d_storage.c_str(); p < ((const unsigned char*) d_storage.c_str()) + d_storage.size() && *p; p+=*p+1) {
@@ -397,8 +410,13 @@ bool DNSName::isHostname() const
 unsigned int DNSName::countLabels() const
 {
   unsigned int count=0;
-  for(const unsigned char* p = (const unsigned char*) d_storage.c_str(); p < ((const unsigned char*) d_storage.c_str()) + d_storage.size() && *p; p+=*p+1)
+  const unsigned char* p = reinterpret_cast<const unsigned char*>(d_storage.c_str());
+  const unsigned char* end = reinterpret_cast<const unsigned char*>(p + d_storage.size());
+
+  while (p < end && *p) {
     ++count;
+    p += *p + 1;
+  }
   return count;
 }
 
@@ -414,20 +432,27 @@ size_t hash_value(DNSName const& d)
   return d.hash();
 }
 
-string DNSName::escapeLabel(const std::string& label)
+void DNSName::appendEscapedLabel(std::string& appendTo, const char* orig, size_t len)
 {
-  string ret;
-  ret.reserve(label.size()); // saves 15% on bulk .COM load
-  for(uint8_t p : label) {
+  size_t pos = 0;
+
+  while (pos < len) {
+    auto p = static_cast<uint8_t>(orig[pos]);
     if(p=='.')
-      ret+="\\.";
+      appendTo+="\\.";
     else if(p=='\\')
-      ret+="\\\\";
-    else if(p > 0x21 && p < 0x7e)
-      ret.append(1, (char)p);
+      appendTo+="\\\\";
+    else if(p > 0x20 && p < 0x7f)
+      appendTo.append(1, (char)p);
     else {
-      ret+="\\" + (boost::format("%03d") % (unsigned int)p).str();
+      char buf[] = "000";
+      auto got = snprintf(buf, sizeof(buf), "%03" PRIu8, p);
+      if (got < 0 || static_cast<size_t>(got) >= sizeof(buf)) {
+        throw std::runtime_error("Error, snprintf returned " + std::to_string(got) + " while escaping label " + std::string(orig, len));
+      }
+      appendTo.append(1, '\\');
+      appendTo += buf;
     }
+    ++pos;
   }
-  return ret;
 }