From 8670f5f2c37e978b5a346424baa09f4a9c8c411e Mon Sep 17 00:00:00 2001 From: Guilherme Maciel Ferreira Date: Fri, 8 Apr 2011 15:25:27 +0200 Subject: [PATCH] Refactoring the ICMP message parsing - IcmpType enum separated from the IcmpHeader class, thus it has its own header without requiring to add the IcmpHeader's header file - the IcmpHeader class delegates the parsing polymorphically to specialized IcmpMessage classes (i.e. allowing the parsing of Destination unreachable messages) - IcmpHeader class does not requires the Payload member variable anymore, once it delegates the parsing to IcmpMessage classes --- src/CMakeLists.txt | 5 + src/icmp/icmpdestinationunreachablemessage.cpp | 128 ++++++++++++++++++++++++ src/icmp/icmpdestinationunreachablemessage.h | 79 +++++++++++++++ src/icmp/icmpechoreplymessage.cpp | 126 +++++++++++++++++++++++ src/icmp/icmpechoreplymessage.h | 75 ++++++++++++++ src/icmp/icmpechorequestmessage.cpp | 126 +++++++++++++++++++++++ src/icmp/icmpechorequestmessage.h | 75 ++++++++++++++ src/icmp/icmpgenericmessage.cpp | 88 ++++++++++++++++ src/icmp/icmpgenericmessage.h | 52 ++++++++++ src/icmp/icmpheader.cpp | 114 +++++++++++++++------- src/icmp/icmpheader.h | 54 ++++------ src/icmp/icmpmessage.cpp | 13 +++ src/icmp/icmpmessage.h | 41 ++++++++ src/icmp/icmppacket.cpp | 2 +- src/icmp/icmppacket.h | 3 +- src/icmp/icmptype.h | 22 ++++ 16 files changed, 933 insertions(+), 70 deletions(-) create mode 100644 src/icmp/icmpdestinationunreachablemessage.cpp create mode 100644 src/icmp/icmpdestinationunreachablemessage.h create mode 100644 src/icmp/icmpechoreplymessage.cpp create mode 100644 src/icmp/icmpechoreplymessage.h create mode 100644 src/icmp/icmpechorequestmessage.cpp create mode 100644 src/icmp/icmpechorequestmessage.h create mode 100644 src/icmp/icmpgenericmessage.cpp create mode 100644 src/icmp/icmpgenericmessage.h create mode 100644 src/icmp/icmpmessage.cpp create mode 100644 src/icmp/icmpmessage.h create mode 100644 src/icmp/icmptype.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 5241752..c062424 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,11 @@ set(SOURCES config/host.cpp dns/dnsresolver.cpp dns/hostaddress.cpp + icmp/icmpdestinationunreachablemessage.cpp + icmp/icmpechoreplymessage.cpp + icmp/icmpechorequestmessage.cpp + icmp/icmpgenericmessage.cpp + icmp/icmpmessage.cpp icmp/icmpheader.cpp icmp/icmppacket.cpp icmp/ipv4header.cpp diff --git a/src/icmp/icmpdestinationunreachablemessage.cpp b/src/icmp/icmpdestinationunreachablemessage.cpp new file mode 100644 index 0000000..674ab43 --- /dev/null +++ b/src/icmp/icmpdestinationunreachablemessage.cpp @@ -0,0 +1,128 @@ +#include "icmp/icmpdestinationunreachablemessage.h" + +using namespace std; + +//----------------------------------------------------------------------------- +// IcmpDestinationUnreachableMessage +//----------------------------------------------------------------------------- + +const int IcmpDestinationUnreachableMessage::MessageSizeInBytes = 44; + +IcmpDestinationUnreachableMessage::IcmpDestinationUnreachableMessage() +{ + fill( Payload, Payload + sizeof(Payload), 0 ); + + set_type( IcmpType_InvalidLast ); + set_code( 0 ); + set_checksum( 0 ); + set_identifier( 0 ); + set_sequence_number( 0 ); +} + +IcmpDestinationUnreachableMessage::IcmpDestinationUnreachableMessage( + const IcmpType type, + const uint8_t code, + const uint16_t checksum, + const uint16_t identifier, + const uint16_t sequence_number +) +{ + fill( Payload, Payload + sizeof(Payload), 0 ); + + set_type( type ); + set_code( code ); + set_checksum( checksum ); + set_identifier( identifier ); + set_sequence_number( sequence_number ); +} + +IcmpDestinationUnreachableMessage::~IcmpDestinationUnreachableMessage() +{ +} + +IcmpType IcmpDestinationUnreachableMessage::get_type() const +{ + IcmpType type = static_cast ( Payload[ 0 ] ); + + return type; +} + +void IcmpDestinationUnreachableMessage::set_type( IcmpType 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 decode( 2, 3 ); +} + +void IcmpDestinationUnreachableMessage::set_checksum( uint16_t checksum ) +{ + encode( 2, 3, checksum ); +} + +uint16_t IcmpDestinationUnreachableMessage::get_identifier() const +{ + return decode( 32, 33 ); +} + +void IcmpDestinationUnreachableMessage::set_identifier( + const uint16_t identifier +) +{ + encode( 32, 33, identifier ); +} + +uint16_t IcmpDestinationUnreachableMessage::get_sequence_number() const +{ + return decode( 34, 35 ); +} + +void IcmpDestinationUnreachableMessage::set_sequence_number( + const uint16_t sequence_number +) +{ + encode( 34, 35, sequence_number ); +} + +std::istream& IcmpDestinationUnreachableMessage::read( std::istream &is ) +{ + return is.read( + reinterpret_cast ( Payload ), + IcmpDestinationUnreachableMessage::MessageSizeInBytes + ); +} + +std::ostream& IcmpDestinationUnreachableMessage::write( + std::ostream &os +) const +{ + return os.write( + reinterpret_cast ( Payload ), + IcmpDestinationUnreachableMessage::MessageSizeInBytes + ); +} + +uint16_t IcmpDestinationUnreachableMessage::decode( int left_byte, int right_byte ) const +{ + return ( Payload[ left_byte ] << 8 ) + Payload[ right_byte ]; +} + +void IcmpDestinationUnreachableMessage::encode( int left_byte, int right_byte, uint16_t value ) +{ + Payload[ left_byte ] = static_cast ( value >> 8 ); + Payload[ right_byte ] = static_cast ( value & 0xFF ); +} diff --git a/src/icmp/icmpdestinationunreachablemessage.h b/src/icmp/icmpdestinationunreachablemessage.h new file mode 100644 index 0000000..cc37291 --- /dev/null +++ b/src/icmp/icmpdestinationunreachablemessage.h @@ -0,0 +1,79 @@ +#ifndef ICMP_DESTINATION_UNREACHABLE_MESSAGE_HPP +#define ICMP_DESTINATION_UNREACHABLE_MESSAGE_HPP + +#include + +#include +#include + +#include "icmp/icmpmessage.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(); + IcmpDestinationUnreachableMessage( + const IcmpType type, + const uint8_t code, + const uint16_t checksum, + const uint16_t identifier, + const uint16_t sequence_number + ); + virtual ~IcmpDestinationUnreachableMessage(); + + IcmpType get_type() const; + void set_type( const IcmpType 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 ); + + std::istream& read( std::istream &is ); + std::ostream& write( std::ostream &os ) const; + +private: + uint16_t decode( int left_byte, int right_byte ) const; + void encode( int left_byte, int right_byte, uint16_t value ); + +private: + static const int MessageSizeInBytes; + uint8_t Payload[ 44 ]; + +}; + +#endif // ICMP_DESTINATION_UNREACHABLE_MESSAGE_HPP diff --git a/src/icmp/icmpechoreplymessage.cpp b/src/icmp/icmpechoreplymessage.cpp new file mode 100644 index 0000000..6d24456 --- /dev/null +++ b/src/icmp/icmpechoreplymessage.cpp @@ -0,0 +1,126 @@ +#include "icmp/icmpechoreplymessage.h" + +using namespace std; + +//----------------------------------------------------------------------------- +// IcmpEchoReplyMessage +//----------------------------------------------------------------------------- + +const int IcmpEchoReplyMessage::MessageSizeInBytes = 8; + +IcmpEchoReplyMessage::IcmpEchoReplyMessage() +{ + fill( Payload, Payload + sizeof(Payload), 0 ); + + set_type( IcmpType_InvalidLast ); + set_code( 0 ); + set_checksum( 0 ); + set_identifier( 0 ); + set_sequence_number( 0 ); +} + +IcmpEchoReplyMessage::IcmpEchoReplyMessage( + const IcmpType type, + const uint8_t code, + const uint16_t checksum, + const uint16_t identifier, + const uint16_t sequence_number +) +{ + fill( Payload, Payload + sizeof(Payload), 0 ); + + set_type( type ); + set_code( code ); + set_checksum( checksum ); + set_identifier( identifier ); + set_sequence_number( sequence_number ); +} + +IcmpEchoReplyMessage::~IcmpEchoReplyMessage() +{ +} + +IcmpType IcmpEchoReplyMessage::get_type() const +{ + IcmpType type = static_cast ( Payload[ 0 ] ); + + return type; +} + +void IcmpEchoReplyMessage::set_type( IcmpType 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 decode( 2, 3 ); +} + +void IcmpEchoReplyMessage::set_checksum( uint16_t checksum ) +{ + encode( 2, 3, checksum ); +} + +uint16_t IcmpEchoReplyMessage::get_identifier() const +{ + return decode( 4, 5 ); +} + +void IcmpEchoReplyMessage::set_identifier( + const uint16_t identifier +) +{ + encode( 4, 5, identifier ); +} + +uint16_t IcmpEchoReplyMessage::get_sequence_number() const +{ + return decode( 6, 7 ); +} + +void IcmpEchoReplyMessage::set_sequence_number( + const uint16_t sequence_number +) +{ + encode( 6, 7, sequence_number ); +} + +std::istream& IcmpEchoReplyMessage::read( std::istream &is ) +{ + return is.read( + reinterpret_cast ( Payload ), + IcmpEchoReplyMessage::MessageSizeInBytes + ); +} + +std::ostream& IcmpEchoReplyMessage::write( std::ostream &os ) const +{ + return os.write( + reinterpret_cast ( Payload ), + IcmpEchoReplyMessage::MessageSizeInBytes + ); +} + +uint16_t IcmpEchoReplyMessage::decode( int left_byte, int right_byte ) const +{ + return ( Payload[ left_byte ] << 8 ) + Payload[ right_byte ]; +} + +void IcmpEchoReplyMessage::encode( int left_byte, int right_byte, uint16_t value ) +{ + Payload[ left_byte ] = static_cast ( value >> 8 ); + Payload[ right_byte ] = static_cast ( value & 0xFF ); +} diff --git a/src/icmp/icmpechoreplymessage.h b/src/icmp/icmpechoreplymessage.h new file mode 100644 index 0000000..eef3579 --- /dev/null +++ b/src/icmp/icmpechoreplymessage.h @@ -0,0 +1,75 @@ +#ifndef ICMP_ECHO_REPLY_MESSAGE_HPP +#define ICMP_ECHO_REPLY_MESSAGE_HPP + +#include + +#include +#include + +#include "icmp/icmpmessage.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(); + IcmpEchoReplyMessage( + const IcmpType type, + const uint8_t code, + const uint16_t checksum, + const uint16_t identifier, + const uint16_t sequence_number + ); + virtual ~IcmpEchoReplyMessage(); + + IcmpType get_type() const; + void set_type( const IcmpType 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 ); + + std::istream& read( std::istream &is ); + std::ostream& write( std::ostream &os ) const; + +private: + uint16_t decode( int left_byte, int right_byte ) const; + void encode( int left_byte, int right_byte, uint16_t value ); + +private: + static const int MessageSizeInBytes; + uint8_t Payload[ 8 ]; + +}; + +#endif // ICMP_ECHO_REPLY_MESSAGE_HPP diff --git a/src/icmp/icmpechorequestmessage.cpp b/src/icmp/icmpechorequestmessage.cpp new file mode 100644 index 0000000..a196c7f --- /dev/null +++ b/src/icmp/icmpechorequestmessage.cpp @@ -0,0 +1,126 @@ +#include "icmp/icmpechorequestmessage.h" + +using namespace std; + +//----------------------------------------------------------------------------- +// IcmpEchoRequestMessage +//----------------------------------------------------------------------------- + +const int IcmpEchoRequestMessage::MessageSizeInBytes = 8; + +IcmpEchoRequestMessage::IcmpEchoRequestMessage() +{ + fill( Payload, Payload + sizeof(Payload), 0 ); + + set_type( IcmpType_InvalidLast ); + set_code( 0 ); + set_checksum( 0 ); + set_identifier( 0 ); + set_sequence_number( 0 ); +} + +IcmpEchoRequestMessage::IcmpEchoRequestMessage( + const IcmpType type, + const uint8_t code, + const uint16_t checksum, + const uint16_t identifier, + const uint16_t sequence_number +) +{ + fill( Payload, Payload + sizeof(Payload), 0 ); + + set_type( type ); + set_code( code ); + set_checksum( checksum ); + set_identifier( identifier ); + set_sequence_number( sequence_number ); +} + +IcmpEchoRequestMessage::~IcmpEchoRequestMessage() +{ +} + +IcmpType IcmpEchoRequestMessage::get_type() const +{ + IcmpType type = static_cast ( Payload[ 0 ] ); + + return type; +} + +void IcmpEchoRequestMessage::set_type( IcmpType 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 decode( 2, 3 ); +} + +void IcmpEchoRequestMessage::set_checksum( uint16_t checksum ) +{ + encode( 2, 3, checksum ); +} + +uint16_t IcmpEchoRequestMessage::get_identifier() const +{ + return decode( 4, 5 ); +} + +void IcmpEchoRequestMessage::set_identifier( + const uint16_t identifier +) +{ + encode( 4, 5, identifier ); +} + +uint16_t IcmpEchoRequestMessage::get_sequence_number() const +{ + return decode( 6, 7 ); +} + +void IcmpEchoRequestMessage::set_sequence_number( + const uint16_t sequence_number +) +{ + encode( 6, 7, sequence_number ); +} + +std::istream& IcmpEchoRequestMessage::read( std::istream &is ) +{ + return is.read( + reinterpret_cast ( Payload ), + IcmpEchoRequestMessage::MessageSizeInBytes + ); +} + +std::ostream& IcmpEchoRequestMessage::write( std::ostream &os ) const +{ + return os.write( + reinterpret_cast ( Payload ), + IcmpEchoRequestMessage::MessageSizeInBytes + ); +} + +uint16_t IcmpEchoRequestMessage::decode( int left_byte, int right_byte ) const +{ + return ( Payload[ left_byte ] << 8 ) + Payload[ right_byte ]; +} + +void IcmpEchoRequestMessage::encode( int left_byte, int right_byte, uint16_t value ) +{ + Payload[ left_byte ] = static_cast ( value >> 8 ); + Payload[ right_byte ] = static_cast ( value & 0xFF ); +} diff --git a/src/icmp/icmpechorequestmessage.h b/src/icmp/icmpechorequestmessage.h new file mode 100644 index 0000000..dfb2bda --- /dev/null +++ b/src/icmp/icmpechorequestmessage.h @@ -0,0 +1,75 @@ +#ifndef ICMP_ECHO_REQUEST_MESSAGE_HPP +#define ICMP_ECHO_REQUEST_MESSAGE_HPP + +#include + +#include +#include + +#include "icmp/icmpmessage.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(); + IcmpEchoRequestMessage( + const IcmpType type, + const uint8_t code, + const uint16_t checksum, + const uint16_t identifier, + const uint16_t sequence_number + ); + virtual ~IcmpEchoRequestMessage(); + + IcmpType get_type() const; + void set_type( const IcmpType 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 ); + + std::istream& read( std::istream &is ); + std::ostream& write( std::ostream &os ) const; + +private: + uint16_t decode( int left_byte, int right_byte ) const; + void encode( int left_byte, int right_byte, uint16_t value ); + +private: + static const int MessageSizeInBytes; + uint8_t Payload[ 8 ]; + +}; + +#endif // ICMP_ECHO_REQUEST_MESSAGE_HPP diff --git a/src/icmp/icmpgenericmessage.cpp b/src/icmp/icmpgenericmessage.cpp new file mode 100644 index 0000000..59418b4 --- /dev/null +++ b/src/icmp/icmpgenericmessage.cpp @@ -0,0 +1,88 @@ +#include "icmp/icmpgenericmessage.h" + +//----------------------------------------------------------------------------- +// IcmpGenericMessage +//----------------------------------------------------------------------------- + +IcmpGenericMessage::IcmpGenericMessage() +{ + set_type( IcmpType_InvalidLast ); + set_code( 0 ); + set_checksum( 0 ); + set_identifier( 0 ); + set_sequence_number( 0 ); +} + +IcmpGenericMessage::IcmpGenericMessage( + const IcmpType type, + const uint8_t code, + const uint16_t checksum, + const uint16_t identifier, + const uint16_t sequence_number +) +{ + set_type( type ); + set_code( code ); + set_checksum( checksum ); + set_identifier( identifier ); + set_sequence_number( sequence_number ); +} + +IcmpGenericMessage::~IcmpGenericMessage() +{ +} + +IcmpType IcmpGenericMessage::get_type() const +{ + return IcmpType_InvalidLast; +} + +void IcmpGenericMessage::set_type( IcmpType ) +{ +} + +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 new file mode 100644 index 0000000..1c0bff9 --- /dev/null +++ b/src/icmp/icmpgenericmessage.h @@ -0,0 +1,52 @@ +#ifndef ICMP_GENERIC_MESSAGE_HPP +#define ICMP_GENERIC_MESSAGE_HPP + +#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(); + IcmpGenericMessage( + const IcmpType type, + const uint8_t code, + const uint16_t checksum, + const uint16_t identifier, + const uint16_t sequence_number + ); + virtual ~IcmpGenericMessage(); + + IcmpType get_type() const; + void set_type( const IcmpType 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 ); + + std::istream& read( std::istream &is ); + std::ostream& write( std::ostream &os ) const; + +}; + +#endif // ICMP_GENERIC_MESSAGE_HPP diff --git a/src/icmp/icmpheader.cpp b/src/icmp/icmpheader.cpp index 54d4124..c19b778 100644 --- a/src/icmp/icmpheader.cpp +++ b/src/icmp/icmpheader.cpp @@ -1,23 +1,32 @@ #include "icmp/icmpheader.h" +#include "icmp/icmpdestinationunreachablemessage.h" +#include "icmp/icmpechoreplymessage.h" +#include "icmp/icmpechorequestmessage.h" +#include "icmp/icmpgenericmessage.h" + +using namespace std; +using boost::shared_ptr; + //----------------------------------------------------------------------------- // IcmpHeader //----------------------------------------------------------------------------- -IcmpHeader::IcmpHeader() +IcmpHeader::IcmpHeader() : + MessageFormat() { - std::fill( Payload, Payload + sizeof(Payload), 0 ); } IcmpHeader::IcmpHeader( - IcmpHeader::IcmpType type, + IcmpType type, uint8_t code, uint16_t checksum, uint16_t identifier, uint16_t sequence_number -) +) : + MessageFormat() { - std::fill( Payload, Payload + sizeof(Payload), 0 ); + set_icmp_message_format( type ); set_type( type ); set_code( code ); @@ -26,59 +35,100 @@ IcmpHeader::IcmpHeader( set_sequence_number( sequence_number ); } -IcmpHeader::IcmpType IcmpHeader::get_type() const +IcmpType IcmpHeader::get_type() const { - uint8_t n = Payload[ 0 ]; - IcmpHeader::IcmpType type = static_cast ( n ); - - return type; + return get_icmp_message_format()->get_type(); } -void IcmpHeader::set_type( IcmpHeader::IcmpType type ) +void IcmpHeader::set_type( IcmpType type ) { - uint8_t n = type; - - Payload[ 0 ] = n; + get_icmp_message_format()->set_type( type ); } uint8_t IcmpHeader::get_code() const { - return Payload[ 1 ]; + return get_icmp_message_format()->get_code(); } void IcmpHeader::set_code( uint8_t code ) { - Payload[ 1 ] = code; + get_icmp_message_format()->set_code( code ); } uint16_t IcmpHeader::get_checksum() const { - return decode( 2, 3 ); + return get_icmp_message_format()->get_checksum(); } void IcmpHeader::set_checksum( uint16_t checksum ) { - encode( 2, 3, checksum ); + get_icmp_message_format()->set_checksum( checksum ); } uint16_t IcmpHeader::get_identifier() const { - return decode( 4, 5 ); + return get_icmp_message_format()->get_identifier(); } void IcmpHeader::set_identifier( uint16_t identifier ) { - encode( 4, 5, identifier ); + get_icmp_message_format()->set_identifier( identifier ); } uint16_t IcmpHeader::get_sequence_number() const { - return decode( 6, 7 ); + return get_icmp_message_format()->get_sequence_number(); } void IcmpHeader::set_sequence_number( uint16_t sequence_number ) { - encode( 6, 7, sequence_number ); + get_icmp_message_format()->set_sequence_number( sequence_number ); +} + +shared_ptr IcmpHeader::get_icmp_message_format() const +{ + BOOST_ASSERT( MessageFormat.get() != NULL ); + + return MessageFormat; +} + +void IcmpHeader::set_icmp_message_format( IcmpType type ) +{ + BOOST_ASSERT( MessageFormat.get() == NULL ); + + if ( MessageFormat.get() == NULL ) + { + switch ( type ) + { + case IcmpType_EchoReply: + MessageFormat.reset( new IcmpEchoReplyMessage ); + break; + case IcmpType_EchoRequest: + MessageFormat.reset( new IcmpEchoRequestMessage ); + break; + case IcmpType_DestinationUnreachable: + MessageFormat.reset( + new IcmpDestinationUnreachableMessage ); + break; + default: + MessageFormat.reset( new IcmpGenericMessage ); + break; + } + } +} + +void IcmpHeader::set_icmp_message_format( std::istream &is ) +{ + // read the first byte, which contains the type of the ICMP message + char first_byte; + is.read( &first_byte, 1 ); + + // must keep the stream intact, so place the read byte back + is.putback( first_byte ); + + // now select the message format for the given type + IcmpType header_type = static_cast ( first_byte ); + set_icmp_message_format( header_type ); } std::istream& operator>>( @@ -86,7 +136,11 @@ std::istream& operator>>( IcmpHeader &header ) { - return is.read( reinterpret_cast ( header.Payload ), 8 ); + // 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<<( @@ -94,16 +148,6 @@ std::ostream& operator<<( const IcmpHeader &header ) { - return os.write( reinterpret_cast ( header.Payload ), 8 ); -} - -uint16_t IcmpHeader::decode( int left_byte, int right_byte ) const -{ - return ( Payload[ left_byte ] << 8 ) + Payload[ right_byte ]; -} - -void IcmpHeader::encode( int left_byte, int right_byte, uint16_t value ) -{ - Payload[ left_byte ] = static_cast ( value >> 8 ); - Payload[ right_byte ] = static_cast ( value & 0xFF ); + // delegate the writing of the fields to a specialized encoder + return header.get_icmp_message_format()->write( os ); } diff --git a/src/icmp/icmpheader.h b/src/icmp/icmpheader.h index 1a477d1..035b736 100644 --- a/src/icmp/icmpheader.h +++ b/src/icmp/icmpheader.h @@ -6,45 +6,33 @@ #include #include +#include + +#include "icmp/icmpmessage.h" +#include "icmp/icmptype.h" + //----------------------------------------------------------------------------- // IcmpHeader //----------------------------------------------------------------------------- -// ICMP header format +// +// ICMP Generic Header Format // // 0 8 16 31 -// +---------------+---------------+------------------------------+ --- -// | | | | ^ -// | type | code | checksum | | -// | | | | | -// +---------------+---------------+------------------------------+ 8 bytes -// | | | | -// | identifier | sequence number | | -// | | | v -// +-------------------------------+------------------------------+ --- +// +---------------+---------------+------------------------------+ --- +// | | | | ^ +// | type | code | checksum | 4 bytes +// | | | | v +// +---------------+---------------+------------------------------+ --- +// | | +// | specific to each message | +// | | +// +-------------------------------+------------------------------+ // //----------------------------------------------------------------------------- class IcmpHeader { public: - enum IcmpType - { - IcmpType_EchoReply = 0, - IcmpType_DestinationUnreachable = 3, - IcmpType_SourceQuench = 4, - IcmpType_Redirect = 5, - IcmpType_EchoRequest = 8, - IcmpType_TimeExceeded = 11, - IcmpType_ParameterProblem = 12, - IcmpType_TimestampRequest = 13, - IcmpType_TimestampReply = 14, - IcmpType_InfoRequest = 15, - IcmpType_InfoReply = 16, - IcmpType_AddressRequest = 17, - IcmpType_AddressReply = 18 - }; - -public: IcmpHeader(); IcmpHeader( IcmpType type, @@ -69,6 +57,10 @@ public: 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( IcmpType type ); + void set_icmp_message_format( std::istream &is ); + friend std::istream& operator>>( std::istream &is, IcmpHeader &header @@ -79,11 +71,7 @@ public: ); private: - uint16_t decode( int left_byte, int right_byte ) const; - void encode( int left_byte, int right_byte, uint16_t value ); - -private: - uint8_t Payload[ 8 ]; + boost::shared_ptr MessageFormat; }; diff --git a/src/icmp/icmpmessage.cpp b/src/icmp/icmpmessage.cpp new file mode 100644 index 0000000..d7ead6e --- /dev/null +++ b/src/icmp/icmpmessage.cpp @@ -0,0 +1,13 @@ +#include "icmp/icmpmessage.h" + +//----------------------------------------------------------------------------- +// IcmpMessage +//----------------------------------------------------------------------------- + +IcmpMessage::IcmpMessage() +{ +} + +IcmpMessage::~IcmpMessage() +{ +} diff --git a/src/icmp/icmpmessage.h b/src/icmp/icmpmessage.h new file mode 100644 index 0000000..02209ce --- /dev/null +++ b/src/icmp/icmpmessage.h @@ -0,0 +1,41 @@ +#ifndef ICMP_MESSAGE_HPP +#define ICMP_MESSAGE_HPP + +#include + +#include +#include + +#include "icmp/icmptype.h" + +//----------------------------------------------------------------------------- +// IcmpMessage +//----------------------------------------------------------------------------- + +class IcmpMessage +{ +public: + IcmpMessage(); + virtual ~IcmpMessage(); + + virtual IcmpType get_type() const = 0; + virtual void set_type( const IcmpType 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; + +}; + +#endif // ICMP_MESSAGE_HPP diff --git a/src/icmp/icmppacket.cpp b/src/icmp/icmppacket.cpp index 43c1873..87f242f 100644 --- a/src/icmp/icmppacket.cpp +++ b/src/icmp/icmppacket.cpp @@ -41,7 +41,7 @@ IcmpData IcmpPacket::get_icmp_data() const } bool IcmpPacket::match( - IcmpHeader::IcmpType type, + IcmpType type, uint16_t identifier, uint16_t sequence_number ) const diff --git a/src/icmp/icmppacket.h b/src/icmp/icmppacket.h index 01ecac7..43e470b 100644 --- a/src/icmp/icmppacket.h +++ b/src/icmp/icmppacket.h @@ -9,6 +9,7 @@ #include "icmp/ipv4header.h" #include "icmp/icmpheader.h" #include "icmp/icmpdata.h" +#include "icmp/icmptype.h" //----------------------------------------------------------------------------- // IcmpPacket @@ -67,7 +68,7 @@ public: IcmpData get_icmp_data() const; bool match( - IcmpHeader::IcmpType type, + IcmpType type, uint16_t identifier, uint16_t sequence_number ) const; diff --git a/src/icmp/icmptype.h b/src/icmp/icmptype.h new file mode 100644 index 0000000..7407f5e --- /dev/null +++ b/src/icmp/icmptype.h @@ -0,0 +1,22 @@ +#ifndef ICMP_TYPE_H +#define ICMP_TYPE_H + +enum IcmpType +{ + IcmpType_EchoReply = 0, + IcmpType_DestinationUnreachable = 3, + IcmpType_SourceQuench = 4, + IcmpType_Redirect = 5, + IcmpType_EchoRequest = 8, + IcmpType_TimeExceeded = 11, + IcmpType_ParameterProblem = 12, + IcmpType_TimestampRequest = 13, + IcmpType_TimestampReply = 14, + IcmpType_InfoRequest = 15, + IcmpType_InfoReply = 16, + IcmpType_AddressRequest = 17, + IcmpType_AddressReply = 18, + IcmpType_InvalidLast = 42 +}; + +#endif /* ICMP_TYPE_H */ -- 1.7.1