Chinaunix
标题: 向tcp报文新增数据后,如何避免接收方校验和出错 [打印本页]
作者: cjCares 时间: 2018-02-14 14:18
标题: 向tcp报文新增数据后,如何避免接收方校验和出错
目标:修改发送方内核,在报文的tcp头和ip头之间添加一段数据;修改接收方内核,解析数据内容,接收报文。
实现过程:在发送方的内核构造完tcp头(在net/ipv4/tcp_output.c文件中的tcp_transmit函数的最后),写入一段字符串;在接收方的内核接收完ip头(在net/ipv4/ip_input.c文件中的ip_local_deliver_finish函数的最后),将skb中的字符串删除。
问题:接收方进行tcp头接收时计算校验和后会将该报文丢弃(在net/ipv4/tcp_ipv4.c文件中的tcp_v4_rcv函数中判断skb_checksum_init(skb, IPPROTO_TCP, inet_compute_pseudo)时出错)。
接收方解析的tcp头信息有误,我将tcp头的端口、check等值都恢复成发送时的数值,但是校验和还是有问题。
还有哪儿有问题会让校验和出错,希望可以提供点思路,谢谢!
作者: Godbach 时间: 2018-02-25 00:39
回复 1# cjCares
加的信息,要在进入接收端的 TCP 栈之前,decode 出来,并去掉
作者: Godbach 时间: 2018-02-25 00:40
回复 1# cjCares
你加载 IP 和 TCP 头之间的信息,是个什么格式,也是一个 TCP header 吗
作者: cjCares 时间: 2018-02-25 16:48
回复 2# Godbach
接收方把插入的数据和原本的tcp头一起当成一个tcp头,加入的数据被当成了tcp头的一部分,然后接收到的tcp头内的信息都乱了,这样去掉加入的数据,tcp校验和还是一直有问题。怎么才能让接收方的tcp头指针指到原来的tcp头呢?我现在尝试的是把tcp头的信息恢复成原来的数值,你觉得这样可以避免校验和出错吗?
作者: goingstudy 时间: 2018-02-26 19:46
看一下是不是checksum offload打开了,可能已经被计算过并且skb->csum已经被填充
作者: cjCares 时间: 2018-02-27 10:16
回复 5# goingstudy
关了还是没有用哎。。。
作者: Godbach 时间: 2018-02-27 18:01
回复 4# cjCares
加入的信息难道是放到原先 TCP 的 opt 里面了吗?
既然加了信息,那么原先 TCP 的校验还有 IP 头的校验和都做相应的调整没有
作者: cjCares 时间: 2018-03-04 21:32
回复 7# Godbach
加入的数据相当于一个新头部,不属于tcp头的一部分。都没有调整。原来发送方的tcp校验和不是在新增数据之前就计算完毕了嘛,我就没有修改。
然后接收方在处理前tcp头,先把新增数据去掉了。现在tcp头和ip头的各个字段都是对的,按理说接收方的tcp校验和应该是正确的吧,您觉得应该是哪里有问题啊?
作者: Godbach 时间: 2018-03-05 20:48
回复 8# cjCares
那你相当于在 IP 和 TCP 头之间加了一个头部,这个头算是什么头,用的什么协议呢。
有些网卡会对 checksum 提前做校验的。你加的这部分数据,有可能会干扰校验。
如果你的数据能收到协议栈,那么你去掉这个 头部的操作代码是什么,show 出来
作者: cjCares 时间: 2018-03-06 09:08
本帖最后由 cjCares 于 2018-03-06 09:18 编辑
回复 9# Godbach
这个是我要自定义的头部,我现在用一串字符“hello world”进行测试的。现在还没有利用其它协议,就是ip头pull掉之后,将字符也pull掉,再将剩余部分提交给tcp层。
作者: cjCares 时间: 2018-03-06 09:18
回复 9# Godbach
{
if(ip_hdr(skb)->protocol==6){
__skb_pull(skb,sizeof("hello world"));
}
{
resubmit:
作者: cjCares 时间: 2018-03-06 14:35
回复 9# Godbach
static int ip_local_deliver_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
__skb_pull(skb, skb_network_header_len(skb));
if(ip_hdr(skb)->protocol==6){
__skb_pull(skb,sizeof("hello world")));
}
rcu_read_lock();
{
int protocol = ip_hdr(skb)->protocol;
const struct net_protocol *ipprot;
int raw;
resubmit:
raw = raw_local_deliver(skb, protocol);
作者: Godbach 时间: 2018-03-06 20:15
回复 12# cjCares
我觉得这样不太稳妥。既然你加了数据,到这里为何不直接把这部分数据删掉呢。这样才是真正还原回来了。
作者: Godbach 时间: 2018-03-06 20:18
回复 12# cjCares
这个是个干扰数据。要清理掉。这个数据是有可能导致 TCP 或者 IP 层的其他处理环节误判的。
作者: cjCares 时间: 2018-03-06 21:08
回复 14# Godbach
skb_pull不应该就是把数据删除了吗?
作者: Godbach 时间: 2018-03-07 11:46
回复 15# cjCares
这个只是移动 data 指向的起始位置,不是真正的移除数据。整个 IP 报文中,你加的这一块数据仍然存在。
作者: cjCares 时间: 2018-03-07 15:11
回复 16# Godbach
好的,谢谢!还有一个疑问,我加了自定义部分的报文接受时skb->ip_summed为0,正常的报文值为1,这个值是在哪个函数里面赋值成1的啊?
作者: goingstudy 时间: 2018-03-08 18:59
回复 17# cjCares
1. 0 是CHECKSUM_NONE吧,表示或者checksum 是bad 或者 硬件不支持校验。但是有个问题,我看skb_checksum_init的代码,好像是NONE的时候,必定回返回0,也就是不会到csum_error那
你确定是从那里退出的吗?
2. 你11L贴的代码对吗?
我看在那个rcu lock 之前还有个reset_transport_header吧?如果没有的话肯定有问题吧
3. 还有我觉得没法把数据移走吧?除非重新分配skb的data 或者移动data,那样就不好了。
其实我觉得你这种应该是类似tunnel,不用移除数据应该是可以实现的,但是协议栈太复杂了,说不定那个地方没改好。
4. 你抓包试过吗?
作者: cjCares 时间: 2018-03-09 11:00
回复 18# goingstudy
1. 0 是CHECKSUM_NONE,我确定是从skb_checksum_init里退出的,你可能记错了吧。我看的源码是这样的:
if (skb->ip_summed == CHECKSUM_COMPLETE) {
if (!csum_fold(csum_add(psum, skb->csum))) {
skb->csum_valid = 1;
return 0;
}
} else if (skb->csum_bad) {
/* ip_summed == CHECKSUM_NONE in this case */
return (__force __sum16)1;
}
2.reset_transport_header我写了的,上面忘记加了,获取的tcp头信息都是对的
3.应该是哪里没改好,感觉还是ip_summed的问题吧,但是找不到它的值在哪变化的
4.我就用wireshark抓了包,但是那上面直接把插入的数据当成tcp头了,信息都不对。我现在都是在内核里用printk打印各个字段,有点麻烦,还可以怎么抓包分析啊?
谢谢指导!
作者: Godbach 时间: 2018-03-09 12:09
回复 17# cjCares
搜下内核代码,找下赋值的地方。太细节的,记不太不清楚。
作者: goingstudy 时间: 2018-03-09 13:31
回复 19# cjCares
指导谈不上,只是最近也在看这个, 也是菜鸟一个。。
1. 我看最新的代码csum_bad已经被删掉了,4.4里头还有。你是哪个版本?你的网卡是什么类型的?atlantic的?
2. 最新的代码是不用加reset_transport_header的,4.4应该要加,你说在tcp_v4_rcv里头printk header没问题的话,那就应该没问题。
3.ip_summed的值应该是在nic 接受包的时候吧,比如ixgb,在ixgb_rx_checksum里头,如果支持硬件校验,回设为uncessary,否则就是none,
在往上的代码没仔细看,如果有ip 分片,gro的话应该还回有变动,然后应该直接就到tcp层了。
你是关了offload是吧?
>> 2.reset_transport_header我写了的,上面忘记加了,获取的tcp头信息都是对的
>> 我就用wireshark抓了包,但是那上面直接把插入的数据当成tcp头了,信息都不对
tcp头的信息到底是对的还是不对的?我的意思是skb里头那些指针指的地方到底是正确的还是错误的?
作者: cjCares 时间: 2018-03-09 13:41
回复 20# Godbach
好的
作者: cjCares 时间: 2018-03-09 14:22
回复 21# goingstudy
感觉还是比我强多了。。。
1.我的是4.5版本的,网卡是e1000的。
2.reset_transport_header我在源码里加了,上面代码展示的时候漏掉了。tcp报头的信息printk出来都是正确的,应该没问题,wireshark应该是无法识别插入的数据。
3.offload就是tx-checksumming吧。关了跟开着我都试了,ip_summed的值都是0,没有变化,感觉很奇怪。
作者: goingstudy 时间: 2018-03-09 14:28
回复 23# cjCares
checksum这个我也搞不很懂,但是rx-checksumming 试过吗?如果rx-checksumming 开着的话,应该就会被直接设置成bad吧
[root@localhost ~]# ethtool -k eno1
Features for eno1:
rx-checksumming: on
tx-checksumming: on
tx-checksum-ipv4: on
tx-checksum-ip-generic: off [fixed]
tx-checksum-ipv6: on
tx-checksum-fcoe-crc: on [fixed]
tx-checksum-sctp: on
作者: cjCares 时间: 2018-03-09 14:45
回复 24# goingstudy
两个同关同闭,我都试过了,都是一样的,都在skb_checksum_init那边挂了。
倒是tcp_v4_do_rcv里的tcp_checksum_complete,默认情况下的不通过。开了rx-checksumming,或者关了tx-checksumming,然后就能通过了...
作者: goingstudy 时间: 2018-03-09 15:03
回复 25# cjCares
skb_checksum_init挂了是什么意思?是到了csum_error吗?
1603 if (skb_checksum_init(skb, IPPROTO_TCP, inet_compute_pseudo))
1604 goto csum_error;
这样的话是怎么到tcp_v4_do_rcv?
作者: cjCares 时间: 2018-03-09 15:23
回复 26# goingstudy
嗯,就是if通过了。我现在把goto csum_error注释了,用了一个打印输出来替代的。
作者: goingstudy 时间: 2018-03-11 17:22
你试试把gro disable 看行不行
$ ethtool -k ens32 | grep 'generic-receive-offload'
generic-receive-offload: on
作者: cjCares 时间: 2018-03-12 10:53
回复 28# goingstudy
可以了哎,谢谢!为什么关了gro就行了呢?
作者: goingstudy 时间: 2018-03-12 12:17
回复 29# cjCares
none 应该是表示csum 是坏的或者没有校验,按最新的代码, 在csum_init那里应该是没问题的,但是4.5里头,因为csum_bad 导致失败,而gro好像是唯一设置csum_bad的地方
没有仔细的看过gro的 代码,不知道这算不算是个bug
但是csum_bad 已经被删掉了
作者: cjCares 时间: 2018-03-12 12:58
回复 30# goingstudy
好的,非常感谢
作者: cjCares 时间: 2018-03-13 15:52
回复 30# goingstudy
再请教你一个问题啊~
三次握手中的第二次握手回复的报文不走协议栈吗?
我在tcp层的tcp_transmit函数,或者是ip层的ip_queue_xmit函数中,向报文插入字符串。这些代码都没执行,对方也能收到回复的报文,它们是怎么发送出去的啊?
作者: goingstudy 时间: 2018-03-14 21:07
回复 32# cjCares
是最后一个ACK吗,肯定走协议栈了吧,对TCP这个巨复杂的协议只看过一点,还忘的差不多了
作者: cjCares 时间: 2018-03-15 11:16
回复 33# goingstudy
不是,是syn+ack那个。tcp确实麻烦,这个任务做的我好心累
欢迎光临 Chinaunix (http://bbs.chinaunix.net/) |
Powered by Discuz! X3.2 |