From 905119760331a55d5ce9aa9382edca9af39d194a Mon Sep 17 00:00:00 2001 From: Ed Catmur Date: Mon, 16 Jan 2017 17:36:33 +0000 Subject: [PATCH] Use actual payload length to construct inner PDU. (#179) Fixes #178 --- include/tins/ipv6.h | 9 +++++++++ src/ipv6.cpp | 34 +++++++++++++++++++++++++++++----- tests/src/ipv6_test.cpp | 22 +++++++++++++++++++++- 3 files changed, 59 insertions(+), 6 deletions(-) diff --git a/include/tins/ipv6.h b/include/tins/ipv6.h index fb896ab..7998467 100644 --- a/include/tins/ipv6.h +++ b/include/tins/ipv6.h @@ -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 * diff --git a/src/ipv6.cpp b/src/ipv6.cpp index f5b2e0f..894775e 100644 --- a/src/ipv6.cpp +++ b/src/ipv6.cpp @@ -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(stream.read()) + 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(); + if (opt_type == PAD_1) { + continue; + } + const uint8_t opt_size = options.read(); + if (opt_type == JUMBO_PAYLOAD) { + if (opt_size != 4) { + throw malformed_packet(); + } + actual_payload_length = stream.read_be(); + 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(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( 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)); } } } diff --git a/tests/src/ipv6_test.cpp b/tests/src/ipv6_test.cpp index c02a449..5f0c283 100644 --- a/tests/src/ipv6_test.cpp +++ b/tests/src/ipv6_test.cpp @@ -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().payload_length(), 24u); + EXPECT_EQ(pkt.rfind_pdu().size(), 24u); + EXPECT_EQ( + PDU::serialization_type(fcs_suffix, fcs_suffix + pkt.size()), + pkt.serialize() + ); +} + TEST_F(IPv6Test, Version) { IPv6 ipv6; ipv6.version(3);