利用SPI编写类似sockscap的代理工具

转自:http://www.cnblogs.com/tanweizlf/archive/2012/06/24/2559733.html

http://bbs.125.la/forum.php?mod=viewthread&tid=13770094&highlight=lsp

利用SPI编写类似sockscap的代理工具

最近帮一个朋友实现sockscap的socks V5代理功能,sockscap貌似是通过API HOOK实现,一开始我便尝试这种方式,遇到各种麻烦的问题,还是用SPI的LSP来试试吧。

SPI的出现其实就是微软为了方便程序员对网络API的各种HOOK,从而省去一些麻烦,然而相对的也会增加不少问题。对于SPI中的LSP这种分层的结构,可以很好的使用强盗手法将自己当作老大放在最上层,但是,如果有其他程序也使用同样的手法,那么就会产生冲突了。

好吧进入正题。。。

一、LSP的安装,先抛开socks代理不说

1、构造自己的LSP,并安装之;

2、遍历已有 服务提供者,找到刚安装的LSP入口ID;

3、构造自己的协议链,并安装之;

4、对所有协议链进行排序,并将我们的协议链放到最上面。

二、LSP的编写

主要操作都在WSPStartup中,其他WSP函数就是对原函数的HOOK,详情看下面代码。

MSDN有完整LSP代码的下载:

ftp://ftp.microsoft.com/bussys/WinSock/winsock2/layered.zip

同时,网上也有一些源代码,与MSDN代码相比,基本一样,只是在LSP安装的第一步有所不同,MSDN代码是手工构造LSP,而网上许多代码都是通过拷贝系统已有LSP进行对自己的LSP构造。

下面代码来自网上:


INST_LSP.Cpp

复制代码
#define UNICODE
#define _UNICODE
#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);
}
BOOL InstallProvider(WCHAR *pwszPathName)
{
    WCHAR wszLSPName[] = L"ZetsinLSP";
    LPWSAPROTOCOL_INFOW pProtoInfo;
    int nProtocols;
    WSAPROTOCOL_INFOW OriginalProtocolInfo[3];
    DWORD dwOrigCatalogId[3];
    int nArrayCount = 0;
    DWORD dwLayeredCatalogId; // 我们分层协议的目录ID号
    int nError;

// 找到我们的下层协议,将信息放入数组中
// 枚举所有服务程序提供者
    pProtoInfo = GetProvider(&nProtocols);
    BOOL bFindUdp = FALSE;
    BOOL bFindTcp = FALSE;
    BOOL bFindRaw = FALSE;
    for (int i=0; i<nProtocols; i++)
    {
        if (pProtoInfo[i].iAddressFamily == AF_INET)
        {
            if (!bFindUdp && pProtoInfo[i].iProtocol == IPPROTO_UDP)
            {
                memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
                OriginalProtocolInfo[nArrayCount].dwServiceFlags1 =
                    OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES);

                dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
                bFindUdp = TRUE;
            }
            if (!bFindTcp && pProtoInfo[i].iProtocol == IPPROTO_TCP)
            {
                memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
                OriginalProtocolInfo[nArrayCount].dwServiceFlags1 =
                    OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES);

                dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
                bFindTcp = TRUE;
            }
            if (!bFindRaw && pProtoInfo[i].iProtocol == IPPROTO_IP)
            {
                memcpy(&OriginalProtocolInfo[nArrayCount], &pProtoInfo[i], sizeof(WSAPROTOCOL_INFOW));
                OriginalProtocolInfo[nArrayCount].dwServiceFlags1 =
                    OriginalProtocolInfo[nArrayCount].dwServiceFlags1 & (~XP1_IFS_HANDLES);

                dwOrigCatalogId[nArrayCount++] = pProtoInfo[i].dwCatalogEntryId;
                bFindRaw = TRUE;
            }
        }
    }
// 安装我们的分层协议,获取一个dwLayeredCatalogId
// 随便找一个下层协议的结构复制过来即可
    WSAPROTOCOL_INFOW LayeredProtocolInfo;
    memcpy(&LayeredProtocolInfo, &OriginalProtocolInfo[0], sizeof(WSAPROTOCOL_INFOW));
// 修改协议名称,类型,设置PFL_HIDDEN标志
    wcscpy_s(LayeredProtocolInfo.szProtocol, wszLSPName);
    LayeredProtocolInfo.ProtocolChain.ChainLen = LAYERED_PROTOCOL; // 0;
    LayeredProtocolInfo.dwProviderFlags |= PFL_HIDDEN;
