123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357 |
- // Copyright (C) 2010 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 <iostream>
- #include <iomanip>
- #include <string>
- #include <sstream>
- #include <vector>
- #include <boost/lexical_cast.hpp>
- #include <util/encode/base32hex.h>
- #include <util/encode/hex.h>
- #include <util/buffer.h>
- #include <dns/exceptions.h>
- #include <dns/messagerenderer.h>
- #include <dns/name.h>
- #include <dns/rrtype.h>
- #include <dns/rrttl.h>
- #include <dns/rdata.h>
- #include <dns/rdataclass.h>
- #include <dns/rdata/generic/detail/nsec_bitmap.h>
- #include <stdio.h>
- #include <time.h>
- using namespace std;
- using namespace isc::dns::rdata::generic::detail::nsec;
- using namespace isc::util::encode;
- using namespace isc::util;
- // BEGIN_ISC_NAMESPACE
- // BEGIN_RDATA_NAMESPACE
- struct NSEC3Impl {
- // straightforward representation of NSEC3 RDATA fields
- NSEC3Impl(uint8_t hashalg, uint8_t flags, uint16_t iterations,
- vector<uint8_t>salt, vector<uint8_t>next,
- vector<uint8_t> typebits) :
- hashalg_(hashalg), flags_(flags), iterations_(iterations),
- salt_(salt), next_(next), typebits_(typebits)
- {}
- uint8_t hashalg_;
- uint8_t flags_;
- uint16_t iterations_;
- vector<uint8_t> salt_;
- vector<uint8_t> next_;
- vector<uint8_t> typebits_;
- };
- NSEC3::NSEC3(const string& nsec3_str) :
- impl_(NULL)
- {
- istringstream iss(nsec3_str);
- unsigned int hashalg, flags, iterations;
- string iterations_str, salthex, nexthash;
- iss >> hashalg >> flags >> iterations_str >> salthex >> 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");
- }
- vector<uint8_t> next;
- decodeBase32Hex(nexthash, next);
- if (next.size() > 255) {
- isc_throw(InvalidRdataText, "NSEC3 hash is too long: "
- << next.size() << " bytes");
- }
- // For NSEC3 empty bitmap is possible and allowed.
- if (iss.eof()) {
- impl_ = new NSEC3Impl(hashalg, flags, iterations, salt, next,
- vector<uint8_t>());
- return;
- }
- vector<uint8_t> typebits;
- uint8_t bitmap[8 * 1024]; // 64k bits
- memset(bitmap, 0, sizeof(bitmap));
- do {
- string type;
- iss >> type;
- if (type.length() != 0) {
- try {
- const int code = RRType(type).getCode();
- bitmap[code / 8] |= (0x80 >> (code % 8));
- } catch (...) {
- isc_throw(InvalidRdataText, "Invalid RRtype in NSEC3");
- }
- }
- } while (!iss.eof());
- for (int window = 0; window < 256; window++) {
- int octet;
- for (octet = 31; octet >= 0; octet--) {
- if (bitmap[window * 32 + octet] != 0) {
- break;
- }
- }
- if (octet < 0)
- continue;
- typebits.push_back(window);
- typebits.push_back(octet + 1);
- for (int i = 0; i <= octet; i++) {
- typebits.push_back(bitmap[window * 32 + i]);
- }
- }
- impl_ = new NSEC3Impl(hashalg, flags, 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;
- }
- const uint8_t nextlen = buffer.readUint8();
- --rdata_len;
- if (nextlen == 0 || rdata_len < nextlen) {
- isc_throw(DNSMessageFORMERR, "NSEC3 invalid hash length: " <<
- static_cast<unsigned int>(nextlen));
- }
- vector<uint8_t> next(nextlen);
- buffer.readData(&next[0], nextlen);
- rdata_len -= nextlen;
- vector<uint8_t> typebits(rdata_len);
- if (rdata_len > 0) {
- // Read and parse the bitmaps only when they exist; empty bitmap
- // is possible for NSEC3.
- buffer.readData(&typebits[0], rdata_len);
- checkRRTypeBitmaps("NSEC3", typebits);
- }
- impl_ = new NSEC3Impl(hashalg, flags, iterations, salt, next, typebits);
- }
- NSEC3::NSEC3(const NSEC3& source) :
- Rdata(), impl_(new NSEC3Impl(*source.impl_))
- {}
- NSEC3&
- NSEC3::operator=(const NSEC3& source) {
- if (impl_ == source.impl_) {
- return (*this);
- }
- NSEC3Impl* newimpl = new NSEC3Impl(*source.impl_);
- delete impl_;
- impl_ = newimpl;
- return (*this);
- }
- NSEC3::~NSEC3() {
- delete impl_;
- }
- string
- NSEC3::toText() const {
- ostringstream s;
- int len = 0;
- for (size_t i = 0; i < impl_->typebits_.size(); i += len) {
- assert(i + 2 <= impl_->typebits_.size());
- int window = impl_->typebits_[i];
- len = impl_->typebits_[i + 1];
- assert(len > 0 && len <= 32);
- i += 2;
- for (int j = 0; j < len; j++) {
- if (impl_->typebits_[i + j] == 0) {
- continue;
- }
- for (int k = 0; k < 8; k++) {
- if ((impl_->typebits_[i + j] & (0x80 >> k)) == 0) {
- continue;
- }
- int t = window * 256 + j * 8 + k;
- s << " " << RRType(t).toText();
- }
- }
- }
- using namespace boost;
- return (lexical_cast<string>(static_cast<int>(impl_->hashalg_)) +
- " " + lexical_cast<string>(static_cast<int>(impl_->flags_)) +
- " " + lexical_cast<string>(static_cast<int>(impl_->iterations_)) +
- " " + encodeHex(impl_->salt_) +
- " " + encodeBase32Hex(impl_->next_) + s.str());
- }
- template <typename OUTPUT_TYPE>
- void
- toWireHelper(const NSEC3Impl& impl, OUTPUT_TYPE& output) {
- output.writeUint8(impl.hashalg_);
- output.writeUint8(impl.flags_);
- output.writeUint16(impl.iterations_);
- output.writeUint8(impl.salt_.size());
- output.writeData(&impl.salt_[0], impl.salt_.size());
- output.writeUint8(impl.next_.size());
- output.writeData(&impl.next_[0], impl.next_.size());
- if (!impl.typebits_.empty()) {
- output.writeData(&impl.typebits_[0], impl.typebits_.size());
- }
- }
- void
- NSEC3::toWire(OutputBuffer& buffer) const {
- toWireHelper(*impl_, buffer);
- }
- void
- NSEC3::toWire(AbstractMessageRenderer& renderer) const {
- toWireHelper(*impl_, renderer);
- }
- int
- NSEC3::compare(const Rdata& other) const {
- const NSEC3& other_nsec3 = dynamic_cast<const NSEC3&>(other);
- if (impl_->hashalg_ != other_nsec3.impl_->hashalg_) {
- return (impl_->hashalg_ < other_nsec3.impl_->hashalg_ ? -1 : 1);
- }
- if (impl_->flags_ != other_nsec3.impl_->flags_) {
- return (impl_->flags_ < other_nsec3.impl_->flags_ ? -1 : 1);
- }
- if (impl_->iterations_ != other_nsec3.impl_->iterations_) {
- return (impl_->iterations_ < other_nsec3.impl_->iterations_ ? -1 : 1);
- }
- size_t this_len = impl_->salt_.size();
- size_t other_len = other_nsec3.impl_->salt_.size();
- size_t cmplen = min(this_len, other_len);
- int cmp = memcmp(&impl_->salt_[0], &other_nsec3.impl_->salt_[0], cmplen);
- if (cmp != 0) {
- return (cmp);
- } else if (this_len < other_len) {
- return (-1);
- } else if (this_len > other_len) {
- return (1);
- }
- this_len = impl_->salt_.size();
- other_len = other_nsec3.impl_->salt_.size();
- cmplen = min(this_len, other_len);
- cmp = memcmp(&impl_->next_[0], &other_nsec3.impl_->next_[0], cmplen);
- if (cmp != 0) {
- return (cmp);
- } else if (this_len < other_len) {
- return (-1);
- } else if (this_len > other_len) {
- return (1);
- }
- this_len = impl_->typebits_.size();
- other_len = other_nsec3.impl_->typebits_.size();
- cmplen = min(this_len, other_len);
- cmp = memcmp(&impl_->typebits_[0], &other_nsec3.impl_->typebits_[0],
- cmplen);
- if (cmp != 0) {
- return (cmp);
- } else if (this_len < other_len) {
- return (-1);
- } else if (this_len > other_len) {
- return (1);
- } else {
- return (0);
- }
- }
- uint8_t
- NSEC3::getHashalg() const {
- return (impl_->hashalg_);
- }
- uint8_t
- NSEC3::getFlags() const {
- return (impl_->flags_);
- }
- uint16_t
- NSEC3::getIterations() const {
- return (impl_->iterations_);
- }
- const vector<uint8_t>&
- NSEC3::getSalt() const {
- return (impl_->salt_);
- }
- const vector<uint8_t>&
- NSEC3::getNext() const {
- return (impl_->next_);
- }
- // END_RDATA_NAMESPACE
- // END_ISC_NAMESPACE
|