LSP(계층형 서비스 제공자)

13147 단어
LSP 자체는 DLL로, 플러그인을 만드는 프로그램이 이 LSP의 어떤 정보도 알 필요가 없이 호출할 수 있도록 winsock 디렉터리에 설치할 수 있습니다.
작동 방법:
플러그인 생성 함수는 winsock 디렉터리에서 적합한 프로토콜을 찾을 것입니다
이 프로토콜을 호출하면 공급자가 내보낸 함수가 각종 기능을 완성합니다.
작성 목적:
사용자로 하여금 사용자 정의 서비스 제공자를 호출하게 하고 사용자 정의 서비스 제공자가 하위 공급자를 호출하게 한다.이렇게 하면 모든 winsock 호출을 캡처할 수 있습니다.
 
서비스 공급자 자체는 DLL이며 winsock API에 해당하는 SPI 함수를 내보냅니다.winsock 라이브러리에서 서비스 제공자를 불러올 때, 이 함수에 의존하여 winsock API를 실현합니다.
LSP도 마찬가지로, Ws2 에서 모든 SPI 함수를 위로 내보냅니다.32.dll 호출, 내부에서 기본 공급자를 호출하여 이러한 SPI를 실현한다.
LSP를 설치합니다.
LSP를 실현하기 전에, 층 공급자를 winsock 디렉터리에 설치하고, WSAPPROTOCOL을 포함하여 설치해야 한다.INFOW 구조는 계층 공급자의 특성과 LSP가 체인을 채우는 방식을 정의합니다.(프로토콜 포털이라고도 함)
 
프로토콜 체인:
프로토콜 체인은 층 공급자가 winsock에 가입하는 디렉터리의 순서를 설명합니다.
typedef struct _WSAPROTOCOLCHAIN{
  int ChainLen;
  DWORD ChainEntries[Max_PROTOCOL_CHAN];
}WSAPROTOCOLCHAIN,*LPWSAPROTOCOLCHAIN;

ChainLen은 0: 계층형 프로토콜은 1 기본 프로토콜이 1 프로토콜 체인보다 큽니다.
ChainLen이 0 또는 1일 경우 ChainEntries 배열은 의미가 없습니다.
1보다 크면 각 서비스 제공자의 디렉터리 ID가 배열에 포함됩니다.
 
LSP의 DLL을 다른 LSP에 로드하거나 WS232.DLL 로드위치에 따라 다릅니다.
만약 LSP가 프로토콜 체인의 맨 위에 있지 않으면, 체인의 맨 위에 있는 LSP에 의해 불러옵니다. 그렇지 않으면 WS232.DLL 로드
 
LSP를 설치할 때 winsock 디렉터리에 두 가지 프로토콜을 설치해야 합니다. 하나는 층 프로토콜이고 하나는 프로토콜 체인입니다.
층 프로토콜을 설치하는 것은 winsock 라이브러리에서 분배된 디렉터리 ID 번호를 얻기 위해 프로토콜 체인에 자신의 위치를 표시합니다.
프로토콜 체인이야말로 winsock 디렉터리에서 LSP의 진정한 입구이며, 연결에는 자신의 층 프로토콜의 디렉터리 ID 번호와 하위 공급자의 디렉터리 ID 번호가 포함되어 있다.
 
설치할 때, 먼저 층 프로토콜을 설치하고, 시스템이 이 층 프로토콜에 분배한 디렉터리 ID와 하위 공급자의 디렉터리 ID로ChainEntries 그룹을 구축하여 WSAPROTOCOLINFOW 구조를 만든 다음 이 프로토콜 체인을 설치합니다.
설치 함수:
LSP GUID DLL WSAPROTOCOL 제공INFOW 구조를 사용할 수 있습니다.
int WSCInstallProvider(
const LPGUID lpProviderId,
const LPWSTR lpszProviderDllPath,
const LPWSAPROTOCOL_INFOW lpProtocolInfoList,
DWORD dwNumberOfEntries,
LPINT lpErrno
);

모든 설치 공급자는 입구를 표시하기 위해 GUID를 필요로 합니다. GUID는 명령행 도구인 UUIDGEN이나 프로그래밍에서 UuidCreate 함수를 사용하여 생성할 수 있습니다.
LSP용 WSAPROTOCOLINFOW 구조는 보통 층을 나누려는 하위 공급자로부터 복사됩니다
1 szProtocol 도메인을 수정하여 새 공급자의 이름을 포함합니다.
2 XP1 이 포함된 경우IFS_HANDLES ID dwServiceFlags1 도메인에서 제거합니다.
 