// 安装
    if (::WSCInstallProvider(&ProviderGuid,
                             pwszPathName, &LayeredProtocolInfo, 1, &nError) == SOCKET_ERROR)
    {
        printf("%d", nError);
        return FALSE;
    }
// 重新枚举协议,获取分层协议的目录ID号
    FreeProvider(pProtoInfo);
    pProtoInfo = GetProvider(&nProtocols);
    for (int i=0; i<nProtocols; i++)
    {
        if (memcmp(&pProtoInfo[i].ProviderId, &ProviderGuid, sizeof(ProviderGuid)) == 0)
        {
            dwLayeredCatalogId = pProtoInfo[i].dwCatalogEntryId;
            break;
        }
    }
// 安装协议链
// 修改协议名称,类型
    WCHAR wszChainName[WSAPROTOCOL_LEN + 1];
    for (int i=0; i<nArrayCount; i++)
    {
        swprintf(wszChainName, L"%ws over %ws", wszLSPName, OriginalProtocolInfo[i].szProtocol);
        wcscpy_s(OriginalProtocolInfo[i].szProtocol, wszChainName);
        if (OriginalProtocolInfo[i].ProtocolChain.ChainLen == 1)
        {
            OriginalProtocolInfo[i].ProtocolChain.ChainEntries[1] = dwOrigCatalogId[i];
        }
        else
        {
            for (int j = OriginalProtocolInfo[i].ProtocolChain.ChainLen; j>0; j--)
            {
                OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j]
                = OriginalProtocolInfo[i].ProtocolChain.ChainEntries[j-1];
            }
        }
        OriginalProtocolInfo[i].ProtocolChain.ChainLen ++;
        OriginalProtocolInfo[i].ProtocolChain.ChainEntries[0] = dwLayeredCatalogId;
    }
// 获取一个Guid,安装之
    GUID ProviderChainGuid;
    if (::UuidCreate(&ProviderChainGuid) == RPC_S_OK)
    {
        if (::WSCInstallProvider(&ProviderChainGuid,
                                 pwszPathName, OriginalProtocolInfo, nArrayCount, &nError) == SOCKET_ERROR)
        {
            return FALSE;
        }
    }
    else
        return FALSE;
// 重新排序Winsock目录,将我们的协议链提前
// 重新枚举安装的协议
    FreeProvider(pProtoInfo);
    pProtoInfo = GetProvider(&nProtocols);
    PDWORD dwIds = (PDWORD)malloc(sizeof(DWORD) * nProtocols);
    int nIndex = 0;
// 添加我们的协议链
    for (int i=0; i<nProtocols; i++)
    {
        if ((pProtoInfo[i].ProtocolChain.ChainLen > 1) &&
                (pProtoInfo[i].ProtocolChain.ChainEntries[0] == dwLayeredCatalogId))
            dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;
    }
// 添加其它协议
    for (int i=0; i<nProtocols; i++)
    {
        if ((pProtoInfo[i].ProtocolChain.ChainLen <= 1) ||
                (pProtoInfo[i].ProtocolChain.ChainEntries[0] != dwLayeredCatalogId))
            dwIds[nIndex++] = pProtoInfo[i].dwCatalogEntryId;
    }
// 重新排序Winsock目录
    if ((nError = ::WSCWriteProviderOrder(dwIds, nIndex)) != ERROR_SUCCESS)
    {
        return FALSE;
    }
    FreeProvider(pProtoInfo);
    return TRUE;
}
BOOL RemoveProvider()
{
    LPWSAPROTOCOL_INFOW pProtoInfo;
    int nProtocols;
    DWORD dwLayeredCatalogId;
// 根据Guid取得分层协议的目录ID号
    pProtoInfo = GetProvider(&nProtocols);
    int nError;
    int i;
    for (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);
    }
    else return FALSE;
    return TRUE;
}
void main(int argc, char *argv[])
{
    char *ptr;
//if(argc==2)
    {
        ptr = argv[1];
        while (*ptr)
            *ptr++ = tolower(*ptr);
        int test;
        scanf("%d", &test);
        if (test == 1)
//if(strcmp(argv[1], "-install")==0)
        {
            TCHAR szPathName[256];
            TCHAR* p;
            if (::GetFullPathName(L"LSP.dll", 256, szPathName, &p) != 0)
            {
                if (InstallProvider(szPathName))
                {
                    printf(" Install successully. /n");
                    return;
                }
            }
            printf(" Install failed. /n");
            return;
        }
        else
//else if(strcmp(argv[1],"-remove")==0)
        {
            if (RemoveProvider())
                printf(" Deinstall successully. /n");
            else
                printf(" Deinstall failed. /n");
            return;
        }
    }

    printf(" Usage: Instlsp [ -install │ -remove ] /n");
}
复制代码

