Commit 82f0bc8e authored by Jelte Jansen's avatar Jelte Jansen
Browse files

Merge branch 'trac501'

parents f1bb311e 629023f2
......@@ -37,5 +37,6 @@ libnsas_la_SOURCES += zone_entry.cc zone_entry.h
libnsas_la_SOURCES += fetchable.h
libnsas_la_SOURCES += address_request_callback.h
libnsas_la_SOURCES += random_number_generator.h
libnsas_la_SOURCES += glue_hints.h glue_hints.cc
CLEANFILES = *.gcno *.gcda
// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include "glue_hints.h"
#include <dns/rrset.h>
#include <dns/rdata.h>
#include <dns/rrtype.h>
#include <dns/rdataclass.h>
#include <asiolink/io_address.h>
#include <nsas/nameserver_entry.h>
using namespace isc::dns;
using namespace isc::nsas;
// This is a simple implementation for finding glue
//
// It iterates over the AUTHORITY section of the given Message,
// and for each NS RR it iterates over the ADDITIONAL section to
// see if there are A or AAAA records.
//
// Of course, this could be done more efficiently. One option is to
// reverse this; check for A and AAAA records (since those will only
// be there if there actually is glue, while NS records will be present
// in any delegation). However, it may be even better to let the
// Response Classifier decide on glue, while it is validating the packet
//
// (er, TODO, so to speak. discuss.)
// Helper functions
namespace {
// Add the contents of the given A or AAAA rrset to the given
// addressvector
//
// This creates an 'dummy' NameserverEntry value, because that
// is enforced by NameserverAddress. We may want to reconsider
// the need for that (perhaps we can change it so that if it is
// NULL, all NSAS-related calls to the NameserverAddress object
// become nops)
void
addRRset(std::vector<NameserverAddress>& addresses,
const RRsetPtr rrset)
{
const std::string ns_name = rrset->getName().toText();
RdataIteratorPtr rdi = rrset->getRdataIterator();
while (!rdi->isLast()) {
AddressEntry entry(asiolink::IOAddress(rdi->getCurrent().toText()));
boost::shared_ptr<NameserverEntry> ns_entry(new NameserverEntry(ns_name, rrset->getClass()));
NameserverAddress ns_address(ns_entry, entry, V4_ONLY);
addresses.push_back(ns_address);
rdi->next();
}
}
}
namespace isc {
namespace nsas {
GlueHints::GlueHints(const std::string& zone_name,
const isc::dns::Message& delegation_message)
{
for (RRsetIterator rssi = delegation_message.beginSection(Message::SECTION_AUTHORITY);
rssi != delegation_message.endSection(Message::SECTION_AUTHORITY);
++rssi) {
if ((*rssi)->getType() == RRType::NS() &&
(*rssi)->getName().toText() == zone_name) {
addGlueForRRset(*rssi, delegation_message);
}
}
}
bool
GlueHints::hasGlue(AddressFamily family) const {
return ((addresses_v4.size() > 0 && (family == ANY_OK || family == V4_ONLY)) ||
(addresses_v6.size() > 0 && (family == ANY_OK || family == V6_ONLY)));
}
NameserverAddress
GlueHints::getGlue(AddressFamily family) const {
// TODO: once we have a more general random lib, use that. Since
// this is simply glue, and we don't need a weighted selection,
// for now srandom should be good enough. Once #583 has been merged,
// (or better yet, once that one and the weighted random have gone
// together in a util lib), we can use that.
int max = 0;
size_t v4s = addresses_v4.size();
size_t v6s = addresses_v6.size();
if (family == ANY_OK || family == V4_ONLY) {
max += v4s;
}
if (family == ANY_OK || family == V6_ONLY) {
max += v6s;
}
assert(max > 0);
long int selection = random() % max;
if (family == ANY_OK) {
if (selection <= v4s) {
return addresses_v4[selection];
} else {
return addresses_v6[selection-v4s];
}
} else if (family == V4_ONLY) {
return addresses_v4[selection];
} else if (family == V6_ONLY) {
return addresses_v6[selection];
} else {
// Unknown family
assert(false);
}
}
// Add the A and AAAA records from the given message for the given
// NS name to the relevant address vector
// (A rrsets are added to addresses_v4, AAAA rrsets are added to
// addresses_v6).
void
GlueHints::addGlueForName(const Name& name, const Message& message)
{
for (RRsetIterator rssi = message.beginSection(Message::SECTION_ADDITIONAL);
rssi != message.endSection(Message::SECTION_ADDITIONAL);
++rssi) {
if ((*rssi)->getName() == name) {
if ((*rssi)->getType() == RRType::A()) {
addRRset(addresses_v4, *rssi);
} else if ((*rssi)->getType() == RRType::AAAA()) {
addRRset(addresses_v6, *rssi);
}
}
}
}
// Add the glue for the given NS RRset in the message to the
// relevant vectors.
void
GlueHints::addGlueForRRset(const RRsetPtr rrset, const Message& message)
{
RdataIteratorPtr rdi = rrset->getRdataIterator();
while (!rdi->isLast()) {
isc::dns::Name name(dynamic_cast<const rdata::generic::NS&>(
rdi->getCurrent()).getNSName());
addGlueForName(name, message);
rdi->next();
}
}
} // namespace nsas
} // namespace isc
// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef __GLUE_HINTS_H
#define __GLUE_HINTS_H
#include <vector>
#include <dns/message.h>
#include "nsas_types.h"
#include "nameserver_address.h"
namespace isc {
namespace nsas {
class GlueHints {
public:
/// \brief Empty constructor
GlueHints() {};
/// \brief Constructor
///
/// Creates a glue hint object, with the glue data found in the
/// given packet.
///
/// \param zone_name The name of the zone to find glue for
/// \param delegation_message The Message that may contain glue
GlueHints(const std::string& zone_name,
const isc::dns::Message& delegation_message);
/// \brief Check if there is glue for the given AddressFamily
///
/// \param family the AddressFamily to check for glue for
/// \return true if there is glue for that family. false if not
bool hasGlue(AddressFamily family) const;
/// \brief Get a random glue address for the given family
///
/// ONLY call this if hasGlue() returned true.
///
/// \param family the AddressFamily to get glue for
/// \return a NameserverAddress specified by the glue
NameserverAddress getGlue(AddressFamily family) const;
private:
void addGlueForName(const isc::dns::Name& name,
const isc::dns::Message& message);
void addGlueForRRset(const isc::dns::RRsetPtr rrset,
const isc::dns::Message& message);
std::vector<NameserverAddress> addresses_v4;
std::vector<NameserverAddress> addresses_v6;
};
}
}
#endif // __GLUE_HINTS_H
......@@ -29,6 +29,7 @@
#include "nameserver_entry.h"
#include "nameserver_address_store.h"
#include "zone_entry.h"
#include "glue_hints.h"
#include "address_request_callback.h"
using namespace isc::dns;
......@@ -80,7 +81,8 @@ newZone(
void
NameserverAddressStore::lookup(const string& zone, const RRClass& class_code,
boost::shared_ptr<AddressRequestCallback> callback, AddressFamily family)
boost::shared_ptr<AddressRequestCallback> callback, AddressFamily family,
const GlueHints glue_hints)
{
pair<bool, boost::shared_ptr<ZoneEntry> > zone_obj(zone_hash_->getOrAdd(HashKey(
zone, class_code), boost::bind(newZone, &resolver_, &zone, &class_code,
......@@ -90,7 +92,8 @@ NameserverAddressStore::lookup(const string& zone, const RRClass& class_code,
} else {
zone_lru_->touch(zone_obj.second);
}
zone_obj.second->addCallback(callback, family);
zone_obj.second->addCallback(callback, family, glue_hints);
}
void
......
......@@ -23,6 +23,7 @@
#include <resolve/resolver_interface.h>
#include "nsas_types.h"
#include "glue_hints.h"
namespace isc {
// Some forward declarations, so we do not need to include so many headers
......@@ -85,7 +86,7 @@ public:
/// \param family Which address is requested.
void lookup(const std::string& zone, const dns::RRClass& class_code,
boost::shared_ptr<AddressRequestCallback> callback, AddressFamily
family = ANY_OK);
family = ANY_OK, const GlueHints = GlueHints());
/// \brief cancel the given lookup action
///
......
......@@ -224,7 +224,8 @@ class ZoneEntry::ResolverCallback :
};
void
ZoneEntry::addCallback(CallbackPtr callback, AddressFamily family) {
ZoneEntry::addCallback(CallbackPtr callback, AddressFamily family,
const GlueHints glue_hints) {
Lock lock(mutex_);
bool ask(false);
......@@ -238,11 +239,18 @@ ZoneEntry::addCallback(CallbackPtr callback, AddressFamily family) {
if (getState() == EXPIRED || getState() == NOT_ASKED) {
ask = true;
}
// We do not have the answer right away, just queue the callback
bool execute(!ask && getState() != IN_PROGRESS &&
callbacks_[family].empty());
callbacks_[family].push_back(callback);
// Unless there was glue
if (ask && glue_hints.hasGlue(family)) {
callback->success(glue_hints.getGlue(family));
} else {
callbacks_[family].push_back(callback);
}
if (execute) {
// Try to process it right away, store if not possible to handle
process(family, NameserverPtr());
......
......@@ -32,6 +32,7 @@
#include "fetchable.h"
#include "nsas_types.h"
#include "random_number_generator.h"
#include "glue_hints.h"
namespace isc {
namespace nsas {
......@@ -97,9 +98,13 @@ public:
*
* \param callback The callback itself.
* \param family Which address family is acceptable as an answer?
* \param glue_hints If a non-empty glue-hints object is passed,
* and the NSAS does not have an immediate answer, it will
* call back immediately with one of the glue hints.
*/
void addCallback(boost::shared_ptr<AddressRequestCallback>
callback, AddressFamily family);
callback, AddressFamily family,
const GlueHints glue_hints = GlueHints());
/**
* \short Remove a callback from the list
......
......@@ -330,7 +330,7 @@ private:
isc::resolve::ResponseClassifier::classify(
question_, incoming, cname_target, cname_count_);
bool found_ns_address = false;
bool found_ns = false;
switch (category) {
case isc::resolve::ResponseClassifier::ANSWER:
......@@ -384,7 +384,7 @@ private:
// classifier should have error'd)
// TODO: should we check if it really is subzone?
for (RRsetIterator rrsi = incoming.beginSection(Message::SECTION_AUTHORITY);
rrsi != incoming.endSection(Message::SECTION_AUTHORITY) && !found_ns_address;
rrsi != incoming.endSection(Message::SECTION_AUTHORITY) && !found_ns;
++rrsi) {
ConstRRsetPtr rrs = *rrsi;
if (rrs->getType() == RRType::NS()) {
......@@ -393,18 +393,26 @@ private:
// libraries, so as not to need many conversions)
cur_zone_ = rrs->getName().toText();
dlog("Referred to zone " + cur_zone_);
found_ns_address = true;
found_ns = true;
break;
}
}
if (found_ns_address) {
if (found_ns) {
// 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();
GlueHints glue_hints(cur_zone_, incoming);
// Ask the NSAS for an address, or glue.
// This will eventually result in either sendTo()
// or stop() being called by nsas_callback_
assert(!nsas_callback_out_);
nsas_callback_out_ = true;
nsas_.lookup(cur_zone_, question_.getClass(),
nsas_callback_, ANY_OK, glue_hints);
return false;
} else {
dlog("No NS RRset in referral?");
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment