編者按:與傳統(tǒng)的包過(guò)濾防火墻技術(shù)不同,本文從應(yīng)用層網(wǎng)關(guān)技術(shù)入手,深入探討了利用WinSock2 SPI進(jìn)行網(wǎng)絡(luò)內(nèi)容訪問(wèn)控制的問(wèn)題。這是網(wǎng)絡(luò)安全的一項(xiàng)新內(nèi)容,或者說(shuō),它為網(wǎng)絡(luò)安全技術(shù)的愛(ài)好者和研發(fā)人員提供了一個(gè)新的思路。
防火墻可以實(shí)施和執(zhí)行網(wǎng)絡(luò)訪問(wèn)策略,但是,傳統(tǒng)的防火墻技術(shù)集中于如何防范外部網(wǎng)絡(luò)對(duì)內(nèi)部網(wǎng)絡(luò)的入侵和攻擊上,而對(duì)于如何控制內(nèi)部用戶(hù)對(duì)外部網(wǎng)絡(luò)的訪問(wèn)
問(wèn)題研究不夠深入,相關(guān)的控制技術(shù)也不多。據(jù)權(quán)威資料顯示,全球現(xiàn)有大約25萬(wàn)色情網(wǎng)站,單純依靠傳統(tǒng)的包過(guò)濾等防火墻技術(shù),勢(shì)必會(huì)嚴(yán)重影響網(wǎng)絡(luò)性能。針
對(duì)這一問(wèn)題,我們從應(yīng)用層網(wǎng)關(guān)技術(shù)入手,利用WinSock2 SPI技術(shù),進(jìn)行了研究和探討。

Winsock2 SPI原理圖
Winsock2
SPI(Service Provider Interface)服務(wù)提供者接口建立在Windows開(kāi)放系統(tǒng)架構(gòu)WOSA(Windows Open
System
Architecture)之上,是Winsock系統(tǒng)組件提供的面向系統(tǒng)底層的編程接口。Winsock系統(tǒng)組件向上面向用戶(hù)應(yīng)用程序提供一個(gè)標(biāo)準(zhǔn)的
API接口;向下在Winsock組件和Winsock服務(wù)提供者(比如TCP/IP協(xié)議棧)之間提供一個(gè)標(biāo)準(zhǔn)的SPI接口。各種服務(wù)提供者是
Windows支持的DLL,掛靠在Winsock2 的Ws2_32.dll模塊下。
對(duì)用戶(hù)應(yīng)用程序使用的Winsock2
API中定義的許多內(nèi)部函數(shù)來(lái)說(shuō),這些服務(wù)提供者都提供了它們的對(duì)應(yīng)的運(yùn)作方式(例如API函數(shù)WSAConnect有相應(yīng)的SPI函數(shù)
WSPConnect)。多數(shù)情況下,一個(gè)應(yīng)用程序在調(diào)用Winsock2 API函數(shù)時(shí),Ws2_32.dll會(huì)調(diào)用相應(yīng)的Winsock2
SPI函數(shù),利用特定的服務(wù)提供者執(zhí)行所請(qǐng)求的服務(wù)。
Winsock2
SPI允許開(kāi)發(fā)兩類(lèi)服務(wù)提供者——傳輸服務(wù)提供者和名字空間服務(wù)提供者。“傳輸提供者”(Transport Providers,
一般稱(chēng)作協(xié)議堆棧,例如TCP/IP)能夠提供建立通信、傳輸數(shù)據(jù)、日常數(shù)據(jù)流控制和錯(cuò)誤控制等傳輸功能方面的服務(wù)。“名字空間提供者”(Name
Space
Providers,例如DNS名字解析服務(wù))則把一個(gè)網(wǎng)絡(luò)協(xié)議的地址屬性和一個(gè)或多個(gè)用戶(hù)友好名稱(chēng)關(guān)聯(lián)到一起,以便啟用與應(yīng)用無(wú)關(guān)的名字解析方案。
Winsock2
中使用的傳輸服務(wù)提供者有兩類(lèi):基礎(chǔ)服務(wù)提供者和分層服務(wù)提供者。基礎(chǔ)服務(wù)提供者執(zhí)行網(wǎng)絡(luò)傳輸協(xié)議(比如TCP/IP)的具體細(xì)節(jié),其中包括在網(wǎng)絡(luò)上收發(fā)
數(shù)據(jù)之類(lèi)的核心網(wǎng)絡(luò)協(xié)議功能。“分層式”(Layered)服務(wù)提供者只負(fù)責(zé)執(zhí)行高級(jí)的自定義通信功能,并依靠下面的基礎(chǔ)服務(wù)提供者,在網(wǎng)絡(luò)上進(jìn)行真正的
數(shù)據(jù)交換。
為了進(jìn)行內(nèi)部用戶(hù)對(duì)外訪問(wèn)控制,我們需要在現(xiàn)有的基礎(chǔ)提供者TCP/IP提供者上設(shè)立一個(gè)分層式的URL過(guò)濾管理者。通過(guò)
URL過(guò)濾管理者我們可以截獲用戶(hù)請(qǐng)求的HTTP數(shù)據(jù)包中的URL地址,繼而可以通過(guò)高效的數(shù)據(jù)檢索算法(如利用Fibonacci散列函數(shù)的哈希表),
在訪問(wèn)規(guī)則庫(kù)(被禁止訪問(wèn)的IP集合)中查找指定的IP,根據(jù)結(jié)果拒絕或提供訪問(wèn)服務(wù)。
傳輸服務(wù)提供者的安裝方式?jīng)Q定了它不僅是
一個(gè)分層提供者,還是一個(gè)基礎(chǔ)服務(wù)提供者。Winsock
2使用系統(tǒng)配置數(shù)據(jù)庫(kù)配置傳輸服務(wù)提供者。配置數(shù)據(jù)庫(kù)讓W(xué)insock2得知服務(wù)提供者的存在,并定義了提供的服務(wù)類(lèi)型。要在Winsock2服務(wù)提供者
數(shù)據(jù)庫(kù)內(nèi)成功安裝和管理服務(wù)提供者,需要四個(gè)函數(shù):WSCEnumProtocols、WSCInstallProvider、
WSCWriteProvider Order、WSCDeInstallProvider。
這些函數(shù)利用WSAPROTOCOL_INFOW結(jié)構(gòu),對(duì)服務(wù)提供者數(shù)據(jù)庫(kù)進(jìn)行查詢(xún)和操作。要安裝分層式服務(wù)提供者,需要建立兩個(gè)
WSPPROTOCOL_INFOW目錄條目結(jié)構(gòu)。一個(gè)代表分層提供者(協(xié)議鏈長(zhǎng)度等于0),另一個(gè)將代表一個(gè)協(xié)議鏈(協(xié)議長(zhǎng)度大于1),該協(xié)議鏈把分層
提供者與一個(gè)基礎(chǔ)服務(wù)提供者鏈接起來(lái)。應(yīng)該使用現(xiàn)有服務(wù)提供者的WSAPROTOCOL_INFOW目錄條目結(jié)構(gòu)的屬性來(lái)初始化這兩個(gè)結(jié)構(gòu)。
調(diào)用WSCEnumProtocols可以獲得已有的服務(wù)提供者的WSAPROTOCOL_INFOW目錄條目結(jié)構(gòu)。初始化之后,首先需要使用
WSCInstallProvider來(lái)安裝我們的訪問(wèn)控制分層服務(wù)提供者目錄條目,然后,利用WSCEnumProtocols列舉出所有的目錄條目,
獲得安裝之后為這個(gè)結(jié)構(gòu)分配的目錄ID。然后,用這個(gè)目錄條目來(lái)設(shè)置一個(gè)協(xié)議鏈目錄條目,通過(guò)它,將我們的訪問(wèn)控制服務(wù)提供者和另一個(gè)提供者(TCP基礎(chǔ)
提供者)鏈接起來(lái)。然后再次調(diào)用WSCInstallProvider來(lái)安裝我們的分層鏈?zhǔn)椒?wù)提供者。
在用
WSCInstallProvider安裝一個(gè)服務(wù)提供者時(shí),目錄條目自動(dòng)成為配置數(shù)據(jù)庫(kù)中的最后一個(gè)條目。要實(shí)現(xiàn)訪問(wèn)控制就必須使我們的URL過(guò)濾服務(wù)
提供者成為默認(rèn)的TCP/IP提供者,必須通過(guò)調(diào)用WSCWriteProviderOrder函數(shù)來(lái)完成此項(xiàng)工作,對(duì)數(shù)據(jù)庫(kù)中提供者目錄條目進(jìn)行重新排
序,并把協(xié)議鏈目錄條目放在TCP/IP基礎(chǔ)提供者之前。
Winsock2傳輸服務(wù)提供者隨標(biāo)準(zhǔn)的Windows動(dòng)態(tài)鏈接庫(kù)模塊
一起執(zhí)行。我們必須在我們的服務(wù)提供者動(dòng)態(tài)鏈接庫(kù)模塊中導(dǎo)入DLLMain函數(shù),同時(shí)還必須導(dǎo)入一個(gè)名為WSPStartup的單一函數(shù)條目。我們的
URL過(guò)濾服務(wù)提供者必須提供對(duì)WSPStartup函數(shù)和其他30個(gè)SPI函數(shù)的支持。調(diào)用WSAStartup期間,Winsock根據(jù)
WSASocket調(diào)用的地址家族、套接字類(lèi)型和協(xié)議參數(shù),來(lái)決定需要加載哪個(gè)服務(wù)提供者。只有在一個(gè)應(yīng)用程序通過(guò)socket或WSASocket
API調(diào)用建立一個(gè)采用地址家族AF_INET、套接字類(lèi)型為SOCK_STREAM的套接字時(shí),Winsock才會(huì)搜索并加載與之相應(yīng)的、能夠提供
TCP/IP能力的傳輸服務(wù)提供者。WSPStartup的參數(shù)UpcallTable取得Ws2_32.dll的SPI函數(shù)派遣表,我們的訪問(wèn)控制分層
服務(wù)提供者利用這些函數(shù)來(lái)管理自身和Winsock2之間的I/O操作。
我們利用WSPConnect函數(shù)來(lái)實(shí)現(xiàn)訪問(wèn)控制功能。
在用戶(hù)請(qǐng)求HTTP服務(wù)時(shí),需要首先建立與目標(biāo)站點(diǎn)的連接,連接成功后,在此連接基礎(chǔ)上發(fā)送HTTP請(qǐng)求數(shù)據(jù)包。用戶(hù)應(yīng)用程序調(diào)用connect或
WSAConnect函數(shù)建立連接時(shí),SPI會(huì)調(diào)用對(duì)應(yīng)的WSPConnect函數(shù):INT WSPAPI WSPConnect(...,const
struct sockaddr FAR *name,...,INT FAR
*lpErrno)。在sockaddr類(lèi)型的參數(shù)name中包含了用戶(hù)將要訪問(wèn)的目標(biāo)站點(diǎn)的IP地址信息。我們將name參數(shù)傳遞到IP可訪問(wèn)性判定例
程IPFilter。如果IPFilter函數(shù)返回代表授權(quán)訪問(wèn)的結(jié)果,我們采用協(xié)議鏈命令路由,調(diào)用下一層的基礎(chǔ)服務(wù)提供者(TCP/IP)來(lái)完成連接
請(qǐng)求。如果IPFilter函數(shù)返回代表拒絕服務(wù)的結(jié)果,我們?cè)O(shè)置lpErrno參數(shù)為相應(yīng)的錯(cuò)誤碼,然后返回,不進(jìn)行協(xié)議鏈下一層服務(wù)提供者的調(diào)用,從
而實(shí)現(xiàn)訪問(wèn)控制。
分層式服務(wù)提供者大大發(fā)揮了聯(lián)網(wǎng)服務(wù)的潛能,增強(qiáng)了Winsock的應(yīng)用,在我們的URL過(guò)濾服務(wù)中發(fā)揮了巨大的作用,基本實(shí)現(xiàn)了對(duì)內(nèi)部用戶(hù)訪問(wèn)外部網(wǎng)絡(luò)的訪問(wèn)控制,為用戶(hù)提供了對(duì)互聯(lián)網(wǎng)的健康性的訪問(wèn)服務(wù)。
(e129)