TCP Checksum calculation doesn't match with the the wireshark calculation

只谈情不闲聊 提交于 2019-12-04 17:41:22

Manual Checksum Calculation

The checksum calculation for TCP/UDP/IP is rather trivial. What is called "16 bit one's complement" arithmetic is just a notion that during addition of two 16-bit numbers whatever was carried over 16 bit is added back from bit 0. E.g.

0x8000 + 0x8000 = 0x10000 => 0x1 + 0x0000 = 0x0001.

One of the properties of this arithmetic is that negative value is produced by simple binary inversion. And 0 in this arithmetic has 2 binary values: 0x0000 and 0xffff

-0x0001 = ~0x0001 = 0xfffe;
0xfffe + 0x8000 + 0x8000 = 0x1fffe => 0x1 + 0xfffe = 0xffff = 0x0000

Another nice thing about 16 bit one's complement is that you don't have to worry about endianness while doing 16-bit additions, you have to properly convert only the final result. This happens because carry bit always travels from one byte to another and is never lost. Here's the same example as if data was read in little endian machine:

0x0080 + 0x0080 = 0x0100 => htons(0x0100) = 0x0001

That's why all algorithms of checksum calculation doesn't bother converting each and every 16-bit value from network to host byte order.

Considering all these, you simply break your data block into 16-bit works, add them all together the regular way, and then add higher 16 bits to the lower 16 bits and invert the result before writing it back to the packet.

In your example, TCP header checksum would be calculated as:

0x0422 + 0x0050 + 0x0001 + 0xe0dd + 0x0001 + 0x4274 + 0x5014 + 0x2238 +
0x0000 + 0x0000 = 0x19a11 = 0x1 + 0x9a11 = 0x9a12
^^^^^^ // <- this is the place for the TCP checksum

As described in TCP checksum calculation you need to add a pseudo header to your TCP packet so that source and destination IP addresses and ports also took part in checksum calculation. This pseudo header is different for IPv4 and IPv6. In your example for IPv6 its going to be:

0x1080 + 0xa2b1 + 0x0000 + 0x0000 + // source IPv6 address
0x0000 + 0x0000 + 0x001e + 0x0000 +
0xff00 + 0x0000 + 0x0000 + 0x0000 + // destination IPv6 address
0x0000 + 0x0000 + 0x0000 + 0x0024 +
0x0016 +                            // IP payload (TCP packet) lenght
0x0006                              // Next Header value for TCP
= 0x1b28f = 0x1 + 0xb28f = 0xb290

Now TCP and IP-pseudo-header checksums combined would be:

0x9a12 + 0xb290 = 0x14ca2 = 0x1 + 0x4ca2 = 0x4ca3

Negating checksum before writing it back to the header:

~0x4ca3 = 0xb35c

Note: this checksum still differ from what you claim Wireshark calculates mostly because the packet you provided as example has 20 bytes of TCP payload data according to IP header, and TCP payload is also used in checksum calculation. In my example I used just TCP header without any other payload.

Problems in Your Code

There's a number of problems spotted in the code provided.

tcp_checksum()

  1. This function calculates IPv4 checksum. To modify it for IPv6 you need to extend IP addresses sizes used in calculation from 4 bytes to 16.

  2. The code around ip_src and ip_dst initialization is wrong and should be:


    uint16_t *ip_src=(uint16_t *)&src_addr->in_addr;
    uint16_t *ip_dst=(uint16_t *)&dest_addr->in_addr;

get_ipv6_udptcp_checksum()

l4_len is not converted from network byte order. It should be:

l4_len = ntohs(ipv6_hdr->ip6_plen);

main()

Calculated checksum is not converted into network byte order, as it should be:

tcphdr.th_sum = htons(get_ipv6_udptcp_checksum(&iphdr, (uint16_t *)&tcphdr));

Checksum calculation for UDP frame with Pseudo header and : SOLVED! (Including C-Code, example output and Wireshark dataframe for verification)

Hello, i have been looking into the same problem: Please find a C program that generates the correct UDP CHECK based on the pseudo header and the frame content. Included is the program output and the wireshark result for the same frame in real life.

unsigned long sum=0, sum2=0, term=0;
CString s;

#define DATABYTES 3

// pseudo header bytes:
unsigned char ip1[]={192,168,11,25};   // ip 1
unsigned char ip2[]={192,168,11,20};  // ip 2
unsigned char pr []= {0,17};         // udp protocol 
unsigned char len[]= {0,8+DATABYTES};         // UDP entire message length entire 

// acutal message bytes:
unsigned char port1[] ={0x22,0xb8};   // port 1
unsigned char port2[] ={0x22,0xb8};   // port 1
unsigned char msglen[]={0,8+DATABYTES};         // UDP entire message length entire 
unsigned char check[] = {0,0};        // check set to 0 
unsigned char msg[DATABYTES]= {0x11,0x22,0x33};         // 10 bytes message length

// add artificial pseudo header bytes to sum
term = ((unsigned short) ip1[0] << 8) + ip1 [1];
sum+=term;
s.Format("Add ip1 = 0x%04x Sum = 0x%04x\n",term,sum);  AfxTrace(s);
term = ((unsigned short) ip1[2] << 8) + ip1 [3];
sum+=term;
s.Format("Add ip1 = 0x%04x Sum = 0x%04x\n",term,sum);  AfxTrace(s);

term = ((unsigned short) ip2[0] << 8) + ip2 [1];
sum+=term;
s.Format("Add ip2 = 0x%04x Sum = 0x%04x\n",term,sum);  AfxTrace(s);
term = ((unsigned short) ip2[2] << 8) + ip2 [3];
sum+=term;
s.Format("Add ip2 = 0x%04x Sum = 0x%04x\n",term,sum);  AfxTrace(s);

term = ((unsigned short) pr[0] << 8) + pr [1];
sum+=term;
s.Format("Add pr = 0x%04x Sum = 0x%04x\n",term,sum);  AfxTrace(s);
term = ((unsigned short) len[0] << 8) + len [1];
sum+=term;
s.Format("Add len = 0x%04x Sum = 0x%04x\n",term,sum);  AfxTrace(s);


// ----------------------------------------------------------------
// add real udp header bytes to sum (ports ....)
term = ((unsigned short) port1[0] << 8) + port1[1];
sum+=term;
s.Format("Add port1 = 0x%04x Sum = 0x%04x\n",term,sum);  AfxTrace(s);
term = ((unsigned short) port2[0] << 8) + port2[1];
sum+=term;
s.Format("Add port2 = 0x%04x Sum = 0x%04x\n",term,sum);  AfxTrace(s);
term = ((unsigned short) msglen[0] << 8) + msglen [1];
sum+=term;
s.Format("Add msglen = 0x%04x Sum = 0x%04x\n",term,sum);  AfxTrace(s);

// ----------------------------------------------------------------
// add data bytes info:
for (int i=0;i<DATABYTES/2;i++)
{
    // add message data bytes to sum sum (ports ....)
    term = ((unsigned short) msg[i*2] << 8) + msg [1+i*2];
    sum+=term;
    s.Format("Add msg = 0x%04x sum = 0x%04x\n",term,sum);  AfxTrace(s);
}

if (DATABYTES % 2 != 0)
{
    term = ((unsigned short) msg[DATABYTES-1] << 8);
    sum+=term;
    s.Format("Add msg = 0x%04x sum = 0x%04x\n",term,sum);  AfxTrace(s);
}

sum= (sum >> 16) + (sum & 0xFFFF);
s.Format("Clean sum = 0x%04x \n",sum);  AfxTrace(s);

sum= (sum >> 16) + (sum & 0xFFFF);
s.Format("Clean sum = 0x%04x \n",sum);  AfxTrace(s);

sum= (~sum & 0xFFFF);
s.Format("not sum = 0x%04x \n",sum);  AfxTrace(s);

Output of the program:

Add ip1 = 0xc0a8 Sum = 0xc0a8
Add ip1 = 0x0b19 Sum = 0xcbc1
Add ip2 = 0xc0a8 Sum = 0x18c69
Add ip2 = 0x0b14 Sum = 0x1977d
Add pr = 0x0011 Sum = 0x1978e
Add len = 0x000b Sum = 0x19799
Add port1 = 0x22b8 Sum = 0x1ba51
Add port2 = 0x22b8 Sum = 0x1dd09
Add msglen = 0x000b Sum = 0x1dd14
Add msg = 0x1122 sum = 0x1ee36
Add msg = 0x3300 sum = 0x22136
Add msg = 0x0000 sum = 0x22136
Add msg = 0x0000 sum = 0x22136
Clean sum = 0x2138 
Clean sum = 0x2138 
not sum = 0xdec7  

And the wireshark frame:

Ethernet II, Src: Intel_af:ef:6f (00:03:47:af:ef:6f), Dst: aa:aa:bb:bb:cc:cd (aa:aa:bb:bb:cc:cd)
    Destination: aa:aa:bb:bb:cc:cd (aa:aa:bb:bb:cc:cd)
        Address: aa:aa:bb:bb:cc:cd (aa:aa:bb:bb:cc:cd)
        .... ..1. .... .... .... .... = LG bit: Locally administered address (this is NOT the factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
    Source: Intel_af:ef:6f (00:03:47:af:ef:6f)
        Address: Intel_af:ef:6f (00:03:47:af:ef:6f)
        .... ..0. .... .... .... .... = LG bit: Globally unique address (factory default)
        .... ...0 .... .... .... .... = IG bit: Individual address (unicast)
    Type: IP (0x0800)
Internet Protocol Version 4, Src: 192.168.11.25 (192.168.11.25), Dst: 192.168.11.20 (192.168.11.20)
    Version: 4
    Header length: 20 bytes
    Differentiated Services Field: 0x00 (DSCP 0x00: Default; ECN: 0x00: Not-ECT (Not ECN-Capable Transport))
        0000 00.. = Differentiated Services Codepoint: Default (0x00)
        .... ..00 = Explicit Congestion Notification: Not-ECT (Not ECN-Capable Transport) (0x00)
    Total Length: 31
    Identification: 0xebe3 (60387)
    Flags: 0x00
        0... .... = Reserved bit: Not set
        .0.. .... = Don't fragment: Not set
        ..0. .... = More fragments: Not set
    Fragment offset: 0
    Time to live: 128
    Protocol: UDP (17)
    Header checksum: 0xb76c [correct]
        [Good: True]
        [Bad: False]
    Source: 192.168.11.25 (192.168.11.25)
    Destination: 192.168.11.20 (192.168.11.20)
    [Source GeoIP: Unknown]
    [Destination GeoIP: Unknown]
User Datagram Protocol, Src Port: ddi-udp-1 (8888), Dst Port: ddi-udp-1 (8888)
    Source port: ddi-udp-1 (8888)
    Destination port: ddi-udp-1 (8888)
    Length: 11
    Checksum: 0xdec7 [correct]
        [Good Checksum: True]
        [Bad Checksum: False]
Data (3 bytes)
    Data: 112233
    [Length: 3]

0000  aa aa bb bb cc cd 00 03 47 af ef 6f 08 00 45 00   ........G..o..E.
0010  00 1f eb e3 00 00 80 11 b7 6c c0 a8 0b 19 c0 a8   .........l......
0020  0b 14 22 b8 22 b8 00 0b de c7 11 22 33            .."."......"3

One thing is missing: if output is 0000, you need to invert it to FFFF to signal for a calculated check instead of a check not present. Good Luck, JOHI.

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!