Reputation: 333
i'm trying to calculate the checksum of an ip address header(without options), following the algorithm: divide the header in 16 bit words, sum all the words, apply NOT operator on the result to obtain the checksum, but i still got wrong results, sniffing the packets with wireshark i can see that they are wrong, for example, this is my method:
void compute_ip_checksum(struct ip_hdr* ip){
unsigned short* begin = (unsigned short*)ip;
unsigned short* end = begin + (IP_NOPT_HEADER_LENGTH / 2);
unsigned short checksum = 0;
ip->checksum = 0;
for (; begin != end; begin++){
checksum += *begin;
}
ip->checksum = htons(~checksum);
}
the ip header i build is:
ip.version_and_length = (IPV4 << 4) | (IP_NOPT_HEADER_LENGTH/4);
ip.type_of_service = 0;
ip.total_length = htons(IP_NOPT_HEADER_LENGTH + TCP_NOPT_HEADER_LENGTH);
ip.frag_id = 0;
ip.flags_and_frag_offset = htons(DONT_FRAGMENT << 13);
ip.time_to_live = 128;
ip.protocol = TCP_PAYLOAD;
ip.src_ip = inet_addr("1.1.1.1");
ip.dst_ip = inet_addr("1.1.1.2");
Since i'm converting all the values to the network byte order, i'm not doing any conversions in the checksum sum, only after the NOT operation, cause i'm almost sure that my windows is LITTLEENDIAN, and if thats the case the result will be put in this byteorder. the result of my functions is: 0x7a17 and the wireshark result is 0x7917 for this header. Can someone explain what is wrong here? my references are: RFC 791 and How to Calculate IpHeader Checksum
Upvotes: 2
Views: 3306
Reputation: 333
So after reading this link: wikipedia i could see that checksum is a little bit more tricky than expected, now this is the code that works for me:
void compute_ip_checksum(struct ip_hdr* ip, struct ip_options* opt){
unsigned short* begin = (unsigned short*)ip;
unsigned short* end = begin + IP_NOPT_HEADER_LENGTH / 2;
unsigned int checksum = 0, first_half, second_half;
ip->checksum = 0;
for (; begin != end; begin++){
checksum += *begin;
}
first_half = (unsigned short)(checksum >> 16);
while (first_half){
second_half = (unsigned short)((checksum << 16) >> 16);
checksum = first_half + second_half;
first_half = (unsigned short)(checksum >> 16);
}
ip->checksum = ~checksum;
}
as you can see, there is no need for conversion after the NOT operation, i've put the carry calculation in a loop because i don't know how many time i have to do this step, i think that in my case it dont exceed one.
Upvotes: 2