NO IMAGE

作者:James Antognini and Thomas F. Divine

Copyright ? 2003 by Printing Communications Assoc., Inc. (PCAUSA). All rights reserved

 

譯:feikoo  時間:200631

 

本文是擴充套件Microsoft? Windows? Driver Development Kit (DDK) PassThru NDIS Intermediate (IM) 驅動示例系列文章的第二部分,將講述如何擴充套件PassThru驅動,使其能對傳送到或接收自某一IP的資料包進行過濾。

 

在文章的第一部分中,講述了擴充套件PassThru驅動的一些基礎知識,包括:

1.基本的DeviceIoControl介面:提供Win32應用程式與PassThru驅動進行通訊的一種基本方法。2.繫結列舉函式:允許Win32應用程式查詢PassThru驅動的繫結資訊;

3. ADAPT結構引用計數:新增對ADAPT結構的邏輯計數;

4.介面卡名柄(Adapter Handle)開啟/關閉功能:建立與某一具體命名的PassThru繫結的使用者模式控制代碼的方法。該控制代碼可以用來在某一介面卡上請求,讀寫I/O和進行其它的操作。

5 處理事件通知:在這節我們將處理已經開啟的驅動控制代碼變為無效的情況(如Pnp)。

6. 在一個開啟的介面卡控制代碼上查詢資訊:增加一種用Win32初始化的NDIS請求在一個開啟的介面卡控制代碼上查詢資訊的方法。 接下來的一系列文章將介紹對PassThru的另一些擴充套件。

 

在接下來的文字中,主要講述如何在PassThru基礎上實現根據被阻止的IP列表過濾傳送或接收的資料包。實現此功能的基本要求則包括:

         1.Filter Driver – PassThru基礎上開發NDIS IM驅動,用於過濾

         2.Control Application – 用來從從文字檔案中讀要阻止的IP地址並生成IP列表。

         3.Statistics Viewer – 提供一種機制,用於統計被過濾驅動程式阻止的資料包。

兩位作者為這篇文章每人寫了一個NDIS IM驅動,儘管它們在功能上是一致的:傳遞給驅動的命令相同,驅動作出的迴應也相同。但是,二者還是在實現方式上有很大的不同。現列舉如下表:

        

 

Thomas

James

Driver API

DeviceIoControl (IOCTL)

Windows Management
Instrumentation (WMI)

Packet Header Definitions

取自 FreeBSD 5.0

取自不同的 RFC文件

 

每一個驅動程式均提供了滿足要求的方法供大家探討。讀者仔細閱讀這兩個驅動程式程式碼是非常有益的,他向我們展示瞭如何在同一起點上卻能產生不同的實現方法和設計思路。

 

文章包括:設計問題的總述,ThomasJames 對他們自己的程式的看法。而文章的精華在於這兩個驅動程式的原始碼。

 

一.設計時需要考慮的問題:

         1.棄包:

在驅動程式中,有三處可以對包進行操作,這三處就是我們進行資料包轉發或棄包(過濾)處理的程式碼位置。其中棄包是通過對資料包不進行轉發來實現的。

         1MPSendPackets這裡可以看見向外傳送的一個或多個資料包。該函式通過將資料包遞交或不遞交給下一層來達到傳送或棄包的目的。

         2PTReceive看見單個的接收資料包。一般情況下,包可能不整,而只是包頭和資料的大部分,該函式在以前的設計方式中或發生資源短缺時由其下層驅動呼叫(在PassThru中,其下層為miniport驅動層)。PTReceive要麼向上層驅動指示有包到來,要麼將包丟棄不作處理。

         3 PTReceivePacket如果驅動程式以較新的思路設計或緩衝資源充分的話,它可接收一個完整的資料包。PTReceivePacket同樣是要麼向上層驅動指示有包到來,要麼將包丟棄不作處理。

 

