raw socket

 衆所周知,通過socket編程,我們能夠實現機器之間的通信.在TCP/IP協議
簇(PF_INET)中,可以建立面向連接的SOCK_STREAM類型的socket,非連接的
SOCK_DGRAM類型的socket.事實上,在所有的網絡程序中,也是這兩種socket用
的最爲廣泛.除此之外,還有一些不常用的socket類型,它們卻是在某些網絡通
信中擔當重要的角色.這裏要講的就是這麼一種socket,稱之爲raw socket.
    raw socket的作用主要在三個方面:
    1.通過raw socket來接受發向本機的ICMP,IGMP協議包,或者用來發送這些
    協議包.
    2.接受發向本機的但TCP/IP棧不能夠處理的IP包.
    3.用來發送一些自己制定源地址特殊作用的IP包(自己寫IP頭,TCP頭等等)

    我們知道,平時我們想看一看網絡是否通達,就用ping命令測試一些.ping
命令用的是ICMP協議.因此,我們不能夠通過建立一個SOCK_STREAM或SOCK_DGRAM
來發送這個包,只能夠自己親自來構建ICMP包來發送.這是一種情況.另一種情況
是:現在許多操作系統在實現網絡部分的時候,通常只實現了常用的幾種協議,
如tcp,udp,icmp等,但象其它的如ospf,ggp等協議,操作系統往往沒有實現,如果
自己有必要編寫位於其上的應用,就必須藉助raw socket來實現,這是因爲操作
系統遇到自己不能夠處理的數據包(ip頭中的protocol所指定的上層協議不能處
理).就將這個包交給raw socket.而最後一種使用raw socket的目的主要是用來
構建一些特殊的協議頭,比如我們想對某臺機器進行denial of service類型的
攻擊,但是有不想留下痕跡,讓別人知道IP包的來源,這時候就可以使用raw 
socket來發送這些僞造源地址信息的包,這其實也是這種攻擊所採用的主要技術
手段.當然了,我說的是HACKER行爲,之所以想要處理這些特殊的IP包,通常也是
爲了診斷網絡的目的.
    
    raw socket的建立是通過如下方式的:
    
    sockfd = socket(PF_INET, SOCK_RAW, protocol);

    第一個參數就不必講了,第二個參數說明建立的是一個raw socket,第三個
參數倒是需要詳細解說一下.這裏分三種情況:
    1.參數protocol用來指明所要接收的協議包,如果是象IPPROTO_TCP(6)這
    種非0,非255的協議,則內核碰到ip頭中protocol域和創建socket所使用參
    數protocol相同的IP包,就會交給這個rawsocket來處理.因此,一般說來,
    要想接收什麼樣的數據包,就應該在參數protocol裏來指定相應的協議.當
    內核向此raw socket交付數據包的時候,是包括整個IP頭的,並且已經是重
    組好的IP包. 如下:

    ---------------------------------------------------------------
    |ip header|tcp header(or x header)|             data          |
    ---------------------------------------------------------------         
    用recvfrom收到的數據包括一個IP頭,一個相應的協議頭,然後是數據(數
    據也可以爲空,就看實際情況了). 但當我們發送IP包的時候,卻不用親自
    處理IP包頭,只需要填 充參數protocol所指定的相應的協議頭即可.也就
    是說,用sendto的時候,我們提供給它的緩衝區數據是從IP包頭的第一個字
    節開始,如下,只需要構造這麼一個緩衝區就可以了.

    --------------------------------------------------------------
    |tcp header(or udp header or x header)|           data       |
    --------------------------------------------------------------
    如果想自己也想親自處理IP頭,則需要IP_HDRINCL的socket選項.如下:

    int flag = 1;
    setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &flag, sizeof(int));

    這樣,發送時所要提供的緩衝區有成如下形式:

    ---------------------------------------------------------------
    |ip header|tcp header(or x header)|             data          |
    ---------------------------------------------------------------         
    但是,即時是這種情況,在我們發送IP包的時候.也不是填充ip頭的所有字
    段,而是應該將ip頭的id(identification)字段設置爲0,表示讓內核來處
    理這個字段.同時,內核還幫你完成ip頭的校驗和的計算,並隨後填充check
    字段.

    2.如果protocol是IPPROTO_RAW(255),這時候,這個socket只能用來發送
    IP包,而不能接收任何數據.發送的數據需要自己填充IP包頭,並且自己計
    算校驗和.
    3.對於protocol爲0(IPPROTO_IP)的raw socket. 在linux和sco unix上
    是不允許建立的.我沒有再試過其他操作系統,誰能給我一個答案:)

    對於raw socket,只有root權限才能夠創建.
    這裏對raw socket總結一下: 當內核接收到IP包的時候,首先檢查ip包的
protocol域,當存在與此域匹配的raw socket時,就將包先傳給此raw socket,
然後交給相應的上層協議處理.交給raw socket的數據是包括IP頭並且已經重
組完成後的.當使用raw socket發送包的時候,如果raw socket創建時的protocol
不是0或255,並且沒有設置IP_HDRINCL選項,則發送的數據不包括IP頭.如果此
選項置位,則需要自己構件IP頭.如果創建protocol爲255的raw socket,此raw
socket只能用來發送包括IP頭,自己構建IP包.

 
附錄:
IP頭結構:

struct iphdr       
        
|-------|--------|---------------|-------------------------------|
|version|   ihl  |     tos      |           tot_len      |
|-------|--------|---------------|-------------------------------|
|  id      |               |        frag_off   |
|----------------|---------------|-------------------------------|
|      ttl       | protocol     |         check             |
|----------------|---------------|-------------------------------|
|                             saddr                              |
|----------------------------------------------------------------|
|         daddr                       |
|----------------------------------------------------------------|

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