2012-03-01 11:46:46 +01:00
|
|
|
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
|
2012-02-20 23:29:31 +01:00
|
|
|
//
|
|
|
|
// 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 <dns/labelsequence.h>
|
2012-03-06 14:06:40 -08:00
|
|
|
#include <dns/name_internal.h>
|
2012-02-20 23:29:31 +01:00
|
|
|
#include <exceptions/exceptions.h>
|
|
|
|
|
2012-03-06 14:06:40 -08:00
|
|
|
#include <boost/functional/hash.hpp>
|
|
|
|
|
2012-05-11 19:30:33 +00:00
|
|
|
#include <cstring>
|
|
|
|
|
2012-02-20 23:29:31 +01:00
|
|
|
namespace isc {
|
|
|
|
namespace dns {
|
|
|
|
|
2012-06-24 22:11:35 +05:30
|
|
|
const uint8_t*
|
2012-02-20 23:29:31 +01:00
|
|
|
LabelSequence::getData(size_t *len) const {
|
2012-03-05 15:51:41 -08:00
|
|
|
*len = getDataLength();
|
2012-03-08 22:49:11 -08:00
|
|
|
return (&name_.ndata_[name_.offsets_[first_label_]]);
|
2012-03-05 15:51:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
LabelSequence::getDataLength() const {
|
2012-02-28 19:46:53 +01:00
|
|
|
// If the labelsequence is absolute, the current last_label_ falls
|
|
|
|
// out of the vector (since it points to the 'label' after the
|
|
|
|
// root label, which doesn't exist; in that case, return
|
|
|
|
// the length for the 'previous' label (the root label) plus
|
|
|
|
// one (for the root label zero octet)
|
|
|
|
if (isAbsolute()) {
|
2012-03-08 22:49:11 -08:00
|
|
|
return (name_.offsets_[last_label_ - 1] -
|
|
|
|
name_.offsets_[first_label_] + 1);
|
2012-02-28 19:46:53 +01:00
|
|
|
} else {
|
2012-03-08 22:49:11 -08:00
|
|
|
return (name_.offsets_[last_label_] - name_.offsets_[first_label_]);
|
2012-02-28 19:46:53 +01:00
|
|
|
}
|
2012-02-20 23:29:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
LabelSequence::equals(const LabelSequence& other, bool case_sensitive) const {
|
2012-02-21 12:37:07 +01:00
|
|
|
size_t len, other_len;
|
2012-06-24 22:11:35 +05:30
|
|
|
const uint8_t* data = getData(&len);
|
|
|
|
const uint8_t* other_data = other.getData(&other_len);
|
2012-02-21 12:37:07 +01:00
|
|
|
|
|
|
|
if (len != other_len) {
|
|
|
|
return (false);
|
|
|
|
}
|
2012-02-20 23:29:31 +01:00
|
|
|
if (case_sensitive) {
|
2012-06-24 22:11:35 +05:30
|
|
|
return (std::memcmp(data, other_data, len) == 0);
|
2012-02-20 23:29:31 +01:00
|
|
|
}
|
2012-03-06 16:05:22 -08:00
|
|
|
|
|
|
|
// As long as the data was originally validated as (part of) a name,
|
|
|
|
// label length must never be a capital ascii character, so we can
|
|
|
|
// simply compare them after converting to lower characters.
|
|
|
|
for (size_t i = 0; i < len; ++i) {
|
2012-06-24 22:11:35 +05:30
|
|
|
const uint8_t ch = data[i];
|
|
|
|
const uint8_t other_ch = other_data[i];
|
2012-03-06 16:05:22 -08:00
|
|
|
if (isc::dns::name::internal::maptolower[ch] !=
|
|
|
|
isc::dns::name::internal::maptolower[other_ch]) {
|
|
|
|
return (false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return (true);
|
2012-02-20 23:29:31 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-03-02 10:31:16 +01:00
|
|
|
LabelSequence::stripLeft(size_t i) {
|
2012-03-01 11:46:46 +01:00
|
|
|
if (i >= getLabelCount()) {
|
2012-03-02 10:31:16 +01:00
|
|
|
isc_throw(OutOfRange, "Cannot strip to zero or less labels; " << i <<
|
2012-02-28 19:46:53 +01:00
|
|
|
" (labelcount: " << getLabelCount() << ")");
|
2012-02-28 12:30:04 +01:00
|
|
|
}
|
2012-03-01 11:46:46 +01:00
|
|
|
first_label_ += i;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2012-03-02 10:31:16 +01:00
|
|
|
LabelSequence::stripRight(size_t i) {
|
2012-03-01 11:46:46 +01:00
|
|
|
if (i >= getLabelCount()) {
|
2012-03-02 10:31:16 +01:00
|
|
|
isc_throw(OutOfRange, "Cannot strip to zero or less labels; " << i <<
|
2012-03-01 11:46:46 +01:00
|
|
|
" (labelcount: " << getLabelCount() << ")");
|
2012-02-20 23:29:31 +01:00
|
|
|
}
|
2012-03-01 11:46:46 +01:00
|
|
|
last_label_ -= i;
|
2012-02-20 23:29:31 +01:00
|
|
|
}
|
|
|
|
|
2012-02-28 19:46:53 +01:00
|
|
|
bool
|
|
|
|
LabelSequence::isAbsolute() const {
|
2012-03-08 22:49:11 -08:00
|
|
|
return (last_label_ == name_.offsets_.size());
|
2012-02-28 19:46:53 +01:00
|
|
|
}
|
|
|
|
|
2012-03-06 14:06:40 -08:00
|
|
|
size_t
|
|
|
|
LabelSequence::getHash(bool case_sensitive) const {
|
|
|
|
size_t length;
|
2012-06-24 22:11:35 +05:30
|
|
|
const uint8_t* s = getData(&length);
|
2012-03-06 14:06:40 -08:00
|
|
|
if (length > 16) {
|
|
|
|
length = 16;
|
|
|
|
}
|
|
|
|
|
|
|
|
size_t hash_val = 0;
|
|
|
|
while (length > 0) {
|
2012-06-24 22:11:35 +05:30
|
|
|
const uint8_t c = *s++;
|
2012-03-06 14:06:40 -08:00
|
|
|
boost::hash_combine(hash_val, case_sensitive ? c :
|
|
|
|
isc::dns::name::internal::maptolower[c]);
|
|
|
|
--length;
|
|
|
|
}
|
|
|
|
return (hash_val);
|
|
|
|
}
|
|
|
|
|
2012-07-02 06:17:49 +05:30
|
|
|
std::string
|
|
|
|
LabelSequence::toText(bool omit_final_dot) const {
|
2012-07-04 09:24:48 +05:30
|
|
|
Name::NameString::const_iterator np = name_.ndata_.begin() +
|
|
|
|
name_.offsets_[first_label_];
|
2012-07-02 12:10:56 -07:00
|
|
|
const Name::NameString::const_iterator np_end = name_.ndata_.end();
|
|
|
|
// use for integrity check
|
|
|
|
unsigned int labels = last_label_ - first_label_;
|
2012-07-02 06:17:49 +05:30
|
|
|
// init with an impossible value to catch error cases in the end:
|
|
|
|
unsigned int count = Name::MAX_LABELLEN + 1;
|
|
|
|
|
|
|
|
// result string: it will roughly have the same length as the wire format
|
|
|
|
// name data. reserve that length to minimize reallocation.
|
|
|
|
std::string result;
|
2012-07-04 09:29:18 +05:30
|
|
|
result.reserve(name_.getLength());
|
2012-07-02 06:17:49 +05:30
|
|
|
|
|
|
|
while (np != np_end) {
|
2012-07-04 10:17:17 +05:30
|
|
|
if (labels == 0) {
|
|
|
|
count = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2012-07-02 06:17:49 +05:30
|
|
|
labels--;
|
|
|
|
count = *np++;
|
|
|
|
|
|
|
|
if (count == 0) {
|
2012-07-04 09:48:35 +05:30
|
|
|
// We've reached the "final dot". If we've not dumped any
|
|
|
|
// character, the entire label sequence is the root name.
|
|
|
|
// In that case we don't omit the final dot.
|
|
|
|
if (!omit_final_dot || result.empty()) {
|
2012-07-02 06:17:49 +05:30
|
|
|
result.push_back('.');
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count <= Name::MAX_LABELLEN) {
|
|
|
|
assert(np_end - np >= count);
|
|
|
|
|
|
|
|
if (!result.empty()) {
|
|
|
|
// just after a non-empty label. add a separating dot.
|
|
|
|
result.push_back('.');
|
|
|
|
}
|
|
|
|
|
|
|
|
while (count-- > 0) {
|
2012-07-02 12:10:56 -07:00
|
|
|
const uint8_t c = *np++;
|
2012-07-02 06:17:49 +05:30
|
|
|
switch (c) {
|
|
|
|
case 0x22: // '"'
|
|
|
|
case 0x28: // '('
|
|
|
|
case 0x29: // ')'
|
|
|
|
case 0x2E: // '.'
|
|
|
|
case 0x3B: // ';'
|
|
|
|
case 0x5C: // '\\'
|
|
|
|
// Special modifiers in zone files.
|
|
|
|
case 0x40: // '@'
|
|
|
|
case 0x24: // '$'
|
|
|
|
result.push_back('\\');
|
|
|
|
result.push_back(c);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (c > 0x20 && c < 0x7f) {
|
|
|
|
// append printable characters intact
|
|
|
|
result.push_back(c);
|
|
|
|
} else {
|
|
|
|
// encode non-printable characters in the form of \DDD
|
|
|
|
result.push_back(0x5c);
|
|
|
|
result.push_back(0x30 + ((c / 100) % 10));
|
|
|
|
result.push_back(0x30 + ((c / 10) % 10));
|
|
|
|
result.push_back(0x30 + (c % 10));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
isc_throw(BadLabelType, "unknown label type in name data");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(labels == 0);
|
2012-07-04 09:58:18 +05:30
|
|
|
assert(count == 0);
|
2012-07-02 06:17:49 +05:30
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
2012-06-29 05:22:47 +05:30
|
|
|
std::string
|
|
|
|
LabelSequence::toText() const {
|
2012-07-02 06:17:49 +05:30
|
|
|
return (toText(!isAbsolute()));
|
2012-06-29 05:22:47 +05:30
|
|
|
}
|
|
|
|
|
2012-06-29 05:29:56 +05:30
|
|
|
std::ostream&
|
|
|
|
operator<<(std::ostream& os, const LabelSequence& label_sequence) {
|
|
|
|
os << label_sequence.toText();
|
|
|
|
return (os);
|
|
|
|
}
|
|
|
|
|
2012-02-20 23:29:31 +01:00
|
|
|
} // end namespace dns
|
|
|
|
} // end namespace isc
|