需要說明的一點是:棄包僅僅是不向其下一層驅動轉發其收到的資料包,NDIS函式庫中是沒有棄包函式的。無論資料包是向下一層驅動遞交或是棄包,都需要最終呼叫函式NdisMSendComplete 來完成操作,以便IM驅動上層的傳送者能夠回收資源。

 

在這個示例中,我們沒有使用MPSend,而是使用了MPSendPackets。這兩個函式只實現其一就可以了(由在註冊minports回撥函式時決定使用哪一個)。註冊miniport回撥函式充許在編譯時選擇old-style the new-style Send 回撥函式。

 

2. 網路配置變化的影響

         當驅動程式安裝好後,又可能因後來的NDIS操作導致需要解除安裝驅動。如使用者通過網路控制面板刪除或取消了NDIS IM PassThru驅動。

         我們要保證整個P過濾驅動的設計不會影響驅動程式的正常解除安裝。如果一個使用者建立了一個驅動程式的控制代碼,則(1)僅讓該控制代碼短暫存在(2)為了使用NDIS操作能繼續進行,需要一個通知上層應用程式的方法,以便讓控制代碼關閉。

 

3.序列化問題

         這裡存在這樣的問題:一些執行在PASSIVE_LEVEL的函式可能被執行在DISPATCH_LEVEL的函式中斷。進一步考慮MP(多處理器系統)系統,兩個驅動程式的例項可能同時執行在兩個不相關的IRQL上。因此,在這種情況下要使用旋轉鎖(Spin lock);在其它情況下,使用Interlocked函式族就足夠保持cache的一致性了(it suffices for purposes of copying statistics counters merely to employ code that preserve cache coherency ("interlocked" family of functions,不知首如何譯).

 

4.設計選項

         以下是驅動開發人員作出的該驅動程式應具體的功能:

         1.管理員許可權問題:有或者沒有管理員許可權的使用者均能設定IP地址列表。對於更進一步的控制,留給有興趣的讀者作為練習。

         2.僅過濾Ipv4的資料包:只有乙太網包頭指明是IPV4的資料包才會被過濾,ARPRARP資料包均不會被過濾掉。

         3.IP地址列表順序:為了簡起見,應用程式提供的過濾IP地址列表就是一個事先排好序的列表,驅動程式會拒絕沒有排序的IP地址列表。

         4.使用者態/核心態API方法:傳統的DeviceIoControl 函式和Windows Management Instrumentation (WMI) API函式均可用於配置IP過濾功能。

 

二.IOCTLWMI作為配置程式介面的優缺點:

         使用者程式與驅動程式的互動被設計成暫時的。應用程式與驅動程式僅僅短暫地通訊以傳遞命令;然後,驅動程式自動執行直到下一互動操作開始。應用程式也可能不時向驅動程式查詢相關統計資訊。

         IOCTLWMI均適合在應用程式與驅動程式之間傳遞命令與統計資訊。但是,二者各有優缺點,列舉如下:

1.IOCTL介面:

         1)優點:A.這是一種常用的使用者與核心通訊的方法,許多人都熟悉。還有,使用者區的程式碼會很簡單(CreateFile,CloseHandle,DeviceIoControl)。B.可以被擴充套件用來提供連續,高速的驅動介面。例如,非同步I/O使用IOCTL就是一個好的包收集介面(公認的)。

         2)缺點:目前還沒實現到更細化的開啟驅動物件授權。NdisMRegisterDevice還沒有像IoCreateDeviceSecure 那樣的授權機制。操作還不支援遠端開啟一個裝置物件。當然,使用者可在本地寫一個遠端伺服器,用於遠端使用者在本地開啟一個裝置驅動,但這會增加工作量。

 

2.WMI介面

         1)優點:

         AWMI本身具有遠端訪問功能(公認的),基於WMI的配置程式可以像控制本地驅動例項一樣來配置一個遠端驅動例項。

         BPerMonWbemTestWMI提供者一起工作。因此,你可以使用PerMonPassThru中獲取統計資訊。

         C)相對於IOCTL,微軟推薦使用WMI來進行簡單的配置操作。

         2)缺點:

         A)這種技術對我們來說較陌生,並且大部分在使用者態工作。本文示例可以清楚地說明這一點。

         B)不能被擴充套件來提供連續,高速的介面。例如,它就不適合作包收集介面。

