From: Paul Selkirk Date: Tue, 7 May 2013 19:59:29 +0000 (-0400) Subject: [2522] add MasterLexer constructor for TSIG X-Git-Tag: bind10-1.2.0beta1-release~430^2~18^2~9 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fc2a9e9876510fd425d693aaa5b93230606d26ec;p=thirdparty%2Fkea.git [2522] add MasterLexer constructor for TSIG --- diff --git a/src/lib/dns/gen-rdatacode.py.in b/src/lib/dns/gen-rdatacode.py.in index e265d56603..a7c0cbc11d 100755 --- a/src/lib/dns/gen-rdatacode.py.in +++ b/src/lib/dns/gen-rdatacode.py.in @@ -40,16 +40,19 @@ new_rdata_factory_users = [('a', 'in'), ('aaaa', 'in'), ('dnskey', 'generic'), ('ds', 'generic'), ('hinfo', 'generic'), - ('naptr', 'generic'), + ('minfo', 'generic'), ('mx', 'generic'), + ('naptr', 'generic'), ('ns', 'generic'), ('nsec', 'generic'), ('nsec3', 'generic'), ('nsec3param', 'generic'), ('ptr', 'generic'), + ('rp', 'generic'), ('soa', 'generic'), ('spf', 'generic'), ('srv', 'in'), + ('tsig', 'any'), ('txt', 'generic') ] diff --git a/src/lib/dns/rdata/any_255/tsig_250.cc b/src/lib/dns/rdata/any_255/tsig_250.cc index ff848fa4e1..82538070b3 100644 --- a/src/lib/dns/rdata/any_255/tsig_250.cc +++ b/src/lib/dns/rdata/any_255/tsig_250.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2010-2013 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -26,19 +26,23 @@ #include #include #include +#include #include +#include using namespace std; using boost::lexical_cast; using namespace isc::util; using namespace isc::util::encode; using namespace isc::util::str; +using namespace isc::dns; +using isc::dns::rdata::generic::detail::createNameFromLexer; // BEGIN_ISC_NAMESPACE // BEGIN_RDATA_NAMESPACE -/// This is a straightforward representation of TSIG RDATA fields. -struct TSIG::TSIGImpl { +// straightforward representation of TSIG RDATA fields +struct TSIGImpl { TSIGImpl(const Name& algorithm, uint64_t time_signed, uint16_t fudge, vector& mac, uint16_t original_id, uint16_t error, vector& other_data) : @@ -68,6 +72,86 @@ struct TSIG::TSIGImpl { const vector other_data_; }; +// helper function for string and lexer constructors +TSIGImpl* +TSIG::constructFromLexer(MasterLexer& lexer) { + // RFC2845 defines Algorithm Name to be "in domain name syntax", + // but it's not actually a domain name, so we allow it to be not + // fully qualified. + const Name root("."); + const Name algorithm = createNameFromLexer(lexer, &root); + + const string time_str = lexer.getNextToken(MasterToken::STRING).getString(); + uint64_t time_signed; + try { + time_signed = boost::lexical_cast(time_str); + } catch (const boost::bad_lexical_cast&) { + isc_throw(InvalidRdataText, "Invalid TSIG Time"); + } + if (time_signed > 0xffffffffffff) { + isc_throw(InvalidRdataText, "TSIG Time out of range"); + } + + const int32_t fudge = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (fudge > 0xffff) { + isc_throw(InvalidRdataText, "TSIG Fudge out of range"); + } + const int32_t macsize = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (macsize > 0xffff) { + isc_throw(InvalidRdataText, "TSIG MAC Size out of range"); + } + + const string mac_txt = (macsize > 0) ? + lexer.getNextToken(MasterToken::STRING).getString() : ""; + vector mac; + decodeBase64(mac_txt, mac); + if (mac.size() != macsize) { + isc_throw(InvalidRdataText, "TSIG MAC Size and data are inconsistent"); + } + + const int32_t orig_id = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (orig_id > 0xffff) { + isc_throw(InvalidRdataText, "TSIG Original ID out of range"); + } + + const string error_txt = lexer.getNextToken(MasterToken::STRING).getString(); + uint16_t error = 0; + // XXX: In the initial implementation we hardcode the mnemonics. + // We'll soon generalize this. + if (error_txt == "NOERROR") { + error = Rcode::NOERROR_CODE; + } else if (error_txt == "BADSIG") { + error = TSIGError::BAD_SIG_CODE; + } else if (error_txt == "BADKEY") { + error = TSIGError::BAD_KEY_CODE; + } else if (error_txt == "BADTIME") { + error = TSIGError::BAD_TIME_CODE; + } else { + try { + error = boost::lexical_cast(error_txt); + } catch (const boost::bad_lexical_cast&) { + isc_throw(InvalidRdataText, "Invalid TSIG Error"); + } + } + + const int32_t otherlen = lexer.getNextToken(MasterToken::NUMBER).getNumber(); + if (otherlen > 0xffff) { + isc_throw(InvalidRdataText, "TSIG Other Len out of range"); + } + const string otherdata_txt = (otherlen > 0) ? + lexer.getNextToken(MasterToken::STRING).getString() : ""; + vector other_data; + decodeBase64(otherdata_txt, other_data); + if (other_data.size() != otherlen) { + isc_throw(InvalidRdataText, + "TSIG Other Data length does not match Other Len"); + } + // also verify Error == BADTIME? + + return new TSIGImpl(algorithm, time_signed, fudge, mac, orig_id, + error, other_data); +} + /// \brief Constructor from string. /// /// \c tsig_str must be formatted as follows: @@ -113,54 +197,51 @@ struct TSIG::TSIGImpl { /// This constructor internally involves resource allocation, and if it fails /// a corresponding standard exception will be thrown. TSIG::TSIG(const std::string& tsig_str) : impl_(NULL) { - istringstream iss(tsig_str); + // We use auto_ptr here because if there is an exception in this + // constructor, the destructor is not called and there could be a + // leak of the DNSKEYImpl that constructFromLexer() returns. + std::auto_ptr impl_ptr(NULL); try { - const Name algorithm(getToken(iss)); - const int64_t time_signed = tokenToNum(getToken(iss)); - const int32_t fudge = tokenToNum(getToken(iss)); - const int32_t macsize = tokenToNum(getToken(iss)); - - const string mac_txt = (macsize > 0) ? getToken(iss) : ""; - vector mac; - decodeBase64(mac_txt, mac); - if (mac.size() != macsize) { - isc_throw(InvalidRdataText, "TSIG MAC size and data are inconsistent"); - } - - const int32_t orig_id = tokenToNum(getToken(iss)); - - const string error_txt = getToken(iss); - int32_t error = 0; - // XXX: In the initial implementation we hardcode the mnemonics. - // We'll soon generalize this. - if (error_txt == "BADSIG") { - error = 16; - } else if (error_txt == "BADKEY") { - error = 17; - } else if (error_txt == "BADTIME") { - error = 18; - } else { - error = tokenToNum(error_txt); - } + std::istringstream ss(tsig_str); + MasterLexer lexer; + lexer.pushSource(ss); - const int32_t otherlen = tokenToNum(getToken(iss)); - const string otherdata_txt = (otherlen > 0) ? getToken(iss) : ""; - vector other_data; - decodeBase64(otherdata_txt, other_data); + impl_ptr.reset(constructFromLexer(lexer)); - if (!iss.eof()) { - isc_throw(InvalidRdataText, "Unexpected input for TSIG RDATA: " << - tsig_str); + if (lexer.getNextToken().getType() != MasterToken::END_OF_FILE) { + isc_throw(InvalidRdataText, + "Extra input text for TSIG: " << tsig_str); } + } catch (const MasterLexer::LexerError& ex) { + isc_throw(InvalidRdataText, + "Failed to construct TSIG from '" << tsig_str << "': " + << ex.what()); + } - impl_ = new TSIGImpl(algorithm, time_signed, fudge, mac, orig_id, - error, other_data); + impl_ = impl_ptr.release(); +} - } catch (const StringTokenError& ste) { - isc_throw(InvalidRdataText, "Invalid TSIG text: " << ste.what() << - ": " << tsig_str); - } +/// \brief Constructor with a context of MasterLexer. +/// +/// The \c lexer should point to the beginning of valid textual +/// representation of an TSIG RDATA. +/// +/// See \c TSIG::TSIG(const std::string&) for description of the +/// expected RDATA fields. +/// +/// \throw MasterLexer::LexerError General parsing error such as +/// missing field. +/// \throw InvalidRdataText if any fields are out of their valid range, +/// or are incorrect. +/// +/// \param lexer A \c MasterLexer object parsing a master file for the +/// RDATA to be created +TSIG::TSIG(MasterLexer& lexer, const Name*, + MasterLoader::Options, MasterLoaderCallbacks&) : + impl_(NULL) +{ + impl_ = constructFromLexer(lexer); } /// \brief Constructor from wire-format data. @@ -298,7 +379,7 @@ TSIG::toText() const { // toWire(). template void -TSIG::TSIGImpl::toWireCommon(Output& output) const { +TSIGImpl::toWireCommon(Output& output) const { output.writeUint16(time_signed_ >> 32); output.writeUint32(time_signed_ & 0xffffffff); output.writeUint16(fudge_); diff --git a/src/lib/dns/rdata/any_255/tsig_250.h b/src/lib/dns/rdata/any_255/tsig_250.h index ff2492584b..f07295ec68 100644 --- a/src/lib/dns/rdata/any_255/tsig_250.h +++ b/src/lib/dns/rdata/any_255/tsig_250.h @@ -1,4 +1,4 @@ -// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2010-2013 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -18,14 +18,9 @@ #include +#include #include -namespace isc { -namespace dns { -class Name; -} -} - // BEGIN_ISC_NAMESPACE // BEGIN_COMMON_DECLARATIONS @@ -33,6 +28,8 @@ class Name; // BEGIN_RDATA_NAMESPACE +struct TSIGImpl; + /// \brief \c rdata::TSIG class represents the TSIG RDATA as defined %in /// RFC2845. /// @@ -145,7 +142,8 @@ public: /// This method never throws an exception. const void* getOtherData() const; private: - struct TSIGImpl; + TSIGImpl* constructFromLexer(isc::dns::MasterLexer& lexer); + TSIGImpl* impl_; }; diff --git a/src/lib/dns/tests/rdata_tsig_unittest.cc b/src/lib/dns/tests/rdata_tsig_unittest.cc index df35842233..09826247be 100644 --- a/src/lib/dns/tests/rdata_tsig_unittest.cc +++ b/src/lib/dns/tests/rdata_tsig_unittest.cc @@ -1,4 +1,4 @@ -// Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC") +// Copyright (C) 2010-2013 Internet Systems Consortium, Inc. ("ISC") // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -23,6 +23,7 @@ #include #include #include +#include #include @@ -72,7 +73,7 @@ TEST_F(Rdata_TSIG_Test, createFromText) { any::TSIG tsig2((string(valid_text2))); EXPECT_EQ(12, tsig2.getMACSize()); - EXPECT_EQ(16, tsig2.getError()); // TODO: use constant + EXPECT_EQ(TSIGError::BAD_SIG_CODE, tsig2.getError()); any::TSIG tsig3((string(valid_text3))); EXPECT_EQ(6, tsig3.getOtherLen());