mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 21:45:37 +00:00
[2491] Added a function to write/read FQDN to/from buffer.
This commit is contained in:
@@ -37,6 +37,7 @@ libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
|
||||
libb10_dhcp___la_CXXFLAGS = $(AM_CXXFLAGS)
|
||||
libb10_dhcp___la_CPPFLAGS = $(AM_CPPFLAGS) $(LOG4CPLUS_INCLUDES)
|
||||
libb10_dhcp___la_LIBADD = $(top_builddir)/src/lib/asiolink/libb10-asiolink.la
|
||||
libb10_dhcp___la_LIBADD += $(top_builddir)/src/lib/dns/libb10-dns++.la
|
||||
libb10_dhcp___la_LIBADD += $(top_builddir)/src/lib/util/libb10-util.la
|
||||
libb10_dhcp___la_LDFLAGS = -no-undefined -version-info 2:0:0
|
||||
|
||||
|
@@ -13,6 +13,8 @@
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <dhcp/option_data_types.h>
|
||||
#include <dns/labelsequence.h>
|
||||
#include <dns/name.h>
|
||||
#include <util/encode/hex.h>
|
||||
|
||||
namespace isc {
|
||||
@@ -206,6 +208,48 @@ OptionDataTypeUtil::writeBool(const bool value,
|
||||
buf.push_back(static_cast<uint8_t>(value ? 1 : 0));
|
||||
}
|
||||
|
||||
std::string
|
||||
OptionDataTypeUtil::readFqdn(const std::vector<uint8_t>& buf) {
|
||||
// If buffer is empty emit an error.
|
||||
if (buf.empty()) {
|
||||
isc_throw(BadDataTypeCast, "unable to read FQDN from a buffer."
|
||||
<< " The buffer is empty");
|
||||
}
|
||||
// Copy the data from a buffer to InputBuffer so as we can use
|
||||
// isc::dns::Name object to get the FQDN. This is not the most
|
||||
// efficient way to do it but currently there is no construtor
|
||||
// in Name that would use std::vector directly.
|
||||
isc::util::InputBuffer in_buf(static_cast<const void*>(&buf[0]), buf.size());
|
||||
try {
|
||||
// Try to create an object from the buffer. If exception is thrown
|
||||
// it means that the buffer doesn't hold a valid domain name (invalid
|
||||
// syntax).
|
||||
isc::dns::Name name(in_buf);
|
||||
return (name.toText());
|
||||
} catch (const isc::Exception& ex) {
|
||||
// Unable to convert the data in the buffer into FQDN.
|
||||
isc_throw(BadDataTypeCast, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
OptionDataTypeUtil::writeFqdn(const std::string& fqdn,
|
||||
std::vector<uint8_t>& buf) {
|
||||
try {
|
||||
isc::dns::Name name(fqdn);
|
||||
isc::dns::LabelSequence labels(name);
|
||||
if (labels.getDataLength() > 0) {
|
||||
buf.resize(buf.size() + labels.getDataLength());
|
||||
size_t read_len = 0;
|
||||
const uint8_t* data = labels.getData(&read_len);
|
||||
memcpy(static_cast<void*>(&buf[buf.size() - labels.getDataLength()]),
|
||||
data, read_len);
|
||||
}
|
||||
} catch (const isc::Exception& ex) {
|
||||
isc_throw(BadDataTypeCast, ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
OptionDataTypeUtil::readString(const std::vector<uint8_t>& buf) {
|
||||
std::string value;
|
||||
|
@@ -332,6 +332,33 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Read FQDN from a buffer as a string value.
|
||||
///
|
||||
/// The format of an FQDN within a buffer complies with RFC1035,
|
||||
/// section 3.1.
|
||||
///
|
||||
/// @param buf input buffer holding a FQDN.
|
||||
///
|
||||
/// @throw BadDataTypeCast if a FQDN stored within a buffer is
|
||||
/// invalid (e.g. empty, contains invalid characters, truncated).
|
||||
/// @return fully qualified domain name in a text form.
|
||||
static std::string readFqdn(const std::vector<uint8_t>& buf);
|
||||
|
||||
/// @brief Append FQDN into a buffer.
|
||||
///
|
||||
/// This method appends the Fully Qualified Domain Name (FQDN)
|
||||
/// represented as string value into a buffer. The format of
|
||||
/// the FQDN being stored into a buffer complies with RFC1035,
|
||||
/// section 3.1.
|
||||
///
|
||||
/// @param fqdn fully qualified domain name to be written.
|
||||
/// @param [out] buf output buffer.
|
||||
///
|
||||
/// @throw isc::dhcp::BadDataTypeCast if provided FQDN
|
||||
/// is invalid.
|
||||
static void writeFqdn(const std::string& fqdn,
|
||||
std::vector<uint8_t>& buf);
|
||||
|
||||
/// @brief Read string value from a buffer.
|
||||
///
|
||||
/// @param buf input buffer.
|
||||
|
@@ -35,6 +35,7 @@ libdhcp___unittests_SOURCES += option6_ia_unittest.cc
|
||||
libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
|
||||
libdhcp___unittests_SOURCES += option6_int_array_unittest.cc
|
||||
libdhcp___unittests_SOURCES += option6_int_unittest.cc
|
||||
libdhcp___unittests_SOURCES += option_data_types_unittest.cc
|
||||
libdhcp___unittests_SOURCES += option_definition_unittest.cc
|
||||
libdhcp___unittests_SOURCES += option_custom_unittest.cc
|
||||
libdhcp___unittests_SOURCES += option_unittest.cc
|
||||
|
144
src/lib/dhcp/tests/option_data_types_unittest.cc
Normal file
144
src/lib/dhcp/tests/option_data_types_unittest.cc
Normal file
@@ -0,0 +1,144 @@
|
||||
// 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 <config.h>
|
||||
#include <dhcp/option_data_types.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
using namespace isc;
|
||||
using namespace isc::dhcp;
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief Test class for option data type utilities.
|
||||
class OptionDataTypesTest : public ::testing::Test {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
OptionDataTypesTest() { }
|
||||
|
||||
};
|
||||
|
||||
// The purpose of this test is to verify that FQDN is read from
|
||||
// a buffer and returned as a text. The representation of the FQDN
|
||||
// in the buffer complies with RFC1035, section 3.1.
|
||||
// This test also checks that if invalid (truncated) FQDN is stored
|
||||
// in a buffer the appropriate exception is returned when trying to
|
||||
// read it as a string.
|
||||
TEST_F(OptionDataTypesTest, readFqdn) {
|
||||
// The binary representation of the "mydomain.example.com".
|
||||
// Values: 8, 7, 3 and 0 specify the lengths of subsequent
|
||||
// labels within the FQDN.
|
||||
const char data[] = {
|
||||
8, 109, 121, 100, 111, 109, 97, 105, 110, // "mydomain"
|
||||
7, 101, 120, 97, 109, 112, 108, 101, // "example"
|
||||
3, 99, 111, 109, // "com"
|
||||
0
|
||||
};
|
||||
|
||||
// Make a vector out of the data.
|
||||
std::vector<uint8_t> buf(data, data + sizeof(data));
|
||||
|
||||
// Read the buffer as FQDN and verify its correctness.
|
||||
std::string fqdn;
|
||||
EXPECT_NO_THROW(fqdn = OptionDataTypeUtil::readFqdn(buf));
|
||||
EXPECT_EQ("mydomain.example.com.", fqdn);
|
||||
|
||||
// By resizing the buffer we simulate truncation. The first
|
||||
// length field (8) indicate that the first label's size is
|
||||
// 8 but the actual buffer size is 5. Expect that conversion
|
||||
// fails.
|
||||
buf.resize(5);
|
||||
EXPECT_THROW(
|
||||
OptionDataTypeUtil::readFqdn(buf),
|
||||
isc::dhcp::BadDataTypeCast
|
||||
);
|
||||
|
||||
// Another special case: provide an empty buffer.
|
||||
buf.clear();
|
||||
EXPECT_THROW(
|
||||
OptionDataTypeUtil::readFqdn(buf),
|
||||
isc::dhcp::BadDataTypeCast
|
||||
);
|
||||
}
|
||||
|
||||
// The purpose of this test is to verify that FQDN's syntax is validated
|
||||
// and that FQDN is correctly written to a buffer in a format described
|
||||
// in RFC1035 section 3.1.
|
||||
TEST_F(OptionDataTypesTest, writeFqdn) {
|
||||
// Create empty buffer. The FQDN will be written to it.
|
||||
OptionBuffer buf;
|
||||
// Write a domain name into the buffer in the format described
|
||||
// in RFC1035 section 3.1. This function should not throw
|
||||
// exception because domain name is well formed.
|
||||
EXPECT_NO_THROW(
|
||||
OptionDataTypeUtil::writeFqdn("mydomain.example.com", buf)
|
||||
);
|
||||
// The length of the data is 22 (8 bytes for "mydomain" label,
|
||||
// 7 bytes for "example" label, 3 bytes for "com" label and
|
||||
// finally 4 bytes positions between labels where length
|
||||
// information is stored.
|
||||
ASSERT_EQ(22, buf.size());
|
||||
|
||||
// Verify that length fields between labels hold valid values.
|
||||
EXPECT_EQ(8, buf[0]); // length of "mydomain"
|
||||
EXPECT_EQ(7, buf[9]); // length of "example"
|
||||
EXPECT_EQ(3, buf[17]); // length of "com"
|
||||
EXPECT_EQ(0, buf[21]); // zero byte at the end.
|
||||
|
||||
// Verify that labels are valid.
|
||||
std::string label0(buf.begin() + 1, buf.begin() + 9);
|
||||
EXPECT_EQ("mydomain", label0);
|
||||
|
||||
std::string label1(buf.begin() + 10, buf.begin() + 17);
|
||||
EXPECT_EQ("example", label1);
|
||||
|
||||
std::string label2(buf.begin() + 18, buf.begin() + 21);
|
||||
EXPECT_EQ("com", label2);
|
||||
|
||||
// The tested function is supposed to append data to a buffer
|
||||
// so let's check that it is a case by appending another domain.
|
||||
OptionDataTypeUtil::writeFqdn("hello.net", buf);
|
||||
|
||||
// The buffer length should be now longer.
|
||||
ASSERT_EQ(33, buf.size());
|
||||
|
||||
// Check the length fields for new labels being appended.
|
||||
EXPECT_EQ(5, buf[22]);
|
||||
EXPECT_EQ(3, buf[28]);
|
||||
|
||||
// And check that labels are ok.
|
||||
std::string label3(buf.begin() + 23, buf.begin() + 28);
|
||||
EXPECT_EQ("hello", label3);
|
||||
|
||||
std::string label4(buf.begin() + 29, buf.begin() + 32);
|
||||
EXPECT_EQ("net", label4);
|
||||
|
||||
// Check that invalid (empty) FQDN is rejected and expected
|
||||
// exception type is thrown.
|
||||
buf.clear();
|
||||
EXPECT_THROW(
|
||||
OptionDataTypeUtil::writeFqdn("", buf),
|
||||
isc::dhcp::BadDataTypeCast
|
||||
);
|
||||
|
||||
// Check another invalid domain name (with repeated dot).
|
||||
buf.clear();
|
||||
EXPECT_THROW(
|
||||
OptionDataTypeUtil::writeFqdn("example..com", buf),
|
||||
isc::dhcp::BadDataTypeCast
|
||||
);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
Reference in New Issue
Block a user