三.棄包的多方面考慮

         以下是NDIS IM驅動棄包處理的一些考慮:

         1.對於傳送操作來說,驅動程式在處理完資料包(轉發或者丟棄)後應該通過NdisMSendComplete 函式來告訴傳送資料包一方。

         2.傳送資料包的程式或者是TCP/IP協議會重新傳送丟棄的包,因為對於TCP/IP協議來說,資料包僅僅是因為未知原因丟失了,它會嘗試重新傳送該資料包。

         3.資料包的內容,即TCP包的淨荷域(除掉包頭的資料部分)是不會被PassThru驅動程式檢查的,它僅僅檢查相關的包頭部分。對於加密的資料包,驅動程式也會同樣的方式處理它。但是,對於VPN協議來說,加密的資料包是不同的:所有的驅動程式只能看到未加密的IP地址等資訊。對於其它在淨荷域中加密過的地址等是無法被看到的。

         4.當驅動程式丟傳送的資料包時,網路臨控器,嗅控器(如Microsft NetMon)同樣會認為資料包已經傳送出去。這是因為這些程式所使用的NDIS協議驅動在NDIS棧中比NDIS IM驅動高,是NDIS IM驅動的上層。同樣,對NDIS IM驅動丟棄的接收資料包,這些應用程式將無法看到。

         文章的其餘部分主要是ThomasJames對各自的驅動程式和測試程式的見解。文章的精華則在於這兩個驅動程式的原始碼。

 

