diff --git a/src/ipv6.cpp b/src/ipv6.cpp index c710f2c..558ac81 100644 --- a/src/ipv6.cpp +++ b/src/ipv6.cpp @@ -82,8 +82,12 @@ 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; + bool is_payload_fragmented = false; while (stream) { if (is_extension_header(current_header)) { + if (current_header == FRAGMENT) { + is_payload_fragmented = true; + } const uint8_t ext_type = stream.read(); // every ext header is at least 8 bytes long // minus one, from the next_header field. @@ -98,24 +102,29 @@ IPv6::IPv6(const uint8_t* buffer, uint32_t total_sz) stream.skip(payload_size); } else { - inner_pdu( - Internals::pdu_from_flag( - static_cast(current_header), - stream.pointer(), - stream.size(), - false - ) - ); - if (!inner_pdu()) { + if (is_payload_fragmented) { + inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size())); + } + else { inner_pdu( - Internals::allocate( - current_header, + Internals::pdu_from_flag( + static_cast(current_header), stream.pointer(), - stream.size() + stream.size(), + false ) ); if (!inner_pdu()) { - inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size())); + inner_pdu( + Internals::allocate( + current_header, + stream.pointer(), + stream.size() + ) + ); + if (!inner_pdu()) { + inner_pdu(new Tins::RawPDU(stream.pointer(), stream.size())); + } } } // We got to an actual PDU, we're done @@ -219,7 +228,9 @@ void IPv6::write_serialization(uint8_t* buffer, uint32_t total_sz, const PDU* pa Internals::pdu_type_to_id(inner_pdu()->pdu_type()) ); } - set_last_next_header(new_flag); + if (new_flag != 0xff) { + set_last_next_header(new_flag); + } } payload_length(static_cast(total_sz - sizeof(header_))); stream.write(header_); diff --git a/tests/src/ipv6.cpp b/tests/src/ipv6.cpp index 35f9d37..f4782e2 100644 --- a/tests/src/ipv6.cpp +++ b/tests/src/ipv6.cpp @@ -24,7 +24,7 @@ using namespace Tins; class IPv6Test : public testing::Test { public: static const uint8_t expected_packet1[], expected_packet2[], - hop_by_hop_options[]; + hop_by_hop_options[], broken1[]; void test_equals(IPv6& ip1, IPv6& ip2); }; @@ -55,6 +55,12 @@ const uint8_t IPv6Test::hop_by_hop_options[] = { 222, 173, 190, 239, 190, 173, 254, 237 }; +const uint8_t IPv6Test::broken1[] = { + 51, 51, 0, 0, 0, 251, 96, 3, 8, 165, 51, 186, 134, 221, 96, 14, 233, 9, 0, 11, 44, 255, + 254, 128, 0, 0, 0, 0, 0, 0, 98, 3, 8, 255, 254, 165, 51, 186, 255, 2, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 251, 17, 0, 11, 80, 53, 98, 2, 81, 72, 50, 10 +}; + void IPv6Test::test_equals(IPv6& ip1, IPv6& ip2) { EXPECT_EQ(ip1.version(), ip2.version()); EXPECT_EQ(ip1.traffic_class(), ip2.traffic_class()); @@ -161,6 +167,14 @@ TEST_F(IPv6Test, Serialize) { test_equals(ip1, ip2); } +TEST_F(IPv6Test, Broken1) { + EthernetII pkt(broken1, sizeof(broken1)); + EXPECT_EQ( + PDU::serialization_type(broken1, broken1 + sizeof(broken1)), + pkt.serialize() + ); +} + TEST_F(IPv6Test, Version) { IPv6 ipv6; ipv6.version(3);