From: Guilherme Maciel Ferreira Date: Sun, 6 Nov 2011 21:28:54 +0000 (-0200) Subject: Bring aboard TCP segment factory. X-Git-Tag: v1.2~33 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=24ed023fb6799ceae3c0855ff5421b0fa9b82baf;p=pingcheck Bring aboard TCP segment factory. - This class handles the TCP segment creation for IPv4 and IPv6 --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c4bc227..c4d9941 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -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 index 0000000..2e0b60d --- /dev/null +++ b/src/tcp/tcpsegmentfactory.cpp @@ -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 + +#include + +#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 index 0000000..50daa32 --- /dev/null +++ b/src/tcp/tcpsegmentfactory.h @@ -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 + +#include + +#include + +#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