Chinaunix
標(biāo)題: 向tcp報(bào)文新增數(shù)據(jù)后,如何避免接收方校驗(yàn)和出錯(cuò) [打印本頁]
作者: cjCares 時(shí)間: 2018-02-14 14:18
標(biāo)題: 向tcp報(bào)文新增數(shù)據(jù)后,如何避免接收方校驗(yàn)和出錯(cuò)
目標(biāo):修改發(fā)送方內(nèi)核,在報(bào)文的tcp頭和ip頭之間添加一段數(shù)據(jù);修改接收方內(nèi)核,解析數(shù)據(jù)內(nèi)容,接收報(bào)文。
實(shí)現(xiàn)過程:在發(fā)送方的內(nèi)核構(gòu)造完tcp頭(在net/ipv4/tcp_output.c文件中的tcp_transmit函數(shù)的最后),寫入一段字符串;在接收方的內(nèi)核接收完ip頭(在net/ipv4/ip_input.c文件中的ip_local_deliver_finish函數(shù)的最后),將skb中的字符串刪除。
問題:接收方進(jìn)行tcp頭接收時(shí)計(jì)算校驗(yàn)和后會(huì)將該報(bào)文丟棄(在net/ipv4/tcp_ipv4.c文件中的tcp_v4_rcv函數(shù)中判斷skb_checksum_init(skb, IPPROTO_TCP, inet_compute_pseudo)時(shí)出錯(cuò))。
接收方解析的tcp頭信息有誤,我將tcp頭的端口、check等值都恢復(fù)成發(fā)送時(shí)的數(shù)值,但是校驗(yàn)和還是有問題。
還有哪兒有問題會(huì)讓校驗(yàn)和出錯(cuò),希望可以提供點(diǎn)思路,謝謝!
作者: Godbach 時(shí)間: 2018-02-25 00:39
回復(fù) 1# cjCares
加的信息,要在進(jìn)入接收端的 TCP 棧之前,decode 出來,并去掉
作者: Godbach 時(shí)間: 2018-02-25 00:40
回復(fù) 1# cjCares
你加載 IP 和 TCP 頭之間的信息,是個(gè)什么格式,也是一個(gè) TCP header 嗎
作者: cjCares 時(shí)間: 2018-02-25 16:48
回復(fù) 2# Godbach
接收方把插入的數(shù)據(jù)和原本的tcp頭一起當(dāng)成一個(gè)tcp頭,加入的數(shù)據(jù)被當(dāng)成了tcp頭的一部分,然后接收到的tcp頭內(nèi)的信息都亂了,這樣去掉加入的數(shù)據(jù),tcp校驗(yàn)和還是一直有問題。怎么才能讓接收方的tcp頭指針指到原來的tcp頭呢?我現(xiàn)在嘗試的是把tcp頭的信息恢復(fù)成原來的數(shù)值,你覺得這樣可以避免校驗(yàn)和出錯(cuò)嗎?
作者: goingstudy 時(shí)間: 2018-02-26 19:46
看一下是不是checksum offload打開了,可能已經(jīng)被計(jì)算過并且skb->csum已經(jīng)被填充
作者: cjCares 時(shí)間: 2018-02-27 10:16
回復(fù) 5# goingstudy
關(guān)了還是沒有用哎。。。
作者: Godbach 時(shí)間: 2018-02-27 18:01
回復(fù) 4# cjCares
加入的信息難道是放到原先 TCP 的 opt 里面了嗎?
既然加了信息,那么原先 TCP 的校驗(yàn)還有 IP 頭的校驗(yàn)和都做相應(yīng)的調(diào)整沒有
作者: cjCares 時(shí)間: 2018-03-04 21:32
回復(fù) 7# Godbach
加入的數(shù)據(jù)相當(dāng)于一個(gè)新頭部,不屬于tcp頭的一部分。都沒有調(diào)整。原來發(fā)送方的tcp校驗(yàn)和不是在新增數(shù)據(jù)之前就計(jì)算完畢了嘛,我就沒有修改。
然后接收方在處理前tcp頭,先把新增數(shù)據(jù)去掉了,F(xiàn)在tcp頭和ip頭的各個(gè)字段都是對的,按理說接收方的tcp校驗(yàn)和應(yīng)該是正確的吧,您覺得應(yīng)該是哪里有問題。
作者: Godbach 時(shí)間: 2018-03-05 20:48
回復(fù) 8# cjCares
那你相當(dāng)于在 IP 和 TCP 頭之間加了一個(gè)頭部,這個(gè)頭算是什么頭,用的什么協(xié)議呢。
有些網(wǎng)卡會(huì)對 checksum 提前做校驗(yàn)的。你加的這部分?jǐn)?shù)據(jù),有可能會(huì)干擾校驗(yàn)。
如果你的數(shù)據(jù)能收到協(xié)議棧,那么你去掉這個(gè) 頭部的操作代碼是什么,show 出來
作者: cjCares 時(shí)間: 2018-03-06 09:08
本帖最后由 cjCares 于 2018-03-06 09:18 編輯
回復(fù) 9# Godbach
這個(gè)是我要自定義的頭部,我現(xiàn)在用一串字符“hello world”進(jìn)行測試的,F(xiàn)在還沒有利用其它協(xié)議,就是ip頭pull掉之后,將字符也pull掉,再將剩余部分提交給tcp層。
作者: cjCares 時(shí)間: 2018-03-06 09:18
回復(fù) 9# Godbach
{
if(ip_hdr(skb)->protocol==6){
__skb_pull(skb,sizeof("hello world"));
}
{
resubmit:
作者: cjCares 時(shí)間: 2018-03-06 14:35
回復(fù) 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 時(shí)間: 2018-03-06 20:15
回復(fù) 12# cjCares
我覺得這樣不太穩(wěn)妥。既然你加了數(shù)據(jù),到這里為何不直接把這部分?jǐn)?shù)據(jù)刪掉呢。這樣才是真正還原回來了。
作者: Godbach 時(shí)間: 2018-03-06 20:18
回復(fù) 12# cjCares
這個(gè)是個(gè)干擾數(shù)據(jù)。要清理掉。這個(gè)數(shù)據(jù)是有可能導(dǎo)致 TCP 或者 IP 層的其他處理環(huán)節(jié)誤判的。
作者: cjCares 時(shí)間: 2018-03-06 21:08
回復(fù) 14# Godbach
skb_pull不應(yīng)該就是把數(shù)據(jù)刪除了嗎?
作者: Godbach 時(shí)間: 2018-03-07 11:46
回復(fù) 15# cjCares
這個(gè)只是移動(dòng) data 指向的起始位置,不是真正的移除數(shù)據(jù)。整個(gè) IP 報(bào)文中,你加的這一塊數(shù)據(jù)仍然存在。
作者: cjCares 時(shí)間: 2018-03-07 15:11
回復(fù) 16# Godbach
好的,謝謝!還有一個(gè)疑問,我加了自定義部分的報(bào)文接受時(shí)skb->ip_summed為0,正常的報(bào)文值為1,這個(gè)值是在哪個(gè)函數(shù)里面賦值成1的啊?
作者: goingstudy 時(shí)間: 2018-03-08 18:59
回復(fù) 17# cjCares
1. 0 是CHECKSUM_NONE吧,表示或者checksum 是bad 或者 硬件不支持校驗(yàn)。但是有個(gè)問題,我看skb_checksum_init的代碼,好像是NONE的時(shí)候,必定回返回0,也就是不會(huì)到csum_error那
你確定是從那里退出的嗎?
2. 你11L貼的代碼對嗎?
我看在那個(gè)rcu lock 之前還有個(gè)reset_transport_header吧?如果沒有的話肯定有問題吧
3. 還有我覺得沒法把數(shù)據(jù)移走吧?除非重新分配skb的data 或者移動(dòng)data,那樣就不好了。
其實(shí)我覺得你這種應(yīng)該是類似tunnel,不用移除數(shù)據(jù)應(yīng)該是可以實(shí)現(xiàn)的,但是協(xié)議棧太復(fù)雜了,說不定那個(gè)地方?jīng)]改好。
4. 你抓包試過嗎?
作者: cjCares 時(shí)間: 2018-03-09 11:00
回復(fù) 18# goingstudy
1. 0 是CHECKSUM_NONE,我確定是從skb_checksum_init里退出的,你可能記錯(cuò)了吧。我看的源碼是這樣的:
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.應(yīng)該是哪里沒改好,感覺還是ip_summed的問題吧,但是找不到它的值在哪變化的
4.我就用wireshark抓了包,但是那上面直接把插入的數(shù)據(jù)當(dāng)成tcp頭了,信息都不對。我現(xiàn)在都是在內(nèi)核里用printk打印各個(gè)字段,有點(diǎn)麻煩,還可以怎么抓包分析?
謝謝指導(dǎo)!
作者: Godbach 時(shí)間: 2018-03-09 12:09
回復(fù) 17# cjCares
搜下內(nèi)核代碼,找下賦值的地方。太細(xì)節(jié)的,記不太不清楚。
作者: goingstudy 時(shí)間: 2018-03-09 13:31
回復(fù) 19# cjCares
指導(dǎo)談不上,只是最近也在看這個(gè), 也是菜鳥一個(gè)。。
1. 我看最新的代碼csum_bad已經(jīng)被刪掉了,4.4里頭還有。你是哪個(gè)版本?你的網(wǎng)卡是什么類型的?atlantic的?
2. 最新的代碼是不用加reset_transport_header的,4.4應(yīng)該要加,你說在tcp_v4_rcv里頭printk header沒問題的話,那就應(yīng)該沒問題。
3.ip_summed的值應(yīng)該是在nic 接受包的時(shí)候吧,比如ixgb,在ixgb_rx_checksum里頭,如果支持硬件校驗(yàn),回設(shè)為uncessary,否則就是none,
在往上的代碼沒仔細(xì)看,如果有ip 分片,gro的話應(yīng)該還回有變動(dòng),然后應(yīng)該直接就到tcp層了。
你是關(guān)了offload是吧?
>> 2.reset_transport_header我寫了的,上面忘記加了,獲取的tcp頭信息都是對的
>> 我就用wireshark抓了包,但是那上面直接把插入的數(shù)據(jù)當(dāng)成tcp頭了,信息都不對
tcp頭的信息到底是對的還是不對的?我的意思是skb里頭那些指針指的地方到底是正確的還是錯(cuò)誤的?
作者: cjCares 時(shí)間: 2018-03-09 13:41
回復(fù) 20# Godbach
好的
作者: cjCares 時(shí)間: 2018-03-09 14:22
回復(fù) 21# goingstudy
感覺還是比我強(qiáng)多了。。。
1.我的是4.5版本的,網(wǎng)卡是e1000的。
2.reset_transport_header我在源碼里加了,上面代碼展示的時(shí)候漏掉了。tcp報(bào)頭的信息printk出來都是正確的,應(yīng)該沒問題,wireshark應(yīng)該是無法識(shí)別插入的數(shù)據(jù)。
3.offload就是tx-checksumming吧。關(guān)了跟開著我都試了,ip_summed的值都是0,沒有變化,感覺很奇怪。
作者: goingstudy 時(shí)間: 2018-03-09 14:28
回復(fù) 23# cjCares
checksum這個(gè)我也搞不很懂,但是rx-checksumming 試過嗎?如果rx-checksumming 開著的話,應(yīng)該就會(huì)被直接設(shè)置成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 時(shí)間: 2018-03-09 14:45
回復(fù) 24# goingstudy
兩個(gè)同關(guān)同閉,我都試過了,都是一樣的,都在skb_checksum_init那邊掛了。
倒是tcp_v4_do_rcv里的tcp_checksum_complete,默認(rèn)情況下的不通過。開了rx-checksumming,或者關(guān)了tx-checksumming,然后就能通過了...
作者: goingstudy 時(shí)間: 2018-03-09 15:03
回復(fù) 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 時(shí)間: 2018-03-09 15:23
回復(fù) 26# goingstudy
嗯,就是if通過了。我現(xiàn)在把goto csum_error注釋了,用了一個(gè)打印輸出來替代的。
作者: goingstudy 時(shí)間: 2018-03-11 17:22
你試試把gro disable 看行不行
$ ethtool -k ens32 | grep 'generic-receive-offload'
generic-receive-offload: on
作者: cjCares 時(shí)間: 2018-03-12 10:53
回復(fù) 28# goingstudy
可以了哎,謝謝!為什么關(guān)了gro就行了呢?
作者: goingstudy 時(shí)間: 2018-03-12 12:17
回復(fù) 29# cjCares
none 應(yīng)該是表示csum 是壞的或者沒有校驗(yàn),按最新的代碼, 在csum_init那里應(yīng)該是沒問題的,但是4.5里頭,因?yàn)閏sum_bad 導(dǎo)致失敗,而gro好像是唯一設(shè)置csum_bad的地方
沒有仔細(xì)的看過gro的 代碼,不知道這算不算是個(gè)bug
但是csum_bad 已經(jīng)被刪掉了
作者: cjCares 時(shí)間: 2018-03-12 12:58
回復(fù) 30# goingstudy
好的,非常感謝
作者: cjCares 時(shí)間: 2018-03-13 15:52
回復(fù) 30# goingstudy
再請教你一個(gè)問題啊~
三次握手中的第二次握手回復(fù)的報(bào)文不走協(xié)議棧嗎?
我在tcp層的tcp_transmit函數(shù),或者是ip層的ip_queue_xmit函數(shù)中,向報(bào)文插入字符串。這些代碼都沒執(zhí)行,對方也能收到回復(fù)的報(bào)文,它們是怎么發(fā)送出去的啊?
作者: goingstudy 時(shí)間: 2018-03-14 21:07
回復(fù) 32# cjCares
是最后一個(gè)ACK嗎,肯定走協(xié)議棧了吧,對TCP這個(gè)巨復(fù)雜的協(xié)議只看過一點(diǎn),還忘的差不多了
作者: cjCares 時(shí)間: 2018-03-15 11:16
回復(fù) 33# goingstudy
不是,是syn+ack那個(gè)。tcp確實(shí)麻煩,這個(gè)任務(wù)做的我好心累
歡迎光臨 Chinaunix (http://72891.cn/) |
Powered by Discuz! X3.2 |