From 9b57585b6271d3282ee9e24f8a484138fb6a2080 Mon Sep 17 00:00:00 2001 From: Matias Fontanini Date: Fri, 13 Dec 2013 17:23:17 -0300 Subject: [PATCH] Added support for ICMP timestamp request/reply packets. ICMP::matches_response now works with these types of packets as well. --- Makefile.in | 4 ++-- include/icmp.h | 51 +++++++++++++++++++++++++++++++++++++++++++--- src/icmp.cpp | 42 +++++++++++++++++++++++++++++++++----- tests/src/icmp.cpp | 33 ++++++++++++++++++++++++++++++ 4 files changed, 120 insertions(+), 10 deletions(-) diff --git a/Makefile.in b/Makefile.in index 0225fe4..cd99c6c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -59,8 +59,8 @@ DIST_COMMON = README $(am__configure_deps) $(libtins_HEADERS) \ $(libtins_dot11_HEADERS) $(srcdir)/Makefile.am \ $(srcdir)/Makefile.in $(srcdir)/libtins.pc.in \ $(top_srcdir)/configure $(top_srcdir)/include/config.h.in \ - AUTHORS COPYING INSTALL THANKS TODO config.guess config.sub \ - depcomp install-sh ltmain.sh missing + AUTHORS THANKS config.guess config.sub depcomp install-sh \ + ltmain.sh missing ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 am__aclocal_m4_deps = $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \ $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ diff --git a/include/icmp.h b/include/icmp.h index daf89d8..079081b 100644 --- a/include/icmp.h +++ b/include/icmp.h @@ -58,6 +58,8 @@ namespace Tins { ECHO_REQUEST = 8, TIME_EXCEEDED = 11, PARAM_PROBLEM = 12, + TIMESTAMP_REQUEST = 13, + TIMESTAMP_REPLY = 14, INFO_REQUEST = 15, INFO_REPLY = 16 }; @@ -131,6 +133,27 @@ namespace Tins { */ void pointer(uint8_t new_pointer); + /** + * \brief Setter for the original timestamp field. + * + * \param new_pointer the value to be set. + */ + void original_timestamp(uint32_t new_timestamp); + + /** + * \brief Setter for the receive timestamp field. + * + * \param new_pointer the value to be set. + */ + void receive_timestamp(uint32_t new_timestamp); + + /** + * \brief Setter for the transmit timestamp field. + * + * \param new_pointer the value to be set. + */ + void transmit_timestamp(uint32_t new_timestamp); + /** * \brief Sets echo request flag for this PDU. * @@ -239,24 +262,45 @@ namespace Tins { /** * \brief Getter for the gateway field. * - * \return Returns the gateways in an unit32_t. + * \return Returns the gateway field value. */ uint32_t gateway() const { return Endian::be_to_host(_icmp.un.gateway); } /** * \brief Getter for the pointer field. * - * \return Returns the pointer value. + * \return Returns the pointer field value. */ uint8_t pointer() const { return this->_icmp.un.pointer; } /** * \brief Getter for the mtu field. * - * \return Returns the mtu value in an uint16_t. + * \return Returns the mtu field value. */ uint16_t mtu() const { return Endian::be_to_host(_icmp.un.frag.mtu); } + /** + * \brief Getter for the original timestamp field. + * + * \return Returns the original timestamp value. + */ + uint32_t original_timestamp() const { return Endian::be_to_host(_orig_timestamp); } + + /** + * \brief Getter for the receive timestamp field. + * + * \return Returns the receive timestamp value. + */ + uint32_t receive_timestamp() const { return Endian::be_to_host(_recv_timestamp); } + + /** + * \brief Getter for the transmit timestamp field. + * + * \return Returns the transmit timestamp value. + */ + uint32_t transmit_timestamp() const { return Endian::be_to_host(_trans_timestamp); } + /** * \brief Returns the header size. * @@ -317,6 +361,7 @@ namespace Tins { void write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *parent); icmphdr _icmp; + uint32_t _orig_timestamp, _recv_timestamp, _trans_timestamp; }; } diff --git a/src/icmp.cpp b/src/icmp.cpp index 35d0eb1..9b4c9c2 100644 --- a/src/icmp.cpp +++ b/src/icmp.cpp @@ -43,6 +43,7 @@ namespace Tins { ICMP::ICMP(Flags flag) +: _orig_timestamp(), _recv_timestamp(), _trans_timestamp() { std::memset(&_icmp, 0, sizeof(icmphdr)); type(flag); @@ -53,9 +54,16 @@ ICMP::ICMP(const uint8_t *buffer, uint32_t total_sz) if(total_sz < sizeof(icmphdr)) throw malformed_packet(); std::memcpy(&_icmp, buffer, sizeof(icmphdr)); + buffer += sizeof(icmphdr); total_sz -= sizeof(icmphdr); + if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) { + const uint32_t *ptr = reinterpret_cast(buffer); + original_timestamp(*ptr++); + receive_timestamp(*ptr++); + transmit_timestamp(*ptr++); + } if(total_sz) - inner_pdu(new RawPDU(buffer + sizeof(icmphdr), total_sz)); + inner_pdu(new RawPDU(buffer, total_sz)); } void ICMP::code(uint8_t new_code) { @@ -90,8 +98,23 @@ void ICMP::pointer(uint8_t new_pointer) { _icmp.un.pointer = new_pointer; } +void ICMP::original_timestamp(uint32_t new_timestamp) { + _orig_timestamp = Endian::host_to_be(new_timestamp); +} + +void ICMP::receive_timestamp(uint32_t new_timestamp) { + _recv_timestamp = Endian::host_to_be(new_timestamp); +} + +void ICMP::transmit_timestamp(uint32_t new_timestamp) { + _trans_timestamp = Endian::host_to_be(new_timestamp); +} + uint32_t ICMP::header_size() const { - return sizeof(icmphdr); + uint32_t extra = 0; + if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) + extra += sizeof(uint32_t) * 3; + return sizeof(icmphdr) + extra; } void ICMP::set_echo_request(uint16_t id, uint16_t seq) { @@ -154,10 +177,18 @@ void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) assert(total_sz >= sizeof(icmphdr)); #endif + if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) { + uint32_t *ptr = reinterpret_cast(buffer + sizeof(icmphdr)); + *ptr++ = original_timestamp(); + *ptr++ = receive_timestamp(); + *ptr++ = transmit_timestamp(); + } + + // checksum calc _icmp.check = 0; - uint32_t checksum = Utils::do_checksum(buffer + sizeof(icmphdr), buffer + total_sz) + - Utils::do_checksum((uint8_t*)&_icmp, ((uint8_t*)&_icmp) + sizeof(icmphdr)); + uint32_t checksum = Utils::do_checksum(buffer + ICMP::header_size(), buffer + total_sz) + + Utils::do_checksum((uint8_t*)&_icmp, ((uint8_t*)&_icmp) + ICMP::header_size()); while (checksum >> 16) checksum = (checksum & 0xffff) + (checksum >> 16); @@ -169,7 +200,8 @@ bool ICMP::matches_response(const uint8_t *ptr, uint32_t total_sz) const { if(total_sz < sizeof(icmphdr)) return false; const icmphdr *icmp_ptr = (const icmphdr*)ptr; - if(_icmp.type == ECHO_REQUEST && icmp_ptr->type == ECHO_REPLY) { + if((_icmp.type == ECHO_REQUEST && icmp_ptr->type == ECHO_REPLY) || + (_icmp.type == TIMESTAMP_REQUEST && icmp_ptr->type == TIMESTAMP_REPLY)) { return icmp_ptr->un.echo.id == _icmp.un.echo.id && icmp_ptr->un.echo.sequence == _icmp.un.echo.sequence; } return false; diff --git a/tests/src/icmp.cpp b/tests/src/icmp.cpp index 29fe5ee..7754f20 100644 --- a/tests/src/icmp.cpp +++ b/tests/src/icmp.cpp @@ -11,6 +11,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 uint32_t expected_packet_count; void test_equals(const ICMP &icmp1, const ICMP &icmp2); @@ -20,8 +21,17 @@ const uint8_t ICMPTest::expected_packets[][8] = { { 8, 1, 173, 123, 86, 209, 243, 177 }, { 12, 0, 116, 255, 127, 0, 0, 0 } }; + const uint32_t ICMPTest::expected_packet_count = 1; +const uint8_t ICMPTest::ts_request[] = { + 13, 0, 180, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106, 97, 106, 97, 106 +}; + +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 +}; + TEST_F(ICMPTest, DefaultConstructor) { ICMP icmp; @@ -99,6 +109,24 @@ TEST_F(ICMPTest, Pointer) { EXPECT_EQ(icmp.pointer(), 0xf1); } +TEST_F(ICMPTest, OriginalTimestamp) { + ICMP icmp; + icmp.original_timestamp(0x1f8172da); + EXPECT_EQ(0x1f8172da, icmp.original_timestamp()); +} + +TEST_F(ICMPTest, ReceiveTimestamp) { + ICMP icmp; + icmp.receive_timestamp(0x1f8172da); + EXPECT_EQ(0x1f8172da, icmp.receive_timestamp()); +} + +TEST_F(ICMPTest, TransmitTimestamp) { + ICMP icmp; + icmp.transmit_timestamp(0x1f8172da); + EXPECT_EQ(0x1f8172da, icmp.transmit_timestamp()); +} + TEST_F(ICMPTest, SetEchoRequest) { ICMP icmp; icmp.set_echo_request(0x7af1, 0x123f); @@ -196,6 +224,11 @@ TEST_F(ICMPTest, Serialize) { EXPECT_EQ(buffer, buffer2); } +TEST_F(ICMPTest, TimestampMatchesResponse) { + ICMP request(ts_request, sizeof(ts_request)); + EXPECT_TRUE(request.matches_response(ts_reply, sizeof(ts_reply))); +} + TEST_F(ICMPTest, ConstructorFromBuffer) { for(unsigned i(0); i < expected_packet_count; ++i) { ICMP icmp1(expected_packets[i], sizeof(expected_packets[i]));