如何计算TCP校验和

我正在写一个内核模块,它使用Netfilter钩子来修改一些TCP头信息,显然,在发送之前,我想重新计算校验和。
我也在接收端编辑标题,所以我也需要重新计算。

在网上search,我发现有些人说我可以简单地把它设置为0,它会为我计算,显然这是行不通的。
我也find了这个function

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

虽然没有人解释这是如何使用的,以及我是否可以在接收/发送方式中实际使用它。
我自己的尝试是将校验和设置为0,然后调用这个函数传递我有的skb和我有的skb-> sk,仍然没有。

那么请问,什么是直接计算TCP数据报校验和的方法?

Solutions Collecting From Web of "如何计算TCP校验和"

要重新计算校验和,最好计算一个增量校验和 – 只要根据已更改的字段修改现有校验和,而不是读取整个数据包。

当您更改数据包时,必须执行此操作,当您知道存储的旧值和新值时。

基本思想是tcp->check += (new_val - old_val)
因为比这更复杂一点,因为:
1. old_valnew_val需要是16位值,它们在2个字节上对齐(例如,改变端口号)。
2.校验和使用补码算术,所以你需要做“带反馈”。 这基本上意味着,如果tcp->check + new_val - old_val是负数,则需要从结果中减去1。

下面是一个结合TCP(非IP)的netfilter API +校验和的例子:

http://www.linuxvirtualserver.org/software/tcpsp/index.html

看看名为tcpsp_core.c的文件。

  th->check = 0; th->check = csum_tcpudp_magic(iph->saddr, iph->daddr, datalen, iph->protocol, csum_partial((char *)th, datalen, 0)); skb->ip_summed = CHECKSUM_UNNECESSARY; 

(注意先分配零,计算校验和,然后IP校验和表示为不需要)。

取决于你加载哪个netfilter模块(有很多!!!),它们将在不同的层次上工作,例如,在IP层的iptable工作如下所示(图片):

http://ars.sciencedirect.com/content/image/1-s2.0-S1389128608004040-gr3.jpg

@ ugoren的答案并不准确。 根据RFC1624 https://tools.ietf.org/html/rfc1624 ,这有时会产生-0(0xFFFF),这是不允许的。

计算校验和的正确方法应该是: new_tcp_check = ~(~old_tcp_check + ~old_val + new_val)