Linux網絡編程:原始套接字的魔力【上】

基於原始套接字編程
       在開發面向連接的TCP和麪向無連接的UDP程序時,我們所關心的核心問題在於數據收發層面,數據的傳輸特性由TCPUDP來保證:
       也就是說,對於TCPUDP的程序開發,焦點在Data字段,我們沒法直接對TCPUDP頭部字段進行赤裸裸的修改,當然還有IP頭。換句話說,我們對它們頭部操作的空間非常受限,只能使用它們已經開放給我們的諸如源、目的IP,源、目的端口等等。
       今天我們討論一下原始套接字的程序開發,用它作爲入門協議棧的進階跳板太合適不過了。OK閒話不多說,進入正題。
       原始套接字的創建方法也不難:socket(AF_INET, SOCK_RAW, protocol)
       重點在protocol字段,這裏就不能簡單的將其值爲0了。在頭文件netinet/in.h中定義了系統中該字段目前能取的值,注意:有些系統中不一定實現了netinet/in.h中的所有協議。源代碼的linux/in.h中和netinet/in.h中的內容一樣。
       我們常見的有IPPROTO_TCPIPPROTO_UDPIPPROTO_ICMP,在博文“(十六)洞悉linux下的Netfilter&iptables:開發自己的hook函數【實戰】(下) ”中我們見到該protocol字段爲IPPROTO_RAW時的情形,後面我們會詳細介紹。
       用這種方式我就可以得到原始的IP包了,然後就可以自定義IP所承載的具體協議類型,如TCPUDPICMP,並手動對每種承載在IP協議之上的報文進行填充。接下來我們看個最著名的例子DOS***的示例代碼,以便大家更好的理解如何基於原始套接字手動去封裝我們所需要TCP報文。
       先簡單複習一下TCP報文的格式,因爲我們本身不是講協議的設計思想,所以只會提及和我們接下來主題相關的字段,如果想對TCP協議原理進行深入瞭解那麼《TCP/IP詳解卷1》無疑是最好的選擇。
       我們目前主要關注上面着色部分的字段就OK了,接下來再看看TCP3次握手的過程。TCP3次握手的一般流程是:
(1) 第一次握手:建立連接時,客戶端A發送SYN(SEQ_NUMBER=j)到服務器B,並進入SYN_SEND狀態,等待服務器B確認。
(2) 第二次握手:服務器B收到SYN包,必須確認客戶ASYN(ACK_NUMBER=j+1),同時自己也發送一個SYN(SEQ_NUMBER=k),即SYN+ACK包,此時服務器B進入SYN_RECV狀態。
(3) 第三次握手:客戶端A收到服務器BSYNACK包,向服務器B發送確認包ACK(ACK_NUMBER=k+1),此包發送完畢,客戶端A和服務器B進入ESTABLISHED狀態,完成三次握手。
 至此3次握手結束,TCP通路就建立起來了,然後客戶端與服務器開始交互數據。上面描述過程中,SYN包表示TCP數據包的標誌位syn=1,同理,ACK表示TCP報文中標誌位ack=1SYN+ACK表示標誌位syn=1ack=1同時成立。
原始套接字還提供了一個非常有用的參數IP_HDRINCL

1、當開啓該參數時:我們可以從IP報文首部第一個字節開始依次構造整個IP報文的所有選項,但是IP報文頭部中的標識字段(設置爲0)IP首部校驗和字段總是由內核自己維護的,不需要我們關心。

2、如果不開啓該參數:我們所構造的報文是從IP首部之後的第一個字節開始,IP首部由內核自己維護,首部中的協議字段被設置成調用socket()函數時我們所傳遞給它的第三個參數。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章