Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to calculate TCP checksum

I am writing a Kernel Module that uses Netfilter hooks to modify some of the TCP header information and obviously, before sending, I want to re-calculate the checksum.
I also edit the header at the receiving side, so I need to re-calculate it there too.

Searching online, I found some people saying I can simply set it to 0 and it'll be calculated for me, apparently that didn't work.
I've also found this function

tcp_v4_send_check(struct sock *sk, struct sk_buff *skb);

Though no one explained how this is used, and whether I can actually use it at the receiving/sending the same way.
My own attempt was to set checksum to 0 then call this function passing the skb I have and the skb->sk I have, still nothing.

So please, what is a straightforward way to calculate the checksum of TCP datagrams?

like image 997
Fingolfin Avatar asked Jul 10 '12 05:07

Fingolfin


1 Answers

To re-calculate the checksum, you better calculate an incremental checksum - just modify the existing checksum based on the fields you've changed, rather than reading the entire packet.

This must be done while you're changing the packet, when you know both the old values and the new values you store.

The basic idea is tcp->check += (new_val - old_val).
It's a bit more complicated than this, becuase:
1. old_val and new_val need to be 16-bit values, which are aligned on 2 bytes (e.g. changing a port number).
2. The checksum uses ones complement arithmetic, so you need to do "carry feedback". This basically means, that if tcp->check + new_val - old_val is negative, you need to subtract 1 from the result.

like image 121
ugoren Avatar answered Sep 28 '22 06:09

ugoren