|
Home > Archive > Unix Programming > October 2005 > IP checksum problem
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
IP checksum problem
|
|
| Fernando Barsoba 2005-10-24, 3:48 pm |
| Hi all,
I'm having a problem calculating the checksum for an IP datagram. I got
the algorithm for the checksum from Steven's book, but I can't make it
work. I checked on a web page what my checksum will be (I tested it with
a real datagram and it works fine).. but my result using the mentioned
algorithm doesn't match with what I expected..
Here's my code, with the values hardcoded:
(the result I get is checksum=30433 (01110110-11100001)
and the one I think I should get is: 62818 (11110101-01100010)
The checksum web page is:
http://mna.nlanr.net/Software/HEC/hec.html
Thanks a lot,
FBM
#include "ipsec_v4.h"
#include <stdio.h>
#include <stdlib.h>
#define IP_VERSION 4
struct ip * build_ip_packet() {
struct ip *iphdr;
int packet_size;
char *packet;
struct in_addr ip_addr;
const char *host = "192.168.2.2";
packet_size = sizeof(struct ip);
packet = malloc(packet_size);
iphdr = (struct ip *)packet;
inet_aton(host, &ip_addr);
iphdr->ip_v = 4;
iphdr->ip_hl = 5;
iphdr->ip_tos = 0;
iphdr->ip_len = 20;
iphdr->ip_id = 0;
iphdr->ip_off = 0;
iphdr->ip_ttl = 64;
iphdr->ip_p = 51;
iphdr->ip_src = ip_addr;
iphdr->ip_dst = ip_addr;
iphdr->ip_sum = in_cksum((u_short *) iphdr, 20);
return iphdr;
}
int main(int argc, char **argv) {
struct ip *ip_datagram;
ip_datagram = build_ip_packet();
exit(0);
}
And the checksum algorithm:
#include <sys/types.h>
uint16_t in_cksum (uint16_t * addr, int len) {
int nleft = len;
uint32_t sum = 0;
uint16_t *w = addr;
uint16_t 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) {
* (unsigned char *) (&answer) = * (unsigned 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);
}
| |
| Giorgos Keramidas 2005-10-24, 3:48 pm |
| Fernando Barsoba <fbarsoba@verizon.net> writes:
> I'm having a problem calculating the checksum for an IP datagram.
> I got the algorithm for the checksum from Steven's book, but I can't
> make it work. I checked on a web page what my checksum will be (I
> tested it with a real datagram and it works fine).. but my result
> using the mentioned algorithm doesn't match with what I expected..
>
> Here's my code, with the values hardcoded:
> (the result I get is checksum=30433 (01110110-11100001)
> and the one I think I should get is: 62818 (11110101-01100010)
> #include "ipsec_v4.h"
> #include <stdio.h>
> #include <stdlib.h>
>
> #define IP_VERSION 4
>
> struct ip * build_ip_packet() {
> struct ip *iphdr;
> int packet_size;
> char *packet;
> struct in_addr ip_addr;
> const char *host = "192.168.2.2";
>
> packet_size = sizeof(struct ip);
> packet = malloc(packet_size);
> iphdr = (struct ip *)packet;
> inet_aton(host, &ip_addr);
>
> iphdr->ip_v = 4;
> iphdr->ip_hl = 5;
> iphdr->ip_tos = 0;
> iphdr->ip_len = 20;
> iphdr->ip_id = 0;
> iphdr->ip_off = 0;
> iphdr->ip_ttl = 64;
> iphdr->ip_p = 51;
> iphdr->ip_src = ip_addr;
> iphdr->ip_dst = ip_addr;
> iphdr->ip_sum = in_cksum((u_short *) iphdr, 20);
> return iphdr;
> }
I think what's wrong is that you should be resetting the ip_sum field to
zero before calling in_cksum() to recalculate it. You should also make
sure you're not using "magic" constants like 20, but the real length of
the IP header, IMHO:
iphdr->ip_sum = 0;
iphdr->ip_sum = in_cksum((uint16_t *)iphdr, (iphdr->ip_hl) << 4);
The fact that you're not resetting ip_sum to zero before the call to
in_cksum() for a recalculation of the checksum may be a good explanation
why you're seeing wrong results.
- Giorgos
| |
| Fernando Barsoba 2005-10-24, 3:48 pm |
| Giorgos Keramidas wrote:
> Fernando Barsoba <fbarsoba@verizon.net> writes:
>
>
>
>
>
> I think what's wrong is that you should be resetting the ip_sum field to
> zero before calling in_cksum() to recalculate it. You should also make
> sure you're not using "magic" constants like 20, but the real length of
> the IP header, IMHO:
>
> iphdr->ip_sum = 0;
> iphdr->ip_sum = in_cksum((uint16_t *)iphdr, (iphdr->ip_hl) << 4);
>
What you are saying makes a lot of sense.. however, I tried
(iphdr->ip_hl) << 4 and what I actually saw is that the length of the
datagram passed to the function is 80... Which is reasonable because
you're shifting 4 bits the 0101 and that's 01010000 (80). I changed it
to << 2 (the header length is 32-bit words) and it passed the 20 to the
function. Sadly, I got the same result.
> The fact that you're not resetting ip_sum to zero before the call to
> in_cksum() for a recalculation of the checksum may be a good explanation
> why you're seeing wrong results.
When I tried leaving the 20 and resetting the ip_sum field to 0, I got
the same result for the checksum.
Also, I realized that I didnt' set the FLAG field. Looking at the
"ip.h", there is the following:
(...)
u_char ip_tos; /* type of service */
u_short ip_len; /* total length */
u_short ip_id; /* identification */
u_short ip_off; /* fragment offset field */
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
u_char ip_ttl; /* time to live */
u_char ip_p; /* protocol */
u_short ip_sum; /* checksum */
struct in_addr ip_src,ip_dst; /* source and dest address */
};
(...)
But no ip_flag or anything.. however, the cheksum has to take into
account the 3-bit flag field to have all the 10x16bit rows. Could the
FLAG field be the cause of the problem?
FBM
>
> - Giorgos
>
| |
| Giorgos Keramidas 2005-10-24, 3:48 pm |
| Fernando Barsoba <fbarsoba@verizon.net> writes:
>Giorgos Keramidas wrote:
It would probably be a good idea to call calloc() here, or bzero() the
allocated area after you allocate it. This way, the entire data area
starts in a well-known, reproducible state.
[vbcol=seagreen]
>
> What you are saying makes a lot of sense.. however, I tried
> (iphdr->ip_hl) << 4 and what I actually saw is that the length of the
> datagram passed to the function is 80... Which is reasonable because
> you're shifting 4 bits the 0101 and that's 01010000 (80). I changed it
> to << 2 (the header length is 32-bit words) and it passed the 20 to
> the function. Sadly, I got the same result.
Err, yeah, you're right of course. I shouldn't really be posting when
I'm just out of bed and still sleepy 
> When I tried leaving the 20 and resetting the ip_sum field to 0, I got
> the same result for the checksum.
Hmmm, it would be nice if you could send 'dumps' of the IP header
before, and after the in_cksum() call.
> Also, I realized that I didnt' set the FLAG field. Looking at the
> "ip.h", there is the following:
What is a "FLAG"?
> (...)
> u_char ip_tos; /* type of service */
> u_short ip_len; /* total length */
> u_short ip_id; /* identification */
> u_short ip_off; /* fragment offset field */
> #define IP_RF 0x8000 /* reserved fragment flag */
> #define IP_DF 0x4000 /* dont fragment flag */
> #define IP_MF 0x2000 /* more fragments flag */
> #define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
> u_char ip_ttl; /* time to live */
> u_char ip_p; /* protocol */
> u_short ip_sum; /* checksum */
> struct in_addr ip_src,ip_dst; /* source and dest address */
> };
>
> (...)
>
> But no ip_flag or anything.. however, the cheksum has to take into
> account the 3-bit flag field to have all the 10x16bit rows. Could the
> FLAG field be the cause of the problem?
I'm not sure I understand what "FLAG" refers to.
| |
| Fernando Barsoba 2005-10-24, 3:48 pm |
| Giorgos Keramidas wrote:
> Fernando Barsoba <fbarsoba@verizon.net> writes:
>
>
>
> It would probably be a good idea to call calloc() here, or bzero() the
> allocated area after you allocate it. This way, the entire data area
> starts in a well-known, reproducible state.
>
>
>
>
> Err, yeah, you're right of course. I shouldn't really be posting when
> I'm just out of bed and still sleepy 
>
>
>
>
> Hmmm, it would be nice if you could send 'dumps' of the IP header
> before, and after the in_cksum() call.
>
Yes. I have it printed out below..
>
>
>
> What is a "FLAG"?
>
>
>
>
> I'm not sure I understand what "FLAG" refers to.
>
The IP header has a 3-bit flag field which is used to calculate the
checksum. I'd want to put them to 0.
http://www.networksorcery.com/enp/protocol/ip.htm
ip header(before):
version: 4
hl: 5
tos: 0
len: 14
id: 0
off: 0
ttl: 40
protocol: 33
src: 202a8c0
dst: 202a8c0
checksum: 0
ip header(after):
version: 4
hl: 5
tos: 0
len: 14
id: 0
off: 0
ttl: 40
protocol: 33
src: 202a8c0
dst: 202a8c0
checksum: 30433
*******new function:
packet_size = sizeof(struct ip);
packet = malloc(packet_size);
bzero(packet, packet_size);
iphdr = (struct ip *)packet;
inet_aton(host, &ip_addr);
iphdr->ip_v = 4;
iphdr->ip_hl = 5;
iphdr->ip_tos = 0;
iphdr->ip_len = 20;
iphdr->ip_id = 0;
iphdr->ip_off = 0;
iphdr->ip_ttl = 64;
iphdr->ip_p = 51;
iphdr->ip_src = ip_addr;
iphdr->ip_dst = ip_addr;
iphdr->ip_sum = 0;
printf("ip header(before):\nversion: %x\nhl: %x\ntos: %x\nlen: %x\nid:
%x\noff: %x\nttl: %x\nprotocol: %x\nsrc: %x\ndst: %x\nchecksum: %u",
iphdr->ip_v, iphdr->ip_hl, iphdr->ip_tos, iphdr->ip_len, iphdr->ip_id,
iphdr->ip_off,iphdr->ip_ttl, iphdr->ip_p, iphdr->ip_src, iphdr->ip_dst,
iphdr->ip_sum);
iphdr->ip_sum = in_cksum((u_short *) iphdr, (iphdr->ip_hl) << 2);
printf("\nip header(after):\nversion: %x\nhl: %x\ntos: %x\nlen: %x\nid:
%x\noff: %x\nttl: %x\nprotocol: %x\nsrc: %x\ndst: %x\nchecksum: %u",
iphdr->ip_v, iphdr->ip_hl, iphdr->ip_tos, iphdr->ip_len, iphdr->ip_id,
iphdr->ip_off,iphdr->ip_ttl, iphdr->ip_p, iphdr->ip_src, iphdr->ip_dst,
iphdr->ip_sum);
return iphdr;
| |
| Fernando Barsoba 2005-10-24, 3:48 pm |
| Giorgos Keramidas wrote:
> Fernando Barsoba <fbarsoba@verizon.net> writes:
>
>
>
> It would probably be a good idea to call calloc() here, or bzero() the
> allocated area after you allocate it. This way, the entire data area
> starts in a well-known, reproducible state.
>
>
>
>
> Err, yeah, you're right of course. I shouldn't really be posting when
> I'm just out of bed and still sleepy 
>
>
>
>
> Hmmm, it would be nice if you could send 'dumps' of the IP header
> before, and after the in_cksum() call.
>
>
>
>
> What is a "FLAG"?
>
>
>
>
> I'm not sure I understand what "FLAG" refers to.
>
dump in hex. The initial address for the structure iphdr is:
0x00461f58 : 0x461F58 <Hex>
Address 0 1 2 3 4 5 6 7 8 9 A B C D E
F
00461E10 22 02 00 00 A0 01 11 61 A2 1C 46 00 A8 1C 46
00
00461E20 21 02 00 00 A0 01 11 61 BA 1C 46 00 C9 1C 46
00
00461E30 EE 03 00 00 A0 01 11 61 FD 1C 46 00 0F 1D 46
00
00461E40 E9 03 00 00 A0 01 11 61 43 1D 46 00 4C 1D 46
00
00461E50 F2 03 00 00 A0 01 11 61 80 1D 46 00 8E 1D 46
00
00461E60 F0 03 00 00 A0 01 11 61 A4 01 11 61 AD 01 11
61
00461E70 FF FF FF FF A0 01 11 61 00 00 00 00 00 00 00
00
00461E80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461E90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461EA0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461EB0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461EC0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461ED0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461EE0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461EF0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461F00 00 00 00 00 00 00 00 00 00 00 00 00 49 00 00
00
00461F10 2F 68 6F 6D 65 2F 46 65 72 6E 61 6E 64 6F 20
42
00461F20 61 72 73 6F 62 61 2F 77 6F 72 6B 70 6C 61 63
65
00461F30 2F 43 53 43 35 37 33 2F 49 50 53 65 63 2F 44
65
00461F40 62 75 67 2F 49 50 53 65 63 00 65 78 65 00 00
00
00461F50 00 00 00 00 19 00 00 00 *45* 00 14 00 00 00
00 00
00461F60 40 33 00 00 C0 A8 02 02 C0 A8 02 02 99 10 00
00
00461F70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461F80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461F90 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461FA0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461FB0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461FC0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461FD0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461FE0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00461FF0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00462000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00462010 00 00 00 00 F1 0F 00 00 00 00 00 00 00 00 00
00
00462020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00462030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00462040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00462050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00462060 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00462070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00462080 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
00462090 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
004620A0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
004620B0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
004620C0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
004620D0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
004620E0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
004620F0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00
| |
| Giorgos Keramidas 2005-10-24, 3:48 pm |
| Fernando Barsoba <fbarsoba@verizon.net> writes:
>Giorgos Keramidas wrote:
>
> The IP header has a 3-bit flag field which is used to calculate the
> checksum. I'd want to put them to
> 0. http://www.networksorcery.com/enp/protocol/ip.htm
Sorry but no, the "Flags" bits are not used "to calculate the checksum".
They are related to IP packet fragments.
> ip header(before):
> version: 4
> hl: 5
> tos: 0
> len: 14
> id: 0
> off: 0
> ttl: 40
> protocol: 33
> src: 202a8c0
> dst: 202a8c0
> checksum: 0
> ip header(after):
> version: 4
> hl: 5
> tos: 0
> len: 14
> id: 0
> off: 0
> ttl: 40
> protocol: 33
> src: 202a8c0
> dst: 202a8c0
> checksum: 30433
This is not a "dump", i.e. a byte for byte display of the IP header's
contents before and after your function call.
> *******new function:
And this is not a function. It's just a snippet of some function whose
arguments type or other details we don't know.
> packet_size = sizeof(struct ip);
> packet = malloc(packet_size);
> bzero(packet, packet_size);
> iphdr = (struct ip *)packet;
> inet_aton(host, &ip_addr);
>
> iphdr->ip_v = 4;
> iphdr->ip_hl = 5;
> iphdr->ip_tos = 0;
> iphdr->ip_len = 20;
> iphdr->ip_id = 0;
> iphdr->ip_off = 0;
> iphdr->ip_ttl = 64;
> iphdr->ip_p = 51;
> iphdr->ip_src = ip_addr;
> iphdr->ip_dst = ip_addr;
> iphdr->ip_sum = 0;
>
> printf("ip header(before):\nversion: %x\nhl: %x\ntos: %x\nlen:
> %x\nid: %x\noff: %x\nttl: %x\nprotocol: %x\nsrc: %x\ndst: %x\nchecksum:
> %u", iphdr->ip_v, iphdr->ip_hl, iphdr->ip_tos, iphdr->ip_len,
> iphdr->ip_id, iphdr->ip_off,iphdr->ip_ttl, iphdr->ip_p, iphdr->ip_src,
> iphdr->ip_dst, iphdr->ip_sum);
>
> iphdr->ip_sum = in_cksum((u_short *) iphdr, (iphdr->ip_hl) << 2);
>
> printf("\nip header(after):\nversion: %x\nhl: %x\ntos: %x\nlen:
> %x\nid: %x\noff: %x\nttl: %x\nprotocol: %x\nsrc: %x\ndst: %x\nchecksum:
> %u", iphdr->ip_v, iphdr->ip_hl, iphdr->ip_tos, iphdr->ip_len,
> iphdr->ip_id, iphdr->ip_off,iphdr->ip_ttl, iphdr->ip_p, iphdr->ip_src,
> iphdr->ip_dst, iphdr->ip_sum);
>
> return iphdr;
| |
| Fernando Barsoba 2005-10-24, 3:48 pm |
| Giorgos Keramidas wrote:
> Fernando Barsoba <fbarsoba@verizon.net> writes:
>
>
>
> Sorry but no, the "Flags" bits are not used "to calculate the checksum".
> They are related to IP packet fragments.
>
>
Sorry, I thought the checksum was calculated over the whole IP header
(20 bytes + options).
>
>
> This is not a "dump", i.e. a byte for byte display of the IP header's
> contents before and after your function call.
>
>
You are right.. in my following post i put the values that I could
obtain (using Eclipse+cdt) using something called in Eclipse memory
monitor. However, I would like to know how to do the dump you are
referring to.. with printf?
>
>
> And this is not a function. It's just a snippet of some function whose
> arguments type or other details we don't know.
>
Right again. I just wanted to show that I did all the modifications
needed (bzero and the ip_sum = 0. The function is the same as my first
post. I used a bad name though.. sorry.[vbcol=seagreen]
>
|
|
|
|
|