Kea: d2_update_message.cc Source File

| Kea 3.2.0-git

d2_update_message.cc
Go to the documentation of this file.
1// Copyright (C) 2013-2021 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 <d2srv/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
15namespace isc {
16namespace d2 {
17
18using namespace isc::dns;
19
20D2UpdateMessage::D2UpdateMessage(const Direction direction)
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) {
26 message_.setOpcode(Opcode(Opcode::UPDATE_CODE));
27 message_.setHeaderFlag(dns::Message::HEADERFLAG_QR, false);
28 message_.setRcode(Rcode::NOERROR());
29 }
30}
31
32 D2UpdateMessage::QRFlag
33D2UpdateMessage::getQRFlag() const {
34 return (message_.getHeaderFlag(dns::Message::HEADERFLAG_QR) ?
35 RESPONSE : REQUEST);
36}
37
38uint16_t
39D2UpdateMessage::getId() const {
40 return (message_.getQid());
41}
42
43void
44D2UpdateMessage::setId(const uint16_t id) {
45 message_.setQid(id);
46}
47
48
49const dns::Rcode&
50D2UpdateMessage::getRcode() const {
51 return (message_.getRcode());
52}
53
54void
55D2UpdateMessage::setRcode(const dns::Rcode& rcode) {
56 message_.setRcode(rcode);
57}
58
59unsigned int
60D2UpdateMessage::getRRCount(const UpdateMsgSection section) const {
61 return (message_.getRRCount(ddnsToDnsSection(section)));
62}
63
64const dns::RRsetIterator
65D2UpdateMessage::beginSection(const UpdateMsgSection section) const {
66 return (message_.beginSection(ddnsToDnsSection(section)));
67}
68
69const dns::RRsetIterator
70D2UpdateMessage::endSection(const UpdateMsgSection section) const {
71 return (message_.endSection(ddnsToDnsSection(section)));
72}
73
74void
75D2UpdateMessage::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) {
80 message_.clearSection(dns::Message::SECTION_QUESTION);
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
89 D2ZonePtr
90D2UpdateMessage::getZone() const {
91 return (zone_);
92}
93
94void
95D2UpdateMessage::addRRset(const UpdateMsgSection section,
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
104void
105D2UpdateMessage::toWire(AbstractMessageRenderer& renderer,
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
123void
124D2UpdateMessage::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.
148 if (getRRCount(D2UpdateMessage::SECTION_ZONE) > 0) {
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 if (!question) {
156 isc_throw(isc::Unexpected, "question is null?!");
157 }
158 zone_.reset(new D2Zone(question->getName(), question->getClass()));
159
160 } else {
161 // Zone section doesn't hold any pointers, so set the pointer to NULL.
162 zone_.reset();
163
164 }
165 // Check that the content of the received message is sane.
166 // One of the basic checks to do is to verify that we have
167 // received the DNS update message. If not, it can be dropped
168 // or an error message can be printed. Other than that, we
169 // will check that there is at most one Zone record and QR flag
170 // is set.
171 validateResponse();
172}
173
174 dns::Message::Section
175D2UpdateMessage::ddnsToDnsSection(const UpdateMsgSection section) {
179 switch(section) {
180 case SECTION_ZONE :
181 return (dns::Message::SECTION_QUESTION);
182
183 case SECTION_PREREQUISITE:
184 return (dns::Message::SECTION_ANSWER);
185
186 case SECTION_UPDATE:
187 return (dns::Message::SECTION_AUTHORITY);
188
189 case SECTION_ADDITIONAL:
190 return (dns::Message::SECTION_ADDITIONAL);
191
192 default:
193 ;
194 }
195 isc_throw(dns::InvalidMessageSection,
196 "unknown message section " << section);
197}
198
199void
200D2UpdateMessage::validateResponse() const {
201 // Verify that we are dealing with the DNS Update message. According to
202 // RFC 2136, section 3.8 server will copy the Opcode from the query.
203 // If we are dealing with a different type of message, we may simply
204 // stop further processing, because it is likely that the message was
205 // directed to someone else.
206 if (message_.getOpcode() != Opcode::UPDATE()) {
207 isc_throw(NotUpdateMessage, "received message is not a DDNS update,"
208 << " received message code is "
209 << message_.getOpcode().getCode());
210 }
211 // Received message should have QR flag set, which indicates that it is
212 // a RESPONSE.
213 if (getQRFlag() == REQUEST) {
214 isc_throw(InvalidQRFlag, "received message should have QR flag set,"
215 " to indicate that it is a RESPONSE message; the QR"
216 << " flag in received message is unset");
217 }
218 // DNS server may copy a Zone record from the query message. Since query
219 // must comprise exactly one Zone record (RFC 2136, section 2.3), the
220 // response message may contain 1 record at most. It may also contain no
221 // records if a server chooses not to copy Zone section.
222 if (getRRCount(SECTION_ZONE) > 1) {
223 isc_throw(InvalidZoneSection, "received message contains "
224 << getRRCount(SECTION_ZONE) << " Zone records,"
225 << " it should contain at most 1 record");
226 }
227}
228
229} // namespace d2
230} // namespace isc
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::Unexpected
A generic exception that is thrown when an unexpected error condition occurs.
Definition exceptions/exceptions.h:153
isc::d2::D2UpdateMessage::getZone
D2ZonePtr getZone() const
Returns a pointer to the object representing Zone record.
Definition d2_update_message.cc:90
isc::d2::D2UpdateMessage::setId
void setId(const uint16_t id)
Sets message ID.
Definition d2_update_message.cc:44
isc::d2::D2UpdateMessage::UpdateMsgSection
UpdateMsgSection
Identifies sections in the DNS Update Message.
Definition d2_update_message.h:117
isc::d2::D2UpdateMessage::SECTION_UPDATE
@ SECTION_UPDATE
Definition d2_update_message.h:120
isc::d2::D2UpdateMessage::SECTION_PREREQUISITE
@ SECTION_PREREQUISITE
Definition d2_update_message.h:119
isc::d2::D2UpdateMessage::SECTION_ZONE
@ SECTION_ZONE
Definition d2_update_message.h:118
isc::d2::D2UpdateMessage::SECTION_ADDITIONAL
@ SECTION_ADDITIONAL
Definition d2_update_message.h:121
isc::d2::D2UpdateMessage::QRFlag
QRFlag
Indicates whether DNS Update message is a REQUEST or RESPONSE.
Definition d2_update_message.h:100
isc::d2::D2UpdateMessage::RESPONSE
@ RESPONSE
Definition d2_update_message.h:102
isc::d2::D2UpdateMessage::REQUEST
@ REQUEST
Definition d2_update_message.h:101
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::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::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::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::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::Direction
Direction
Indicates if the D2UpdateMessage object encapsulates Inbound or Outbound message.
Definition d2_update_message.h:94
isc::d2::D2UpdateMessage::INBOUND
@ INBOUND
Definition d2_update_message.h:95
isc::d2::D2UpdateMessage::OUTBOUND
@ OUTBOUND
Definition d2_update_message.h:96
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::setRcode
void setRcode(const dns::Rcode &rcode)
Sets message RCode.
Definition d2_update_message.cc:55
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::getId
uint16_t getId() const
Returns message ID.
Definition d2_update_message.cc:39
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::setZone
void setZone(const dns::Name &zone, const dns::RRClass &rrclass)
Sets the Zone record.
Definition d2_update_message.cc:75
isc::d2::D2UpdateMessage::getRcode
const dns::Rcode & getRcode() const
Returns an object representing message RCode.
Definition d2_update_message.cc:50
isc::d2::D2Zone
The D2Zone encapsulates the Zone section in DNS Update message.
Definition d2_zone.h:32
isc::d2::InvalidQRFlag
Exception indicating that QR flag has invalid value.
Definition d2_update_message.h:43
isc::d2::InvalidZoneSection
Exception indicating that Zone section contains invalid content.
Definition d2_update_message.h:29
isc::d2::TSIGVerifyError
Exception indicating that a signed, inbound message failed to verify.
Definition d2_update_message.h:63
isc::dns::AbstractMessageRenderer
The AbstractMessageRenderer class is an abstract base class that provides common interfaces for rende...
Definition messagerenderer.h:69
isc::dns::InvalidMessageSection
A standard DNS module exception that is thrown if a section iterator is being constructed for an inco...
Definition message.h:44
isc::dns::Message
The Message class encapsulates a standard DNS message.
Definition message.h:152
isc::dns::Message::HEADERFLAG_QR
@ HEADERFLAG_QR
Definition message.h:203
isc::dns::Message::Section
Section
Constants to specify sections of a DNS message.
Definition message.h:242
isc::dns::Message::SECTION_ADDITIONAL
@ SECTION_ADDITIONAL
Definition message.h:246
isc::dns::Message::SECTION_AUTHORITY
@ SECTION_AUTHORITY
Definition message.h:245
isc::dns::Message::SECTION_ANSWER
@ SECTION_ANSWER
Definition message.h:244
isc::dns::Message::SECTION_QUESTION
@ SECTION_QUESTION
Definition message.h:243
isc::dns::Message::getOpcode
const Opcode & getOpcode() const
Return the OPCODE given in the header section of the message.
Definition dns/message.cc:452
isc::dns::Name
The Name class encapsulates DNS names.
Definition name.h:219
isc::dns::Opcode
The Opcode class objects represent standard OPCODEs of the header section of DNS messages as defined ...
Definition opcode.h:32
isc::dns::Opcode::UPDATE
static const Opcode & UPDATE()
A constant object for the UPDATE Opcode.
Definition opcode.h:208
isc::dns::Opcode::getCode
CodeValue getCode() const
Returns the Opcode code value.
Definition opcode.h:78
isc::dns::Opcode::UPDATE_CODE
@ UPDATE_CODE
5: Dynamic update (RFC2136)
Definition opcode.h:41
isc::dns::Question
The Question class encapsulates the common search key of DNS lookup, consisting of owner name,...
Definition question.h:88
isc::dns::Question::getName
const Name & getName() const
Returns the owner name of the Question.
Definition question.h:136
isc::dns::Question::getClass
const RRClass & getClass() const
Returns the RR Type of the Question.
Definition question.h:156
isc::dns::RRClass
The RRClass class encapsulates DNS resource record classes.
Definition rrclass.h:89
isc::dns::RRType::SOA
static const RRType & SOA()
Definition rrtype.h:291
isc::dns::Rcode
DNS Response Codes (RCODEs) class.
Definition rcode.h:40
isc::dns::Rcode::NOERROR
static const Rcode & NOERROR()
A constant object for the NOERROR Rcode (see Rcode::NOERROR_CODE).
Definition rcode.h:228
isc::dns::TSIGContext
TSIG session context.
Definition tsig.h:171
isc::dns::TSIGContext::verify
virtual TSIGError verify(const TSIGRecord *const record, const void *const data, const size_t data_len)
Verify a DNS message.
Definition tsig.cc:419
isc::dns::TSIGError
TSIG errors.
Definition tsigerror.h:22
isc::dns::TSIGError::NOERROR
static const TSIGError & NOERROR()
A constant TSIG error object derived from Rcode::NOERROR().
Definition tsigerror.h:227
isc::util::InputBuffer
The InputBuffer class is a buffer abstraction for manipulating read-only data.
Definition buffer.h:81
d2_update_message.h
isc_throw
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
Definition exceptions/exceptions.h:210
messagerenderer.h
name.h
isc::d2
Definition check_exists_add.cc:19
isc::d2::D2ZonePtr
boost::shared_ptr< D2Zone > D2ZonePtr
Definition d2_zone.h:93
isc::dns
Definition char_string.cc:26
isc::dns::QuestionPtr
boost::shared_ptr< Question > QuestionPtr
A pointer-like type pointing to an Question object.
Definition question.h:24
isc::dns::RRsetPtr
boost::shared_ptr< AbstractRRset > RRsetPtr
A pointer-like type pointing to an RRset object.
Definition rrset.h:50
isc::dns::RRsetIterator
SectionIterator< RRsetPtr > RRsetIterator
Definition message.h:114
isc
Defines the logger used by the top-level component of kea-lfc.
Definition check_exists_add.cc:18
opcode.h
question.h