|
@@ -26,8 +26,10 @@
|
|
|
|
|
|
#include <dns/question.h>
|
|
|
#include <dns/message.h>
|
|
|
+#include <dns/opcode.h>
|
|
|
|
|
|
#include <resolve/resolve.h>
|
|
|
+#include <cache/resolver_cache.h>
|
|
|
|
|
|
#include <asio.hpp>
|
|
|
#include <asiolink/dns_service.h>
|
|
@@ -123,7 +125,7 @@ private:
|
|
|
asio::deadline_timer lookup_timer;
|
|
|
|
|
|
size_t queries_out_;
|
|
|
-
|
|
|
+
|
|
|
// If we timed out ourselves (lookup timeout), stop issuing queries
|
|
|
bool done_;
|
|
|
|
|
@@ -132,6 +134,26 @@ private:
|
|
|
// answer if we do find one later (or if we have a lookup_timeout)
|
|
|
bool answer_sent_;
|
|
|
|
|
|
+ // Reference to our cache
|
|
|
+ isc::cache::ResolverCache& cache_;
|
|
|
+
|
|
|
+ // perform a single lookup; first we check the cache to see
|
|
|
+ // if we have a response for our query stored already. if
|
|
|
+ // so, call handlerecursiveresponse(), if not, we call send()
|
|
|
+ void doLookup() {
|
|
|
+ dlog("doLookup: try cache");
|
|
|
+ Message cached_message(Message::RENDER);
|
|
|
+ isc::resolve::initResponseMessage(question_, cached_message);
|
|
|
+ if (cache_.lookup(question_.getName(), question_.getType(),
|
|
|
+ question_.getClass(), cached_message)) {
|
|
|
+ dlog("Message found in cache, returning that");
|
|
|
+ handleRecursiveAnswer(cached_message);
|
|
|
+ } else {
|
|
|
+ send();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
// (re)send the query to the server.
|
|
|
void send() {
|
|
|
const int uc = upstream_->size();
|
|
@@ -184,6 +206,11 @@ private:
|
|
|
question_, incoming, cname_target, cname_count_, true);
|
|
|
|
|
|
bool found_ns_address = false;
|
|
|
+
|
|
|
+ // If the packet is OK, store it in the cache
|
|
|
+ if (!isc::resolve::ResponseClassifier::error(category)) {
|
|
|
+ cache_.update(incoming);
|
|
|
+ }
|
|
|
|
|
|
switch (category) {
|
|
|
case isc::resolve::ResponseClassifier::ANSWER:
|
|
@@ -213,7 +240,7 @@ private:
|
|
|
question_.getType());
|
|
|
|
|
|
dlog("Following CNAME chain to " + question_.toText());
|
|
|
- send();
|
|
|
+ doLookup();
|
|
|
return false;
|
|
|
break;
|
|
|
case isc::resolve::ResponseClassifier::NXDOMAIN:
|
|
@@ -245,11 +272,16 @@ private:
|
|
|
// TODO should use NSAS
|
|
|
zone_servers_.push_back(addr_t(addr_str, 53));
|
|
|
found_ns_address = true;
|
|
|
+ break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
if (found_ns_address) {
|
|
|
// next resolver round
|
|
|
+ // we do NOT use doLookup() here, but send() (i.e. we
|
|
|
+ // skip the cache), since if we had the final answer
|
|
|
+ // instead of a delegation cached, we would have been
|
|
|
+ // there by now.
|
|
|
send();
|
|
|
return false;
|
|
|
} else {
|
|
@@ -291,7 +323,8 @@ public:
|
|
|
OutputBufferPtr buffer,
|
|
|
isc::resolve::ResolverInterface::CallbackPtr cb,
|
|
|
int query_timeout, int client_timeout, int lookup_timeout,
|
|
|
- unsigned retries) :
|
|
|
+ unsigned retries,
|
|
|
+ isc::cache::ResolverCache& cache) :
|
|
|
io_(io),
|
|
|
question_(question),
|
|
|
answer_message_(answer_message),
|
|
@@ -306,7 +339,8 @@ public:
|
|
|
lookup_timer(io.get_io_service()),
|
|
|
queries_out_(0),
|
|
|
done_(false),
|
|
|
- answer_sent_(false)
|
|
|
+ answer_sent_(false),
|
|
|
+ cache_(cache)
|
|
|
{
|
|
|
// Setup the timer to stop trying (lookup_timeout)
|
|
|
if (lookup_timeout >= 0) {
|
|
@@ -328,7 +362,7 @@ public:
|
|
|
setZoneServersToRoot();
|
|
|
}
|
|
|
|
|
|
- send();
|
|
|
+ doLookup();
|
|
|
}
|
|
|
|
|
|
void setZoneServersToRoot() {
|
|
@@ -369,6 +403,26 @@ public:
|
|
|
done_ = true;
|
|
|
if (resume && !answer_sent_) {
|
|
|
answer_sent_ = true;
|
|
|
+
|
|
|
+ // There are two types of messages we could store in the
|
|
|
+ // cache;
|
|
|
+ // 1. answers to our fetches from authoritative servers,
|
|
|
+ // exactly as we receive them, and
|
|
|
+ // 2. answers to queries we received from clients, which
|
|
|
+ // have received additional processing (following CNAME
|
|
|
+ // chains, for instance)
|
|
|
+ //
|
|
|
+ // Doing only the first would mean we would have to re-do
|
|
|
+ // processing when we get data from our cache, and doing
|
|
|
+ // only the second would miss out on the side-effect of
|
|
|
+ // having nameserver data in our cache.
|
|
|
+ //
|
|
|
+ // So right now we do both. Since the cache (currently)
|
|
|
+ // stores Messages on their question section only, this
|
|
|
+ // does mean that we overwrite the messages we stored in
|
|
|
+ // the previous iteration if we are following a delegation.
|
|
|
+ cache_.update(*answer_message_);
|
|
|
+
|
|
|
resolvercallback_->success(answer_message_);
|
|
|
} else {
|
|
|
resolvercallback_->failure();
|
|
@@ -426,12 +480,26 @@ RecursiveQuery::resolve(const QuestionPtr& question,
|
|
|
IOService& io = dns_service_.getIOService();
|
|
|
|
|
|
MessagePtr answer_message(new Message(Message::RENDER));
|
|
|
+ isc::resolve::initResponseMessage(*question, *answer_message);
|
|
|
+
|
|
|
OutputBufferPtr buffer(new OutputBuffer(0));
|
|
|
-
|
|
|
- // It will delete itself when it is done
|
|
|
- new RunningQuery(io, *question, answer_message, upstream_,
|
|
|
- upstream_root_, buffer, callback, query_timeout_,
|
|
|
- client_timeout_, lookup_timeout_, retries_);
|
|
|
+
|
|
|
+ dlog("Try out cache first (direct call to resolve)");
|
|
|
+ // First try to see if we have something cached in the messagecache
|
|
|
+ if (cache_.lookup(question->getName(), question->getType(),
|
|
|
+ question->getClass(), *answer_message)) {
|
|
|
+ dlog("Message found in cache, returning that");
|
|
|
+ // TODO: err, should cache set rcode as well?
|
|
|
+ answer_message->setRcode(Rcode::NOERROR());
|
|
|
+ callback->success(answer_message);
|
|
|
+ } else {
|
|
|
+ dlog("Message not found in cache, starting recursive query");
|
|
|
+ // It will delete itself when it is done
|
|
|
+ new RunningQuery(io, *question, answer_message, upstream_,
|
|
|
+ upstream_root_, buffer, callback, query_timeout_,
|
|
|
+ client_timeout_, lookup_timeout_, retries_,
|
|
|
+ cache_);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
void
|
|
@@ -448,11 +516,26 @@ RecursiveQuery::resolve(const Question& question,
|
|
|
|
|
|
isc::resolve::ResolverInterface::CallbackPtr crs(
|
|
|
new isc::resolve::ResolverCallbackServer(server));
|
|
|
+
|
|
|
+ // TODO: general 'prepareinitialanswer'
|
|
|
+ answer_message->setOpcode(isc::dns::Opcode::QUERY());
|
|
|
+ answer_message->addQuestion(question);
|
|
|
|
|
|
- // It will delete itself when it is done
|
|
|
- new RunningQuery(io, question, answer_message, upstream_, upstream_root_,
|
|
|
- buffer, crs, query_timeout_, client_timeout_,
|
|
|
- lookup_timeout_, retries_);
|
|
|
+ // First try to see if we have something cached in the messagecache
|
|
|
+ dlog("Try out cache first (started by incoming event)");
|
|
|
+ if (cache_.lookup(question.getName(), question.getType(),
|
|
|
+ question.getClass(), *answer_message)) {
|
|
|
+ dlog("Message found in cache, returning that");
|
|
|
+ // TODO: err, should cache set rcode as well?
|
|
|
+ answer_message->setRcode(Rcode::NOERROR());
|
|
|
+ crs->success(answer_message);
|
|
|
+ } else {
|
|
|
+ dlog("Message not found in cache, starting recursive query");
|
|
|
+ // It will delete itself when it is done
|
|
|
+ new RunningQuery(io, question, answer_message, upstream_, upstream_root_,
|
|
|
+ buffer, crs, query_timeout_, client_timeout_,
|
|
|
+ lookup_timeout_, retries_, cache_);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
|