17 #include <boost/foreach.hpp> 18 #include <boost/lexical_cast.hpp> 19 #include <boost/shared_ptr.hpp> 41 using boost::lexical_cast;
50 const size_t HEADERLEN = 12;
52 const unsigned int OPCODE_MASK = 0x7800;
53 const unsigned int OPCODE_SHIFT = 11;
54 const unsigned int RCODE_MASK = 0x000f;
70 const unsigned int HEADERFLAG_MASK = 0x87b0;
77 const uint16_t MESSAGE_REPLYPRESERVE = (Message::HEADERFLAG_RD |
78 Message::HEADERFLAG_CD);
80 const char*
const sectiontext[] = {
108 static const unsigned int NUM_SECTIONS = 4;
109 int counts_[NUM_SECTIONS];
111 vector<RRsetPtr> rrsets_[NUM_SECTIONS];
118 void setOpcode(
const Opcode& opcode);
119 void setRcode(
const Rcode& rcode);
144 rcode_placeholder_(
Rcode(0)),
145 opcode_placeholder_(
Opcode(0))
199 template <
typename T>
200 struct RenderSection {
205 void operator()(
const T& entry) {
210 const size_t pos0 =
renderer_.getLength();
220 unsigned int getTotalCount() {
return (
counter_); }
232 "Message rendering attempted in non render mode");
236 "Message rendering attempted without Rcode set");
240 "Message rendering attempted without Opcode set");
247 const size_t tsig_len = (tsig_ctx != NULL) ? tsig_ctx->
getTSIGLength() : 0;
259 if (tsig_len > orig_msg_len_limit) {
261 "too small limit for a TSIG (" <<
262 orig_msg_len_limit <<
")");
272 "too small limit for a Header");
274 renderer.
skip(HEADERLEN);
278 RenderSection<QuestionPtr>(renderer,
false)).getTotalCount();
281 uint16_t ancount = 0;
282 if (!renderer.isTruncated()) {
286 RenderSection<RRsetPtr>(renderer,
true)).getTotalCount();
288 uint16_t nscount = 0;
289 if (!renderer.isTruncated()) {
293 RenderSection<RRsetPtr>(renderer,
true)).getTotalCount();
295 uint16_t arcount = 0;
296 if (renderer.isTruncated()) {
302 RenderSection<RRsetPtr>(renderer,
false)).getTotalCount();
308 if (!renderer.isTruncated()) {
321 if (tsig_ctx != NULL && renderer.isTruncated()) {
323 renderer.setLengthLimit(orig_msg_len_limit - tsig_len);
324 renderer.setCompressMode(orig_compress_mode);
325 renderer.skip(HEADERLEN);
327 RenderSection<QuestionPtr>(renderer,
328 false)).getTotalCount();
345 size_t header_pos = 0;
346 renderer.writeUint16At(
qid_, header_pos);
347 header_pos +=
sizeof(uint16_t);
349 uint16_t codes_and_flags =
352 codes_and_flags |= (
flags_ & HEADERFLAG_MASK);
353 renderer.writeUint16At(codes_and_flags, header_pos);
354 header_pos +=
sizeof(uint16_t);
356 renderer.writeUint16At(qdcount, header_pos);
357 header_pos +=
sizeof(uint16_t);
358 renderer.writeUint16At(ancount, header_pos);
359 header_pos +=
sizeof(uint16_t);
360 renderer.writeUint16At(nscount, header_pos);
361 header_pos +=
sizeof(uint16_t);
362 renderer.writeUint16At(arcount, header_pos);
365 if (tsig_ctx != NULL) {
367 renderer.setLengthLimit(orig_msg_len_limit);
369 const int tsig_count =
370 tsig_ctx->
sign(
qid_, renderer.getData(),
371 renderer.getLength())->
toWire(renderer);
372 if (tsig_count != 1) {
378 renderer.writeUint16At(++arcount, header_pos);
392 if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
394 "Message::getHeaderFlag:: Invalid flag is specified: " <<
395 "0x" << std::hex << flag);
397 return ((impl_->
flags_ & flag) != 0);
404 "setHeaderFlag performed in non-render mode");
406 if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
408 "Message::getHeaderFlag:: Invalid flag is specified: " <<
409 "0x" << std::hex << flag);
420 return (impl_->
qid_);
427 "setQid performed in non-render mode");
434 if (impl_->
rcode_ == NULL) {
444 "setRcode performed in non-render mode");
461 "setOpcode performed in non-render mode");
468 return (impl_->
edns_);
475 "setEDNS performed in non-render mode");
484 "getTSIGRecord performed in non-parse mode");
495 return (impl_->
counts_[section]);
502 "NULL RRset is given to Message::addRRset");
506 "addRRset performed in non-render mode");
512 impl_->
rrsets_[section].push_back(rrset);
513 impl_->
counts_[section] += rrset->getRdataCount();
514 impl_->
counts_[section] += rrset->getRRsigDataCount();
526 if (r->getClass() == rrclass &&
527 r->getType() == rrtype &&
528 r->getName() == name) {
538 return (
hasRRset(section, rrset->getName(),
539 rrset->getClass(), rrset->getType()));
548 bool removed =
false;
549 for (vector<RRsetPtr>::iterator i = impl_->
rrsets_[section].begin();
550 i != impl_->
rrsets_[section].end(); ++i) {
551 if (((*i)->getName() == (*iterator)->getName()) &&
552 ((*i)->getClass() == (*iterator)->getClass()) &&
553 ((*i)->getType() == (*iterator)->getType())) {
556 impl_->
counts_[section] -= (*iterator)->getRdataCount();
557 impl_->
counts_[section] -= (*iterator)->getRRsigDataCount();
558 impl_->
rrsets_[section].erase(i);
571 "clearSection performed in non-render mode");
579 impl_->
rrsets_[section].clear();
588 "addQuestion performed in non-render mode");
602 impl_->
toWire(renderer, tsig_ctx);
609 "Message parse attempted in non parse mode");
622 const uint16_t codes_and_flags = buffer.
readUint16();
623 impl_->
setOpcode(
Opcode((codes_and_flags & OPCODE_MASK) >> OPCODE_SHIFT));
625 impl_->
flags_ = (codes_and_flags & HEADERFLAG_MASK);
638 "Message parse attempted in non parse mode");
658 unsigned int added = 0;
660 for (
unsigned int count = 0;
663 const Name name(buffer);
666 2 *
sizeof(uint16_t)) {
688 bool operator()(
const RRsetPtr& rrset)
const {
689 return (rrset->getType() ==
rrtype_ &&
691 rrset->getName() ==
name_);
733 unsigned int added = 0;
735 for (
unsigned int count = 0; count < counts_[section]; ++count) {
737 const size_t start_position = buffer.
getPosition();
739 const Name name(buffer);
743 3 *
sizeof(uint16_t) +
sizeof(uint32_t)) {
745 " section too short: " <<
760 addRR(section, name, rrclass, rrtype, ttl, options);
767 addEDNS(section, name, rrclass, rrtype, ttl, *rdata);
769 addTSIG(section, count, buffer, start_position, name, rrclass, ttl,
772 addRR(section, name, rrclass, rrtype, ttl, rdata, options);
787 vector<RRsetPtr>::iterator it =
788 find_if(rrsets_[section].begin(), rrsets_[section].end(),
789 MatchRR(name, rrtype, rrclass));
790 if (it != rrsets_[section].end()) {
791 (*it)->setTTL(min((*it)->getTTL(), ttl));
792 (*it)->addRdata(rdata);
797 rrset->addRdata(rdata);
798 rrsets_[section].push_back(rrset);
807 vector<RRsetPtr>::iterator it =
808 find_if(rrsets_[section].begin(), rrsets_[section].end(),
809 MatchRR(name, rrtype, rrclass));
810 if (it != rrsets_[section].end()) {
811 (*it)->setTTL(min((*it)->getTTL(), ttl));
816 rrsets_[section].push_back(rrset);
826 "EDNS OPT RR found in an invalid section");
832 uint8_t extended_rcode;
846 "TSIG RR found in an invalid section");
848 if (count != counts_[section] - 1) {
863 template <
typename T>
864 struct SectionFormatter {
867 void operator()(
const T& entry) {
883 if (impl_->rcode_ == NULL) {
885 "Message::toText() attempted without Rcode set");
887 if (impl_->opcode_ == NULL) {
889 "Message::toText() attempted without Opcode set");
894 s +=
";; ->>HEADER<<- opcode: " + impl_->opcode_->toText();
896 s +=
", status: " + impl_->rcode_->toText();
897 s +=
", id: " + boost::lexical_cast<
string>(impl_->qid_);
926 s +=
", AUTHORITY: " +
930 if (impl_->edns_ != NULL) {
933 if (impl_->tsig_rr_ != NULL) {
936 s +=
", ADDITIONAL: " + lexical_cast<
string>(arcount) +
"\n";
938 if (impl_->edns_ != NULL) {
939 s +=
"\n;; OPT PSEUDOSECTION:\n";
940 s += impl_->edns_->toText();
943 if (!impl_->questions_.empty()) {
946 for_each(impl_->questions_.begin(), impl_->questions_.end(),
952 for_each(impl_->rrsets_[SECTION_ANSWER].begin(),
959 for_each(impl_->rrsets_[SECTION_AUTHORITY].begin(),
967 for_each(impl_->rrsets_[SECTION_ADDITIONAL].begin(),
972 if (impl_->tsig_rr_ != NULL) {
973 s +=
"\n;; TSIG PSEUDOSECTION:\n";
974 s += impl_->tsig_rr_->toText();
1011 "makeResponse() is performed in non-parse mode");
1017 impl_->flags_ &= MESSAGE_REPLYPRESERVE;
1031 template <
typename T>
1035 typename vector<T>::const_iterator
it_;
1038 template <
typename T>
1043 template <
typename T>
1048 template <
typename T>
1053 template <
typename T>
1056 if (impl_ == source.impl_) {
1065 template <
typename T>
1072 template <
typename T>
1080 template <
typename T>
1083 return (*(impl_->it_));
1086 template <
typename T>
1089 return (&(
operator*()));
1092 template <
typename T>
1095 return (impl_->it_ == other.impl_->it_);
1098 template <
typename T>
1101 return (impl_->it_ != other.impl_->it_);
1121 return (
QuestionIterator(QuestionIteratorImpl(impl_->questions_.begin())));
1137 if (section == SECTION_QUESTION) {
1139 "RRset iterator is requested for question");
1142 return (
RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].begin())));
1150 if (section == SECTION_QUESTION) {
1152 "RRset iterator is requested for question");
1155 return (
RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].end())));
1160 return (os << message.
toText());
The Name class encapsulates DNS names.
bool hasRRset(const Section section, const Name &name, const RRClass &rrclass, const RRType &rrtype) const
Determine whether the given section already has an RRset matching the given name, RR class and RR typ...
unsigned int getRRCount(const Section section) const
Returns the number of RRs contained in the given section.
void toWire(AbstractMessageRenderer &renderer, TSIGContext *tsig_ctx=NULL)
Render the message in wire formant into a message renderer object with (or without) TSIG...
Render mode (building an outgoing message)
void clear(Mode mode)
Clear the message content (if any) and reinitialize it in the specified mode.
void setEDNS(ConstEDNSPtr edns)
Set EDNS for the message.
qid_t getQid() const
Return the query ID given in the header section of the message.
Mode
Constants to specify the operation mode of the Message.
ostream & operator<<(std::ostream &os, const EDNS &edns)
Insert the EDNS as a string into stream.
A standard DNS module exception that is thrown if a Message class method is called that is prohibited...
const Opcode & getOpcode() const
Return the OPCODE given in the header section of the message.
static const RRType & TSIG()
ParseOptions
Parse options.
The Question class encapsulates the common search key of DNS lookup, consisting of owner name...
ConstTSIGRecordPtr tsig_rr_
AbstractMessageRenderer & renderer_
int parseQuestion(InputBuffer &buffer)
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
void skip(size_t len)
Insert a specified length of gap at the end of the buffer.
const TSIGRecord * getTSIGRecord() const
Return, if any, the TSIG record contained in the received message.
boost::shared_ptr< const EDNS > ConstEDNSPtr
A pointer-like type pointing to an immutable EDNS object.
virtual ConstTSIGRecordPtr sign(const uint16_t qid, const void *const data, const size_t data_len)
Sign a DNS message.
~Message()
The destructor.
boost::shared_ptr< const Rdata > ConstRdataPtr
const QuestionIterator beginQuestion() const
Return an iterator corresponding to the beginning of the Question section of the message.
The Rdata class is an abstract base class that provides a set of common interfaces to manipulate conc...
vector< RRsetPtr > rrsets_[NUM_SECTIONS]
void clearSection(const Section section)
Remove all RRSets from the given Section.
RdataPtr createRdata(const RRType &rrtype, const RRClass &rrclass, const std::string &rdata_string)
Create RDATA of a given pair of RR type and class from a string.
void setRcode(const Rcode &rcode)
Set the Response Code of the message.
DNS Response Codes (RCODEs) class.
void setHeaderFlag(const HeaderFlag flag, const bool on=true)
Set or clear the specified header flag bit in the header section.
SectionIterator< T > & operator++()
static const RRType & OPT()
The Message class encapsulates a standard DNS message.
SectionIterator< QuestionPtr > QuestionIterator
The RRClass class encapsulates DNS resource record classes.
Template version of Section Iterator.
virtual void clear()
Clear the internal buffer and other internal resources.
void operator=(const SectionIterator< T > &source)
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
A standard DNS module exception that is thrown if a section iterator is being constructed for an inco...
boost::shared_ptr< EDNS > EDNSPtr
A pointer-like type pointing to an EDNS object.
void fromWire(isc::util::InputBuffer &buffer, ParseOptions options=PARSE_DEFAULT)
(Re)build a Message object from wire-format data.
const T & operator*() const
The AbstractMessageRenderer class is an abstract base class that provides common interfaces for rende...
SectionIteratorImpl(const typename vector< T >::const_iterator &it)
void addQuestion(QuestionPtr question)
Add a (pointer like object of) Question to the message.
Opcode opcode_placeholder_
CompressMode
Compression mode constants.
bool operator==(const SectionIterator< T > &other) const
A generic exception that is thrown when an unexpected error condition occurs.
uint8_t getExtendedCode() const
Returns the upper 8-bit of the Rcode code value.
bool getHeaderFlag(const HeaderFlag flag) const
Return whether the specified header flag bit is set in the header section.
Parse mode (handling an incoming message)
virtual void setCompressMode(CompressMode mode)=0
Set the compression mode of the renderer class object.
The RRTTL class encapsulates TTLs used in DNS resource records.
const RRsetIterator endSection(const Section section) const
Return an iterator corresponding to the end of the given section (other than Question) of the message...
The EDNS class represents the EDNS OPT RR defined in RFC2671.
Query (if cleared) or response (if set)
DNSSEC checking disabled (RFC4035)
EDNS * createEDNSFromRR(const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl, const Rdata &rdata, uint8_t &extended_rcode)
Create a new EDNS object from a set of RR parameters, also providing the extended RCODE value...
vector< T >::const_iterator it_
A standard DNS module exception that is thrown if a wire format message parser encounters a short len...
vector< QuestionPtr > questions_
const Rcode & getRcode() const
Return the Response Code of the message.
const Message::Section section_
static const RRClass & ANY()
void setOpcode(const Opcode &opcode)
boost::shared_ptr< const TSIGRecord > ConstTSIGRecordPtr
A pointer-like type pointing to an immutable TSIGRecord object.
Defines the logger used by the top-level component of kea-lfc.
ConstEDNSPtr getEDNS() const
Return, if any, the EDNS associated with the message.
void toWire(AbstractMessageRenderer &renderer, TSIGContext *tsig_ctx)
std::string toText() const
Convert the Message to a string.
SectionIterator is a templated class to provide standard-compatible iterators for Questions and RRset...
void setRcode(const Rcode &rcode)
SectionIterator< RRsetPtr > RRsetIterator
void setOpcode(const Opcode &opcode)
Set the OPCODE of the header section of the message.
Section
Constants to specify sections of a DNS message.
void addTSIG(Message::Section section, unsigned int count, const InputBuffer &buffer, size_t start_position, const Name &name, const RRClass &rrclass, const RRTTL &ttl, const Rdata &rdata)
The RRset class is a concrete derived class of BasicRRset which contains a pointer to an additional R...
bool removeRRset(const Section section, RRsetIterator &iterator)
Remove RRSet from Message.
int counts_[NUM_SECTIONS]
const QuestionIterator endQuestion() const
Return an iterator corresponding to the end of the Question section of the message.
virtual size_t getTSIGLength() const
Return the expected length of TSIG RR after sign()
void appendSection(const Section section, const Message &source)
Adds all rrsets from the source the given section in the source message to the same section of this m...
The RRType class encapsulates DNS resource record types.
virtual void setLengthLimit(size_t len)=0
Set the maximum length of rendered data that can fit in the corresponding DNS message without truncat...
const T * operator->() const
void parseHeader(isc::util::InputBuffer &buffer)
Parse the header section of the Message.
static const RRClass & NONE()
void setQid(qid_t qid)
Set the query ID of the header section of the message.
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
void addRR(Message::Section section, const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl, ConstRdataPtr rdata, Message::ParseOptions options)
CodeValue getCode() const
Returns the Opcode code value.
boost::shared_ptr< const AbstractRRset > ConstRRsetPtr
A pointer-like type pointing to an (immutable) RRset object.
boost::shared_ptr< AbstractRRset > RRsetPtr
A pointer-like type pointing to an RRset object.
static const unsigned int NUM_SECTIONS
HeaderFlag
Constants for flag bit fields of a DNS message header.
void makeResponse()
Prepare for making a response from a request.
void addEDNS(Message::Section section, const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl, const Rdata &rdata)
The Opcode class objects represent standard OPCODEs of the header section of DNS messages as defined ...
virtual size_t getLengthLimit() const =0
Return the maximum length of rendered data that can fit in the corresponding DNS message without trun...
const RRsetIterator beginSection(const Section section) const
Return an iterator corresponding to the beginning of the given section (other than Question) of the m...
boost::shared_ptr< Question > QuestionPtr
A pointer-like type pointing to an Question object.
void addRRset(const Section section, RRsetPtr rrset)
Add a (pointer like object of) RRset to the given section of the message.
int parseSection(const Message::Section section, InputBuffer &buffer, Message::ParseOptions options)
uint16_t getCode() const
Returns the Rcode code value.
Preserve RR order and don't combine them.
virtual CompressMode getCompressMode() const =0
Return the compression mode of the renderer class object.
bool operator!=(const SectionIterator< T > &other) const
Message(Mode mode)
The constructor.