C Programming TCP Checksum

19,674

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.

Share:
19,674
Hudson Worden
Author by

Hudson Worden

Updated on June 04, 2022

Comments

  • Hudson Worden
    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
    Perennial over 4 years
    Link is obsolete.
  • david-hoze
    david-hoze over 4 years
    @Perennial, recovered site and updated link, see UPDATE.