// Copyright (C) 2011-2015 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 #include using namespace std; using boost::lexical_cast; using namespace isc::util; using namespace isc::dns; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE class NAPTRImpl { public: NAPTRImpl() : order(0), preference(0), replacement(".") {} NAPTRImpl(InputBuffer& buffer, size_t rdata_len) : replacement(".") { if (rdata_len < 4 || buffer.getLength() - buffer.getPosition() < 4) { isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing " "NAPTR RDATA wire format: insufficient length "); } order = buffer.readUint16(); preference = buffer.readUint16(); rdata_len -= 4; rdata_len -= detail::bufferToCharString(buffer, rdata_len, flags); rdata_len -= detail::bufferToCharString(buffer, rdata_len, services); rdata_len -= detail::bufferToCharString(buffer, rdata_len, regexp); replacement = Name(buffer); if (rdata_len < 1) { isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing " "NAPTR RDATA wire format: missing replacement name"); } rdata_len -= replacement.getLength(); if (rdata_len != 0) { isc_throw(isc::dns::DNSMessageFORMERR, "Error in parsing " << "NAPTR RDATA: bytes left at end: " << static_cast(rdata_len)); } } NAPTRImpl(const std::string& naptr_str) : replacement(".") { std::istringstream ss(naptr_str); MasterLexer lexer; lexer.pushSource(ss); try { parseNAPTRData(lexer); // Should be at end of data now if (lexer.getNextToken(MasterToken::QSTRING, true).getType() != MasterToken::END_OF_FILE) { isc_throw(InvalidRdataText, "Invalid NAPTR text format: too many fields."); } } catch (const MasterLexer::LexerError& ex) { isc_throw(InvalidRdataText, "Failed to construct NAPTR RDATA from " << naptr_str << "': " << ex.what()); } } NAPTRImpl(MasterLexer& lexer) : replacement(".") { parseNAPTRData(lexer); } private: void parseNAPTRData(MasterLexer& lexer) { MasterToken token = lexer.getNextToken(MasterToken::NUMBER); if (token.getNumber() > 65535) { isc_throw(InvalidRdataText, "Invalid NAPTR text format: order out of range: " << token.getNumber()); } order = token.getNumber(); token = lexer.getNextToken(MasterToken::NUMBER); if (token.getNumber() > 65535) { isc_throw(InvalidRdataText, "Invalid NAPTR text format: preference out of range: " << token.getNumber()); } preference = token.getNumber(); token = lexer.getNextToken(MasterToken::QSTRING); stringToCharString(token.getStringRegion(), flags); token = lexer.getNextToken(MasterToken::QSTRING); stringToCharString(token.getStringRegion(), services); token = lexer.getNextToken(MasterToken::QSTRING); stringToCharString(token.getStringRegion(), regexp); token = lexer.getNextToken(MasterToken::STRING); replacement = Name(token.getString()); } public: uint16_t order; uint16_t preference; detail::CharString flags; detail::CharString services; detail::CharString regexp; Name replacement; }; NAPTR::NAPTR(InputBuffer& buffer, size_t rdata_len) : impl_(new NAPTRImpl(buffer, rdata_len)) {} NAPTR::NAPTR(const std::string& naptr_str) : impl_(new NAPTRImpl(naptr_str)) {} NAPTR::NAPTR(MasterLexer& lexer, const Name*, MasterLoader::Options, MasterLoaderCallbacks&) : impl_(new NAPTRImpl(lexer)) {} NAPTR::NAPTR(const NAPTR& naptr) : Rdata(), impl_(new NAPTRImpl(*naptr.impl_)) {} NAPTR& NAPTR::operator=(const NAPTR& source) { impl_.reset(new NAPTRImpl(*source.impl_)); return (*this); } NAPTR::~NAPTR() { } void NAPTR::toWire(OutputBuffer& buffer) const { toWireHelper(buffer); impl_->replacement.toWire(buffer); } void NAPTR::toWire(AbstractMessageRenderer& renderer) const { toWireHelper(renderer); // Type NAPTR is not "well-known", and name compression must be disabled // per RFC3597. renderer.writeName(impl_->replacement, false); } string NAPTR::toText() const { string result; result += lexical_cast(impl_->order); result += " "; result += lexical_cast(impl_->preference); result += " \""; result += detail::charStringToString(impl_->flags); result += "\" \""; result += detail::charStringToString(impl_->services); result += "\" \""; result += detail::charStringToString(impl_->regexp); result += "\" "; result += impl_->replacement.toText(); return (result); } int NAPTR::compare(const Rdata& other) const { const NAPTR other_naptr = dynamic_cast(other); if (impl_->order < other_naptr.impl_->order) { return (-1); } else if (impl_->order > other_naptr.impl_->order) { return (1); } if (impl_->preference < other_naptr.impl_->preference) { return (-1); } else if (impl_->preference > other_naptr.impl_->preference) { return (1); } const int fcmp = detail::compareCharStrings(impl_->flags, other_naptr.impl_->flags); if (fcmp != 0) { return (fcmp); } const int scmp = detail::compareCharStrings(impl_->services, other_naptr.impl_->services); if (scmp != 0) { return (scmp); } const int rcmp = detail::compareCharStrings(impl_->regexp, other_naptr.impl_->regexp); if (rcmp != 0) { return (rcmp); } return (compareNames(impl_->replacement, other_naptr.impl_->replacement)); } uint16_t NAPTR::getOrder() const { return (impl_->order); } uint16_t NAPTR::getPreference() const { return (impl_->preference); } const std::string NAPTR::getFlags() const { return (detail::charStringToString(impl_->flags)); } const std::string NAPTR::getServices() const { return (detail::charStringToString(impl_->services)); } const std::string NAPTR::getRegexp() const { return (detail::charStringToString(impl_->regexp)); } const Name& NAPTR::getReplacement() const { return (impl_->replacement); } template void NAPTR::toWireHelper(T& outputer) const { outputer.writeUint16(impl_->order); outputer.writeUint16(impl_->preference); outputer.writeData(&impl_->flags[0], impl_->flags.size()); outputer.writeData(&impl_->services[0], impl_->services.size()); outputer.writeData(&impl_->regexp[0], impl_->regexp.size()); } // END_RDATA_NAMESPACE // END_ISC_NAMESPACE