LSP.Cpp

复制代码
#define UNICODE
#define _UNICODE
#include <ws2spi.h>
#include <errno.h>
#include <fstream>
#pragma comment(lib,"Ws2_32.lib")
GUID filterguid = {0xd3c21122, 0x85e1, 0x48f3,
                   {0x9a,0xb6,0x23,0xd9,0x0c,0x73,0x07,0xef}
                  };
LPWSAPROTOCOL_INFOW ProtoInfo=NULL;
WSPPROC_TABLE NextProcTable;
DWORD ProtoInfoSize=0;
int TotalProtos=0;
// 输出函数
int PutDbgStr(LPCTSTR lpFmt, ...)
{
    TCHAR Msg[1024];
    int len=wvsprintf(Msg,lpFmt,va_list(1+&lpFmt));
    OutputDebugString(Msg);
    return len;
}
// 获取各种值
BOOL GetLSP()
{
    int errorcode;
    ProtoInfo=NULL;
    ProtoInfoSize=0;
    TotalProtos=0;
    if (WSCEnumProtocols(NULL,ProtoInfo,&ProtoInfoSize,&errorcode)==SOCKET_ERROR)
    {
        if (errorcode!=WSAENOBUFS)
        {
            PutDbgStr(L"First WSCEnumProtocols Error!");
            return FALSE;
        }
    }
    if ((ProtoInfo=(LPWSAPROTOCOL_INFOW)GlobalAlloc(GPTR,ProtoInfoSize))==NULL)
    {
        PutDbgStr(L"GlobalAlloc Error!");
        return FALSE;
    }
    if ((TotalProtos=WSCEnumProtocols(NULL,ProtoInfo,&ProtoInfoSize,&errorcode))==SOCKET_ERROR)
    {
        PutDbgStr(L"Second WSCEnumProtocols Error!");
        return FALSE;
    }
    return TRUE;
}
// 释放内存
void FreeLSP()
{
    GlobalFree(ProtoInfo);
}
// DLL入口函数
BOOL WINAPI DllMain(HINSTANCE hmodule,
                    DWORD reason,
                    LPVOID lpreserved)
{
    TCHAR processname[MAX_PATH];
    if (reason==DLL_PROCESS_ATTACH)
    {
        GetModuleFileName(NULL,processname,MAX_PATH);
        PutDbgStr(L"%s Loading IPFilter ...", processname);
    }
    return TRUE;
}
/********************************* 改写WSP函数,只有WSPConnect被改写成调用socksProxy函数,其它的直接调用下层WSP函数 ****************************************/
//WSPConnect
int WSPAPI WSPConnect(
    SOCKET s,
    const struct sockaddr *name,
    int namelen,
    LPWSABUF lpCallerData,
    LPWSABUF lpCalleeData,
    LPQOS lpSQOS,
    LPQOS lpGQOS,
    LPINT lpErrno)
{
    return NextProcTable.lpWSPConnect(s, name, namelen, lpCallerData, lpCalleeData, lpSQOS, lpGQOS, lpErrno);
}
}
//WSPSocket
SOCKET WINAPI WSPSocket(
    __in int af,
    __in int type,
    __in int protocol,
    __in LPWSAPROTOCOL_INFO lpProtocolInfo,
    __in GROUP g,
    DWORD dwFlags,
    __out LPINT lpErrno
)
{
    PutDbgStr(L"WSPSocket");
    return NextProcTable.lpWSPSocket(af, type, protocol, lpProtocolInfo, g, dwFlags, lpErrno);
}
//WSPBind
int WINAPI WSPBind(
    __in SOCKET s,
    __in const struct sockaddr *name,
    __in int namelen,
    __out LPINT lpErrno
)
{
    PutDbgStr(L"WSPBind");
    return NextProcTable.lpWSPBind(s, name, namelen, lpErrno);
}
//WSPSend
int WINAPI WSPSend(
    __in SOCKET s,
    __in LPWSABUF lpBuffers,
    __in DWORD dwBufferCount,
    __out LPDWORD lpNumberOfBytesSent,
    __in DWORD dwFlags,
    __in LPWSAOVERLAPPED lpOverlapped,
    __in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
    __in LPWSATHREADID lpThreadId,
    __out LPINT lpErrno
)
{
    PutDbgStr(L"WSPSend");
    return NextProcTable.lpWSPSend(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);
}
//WSPSendTo
int WINAPI WSPSendTo(
    __in SOCKET s,
    __in LPWSABUF lpBuffers,
    __in DWORD dwBufferCount,
    __out LPDWORD lpNumberOfBytesSent,
    __in DWORD dwFlags,
    __in const struct sockaddr *lpTo,
    __in int iTolen,
    __in LPWSAOVERLAPPED lpOverlapped,
    __in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
    __in LPWSATHREADID lpThreadId,
    __out LPINT lpErrno
)
{
    PutDbgStr(L"WSPSendTo");
    return NextProcTable.lpWSPSendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);
}
//WSPRecv
int WINAPI WSPRecv(
    __in SOCKET s,
    __inout LPWSABUF lpBuffers,
    __in DWORD dwBufferCount,
    __out LPDWORD lpNumberOfBytesRecvd,
    __inout LPDWORD lpFlags,
    __in LPWSAOVERLAPPED lpOverlapped,
    __in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
    __in LPWSATHREADID lpThreadId,
    __out LPINT lpErrno
)
{
    PutDbgStr(L"WSPRecv");
    return NextProcTable.lpWSPRecv(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);
}
//WSPRecvFrom
int WINAPI WSPRecvFrom(
    __in SOCKET s,
    __inout LPWSABUF lpBuffers,
    __in DWORD dwBufferCount,
    __out LPDWORD lpNumberOfBytesRecvd,
    __inout LPDWORD lpFlags,
    __out struct sockaddr *lpFrom,
    __inout LPINT lpFromlen,
    __in LPWSAOVERLAPPED lpOverlapped,
    __in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
    __in LPWSATHREADID lpThreadId,
    __inout LPINT lpErrno
)
{
    PutDbgStr(L"WSPRecvFrom");
    return NextProcTable.lpWSPRecvFrom(s, lpBuffers, dwBufferCount, lpNumberOfBytesRecvd, lpFlags, lpFrom, lpFromlen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);
}
//WSPStartup
int WSPAPI WSPStartup(
    WORD wversionrequested,
    LPWSPDATA lpwspdata,
    LPWSAPROTOCOL_INFOW lpProtoInfo,
    WSPUPCALLTABLE upcalltable,
    LPWSPPROC_TABLE lpproctable
)
{
    PutDbgStr(L"IPFilter WSPStartup ...");
    int i;
    int errorcode;
    int filterpathlen;
    DWORD layerid=0;
    DWORD nextlayerid=0;
    TCHAR *filterpath;
    HINSTANCE hfilter;
    LPWSPSTARTUP wspstartupfunc=NULL;
    if (lpProtoInfo->ProtocolChain.ChainLen<=1)
    {
        PutDbgStr(L"ChainLen<=1");
        return FALSE;
    }
    GetLSP();
    for (i=0;i<TotalProtos;i++)
    {
        if (memcmp(&ProtoInfo[i].ProviderId,&filterguid,sizeof(GUID))==0)
        {
            layerid=ProtoInfo[i].dwCatalogEntryId;
            break;
        }
    }
    for (i=0;i<lpProtoInfo->ProtocolChain.ChainLen;i++)
    {
        if (lpProtoInfo->ProtocolChain.ChainEntries[i]==layerid)
        {
            nextlayerid=lpProtoInfo->ProtocolChain.ChainEntries[i+1];
            break;
        }
    }
    filterpathlen=MAX_PATH;
    filterpath=(TCHAR*)GlobalAlloc(GPTR,filterpathlen);
    for (i=0;i<TotalProtos;i++)
    {
        if (nextlayerid==ProtoInfo[i].dwCatalogEntryId)
        {
            if (WSCGetProviderPath(&ProtoInfo[i].ProviderId,filterpath,&filterpathlen,&errorcode)==SOCKET_ERROR)
            {
                PutDbgStr(L"WSCGetProviderPath Error!");
                return WSAEPROVIDERFAILEDINIT;
            }
            break;
        }
    }
    if (!ExpandEnvironmentStrings(filterpath,filterpath,MAX_PATH))
    {
        PutDbgStr(L"ExpandEnvironmentStrings Error!");
        return WSAEPROVIDERFAILEDINIT;
    }
    if ((hfilter=LoadLibrary(filterpath))==NULL)
    {
        PutDbgStr(L"LoadLibrary Error!");
        return WSAEPROVIDERFAILEDINIT;
    }
    if ((wspstartupfunc=(LPWSPSTARTUP)GetProcAddress(hfilter,"WSPStartup"))==NULL)
    {
        PutDbgStr(L"GetProcessAddress Error!");
        return WSAEPROVIDERFAILEDINIT;
    }
    if ((errorcode=wspstartupfunc(wversionrequested,lpwspdata,lpProtoInfo,upcalltable,lpproctable))!=ERROR_SUCCESS)
    {
        PutDbgStr(L"wspstartupfunc Error!");
        return errorcode;
    }
    NextProcTable=*lpproctable;// 保存原来的入口函数表
//改写函数
    lpproctable->lpWSPSendTo = WSPSendTo;
    lpproctable->lpWSPSend = WSPSend;
    lpproctable->lpWSPBind = WSPBind;
    lpproctable->lpWSPConnect = WSPConnect;
    lpproctable->lpWSPRecv = WSPRecv;
    lpproctable->lpWSPRecvFrom = WSPRecvFrom;
    lpproctable->lpWSPSocket = WSPSocket;
    FreeLSP();
    return 0;
}
复制代码



