最近狂補基礎(chǔ),猛看TCP/IP協(xié)議。不過,書上的東西太抽象了,沒有什么數(shù)據(jù)實例,看了不 久就忘了。于是,搬來一個sniffer,抓了數(shù)據(jù)包來看,呵呵,結(jié)合書里面得講解,理解得 比較快。我就來灌點基礎(chǔ)知識。
開始吧,先介紹IP協(xié)議。
IP協(xié)議(Internet Protocol)是網(wǎng)絡(luò)層協(xié)議,用在因特網(wǎng)上,TCP,UDP,ICMP,IGMP數(shù)據(jù)都是按照IP數(shù)據(jù)格式發(fā)送得。IP協(xié)議提供的是不可靠無連接得服務(wù)。IP數(shù)據(jù)包由一個頭部和一個正文部分構(gòu)成。正文主要是傳輸?shù)臄?shù)據(jù),我們主要來理解頭部數(shù)據(jù),可以從其理解到IP協(xié)議。
IP數(shù)據(jù)包頭部格式(RFC791)

Example Internet Datagram Header
上面的就是IP數(shù)據(jù)的頭部格式,這里大概地介紹一下。
IP頭部由20字節(jié)的固定長度和一個可選任意長度部分構(gòu)成,以大段點機次序傳送,從左到 右。
TCP協(xié)議
TCP協(xié)議(TRANSMISSION CONTROL PROTOCOL)是傳輸層協(xié)議,為應(yīng)用層提供服務(wù),和UDP不同的是,TCP協(xié)議提供的可靠的面向連接的服務(wù)。在RFC793中是基本的TCP描述。關(guān)于TCP協(xié)議的頭部格式內(nèi)容的說明:
TCP Header FORMat