WSCWriteProviderOrder 순서재정리
새로 설치된 LSP는 기본적으로 winsock 디렉터리의 끝에 설치되어 있으며, 시스템이 호출될 때 원래 호출된 LSP를 호출하기 때문에, 다시 정렬해야만 시스템이 새로 설치된 LSP로 호출될 수 있습니다.
요약:
1 계층형 프로토콜 포털을 설치하여 시스템에서 할당한 디렉토리 ID 번호를 가져옵니다.
2 하나 이상의 프로토콜 체인을 설치한다. 설치 수량은 층을 나누는 하위 프로토콜의 수량에 달려 있다.
3 디렉토리는 끝에서 정렬됩니다.
코드 예:
////////////////////////////////////////////////////////
// InstDemo.cpp

#include <Ws2spi.h>
#include <Sporder.h>                //    WSCWriteProviderOrder  

#include <windows.h>
#include <stdio.h>

#pragma comment(lib, "Ws2_32.lib")
#pragma comment(lib, "Rpcrt4.lib")    //    UuidCreate  


//     LSP    ,           
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       
int InstallProvider(WCHAR *wszDllPath)
{
    WCHAR wszLSPName[] = L"TinyLSP";    //    LSP   
    int nError = NO_ERROR;

    LPWSAPROTOCOL_INFOW pProtoInfo;
    int nProtocols;
    WSAPROTOCOL_INFOW UDPLayeredInfo, UDPChainInfo; //       UDP        
    DWORD dwUdpOrigCatalogId, dwLayeredCatalogId;

        //  Winsock        UDP       ,   LSP       
    //            
    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;  
            //        ID
            dwUdpOrigCatalogId = pProtoInfo[i].dwCatalogEntryId;
            break;
        }
    }  

        //         ,    Winsock      ID , dwLayeredCatalogId
    //          WSAPROTOCOL_INFOW    
    memcpy(&UDPLayeredInfo, &UDPChainInfo, sizeof(UDPLayeredInfo));
    //       ,  ,  PFL_HIDDEN  
    wcscpy(UDPLayeredInfo.szProtocol, wszLSPName);
    UDPLayeredInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL;        // LAYERED_PROTOCOL 0
    UDPLayeredInfo.dwProviderFlags |= PFL_HIDDEN;
    //   
    if(::WSCInstallProvider(&ProviderGuid, 
                    wszDllPath, &UDPLayeredInfo, 1, &nError) == SOCKET_ERROR)
        return nError;
    //       ,         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;
        }
    }

        //      
    //
    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 ++;
    //                  
    UDPChainInfo.ProtocolChain.ChainEntries[0] = dwLayeredCatalogId; 
    //     Guid,   
    GUID ProviderChainGuid;
    if(::UuidCreate(&ProviderChainGuid) == RPC_S_OK)
    {
        if(::WSCInstallProvider(&ProviderChainGuid, 
                    wszDllPath, &UDPChainInfo, 1, &nError) == SOCKET_ERROR)
                    return nError;
    }
    else
        return GetLastError();



        //     Winsock  ,         
    //          
    FreeProvider(pProtoInfo);
    pProtoInfo = GetProvider(&nProtocols);

    DWORD dwIds[20];
    int nIndex = 0;
    //         
    for(i=0; i<nProtocols; i++)
    {
        if((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&
                    (pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))
            dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;
    }
    //       
    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;

    //   Guid         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)
    {
        //      
        for(i=0; i<nProtocols; i++)
        {
            if((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&
                    (pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))
            {
                ::WSCDeinstallProvider(&pProtoInfo[i].ProviderId, &nError);
            }
        }
        //       
        ::WSCDeinstallProvider(&ProviderGuid, &nError);
    }
}



////////////////////////////////////////////////////

int binstall = 0;
void main()
{
    if(binstall)
    {
        if(InstallProvider(L"lsp.dll") == ERROR_SUCCESS)
        {
            printf(" Install successully 
"); } else { printf(" Install failed
"); } } else RemoveProvider(); }

좋은 웹페이지 즐겨찾기