BIND 10 master, updated. 7c54055c0e47c7a0e36fcfab4b47ff180c0ca8c8 [master] Merge branch 'trac871'
BIND 10 source code commits
bind10-changes at lists.isc.org
Thu May 5 09:10:33 UTC 2011
The branch, master has been updated
via 7c54055c0e47c7a0e36fcfab4b47ff180c0ca8c8 (commit)
via 89fcb0f002447e2cc3148e212f1ecd4f6d1bd821 (commit)
via 28c50de2e9ef07250b54a3d99850ee353f511ffe (commit)
via 297955d6928e3202c25d0f1fa17708c032c46a40 (commit)
via 2979d921553eaaf59cfbe6b78bd726e09006ca9e (commit)
via 31a6f34026c83594bd9f205df18eb290114d9ea1 (commit)
via b8422db8e0120d3998b15581dddcbfe4efe91a68 (commit)
via da16cc776443e1414f779d7402996c6949934765 (commit)
via d6db622c5649e745fb3c64218e36c41545c47aed (commit)
via cce60befee1e0c25e20449b9242112cc0a777089 (commit)
via 89dd4548179485bdf76a84d289ab88ba65bd07bc (commit)
via 364be72653933235d362a57c9342bae1c6e17b3a (commit)
via 28143beb0e57bbd4d62432b81edc8e179b95959f (commit)
via 76705c8fc54809ece24609deda2d156a844d2bf5 (commit)
via a42b39784b65894e7dc164f1b7f2f887715f0c45 (commit)
via 29170e28d19f35a874d84b88f7c0873c51e28f89 (commit)
via 53d9f46923a22920c04d5bc4fc706ec202686b1b (commit)
via 2842dda9275c1a471d70d3a571d810c8d715bf3a (commit)
via daa24430a497d145849a687f51252bfed16a2caf (commit)
via cc788af2c45043fbb98365d5fb85c1d16307dda2 (commit)
from 5c497dfce7d23487c2aefe9907f942c39c4c5846 (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 7c54055c0e47c7a0e36fcfab4b47ff180c0ca8c8
Merge: 5c497df 89fcb0f
Author: JINMEI Tatuya <jinmei at isc.org>
Date: Thu May 5 01:58:09 2011 -0700
[master] Merge branch 'trac871'
-----------------------------------------------------------------------
Summary of changes:
src/lib/dns/Makefile.am | 1 +
src/lib/dns/edns.cc | 29 ++-
src/lib/dns/edns.h | 10 +-
src/lib/dns/message.cc | 276 +++++++++++---------
src/lib/dns/message.h | 25 ++-
src/lib/dns/question.cc | 2 +-
src/lib/dns/question.h | 6 +-
src/lib/dns/rdata/any_255/tsig_250.cc | 12 +-
src/lib/dns/rrclass-placeholder.h | 4 +-
src/lib/dns/rrclass.cc | 2 +-
src/lib/dns/rrset.cc | 6 +-
src/lib/dns/rrset.h | 6 +-
src/lib/dns/rrttl.cc | 2 +-
src/lib/dns/rrttl.h | 4 +-
src/lib/dns/tests/Makefile.am | 1 +
src/lib/dns/tests/message_unittest.cc | 80 ++++++-
src/lib/dns/tests/testdata/Makefile.am | 9 +-
src/lib/dns/tests/testdata/gen-wiredata.py.in | 17 +-
src/lib/dns/tests/testdata/message_toWire2.spec | 21 ++
src/lib/dns/tests/testdata/message_toWire3.spec | 22 ++
src/lib/dns/tests/testdata/tsigrecord_toWire1.spec | 16 ++
src/lib/dns/tests/testdata/tsigrecord_toWire2.spec | 19 ++
src/lib/dns/tests/tsig_unittest.cc | 30 +-
src/lib/dns/tests/tsigrecord_unittest.cc | 120 +++++++++
src/lib/dns/tsig.cc | 33 +--
src/lib/dns/tsig.h | 72 +-----
src/lib/dns/tsigrecord.cc | 109 ++++++++
src/lib/dns/tsigrecord.h | 191 ++++++++++++++
src/lib/util/time_utilities.cc | 7 +-
src/lib/util/time_utilities.h | 28 ++
30 files changed, 869 insertions(+), 291 deletions(-)
create mode 100644 src/lib/dns/tests/testdata/message_toWire2.spec
create mode 100644 src/lib/dns/tests/testdata/message_toWire3.spec
create mode 100644 src/lib/dns/tests/testdata/tsigrecord_toWire1.spec
create mode 100644 src/lib/dns/tests/testdata/tsigrecord_toWire2.spec
create mode 100644 src/lib/dns/tests/tsigrecord_unittest.cc
create mode 100644 src/lib/dns/tsigrecord.cc
create mode 100644 src/lib/dns/tsigrecord.h
-----------------------------------------------------------------------
diff --git a/src/lib/dns/Makefile.am b/src/lib/dns/Makefile.am
index 300cd92..887ac09 100644
--- a/src/lib/dns/Makefile.am
+++ b/src/lib/dns/Makefile.am
@@ -87,6 +87,7 @@ libdns___la_SOURCES += question.h question.cc
libdns___la_SOURCES += tsig.h tsig.cc
libdns___la_SOURCES += tsigerror.h tsigerror.cc
libdns___la_SOURCES += tsigkey.h tsigkey.cc
+libdns___la_SOURCES += tsigrecord.h tsigrecord.cc
libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.h
libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.cc
diff --git a/src/lib/dns/edns.cc b/src/lib/dns/edns.cc
index 5405dab..447b479 100644
--- a/src/lib/dns/edns.cc
+++ b/src/lib/dns/edns.cc
@@ -110,19 +110,25 @@ EDNS::toText() const {
return (ret);
}
+namespace {
+/// Helper function to define unified implementation for the public versions
+/// of toWire().
template <typename Output>
int
-EDNS::toWire(Output& output, const uint8_t extended_rcode) const {
+toWireCommon(Output& output, const uint8_t version,
+ const uint16_t udp_size, const bool dnssec_aware,
+ const uint8_t extended_rcode)
+{
// Render EDNS OPT RR
uint32_t extrcode_flags = extended_rcode << EXTRCODE_SHIFT;
- extrcode_flags |= (version_ << VERSION_SHIFT) & VERSION_MASK;
- if (dnssec_aware_) {
+ extrcode_flags |= (version << VERSION_SHIFT) & VERSION_MASK;
+ if (dnssec_aware) {
extrcode_flags |= EXTFLAG_DO;
}
// Construct an RRset corresponding to the EDNS.
// We don't support any options for now, so the OPT RR can be empty.
- RRsetPtr edns_rrset(new RRset(Name::ROOT_NAME(), RRClass(udp_size_),
+ RRsetPtr edns_rrset(new RRset(Name::ROOT_NAME(), RRClass(udp_size),
RRType::OPT(), RRTTL(extrcode_flags)));
edns_rrset->addRdata(ConstRdataPtr(new generic::OPT()));
@@ -130,9 +136,12 @@ EDNS::toWire(Output& output, const uint8_t extended_rcode) const {
return (1);
}
+}
unsigned int
-EDNS::toWire(MessageRenderer& renderer, const uint8_t extended_rcode) const {
+EDNS::toWire(AbstractMessageRenderer& renderer,
+ const uint8_t extended_rcode) const
+{
// If adding the OPT RR would exceed the size limit, don't do it.
// 11 = len(".") + type(2byte) + class(2byte) + TTL(4byte) + RDLEN(2byte)
// (RDATA is empty in this simple implementation)
@@ -140,12 +149,16 @@ EDNS::toWire(MessageRenderer& renderer, const uint8_t extended_rcode) const {
return (0);
}
- return (toWire<MessageRenderer>(renderer, extended_rcode));
+ return (toWireCommon(renderer, version_, udp_size_, dnssec_aware_,
+ extended_rcode));
}
unsigned int
-EDNS::toWire(isc::util::OutputBuffer& buffer, const uint8_t extended_rcode) const {
- return (toWire<isc::util::OutputBuffer>(buffer, extended_rcode));
+EDNS::toWire(isc::util::OutputBuffer& buffer,
+ const uint8_t extended_rcode) const
+{
+ return (toWireCommon(buffer, version_, udp_size_, dnssec_aware_,
+ extended_rcode));
}
EDNS*
diff --git a/src/lib/dns/edns.h b/src/lib/dns/edns.h
index 5731b95..a7bc4c4 100644
--- a/src/lib/dns/edns.h
+++ b/src/lib/dns/edns.h
@@ -32,7 +32,7 @@ namespace dns {
class EDNS;
class Name;
-class MessageRenderer;
+class AbstractMessageRenderer;
class RRClass;
class RRTTL;
class RRType;
@@ -314,7 +314,7 @@ public:
/// \param extended_rcode Upper 8 bits of extended RCODE to be rendered as
/// part of the EDNS OPT RR.
/// \return 1 if the OPT RR fits in the message size limit; otherwise 0.
- unsigned int toWire(MessageRenderer& renderer,
+ unsigned int toWire(AbstractMessageRenderer& renderer,
const uint8_t extended_rcode) const;
/// \brief Render the \c EDNS in the wire format.
@@ -354,12 +354,6 @@ public:
// something like this.
//void addOption();
-private:
- /// Helper method to define unified implementation for the public versions
- /// of toWire().
- template <typename Output>
- int toWire(Output& output, const uint8_t extended_rcode) const;
-
public:
/// \brief The highest EDNS version this implementation supports.
static const uint8_t SUPPORTED_VERSION = 0;
diff --git a/src/lib/dns/message.cc b/src/lib/dns/message.cc
index d1025d1..770698a 100644
--- a/src/lib/dns/message.cc
+++ b/src/lib/dns/message.cc
@@ -15,6 +15,7 @@
#include <stdint.h>
#include <algorithm>
+#include <cassert>
#include <string>
#include <sstream>
#include <vector>
@@ -40,6 +41,7 @@
#include <dns/rrtype.h>
#include <dns/rrttl.h>
#include <dns/rrset.h>
+#include <dns/tsig.h>
using namespace std;
using namespace boost;
@@ -123,6 +125,7 @@ public:
void setRcode(const Rcode& rcode);
int parseQuestion(InputBuffer& buffer);
int parseSection(const Message::Section section, InputBuffer& buffer);
+ void toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx);
};
MessageImpl::MessageImpl(Message::Mode mode) :
@@ -164,6 +167,154 @@ MessageImpl::setRcode(const Rcode& rcode) {
rcode_ = &rcode_placeholder_;
}
+namespace {
+// This helper class is used by MessageImpl::toWire() to render a set of
+// RRsets of a specific section of message to a given MessageRenderer.
+//
+// A RenderSection object is expected to be used with a QuestionIterator or
+// SectionIterator. Its operator() is called for each RRset as the iterator
+// iterates over the corresponding section, and it renders the RRset to
+// the given MessageRenderer, while counting the number of RRs (note: not
+// RRsets) successfully rendered. If the MessageRenderer reports the need
+// for truncation (via its isTruncated() method), the RenderSection object
+// stops rendering further RRsets. In addition, unless partial_ok (given on
+// construction) is true, it removes any RRs that are partially rendered
+// from the MessageRenderer.
+//
+// On the completion of rendering the entire section, the owner of the
+// RenderSection object can get the number of rendered RRs via the
+// getTotalCount() method.
+template <typename T>
+struct RenderSection {
+ RenderSection(AbstractMessageRenderer& renderer, const bool partial_ok) :
+ counter_(0), renderer_(renderer), partial_ok_(partial_ok),
+ truncated_(false)
+ {}
+ void operator()(const T& entry) {
+ // If it's already truncated, ignore the rest of the section.
+ if (truncated_) {
+ return;
+ }
+ const size_t pos0 = renderer_.getLength();
+ counter_ += entry->toWire(renderer_);
+ if (renderer_.isTruncated()) {
+ truncated_ = true;
+ if (!partial_ok_) {
+ // roll back to the end of the previous RRset.
+ renderer_.trim(renderer_.getLength() - pos0);
+ }
+ }
+ }
+ unsigned int getTotalCount() { return (counter_); }
+ unsigned int counter_;
+ AbstractMessageRenderer& renderer_;
+ const bool partial_ok_;
+ bool truncated_;
+};
+}
+
+void
+MessageImpl::toWire(AbstractMessageRenderer& renderer, TSIGContext* tsig_ctx) {
+ if (mode_ != Message::RENDER) {
+ isc_throw(InvalidMessageOperation,
+ "Message rendering attempted in non render mode");
+ }
+ if (rcode_ == NULL) {
+ isc_throw(InvalidMessageOperation,
+ "Message rendering attempted without Rcode set");
+ }
+ if (opcode_ == NULL) {
+ isc_throw(InvalidMessageOperation,
+ "Message rendering attempted without Opcode set");
+ }
+
+ // reserve room for the header
+ renderer.skip(HEADERLEN);
+
+ uint16_t qdcount =
+ for_each(questions_.begin(), questions_.end(),
+ RenderSection<QuestionPtr>(renderer, false)).getTotalCount();
+
+ // TODO: sort RRsets in each section based on configuration policy.
+ uint16_t ancount = 0;
+ if (!renderer.isTruncated()) {
+ ancount =
+ for_each(rrsets_[Message::SECTION_ANSWER].begin(),
+ rrsets_[Message::SECTION_ANSWER].end(),
+ RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
+ }
+ uint16_t nscount = 0;
+ if (!renderer.isTruncated()) {
+ nscount =
+ for_each(rrsets_[Message::SECTION_AUTHORITY].begin(),
+ rrsets_[Message::SECTION_AUTHORITY].end(),
+ RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
+ }
+ uint16_t arcount = 0;
+ if (renderer.isTruncated()) {
+ flags_ |= Message::HEADERFLAG_TC;
+ } else {
+ arcount =
+ for_each(rrsets_[Message::SECTION_ADDITIONAL].begin(),
+ rrsets_[Message::SECTION_ADDITIONAL].end(),
+ RenderSection<RRsetPtr>(renderer, false)).getTotalCount();
+ }
+
+ // Add EDNS OPT RR if necessary. Basically, we add it only when EDNS
+ // has been explicitly set. However, if the RCODE would require it and
+ // no EDNS has been set we generate a temporary local EDNS and use it.
+ if (!renderer.isTruncated()) {
+ ConstEDNSPtr local_edns = edns_;
+ if (!local_edns && rcode_->getExtendedCode() != 0) {
+ local_edns = ConstEDNSPtr(new EDNS());
+ }
+ if (local_edns) {
+ arcount += local_edns->toWire(renderer, rcode_->getExtendedCode());
+ }
+ }
+
+ // Adjust the counter buffer.
+ // XXX: these may not be equal to the number of corresponding entries
+ // in rrsets_[] or questions_ if truncation occurred or an EDNS OPT RR
+ // was inserted. This is not good, and we should revisit the entire
+ // design.
+ counts_[Message::SECTION_QUESTION] = qdcount;
+ counts_[Message::SECTION_ANSWER] = ancount;
+ counts_[Message::SECTION_AUTHORITY] = nscount;
+ counts_[Message::SECTION_ADDITIONAL] = arcount;
+
+ // fill in the header
+ size_t header_pos = 0;
+ renderer.writeUint16At(qid_, header_pos);
+ header_pos += sizeof(uint16_t);
+
+ uint16_t codes_and_flags =
+ (opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
+ codes_and_flags |= (rcode_->getCode() & RCODE_MASK);
+ codes_and_flags |= (flags_ & HEADERFLAG_MASK);
+ renderer.writeUint16At(codes_and_flags, header_pos);
+ header_pos += sizeof(uint16_t);
+ // TODO: should avoid repeated pattern
+ renderer.writeUint16At(qdcount, header_pos);
+ header_pos += sizeof(uint16_t);
+ renderer.writeUint16At(ancount, header_pos);
+ header_pos += sizeof(uint16_t);
+ renderer.writeUint16At(nscount, header_pos);
+ header_pos += sizeof(uint16_t);
+ renderer.writeUint16At(arcount, header_pos);
+
+ // Add TSIG, if necessary, at the end of the message.
+ // TODO: truncate case consideration
+ if (tsig_ctx != NULL) {
+ tsig_ctx->sign(qid_, renderer.getData(),
+ renderer.getLength())->toWire(renderer);
+
+ // update the ARCOUNT for the TSIG RR. Note that for a sane DNS
+ // message arcount should never overflow to 0.
+ renderer.writeUint16At(++arcount, header_pos);
+ }
+}
+
Message::Message(Mode mode) :
impl_(new MessageImpl(mode))
{}
@@ -363,129 +514,14 @@ Message::addQuestion(const Question& question) {
addQuestion(QuestionPtr(new Question(question)));
}
-namespace {
-template <typename T>
-struct RenderSection {
- RenderSection(MessageRenderer& renderer, const bool partial_ok) :
- counter_(0), renderer_(renderer), partial_ok_(partial_ok),
- truncated_(false)
- {}
- void operator()(const T& entry) {
- // If it's already truncated, ignore the rest of the section.
- if (truncated_) {
- return;
- }
- const size_t pos0 = renderer_.getLength();
- counter_ += entry->toWire(renderer_);
- if (renderer_.isTruncated()) {
- truncated_ = true;
- if (!partial_ok_) {
- // roll back to the end of the previous RRset.
- renderer_.trim(renderer_.getLength() - pos0);
- }
- }
- }
- unsigned int getTotalCount() { return (counter_); }
- unsigned int counter_;
- MessageRenderer& renderer_;
- const bool partial_ok_;
- bool truncated_;
-};
+void
+Message::toWire(AbstractMessageRenderer& renderer) {
+ impl_->toWire(renderer, NULL);
}
void
-Message::toWire(MessageRenderer& renderer) {
- if (impl_->mode_ != Message::RENDER) {
- isc_throw(InvalidMessageOperation,
- "Message rendering attempted in non render mode");
- }
- if (impl_->rcode_ == NULL) {
- isc_throw(InvalidMessageOperation,
- "Message rendering attempted without Rcode set");
- }
- if (impl_->opcode_ == NULL) {
- isc_throw(InvalidMessageOperation,
- "Message rendering attempted without Opcode set");
- }
-
- // reserve room for the header
- renderer.skip(HEADERLEN);
-
- uint16_t qdcount =
- for_each(impl_->questions_.begin(), impl_->questions_.end(),
- RenderSection<QuestionPtr>(renderer, false)).getTotalCount();
-
- // TBD: sort RRsets in each section based on configuration policy.
- uint16_t ancount = 0;
- if (!renderer.isTruncated()) {
- ancount =
- for_each(impl_->rrsets_[SECTION_ANSWER].begin(),
- impl_->rrsets_[SECTION_ANSWER].end(),
- RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
- }
- uint16_t nscount = 0;
- if (!renderer.isTruncated()) {
- nscount =
- for_each(impl_->rrsets_[SECTION_AUTHORITY].begin(),
- impl_->rrsets_[SECTION_AUTHORITY].end(),
- RenderSection<RRsetPtr>(renderer, true)).getTotalCount();
- }
- uint16_t arcount = 0;
- if (renderer.isTruncated()) {
- setHeaderFlag(HEADERFLAG_TC, true);
- } else {
- arcount =
- for_each(impl_->rrsets_[SECTION_ADDITIONAL].begin(),
- impl_->rrsets_[SECTION_ADDITIONAL].end(),
- RenderSection<RRsetPtr>(renderer, false)).getTotalCount();
- }
-
- // Add EDNS OPT RR if necessary. Basically, we add it only when EDNS
- // has been explicitly set. However, if the RCODE would require it and
- // no EDNS has been set we generate a temporary local EDNS and use it.
- if (!renderer.isTruncated()) {
- ConstEDNSPtr local_edns = impl_->edns_;
- if (!local_edns && impl_->rcode_->getExtendedCode() != 0) {
- local_edns = ConstEDNSPtr(new EDNS());
- }
- if (local_edns) {
- arcount += local_edns->toWire(renderer,
- impl_->rcode_->getExtendedCode());
- }
- }
-
- // Adjust the counter buffer.
- // XXX: these may not be equal to the number of corresponding entries
- // in rrsets_[] or questions_ if truncation occurred or an EDNS OPT RR
- // was inserted. This is not good, and we should revisit the entire
- // design.
- impl_->counts_[SECTION_QUESTION] = qdcount;
- impl_->counts_[SECTION_ANSWER] = ancount;
- impl_->counts_[SECTION_AUTHORITY] = nscount;
- impl_->counts_[SECTION_ADDITIONAL] = arcount;
-
- // TBD: TSIG, SIG(0) etc.
-
- // fill in the header
- size_t header_pos = 0;
- renderer.writeUint16At(impl_->qid_, header_pos);
- header_pos += sizeof(uint16_t);
-
- uint16_t codes_and_flags =
- (impl_->opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
- codes_and_flags |= (impl_->rcode_->getCode() & RCODE_MASK);
- codes_and_flags |= (impl_->flags_ & HEADERFLAG_MASK);
- renderer.writeUint16At(codes_and_flags, header_pos);
- header_pos += sizeof(uint16_t);
- // XXX: should avoid repeated pattern (TODO)
- renderer.writeUint16At(qdcount, header_pos);
- header_pos += sizeof(uint16_t);
- renderer.writeUint16At(ancount, header_pos);
- header_pos += sizeof(uint16_t);
- renderer.writeUint16At(nscount, header_pos);
- header_pos += sizeof(uint16_t);
- renderer.writeUint16At(arcount, header_pos);
- header_pos += sizeof(uint16_t);
+Message::toWire(AbstractMessageRenderer& renderer, TSIGContext& tsig_ctx) {
+ impl_->toWire(renderer, &tsig_ctx);
}
void
diff --git a/src/lib/dns/message.h b/src/lib/dns/message.h
index 5601299..cd3ae88 100644
--- a/src/lib/dns/message.h
+++ b/src/lib/dns/message.h
@@ -33,6 +33,7 @@ class InputBuffer;
}
namespace dns {
+class TSIGContext;
///
/// \brief A standard DNS module exception that is thrown if a wire format
@@ -80,7 +81,7 @@ public:
typedef uint16_t qid_t;
-class MessageRenderer;
+class AbstractMessageRenderer;
class Message;
class MessageImpl;
class Opcode;
@@ -523,13 +524,31 @@ public:
/// class \c InvalidMessageOperation will be thrown.
std::string toText() const;
- /// \brief Render the message in wire formant into a \c MessageRenderer
+ /// \brief Render the message in wire formant into a message renderer
/// object.
///
/// This \c Message must be in the \c RENDER mode and both \c Opcode and
/// \c Rcode must have been set beforehand; otherwise, an exception of
/// class \c InvalidMessageOperation will be thrown.
- void toWire(MessageRenderer& renderer);
+ ///
+ /// \param renderer DNS message rendering context that encapsulates the
+ /// output buffer and name compression information.
+ void toWire(AbstractMessageRenderer& renderer);
+
+ /// \brief Render the message in wire formant into a message renderer
+ /// object with TSIG.
+ ///
+ /// This method is similar to the other version of \c toWire(), but
+ /// it will also add a TSIG RR with (in many cases) the TSIG MAC for
+ /// the message along with the given TSIG context (\c tsig_ctx).
+ /// The TSIG RR will be placed at the end of \c renderer.
+ /// \c tsig_ctx will be updated based on the fact it was used for signing
+ /// and with the latest MAC.
+ ///
+ /// \param renderer See the other version
+ /// \param tsig_ctx A TSIG context that is to be used for signing the
+ /// message
+ void toWire(AbstractMessageRenderer& renderer, TSIGContext& tsig_ctx);
/// \brief Parse the header section of the \c Message.
void parseHeader(isc::util::InputBuffer& buffer);
diff --git a/src/lib/dns/question.cc b/src/lib/dns/question.cc
index 723fc88..96e2a9c 100644
--- a/src/lib/dns/question.cc
+++ b/src/lib/dns/question.cc
@@ -56,7 +56,7 @@ Question::toWire(OutputBuffer& buffer) const {
}
unsigned int
-Question::toWire(MessageRenderer& renderer) const {
+Question::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeName(name_);
rrtype_.toWire(renderer);
rrclass_.toWire(renderer);
diff --git a/src/lib/dns/question.h b/src/lib/dns/question.h
index 3c038b3..b3f3d98 100644
--- a/src/lib/dns/question.h
+++ b/src/lib/dns/question.h
@@ -32,7 +32,7 @@ class OutputBuffer;
namespace dns {
-class MessageRenderer;
+class AbstractMessageRenderer;
class Question;
/// \brief A pointer-like type pointing to an \c Question object.
@@ -218,13 +218,13 @@ public:
/// \param renderer DNS message rendering context that encapsulates the
/// output buffer and name compression information.
/// \return 1
- unsigned int toWire(MessageRenderer& renderer) const;
+ unsigned int toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the Question in the wire format without name compression.
///
/// This method behaves like the render version except it doesn't compress
/// the owner name.
- /// See \c toWire(MessageRenderer& renderer)const.
+ /// See \c toWire(AbstractMessageRenderer& renderer)const.
///
/// \param buffer An output buffer to store the wire data.
/// \return 1
diff --git a/src/lib/dns/rdata/any_255/tsig_250.cc b/src/lib/dns/rdata/any_255/tsig_250.cc
index f2bd7ad..8211e7f 100644
--- a/src/lib/dns/rdata/any_255/tsig_250.cc
+++ b/src/lib/dns/rdata/any_255/tsig_250.cc
@@ -24,7 +24,7 @@
#include <dns/messagerenderer.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
-
+#include <dns/tsigerror.h>
using namespace std;
using namespace boost;
@@ -313,15 +313,7 @@ TSIG::toText() const {
result += encodeBase64(impl_->mac_) + " ";
}
result += lexical_cast<string>(impl_->original_id_) + " ";
- if (impl_->error_ == 16) { // XXX: we'll soon introduce generic converter.
- result += "BADSIG ";
- } else if (impl_->error_ == 17) {
- result += "BADKEY ";
- } else if (impl_->error_ == 18) {
- result += "BADTIME ";
- } else {
- result += lexical_cast<string>(impl_->error_) + " ";
- }
+ result += TSIGError(impl_->error_).toText() + " ";
result += lexical_cast<string>(impl_->other_data_.size());
if (impl_->other_data_.size() > 0) {
result += " " + encodeBase64(impl_->other_data_);
diff --git a/src/lib/dns/rrclass-placeholder.h b/src/lib/dns/rrclass-placeholder.h
index ae3ff6f..80035d8 100644
--- a/src/lib/dns/rrclass-placeholder.h
+++ b/src/lib/dns/rrclass-placeholder.h
@@ -31,7 +31,7 @@ class OutputBuffer;
namespace dns {
// forward declarations
-class MessageRenderer;
+class AbstractMessageRenderer;
///
/// \brief A standard DNS module exception that is thrown if an RRClass object
@@ -169,7 +169,7 @@ public:
/// standard exception will be thrown.
///
/// \param buffer An output buffer to store the wire data.
- void toWire(MessageRenderer& renderer) const;
+ void toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the \c RRClass in the wire format.
///
/// This method renders the class code in network byte order into the
diff --git a/src/lib/dns/rrclass.cc b/src/lib/dns/rrclass.cc
index f1bb8d7..a28e5cf 100644
--- a/src/lib/dns/rrclass.cc
+++ b/src/lib/dns/rrclass.cc
@@ -52,7 +52,7 @@ RRClass::toWire(OutputBuffer& buffer) const {
}
void
-RRClass::toWire(MessageRenderer& renderer) const {
+RRClass::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeUint16(classcode_);
}
diff --git a/src/lib/dns/rrset.cc b/src/lib/dns/rrset.cc
index e80afdb..776d49f 100644
--- a/src/lib/dns/rrset.cc
+++ b/src/lib/dns/rrset.cc
@@ -104,8 +104,8 @@ AbstractRRset::toWire(OutputBuffer& buffer) const {
}
unsigned int
-AbstractRRset::toWire(MessageRenderer& renderer) const {
- const unsigned int rrs_written = rrsetToWire<MessageRenderer>(
+AbstractRRset::toWire(AbstractMessageRenderer& renderer) const {
+ const unsigned int rrs_written = rrsetToWire<AbstractMessageRenderer>(
*this, renderer, renderer.getLengthLimit());
if (getRdataCount() > rrs_written) {
renderer.setTruncated();
@@ -202,7 +202,7 @@ BasicRRset::toWire(OutputBuffer& buffer) const {
}
unsigned int
-BasicRRset::toWire(MessageRenderer& renderer) const {
+BasicRRset::toWire(AbstractMessageRenderer& renderer) const {
return (AbstractRRset::toWire(renderer));
}
diff --git a/src/lib/dns/rrset.h b/src/lib/dns/rrset.h
index bf7adc0..6c15b53 100644
--- a/src/lib/dns/rrset.h
+++ b/src/lib/dns/rrset.h
@@ -47,7 +47,7 @@ class Name;
class RRType;
class RRClass;
class RRTTL;
-class MessageRenderer;
+class AbstractMessageRenderer;
class AbstractRRset;
class BasicRRset;
class RdataIterator;
@@ -311,7 +311,7 @@ public:
/// \return The number of RRs rendered. If the truncation is necessary
/// this value may be different from the number of RDATA objects contained
/// in the RRset.
- virtual unsigned int toWire(MessageRenderer& renderer) const = 0;
+ virtual unsigned int toWire(AbstractMessageRenderer& renderer) const = 0;
/// \brief Render the RRset in the wire format without any compression.
///
@@ -617,7 +617,7 @@ public:
///
/// This method simply uses the default implementation.
/// See \c AbstractRRset::toWire(MessageRenderer&)const.
- virtual unsigned int toWire(MessageRenderer& renderer) const;
+ virtual unsigned int toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the RRset in the wire format without any compression.
///
diff --git a/src/lib/dns/rrttl.cc b/src/lib/dns/rrttl.cc
index a4c4f83..ecd8cc6 100644
--- a/src/lib/dns/rrttl.cc
+++ b/src/lib/dns/rrttl.cc
@@ -63,7 +63,7 @@ RRTTL::toWire(OutputBuffer& buffer) const {
}
void
-RRTTL::toWire(MessageRenderer& renderer) const {
+RRTTL::toWire(AbstractMessageRenderer& renderer) const {
renderer.writeUint32(ttlval_);
}
diff --git a/src/lib/dns/rrttl.h b/src/lib/dns/rrttl.h
index 17ec891..bf23295 100644
--- a/src/lib/dns/rrttl.h
+++ b/src/lib/dns/rrttl.h
@@ -28,7 +28,7 @@ class OutputBuffer;
namespace dns {
// forward declarations
-class MessageRenderer;
+class AbstractMessageRenderer;
///
/// \brief A standard DNS module exception that is thrown if an RRTTL object
@@ -123,7 +123,7 @@ public:
///
/// \param renderer DNS message rendering context that encapsulates the
/// output buffer in which the RRTTL is to be stored.
- void toWire(MessageRenderer& renderer) const;
+ void toWire(AbstractMessageRenderer& renderer) const;
/// \brief Render the \c RRTTL in the wire format.
///
/// This method renders the TTL value in network byte order into the
diff --git a/src/lib/dns/tests/Makefile.am b/src/lib/dns/tests/Makefile.am
index 7a94653..9783beb 100644
--- a/src/lib/dns/tests/Makefile.am
+++ b/src/lib/dns/tests/Makefile.am
@@ -50,6 +50,7 @@ run_unittests_SOURCES += message_unittest.cc
run_unittests_SOURCES += tsig_unittest.cc
run_unittests_SOURCES += tsigerror_unittest.cc
run_unittests_SOURCES += tsigkey_unittest.cc
+run_unittests_SOURCES += tsigrecord_unittest.cc
run_unittests_SOURCES += run_unittests.cc
run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
diff --git a/src/lib/dns/tests/message_unittest.cc b/src/lib/dns/tests/message_unittest.cc
index 4031e4f..c92b950 100644
--- a/src/lib/dns/tests/message_unittest.cc
+++ b/src/lib/dns/tests/message_unittest.cc
@@ -12,9 +12,13 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
+#include <boost/scoped_ptr.hpp>
+
#include <exceptions/exceptions.h>
#include <util/buffer.h>
+#include <util/time_utilities.h>
+
#include <dns/edns.h>
#include <dns/exceptions.h>
#include <dns/message.h>
@@ -26,6 +30,8 @@
#include <dns/rrclass.h>
#include <dns/rrttl.h>
#include <dns/rrtype.h>
+#include <dns/tsig.h>
+#include <dns/tsigkey.h>
#include <gtest/gtest.h>
@@ -53,6 +59,14 @@ using namespace isc::dns::rdata;
const uint16_t Message::DEFAULT_MAX_UDPSIZE;
const Name test_name("test.example.com");
+namespace isc {
+namespace util {
+namespace detail {
+extern int64_t (*gettimeFunction)();
+}
+}
+}
+
namespace {
class MessageTest : public ::testing::Test {
protected:
@@ -60,7 +74,9 @@ protected:
message_parse(Message::PARSE),
message_render(Message::RENDER),
bogus_section(static_cast<Message::Section>(
- Message::SECTION_ADDITIONAL + 1))
+ Message::SECTION_ADDITIONAL + 1)),
+ tsig_ctx(TSIGKey("www.example.com:"
+ "SFuWd/q99SzF8Yzd1QbB9g=="))
{
rrset_a = RRsetPtr(new RRset(test_name, RRClass::IN(),
RRType::A(), RRTTL(3600)));
@@ -88,6 +104,9 @@ protected:
RRsetPtr rrset_a; // A RRset with two RDATAs
RRsetPtr rrset_aaaa; // AAAA RRset with one RDATA with RRSIG
RRsetPtr rrset_rrsig; // RRSIG for the AAAA RRset
+ TSIGContext tsig_ctx;
+ vector<unsigned char> expected_data;
+
static void factoryFromFile(Message& message, const char* datafile);
};
@@ -519,6 +538,65 @@ TEST_F(MessageTest, toWireInParseMode) {
EXPECT_THROW(message_parse.toWire(renderer), InvalidMessageOperation);
}
+// See dnssectime_unittest.cc
+template <int64_t NOW>
+int64_t
+testGetTime() {
+ return (NOW);
+}
+
+void
+commonTSIGToWireCheck(Message& message, MessageRenderer& renderer,
+ TSIGContext& tsig_ctx, const char* const expected_file)
+{
+ message.setOpcode(Opcode::QUERY());
+ message.setRcode(Rcode::NOERROR());
+ message.setHeaderFlag(Message::HEADERFLAG_RD, true);
+ message.addQuestion(Question(Name("www.example.com"), RRClass::IN(),
+ RRType::A()));
+
+ message.toWire(renderer, tsig_ctx);
+ vector<unsigned char> expected_data;
+ UnitTestUtil::readWireData(expected_file, expected_data);
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData, renderer.getData(),
+ renderer.getLength(),
+ &expected_data[0], expected_data.size());
+}
+
+TEST_F(MessageTest, toWireWithTSIG) {
+ // Rendering a message with TSIG. Various special cases specific to
+ // TSIG are tested in the tsig tests. We only check the message contains
+ // a TSIG at the end and the ARCOUNT of the header is updated.
+
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
+
+ message_render.setQid(0x2d65);
+
+ {
+ SCOPED_TRACE("Message sign with TSIG");
+ commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ "message_toWire2.wire");
+ }
+}
+
+TEST_F(MessageTest, toWireWithEDNSAndTSIG) {
+ // Similar to the previous test, but with an EDNS before TSIG.
+ // The wire data check will confirm the ordering.
+ isc::util::detail::gettimeFunction = testGetTime<0x4db60d1f>;
+
+ message_render.setQid(0x6cd);
+
+ EDNSPtr edns(new EDNS());
+ edns->setUDPSize(4096);
+ message_render.setEDNS(edns);
+
+ {
+ SCOPED_TRACE("Message sign with TSIG and EDNS");
+ commonTSIGToWireCheck(message_render, renderer, tsig_ctx,
+ "message_toWire3.wire");
+ }
+}
+
TEST_F(MessageTest, toWireWithoutOpcode) {
message_render.setRcode(Rcode::NOERROR());
EXPECT_THROW(message_render.toWire(renderer), InvalidMessageOperation);
diff --git a/src/lib/dns/tests/testdata/Makefile.am b/src/lib/dns/tests/testdata/Makefile.am
index 31771bb..0c26393 100644
--- a/src/lib/dns/tests/testdata/Makefile.am
+++ b/src/lib/dns/tests/testdata/Makefile.am
@@ -3,6 +3,7 @@ CLEANFILES = *.wire
BUILT_SOURCES = edns_toWire1.wire edns_toWire2.wire edns_toWire3.wire
BUILT_SOURCES += edns_toWire4.wire
BUILT_SOURCES += message_fromWire10.wire message_fromWire11.wire
+BUILT_SOURCES += message_toWire2.wire message_toWire3.wire
BUILT_SOURCES += name_toWire5.wire name_toWire6.wire
BUILT_SOURCES += rdatafields1.wire rdatafields2.wire rdatafields3.wire
BUILT_SOURCES += rdatafields4.wire rdatafields5.wire rdatafields6.wire
@@ -33,6 +34,7 @@ BUILT_SOURCES += rdata_tsig_fromWire9.wire
BUILT_SOURCES += rdata_tsig_toWire1.wire rdata_tsig_toWire2.wire
BUILT_SOURCES += rdata_tsig_toWire3.wire rdata_tsig_toWire4.wire
BUILT_SOURCES += rdata_tsig_toWire5.wire
+BUILT_SOURCES += tsigrecord_toWire1.wire tsigrecord_toWire2.wire
# NOTE: keep this in sync with real file listing
# so is included in tarball
@@ -46,7 +48,7 @@ EXTRA_DIST += message_fromWire5 message_fromWire6
EXTRA_DIST += message_fromWire7 message_fromWire8
EXTRA_DIST += message_fromWire9 message_fromWire10.spec
EXTRA_DIST += message_fromWire11.spec
-EXTRA_DIST += message_toWire1
+EXTRA_DIST += message_toWire1 message_toWire2.spec message_toWire3.spec
EXTRA_DIST += name_fromWire1 name_fromWire2 name_fromWire3_1 name_fromWire3_2
EXTRA_DIST += name_fromWire4 name_fromWire6 name_fromWire7 name_fromWire8
EXTRA_DIST += name_fromWire9 name_fromWire10 name_fromWire11 name_fromWire12
@@ -66,7 +68,8 @@ EXTRA_DIST += rdata_nsec_fromWire6.spec rdata_nsec_fromWire7.spec
EXTRA_DIST += rdata_nsec_fromWire8.spec rdata_nsec_fromWire9.spec
EXTRA_DIST += rdata_nsec_fromWire10.spec
EXTRA_DIST += rdata_nsec3param_fromWire1
-EXTRA_DIST += rdata_nsec3_fromWire1 rdata_nsec3_fromWire3
+EXTRA_DIST += rdata_nsec3_fromWire1
+EXTRA_DIST += rdata_nsec3_fromWire2.spec rdata_nsec3_fromWire3
EXTRA_DIST += rdata_nsec3_fromWire4.spec rdata_nsec3_fromWire5.spec
EXTRA_DIST += rdata_nsec3_fromWire6.spec rdata_nsec3_fromWire7.spec
EXTRA_DIST += rdata_nsec3_fromWire8.spec rdata_nsec3_fromWire9.spec
@@ -94,7 +97,7 @@ EXTRA_DIST += rdata_tsig_fromWire9.spec
EXTRA_DIST += rdata_tsig_toWire1.spec rdata_tsig_toWire2.spec
EXTRA_DIST += rdata_tsig_toWire3.spec rdata_tsig_toWire4.spec
EXTRA_DIST += rdata_tsig_toWire5.spec
-EXTRA_DIST += rdata_nsec3_fromWire2.spec
+EXTRA_DIST += tsigrecord_toWire1.spec tsigrecord_toWire2.spec
.spec.wire:
./gen-wiredata.py -o $@ $<
diff --git a/src/lib/dns/tests/testdata/gen-wiredata.py.in b/src/lib/dns/tests/testdata/gen-wiredata.py.in
index 72cbdaa..15a2b12 100755
--- a/src/lib/dns/tests/testdata/gen-wiredata.py.in
+++ b/src/lib/dns/tests/testdata/gen-wiredata.py.in
@@ -433,6 +433,11 @@ class RRSIG:
f.write('%04x %s %s\n' % (self.tag, name_wire, sig_wire))
class TSIG:
+ as_rr = False
+ rr_name = 'example.com' # only when as_rr is True, same for class/TTL
+ rr_class = parse_value('ANY', dict_rrclass)
+ rr_ttl = 0
+
rdlen = None # auto-calculate
algorithm = 'hmac-sha256'
time_signed = 1286978795 # arbitrarily chosen default
@@ -471,8 +476,16 @@ class TSIG:
if rdlen is None:
rdlen = int(len(name_wire) / 2 + 16 + len(mac) / 2 + \
len(other_data) / 2)
- f.write('\n# TSIG RDATA (RDLEN=%d)\n' % rdlen)
- f.write('%04x\n' % rdlen);
+ if self.as_rr:
+ f.write('\n# TSIG RR (QNAME=%s Class=%s TTL=%d RDLEN=%d)\n' %
+ (self.rr_name, rdict_rrclass[self.rr_class],
+ self.rr_ttl, rdlen))
+ f.write('%s %04x %04x %08x %04x\n' %
+ (encode_name(self.rr_name), dict_rrtype['tsig'],
+ self.rr_class, self.rr_ttl, rdlen))
+ else:
+ f.write('\n# TSIG RDATA (RDLEN=%d)\n' % rdlen)
+ f.write('%04x\n' % rdlen);
f.write('# Algorithm=%s Time-Signed=%d Fudge=%d\n' %
(self.algorithm, self.time_signed, self.fudge))
f.write('%s %012x %04x\n' % (name_wire, self.time_signed, self.fudge))
diff --git a/src/lib/dns/tests/testdata/message_toWire2.spec b/src/lib/dns/tests/testdata/message_toWire2.spec
new file mode 100644
index 0000000..19f0720
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toWire2.spec
@@ -0,0 +1,21 @@
+#
+# A simple DNS response message with TSIG signed
+#
+
+[custom]
+sections: header:question:tsig
+[header]
+id: 0x2d65
+rd: 1
+arcount: 1
+[question]
+name: www.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0x227026ad297beee721ce6c6fff1e9ef3
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/message_toWire3.spec b/src/lib/dns/tests/testdata/message_toWire3.spec
new file mode 100644
index 0000000..79b4c7e
--- /dev/null
+++ b/src/lib/dns/tests/testdata/message_toWire3.spec
@@ -0,0 +1,22 @@
+#
+# A simple DNS response message with EDNS and TSIG
+#
+
+[custom]
+sections: header:question:edns:tsig
+[header]
+id: 0x06cd
+rd: 1
+arcount: 2
+[question]
+name: www.example.com
+[edns]
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4db60d1f
+mac_size: 16
+mac: 0x93444053881c83d7eb120e86f25b369e
+original_id: 0x06cd
diff --git a/src/lib/dns/tests/testdata/tsigrecord_toWire1.spec b/src/lib/dns/tests/testdata/tsigrecord_toWire1.spec
new file mode 100644
index 0000000..a25dc46
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsigrecord_toWire1.spec
@@ -0,0 +1,16 @@
+#
+# A simple TSIG RR (some of the parameters are taken from a live example
+# and don't have a specific meaning)
+#
+
+[custom]
+sections: tsig
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0xdadadadadadadadadadadadadadadada
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/testdata/tsigrecord_toWire2.spec b/src/lib/dns/tests/testdata/tsigrecord_toWire2.spec
new file mode 100644
index 0000000..f667e4c
--- /dev/null
+++ b/src/lib/dns/tests/testdata/tsigrecord_toWire2.spec
@@ -0,0 +1,19 @@
+#
+# TSIG RR after some names that could (unexpectedly) cause name compression
+#
+
+[custom]
+sections: name/1:name/2:tsig
+[name/1]
+name: hmac-md5.sig-alg.reg.int
+[name/2]
+name: foo.example.com
+[tsig]
+as_rr: True
+# TSIG QNAME won't be compressed
+rr_name: www.example.com
+algorithm: hmac-md5
+time_signed: 0x4da8877a
+mac_size: 16
+mac: 0xdadadadadadadadadadadadadadadada
+original_id: 0x2d65
diff --git a/src/lib/dns/tests/tsig_unittest.cc b/src/lib/dns/tests/tsig_unittest.cc
index 28189cc..efa0490 100644
--- a/src/lib/dns/tests/tsig_unittest.cc
+++ b/src/lib/dns/tests/tsig_unittest.cc
@@ -26,6 +26,7 @@
#include <util/buffer.h>
#include <util/encode/base64.h>
#include <util/unittests/newhook.h>
+#include <util/time_utilities.h>
#include <dns/message.h>
#include <dns/messagerenderer.h>
@@ -36,6 +37,7 @@
#include <dns/rrtype.h>
#include <dns/tsig.h>
#include <dns/tsigkey.h>
+#include <dns/tsigrecord.h>
#include <dns/tests/unittest_util.h>
@@ -49,14 +51,12 @@ using isc::UnitTestUtil;
// See dnssectime.cc
namespace isc {
-namespace dns {
-namespace tsig {
+namespace util {
namespace detail {
extern int64_t (*gettimeFunction)();
}
}
}
-}
namespace {
// See dnssectime_unittest.cc
@@ -75,7 +75,7 @@ protected:
{
// Make sure we use the system time by default so that we won't be
// confused due to other tests that tweak the time.
- tsig::detail::gettimeFunction = NULL;
+ isc::util::detail::gettimeFunction = NULL;
decodeBase64("SFuWd/q99SzF8Yzd1QbB9g==", secret);
tsig_ctx.reset(new TSIGContext(TSIGKey(test_name,
@@ -87,7 +87,7 @@ protected:
secret.size())));
}
~TSIGTest() {
- tsig::detail::gettimeFunction = NULL;
+ isc::util::detail::gettimeFunction = NULL;
}
// Many of the tests below create some DNS message and sign it under
@@ -209,7 +209,7 @@ const uint8_t common_expected_mac[] = {
0x21, 0xce, 0x6c, 0x6f, 0xff, 0x1e, 0x9e, 0xf3
};
TEST_F(TSIGTest, sign) {
- tsig::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
{
SCOPED_TRACE("Sign test for query");
@@ -223,7 +223,7 @@ TEST_F(TSIGTest, sign) {
// non canonical) characters. The digest must be the same. It should actually
// be ensured at the level of TSIGKey, but we confirm that at this level, too.
TEST_F(TSIGTest, signUsingUpperCasedKeyName) {
- tsig::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
TSIGContext cap_ctx(TSIGKey(Name("WWW.EXAMPLE.COM"),
TSIGKey::HMACMD5_NAME(),
@@ -239,7 +239,7 @@ TEST_F(TSIGTest, signUsingUpperCasedKeyName) {
// Same as the previous test, but for the algorithm name.
TEST_F(TSIGTest, signUsingUpperCasedAlgorithmName) {
- tsig::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
TSIGContext cap_ctx(TSIGKey(test_name,
Name("HMAC-md5.SIG-alg.REG.int"),
@@ -325,7 +325,7 @@ TEST_F(TSIGTest, signExceptionSafety) {
// HMAC Size: 20
// HMAC: 415340c7daf824ed684ee586f7b5a67a2febc0d3
TEST_F(TSIGTest, signUsingHMACSHA1) {
- tsig::detail::gettimeFunction = testGetTime<0x4dae7d5f>;
+ isc::util::detail::gettimeFunction = testGetTime<0x4dae7d5f>;
secret.clear();
decodeBase64("MA+QDhXbyqUak+qnMFyTyEirzng=", secret);
@@ -350,7 +350,7 @@ TEST_F(TSIGTest, signUsingHMACSHA1) {
// Answer: www.example.com. 86400 IN A 192.0.2.1
// MAC: 8fcda66a7cd1a3b9948eb1869d384a9f
TEST_F(TSIGTest, signResponse) {
- tsig::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
ConstTSIGRecordPtr tsig = createMessageAndSign(qid, test_name,
tsig_ctx.get());
@@ -385,7 +385,7 @@ TEST_F(TSIGTest, signResponse) {
// Answer: example.com. 86400 IN NS ns.example.com.
// MAC: 102458f7f62ddd7d638d746034130968
TEST_F(TSIGTest, signContinuation) {
- tsig::detail::gettimeFunction = testGetTime<0x4da8e951>;
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8e951>;
const uint16_t axfr_qid = 0x3410;
const Name zone_name("example.com");
@@ -435,7 +435,7 @@ TEST_F(TSIGTest, signContinuation) {
// Error: 0x12 (BADTIME), Other Len: 6
// Other data: 00004da8be86
TEST_F(TSIGTest, badtimeResponse) {
- tsig::detail::gettimeFunction = testGetTime<0x4da8b9d6>;
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8b9d6>;
const uint16_t test_qid = 0x7fc4;
ConstTSIGRecordPtr tsig = createMessageAndSign(test_qid, test_name,
@@ -444,7 +444,7 @@ TEST_F(TSIGTest, badtimeResponse) {
// "advance the clock" and try validating, which should fail due to BADTIME
// (verifyTentative actually doesn't check the time, though)
- tsig::detail::gettimeFunction = testGetTime<0x4da8be86>;
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8be86>;
tsig_verify_ctx->verifyTentative(tsig, TSIGError::BAD_TIME());
EXPECT_EQ(TSIGError::BAD_TIME(), tsig_verify_ctx->getError());
@@ -468,7 +468,7 @@ TEST_F(TSIGTest, badtimeResponse) {
}
TEST_F(TSIGTest, badsigResponse) {
- tsig::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
// Sign a simple message, and force the verification to fail with
// BADSIG.
@@ -489,7 +489,7 @@ TEST_F(TSIGTest, badsigResponse) {
TEST_F(TSIGTest, badkeyResponse) {
// A similar test as badsigResponse but for BADKEY
- tsig::detail::gettimeFunction = testGetTime<0x4da8877a>;
+ isc::util::detail::gettimeFunction = testGetTime<0x4da8877a>;
tsig_verify_ctx->verifyTentative(createMessageAndSign(qid, test_name,
tsig_ctx.get()),
TSIGError::BAD_KEY());
diff --git a/src/lib/dns/tests/tsigrecord_unittest.cc b/src/lib/dns/tests/tsigrecord_unittest.cc
new file mode 100644
index 0000000..c1223ee
--- /dev/null
+++ b/src/lib/dns/tests/tsigrecord_unittest.cc
@@ -0,0 +1,120 @@
+// 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 <vector>
+#include <sstream>
+
+#include <gtest/gtest.h>
+
+#include <util/buffer.h>
+
+#include <dns/messagerenderer.h>
+#include <dns/name.h>
+#include <dns/rdataclass.h>
+#include <dns/tsig.h>
+#include <dns/tsigkey.h>
+#include <dns/tsigrecord.h>
+
+#include <dns/tests/unittest_util.h>
+
+using namespace std;
+using namespace isc::util;
+using namespace isc::dns;
+using namespace isc::dns::rdata;
+using isc::UnitTestUtil;
+
+namespace {
+class TSIGRecordTest : public ::testing::Test {
+protected:
+ TSIGRecordTest() :
+ test_name("www.example.com"), test_mac(16, 0xda),
+ test_record(test_name, any::TSIG(TSIGKey::HMACMD5_NAME(), 0x4da8877a,
+ TSIGContext::DEFAULT_FUDGE,
+ test_mac.size(), &test_mac[0],
+ 0x2d65, 0, 0, NULL)),
+ buffer(0), renderer(buffer)
+ {}
+ const Name test_name;
+ vector<unsigned char> test_mac;
+ const TSIGRecord test_record;
+ OutputBuffer buffer;
+ MessageRenderer renderer;
+ vector<unsigned char> data;
+};
+
+TEST_F(TSIGRecordTest, getName) {
+ EXPECT_EQ(test_name, test_record.getName());
+}
+
+TEST_F(TSIGRecordTest, getLength) {
+ // 85 = 17 + 26 + 16 + 26
+ // len(www.example.com) = 17
+ // len(hmac-md5.sig-alg.reg.int) = 26
+ // len(MAC) = 16
+ // the rest are fixed length fields (26 in total)
+ EXPECT_EQ(85, test_record.getLength());
+}
+
+TEST_F(TSIGRecordTest, recordToWire) {
+ UnitTestUtil::readWireData("tsigrecord_toWire1.wire", data);
+ EXPECT_EQ(1, test_record.toWire(renderer));
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+ renderer.getData(), renderer.getLength(),
+ &data[0], data.size());
+
+ // Same test for a dumb buffer
+ buffer.clear();
+ EXPECT_EQ(1, test_record.toWire(buffer));
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+ buffer.getData(), buffer.getLength(),
+ &data[0], data.size());
+}
+
+TEST_F(TSIGRecordTest, recordToOLongToWire) {
+ // By setting the limit to "record length - 1", it will fail, and the
+ // renderer will be marked as "truncated".
+ renderer.setLengthLimit(test_record.getLength() - 1);
+ EXPECT_FALSE(renderer.isTruncated()); // not marked before render attempt
+ EXPECT_EQ(0, test_record.toWire(renderer));
+ EXPECT_TRUE(renderer.isTruncated());
+}
+
+TEST_F(TSIGRecordTest, recordToWireAfterNames) {
+ // A similar test but the TSIG RR follows some domain names that could
+ // cause name compression inside TSIG. Our implementation shouldn't
+ // compress either owner (key) name or the algorithm name. This test
+ // confirms that.
+
+ UnitTestUtil::readWireData("tsigrecord_toWire2.wire", data);
+ renderer.writeName(TSIGKey::HMACMD5_NAME());
+ renderer.writeName(Name("foo.example.com"));
+ EXPECT_EQ(1, test_record.toWire(renderer));
+ EXPECT_PRED_FORMAT4(UnitTestUtil::matchWireData,
+ renderer.getData(), renderer.getLength(),
+ &data[0], data.size());
+}
+
+TEST_F(TSIGRecordTest, toText) {
+ EXPECT_EQ("www.example.com. 0 ANY TSIG hmac-md5.sig-alg.reg.int. "
+ "1302890362 300 16 2tra2tra2tra2tra2tra2g== 11621 NOERROR 0\n",
+ test_record.toText());
+}
+
+// test operator<<. We simply confirm it appends the result of toText().
+TEST_F(TSIGRecordTest, LeftShiftOperator) {
+ ostringstream oss;
+ oss << test_record;
+ EXPECT_EQ(test_record.toText(), oss.str());
+}
+} // end namespace
diff --git a/src/lib/dns/tsig.cc b/src/lib/dns/tsig.cc
index 48ac5e0..8e8301d 100644
--- a/src/lib/dns/tsig.cc
+++ b/src/lib/dns/tsig.cc
@@ -24,6 +24,7 @@
#include <exceptions/exceptions.h>
#include <util/buffer.h>
+#include <util/time_utilities.h>
#include <dns/rdataclass.h>
#include <dns/rrclass.h>
@@ -41,38 +42,10 @@ using namespace isc::dns::rdata;
namespace isc {
namespace dns {
-
-// Borrowed from dnssectime.cc. This trick should be unified somewhere.
-namespace tsig {
-namespace detail {
-int64_t (*gettimeFunction)() = NULL;
-}
-}
-
-namespace {
-int64_t
-gettimeofdayWrapper() {
- using namespace tsig::detail;
- if (gettimeFunction != NULL) {
- return (gettimeFunction());
- }
-
- struct timeval now;
- gettimeofday(&now, NULL);
-
- return (static_cast<int64_t>(now.tv_sec));
-}
-}
-
namespace {
typedef boost::shared_ptr<HMAC> HMACPtr;
}
-const RRClass&
-TSIGRecord::getClass() {
- return (RRClass::ANY());
-}
-
struct TSIGContext::TSIGContextImpl {
TSIGContextImpl(const TSIGKey& key) :
state_(INIT), key_(key), error_(Rcode::NOERROR()),
@@ -118,7 +91,7 @@ TSIGContext::sign(const uint16_t qid, const void* const data,
// represents a value in the expected range. (In reality, however,
// gettimeofdayWrapper() will return a positive integer that will fit
// in 48 bits)
- const uint64_t now = (gettimeofdayWrapper() & 0x0000ffffffffffffULL);
+ const uint64_t now = (detail::gettimeWrapper() & 0x0000ffffffffffffULL);
// For responses adjust the error code.
if (impl_->state_ == CHECKED) {
@@ -129,6 +102,7 @@ TSIGContext::sign(const uint16_t qid, const void* const data,
// specified in Section 4.3 of RFC2845.
if (error == TSIGError::BAD_SIG() || error == TSIGError::BAD_KEY()) {
ConstTSIGRecordPtr tsig(new TSIGRecord(
+ impl_->key_.getKeyName(),
any::TSIG(impl_->key_.getAlgorithmName(),
now, DEFAULT_FUDGE, 0, NULL,
qid, error.getCode(), 0, NULL)));
@@ -198,6 +172,7 @@ TSIGContext::sign(const uint16_t qid, const void* const data,
// Get the final digest, update internal state, then finish.
vector<uint8_t> digest = hmac->sign();
ConstTSIGRecordPtr tsig(new TSIGRecord(
+ impl_->key_.getKeyName(),
any::TSIG(impl_->key_.getAlgorithmName(),
time_signed, DEFAULT_FUDGE,
digest.size(), &digest[0],
diff --git a/src/lib/dns/tsig.h b/src/lib/dns/tsig.h
index 55ab41e..fbcb1bb 100644
--- a/src/lib/dns/tsig.h
+++ b/src/lib/dns/tsig.h
@@ -15,84 +15,14 @@
#ifndef __TSIG_H
#define __TSIG_H 1
-#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
-#include <dns/rdataclass.h>
#include <dns/tsigerror.h>
#include <dns/tsigkey.h>
+#include <dns/tsigrecord.h>
namespace isc {
namespace dns {
-/// TSIG resource record.
-///
-/// A \c TSIGRecord class object represents a TSIG resource record and is
-/// responsible for conversion to and from wire format TSIG record based on
-/// the protocol specification (RFC2845).
-/// This class is provided so that other classes and applications can handle
-/// TSIG without knowing protocol details of TSIG, such as that it uses a
-/// fixed constant of TTL.
-///
-/// \note So the plan is to eventually provide a \c toWire() method and
-/// the "from wire" constructor. They are not yet provided in this initial
-/// step.
-///
-/// \note
-/// This class could be a derived class of \c AbstractRRset. That way
-/// it would be able to be used in a polymorphic way; for example,
-/// an application can construct a TSIG RR by itself and insert it to a
-/// \c Message object as a generic RRset. On the other hand, it would mean
-/// this class would have to implement an \c RdataIterator (even though it
-/// can be done via straightforward forwarding) while the iterator is mostly
-/// redundant since there should be one and only one RDATA for a valid TSIG
-/// RR. Likewise, some methods such as \c setTTL() method wouldn't be well
-/// defined due to such special rules for TSIG as using a fixed TTL.
-/// Overall, TSIG is a very special RR type that simply uses the compatible
-/// resource record format, and it will be unlikely that a user wants to
-/// handle it through a generic interface in a polymorphic way.
-/// We therefore chose to define it as a separate class. This is also
-/// similar to why \c EDNS is a separate class.
-class TSIGRecord {
-public:
- /// Constructor from TSIG RDATA
- ///
- /// \exception std::bad_alloc Resource allocation for copying the RDATA
- /// fails
- explicit TSIGRecord(const rdata::any::TSIG& tsig_rdata) :
- rdata_(tsig_rdata)
- {}
-
- /// Return the RDATA of the TSIG RR
- ///
- /// \exception None
- const rdata::any::TSIG& getRdata() const { return (rdata_); }
-
- /// \name Protocol constants and defaults
- ///
- //@{
- /// Return the RR class of TSIG
- ///
- /// TSIG always uses the ANY RR class. This static method returns it,
- /// when, though unlikely, an application wants to know which class TSIG
- /// is supposed to use.
- ///
- /// \exception None
- static const RRClass& getClass();
-
- /// The TTL value to be used in TSIG RRs.
- static const uint32_t TSIG_TTL = 0;
- //@}
-
-private:
- const rdata::any::TSIG rdata_;
-};
-
-/// A pointer-like type pointing to a \c TSIGRecord object.
-typedef boost::shared_ptr<TSIGRecord> TSIGRecordPtr;
-
-/// A pointer-like type pointing to an immutable \c TSIGRecord object.
-typedef boost::shared_ptr<const TSIGRecord> ConstTSIGRecordPtr;
-
/// TSIG session context.
///
/// The \c TSIGContext class maintains a context of a signed session of
diff --git a/src/lib/dns/tsigrecord.cc b/src/lib/dns/tsigrecord.cc
new file mode 100644
index 0000000..503ee2c
--- /dev/null
+++ b/src/lib/dns/tsigrecord.cc
@@ -0,0 +1,109 @@
+// 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 <ostream>
+#include <string>
+
+#include <util/buffer.h>
+
+#include <dns/messagerenderer.h>
+#include <dns/rrclass.h>
+#include <dns/rrttl.h>
+#include <dns/tsigrecord.h>
+
+using namespace isc::util;
+
+namespace {
+// Internally used constants:
+
+// Size in octets for the RR type, class TTL, RDLEN fields.
+const size_t RR_COMMON_LEN = 10;
+
+// Size in octets for the fixed part of TSIG RDATAs.
+// - Time Signed (6)
+// - Fudge (2)
+// - MAC Size (2)
+// - Original ID (2)
+// - Error (2)
+// - Other Len (2)
+const size_t RDATA_COMMON_LEN = 16;
+}
+
+namespace isc {
+namespace dns {
+TSIGRecord::TSIGRecord(const Name& key_name,
+ const rdata::any::TSIG& tsig_rdata) :
+ key_name_(key_name), rdata_(tsig_rdata),
+ length_(RR_COMMON_LEN + RDATA_COMMON_LEN + key_name_.getLength() +
+ rdata_.getAlgorithm().getLength() +
+ rdata_.getMACSize() + rdata_.getOtherLen())
+{}
+
+const RRClass&
+TSIGRecord::getClass() {
+ return (RRClass::ANY());
+}
+
+namespace {
+template <typename OUTPUT>
+void
+toWireCommon(OUTPUT& output, const rdata::any::TSIG& rdata) {
+ // RR type, class, TTL are fixed constants.
+ RRType::TSIG().toWire(output);
+ TSIGRecord::getClass().toWire(output);
+ output.writeUint32(TSIGRecord::TSIG_TTL);
+
+ // RDLEN
+ output.writeUint16(RDATA_COMMON_LEN + rdata.getAlgorithm().getLength() +
+ rdata.getMACSize() + rdata.getOtherLen());
+
+ // TSIG RDATA
+ rdata.toWire(output);
+}
+}
+
+int
+TSIGRecord::toWire(AbstractMessageRenderer& renderer) const {
+ // If adding the TSIG would exceed the size limit, don't do it.
+ if (renderer.getLength() + length_ > renderer.getLengthLimit()) {
+ renderer.setTruncated();
+ return (0);
+ }
+
+ // key name = owner. note that we disable compression.
+ renderer.writeName(key_name_, false);
+ toWireCommon(renderer, rdata_);
+ return (1);
+}
+
+int
+TSIGRecord::toWire(OutputBuffer& buffer) const {
+ key_name_.toWire(buffer);
+ toWireCommon(buffer, rdata_);
+ return (1);
+}
+
+std::string
+TSIGRecord::toText() const {
+ return (key_name_.toText() + " " + RRTTL(TSIG_TTL).toText() + " " +
+ getClass().toText() + " " + RRType::TSIG().toText() + " " +
+ rdata_.toText() + "\n");
+}
+
+std::ostream&
+operator<<(std::ostream& os, const TSIGRecord& record) {
+ return (os << record.toText());
+}
+} // namespace dns
+} // namespace isc
diff --git a/src/lib/dns/tsigrecord.h b/src/lib/dns/tsigrecord.h
new file mode 100644
index 0000000..7688a36
--- /dev/null
+++ b/src/lib/dns/tsigrecord.h
@@ -0,0 +1,191 @@
+// 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.
+
+#ifndef __TSIGRECORD_H
+#define __TSIGRECORD_H 1
+
+#include <ostream>
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+
+#include <dns/name.h>
+#include <dns/rdataclass.h>
+
+namespace isc {
+namespace util {
+class OutputBuffer;
+}
+namespace dns {
+class AbstractMessageRenderer;
+
+/// TSIG resource record.
+///
+/// A \c TSIGRecord class object represents a TSIG resource record and is
+/// responsible for conversion to and from wire format TSIG record based on
+/// the protocol specification (RFC2845).
+/// This class is provided so that other classes and applications can handle
+/// TSIG without knowing protocol details of TSIG, such as that it uses a
+/// fixed constant of TTL.
+///
+/// \todo So the plan is to eventually provide the "from wire" constructor.
+/// It's not yet provided in the current phase of development.
+///
+/// \note
+/// This class could be a derived class of \c AbstractRRset. That way
+/// it would be able to be used in a polymorphic way; for example,
+/// an application can construct a TSIG RR by itself and insert it to a
+/// \c Message object as a generic RRset. On the other hand, it would mean
+/// this class would have to implement an \c RdataIterator (even though it
+/// can be done via straightforward forwarding) while the iterator is mostly
+/// redundant since there should be one and only one RDATA for a valid TSIG
+/// RR. Likewise, some methods such as \c setTTL() method wouldn't be well
+/// defined due to such special rules for TSIG as using a fixed TTL.
+/// Overall, TSIG is a very special RR type that simply uses the compatible
+/// resource record format, and it will be unlikely that a user wants to
+/// handle it through a generic interface in a polymorphic way.
+/// We therefore chose to define it as a separate class. This is also
+/// similar to why \c EDNS is a separate class.
+class TSIGRecord {
+public:
+ /// Constructor from TSIG key name and RDATA
+ ///
+ /// \exception std::bad_alloc Resource allocation for copying the name or
+ /// RDATA fails
+ TSIGRecord(const Name& key_name, const rdata::any::TSIG& tsig_rdata);
+
+ /// Return the owner name of the TSIG RR, which is the TSIG key name
+ ///
+ /// \exception None
+ const Name& getName() const { return (key_name_); }
+
+ /// Return the RDATA of the TSIG RR
+ ///
+ /// \exception None
+ const rdata::any::TSIG& getRdata() const { return (rdata_); }
+
+ /// \name Protocol constants and defaults
+ ///
+ //@{
+ /// Return the RR class of TSIG
+ ///
+ /// TSIG always uses the ANY RR class. This static method returns it,
+ /// when, though unlikely, an application wants to know which class TSIG
+ /// is supposed to use.
+ ///
+ /// \exception None
+ static const RRClass& getClass();
+
+ /// Return the length of the TSIG record
+ ///
+ /// When constructed from the key name and RDATA, it is the length of
+ /// the record when it is rendered by the \c toWire() method.
+ ///
+ /// \note When constructed "from wire", that will mean the length of
+ /// the wire format data for the TSIG RR. The length will be necessary
+ /// to verify the message once parse is completed. But this part is not
+ /// implemented yet.
+ ///
+ /// \exception None
+ size_t getLength() const { return (length_); }
+
+ /// \brief Render the \c TSIG RR in the wire format.
+ ///
+ /// This method renders the TSIG record as a form of a DNS TSIG RR
+ /// via \c renderer, which encapsulates output buffer and other rendering
+ /// contexts.
+ ///
+ /// Normally this version of \c toWire() method tries to compress the
+ /// owner name of the RR whenever possible, but this method intentionally
+ /// skips owner name compression. This is due to a report that some
+ /// Windows clients refuse a TSIG if its owner name is compressed
+ /// (See http://marc.info/?l=bind-workers&m=126637138430819&w=2).
+ /// Reportedly this seemed to be specific to GSS-TSIG, but this
+ /// implementation skip compression regardless of the algorithm.
+ ///
+ /// If by adding the TSIG RR the message size would exceed the limit
+ /// maintained in \c renderer, this method skips rendering the RR
+ /// and returns 0 and mark \c renderer as "truncated" (so that a
+ /// subsequent call to \c isTruncated() on \c renderer will result in
+ /// \c true); otherwise it returns 1, which is the number of RR
+ /// rendered.
+ ///
+ /// \note If the caller follows the specification of adding TSIG
+ /// as described in RFC2845, this should not happen; the caller is
+ /// generally expected to leave a sufficient room in the message for
+ /// the TSIG. But this method checks the unexpected case nevertheless.
+ ///
+ /// \exception std::bad_alloc Internal resource allocation fails (this
+ /// should be rare).
+ ///
+ /// \param renderer DNS message rendering context that encapsulates the
+ /// output buffer and name compression information.
+ /// \return 1 if the TSIG RR fits in the message size limit; otherwise 0.
+ int toWire(AbstractMessageRenderer& renderer) const;
+
+ /// \brief Render the \c TSIG RR in the wire format.
+ ///
+ /// This method is same as \c toWire(AbstractMessageRenderer&)const
+ /// except it renders the RR in an \c OutputBuffer and therefore
+ /// does not care about message size limit.
+ /// As a consequence it always returns 1.
+ int toWire(isc::util::OutputBuffer& buffer) const;
+
+ /// Convert the TSIG record to a string.
+ ///
+ /// The output format is the same as the result of \c toText() for
+ /// other normal types of RRsets (with always using the same RR class
+ /// and TTL). It also ends with a newline.
+ ///
+ /// \exception std::bad_alloc Internal resource allocation fails (this
+ /// should be rare).
+ ///
+ /// \return A string representation of \c TSIG record
+ std::string toText() const;
+
+ /// The TTL value to be used in TSIG RRs.
+ static const uint32_t TSIG_TTL = 0;
+ //@}
+
+private:
+ const Name key_name_;
+ const rdata::any::TSIG rdata_;
+ const size_t length_;
+};
+
+/// A pointer-like type pointing to a \c TSIGRecord object.
+typedef boost::shared_ptr<TSIGRecord> TSIGRecordPtr;
+
+/// A pointer-like type pointing to an immutable \c TSIGRecord object.
+typedef boost::shared_ptr<const TSIGRecord> ConstTSIGRecordPtr;
+
+/// Insert the \c TSIGRecord as a string into stream.
+///
+/// This method convert \c record into a string and inserts it into the
+/// output stream \c os.
+///
+/// \param os A \c std::ostream object on which the insertion operation is
+/// performed.
+/// \param record An \c TSIGRecord object output by the operation.
+/// \return A reference to the same \c std::ostream object referenced by
+/// parameter \c os after the insertion operation.
+std::ostream& operator<<(std::ostream& os, const TSIGRecord& record);
+}
+}
+
+#endif // __TSIGRECORD_H
+
+// Local Variables:
+// mode: c++
+// End:
diff --git a/src/lib/util/time_utilities.cc b/src/lib/util/time_utilities.cc
index 229800d..9303ab5 100644
--- a/src/lib/util/time_utilities.cc
+++ b/src/lib/util/time_utilities.cc
@@ -110,12 +110,9 @@ timeToText64(uint64_t value) {
// library, it's not even declared in a header file.
namespace detail {
int64_t (*gettimeFunction)() = NULL;
-}
-namespace {
int64_t
-gettimeofdayWrapper() {
- using namespace detail;
+gettimeWrapper() {
if (gettimeFunction != NULL) {
return (gettimeFunction());
}
@@ -132,7 +129,7 @@ timeToText32(const uint32_t value) {
// We first adjust the time to the closest epoch based on the current time.
// Note that the following variables must be signed in order to handle
// time until year 2038 correctly.
- const int64_t start = gettimeofdayWrapper() - 0x7fffffff;
+ const int64_t start = detail::gettimeWrapper() - 0x7fffffff;
int64_t base = 0;
int64_t t;
while ((t = (base + value)) < start) {
diff --git a/src/lib/util/time_utilities.h b/src/lib/util/time_utilities.h
index 0558f16..a53089d 100644
--- a/src/lib/util/time_utilities.h
+++ b/src/lib/util/time_utilities.h
@@ -15,6 +15,8 @@
#ifndef __TIME_UTILITIES_H
#define __TIME_UTILITIES_H 1
+#include <string>
+
#include <sys/types.h>
#include <stdint.h>
@@ -39,6 +41,32 @@ public:
isc::Exception(file, line, what) {}
};
+namespace detail {
+/// Return the current time in seconds
+///
+/// This function returns the "current" time in seconds from epoch
+/// (00:00:00 January 1, 1970) as a 64-bit signed integer. The return
+/// value can represent a point of time before epoch as a negative number.
+///
+/// This function is provided to help test time conscious implementations
+/// such as DNSSEC and TSIG signatures. It is difficult to test them with
+/// an unusual or a specifically chosen "current" via system-provided
+/// library functions to get time. This function acts as a straightforward
+/// wrapper of such a library function, but provides test code with a hook
+/// to return an arbitrary time value: if \c isc::util::detail::gettimeFunction
+/// is set to a pointer of function that returns 64-bit signed integer,
+/// \c gettimeWrapper() calls that function instead of the system library.
+///
+/// This hook variable is specifically intended for testing purposes, so,
+/// even if it's visible outside of this library, it's not even declared in a
+/// header file.
+///
+/// If the implementation doesn't need to be tested with faked current time,
+/// it should simply use the system supplied library function instead of
+/// this one.
+int64_t gettimeWrapper();
+}
+
///
/// \name DNSSEC time conversion functions.
///
More information about the bind10-changes
mailing list