From: Ensar Sarajčić Date: Mon, 3 Jun 2024 14:27:34 +0000 (+0200) Subject: rec: add `udr-ignore-list` option X-Git-Tag: rec-5.2.0-alpha0~19^2~16 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=74a82fadb8ffab3f06de46805548a28da45d1fd4;p=thirdparty%2Fpdns.git rec: add `udr-ignore-list` option This adds a `udr-ignore-list` option, similar to `new-domain-ignore-list` option which can be used to provide a list of domains to not consider for UDR algorithm. Fixes: #14273 --- diff --git a/pdns/recursordist/docs/nod_udr.rst b/pdns/recursordist/docs/nod_udr.rst index 2da15412ad..705090633d 100644 --- a/pdns/recursordist/docs/nod_udr.rst +++ b/pdns/recursordist/docs/nod_udr.rst @@ -59,6 +59,8 @@ The data is persisted to /var/lib/pdns-recursor/udr by default, which can be cha The SBF (which is maintained separately per recursor thread) cell size defaults to 67108864, which can be changed using the setting ``unique-response-db-size``. The same caveats regarding FPs/FNs apply as for NOD. +Similarly to NOD, administrators may wish to prevent certain domains or subdomains from ever triggering the UDR algorithm, in which case those domains must be added to the ``udr-ignore-list`` setting as a comma separated list. No domain (or subdomain of a domain) listed will be considered a new unique domain response. + Similarly to NOD, unique domain responses can be tracked using several mechanisms: Logging diff --git a/pdns/recursordist/pdns_recursor.cc b/pdns/recursordist/pdns_recursor.cc index 5e0c98ee5a..f43314b2d1 100644 --- a/pdns/recursordist/pdns_recursor.cc +++ b/pdns/recursordist/pdns_recursor.cc @@ -664,22 +664,25 @@ static void sendNODLookup(Logr::log_t nodlogger, const DNSName& dname) static bool udrCheckUniqueDNSRecord(Logr::log_t nodlogger, const DNSName& dname, uint16_t qtype, const DNSRecord& record) { bool ret = false; - if (record.d_place == DNSResourceRecord::ANSWER || record.d_place == DNSResourceRecord::ADDITIONAL) { - // Create a string that represent a triplet of (qname, qtype and RR[type, name, content]) - std::stringstream strStream; - strStream << dname.toDNSStringLC() << ":" << qtype << ":" << qtype << ":" << record.d_type << ":" << record.d_name.toDNSStringLC() << ":" << record.getContent()->getZoneRepresentation(); - if (g_udrDBp && g_udrDBp->isUniqueResponse(strStream.str())) { - if (g_udrLog) { - // This should also probably log to a dedicated file. - SLOG(g_log << Logger::Notice << "Unique response observed: qname=" << dname << " qtype=" << QType(qtype) << " rrtype=" << QType(record.d_type) << " rrname=" << record.d_name << " rrcontent=" << record.getContent()->getZoneRepresentation() << endl, - nodlogger->info(Logr::Notice, "New response observed", - "qtype", Logging::Loggable(QType(qtype)), - "rrtype", Logging::Loggable(QType(record.d_type)), - "rrname", Logging::Loggable(record.d_name), - "rrcontent", Logging::Loggable(record.getContent()->getZoneRepresentation()));); - } - t_Counters.at(rec::Counter::udrCount)++; - ret = true; + // First check the (sub)domain isn't ignored for UDR purposes + if (!g_udrDomainWL.check(dname)) { + if (record.d_place == DNSResourceRecord::ANSWER || record.d_place == DNSResourceRecord::ADDITIONAL) { + // Create a string that represent a triplet of (qname, qtype and RR[type, name, content]) + std::stringstream strStream; + strStream << dname.toDNSStringLC() << ":" << qtype << ":" << qtype << ":" << record.d_type << ":" << record.d_name.toDNSStringLC() << ":" << record.getContent()->getZoneRepresentation(); + if (g_udrDBp && g_udrDBp->isUniqueResponse(strStream.str())) { + if (g_udrLog) { + // This should also probably log to a dedicated file. + SLOG(g_log << Logger::Notice << "Unique response observed: qname=" << dname << " qtype=" << QType(qtype) << " rrtype=" << QType(record.d_type) << " rrname=" << record.d_name << " rrcontent=" << record.getContent()->getZoneRepresentation() << endl, + nodlogger->info(Logr::Notice, "New response observed", + "qtype", Logging::Loggable(QType(qtype)), + "rrtype", Logging::Loggable(QType(record.d_type)), + "rrname", Logging::Loggable(record.d_name), + "rrcontent", Logging::Loggable(record.getContent()->getZoneRepresentation()));); + } + t_Counters.at(rec::Counter::udrCount)++; + ret = true; + } } } return ret; diff --git a/pdns/recursordist/rec-main.cc b/pdns/recursordist/rec-main.cc index 2b2d1705b3..11c75955c8 100644 --- a/pdns/recursordist/rec-main.cc +++ b/pdns/recursordist/rec-main.cc @@ -92,6 +92,7 @@ bool g_nodEnabled; DNSName g_nodLookupDomain; bool g_nodLog; SuffixMatchNode g_nodDomainWL; +SuffixMatchNode g_udrDomainWL; std::string g_nod_pbtag; bool g_udrEnabled; bool g_udrLog; @@ -867,6 +868,15 @@ static void parseNODIgnorelist(const std::string& wlist) } } +static void parseUDRIgnorelist(const std::string& wlist) +{ + vector parts; + stringtok(parts, wlist, ",; "); + for (const auto& part : parts) { + g_udrDomainWL.add(DNSName(part)); + } +} + static void setupNODGlobal() { // Setup NOD subsystem @@ -881,6 +891,7 @@ static void setupNODGlobal() g_udrLog = ::arg().mustDo("unique-response-log"); g_nod_pbtag = ::arg()["new-domain-pb-tag"]; g_udr_pbtag = ::arg()["unique-response-pb-tag"]; + parseUDRIgnorelist(::arg()["udr-ignore-list"]); } #endif /* NOD_ENABLED */ diff --git a/pdns/recursordist/rec-main.hh b/pdns/recursordist/rec-main.hh index c69e4de74a..67e60785ad 100644 --- a/pdns/recursordist/rec-main.hh +++ b/pdns/recursordist/rec-main.hh @@ -245,6 +245,7 @@ extern bool g_nodEnabled; extern DNSName g_nodLookupDomain; extern bool g_nodLog; extern SuffixMatchNode g_nodDomainWL; +extern SuffixMatchNode g_udrDomainWL; extern std::string g_nod_pbtag; extern bool g_udrEnabled; extern bool g_udrLog; diff --git a/pdns/recursordist/settings/table.py b/pdns/recursordist/settings/table.py index e16200c7d1..758d3ed6f7 100644 --- a/pdns/recursordist/settings/table.py +++ b/pdns/recursordist/settings/table.py @@ -1795,6 +1795,23 @@ feature. ''', 'versionadded': '4.5.0' }, + { + 'name' : 'udr_ignore_list', + 'section' : 'nod', + 'oldname' : 'udr-ignore-list', + 'type' : LType.ListStrings, + 'default' : '', + 'help' : 'List of domains (and implicitly all subdomains) which will never be considered for UDR', + 'doc' : ''' +This setting is a list of all domains (and implicitly all subdomains) +that will never be considered for a new unique domain request. +For example, if the domain 'xyz123.tv' is in the list, then 'foo.bar.xyz123.tv' +will never be considered for a new unique domain request. One use-case for the +ignore list is to never reveal details of internal subdomains +via the new-domain-lookup feature. + ''', + 'versionadded' : '5.1.0' + }, { 'name' : 'pb_tag', 'section' : 'nod',