#include "dnsname.hh"
#include <boost/format.hpp>
#include <string>
+#include <cinttypes>
#include "dnswriter.hh"
#include "misc.hh"
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());
- return ret.substr(0, ret.size()-!trailing);
+ {
+ // iterate over the raw labels
+ const char* p = d_storage.c_str();
+ const char* end = p + d_storage.size();
+
+ 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
clear();
}
+DNSName DNSName::getCommonLabels(const DNSName& other) const
+{
+ DNSName result;
+
+ const std::vector<std::string> ours = getRawLabels();
+ const std::vector<std::string> others = other.getRawLabels();
+
+ for (size_t pos = 0; ours.size() > pos && others.size() > pos; pos++) {
+ const std::string& ourLabel = ours.at(ours.size() - pos - 1);
+ const std::string& otherLabel = others.at(others.size() - pos - 1);
+
+ if (!pdns_iequals(ourLabel, otherLabel)) {
+ break;
+ }
+
+ result.prependRawLabel(ourLabel);
+ }
+
+ return result;
+}
+
DNSName DNSName::labelReverse() const
{
DNSName ret;
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) {
throw std::out_of_range("trying to get label at position "+std::to_string(pos)+" of a DNSName that only has "+std::to_string(currentPos)+" labels");
}
+DNSName DNSName::getLastLabel() const
+{
+ DNSName ret(*this);
+ ret.trimToLabels(1);
+ return ret;
+}
+
bool DNSName::chopOff()
{
if(d_storage.empty() || d_storage[0]==0)
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;
}
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;
}