关于SOCKS V5代理,下回修改文章再贴上。

zetsin@gmail.com

2011-04-30 20:57:02


要说SOCKS V5代理,其实非常简单,细读一遍RFC1928文档就OK了,文档地址如下:

http://www.ietf.org/rfc/rfc1928.txt

如果需要远程解析域名,则将上述文档中第四点的 ATYP 置为 /X03

最后将前面所写的LSP与SOCKS V5代理结合,TCP的话只要拦截WSPCONNECT函数,UDP因为不是面向连接的所以只要拦截WSPSENDTO即可,具体代码如下:

// 连接socks5代理

复制代码
int socksProxy(SOCKET s, const struct sockaddr *name, int namelen)
{
    int rc = 0;
// 这里应该先保存下socket的阻塞/非阻塞类型,在最后面跟据这里的值将它还原,但是不知道怎样获取此类型
// 修改socket为阻塞类型
    if (rc = WSAEventSelect(s, 0, NULL))//这一个可以不用执行
    {
        PutDbgStr(L"Error %d : WSAEventSelect Failure!", WSAGetLastError());
    }
    else
    {
        PutDbgStr(L"Message : WSAEventSelect successfully!");
    }
    unsigned long nonBlock = 0;
    if (rc = ioctlsocket(s, FIONBIO, &nonBlock))// 这个真正修改为阻塞类型
    {
        PutDbgStr(L"Error %d : Set Blocking Failure!", WSAGetLastError());
    }
    else
    {
        PutDbgStr(L"Message : Set Blocking successfully!");
    }
//连接代理服务器
    sockaddr_in serveraddr;
    memset(&serveraddr, 0, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_addr.S_un.S_addr = inet_addr("76.120.160.122"); //代理服务器地址,从无忧代理网获取的,质量还行,不过只能用几天,发现连不上的话重新获取吧
    serveraddr.sin_port = htons(27977); // 端口号
    WSABUF DataBuf;
    char buffer[4];
    memset(buffer, 0, sizeof(buffer));
    DataBuf.len = 4;
    DataBuf.buf = buffer;
    int err = 0;
    if ((rc = NextProcTable.lpWSPConnect(s, (struct sockaddr *)&serveraddr, sizeof(struct sockaddr), &DataBuf, NULL, NULL, NULL, &err)) != 0)
    {
        PutDbgStr(L"Error %d : attempting to connect to SOCKS server!", err);
        return rc;
    }
    else
    {
        PutDbgStr(L"Message : Connect to SOCKS server successfully!");
    }
//发送请求来协商版本和认证方法
//VER NMETHODS METHODS
//1 1 1 to 255
    char verstring[257];
    verstring[0] = 0x05; //VER (1 Byte)
    verstring[1] = 0x01; //NMETHODS (1 Byte)
    verstring[2] = 0x00; //METHODS (allow 1 - 255 bytes, current 1 byte)
    if ((rc = send(s, verstring, 3, 0)) < 0)
    {
        PutDbgStr(L"Error %d : attempting to send SOCKS method negotiation!", WSAGetLastError());
        return rc;
    }
    else
    {
        PutDbgStr(L"Message : send SOCKS method negotiation successfully!");
    }
//接收代理服务器返回信息
//VER METHOD
//1 1
    /*当前定义的方法有:
    · X'00' 不需要认证
    · X'01' GSSAPI
    · X'02' 用户名/密码
    · X'03' -- X'7F' 由IANA分配
    · X'80' -- X'FE' 为私人方法所保留的
    · X'FF' 没有可以接受的方法*/
    if ((rc = recv(s, verstring, 257, 0)) < 0)
    {
        PutDbgStr(L"Error %d : attempting to receive SOCKS method negotiation reply!", WSAGetLastError());
        return rc;
    }
    else
    {
        PutDbgStr(L"Message : receive SOCKS method negotiation reply successfully!");
    }
    if (rc < 2)//返回2字节
    {
        PutDbgStr(L"Error : Short reply from SOCKS server!");
        rc = ECONNREFUSED;
        return rc;
    }
    else
    {
        PutDbgStr(L"Message : reply from SOCKS server larger than 2");
    }
// 代理服务器选择方法
// 判断我们的方法是否可行
    if (verstring[1] == '/xff')
    {
        PutDbgStr(L"Error : SOCKS server refused authentication methods!");
        rc = ECONNREFUSED;
        return rc;
    }
    else if (verstring[1] == '/x02')// 方法2 : 用户名/密码
    {
//另外处理
        PutDbgStr(L"Error : SOCKS server need username/password!");
    }
    else if (verstring[1] == '/x00')// 方法0: 不需要认证
    {
//发送SOCKS请求
//VER CMD RSV ATYP DST.ADDR DST.PROT
//1 1 X'00' 1 Variable 2
        /* VER 协议版本: X'05'
        · CMD
        · CONNECT:X'01'
        · BIND:X'02'
        · UDP ASSOCIATE:X'03'
        · RSV 保留
        · ATYP 后面的地址类型
        · IPV4:X'01'
        · 域名:X'03'
        · IPV6:X'04''
        · DST.ADDR 目的地址
        · DST.PORT 以网络字节顺序出现的端口号
        SOCKS服务器会根据源地址和目的地址来分析请求,然后根据请求类型返回一个或多个应答。*/
        struct sockaddr_in sin;
        sin = *(const struct sockaddr_in *)name;
        char buf[10];
        buf[0] = '/x05'; // 版本 SOCKS5
        buf[1] = '/x01'; // 连接请求
        buf[2] = '/x00'; // 保留字段
        buf[3] = '/x01'; // IPV4
        memcpy(&buf[4], &sin.sin_addr.S_un.S_addr, 4);
        memcpy(&buf[8], &sin.sin_port, 2);
//发送
        if ((rc = send(s, buf, 10, 0)) < 0)
        {
            PutDbgStr(L"Error %d : attempting to send SOCKS connect command!", WSAGetLastError());
            return rc;
        }
        else
        {
            PutDbgStr(L"Message : send SOCKS connect command successfully!");
        }
//应答
//VER REP RSV ATYP BND.ADDR BND.PORT
//1 1 X'00' 1 Variable 2
        /*VER 协议版本: X'05'
        · REP 应答字段:
        · X'00' 成功
        · X'01' 普通的SOCKS服务器请求失败
        · X'02' 现有的规则不允许的连接
        · X'03' 网络不可达
        · X'04' 主机不可达
        · X'05' 连接被拒
        · X'06' TTL超时
        · X'07' 不支持的命令
        · X'08' 不支持的地址类型
        · X'09' - X'FF' 未定义
        · RSV 保留
        · ATYP 后面的地址类型
        · IPV4:X'01'
        · 域名:X'03'
        · IPV6:X'04'
        · BND.ADDR 服务器绑定的地址
        · BND.PORT 以网络字节顺序表示的服务器绑定的段口
        标识为RSV的字段必须设为X'00'。*/
        if ((rc = recv(s, buf, 10, 0)) < 0) // 用了天翼的网络之后,这里就接收不到返回信息了,不解
        {
            PutDbgStr(L"Error %d : attempting to receive SOCKS connection reply!", WSAGetLastError());
            rc = ECONNREFUSED;
            return rc;
        }
        else
        {
            PutDbgStr(L"Message : receive SOCKS connection reply successfully!");
        }
        if (rc < 10)
        {
            PutDbgStr(L"Message : Short reply from SOCKS server!");
            return rc;
        }
        else
        {
            PutDbgStr(L"Message : reply from SOCKS larger than 10!");
        }
//连接不成功
        if (buf[0] != '/x05')
        {
            PutDbgStr(L"Message : Socks V5 not supported!");
            return ECONNABORTED;
        }
        else
        {
            PutDbgStr(L"Message : Socks V5 is supported!");
        }
        if (buf[1] != '/x00')
        {
            PutDbgStr(L"Message : SOCKS connect failed!");
            switch ((int)buf[1])
            {
            case 1:
                PutDbgStr(L"General SOCKS server failure!");
                return ECONNABORTED;
            case 2:
                PutDbgStr(L"Connection denied by rule!");
                return ECONNABORTED;
            case 3:
                PutDbgStr(L"Network unreachable!");
                return ENETUNREACH;
            case 4:
                PutDbgStr(L"Host unreachable!");
                return EHOSTUNREACH;
            case 5:
                PutDbgStr(L"Connection refused!");
                return ECONNREFUSED;
            case 6:
                PutDbgStr(L"TTL Expired!");
                return ETIMEDOUT;
            case 7:
                PutDbgStr(L"Command not supported!");
                return ECONNABORTED;
            case 8:
                PutDbgStr(L"Address type not supported!");
                return ECONNABORTED;
            default:
                PutDbgStr(L"Unknown error!");
                return ECONNABORTED;
            }
        }
        else
        {
            PutDbgStr(L"Message : SOCKS connect Success!");
        }
    }
    else
    {
        PutDbgStr(L"Error : Method not supported!");
    }
//修改socket为非阻塞类型
    nonBlock = 1;
    if (rc = ioctlsocket(s, FIONBIO, &nonBlock))
    {
        PutDbgStr(L"Error %d : Set Non-Blocking Failure!", WSAGetLastError());
        return rc;
    }
    else
    {
        PutDbgStr(L"Message : Set Non-Blocking Successful!");
    }
    PutDbgStr(L"Message : Success!");
    return 0;
}
//WSPConnect
int WSPAPI WSPConnect(
    SOCKET s,
    const struct sockaddr *name,
    int namelen,
    LPWSABUF lpCallerData,
    LPWSABUF lpCalleeData,
    LPQOS lpSQOS,
    LPQOS lpGQOS,
    LPINT lpErrno)
{
    PutDbgStr(L"WSPConnect");
    struct sockaddr_in sin;
    sin=*(const struct sockaddr_in *)name;
    if (strcmp(inet_ntoa(sin.sin_addr), "127.0.0.1") == 0)
    {
        return NextProcTable.lpWSPConnect(s, name, namelen, lpCallerData, lpCalleeData, lpSQOS, lpGQOS, lpErrno);
    }
    return socksProxy(s, name, namelen);
}
//WSPSendTo
int WINAPI WSPSendTo(
    __in SOCKET s,
    __in LPWSABUF lpBuffers,
    __in DWORD dwBufferCount,
    __out LPDWORD lpNumberOfBytesSent,
    __in DWORD dwFlags,
    __in const struct sockaddr *lpTo,
    __in int iTolen,
    __in LPWSAOVERLAPPED lpOverlapped,
    __in LPWSAOVERLAPPED_COMPLETION_ROUTINE lpCompletionRoutine,
    __in LPWSATHREADID lpThreadId,
    __out LPINT lpErrno
)
{
    PutDbgStr(L"WSPSendTo");
    struct sockaddr_in sin;
    sin=*(const struct sockaddr_in *)name;
    if (strcmp(inet_ntoa(sin.sin_addr), "127.0.0.1") == 0)
    {
        return NextProcTable.lpWSPSendTo(s, lpBuffers, dwBufferCount, lpNumberOfBytesSent, dwFlags, lpTo, iTolen, lpOverlapped, lpCompletionRoutine, lpThreadId, lpErrno);
    }
    return socksProxy(s, lpTo, iTolen);
}
复制代码

zetsin@gmail.com

2011-05-02 18:25:39

转自:http://blog.csdn.net/ze_tsin/article/details/6376831


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值