Hi All,
I got stuck with TCP header checksum calculation.
RFC 793 says checksum is calculated using the same algorithm as IP header checksum and includes 96-bit pseudo header + data.
I have written a checksum calculation function, and it works well for IP headers, but when I apply it to the TCP packet the function produces wrong results.
I have captured a TCP packet from my network, and put it into my
test program. There are 2 checksum functions in the code: Checksum and ChecksumRFC. The last one is taken from RFC1071.
The code is for Windows 2000, VC6.0
Could anyone explain me what I do wrong?
<br />
#include <stdio.h><br />
#include <windows.h><br />
<br />
<br />
<br />
#include <pshpack1.h><br />
<br />
typedef struct _IP_HEADER<br />
{<br />
UCHAR HeaderLength :4;
UCHAR Version :4;
<br />
UCHAR TypeOfService;
USHORT TotalLength;
USHORT Identification;
USHORT FlagsFragment;
UCHAR TimeToLive;
UCHAR Protocol;
USHORT Checksum;
ULONG SourceAddress;
ULONG DestAddress;
} IP_HEADER, *PIP_HEADER;<br />
<br />
<br />
#define IPPROTO_TCP 6<br />
#define IPPROTO_UDP 17<br />
<br />
<br />
<br />
typedef struct _TCP_HEADER<br />
{<br />
USHORT SourcePort;
USHORT DestPort;
ULONG SeqNumber;
ULONG AckNumber;
UCHAR Reserved :4;
UCHAR Offset :4;
UCHAR FIN :1;
UCHAR SYN :1;
UCHAR RST :1;
UCHAR PSH :1;
UCHAR ACK :1;
UCHAR URG :1;
UCHAR Reserved1:1;
UCHAR Reserved2:1;
USHORT Window;
USHORT Checksum;
USHORT Urgent;
} TCP_HEADER, *PTCP_HEADER;<br />
<br />
<br />
<br />
typedef struct _TCP_PSEUDOHEADER<br />
{<br />
ULONG SourceAddress;
ULONG DestAddress;
UCHAR Zero;
UCHAR Protocol;
USHORT TcpLength;
} TCP_PSEUDOHEADER, *PTCP_PSEUDOHEADER;<br />
<br />
#include <poppack.h><br />
<br />
<br />
VOID DumpIPHeader( PIP_HEADER IpHeader )<br />
{<br />
printf <br />
(<br />
"=== IP Header Dump Begin ===\n"<br />
"Header length (32bit words): %d\n"<br />
"Version: %d\n"<br />
"TypeOfService: %d\n"<br />
"TotalLength: %d\n"<br />
"Identification: 0x%0X\n"<br />
"Flags/Fragment: 0x%X\n"<br />
"TimeToLive: 0x%X\n"<br />
"Protocol: 0x%X\n"<br />
"Checksum: 0x%X\n"<br />
"Source: 0x%08X\n"<br />
"Dest: 0x%08X\n"<br />
,<br />
IpHeader->HeaderLength,<br />
IpHeader->Version, <br />
IpHeader->TypeOfService, <br />
ntohs( IpHeader->TotalLength ), <br />
IpHeader->Identification, <br />
IpHeader->FlagsFragment, <br />
IpHeader->TimeToLive, <br />
IpHeader->Protocol, <br />
IpHeader->Checksum, <br />
IpHeader->SourceAddress, <br />
IpHeader->DestAddress<br />
);<br />
}<br />
<br />
VOID DumpTCPHeader( PTCP_HEADER TcpHeader )<br />
{<br />
<br />
printf (<br />
"=== TCP Header Dump Begin ===\n"<br />
"Source port: 0x%4X\n"<br />
"Dest port : 0x%4X\n"<br />
"Sequence : 0x%0X\n"<br />
"Acknowledge: 0x%0X\n"<br />
"Offset : %d\n"<br />
"SYN : 0x%X\n"<br />
"Window : 0x%X\n"<br />
"Checksum : 0x%X\n"<br />
"Urgent : 0x%X\n"<br />
"ACK : 0x%X\n"<br />
"PSH : 0x%X\n"<br />
,<br />
TcpHeader->SourcePort, <br />
TcpHeader->DestPort, <br />
ntohl(TcpHeader->SeqNumber),<br />
ntohl(TcpHeader->AckNumber), <br />
TcpHeader->Offset,<br />
TcpHeader->SYN, <br />
TcpHeader->Window, <br />
TcpHeader->Checksum,<br />
TcpHeader->Urgent,<br />
TcpHeader->ACK, <br />
TcpHeader->PSH<br />
<br />
);<br />
}<br />
<br />
<br />
UCHAR Packet[478] =<br />
{<br />
0x45, 0x00, <br />
0x01, 0xDE, 0x50, 0xA8, 0x40, 0x00, 0x80, 0x06, 0xC5, 0x8E, 0xC0, 0xA8, 0x04, 0x30, 0x14, 0x0A, <br />
0x0A, 0x01, 0x0B, 0x27, 0x00, 0x50, 0xAC, 0x78, 0xD2, 0x04, 0xB0, 0x9A, 0x29, 0x07, 0x50, 0x18,<br />
0x44, 0x70, 0xE3, 0x3F, 0x00, 0x00, 0x47, 0x45, 0x54, 0x20, 0x2F, 0x74, 0x65, 0x73, 0x74, 0x20,<br />
0x48, 0x54, 0x54, 0x50, 0x2F, 0x31, 0x2E, 0x31, 0x0D, 0x0A, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74,<br />
0x3A, 0x20, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2F, 0x67, 0x69, 0x66, 0x2C, 0x20, 0x69, 0x6D, 0x61, <br />
0x67, 0x65, 0x2F, 0x78, 0x2D, 0x78, 0x62, 0x69, 0x74, 0x6D, 0x61, 0x70, 0x2C, 0x20, 0x69, 0x6D,<br />
0x61, 0x67, 0x65, 0x2F, 0x6A, 0x70, 0x65, 0x67, 0x2C, 0x20, 0x69, 0x6D, 0x61, 0x67, 0x65, 0x2F,<br />
0x70, 0x6A, 0x70, 0x65, 0x67, 0x2C, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, <br />
0x6F, 0x6E, 0x2F, 0x76, 0x6E, 0x64, 0x2E, 0x6D, 0x73, 0x2D, 0x65, 0x78, 0x63, 0x65, 0x6C, 0x2C,<br />
0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E, 0x2F, 0x6D, 0x73, 0x77,<br />
0x6F, 0x72, 0x64, 0x2C, 0x20, 0x61, 0x70, 0x70, 0x6C, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6F, 0x6E,<br />
0x2F, 0x76, 0x6E, 0x64, 0x2E, 0x6D, 0x73, 0x2D, 0x70, 0x6F, 0x77, 0x65, 0x72, 0x70, 0x6F, 0x69,<br />
0x6E, 0x74, 0x2C, 0x20, 0x2A, 0x2F, 0x2A, 0x0D, 0x0A, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2D,<br />
0x4C, 0x61, 0x6E, 0x67, 0x75, 0x61, 0x67, 0x65, 0x3A, 0x20, 0x65, 0x6E, 0x2D, 0x67, 0x62, 0x0D,<br />
0x0A, 0x41, 0x63, 0x63, 0x65, 0x70, 0x74, 0x2D, 0x45, 0x6E, 0x63, 0x6F, 0x64, 0x69, 0x6E, 0x67, <br />
0x3A, 0x20, 0x67, 0x7A, 0x69, 0x70, 0x2C, 0x20, 0x64, 0x65, 0x66, 0x6C, 0x61, 0x74, 0x65, 0x0D,<br />
0x0A, 0x55, 0x73, 0x65, 0x72, 0x2D, 0x41, 0x67, 0x65, 0x6E, 0x74, 0x3A, 0x20, 0x4D, 0x6F, 0x7A,<br />
0x69, 0x6C, 0x6C, 0x61, 0x2F, 0x34, 0x2E, 0x30, 0x20, 0x28, 0x63, 0x6F, 0x6D, 0x70, 0x61, 0x74, <br />
0x69, 0x62, 0x6C, 0x65, 0x3B, 0x20, 0x4D, 0x53, 0x49, 0x45, 0x20, 0x35, 0x2E, 0x30, 0x31, 0x3B,<br />
0x20, 0x57, 0x69, 0x6E, 0x64, 0x6F, 0x77, 0x73, 0x20, 0x4E, 0x54, 0x20, 0x35, 0x2E, 0x30, 0x29,<br />
0x0D, 0x0A, 0x48, 0x6F, 0x73, 0x74, 0x3A, 0x20, 0x32, 0x30, 0x2E, 0x31, 0x30, 0x2E, 0x31, 0x30, <br />
0x2E, 0x31, 0x0D, 0x0A, 0x43, 0x6F, 0x6E, 0x6E, 0x65, 0x63, 0x74, 0x69, 0x6F, 0x6E, 0x3A, 0x20,<br />
0x4B, 0x65, 0x65, 0x70, 0x2D, 0x41, 0x6C, 0x69, 0x76, 0x65, 0x0D, 0x0A, 0x43, 0x6F, 0x6F, 0x6B,<br />
0x69, 0x65, 0x3A, 0x20, 0x4D, 0x53, 0x41, 0x53, 0x50, 0x43, 0x6C, 0x69, 0x65, 0x6E, 0x74, 0x53,<br />
0x69, 0x64, 0x65, 0x43, 0x6F, 0x6C, 0x6F, 0x72, 0x3D, 0x38, 0x30, 0x38, 0x30, 0x30, 0x30, 0x3B,<br />
0x20, 0x4D, 0x53, 0x41, 0x53, 0x50, 0x48, 0x54, 0x4D, 0x4C, 0x43, 0x6F, 0x6C, 0x6F, 0x72, 0x3D,<br />
0x25, 0x32, 0x33, 0x46, 0x46, 0x38, 0x30, 0x38, 0x30, 0x3B, 0x20, 0x41, 0x53, 0x50, 0x53, 0x45,<br />
0x53, 0x53, 0x49, 0x4F, 0x4E, 0x49, 0x44, 0x51, 0x47, 0x47, 0x47, 0x47, 0x52, 0x43, 0x43, 0x3D, <br />
0x4D, 0x46, 0x42, 0x4C, 0x49, 0x4C, 0x4D, 0x42, 0x4B, 0x48, 0x4A, 0x41, 0x47, 0x48, 0x47, 0x50, <br />
0x4F, 0x46, 0x41, 0x43, 0x47, 0x45, 0x4E, 0x49, 0x0D, 0x0A, 0x0D, 0x0A<br />
};<br />
<br />
<br />
USHORT Checksum( PUCHAR Data, USHORT Length )<br />
{<br />
ULONG Sum = 0;<br />
USHORT ShortSum = 0;<br />
PUSHORT WordData = (PUSHORT) Data;<br />
USHORT WordCount = Length >> 1;<br />
<br />
while( WordCount-- )<br />
Sum += *WordData++;<br />
<br />
if( Length & 1 )<br />
Sum += *(PUCHAR)WordData;<br />
<br />
Sum = (USHORT) Sum + (Sum >> 16) & 0xFFFF;<br />
ShortSum = (USHORT) Sum + (USHORT)(Sum >> 16);<br />
<br />
return (ShortSum != 0xFFFF) ? ~ShortSum : ShortSum;<br />
} <br />
<br />
USHORT ChecksumRFC( PUCHAR Data, USHORT Length )<br />
{<br />
ULONG Sum = 0;<br />
PUSHORT WD = (PUSHORT) Data;<br />
<br />
while( Length > 1 )<br />
{<br />
Sum += * WD++;<br />
Length -= 2;<br />
}<br />
<br />
if( Length > 0 )<br />
{<br />
Sum += *(PUCHAR)WD;<br />
}<br />
<br />
while( Sum >> 16 )<br />
{<br />
Sum = (Sum & 0xFFFF) + (Sum >> 16);<br />
}<br />
<br />
return (USHORT) ~Sum;<br />
}<br />
<br />
<br />
void main()<br />
{<br />
PIP_HEADER IpHeader = (PIP_HEADER) Packet;<br />
PTCP_HEADER TcpHeader = (PTCP_HEADER)( Packet + IpHeader->HeaderLength*4);<br />
USHORT TcpDataLength = ntohs( IpHeader->TotalLength ) - IpHeader->HeaderLength*4;<br />
<br />
DumpIPHeader( IpHeader );<br />
DumpTCPHeader( TcpHeader );<br />
printf( "\nTcpDataLength %d\n", TcpDataLength );<br />
<br />
USHORT OldChecksum;<br />
<br />
OldChecksum = IpHeader->Checksum;<br />
IpHeader->Checksum = 0;<br />
<br />
printf( "\nIpHeader->Checksum 0x%X\n", Checksum( (PUCHAR) IpHeader, IpHeader->HeaderLength*4) );<br />
printf( "\nRFC IpHeader->Checksum 0x%X\n", ChecksumRFC( (PUCHAR) IpHeader, IpHeader->HeaderLength*4) );<br />
<br />
IpHeader->Checksum = OldChecksum;<br />
<br />
TCP_PSEUDOHEADER TcpPSHeader;<br />
<br />
TcpPSHeader.SourceAddress = IpHeader->SourceAddress;<br />
TcpPSHeader.DestAddress = IpHeader->DestAddress;<br />
TcpPSHeader.Zero = 0;<br />
TcpPSHeader.Protocol = IpHeader->Protocol;<br />
TcpPSHeader.TcpLength = TcpDataLength;<br />
<br />
UCHAR tcp[ 478 + 12 ];<br />
<br />
OldChecksum = TcpHeader->Checksum;<br />
<br />
memset( tcp, 0, 478 + 12 );<br />
memcpy( &tcp[ 0 ], &TcpPSHeader, sizeof( TcpPSHeader ) );<br />
memcpy( &tcp[ 12 ], TcpHeader, TcpDataLength );<br />
<br />
printf( "\nTCP Checksum 0x%X\n", Checksum( tcp, 478+12 ) );<br />
printf( "\nRFC TCP Checksum 0x%X\n", ChecksumRFC( tcp, 478+12 ) );<br />
<br />
TcpHeader->Checksum = OldChecksum;<br />
<br />
printf( "\n0x%X\n", (USHORT)~OldChecksum );<br />
<br />
}<br />
|