From: Guilherme Maciel Ferreira Date: Mon, 21 Nov 2011 22:45:18 +0000 (-0200) Subject: TCP checksum for IPv6 X-Git-Tag: v1.2~4 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=5725cb0f0aa4a6e7c87e4caa66c3fecb4dfa2c63;p=pingcheck TCP checksum for IPv6 --- diff --git a/src/ip/pseudoipv6header.h b/src/ip/pseudoipv6header.h new file mode 100644 index 0000000..375afea --- /dev/null +++ b/src/ip/pseudoipv6header.h @@ -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 diff --git a/src/tcp/tcpheader.cpp b/src/tcp/tcpheader.cpp index 1677f4e..fb9ef07 100644 --- a/src/tcp/tcpheader.cpp +++ b/src/tcp/tcpheader.cpp @@ -28,9 +28,11 @@ on this file might be covered by the GNU General Public License. #include #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( &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( 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 ); diff --git a/src/tcp/tcpheader.h b/src/tcp/tcpheader.h index 60e60f8..33cd52d 100644 --- a/src/tcp/tcpheader.h +++ b/src/tcp/tcpheader.h @@ -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 );