--- /dev/null
+/*
+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 <cstring>
+#include <netinet/in.h>
+#include <sys/socket.h>
+
+#include <algorithm>
+
+#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<uint8_t>( ( 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<uint16_t>( (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);
+}
#ifndef TCP_HEADER_H
#define TCP_HEADER_H
-#include <algorithm>
+#include <stdint.h>
-#include <boost/asio/ip/tcp_raw_protocol.hpp>
-
-#include "ip/pseudoipv4header.h"
+#include <istream>
+#include <ostream>
+//-----------------------------------------------------------------------------
+// TcpHeader
+//-----------------------------------------------------------------------------
+//
// TCP Segment header.
//
// The wire format of a TCP header is:
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<uint8_t>( ( 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<uint16_t>( (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];
};