{QType::NAPTR, {{QType::A, QType::AAAA, QType::SRV}, SyncRes::AddtionalMode::ResolveImmediately}}
};
-void SyncRes::getAdditionals(const DNSName& qname, QType qtype, AddtionalMode mode, std::set<DNSRecord>& additionals, unsigned int depth)
+void SyncRes::resolveAdditionals(const DNSName& qname, QType qtype, AddtionalMode mode, std::vector<DNSRecord>& additionals, unsigned int depth)
{
vector<DNSRecord> addRecords;
vState state = vState::Indeterminate;
switch (mode) {
case AddtionalMode::ResolveImmediately: {
- set<GetBestNSAnswer> lbeenthere;
- int res = doResolve(qname, qtype, addRecords, depth, lbeenthere, state);
+ set<GetBestNSAnswer> beenthere;
+ int res = doResolve(qname, qtype, addRecords, depth, beenthere, state);
if (res != 0) {
return;
}
if (vStateIsBogus(state)) {
return;
}
- for (auto rec : addRecords) {
+ for (const auto& rec : addRecords) {
if (rec.d_place == DNSResourceRecord::ANSWER) {
- rec.d_place = DNSResourceRecord::ADDITIONAL;
- additionals.insert(rec);
+ additionals.push_back(rec);
}
}
break;
if (vStateIsBogus(state)) {
return;
}
- for (auto rec : addRecords) {
+ for (auto& rec : addRecords) {
if (rec.d_place == DNSResourceRecord::ANSWER) {
- rec.d_place = DNSResourceRecord::ADDITIONAL;
rec.d_ttl -= d_now.tv_sec ;
- additionals.insert(rec);
+ additionals.push_back(rec);
}
}
break;
}
case AddtionalMode::ResolveDeferred:
// 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.
break;
case AddtionalMode::Ignore:
break;
}
}
+// The main (recursive) function to add additonals
+// qtype: the original query type to expand
+// start: records to start from
+// This function uses to state sets to avoid infinite recursion
+// 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::pair<DNSName, QType>>& uniqueResults, unsigned int depth, unsigned additionaldepth)
+{
+ if (additionaldepth >= 5 || start.empty()) {
+ return;
+ }
+ const auto it = additionalTypes.find(qtype);
+ if (it == additionalTypes.end()) {
+ return;
+ }
+ std::unordered_set<DNSName> addnames;
+ for (const auto& rec : start) {
+ if (rec.d_place == DNSResourceRecord::ANSWER) {
+ // currently, this funtion only knows about names, we could also take the target types that are dependent on
+ // reord contents into account
+ // e.g. for NAPTR records, go only for SRV for flag value "s", or A/AAAA for flag value "a"
+ allowAdditionalEntry(addnames, rec);
+ }
+ }
+
+ auto mode = it->second.second;
+ for (const auto& targettype : it->second.first) {
+ for (const auto& addname : addnames) {
+ if ((targettype == QType::A && !s_doIPv4) || (targettype == QType::AAAA && !s_doIPv6)) {
+ continue;
+ }
+ std::vector<DNSRecord> records;
+ if (uniqueCalls.count(std::pair(addname, targettype)) == 0) {
+ uniqueCalls.emplace(addname, targettype);
+ resolveAdditionals(addname, targettype, mode, records, depth);
+ }
+ if (!records.empty()) {
+ for (auto r = records.begin(); r != records.end(); ) {
+ if (uniqueResults.count(std::pair(r->d_name, QType(r->d_type))) > 0) {
+ // A bit expensive for vectors, but they are small
+ r = records.erase(r);
+ } else {
+ ++r;
+ }
+ }
+ for (const auto& r : records) {
+ additionals.push_back(r);
+ uniqueResults.emplace(r.d_name, r.d_type);
+ }
+ addAdditionals(targettype, records, additionals, uniqueCalls, uniqueResults, depth, additionaldepth + 1);
+ }
+ }
+ }
+}
+
+// The entry point for other code
+void SyncRes::addAdditionals(QType qtype, vector<DNSRecord>&ret, unsigned int depth)
+{
+ // The additional records of interest
+ std::vector<DNSRecord> additionals;
+
+ // We only call resolve for a specific name/type combo once
+ std::set<std::pair<DNSName, QType>> uniqueCalls;
+
+ // Collect multiple name/qtype from a single resolve but do not add a new set from new resolve calls
+ std::set<std::pair<DNSName, QType>> uniqueResults;
+
+ addAdditionals(qtype, ret, additionals, uniqueCalls, uniqueResults, depth, 0);
+
+ for (auto& rec : additionals) {
+ rec.d_place = DNSResourceRecord::ADDITIONAL;
+ ret.push_back(rec);
+ }
+}
+
/** everything begins here - this is the entry point just after receiving a packet */
int SyncRes::beginResolve(const DNSName &qname, const QType qtype, QClass qclass, vector<DNSRecord>&ret, unsigned int depth)
{
}
}
- const auto it = additionalTypes.find(qtype);
- if (it != additionalTypes.end()) {
- std::unordered_set<DNSName> addnames;
- for (const auto& rec : ret) {
- if (rec.d_place == DNSResourceRecord::ANSWER) {
- allowAdditionalEntry(addnames, rec);
- }
- }
- std::set<DNSRecord> additionals;
- auto mode = it->second.second;
- for (const auto& targettype : it->second.first) {
- for (const auto& addname : addnames) {
- vector<DNSRecord> addRecords;
- if ((targettype == QType::A && !s_doIPv4) || (targettype == QType::AAAA && !s_doIPv6)) {
- continue;
- }
- getAdditionals(addname, targettype, mode, additionals, depth);
- }
- }
- for (const auto& rec : additionals) {
- ret.push_back(rec);
- }
+ if (qclass == QClass::IN && additionalTypes.find(qtype) != additionalTypes.end()) {
+ addAdditionals(qtype, ret, depth);
}
d_eventTrace.add(RecEventTrace::SyncRes, res, false);
return res;
typedef std::function<LWResult::Result(const ComboAddress& ip, const DNSName& qdomain, int qtype, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, boost::optional<Netmask>& srcmask, boost::optional<const ResolveContext&> context, LWResult *lwr, bool* chained)> asyncresolve_t;
enum class HardenNXD { No, DNSSEC, Yes };
-
+
+ enum class AddtionalMode : uint8_t {
+ Ignore,
+ CacheOnly,
+ CacheOnlyRequireAuth,
+ ResolveImmediately,
+ ResolveDeferred
+ };
+
//! This represents a number of decaying Ewmas, used to store performance per nameserver-name.
/** Modelled to work mostly like the underlying DecayingEwma */
struct DecayingEwmaCollection
explicit SyncRes(const struct timeval& now);
- enum class AddtionalMode : uint8_t {
- Ignore,
- CacheOnly,
- CacheOnlyRequireAuth,
- ResolveImmediately,
- ResolveDeferred
- };
-
- void getAdditionals(const DNSName& qname, QType qtype, AddtionalMode, std::set<DNSRecord>& additionals, unsigned int depth);
int beginResolve(const DNSName &qname, QType qtype, QClass qclass, vector<DNSRecord>&ret, unsigned int depth = 0);
void setId(int id)
typedef std::map<DNSName,vState> zonesStates_t;
enum StopAtDelegation { DontStop, Stop, Stopped };
+ void resolveAdditionals(const DNSName& qname, QType qtype, AddtionalMode, std::vector<DNSRecord>& additionals, unsigned int depth);
+ void addAdditionals(QType qtype, const vector<DNSRecord>&start, vector<DNSRecord>&addditionals, std::set<std::pair<DNSName, QType>>& uniqueCalls, std::set<std::pair<DNSName, QType>>& uniqueResults, unsigned int depth, unsigned int adddepth);
+ void addAdditionals(QType qtype, vector<DNSRecord>&ret, unsigned int depth);
+
bool doDoTtoAuth(const DNSName& ns) const;
int doResolveAt(NsSet &nameservers, DNSName auth, bool flawedNSSet, const DNSName &qname, QType qtype, vector<DNSRecord>&ret,
unsigned int depth, set<GetBestNSAnswer>&beenthere, vState& state, StopAtDelegation* stopAtDelegation);