简体   繁体   English

如何计算TCP校验和

[英]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. 我正在编写一个使用Netfilter挂钩修改一些TCP头信息的内核模块,显然,在发送之前,我想重新计算校验和。
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. 在网上搜索,我发现有些人说我可以简单地将它设置为0并且它将为我计算,显然这不起作用。
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. 我自己的尝试是将校验和设置为0然后调用此函数传递我拥有的skb和我拥有的skb-> sk,仍然没有。

So please, what is a straightforward way to calculate the checksum of TCP datagrams? 那么请问,计算TCP数据报校验和的简单方法是什么?

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) . 基本思路是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 (eg changing a port number). 1. old_valnew_val需要是16位值,它们在2个字节上对齐(例如,更改端口号)。
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. 这基本上意味着,如果tcp->check + new_val - old_val为负数,则需要从结果中减去1。

Here is an example which combine netfilter API + checksum for TCP (not IP): 这是一个结合TCP(而不是IP)的netfilter API +校验和的示例:

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

Look into the file called tcpsp_core.c. 查看名为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;

(notice it is assigned zero first, checksum calculated, then IP checksum indicated as not needed). (注意首先将其分配为零,计算校验和,然后将IP校验和指示为不需要)。

Depends on which netfilter module u load (there are many!!!) they will work at different layer, eg, iptable working at IP layer is shown below (image): 取决于你加载哪个netfilter模块(有很多!!!)它们将在不同的层工作,例如iptable在IP层工作如下所示(图像):

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

@ugoren's answer is not precise. @ ugoren的回答并不准确。 According to RFC1624 https://tools.ietf.org/html/rfc1624 , this will sometimes produce -0 (0xFFFF), which is not allowed. 根据RFC1624 https://tools.ietf.org/html/rfc1624 ,这有时会产生-0(0xFFFF),这是不允许的。

The correct way to compute checksum should be: new_tcp_check = ~(~old_tcp_check + ~old_val + new_val) 计算校验和的正确方法应该是: new_tcp_check = ~(~old_tcp_check + ~old_val + new_val)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM