0

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 ??

auspicious99
  • 3,902
  • 1
  • 44
  • 58
bengalurean
  • 69
  • 1
  • 3
  • 10
  • 1
    I can see you put some effort on this question. If you dare to ask a question on SO again, bengalurean, there are some ways to improve it. First, try to keep your question simple. State your problem clearly, say what you expected to get, and what you got instead. Sometimes you need to add detailed examples and code, but don't do that unless you have to. If you do, make use of the formatting to put it in code blocks so it's easier to read. I hope you were able to persevere through this problem. Read up on one's complement until you understand that thoroughly. – labyrinth Jun 09 '18 at 13:38
  • 1
    Also, use standard English in the title. You did pretty well except in your title. "calculate checksum ipv4 packet" could be improved to "Calculating the checksum of an IPv4 packet" or "How do I calculate the IPv4 checksum to verify a received packet?" – labyrinth Jun 09 '18 at 13:42
  • [This question](https://stackoverflow.com/questions/3987603/how-to-calculate-internet-checksum) contains answers that show how to calculate the IPv4 checksum. – Matthias Braun Feb 08 '23 at 09:56

3 Answers3

3

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

2

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.

Community
  • 1
  • 1
Ron Maupin
  • 6,180
  • 4
  • 29
  • 36
  • Yes, I saw this article in other posts, but unfortunately that did not help. – bengalurean Nov 08 '16 at 00:51
  • You couldn't understand the detailed algorithm in the RFCs, even with the code examples? – Ron Maupin Nov 08 '16 at 00:54
  • No, I did not. :( – bengalurean Nov 08 '16 at 00:57
  • 1
    I don't know what to tell you then. RFC 1071 gives you a simple C example of how to do it. You should be able to translate that to most any language. – Ron Maupin Nov 08 '16 at 00:58
  • Way to welcome the newb. rtfm is always a great answer, especially for someone who is admittedly new to networking and likely doesn't know a lick of C (or possibly any other language). It's especially helpful to answer this way on topics that require a solid intro course in EE/CE and some facility in reading RFCs/technical specifications. Be sure to rub it in when they falter, too. That reinforces learning. I can't imagine why poor bengalurean hasn't ventured another question in two years. – labyrinth Jun 09 '18 at 13:31
  • 1
    @labyrinth "_likely doesn't know a lick of C (or possibly any other language)_" I would assume a person would/should not ask a question on a programming site if the person does not know how to program (there are other SE sites for network theory). It really doesn't get much simpler than having a code example of how to do what you want handed to you. In fact, _nobody else, including you_, even tried to answer the question. Where is your answer? Will you write simpler code for him? – Ron Maupin Jun 09 '18 at 19:38
  • @Maupin I'm planning to give an explanation on where to start studying to have the background knowledge to continue with the various RFCs you referred to. I know 2 licks of C, 1.5 licks of PHP, 20 licks of Ruby, 7 licks of Python etc. I've been messing around w/ doing some OO modeling of IP packets but ran out of time when working on the checksum function. But yes, I agree that since this is a programming forum, the OP should have tied their question to something to do with programming. I'm certainly not upvoting it in the state it's in. I just want something more for newbs to go on. – labyrinth Jun 12 '18 at 20:26
0

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;
}