简体   繁体   中英

IP and TCP header checksum calculate in c

I'm writing a simple program to send/receive TCP packets and incorporate it into a larger project. I got stuck at the checksum part where the number I calculated is not matched with the wireshark number.

For checksum function, I re-use the code from Mike Muss as below:

static int
in_cksum(u_short *addr, int len)
{
    register int nleft = len;
    register u_short *w = addr;
    register int sum = 0;
    u_short answer = 0;

    /*
     * Our algorithm is simple, using a 32 bit accumulator (sum), we add
     * sequential 16 bit words to it, and at the end, fold back all the
     * carry bits from the top 16 bits into the lower 16 bits.
     */
    while (nleft > 1)  {
        sum += *w++;
        nleft -= 2;
    }

    /* mop up an odd byte, if necessary */
    if (nleft == 1) {
        *(u_char *)(&answer) = *(u_char *)w ;
        sum += answer;
    }

    /* add back carry outs from top 16 bits to low 16 bits */
    sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */
    sum += (sum >> 16);         /* add carry */
    answer = ~sum;              /* truncate to 16 bits */
    return(answer);
}

I received a packet and store in char buffer[2048]. In order to get IP header, I do:

struct iphdr* ip;
ip = (struct iphdr*) buffer;

From here, I can read information correctly as ip->protocol, ip->saddr, etc., and even print out the correct checksum as displayed in wireshark

printf("Print checksum = 0x%x\n",ntohs(ip->check));

Then I try to calculate the checksum using the function above and print it out

printf("My calculated checksum =0x%x\n",in_cksum ((unsigned short*) ip, sizeof(struct iphdr)));

What I got is "My calculated checksym = 0x0" and it seems that there is nothing in IP header. I guess that I might not pass in the in_cksum function parameter correctly, but I'm not sure how to fix or if there is another problem in the way that I'm doing.

IP cksum problem is SOLVED below. However, I meet a similar problem when try to calculate TCP checksum. Below is how I get tcp header:

tcp=(struct tcphdr*) (buffer+sizeof(struct iphdr);

After this, again I can read correct information about tcp header such as tcp->source, tcp->dest, and even tcp->check

Then I tried to re-compute the checksum as below:

tcp->check=0;
tcp->check=in_cksum((unsigned short*)tcp, ntohs(ip->tot_length)-(4*ip->ihl));

The result I got here is different from what I printed out before. I think my problem could in the length that I pass in the cksum function, but am not quite sure how to fix it.

Any help would be greatly appreciated. Thank you in advance!

The calculation of the IP checksum must not include the field that contains that checksum - zero should be used for that field instead. From RFC 791 :

The checksum field is the 16 bit one's complement of the one's complement sum of all 16 bit words in the header. For purposes of computing the checksum, the value of the checksum field is zero.

I haven't done the math, but I suspect that getting zero is the expected consequence of recalculating the checksum over the entire header, ie it causes the calculated sum to cancel itself out.

[I checked - Wikipedia agrees: "The result of summing the entire IP header, including checksum, should be zero if there is no corruption" . Zero is therefore in fact the correct result when verifying the checksum]

Note that an IP header can only be a multiple of 4 bytes long, so your padding code is unnecessary in this particular case, albeit potentially useful if wanting to calculate the generic ones-complement checksum of other data.

Also, instead of passing sizeof(struct iphdr) you should be passing 4 * ip->ihl to account for any IP options that may be in the header, having first ensured that you actually have at least that many bytes in your buffer.

sum += (sum >> 16); /* add carry / answer = ~sum; / truncate to 16 bits */

If you add carry to the lower 2 bytes and negative it .

It will be obviously zero.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM