9

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.

2
  • How do you load the information into the structures and where does it come from? Commented Jan 13, 2012 at 2:36
  • You should also look at RFC 1071, which gives correct C code for the calculation. Commented Mar 28, 2022 at 5:46

4 Answers 4

7

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);
}
Sign up to request clarification or add additional context in comments.

Comments

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.

Comments

4

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

2 Comments

Link is obsolete.
@Perennial, recovered site and updated link, see UPDATE.
3

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?

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.