--- /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.
+*/
+
+#ifndef PSEUDO_IPV4_HEADER_H
+#define PSEUDO_IPV4_HEADER_H
+
+//-----------------------------------------------------------------------------
+// PseudoIpv4Header
+//-----------------------------------------------------------------------------
+// Pseudo IPv4 header format used by TCP and UDP checksums:
+//
+// 0 8 16 31
+// +--------------------------------------------------------------+ ---
+// | | ^
+// | source IPv4 address | |
+// | | |
+// +--------------------------------------------------------------+ |
+// | | |
+// | destination IPv4 address | 12 bytes
+// | | |
+// +---------------+---------------+------------------------------+ |
+// | | | | |
+// | zero | protocol | header length | |
+// | | | | v
+// +---------------+---------------+------------------------------+ ---
+//
+//-----------------------------------------------------------------------------
+
+class PseudoIpv4Header
+{
+public:
+ uint32_t source_address;
+ uint32_t destination_address;
+ uint8_t zero_byte;
+ uint8_t protocol; // protocol
+ uint16_t header_length; // TCP or UDP header length
+};
+
+#endif /* PSEUDO_IPV4_HEADER_H */
--- /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.
+*/
+#ifndef TCP_HEADER_H
+#define TCP_HEADER_H
+
+#include <algorithm>
+
+#include <boost/asio/ip/tcp_raw_protocol.hpp>
+
+#include "ip/pseudoipv4header.h"
+
+// TCP Segment header.
+//
+// The wire format of a TCP header is:
+//
+// 0 4 8 16 24 31
+// +-------------------------------+------------------------------+ ---
+// | | | ^
+// | source port | destination port | |
+// | | | |
+// +--------------------------------------------------------------+ |
+// | | |
+// | sequence number | |
+// | | |
+// +--------------------------------------------------------------+ |
+// | | |
+// | acknowledgment number (if ACK set) | 20 bytes
+// | | |
+// +-------+-------+-+-+-+-+-+-+-+-+------------------------------+ |
+// | data | reser-|C|E|U|A|P|R|S|F| | |
+// |offset | ved |W|C|R|C|S|S|Y|I| window size | |
+// | | |R|E|G|K|H|T|N|N| | |
+// +---------------+-+-+-+-+-+-+-+-+------------------------------+ |
+// | | | |
+// | checksum | urgent pointer (if URG set) | |
+// | | | v
+// +-----------------------------------------------+--------------+ ---
+// | | | ^
+// | | | |
+// | options (if Data Offset > 5) | padding / 0 - 40
+// | | / bytes
+// | | | |
+// | | | v
+// +-----------------------------------------------+--------------+ ---
+//
+//-----------------------------------------------------------------------------
+
+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 );
+ }
+
+ uint16_t calculate_tcp_checksum(
+ uint32_t src_addr,
+ uint32_t dest_addr,
+ char* payload_data,
+ uint16_t payload_size_in_bytes )
+ {
+ checksum( 0 );
+ uint16_t tcp_header_size_in_bytes = 20;
+
+ 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_header_size_in_bytes + payload_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,
+ payload_data, payload_size_in_bytes );
+
+ uint16_t cksum = calculate_checksum( (uint16_t *)
+ tcp_buffer,
+ pseudo_header_size_in_bytes + tcp_header_size_in_bytes + 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 = ( 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 );
+ }
+
+private:
+ uint16_t decode( int a, int b ) const
+ {
+ return (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);
+ }
+
+ uint8_t rep_[60];
+};
+
+#endif /* TCP_HEADER_H */