|
@@ -25,8 +25,12 @@ using namespace isc::dns;
|
|
|
|
|
|
D2UpdateMessage::D2UpdateMessage(const bool parse)
|
|
|
: message_(parse ? dns::Message::PARSE : dns::Message::RENDER) {
|
|
|
+ // If this object is to create an outgoing message, we have to
|
|
|
+ // set the proper Opcode field and QR flag here.
|
|
|
if (!parse) {
|
|
|
message_.setOpcode(Opcode(Opcode::UPDATE_CODE));
|
|
|
+ message_.setHeaderFlag(dns::Message::HEADERFLAG_QR, false);
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -36,20 +40,14 @@ D2UpdateMessage::getQRFlag() const {
|
|
|
RESPONSE : REQUEST);
|
|
|
}
|
|
|
|
|
|
-void
|
|
|
-D2UpdateMessage::setQRFlag(const QRFlag flag) {
|
|
|
- bool on = (flag == RESPONSE ? true : false);
|
|
|
- message_.setHeaderFlag(dns::Message::HEADERFLAG_QR, on);
|
|
|
-}
|
|
|
-
|
|
|
uint16_t
|
|
|
-D2UpdateMessage::getQid() const {
|
|
|
+D2UpdateMessage::getId() const {
|
|
|
return (message_.getQid());
|
|
|
}
|
|
|
|
|
|
void
|
|
|
-D2UpdateMessage::setQid(const uint16_t qid) {
|
|
|
- message_.setQid(qid);
|
|
|
+D2UpdateMessage::setId(const uint16_t id) {
|
|
|
+ message_.setQid(id);
|
|
|
}
|
|
|
|
|
|
|
|
@@ -80,12 +78,16 @@ D2UpdateMessage::endSection(const UpdateMsgSection section) const {
|
|
|
|
|
|
void
|
|
|
D2UpdateMessage::setZone(const Name& zone, const RRClass& rrclass) {
|
|
|
+ // The Zone data is kept in the underlying Question class. If there
|
|
|
+ // is a record stored there already, we need to remove it, because
|
|
|
+ // we may have at most one Zone record in the DNS Update message.
|
|
|
if (message_.getRRCount(dns::Message::SECTION_QUESTION) > 0) {
|
|
|
message_.clearSection(dns::Message::SECTION_QUESTION);
|
|
|
}
|
|
|
-
|
|
|
+ // Add the new record...
|
|
|
Question question(zone, rrclass, RRType::SOA());
|
|
|
message_.addQuestion(question);
|
|
|
+ // ... and update the local class member holding the D2Zone object.
|
|
|
zone_.reset(new D2Zone(question.getName(), question.getClass()));
|
|
|
}
|
|
|
|
|
@@ -98,22 +100,19 @@ void
|
|
|
D2UpdateMessage::addRRset(const UpdateMsgSection section,
|
|
|
const dns::RRsetPtr& rrset) {
|
|
|
message_.addRRset(ddnsToDnsSection(section), rrset);
|
|
|
-
|
|
|
-}
|
|
|
-
|
|
|
-bool
|
|
|
-D2UpdateMessage::hasRRset(const UpdateMsgSection section, const dns::Name& name,
|
|
|
- const dns::RRClass& rrclass, const dns::RRType& rrtype) {
|
|
|
- return (message_.hasRRset(ddnsToDnsSection(section), name, rrclass, rrtype));
|
|
|
-}
|
|
|
-
|
|
|
-bool
|
|
|
-D2UpdateMessage::hasRRset(const UpdateMsgSection section, const dns::RRsetPtr &rrset) {
|
|
|
- return (message_.hasRRset(ddnsToDnsSection(section), rrset));
|
|
|
}
|
|
|
|
|
|
void
|
|
|
D2UpdateMessage::toWire(AbstractMessageRenderer& renderer) {
|
|
|
+ // We are preparing the wire format of the message, meaning
|
|
|
+ // that this message will be sent as a request to the DNS.
|
|
|
+ // Therefore, we expect that this message is a REQUEST.
|
|
|
+ if (getQRFlag() != REQUEST) {
|
|
|
+ isc_throw(InvalidQRFlag, "QR flag must be cleared for the outgoing"
|
|
|
+ " DNS Update message");
|
|
|
+ }
|
|
|
+ // According to RFC2136, the ZONE section may contain exactly one
|
|
|
+ // record.
|
|
|
if (getRRCount(SECTION_ZONE) != 1) {
|
|
|
isc_throw(InvalidZoneSection, "Zone section of the DNS Update message"
|
|
|
" must comprise exactly one record (RFC2136, section 2.3)");
|
|
@@ -123,16 +122,36 @@ D2UpdateMessage::toWire(AbstractMessageRenderer& renderer) {
|
|
|
|
|
|
void
|
|
|
D2UpdateMessage::fromWire(isc::util::InputBuffer& buffer) {
|
|
|
+ // First, use the underlying dns::Message implementation to get the
|
|
|
+ // contents of the DNS response message. Note that it may or may
|
|
|
+ // not be the message that we are interested in, but needs to be
|
|
|
+ // parsed so as we can check its ID, Opcode etc.
|
|
|
message_.fromWire(buffer);
|
|
|
+ // This class implements exposes the getZone() function. This function
|
|
|
+ // will return pointer to the D2Zone object if non-empty Zone
|
|
|
+ // section exists in the received message. It will return NULL pointer
|
|
|
+ // if it doesn't exist. The pointer is held in the D2UpdateMessage class
|
|
|
+ // member. We need to update this pointer every time we parse the
|
|
|
+ // message.
|
|
|
if (getRRCount(D2UpdateMessage::SECTION_ZONE) > 0) {
|
|
|
+ // There is a Zone section in the received message. Replace
|
|
|
+ // Zone pointer with the new value.
|
|
|
QuestionPtr question = *message_.beginQuestion();
|
|
|
assert(question);
|
|
|
zone_.reset(new D2Zone(question->getName(), question->getClass()));
|
|
|
|
|
|
} else {
|
|
|
+ // Zone section doesn't hold any pointers, so set the pointer to NULL.
|
|
|
zone_.reset();
|
|
|
|
|
|
}
|
|
|
+ // Check that the content of the received message is sane.
|
|
|
+ // One of the basic checks to do is to verify that we have
|
|
|
+ // received the DNS update message. If not, it can be dropped
|
|
|
+ // or an error message can be printed. Other than that, we
|
|
|
+ // will check that there is at most one Zone record and QR flag
|
|
|
+ // is set.
|
|
|
+ validate();
|
|
|
}
|
|
|
|
|
|
dns::Message::Section
|
|
@@ -153,6 +172,33 @@ D2UpdateMessage::ddnsToDnsSection(const UpdateMsgSection section) {
|
|
|
"unknown message section " << section);
|
|
|
}
|
|
|
|
|
|
+void
|
|
|
+D2UpdateMessage::validate() const {
|
|
|
+ // Verify that we are dealing with the DNS Update message. According to
|
|
|
+ // RFC 2136, section 3.8 server will copy the Opcode from the query.
|
|
|
+ // If we are dealing with a different type of message, we may simply
|
|
|
+ // stop further processing, because it is likely that the message was
|
|
|
+ // directed to someone else.
|
|
|
+ if (message_.getOpcode() != Opcode::UPDATE()) {
|
|
|
+ isc_throw(NotUpdateMessage, "received message is not a DDNS update, received"
|
|
|
+ " message code is " << message_.getOpcode().getCode());
|
|
|
+ }
|
|
|
+ // Received message should have QR flag set, which indicates that it is
|
|
|
+ // a RESPONSE.
|
|
|
+ if (getQRFlag() == REQUEST) {
|
|
|
+ isc_throw(NotUpdateMessage, "received message should should have QR flag set,"
|
|
|
+ " to indicate that it is a RESPONSE message, the QR flag is unset");
|
|
|
+ }
|
|
|
+ // DNS server may copy a Zone record from the query message. Since query must
|
|
|
+ // comprise exactly one Zone record (RFC 2136, section 2.3), the response message
|
|
|
+ // may contain 1 record at most. It may also contain no records if a server
|
|
|
+ // chooses not to copy Zone section.
|
|
|
+ if (getRRCount(SECTION_ZONE) > 1) {
|
|
|
+ isc_throw(InvalidZoneSection, "received message contains " << getRRCount(SECTION_ZONE)
|
|
|
+ << " Zone records, it should contain at most 1 record");
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
} // namespace d2
|
|
|
} // namespace isc
|
|
|
|