2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-08-30 21:45:37 +00:00

[#939] Adding more unit tests

Also removing OutOfRange check from OptionOpaqueDataTuples#unpack(begin, end).
Also updating AUTHORS and the ChangeLog.
This commit is contained in:
Piotrek Zadroga
2023-03-22 13:07:23 +01:00
parent 2292c88781
commit b1137ad6d7
5 changed files with 246 additions and 12 deletions

View File

@@ -31,7 +31,7 @@ Primary developers:
- Slawek Figiel (documentation)
- Dan Theisen (documentation, option handling, shell scripts)
- Marcin Godzina (documentation, release engineering, testing)
- Piotrek Zadroga (documentation)
- Piotrek Zadroga (documentation, options handling)
Former developers who are no longer active:
- Stephen Morris (Hooks, MySQL)

View File

@@ -1,3 +1,8 @@
2116. [func] piotrek
Added support of Secure Zero Touch Provisioning options as per
RFC8572. Kea can now handle DHCPv4 Option code #143 and DHCPv6
Option code #136.
2115. [func] tmark
Added the parameter, offer-lifetime, to kea-dhcp4. When
greater than zero, the server temporarily allocates and

View File

@@ -55,10 +55,9 @@ OptionOpaqueDataTuples::pack(isc::util::OutputBuffer& buf, bool check) const {
void
OptionOpaqueDataTuples::unpack(OptionBufferConstIter begin,
OptionBufferConstIter end) {
if (std::distance(begin, end) < getMinimalLength() - getHeaderLen()) {
isc_throw(OutOfRange, "parsed data tuples option data truncated to"
" size " << std::distance(begin, end));
}
// We are skipping typical OutOfRange check for Option#unpack(begin, end),
// since empty collection of tuples is also a valid case where
// std::distance(begin, end) = 0
// Start reading opaque data.
size_t offset = 0;

View File

@@ -149,13 +149,6 @@ private:
/// @brief length of the field which holds he size of the tuple.
OpaqueDataTuple::LengthFieldType length_field_type_;
/// @brief Returns minimal length of the option for the given universe.
/// Currently this class is only used for a DHCPv6 option it may be expanded
/// for DHCPv4 in the future.
uint16_t getMinimalLength() const {
return (4);
}
/// @brief Collection of opaque data tuples carried by the option.
TuplesCollection tuples_;

View File

@@ -17,6 +17,16 @@ using namespace isc::util;
namespace {
// This test checks that the DHCPv4 option constructor sets the default
// properties to the expected values.
TEST(OptionOpaqueDataTuples, constructor4) {
OptionOpaqueDataTuples data_tuple(Option::V4, 200);
// Option length is 1 byte for option code + 1 byte for option size
EXPECT_EQ(2, data_tuple.len());
// There should be no tuples.
EXPECT_EQ(0, data_tuple.getTuplesNum());
}
// This test checks that the DHCPv6 option constructor sets the default
// properties to the expected values.
TEST(OptionOpaqueDataTuples, constructor6) {
@@ -98,6 +108,23 @@ TEST(OptionOpaqueDataTuples, setTuple) {
EXPECT_THROW(data_tuple.setTuple(2, tuple), isc::OutOfRange);
}
// Check that the returned length of the DHCPv4 option is correct.
TEST(OptionOpaqueDataTuples, len4) {
OptionOpaqueDataTuples data_tuple(Option::V4, 200);
ASSERT_EQ(2, data_tuple.len());
// Add first tuple.
OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE);
tuple = "xyz";
ASSERT_NO_THROW(data_tuple.addTuple(tuple));
// The total length grows by 1 byte of the length field and 3 bytes
// consumed by 'xyz'.
EXPECT_EQ(6, data_tuple.len());
// Add another tuple and check that the total size gets increased.
tuple = "abc";
data_tuple.addTuple(tuple);
EXPECT_EQ(10, data_tuple.len());
}
// Check that the returned length of the DHCPv4 option is correct when
// LTF is passed explicitly in constructor.
TEST(OptionOpaqueDataTuples, len4_constructor_with_ltf) {
@@ -134,6 +161,71 @@ TEST(OptionOpaqueDataTuples, len6) {
EXPECT_EQ(14, data_tuple.len());
}
// Check that the DHCPv4 option is rendered to the buffer in wire format.
TEST(OptionOpaqueDataTuples, pack4) {
OptionOpaqueDataTuples data_tuple(Option::V4, 200);
ASSERT_EQ(0, data_tuple.getTuplesNum());
// Add tuple.
OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_1_BYTE);
tuple = "Hello world";
data_tuple.addTuple(tuple);
// And add another tuple so as resulting option is a bit more complex.
tuple = "foo";
data_tuple.addTuple(tuple);
// Render the data to the buffer.
OutputBuffer buf(10);
ASSERT_NO_THROW(data_tuple.pack(buf));
ASSERT_EQ(18, buf.getLength());
// Prepare reference data.
const uint8_t ref[] = {
0xC8, 0x10, // option 200, length 16
0x0B, // tuple length is 11
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space>
0x77, 0x6F, 0x72, 0x6C, 0x64, // world
0x03, // tuple length is 3
0x66, 0x6F, 0x6F // foo
};
// Compare the buffer with reference data.
EXPECT_EQ(0, memcmp(static_cast<const void*>(ref),
static_cast<const void*>(buf.getData()),
buf.getLength()));
}
// Check that the DHCPv4 option is rendered to the buffer in wire format,
// when tuple's length field is coded on 2 octets.
TEST(OptionOpaqueDataTuples, pack4_with_ltf) {
OptionOpaqueDataTuples data_tuple(Option::V4, 143, OpaqueDataTuple::LENGTH_2_BYTES);
ASSERT_EQ(0, data_tuple.getTuplesNum());
// Add tuple.
OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
tuple = "Hello world";
data_tuple.addTuple(tuple);
// And add another tuple so as resulting option is a bit more complex.
tuple = "foo";
data_tuple.addTuple(tuple);
// Render the data to the buffer.
OutputBuffer buf(10);
ASSERT_NO_THROW(data_tuple.pack(buf));
ASSERT_EQ(20, buf.getLength());
// Prepare reference data.
const uint8_t ref[] = {
0x8F, 0x12, // option 143, length 18
0x00, 0x0B, // tuple length is 11
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space>
0x77, 0x6F, 0x72, 0x6C, 0x64, // world
0x00, 0x03, // tuple length is 3
0x66, 0x6F, 0x6F // foo
};
// Compare the buffer with reference data.
EXPECT_EQ(0, memcmp(static_cast<const void*>(ref),
static_cast<const void*>(buf.getData()),
buf.getLength()));
}
// Check that the DHCPv6 option is rendered to the buffer in wire format.
TEST(OptionOpaqueDataTuples, pack6) {
OptionOpaqueDataTuples data_tuple(Option::V6, 60);
@@ -166,6 +258,33 @@ TEST(OptionOpaqueDataTuples, pack6) {
buf.getLength()));
}
// This function checks that the DHCPv4 option with two opaque data tuples
// is parsed correctly.
TEST(OptionOpaqueDataTuples, unpack4) {
// Prepare data to decode.
const uint8_t buf_data[] = {
0x0B, // tuple length is 11
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space>
0x77, 0x6F, 0x72, 0x6C, 0x64, // world
0x03, // tuple length is 3
0x66, 0x6F, 0x6F // foo
};
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
OptionOpaqueDataTuplesPtr data_tuple;
ASSERT_NO_THROW(
data_tuple = OptionOpaqueDataTuplesPtr(
new OptionOpaqueDataTuples(Option::V4,
143,
buf.begin(),
buf.end()));
);
EXPECT_EQ(DHO_V4_SZTP_REDIRECT, data_tuple->getType());
ASSERT_EQ(2, data_tuple->getTuplesNum());
EXPECT_EQ("Hello world", data_tuple->getTuple(0).getText());
EXPECT_EQ("foo", data_tuple->getTuple(1).getText());
}
// This function checks that the DHCPv4 option with two opaque data tuples
// is parsed correctly. Tuple's LTF is passed explicitly in constructor.
TEST(OptionOpaqueDataTuples, unpack4_constructor_with_ltf) {
@@ -220,6 +339,46 @@ TEST(OptionOpaqueDataTuples, unpack6) {
EXPECT_EQ("foo", data_tuple->getTuple(1).getText());
}
// This test checks that the DHCPv4 option with opaque data of size 0
// is correctly parsed.
TEST(OptionOpaqueDataTuples, unpack4EmptyTuple) {
// Prepare data to decode.
const uint8_t buf_data[] = {0x00}; // tuple length is 0
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
OptionOpaqueDataTuplesPtr data_tuple;
ASSERT_NO_THROW(
data_tuple = OptionOpaqueDataTuplesPtr(new OptionOpaqueDataTuples(Option::V4,
124,
buf.begin(),
buf.end()));
);
EXPECT_EQ(DHO_VIVCO_SUBOPTIONS, data_tuple->getType());
ASSERT_EQ(1, data_tuple->getTuplesNum());
EXPECT_TRUE(data_tuple->getTuple(0).getText().empty());
}
// This test checks that the DHCPv4 option with opaque data of size 0
// is correctly parsed. Tuple's LTF is passed explicitly in constructor.
TEST(OptionOpaqueDataTuples, unpack4EmptyTuple_constructor_with_ltf) {
// Prepare data to decode.
const uint8_t buf_data[] = {0x00, 0x00}; // tuple length is 0
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
OptionOpaqueDataTuplesPtr data_tuple;
ASSERT_NO_THROW(
data_tuple = OptionOpaqueDataTuplesPtr(
new OptionOpaqueDataTuples(Option::V4,
143,
buf.begin(),
buf.end(),
OpaqueDataTuple::LENGTH_2_BYTES));
);
EXPECT_EQ(DHO_V4_SZTP_REDIRECT, data_tuple->getType());
ASSERT_EQ(1, data_tuple->getTuplesNum());
EXPECT_TRUE(data_tuple->getTuple(0).getText().empty());
}
// This test checks that the DHCPv6 option with opaque data of size 0
// is correctly parsed.
TEST(OptionOpaqueDataTuples, unpack6EmptyTuple) {
@@ -239,6 +398,39 @@ TEST(OptionOpaqueDataTuples, unpack6EmptyTuple) {
EXPECT_TRUE(data_tuple->getTuple(0).getText().empty());
}
// This test checks that exception is thrown when parsing truncated DHCPv4 option
TEST(OptionOpaqueDataTuples, unpack4Truncated) {
// Prepare data to decode.
const uint8_t buf_data[] = {
0x0B, // tuple length is 11
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space>
0x77, 0x6F, 0x72, 0x6C // worl (truncated d!)
};
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
EXPECT_THROW(OptionOpaqueDataTuples (Option::V4, 200, buf.begin(), buf.end()),
isc::dhcp::OpaqueDataTupleError);
}
// This test checks that exception is thrown when parsing truncated DHCPv4 option,
// when tuple's length field is coded on 2 octets.
TEST(OptionOpaqueDataTuples, unpack4Truncated_with_ltf) {
// Prepare data to decode.
const uint8_t buf_data[] = {
0x00, 0x0B, // tuple length is 11
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space>
0x77, 0x6F, 0x72, 0x6C // worl (truncated d!)
};
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
EXPECT_THROW(OptionOpaqueDataTuples (Option::V4,
143,
buf.begin(),
buf.end(),
OpaqueDataTuple::LENGTH_2_BYTES),
isc::dhcp::OpaqueDataTupleError);
}
// This test checks that exception is thrown when parsing truncated DHCPv6
// bootfile-param option
TEST(OptionOpaqueDataTuples, unpack6Truncated) {
@@ -254,6 +446,27 @@ TEST(OptionOpaqueDataTuples, unpack6Truncated) {
isc::dhcp::OpaqueDataTupleError);
}
// This test checks that the DHCPv4 option containing no opaque
// data is parsed correctly.
TEST(OptionOpaqueDataTuples, unpack4NoTuple) {
// Prepare data to decode.
const uint8_t buf_data[] = {
};
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
OptionOpaqueDataTuplesPtr data_tuple;
ASSERT_NO_THROW(
data_tuple = OptionOpaqueDataTuplesPtr(
new OptionOpaqueDataTuples(Option::V4,
143,
buf.begin(),
buf.end(),
OpaqueDataTuple::LENGTH_2_BYTES));
);
EXPECT_EQ(DHO_V4_SZTP_REDIRECT, data_tuple->getType());
EXPECT_EQ(0, data_tuple->getTuplesNum());
}
// This test checks that the DHCPv6 bootfile-param option containing no opaque
// data is parsed correctly.
TEST(OptionOpaqueDataTuples, unpack6NoTuple) {
@@ -273,6 +486,30 @@ TEST(OptionOpaqueDataTuples, unpack6NoTuple) {
EXPECT_EQ(0, data_tuple->getTuplesNum());
}
// Verifies correctness of the text representation of the DHCPv4 option.
TEST(OptionOpaqueDataTuples, toText4) {
OptionOpaqueDataTuples data_tuple(Option::V4, 143, OpaqueDataTuple::LENGTH_2_BYTES);
ASSERT_EQ(0, data_tuple.getTuplesNum());
// Lets add a tuple
OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
tuple = "Hello world";
data_tuple.addTuple(tuple);
// And add another tuple so as resulting option is a bit more complex.
tuple = "foo";
data_tuple.addTuple(tuple);
// Check that the text representation of the option is as expected.
EXPECT_EQ("type=143, len=18,"
" data-len0=11, data0='Hello world',"
" data-len1=3, data1='foo'",
data_tuple.toText());
// Check that indentation works.
EXPECT_EQ(" type=143, len=18,"
" data-len0=11, data0='Hello world',"
" data-len1=3, data1='foo'",
data_tuple.toText(2));
}
// Verifies correctness of the text representation of the DHCPv6 option.
TEST(OptionOpaqueDataTuples, toText6) {
OptionOpaqueDataTuples data_tuple(Option::V6, 60);