C Programming TCP Checksum
Solution 1
I found a fairly good example on the winpcap-users mailing list which should address Greg's comment about odd length data and give you something to compare your code against.
USHORT CheckSum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size >1)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size)
cksum += *(UCHAR*)buffer;
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}
Solution 2
I see a couple of things:
- You are not accounting for odd length data by padding with zero.
- You will need to account for network byte order when reading each word from the packet.
- Your use of
htonl(0x0000ffff)
seems suspicious. Why are you converting a constant to network byte order to combine it with data in host byte order?
Solution 3
I too struggled to find c++/c code that computes it, until I found How to Calculate IP/TCP/UDP Checksum–Part 2 Implementation – roman10, and it worked! Tested it with Wireshark's validation.
UPDATE
Link broke meanwhile, recovered it and put it as a gist in my account - How to Calculate IP/TCP/UDP Checksum
Solution 4
RFC 793 says "If a segment contains an odd number of header and text octets to be checksummed, the last octet is padded on the right with zeros to form a 16 bit word for checksum purposes." Your code above does not handle that case. I think the loop conditional should be i > 1 and then check for i == 1 outside the loop and do the special handling for the last octet.
Hudson Worden
Updated on June 04, 2022Comments
-
Hudson Worden almost 2 years
I have been having trouble doing the checksum for TCP for several days now. I have looked at many sources on the Internet but none of the examples that I have seen show you how to do the TCP checksum. I have also looked at the RFC document and still I am having trouble:
Below is the code I am using to generate the checksum:
unsigned short checksum(unsigned short * buffer, int bytes) { unsigned long sum = 0; unsigned short answer = 0; int i = bytes; while(i>0) { sum+=*buffer; buffer+=1; i-=2; } sum = (sum >> 16) + (sum & htonl(0x0000ffff)); sum += (sum >> 16); return ~sum; }
This function works for the IP checksum.
Below is the struct I have made for my TCP header:
struct tcp_header { unsigned short tcp_sprt; unsigned short tcp_dprt; unsigned int tcp_seq; unsigned int tcp_ack; unsigned char tcp_res:4; unsigned char tcp_off:4; unsigned char tcp_flags; unsigned short tcp_win; unsigned short tcp_csum; unsigned short tcp_urp; };
I have been using Wireshark to test these packets and the only thing wrong is the checksum.
Finally here is the pseudo header struct that I load up with the TCP header and information from the IP header:
struct pseudoTcpHeader { unsigned int ip_src; unsigned int ip_dst; unsigned char zero;//always zero unsigned char protocol;// = 6;//for tcp unsigned short tcp_len; struct tcp_header tcph; };
Once I load up this struct with the correct information I then use the checksum function on the entire pseudo header struct and assign the TCP checksum to that value. Do you see anything wrong with what I have provided? If the problem isn't here it may be a careless error that I can't see.
-
Perennial over 4 yearsLink is obsolete.
-
david-hoze over 4 years@Perennial, recovered site and updated link, see UPDATE.