Commit 001717c6 authored by JINMEI Tatuya's avatar JINMEI Tatuya
Browse files

[1638] consolidated common logic of parsing text/wire NSEC3/NSEC3PARAM RDATA

into a shared helper module.
parent bf67156c
......@@ -23,6 +23,8 @@ EXTRA_DIST += rdata/generic/cname_5.cc
EXTRA_DIST += rdata/generic/cname_5.h
EXTRA_DIST += rdata/generic/detail/nsec_bitmap.cc
EXTRA_DIST += rdata/generic/detail/nsec_bitmap.h
EXTRA_DIST += rdata/generic/detail/nsec3param_common.cc
EXTRA_DIST += rdata/generic/detail/nsec3param_common.h
EXTRA_DIST += rdata/generic/detail/txt_like.h
EXTRA_DIST += rdata/generic/detail/ds_like.h
EXTRA_DIST += rdata/generic/dlv_32769.cc
......@@ -113,6 +115,8 @@ libdns___la_SOURCES += tsigrecord.h tsigrecord.cc
libdns___la_SOURCES += character_string.h character_string.cc
libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.h
libdns___la_SOURCES += rdata/generic/detail/nsec_bitmap.cc
libdns___la_SOURCES += rdata/generic/detail/nsec3param_common.cc
libdns___la_SOURCES += rdata/generic/detail/nsec3param_common.h
libdns___la_SOURCES += rdata/generic/detail/txt_like.h
libdns___la_SOURCES += rdata/generic/detail/ds_like.h
......
// Copyright (C) 2012 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <exceptions/exceptions.h>
#include <util/encode/hex.h>
#include <util/buffer.h>
#include <dns/exceptions.h>
#include <dns/rdata.h>
#include <dns/rdata/generic/detail/nsec3param_common.h>
#include <boost/lexical_cast.hpp>
#include <sstream>
#include <vector>
#include <stdint.h>
using namespace std;
using namespace isc::util;
using namespace isc::util::encode;
namespace isc {
namespace dns {
namespace rdata {
namespace generic {
namespace detail {
namespace nsec3 {
ParseNSEC3ParamResult
parseNSEC3ParamText(const char* const rrtype_name,
const string& rdata_str, istringstream& iss,
vector<uint8_t>& salt)
{
unsigned int hashalg, flags, iterations;
string iterations_str, salthex;
iss >> hashalg >> flags >> iterations_str >> salthex;
if (iss.bad() || iss.fail()) {
isc_throw(InvalidRdataText, "Invalid " << rrtype_name <<
" text: " << rdata_str);
}
if (hashalg > 0xff) {
isc_throw(InvalidRdataText, rrtype_name <<
" hash algorithm out of range: " << hashalg);
}
if (flags > 0xff) {
isc_throw(InvalidRdataText, rrtype_name << " flags out of range: " <<
flags);
}
// Convert iteration. To reject an invalid case where there's no space
// between iteration and salt, we extract this field as string and convert
// to integer.
try {
iterations = boost::lexical_cast<unsigned int>(iterations_str);
} catch (const boost::bad_lexical_cast&) {
isc_throw(InvalidRdataText, "Bad " << rrtype_name <<
" iteration: " << iterations_str);
}
if (iterations > 0xffff) {
isc_throw(InvalidRdataText, rrtype_name <<
" iterations out of range: " <<
iterations);
}
if (salthex != "-") { // "-" means a 0-length salt
decodeHex(salthex, salt);
}
if (salt.size() > 255) {
isc_throw(InvalidRdataText, rrtype_name << " salt is too long: "
<< salt.size() << " bytes");
}
return (ParseNSEC3ParamResult(hashalg, flags, iterations));
}
ParseNSEC3ParamResult
parseNSEC3ParamWire(const char* const rrtype_name,
InputBuffer& buffer,
size_t& rdata_len, std::vector<uint8_t>& salt)
{
// NSEC3/NSEC3PARAM RR must have at least 5 octets:
// hash algorithm(1), flags(1), iteration(2), saltlen(1)
if (rdata_len < 5) {
isc_throw(DNSMessageFORMERR, rrtype_name << " too short, length: "
<< rdata_len);
}
const uint8_t hashalg = buffer.readUint8();
const uint8_t flags = buffer.readUint8();
const uint16_t iterations = buffer.readUint16();
const uint8_t saltlen = buffer.readUint8();
rdata_len -= 5;
if (rdata_len < saltlen) {
isc_throw(DNSMessageFORMERR, rrtype_name <<
" salt length is too large: " <<
static_cast<unsigned int>(saltlen));
}
salt.resize(saltlen);
if (saltlen > 0) {
buffer.readData(&salt[0], saltlen);
rdata_len -= saltlen;
}
return (ParseNSEC3ParamResult(hashalg, flags, iterations));
}
} // end of nsec3
} // end of detail
} // end of generic
} // end of rdata
} // end of dns
} // end of isc
// Copyright (C) 2012 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
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef __NSEC3PARAM_COMMON_H
#define __NSEC3PARAM_COMMON_H 1
#include <util/buffer.h>
#include <stdint.h>
#include <sstream>
#include <string>
#include <vector>
namespace isc {
namespace dns {
namespace rdata {
namespace generic {
namespace detail {
namespace nsec3 {
/// \file
///
/// This helper module provides some utilities that handle NSEC3 and
/// NSEC3PARAM RDATA. They share the first few fields, and some operations
/// on these fields are sufficiently complicated, so it would make sense to
/// consolidate the processing logic into a single implementation module.
///
/// The functions defined here are essentially private and are only expected
/// to be called from the \c NSEC3 and \c NSEC3PARAM class implementations.
/// \brief Result values of the utilities.
///
/// This structure encapsulates a tuple of NSEC3/NSEC3PARAM algorithm,
/// flags and iterations field values. This is used as the return value
/// of the utility functions defined in this module so the caller can
/// use it for constructing the corresponding RDATA.
struct ParseNSEC3ParamResult {
ParseNSEC3ParamResult(uint8_t param_algorithm, uint8_t param_flags,
uint16_t param_iterations) :
algorithm(param_algorithm), flags(param_flags),
iterations(param_iterations)
{}
const uint8_t algorithm;
const uint8_t flags;
const uint16_t iterations;
};
/// \brief Convert textual representation of NSEC3 parameters.
///
/// This function takes an input string stream that consists of a complete
/// textual representation of an NSEC3 or NSEC3PARAM RDATA and parses it
/// extracting the hash algorithm, flags, iterations, and salt fields.
///
/// The first three fields are returned as the return value of this function.
/// The salt will be stored in the given vector. The vector is expected
/// to be empty, but if not, the existing content will be overridden.
///
/// On successful return the given input stream will reach the end of the
/// salt field.
///
/// \exception isc::BadValue The salt is not a valid hex string.
/// \exception InvalidRdataText The given string is otherwise invalid for
/// NSEC3 or NSEC3PARAM fields.
///
/// \param rrtype_name Either "NSEC3" or "NSEC3PARAM"; used as part of
/// exception messages.
/// \param rdata_str A complete textual string of the RDATA; used as part of
/// exception messages.
/// \param iss Input stream that consists of a complete textual string of
/// the RDATA.
/// \param salt A placeholder for the salt field value of the RDATA.
/// Expected to be empty, but it's not checked (and will be overridden).
///
/// \return The hash algorithm, flags, iterations in the form of
/// ParseNSEC3ParamResult.
ParseNSEC3ParamResult parseNSEC3ParamText(const char* const rrtype_name,
const std::string& rdata_str,
std::istringstream& iss,
std::vector<uint8_t>& salt);
/// \brief Extract NSEC3 parameters from wire-format data.
///
/// This function takes an input buffer that stores wire-format NSEC3 or
/// NSEC3PARAM RDATA and parses it extracting the hash algorithm, flags,
/// iterations, and salt fields.
///
/// The first three fields are returned as the return value of this function.
/// The salt will be stored in the given vector. The vector is expected
/// to be empty, but if not, the existing content will be overridden.
///
/// On successful return the input buffer will point to the end of the
/// salt field; rdata_len will be the length of the rest of RDATA
/// (in the case of a valid NSEC3PARAM, it should be 0).
///
/// \exception DNSMessageFORMERR The wire data is invalid.
///
/// \param rrtype_name Either "NSEC3" or "NSEC3PARAM"; used as part of
/// exception messages.
/// \param buffer An input buffer that stores wire-format RDATA. It must
/// point to the beginning of the data.
/// \param rdata_len The total length of the RDATA.
/// \param salt A placeholder for the salt field value of the RDATA.
/// Expected to be empty, but it's not checked (and will be overridden).
///
/// \return The hash algorithm, flags, iterations in the form of
/// ParseNSEC3ParamResult.
ParseNSEC3ParamResult parseNSEC3ParamWire(const char* const rrtype_name,
isc::util::InputBuffer& buffer,
size_t& rdata_len,
std::vector<uint8_t>& salt);
}
}
}
}
}
}
#endif // __NSEC3PARAM_COMMON_H
// Local Variables:
// mode: c++
// End:
......@@ -12,6 +12,9 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef __NSECBITMAP_H
#define __NSECBITMAP_H 1
#include <stdint.h>
#include <sstream>
......@@ -97,6 +100,8 @@ void bitmapsToText(const std::vector<uint8_t>& typebits,
}
}
#endif // __NSECBITMAP_H
// Local Variables:
// mode: c++
// End:
......@@ -33,12 +33,14 @@
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdata/generic/detail/nsec_bitmap.h>
#include <dns/rdata/generic/detail/nsec3param_common.h>
#include <stdio.h>
#include <time.h>
using namespace std;
using namespace isc::dns::rdata::generic::detail::nsec;
using namespace isc::dns::rdata::generic::detail::nsec3;
using namespace isc::util::encode;
using namespace isc::util;
......@@ -66,43 +68,16 @@ NSEC3::NSEC3(const string& nsec3_str) :
impl_(NULL)
{
istringstream iss(nsec3_str);
unsigned int hashalg, flags, iterations;
string iterations_str, salthex, nexthash;
vector<uint8_t> salt;
const ParseNSEC3ParamResult params =
parseNSEC3ParamText("NSEC3", nsec3_str, iss, salt);
iss >> hashalg >> flags >> iterations_str >> salthex >> nexthash;
// Extract Next hash. It must not be a padded base32hex string.
string nexthash;
iss >> nexthash;
if (iss.bad() || iss.fail()) {
isc_throw(InvalidRdataText, "Invalid NSEC3 text: " << nsec3_str);
}
if (hashalg > 0xff) {
isc_throw(InvalidRdataText,
"NSEC3 hash algorithm out of range: " << hashalg);
}
if (flags > 0xff) {
isc_throw(InvalidRdataText, "NSEC3 flags out of range: " << flags);
}
// Convert iteration. To reject an invalid case where there's no space
// between iteration and salt, we extract this field as string and convert
// to integer.
try {
iterations = boost::lexical_cast<unsigned int>(iterations_str);
} catch (const boost::bad_lexical_cast&) {
isc_throw(InvalidRdataText, "Bad NSEC3 iteration: " << iterations_str);
}
if (iterations > 0xffff) {
isc_throw(InvalidRdataText, "NSEC3 iterations out of range: " <<
iterations);
}
vector<uint8_t> salt;
if (salthex != "-") { // "-" means a 0-length salt
decodeHex(salthex, salt);
}
if (salt.size() > 255) {
isc_throw(InvalidRdataText, "NSEC3 salt is too long: "
<< salt.size() << " bytes");
}
// Next hash must not be a padded base32hex string.
assert(!nexthash.empty());
if (*nexthash.rbegin() == '=') {
isc_throw(InvalidRdataText, "NSEC3 hash has padding: " << nsec3_str);
......@@ -116,7 +91,8 @@ NSEC3::NSEC3(const string& nsec3_str) :
// For NSEC3 empty bitmap is possible and allowed.
if (iss.eof()) {
impl_ = new NSEC3Impl(hashalg, flags, iterations, salt, next,
impl_ = new NSEC3Impl(params.algorithm, params.flags,
params.iterations, salt, next,
vector<uint8_t>());
return;
}
......@@ -124,36 +100,18 @@ NSEC3::NSEC3(const string& nsec3_str) :
vector<uint8_t> typebits;
buildBitmapsFromText("NSEC3", iss, typebits);
impl_ = new NSEC3Impl(hashalg, flags, iterations, salt, next, typebits);
impl_ = new NSEC3Impl(params.algorithm, params.flags, params.iterations,
salt, next, typebits);
}
NSEC3::NSEC3(InputBuffer& buffer, size_t rdata_len) {
// NSEC3 RR must have at least 5 octets:
// hash algorithm(1), flags(1), iteration(2), saltlen(1)
if (rdata_len < 5) {
isc_throw(DNSMessageFORMERR, "NSEC3 too short, length: " << rdata_len);
}
const uint8_t hashalg = buffer.readUint8();
const uint8_t flags = buffer.readUint8();
const uint16_t iterations = buffer.readUint16();
const uint8_t saltlen = buffer.readUint8();
rdata_len -= 5;
if (rdata_len < saltlen) {
isc_throw(DNSMessageFORMERR, "NSEC3 salt length is too large: " <<
static_cast<unsigned int>(saltlen));
}
vector<uint8_t> salt(saltlen);
if (saltlen > 0) {
buffer.readData(&salt[0], saltlen);
rdata_len -= saltlen;
}
vector<uint8_t> salt;
const ParseNSEC3ParamResult params =
parseNSEC3ParamWire("NSEC3", buffer, rdata_len, salt);
if (rdata_len < 1) {
isc_throw(DNSMessageFORMERR, "NSEC3 too short to contain hash length, "
"length: " << rdata_len + saltlen + 5);
"length: " << rdata_len + salt.size() + 5);
}
const uint8_t nextlen = buffer.readUint8();
--rdata_len;
......@@ -174,7 +132,8 @@ NSEC3::NSEC3(InputBuffer& buffer, size_t rdata_len) {
checkRRTypeBitmaps("NSEC3", typebits);
}
impl_ = new NSEC3Impl(hashalg, flags, iterations, salt, next, typebits);
impl_ = new NSEC3Impl(params.algorithm, params.flags, params.iterations,
salt, next, typebits);
}
NSEC3::NSEC3(const NSEC3& source) :
......
......@@ -12,22 +12,19 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <boost/lexical_cast.hpp>
#include <util/buffer.h>
#include <util/encode/hex.h>
#include <dns/messagerenderer.h>
#include <dns/name.h>
#include <dns/rdata.h>
#include <dns/rdataclass.h>
#include <dns/rdata/generic/detail/nsec3param_common.h>
#include <stdio.h>
#include <time.h>
#include <boost/lexical_cast.hpp>
#include <string>
#include <sstream>
#include <vector>
using namespace std;
using namespace isc::util;
......@@ -53,75 +50,26 @@ NSEC3PARAM::NSEC3PARAM(const string& nsec3param_str) :
impl_(NULL)
{
istringstream iss(nsec3param_str);
unsigned int hashalg, flags, iterations;
string iterations_str, salt_str;
iss >> hashalg >> flags >> iterations_str >> salt_str;
if (iss.bad() || iss.fail()) {
isc_throw(InvalidRdataText, "Invalid NSEC3PARAM text");
}
if (hashalg > 0xff) {
isc_throw(InvalidRdataText, "NSEC3PARAM hash algorithm out of range");
}
if (flags > 0xff) {
isc_throw(InvalidRdataText, "NSEC3PARAM flags out of range");
}
// Convert iteration. To reject an invalid case where there's no space
// between iteration and salt, we extract this field as string and convert
// to integer.
try {
iterations = boost::lexical_cast<unsigned int>(iterations_str);
} catch (const boost::bad_lexical_cast&) {
isc_throw(InvalidRdataText, "Bad NSEC3PARAM iteration: " <<
iterations_str);
}
if (iterations > 0xffff) {
isc_throw(InvalidRdataText, "NSEC3PARAM iterations out of range: " <<
iterations);
}
vector<uint8_t> salt;
if (salt_str != "-") { // "-" means an empty salt, no need to touch vector
decodeHex(salt_str, salt);
}
if (salt.size() > 255) {
isc_throw(InvalidRdataText, "NSEC3PARAM salt is too long: "
<< salt.size() << " bytes");
}
const ParseNSEC3ParamResult params =
parseNSEC3ParamText("NSEC3PARAM", nsec3param_str, iss, salt);
if (!iss.eof()) {
isc_throw(InvalidRdataText, "Invalid NSEC3PARAM (redundant text): "
<< nsec3param_str);
}
impl_ = new NSEC3PARAMImpl(hashalg, flags, iterations, salt);
impl_ = new NSEC3PARAMImpl(params.algorithm, params.flags,
params.iterations, salt);
}
NSEC3PARAM::NSEC3PARAM(InputBuffer& buffer, size_t rdata_len) {
// NSEC3 RR must have at least 5 octets:
// hash algorithm(1), flags(1), iteration(2), saltlen(1)
if (rdata_len < 5) {
isc_throw(DNSMessageFORMERR, "NSEC3PARAM too short, length: "
<< rdata_len);
}
const uint8_t hashalg = buffer.readUint8();
const uint8_t flags = buffer.readUint8();
const uint16_t iterations = buffer.readUint16();
const uint8_t saltlen = buffer.readUint8();
rdata_len -= 5;
if (rdata_len < saltlen) {
isc_throw(DNSMessageFORMERR, "NSEC3PARAM salt length is too large: "
<< static_cast<unsigned int>(saltlen));
}
vector<uint8_t> salt(saltlen);
if (saltlen > 0) {
buffer.readData(&salt[0], saltlen);
}
vector<uint8_t> salt;
const ParseNSEC3ParamResult params =
parseNSEC3ParamWire("NSEC3PARAM", buffer, rdata_len, salt);
impl_ = new NSEC3PARAMImpl(hashalg, flags, iterations, salt);
impl_ = new NSEC3PARAMImpl(params.algorithm, params.flags,
params.iterations, salt);
}
NSEC3PARAM::NSEC3PARAM(const NSEC3PARAM& source) :
......@@ -225,6 +173,5 @@ NSEC3PARAM::getSalt() const {
return (impl_->salt_);
}
// END_RDATA_NAMESPACE
// END_ISC_NAMESPACE
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment