1
0
mirror of https://github.com/mfontanini/libtins synced 2026-01-23 02:35:57 +01:00

Use actual payload length to construct inner PDU. (#179)

Fixes #178
This commit is contained in:
Ed Catmur
2017-01-16 17:36:33 +00:00
committed by Matias Fontanini
parent d5cba00ce0
commit 9051197603
3 changed files with 59 additions and 6 deletions

View File

@@ -89,6 +89,15 @@ public:
NO_NEXT_HEADER = 59
};
/**
* The values used to identify Hop-By-Hop Options and Destination Options.
*/
enum OptionType {
PAD_1 = 0,
PAD_N = 1,
JUMBO_PAYLOAD = 0xC2,
};
/**
* \brief Extracts metadata for this protocol based on the buffer provided
*

View File

@@ -82,6 +82,7 @@ IPv6::IPv6(const uint8_t* buffer, uint32_t total_sz)
InputMemoryStream stream(buffer, total_sz);
stream.read(header_);
uint8_t current_header = header_.next_header;
uint32_t actual_payload_length = payload_length();
bool is_payload_fragmented = false;
while (stream) {
if (is_extension_header(current_header)) {
@@ -93,24 +94,47 @@ IPv6::IPv6(const uint8_t* buffer, uint32_t total_sz)
// minus one, from the next_header field.
const uint32_t ext_size = (static_cast<uint32_t>(stream.read<uint8_t>()) + 1) * 8;
const uint32_t payload_size = ext_size - sizeof(uint8_t) * 2;
if (!stream.can_read(ext_size)) {
if (!stream.can_read(payload_size)) {
throw malformed_packet();
}
// minus one, from the size field
add_ext_header(ext_header(ext_type, payload_size, stream.pointer()));
if (actual_payload_length == 0u && current_header == HOP_BY_HOP) {
// could be a jumbogram, look for Jumbo Payload Option
InputMemoryStream options(stream.pointer(), payload_size);
while (options) {
const uint8_t opt_type = options.read<uint8_t>();
if (opt_type == PAD_1) {
continue;
}
const uint8_t opt_size = options.read<uint8_t>();
if (opt_type == JUMBO_PAYLOAD) {
if (opt_size != 4) {
throw malformed_packet();
}
actual_payload_length = stream.read_be<uint32_t>();
break;
}
options.skip(opt_size);
}
}
current_header = ext_type;
actual_payload_length -= ext_size;
stream.skip(payload_size);
}
else {
if (!stream.can_read(actual_payload_length)) {
throw malformed_packet();
}
if (is_payload_fragmented) {
inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size()));
inner_pdu(new Tins::RawPDU(stream.pointer(), actual_payload_length));
}
else {
inner_pdu(
Internals::pdu_from_flag(
static_cast<Constants::IP::e>(current_header),
stream.pointer(),
stream.size(),
actual_payload_length,
false
)
);
@@ -119,11 +143,11 @@ IPv6::IPv6(const uint8_t* buffer, uint32_t total_sz)
Internals::allocate<IPv6>(
current_header,
stream.pointer(),
stream.size()
actual_payload_length
)
);
if (!inner_pdu()) {
inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size()));
inner_pdu(new Tins::RawPDU(stream.pointer(), actual_payload_length));
}
}
}

View File

@@ -24,7 +24,8 @@ using namespace Tins;
class IPv6Test : public testing::Test {
public:
static const uint8_t expected_packet1[], expected_packet2[],
hop_by_hop_options[], broken1[];
hop_by_hop_options[], broken1[],
fcs_suffix[];
void test_equals(IPv6& ip1, IPv6& ip2);
};
@@ -61,6 +62,15 @@ const uint8_t IPv6Test::broken1[] = {
0, 0, 0, 0, 0, 0, 0, 251, 17, 0, 11, 80, 53, 98, 2, 81, 72, 50, 10
};
const uint8_t IPv6Test::fcs_suffix[] = {
0x33, 0x33, 0xff, 0x01, 0x31, 0x3e, 0x64, 0x3f, 0x5f, 0x01, 0x31, 0x3e, 0x86, 0xdd, 0x60, 0x00,
0x00, 0x00, 0x00, 0x18, 0x3a, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0xff, 0x01, 0x31, 0x3e, 0x87, 0x00, 0x55, 0x69, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x3f, 0x5f, 0xff, 0xfe, 0x01, 0x31, 0x3e, 0x23, 0x0c,
0x57, 0xb7
};
void IPv6Test::test_equals(IPv6& ip1, IPv6& ip2) {
EXPECT_EQ(ip1.version(), ip2.version());
EXPECT_EQ(ip1.traffic_class(), ip2.traffic_class());
@@ -175,6 +185,16 @@ TEST_F(IPv6Test, Broken1) {
);
}
TEST_F(IPv6Test, FCSSuffix) {
EthernetII pkt(fcs_suffix, sizeof(fcs_suffix));
EXPECT_EQ(pkt.rfind_pdu<IPv6>().payload_length(), 24u);
EXPECT_EQ(pkt.rfind_pdu<ICMPv6>().size(), 24u);
EXPECT_EQ(
PDU::serialization_type(fcs_suffix, fcs_suffix + pkt.size()),
pkt.serialize()
);
}
TEST_F(IPv6Test, Version) {
IPv6 ipv6;
ipv6.version(3);