diff --git a/include/icmp.h b/include/icmp.h index 079081b..6aa5d4f 100644 --- a/include/icmp.h +++ b/include/icmp.h @@ -33,6 +33,7 @@ #include "macros.h" #include "pdu.h" #include "endianness.h" +#include "ip_address.h" namespace Tins { @@ -61,7 +62,9 @@ namespace Tins { TIMESTAMP_REQUEST = 13, TIMESTAMP_REPLY = 14, INFO_REQUEST = 15, - INFO_REPLY = 16 + INFO_REPLY = 16, + ADDRESS_MASK_REQUEST = 17, + ADDRESS_MASK_REPLY = 18 }; /** @@ -136,24 +139,31 @@ namespace Tins { /** * \brief Setter for the original timestamp field. * - * \param new_pointer the value to be set. + * \param new_timestamp 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. + * \param new_timestamp 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. + * \param new_timestamp the value to be set. */ void transmit_timestamp(uint32_t new_timestamp); + /** + * \brief Setter for the address mask field. + * + * \param new_mask the value to be set. + */ + void address_mask(IPv4Address new_mask); + /** * \brief Sets echo request flag for this PDU. * @@ -285,7 +295,7 @@ namespace Tins { * * \return Returns the original timestamp value. */ - uint32_t original_timestamp() const { return Endian::be_to_host(_orig_timestamp); } + uint32_t original_timestamp() const { return Endian::be_to_host(_orig_timestamp_or_address_mask); } /** * \brief Getter for the receive timestamp field. @@ -301,6 +311,15 @@ namespace Tins { */ uint32_t transmit_timestamp() const { return Endian::be_to_host(_trans_timestamp); } + /** + * \brief Getter for the address mask field. + * + * \return Returns the address mask value. + */ + IPv4Address address_mask() const { + return IPv4Address(Endian::be_to_host(_orig_timestamp_or_address_mask)); + } + /** * \brief Returns the header size. * @@ -361,7 +380,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; + uint32_t _orig_timestamp_or_address_mask, _recv_timestamp, _trans_timestamp; }; } diff --git a/src/icmp.cpp b/src/icmp.cpp index 0ce0242..2f7050f 100644 --- a/src/icmp.cpp +++ b/src/icmp.cpp @@ -43,7 +43,7 @@ namespace Tins { ICMP::ICMP(Flags flag) -: _orig_timestamp(), _recv_timestamp(), _trans_timestamp() +: _orig_timestamp_or_address_mask(), _recv_timestamp(), _trans_timestamp() { std::memset(&_icmp, 0, sizeof(icmphdr)); type(flag); @@ -66,6 +66,14 @@ ICMP::ICMP(const uint8_t *buffer, uint32_t total_sz) total_sz -= sizeof(uint32_t) * 3; buffer += sizeof(uint32_t) * 3; } + else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) { + if(total_sz < sizeof(uint32_t)) + throw malformed_packet(); + const uint32_t *ptr = reinterpret_cast(buffer); + address_mask(IPv4Address(*ptr++)); + total_sz -= sizeof(uint32_t); + buffer += sizeof(uint32_t); + } if(total_sz) inner_pdu(new RawPDU(buffer, total_sz)); } @@ -103,7 +111,7 @@ void ICMP::pointer(uint8_t new_pointer) { } void ICMP::original_timestamp(uint32_t new_timestamp) { - _orig_timestamp = Endian::host_to_be(new_timestamp); + _orig_timestamp_or_address_mask = Endian::host_to_be(new_timestamp); } void ICMP::receive_timestamp(uint32_t new_timestamp) { @@ -114,10 +122,16 @@ void ICMP::transmit_timestamp(uint32_t new_timestamp) { _trans_timestamp = Endian::host_to_be(new_timestamp); } +void ICMP::address_mask(IPv4Address new_mask) { + _orig_timestamp_or_address_mask = Endian::host_to_be(static_cast(new_mask)); +} + uint32_t ICMP::header_size() const { uint32_t extra = 0; if(type() == TIMESTAMP_REQUEST || type() == TIMESTAMP_REPLY) - extra += sizeof(uint32_t) * 3; + extra = sizeof(uint32_t) * 3; + else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) + extra = sizeof(uint32_t); return sizeof(icmphdr) + extra; } @@ -187,6 +201,10 @@ void ICMP::write_serialization(uint8_t *buffer, uint32_t total_sz, const PDU *) *ptr++ = receive_timestamp(); *ptr++ = transmit_timestamp(); } + else if(type() == ADDRESS_MASK_REQUEST || type() == ADDRESS_MASK_REPLY) { + uint32_t *ptr = reinterpret_cast(buffer + sizeof(icmphdr)); + *ptr++ = address_mask(); + } // checksum calc _icmp.check = 0; memcpy(buffer, &_icmp, sizeof(icmphdr)); @@ -204,7 +222,8 @@ bool ICMP::matches_response(const uint8_t *ptr, uint32_t total_sz) const { return false; const icmphdr *icmp_ptr = (const icmphdr*)ptr; if((_icmp.type == ECHO_REQUEST && icmp_ptr->type == ECHO_REPLY) || - (_icmp.type == TIMESTAMP_REQUEST && icmp_ptr->type == TIMESTAMP_REPLY)) { + (_icmp.type == TIMESTAMP_REQUEST && icmp_ptr->type == TIMESTAMP_REPLY) || + (_icmp.type == ADDRESS_MASK_REQUEST && icmp_ptr->type == ADDRESS_MASK_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 2b73850..8db868b 100644 --- a/tests/src/icmp.cpp +++ b/tests/src/icmp.cpp @@ -82,6 +82,19 @@ TEST_F(ICMPTest, ChecksumOnTimestamp) { EXPECT_EQ(0xed8d, pkt.rfind_pdu().check()); } +TEST_F(ICMPTest, AddressMaskRequest) { + const uint8_t raw_pkt[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 69, 0, 0, 32, 0, 1, 0, + 0, 64, 1, 249, 38, 192, 168, 0, 100, 192, 168, 0, 1, 17, 0, 234, + 249, 0, 0, 0, 0, 1, 2, 3, 4 + }; + EthernetII pkt(raw_pkt, sizeof(raw_pkt)); + IP::serialization_type buffer = pkt.serialize(); + EXPECT_EQ(0xf926, pkt.rfind_pdu().checksum()); + EXPECT_EQ(0xeaf9, pkt.rfind_pdu().check()); + EXPECT_EQ(IPv4Address("1.2.3.4"), pkt.rfind_pdu().address_mask()); +} + TEST_F(ICMPTest, Code) { ICMP icmp; icmp.code(0x7a); @@ -142,6 +155,12 @@ TEST_F(ICMPTest, TransmitTimestamp) { EXPECT_EQ(0x1f8172da, icmp.transmit_timestamp()); } +TEST_F(ICMPTest, AddressMask) { + ICMP icmp; + icmp.address_mask("192.168.0.1"); + EXPECT_EQ(IPv4Address("192.168.0.1"), icmp.address_mask()); +} + TEST_F(ICMPTest, SetEchoRequest) { ICMP icmp; icmp.set_echo_request(0x7af1, 0x123f);