// Copyright (C) 2010-2016 Internet Systems Consortium, Inc. ("ISC") // // This Source Code Form is subject to the terms of the Mozilla Public // License, v. 2.0. If a copy of the MPL was not distributed with this // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include #include #include #include #include #include #include #include using namespace std; using namespace isc::util; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE /// \brief Constructor. OPT::PseudoRR::PseudoRR(uint16_t code, boost::shared_ptr >& data) : code_(code), data_(data) { } uint16_t OPT::PseudoRR::getCode() const { return (code_); } const uint8_t* OPT::PseudoRR::getData() const { return (&(*data_)[0]); } uint16_t OPT::PseudoRR::getLength() const { return (data_->size()); } struct OPTImpl { OPTImpl() : rdlength_(0) {} uint16_t rdlength_; std::vector pseudo_rrs_; }; /// \brief Default constructor. OPT::OPT() : impl_(new OPTImpl) { } /// \brief Constructor from string. /// /// This constructor cannot be used, and always throws an exception. /// /// \throw InvalidRdataText OPT RR cannot be constructed from text. OPT::OPT(const std::string&) : impl_(NULL) { isc_throw(InvalidRdataText, "OPT RR cannot be constructed from text"); } /// \brief Constructor with a context of MasterLexer. /// /// This constructor cannot be used, and always throws an exception. /// /// \throw InvalidRdataText OPT RR cannot be constructed from text. OPT::OPT(MasterLexer&, const Name*, MasterLoader::Options, MasterLoaderCallbacks&) : impl_(NULL) { isc_throw(InvalidRdataText, "OPT RR cannot be constructed from text"); } OPT::OPT(InputBuffer& buffer, size_t rdata_len) : impl_(NULL) { std::unique_ptr impl_ptr(new OPTImpl); while (true) { if (rdata_len == 0) { break; } if (rdata_len < 4) { isc_throw(InvalidRdataLength, "Pseudo OPT RR record too short: " << rdata_len << " bytes"); } const uint16_t option_code = buffer.readUint16(); const uint16_t option_length = buffer.readUint16(); rdata_len -= 4; if (static_cast(impl_ptr->rdlength_ + option_length) < impl_ptr->rdlength_) { isc_throw(InvalidRdataText, "Option length " << option_length << " would overflow OPT RR RDLEN (currently " << impl_ptr->rdlength_ << ")."); } if (rdata_len < option_length) { isc_throw(InvalidRdataLength, "Corrupt pseudo OPT RR record"); } boost::shared_ptr > option_data(new std::vector(option_length)); buffer.readData(&(*option_data)[0], option_length); impl_ptr->pseudo_rrs_.push_back(PseudoRR(option_code, option_data)); impl_ptr->rdlength_ += option_length; rdata_len -= option_length; } impl_ = impl_ptr.release(); } OPT::OPT(const OPT& other) : Rdata(), impl_(new OPTImpl(*other.impl_)) { } OPT& OPT::operator=(const OPT& source) { if (this == &source) { return (*this); } OPTImpl* newimpl = new OPTImpl(*source.impl_); delete impl_; impl_ = newimpl; return (*this); } OPT::~OPT() { delete impl_; } std::string OPT::toText() const { isc_throw(isc::InvalidOperation, "OPT RRs do not have a presentation format"); } void OPT::toWire(OutputBuffer& buffer) const { BOOST_FOREACH(const PseudoRR& pseudo_rr, impl_->pseudo_rrs_) { buffer.writeUint16(pseudo_rr.getCode()); const uint16_t length = pseudo_rr.getLength(); buffer.writeUint16(length); if (length > 0) { buffer.writeData(pseudo_rr.getData(), length); } } } void OPT::toWire(AbstractMessageRenderer& renderer) const { BOOST_FOREACH(const PseudoRR& pseudo_rr, impl_->pseudo_rrs_) { renderer.writeUint16(pseudo_rr.getCode()); const uint16_t length = pseudo_rr.getLength(); renderer.writeUint16(length); if (length > 0) { renderer.writeData(pseudo_rr.getData(), length); } } } int OPT::compare(const Rdata&) const { isc_throw(isc::InvalidOperation, "It is meaningless to compare a set of OPT pseudo RRs; " "they have unspecified order"); return (0); } void OPT::appendPseudoRR(uint16_t code, const uint8_t* data, uint16_t length) { // See if it overflows 16-bit length field. We only worry about the // pseudo-RR length here, not the whole message length (which should // be checked and enforced elsewhere). if (static_cast(impl_->rdlength_ + length) < impl_->rdlength_) { isc_throw(isc::InvalidParameter, "Option length " << length << " would overflow OPT RR RDLEN (currently " << impl_->rdlength_ << ")."); } boost::shared_ptr > option_data(new std::vector(length)); if (length != 0) { std::memcpy(&(*option_data)[0], data, length); } impl_->pseudo_rrs_.push_back(PseudoRR(code, option_data)); impl_->rdlength_ += length; } const std::vector& OPT::getPseudoRRs() const { return (impl_->pseudo_rrs_); } // END_RDATA_NAMESPACE // END_ISC_NAMESPACE