This flavour sorts labels made of digits numerically.
Co-Authored-By: Peter Samuelson <psamuelson@efolder.net>
Signed-off-by: Miod Vallat <miod.vallat@powerdns.com>
return 0; // eq
}
-int DNSName::canonCompare_three_way(const DNSName& rhs) const
+int DNSName::canonCompare_three_way(const DNSName& rhs, bool pretty) const
{
// 01234567890abcd
// us: 1a3www4ds9a2nl
rhscount--;
// NOLINTBEGIN(cppcoreguidelines-pro-bounds-pointer-arithmetic)
- int res = pdns_ilexicographical_compare_three_way(
- std::string_view(
- d_storage.c_str() + ourpos.at(ourcount) + 1,
- *(d_storage.c_str() + ourpos.at(ourcount))),
- std::string_view(
- rhs.d_storage.c_str() + rhspos.at(rhscount) + 1,
- *(rhs.d_storage.c_str() + rhspos.at(rhscount))));
+ const uint8_t ourlen = *(d_storage.c_str() + ourpos.at(ourcount));
+ const uint8_t rhslen = *(rhs.d_storage.c_str() + rhspos.at(rhscount));
+ std::string_view ourstr(d_storage.c_str() + ourpos.at(ourcount) + 1, ourlen);
+ std::string_view rhsstr(rhs.d_storage.c_str() + rhspos.at(rhscount) + 1, rhslen);
// NOLINTEND(cppcoreguidelines-pro-bounds-pointer-arithmetic)
+
+ // If pretty ordering requested, sort numerical values, well,
+ // numerically (i.e. 999.example.com < 1000.example.com).
+ // Do not use for anything but human-intended output, as this breaks
+ // the DNSSEC order.
+ if (pretty) {
+ // If both names are numerical (made of digits), then the longest one
+ // always compares higher.
+ if (ourlen != rhslen) {
+ bool isNumerical{true};
+ for (const auto chr : ourstr) {
+ if (std::isdigit(static_cast<unsigned char>(chr)) == 0) {
+ isNumerical = false;
+ break;
+ }
+ }
+ if (isNumerical) {
+ for (const auto chr : rhsstr) {
+ if (std::isdigit(static_cast<unsigned char>(chr)) == 0) {
+ isNumerical = false;
+ break;
+ }
+ }
+ }
+ if (isNumerical) {
+ return ourlen < rhslen ? -1 : 1;
+ }
+ }
+ }
+
+ int res = pdns_ilexicographical_compare_three_way(ourstr, rhsstr);
if (res != 0) {
return res;
}
}
int slowCanonCompare_three_way(const DNSName& rhs) const;
- int canonCompare_three_way(const DNSName& rhs) const;
- inline bool canonCompare(const DNSName& rhs) const { return canonCompare_three_way(rhs) < 0; }
+ int canonCompare_three_way(const DNSName& rhs, bool pretty = false) const;
+ inline bool canonCompare(const DNSName& rhs, bool pretty = false) const { return canonCompare_three_way(rhs, pretty) < 0; }
typedef boost::container::string string_t;
auto aType = (a.d_type == QType::SOA) ? 0 : a.d_type;
auto bType = (b.d_type == QType::SOA) ? 0 : b.d_type;
- int res = a.d_name.canonCompare_three_way(b.d_name);
+ int res = a.d_name.canonCompare_three_way(b.d_name, true);
if (res < 0) {
return true;
}
// DNSName
d_lw->writeFunction("newDN", [](const std::string& dom){ return DNSName(dom); });
d_lw->registerFunction("__lt", &DNSName::operator<);
- d_lw->registerFunction("canonCompare", &DNSName::canonCompare);
+ d_lw->registerFunction<bool(DNSName::*)(const DNSName&)>("canonCompare", [](const DNSName& name, const DNSName& rhs) { return name.canonCompare(rhs); });
d_lw->registerFunction<DNSName(DNSName::*)(const DNSName&)>("makeRelative", [](const DNSName& name, const DNSName& zone) { return name.makeRelative(zone); });
d_lw->registerFunction<bool(DNSName::*)(const DNSName&)>("isPartOf", [](const DNSName& name, const DNSName& rhs) { return name.isPartOf(rhs); });
d_lw->registerFunction("getRawLabels", &DNSName::getRawLabels);
BOOST_CHECK(vec==right);
}
+BOOST_AUTO_TEST_CASE(test_compare_pretty) {
+ BOOST_CHECK(DNSName("99.2.1.10.in-addr.arpa").canonCompare(DNSName("101.2.1.10.in-addr.arpa"), true));
+ BOOST_CHECK(!DNSName("101.2.1.10.in-addr.arpa").canonCompare(DNSName("99.2.1.10.in-addr.arpa"), true));
+ BOOST_CHECK(DNSName("ns12.example.com").canonCompare(DNSName("ns8.example.com"), true));
+ BOOST_CHECK(!DNSName("ns8.example.com").canonCompare(DNSName("ns12.example.com"), true));
+ BOOST_CHECK(DNSName("135.org").canonCompare(DNSName("2x.org"), true));
+ BOOST_CHECK(!DNSName("2x.org").canonCompare(DNSName("135.org"), true));
+}
BOOST_AUTO_TEST_CASE(test_empty_label) { // empty label