From 0a16d8f462cc689fa4a8ab5a5d508102355426d1 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Thu, 17 Dec 2015 20:42:57 -0800 Subject: [PATCH] Add ICMP extensions to ICMP PDU The length field is still not being set --- include/tins/icmp.h | 32 ++++++++++++++++++++++++++++++-- include/tins/icmp_extension.h | 7 +++++++ src/icmp.cpp | 26 ++++++++++++++++++++++++++ src/icmp_extension.cpp | 8 ++++++-- tests/src/icmp.cpp | 22 +++++++++++++++++++--- 5 files changed, 88 insertions(+), 7 deletions(-) diff --git a/include/tins/icmp.h b/include/tins/icmp.h index a5f18b2..5c9a5df 100644 --- a/include/tins/icmp.h +++ b/include/tins/icmp.h @@ -353,10 +353,21 @@ namespace Tins { * \brief Returns the header size. * * This metod overrides PDU::header_size. This size includes the - * payload and options size. \sa PDU::header_size + * payload and options size. + * + * \sa PDU::header_size */ uint32_t header_size() const; + /** + * \brief Returns the trailer size. + * + * This metod overrides PDU::trailer_size. This size will hold the extensions size + * + * \sa PDU::header_size + */ + uint32_t trailer_size() const; + /** * \brief Check wether ptr points to a valid response for this PDU. * @@ -366,7 +377,24 @@ namespace Tins { */ bool matches_response(const uint8_t *ptr, uint32_t total_sz) const; - const ICMPExtensionsStructure& extensions() { return extensions_; } + /** + * \brief Getter for the extensions field. + * + * \return The extensions field + */ + const ICMPExtensionsStructure& extensions() const { return extensions_; } + + /** + * \brief Getter for the extensions field. + * + * \return The extensions field + */ + ICMPExtensionsStructure& extensions() { return extensions_; } + + /** + * \brief Indicates whether this object contains ICMP extensions + */ + bool has_extensions() const { return !extensions_.extensions().empty(); } /** * \brief Getter for the PDU's type. diff --git a/include/tins/icmp_extension.h b/include/tins/icmp_extension.h index 8035bab..5f0ffac 100644 --- a/include/tins/icmp_extension.h +++ b/include/tins/icmp_extension.h @@ -189,6 +189,13 @@ public: */ const extensions_type& extensions() const { return extensions_; } + /** + * \brief Adds an extension to this structure + * + * \param extension The extension to be added; + */ + void add_extension(const ICMPExtension& extension); + /** * \brief Gets the size of this ICMP extensions structure * diff --git a/src/icmp.cpp b/src/icmp.cpp index 12292b9..02ae000 100644 --- a/src/icmp.cpp +++ b/src/icmp.cpp @@ -140,9 +140,21 @@ uint32_t ICMP::header_size() const { extra = sizeof(uint32_t) * 3; else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) extra = sizeof(uint32_t); + return sizeof(icmphdr) + extra; } +uint32_t ICMP::trailer_size() const { + uint32_t output = 0; + if (has_extensions()) { + output += extensions_.size(); + if (inner_pdu()) { + output += 128 - std::min(inner_pdu()->size(), 128U); + } + } + return output; +} + void ICMP::set_echo_request(uint16_t id, uint16_t seq) { type(ECHO_REQUEST); this->id(id); @@ -216,6 +228,20 @@ void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) uint32_t_buffer = address_mask(); memcpy(buffer + sizeof(icmphdr), &uint32_t_buffer, sizeof(uint32_t)); } + + if (has_extensions()) { + uint8_t* extensions_ptr = buffer + sizeof(icmphdr); + if (inner_pdu()) { + uint32_t inner_pdu_size = inner_pdu()->size(); + if (inner_pdu_size < 128) { + memset(buffer + sizeof(icmphdr) + inner_pdu_size, 0, 128 - inner_pdu_size); + inner_pdu_size = 128; + } + extensions_ptr += inner_pdu_size; + } + extensions_.serialize(extensions_ptr, total_sz - (extensions_ptr - buffer)); + } + // checksum calc _icmp.check = 0; memcpy(buffer, &_icmp, sizeof(icmphdr)); diff --git a/src/icmp_extension.cpp b/src/icmp_extension.cpp index 8c94e92..6e11150 100644 --- a/src/icmp_extension.cpp +++ b/src/icmp_extension.cpp @@ -76,8 +76,8 @@ ICMPExtension::serialization_type ICMPExtension::serialize() const { const uint32_t ICMPExtensionsStructure::BASE_HEADER_SIZE = sizeof(uint16_t) * 2; ICMPExtensionsStructure::ICMPExtensionsStructure() -: version_and_reserved_(0x2000), checksum_(0) { - +: version_and_reserved_(), checksum_(0) { + version(2); } ICMPExtensionsStructure::ICMPExtensionsStructure(const uint8_t* buffer, uint32_t total_sz) { @@ -135,6 +135,10 @@ uint32_t ICMPExtensionsStructure::size() const { return output; } +void ICMPExtensionsStructure::add_extension(const ICMPExtension& extension) { + extensions_.push_back(extension); +} + void ICMPExtensionsStructure::serialize(uint8_t* buffer, uint32_t buffer_size) { const uint32_t structure_size = size(); if (buffer_size < structure_size) { diff --git a/tests/src/icmp.cpp b/tests/src/icmp.cpp index b09668a..cb8da48 100644 --- a/tests/src/icmp.cpp +++ b/tests/src/icmp.cpp @@ -14,7 +14,7 @@ using namespace Tins; class ICMPTest : public testing::Test { public: static const uint8_t expected_packets[][8]; - static const uint8_t ts_request[], ts_reply[]; + static const uint8_t ts_request[], ts_reply[], packet_with_extensions[]; static const uint32_t expected_packet_count; void test_equals(const ICMP &icmp1, const ICMP &icmp2); @@ -35,6 +35,16 @@ const uint8_t ICMPTest::ts_reply[] = { 14, 0, 172, 45, 0, 0, 0, 0, 0, 0, 0, 0, 4, 144, 30, 89, 4, 144, 30, 89, 0, 0, 0, 0, 0, 0 }; +const uint8_t ICMPTest::packet_with_extensions[] = { + 11, 0, 205, 4, 0, 0, 0, 0, 69, 0, 0, 40, 165, 76, 0, 0, 1, 17, 247, 111, 12, 4, 4, 4, 12, + 1, 1, 1, 165, 75, 130, 155, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 197, 95, 0, + 8, 1, 1, 24, 150, 1, 1 +}; + + TEST_F(ICMPTest, DefaultConstructor) { ICMP icmp; @@ -289,10 +299,9 @@ TEST_F(ICMPTest, ConstructorFromBuffer) { } TEST_F(ICMPTest, ExtensionsParsingWithoutALengthField) { - const uint8_t packet[] = { 11, 0, 205, 4, 0, 0, 0, 0, 69, 0, 0, 40, 165, 76, 0, 0, 1, 17, 247, 111, 12, 4, 4, 4, 12, 1, 1, 1, 165, 75, 130, 155, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 197, 95, 0, 8, 1, 1, 24, 150, 1, 1 }; const uint8_t encapsulated[] = { 69, 0, 0, 40, 165, 76, 0, 0, 1, 17, 247, 111, 12, 4, 4, 4, 12, 1, 1, 1, 165, 75, 130, 155, 0, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; const uint8_t ext[] = { 0, 8, 1, 1, 24, 150, 1, 1 }; - ICMP icmp(packet, sizeof(packet)); + ICMP icmp(packet_with_extensions, sizeof(packet_with_extensions)); ICMPExtensionsStructure extensions = icmp.extensions(); ASSERT_EQ(1, extensions.extensions().size()); EXPECT_EQ( @@ -305,4 +314,11 @@ TEST_F(ICMPTest, ExtensionsParsingWithoutALengthField) { RawPDU::payload_type(encapsulated, encapsulated + sizeof(encapsulated)), raw->payload() ); + + PDU::serialization_type buffer = icmp.serialize(); + EXPECT_EQ(sizeof(packet_with_extensions), buffer.size()); + EXPECT_EQ( + buffer, + PDU::serialization_type(packet_with_extensions, packet_with_extensions + sizeof(packet_with_extensions)) + ); }