From: Christian Herdtweck Date: Thu, 12 Mar 2015 10:04:43 +0000 (+0100) Subject: re-ordered class for IcmpPacket X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=c120ad42aad7195aca9ac197c0636dd124e19263;p=pingcheck re-ordered class for IcmpPacket old: IcmpPacket has and IpvXHeader, an IcmpvXHeader which varies according to ICMP message type and also contains part of Icmp message data, and an IcmpData which is a string; new: IcmpPacket has an IpHeader, an IcmpHeader which represents only the common first 4 byte of ICMP v4/v6, and IcmpData which is either a IcmpEchoData for echo request/reply or a IcmpDestinationUnreachableData tried to abstract away as much as possible (for a lay programmer like me) the difference between v4 and v6 This code now compiles, need to see whether it does anything usefull Tests not compiled/run yet --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 11ecd07..9657ff3 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -76,15 +76,6 @@ set(SOURCES host/pingprotocol.cpp host/pingrotate.cpp host/pingscheduler.cpp - icmp/icmpdestinationunreachablemessage.cpp - icmp/icmpechoreplymessage.cpp - icmp/icmpechorequestmessage.cpp - icmp/icmpgenericmessage.cpp - icmp/icmpv4header.cpp - icmp/icmpv6header.cpp - icmp/icmpmessage.cpp - icmp/icmpv4packet.cpp - icmp/icmpv6packet.cpp icmp/icmppacket.cpp icmp/icmppinger.cpp icmp/icmppacketfactory.cpp diff --git a/src/icmp/icmpdata.h b/src/icmp/icmpdata.h index cda6140..dcb8586 100644 --- a/src/icmp/icmpdata.h +++ b/src/icmp/icmpdata.h @@ -1,18 +1,89 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) +/* + The software in this package is distributed under the GNU General + Public License version 2 (with a special exception described below). + + A copy of GNU General Public License (GPL) is included in this distribution, + in the file COPYING.GPL. + + As a special exception, if other files instantiate templates or use macros + or inline functions from this file, or you compile this file and link it + with other works to produce a work based on this file, this file + does not by itself cause the resulting work to be covered + by the GNU General Public License. + + However the source code for this file must still be made available + in accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work based + on this file might be covered by the GNU General Public License. + + Christian Herdtweck, Intra2net AG 2015 + */ + #ifndef ICMP_DATA_H #define ICMP_DATA_H -#include +#include +#include +#include +#include +#include "host/messagepayload.h" + +/** @brief contents of ICMP packets after the first 4 bytes of the ICMP header + * used for ICMPv4 and ICMPv6 + * + * subclasses only have to specify which part of raw_data to access for which + * information + */ +class IcmpData +{ +public: + IcmpData() + : size( 0 ) + , raw_data( 0 ) + {} + + virtual bool match_echo_reply(const uint16_t identifier, + const uint16_t sequence_number) const + { return false; }; + + virtual bool match_destination_unreachable(const uint16_t identifier, + const uint16_t sequence_number) const + { return false; }; + + std::size_t get_size() { return size; }; + + virtual std::istream& read(std::istream &is) // read raw data + { return raw_data.read(is); } + + std::ostream& write(std::ostream &os) + { return raw_data.write(os); } + + virtual ~IcmpData() {} + + uint32_t calc_checksum_part() const + { return raw_data.calc_checksum_part(); } + + virtual void print( const size_t &bytes_received, + const boost::posix_time::ptime &time_packet_sent, + const std::string &remote_address, + const uint32_t ttl) const + {} + +protected: + + IcmpData(const std::size_t size_arg) + : size( size_arg ) + , raw_data( size_arg ) + {} + + std::size_t size; + MessagePayload raw_data; +}; + +typedef boost::shared_ptr IcmpDataPtr; -//----------------------------------------------------------------------------- -// IcmpData -//----------------------------------------------------------------------------- +#endif -typedef std::string IcmpData; +// (created using vim -- the world's best text editor) -#endif // ICMP_DATA_H diff --git a/src/icmp/icmpdestinationunreachabledata.h b/src/icmp/icmpdestinationunreachabledata.h new file mode 100644 index 0000000..de375fd --- /dev/null +++ b/src/icmp/icmpdestinationunreachabledata.h @@ -0,0 +1,154 @@ +/* + The software in this package is distributed under the GNU General + Public License version 2 (with a special exception described below). + + A copy of GNU General Public License (GPL) is included in this distribution, + in the file COPYING.GPL. + + As a special exception, if other files instantiate templates or use macros + or inline functions from this file, or you compile this file and link it + with other works to produce a work based on this file, this file + does not by itself cause the resulting work to be covered + by the GNU General Public License. + + However the source code for this file must still be made available + in accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work based + on this file might be covered by the GNU General Public License. + + Christian Herdtweck, Intra2net AG 2015 + */ + + +#ifndef ICMP_DEST_11_H +#define ICMP_DEST_11_H + +#include +#include +#include "icmp/icmpdata.h" + +#include +using I2n::Logger::GlobalLogger; + +/** + * structure of these packets (if originated from an ICMP request): + * +---------------------------+ + * | reply IP header | 20/40 bytes --> not contained in here + * +---------------------------+ + * | reply ICMP header: | + * | type | code | checksum | 4 byte --> not contained in here ! + * | 4 uninteresting bytes | 4 byte --> contained in here! + * +---------------------------+ + * | request | 20 / 40 bytes + * | IP header | for IP v4 / v6 + * +---------------------------+ + * | request ICMP packet: | + * | type | code | checksum | 1+1+2 byte + * | identifier | seq. number | 2+2 byte + * | data | 4 byte + * | data | 4 byte + * +---------------------------+ + * (where "in here" means in variable raw_data of class + * IcmpDestinationUnreachableData) + * + * see also: https://tools.ietf.org/html/rfc792 (ICMP v4) + * https://tools.ietf.org/html/rfc4443 (ICMP v6) + */ + +/** + * contains the request IP and ICMP header and possibly more data from request + */ +class IcmpDestinationUnreachableData : public IcmpData +{ +public: + IcmpDestinationUnreachableData(const std::size_t size_arg) + : IcmpData( size_arg ) + {} + + bool match_echo_reply(const uint16_t identifier, + const uint16_t sequence_number) const + { return false; } + + bool match_destination_unreachable(const uint16_t identifier, + const uint16_t sequence_number) const + { + // payload should be the original query, which is an IP packet. + // first check wheter that IP packet contains an ICMP message at all + bool is_icmp; + int offset = 4; // the 4 uninteresting bytes we need to skip + if (IcmpData::raw_data[offset+0] == 4) // IPv4 + { + is_icmp = IcmpData::raw_data[offset+9] == 1; + offset += 20; // 20 byte for IPv4 header + } + else if (IcmpData::raw_data[offset+0] == 6) // IPv6 + { + is_icmp = IcmpData::raw_data[offset+6] == 58; + offset += 40; // 40 byte for IPv6 header + } + + // if it is an icmp message, then the icmp packet comes right after the + // IP header. Inside the icmp packet we need bytes 5-8 + return identifier == get_icmp_identifier() && + sequence_number == get_icmp_sequence_number(); + } + + + uint16_t get_icmp_identifier() const + { return get_icmp_request_data(5); } + + uint16_t get_icmp_sequence_number() const + { return get_icmp_request_data(7); } + + uint16_t get_icmp_request_data(const int data_offset) const + { + // payload should be the original query, which is an IP packet. + // first check wheter that IP packet contains an ICMP message at all + bool is_icmp; + int offset = 4; // the 4 uninteresting bytes we need to skip + if (IcmpData::raw_data[offset+0] == 4) // IPv4 + { + is_icmp = IcmpData::raw_data[offset+9] == 1; + offset += 20; // 20 byte for IPv4 header + } + else if (IcmpData::raw_data[offset+0] == 6) // IPv6 + { + is_icmp = IcmpData::raw_data[offset+6] == 58; + offset += 40; // 40 byte for IPv6 header + } + + if ( !is_icmp ) + return static_cast(-1); + else + // if it is an icmp message, then the icmp packet comes right after + // the IP header. Inside the icmp packet we need bytes 5-8 + IcmpData::raw_data.decode16(offset+data_offset, + offset+data_offset+1); + } + + /** + * @brief Prints the destination unreachable messages. + * + * @return void + */ + void print( const size_t &bytes_received, + const boost::posix_time::ptime &time_packet_sent, + const std::string &remote_address, + const uint32_t ttl) const + { + uint16_t sequence_number = get_icmp_sequence_number(); + + GlobalLogger.info() << "Destination " << remote_address + << " (icmp_seq=" << sequence_number << ") unreachable!" + << std::endl; + } + + + +}; + +#endif + +// (created using vim -- the world's best text editor) + diff --git a/src/icmp/icmpdestinationunreachablemessage.cpp b/src/icmp/icmpdestinationunreachablemessage.cpp deleted file mode 100644 index ac3e0e6..0000000 --- a/src/icmp/icmpdestinationunreachablemessage.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#include "icmp/icmpdestinationunreachablemessage.h" - -#include - -using namespace std; - -//----------------------------------------------------------------------------- -// IcmpDestinationUnreachableMessage -//----------------------------------------------------------------------------- - -static const size_t MessageSizeInBytes = 44; - -IcmpDestinationUnreachableMessage::IcmpDestinationUnreachableMessage() : - Payload( MessageSizeInBytes ) -{ -} - -IcmpDestinationUnreachableMessage::~IcmpDestinationUnreachableMessage() -{ -} - -Icmpv4Type IcmpDestinationUnreachableMessage::get_type_v4() const -{ - Icmpv4Type type = static_cast( Payload[ 0 ] ); - - return type; -} - -void IcmpDestinationUnreachableMessage::set_type_v4( const Icmpv4Type type ) -{ - uint8_t n = static_cast( type ); - - Payload[ 0 ] = n; -} - -Icmpv6Type IcmpDestinationUnreachableMessage::get_type_v6() const -{ - Icmpv6Type type = static_cast( Payload[ 0 ] ); - - return type; -} - -void IcmpDestinationUnreachableMessage::set_type_v6( const Icmpv6Type type ) -{ - uint8_t n = static_cast( type ); - - Payload[ 0 ] = n; -} - -uint8_t IcmpDestinationUnreachableMessage::get_code() const -{ - return Payload[ 1 ]; -} - -void IcmpDestinationUnreachableMessage::set_code( uint8_t code ) -{ - Payload[ 1 ] = code; -} - -uint16_t IcmpDestinationUnreachableMessage::get_checksum() const -{ - return Payload.decode16( 2, 3 ); -} - -void IcmpDestinationUnreachableMessage::set_checksum( uint16_t checksum ) -{ - Payload.encode16( 2, 3, checksum ); -} - -uint16_t IcmpDestinationUnreachableMessage::get_identifier() const -{ - return Payload.decode16( 32, 33 ); -} - -void IcmpDestinationUnreachableMessage::set_identifier( - const uint16_t identifier -) -{ - Payload.encode16( 32, 33, identifier ); -} - -uint16_t IcmpDestinationUnreachableMessage::get_sequence_number() const -{ - return Payload.decode16( 34, 35 ); -} - -void IcmpDestinationUnreachableMessage::set_sequence_number( - const uint16_t sequence_number -) -{ - Payload.encode16( 34, 35, sequence_number ); -} - -std::istream& IcmpDestinationUnreachableMessage::read( std::istream &is ) -{ - return Payload.read( is ); -} - -std::ostream& IcmpDestinationUnreachableMessage::write( - std::ostream &os -) const -{ - return Payload.write( os ); -} diff --git a/src/icmp/icmpdestinationunreachablemessage.h b/src/icmp/icmpdestinationunreachablemessage.h deleted file mode 100644 index 387d68e..0000000 --- a/src/icmp/icmpdestinationunreachablemessage.h +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef ICMP_DESTINATION_UNREACHABLE_MESSAGE_H -#define ICMP_DESTINATION_UNREACHABLE_MESSAGE_H - -#include - -#include -#include - -#include "icmp/icmpmessage.h" -#include "host/messagepayload.h" - -//----------------------------------------------------------------------------- -// IcmpDestinationUnreachableMessage -//----------------------------------------------------------------------------- -// -// ICMP Destination Unreachable Message Format - -// 0 8 16 31 -// +---------------+---------------+------------------------------+ --- -// | | | | ^ -// | type | code | checksum | | -// | | | | | -// +---------------+---------------+------------------------------+ 8 bytes -// | | | -// | unused | | -// | | v -// +-------------------------------+------------------------------+ --- -// | | ^ -// | Internet Protocol (IP) Header | 20 bytes -// | | v -// +-------------------------------+------------------------------+ --- -// | | ^ -// | Original ICMP Data Datagram | 20 bytes -// | | v -// +-------------------------------+------------------------------+ --- -// -//----------------------------------------------------------------------------- - -class IcmpDestinationUnreachableMessage : public IcmpMessage -{ -public: - IcmpDestinationUnreachableMessage(); - virtual ~IcmpDestinationUnreachableMessage(); - - virtual Icmpv4Type get_type_v4() const; - virtual void set_type_v4( const Icmpv4Type type ); - - virtual Icmpv6Type get_type_v6() const; - virtual void set_type_v6( const Icmpv6Type type ); - - virtual uint8_t get_code() const; - virtual void set_code( const uint8_t code ); - - virtual uint16_t get_checksum() const; - virtual void set_checksum( const uint16_t checksum ); - - virtual uint16_t get_identifier() const; - virtual void set_identifier( const uint16_t identifier ); - - virtual uint16_t get_sequence_number() const; - virtual void set_sequence_number( const uint16_t sequence_number ); - - virtual std::istream& read( std::istream &is ); - virtual std::ostream& write( std::ostream &os ) const; - -private: - /// packet payload object - MessagePayload Payload; - -}; - -#endif // ICMP_DESTINATION_UNREACHABLE_MESSAGE_H diff --git a/src/icmp/icmpechodata.h b/src/icmp/icmpechodata.h new file mode 100644 index 0000000..ae31517 --- /dev/null +++ b/src/icmp/icmpechodata.h @@ -0,0 +1,103 @@ +/* + The software in this package is distributed under the GNU General + Public License version 2 (with a special exception described below). + + A copy of GNU General Public License (GPL) is included in this distribution, + in the file COPYING.GPL. + + As a special exception, if other files instantiate templates or use macros + or inline functions from this file, or you compile this file and link it + with other works to produce a work based on this file, this file + does not by itself cause the resulting work to be covered + by the GNU General Public License. + + However the source code for this file must still be made available + in accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work based + on this file might be covered by the GNU General Public License. + + Christian Herdtweck, Intra2net AG 2015 + */ + +#ifndef ICMP_ECHO_DATA_H +#define ICMP_ECHO_DATA_H + +#include +#include "icmp/icmpdata.h" + +#include +#include "boost/date_time/posix_time/posix_time_types.hpp" +#include "boost/date_time/time_resolution_traits.hpp" +#include + +using boost::date_time::time_resolution_traits_adapted64_impl; +using I2n::Logger::GlobalLogger; + +/** @brief Data part of ICMP echo request and echo reply packets + * + * represents the last 4 bytes of the ICMP header (for v4) and the 8 bytes + * of optional data; for v6 this (same amount of?!) data is defined as the + * body + */ +class IcmpEchoData : public IcmpData +{ +public: + IcmpEchoData(const uint16_t identifier, const uint16_t sequence_number, + const std::string &optional_data) + : IcmpData(12) + { + IcmpData::raw_data.encode16(0, 1, identifier); + IcmpData::raw_data.encode16(2, 3, sequence_number); + IcmpData::raw_data.encode_string(4, optional_data); + } + + IcmpEchoData(const std::size_t size_arg) + : IcmpData( size_arg ) + {} + + bool match_destination_unreachable(const uint16_t identifier, + const uint16_t sequence_number) const + { return false; } + + bool match_echo_reply(const uint16_t identifier, + const uint16_t sequence_number) const + { + return get_identifier() == identifier + && get_sequence_number() == sequence_number; + }; + + uint16_t get_identifier() const + { return IcmpData::raw_data.decode16(0, 1); } + + uint16_t get_sequence_number() const + { return IcmpData::raw_data.decode16(2, 3); } + + /** + * @brief Prints the ICMP echo reply messages. + * + * @return void + */ + void print( const size_t &bytes_received, + const boost::posix_time::ptime &time_packet_sent, + const std::string &remote_address, + const uint32_t ttl) const + { + boost::posix_time::ptime now + = boost::posix_time::microsec_clock::universal_time(); + time_resolution_traits_adapted64_impl::int_type elapsed_time = + (now - time_packet_sent).total_milliseconds(); + + GlobalLogger.info() << bytes_received << " bytes " + << "from " << remote_address + << ": icmp_seq=" << get_sequence_number() + << " ttl=" << ttl + << " time=" << elapsed_time << " ms" << std::endl; + } + +}; + +#endif + +// (created using vim -- the world's best text editor) + diff --git a/src/icmp/icmpechoreplymessage.cpp b/src/icmp/icmpechoreplymessage.cpp deleted file mode 100644 index 19719c8..0000000 --- a/src/icmp/icmpechoreplymessage.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#include "icmp/icmpechoreplymessage.h" - -#include - -using namespace std; - -//----------------------------------------------------------------------------- -// IcmpEchoReplyMessage -//----------------------------------------------------------------------------- - -static const size_t MessageSizeInBytes = 8; - -IcmpEchoReplyMessage::IcmpEchoReplyMessage() : - Payload( MessageSizeInBytes ) -{ -} - -IcmpEchoReplyMessage::~IcmpEchoReplyMessage() -{ -} - -Icmpv4Type IcmpEchoReplyMessage::get_type_v4() const -{ - Icmpv4Type type = static_cast( Payload[ 0 ] ); - - return type; -} - -void IcmpEchoReplyMessage::set_type_v4( const Icmpv4Type type ) -{ - uint8_t n = static_cast( type ); - - Payload[ 0 ] = n; -} - -Icmpv6Type IcmpEchoReplyMessage::get_type_v6() const -{ - Icmpv6Type type = static_cast( Payload[ 0 ] ); - - return type; -} - -void IcmpEchoReplyMessage::set_type_v6( const Icmpv6Type type ) -{ - uint8_t n = static_cast( type ); - - Payload[ 0 ] = n; -} - -uint8_t IcmpEchoReplyMessage::get_code() const -{ - return Payload[ 1 ]; -} - -void IcmpEchoReplyMessage::set_code( uint8_t code ) -{ - Payload[ 1 ] = code; -} - -uint16_t IcmpEchoReplyMessage::get_checksum() const -{ - return Payload.decode16( 2, 3 ); -} - -void IcmpEchoReplyMessage::set_checksum( uint16_t checksum ) -{ - Payload.encode16( 2, 3, checksum ); -} - -uint16_t IcmpEchoReplyMessage::get_identifier() const -{ - return Payload.decode16( 4, 5 ); -} - -void IcmpEchoReplyMessage::set_identifier( - const uint16_t identifier -) -{ - Payload.encode16( 4, 5, identifier ); -} - -uint16_t IcmpEchoReplyMessage::get_sequence_number() const -{ - return Payload.decode16( 6, 7 ); -} - -void IcmpEchoReplyMessage::set_sequence_number( - const uint16_t sequence_number -) -{ - Payload.encode16( 6, 7, sequence_number ); -} - -std::istream& IcmpEchoReplyMessage::read( std::istream &is ) -{ - return Payload.read( is ); -} - -std::ostream& IcmpEchoReplyMessage::write( std::ostream &os ) const -{ - return Payload.write( os ); -} diff --git a/src/icmp/icmpechoreplymessage.h b/src/icmp/icmpechoreplymessage.h deleted file mode 100644 index 32016d6..0000000 --- a/src/icmp/icmpechoreplymessage.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef ICMP_ECHO_REPLY_MESSAGE_H -#define ICMP_ECHO_REPLY_MESSAGE_H - -#include - -#include -#include - -#include "icmp/icmpmessage.h" -#include "host/messagepayload.h" - -//----------------------------------------------------------------------------- -// IcmpEchoReplyMessage -//----------------------------------------------------------------------------- -// -// ICMP Echo Reply Message Format -// -// 0 8 16 31 -// +---------------+---------------+------------------------------+ --- -// | | | | ^ -// | type | code | checksum | | -// | | | | | -// +---------------+---------------+------------------------------+ 8 bytes -// | | | | -// | identifier | sequence number | | -// | | | v -// +-------------------------------+------------------------------+ --- -// | | -// | data (n bytes) | -// | | -// +-------------------------------+------------------------------+ -// -//----------------------------------------------------------------------------- - -class IcmpEchoReplyMessage : public IcmpMessage -{ -public: - IcmpEchoReplyMessage(); - virtual ~IcmpEchoReplyMessage(); - - virtual Icmpv4Type get_type_v4() const; - virtual void set_type_v4( const Icmpv4Type type ); - - virtual Icmpv6Type get_type_v6() const; - virtual void set_type_v6( const Icmpv6Type type ); - - virtual uint8_t get_code() const; - virtual void set_code( const uint8_t code ); - - virtual uint16_t get_checksum() const; - virtual void set_checksum( const uint16_t checksum ); - - virtual uint16_t get_identifier() const; - virtual void set_identifier( const uint16_t identifier ); - - virtual uint16_t get_sequence_number() const; - virtual void set_sequence_number( const uint16_t sequence_number ); - - virtual std::istream& read( std::istream &is ); - virtual std::ostream& write( std::ostream &os ) const; - -private: - /// packet payload object - MessagePayload Payload; - -}; - -#endif // ICMP_ECHO_REPLY_MESSAGE_H diff --git a/src/icmp/icmpechorequestmessage.cpp b/src/icmp/icmpechorequestmessage.cpp deleted file mode 100644 index 28bf382..0000000 --- a/src/icmp/icmpechorequestmessage.cpp +++ /dev/null @@ -1,108 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#include "icmp/icmpechorequestmessage.h" - -#include - -using namespace std; - -//----------------------------------------------------------------------------- -// IcmpEchoRequestMessage -//----------------------------------------------------------------------------- - -static const size_t MessageSizeInBytes = 8; - -IcmpEchoRequestMessage::IcmpEchoRequestMessage() : - Payload( MessageSizeInBytes ) -{ -} - -IcmpEchoRequestMessage::~IcmpEchoRequestMessage() -{ -} - -Icmpv4Type IcmpEchoRequestMessage::get_type_v4() const -{ - Icmpv4Type type = static_cast( Payload[ 0 ] ); - - return type; -} - -void IcmpEchoRequestMessage::set_type_v4( const Icmpv4Type type ) -{ - uint8_t n = static_cast( type ); - - Payload[ 0 ] = n; -} - -Icmpv6Type IcmpEchoRequestMessage::get_type_v6() const -{ - Icmpv6Type type = static_cast( Payload[ 0 ] ); - - return type; -} - -void IcmpEchoRequestMessage::set_type_v6( const Icmpv6Type type ) -{ - uint8_t n = static_cast( type ); - - Payload[ 0 ] = n; -} - -uint8_t IcmpEchoRequestMessage::get_code() const -{ - return Payload[ 1 ]; -} - -void IcmpEchoRequestMessage::set_code( uint8_t code ) -{ - Payload[ 1 ] = code; -} - -uint16_t IcmpEchoRequestMessage::get_checksum() const -{ - return Payload.decode16( 2, 3 ); -} - -void IcmpEchoRequestMessage::set_checksum( uint16_t checksum ) -{ - Payload.encode16( 2, 3, checksum ); -} - -uint16_t IcmpEchoRequestMessage::get_identifier() const -{ - return Payload.decode16( 4, 5 ); -} - -void IcmpEchoRequestMessage::set_identifier( - const uint16_t identifier -) -{ - Payload.encode16( 4, 5, identifier ); -} - -uint16_t IcmpEchoRequestMessage::get_sequence_number() const -{ - return Payload.decode16( 6, 7 ); -} - -void IcmpEchoRequestMessage::set_sequence_number( - const uint16_t sequence_number -) -{ - Payload.encode16( 6, 7, sequence_number ); -} - -std::istream& IcmpEchoRequestMessage::read( std::istream &is ) -{ - return Payload.read( is ); -} - -std::ostream& IcmpEchoRequestMessage::write( std::ostream &os ) const -{ - return Payload.write( os ); -} diff --git a/src/icmp/icmpechorequestmessage.h b/src/icmp/icmpechorequestmessage.h deleted file mode 100644 index 246562c..0000000 --- a/src/icmp/icmpechorequestmessage.h +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef ICMP_ECHO_REQUEST_MESSAGE_H -#define ICMP_ECHO_REQUEST_MESSAGE_H - -#include - -#include -#include - -#include "icmp/icmpmessage.h" -#include "host/messagepayload.h" - -//----------------------------------------------------------------------------- -// IcmpEchoRequestMessage -//----------------------------------------------------------------------------- -// -// ICMP Echo Request Message Format -// -// 0 8 16 31 -// +---------------+---------------+------------------------------+ --- -// | | | | ^ -// | type | code | checksum | | -// | | | | | -// +---------------+---------------+------------------------------+ 8 bytes -// | | | | -// | identifier | sequence number | | -// | | | v -// +-------------------------------+------------------------------+ --- -// | | -// | data (n bytes) | -// | | -// +-------------------------------+------------------------------+ -// -//----------------------------------------------------------------------------- - -class IcmpEchoRequestMessage : public IcmpMessage -{ -public: - IcmpEchoRequestMessage(); - virtual ~IcmpEchoRequestMessage(); - - virtual Icmpv4Type get_type_v4() const; - virtual void set_type_v4( const Icmpv4Type type ); - - virtual Icmpv6Type get_type_v6() const; - virtual void set_type_v6( const Icmpv6Type type ); - - virtual uint8_t get_code() const; - virtual void set_code( const uint8_t code ); - - virtual uint16_t get_checksum() const; - virtual void set_checksum( const uint16_t checksum ); - - virtual uint16_t get_identifier() const; - virtual void set_identifier( const uint16_t identifier ); - - virtual uint16_t get_sequence_number() const; - virtual void set_sequence_number( const uint16_t sequence_number ); - - virtual std::istream& read( std::istream &is ); - virtual std::ostream& write( std::ostream &os ) const; - -private: - /// packet payload object - MessagePayload Payload; - -}; - -#endif // ICMP_ECHO_REQUEST_MESSAGE_H diff --git a/src/icmp/icmpgenericmessage.cpp b/src/icmp/icmpgenericmessage.cpp deleted file mode 100644 index 1bbee87..0000000 --- a/src/icmp/icmpgenericmessage.cpp +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#include "icmp/icmpgenericmessage.h" - -//----------------------------------------------------------------------------- -// IcmpGenericMessage -//----------------------------------------------------------------------------- - -IcmpGenericMessage::IcmpGenericMessage() -{ -} - -IcmpGenericMessage::~IcmpGenericMessage() -{ -} - -Icmpv4Type IcmpGenericMessage::get_type_v4() const -{ - return Icmpv4Type_Generic; -} - -void IcmpGenericMessage::set_type_v4( const Icmpv4Type ) -{ -} - -Icmpv6Type IcmpGenericMessage::get_type_v6() const -{ - return Icmpv6Type_Generic; -} - -void IcmpGenericMessage::set_type_v6( const Icmpv6Type ) -{ -} - -uint8_t IcmpGenericMessage::get_code() const -{ - return 0; -} - -void IcmpGenericMessage::set_code( uint8_t ) -{ -} - -uint16_t IcmpGenericMessage::get_checksum() const -{ - return 0; -} - -void IcmpGenericMessage::set_checksum( uint16_t ) -{ -} - -uint16_t IcmpGenericMessage::get_identifier() const -{ - return 0; -} - -void IcmpGenericMessage::set_identifier( uint16_t ) -{ -} - -uint16_t IcmpGenericMessage::get_sequence_number() const -{ - return 0; -} - -void IcmpGenericMessage::set_sequence_number( uint16_t ) -{ -} - -std::istream& IcmpGenericMessage::read( std::istream &is ) -{ - return is; -} - -std::ostream& IcmpGenericMessage::write( std::ostream &os ) const -{ - return os; -} diff --git a/src/icmp/icmpgenericmessage.h b/src/icmp/icmpgenericmessage.h deleted file mode 100644 index 3404dc0..0000000 --- a/src/icmp/icmpgenericmessage.h +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef ICMP_GENERIC_MESSAGE_H -#define ICMP_GENERIC_MESSAGE_H - -#include - -#include -#include - -#include "icmp/icmpmessage.h" - -//----------------------------------------------------------------------------- -// IcmpGenericMessage -//----------------------------------------------------------------------------- - -/** - * This class intends to handle ICMP messages that the application do not - * want to read. It acts like a stub. - */ -class IcmpGenericMessage : public IcmpMessage -{ -public: - IcmpGenericMessage(); - virtual ~IcmpGenericMessage(); - - virtual Icmpv4Type get_type_v4() const; - virtual void set_type_v4( const Icmpv4Type type ); - - virtual Icmpv6Type get_type_v6() const; - virtual void set_type_v6( const Icmpv6Type type ); - - virtual uint8_t get_code() const; - virtual void set_code( const uint8_t code ); - - virtual uint16_t get_checksum() const; - virtual void set_checksum( const uint16_t checksum ); - - virtual uint16_t get_identifier() const; - virtual void set_identifier( const uint16_t identifier ); - - virtual uint16_t get_sequence_number() const; - virtual void set_sequence_number( const uint16_t sequence_number ); - - virtual std::istream& read( std::istream &is ); - virtual std::ostream& write( std::ostream &os ) const; - -}; - -#endif // ICMP_GENERIC_MESSAGE_H diff --git a/src/icmp/icmpheader.h b/src/icmp/icmpheader.h new file mode 100644 index 0000000..b9922d9 --- /dev/null +++ b/src/icmp/icmpheader.h @@ -0,0 +1,101 @@ +/* + The software in this package is distributed under the GNU General + Public License version 2 (with a special exception described below). + + A copy of GNU General Public License (GPL) is included in this distribution, + in the file COPYING.GPL. + + As a special exception, if other files instantiate templates or use macros + or inline functions from this file, or you compile this file and link it + with other works to produce a work based on this file, this file + does not by itself cause the resulting work to be covered + by the GNU General Public License. + + However the source code for this file must still be made available + in accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work based + on this file might be covered by the GNU General Public License. + + Christian Herdtweck, Intra2net AG 2015 + */ + +#ifndef ICMP_HEADER_H +#define ICMP_HEADER_H + +#include +#include +#include + +/** @brief first 4 byte of ICMP header (v4 and v6) + * + * In ICMP v4, the first 4 bytes are standardized, the other 4 depend on + * message type. In Icmp v6, the header IS only the first 4 bytes. + * So everything after those first 4 bytes is contained in IcmpData subclasses + */ +class IcmpHeader +{ +public: + IcmpHeader() + : type( 0 ) + , code( 0 ) + , checksum( 0 ) + {} + + IcmpHeader(const uint8_t type_arg, const uint8_t code_arg) + : type( type_arg ) + , code( code_arg ) + , checksum( 0 ) + {} + + std::istream& read(std::istream &is) + { + boost::scoped_array buf( new char[4] ); + is.read(buf.get(), 4); + type = static_cast(buf[0]); + code = static_cast(buf[1]); + checksum = ( static_cast(buf[2]) << 8 ) + + static_cast(buf[3]); + + return is; + } + + uint8_t get_type() const { return type; } + uint8_t get_code() const { return code; } + uint16_t get_checksum() const { return checksum; } + + // code adapted from boost icmp example by Christopher M. Kohlhoff + // --> boost license?!? + void calc_checksum( const uint32_t body_checksum_part ) + { + uint32_t sum = (type << 8) + code; + sum += body_checksum_part; + + sum = (sum >> 16) + (sum & 0xFFFF); + sum += (sum >> 16); + + checksum = static_cast( ~sum ); + } + + bool write(std::ostream &os) const + { + os << type << code << checksum; + return os.good(); + } + + // returns the amount of data represented by this class; + // for Icmp v4, the header is actually 8 bytes, see comments above + uint16_t get_header_length() const + { return 4; } + +protected: + uint8_t type; + uint8_t code; + uint16_t checksum; // to be used in check_integrity +}; + + +#endif + +// (created using vim -- the world's best text editor) + diff --git a/src/icmp/icmpmessage.cpp b/src/icmp/icmpmessage.cpp deleted file mode 100644 index cffff70..0000000 --- a/src/icmp/icmpmessage.cpp +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#include "icmp/icmpmessage.h" - -//----------------------------------------------------------------------------- -// IcmpMessage -//----------------------------------------------------------------------------- - -/** - * @brief Default constructor. - */ -IcmpMessage::IcmpMessage() -{ -} - -/** - * @brief Destructor. - */ -IcmpMessage::~IcmpMessage() -{ -} - -/** - * This method MUST be called to initialize the data member of ICMP Messages. - */ -void IcmpMessage::init( const Icmpv4Type type ) -{ - // Note: this code can not be placed in the constructor, because it calls - // virtual function. If you call virtual functions from within a - // constructor, the Base class version of methods will be called, not the - // Derived class, because the Base is constructed before the Derived class. - set_type_v4( type ); - set_code( 0 ); - set_checksum( 0 ); - set_identifier( 0 ); - set_sequence_number( 0 ); -} - -/** - * This method MUST be called to initialize the data member of ICMP Messages. - */ -void IcmpMessage::init( const Icmpv6Type type ) -{ - // Note: this code can not be placed in the constructor, because it calls - // virtual function. If you call virtual functions from within a - // constructor, the Base class version of methods will be called, not the - // Derived class, because the Base is constructed before the Derived class. - set_type_v6( type ); - set_code( 0 ); - set_checksum( 0 ); - set_identifier( 0 ); - set_sequence_number( 0 ); -} diff --git a/src/icmp/icmpmessage.h b/src/icmp/icmpmessage.h deleted file mode 100644 index 60ae871..0000000 --- a/src/icmp/icmpmessage.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef ICMP_MESSAGE_H -#define ICMP_MESSAGE_H - -#include - -#include -#include -#include - -#include "icmp/icmptype.h" - -//----------------------------------------------------------------------------- -// IcmpMessage -//----------------------------------------------------------------------------- - -/** - * @brief Abstract class to which the ICMP messages are interpreted. - */ -class IcmpMessage : boost::noncopyable -{ -public: - void init( const Icmpv4Type type ); - void init( const Icmpv6Type type ); - - virtual Icmpv4Type get_type_v4() const = 0; - virtual void set_type_v4( const Icmpv4Type type ) = 0; - - virtual Icmpv6Type get_type_v6() const = 0; - virtual void set_type_v6( const Icmpv6Type type ) = 0; - - virtual uint8_t get_code() const = 0; - virtual void set_code( const uint8_t code ) = 0; - - virtual uint16_t get_checksum() const = 0; - virtual void set_checksum( const uint16_t checksum ) = 0; - - virtual uint16_t get_identifier() const = 0; - virtual void set_identifier( const uint16_t identifier ) = 0; - - virtual uint16_t get_sequence_number() const = 0; - virtual void set_sequence_number( const uint16_t sequence_number ) = 0; - - virtual std::istream& read( std::istream &is ) = 0; - virtual std::ostream& write( std::ostream &os ) const = 0; - -protected: - IcmpMessage(); - virtual ~IcmpMessage(); - -}; - -#endif // ICMP_MESSAGE_H diff --git a/src/icmp/icmppacket.cpp b/src/icmp/icmppacket.cpp index c012ec9..f92bdec 100644 --- a/src/icmp/icmppacket.cpp +++ b/src/icmp/icmppacket.cpp @@ -16,27 +16,102 @@ This exception does not invalidate any other reasons why a work based on this file might be covered by the GNU General Public License. + + Christian Herdtweck, Intra2net AG 2015 */ #include "icmp/icmppacket.h" + #include +#include -//----------------------------------------------------------------------------- -// IcmpPacket -//----------------------------------------------------------------------------- +#include -/** - * @brief Default constructor. - */ -IcmpPacket::IcmpPacket() -{ -} +#include "boost_assert_handler.h" +#include "icmp/icmpechodata.h" +#include "icmp/icmpdestinationunreachabledata.h" + + +using I2n::Logger::GlobalLogger; /** - * @brief Destructor. + * @brief Read (part of) the ICMP packet from the input stream @a is + * + * @param is The input stream. + * + * @return result of the read, currently one of {ok, fail, not enough data} */ -IcmpPacket::~IcmpPacket() +IcmpPacket::ReadReturnCode IcmpPacket::read( std::istream &is ) { + if ( !is.good() ) + return IcmpPacket::ReadReturnCode_BAD_STREAM; + + // try to read ip header + uint8_t version = static_cast( is.peek() ); + if (version == 4) + { + Ipv4Header *new_header = new Ipv4Header(); + is >> *new_header; + ip_head_ptr.reset( new_header ); + } + else if (version == 6) + { + Ipv6Header *new_header = new Ipv6Header(); + is >> *new_header; + ip_head_ptr.reset( new_header ); + } + else // pingcheck-type error throwing + BOOST_ASSERT( !"Invalid IP version!" ); + + if ( is.eof() ) + return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA; + else if ( !is.good() ) + return IcmpPacket::ReadReturnCode_BAD_STREAM; + + // try to read the icmp header + icmp_header.read(is); + + if ( is.eof() ) + return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA; + else if ( !is.good() ) + return IcmpPacket::ReadReturnCode_BAD_STREAM; + + // calculate the size of the ICMP data + std::streamsize data_length = static_cast( ip_head_ptr->get_total_length() ) + - static_cast( ip_head_ptr->get_header_length() ) + - static_cast( icmp_header.get_header_length() ); + + // try to read that amount of data + if ( data_length < 0 ) + { + GlobalLogger.error() << "Invalid size for optional ICMP data: " + << data_length << std::endl; + is.setstate( std::ios::failbit ); + return IcmpPacket::ReadReturnCode_INVALID_SIZE; + } + else if ( data_length > 0 ) + { + if ( get_type_v4() == Icmpv4Type_EchoRequest + || get_type_v4() == Icmpv4Type_EchoReply + || get_type_v6() == Icmpv6Type_EchoRequest + || get_type_v6() == Icmpv6Type_EchoReply ) + icmp_data_ptr.reset( new IcmpEchoData( + static_cast(data_length)) ); + else if (get_type_v4() == Icmpv4Type_DestinationUnreachable + || get_type_v6() == Icmpv6Type_DestinationUnreachable) + icmp_data_ptr.reset( new IcmpDestinationUnreachableData( + static_cast(data_length)) ); + else + return ReadReturnCode_UNKNOWN_ICMP_TYPE; + icmp_data_ptr->read( is ); + } + + if ( is.eof() ) + return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA; + else if ( !is.good() ) + return IcmpPacket::ReadReturnCode_BAD_STREAM; + else + return IcmpPacket::ReadReturnCode_OK; } @@ -51,6 +126,9 @@ std::string IcmpPacket::return_code_to_string( const IcmpPacket::ReadReturnCode case IcmpPacket::ReadReturnCode_BAD_STREAM: return "bad stream!"; break; case IcmpPacket::ReadReturnCode_INVALID_SIZE: return "invalid data size!"; break; case IcmpPacket::ReadReturnCode_UNKNOWN_PROTOCOL: return "unknown protocol, expect ICMPv4/6!"; break; + case IcmpPacket::ReadReturnCode_UNKNOWN_ICMP_TYPE: + return "unknown icmp type, expect echo request/reply or destination unreachable!"; + break; } // if nothing matched @@ -58,6 +136,26 @@ std::string IcmpPacket::return_code_to_string( const IcmpPacket::ReadReturnCode } /** + * @brief Write the ICMP packet to the @c ostream. + * + * the IP header is not written to stream! + * (is usually all 0s anyway) + * + * @param os The output stream. + * + * @return @c true if the write was successful, or @c false if an error occurred. + */ +bool IcmpPacket::write( std::ostream &os ) const +{ + os.clear(); + + icmp_header.write(os); + icmp_data_ptr->write(os); + + return !os.fail(); +} + +/** * @brief create packet from data in @a is; calls IcmpPacket::read * * @param is input stream with hopefully sufficient data @@ -85,3 +183,5 @@ std::ostream& operator<<( packet.write( os ); return os; } + +// (created using vim -- the world's best text editor) diff --git a/src/icmp/icmppacket.h b/src/icmp/icmppacket.h index 139957e..d726ca5 100644 --- a/src/icmp/icmppacket.h +++ b/src/icmp/icmppacket.h @@ -1,47 +1,54 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) +/* + The software in this package is distributed under the GNU General + Public License version 2 (with a special exception described below). + + A copy of GNU General Public License (GPL) is included in this distribution, + in the file COPYING.GPL. + + As a special exception, if other files instantiate templates or use macros + or inline functions from this file, or you compile this file and link it + with other works to produce a work based on this file, this file + does not by itself cause the resulting work to be covered + by the GNU General Public License. + + However the source code for this file must still be made available + in accordance with section (3) of the GNU General Public License. + + This exception does not invalidate any other reasons why a work based + on this file might be covered by the GNU General Public License. + + Christian Herdtweck, Intra2net AG 2015 + */ + #ifndef ICMP_PACKET_H #define ICMP_PACKET_H #include - #include -#include -#include #include -#include +#include +#include +#include -//----------------------------------------------------------------------------- -// IcmpPacket -//----------------------------------------------------------------------------- +#include "ip/ipheader.h" +#include "ip/ipv4header.h" +#include "ip/ipv6header.h" +#include "icmp/icmpheader.h" +#include "icmp/icmpdata.h" +#include "icmp/icmptype.h" -/** - * @brief Abstract class for ICMP Packets. - */ -class IcmpPacket : boost::noncopyable +using boost::asio::ip::icmp; +using boost::asio::ip::address; + +class IcmpPacket { +protected: + IpHeaderPtr ip_head_ptr; + IcmpHeader icmp_header; + IcmpDataPtr icmp_data_ptr; + public: - virtual bool match_echo_reply( - const uint16_t identifier, - const uint16_t sequence_number, - const boost::asio::ip::address &source_address - ) const = 0; - virtual bool match_destination_unreachable( - const uint16_t identifier, - const uint16_t sequence_number, - const boost::asio::ip::address &source_address - ) const = 0; - - virtual void print_echo_reply( - const std::size_t &bytes_transferred, - const boost::posix_time::ptime &time_packet_sent - ) const = 0; - virtual void print_destination_unreachable() const = 0; enum ReadReturnCode { ReadReturnCode_OK = 0, @@ -50,33 +57,102 @@ public: ReadReturnCode_NOT_ENOUGH_DATA, ReadReturnCode_BAD_STREAM, ReadReturnCode_INVALID_SIZE, - ReadReturnCode_UNKNOWN_PROTOCOL + ReadReturnCode_UNKNOWN_PROTOCOL, + ReadReturnCode_UNKNOWN_ICMP_TYPE }; static std::string return_code_to_string( const ReadReturnCode &code ); - virtual ReadReturnCode read( std::istream &is ) = 0; - virtual bool write( std::ostream &os ) const = 0; + IcmpPacket() + : ip_head_ptr() + , icmp_header() + , icmp_data_ptr() + {} - friend std::istream& operator>>( - std::istream &is, - IcmpPacket &packet - ); - friend std::ostream& operator<<( - std::ostream &os, - const IcmpPacket &packet - ); + // IP header is created with only 0s, is not used in write, anyway + IcmpPacket(const icmp::socket::protocol_type &protocol, + const IcmpHeader &icmp_header_arg, + const IcmpDataPtr &icmp_data_arg) + : ip_head_ptr() + , icmp_header( icmp_header_arg ) + , icmp_data_ptr( icmp_data_arg ) + { + if ( icmp::v4() == protocol ) + ip_head_ptr.reset( new Ipv4Header() ); + else if ( icmp::v6() == protocol ) + ip_head_ptr.reset( new Ipv6Header() ); + else // pingcheck-type throwing of exceptions: + BOOST_ASSERT( !"Invalid IP version, need 4 or 6!" ); -protected: - IcmpPacket(); - virtual ~IcmpPacket(); + // create checksum + icmp_header.calc_checksum( icmp_data_ptr->calc_checksum_part() ); + } -}; + Icmpv4Type get_type_v4() + { + if (ip_head_ptr->get_version() == 4) + return static_cast( icmp_header.get_type() ); + else + return Icmpv4Type_InvalidLast; // invalid + } + + Icmpv6Type get_type_v6() + { + if (ip_head_ptr->get_version() == 6) + return static_cast( icmp_header.get_type() ); + else + return Icmpv6Type_InvalidLast; // invalid + } + + + bool check_integrity() { return false; } // not implemented yet + + bool match_destination_unreachable(const uint16_t identifier, + const uint16_t sequence_number, + const address &destination_address) + { + return ip_head_ptr->get_source_address() == destination_address + && icmp_data_ptr->match_destination_unreachable(identifier, + sequence_number); + } -//----------------------------------------------------------------------------- -// IcmpPacketItem -//----------------------------------------------------------------------------- + bool match_echo_reply(const uint16_t identifier, + const uint16_t sequence_number, + const address &destination_address) + { + return ip_head_ptr->get_source_address() == destination_address + && icmp_data_ptr->match_echo_reply(identifier, sequence_number); + } + + /** + * @brief print echo reply / destination unreachable message depending on + * ICMP data type + * + * @param bytes_transferred Number of bytes transferred. + * @param time_packet_sent The time when this packet was sent. + * + * @return void + */ + void print( const size_t &bytes_transferred, + const boost::posix_time::ptime &time_packet_sent ) const + { + size_t bytes_received = bytes_transferred + - ip_head_ptr->get_header_length(); + std::string remote_address + = ip_head_ptr->get_source_address().to_string(); + uint32_t ttl = ip_head_ptr->get_time_to_live(); + icmp_data_ptr->print( bytes_received, time_packet_sent, + remote_address, ttl); + } + + ReadReturnCode read(std::istream &is); + + bool write(std::ostream &os) const; +}; typedef boost::shared_ptr IcmpPacketItem; -#endif // ICMP_PACKET_H +#endif + +// (created using vim -- the world's best text editor) + diff --git a/src/icmp/icmppacketfactory.cpp b/src/icmp/icmppacketfactory.cpp index 448e5c0..ddfd9fe 100644 --- a/src/icmp/icmppacketfactory.cpp +++ b/src/icmp/icmppacketfactory.cpp @@ -30,13 +30,10 @@ #include #include "boost_assert_handler.h" -#include "icmp/icmpchecksum.h" #include "icmp/icmpdata.h" +#include "icmp/icmpheader.h" #include "icmp/icmptype.h" -#include "icmp/icmpv4header.h" -#include "icmp/icmpv4packet.h" -#include "icmp/icmpv6header.h" -#include "icmp/icmpv6packet.h" +#include "icmp/icmpechodata.h" using namespace std; using boost::asio::ip::icmp; @@ -145,14 +142,8 @@ IcmpPacketItem IcmpPacketFactory::create_icmp_packet( { IcmpPacketItem icmp_packet; - if ( icmp::v4() == protocol ) - { - icmp_packet.reset( new Icmpv4Packet() ); - } - else if ( icmp::v6() == protocol ) - { - icmp_packet.reset( new Icmpv6Packet() ); - } + if ( icmp::v4() == protocol || icmp::v6() == protocol ) + icmp_packet.reset( new IcmpPacket() ); else { GlobalLogger.warning() << "ICMP packet creation failed: " @@ -224,80 +215,23 @@ IcmpPacketItem IcmpPacketFactory::create_icmp_packet_echo_request( { BOOST_ASSERT( (icmp::v4() == protocol) || (icmp::v6() == protocol) ); - IcmpPacketItem icmp_packet; - + uint8_t type; if ( icmp::v4() == protocol ) - { - icmp_packet = create_icmpv4_packet_echo_request( identifier, sequence_number ); - } + type = static_cast(Icmpv4Type_EchoRequest); else if ( icmp::v6() == protocol ) - { - icmp_packet = create_icmpv6_packet_echo_request( identifier, sequence_number ); - } - else - { - BOOST_ASSERT( !"Invalid ICMP Packet Type." ); //lint !e506 - } - - return icmp_packet; -} - -/** - * @brief Creates an ICMPv4 Echo Request packet. - * - * @param identifier The packet's identifier number. - * @param sequence_number The packet's sequence number. - * - * @return An ICMPv4 Echo Request packet object. - */ -IcmpPacketItem IcmpPacketFactory::create_icmpv4_packet_echo_request( - const uint16_t identifier, - const uint16_t sequence_number -) -{ - const IcmpData icmp_data( "ping-message" ); + type = static_cast(Icmpv6Type_EchoRequest); + // other case caught be BOOST_ASSERT above - Icmpv4Type type = Icmpv4Type_EchoRequest; uint8_t code = 0; - IcmpChecksum calculator( icmp_data.begin(), icmp_data.end() ); - uint16_t checksum = calculator.compute( - type, code, identifier, sequence_number - ); - Icmpv4Header icmp_header( - type, code, checksum, identifier, sequence_number - ); - IcmpPacketItem icmp_packet( new Icmpv4Packet( icmp_header, icmp_data ) ); - - return icmp_packet; -} + IcmpHeader icmp_header( type, code ); -/** - * @brief Creates an ICMPv6 Echo Request packet. - * - * @param identifier The packet's identifier number. - * @param sequence_number The packet's sequence number. - * - * @return An ICMPv6 Echo Request packet object. - */ -IcmpPacketItem IcmpPacketFactory::create_icmpv6_packet_echo_request( - const uint16_t identifier, - const uint16_t sequence_number -) -{ - const IcmpData icmp_data( "ping-message" ); + IcmpDataPtr icmp_data( new IcmpEchoData( identifier, sequence_number, + "ping-message" ) ); - Icmpv6Type type = Icmpv6Type_EchoRequest; - uint8_t code = 0; - IcmpChecksum calculator( icmp_data.begin(), icmp_data.end() ); - uint16_t checksum = calculator.compute( - type, code, identifier, sequence_number - ); - Icmpv6Header icmp_header( - type, code, checksum, identifier, sequence_number - ); - IcmpPacketItem icmp_packet( new Icmpv6Packet( icmp_header, icmp_data ) ); + IcmpPacketItem icmp_packet( new IcmpPacket( protocol, + icmp_header, + icmp_data ) ); return icmp_packet; } - diff --git a/src/icmp/icmppinger.cpp b/src/icmp/icmppinger.cpp index 9d2f864..496738e 100644 --- a/src/icmp/icmppinger.cpp +++ b/src/icmp/icmppinger.cpp @@ -320,7 +320,7 @@ bool IcmpPinger::handle_receive_icmp_packet(const IcmpPacketItem icmp_packet, ReplyReceived = true; does_match = true; - icmp_packet->print_echo_reply( bytes_transferred, TimeSent ); + icmp_packet->print( bytes_transferred, TimeSent ); set_ping_status( PingStatus_SuccessReply ); @@ -337,7 +337,7 @@ bool IcmpPinger::handle_receive_icmp_packet(const IcmpPacketItem icmp_packet, ReplyReceived = true; does_match = true; - icmp_packet->print_destination_unreachable(); + icmp_packet->print( bytes_transferred, TimeSent ); set_ping_status( PingStatus_FailureDestinationUnreachable ); diff --git a/src/icmp/icmpv4header.cpp b/src/icmp/icmpv4header.cpp deleted file mode 100644 index 1f0e680..0000000 --- a/src/icmp/icmpv4header.cpp +++ /dev/null @@ -1,191 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#include "icmp/icmpv4header.h" - -#include "boost_assert_handler.h" -#include "icmp/icmpdestinationunreachablemessage.h" -#include "icmp/icmpechoreplymessage.h" -#include "icmp/icmpechorequestmessage.h" -#include "icmp/icmpgenericmessage.h" - -#include -using I2n::Logger::GlobalLogger; - -using namespace std; -using boost::shared_ptr; - -//----------------------------------------------------------------------------- -// Icmpv4Header -//----------------------------------------------------------------------------- - -static const size_t HeaderSizeInBytes = 8; - -Icmpv4Header::Icmpv4Header() : - MessageFormat() -{ -} - -Icmpv4Header::Icmpv4Header( - const Icmpv4Type type, - const uint8_t code, - const uint16_t checksum, - const uint16_t identifier, - const uint16_t sequence_number -) : - MessageFormat() -{ - set_icmp_message_format( type ); - - set_type( type ); - set_code( code ); - set_checksum( checksum ); - set_identifier( identifier ); - set_sequence_number( sequence_number ); -} - -Icmpv4Type Icmpv4Header::get_type() const -{ - return get_icmp_message_format()->get_type_v4(); -} - -void Icmpv4Header::set_type( const Icmpv4Type type ) -{ - get_icmp_message_format()->set_type_v4( type ); -} //lint !e1762 - -uint8_t Icmpv4Header::get_code() const -{ - return get_icmp_message_format()->get_code(); -} - -void Icmpv4Header::set_code( const uint8_t code ) -{ - get_icmp_message_format()->set_code( code ); -} //lint !e1762 - -uint16_t Icmpv4Header::get_checksum() const -{ - return get_icmp_message_format()->get_checksum(); -} - -void Icmpv4Header::set_checksum( const uint16_t checksum ) -{ - get_icmp_message_format()->set_checksum( checksum ); -} //lint !e1762 - -uint16_t Icmpv4Header::get_identifier() const -{ - return get_icmp_message_format()->get_identifier(); -} - -void Icmpv4Header::set_identifier( const uint16_t identifier ) -{ - get_icmp_message_format()->set_identifier( identifier ); -} //lint !e1762 - -uint16_t Icmpv4Header::get_sequence_number() const -{ - return get_icmp_message_format()->get_sequence_number(); -} - -void Icmpv4Header::set_sequence_number( const uint16_t sequence_number ) -{ - get_icmp_message_format()->set_sequence_number( sequence_number ); -} //lint !e1762 - -shared_ptr Icmpv4Header::get_icmp_message_format() const -{ - BOOST_ASSERT( MessageFormat.get() != NULL ); - - return MessageFormat; -} - -void Icmpv4Header::set_icmp_message_format( const Icmpv4Type type ) -{ - BOOST_ASSERT( MessageFormat.get() == NULL ); - - if ( MessageFormat.get() == NULL ) - { - switch ( type ) - { - case Icmpv4Type_EchoReply: - MessageFormat.reset( new IcmpEchoReplyMessage ); - break; - case Icmpv4Type_EchoRequest: - MessageFormat.reset( new IcmpEchoRequestMessage ); - break; - case Icmpv4Type_DestinationUnreachable: - MessageFormat.reset( - new IcmpDestinationUnreachableMessage - ); - break; - case Icmpv4Type_SourceQuench: - case Icmpv4Type_Redirect: - case Icmpv4Type_TimeExceeded: - case Icmpv4Type_ParameterProblem: - case Icmpv4Type_TimestampRequest: - case Icmpv4Type_TimestampReply: - case Icmpv4Type_InfoRequest: - case Icmpv4Type_InfoReply: - case Icmpv4Type_AddressRequest: - case Icmpv4Type_AddressReply: - case Icmpv4Type_Generic: - MessageFormat.reset( new IcmpGenericMessage ); - break; - case Icmpv4Type_InvalidLast: - default: - GlobalLogger.error() << "Invalid ICMPv4 message type " << static_cast(type) << "!"; - BOOST_ASSERT( !"Try to set an invalid ICMPv4 message type" ); - break; - } - - MessageFormat->init( type ); - } - - BOOST_ASSERT( MessageFormat.get() != NULL ); - BOOST_ASSERT( MessageFormat->get_type_v4() != Icmpv4Type_InvalidLast ); -} - -void Icmpv4Header::set_icmp_message_format( std::istream &is ) -{ - // read the first byte, which contains the type of the ICMP message - char first_byte; - (void) is.read( &first_byte, 1 ); - - // must keep the stream intact, so place the read byte back - (void) is.putback( first_byte ); - - // now select the message format for the given type - Icmpv4Type header_type = static_cast( first_byte ); - set_icmp_message_format( header_type ); -} - -size_t Icmpv4Header::get_header_length() const -{ - return HeaderSizeInBytes; -} - -std::istream& operator>>( - std::istream &is, - Icmpv4Header &header -) -{ - // select the message format which will parse the fields - header.set_icmp_message_format( is ); - - // delegate the parsing of the fields to a specialized decoder - return header.get_icmp_message_format()->read( is ); -} - -std::ostream& operator<<( - std::ostream &os, - const Icmpv4Header &header -) -{ - // delegate the writing of the fields to a specialized encoder - return header.get_icmp_message_format()->write( os ); -} diff --git a/src/icmp/icmpv4header.h b/src/icmp/icmpv4header.h deleted file mode 100644 index 86173c1..0000000 --- a/src/icmp/icmpv4header.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef ICMPV4_HEADER_H -#define ICMPV4_HEADER_H - -#include - -#include -#include - -#include - -#include "icmp/icmpmessage.h" -#include "icmp/icmptype.h" - -//----------------------------------------------------------------------------- -// Icmpv4Header -//----------------------------------------------------------------------------- - -/** - * @brief This class represents the ICMP version 4 Header. - * - * The ICMP Generic Header Format is: - * - * @code - * 0 8 16 31 - * +---------------+---------------+------------------------------+ --- - * | | | | ^ - * | type | code | checksum | 4 bytes - * | | | | v - * +---------------+---------------+------------------------------+ --- - * | | - * | specific to each message | - * | | - * +-------------------------------+------------------------------+ - * @endcode - */ -class Icmpv4Header -{ -public: - Icmpv4Header(); - Icmpv4Header( - const Icmpv4Type type, - const uint8_t code, - const uint16_t checksum, - const uint16_t identifier, - const uint16_t sequence_number - ); - - Icmpv4Type get_type() const; - void set_type( const Icmpv4Type type ); - - uint8_t get_code() const; - void set_code( const uint8_t code ); - - uint16_t get_checksum() const; - void set_checksum( const uint16_t checksum ); - - uint16_t get_identifier() const; - void set_identifier( const uint16_t identifier ); - - uint16_t get_sequence_number() const; - void set_sequence_number( const uint16_t sequence_number ); - - boost::shared_ptr get_icmp_message_format() const; - void set_icmp_message_format( const Icmpv4Type type ); - void set_icmp_message_format( std::istream &is ); - - size_t get_header_length() const; - - friend std::istream& operator>>( - std::istream &is, - Icmpv4Header &header - ); - friend std::ostream& operator<<( - std::ostream &os, - const Icmpv4Header &header - ); - -private: - /// Changeable pointer to different ICMP messages types. - boost::shared_ptr MessageFormat; - -}; - -#endif // ICMPV4_HEADER_H diff --git a/src/icmp/icmpv4packet.cpp b/src/icmp/icmpv4packet.cpp deleted file mode 100644 index 82ed70d..0000000 --- a/src/icmp/icmpv4packet.cpp +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#include "icmp/icmpv4packet.h" - -#include - -#include -#include - -#include "boost_assert_handler.h" - -using namespace std; -using boost::asio::ip::address; -using boost::date_time::time_resolution_traits_adapted64_impl; -using boost::posix_time::ptime; -using boost::posix_time::microsec_clock; -using boost::scoped_array; -using I2n::Logger::GlobalLogger; - -//----------------------------------------------------------------------------- -// Icmpv4Packet -//----------------------------------------------------------------------------- - -/** - * @brief Default constructor. - */ -Icmpv4Packet::Icmpv4Packet() : - IpHeader(), - IcmpPayloadHeader(), - IcmpPayloadData() -{ -} - -/** - * @brief Parameterized constructor. - * - * @param icmp_header The ICMP header. - * @param icmp_data The ICMP payload data. - */ -Icmpv4Packet::Icmpv4Packet( - const Icmpv4Header &icmp_header, - const IcmpData &icmp_data -) : - IpHeader(), - IcmpPayloadHeader( icmp_header ), - IcmpPayloadData( icmp_data ) -{ -} - -/** - * @brief Destructor. - */ -Icmpv4Packet::~Icmpv4Packet() -{ -} - -/** - * @brief Obtain the IP header. - * - * @return The IP header object. - */ -Ipv4Header Icmpv4Packet::get_ip_header() const -{ - return IpHeader; -} - -/** - * @brief Obtain the ICMP header. - * - * @return The ICMP header object. - */ -Icmpv4Header Icmpv4Packet::get_icmp_header() const -{ - return IcmpPayloadHeader; -} - -/** - * @brief Obtain the ICMP payload data. - * - * @return The ICMP data. - */ -IcmpData Icmpv4Packet::get_icmp_data() const -{ - return IcmpPayloadData; -} - -/** - * @brief Convenience method to check if this packet, matching the arguments, - * is an echo reply. - * - * @param identifier The identifier. - * @param sequence_number The sequence number. - * @param source_address The source address. - * - * @return @c true if this packet is an echo reply, or @c false otherwise. - */ -bool Icmpv4Packet::match_echo_reply( - const uint16_t identifier, - const uint16_t sequence_number, - const address &source_address -) const -{ - BOOST_ASSERT( source_address.is_v4() ); - - return match( Icmpv4Type_EchoReply, identifier, sequence_number, source_address ); -} - -/** - * @brief Convenience method to check if this packet, matching the arguments, - * is a destination unreachable. - * - * @param identifier The identifier. - * @param sequence_number The sequence number. - * @param source_address The source address. - * - * @return @c true if this packet is a destination unreachable, or @c false - * otherwise. - */ -bool Icmpv4Packet::match_destination_unreachable( - const uint16_t identifier, - const uint16_t sequence_number, - const address &source_address -) const -{ - BOOST_ASSERT( source_address.is_v4() ); - - return match( Icmpv4Type_DestinationUnreachable, identifier, sequence_number, source_address ); -} - -/** - * @brief Check if this object matches with all the parameters. - * - * @param type The type of ICMP message. - * @param identifier The identifier. - * @param sequence_number The sequence number. - * @param source_address The source address. - * - * @return @c true if this matches all the parameters, or @c false if at least - * one does not match. - */ -bool Icmpv4Packet::match( - const Icmpv4Type type, - const uint16_t identifier, - const uint16_t sequence_number, - const address &source_address -) const -{ - BOOST_ASSERT( source_address.is_v4() ); - - bool type_match = IcmpPayloadHeader.get_type() == type ? true : false; - bool identifier_match = IcmpPayloadHeader.get_identifier() == identifier ? true: false; - bool seq_num_match = IcmpPayloadHeader.get_sequence_number() == sequence_number ? true : false; - bool address_match = IpHeader.get_source_address() == source_address ? true : false; - - return ( type_match && identifier_match && seq_num_match && address_match ); -} - -/** - * @brief Prints the ICMP echo reply messages. - * - * @param bytes_transferred Number of bytes transferred. - * @param time_packet_sent The time when this packet was sent. - * - * @return void - */ -void Icmpv4Packet::print_echo_reply( - const size_t &bytes_transferred, - const ptime &time_packet_sent -) const -{ - BOOST_ASSERT( get_icmp_header().get_type() == Icmpv4Type_EchoReply ); - - Ipv4Header ipv4_header = get_ip_header(); - Icmpv4Header icmpv4_header = get_icmp_header(); - - size_t bytes_received = bytes_transferred - ipv4_header.get_header_length(); - string remote_address = ipv4_header.get_source_address().to_string(); - uint16_t sequence_number = icmpv4_header.get_sequence_number(); - uint32_t ttl = ipv4_header.get_time_to_live(); - ptime now = microsec_clock::universal_time(); - time_resolution_traits_adapted64_impl::int_type elapsed_time = - (now - time_packet_sent).total_milliseconds(); - - GlobalLogger.info() << bytes_received << " bytes " - << "from " << remote_address - << ": icmp_seq=" << sequence_number - << " ttl=" << ttl - << " time=" << elapsed_time << " ms" << endl; -} - -/** - * @brief Prints the destination unreachable messages. - * - * @return void - */ -void Icmpv4Packet::print_destination_unreachable() const -{ - BOOST_ASSERT( get_icmp_header().get_type() == Icmpv4Type_DestinationUnreachable ); - - Ipv4Header ipv4_hdr = get_ip_header(); - Icmpv4Header icmpv4_hdr = get_icmp_header(); - - string local_address = ipv4_hdr.get_destination_address().to_string(); - uint16_t sequence_number = icmpv4_hdr.get_sequence_number(); - - GlobalLogger.info() << "From " << local_address - << " icmp_seq=" << sequence_number - << " Destination Net Unreachable" << endl; -} - -/** - * @brief Read (part of) the ICMP packet from the input stream @a is - * - * @param is The input stream. - * - * @return result of the read, currently one of {ok, fail, not enough data} - */ -IcmpPacket::ReadReturnCode Icmpv4Packet::read( istream &is ) -{ - if ( !is.good() ) - return IcmpPacket::ReadReturnCode_BAD_STREAM; - - // try to read ip header - is >> IpHeader; - - if ( is.eof() ) - return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA; - else if ( !is.good() ) - return IcmpPacket::ReadReturnCode_BAD_STREAM; - - // try to read the icmp header - is >> IcmpPayloadHeader; - - if ( is.eof() ) - return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA; - else if ( !is.good() ) - return IcmpPacket::ReadReturnCode_BAD_STREAM; - - // calculate the size of the ICMP data - streamsize data_length = static_cast( IpHeader.get_total_length() ) - - static_cast( IpHeader.get_header_length() ) - - static_cast( IcmpPayloadHeader.get_header_length() ); - - // try to read that amount of data - if ( data_length < 0 ) - { - GlobalLogger.error() << "Invalid size for optional ICMP data: " - << data_length << endl; - is.setstate( ios::failbit ); - return IcmpPacket::ReadReturnCode_INVALID_SIZE; - } - else if ( data_length > 0 ) - { - size_t options_size = static_cast( data_length ); - scoped_array scoped_data( new uint8_t[options_size+1] ); // need a 0 after data - memset(scoped_data.get(), 0, (options_size+1)*sizeof(uint8_t)); - char *char_data = reinterpret_cast( scoped_data.get() ); - - (void) is.read( char_data, data_length ); // leave 0 at the end - IcmpPayloadData = char_data; // implicit cast - } - - if ( is.eof() ) - return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA; - else if ( !is.good() ) - return IcmpPacket::ReadReturnCode_BAD_STREAM; - else - return IcmpPacket::ReadReturnCode_OK; -} - -/** - * @brief Write the ICMP packet to the @c ostream. - * - * @param os The output stream. - * - * @return @c true if the write was successful, or @c false if an error occurred. - */ -bool Icmpv4Packet::write( std::ostream &os ) const -{ - os.clear(); - - os << IcmpPayloadHeader << IcmpPayloadData; - - return !os.fail(); -} - diff --git a/src/icmp/icmpv4packet.h b/src/icmp/icmpv4packet.h deleted file mode 100644 index 1c0d075..0000000 --- a/src/icmp/icmpv4packet.h +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef ICMPV4_PACKET_H -#define ICMPV4_PACKET_H - -#include - -#include -#include - -#include - -#include "icmp/icmppacket.h" -#include "icmp/icmpv4header.h" -#include "icmp/icmpdata.h" -#include "icmp/icmptype.h" -#include "ip/ipv4header.h" - -//----------------------------------------------------------------------------- -// Icmpv4Packet -//----------------------------------------------------------------------------- - -/** - * @brief This class represents the ICMP version 4 Packet. - * - * The ICMP Packet format is: - * - * @code - * 0 8 16 31 - * +-------+-------+---------------+------------------------------+ --- - * | | | | | ^ - * |version|header | type of | total length in bytes | | - * | (4) | length| service | | | - * +-------+-------+---------------+-+-+-+------------------------+ | - * | | | | | | | - * | identification |0|D|M| fragment offset | | - * | | |F|F| | | - * +---------------+---------------+-+-+-+------------------------+ | - * | | | | | - * | time to live | protocol | header checksum | IPv4 Header - * | | | | 20 bytes - * +---------------+---------------+------------------------------+ | - * | | | - * | source IPv4 address | | - * | | | - * +--------------------------------------------------------------+ | - * | | | - * | destination IPv4 address | | - * | | v - * +---------------+---------------+------------------------------+ --- - * | | | | ^ - * | type | code | checksum | | - * | | | | | - * +---------------+---------------+------------------------------+ | - * | | | ICMP Payload - * | identifier | sequence number | (header + - * | | | data) - * +-------------------------------+------------------------------+ 8+ bytes - * | | | - * | data (optional) | | - * | | v - * +-------------------------------+------------------------------+ --- - * @endcode - */ -class Icmpv4Packet : public IcmpPacket -{ -public: - Icmpv4Packet(); - Icmpv4Packet( - const Icmpv4Header &icmp_header, - const IcmpData &icmp_data - ); - virtual ~Icmpv4Packet(); - - Ipv4Header get_ip_header() const; - Icmpv4Header get_icmp_header() const; - IcmpData get_icmp_data() const; - - virtual bool match_echo_reply( - const uint16_t identifier, - const uint16_t sequence_number, - const boost::asio::ip::address &source_address - ) const; - virtual bool match_destination_unreachable( - const uint16_t identifier, - const uint16_t sequence_number, - const boost::asio::ip::address &source_address - ) const; - - virtual void print_echo_reply( - const std::size_t &bytes_transferred, - const boost::posix_time::ptime &time_packet_sent - ) const; - virtual void print_destination_unreachable() const; - - virtual ReadReturnCode read( std::istream &is ); - bool write( std::ostream &os ) const; - - -private: - bool match( - const Icmpv4Type type, - const uint16_t identifier, - const uint16_t sequence_number, - const boost::asio::ip::address &source_address - ) const; - -private: - /// The IP header. - Ipv4Header IpHeader; - /// The ICMP packet header. - Icmpv4Header IcmpPayloadHeader; - /// The ICMP packet payload (data). - IcmpData IcmpPayloadData; -}; - -#endif // ICMPV4_PACKET_H diff --git a/src/icmp/icmpv6header.cpp b/src/icmp/icmpv6header.cpp deleted file mode 100644 index fd5425d..0000000 --- a/src/icmp/icmpv6header.cpp +++ /dev/null @@ -1,201 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#include "icmp/icmpv6header.h" - -#include "boost_assert_handler.h" -#include "icmp/icmpdestinationunreachablemessage.h" -#include "icmp/icmpechoreplymessage.h" -#include "icmp/icmpechorequestmessage.h" -#include "icmp/icmpgenericmessage.h" - -using namespace std; -using boost::shared_ptr; - -//----------------------------------------------------------------------------- -// Icmpv6Header -//----------------------------------------------------------------------------- - -static const size_t HeaderSizeInBytes = 4; - -Icmpv6Header::Icmpv6Header() : - MessageFormat() -{ -} - -Icmpv6Header::Icmpv6Header( - const Icmpv6Type type, - const uint8_t code, - const uint16_t checksum, - const uint16_t identifier, - const uint16_t sequence_number -) : - MessageFormat() -{ - set_icmp_message_format( type ); - - set_type( type ); - set_code( code ); - set_checksum( checksum ); - set_identifier( identifier ); - set_sequence_number( sequence_number ); -} - -Icmpv6Type Icmpv6Header::get_type() const -{ - return get_icmp_message_format()->get_type_v6(); -} - -void Icmpv6Header::set_type( const Icmpv6Type type ) -{ - get_icmp_message_format()->set_type_v6( type ); -} //lint !e1762 - -uint8_t Icmpv6Header::get_code() const -{ - return get_icmp_message_format()->get_code(); -} - -void Icmpv6Header::set_code( const uint8_t code ) -{ - get_icmp_message_format()->set_code( code ); -} //lint !e1762 - -uint16_t Icmpv6Header::get_checksum() const -{ - return get_icmp_message_format()->get_checksum(); -} - -void Icmpv6Header::set_checksum( const uint16_t checksum ) -{ - get_icmp_message_format()->set_checksum( checksum ); -} //lint !e1762 - -uint16_t Icmpv6Header::get_identifier() const -{ - return get_icmp_message_format()->get_identifier(); -} - -void Icmpv6Header::set_identifier( const uint16_t identifier ) -{ - get_icmp_message_format()->set_identifier( identifier ); -} //lint !e1762 - -uint16_t Icmpv6Header::get_sequence_number() const -{ - return get_icmp_message_format()->get_sequence_number(); -} - -void Icmpv6Header::set_sequence_number( const uint16_t sequence_number ) -{ - get_icmp_message_format()->set_sequence_number( sequence_number ); -} //lint !e1762 - -shared_ptr Icmpv6Header::get_icmp_message_format() const -{ - BOOST_ASSERT( MessageFormat.get() != NULL ); - - return MessageFormat; -} - -void Icmpv6Header::set_icmp_message_format( const Icmpv6Type type ) -{ - BOOST_ASSERT( MessageFormat.get() == NULL ); - - if ( MessageFormat.get() == NULL ) - { - switch ( type ) - { - case Icmpv6Type_EchoReply: - MessageFormat.reset( new IcmpEchoReplyMessage ); - break; - case Icmpv6Type_EchoRequest: - MessageFormat.reset( new IcmpEchoRequestMessage ); - break; - case Icmpv6Type_DestinationUnreachable: - MessageFormat.reset( - new IcmpDestinationUnreachableMessage - ); - break; - case Icmpv6Type_PacketTooBig: - case Icmpv6Type_TimeExceeded: - case Icmpv6Type_ParameterProblem: - case Icmpv6Type_RouterSolicitation: - case Icmpv6Type_RouterAdvertisement: - case Icmpv6Type_NeighborSolicitation: - case Icmpv6Type_NeighborAdvertisement: - case Icmpv6Type_RedirectMessage: - case Icmpv6Type_RouterRenumbering: - case Icmpv6Type_ICMPNodeInformationQuery: - case Icmpv6Type_ICMPNodeInformationResponse: - case Icmpv6Type_InverseNeighborDiscoverySolicitationMessage: - case Icmpv6Type_InverseNeighborDiscoveryAdvertisementMessage: - case Icmpv6Type_MulticastListenerDiscovery: - case Icmpv6Type_HomeAgentAddressDiscoveryRequestMessage: - case Icmpv6Type_HomeAgentAddressDiscoveryReplyMessage: - case Icmpv6Type_MobilePrefixSolicitation: - case Icmpv6Type_MobilePrefixAdvertisement: - case Icmpv6Type_CertificationPathSolicitation: - case Icmpv6Type_CertificationPathAdvertisement: - case Icmpv6Type_MulticastRouterAdvertisement: - case Icmpv6Type_MulticastRouterSolicitation: - case Icmpv6Type_MulticastRouterTermination: - case Icmpv6Type_Generic: - MessageFormat.reset( new IcmpGenericMessage ); - break; - case Icmpv6Type_First: - case Icmpv6Type_InvalidLast: - default: - BOOST_ASSERT( !"Try to set an invalid ICMPv6 message type" ); - break; - } - - MessageFormat->init( type ); - } - - BOOST_ASSERT( MessageFormat.get() != NULL ); - BOOST_ASSERT( MessageFormat->get_type_v6() != Icmpv6Type_InvalidLast ); -} - -void Icmpv6Header::set_icmp_message_format( std::istream &is ) -{ - // read the first byte, which contains the type of the ICMP message - uint8_t first_byte = 0; - (void) is.read( reinterpret_cast(&first_byte), 1 ); - - // must keep the stream intact, so place the read byte back - (void) is.putback( static_cast(first_byte) ); - - // now select the message format for the given type - Icmpv6Type header_type = static_cast( first_byte ); - set_icmp_message_format( header_type ); -} - -size_t Icmpv6Header::get_header_length() const -{ - return HeaderSizeInBytes; -} - -std::istream& operator>>( - std::istream &is, - Icmpv6Header &header -) -{ - // select the message format which will parse the fields - header.set_icmp_message_format( is ); - - // delegate the parsing of the fields to a specialized decoder - return header.get_icmp_message_format()->read( is ); -} - -std::ostream& operator<<( - std::ostream &os, - const Icmpv6Header &header -) -{ - // delegate the writing of the fields to a specialized encoder - return header.get_icmp_message_format()->write( os ); -} diff --git a/src/icmp/icmpv6header.h b/src/icmp/icmpv6header.h deleted file mode 100644 index 3aec4b0..0000000 --- a/src/icmp/icmpv6header.h +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef ICMPV6_HEADER_H -#define ICMPV6_HEADER_H - -#include - -#include -#include - -#include - -#include "icmp/icmpmessage.h" -#include "icmp/icmptype.h" - -//----------------------------------------------------------------------------- -// Icmpv6Header -//----------------------------------------------------------------------------- - -/** - * @brief This class represents the ICMP version 6 Header. - * - * The ICMP Generic Header Format is: - * - * @code - * 0 8 16 31 - * +---------------+---------------+------------------------------+ --- - * | | | | ^ - * | type | code | checksum | 4 bytes - * | | | | v - * +---------------+---------------+------------------------------+ --- - * | | - * | specific to each message | - * | | - * +-------------------------------+------------------------------+ - * @endcode - */ -class Icmpv6Header -{ -public: - Icmpv6Header(); - Icmpv6Header( - const Icmpv6Type type, - const uint8_t code, - const uint16_t checksum, - const uint16_t identifier, - const uint16_t sequence_number - ); - - Icmpv6Type get_type() const; - void set_type( const Icmpv6Type type ); - - uint8_t get_code() const; - void set_code( const uint8_t code ); - - uint16_t get_checksum() const; - void set_checksum( const uint16_t checksum ); - - uint16_t get_identifier() const; - void set_identifier( const uint16_t identifier ); - - uint16_t get_sequence_number() const; - void set_sequence_number( const uint16_t sequence_number ); - - boost::shared_ptr get_icmp_message_format() const; - void set_icmp_message_format( const Icmpv6Type type ); - void set_icmp_message_format( std::istream &is ); - - size_t get_header_length() const; - - friend std::istream& operator>>( - std::istream &is, - Icmpv6Header &header - ); - friend std::ostream& operator<<( - std::ostream &os, - const Icmpv6Header &header - ); - -private: - /// Changeable pointer to different ICMP messages types. - boost::shared_ptr MessageFormat; - -}; - -#endif // ICMPV6_HEADER_H diff --git a/src/icmp/icmpv6packet.cpp b/src/icmp/icmpv6packet.cpp deleted file mode 100644 index 6e8dfb8..0000000 --- a/src/icmp/icmpv6packet.cpp +++ /dev/null @@ -1,305 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#include "icmp/icmpv6packet.h" - -#include - -#include -#include - -#include "boost_assert_handler.h" - -using namespace std; -using boost::asio::ip::address; -using boost::date_time::time_resolution_traits_adapted64_impl; -using boost::posix_time::ptime; -using boost::posix_time::microsec_clock; -using boost::scoped_array; -using I2n::Logger::GlobalLogger; - -//----------------------------------------------------------------------------- -// Icmpv6Packet -//----------------------------------------------------------------------------- - -/** - * @brief Default constructor. - */ -Icmpv6Packet::Icmpv6Packet() : - IpHeader(), - IcmpPayloadHeader(), - IcmpPayloadData() -{ -} - -/** - * @brief Parameterized constructor. - * - * @param icmp_header The ICMP header. - * @param icmp_data The ICMP payload data. - */ -Icmpv6Packet::Icmpv6Packet( - const Icmpv6Header &icmp_header, - const IcmpData &icmp_data -) : - IpHeader(), - IcmpPayloadHeader( icmp_header ), - IcmpPayloadData( icmp_data ) -{ -} - -/** - * @brief Destructor. - */ -Icmpv6Packet::~Icmpv6Packet() -{ -} - -/** - * @brief Obtain the IP header. - * - * @return The IP header object. - */ -Ipv6Header Icmpv6Packet::get_ip_header() const -{ - return IpHeader; -} - -/** - * @brief Obtain the ICMP header. - * - * @return The ICMP header object. - */ -Icmpv6Header Icmpv6Packet::get_icmp_header() const -{ - return IcmpPayloadHeader; -} - -/** - * @brief Obtain the ICMP payload data. - * - * @return The ICMP data. - */ -IcmpData Icmpv6Packet::get_icmp_data() const -{ - return IcmpPayloadData; -} - -/** - * @brief Convenience method to check if this packet, matching the arguments, - * is a echo reply. - * - * @param identifier The identifier. - * @param sequence_number The sequence number. - * @param source_address The source address. - * - * @return @c true if this packet is a echo reply, or @c false otherwise. - */ -bool Icmpv6Packet::match_echo_reply( - const uint16_t identifier, - const uint16_t sequence_number, - const address &source_address -) const -{ - BOOST_ASSERT( source_address.is_v6() ); - - return match( Icmpv6Type_EchoReply, identifier, sequence_number, source_address ); -} - -/** - * @brief Convenience method to check if this packet, matching the arguments, - * is a destination unreachable. - * - * @param identifier The identifier. - * @param sequence_number The sequence number. - * @param source_address The source address. - * - * @return @c true if this packet is a destination unreachable, or @c false - * otherwise. - */ -bool Icmpv6Packet::match_destination_unreachable( - const uint16_t identifier, - const uint16_t sequence_number, - const address &source_address -) const -{ - BOOST_ASSERT( source_address.is_v6() ); - - return match( Icmpv6Type_DestinationUnreachable, identifier, sequence_number, source_address ); -} - -/** - * @brief Check if this object matches with all the parameters. - * - * @param type The type of ICMP message. - * @param identifier The identifier. - * @param sequence_number The sequence number. - * @param source_address The source address. - * - * @return @c true if this matches all the parameters, or @c false if at least - * one does not match. - */ -bool Icmpv6Packet::match( - const Icmpv6Type type, - const uint16_t identifier, - const uint16_t sequence_number, - const address &source_address -) const -{ - BOOST_ASSERT( source_address.is_v6() ); - - bool type_match = IcmpPayloadHeader.get_type() == type ? true : false; - bool identifier_match = IcmpPayloadHeader.get_identifier() == identifier ? true: false; - bool seq_num_match = IcmpPayloadHeader.get_sequence_number() == sequence_number ? true : false; -#ifdef IPV6_DATA_PRESENT_IN_ISTREAM - // TODO operator>> does not read IpHeader, thus this object is not initialized - // must check why IPv6 data does not come in the istream like IPv4 data - bool address_match = IpHeader.get_source_address() == source_address ? true : false; - - return ( type_match && identifier_match && seq_num_match && address_match ); -#else - - return ( type_match && identifier_match && seq_num_match ); -#endif -} - -/** - * @brief Prints the ICMP echo reply messages. - * - * @param bytes_transferred Number of bytes transferred. - * @param time_packet_sent The time when this packet was sent. - * - * @return void - */ -void Icmpv6Packet::print_echo_reply( - const size_t &bytes_transferred, - const ptime &time_packet_sent -) const -{ - BOOST_ASSERT( get_icmp_header().get_type() == Icmpv6Type_EchoReply ); - - Ipv6Header ipv6_header = get_ip_header(); - Icmpv6Header icmpv6_header = get_icmp_header(); - - size_t bytes_received = bytes_transferred - ipv6_header.get_payload_length(); -#ifdef IPV6_DATA_PRESENT_IN_ISTREAM - //TODO WHY IPv6 does not come like IPv4???? - string remote_address = ipv6_header.get_source_address().to_string(); -#else - string remote_address = "?"; -#endif - - uint16_t sequence_number = icmpv6_header.get_sequence_number(); - uint32_t ttl = ipv6_header.get_hop_limit(); - ptime now = microsec_clock::universal_time(); - time_resolution_traits_adapted64_impl::int_type elapsed_time = - (now - time_packet_sent).total_milliseconds(); - - GlobalLogger.info() << bytes_received << " bytes " - << "from " << remote_address - << ": icmp_seq=" << sequence_number - << " ttl=" << ttl - << " time=" << elapsed_time << " ms" << endl; -} - -/** - * @brief Prints the destination unreachable messages. - * - * @return void - */ -void Icmpv6Packet::print_destination_unreachable() const -{ - BOOST_ASSERT( get_icmp_header().get_type() == Icmpv6Type_DestinationUnreachable ); - - Ipv6Header ipv6_hdr = get_ip_header(); - Icmpv6Header icmpv6_hdr = get_icmp_header(); - - string local_address = ipv6_hdr.get_destination_address().to_string(); - uint16_t sequence_number = icmpv6_hdr.get_sequence_number(); - - GlobalLogger.info() << "From " << local_address - << " icmp_seq=" << sequence_number - << " Destination Net Unreachable" << endl; -} - -/** - * @brief Read (part of) the ICMP packet from the input stream @a is - * - * @param is The input stream. - * - * @return result of the read, currently one of {ok, fail, not enough data} - */ -IcmpPacket::ReadReturnCode Icmpv6Packet::read( istream &is ) -{ - if ( !is.good() ) - return IcmpPacket::ReadReturnCode_BAD_STREAM; - -#ifdef IPV6_DATA_PRESENT_IN_ISTREAM - //TODO WHY IPv6 does not come like IPv4???? - // try to read ip header - is >> IpHeader; - - if ( is.eof() ) - return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA; - else if ( !is.good() ) - return IcmpPacket::ReadReturnCode_BAD_STREAM; -#endif - - // try to read the icmp header - is >> IcmpPayloadHeader; - - if ( is.eof() ) - return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA; - else if ( !is.good() ) - return IcmpPacket::ReadReturnCode_BAD_STREAM; - - // calculate the size of the ICMP data - streamsize data_length = static_cast( IpHeader.get_payload_length() ) - - static_cast( IcmpPayloadHeader.get_header_length() ); - - // try to read that amount of data - if ( data_length < 0 ) - { - GlobalLogger.error() << "Invalid size for optional ICMP data: " - << data_length << endl; - is.setstate( ios::failbit ); - return IcmpPacket::ReadReturnCode_INVALID_SIZE; - } - else if ( data_length > 0 ) - { - size_t options_size = static_cast( data_length ); - scoped_array scoped_data( new uint8_t[options_size+1] ); // need a 0 after data - memset(scoped_data.get(), 0, (options_size+1)*sizeof(uint8_t)); - char *char_data = reinterpret_cast( scoped_data.get() ); - - (void) is.read( char_data, data_length ); // leave 0 at the end - IcmpPayloadData = char_data; // implicit cast - } - - if ( is.eof() ) - return IcmpPacket::ReadReturnCode_NOT_ENOUGH_DATA; - else if ( !is.good() ) - return IcmpPacket::ReadReturnCode_BAD_STREAM; - else - return IcmpPacket::ReadReturnCode_OK; -} - -/** - * @brief Write the ICMP packet to the @c ostream. - * - * @param os The output stream. - * - * @return @c true if the write was successful, or @c false if an error occurred. - */ -bool Icmpv6Packet::write( std::ostream &os ) const -{ - os.clear(); - - os << IcmpPayloadHeader << IcmpPayloadData; - - return !os.fail(); -} - diff --git a/src/icmp/icmpv6packet.h b/src/icmp/icmpv6packet.h deleted file mode 100644 index 0947398..0000000 --- a/src/icmp/icmpv6packet.h +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright (c) 2003-2010 Christopher M. Kohlhoff -// Modifications (c) 2011 by Guilherme Maciel Ferreira / Intra2net AG -// -// Distributed under the Boost Software License, Version 1.0. -// (See accompanying file LICENSE_1_0.txt or copy at -// http://www.boost.org/LICENSE_1_0.txt) -#ifndef ICMPV6_PACKET_H -#define ICMPV6_PACKET_H - -#include - -#include -#include - -#include - -#include "icmp/icmppacket.h" -#include "icmp/icmpv6header.h" -#include "icmp/icmpdata.h" -#include "icmp/icmptype.h" -#include "ip/ipv6header.h" - -//----------------------------------------------------------------------------- -// Icmpv6Packet -//----------------------------------------------------------------------------- - -/** - * @brief This class represents the ICMP version 6 Packet. - * - * The ICMP Packet format is: - * - * @code - * 0 3 4 11 12 15 16 23 24 31 - * +-------+---------------+--------------------------------------+ --- - * | | | | ^ - * |version| traffic class | flow label | | - * | (6) | | | | - * +-------+---------------+-------+--------------+---------------+ | - * | | | | | - * | payload length | next header | hop limit | | - * | | | | | - * +---------------+---------------+--------------+---------------+ | - * | | | - * | | | - * | | | - * | | | - * | | | - * | source IPv6 address | IPv6 Header - * | | 40 bytes - * | | | - * | | | - * | | | - * | | | - * | | | - * +--------------------------------------------------------------+ | - * | | | - * | | | - * | | | - * | | | - * | | | - * | destination IPv6 address | | - * | | | - * | | | - * | | | - * | | | - * | | | - * | | v - * +---------------+---------------+------------------------------+ --- - * | | | | ^ - * | type | code | checksum | | - * | | | | | - * +---------------+---------------+------------------------------+ | - * | | | ICMP Payload - * | identifier | sequence number | (header + - * | | | data) - * +-------------------------------+------------------------------+ 8+ bytes - * | | | - * | data (optional) | | - * | | v - * +-------------------------------+------------------------------+ --- - * @endcode - */ -class Icmpv6Packet : public IcmpPacket -{ -public: - Icmpv6Packet(); - Icmpv6Packet( - const Icmpv6Header &icmp_header, - const IcmpData &icmp_data - ); - virtual ~Icmpv6Packet(); - - Ipv6Header get_ip_header() const; - Icmpv6Header get_icmp_header() const; - IcmpData get_icmp_data() const; - - virtual bool match_echo_reply( - const uint16_t identifier, - const uint16_t sequence_number, - const boost::asio::ip::address &source_address - ) const; - virtual bool match_destination_unreachable( - const uint16_t identifier, - const uint16_t sequence_number, - const boost::asio::ip::address &source_address - ) const; - - virtual void print_echo_reply( - const std::size_t &bytes_transferred, - const boost::posix_time::ptime &time_packet_sent - ) const; - virtual void print_destination_unreachable() const; - - virtual ReadReturnCode read( std::istream &is ); - bool write( std::ostream &os ) const; - - -private: - bool match( - const Icmpv6Type type, - const uint16_t identifier, - const uint16_t sequence_number, - const boost::asio::ip::address &source_address - ) const; - -private: - /// The IP header. - Ipv6Header IpHeader; - /// The ICMP packet header. - Icmpv6Header IcmpPayloadHeader; - /// The ICMP packet payload (data). - IcmpData IcmpPayloadData; -}; - -#endif // ICMPV6_PACKET_H