TCP校正值的偽頭以及校正值計算

來源:互聯網
上載者:User

tcp層的校正值難道還需要ip層的中繼資料也就是ip頭嗎?如果一切都是理想的顯然不需要,因為這違背了分層隔離的原則,下層一定不能依賴上層,但是上層可以訪問下層,還好tcp使用ip資訊正是這一點。按照封包原則,封裝到TCP層的時候,ip資訊還沒有封裝上去,但是校正值卻需要馬上進行計算,所以必須手工構造一個偽頭部來表示ip層的資訊,怎麼構造呢?在資料到tcp層的時候其實使用者肯定知道資料發往何處,源地址和目的地址都有,只不過是還沒有封裝到資料上罷了,簡單的例子就是在socket程式中,connect或者accept或者recvfrom以及sendto都會保留有地址資訊,另外偽頭中還將保留有傳輸層協議資訊,所有這一切都是為了使得通訊更加安全和縝密,試想如果一個中間人截獲了一個icmp包,然後改為了udp包或發生什麼,該udp不是隨意的而是精心構造的,但是加入了偽頭部如此之行為得逞就困難多了,因為偽頭部中有協議欄位,除此之外,任何錯誤的投遞,錯誤的資料長度以及錯誤的協議都會被檢測到。看一下偽頭吧:

struct psd_head

{

__u32 saddr; // 源網路層地址

__u32 daddr; // 目的網路層地址

__u8 mbz; //賦0

__u8 ptcl; // 傳輸層協議

__u16 tcpudpl; //傳輸層長度

};

以下是一個簡單的校正和校正碼的計算函數

void tcpv4_check_addr( __u16 * ppkgdata )

{

char * indata;

__u16 ippktlen, udppktlen,tcppktlen,wd;

__u32 ipheadlen;

__u32 sum,i,pl,el;

struct psd_head psd;

struct iphdr * ipd;

struct tcphdr * tcpd;

struct udphdr * udpd;

__u16 * databegin;

indata = (char *)ppkgdata; //從MAC開始的整個幀

ipheadlen = 14 + (indata[14]&0x0f)*4 ; //MAC和ip頭的長度和

databegin = (__u16 *)(indata + ipheadlen); //ip資料

ipd = (struct iphdr *)(indata + 14); //MAC資料

tcpd = (struct tcphdr *)(indata + ipheadlen); //ip資料

ippktlen = htons(ipd->tot_len); //ip頭和ip資料的總長度

if(ipd->protocol == 0x6){

tcppktlen = ippktlen +14 - ipheadlen; //tcp頭和tcp資料的總長度

tcpd->check = 0;

psd.saddr = ipd->saddr; //構造偽頭部

psd.daddr = ipd->daddr;

psd.mbz=0;

psd.ptcl = 0x06; //ip的下一個頭

psd.tcpudpl = htons(tcppktlen);

sum = 0;

wd = tcppktlen/2; //每次資料前移16位而不是一個位元組

for(i=0;i

sum += *databegin;

databegin++;

}

el = tcppktlen - wd*2;

if(el != 0)

sum += (*databegin&0xff);

wd = sizeof(struct psd_head)/2;

databegin = (__u16 *) &psd.saddr;

for(i=0;i

sum += *databegin;

databegin++;

}//下面這個運算式就是高低16分別相加,sum/65536就是高16位:sum

pl = (sum + sum/65536)&0xffff;

sum = 0xffff^pl;

tcpd->check = (__u16)sum; //檢驗和的計算很簡單,就是將資料相加並且回卷之後取反

}

return;

}

以上的演算法再清晰不過了,甚至將tcp,ip頭部的位移怎麼計算都表達了出來,但是這個函數並不適用於實際情況,因為在高負載網路環境下,特別是NAT或者資料過濾網關環境下,校正和的計算是一個很頻繁的過程,因此上述函數的c語言本質將很影響效率,取而代之的是用彙編實現,正如linux核心中的那樣:

static inline __sum16 csum_fold(__wsum sum)

{

__asm__(

"addl %1, %0 ;/n"

"adcl $0xffff, %0 ;/n"

: "=r" (sum)

: "r" ((__force u32)sum

"" ((__force u32)sum & 0xffff0000)

);

return (__force __sum16)(~(__force u32)sum >> 16);

}

static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr, unsigned short len, unsigned short proto, __wsum sum)

{

__asm__(

"addl %1, %0 ;/n"

"adcl %2, %0 ;/n"

"adcl %3, %0 ;/n"

"adcl $0, %0 ;/n"

: "=r" (sum)

: "g" (daddr), "g"(saddr), "g"((len + proto)

return sum;

}

static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr, unsigned short len, unsigned short proto, __wsum sum)

{

return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum));

}

別看一個小小的計算校正和,它本質上影響了網路傳輸的效率,如果用tcpv4_check_addr這個Function Compute校正和,效率慢了10倍之多,但是用彙編取而代之的話,效率雖然由於額外吸收而有所下降,但是數量級並沒有改變。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.