32#include <boost/lexical_cast.hpp>
33#include <boost/shared_ptr.hpp>
39using boost::lexical_cast;
46const size_t HEADERLEN = 12;
48const unsigned int OPCODE_MASK = 0x7800;
49const unsigned int OPCODE_SHIFT = 11;
50const unsigned int RCODE_MASK = 0x000f;
66const unsigned int HEADERFLAG_MASK = 0x87b0;
76const char*
const sectiontext[] = {
143 rcode_placeholder_(
Rcode(0)),
144 opcode_placeholder_(
Opcode(0)) {
198struct RenderSection {
204 void operator()(
const T& entry) {
209 const size_t pos0 =
renderer_.getLength();
210 counter_ += entry->toWire(renderer_);
220 unsigned int getTotalCount() {
238 "Message rendering attempted in non render mode");
242 "Message rendering attempted without Rcode set");
246 "Message rendering attempted without Opcode set");
253 const size_t tsig_len = (tsig_ctx ? tsig_ctx->getTSIGLength() : 0);
254 const size_t orig_msg_len_limit = renderer.getLengthLimit();
256 renderer.getCompressMode();
262 renderer.setCompressMode(orig_compress_mode);
265 if (tsig_len > orig_msg_len_limit) {
267 "too small limit for a TSIG (" <<
268 orig_msg_len_limit <<
")");
270 renderer.setLengthLimit(orig_msg_len_limit - tsig_len);
272 renderer.setLengthLimit(orig_msg_len_limit);
276 if (renderer.getLengthLimit() < HEADERLEN) {
278 "too small limit for a Header");
280 renderer.skip(HEADERLEN);
284 RenderSection<QuestionPtr>(renderer,
false)).getTotalCount();
287 uint16_t ancount = 0;
288 if (!renderer.isTruncated()) {
292 RenderSection<RRsetPtr>(renderer,
true)).getTotalCount();
294 uint16_t nscount = 0;
295 if (!renderer.isTruncated()) {
299 RenderSection<RRsetPtr>(renderer,
true)).getTotalCount();
301 uint16_t arcount = 0;
302 if (renderer.isTruncated()) {
308 RenderSection<RRsetPtr>(renderer,
false)).getTotalCount();
314 if (!renderer.isTruncated()) {
316 if (!local_edns &&
rcode_->getExtendedCode() != 0) {
320 arcount += local_edns->toWire(renderer,
rcode_->getExtendedCode());
327 if (tsig_ctx && renderer.isTruncated()) {
329 renderer.setLengthLimit(orig_msg_len_limit - tsig_len);
330 renderer.setCompressMode(orig_compress_mode);
331 renderer.skip(HEADERLEN);
333 RenderSection<QuestionPtr>(renderer,
334 false)).getTotalCount();
351 size_t header_pos = 0;
352 renderer.writeUint16At(
qid_, header_pos);
353 header_pos +=
sizeof(uint16_t);
355 uint16_t codes_and_flags =
356 (
opcode_->getCode() << OPCODE_SHIFT) & OPCODE_MASK;
357 codes_and_flags |= (
rcode_->getCode() & RCODE_MASK);
358 codes_and_flags |= (
flags_ & HEADERFLAG_MASK);
359 renderer.writeUint16At(codes_and_flags, header_pos);
360 header_pos +=
sizeof(uint16_t);
362 renderer.writeUint16At(qdcount, header_pos);
363 header_pos +=
sizeof(uint16_t);
364 renderer.writeUint16At(ancount, header_pos);
365 header_pos +=
sizeof(uint16_t);
366 renderer.writeUint16At(nscount, header_pos);
367 header_pos +=
sizeof(uint16_t);
368 renderer.writeUint16At(arcount, header_pos);
373 renderer.setLengthLimit(orig_msg_len_limit);
375 const int tsig_count =
376 tsig_ctx->sign(
qid_, renderer.getData(),
377 renderer.getLength())->
toWire(renderer);
378 if (tsig_count != 1) {
384 renderer.writeUint16At(++arcount, header_pos);
394 if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
396 "Message::getHeaderFlag:: Invalid flag is specified: " <<
397 "0x" << std::hex << flag);
399 return ((impl_->flags_ & flag) != 0);
406 "setHeaderFlag performed in non-render mode");
408 if (flag == 0 || (flag & ~HEADERFLAG_MASK) != 0) {
410 "Message::getHeaderFlag:: Invalid flag is specified: " <<
411 "0x" << std::hex <<
static_cast<int>(flag));
414 impl_->flags_ |= flag;
416 impl_->flags_ &= ~flag;
422 return (impl_->qid_);
429 "setQid performed in non-render mode");
436 if (!impl_->rcode_) {
439 return (*impl_->rcode_);
446 "setRcode performed in non-render mode");
448 impl_->setRcode(rcode);
453 if (!impl_->opcode_) {
456 return (*impl_->opcode_);
463 "setOpcode performed in non-render mode");
465 impl_->setOpcode(opcode);
470 return (impl_->edns_);
477 "setEDNS performed in non-render mode");
486 "getTSIGRecord performed in non-parse mode");
489 return (impl_->tsig_rr_.get());
497 return (impl_->counts_[section]);
504 "null RRset is given to Message::addRRset");
508 "addRRset performed in non-render mode");
514 impl_->rrsets_[section].push_back(rrset);
515 impl_->counts_[section] += rrset->getRdataCount();
516 impl_->counts_[section] += rrset->getRRsigDataCount();
526 for (
auto const& r : impl_->rrsets_[section]) {
527 if (r->getClass() == rrclass &&
528 r->getType() == rrtype &&
529 r->getName() == name) {
539 return (
hasRRset(section, rrset->getName(),
540 rrset->getClass(), rrset->getType()));
549 bool removed =
false;
550 for (
auto i = impl_->rrsets_[section].begin(); 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");
577 impl_->questions_.clear();
579 impl_->rrsets_[section].clear();
581 impl_->counts_[section] = 0;
588 "addQuestion performed in non-render mode");
591 impl_->questions_.push_back(question);
602 impl_->toWire(renderer, tsig_ctx);
609 "Message parse attempted in non parse mode");
612 if (impl_->header_parsed_) {
616 if ((buffer.getLength() - buffer.getPosition()) < HEADERLEN) {
618 << buffer.getLength() - buffer.getPosition());
621 impl_->qid_ = buffer.readUint16();
622 const uint16_t codes_and_flags = buffer.readUint16();
623 impl_->setOpcode(
Opcode((codes_and_flags & OPCODE_MASK) >> OPCODE_SHIFT));
624 impl_->setRcode(
Rcode(codes_and_flags & RCODE_MASK));
625 impl_->flags_ = (codes_and_flags & HEADERFLAG_MASK);
631 impl_->header_parsed_ =
true;
638 "Message parse attempted in non parse mode");
644 buffer.setPosition(0);
658 unsigned int added = 0;
660 for (
unsigned int count = 0;
663 const Name name(buffer);
665 if ((buffer.getLength() - buffer.getPosition()) <
666 2 *
sizeof(uint16_t)) {
668 (buffer.getLength() - buffer.getPosition()) <<
" bytes");
670 const RRType rrtype(buffer.readUint16());
671 const RRClass rrclass(buffer.readUint16());
690 bool operator()(
const RRsetPtr& rrset)
const {
691 return (rrset->getType() == rrtype_ &&
692 rrset->getClass() == rrclass_ &&
693 rrset->getName() == name_);
739 unsigned int added = 0;
741 for (
unsigned int count = 0; count <
counts_[section]; ++count) {
743 const size_t start_position = buffer.getPosition();
745 const Name name(buffer);
748 if ((buffer.getLength() - buffer.getPosition()) <
749 3 *
sizeof(uint16_t) +
sizeof(uint32_t)) {
751 " section too short: " <<
752 (buffer.getLength() - buffer.getPosition()) <<
" bytes");
755 const RRType rrtype(buffer.readUint16());
756 const RRClass rrclass(buffer.readUint16());
757 const RRTTL ttl(buffer.readUint32());
758 const size_t rdlen = buffer.readUint16();
766 addRR(section, name, rrclass, rrtype, ttl, options);
773 addEDNS(section, name, rrclass, rrtype, ttl, *rdata);
775 addTSIG(section, count, buffer, start_position, name, rrclass, ttl,
778 addRR(section, name, rrclass, rrtype, ttl, rdata, options);
792 vector<RRsetPtr>::iterator it =
794 MatchRR(name, rrtype, rrclass));
795 if (it !=
rrsets_[section].end()) {
796 (*it)->setTTL(min((*it)->getTTL(), ttl));
797 (*it)->addRdata(rdata);
802 rrset->addRdata(rdata);
803 rrsets_[section].push_back(rrset);
811 vector<RRsetPtr>::iterator it =
813 MatchRR(name, rrtype, rrclass));
814 if (it !=
rrsets_[section].end()) {
815 (*it)->setTTL(min((*it)->getTTL(), ttl));
820 rrsets_[section].push_back(rrset);
829 "EDNS OPT RR found in an invalid section");
835 uint8_t extended_rcode;
848 "TSIG RR found in an invalid section");
850 if (count !=
counts_[section] - 1) {
860 buffer.getPosition() -
866struct SectionFormatter {
871 void operator()(
const T& entry) {
889 if (!impl_->rcode_) {
891 "Message::toText() attempted without Rcode set");
893 if (!impl_->opcode_) {
895 "Message::toText() attempted without Opcode set");
900 s +=
";; ->>HEADER<<- opcode: " + impl_->opcode_->toText();
902 s +=
", status: " + impl_->rcode_->toText();
903 s +=
", id: " + boost::lexical_cast<string>(impl_->qid_);
932 s +=
", AUTHORITY: " +
939 if (impl_->tsig_rr_) {
942 s +=
", ADDITIONAL: " + lexical_cast<string>(arcount) +
"\n";
945 s +=
"\n;; OPT PSEUDOSECTION:\n";
946 s += impl_->edns_->toText();
949 if (!impl_->questions_.empty()) {
952 for_each(impl_->questions_.begin(), impl_->questions_.end(),
978 if (impl_->tsig_rr_) {
979 s +=
"\n;; TSIG PSEUDOSECTION:\n";
980 s += impl_->tsig_rr_->toText();
999 for (
auto qi = source.beginQuestion(); qi != source.endQuestion(); ++qi) {
1003 for (
auto rrsi = source.beginSection(section); rrsi != source.endSection(section); ++rrsi) {
1013 "makeResponse() is performed in non-parse mode");
1019 impl_->flags_ &= MESSAGE_REPLYPRESERVE;
1033template <
typename T>
1039 typename vector<T>::const_iterator
it_;
1042template <
typename T>
1044 impl_ =
new SectionIteratorImpl<T>(impl.it_);
1047template <
typename T>
1052template <
typename T>
1057template <
typename T>
1060 if (impl_ == source.impl_) {
1063 SectionIteratorImpl<T>* newimpl =
1064 new SectionIteratorImpl<T>(source.impl_->it_);
1069template <
typename T>
1076template <
typename T>
1079 SectionIterator<T> tmp(*
this);
1084template <
typename T>
1087 return (*(impl_->it_));
1090template <
typename T>
1093 return (&(
operator*()));
1096template <
typename T>
1099 return (impl_->it_ == other.impl_->it_);
1102template <
typename T>
1105 return (impl_->it_ != other.impl_->it_);
1112template class SectionIterator<QuestionPtr>;
1113template class SectionIterator<RRsetPtr>;
1116typedef SectionIteratorImpl<QuestionPtr> QuestionIteratorImpl;
1117typedef SectionIteratorImpl<RRsetPtr> RRsetIteratorImpl;
1125 return (
QuestionIterator(QuestionIteratorImpl(impl_->questions_.begin())));
1136const SectionIterator<RRsetPtr>
1143 "RRset iterator is requested for question");
1146 return (
RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].begin())));
1149const SectionIterator<RRsetPtr>
1156 "RRset iterator is requested for question");
1159 return (
RRsetIterator(RRsetIteratorImpl(impl_->rrsets_[section].end())));
1164 return (os << message.toText());
A generic exception that is thrown if a parameter given to a method or function is considered invalid...
A generic exception that is thrown if a parameter given to a method would refer to or modify out-of-r...
A generic exception that is thrown when an unexpected error condition occurs.
The AbstractMessageRenderer class is an abstract base class that provides common interfaces for rende...
CompressMode
Compression mode constants.
The EDNS class represents the EDNS OPT RR defined in RFC2671.
A standard DNS module exception that is thrown if a Message class method is called that is prohibited...
A standard DNS module exception that is thrown if a section iterator is being constructed for an inco...
void toWire(AbstractMessageRenderer &renderer, TSIGContext *tsig_ctx)
void addRR(Message::Section section, const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl, ConstRdataPtr rdata, Message::ParseOptions options)
static const unsigned int NUM_SECTIONS
vector< QuestionPtr > questions_
vector< RRsetPtr > rrsets_[NUM_SECTIONS]
int parseSection(const Message::Section section, InputBuffer &buffer, Message::ParseOptions options)
Opcode opcode_placeholder_
MessageImpl(Message::Mode mode)
void setOpcode(const Opcode &opcode)
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)
void addEDNS(Message::Section section, const Name &name, const RRClass &rrclass, const RRType &rrtype, const RRTTL &ttl, const Rdata &rdata)
ConstTSIGRecordPtr tsig_rr_
int parseQuestion(InputBuffer &buffer)
void setRcode(const Rcode &rcode)
int counts_[NUM_SECTIONS]
A standard DNS module exception that is thrown if a wire format message parser encounters a short len...
The Message class encapsulates a standard DNS message.
const QuestionIterator beginQuestion() const
Return an iterator corresponding to the beginning of the Question section of the message.
const QuestionIterator endQuestion() const
Return an iterator corresponding to the end of the Question section of the message.
void toWire(AbstractMessageRenderer &renderer, TSIGContext *tsig_ctx=0)
Render the message in wire formant into a message renderer object with (or without) TSIG.
const Rcode & getRcode() const
Return the Response Code of the message.
bool getHeaderFlag(const HeaderFlag flag) const
Return whether the specified header flag bit is set in the header section.
void clear(Mode mode)
Clear the message content (if any) and reinitialize it in the specified mode.
void clearSection(const Section section)
Remove all RRSets from the given Section.
Section
Constants to specify sections of a DNS message.
ParseOptions
Parse options.
Mode
Constants to specify the operation mode of the Message.
unsigned int getRRCount(const Section section) const
Returns the number of RRs contained in the given section.
void setOpcode(const Opcode &opcode)
Set the OPCODE of the header section of the message.
bool removeRRset(const Section section, RRsetIterator &iterator)
Remove RRSet from Message.
void addRRset(const Section section, RRsetPtr rrset)
Add a (pointer like object of) RRset to the given section of the message.
void fromWire(isc::util::InputBuffer &buffer, ParseOptions options=PARSE_DEFAULT)
(Re)build a Message object from wire-format data.
HeaderFlag
Constants for flag bit fields of a DNS message header.
const RRsetIterator endSection(const Section section) const
Return an iterator corresponding to the end of the given section (other than Question) of the message...
const TSIGRecord * getTSIGRecord() const
Return, if any, the TSIG record contained in the received message.
std::string toText() const
Convert the Message to a string.
void makeResponse()
Prepare for making a response from a request.
void setHeaderFlag(const HeaderFlag flag, const bool on=true)
Set or clear the specified header flag bit in the header section.
ConstEDNSPtr getEDNS() const
Return, if any, the EDNS associated with the message.
const Opcode & getOpcode() const
Return the OPCODE given in the header section of the message.
void parseHeader(isc::util::InputBuffer &buffer)
Parse the header section of the Message.
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...
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...
void addQuestion(QuestionPtr question)
Add a (pointer like object of) Question to the message.
void setQid(qid_t qid)
Set the query ID of the header section of the message.
qid_t getQid() const
Return the query ID given in the header section of the message.
const RRsetIterator beginSection(const Section section) const
Return an iterator corresponding to the beginning of the given section (other than Question) of the m...
void setRcode(const Rcode &rcode)
Set the Response Code of the message.
Message(Mode mode)
The constructor.
void setEDNS(ConstEDNSPtr edns)
Set EDNS for the message.
The Name class encapsulates DNS names.
The Opcode class objects represent standard OPCODEs of the header section of DNS messages as defined ...
The Question class encapsulates the common search key of DNS lookup, consisting of owner name,...
The RRClass class encapsulates DNS resource record classes.
static const RRClass & ANY()
static const RRClass & NONE()
The RRTTL class encapsulates TTLs used in DNS resource records.
The RRType class encapsulates DNS resource record types.
static const RRType & TSIG()
static const RRType & OPT()
The RRset class is a concrete derived class of BasicRRset which contains a pointer to an additional R...
DNS Response Codes (RCODEs) class.
SectionIterator is a templated class to provide standard-compatible iterators for Questions and RRset...
const T & operator*() const
const T * operator->() const
bool operator!=(const SectionIterator< T > &other) const
bool operator==(const SectionIterator< T > &other) const
SectionIterator< T > & operator++()
void operator=(const SectionIterator< T > &source)
The Rdata class is an abstract base class that provides a set of common interfaces to manipulate conc...
AbstractMessageRenderer & renderer_
const Message::Section section_
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
boost::shared_ptr< const Rdata > ConstRdataPtr
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.
boost::shared_ptr< MessageImpl > MessageImplPtr
Pointer to the MessageImpl object.
boost::shared_ptr< const TSIGRecord > ConstTSIGRecordPtr
A pointer-like type pointing to an immutable TSIGRecord object.
boost::shared_ptr< Question > QuestionPtr
A pointer-like type pointing to an Question object.
SectionIterator< QuestionPtr > QuestionIterator
boost::shared_ptr< AbstractRRset > RRsetPtr
A pointer-like type pointing to an RRset object.
ostream & operator<<(std::ostream &os, const EDNS &edns)
Insert the EDNS as a string into stream.
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.
boost::shared_ptr< const EDNS > ConstEDNSPtr
A pointer-like type pointing to an immutable EDNS object.
boost::shared_ptr< EDNS > EDNSPtr
A pointer-like type pointing to an EDNS object.
SectionIterator< RRsetPtr > RRsetIterator
Defines the logger used by the top-level component of kea-lfc.
Template version of Section Iterator.
vector< T >::const_iterator it_
SectionIteratorImpl(const typename vector< T >::const_iterator &it)