Q:你好!
看過了你在csdn上發表的《用C#下的Raw Socket編程實現網路封包監視》,覺得高度興趣,而且對我的協助很大。不過在調試的過程中遇到一些問題,特此向你請教一下。謝謝!
首先
socket.SetSocketOption(SocketOptionLevel.IP,
SocketOptionName.HeaderIncluded, 1);
byte []IN = new byte[4]{1, 0, 0, 0};
byte []OUT = new byte[4];
//低層級操作模式,接受所有的資料包,這一步是關鍵必須把socket設成raw和IPLevel才可用SIO_RCVALL
int ret_code = socket.IOControl(SIO_RCVALL, IN, OUT);
ret_code = OUT[0] + OUT[1] + OUT[2] + OUT[3];//把4個8位位元組合成一個32位整數
if(ret_code != 0) ret_value = false;
應改是用來設定socket的工作方式的,我想知道的是你所是值得常量SIO_RCVALL = 0x98000001是如何得到的(我是指後面的十六進位數十怎麼得到的),有沒有相關的文檔推薦一下。我看過一些,不過沒有眉目。這些數字應該是什麼所謂的操作控制碼,但我找不到更詳細的資料,希望能指點一下。另外,在第二行中那個IN數組為什麼要那麼設定,這點我還不太明白。
第二
e.HeaderLength=(uint)(head->ip_verlen & 0x0F) << 2;
在這句話中,你是想要得到資料包的IP頭長,從IP的結構來看,似乎是不應該移位(即左移兩位)的,因為屏蔽掉前前四位之後,所剩的四位正好為頭長,不知這個地方是否有問題。
第三
這段代碼是由原始通訊端作封包監視,但不知能否實現資料包的攔截。因為如果可以的話就可以實現放火牆的功能了。
不好意思!
第一次給你發信就問了這麼一大堆,耽誤了你的時間!
再次表示感謝!
等待你的回信:)
A:
第一.
在winsock2.h中定義了以下宏:
#define IOC_VOID 0x20000000 /* no parameters */
#define IOC_OUT 0x40000000 /* copy out parameters */
#define IOC_IN 0x80000000 /* copy in parameters */
#define IOC_UNIX 0x00000000
#define IOC_WS2 0x08000000
#define IOC_PROTOCOL 0x10000000
#define IOC_VENDOR 0x18000000
#define _WSAIO(x,y) (IOC_VOID|(x)|(y))
#define _WSAIOR(x,y) (IOC_OUT|(x)|(y))
#define _WSAIOW(x,y) (IOC_IN|(x)|(y))
#define _WSAIORW(x,y) (IOC_INOUT|(x)|(y))
裡面沒有SIO_RCVALL的定義,但是你可以查看msdn中的ms-help://MS.MSDNQTR.2003FEB.2052/winsock/winsock/wsaioctl_2.htm看WSAIoctl函數中的SIO_RCVALL 的說明,你可以知道它是這樣定義的:
#define SIO_RCVALL _WSAIOW(IOC_VENDOR,1)
即:
0x80000000|0x18000000|0x00000001
其中IOC_VENDOR 實際上是IOC_WS2|IOC_PROTOCOL ,因為要receive all IP packets on the network on win32 platform.
至於用四位元組數組來接收資料流,是因為網路資料流串列的在網線傳輸,需要接收到32位(二進位)後才能對該串列流進行解析,這是一種串列通訊協定,當接收到32位後,網卡會把這32位(二進位)傳給一個四位元組數組。因為要和IOControl的傳回值保持一致,返回的是32位的int32,所以要把out〔〕數組整合成int。至於byte []IN = new byte[4]{1, 0, 0, 0};這樣定義是,因為這樣整合成的整形數是(十六進位) 00 00 00 01 ,即1,輸入32位元的值為一,是因為要把socket設定成非阻塞狀態(which is nonzero if nonblocking mode is to be enabled and zero if it is to be disabled. )。而out得到的是一次接收操作中得到的位元組數 (returns the total amount of data that can be read in a single receive operation; )。
第二:
資料包包頭長的值為4位二進位,範圍0-15,如果不移位的話包頭長度不會超過15位元組,怎麼會?正如上面所說。每32位二進位是一個網路串列通訊的資料單元,描述包頭長的四位記錄的是資料單元數,不是位元組數,所以要乘與四(32bit資料單元長度/8bit位元組長度),即左移二位。
第三:
基於.net的raw socket是基於winsock2來實現的,它實現在七層模型的應用程式層,而應用程式層的封包攔截向來很弱,一般在應用程式層實現可用spi(服務提供者),其實這需要系統調用。我試過,在.net下效果不是太好,資料包要麼全部都攔住了,要麼全部允許存取,系統反應很慢,穩定性很弱,呵呵,這是.net的隱痛。一種比較流行的做法是寫網路層的ndis驅動程式,ndis hook driver和ndis中介層驅動都可以,其中ndis中介層驅動功能強大,不光可以進行封包攔截,還可以實現對網路資料流的加密,強烈建議使用!
至於在.net下做防火牆,可用managed C++做來DeviceIoControl,可以查看我的文章:
http://www.csdn.net/develop/read_article.asp?id=21480
獲得RawSocket的C#原始碼請訪問:http://www.mscenter.edu.cn/blog/seafrog/archive/2005/05/30/2866.html