Commit 0b23de1d authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[1578] Merge branch 'trac1574b' into trac1578

parents 6b562b9f 13ef8a1a
......@@ -16,6 +16,13 @@ $NAMESPACE isc::datasrc
# \brief Messages for the data source library
% DATASRC_BAD_NSEC3_NAME NSEC3 record has a bad owner name '%1'
The software refuses to load NSEC3 records into a wildcard domain or
the owner name has two or more labels below the zone origin.
It isn't explicitly forbidden, but no sane zone wouldn have such names
for NSEC3. BIND 9 also refuses NSEC3 at wildcard, so this behavior is
compatible with BIND 9.
% DATASRC_CACHE_CREATE creating the hotspot cache
This is a debug message issued during startup when the hotspot cache
is created.
......@@ -143,6 +150,34 @@ were found to be different. This isn't allowed on the wire and is considered
an error, so we set it to the lowest value we found (but we don't modify the
database). The data in database should be checked and fixed.
% DATASRC_DATABASE_JOURNALREADER_END %1/%2 on %3 from %4 to %5
This is a debug message indicating that the program (successfully)
reaches the end of sequences of a zone's differences. The zone's name
and class, database name, and the start and end serials are shown in
the message.
% DATASRC_DATABASE_JOURNALREADER_NEXT %1/%2 in %3/%4 on %5
This is a debug message indicating that the program retrieves one
difference in difference sequences of a zone and successfully converts
it to an RRset. The zone's name and class, database name, and the
name and RR type of the retrieved diff are shown in the message.
% DATASRC_DATABASE_JOURNALREADER_START %1/%2 on %3 from %4 to %5
This is a debug message indicating that the program starts reading
a zone's difference sequences from a database-based data source. The
zone's name and class, database name, and the start and end serials
are shown in the message.
% DATASRC_DATABASE_JOURNALREADR_BADDATA failed to convert a diff to RRset in %1/%2 on %3 between %4 and %5: %6
This is an error message indicating that a zone's diff is broken and
the data source library failed to convert it to a valid RRset. The
most likely cause of this is that someone has manually modified the
zone's diff in the database and inserted invalid data as a result.
The zone's name and class, database name, and the start and end
serials, and an additional detail of the error are shown in the
message. The administrator should examine the diff in the database
to find any invalid data and fix it.
% DATASRC_DATABASE_NO_MATCH not match for %2/%3/%4 in %1
No match (not even a wildcard) was found in the named data source for the given
name/type/class in the data source.
......@@ -307,6 +342,14 @@ Debug information. The content of master file is being loaded into the memory.
% DATASRC_MEM_NOT_FOUND requested domain '%1' not found
Debug information. The requested domain does not exist.
% DATASRC_MEM_NO_NSEC3PARAM NSEC3PARAM is missing for NSEC3-signed zone %1/%2
The in-memory data source has loaded a zone signed with NSEC3 RRs,
but it doesn't have a NSEC3PARAM RR at the zone origin. It's likely that
the zone is somehow broken, but this RR is not necessarily needed for
handling lookups with NSEC3 in this data source, so it accepts the given
content of the zone. Nevertheless the administrator should look into
the integrity of the zone data.
% DATASRC_MEM_NS_ENCOUNTERED encountered a NS
Debug information. While searching for the requested domain, a NS was
encountered on the way (a delegation). This may lead to stop of the search.
......@@ -671,66 +714,3 @@ data source.
% DATASRC_UNEXPECTED_QUERY_STATE unexpected query state
This indicates a programming error. An internal task of unknown type was
generated.
% DATASRC_DATABASE_UPDATER_CREATED zone updater created for '%1/%2' on %3
Debug information. A zone updater object is created to make updates to
the shown zone on the shown backend database.
% DATASRC_DATABASE_UPDATER_DESTROYED zone updater destroyed for '%1/%2' on %3
Debug information. A zone updater object is destroyed, either successfully
or after failure of, making updates to the shown zone on the shown backend
database.
%DATASRC_DATABASE_UPDATER_ROLLBACK zone updates roll-backed for '%1/%2' on %3
A zone updater is being destroyed without committing the changes.
This would typically mean the update attempt was aborted due to some
error, but may also be a bug of the application that forgets committing
the changes. The intermediate changes made through the updater won't
be applied to the underlying database. The zone name, its class, and
the underlying database name are shown in the log message.
%DATASRC_DATABASE_UPDATER_ROLLBACKFAIL failed to roll back zone updates for '%1/%2' on %3: %4
A zone updater is being destroyed without committing the changes to
the database, and attempts to rollback incomplete updates, but it
unexpectedly fails. The higher level implementation does not expect
it to fail, so this means either a serious operational error in the
underlying data source (such as a system failure of a database) or
software bug in the underlying data source implementation. In either
case if this message is logged the administrator should carefully
examine the underlying data source to see what exactly happens and
whether the data is still valid. The zone name, its class, and the
underlying database name as well as the error message thrown from the
database module are shown in the log message.
% DATASRC_DATABASE_UPDATER_COMMIT updates committed for '%1/%2' on %3
Debug information. A set of updates to a zone has been successfully
committed to the corresponding database backend. The zone name,
its class and the database name are printed.
% DATASRC_DATABASE_JOURNALREADER_START %1/%2 on %3 from %4 to %5
This is a debug message indicating that the program starts reading
a zone's difference sequences from a database-based data source. The
zone's name and class, database name, and the start and end serials
are shown in the message.
% DATASRC_DATABASE_JOURNALREADER_NEXT %1/%2 in %3/%4 on %5
This is a debug message indicating that the program retrieves one
difference in difference sequences of a zone and successfully converts
it to an RRset. The zone's name and class, database name, and the
name and RR type of the retrieved diff are shown in the message.
% DATASRC_DATABASE_JOURNALREADER_END %1/%2 on %3 from %4 to %5
This is a debug message indicating that the program (successfully)
reaches the end of sequences of a zone's differences. The zone's name
and class, database name, and the start and end serials are shown in
the message.
% DATASRC_DATABASE_JOURNALREADR_BADDATA failed to convert a diff to RRset in %1/%2 on %3 between %4 and %5: %6
This is an error message indicating that a zone's diff is broken and
the data source library failed to convert it to a valid RRset. The
most likely cause of this is that someone has manually modified the
zone's diff in the database and inserted invalid data as a result.
The zone's name and class, database name, and the start and end
serials, and an additional detail of the error are shown in the
message. The administrator should examine the diff in the database
to find any invalid data and fix it.
This diff is collapsed.
......@@ -89,6 +89,16 @@ public:
virtual FindNSEC3Result
findNSEC3(const isc::dns::Name& name, bool recursive);
// A temporary fake version of findNSEC3 for tests
//
// This method intentionally has the same interface as findNSEC3 but
// uses internally hardcoded hash values and offers a limited set
// of functionality for the convenience of tests. This is a temporary
// workaround until #1577 is completed. At that point this method
// should be removed.
FindNSEC3Result
findNSEC3Tmp(const isc::dns::Name& name, bool recursive);
/// \brief Imelementation of the ZoneFinder::findPreviousName method
///
/// This one throws NotImplemented exception, as InMemory doesn't
......
......@@ -110,6 +110,8 @@ endif
EXTRA_DIST = testdata/brokendb.sqlite3
EXTRA_DIST += testdata/example.com.signed
EXTRA_DIST += testdata/example.org
EXTRA_DIST += testdata/example.org.nsec3-signed
EXTRA_DIST += testdata/example.org.nsec3-signed-noparam
EXTRA_DIST += testdata/example.org.sqlite3
EXTRA_DIST += testdata/example2.com
EXTRA_DIST += testdata/example2.com.sqlite3
......
......@@ -1307,4 +1307,249 @@ TEST_F(InMemoryZoneFinderTest, addbadRRsig) {
EXPECT_THROW(zone_finder_.add(textToRRset(rrsig_a_txt)),
InMemoryZoneFinder::AddError);
}
//
// (Faked) NSEC3 hash data. Arbitrarily borrowed from RFC515 examples.
//
// Commonly used NSEC3 suffix. It's incorrect to use it for all NSEC3s, but
// doesn't matter for the purpose of our tests.
const char* const nsec3_common = " 300 IN NSEC3 1 1 12 aabbccdd "
"2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG";
// Likewise, common RRSIG suffix for NSEC3s.
const char* const nsec3_rrsig_common = " 300 IN RRSIG NSEC3 5 3 3600 "
"20000101000000 20000201000000 12345 example.org. FAKEFAKEFAKE";
// For apex (example.org)
const char* const apex_hash = "0P9MHAVEQVM6T7VBL5LOP2U3T2RP3TOM";
const char* const apex_hash_lower = "0p9mhaveqvm6t7vbl5lop2u3t2rp3tom";
// For ns1.example.org
const char* const ns1_hash = "2T7B4G4VSA5SMI47K61MV5BV1A22BOJR";
// For x.y.w.example.org (lower-cased)
const char* const xrw_hash = "2vptu5timamqttgl4luu9kg21e0aor3s";
void
nsec3Check(bool expected_matched, const string& expected_rrsets_txt,
const ZoneFinder::FindNSEC3Result& result,
bool expected_sig = false)
{
vector<ConstRRsetPtr> actual_rrsets;
EXPECT_EQ(expected_matched, result.matched);
ASSERT_TRUE(result.closest_proof);
if (expected_sig) {
ASSERT_TRUE(result.closest_proof->getRRsig());
}
actual_rrsets.push_back(result.closest_proof);
if (expected_sig) {
actual_rrsets.push_back(result.closest_proof->getRRsig());
}
rrsetsCheck(expected_rrsets_txt, actual_rrsets.begin(),
actual_rrsets.end());
}
// In the following tests we use a temporary faked version of findNSEC3
// as the real version isn't implemented yet (it's a task for #1577).
// When #1577 is done the tests should be updated using the real version.
// If we can use fake hash calculator (see #1575), we should be able to
// just replace findNSEC3Tmp with findNSEC3.
TEST_F(InMemoryZoneFinderTest, addNSEC3) {
const string nsec3_text = string(apex_hash) + ".example.org." +
string(nsec3_common);
// This name shouldn't be found in the normal domain tree.
EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
EXPECT_EQ(ZoneFinder::NXDOMAIN,
zone_finder_.find(Name(string(apex_hash) + ".example.org"),
RRType::NSEC3()).code);
// Dedicated NSEC3 find should be able to find it.
nsec3Check(true, nsec3_text,
zone_finder_.findNSEC3Tmp(Name("example.org"), false));
// This implementation rejects duplicate/update add of the same hash name
EXPECT_EQ(result::EXIST,
zone_finder_.add(textToRRset(
string(apex_hash) + ".example.org." +
string(nsec3_common) + " AAAA")));
// The original NSEC3 should be intact
nsec3Check(true, nsec3_text,
zone_finder_.findNSEC3Tmp(Name("example.org"), false));
// NSEC3-like name but of ordinary RR type should go to normal tree.
const string nonsec3_text = string(apex_hash) + ".example.org. " +
"300 IN A 192.0.2.1";
EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nonsec3_text)));
EXPECT_EQ(ZoneFinder::SUCCESS,
zone_finder_.find(Name(string(apex_hash) + ".example.org"),
RRType::A()).code);
}
TEST_F(InMemoryZoneFinderTest, addNSEC3Lower) {
// Similar to the previous case, but NSEC3 owner name is lower-cased.
const string nsec3_text = string(apex_hash_lower) + ".example.org." +
string(nsec3_common);
EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
nsec3Check(true, nsec3_text,
zone_finder_.findNSEC3Tmp(Name("example.org"), false));
}
TEST_F(InMemoryZoneFinderTest, addNSEC3Ordering) {
// Check that the internal storage ensures comparison based on the NSEC3
// semantics, regardless of the add order or the letter-case of hash.
// Adding "0P..", "2v..", then "2T..".
const string smallest = string(apex_hash) + ".example.org." +
string(nsec3_common);
const string middle = string(ns1_hash) + ".example.org." +
string(nsec3_common);
const string largest = string(xrw_hash) + ".example.org." +
string(nsec3_common);
zone_finder_.add(textToRRset(smallest));
zone_finder_.add(textToRRset(largest));
zone_finder_.add(textToRRset(middle));
// Then look for NSEC3 that covers a name whose hash is "2S.."
// The covering NSEC3 should be "0P.."
nsec3Check(false, smallest,
zone_finder_.findNSEC3Tmp(Name("www.example.org"), false));
// Look for NSEC3 that covers names whose hash are "Q0.." and "0A.."
// The covering NSEC3 should be "2v.." in both cases
nsec3Check(false, largest,
zone_finder_.findNSEC3Tmp(Name("xxx.example.org"), false));
nsec3Check(false, largest,
zone_finder_.findNSEC3Tmp(Name("yyy.example.org"), false));
}
TEST_F(InMemoryZoneFinderTest, badNSEC3Name) {
// Our implementation refuses to load NSEC3 at a wildcard name
EXPECT_THROW(zone_finder_.add(textToRRset("*.example.org." +
string(nsec3_common))),
InMemoryZoneFinder::AddError);
// Likewise, if the owner name of NSEC3 has too many labels, it's refused.
EXPECT_THROW(zone_finder_.add(textToRRset("a." + string(apex_hash) +
".example.org." +
string(nsec3_common))),
InMemoryZoneFinder::AddError);
}
TEST_F(InMemoryZoneFinderTest, addMultiNSEC3) {
// In this current implementation multiple NSEC3 RDATA isn't supported.
RRsetPtr nsec3(new RRset(Name(string(apex_hash) + ".example.org"),
RRClass::IN(), RRType::NSEC3(), RRTTL(300)));
nsec3->addRdata(
generic::NSEC3("1 0 12 aabbccdd 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A"));
nsec3->addRdata(
generic::NSEC3("1 1 1 ddccbbaa 2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A"));
EXPECT_THROW(zone_finder_.add(nsec3), InMemoryZoneFinder::AddError);
}
TEST_F(InMemoryZoneFinderTest, addNSEC3WithRRSIG) {
// Adding NSEC3 and its RRSIG
const string nsec3_text = string(apex_hash) + ".example.org." +
string(nsec3_common);
EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_text)));
const string nsec3_rrsig_text = string(apex_hash) + ".example.org." +
string(nsec3_rrsig_common);
EXPECT_EQ(result::SUCCESS, zone_finder_.add(textToRRset(nsec3_rrsig_text)));
// Then look for it. The NSEC3 should have the RRSIG that was just added.
nsec3Check(true, nsec3_text + "\n" + nsec3_rrsig_text,
zone_finder_.findNSEC3Tmp(Name("example.org"), false), true);
// Duplicate add of RRSIG for the same NSEC3 is prohibited.
EXPECT_THROW(zone_finder_.add(textToRRset(nsec3_rrsig_text)),
InMemoryZoneFinder::AddError);
// Same check using the lower-cased name. This also confirms matching
// is case-insensitive.
EXPECT_THROW(zone_finder_.add(textToRRset(string(apex_hash_lower) +
".example.org."
+ string(nsec3_rrsig_common))),
InMemoryZoneFinder::AddError);
}
TEST_F(InMemoryZoneFinderTest, badRRsigForNSEC3) {
// adding RRSIG for NSEC3 even before adding any NSEC3 (internally,
// a space for NSEC3 namespace isn't yet allocated)
EXPECT_THROW(zone_finder_.add(textToRRset(string(apex_hash) +
".example.org." +
string(nsec3_rrsig_common))),
InMemoryZoneFinder::AddError);
// Add an NSEC3
EXPECT_EQ(result::SUCCESS, zone_finder_.add(
textToRRset(string(apex_hash) + ".example.org." +
string(nsec3_common))));
// Then add an NSEC3 for a non existent NSEC3. It should fail in the
// current implementation.
EXPECT_THROW(zone_finder_.add(textToRRset(string(ns1_hash) +
".example.org." +
string(nsec3_rrsig_common))),
InMemoryZoneFinder::AddError);
}
TEST_F(InMemoryZoneFinderTest, paramConsistencyWithNSEC3PARAM) {
// First, add an NSEC3PARAM RR
EXPECT_EQ(result::SUCCESS,
zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
"1 0 12 aabbccdd")));
// Adding an NSEC3 that has matching parameters is okay.
EXPECT_EQ(result::SUCCESS, zone_finder_.add(
textToRRset(string(apex_hash) + ".example.org." +
string(nsec3_common))));
// NSEC3 with inconsistent parameter will be rejected
EXPECT_THROW(zone_finder_.add(
textToRRset("a.example.org. 300 IN NSEC3 1 0 1 aabbccdd "
"2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG")),
InMemoryZoneFinder::AddError);
}
TEST_F(InMemoryZoneFinderTest, paramConsistencyWithNSEC3) {
// Add an NSEC3 without adding NSEC3PARAM
EXPECT_EQ(result::SUCCESS, zone_finder_.add(
textToRRset(string(apex_hash) + ".example.org." +
string(nsec3_common))));
// Adding an NSEC3 with inconsistent parameter will be rejected at this pt.
EXPECT_THROW(zone_finder_.add(
textToRRset("a.example.org. 300 IN NSEC3 1 0 1 aabbccdd "
"2T7B4G4VSA5SMI47K61MV5BV1A22BOJR A RRSIG")),
InMemoryZoneFinder::AddError);
// Likewise, NSEC3PARAM with inconsistent parameter will be rejected.
EXPECT_THROW(zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
"1 0 1 aabbccdd")),
InMemoryZoneFinder::AddError);
}
TEST_F(InMemoryZoneFinderTest, multiNSEC3PARAM) {
// In this current implementation multiple NSEC3PARAM isn't supported.
RRsetPtr nsec3param(new RRset(Name("example.org"), RRClass::IN(),
RRType::NSEC3PARAM(), RRTTL(300)));
nsec3param->addRdata(generic::NSEC3PARAM("1 0 12 aabbccdd"));
nsec3param->addRdata(generic::NSEC3PARAM("1 1 1 ddccbbaa"));
EXPECT_THROW(zone_finder_.add(nsec3param), InMemoryZoneFinder::AddError);
}
TEST_F(InMemoryZoneFinderTest, nonOriginNSEC3PARAM) {
// This is a normal NSEC3PARAM at the zone origin
EXPECT_EQ(result::SUCCESS,
zone_finder_.add(textToRRset("example.org. 300 IN NSEC3PARAM "
"1 0 12 aabbccdd")));
// Add another (with different param) at a non origin node. This is
// awkward, but the implementation accepts it as an ordinary RR.
EXPECT_EQ(result::SUCCESS,
zone_finder_.add(textToRRset("a.example.org. 300 IN NSEC3PARAM "
"1 1 1 aabbccdd")));
}
TEST_F(InMemoryZoneFinderTest, loadNSEC3Zone) {
// Check if it can load validly NSEC3-signed zone. At this moment
// it's sufficient to see it doesn't crash
zone_finder_.load(TEST_DATA_DIR "/example.org.nsec3-signed");
// Reload the zone with a version that doesn't have NSEC3PARAM.
// This is an abnormal case, but the implementation accepts it.
zone_finder_.load(TEST_DATA_DIR "/example.org.nsec3-signed-noparam");
}
}
example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012013000 7200 3600 2592000 1200
example.org. 86400 IN RRSIG SOA 7 2 86400 20120301040838 20120131040838 19562 example.org. Jt9wCRLS5TQxZH0IBqrM9uMGD453rIoxYopfM9AjjRZfEx+HGlBpOZeR pGN7yLcN+URnicOD0ydLHiakaBODiZyNoYCKYG5d2ZOhL+026REnDKNM 0m5T3X3sczP+l55An/GITheTdrKt3Y1Ouc2yKI8ro8JjOxV/a4nGDWjK x9A=
example.org. 86400 IN NS ns.example.org.
example.org. 86400 IN RRSIG NS 7 2 86400 20120301040838 20120131040838 19562 example.org. gYXL3xK4IFdJU6TtiVuzqDBb2MeA8xB3AKtHlJGFTfTRNHyuej0ZGovx TeUYsLYmoiGYaJG66iD1tYYFq0qdj0xWq+LEa53ACtKvYf9IIwK4ijJs k0g6xCNavc6/qPppymDhN7MvoFVkW59uJa0HPWlsIIuRlEAr7xyt85vq yoA=
example.org. 86400 IN DNSKEY 256 3 7 AwEAAbrBkKf2gmGtG4aogZY4svIZCrOLLZlQzVHwz7WxJdTR8iEnvz/x Q/jReDroS5CBZWvzwLlhPIpsJAojx0oj0RvfJNsz3+6LN8q7x9u6+86B 85CYjTk3dcFOebgkF4fXr7/kkOX+ZY94Zk0Z1+pUC3eY4gkKcyME/Uxm O18PBTeB
example.org. 86400 IN RRSIG DNSKEY 7 2 86400 20120301040838 20120131040838 19562 example.org. d0eLF8JqNHaGuBSX0ashU5c1O/wyWU43UUsKGrMQIoBDiJ588MWQOnas rwvW6vdkLNqRqCsP/B4epV/EtLL0tBsk5SHkTYbNo80gGrBufQ6YrWRr Ile8Z+h+MR4y9DybbjmuNKqaO4uQMg/X6+4HqRAKx1lmZMTcrcVeOwDM ZA4=
example.org. 0 IN NSEC3PARAM 1 0 10 AABBCCDD
example.org. 0 IN RRSIG NSEC3PARAM 7 2 0 20120301040838 20120131040838 19562 example.org. Ggs5MiQDlXXt22Fz9DNg3Ujc0T6MBfumlRkd8/enBbJwLmqw2QXAzDEk pjUeGstCEHKzxJDJstavGoCpTDJgoV4Fd9szooMx69rzPrq9tdoM46jG xZHqw+Pv2fkRGC6aP7ZX1r3Qnpwpk47AQgATftbO4G6KcMcO8JoKE47x XLM=
ns.example.org. 86400 IN A 192.0.2.1
ns.example.org. 86400 IN RRSIG A 7 3 86400 20120301040838 20120131040838 19562 example.org. dOH+Dxib8VcGnjLrKILsqDhS1wki6BWk1dZwpOGUGHyLWcLNW8ygWY2o r29jPhHtaFCNWpn46JebgnXDPRiQjaY3dQqL8rcf2QX1e3+Cicw1OSrs S0sUDE5DmMNEac+ZCUQ0quCStZTCldl05hlspV2RS92TpApnoOK0nXMp Uak=
09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3 1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKO yfZc8wKRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVv cD3dFksPyiKHf/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3 CTM=
RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN NSEC3 1 0 10 AABBCCDD 09GM5T42SMIMT7R8DF6RTG80SFMS1NLU NS SOA RRSIG DNSKEY NSEC3PARAM
RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN RRSIG NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. j7d8GL4YqX035FBcPPsEcSWHjWcKdlQMHLL4TB67xVNFnl4SEFQCp4OO AtPap5tkKakwgWxoQVN9XjnqrBz+oQhofDkB3aTatAjIIkcwcnrm3AYQ rTI3E03ySiRwuCPKVmHOLUV2cG6O4xzcmP+MYZcvPTS8V3F5LlaU22i7 A3E=
;; This file intentionally removes NSEC3PARAM from example.org.nsec3-signed
example.org. 86400 IN SOA ns.example.org. ns.example.org. 2012013000 7200 3600 2592000 1200
example.org. 86400 IN RRSIG SOA 7 2 86400 20120301040838 20120131040838 19562 example.org. Jt9wCRLS5TQxZH0IBqrM9uMGD453rIoxYopfM9AjjRZfEx+HGlBpOZeR pGN7yLcN+URnicOD0ydLHiakaBODiZyNoYCKYG5d2ZOhL+026REnDKNM 0m5T3X3sczP+l55An/GITheTdrKt3Y1Ouc2yKI8ro8JjOxV/a4nGDWjK x9A=
example.org. 86400 IN NS ns.example.org.
example.org. 86400 IN RRSIG NS 7 2 86400 20120301040838 20120131040838 19562 example.org. gYXL3xK4IFdJU6TtiVuzqDBb2MeA8xB3AKtHlJGFTfTRNHyuej0ZGovx TeUYsLYmoiGYaJG66iD1tYYFq0qdj0xWq+LEa53ACtKvYf9IIwK4ijJs k0g6xCNavc6/qPppymDhN7MvoFVkW59uJa0HPWlsIIuRlEAr7xyt85vq yoA=
example.org. 86400 IN DNSKEY 256 3 7 AwEAAbrBkKf2gmGtG4aogZY4svIZCrOLLZlQzVHwz7WxJdTR8iEnvz/x Q/jReDroS5CBZWvzwLlhPIpsJAojx0oj0RvfJNsz3+6LN8q7x9u6+86B 85CYjTk3dcFOebgkF4fXr7/kkOX+ZY94Zk0Z1+pUC3eY4gkKcyME/Uxm O18PBTeB
example.org. 86400 IN RRSIG DNSKEY 7 2 86400 20120301040838 20120131040838 19562 example.org. d0eLF8JqNHaGuBSX0ashU5c1O/wyWU43UUsKGrMQIoBDiJ588MWQOnas rwvW6vdkLNqRqCsP/B4epV/EtLL0tBsk5SHkTYbNo80gGrBufQ6YrWRr Ile8Z+h+MR4y9DybbjmuNKqaO4uQMg/X6+4HqRAKx1lmZMTcrcVeOwDM ZA4=
;; example.org. 0 IN NSEC3PARAM 1 0 10 AABBCCDD
;; example.org. 0 IN RRSIG NSEC3PARAM 7 2 0 20120301040838 20120131040838 19562 example.org. Ggs5MiQDlXXt22Fz9DNg3Ujc0T6MBfumlRkd8/enBbJwLmqw2QXAzDEk pjUeGstCEHKzxJDJstavGoCpTDJgoV4Fd9szooMx69rzPrq9tdoM46jG xZHqw+Pv2fkRGC6aP7ZX1r3Qnpwpk47AQgATftbO4G6KcMcO8JoKE47x XLM=
ns.example.org. 86400 IN A 192.0.2.1
ns.example.org. 86400 IN RRSIG A 7 3 86400 20120301040838 20120131040838 19562 example.org. dOH+Dxib8VcGnjLrKILsqDhS1wki6BWk1dZwpOGUGHyLWcLNW8ygWY2o r29jPhHtaFCNWpn46JebgnXDPRiQjaY3dQqL8rcf2QX1e3+Cicw1OSrs S0sUDE5DmMNEac+ZCUQ0quCStZTCldl05hlspV2RS92TpApnoOK0nXMp Uak=
09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN NSEC3 1 0 10 AABBCCDD RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD A RRSIG
09GM5T42SMIMT7R8DF6RTG80SFMS1NLU.example.org. 1200 IN RRSIG NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. EdwMeepLf//lV+KpCAN+213Scv1rrZyj4i2OwoCP4XxxS3CWGSuvYuKO yfZc8wKRcrD/4YG6nZVXE0s5O8NahjBJmDIyVt4WkfZ6QthxGg8ggLVv cD3dFksPyiKHf/WrTOZPSsxvN5m/i1Ey6+YWS01Gf3WDCMWDauC7Nmh3 CTM=
RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN NSEC3 1 0 10 AABBCCDD 09GM5T42SMIMT7R8DF6RTG80SFMS1NLU NS SOA RRSIG DNSKEY NSEC3PARAM
RKOF8QMFRB5F2V9EJHFBVB2JPVSA0DJD.example.org. 1200 IN RRSIG NSEC3 7 3 1200 20120301040838 20120131040838 19562 example.org. j7d8GL4YqX035FBcPPsEcSWHjWcKdlQMHLL4TB67xVNFnl4SEFQCp4OO AtPap5tkKakwgWxoQVN9XjnqrBz+oQhofDkB3aTatAjIIkcwcnrm3AYQ rTI3E03ySiRwuCPKVmHOLUV2cG6O4xzcmP+MYZcvPTS8V3F5LlaU22i7 A3E=
......@@ -15,6 +15,7 @@
#include <stdint.h>
#include <cassert>
#include <cstring>
#include <string>
#include <vector>
......@@ -55,10 +56,10 @@ private:
static const uint8_t NSEC3_HASH_SHA1 = 1;
public:
NSEC3HashRFC5155(const generic::NSEC3PARAM& param) :
algorithm_(param.getHashalg()),
iterations_(param.getIterations()),
salt_(param.getSalt()), digest_(SHA1_HASHSIZE), obuf_(Name::MAX_WIRE)
NSEC3HashRFC5155(uint8_t algorithm, uint16_t iterations,
const vector<uint8_t>& salt) :
algorithm_(algorithm), iterations_(iterations),
salt_(salt), digest_(SHA1_HASHSIZE), obuf_(Name::MAX_WIRE)
{
if (algorithm_ != NSEC3_HASH_SHA1) {
isc_throw(UnknownNSEC3HashAlgorithm, "Unknown NSEC3 algorithm: " <<
......@@ -69,6 +70,11 @@ public:
virtual std::string calculate(const Name& name) const;
virtual bool match(const generic::NSEC3& nsec3) const;
virtual bool match(const generic::NSEC3PARAM& nsec3param) const;
bool match(uint8_t algorithm, uint16_t iterations,
const vector<uint8_t>& salt) const;
private:
const uint8_t algorithm_;
const uint16_t iterations_;
......@@ -115,6 +121,27 @@ NSEC3HashRFC5155::calculate(const Name& name) const {
return (encodeBase32Hex(digest_));
}
bool
NSEC3HashRFC5155::match(uint8_t algorithm, uint16_t iterations,
const vector<uint8_t>& salt) const
{
return (algorithm_ == algorithm && iterations_ == iterations &&
salt_.size() == salt.size() &&
(salt_.empty() || memcmp(&salt_[0], &salt[0], salt_.size()) == 0));
}
bool
NSEC3HashRFC5155::match(const generic::NSEC3& nsec3) const {
return (match(nsec3.getHashalg(), nsec3.getIterations(),
nsec3.getSalt()));
}
bool
NSEC3HashRFC5155::match(const generic::NSEC3PARAM& nsec3param) const {
return (match(nsec3param.getHashalg(), nsec3param.getIterations(),
nsec3param.getSalt()));
}
} // end of unnamed namespace
namespace isc {
......@@ -122,7 +149,14 @@ namespace dns {
NSEC3Hash*
NSEC3Hash::create(const generic::NSEC3PARAM& param) {
return (new NSEC3HashRFC5155(param));
return (new NSEC3HashRFC5155(param.getHashalg(), param.getIterations(),
param.getSalt()));
}
NSEC3Hash*
NSEC3Hash::create(const generic::NSEC3& nsec3) {
return (new NSEC3HashRFC5155(nsec3.getHashalg(), nsec3.getIterations(),
nsec3.getSalt()));
}
} // namespace dns
......
......@@ -25,6 +25,7 @@ class Name;
namespace rdata {
namespace generic {
class NSEC3;
class NSEC3PARAM;
}
}
......@@ -108,6 +109,12 @@ public:
/// \return A pointer to a concrete derived object of \c NSEC3Hash.
static NSEC3Hash* create(const rdata::generic::NSEC3PARAM& param);
/// \brief Factory method of NSECHash from NSEC3 RDATA.
///
/// This is similar to the other version, but extracts the parameters
/// for hash calculation from an NSEC3 RDATA object.
static NSEC3Hash* create(const rdata::generic::NSEC3& nsec3);
/// \brief The destructor.
virtual ~NSEC3Hash() {}
......@@ -123,6 +130,28 @@ public:
/// calculated.
/// \return Base32hex-encoded string of the hash value.
virtual std::string calculate(const Name& name) const = 0;
/// \brief Match given NSEC3 parameters with that of the hash.
///
/// This method compares NSEC3 parameters used for hash calculation
/// in the object with those in the given NSEC3 RDATA, and return
/// true iff they completely match. In the current implementation
/// only the algorithm, iterations and salt are compared; the flags
/// are ignored (as they don't affect hash calculation per RFC5155).
///
/// \throw None
///
/// \param nsec3 An NSEC3 RDATA object whose hash parameters are to be
/// matched
/// \return true If the given parameters match the local ones; false
/// otherwise.
virtual bool match(const rdata::generic::NSEC3& nsec3) const = 0;
/// \brief Match given NSEC3PARAM parameters with that of the hash.
///
/// This is similar to the other version, but extracts the parameters
/// to compare from an NSEC3PARAM RDATA object.
virtual bool match(const rdata::generic::NSEC3PARAM& nsec3param) const = 0;
};
}
......
......@@ -55,13 +55,24 @@ NSEC3Hash_init(PyObject* po_self, PyObject* args, PyObject*) {
if (PyArg_ParseTuple(args, "O", &po_rdata)) {
if (!PyRdata_Check(po_rdata)) {
PyErr_Format(PyExc_TypeError,
"param must be an Rdata of type NSEC3HASH, "
"not %.200s", po_rdata->ob_type->tp_name);
"param must be an Rdata of type NSEC3/NSEC3PARAM,"
" not %.200s", po_rdata->ob_type->tp_name);
return (-1);
}
const Rdata& rdata = PyRdata_ToRdata(po_rdata);
const generic::NSEC3PARAM* nsec3param =
dynamic_cast<const generic::NSEC3PARAM*>(&rdata);
const generic::NSEC3* nsec3 =
dynamic_cast<const generic::NSEC3*>(&rdata);
if (nsec3param != NULL) {
self->cppobj = NSEC3Hash::create(*nsec3param);
} else if (nsec3 != NULL) {
self->cppobj = NSEC3Hash::create(*nsec3);
} else {
PyErr_Format(PyExc_TypeError,
"param must be an Rdata of type NSEC3/NSEC3HASH");
return (-1);
}
self->cppobj = NSEC3Hash::create(
dynamic_cast<const generic::NSEC3PARAM&>(
PyRdata_ToRdata(po_rdata)));
return (0);
}
} catch (const UnknownNSEC3HashAlgorithm& ex) {
......@@ -118,6 +129,51 @@ NSEC3Hash_calculate(PyObject* po_self, PyObject* args) {
return (NULL);