Commit 1170780a authored by Mukund Sivaraman's avatar Mukund Sivaraman
Browse files

Merge branch 'master' into trac2052

Conflicts:
	src/lib/dns/name.cc
parents dbef0e25 1a0fc96a
451. [bug] muks, jinmei
libdatasrc: the database-based data source now correctly returns
glue records on (not under) a zone cut, such as in the case where
the NS name of an NS record is identical to its owner name. (Note:
libdatasrc itself doesn't judge what kind of record type can be a
"glue"; it's the caller's responsibility.)
(Trac #1771, git 483f1075942965f0340291e7ff7dae7806df22af)
450. [func]* tomek
b10-dhcp4: DHCPv4 server component is now integrated into
BIND10 framework. It can be started from BIND10 (using bindctl)
......
This diff is collapsed.
......@@ -110,6 +110,9 @@ look into the cause and address the issue. The log message includes
the client's address (and port), and the error message sent from the
lower layer that detects the failure.
% AUTH_RECEIVED_NOTIFY received incoming NOTIFY for zone name %1, zone class %2
This is a debug message reporting that an incoming NOTIFY was received.
% AUTH_NOTIFY_QUESTIONS invalid number of questions (%1) in incoming NOTIFY
This debug message is logged by the authoritative server when it receives
a NOTIFY packet that contains zero or more than one question. (A valid
......
......@@ -828,6 +828,9 @@ AuthSrvImpl::processNotify(const IOMessage& io_message, Message& message,
return (false);
}
LOG_DEBUG(auth_logger, DBG_AUTH_DETAIL, AUTH_RECEIVED_NOTIFY)
.arg(question->getName()).arg(question->getClass());
const string remote_ip_address =
io_message.getRemoteEndpoint().getAddress().toText();
static const string command_template_start =
......
......@@ -541,7 +541,7 @@ class SecureHTTPServer(socketserver_mixin.NoPollMixIn,
ssl_version = ssl.PROTOCOL_SSLv23)
return ssl_sock
except (ssl.SSLError, CmdctlException) as err :
logger.info(CMDCTL_SSL_SETUP_FAILURE_USER_DENIED, err)
logger.error(CMDCTL_SSL_SETUP_FAILURE_USER_DENIED, err)
self.close_request(sock)
# raise socket error to finish the request
raise socket.error
......
......@@ -20,7 +20,7 @@
<refentry>
<refentryinfo>
<date>August 4, 2010</date>
<date>June 25, 2012</date>
</refentryinfo>
<refmeta>
......@@ -91,10 +91,6 @@
</itemizedlist>
</para>
<para>
It listens on 127.0.0.1.
</para>
<para>
The <command>b10-msgq</command> daemon may be cleanly stopped by
sending the SIGTERM signal to the process.
......@@ -168,5 +164,3 @@
- End:
-->
......@@ -889,6 +889,10 @@ class XfrinConnection(asyncore.dispatcher):
req_str = 'IXFR' if request_type == RRType.IXFR() else 'AXFR'
if check_soa:
self._check_soa_serial()
self.close()
self.init_socket()
if not self.connect_to_master():
raise XfrinException('Unable to reconnect to master')
logger.info(XFRIN_XFR_TRANSFER_STARTED, req_str, self.zone_str())
self._send_query(self._request_type)
......
......@@ -952,6 +952,9 @@ class XfroutServer:
def _start_notifier(self):
datasrc = self._unix_socket_server.get_db_file()
self._notifier = notify_out.NotifyOut(datasrc)
if 'also_notify' in self._config_data:
for slave in self._config_data['also_notify']:
self._notifier.add_slave(slave['address'], slave['port'])
self._notifier.dispatcher()
def send_notify(self, zone_name, zone_class):
......
......@@ -20,6 +20,33 @@
"item_optional": true
}
},
{
"item_name": "also_notify",
"item_type": "list",
"item_optional": true,
"item_default": [],
"list_item_spec":
{
"item_name": "also_notify_element",
"item_type": "map",
"item_optional": true,
"item_default": {},
"map_item_spec": [
{
"item_name": "address",
"item_type": "string",
"item_optional": false,
"item_default": ""
},
{
"item_name": "port",
"item_type": "integer",
"item_optional": false,
"item_default": 0
}
]
}
},
{
"item_name": "zone_config",
"item_type": "list",
......
......@@ -33,7 +33,6 @@ using namespace isc::data;
using namespace isc::config;
using namespace isc::cc;
using namespace std;
using namespace boost;
namespace {
std::string
......@@ -52,6 +51,7 @@ protected:
root_name(isc::log::getRootLoggerName())
{
// upon creation of a ModuleCCSession, the class
// sends its specification to the config manager.
// it expects an ok answer back, so everytime we
// create a ModuleCCSession, we must set an initial
......@@ -740,8 +740,9 @@ protected:
registerCommand(const string& recipient)
{
return (mccs_.groupRecvMsgAsync(
bind(&AsyncReceiveCCSessionTest::callback, this, next_flag_ ++, _1,
_2, _3), false, -1, recipient));
boost::bind(&AsyncReceiveCCSessionTest::callback, this,
next_flag_++, _1, _2, _3), false, -1,
recipient));
}
/// \brief Convenience function to queue a request to get a reply
/// message.
......@@ -749,8 +750,8 @@ protected:
registerReply(int seq)
{
return (mccs_.groupRecvMsgAsync(
bind(&AsyncReceiveCCSessionTest::callback, this, next_flag_ ++, _1,
_2, _3), true, seq));
boost::bind(&AsyncReceiveCCSessionTest::callback, this,
next_flag_++, _1, _2, _3), true, seq));
}
/// \brief Check the next called callback was with this flag
void called(int flag) {
......
......@@ -179,8 +179,7 @@ private:
DatabaseClient::Finder::FoundRRsets
DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
bool check_ns, const string* construct_name,
bool any,
const string* construct_name, bool any,
DatabaseAccessor::IteratorContextPtr context)
{
RRsigStore sig_store;
......@@ -204,9 +203,7 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
const Name construct_name_object(*construct_name);
bool seen_cname(false);
bool seen_ds(false);
bool seen_other(false);
bool seen_ns(false);
while (context->getNext(columns)) {
// The domain is not empty
......@@ -249,16 +246,12 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
if (cur_type == RRType::CNAME()) {
seen_cname = true;
} else if (cur_type == RRType::NS()) {
seen_ns = true;
} else if (cur_type == RRType::DS()) {
seen_ds = true;
} else if (cur_type != RRType::RRSIG() &&
cur_type != RRType::NSEC3() &&
cur_type != RRType::NSEC()) {
// NSEC and RRSIG can coexist with anything, otherwise
// we've seen something that can't live together with potential
// CNAME or NS
// CNAME.
//
// NSEC3 lives in separate namespace from everything, therefore
// we just ignore it here for these checks as well.
......@@ -278,14 +271,10 @@ DatabaseClient::Finder::getRRsets(const string& name, const WantedTypes& types,
RDATA_COLUMN]);
}
}
if (seen_cname && (seen_other || seen_ns || seen_ds)) {
if (seen_cname && seen_other) {
isc_throw(DataSourceError, "CNAME shares domain " << name <<
" with something else");
}
if (check_ns && seen_ns && seen_other) {
isc_throw(DataSourceError, "NS shares domain " << name <<
" with something else");
}
// Add signatures to all found RRsets
for (std::map<RRType, RRsetPtr>::iterator i(result.begin());
i != result.end(); ++ i) {
......@@ -455,20 +444,20 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
for (int i = remove_labels; i > 0; --i) {
const Name superdomain(name.split(i));
// Note if this is the origin. (We don't count NS records at the origin
// as a delegation so this controls whether NS RRs are included in
// the results of some searches.)
const bool not_origin = (i != remove_labels);
// Look if there's NS or DNAME at this point of the tree, but ignore
// the NS RRs at the apex of the zone.
const FoundRRsets found = getRRsets(superdomain.toText(),
DELEGATION_TYPES(), not_origin);
DELEGATION_TYPES());
if (found.first) {
// This node contains either NS or DNAME RRs so it does exist.
const FoundIterator nsi(found.second.find(RRType::NS()));
const FoundIterator dni(found.second.find(RRType::DNAME()));
// Note if this is the origin. (We don't count NS records at the
// origin as a delegation so this controls whether NS RRs are
// included in the results of some searches.)
const bool not_origin = (i != remove_labels);
// An optimisation. We know that there is an exact match for
// something at this point in the tree so remember it. If we have
// to do a wildcard search, as we search upwards through the tree
......@@ -477,7 +466,7 @@ DatabaseClient::Finder::findDelegationPoint(const isc::dns::Name& name,
last_known = superdomain.getLabelCount();
if (glue_ok && !first_ns && not_origin &&
nsi != found.second.end()) {
nsi != found.second.end()) {
// If we are searching for glue ("glue OK" mode), store the
// highest NS record that we find that is not the apex. This
// is another optimisation for later, where we need the
......@@ -590,8 +579,9 @@ DatabaseClient::Finder::findWildcardMatch(
// TODO Add a check for DNAME, as DNAME wildcards are discouraged (see
// RFC 4592 section 4.4).
// Search for a match. The types are the same as with original query.
FoundRRsets found = getRRsets(wildcard, final_types, true,
&construct_name, type == RRType::ANY());
const FoundRRsets found = getRRsets(wildcard, final_types,
&construct_name,
type == RRType::ANY());
if (found.first) {
// Found something - but what?
......@@ -694,7 +684,7 @@ DatabaseClient::Finder::FindDNSSECContext::probe() {
// such cases).
const string origin = finder_.getOrigin().toText();
const FoundRRsets nsec3_found =
finder_.getRRsets(origin, NSEC3PARAM_TYPES(), false);
finder_.getRRsets(origin, NSEC3PARAM_TYPES());
const FoundIterator nfi=
nsec3_found.second.find(RRType::NSEC3PARAM());
is_nsec3_ = (nfi != nsec3_found.second.end());
......@@ -705,7 +695,7 @@ DatabaseClient::Finder::FindDNSSECContext::probe() {
// described in Section 10.4 of RFC 5155.
if (!is_nsec3_) {
const FoundRRsets nsec_found =
finder_.getRRsets(origin, NSEC_TYPES(), false);
finder_.getRRsets(origin, NSEC_TYPES());
const FoundIterator nfi =
nsec_found.second.find(RRType::NSEC());
is_nsec_ = (nfi != nsec_found.second.end());
......@@ -757,10 +747,8 @@ DatabaseClient::Finder::FindDNSSECContext::getDNSSECRRset(const Name &name,
try {
const Name& nsec_name =
covering ? finder_.findPreviousName(name) : name;
const bool need_nscheck = (nsec_name != finder_.getOrigin());
const FoundRRsets found = finder_.getRRsets(nsec_name.toText(),
NSEC_TYPES(),
need_nscheck);
NSEC_TYPES());
const FoundIterator nci = found.second.find(RRType::NSEC());
if (nci != found.second.end()) {
return (nci->second);
......@@ -984,16 +972,15 @@ DatabaseClient::Finder::findInternal(const Name& name, const RRType& type,
// - Requested name is a delegation point (NS only but not at the zone
// apex - DNAME is ignored here as it redirects DNS names subordinate to
// the owner name - the owner name itself is not redirected.)
const bool is_origin = (name == getOrigin());
WantedTypes final_types(FINAL_TYPES());
final_types.insert(type);
const FoundRRsets found = getRRsets(name.toText(), final_types,
!is_origin, NULL,
type == RRType::ANY());
NULL, type == RRType::ANY());
FindDNSSECContext dnssec_ctx(*this, options);
if (found.first) {
// Something found at the domain name. Look into it further to get
// the final result.
const bool is_origin = (name == getOrigin());
return (findOnNameResult(name, type, options, is_origin, found, NULL,
target, dnssec_ctx));
} else {
......@@ -1021,7 +1008,7 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
// Now, we need to get the NSEC3 params from the apex and create the hash
// creator for it.
const FoundRRsets nsec3param(getRRsets(getOrigin().toText(),
NSEC3PARAM_TYPES(), false));
NSEC3PARAM_TYPES()));
const FoundIterator param(nsec3param.second.find(RRType::NSEC3PARAM()));
if (!nsec3param.first || param == nsec3param.second.end()) {
// No NSEC3 params? :-(
......@@ -1061,7 +1048,7 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
}
const FoundRRsets nsec3(getRRsets(hash + "." + otext, NSEC3_TYPES(),
false, NULL, false, context));
NULL, false, context));
if (nsec3.first) {
// We found an exact match against the current label.
......@@ -1086,8 +1073,8 @@ DatabaseClient::Finder::findNSEC3(const Name& name, bool recursive) {
arg(labels).arg(prevHash);
context = accessor_->getNSEC3Records(prevHash, zone_id_);
const FoundRRsets prev_nsec3(getRRsets(prevHash + "." + otext,
NSEC3_TYPES(), false, NULL,
false, context));
NSEC3_TYPES(), NULL, false,
context));
if (!prev_nsec3.first) {
isc_throw(DataSourceError, "Hash " + prevHash + " returned "
......
......@@ -963,17 +963,14 @@ public:
///
/// \param name Which domain name should be scanned.
/// \param types List of types the caller is interested in.
/// \param check_ns If this is set to true, it checks nothing lives
/// together with NS record (with few little exceptions, like RRSIG
/// or NSEC). This check is meant for non-apex NS records.
/// \param construct_name If this is NULL, the resulting RRsets have
/// their name set to name. If it is not NULL, it overrides the name
/// and uses this one (this can be used for wildcard synthesized
/// records).
/// their name set to name. If it is not NULL, it overrides the
/// name and uses this one (this can be used for wildcard
/// synthesized records).
/// \param any If this is true, it records all the types, not only the
/// ones requested by types. It also puts a NULL pointer under the
/// ANY type into the result, if it finds any RRs at all, to easy the
/// identification of success.
/// ANY type into the result, if it finds any RRs at all, to easy
/// the identification of success.
/// \param srcContext This can be set to non-NULL value to override the
/// iterator context used for obtaining the data. This can be used,
/// for example, to get data from the NSEC3 namespace.
......@@ -986,7 +983,7 @@ public:
/// \throw DataSourceError If there's a low-level error with the
/// database or the database contains bad data.
FoundRRsets getRRsets(const std::string& name,
const WantedTypes& types, bool check_ns,
const WantedTypes& types,
const std::string* construct_name = NULL,
bool any = false,
DatabaseAccessor::IteratorContextPtr srcContext =
......
......@@ -168,13 +168,16 @@ const char* const TEST_RECORDS[][5] = {
{"child.insecdelegation.example.org.", "DS", "3600", "", "DS 5 3 3600 "
"20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE"},
// Broken NS
// Delegation NS and other ordinary type of RR coexist at the same
// name. This is deviant (except for some special cases like the other
// RR could be used for addressing the NS name), but as long as the
// other records are hidden behind the delegation for normal queries
// it's not necessarily harmful. (so "broken" may be too strong, but we
// keep the name since it could be in a chain of sorted names for DNSSEC
// processing and renaming them may have other bad effects for tests).
{"brokenns1.example.org.", "A", "3600", "", "192.0.2.1"},
{"brokenns1.example.org.", "NS", "3600", "", "ns.example.com."},
{"brokenns2.example.org.", "NS", "3600", "", "ns.example.com."},
{"brokenns2.example.org.", "A", "3600", "", "192.0.2.1"},
// Now double DNAME, to test failure mode
{"baddname.example.org.", "DNAME", "3600", "", "dname1.example.com."},
{"baddname.example.org.", "DNAME", "3600", "", "dname2.example.com."},
......@@ -2202,15 +2205,23 @@ TYPED_TEST(DatabaseClientTest, findDelegation) {
ZoneFinder::FIND_DEFAULT),
DataSourceError);
// Broken NS - it lives together with something else
EXPECT_THROW(finder->find(isc::dns::Name("brokenns1.example.org."),
this->qtype_,
ZoneFinder::FIND_DEFAULT),
DataSourceError);
EXPECT_THROW(finder->find(isc::dns::Name("brokenns2.example.org."),
this->qtype_,
ZoneFinder::FIND_DEFAULT),
DataSourceError);
// NS and other type coexist: deviant and not necessarily harmful.
// It should normally just result in DELEGATION; if GLUE_OK is specified,
// the other RR should be visible.
this->expected_rdatas_.clear();
this->expected_rdatas_.push_back("ns.example.com");
doFindTest(*finder, Name("brokenns1.example.org"), this->qtype_,
RRType::NS(), this->rrttl_, ZoneFinder::DELEGATION,
this->expected_rdatas_, this->empty_rdatas_,
ZoneFinder::RESULT_DEFAULT);
this->expected_rdatas_.clear();
this->expected_rdatas_.push_back("192.0.2.1");
doFindTest(*finder, Name("brokenns1.example.org"), this->qtype_,
this->qtype_, this->rrttl_, ZoneFinder::SUCCESS,
this->expected_rdatas_, this->empty_rdatas_,
ZoneFinder::RESULT_DEFAULT, Name("brokenns1.example.org"),
ZoneFinder::FIND_GLUE_OK);
}
TYPED_TEST(DatabaseClientTest, findDS) {
......
......@@ -208,13 +208,6 @@ TEST_P(ZoneFinderContextTest, getAdditionalDelegation) {
TEST_P(ZoneFinderContextTest, getAdditionalDelegationAtZoneCut) {
// Similar to the previous case, but one of the NS addresses is at the
// zone cut.
// XXX: the current database-based data source incorrectly rejects this
// setup (see #1771)
if (GetParam() == createSQLite3Client) {
return;
}
ZoneFinderContextPtr ctx = finder_->find(Name("www.b.example.org"),
RRType::SOA());
EXPECT_EQ(ZoneFinder::DELEGATION, ctx->code);
......@@ -316,12 +309,6 @@ TEST_P(ZoneFinderContextTest, getAdditionalMX) {
}
TEST_P(ZoneFinderContextTest, getAdditionalMXAtZoneCut) {
// XXX: the current database-based data source incorrectly rejects this
// setup (see #1771)
if (GetParam() == createSQLite3Client) {
return;
}
ZoneFinderContextPtr ctx = finder_->find(Name("mxatcut.example.org."),
RRType::MX());
EXPECT_EQ(ZoneFinder::SUCCESS, ctx->code);
......
......@@ -376,6 +376,16 @@ public:
/// RRsets for that name are searched just like the normal case;
/// otherwise, if the search has encountered a zone cut, \c DELEGATION
/// with the information of the highest zone cut will be returned.
/// Note: the term "glue" in the DNS protocol standard may sometimes
/// cause confusion: some people use this term strictly for an address
/// record (type AAAA or A) for the name used in the RDATA of an NS RR;
/// some others seem to give it broader flexibility. Nevertheless,
/// in this API the "GLUE OK" simply means the search by find() can
/// continue beyond a zone cut; the derived class implementation does
/// not have to, and should not, check whether the type is an address
/// record or whether the query name is pointed by some NS RR.
/// It's up to the caller with which definition of "glue" the search
/// result with this option should be used.
/// - \c FIND_DNSSEC Request that DNSSEC data (like NSEC, RRSIGs) are
/// returned with the answer. It is allowed for the data source to
/// include them even when not requested.
......
......@@ -23,7 +23,7 @@
namespace isc {
namespace dns {
const char*
const uint8_t*
LabelSequence::getData(size_t *len) const {
*len = getDataLength();
return (&name_.ndata_[name_.offsets_[first_label_]]);
......@@ -47,22 +47,22 @@ LabelSequence::getDataLength() const {
bool
LabelSequence::equals(const LabelSequence& other, bool case_sensitive) const {
size_t len, other_len;
const char* data = getData(&len);
const char* other_data = other.getData(&other_len);
const uint8_t* data = getData(&len);
const uint8_t* other_data = other.getData(&other_len);
if (len != other_len) {
return (false);
}
if (case_sensitive) {
return (std::strncmp(data, other_data, len) == 0);
return (std::memcmp(data, other_data, len) == 0);
}
// As long as the data was originally validated as (part of) a name,
// label length must never be a capital ascii character, so we can
// simply compare them after converting to lower characters.
for (size_t i = 0; i < len; ++i) {
const unsigned char ch = data[i];
const unsigned char other_ch = other_data[i];
const uint8_t ch = data[i];
const uint8_t other_ch = other_data[i];
if (isc::dns::name::internal::maptolower[ch] !=
isc::dns::name::internal::maptolower[other_ch]) {
return (false);
......@@ -112,14 +112,14 @@ LabelSequence::isAbsolute() const {
size_t
LabelSequence::getHash(bool case_sensitive) const {
size_t length;
const char* s = getData(&length);
const uint8_t* s = getData(&length);
if (length > 16) {
length = 16;
}
size_t hash_val = 0;
while (length > 0) {
const unsigned char c = *s++;
const uint8_t c = *s++;
boost::hash_combine(hash_val, case_sensitive ? c :
isc::dns::name::internal::maptolower[c]);
--length;
......
......@@ -67,7 +67,7 @@ public:
/// \param len Pointer to a size_t where the length of the data
/// will be stored (in number of octets)
/// \return Pointer to the wire-format data of this label sequence
const char* getData(size_t* len) const;
const uint8_t* getData(size_t* len) const;
/// \brief Return the length of the wire-format data of this LabelSequence
///
......
......@@ -100,8 +100,8 @@ struct NameCompare {
uint16_t item_label_len = 0;
for (size_t i = 0; i < item.len_; ++i, ++item_pos) {
item_pos = nextPosition(*buffer_, item_pos, item_label_len);
const unsigned char ch1 = (*buffer_)[item_pos];
const unsigned char ch2 = name_buf_->readUint8();
const uint8_t ch1 = (*buffer_)[item_pos];
const uint8_t ch2 = name_buf_->readUint8();
if (CASE_SENSITIVE) {
if (ch1 != ch2) {
return (false);
......@@ -293,7 +293,7 @@ MessageRenderer::writeName(const Name& name, const bool compress) {
LabelSequence sequence(name);
const size_t nlabels = sequence.getLabelCount();
size_t data_len;
const char* data;
const uint8_t* data;
// Find the offset in the offset table whose name gives the longest
// match against the name to be rendered.
......
......@@ -75,7 +75,7 @@ const char digitvalue[256] = {
namespace name {
namespace internal {
const unsigned char maptolower[] = {
const uint8_t maptolower[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
......@@ -147,11 +147,11 @@ Name::Name(const std::string &namestring, bool downcase) {
bool is_root = false;
ft_state state = ft_init;
std::vector<unsigned char> offsets;
NameOffsets offsets;
offsets.reserve(Name::MAX_LABELS);
offsets.push_back(0);
std::string ndata;
NameString ndata;
ndata.reserve(Name::MAX_WIRE);
// should we refactor this code using, e.g, the state pattern? Probably
......@@ -310,7 +310,7 @@ typedef enum {
}
Name::Name(InputBuffer& buffer, bool downcase) {
std::vector<unsigned char> offsets;
NameOffsets offsets;
offsets.reserve(Name::MAX_LABELS);
/*
......@@ -436,8 +436,8 @@ Name::toText(bool omit_final_dot) const {
return (".");
}
std::string::const_iterator np = ndata_.begin();
std::string::const_iterator np_end = ndata_.end();
NameString::const_iterator np = ndata_.begin();
NameString::const_iterator np_end = ndata_.end();
unsigned int labels = labelcount_; // use for integrity check
// init with an impossible value to catch error cases in the end:
unsigned int count = MAX_LABELLEN + 1;
......@@ -467,7 +467,7 @@ Name::toText(bool omit_final_dot) const {
}
while (count-- > 0) {
unsigned char c = *np++;
uint8_t c = *np++;
switch (c) {
case 0x22: // '"'
case 0x28: // '('
......@@ -554,8 +554,8 @@ Name::compare(const Name& other,
unsigned int count = (cdiff < 0) ? count1 : count2;
while (count > 0) {
unsigned char label1 = ndata_[pos1];