includeboilerplate(NAPTR)
template<class Convertor> void xfrRecordContent(Convertor& conv);
- string getFlags() const
+ const string& getFlags() const
{
return d_flags;
}
- DNSName getReplacement() const
+ const DNSName& getReplacement() const
{
return d_replacement;
}
}
void postPrepareContext() override
{
+ // clang-format off
+ d_pd.push_back({"AdditionalMode", in_t{
+ {"Ignore", static_cast<int>(AdditionalMode::Ignore)},
+ {"CacheOnly", static_cast<int>(AdditionalMode::CacheOnly)},
+ {"CacheOnlyRequireAuth", static_cast<int>(AdditionalMode::CacheOnlyRequireAuth)},
+ {"ResolveImmediately", static_cast<int>(AdditionalMode::ResolveImmediately)},
+ {"ResolveDeferred", static_cast<int>(AdditionalMode::ResolveDeferred)}
+ }});
}
void postLoad() override
{
});
#endif /* HAVE_FSTRM */
- Lua->writeFunction("addAllowedAdditionalQType", [&lci](int qtype, std::unordered_map<int, int> targetqtypes, boost::optional<std::map<std::string, std::string>> options) {
+ Lua->writeFunction("addAllowedAdditionalQType", [&lci](int qtype, std::unordered_map<int, int> targetqtypes, boost::optional<std::map<std::string, int>> options) {
switch (qtype) {
case QType::MX:
case QType::SRV:
if (options) {
if (const auto it = options->find("mode"); it != options->end()) {
- const map<string, AdditionalMode> modeMap = {
- {"Ignore", AdditionalMode::Ignore},
- {"CacheOnly", AdditionalMode::CacheOnly},
- {"CacheOnlyRequireAuth", AdditionalMode::CacheOnlyRequireAuth},
- {"ResolveImmediately", AdditionalMode::ResolveImmediately},
- {"ResolveDeferred", AdditionalMode::ResolveDeferred}};
- if (modeMap.find(it->second) == modeMap.end()) {
+ mode = static_cast<AdditionalMode>(it->second);
+ if (mode > AdditionalMode::ResolveDeferred) {
g_log << Logger::Error << "addAllowedAdditionalQType: unknown mode " << it->second << endl;
- return;
}
- mode = modeMap.at(it->second);
}
}
lci.allowAdditionalQTypes.insert_or_assign(qtype, pair(targets, mode));
.. code-block:: Lua
addAllowedAdditionalQType(pdns.MX, {pdns.A, pdns.AAAA})
- addAllowedAdditionalQType(pdns.NAPTR, {pdns.A, pdns.AAAA, pdns.SRV}, {mode="ResolveImmediately"})
+ addAllowedAdditionalQType(pdns.NAPTR, {pdns.A, pdns.AAAA, pdns.SRV}, {mode=pdns.AdditionalMode.ResolveImmediately})
The first line specifies that additional records should be added to the results of ``MX`` queries using the default mode.
The qtype of the records to be added are ``A`` and ``AAAA``.
-The default mode is ``CacheOnlyRequireAuth``, this mode will only look in the record cache.
+The default mode is ``pdns.AdditionalMode.CacheOnlyRequireAuth``, this mode will only look in the record cache.
The second line specifies that three record types should be added to ``NAPTR`` answers.
If needed, the Recursor will do an active resolve to retrieve these records.
The modes available are:
- * ``Ignore`` Do not do any additional processing for this qtype. This is equivalent to not calling :func:`addAllowedAdditionalQType` for the qtype.
- * ``CacheOnly`` Look in the record cache for available records. Allow non-authoritative (learned from additional sections received from authoritative servers) records to be added.
- * ``CacheOnlyRequireAuth`` Look in the record cache for available records. Only authoritative records will be added. These are records received from the nameservers for the specific domain.
- * ``ResolveImmediately`` Add records from the record cache (including DNSSEC records if relevant). If no record is found in the record cache, actively try to resolve the target name/qtype. This will delay the answer to the client.
- * ``ResolveDeferred`` Add records from the record cache (including DNSSEC records if relevant). If no record is found in the record cache and the negative cache also has no entry, schedule a background task to resolve the target name/qtype. The next time the query is processed, the cache might hold the relevant information. This mode is not implemented yet.
-If an additional record is not available at that time the query is stored into the packet cache the answer packet stored in the packer cache will not contain the additional record.
+``pdns.AdditionalMode.Ignore``
+ Do not do any additional processing for this qtype. This is equivalent to not calling :func:`addAllowedAdditionalQType` for the qtype.
+``pdns.AdditionalMode.CacheOnly``
+ Look in the record cache for available records. Allow non-authoritative (learned from additional sections received from authoritative servers) records to be added.
+``pdns.AdditionalMode.CacheOnlyRequireAuth``
+ Look in the record cache for available records. Only authoritative records will be added. These are records received from the nameservers for the specific domain.
+``pdns.AdditionalMode.ResolveImmediately``
+ Add records from the record cache (including DNSSEC records if relevant). If no record is found in the record cache, actively try to resolve the target name/qtype. This will delay the answer to the client.
+``pdns.AdditionalMode.ResolveDeferred``
+ Add records from the record cache (including DNSSEC records if relevant). If no record is found in the record cache and the negative cache also has no entry, schedule a background task to resolve the target name/qtype. The next time the query is processed, the cache might hold the relevant information. This mode is not implemented yet.
+
+If an additional record is not available at that time the query is stored into the packet cache the answer packet stored in the packet cache will not contain the additional record.
Clients repeating the same question will get an answer from the packet cache if the question is still in the packet cache.
-These answers do not have the additional record, even if in the meantime the record cache has learned it.
-Clients wil only see the additional record once the packet cache entry expires and the record cache is consulted again.
-The ``ResolveImmediately`` will not have this issue, at the cost of delaying the first query to resolve the additional records needed.
+These answers do not have the additional record, even if the record cache has learned it in the meantime .
+Clients will only see the additional record once the packet cache entry expires and the record cache is consulted again.
+The ``pdns.AdditionalMode.ResolveImmediately`` mode will not have this issue, at the cost of delaying the first query to resolve the additional records needed.
Configuring additional record processing
----------------------------------------
:param int qtype: the qtype number to enable additional record processing for. Supported are: ``pdns.MX``, ``pdns.SRV``, ``pdns.SVCB``, ``pdns.HTTPS`` and ``pdns.NAPTR``.
:param targets: the target qtypes to look for when adding the additionals. For example ``{pdns.A, pdns.AAAA}``.
:type targets: list of qtype numbers
- :param table options: a table of options. Currently the only option is ``mode`` having a string value. For the available modes, see above. If no mode is specified, the default ``"CacheOnlyRequireAuth"`` mode is used.
+ :param table options: a table of options. Currently the only option is ``mode`` having an integer value. For the available modes, see above. If no mode is specified, the default ``pdns.AdditionalMode.CacheOnlyRequireAuth`` mode is used.
-Lua Configuration: Trustanchors, Query Logging, RPZs, Sortlist and Zone to Cache
+Advanced Configuration Using Lua
================================================================================
Since version 4.0.0, the PowerDNS Recursor supports additional configuration options that have to be loaded through :ref:`setting-lua-config-file`.
if (shouldValidate() && state != vState::Secure && state != vState::Insecure) {
return;
}
- for (const auto& rec : addRecords) {
+ for (auto& rec : addRecords) {
if (rec.d_place == DNSResourceRecord::ANSWER) {
- additionals.push_back(rec);
+ additionals.push_back(std::move(rec));
}
}
break;
for (auto& rec : addRecords) {
if (rec.d_place == DNSResourceRecord::ANSWER) {
rec.d_ttl -= d_now.tv_sec ;
- additionals.push_back(rec);
+ additionals.push_back(std::move(rec));
}
}
break;
}
case AdditionalMode::ResolveDeferred:
- // Not yet implemented
+ // FIXME: Not yet implemented
// Look in cache for authoritative answer, if available return it
// If not, look in nergache and submit if not there as well. The logic should be the same as
// #11294, which is in review atm.
}
}
-// The main (recursive) function to add additonals
+// The main (recursive) function to add additionals
// qtype: the original query type to expand
// start: records to start from
-// This function uses to state sets to avoid infinite recursion
+// This function uses to state sets to avoid infinite recursion and allow depulication
// depth is the main recursion depth
// additionaldepth is the depth for addAdditionals itself
void SyncRes::addAdditionals(QType qtype, const vector<DNSRecord>&start, vector<DNSRecord>&additionals, std::set<std::pair<DNSName, QType>>& uniqueCalls, std::set<std::tuple<DNSName, QType, QType>>& uniqueResults, unsigned int depth, unsigned additionaldepth)
}
}
+ // We maintain two sets for deduplication:
+ // - uniqueCalls makes sure we never resolve a qname/qtype twice
+ // - uniqueResults makes sure we never add the same qname/qytype RRSet to the result twice,
+ // but note that that set might contain multiple elements.
+
auto mode = it->second.second;
for (const auto& targettype : it->second.first) {
for (const auto& addname : addnames) {
std::vector<DNSRecord> records;
- if (uniqueCalls.count(std::pair(addname, targettype)) == 0) {
- uniqueCalls.emplace(addname, targettype);
+ bool inserted = uniqueCalls.emplace(addname, targettype).second;
+ if (inserted) {
resolveAdditionals(addname, targettype, mode, records, depth);
}
if (!records.empty()) {
for (auto& rec : additionals) {
rec.d_place = DNSResourceRecord::ADDITIONAL;
- ret.push_back(rec);
+ ret.push_back(std::move(rec));
}
}
}
}
+ // Avoid calling addAdditionals() if we know we won't find anything
auto luaLocal = g_luaconfs.getLocal();
if (res == 0 && qclass == QClass::IN && luaLocal->allowAdditionalQTypes.find(qtype) != luaLocal->allowAdditionalQTypes.end()) {
addAdditionals(qtype, ret, depth);
allowedAdditionals.insert(target);
}
else {
- // Alias mode not implemented yet
+ // FIXME: Alias mode not implemented yet
}
}
break;
disable-packetcache
"""
_lua_config_file = """
- addAllowedAdditionalQType(pdns.MX, {pdns.A, pdns.AAAA}, { mode = "ResolveImmediately"})
- addAllowedAdditionalQType(pdns.NAPTR, {pdns.A, pdns.AAAA, pdns.SRV}, { mode = "ResolveImmediately"})
- addAllowedAdditionalQType(pdns.SRV, {pdns.A, pdns.AAAA}, { mode = "ResolveImmediately"})
+ addAllowedAdditionalQType(pdns.MX, {pdns.A, pdns.AAAA}, { mode = pdns.AdditionalMode.ResolveImmediately})
+ addAllowedAdditionalQType(pdns.NAPTR, {pdns.A, pdns.AAAA, pdns.SRV}, { mode = pdns.AdditionalMode.ResolveImmediately})
+ addAllowedAdditionalQType(pdns.SRV, {pdns.A, pdns.AAAA}, { mode = pdns.AdditionalMode.ResolveImmediately})
"""
def testMX(self):
disable-packetcache
"""
_lua_config_file = """
- addAllowedAdditionalQType(pdns.MX, {pdns.A, pdns.AAAA}, { mode = "ResolveImmediately"})
+ addAllowedAdditionalQType(pdns.MX, {pdns.A, pdns.AAAA}, { mode = pdns.AdditionalMode.ResolveImmediately})
"""
def testMX(self):