Bring aboard TCP segment factory.
authorGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Sun, 6 Nov 2011 21:28:54 +0000 (19:28 -0200)
committerGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Sun, 6 Nov 2011 21:28:54 +0000 (19:28 -0200)
- This class handles the TCP segment creation for IPv4 and IPv6

src/CMakeLists.txt
src/tcp/tcpsegmentfactory.cpp [new file with mode: 0644]
src/tcp/tcpsegmentfactory.h [new file with mode: 0644]

index c4bc227..c4d9941 100644 (file)
@@ -64,6 +64,7 @@ set(SOURCES
     tcp/tcppinger.cpp
     tcp/tcpipv4segment.cpp
     tcp/tcpsegment.cpp
+    tcp/tcpsegmentfactory.cpp
     main.cpp
 )
 
diff --git a/src/tcp/tcpsegmentfactory.cpp b/src/tcp/tcpsegmentfactory.cpp
new file mode 100644 (file)
index 0000000..2e0b60d
--- /dev/null
@@ -0,0 +1,176 @@
+/*
+ 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/tcpsegmentfactory.h"
+
+#include <boost/assert.hpp>
+
+#include <logfunc.hpp>
+
+#include "tcp/tcpheader.h"
+#include "tcp/tcpipv4segment.h"
+
+using namespace std;
+using boost::asio::ip::address;
+using I2n::Logger::GlobalLogger;
+
+//-----------------------------------------------------------------------------
+// TcpSegmentFactory
+//-----------------------------------------------------------------------------
+
+TcpSegmentItem TcpSegmentFactory::create_tcp_segment(
+        const IpVersion version,
+        std::istream &is
+)
+{
+    BOOST_ASSERT( (IP_VERSION_4 == version) || (IP_VERSION_6 == version) );
+
+    TcpSegmentItem tcp_segment;
+
+    switch ( version )
+    {
+    case IP_VERSION_4:
+        tcp_segment.reset( new TcpIpv4Segment() );
+        break;
+#ifdef IPV6_WORKING
+    case IP_VERSION_6:
+        tcp_segment.reset( new TcpIpv6Segment() );
+        break;
+#endif
+    default:
+        BOOST_ASSERT( !"Invalid TCP Segment Type." );
+        break;
+    }
+
+    if ( !tcp_segment->read( is ) )
+    {
+        GlobalLogger.notice() << "Could not read TCP Segment." << endl;
+
+        // TODO why good packets reports as bad?
+        //IcmpPacketItem icmp_packet_empty;
+        //tcp_segment = icmp_packet_empty;
+    }
+
+    return tcp_segment;
+}
+
+
+TcpSegmentItem TcpSegmentFactory::create_tcp_segment_ack_request(
+        const IpVersion version,
+        const uint32_t source_address,
+        const uint32_t destination_address,
+        const uint16_t source_port,
+        const uint16_t destination_port,
+        const uint16_t sequence_number
+)
+{
+    BOOST_ASSERT( (IP_VERSION_4 == version) || (IP_VERSION_6 == version) );
+
+    TcpSegmentItem tcp_segment;
+
+    switch (version)
+    {
+    case IP_VERSION_4:
+        tcp_segment = create_tcp_ipv4_segment_ack_request(
+                source_address, destination_address,
+                source_port, destination_port, sequence_number );
+        break;
+#ifdef IPV6_WORKING
+    case IP_VERSION_6:
+        tcp_segment = create_tcp_ipv6_segment_ack_request(
+                source_address, destination_address,
+                source_port, destination_port, sequence_number );
+        break;
+#endif
+    default:
+        BOOST_ASSERT( !"Invalid TCP Segment Type." );
+        break;
+    }
+
+    return tcp_segment;
+}
+
+TcpSegmentItem TcpSegmentFactory::create_tcp_ipv4_segment_ack_request(
+        const uint32_t source_address,
+        const uint32_t destination_address,
+        const uint16_t source_port,
+        const uint16_t destination_port,
+        const uint16_t sequence_number
+)
+{
+    // (5 words of 32 bits = 5 * 4 bytes = 20 bytes)
+    const uint8_t header_size_in_words = 5; // size in units of 32 bits
+    const uint16_t window_size_in_octets = 32768;
+
+    // Create an TCP header for an ACK request.
+    TcpHeader tcp_header;
+    tcp_header.set_source_port( source_port ); // assign a random ephemeral port number
+    tcp_header.set_destination_port( destination_port );
+    tcp_header.set_sequence_number( sequence_number );
+    tcp_header.set_header_length( header_size_in_words );
+    tcp_header.set_acknowledgment( true );
+    tcp_header.set_window_size( window_size_in_octets ); // window size
+
+    // Calculate the checksum of the TCP header
+    uint16_t cksum = tcp_header.calculate_tcp_checksum(
+            source_address, destination_address, NULL, 0
+    );
+    tcp_header.set_checksum( cksum );
+
+    TcpSegmentItem tcp_segment( new TcpIpv4Segment( tcp_header ) );
+
+    return tcp_segment;
+}
+
+TcpSegmentItem TcpSegmentFactory::create_tcp_ipv6_segment_ack_request(
+        const address source_address,
+        const address destination_address,
+        const uint16_t source_port,
+        const uint16_t destination_port,
+        const uint16_t sequence_number
+)
+{
+#ifdef IPV6_WORKING
+    // (5 words of 32 bits = 5 * 4 bytes = 20 bytes)
+    const uint8_t header_size_in_words = 5; // size in units of 32 bits
+    const uint16_t window_size_in_octets = 32768;
+
+    // Create an TCP header for an ACK request.
+    TcpHeader tcp_header;
+    tcp_header.set_source_port( source_port ); // assign a random ephemeral port number
+    tcp_header.set_destination_port( destination_port );
+    tcp_header.set_sequence_number( sequence_number );
+    tcp_header.set_header_length( header_size_in_words );
+    tcp_header.set_acknowledgment( true );
+    tcp_header.set_window_size( window_size_in_octets ); // window size
+
+    // Calculate the checksum
+    uint32_t src_address = source_address.to_v6().to_ulong();
+    uint32_t dst_address = destination_address.to_v6().to_ulong();
+    uint16_t cksum = tcp_header.calculate_tcp_checksum(
+            src_address, dst_address, NULL, 0
+    );
+    tcp_header.set_checksum( cksum );
+
+    TcpSegmentItem tcp_segment( new TcpIpv6Segment( tcp_header ) );
+#endif
+    TcpSegmentItem tcp_segment;
+    return tcp_segment;
+}
diff --git a/src/tcp/tcpsegmentfactory.h b/src/tcp/tcpsegmentfactory.h
new file mode 100644 (file)
index 0000000..50daa32
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ 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_SEGMENT_FACTORY_H
+#define TCP_SEGMENT_FACTORY_H
+
+#include <stdint.h>
+
+#include <iostream>
+
+#include <boost/asio.hpp>
+
+#include "ip/ipversion.h"
+#include "tcp/tcpsegment.h"
+
+//-----------------------------------------------------------------------------
+// TcpSegmentFactory
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief Class which constructs TCP Segments, hiding from the class users the
+ * underlying details on how to build each segment.
+ */
+class TcpSegmentFactory
+{
+public:
+    static TcpSegmentItem create_tcp_segment(
+            const IpVersion version,
+            std::istream &is
+    );
+    static TcpSegmentItem create_tcp_segment_ack_request(
+            const IpVersion version,
+            const uint32_t source_address,
+            const uint32_t destination_address,
+            const uint16_t source_port,
+            const uint16_t destination_port,
+            const uint16_t sequence_number
+    );
+
+private:
+    static TcpSegmentItem create_tcp_ipv4_segment_ack_request(
+            const uint32_t source_address,
+            const uint32_t destination_address,
+            const uint16_t source_port,
+            const uint16_t destination_port,
+            const uint16_t sequence_number
+    );
+    static TcpSegmentItem create_tcp_ipv6_segment_ack_request(
+            const boost::asio::ip::address source_address,
+            const boost::asio::ip::address destination_address,
+            const uint16_t source_port,
+            const uint16_t destination_port,
+            const uint16_t sequence_number
+    );
+
+};
+
+#endif // TCP_SEGMENT_FACTORY_H