From 12a35dbb1de7cc5e3cc12bd721cd2f0533b94405 Mon Sep 17 00:00:00 2001 From: Guilherme Maciel Ferreira Date: Thu, 21 Jul 2011 23:16:37 -0300 Subject: [PATCH] Split the TcpHeader implementation and header --- src/CMakeLists.txt | 1 + src/tcp/tcpheader.cpp | 291 ++++++++++++++++++++++++++++++++++++++++++++++ src/tcp/tcpheader.h | 304 ++++++++---------------------------------------- 3 files changed, 343 insertions(+), 253 deletions(-) create mode 100644 src/tcp/tcpheader.cpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d601e4b..0f02a6a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -52,6 +52,7 @@ set(SOURCES ip/ipv4header.cpp link/linkstatusanalyzer.cpp link/statusnotifiercommand.cpp + tcp/tcpheader.cpp tcp/tcppinger.cpp main.cpp ) diff --git a/src/tcp/tcpheader.cpp b/src/tcp/tcpheader.cpp new file mode 100644 index 0000000..f1cb206 --- /dev/null +++ b/src/tcp/tcpheader.cpp @@ -0,0 +1,291 @@ +/* +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. +*/ +#include "tcp/tcpheader.h" + +#include +#include +#include + +#include + +#include "ip/pseudoipv4header.h" + +using namespace std; + +//----------------------------------------------------------------------------- +// TcpHeader +//----------------------------------------------------------------------------- + +TcpHeader::TcpHeader() +{ + fill( rep_, rep_ + sizeof(rep_), 0 ); +} + +uint16_t TcpHeader::source_port() const +{ + return decode( 0, 1 ); +} + +uint16_t TcpHeader::destination_port() const +{ + return decode( 2, 3 ); +} + +uint32_t TcpHeader::sequence_number() const +{ + uint32_t seq_num = (uint32_t) ( + rep_[4] << 24 | + rep_[5] << 16 | + rep_[6] << 8 | + rep_[7] + ); + + return seq_num; +} + +uint32_t TcpHeader::acknowledgment_number() const +{ + uint32_t ack_num = (uint32_t) ( + rep_[8] << 24 | + rep_[9] << 16 | + rep_[10] << 8 | + rep_[11] + ); + + return ack_num; +} + +uint8_t TcpHeader::header_length() const +{ + return (rep_[12] & 0xF0) >> 4; +} + +bool TcpHeader::congestion_window_reduced() const +{ + return (rep_[13] & 0x80); +} + +bool TcpHeader::ecn_echo() const +{ + return (rep_[13] & 0x40); +} + +bool TcpHeader::urgent() const +{ + return (rep_[13] & 0x20); +} + +bool TcpHeader::acknowledgment() const +{ + return (rep_[13] & 0x10); +} + +bool TcpHeader::push() const +{ + return (rep_[13] & 0x08); +} + +bool TcpHeader::reset() const +{ + return (rep_[13] & 0x04); +} + +bool TcpHeader::synchronize() const +{ + return (rep_[13] & 0x02); +} + +bool TcpHeader::finish() const +{ + return (rep_[13] & 0x01); +} + +uint16_t TcpHeader::window_size() const +{ + return decode( 14, 15 ); +} + +uint16_t TcpHeader::checksum() const +{ + return decode( 16, 17 ); +} + +uint16_t TcpHeader::calculate_tcp_checksum( + const uint32_t src_addr, + const uint32_t dest_addr, + const char* tcp_payload_data, + const uint16_t tcp_payload_size_in_bytes ) +{ + checksum( 0 ); + uint16_t tcp_header_size_in_bytes = 20; + uint16_t tcp_segment_size_in_bytes = static_cast< uint16_t > ( + tcp_header_size_in_bytes + tcp_payload_size_in_bytes + ); + + PseudoIpv4Header pseudo_header; + pseudo_header.source_address = htonl(src_addr); + pseudo_header.destination_address = htonl(dest_addr); + pseudo_header.zero_byte = 0; + pseudo_header.protocol = IPPROTO_TCP; + pseudo_header.header_length = htons( tcp_segment_size_in_bytes ); + + int pseudo_header_size_in_bytes = sizeof(PseudoIpv4Header); + + uint8_t tcp_buffer[65536]; + memset( tcp_buffer, 0, sizeof(tcp_buffer) ); + + memcpy( tcp_buffer, &pseudo_header, pseudo_header_size_in_bytes ); + memcpy( tcp_buffer + pseudo_header_size_in_bytes, rep_, + tcp_header_size_in_bytes ); + memcpy( tcp_buffer + pseudo_header_size_in_bytes + tcp_header_size_in_bytes, + tcp_payload_data, tcp_payload_size_in_bytes ); + + uint16_t cksum = calculate_checksum( + (uint16_t *) tcp_buffer, + pseudo_header_size_in_bytes + tcp_header_size_in_bytes + tcp_payload_size_in_bytes + ); + + cksum = ntohs( cksum ); + + return cksum; +} + +void TcpHeader::source_port( const uint16_t port ) +{ + encode( 0, 1, port ); +} + +void TcpHeader::destination_port( const uint16_t port ) +{ + encode( 2, 3, port ); +} + +void TcpHeader::sequence_number( const uint32_t seq_num ) +{ + rep_[4] = (uint8_t) (seq_num >> 24) & 0xFF; + rep_[5] = (uint8_t) (seq_num >> 16) & 0xFF; + rep_[6] = (uint8_t) (seq_num >> 8) & 0xFF; + rep_[7] = (uint8_t) seq_num & 0xFF; +} + +void TcpHeader::acknowledgment_number( const uint32_t ack_num ) +{ + rep_[8] = (uint8_t) (ack_num >> 24) & 0xFF; + rep_[9] = (uint8_t) (ack_num >> 16) & 0xFF; + rep_[10] = (uint8_t) (ack_num >> 8) & 0xFF; + rep_[11] = (uint8_t) ack_num & 0xFF; +} + +void TcpHeader::header_length( const uint8_t offset ) +{ + uint8_t high_nimble = static_cast( ( offset << 4 ) & 0xF0 ); + uint8_t lower_nimble = ( rep_[12] & 0x0F ); + rep_[12] = high_nimble | lower_nimble; +} + +void TcpHeader::congestion_window_reduced( bool bit ) +{ + rep_[13] |= bit ? 0x80 : 0x0; +} + +void TcpHeader::ecn_echo( bool bit ) +{ + rep_[13] |= bit ? 0x40 : 0x0; +} + +void TcpHeader::urgent( bool bit ) +{ + rep_[13] |= bit ? 0x20 : 0x0; +} + +void TcpHeader::acknowledgment( bool bit ) +{ + rep_[13] |= bit ? 0x10 : 0x0; +} + +void TcpHeader::push( bool bit ) +{ + rep_[13] |= bit ? 0x08 : 0x0; +} + +void TcpHeader::reset( bool bit ) +{ + rep_[13] |= bit ? 0x04 : 0x0; +} + +void TcpHeader::synchronize( bool bit ) +{ + rep_[13] |= bit ? 0x02 : 0x0; +} + +void TcpHeader::finish( bool bit ) +{ + rep_[13] |= bit ? 0x01 : 0x0; +} + +void TcpHeader::window_size( const uint16_t wnd_size ) +{ + encode( 14, 15, wnd_size ); +} + +void TcpHeader::checksum( const uint16_t sum ) +{ + encode( 16, 17, sum ); +} + +istream& operator>>( istream& is, TcpHeader& header ) +{ + return is.read( reinterpret_cast< char* > ( header.rep_ ), 20 ); +} + +ostream& operator<<( ostream& os, const TcpHeader& header ) +{ + return os.write( reinterpret_cast< const char* > ( header.rep_ ), 20 ); +} + +uint16_t TcpHeader::decode( int a, int b ) const +{ + return static_cast( (rep_[a] << 8) + rep_[b] ); +} + +void TcpHeader::encode( int a, int b, const uint16_t n ) +{ + rep_[a] = static_cast< uint8_t > ( n >> 8 ); + rep_[b] = static_cast< uint8_t > ( n & 0xFF ); +} + +uint16_t TcpHeader::calculate_checksum( const uint16_t *word_array, int size ) +{ + unsigned long cksum = 0; + while ( size > 1 ) + { + cksum += *word_array++; + size -= sizeof(word_array[ 0 ]); + } + if ( size ) + { + cksum += *(uint8_t*) word_array; + } + + cksum = (cksum >> 16) + (cksum & 0xffff); + cksum += (cksum >> 16); + + return (uint16_t) (~cksum); +} diff --git a/src/tcp/tcpheader.h b/src/tcp/tcpheader.h index 6062771..045c7c4 100644 --- a/src/tcp/tcpheader.h +++ b/src/tcp/tcpheader.h @@ -20,12 +20,15 @@ on this file might be covered by the GNU General Public License. #ifndef TCP_HEADER_H #define TCP_HEADER_H -#include +#include -#include - -#include "ip/pseudoipv4header.h" +#include +#include +//----------------------------------------------------------------------------- +// TcpHeader +//----------------------------------------------------------------------------- +// // TCP Segment header. // // The wire format of a TCP header is: @@ -65,259 +68,54 @@ on this file might be covered by the GNU General Public License. class TcpHeader { public: - TcpHeader() - { - std::fill( rep_, rep_ + sizeof(rep_), 0 ); - } - - uint16_t source_port() const - { - return decode( 0, 1 ); - } - - uint16_t destination_port() const - { - return decode( 2, 3 ); - } - - uint32_t sequence_number() const - { - uint32_t seq_num = (uint32_t) ( - rep_[4] << 24 | - rep_[5] << 16 | - rep_[6] << 8 | - rep_[7] - ); - - return seq_num; - } - - uint32_t acknowledgment_number() const - { - uint32_t ack_num = (uint32_t) ( - rep_[8] << 24 | - rep_[9] << 16 | - rep_[10] << 8 | - rep_[11] - ); - - return ack_num; - } - - uint8_t header_length() const - { - return (rep_[12] & 0xF0) >> 4; - } - - bool congestion_window_reduced() const - { - return (rep_[13] & 0x80); - } - - bool ecn_echo() const - { - return (rep_[13] & 0x40); - } - - bool urgent() const - { - return (rep_[13] & 0x20); - } - - bool acknowledgment() const - { - return (rep_[13] & 0x10); - } - - bool push() const - { - return (rep_[13] & 0x08); - } - - bool reset() const - { - return (rep_[13] & 0x04); - } - - bool synchronize() const - { - return (rep_[13] & 0x02); - } - - bool finish() const - { - return (rep_[13] & 0x01); - } - - uint16_t window_size() const - { - return decode( 14, 15 ); - } - - uint16_t checksum() const - { - return decode( 16, 17 ); - } + TcpHeader(); + + uint16_t source_port() const; + uint16_t destination_port() const; + uint32_t sequence_number() const; + uint32_t acknowledgment_number() const; + uint8_t header_length() const; + bool congestion_window_reduced() const; + bool ecn_echo() const; + bool urgent() const; + bool acknowledgment() const; + bool push() const; + bool reset() const; + bool synchronize() const; + bool finish() const; + uint16_t window_size() const; + uint16_t checksum() const; uint16_t calculate_tcp_checksum( - uint32_t src_addr, - uint32_t dest_addr, - char* tcp_payload_data, - uint16_t tcp_payload_size_in_bytes ) - { - checksum( 0 ); - uint16_t tcp_header_size_in_bytes = 20; - uint16_t tcp_segment_size_in_bytes = static_cast< uint16_t > ( - tcp_header_size_in_bytes + tcp_payload_size_in_bytes - ); - - PseudoIpv4Header pseudo_header; - pseudo_header.source_address = htonl(src_addr); - pseudo_header.destination_address = htonl(dest_addr); - pseudo_header.zero_byte = 0; - pseudo_header.protocol = IPPROTO_TCP; - pseudo_header.header_length = htons( tcp_segment_size_in_bytes ); - - int pseudo_header_size_in_bytes = sizeof(PseudoIpv4Header); - - uint8_t tcp_buffer[65536]; - memset( tcp_buffer, 0, sizeof(tcp_buffer) ); - - memcpy( tcp_buffer, &pseudo_header, pseudo_header_size_in_bytes ); - memcpy( tcp_buffer + pseudo_header_size_in_bytes, rep_, - tcp_header_size_in_bytes ); - memcpy( tcp_buffer + pseudo_header_size_in_bytes + tcp_header_size_in_bytes, - tcp_payload_data, tcp_payload_size_in_bytes ); - - uint16_t cksum = calculate_checksum( (uint16_t *) - tcp_buffer, - pseudo_header_size_in_bytes + tcp_header_size_in_bytes + tcp_payload_size_in_bytes - ); - - cksum = ntohs( cksum ); - - return cksum; - } - - void source_port( uint16_t port ) - { - encode( 0, 1, port ); - } - - void destination_port( uint16_t port ) - { - encode( 2, 3, port ); - } - - void sequence_number( uint32_t seq_num ) - { - rep_[4] = (uint8_t) (seq_num >> 24) & 0xFF; - rep_[5] = (uint8_t) (seq_num >> 16) & 0xFF; - rep_[6] = (uint8_t) (seq_num >> 8) & 0xFF; - rep_[7] = (uint8_t) seq_num & 0xFF; - } - - void acknowledgment_number( uint32_t ack_num ) - { - rep_[8] = (uint8_t) (ack_num >> 24) & 0xFF; - rep_[9] = (uint8_t) (ack_num >> 16) & 0xFF; - rep_[10] = (uint8_t) (ack_num >> 8) & 0xFF; - rep_[11] = (uint8_t) ack_num & 0xFF; - } - - void header_length( uint8_t offset ) - { - uint8_t high_nimble = static_cast( ( offset << 4 ) & 0xF0 ); - uint8_t lower_nimble = ( rep_[12] & 0x0F ); - rep_[12] = high_nimble | lower_nimble; - } - - void congestion_window_reduced( bool bit ) - { - rep_[13] |= bit ? 0x80 : 0x0; - } - - void ecn_echo( bool bit ) - { - rep_[13] |= bit ? 0x40 : 0x0; - } - - void urgent( bool bit ) - { - rep_[13] |= bit ? 0x20 : 0x0; - } - - void acknowledgment( bool bit ) - { - rep_[13] |= bit ? 0x10 : 0x0; - } - - void push( bool bit ) - { - rep_[13] |= bit ? 0x08 : 0x0; - } - - void reset( bool bit ) - { - rep_[13] |= bit ? 0x04 : 0x0; - } - - void synchronize( bool bit ) - { - rep_[13] |= bit ? 0x02 : 0x0; - } - - void finish( bool bit ) - { - rep_[13] |= bit ? 0x01 : 0x0; - } - - void window_size( uint16_t wnd_size ) - { - encode( 14, 15, wnd_size ); - } - - void checksum( uint16_t sum ) - { - encode( 16, 17, sum ); - } - - friend std::istream& operator>>( std::istream& is, TcpHeader& header ) - { - return is.read( reinterpret_cast< char* > ( header.rep_ ), 20 ); - } - - friend std::ostream& operator<<( std::ostream& os, const TcpHeader& header ) - { - return os.write( reinterpret_cast< const char* > ( header.rep_ ), 20 ); - } + const uint32_t src_addr, + const uint32_t dest_addr, + const char* tcp_payload_data, + const uint16_t tcp_payload_size_in_bytes + ); + + void source_port( const uint16_t port ); + void destination_port( const uint16_t port ); + void sequence_number( const uint32_t seq_num ); + void acknowledgment_number( const uint32_t ack_num ); + void header_length( const uint8_t offset ); + void congestion_window_reduced( bool bit ); + void ecn_echo( bool bit ); + void urgent( bool bit ); + void acknowledgment( bool bit ); + void push( bool bit ); + void reset( bool bit ); + void synchronize( bool bit ); + void finish( bool bit ); + void window_size( const uint16_t wnd_size ); + void checksum( const uint16_t sum ); + + friend std::istream& operator>>( std::istream& is, TcpHeader& header ); + friend std::ostream& operator<<( std::ostream& os, const TcpHeader& header ); private: - uint16_t decode( int a, int b ) const - { - return static_cast( (rep_[a] << 8) + rep_[b] ); - } - - void encode( int a, int b, uint16_t n ) - { - rep_[a] = static_cast< uint8_t > ( n >> 8 ); - rep_[b] = static_cast< uint8_t > ( n & 0xFF ); - } - - uint16_t calculate_checksum( uint16_t *word_array, int size ) - { - unsigned long cksum = 0; - while ( size > 1 ) { - cksum += *word_array++; - size -= sizeof(word_array[ 0 ]); - } - if ( size ) - cksum += *(uint8_t*) word_array; - - cksum = (cksum >> 16) + (cksum & 0xffff); - cksum += (cksum >> 16); - return (uint16_t) (~cksum); - } + uint16_t decode( int a, int b ) const; + void encode( int a, int b, const uint16_t n ); + uint16_t calculate_checksum( const uint16_t *word_array, int size ); uint8_t rep_[60]; }; -- 1.7.1