diff --git a/include/tins/ipv6.h b/include/tins/ipv6.h index 2e2283a6..0fbaaa74 100644 --- a/include/tins/ipv6.h +++ b/include/tins/ipv6.h @@ -356,6 +356,7 @@ class TINS_API IPv6 : public PDU { uint32_t calculate_headers_size() const; static void write_header(const ext_header& header, Memory::OutputMemoryStream& stream); static bool is_extension_header(uint8_t header_id); + static uint32_t get_padding_size(const ext_header& header); TINS_BEGIN_PACK struct ipv6_header { diff --git a/src/ipv6.cpp b/src/ipv6.cpp index c81b8436..02967f35 100644 --- a/src/ipv6.cpp +++ b/src/ipv6.cpp @@ -164,6 +164,11 @@ bool IPv6::is_extension_header(uint8_t header_id) { || header_id == MOBILITY || header_id == NO_NEXT_HEADER; } +uint32_t IPv6::get_padding_size(const ext_header& header) { + const uint32_t padding = (header.data_size() + sizeof(uint8_t) * 2) % 8; + return padding == 0 ? 0 : (8 - padding); +} + void IPv6::version(small_uint<4> new_version) { header_.version = new_version; } @@ -337,6 +342,8 @@ uint32_t IPv6::calculate_headers_size() const { uint32_t output = 0; for (const_iterator iter = ext_headers_.begin(); iter != ext_headers_.end(); ++iter) { output += static_cast(iter->data_size() + sizeof(uint8_t) * 2); + output += get_padding_size(*iter); + } return output; } @@ -346,6 +353,8 @@ void IPv6::write_header(const ext_header& header, OutputMemoryStream& stream) { stream.write(header.option()); stream.write(length); stream.write(header.data_ptr(), header.data_size()); + // Append padding + stream.fill(get_padding_size(header), 0); } } // Tins diff --git a/tests/src/ipv6_test.cpp b/tests/src/ipv6_test.cpp index 029a1612..e317456b 100644 --- a/tests/src/ipv6_test.cpp +++ b/tests/src/ipv6_test.cpp @@ -360,3 +360,9 @@ TEST_F(IPv6Test, OptionAddition) { EXPECT_TRUE(ipv6.search_header(IPv6::ROUTING) != 0); EXPECT_TRUE(ipv6.search_header(IPv6::AUTHENTICATION) != 0); } + +TEST_F(IPv6Test, HopByHopPadding) { + IPv6 ipv6_header; + ipv6_header.add_header(IPv6::ExtensionHeader::HOP_BY_HOP); + EXPECT_EQ(48UL, ipv6_header.serialize().size()); +}