Kea  1.5.0
d2_update_message.cc
Go to the documentation of this file.
1 // Copyright (C) 2013-2015,2017 Internet Systems Consortium, Inc. ("ISC")
2 //
3 // This Source Code Form is subject to the terms of the Mozilla Public
4 // License, v. 2.0. If a copy of the MPL was not distributed with this
5 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
6 
7 #include <config.h>
8 
9 #include <d2/d2_update_message.h>
10 #include <dns/messagerenderer.h>
11 #include <dns/name.h>
12 #include <dns/opcode.h>
13 #include <dns/question.h>
14 
15 namespace isc {
16 namespace d2 {
17 
18 using namespace isc::dns;
19 
21  : message_(direction == INBOUND ?
22  dns::Message::PARSE : dns::Message::RENDER) {
23  // If this object is to create an outgoing message, we have to
24  // set the proper Opcode field and QR flag here.
25  if (direction == OUTBOUND) {
28  message_.setRcode(Rcode::NOERROR());
29  }
30 }
31 
34  return (message_.getHeaderFlag(dns::Message::HEADERFLAG_QR) ?
35  RESPONSE : REQUEST);
36 }
37 
38 uint16_t
40  return (message_.getQid());
41 }
42 
43 void
44 D2UpdateMessage::setId(const uint16_t id) {
45  message_.setQid(id);
46 }
47 
48 
49 const dns::Rcode&
51  return (message_.getRcode());
52 }
53 
54 void
56  message_.setRcode(rcode);
57 }
58 
59 unsigned int
61  return (message_.getRRCount(ddnsToDnsSection(section)));
62 }
63 
66  return (message_.beginSection(ddnsToDnsSection(section)));
67 }
68 
71  return (message_.endSection(ddnsToDnsSection(section)));
72 }
73 
74 void
75 D2UpdateMessage::setZone(const Name& zone, const RRClass& rrclass) {
76  // The Zone data is kept in the underlying Question class. If there
77  // is a record stored there already, we need to remove it, because
78  // we may have at most one Zone record in the DNS Update message.
79  if (message_.getRRCount(dns::Message::SECTION_QUESTION) > 0) {
81  }
82  // Add the new record...
83  Question question(zone, rrclass, RRType::SOA());
84  message_.addQuestion(question);
85  // ... and update the local class member holding the D2Zone object.
86  zone_.reset(new D2Zone(question.getName(), question.getClass()));
87 }
88 
91  return (zone_);
92 }
93 
94 void
96  const dns::RRsetPtr& rrset) {
97  if (section == SECTION_ZONE) {
98  isc_throw(isc::BadValue, "unable to add RRset to the Zone section"
99  " of the DNS Update message, use setZone instead");
100  }
101  message_.addRRset(ddnsToDnsSection(section), rrset);
102 }
103 
104 void
106  TSIGContext* const tsig_context) {
107  // We are preparing the wire format of the message, meaning
108  // that this message will be sent as a request to the DNS.
109  // Therefore, we expect that this message is a REQUEST.
110  if (getQRFlag() != REQUEST) {
111  isc_throw(InvalidQRFlag, "QR flag must be cleared for the outgoing"
112  " DNS Update message");
113  }
114  // According to RFC2136, the ZONE section may contain exactly one
115  // record.
116  if (getRRCount(SECTION_ZONE) != 1) {
117  isc_throw(InvalidZoneSection, "Zone section of the DNS Update message"
118  " must comprise exactly one record (RFC2136, section 2.3)");
119  }
120  message_.toWire(renderer, tsig_context);
121 }
122 
123 void
124 D2UpdateMessage::fromWire(const void* received_data, size_t bytes_received,
125  dns::TSIGContext* const tsig_context) {
126  // First, use the underlying dns::Message implementation to get the
127  // contents of the DNS response message. Note that it may or may
128  // not be the message that we are interested in, but needs to be
129  // parsed so as we can check its ID, Opcode etc.
130  isc::util::InputBuffer received_data_buffer(received_data, bytes_received);
131  message_.fromWire(received_data_buffer);
132 
133  // If tsig_context is not NULL, then we need to verify the message.
134  if (tsig_context) {
135  TSIGError error = tsig_context->verify(message_.getTSIGRecord(),
136  received_data, bytes_received);
137  if (error != TSIGError::NOERROR()) {
138  isc_throw(TSIGVerifyError, "TSIG verification failed: "
139  << error.toText());
140  }
141  }
142 
143  // This class exposes the getZone() function. This function will return
144  // pointer to the D2Zone object if non-empty Zone section exists in the
145  // received message. It will return NULL pointer if it doesn't exist.
146  // The pointer is held in the D2UpdateMessage class member. We need to
147  // update this pointer every time we parse the message.
149  // There is a Zone section in the received message. Replace
150  // Zone pointer with the new value.
151  QuestionPtr question = *message_.beginQuestion();
152  // If the Zone counter is greater than 0 (which we have checked)
153  // there must be a valid Question pointer stored in the message_
154  // object. If there isn't, it is a programming error.
155  assert(question);
156  zone_.reset(new D2Zone(question->getName(), question->getClass()));
157 
158  } else {
159  // Zone section doesn't hold any pointers, so set the pointer to NULL.
160  zone_.reset();
161 
162  }
163  // Check that the content of the received message is sane.
164  // One of the basic checks to do is to verify that we have
165  // received the DNS update message. If not, it can be dropped
166  // or an error message can be printed. Other than that, we
167  // will check that there is at most one Zone record and QR flag
168  // is set.
169  validateResponse();
170 }
171 
173 D2UpdateMessage::ddnsToDnsSection(const UpdateMsgSection section) {
177  switch(section) {
178  case SECTION_ZONE :
180 
183 
184  case SECTION_UPDATE:
186 
187  case SECTION_ADDITIONAL:
189 
190  default:
191  ;
192  }
194  "unknown message section " << section);
195 }
196 
197 void
198 D2UpdateMessage::validateResponse() const {
199  // Verify that we are dealing with the DNS Update message. According to
200  // RFC 2136, section 3.8 server will copy the Opcode from the query.
201  // If we are dealing with a different type of message, we may simply
202  // stop further processing, because it is likely that the message was
203  // directed to someone else.
204  if (message_.getOpcode() != Opcode::UPDATE()) {
205  isc_throw(NotUpdateMessage, "received message is not a DDNS update,"
206  << " received message code is "
207  << message_.getOpcode().getCode());
208  }
209  // Received message should have QR flag set, which indicates that it is
210  // a RESPONSE.
211  if (getQRFlag() == REQUEST) {
212  isc_throw(InvalidQRFlag, "received message should have QR flag set,"
213  " to indicate that it is a RESPONSE message; the QR"
214  << " flag in received message is unset");
215  }
216  // DNS server may copy a Zone record from the query message. Since query
217  // must comprise exactly one Zone record (RFC 2136, section 2.3), the
218  // response message may contain 1 record at most. It may also contain no
219  // records if a server chooses not to copy Zone section.
220  if (getRRCount(SECTION_ZONE) > 1) {
221  isc_throw(InvalidZoneSection, "received message contains "
222  << getRRCount(SECTION_ZONE) << " Zone records,"
223  << " it should contain at most 1 record");
224  }
225 }
226 
227 } // namespace d2
228 } // namespace isc
229 
isc::dns::QuestionPtr
boost::shared_ptr< Question > QuestionPtr
A pointer-like type pointing to an Question object.
Definition: question.h:28
isc::dns::Message::SECTION_AUTHORITY
@ SECTION_AUTHORITY
Authority section.
Definition: message.h:236
isc::d2::D2UpdateMessage::getRcode
const dns::Rcode & getRcode() const
Returns an object representing message RCode.
Definition: d2_update_message.cc:50
isc::dns::Question::getClass
const RRClass & getClass() const
Returns the RR Type of the Question.
Definition: question.h:159
isc::dns::RRsetPtr
boost::shared_ptr< AbstractRRset > RRsetPtr
A pointer-like type pointing to an RRset object.
Definition: rrset.h:47
isc::dns::Opcode
The Opcode class objects represent standard OPCODEs of the header section of DNS messages as defined ...
Definition: opcode.h:32
isc::d2::D2UpdateMessage::setRcode
void setRcode(const dns::Rcode &rcode)
Sets message RCode.
Definition: d2_update_message.cc:55
isc::d2::D2UpdateMessage::SECTION_ZONE
@ SECTION_ZONE
Definition: d2_update_message.h:118
opcode.h
isc::d2::D2UpdateMessage::REQUEST
@ REQUEST
Definition: d2_update_message.h:101
isc::d2::D2UpdateMessage::fromWire
void fromWire(const void *received_data, size_t bytes_received, dns::TSIGContext *const tsig_context=NULL)
Decode incoming message from the wire format.
Definition: d2_update_message.cc:124
isc::d2::D2UpdateMessage::setZone
void setZone(const dns::Name &zone, const dns::RRClass &rrclass)
Sets the Zone record.
Definition: d2_update_message.cc:75
name.h
isc::d2::D2UpdateMessage::getRRCount
unsigned int getRRCount(const UpdateMsgSection section) const
Returns number of RRsets in the specified message section.
Definition: d2_update_message.cc:60
isc::d2::D2UpdateMessage::endSection
const dns::RRsetIterator endSection(const UpdateMsgSection section) const
Return iterators pointing to the end of the list of RRsets, which belong to the specified section.
Definition: d2_update_message.cc:70
isc::dns::Message::HEADERFLAG_QR
@ HEADERFLAG_QR
Query (if cleared) or response (if set)
Definition: message.h:194
isc::dns::Message::getQid
qid_t getQid() const
Return the query ID given in the header section of the message.
Definition: dns/message.cc:419
isc::dns::Message::getRRCount
unsigned int getRRCount(const Section section) const
Returns the number of RRs contained in the given section.
Definition: dns/message.cc:491
isc::dns::Opcode::UPDATE_CODE
@ UPDATE_CODE
5: Dynamic update (RFC2136)
Definition: opcode.h:41
isc::dns::Message::SECTION_ADDITIONAL
@ SECTION_ADDITIONAL
Additional section.
Definition: message.h:237
isc::dns::Question::getName
const Name & getName() const
Returns the owner name of the Question.
Definition: question.h:143
isc::dns::Rcode::NOERROR
static const Rcode & NOERROR()
A constant object for the NOERROR Rcode (see Rcode::NOERROR_CODE).
Definition: rcode.h:220
isc::dns::Message::getHeaderFlag
bool getHeaderFlag(const HeaderFlag flag) const
Return whether the specified header flag bit is set in the header section.
Definition: dns/message.cc:391
d2_update_message.h
isc::dns::SectionIterator
SectionIterator is a templated class to provide standard-compatible iterators for Questions and RRset...
Definition: message.h:91
isc::d2::D2UpdateMessage::beginSection
const dns::RRsetIterator beginSection(const UpdateMsgSection section) const
Return iterators pointing to the beginning of the list of RRsets, which belong to the specified secti...
Definition: d2_update_message.cc:65
isc::dns::AbstractMessageRenderer
The AbstractMessageRenderer class is an abstract base class that provides common interfaces for rende...
Definition: messagerenderer.h:68
isc::dns::Message::setQid
void setQid(qid_t qid)
Set the query ID of the header section of the message.
Definition: dns/message.cc:424
isc::dns::TSIGError
TSIG errors.
Definition: tsigerror.h:22
isc::d2::D2UpdateMessage::getId
uint16_t getId() const
Returns message ID.
Definition: d2_update_message.cc:39
isc
Defines the logger used by the top-level component of kea-dhcp-ddns.
Definition: agent_parser.cc:144
isc::dns::Message::fromWire
void fromWire(isc::util::InputBuffer &buffer, ParseOptions options=PARSE_DEFAULT)
(Re)build a Message object from wire-format data.
Definition: dns/message.cc:635
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition: exceptions/exceptions.h:192
isc::dns::TSIGError::NOERROR
static const TSIGError & NOERROR()
A constant TSIG error object derived from Rcode::NOERROR()
Definition: tsigerror.h:219
question.h
isc::dns::Question
The Question class encapsulates the common search key of DNS lookup, consisting of owner name,...
Definition: question.h:95
isc::BadValue
A generic exception that is thrown if a parameter given to a method is considered invalid in that con...
Definition: exceptions/exceptions.h:132
isc::dns::Message::SECTION_QUESTION
@ SECTION_QUESTION
Question section
Definition: message.h:234
isc::dns::Name
The Name class encapsulates DNS names.
Definition: name.h:223
isc::dns::Message::setOpcode
void setOpcode(const Opcode &opcode)
Set the OPCODE of the header section of the message.
Definition: dns/message.cc:458
isc::d2::D2UpdateMessage::getQRFlag
QRFlag getQRFlag() const
Returns enum value indicating if the message is a REQUEST or RESPONSE.
Definition: d2_update_message.cc:33
isc::d2::D2UpdateMessage::SECTION_PREREQUISITE
@ SECTION_PREREQUISITE
Definition: d2_update_message.h:119
isc::dns::Message::beginSection
const RRsetIterator beginSection(const Section section) const
Return an iterator corresponding to the beginning of the given section (other than Question) of the m...
Definition: dns/message.cc:1133
isc::dns::InvalidMessageSection
A standard DNS module exception that is thrown if a section iterator is being constructed for an inco...
Definition: message.h:47
isc::d2::D2UpdateMessage::RESPONSE
@ RESPONSE
Definition: d2_update_message.h:102
isc::dns::Message::endSection
const RRsetIterator endSection(const Section section) const
Return an iterator corresponding to the end of the given section (other than Question) of the message...
Definition: dns/message.cc:1146
isc::dns::Message::beginQuestion
const QuestionIterator beginQuestion() const
Return an iterator corresponding to the beginning of the Question section of the message.
Definition: dns/message.cc:1120
isc::dns::Message::getRcode
const Rcode & getRcode() const
Return the Response Code of the message.
Definition: dns/message.cc:433
isc::d2::D2UpdateMessage::toWire
void toWire(dns::AbstractMessageRenderer &renderer, dns::TSIGContext *const tsig_ctx=NULL)
Encode outgoing message into wire format.
Definition: d2_update_message.cc:105
isc::d2::D2UpdateMessage::addRRset
void addRRset(const UpdateMsgSection section, const dns::RRsetPtr &rrset)
Adds an RRset to the specified section.
Definition: d2_update_message.cc:95
isc::d2::D2UpdateMessage::SECTION_UPDATE
@ SECTION_UPDATE
Definition: d2_update_message.h:120
isc::util::InputBuffer
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition: buffer.h:81
isc::d2::D2UpdateMessage::D2UpdateMessage
D2UpdateMessage(const Direction direction=OUTBOUND)
Constructor used to create an instance of the DNS Update Message (either outgoing or incoming).
Definition: d2_update_message.cc:20
isc::d2::D2UpdateMessage::setId
void setId(const uint16_t id)
Sets message ID.
Definition: d2_update_message.cc:44
isc::d2::D2UpdateMessage::Direction
Direction
Indicates if the D2UpdateMessage object encapsulates Inbound or Outbound message.
Definition: d2_update_message.h:94
isc::dns::Message::getTSIGRecord
const TSIGRecord * getTSIGRecord() const
Return, if any, the TSIG record contained in the received message.
Definition: dns/message.cc:481
isc::dns::Message::addRRset
void addRRset(const Section section, RRsetPtr rrset)
Add a (pointer like object of) RRset to the given section of the message.
Definition: dns/message.cc:499
isc::d2::InvalidQRFlag
Exception indicating that QR flag has invalid value.
Definition: d2_update_message.h:43
isc::d2::D2UpdateMessage::SECTION_ADDITIONAL
@ SECTION_ADDITIONAL
Definition: d2_update_message.h:121
isc::dns::Message::setRcode
void setRcode(const Rcode &rcode)
Set the Response Code of the message.
Definition: dns/message.cc:441
isc::d2::TSIGVerifyError
Exception indicating that a signed, inbound message failed to verify.
Definition: d2_update_message.h:63
isc::dns::TSIGError::toText
std::string toText() const
Convert the TSIGError to a string.
Definition: tsigerror.cc:40
isc::dns::Opcode::getCode
CodeValue getCode() const
Returns the Opcode code value.
Definition: opcode.h:78
isc::dns::Message
The Message class encapsulates a standard DNS message.
Definition: message.h:143
isc::dns::Message::clearSection
void clearSection(const Section section)
Remove all RRSets from the given Section.
Definition: dns/message.cc:568
isc::dns::TSIGContext::verify
TSIGError verify(const TSIGRecord *const record, const void *const data, const size_t data_len)
Verify a DNS message.
Definition: tsig.cc:428
isc::d2::D2Zone
The D2Zone encapsulates the Zone section in DNS Update message.
Definition: d2_zone.h:32
isc::dns::Message::toWire
void toWire(AbstractMessageRenderer &renderer, TSIGContext *tsig_ctx=NULL)
Render the message in wire formant into a message renderer object with (or without) TSIG.
Definition: dns/message.cc:601
isc::dns::Message::setHeaderFlag
void setHeaderFlag(const HeaderFlag flag, const bool on=true)
Set or clear the specified header flag bit in the header section.
Definition: dns/message.cc:401
isc::dns::Message::SECTION_ANSWER
@ SECTION_ANSWER
Answer section.
Definition: message.h:235
isc::d2::InvalidZoneSection
Exception indicating that Zone section contains invalid content.
Definition: d2_update_message.h:29
isc::dns::Opcode::UPDATE
static const Opcode & UPDATE()
A constant object for the UPDATE Opcode.
Definition: opcode.h:200
isc::d2::D2UpdateMessage::UpdateMsgSection
UpdateMsgSection
Identifies sections in the DNS Update Message.
Definition: d2_update_message.h:117
isc::dns::Message::getOpcode
const Opcode & getOpcode() const
Return the OPCODE given in the header section of the message.
Definition: dns/message.cc:450
isc::dns
Definition: dns_fwd.h:18
isc::d2::D2UpdateMessage::getZone
D2ZonePtr getZone() const
Returns a pointer to the object representing Zone record.
Definition: d2_update_message.cc:90
isc::dns::Message::Section
Section
Constants to specify sections of a DNS message.
Definition: message.h:233
isc::dns::RRClass
The RRClass class encapsulates DNS resource record classes.
Definition: rrclass.h:98
isc::d2::D2UpdateMessage::OUTBOUND
@ OUTBOUND
Definition: d2_update_message.h:96
isc::d2::D2ZonePtr
boost::shared_ptr< D2Zone > D2ZonePtr
Definition: d2_zone.h:93
isc::dns::TSIGContext
TSIG session context.
Definition: tsig.h:172
isc::dns::Rcode
DNS Response Codes (RCODEs) class.
Definition: rcode.h:40
messagerenderer.h
isc::dns::RRType::SOA
static const RRType & SOA()
Definition: rrtype.h:485
isc::dns::Message::addQuestion
void addQuestion(QuestionPtr question)
Add a (pointer like object of) Question to the message.
Definition: dns/message.cc:585
isc::d2::D2UpdateMessage::QRFlag
QRFlag
Indicates whether DNS Update message is a REQUEST or RESPONSE.
Definition: d2_update_message.h:100