Commit b4a1bc9b authored by chenzhengzhang's avatar chenzhengzhang
Browse files

[trac1114] implement afsdb rdata

parent 004afad6
......@@ -51,6 +51,8 @@ EXTRA_DIST += rdata/generic/soa_6.cc
EXTRA_DIST += rdata/generic/soa_6.h
EXTRA_DIST += rdata/generic/txt_16.cc
EXTRA_DIST += rdata/generic/txt_16.h
EXTRA_DIST += rdata/generic/afsdb_18.cc
EXTRA_DIST += rdata/generic/afsdb_18.h
EXTRA_DIST += rdata/hs_4/a_1.cc
EXTRA_DIST += rdata/hs_4/a_1.h
EXTRA_DIST += rdata/in_1/a_1.cc
......
// 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 <string>
#include <sstream>
#include <util/buffer.h>
#include <util/strutil.h>
#include <dns/name.h>
#include <dns/messagerenderer.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
using namespace std;
using namespace isc::util::str;
// BEGIN_ISC_NAMESPACE
// BEGIN_RDATA_NAMESPACE
/// \brief Constructor from string.
///
/// \c afsdb_str must be formatted as follows:
/// \code <subtype> <server name>
/// \endcode
/// where server name field must represent a valid domain name.
///
/// An example of valid string is:
/// \code "1 server.example.com." \endcode
///
/// <b>Exceptions</b>
///
/// \exception InvalidRdataText The number of RDATA fields (must be 2) is
/// incorrect.
/// \exception std::bad_alloc Memory allocation fails.
/// \exception Other The constructor of the \c Name class will throw if the
/// names in the string is invalid.
AFSDB::AFSDB(const std::string& afsdb_str) :
subtype_(0), server_(Name::ROOT_NAME())
{
istringstream iss(afsdb_str);
try {
const uint32_t subtype = tokenToNum<int32_t, 16>(getToken(iss));
const Name servername(getToken(iss));
string server;
if (!iss.eof()) {
isc_throw(InvalidRdataText, "Unexpected input for AFSDB"
"RDATA: " << afsdb_str);
}
subtype_ = subtype;
server_ = servername;
} catch (const StringTokenError& ste) {
isc_throw(InvalidRdataText, "Invalid AFSDB text: " <<
ste.what() << ": " << afsdb_str);
}
}
/// \brief Constructor from wire-format data.
///
/// This constructor doesn't check the validity of the second parameter (rdata
/// length) for parsing.
/// If necessary, the caller will check consistency.
///
/// \exception std::bad_alloc Memory allocation fails.
/// \exception Other The constructor of the \c Name class will throw if the
/// names in the wire is invalid.
AFSDB::AFSDB(InputBuffer& buffer, size_t) :
subtype_(buffer.readUint16()), server_(buffer)
{}
/// \brief Copy constructor.
///
/// \exception std::bad_alloc Memory allocation fails in copying internal
/// member variables (this should be very rare).
AFSDB::AFSDB(const AFSDB& other) :
Rdata(), subtype_(other.subtype_), server_(other.server_)
{}
AFSDB&
AFSDB::operator=(const AFSDB& source) {
subtype_ = source.subtype_;
server_ = source.server_;
return (*this);
}
/// \brief Convert the \c AFSDB to a string.
///
/// The output of this method is formatted as described in the "from string"
/// constructor (\c AFSDB(const std::string&))).
///
/// \exception std::bad_alloc Internal resource allocation fails.
///
/// \return A \c string object that represents the \c AFSDB object.
string
AFSDB::toText() const {
return (lexical_cast<string>(subtype_) + " " + server_.toText());
}
/// \brief Render the \c AFSDB in the wire format without name compression.
///
/// \exception std::bad_alloc Internal resource allocation fails.
///
/// \param buffer An output buffer to store the wire data.
void
AFSDB::toWire(OutputBuffer& buffer) const {
buffer.writeUint16(subtype_);
server_.toWire(buffer);
}
/// \brief Render the \c AFSDB in the wire format with taking into account
/// compression.
///
/// As specified in RFC3597, TYPE AFSDB is not "well-known", the server
/// field (domain name) will not be compressed.
///
/// \exception std::bad_alloc Internal resource allocation fails.
///
/// \param renderer DNS message rendering context that encapsulates the
/// output buffer and name compression information.
void
AFSDB::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeUint16(subtype_);
renderer.writeName(server_, false);
}
/// \brief Compare two instances of \c AFSDB RDATA.
///
/// See documentation in \c Rdata.
int
AFSDB::compare(const Rdata& other) const {
const AFSDB& other_afsdb = dynamic_cast<const AFSDB&>(other);
if (subtype_ < other_afsdb.subtype_) {
return (-1);
} else if (subtype_ > other_afsdb.subtype_) {
return (1);
}
return (compareNames(server_, other_afsdb.server_));
}
const Name&
AFSDB::getServer() const {
return (server_);
}
uint16_t
AFSDB::getSubtype() const {
return (subtype_);
}
// END_RDATA_NAMESPACE
// END_ISC_NAMESPACE
// 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.
// BEGIN_HEADER_GUARD
#include <stdint.h>
#include <string>
#include <dns/name.h>
#include <dns/rdata.h>
// BEGIN_ISC_NAMESPACE
// BEGIN_COMMON_DECLARATIONS
// END_COMMON_DECLARATIONS
// BEGIN_RDATA_NAMESPACE
/// \brief \c rdata::AFSDB class represents the AFSDB RDATA as defined %in
/// RFC1183.
///
/// This class implements the basic interfaces inherited from the abstract
/// \c rdata::Rdata class, and provides trivial accessors specific to the
/// AFSDB RDATA.
class AFSDB : public Rdata {
public:
// BEGIN_COMMON_MEMBERS
// END_COMMON_MEMBERS
/// \brief Assignment operator.
///
/// This method never throws an exception.
AFSDB& operator=(const AFSDB& source);
///
/// Specialized methods
///
/// \brief Return the value of the server field.
///
/// \return A reference to a \c Name class object corresponding to the
/// internal server name.
///
/// This method never throws an exception.
const Name& getServer() const;
/// \brief Return the value of the subtype field.
///
/// This method never throws an exception.
uint16_t getSubtype() const;
private:
uint16_t subtype_;
Name server_;
};
// END_RDATA_NAMESPACE
// END_ISC_NAMESPACE
// END_HEADER_GUARD
// Local Variables:
// mode: c++
// End:
......@@ -32,6 +32,7 @@ run_unittests_SOURCES += rdata_ns_unittest.cc rdata_soa_unittest.cc
run_unittests_SOURCES += rdata_txt_unittest.cc rdata_mx_unittest.cc
run_unittests_SOURCES += rdata_ptr_unittest.cc rdata_cname_unittest.cc
run_unittests_SOURCES += rdata_dname_unittest.cc
run_unittests_SOURCES += rdata_afsdb_unittest.cc
run_unittests_SOURCES += rdata_opt_unittest.cc
run_unittests_SOURCES += rdata_dnskey_unittest.cc
run_unittests_SOURCES += rdata_ds_unittest.cc
......
// 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 <util/buffer.h>
#include <dns/exceptions.h>
#include <dns/messagerenderer.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rrclass.h>
#include <dns/rrtype.h>
#include <gtest/gtest.h>
#include <dns/tests/unittest_util.h>
#include <dns/tests/rdata_unittest.h>
using isc::UnitTestUtil;
using namespace std;
using namespace isc::dns;
using namespace isc::util;
using namespace isc::dns::rdata;
const char* const afsdb_text = "1 afsdb.example.com.";
const char* const afsdb_text2 = "0 root.example.com.";
const char* const too_long_label("012345678901234567890123456789"
"0123456789012345678901234567890123");
namespace {
class Rdata_AFSDB_Test : public RdataTest {
protected:
Rdata_AFSDB_Test() :
rdata_afsdb(string(afsdb_text)), rdata_afsdb2(string(afsdb_text2))
{}
const generic::AFSDB rdata_afsdb;
const generic::AFSDB rdata_afsdb2;
vector<uint8_t> expected_wire;
};
TEST_F(Rdata_AFSDB_Test, createFromText) {
EXPECT_EQ(1, rdata_afsdb.getSubtype());
EXPECT_EQ(Name("afsdb.example.com."), rdata_afsdb.getServer());
EXPECT_EQ(0, rdata_afsdb2.getSubtype());
EXPECT_EQ(Name("root.example.com."), rdata_afsdb2.getServer());
}
TEST_F(Rdata_AFSDB_Test, badText) {
// subtype is too large
EXPECT_THROW(const generic::AFSDB rdata_afsdb("99999999 afsdb.example.com."),
InvalidRdataText);
// incomplete text
EXPECT_THROW(const generic::AFSDB rdata_afsdb("10"), InvalidRdataText);
EXPECT_THROW(const generic::AFSDB rdata_afsdb("SPOON"), InvalidRdataText);
EXPECT_THROW(const generic::AFSDB rdata_afsdb("1root.example.com."), InvalidRdataText);
// number of fields (must be 2) is incorrect
EXPECT_THROW(const generic::AFSDB rdata_afsdb("10 afsdb. example.com."),
InvalidRdataText);
// bad name
EXPECT_THROW(const generic::AFSDB rdata_afsdb("1 afsdb.example.com." +
string(too_long_label)), TooLongLabel);
}
TEST_F(Rdata_AFSDB_Test, assignment) {
generic::AFSDB copy((string(afsdb_text2)));
copy = rdata_afsdb;
EXPECT_EQ(0, copy.compare(rdata_afsdb));
// Check if the copied data is valid even after the original is deleted
generic::AFSDB* copy2 = new generic::AFSDB(rdata_afsdb);
generic::AFSDB copy3((string(afsdb_text2)));
copy3 = *copy2;
delete copy2;
EXPECT_EQ(0, copy3.compare(rdata_afsdb));
// Self assignment
copy = copy;
EXPECT_EQ(0, copy.compare(rdata_afsdb));
}
TEST_F(Rdata_AFSDB_Test, createFromWire) {
// uncompressed names
EXPECT_EQ(0, rdata_afsdb.compare(
*rdataFactoryFromFile(RRType::AFSDB(), RRClass::IN(),
"rdata_afsdb_fromWire1.wire")));
// compressed name
EXPECT_EQ(0, rdata_afsdb.compare(
*rdataFactoryFromFile(RRType::AFSDB(), RRClass::IN(),
"rdata_afsdb_fromWire2.wire", 13)));
// RDLENGTH is too short
EXPECT_THROW(rdataFactoryFromFile(RRType::AFSDB(), RRClass::IN(),
"rdata_afsdb_fromWire3.wire"),
InvalidRdataLength);
// RDLENGTH is too long
EXPECT_THROW(rdataFactoryFromFile(RRType::AFSDB(), RRClass::IN(),
"rdata_afsdb_fromWire4.wire"),
InvalidRdataLength);
// bogus server name, the error should be detected in the name
// constructor
EXPECT_THROW(rdataFactoryFromFile(RRType::AFSDB(), RRClass::IN(),
"rdata_afsdb_fromWire5.wire"),
DNSMessageFORMERR);
}
TEST_F(Rdata_AFSDB_Test, toWireBuffer) {
// construct actual data
rdata_afsdb.toWire(obuffer);
// construct expected data
UnitTestUtil::readWireData("rdata_afsdb_toWire1.wire", expected_wire);
// then compare them
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
obuffer.getData(), obuffer.getLength(),
&expected_wire[0], expected_wire.size());
// clear buffer for the next test
obuffer.clear();
// construct actual data
Name("example.com.").toWire(obuffer);
rdata_afsdb2.toWire(obuffer);
// construct expected data
UnitTestUtil::readWireData("rdata_afsdb_toWire2.wire", expected_wire);
// then compare them
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
obuffer.getData(), obuffer.getLength(),
&expected_wire[0], expected_wire.size());
}
TEST_F(Rdata_AFSDB_Test, toWireRenderer) {
// similar to toWireBuffer, but names in RDATA could be compressed due to
// preceding names. Actually they must not be compressed according to
// RFC3597, and this test checks that.
// construct actual data
rdata_afsdb.toWire(renderer);
// construct expected data
UnitTestUtil::readWireData("rdata_afsdb_toWire1.wire", expected_wire);
// then compare them
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
renderer.getData(), renderer.getLength(),
&expected_wire[0], expected_wire.size());
// clear renderer for the next test
renderer.clear();
// construct actual data
Name("example.com.").toWire(obuffer);
rdata_afsdb2.toWire(renderer);
// construct expected data
UnitTestUtil::readWireData("rdata_afsdb_toWire2.wire", expected_wire);
// then compare them
EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
renderer.getData(), renderer.getLength(),
&expected_wire[0], expected_wire.size());
}
TEST_F(Rdata_AFSDB_Test, toText) {
EXPECT_EQ(afsdb_text, rdata_afsdb.toText());
EXPECT_EQ(afsdb_text2, rdata_afsdb2.toText());
}
TEST_F(Rdata_AFSDB_Test, compare) {
// check reflexivity
EXPECT_EQ(0, rdata_afsdb.compare(rdata_afsdb));
// name must be compared in case-insensitive manner
EXPECT_EQ(0, rdata_afsdb.compare(generic::AFSDB("1 "
"AFSDB.example.com.")));
const generic::AFSDB small1("10 afsdb.example.com");
const generic::AFSDB large1("65535 afsdb.example.com");
const generic::AFSDB large2("256 afsdb.example.com");
// confirm these are compared as unsigned values
EXPECT_GT(0, rdata_afsdb.compare(large1));
EXPECT_LT(0, large1.compare(rdata_afsdb));
// confirm these are compared in network byte order
EXPECT_GT(0, small1.compare(large2));
EXPECT_LT(0, large2.compare(small1));
// another AFSDB whose server name is larger than that of rdata_afsdb.
const generic::AFSDB large3("256 zzzzz.example.com");
EXPECT_GT(0, large2.compare(large3));
EXPECT_LT(0, large3.compare(large2));
// comparison attempt between incompatible RR types should be rejected
EXPECT_THROW(rdata_afsdb.compare(*rdata_nomatch), bad_cast);
}
}
......@@ -30,6 +30,10 @@ BUILT_SOURCES += rdata_rp_fromWire1.wire rdata_rp_fromWire2.wire
BUILT_SOURCES += rdata_rp_fromWire3.wire rdata_rp_fromWire4.wire
BUILT_SOURCES += rdata_rp_fromWire5.wire rdata_rp_fromWire6.wire
BUILT_SOURCES += rdata_rp_toWire1.wire rdata_rp_toWire2.wire
BUILT_SOURCES += rdata_afsdb_fromWire1.wire rdata_afsdb_fromWire2.wire
BUILT_SOURCES += rdata_afsdb_fromWire3.wire rdata_afsdb_fromWire4.wire
BUILT_SOURCES += rdata_afsdb_fromWire5.wire
BUILT_SOURCES += rdata_afsdb_toWire1.wire rdata_afsdb_toWire2.wire
BUILT_SOURCES += rdata_soa_toWireUncompressed.wire
BUILT_SOURCES += rdata_txt_fromWire2.wire rdata_txt_fromWire3.wire
BUILT_SOURCES += rdata_txt_fromWire4.wire rdata_txt_fromWire5.wire
......@@ -99,6 +103,10 @@ EXTRA_DIST += rdata_rp_fromWire1.spec rdata_rp_fromWire2.spec
EXTRA_DIST += rdata_rp_fromWire3.spec rdata_rp_fromWire4.spec
EXTRA_DIST += rdata_rp_fromWire5.spec rdata_rp_fromWire6.spec
EXTRA_DIST += rdata_rp_toWire1.spec rdata_rp_toWire2.spec
EXTRA_DIST += rdata_afsdb_fromWire1.spec rdata_afsdb_fromWire2.spec
EXTRA_DIST += rdata_afsdb_fromWire3.spec rdata_afsdb_fromWire4.spec
EXTRA_DIST += rdata_afsdb_fromWire5.spec
EXTRA_DIST += rdata_afsdb_toWire1.spec rdata_afsdb_toWire2.spec
EXTRA_DIST += rdata_soa_fromWire rdata_soa_toWireUncompressed.spec
EXTRA_DIST += rdata_srv_fromWire
EXTRA_DIST += rdata_txt_fromWire1 rdata_txt_fromWire2.spec
......
[custom]
sections: name:afsdb
[name]
name: example.com
[afsdb]
server: afsdb.ptr=0
[custom]
sections: afsdb
[afsdb]
rdlen: 3
[custom]
sections: afsdb
[afsdb]
rdlen: 80
[custom]
sections: afsdb
[afsdb]
server: "01234567890123456789012345678901234567890123456789012345678901234"
[custom]
sections: afsdb
[afsdb]
rdlen: -1
[custom]
sections: name:afsdb
[name]
name: example.com.
[afsdb]
subtype: 0
server: root.example.com
rdlen: -1
......@@ -822,6 +822,27 @@ class RP(RR):
f.write('# MAILBOX=%s TEXT=%s\n' % (self.mailbox, self.text))
f.write('%s %s\n' % (mailbox_wire, text_wire))
class AFSDB(RR):
'''Implements rendering AFSDB RDATA in the test data format.
Configurable parameters are as follows (see the description of the
same name of attribute for the default value):
- subtype (16 bit int): The subtype field.
- server (string): The server field.
The string must be interpreted as a valid domain name.
'''
subtype = 1
server = 'afsdb.example.com'
def dump(self, f):
server_wire = encode_name(self.server)
if self.rdlen is None:
self.rdlen = 2 + len(server_wire) / 2
else:
self.rdlen = int(self.rdlen)
self.dump_header(f, self.rdlen)
f.write('# SUBTYPE=%d SERVER=%s\n' % (self.subtype, self.server))
f.write('%04x %s\n' % (self.subtype, server_wire))
class NSECBASE(RR):
'''Implements rendering NSEC/NSEC3 type bitmaps commonly used for
these RRs. The NSEC and NSEC3 classes will be inherited from this
......
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