LSP(分层服务提供者)
2019獨(dú)角獸企業(yè)重金招聘Python工程師標(biāo)準(zhǔn)>>>
LSP本身是DLL,可以將它安裝到winsock目錄,以便創(chuàng)建套接字的應(yīng)用程序不必知道此LSP的任何信息就能調(diào)用它。
運(yùn)行原理:
套接字創(chuàng)建函數(shù)會在winsock目錄中尋找合適的協(xié)議
調(diào)用此協(xié)議,的提供者導(dǎo)出的函數(shù) 完成各種功能。
編寫目的:
讓用戶調(diào)用自定義的服務(wù)提供者,有自定義的服務(wù)提供者調(diào)用下層提供者。這樣便截獲所有的winsock調(diào)用了。
?
服務(wù)提供者本身是DLL,導(dǎo)出一些與winsock API相對應(yīng)的SPI函數(shù)。winsock庫加載服務(wù)提供者時(shí),便依靠這些函數(shù)來實(shí)現(xiàn)winsockAPI。
LSP也是如此,它向上導(dǎo)出所有的SPI函數(shù)供 Ws2_32.dll調(diào)用,在內(nèi)部通過調(diào)用基礎(chǔ)提供者實(shí)現(xiàn)這些SPI。
安裝LSP:
實(shí)現(xiàn)LSP之前,要先將分層提供者安裝到winsock目錄,安裝包括一個(gè)WSAPPROTOCOL_INFOW結(jié)構(gòu),定義了分層提供者的特性和LSP填寫鏈的方式。(也叫做協(xié)議入口)
?
協(xié)議鏈:
協(xié)議鏈描述了 分層提供者 加入winsock的目錄的順序。
typedef struct _WSAPROTOCOLCHAIN{int ChainLen;DWORD ChainEntries[Max_PROTOCOL_CHAN]; }WSAPROTOCOLCHAIN,*LPWSAPROTOCOLCHAIN;ChainLen為0:分層協(xié)議 為1 基礎(chǔ)協(xié)議? 大于1 協(xié)議鏈
當(dāng)ChainLen為0或者1時(shí),ChainEntries數(shù)組無意義
大于1時(shí),各個(gè)服務(wù)提供者的目錄ID就包含在數(shù)組中。
?
實(shí)現(xiàn)LSP的DLL要么被另一個(gè)LSP加載,要么直接被WS2_32.DLL加載。取決于它的位置。
如果LSP沒有在協(xié)議鏈的頂端,就會被鏈中位于它上層的LSP加載,否則的話,將被WS2_32.DLL加載。
?
安裝LSP時(shí),必須在winsock目錄中安裝兩種協(xié)議:一個(gè)分層協(xié)議,一個(gè)協(xié)議鏈。
安裝分層協(xié)議視為了獲取winsock庫分配的目錄ID號,一邊在協(xié)議鏈中標(biāo)識自己的位置。
協(xié)議鏈才是winsock目錄中LSP的真正入口,連中包含了自己分層協(xié)議的目錄ID號和下層提供者的目錄ID號。
?
在安裝時(shí),要先安裝一個(gè)分層協(xié)議,用系統(tǒng)分配給此分層協(xié)議的目錄ID和下層提供者的目錄ID構(gòu)建一個(gè) ChainEntries數(shù)組,進(jìn)而構(gòu)建一個(gè)WSAPROTOCOL_INFOW結(jié)構(gòu),然后再安裝這個(gè)協(xié)議鏈。
安裝函數(shù):
提供LSP GUID DLL WSAPROTOCOL_INFOW結(jié)構(gòu)便可。
int WSCInstallProvider( const LPGUID lpProviderId, const LPWSTR lpszProviderDllPath, const LPWSAPROTOCOL_INFOW lpProtocolInfoList, DWORD dwNumberOfEntries, LPINT lpErrno );每一個(gè)安裝提供者需要一個(gè)GUID來標(biāo)識它的入口,GUID可以通過命令行工具UUIDGEN或者在編程使用UuidCreate函數(shù)來生成。
LSP的WSAPROTOCOL_INFOW結(jié)構(gòu)通常從它要分層的下層提供者拷貝
1 szProtocol域要修改,以包含新提供者的名稱
2 如果包含XP1_IFS_HANDLES標(biāo)識,要從dwServiceFlags1域移除。
?
重新目錄排序 WSCWriteProviderOrder
新安裝的LSP會默認(rèn)安裝到winsock目錄的結(jié)尾,這樣系統(tǒng)調(diào)用的時(shí)候,還是會調(diào)用原先調(diào)用的LSP,因此只有進(jìn)行重新的排序才能讓系統(tǒng)調(diào)用到新安裝的LSP。
總結(jié):
1 安裝分層協(xié)議入口,以便獲取系統(tǒng)分配的目錄ID號。
2 安裝一個(gè)或者多個(gè)協(xié)議鏈,安裝的數(shù)量取決于要分層的下層協(xié)議的數(shù)量。
3 在結(jié)尾進(jìn)行目錄排序。
示例代碼:
//// // InstDemo.cpp #include <Ws2spi.h> #include <Sporder.h> // 定義了WSCWriteProviderOrder函數(shù) #include <windows.h> #include <stdio.h>#pragma comment(lib, "Ws2_32.lib") #pragma comment(lib, "Rpcrt4.lib") // 實(shí)現(xiàn)了UuidCreate函數(shù)// 要安裝的LSP的硬編碼,在移除的時(shí)候還要使用它 GUID ProviderGuid = {0xd3c21122, 0x85e1, 0x48f3, {0x9a,0xb6,0x23,0xd9,0x0c,0x73,0x07,0xef}};LPWSAPROTOCOL_INFOW GetProvider(LPINT lpnTotalProtocols) {DWORD dwSize = 0;int nError;LPWSAPROTOCOL_INFOW pProtoInfo = NULL;// 取得需要的長度if(::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError) == SOCKET_ERROR){if(nError != WSAENOBUFS)return NULL;}pProtoInfo = (LPWSAPROTOCOL_INFOW)::GlobalAlloc(GPTR, dwSize);*lpnTotalProtocols = ::WSCEnumProtocols(NULL, pProtoInfo, &dwSize, &nError);return pProtoInfo; }void FreeProvider(LPWSAPROTOCOL_INFOW pProtoInfo) {::GlobalFree(pProtoInfo); }// 將LSP安裝到UDP協(xié)議提供者之上 int InstallProvider(WCHAR *wszDllPath) {WCHAR wszLSPName[] = L"TinyLSP"; // 我們的LSP的名稱int nError = NO_ERROR;LPWSAPROTOCOL_INFOW pProtoInfo;int nProtocols;WSAPROTOCOL_INFOW UDPLayeredInfo, UDPChainInfo; // 我們要安裝的UDP分層協(xié)議和協(xié)議鏈 DWORD dwUdpOrigCatalogId, dwLayeredCatalogId;// 在Winsock目錄中找到原來的UDP協(xié)議服務(wù)提供者,我們的LSP要安裝在它之上// 枚舉所有服務(wù)程序提供者pProtoInfo = GetProvider(&nProtocols);for(int i=0; i<nProtocols; i++){if(pProtoInfo[i].iAddressFamily == AF_INET && pProtoInfo[i].iProtocol == IPPROTO_UDP){memcpy(&UDPChainInfo, &pProtoInfo[i], sizeof(UDPLayeredInfo));// UDPChainInfo.dwServiceFlags1 = UDPChainInfo.dwServiceFlags1 & ~XP1_IFS_HANDLES; // 保存原來的入口IDdwUdpOrigCatalogId = pProtoInfo[i].dwCatalogEntryId;break;}} // 首先安裝分層協(xié)議,獲取一個(gè)Winsock庫安排的目錄ID號,即dwLayeredCatalogId// 直接使用下層協(xié)議的WSAPROTOCOL_INFOW結(jié)構(gòu)即可memcpy(&UDPLayeredInfo, &UDPChainInfo, sizeof(UDPLayeredInfo));// 修改協(xié)議名稱,類型,設(shè)置PFL_HIDDEN標(biāo)志 wcscpy(UDPLayeredInfo.szProtocol, wszLSPName);UDPLayeredInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL; // LAYERED_PROTOCOL即0UDPLayeredInfo.dwProviderFlags |= PFL_HIDDEN;// 安裝if(::WSCInstallProvider(&ProviderGuid, wszDllPath, &UDPLayeredInfo, 1, &nError) == SOCKET_ERROR)return nError;// 重新枚舉協(xié)議,獲取分層協(xié)議的目錄ID號 FreeProvider(pProtoInfo);pProtoInfo = GetProvider(&nProtocols);for(i=0; i<nProtocols; i++){if(memcmp(&pProtoInfo[i].ProviderId, &ProviderGuid, sizeof(ProviderGuid)) == 0){dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;break;}}// 安裝協(xié)議鏈// 修改協(xié)議名稱,類型WCHAR wszChainName[WSAPROTOCOL_LEN + 1];swprintf(wszChainName, L"%ws over %ws", wszLSPName, UDPChainInfo.szProtocol);wcscpy(UDPChainInfo.szProtocol, wszChainName);if(UDPChainInfo.ProtocolChain.ChainLen == 1){UDPChainInfo.ProtocolChain.ChainEntries[1] = dwUdpOrigCatalogId;}else{for(i=UDPChainInfo.ProtocolChain.ChainLen; i>0 ; i--){UDPChainInfo.ProtocolChain.ChainEntries[i] = UDPChainInfo.ProtocolChain.ChainEntries[i-1];}}UDPChainInfo.ProtocolChain.ChainLen ++;// 將我們的分層協(xié)議置于此協(xié)議鏈的頂層UDPChainInfo.ProtocolChain.ChainEntries[0] = dwLayeredCatalogId; // 獲取一個(gè)Guid,安裝之 GUID ProviderChainGuid;if(::UuidCreate(&ProviderChainGuid) == RPC_S_OK){if(::WSCInstallProvider(&ProviderChainGuid, wszDllPath, &UDPChainInfo, 1, &nError) == SOCKET_ERROR)return nError;}elsereturn GetLastError();// 重新排序Winsock目錄,將我們的協(xié)議鏈提前// 重新枚舉安裝的協(xié)議 FreeProvider(pProtoInfo);pProtoInfo = GetProvider(&nProtocols);DWORD dwIds[20];int nIndex = 0;// 添加我們的協(xié)議鏈for(i=0; i<nProtocols; i++){if((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&(pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;}// 添加其它協(xié)議for(i=0; i<nProtocols; i++){if((pProtoInfo[i].ProtocolChain.ChainLen <= 1) ||(pProtoInfo[i].ProtocolChain.ChainEntries[0] != dwLayeredCatalogId))dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;}// 重新排序Winsock目錄nError = ::WSCWriteProviderOrder(dwIds, nIndex);FreeProvider(pProtoInfo);return nError; }void RemoveProvider() { LPWSAPROTOCOL_INFOW pProtoInfo;int nProtocols;DWORD dwLayeredCatalogId;// 根據(jù)Guid取得分層協(xié)議的目錄ID號pProtoInfo = GetProvider(&nProtocols);int nError;for(int i=0; i<nProtocols; i++){if(memcmp(&ProviderGuid, &pProtoInfo[i].ProviderId, sizeof(ProviderGuid)) == 0){dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;break;}}if(i < nProtocols){// 移除協(xié)議鏈for(i=0; i<nProtocols; i++){if((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&(pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId)){::WSCDeinstallProvider(&pProtoInfo[i].ProviderId, &nError);}}// 移除分層協(xié)議::WSCDeinstallProvider(&ProviderGuid, &nError);} }////int binstall = 0; void main() {if(binstall){if(InstallProvider(L"lsp.dll") == ERROR_SUCCESS){printf(" Install successully \n");}else{printf(" Install failed \n");}}elseRemoveProvider(); }轉(zhuǎn)載于:https://my.oschina.net/u/204616/blog/545523
總結(jié)
以上是生活随笔為你收集整理的LSP(分层服务提供者)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql实战17 | 如何正确地显示随
- 下一篇: Elasticsearch聚合 之 Da