2024-03-22 15:55:27 +00:00
|
|
|
// Copyright (C) 2012-2024 Internet Systems Consortium, Inc. ("ISC")
|
2012-02-20 23:29:31 +01:00
|
|
|
//
|
2015-12-15 21:37:34 +01:00
|
|
|
// 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/.
|
2012-02-20 23:29:31 +01:00
|
|
|
|
2014-01-28 11:34:44 +00:00
|
|
|
#include <config.h>
|
2014-01-22 09:54:01 +05:30
|
|
|
|
2012-02-20 23:29:31 +01:00
|
|
|
#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>
|
2019-07-12 07:01:01 -04:00
|
|
|
#include <exceptions/isc_assert.h>
|
2012-02-20 23:29:31 +01:00
|
|
|
|
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-07-20 18:30:32 -07:00
|
|
|
LabelSequence::LabelSequence(const void* buf) {
|
2014-01-22 09:54:01 +05:30
|
|
|
#ifdef ENABLE_DEBUG
|
2024-03-10 00:23:20 +01:00
|
|
|
// In non-debug mode, dereferencing the null pointer further below
|
2014-01-22 09:54:01 +05:30
|
|
|
// will lead to a crash, so disabling this check is not
|
|
|
|
// unsafe. Except for a programming mistake, this case should not
|
|
|
|
// happen.
|
2024-03-08 20:19:05 +02:00
|
|
|
if (!buf) {
|
2012-07-20 18:30:32 -07:00
|
|
|
isc_throw(BadValue,
|
|
|
|
"Null pointer passed to LabelSequence constructor");
|
|
|
|
}
|
2014-01-22 09:54:01 +05:30
|
|
|
#endif
|
2012-07-20 18:30:32 -07:00
|
|
|
|
|
|
|
const uint8_t* bp = reinterpret_cast<const uint8_t*>(buf);
|
|
|
|
first_label_ = 0;
|
|
|
|
const uint8_t offsets_len = *bp++;
|
2014-01-22 09:54:01 +05:30
|
|
|
|
|
|
|
#ifdef ENABLE_DEBUG
|
2012-07-20 18:30:32 -07:00
|
|
|
if (offsets_len == 0 || offsets_len > Name::MAX_LABELS) {
|
|
|
|
isc_throw(BadValue,
|
|
|
|
"Bad offsets len in serialized LabelSequence data: "
|
|
|
|
<< static_cast<unsigned int>(offsets_len));
|
|
|
|
}
|
2014-01-22 09:54:01 +05:30
|
|
|
#endif
|
|
|
|
|
2012-07-20 18:30:32 -07:00
|
|
|
last_label_ = offsets_len - 1;
|
|
|
|
offsets_ = bp;
|
|
|
|
data_ = bp + offsets_len;
|
|
|
|
|
2014-01-22 09:54:01 +05:30
|
|
|
#ifdef ENABLE_DEBUG
|
2012-07-20 18:30:32 -07:00
|
|
|
// Check the integrity on the offsets and the name data
|
|
|
|
const uint8_t* dp = data_;
|
|
|
|
for (size_t cur_offset = 0; cur_offset < offsets_len; ++cur_offset) {
|
2012-09-21 15:11:13 -07:00
|
|
|
if (dp - data_ != offsets_[cur_offset] || *dp > Name::MAX_LABELLEN) {
|
2012-07-20 18:30:32 -07:00
|
|
|
isc_throw(BadValue,
|
|
|
|
"Broken offset or name data in serialized "
|
|
|
|
"LabelSequence data");
|
|
|
|
}
|
|
|
|
dp += (1 + *dp);
|
|
|
|
}
|
2014-01-22 09:54:01 +05:30
|
|
|
#endif
|
2012-07-20 18:30:32 -07:00
|
|
|
}
|
2012-07-12 13:14:40 +02:00
|
|
|
|
2012-07-25 11:41:33 +02:00
|
|
|
LabelSequence::LabelSequence(const LabelSequence& src,
|
2024-03-01 20:37:15 +02:00
|
|
|
uint8_t buf[MAX_SERIALIZED_LENGTH]) {
|
2012-07-25 11:41:33 +02:00
|
|
|
size_t data_len;
|
|
|
|
const uint8_t *data = src.getData(&data_len);
|
2012-07-30 14:07:41 +02:00
|
|
|
std::memcpy(buf, data, data_len);
|
2012-07-25 11:41:33 +02:00
|
|
|
|
|
|
|
for (size_t i = 0; i < src.getLabelCount(); ++i) {
|
|
|
|
buf[Name::MAX_WIRE + i] = src.offsets_[i + src.first_label_] -
|
|
|
|
src.offsets_[src.first_label_];
|
|
|
|
}
|
|
|
|
|
|
|
|
first_label_ = 0;
|
|
|
|
last_label_ = src.last_label_ - src.first_label_;
|
|
|
|
data_ = buf;
|
|
|
|
offsets_ = &buf[Name::MAX_WIRE];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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-07-12 12:35:54 +02:00
|
|
|
return (&data_[offsets_[first_label_]]);
|
2012-03-05 15:51:41 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
size_t
|
|
|
|
LabelSequence::getDataLength() const {
|
2012-07-20 15:09:35 -07:00
|
|
|
const size_t last_label_len = data_[offsets_[last_label_]] + 1;
|
|
|
|
return (offsets_[last_label_] - offsets_[first_label_] + last_label_len);
|
2012-02-20 23:29:31 +01:00
|
|
|
}
|
|
|
|
|
2012-07-20 18:30:32 -07:00
|
|
|
size_t
|
|
|
|
LabelSequence::getSerializedLength() const {
|
|
|
|
return (1 + getLabelCount() + getDataLength());
|
|
|
|
}
|
|
|
|
|
2012-08-23 13:10:01 -07:00
|
|
|
namespace {
|
|
|
|
// Check if buf is not in the range of [bp, ep), which means
|
|
|
|
// - end of buffer is before bp, or
|
|
|
|
// - beginning of buffer is on or after ep
|
|
|
|
bool
|
|
|
|
isOutOfRange(const uint8_t* bp, const uint8_t* ep,
|
2024-03-01 20:37:15 +02:00
|
|
|
const uint8_t* buf, size_t buf_len) {
|
2012-08-23 13:10:01 -07:00
|
|
|
return (bp >= buf + buf_len || // end of buffer is before bp
|
|
|
|
ep <= buf); // beginning of buffer is on or after ep
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-20 18:30:32 -07:00
|
|
|
void
|
|
|
|
LabelSequence::serialize(void* buf, size_t buf_len) const {
|
|
|
|
const size_t expected_size = getSerializedLength();
|
|
|
|
if (expected_size > buf_len) {
|
|
|
|
isc_throw(BadValue, "buffer too short for LabelSequence::serialize");
|
|
|
|
}
|
|
|
|
|
|
|
|
const size_t offsets_len = getLabelCount();
|
2019-07-12 07:01:01 -04:00
|
|
|
isc_throw_assert(offsets_len < 256); // should be in the 8-bit range
|
2012-07-20 18:30:32 -07:00
|
|
|
|
2012-08-23 13:10:01 -07:00
|
|
|
// Overridden check. Buffer shouldn't overwrap the offset of name data
|
|
|
|
// regions.
|
2012-07-20 18:30:32 -07:00
|
|
|
uint8_t* bp = reinterpret_cast<uint8_t*>(buf);
|
2012-08-23 13:10:01 -07:00
|
|
|
const size_t ndata_len = getDataLength();
|
|
|
|
if (!isOutOfRange(offsets_, offsets_ + offsets_len, bp, buf_len) ||
|
|
|
|
!isOutOfRange(data_, data_ + ndata_len, bp, buf_len)) {
|
|
|
|
isc_throw(BadValue, "serialize would break the source sequence");
|
|
|
|
}
|
|
|
|
|
2012-07-20 18:30:32 -07:00
|
|
|
*bp++ = offsets_len;
|
|
|
|
for (size_t i = 0; i < offsets_len; ++i) {
|
|
|
|
*bp++ = offsets_[first_label_ + i] - offsets_[first_label_];
|
|
|
|
}
|
2012-07-29 05:02:49 +00:00
|
|
|
std::memcpy(bp, &data_[offsets_[first_label_]], ndata_len);
|
2012-07-20 18:30:32 -07:00
|
|
|
bp += ndata_len;
|
|
|
|
|
2025-03-11 16:44:24 +01:00
|
|
|
isc_throw_assert(bp - reinterpret_cast<const uint8_t*>(buf) ==
|
2025-03-12 11:00:47 +01:00
|
|
|
static_cast<ssize_t>(expected_size));
|
2012-07-20 18:30:32 -07: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
|
|
|
}
|
|
|
|
|
2012-06-25 03:36:44 +05:30
|
|
|
NameComparisonResult
|
|
|
|
LabelSequence::compare(const LabelSequence& other,
|
2024-03-01 20:37:15 +02:00
|
|
|
bool case_sensitive) const {
|
2012-07-05 17:53:43 +02:00
|
|
|
// Determine the relative ordering under the DNSSEC order relation of
|
|
|
|
// 'this' and 'other', and also determine the hierarchical relationship
|
2012-07-20 14:39:41 -07:00
|
|
|
// of the labels.
|
2012-07-05 17:53:43 +02:00
|
|
|
|
|
|
|
unsigned int nlabels = 0;
|
2012-07-20 15:09:35 -07:00
|
|
|
int l1 = getLabelCount();
|
|
|
|
int l2 = other.getLabelCount();
|
2012-07-20 00:58:05 -07:00
|
|
|
const int ldiff = static_cast<int>(l1) - static_cast<int>(l2);
|
2012-07-05 17:53:43 +02:00
|
|
|
unsigned int l = (ldiff < 0) ? l1 : l2;
|
|
|
|
|
|
|
|
while (l > 0) {
|
|
|
|
--l;
|
|
|
|
--l1;
|
|
|
|
--l2;
|
|
|
|
size_t pos1 = offsets_[l1 + first_label_];
|
|
|
|
size_t pos2 = other.offsets_[l2 + other.first_label_];
|
|
|
|
unsigned int count1 = data_[pos1++];
|
|
|
|
unsigned int count2 = other.data_[pos2++];
|
|
|
|
|
|
|
|
// We don't support any extended label types including now-obsolete
|
|
|
|
// bitstring labels.
|
2019-07-12 07:01:01 -04:00
|
|
|
isc_throw_assert(count1 <= Name::MAX_LABELLEN && count2 <= Name::MAX_LABELLEN);
|
2012-07-05 17:53:43 +02:00
|
|
|
|
2012-07-20 00:58:05 -07:00
|
|
|
const int cdiff = static_cast<int>(count1) - static_cast<int>(count2);
|
2012-07-05 17:53:43 +02:00
|
|
|
unsigned int count = (cdiff < 0) ? count1 : count2;
|
|
|
|
|
|
|
|
while (count > 0) {
|
2012-07-20 00:58:05 -07:00
|
|
|
const uint8_t label1 = data_[pos1];
|
|
|
|
const uint8_t label2 = other.data_[pos2];
|
2012-07-05 17:53:43 +02:00
|
|
|
int chdiff;
|
|
|
|
|
|
|
|
if (case_sensitive) {
|
2012-07-20 00:58:05 -07:00
|
|
|
chdiff = static_cast<int>(label1) - static_cast<int>(label2);
|
2012-07-05 17:53:43 +02:00
|
|
|
} else {
|
2012-07-20 00:58:05 -07:00
|
|
|
chdiff = static_cast<int>(
|
|
|
|
isc::dns::name::internal::maptolower[label1]) -
|
|
|
|
static_cast<int>(
|
|
|
|
isc::dns::name::internal::maptolower[label2]);
|
2012-07-05 17:53:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (chdiff != 0) {
|
2012-07-20 14:06:38 -07:00
|
|
|
return (NameComparisonResult(
|
|
|
|
chdiff, nlabels,
|
|
|
|
nlabels == 0 ? NameComparisonResult::NONE :
|
|
|
|
NameComparisonResult::COMMONANCESTOR));
|
2012-07-05 17:53:43 +02:00
|
|
|
}
|
|
|
|
--count;
|
|
|
|
++pos1;
|
|
|
|
++pos2;
|
|
|
|
}
|
|
|
|
if (cdiff != 0) {
|
2012-07-20 12:26:32 -07:00
|
|
|
return (NameComparisonResult(
|
|
|
|
cdiff, nlabels,
|
|
|
|
nlabels == 0 ? NameComparisonResult::NONE :
|
|
|
|
NameComparisonResult::COMMONANCESTOR));
|
2012-07-05 17:53:43 +02:00
|
|
|
}
|
|
|
|
++nlabels;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ldiff < 0) {
|
|
|
|
return (NameComparisonResult(ldiff, nlabels,
|
|
|
|
NameComparisonResult::SUPERDOMAIN));
|
|
|
|
} else if (ldiff > 0) {
|
|
|
|
return (NameComparisonResult(ldiff, nlabels,
|
|
|
|
NameComparisonResult::SUBDOMAIN));
|
|
|
|
}
|
|
|
|
|
|
|
|
return (NameComparisonResult(ldiff, nlabels, NameComparisonResult::EQUAL));
|
2012-06-25 03:36:44 +05:30
|
|
|
}
|
|
|
|
|
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-07-20 15:09:35 -07:00
|
|
|
return (data_[offsets_[last_label_]] == 0);
|
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);
|
|
|
|
}
|
|
|
|
|
2018-07-20 11:21:23 -04:00
|
|
|
std::string
|
|
|
|
LabelSequence::toRawText(bool omit_final_dot) const {
|
|
|
|
const uint8_t* np = &data_[offsets_[first_label_]];
|
|
|
|
const uint8_t* np_end = np + getDataLength();
|
|
|
|
|
|
|
|
// use for integrity check
|
|
|
|
unsigned int labels = getLabelCount();
|
|
|
|
// 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
|
|
|
|
// label sequence data. reserve that length to minimize reallocation.
|
|
|
|
std::string result;
|
|
|
|
result.reserve(getDataLength());
|
|
|
|
|
|
|
|
while (np != np_end) {
|
|
|
|
labels--;
|
|
|
|
count = *np++;
|
|
|
|
|
|
|
|
if (count == 0) {
|
|
|
|
// 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()) {
|
|
|
|
result.push_back('.');
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count <= Name::MAX_LABELLEN) {
|
2019-07-12 07:01:01 -04:00
|
|
|
isc_throw_assert(np_end - np >= count);
|
2018-07-20 11:21:23 -04:00
|
|
|
|
|
|
|
if (!result.empty()) {
|
|
|
|
// just after a non-empty label. add a separating dot.
|
|
|
|
result.push_back('.');
|
|
|
|
}
|
|
|
|
|
|
|
|
while (count-- > 0) {
|
|
|
|
const uint8_t c = *np++;
|
|
|
|
result.push_back(c);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
isc_throw(BadLabelType, "unknown label type in name data");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// We should be at the end of the data and have consumed all labels.
|
2019-07-12 07:01:01 -04:00
|
|
|
isc_throw_assert(np == np_end);
|
|
|
|
isc_throw_assert(labels == 0);
|
2018-07-20 11:21:23 -04:00
|
|
|
|
|
|
|
return (result);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-07-02 06:17:49 +05:30
|
|
|
std::string
|
|
|
|
LabelSequence::toText(bool omit_final_dot) const {
|
2012-07-05 17:53:43 +02:00
|
|
|
const uint8_t* np = &data_[offsets_[first_label_]];
|
|
|
|
const uint8_t* np_end = np + getDataLength();
|
|
|
|
|
2012-07-02 12:10:56 -07:00
|
|
|
// use for integrity check
|
2012-07-20 15:09:35 -07:00
|
|
|
unsigned int labels = getLabelCount();
|
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
|
2012-07-05 11:08:41 +05:30
|
|
|
// label sequence data. reserve that length to minimize reallocation.
|
2012-07-02 06:17:49 +05:30
|
|
|
std::string result;
|
2012-07-05 11:08:41 +05:30
|
|
|
result.reserve(getDataLength());
|
2012-07-02 06:17:49 +05:30
|
|
|
|
|
|
|
while (np != np_end) {
|
|
|
|
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) {
|
2019-07-12 07:01:01 -04:00
|
|
|
isc_throw_assert(np_end - np >= count);
|
2012-07-02 06:17:49 +05:30
|
|
|
|
|
|
|
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");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-05 11:08:41 +05:30
|
|
|
// We should be at the end of the data and have consumed all labels.
|
2019-07-12 07:01:01 -04:00
|
|
|
isc_throw_assert(np == np_end);
|
|
|
|
isc_throw_assert(labels == 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-07-25 15:29:01 +02:00
|
|
|
void
|
|
|
|
LabelSequence::extend(const LabelSequence& labels,
|
2024-03-01 20:37:15 +02:00
|
|
|
uint8_t buf[MAX_SERIALIZED_LENGTH]) {
|
2012-07-25 18:05:02 +02:00
|
|
|
// collect data to perform steps before anything is changed
|
|
|
|
size_t label_count = last_label_ + 1;
|
|
|
|
// Since we may have been stripped, do not use getDataLength(), but
|
2012-07-25 18:15:51 +02:00
|
|
|
// calculate actual data size this labelsequence currently uses
|
2012-07-25 18:05:02 +02:00
|
|
|
size_t data_pos = offsets_[last_label_] + data_[offsets_[last_label_]] + 1;
|
|
|
|
|
|
|
|
// If this labelsequence is absolute, virtually strip the root label.
|
2012-07-27 16:18:26 +02:00
|
|
|
if (isAbsolute()) {
|
2012-07-25 18:05:02 +02:00
|
|
|
data_pos--;
|
|
|
|
label_count--;
|
|
|
|
}
|
2012-07-27 16:18:26 +02:00
|
|
|
const size_t append_label_count = labels.getLabelCount();
|
2012-07-25 18:05:02 +02:00
|
|
|
size_t data_len;
|
|
|
|
const uint8_t *data = labels.getData(&data_len);
|
|
|
|
|
|
|
|
// Sanity checks
|
2012-07-25 15:29:01 +02:00
|
|
|
if (data_ != buf || offsets_ != &buf[Name::MAX_WIRE]) {
|
|
|
|
isc_throw(BadValue,
|
|
|
|
"extend() called with unrelated buffer");
|
|
|
|
}
|
2015-06-13 13:26:04 +02:00
|
|
|
// Check MAX_LABELS before MAX_WIRE or it will be never reached
|
2012-07-25 18:05:02 +02:00
|
|
|
if (label_count + append_label_count > Name::MAX_LABELS) {
|
2012-07-25 15:29:01 +02:00
|
|
|
isc_throw(BadValue,
|
|
|
|
"extend() would exceed maximum number of labels");
|
|
|
|
}
|
2015-06-13 13:26:04 +02:00
|
|
|
if (data_pos + data_len > Name::MAX_WIRE) {
|
|
|
|
isc_throw(BadValue,
|
|
|
|
"extend() would exceed maximum wire length");
|
|
|
|
}
|
2012-07-25 15:29:01 +02:00
|
|
|
|
2012-07-25 18:05:02 +02:00
|
|
|
// All seems to be reasonably ok, let's proceed.
|
2012-07-30 14:07:41 +02:00
|
|
|
std::memmove(&buf[data_pos], data, data_len);
|
2012-07-25 15:29:01 +02:00
|
|
|
|
2012-07-25 18:05:02 +02:00
|
|
|
for (size_t i = 0; i < append_label_count; ++i) {
|
|
|
|
buf[Name::MAX_WIRE + label_count + i] =
|
2012-07-30 14:07:41 +02:00
|
|
|
data_pos +
|
2012-07-25 18:15:51 +02:00
|
|
|
labels.offsets_[i + labels.first_label_] -
|
|
|
|
labels.offsets_[labels.first_label_];
|
2012-07-25 15:29:01 +02:00
|
|
|
}
|
2012-07-25 18:05:02 +02:00
|
|
|
last_label_ = label_count + append_label_count - 1;
|
2012-07-25 15:29:01 +02:00
|
|
|
}
|
|
|
|
|
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
|