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

[#1860] unit tests for lenient option parsing

This commit is contained in:
Andrei Pavel
2021-05-17 12:39:32 +03:00
parent 5e94de9ed2
commit 4a491f693c
2 changed files with 170 additions and 8 deletions

View File

@@ -5,9 +5,12 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
#include <dhcp/opaque_data_tuple.h>
#include <util/buffer.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <sstream>
#include <vector>
@@ -18,6 +21,20 @@ using namespace isc::util;
namespace {
struct OpaqueDataTupleLenientParsing : ::testing::Test {
OpaqueDataTupleLenientParsing() : previous_(Option::lenient_parsing_) {
// Enable lenient parsing.
Option::lenient_parsing_ = true;
}
~OpaqueDataTupleLenientParsing() {
// Restore.
Option::lenient_parsing_ = previous_;
}
bool previous_;
};
// This test checks that when the default constructor is called, the data buffer
// is empty.
TEST(OpaqueDataTuple, constructor) {
@@ -42,7 +59,6 @@ TEST(OpaqueDataTuple, constructorParse1Byte) {
EXPECT_EQ(11, tuple.getLength());
EXPECT_EQ("Hello world", tuple.getText());
}
// Test that the constructor which takes the buffer as argument parses the
@@ -59,7 +75,6 @@ TEST(OpaqueDataTuple, constructorParse2Bytes) {
EXPECT_EQ(11, tuple.getLength());
EXPECT_EQ("Hello world", tuple.getText());
}
@@ -225,7 +240,6 @@ TEST(OpaqueDataTuple, operatorOutputStream) {
EXPECT_NO_THROW(tuple = " and some other text");
EXPECT_NO_THROW(s << tuple);
EXPECT_EQ(s.str(), "Some text and some other text");
}
// This test verifies that the value of the tuple can be initialized from the
@@ -457,7 +471,7 @@ TEST(OpaqueDataTuple, unpack2ByteEmptyBuffer) {
EXPECT_THROW(tuple.unpack(wire_data, wire_data), OpaqueDataTupleError);
}
// This test verifies that exception if thrown when parsing truncated buffer.
// This test verifies that exception is thrown when parsing truncated buffer.
TEST(OpaqueDataTuple, unpack2ByteTruncatedBuffer) {
OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
// Specify the data with the length of 10, but limit the buffer size to
@@ -470,5 +484,15 @@ TEST(OpaqueDataTuple, unpack2ByteTruncatedBuffer) {
OpaqueDataTupleError);
}
// Test that an exception is not thrown when parsing in lenient mode.
TEST_F(OpaqueDataTupleLenientParsing, unpack) {
OpaqueDataTuple tuple(OpaqueDataTuple::LENGTH_2_BYTES);
// Specify the data with the length of 10, but limit the buffer size to 2.
const char wire_data[] = {
0, 10, 2, 3
};
EXPECT_NO_THROW(tuple.unpack(wire_data, wire_data + sizeof(wire_data)));
EXPECT_EQ(tuple.getData(), OpaqueDataTuple::Buffer({2, 3}));
}
} // anonymous namespace

View File

@@ -9,6 +9,7 @@
#include <exceptions/exceptions.h>
#include <dhcp/option_vendor_class.h>
#include <util/buffer.h>
#include <gtest/gtest.h>
using namespace isc;
@@ -17,6 +18,20 @@ using namespace isc::util;
namespace {
struct OptionVendorClassLenientParsing : ::testing::Test {
OptionVendorClassLenientParsing() : previous_(Option::lenient_parsing_) {
// Enable lenient parsing.
Option::lenient_parsing_ = true;
}
~OptionVendorClassLenientParsing() {
// Restore.
Option::lenient_parsing_ = previous_;
}
bool previous_;
};
// This test checks that the DHCPv4 option constructor sets the default
// properties to the expected values. This constructor should add an
// empty opaque data tuple (it is essentially the same as adding a 1-byte
@@ -248,7 +263,7 @@ TEST(OptionVendorClass, unpack4) {
EXPECT_EQ("foo", vendor_class->getTuple(1).getText());
}
// This function checks that the DHCPv4 option with two opaque data tuples
// This function checks that the DHCPv6 option with two opaque data tuples
// is parsed correctly.
TEST(OptionVendorClass, unpack6) {
// Prepare data to decode.
@@ -276,7 +291,7 @@ TEST(OptionVendorClass, unpack6) {
}
// This test checks that the DHCPv4 option with opaque data of size 0
// This test checks that the DHCPv6 option with opaque data of size 0
// is correctly parsed.
TEST(OptionVendorClass, unpack4EmptyTuple) {
// Prepare data to decode.
@@ -418,7 +433,7 @@ TEST(OptionVendorClass, toText4) {
vendor_class.toText(3));
}
// Verifies correctness of the text representation of the DHCPv4 option.
// Verifies correctness of the text representation of the DHCPv6 option.
TEST(OptionVendorClass, toText6) {
OptionVendorClass vendor_class(Option::V6, 1234);
ASSERT_EQ(0, vendor_class.getTuplesNum());
@@ -443,5 +458,128 @@ TEST(OptionVendorClass, toText6) {
vendor_class.toText(2));
}
} // end of anonymous namespace
// Test that the DHCPv6 option with truncated or over-extending (depends on
// perspective) buffers is parsed correctly when lenient mode is enabled.
TEST_F(OptionVendorClassLenientParsing, unpack6) {
// Enable lenient parsing.
bool const previous(Option::lenient_parsing_);
Option::lenient_parsing_ = true;
// Prepare data to decode.
const uint8_t buf_data[] = {
0, 0, 0x4, 0xD2, // enterprise id 1234
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
};
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
OptionVendorClassPtr vendor_class;
ASSERT_NO_THROW(
vendor_class = OptionVendorClassPtr(
new OptionVendorClass(Option::V6, buf.begin(), buf.end())););
EXPECT_EQ(D6O_VENDOR_CLASS, vendor_class->getType());
EXPECT_EQ(1234, vendor_class->getVendorId());
ASSERT_EQ(2, vendor_class->getTuplesNum());
EXPECT_EQ("Hello world", vendor_class->getTuple(0).getText());
EXPECT_EQ("foo", vendor_class->getTuple(1).getText());
// Restore.
Option::lenient_parsing_ = previous;
}
// Test that the DHCPv6 option with truncated or over-extending (depends on
// perspective) buffers is parsed correctly when lenient mode is enabled.
TEST_F(OptionVendorClassLenientParsing, unpack6FirstLengthIsBad) {
// Prepare data to decode.
const uint8_t buf_data[] = {
0, 0, 0x4, 0xD2, // enterprise id 1234
0x00, 0x0C, // tuple length is 12 (should be 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
};
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
OptionVendorClassPtr vendor_class;
ASSERT_NO_THROW(
vendor_class = OptionVendorClassPtr(
new OptionVendorClass(Option::V6, buf.begin(), buf.end())););
EXPECT_EQ(D6O_VENDOR_CLASS, vendor_class->getType());
EXPECT_EQ(1234, vendor_class->getVendorId());
ASSERT_EQ(2, vendor_class->getTuplesNum());
// The first value will have one extra byte.
EXPECT_EQ(std::string("Hello world") + '\0',
vendor_class->getTuple(0).getText());
// The length would have internally been interpreted as {0x03, 0x66} == 870,
// but the parser would have stopped at the end of the option, so the second
// value should be "oo".
EXPECT_EQ("oo", vendor_class->getTuple(1).getText());
}
// Test that the DHCPv6 option with truncated or over-extending (depends on
// perspective) buffers is parsed correctly when lenient mode is enabled.
TEST_F(OptionVendorClassLenientParsing, unpack6SecondLengthIsBad) {
// Prepare data to decode.
const uint8_t buf_data[] = {
0, 0, 0x4, 0xD2, // enterprise id 1234
0x00, 0x0B, // tuple length is 11
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space>
0x77, 0x6F, 0x72, 0x6C, 0x64, // world
0x00, 0x04, // tuple length is 4 (should be 3)
0x66, 0x6F, 0x6F // foo
};
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
OptionVendorClassPtr vendor_class;
ASSERT_NO_THROW(
vendor_class = OptionVendorClassPtr(
new OptionVendorClass(Option::V6, buf.begin(), buf.end())););
EXPECT_EQ(D6O_VENDOR_CLASS, vendor_class->getType());
EXPECT_EQ(1234, vendor_class->getVendorId());
ASSERT_EQ(2, vendor_class->getTuplesNum());
EXPECT_EQ("Hello world", vendor_class->getTuple(0).getText());
// The length would have internally been interpreted as {0x00, 0x04} == 4,
// but the parser would have stopped at the end of the option, so the second
// value should be "foo" just like normal.
EXPECT_EQ("foo", vendor_class->getTuple(1).getText());
}
// Test that the DHCPv6 option with truncated or over-extending (depends on
// perspective) buffers is parsed correctly when lenient mode is enabled.
TEST_F(OptionVendorClassLenientParsing, unpack6BothLengthsAreBad) {
// Prepare data to decode.
const uint8_t buf_data[] = {
0, 0, 0x4, 0xD2, // enterprise id 1234
0x00, 0x0C, // tuple length is 12 (should be 11)
0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x20, // Hello<space>
0x77, 0x6F, 0x72, 0x6C, 0x64, // world
0x00, 0x04, // tuple length is 4 (should be 3)
0x66, 0x6F, 0x6F // foo
};
OptionBuffer buf(buf_data, buf_data + sizeof(buf_data));
OptionVendorClassPtr vendor_class;
ASSERT_NO_THROW(
vendor_class = OptionVendorClassPtr(
new OptionVendorClass(Option::V6, buf.begin(), buf.end())););
EXPECT_EQ(D6O_VENDOR_CLASS, vendor_class->getType());
EXPECT_EQ(1234, vendor_class->getVendorId());
ASSERT_EQ(2, vendor_class->getTuplesNum());
// The first value will have one extra byte.
EXPECT_EQ(std::string("Hello world") + '\0',
vendor_class->getTuple(0).getText());
// The length would have internally been interpreted as {0x04, 0x66} == 1126,
// but the parser would have stopped at the end of the option, so the second
// value should be "oo".
EXPECT_EQ("oo", vendor_class->getTuple(1).getText());
}
} // end of anonymous namespace