Reputation: 69
How do I calculate the checksum for a sample IPv4 packet received like this:
4500 062A 42A1 8001 4210 XXXX C0A8 0001 C0A8 0003
where xxxx
is the checksum that needs to be sent with the packet.
so far this is what I have found: convert to binary, add, and then the ones complement of the sum, once converted back should be the checksum? But I am not able to get that far:
4500 062A 42A1 8001 4210 XXXX C0A8 0001 C0A8 0003
4500 - 0100 0101 0000 0000
062A - 0000 0110 0010 1010
42A1 - 0100 0010 1010 0001
8001 - 1000 0000 0000 0001
xxxx - 0000
C0A8 - 1100 0000 1010 1000
0003 - 0000 0000 0000 0011
adding all of them:
4500 - 0100 0101 0000 0000 062A - 0000 0110 0010 1010
19242 - 0100101100101010 //first result 42A1 - 0100 0010 1010 0001
36299 - 01000110111001011 //second result 8001 - 1000 0000 0000 0001
69068 - 010000110111001100 //third result C0A8 - 1100 0000 1010 1000
118388 - 011100111001110100 0003 - 0000 0000 0000 0011
118391 - 011100111001110111 taking one’s complement of 118391- 100011000110001000
—> 23188 - 100011000110001000
so is 23188 the checksum ??
Upvotes: 0
Views: 10868
Reputation: 988
I have used next algorithm in C in macOS for IP packet checksum calculation
uint16_t swap_uint16(uint16_t val)
{
return (val << 8) | (val >> 8 );
}
unsigned short in_cksum(const void* ip)
{
const unsigned short* ptr = (const unsigned short *)ip;
unsigned int sum = 0;
for (int i = 0; i < 10; i++)
{
if (i != 5) // skip IP packet checksum value.
{
unsigned short value = *ptr;
sum += swap_uint16(value);
}
ptr++;
if (sum > UINT16_MAX)
{
sum -= UINT16_MAX;
}
}
sum = ~sum;
sum = swap_uint16(sum);
return sum;
}
Upvotes: 1
Reputation: 51
There are four RFCs to read regarding the IPv4 checksum calculation:
RFC 791, RFC 1071, RFC 1141, and RFC 1624.
I did not read them and until I bump into a really weird problem, I do not intend to do so. But there is also another great page talking about IPv4's checksum field: Wikipedia's IPv4 Header Checksum. Following the example on Wikipedia, here goes my attempt to calculate the checksum:
Step 1. Calculate the one's complement sum of all the IPv4 header's fields:
We can add all these numbers either in hex, or in binary. I will do both methods:
Step 1a.1: I will add the first two fields (4500 + 062A). I will then add the third field to the result of the previous addition (4B2A+42A1). From there on, I will be adding the next field's value to the accumulated sum.
1 1111 1 1
4500 4B2A 8DCB 10DCC 14FDC 21084 21085 2D12D
062A 42A1 8001 4210 C0A8 0001 C0A8 0003
----- ----- ---- ----- ----- ----- ----- -----
4B2A 8DCB 10DCC 14FDC 21084 21085 2D12D 2D130
Step 1b.1
In octave:
-------------------
octave:14> hex2dec("4500")+hex2dec("062a")+hex2dec("42a1")+hex2dec("8001")+hex2dec("4210")+hex2dec("c0a8")+hex2dec("0001")+hex2dec("c0a8")+hex2dec("0003")
ans = 184624
octave:15>
octave:15> dec2hex(184624)
ans = 2D130
octave:16>
Step 1a.2: The addition of step 1a.1 is a simple mathematical addition of a bunch of numbers. In the one's complement addition, on the other hand, we need to do one more thing. Since the result must fit within 16 bits (meaning that the result should be 4 hex digits), then this means we must do with the most significant digit of the result. The "2" in 0x2D130 must go somewhere, because the one's complement addition must have the same length as all the numbers we added. In one's complement addition, we add the overflowing number back into the number. So, 0xD130+ 0x2 = 0xD132
The one's complement addition of the header fields then is: 0xD132
.
Step 1b.2:
In octave:
-------------------
octave:14> hex2dec("4500")+hex2dec("062a")+hex2dec("42a1")+hex2dec("8001")+hex2dec("4210")+hex2dec("c0a8")+hex2dec("0001")+hex2dec("c0a8")+hex2dec("0003")
ans = 184624
octave:15> dec2hex(184624)
ans = 2D130
octave:16> 16^4
ans = 65536
octave:17> 184624-(2*65536)
ans = 53552
octave:18> 184624-(2*65536)+2
ans = 53554
octave:19> dec2hex(184624-(2*65536)+2)
ans = D132
octave:20>
Step 1c.1:
Convert the fields into binary:
4500: 0100 0101 0000 0000
062A: 0000 0110 0010 1010
42A1: 0100 0010 1010 0001
8001: 1000 0000 0000 0001
4210: 0100 0010 0001 0000
C0A8: 1100 0000 1010 1000
0001: 0000 0000 0000 0001
C0A8: 1100 0000 1010 1000
0003: 0000 0000 0000 0011
4500+062A:
00 0100 0101 0000 0000+
00 0000 0110 0010 1010
-----------------------
00 0100 1011 0010 1010 (04B2A)
+42A1
00 0100 1011 0010 1010+
00 0100 0010 1010 0001
-----------------------
00 1000 1101 1100 1011 (08DCB)
+8001
00 1000 1101 1100 1011+
00 1000 0000 0000 0001
------------------------
01 0000 1101 1100 1100 (10DCC)
+4210
01 0000 1101 1100 1100+
00 0100 0010 0001 0000
------------------------
01 0100 1111 1101 1100 (14FDC)
+C0A8
01 0100 1111 1101 1100+
00 1100 0000 1010 1000
-----------------------
10 0001 0000 1000 0100 (21084)
+0001
10 0001 0000 1000 0100+
00 0000 0000 0000 0001
-----------------------
10 0001 0000 1000 0101 (21085)
+C0A8
10 0001 0000 1000 0101+
00 1100 0000 1010 1000
-----------------------
10 1101 0001 0010 1101 (2D12D)
+0003
10 1101 0001 0010 1101+
00 0000 0000 0000 0011
-----------------------
10 1101 0001 0011 0000 (2D130)
Step 1c.2: Add 10 (the left most bits) to the number:
1101 0001 0011 0000+
0000 0000 0000 0010
--------------------
1101 0001 0011 0010 (D132)
Step 2.
Regardless of how you did the one's complement addition, you must now take the one's complement of the result. The one's complement of any binary number is just a fancy name for "flip all the bits in the number":
1101 0001 0011 0010 -> 0010 1110 1100 1101 (2ECD)
If you want to take the one's complement of a hex digit without converting to binary, below is a handy table:
n | 1' |
---|---|
0 | F |
1 | E |
2 | D |
3 | C |
4 | B |
5 | A |
6 | 9 |
7 | 8 |
8 | 7 |
9 | 6 |
A | 5 |
B | 4 |
C | 3 |
D | 2 |
E | 1 |
F | 0 |
So taking the one's complement of D132 is:
D->2
1->E
3->C
2->D
So the checksum of the IPv4 header 4500 062A 42A1 8001 4210 XXXX C0A8 0001 C0A8 0003
is 0x2ECD
.
A small go program that will demonstrate the steps:
https://go.dev/play/p/DOj28mjuqtP
Upvotes: 4
Reputation: 6482
The IPv4 Header Checksum is described in RFC 791, INTERNET PROTOCOL:
Header Checksum: 16 bits
A checksum on the header only. Since some header fields change (e.g., time to live), this is recomputed and verified at each point that the internet header is processed.
The checksum algorithm is:
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.
This is a simple to compute checksum and experimental evidence indicates it is adequate, but it is provisional and may be replaced by a CRC procedure, depending on further experience.
The algorithm for this is detailed in RFC 1071, Computing the Internet Checksum, updated by RFC 1141, Incremental Updating of the Internet Checksum, updated by RFC 1624, Computation of the Internet Checksum via Incremental Update.
Upvotes: 2