TCP checksum for IPv6
authorGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Mon, 21 Nov 2011 22:45:18 +0000 (20:45 -0200)
committerGuilherme Maciel Ferreira <guilherme.maciel.ferreira@gmail.com>
Mon, 21 Nov 2011 22:45:18 +0000 (20:45 -0200)
src/ip/pseudoipv6header.h [new file with mode: 0644]
src/tcp/tcpheader.cpp
src/tcp/tcpheader.h

diff --git a/src/ip/pseudoipv6header.h b/src/ip/pseudoipv6header.h
new file mode 100644 (file)
index 0000000..375afea
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+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_IPV6_HEADER_H
+#define PSEUDO_IPV6_HEADER_H
+
+//-----------------------------------------------------------------------------
+// PseudoIpv6Header
+//-----------------------------------------------------------------------------
+
+/**
+ * @brief This class represents a pseudo IPv6 header used to compute checksum of
+ * transport layer protocols.
+ *
+ * When TCP runs over IPv6, the method used to compute the checksum is defined
+ * in RFC 2460.
+ *
+ * Pseudo IPv6 header format used by TCP and UDP checksums:
+ *
+ * @code
+ * 0                                             23 24           31
+ * +--------------------------------------------------------------+      ---
+ * |                                                              |       ^
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                      source IPv6 address                     |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * +--------------------------------------------------------------+       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |   40 bytes
+ * |                   destination IPv6 address                   |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * |                                                              |       |
+ * +--------------------------------------------------------------+       |
+ * |                                                              |       |
+ * |              upper-layer packet length in bytes              |       |
+ * |                                                              |       |
+ * +-----------------------------------------------+--------------+       |
+ * |                                               |              |       |
+ * |                     zero                      | next header  |       |
+ * |                                               |              |       v
+ * +-----------------------------------------------+--------------+      ---
+ * @endcode
+ */
+class PseudoIpv6Header
+{
+public:
+    /// Source IPv6 address
+    uint8_t source_address[16];
+    /// Destination IPv6 address
+    uint8_t destination_address[16];
+    /// The length of the upper-layer header and data (e.g. TCP header plus
+    /// TCP data).
+    uint32_t next_packet_length_in_bytes;
+    /// Zero has 24 bits split among three 8 bits, once there is no uint24_t
+    uint8_t zero_byte[3];
+    /// The header of the next protocol
+    uint8_t next_header;
+
+};
+
+#endif // PSEUDO_IPV6_HEADER_H
index 1677f4e..fb9ef07 100644 (file)
@@ -28,9 +28,11 @@ on this file might be covered by the GNU General Public License.
 #include <boost/assert.hpp>
 
 #include "ip/pseudoipv4header.h"
+#include "ip/pseudoipv6header.h"
 
 using namespace std;
 using boost::asio::ip::address_v4;
+using boost::asio::ip::address_v6;
 
 //-----------------------------------------------------------------------------
 // TcpHeader
@@ -166,6 +168,53 @@ uint16_t TcpHeader::calculate_tcp_checksum(
     return cksum;
 }
 
+uint16_t TcpHeader::calculate_tcp_checksum(
+        const address_v6::bytes_type &src_addr,
+        const address_v6::bytes_type &dest_addr,
+        const uint8_t* tcp_payload_data,
+        const uint16_t tcp_payload_size_in_bytes )
+{
+    set_checksum( 0 );
+    uint16_t tcp_segment_size_in_bytes = static_cast< uint16_t > (
+            TcpHeaderSizeInBytes + tcp_payload_size_in_bytes
+    );
+
+    PseudoIpv6Header pseudo_header;
+    BOOST_ASSERT( src_addr.size() == sizeof(pseudo_header.source_address) );
+    BOOST_ASSERT( dest_addr.size() == sizeof(pseudo_header.destination_address) );
+    copy( src_addr.begin(), src_addr.end(), pseudo_header.source_address );
+    copy( dest_addr.begin(), dest_addr.end(), pseudo_header.destination_address );
+    fill_n( pseudo_header.zero_byte, 3, 0 );
+    pseudo_header.next_header = IPPROTO_TCP;
+    pseudo_header.next_packet_length_in_bytes = tcp_segment_size_in_bytes;
+
+    uint8_t *pseudo_header_data = reinterpret_cast<uint8_t *>( &pseudo_header );
+    size_t pseudo_header_size_in_bytes = sizeof(pseudo_header);
+
+    uint8_t *tcp_header_data = Payload.get();
+    size_t tcp_header_size_in_bytes = TcpHeaderSizeInBytes;
+
+    uint8_t tcp_buffer[65536];
+    size_t tcp_buffer_size_in_bytes = sizeof(tcp_buffer);
+    fill( tcp_buffer, tcp_buffer + tcp_buffer_size_in_bytes, 0 );
+
+    copy( pseudo_header_data, pseudo_header_data + pseudo_header_size_in_bytes,
+          tcp_buffer );
+    copy( tcp_header_data, tcp_header_data + tcp_header_size_in_bytes,
+          tcp_buffer + pseudo_header_size_in_bytes );
+    copy( tcp_payload_data, tcp_payload_data + tcp_payload_size_in_bytes,
+          tcp_buffer + pseudo_header_size_in_bytes + tcp_header_size_in_bytes );
+
+    uint16_t cksum = calculate_checksum(
+            reinterpret_cast<uint16_t *>( tcp_buffer ),
+            pseudo_header_size_in_bytes + TcpHeaderSizeInBytes + tcp_payload_size_in_bytes
+    );
+
+    cksum = ntohs( cksum );
+
+    return cksum;
+}
+
 void TcpHeader::set_source_port( const uint16_t port )
 {
     Payload.encode16( 0, 1, port );
index 60e60f8..33cd52d 100644 (file)
@@ -97,6 +97,12 @@ public:
             const uint8_t *tcp_payload_data,
             const uint16_t tcp_payload_size_in_bytes
     );
+    uint16_t calculate_tcp_checksum(
+            const boost::asio::ip::address_v6::bytes_type &src_addr,
+            const boost::asio::ip::address_v6::bytes_type &dest_addr,
+            const uint8_t *tcp_payload_data,
+            const uint16_t tcp_payload_size_in_bytes
+    );
 
     void set_source_port( const uint16_t port );
     void set_destination_port( const uint16_t port );