TCP Header FORMat
跟IP頭部差不多,基本的長度也是20字節(jié)。TCP數(shù)據(jù)包是包含在一個IP數(shù)據(jù)報文中的。
好了,簡單介紹到此為止。來看看我捕獲的例子吧。這是一次FTP的連接,呵呵,是cuteftp默認(rèn)的cuteftp的FTP站點,IP地址是:216.3.226.21。我的IP地址假設(shè)為:192.168.1.1。下面的數(shù)據(jù)就是TCO/IP連接過程中的數(shù)據(jù)傳輸。我們可以分析TCP/IP協(xié)議數(shù)據(jù)格式以及TCP/IP連接的三次握手(ThreeWay-Handshake)情況。下面的這些十六進制數(shù)據(jù)只是TCP/IP協(xié)議的數(shù)據(jù),不是完整的網(wǎng)絡(luò)通訊數(shù)據(jù)。
第一次,我向FTP站點發(fā)送連接請求(我把TCP數(shù)據(jù)的可選部分去掉了)
192.168.1.1->216.3.226.21
IP頭部: 45 00 00 30 52 52 40 00 80 06 2c 23 c0 a8 01 01 d8 03 e2 15
TCP頭部:0d 28 00 15 50 5f a9 06 00 00 00 00 70 02 40 00 c0 29 00 00
來看看IP頭部的數(shù)據(jù)是些什么。
第一字節(jié),“45”,其中“4”是IP協(xié)議的版本(Version),說明是IP4。“5”是IHL位,表示IP頭部的長度,是一個4bit字段,最大就是1111了,值為12,IP頭部的最大長度就是60字節(jié)。而這里為“5”,說明是20字節(jié),這是標(biāo)準(zhǔn)的IP頭部長度,頭部報文中沒有發(fā)送可選部分?jǐn)?shù)據(jù)。
接下來的一個字節(jié)“00”是服務(wù)類型(Type of Service)。這個8bit字段由3bit的優(yōu)先權(quán)子字段(現(xiàn)在已經(jīng)被忽略),4 bit的TOS子字段以及1 bit的未用字段(現(xiàn)在為0)構(gòu)成.4 bit的TOS子字段包含:最小延時、最大吞吐量、最高可靠性以及最小費用構(gòu)成,這四個1bit位最多只能有一個為1,本例中都為0,表示是一般服務(wù)。
接著的兩個字節(jié)“00 30”是IP數(shù)據(jù)報文總長,包含頭部以及數(shù)據(jù),這里表示48字節(jié)。這48字節(jié)由20字節(jié)的IP頭部以及28字節(jié)的TCP頭構(gòu)成(本來截取的TCP頭應(yīng)該是28字節(jié)的,其中8字節(jié)為可選部分,被我省去了)。因此目前最大的IP數(shù)據(jù)包長度是65535字節(jié)。
再是兩個字節(jié)的標(biāo)志位(Identification):“5252”,轉(zhuǎn)換為十進制就是21074。這個是讓目的主機來判斷新來的分段屬于哪個分組。
下一個字節(jié)“40”,轉(zhuǎn)換為二進制就是“0100 0000”,其中第一位是IP協(xié)議目前沒有用上的,為0。接著的是兩個標(biāo)志DF和MF。DF為1表示不要分段,MF為1表示還有進一步的分段(本例為0)。然后的“0 0000”是分段便移(Fragment Offset)。
“80”這個字節(jié)就是TTL(Time To Live)了,表示一個IP數(shù)據(jù)流的生命周期,用Ping顯示的結(jié)果,能得到TTL的值,很多文章就說通過TTL位來判別主機類型。因為一般主機都有默認(rèn)的TTL值,不同系統(tǒng)的默認(rèn)值不一樣。比如WINDOWS為128。不過,一般Ping得到的都不是默認(rèn)值,這是因為每次IP數(shù)據(jù)包經(jīng)過一個路由器的時候TTL就減一,當(dāng)減到0時,這個數(shù)據(jù)包就消亡了。這也時Tracert的原理。本例中為“80”,轉(zhuǎn)換為十進制就是128了,我用的WIN2000。
繼續(xù)下來的是“06”,這個字節(jié)表示傳輸層的協(xié)議類型(Protocol)。在RFC790中有定義,6表示傳輸層是TCP協(xié)議。
“2c 23”這個16bit是頭校驗和(Header Checksum)。
接下來“c0 a8 01 01”,這個就是源地址(Source Address)了,也就是我的IP地址。
轉(zhuǎn)換為十進制的IP地址就是:192.168.1.1,同樣,繼續(xù)下來的32位“d8 03 e2 15”是目標(biāo)地址,216.3.226.21
好了,真累啊,終于看完基本的20字節(jié)的IP數(shù)據(jù)報頭了。繼續(xù)看TCP的頭部吧,這個是作為IP數(shù)據(jù)包的數(shù)據(jù)部分傳輸?shù)摹!?
TCP頭部:0d 28 00 15 50 5f a9 06 00 00 00 00 70 02 40 00 c0 29 00 00
一來就是一個兩字節(jié)段“0d 28”,表示本地端口號,轉(zhuǎn)換為十進制就是3368。第二個兩字節(jié)段“00 15”表示目標(biāo)端口,因為我是連接FTP站點,所以,這個就是21啦,十六進制當(dāng)然就是“00 15”。
接下來的四個字節(jié)“50 5f a9 06”是順序號(Sequence Number),簡寫為SEQ,SEQ=1348446470下面的四個字節(jié)“00 00 00 00”是確認(rèn)號(Acknowledgment Number),簡寫為ACKNUM。
繼續(xù)兩個字節(jié),“70 02”,轉(zhuǎn)換為二進制吧,“0111 0000 0000 0010”。這兩個字節(jié),總共16bit,有好多東西呢。第一個4bit“0111”,是TCP頭長,十進制為7,表示28個字節(jié)(剛才說了,我省略了8字節(jié)的option數(shù)據(jù),所以你只看見了20字節(jié))。接著的6bit現(xiàn)在TCP協(xié)議沒有用上,都為0。最后的6bit“00 0010”是六個重要的標(biāo)志。這是兩個計算機數(shù)據(jù)交流的信息標(biāo)志。接收和發(fā)送斷根據(jù)這些標(biāo)志來確定信息流的種類。下面是一些介紹:
URG:(Urgent Pointer field significant)緊急指針。用到的時候值為1,用來處理避免TCP數(shù)據(jù)流中斷
ACK:(Acknowledgment fieldsignificant)置1時表示確認(rèn)號(AcknowledgmentNumber)為合法,為0的時候表示數(shù)據(jù)段不包含確認(rèn)信息,確認(rèn)號被忽略。
PSH:(Push Function),PUSH標(biāo)志的數(shù)據(jù),置1時請求的數(shù)據(jù)段在接收方得到后就可直接送到應(yīng)用程序,而不必等到緩沖區(qū)滿時才傳送。
RST:(Reset the connection)用于復(fù)位因某種原因引起出現(xiàn)的錯誤連接,也用來拒絕非法數(shù)據(jù)和請求。如果接收到RST位時候,通常發(fā)生了某些錯誤。
SYN:(Synchronize sequence numbers)用來建立連接,在連接請求中,SYN=1,ACK=0,連接響應(yīng)時,SYN=1,ACK=1。即,SYN和ACK來區(qū)分Connection Request和Connection Accepted。
FIN:(No more data from sender)用來釋放連接,表明發(fā)送方已經(jīng)沒有數(shù)據(jù)發(fā)送了。
這6個標(biāo)志位,你們自己對號入座吧。本例中SYN=1,ACK=0,當(dāng)然就是表示連接請求了。我們可以注意下面兩個過程的這兩位的變換。
后面的“40 00 c0 29 00 00”不講了,呵呵,偷懶了。后面兩次通訊的數(shù)據(jù),自己分開看吧。我們看看連接的過程,一些重要地方的變化。
第二次,F(xiàn)TP站點返回一個可以連接的信號。
216.3.226.21->192.168.1.1
IP頭部: 45 00 00 2c c6 be 40 00 6a 06 cd ba d8 03 e2 15 c0 a8 01 01
TCP頭部:00 15 0d 28 4b 4f 45 c1 50 5f a9 07 60 12 20 58 64 07 00 00
第三次,我確認(rèn)連接。TCP連接建立起來。
192.168.1.1->216.3.226.21
IP頭部: 45 00 00 28 52 53 40 00 80 06 2c 2a c0 a8 01 01 d8 03 e2 15
TCP頭部:0d 28 00 15 50 5f a9 07 4b 4f 45 c2 50 10 40 b0 5b 1c 00 00
好,我們看看整個Threeway_handshake過程。
第一步,我發(fā)出連接請求,TCP數(shù)據(jù)為:SEQ=50 5f a9 06,ACKNUM=00 00 00 00,SYN=1,ACK=0。
第二步,對方確認(rèn)可以連接,TCP數(shù)據(jù)為:SEQ=4b 4f 45 c1,ACKNUM=50 5f a9 07,SYN=1,ACK=1。
第三步,我確認(rèn)建立連接。SEQ=50 5f a9 07, ACKNUM=4b 4f45c2,SYN=0,ACK=1。
可以看出什么變化么?正式建立連接了呢,這些東西是什么值?
我接收從216.3.226.21->192.168.1.1的下一個數(shù)據(jù)包中:
SEQ=4b 4f 45 c2,ACKNUM=50 5f a9 07,SYN=0,ACK=1這些都是很基礎(chǔ)的東西,對于編寫sniffer這樣的東西是必須非常熟悉的。這里只講解了TCP/IP協(xié)議的一點點東西,主要是頭部數(shù)據(jù)的格式