原始通訊端可以訪問ICMP和ICMP等協議包,可以讀寫核心不處理的IP資料包。可以建立自訂的IP資料包首部。一句話,使用原始通訊端可以 編寫基於IP協議的通訊程式。 1.建立原始通訊端 具體格式如下: int sockfd; sockfd = socktet(AF_INET, SOCK_RAW, IPPROTO_ICMP); 第一個參數:協議族 AF_INET 代表TCP/IP協議 第二個參數:SOCKET類型 第三個參數:協議類型 注意: @如果指定協議為0時,原始通訊端可以接收核心傳遞給原始通訊端的任何IP資料包,且只有超級使用者才可以建立原始通訊端。 @當需要編寫自己的IP資料包首部時,可以在原始通訊端上設定通訊端選項IP_HDRINCL。在不設定這個選項的情況下,IP協議自動填滿IP資料包的首部。 int on = 1; if(setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, &on, sizeof(on)) < 0) { fprintf(stderr, "setsockopt IP_HDRINCL ERROR! /n"); exit(1); } 原始通訊端直接使用IP協議的通訊端,所以是非連線導向的。在這個通訊端上可以調用connect和bind函數,分別執行綁定對方和本地地址。 說明: bind函數:調用bind函數後,發送資料包的源IP地址將是bind函數指定的地址。如是不調用bind,則核心將以發介面的主IP地址填充。如果設定了IP_HDRINCL,那麼必須手工填充每個發送資料包的源IP地址。 connetc函數:調用connect函數後,可以用write和send發送資料包。核心將用這個綁定的地址填充IP資料包的目的IP地址。 發送資料包 使用原始通訊端發送資料包必須遵循以下規則: 1.如果沒有用connect函數綁定對方地址時,則應使用sendto或sendmsg函數發送資料包,在函數參數中指定對方地址。如果調用了connect函數,則可以直接使用send,write或writev來發送資料包。 2.如果沒有設定IP_HDRINCL選項時,包內可寫的內容為資料部分,核心將自動建立IP首部。如果設定了IP_HDRINCL選項,則包內要填充的內容為IP資料包和首部。核心只負責填充下面兩個域: ·如果將IP資料包的標識網域設定為0,核心將設定這個域 ·核心總是計算和填充IP資料包首部的校正和。 注意:IP資料包首部各個域的內容都是網路位元組順序。 接收資料包 核心遵循以下規則接收資料包: 1.UDP和TCP資料包從不傳送給一個原始通訊端。如果要查看這兩類資料包,只能通過直接存取資料連結層來實現。 2.大多數ICMP資料包的一個拷貝傳送給匹配的原始通訊端。 3.核心處理的所有其它類型的資料包的一個拷貝都傳給匹配的原始通訊端。 4.所有核心不能識別的協議類型的IP資料包都傳送給匹配的原始通訊端。對於這些IP資料包,核心只做必要的檢驗工作。 在將一個IP資料包傳送給原始通訊端之前,核心需要選擇匹配的原始通訊端 1.資料包的協議域必須與接收原始通訊端的協議類型匹配。 2.如果原始通訊端調用了bind函數綁定了本地IP地址,那麼到達的IP資料包的源IP地址必須和對方的IP相匹配。 3.如果原始通訊端調用connect函數指定了對方的IP地址,則到達的IP資料包的源IP地址秘須與這它相同。 |