四.NDIS IM IP過濾驅動(Thomas

 

1.驅動概述

         本文從前一篇文章中提及的驅動程式框架著手,我們先修改原始碼,加入新模組(filter.c),將過濾功能獨立出來。這樣做的目的主要是便於以後修改過濾模組來用不同方法實現過濾功能。

Filter.c中的主要函式有:

         1FltFilterSendPacket – 過濾傳遞給 MPSend and MPSendPackets函式的每一個資料包。

2FltFilterReceivedPacket – 過濾每一個傳遞給PtReccievePacket.的資料包。

3FltFilterReceive – 過濾每一個傳遞給 PtReceive的資料包。

TestIOCTL程式讀取含有適配名和要過濾的IP列表的文字檔案,排好序的IP地址列表通過命令IOCTL_PTUSERIO_SET_IPv4_BLOCK_FILTER傳送給驅動程式。在FltDevIoControl

函式,IP地址列表被複制到ADAPT結構中的FilterReserved域中。當資料包進行FltFilterXYZ函式時被檢查,然後提取包中源地址和目的地址。本示例中使用從FreeBSD 5.0拷貝過來的與網路的IP頭定義 。例如,程式引用/B2Winet/ip.h作為IP頭的定義。在同一個目錄,還有許多的包頭定義,為了能在WINDOWS環境中使用,標頭檔案被作了稍微的修改。如果你對其它的頭感興趣(如IPV6),你可以在網上下載相關的H檔案。

 

2.測試程式概述

要檢視在NDIS IM驅動程式上繫結的介面卡資訊,可以帶引數執行TestIOCTL程式:TestIOCTL /enum 你將會看類似以下的資訊:

         TestIOCTL /enum

 

You will see information similar to this example output:

 

PassThru User I/O Test Application

Copyright (c) 2003 Printing Communications Assoc., Inc. (PCAUSA)

All rights reserved.

Driver Bindings:

   "/Device/{B3B985AD-EB56-4F6A-8D16-131118E52131}"

      "/DEVICE/{9C9770B5-CFBC-41DF-BE1D-510CEC826190}"  <– Lower Adapter Name

      Description: " National Semiconductor Corp. DP83820 10/100/1000 GigPhyter PCI Adapter"

      Medium: 802.3

      Mac address = 00-40-F4-00-07-B5

      Media Connect Status: Connected

   "/Device/{03BB2564-4AA2-4E9B-B251-79D6A69B461F}"

      "/DEVICE/NDISWANIP"

      Description: " NdisWan Adapter"

      Medium: 802.3

      Mac address = A6-3E-20-52-41-53

      Media Connect Status: Connected

要設定過濾IP列表,這樣使用:TestIOCTL /set filename 檔案的格式如下所示。

 

 

#

# Sample IP Address Blocking List File

#

# Lines beginning with ‘#’ are comments. Leading and trailing whitespace

# is ignored. Empty lines are ignored.

#

# The first non-comment line must be the NDIS name of the lower adapter

# that the list of IP addresses to block is intended.

#

/Device/{B3B985AD-EB56-4F6A-8D16-131118E52131}

#

# Then comes the list of IP addresses to block. The IP addresses can

# have a comment, if desirable.

#

172.16.1.10

  192.168.2.1

    192.168.2.2    

 192.168.2.3   

172.16.100.5

192.168.2.4     ; Can have comments per IP address, if desirable…

 

如果要重置所有的介面卡到初始狀態,執行:TestIOCTL /setdflt

如果要檢視統計資訊:TestIOCTL /stats

 

3.編譯環境:

         測試程式是用visual Studio.net 編譯的,驅動程式是用XP DDK編譯的。用高版本的DDK也可編譯。

五.NDIS IM IP過濾驅動(James

 

1.驅動程式概述:

文章以Windows2003 Server DDKPassThru為起點,我們有意識地對程式作了一些改進,這些改動過的程式碼用以下這種形式來區分:

         // This is a comment. ja, 31 Oct 2003.

過濾程式碼主要放在新的核心模組檔案FilterRtns.cppUtilRtns.c and WMIRtns.cpp中,使用者程式的程式碼放在SetIPAddrArray.cppPassThruStats.cpp, SetSecurity.cpp and ReportError.cpp中。

 

注:FilterRtns.cpp and WMIRtns.cpp是一般的C 檔案(由副檔名可看出),但其中的實現卻是完全意義上的C語言。使用者應用程式是用真正的C 語言寫的,主要是因為作者有關於COM/DCOM/WMI APIs.的示例程式碼。

 

設定過濾器的值和提供資料統計這兩項功能是基於WMI的,你可以在miniport.c中看到相關的技術,而且集中在MPQueryInformation and MPSetInformation. 中。但是,注意,在miniport.c的開頭,有一個包括兩個PassThru支援的GUID。檢查資料包,在需要棄包以及持續記錄統計資訊主要是在MPSendPackets, PTReceive and PTReceivePacket 三個函式中完成。轉發或者丟棄資料包是在函式FilterPacket(在FilterRtns.cpp中定義)中決定的,這個函式由MPSendPackets, PTReceive and PTReceivePacket  函式呼叫。

 

FilterPacket 函式首先確定資料包是否IPV4資料包,接著找到一個過濾IP列表的拷貝,最後它地該列表進行二分搜尋,對於接收的包,如果它的源IP與過濾IP列表的IP匹配,對於傳送的包,如果它的目的IP與過濾IP列表的IP匹配,則丟棄。

 

為了得到與相關包相聯絡的介面卡上的IP過濾列表,FilterPacket 呼叫PassthruWMIGetAddrArray (WMIRtns.cpp中定義);為了設定列表,MPSetInformation 呼叫PassthruWMISetAddrArrayPassthruWMIGetAddrArray 會對過濾器上的ADAPT結構的一部分加一個讀鎖,PassthruWMISetAddrArray 會加一個更新鎖,因此,對一個介面卡來說IP地址列表一致性得到保證。

 

注意:在介面卡上的IP地址列表讀和更新操作不是序列化的,作者認為並不認為這有什麼意義。有可能在同一時刻,一個應用程式有兩個例項在執行,並且每一個例項可能更新所有介面卡,並且為每一個不同的介面卡指定不同的列表。但是,對於某一個介面卡來說,更新或者複製IP列表都是原語操作。

 

2.測試程式概述

 

1. SetIPAddrArray- 過濾控制程式

SetIPAddrArray是一個使用者態程式,用於獲取或設定過濾地址。PassThruStats獲取統計資訊(如接收到的包,丟棄的包等)。

對於設定過濾器,SetIPAddrArray使用嚴格的格式來讀取c:/Temp/passthru/AddrArray.txt檔案,第一行必須包含點式IP地址,並且地址必須為升序排列。通過編輯該檔案來輸入你想新增的IP地址。如果你想使你的改動對系統上所有的適配均有效,則需在命令視窗輸入:

         SetIPAddrArray set

如果你想看你當前系統上的活動IP過濾器,則輸入:

    SetIPAddrArray get

如果你想設定特定的介面卡資訊而不是其它的,則需拷貝你呼叫SetIPAddrArray get 時返回的資訊,並將此資訊用雙引號引起來提供給SetIPAddrArray。如:

    SetIPAddrArray set a="Linksys LNE100TX(v5) Fast Ethernet Adapter – Passthru Miniport"

當你再次呼叫SetIPAddrArray get時,你就會發現你所設的已在該介面卡上生效了。

如果你想重置所有的介面卡到沒有IP列表和過濾器狀態,執行:

    SetIPAddrArray setdflt

2. PassThruStats – 統計資訊檢視器

要得到統計資訊,使用以下的命令:

         PassThruStats get

這個命令會報告MPSendPackets, PTReceive and PTReceivePacket. 所接收和丟棄的包的數量。

SetIPAddrArray and PassThruStats均接收除動詞以外的其它引數。這些引數指定系統(當遠端呼叫時),Userid和密碼,對SetIPAddrArray還可以指定設定某一介面卡的名字。例如:

         PassThruStats get MyFavoriteSystem MyUserid MyPassword

像我們以前說明的,PerfMon and WbemTest會與PassThru一道工作,因為它使用WMI作為介面。使用者可以通過啟動PerfMon,右擊資料視窗,可以添中讀數器,選擇統計功能和其它一些待定的功能。

 

3WMI and MOF

 

WMIMOF才是問題的實質。對驅動程式,WMI迴圈出現在.MOF檔案中來描述資料。PassThru.Mof展示了怎樣設定由ULONG組成的變數。PassThru.mof檔案是PassThru_WMI.h檔案基礎,它會作為編譯驅動程式的一部分而建立。

 

PassThru.rc(驅動程式的資原始檔)指向PassThru.mof檔案。注意的是,MOF由操作符NdisMofResource指定,必須使用這個名字,而不是作為WDM驅動標準名字的MofResource

So far as this writer is aware, the need to employ this different form is nowhere documented.

 

使用者程式用類名(資源資訊)與MOF檔案中的值相對應。

 

4.編譯環境

 

可執行檔案驅動程式和兩個使用者程式是通過DDK編譯的,但值得注意的是,後兩程式的源程式引用了SDK檔案,所以得在源程式作相應的改變。如果你這樣做了,請確保你沒有使用含空格的路徑的名而是用標準的8.3檔名形式。這裡提供了VS6工程檔案,以便讀者有VS編譯使用者程式(User-Space Programs)。

 

 

原文版權:

Copyright ? 2003 Printing Communications Associates, Inc. (PCAUSA). All rights reserved.

PCAUSA does not grant the right to redistribute or publish this article without written permission

版權資訊:

         由於時間關係,關於版權的資訊就不再翻譯,本文的目的是為了方便廣大不習慣使用英文的驅動及NDIS愛好者學習和研究使用,請尊重作者的勞動成果。未經授權而在商業上使用原作者的文章屬侵權行為,後果由使用者自負,本人不承擔任何法律責任。

 

下載本文所提及的源程式:

http://www.wd-3.com/downloads/PassThru2.zip