SOCKS5代理连接代码(伪connect形式)

关于socks5代理的简单讲解

Socks5代理的请求和返回信息. 

1.客户端发送到socks5代理至少三个字节的请求,第一个字节一定为5,第二个字节为使用多少种验证,第三个字节为验证模式代码. bitsCN.Com 

例:如果要使用"USERNAME/PASSWORD",那么这三个字节为5 1 2 

2.Sock5代理接到上面请求后,如果是支持"USERNAME/PASSORD"的验证模式,就会返回两个字节,第一字节为5,第二字节为2. 

3.客户端然后就向socks5代理发送验证信息,信息第一字节不需要理会,第二字节为验证用户名的长度,第三字节开始是用户名和密码信息. 

4.socks5代理验证用户名和密码成功后,向客户端返回两个字节,5和0,如果验证失败,返回0x05和0xff. 

5.客户端开始向sock5代理发送第一个向远程目标进行操作的请求,请求模式如下: 

第一位为5 

第二位是使用模式,0x01代表TCP CONNECT,0x02代表TCP BIND,0x03代表UDP ASSOCIATE 

第三位保留 

第四位是地址使用模式:0x01代表IP V4地址;0x03代表域名;0x04代表IP V6地址(一般常见的只是0x01和0x03两种模式,因为很多软件都不支持IP V6的) 

第五位开始就是目标的地址和端口. 

6.socks代理开始处理这个请求,对于TCP CONNECT和UDP ASSOCIATE模式有不同的处理. 

A.对于TCP CONNECT 

将请求分析后,将目标地址和 目标端口从请求中解析出来(无论请求中带的地址是否以域名方式发送过来,最终要将地址转换为IPV4的地址),然后使用connect()连接到目标地址中的目标端口中去,如果成功连接,那就向客户端发送回10个字节的信息,第一字节为5,第二字节为0,第三字节为0,第四字节为1,其它字节都为0. 中国.网管联盟 

B.对于UDP ASSOCIATE(这个复杂很多了) 

将请求分析后,先保存好客户端的连接信息(客户端的IP和连接过来的源端口),然后本地创建一个UDP的socket,并将socket使用bind()绑入本地所有地址中的一个UDP端口中去,然后得到本地UDP绑定的IP和端口,创建一个10个字节的信息,返回给客户端去.第一字节为0x05,第二和第三字节都为0,第四字节为0x01(IPV4地址),第五位到第8位是UDP绑定的IP(以DWORD模式保存),第Array位和第10位是UDP绑定的端口(以WORD模式保存). 

在这里,我们要详解了解的则是“0x02 用户名/密码”验证的过程。

当客户端发送带有0x02认证方法的报文(如:“0x05 0x01 0x02”)到服务端时,根据报文,服务端得知客户端支持用户名/密码认证(0x02),因此如果服务端需要验证,则发送“0x05 0x02”应答,这样客户端将会进入“用户名/密码”验证过程。

“0x02 用户名/密码”验证协议的报文格式是:

0x01 | 用户名长度(1字节)| 用户名(长度根据用户名长度域指定) | 口令长度(1字节) | 口令(长度由口令长度域指定)

所以报文的长度是根据用户名与密码的长度而定,比如以下报文:

0x01 0x02 0x41 0x42 0x02 0x43 0x43

则表示发送用户名为“AB”密码为“CC”的验证报文。

服务端接收到用户名/密码验证报文后进行相应处理并返回以下格式的应答报文:

0x01 | 验证结果标志

如果验证通过则“验证结果标志”的值为“0x00”,否则其它值都表示验证失败!不允许再进行下一步的操作。

这时socks5代理就验证了用户名laotse密码666888对不对啊,如果不对直接关闭连接就可不用反馈了。

如果这个用户名和密码通过了,可以进行代理,那么就发送01 00给客户端。那么下面就和匿名是一样的了,匿名就是省略了这一步而已。

代码示例

#include <WinSock2.h>

#pragma comment(lib,"ws2_32.lib")

//用法相当于connect

int connect_proxy(SOCKET sock, const char *lpszDestHost, int nDestPort, const char * lpszProxyAddress, const int nProxyPort, BOOL bNeedAuth, const char * lpszUserName, const char * lpszPassword)

{

    //connect to proxy

    char szBuffer[1024 + 1] = { "" };

    int nLen = 0;

    SOCKADDR_IN saProxy;

    saProxy.sin_family = AF_INET;

    saProxy.sin_port = htons(nProxyPort);

    saProxy.sin_addr.s_addr = inet_addr(lpszProxyAddress);

    if (saProxy.sin_addr.S_un.S_addr == INADDR_NONE)

    {

        LPHOSTENT lphost;

        lphost = gethostbyname(lpszProxyAddress);

        if (lphost != NULL)

        {

            saProxy.sin_addr.S_un.S_addr = ((LPIN_ADDR)lphost->h_addr)->s_addr;

        }

        else

        {

            return -1;

        }

    }

//LSP层HOOK的时候才用的方式

    //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)) == SOCKET_ERROR)

    int nRet = -1;

    if (oConnect(sock, (sockaddr*)&saProxy, sizeof(sockaddr)) == SOCKET_ERROR)

    {

        if (WSAGetLastError() == WSAEWOULDBLOCK)

        {

            fd_set fdWrite;

            FD_ZERO(&fdWrite);//初始化fd_set

            FD_SET(sock, &fdWrite);

            timeval tv;

            tv.tv_sec = 30;

            tv.tv_usec = 0;

            nRet = select(0, NULL, &fdWrite, NULL, &tv);

            if (nRet <= 0)

            {

                return -1;

            }

        }

        else

        {

            return -1;

        }

    }

    //auth

    nLen = 0;

    if (bNeedAuth)

    {

        szBuffer[0] = 5;

        szBuffer[1] = 2;

        szBuffer[2] = 0;

        szBuffer[3] = 2;

        nLen = 4;

        send(sock, szBuffer, nLen, 0);

        fd_set      fdread;

        FD_ZERO(&fdread);//初始化fd_set

        FD_SET(sock, &fdread);

        timeval     tv;

        tv.tv_sec = 30;

        tv.tv_usec = 0;

        nRet = select(0, &fdread, NULL, NULL, &tv);

        if (nRet <= 0)

        {

            return -1;

        }

 

        nLen = 2;

        recv(sock, szBuffer, nLen, 0);

        if (szBuffer[0] == 5)

        {

            //need auth

            if (szBuffer[1] == 2)

            {

                szBuffer[0] = 1;

                nLen = strlen(lpszUserName);

                szBuffer[1] = nLen;

                strcpy(szBuffer + 2, lpszUserName);

                nLen += 2;

                szBuffer[nLen] = strlen(lpszPassword);

                strcpy(szBuffer + nLen + 1, lpszPassword);

                nLen = nLen + 1 + strlen(lpszPassword);

                send(sock, szBuffer, nLen, 0);

                nLen = 2;

 

                fd_set      fdread;

                FD_ZERO(&fdread);//初始化fd_set

                FD_SET(sock, &fdread);

                timeval     tv;

                tv.tv_sec = 30;

                tv.tv_usec = 0;

                nRet = select(0, &fdread, NULL, NULL, &tv);

                if (nRet <= 0)

                {

                    return -1;

                }

                recv(sock, szBuffer, nLen, 0);

                if (szBuffer[1] != 0)

                {

                    return -1;//帐号或密码错误

                }

            }

            else

            {

                if (szBuffer[1] != 0)

                {

                    return -1;

                }

            }

        }

        else

        {

            return -1;

        }

    }

    //进入发送代理请求的阶段

    else

    {

        szBuffer[0] = 5;

        szBuffer[1] = 1;

        szBuffer[2] = 0;

        nLen = 3;

        send(sock, szBuffer, nLen, 0);

 

        fd_set      fdread;

        FD_ZERO(&fdread);//初始化fd_set

        FD_SET(sock, &fdread);

        timeval     tv;

        tv.tv_sec = 30;

        tv.tv_usec = 0;

        nRet = select(0, &fdread, NULL, NULL, &tv);

        if (nRet <= 0)

        {

            return -1;

        }

 

        nLen = 2;

        recv(sock, szBuffer, nLen, 0);

        if (szBuffer[0] != 5 || szBuffer[1] != 0)

        {

            return -1;

        }

 

    }

    //translate DestAddr

    szBuffer[0] = 5;

    szBuffer[1] = 1;

    szBuffer[2] = 0;

    szBuffer[3] = 3;//DOMAIN

 

    szBuffer[4] = strlen(lpszDestHost);//domain len

    strcpy(szBuffer + 5, lpszDestHost);

    unsigned short uPort = htons(nDestPort);

    memcpy(szBuffer + 5 + strlen(lpszDestHost), &uPort, 2);

    nLen = 5 + strlen(lpszDestHost) + 2;

    send(sock, szBuffer, nLen, 0);

  

    fd_set      fdread;

    FD_ZERO(&fdread);//初始化fd_set

    FD_SET(sock, &fdread);

    timeval     tv;

    tv.tv_sec = 30;

    tv.tv_usec = 0;

    nRet = select(0, &fdread, NULL, NULL, &tv);

    if (nRet <= 0)

    {

        return -1;

    }

 

    nLen = 10;

    recv(sock, szBuffer, nLen, 0);

 

    if (szBuffer[0] != 5 || szBuffer[1] != 0)

    {

        return -1;

    }

 

    //以下为测试能否发送与返回数据的测试代码(测试无问题)

    //char buffer[1024] = { 0 };

    //sprintf(buffer, "GET / HTTP/1.0\nHost:www.baidu.com\n\n");

    //int ret = send(s, buffer, strlen(buffer), 0);//send

    //if (ret == SOCKET_ERROR)

    //{

    //  closesocket(s);

    //  return rc;

    //}

    //while (1)

    //{

    //  ZeroMemory(buffer, 1024);

    //  ret = recv(s, buffer, 1024, 0);//recv

    //  if (ret == SOCKET_ERROR)

    //  {

    //      fprintf(stderr, "recv() 函数错误 : %d\n", WSAGetLastError());

    //      break;

    //  }

    //  MessageBoxA(0, buffer, "", 0);

    //}

 

    return 0;

}

 

//其他例程:

TCP代理测试:

// socks5.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h"

#include<WinSock2.h>

#include<stdio.h> 

#pragma comment(lib, "WS2_32.lib"

 

int main(int argc, char* argv[])

{

    WSADATA wsaData;

    WORD sockVersion = MAKEWORD(2, 0);//指定版本号 

    ::WSAStartup(sockVersion, &wsaData);//载入winsock的dll 

 

                                        //建立socket,基于tcp 

    SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (s == INVALID_SOCKET)

    {

        printf("error");

        ::WSACleanup(); //释放资源 

        return 0;

    }

 

    sockaddr_in servAddr;

    servAddr.sin_family = AF_INET;

    servAddr.sin_port = htons(1080);//端口号 

    servAddr.sin_addr.S_un.S_addr = inet_addr("192.168.50.103");//IP

 

                                                                //连接 

    if (::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)

    {

        printf("error");

        ::WSACleanup(); //释放资源 

        return 0;

    }

 

    //发送链接请求

    char request[10] = { 0x05,0x01,0x02 };

    int ret = send(s, request, 3, 0);

    char buff[156];//缓冲区 

    int nRecv = ::recv(s, buff, 156, 0);//接收数据 

    if (nRecv > 0)

    {

        buff[nRecv] = '\0';

    }

 

    //发送账户密码

    char username[30] = "liujiayu";

    char pwd[30] = "liujiayu";

    char validatebuf[100] = { 0 };

    validatebuf[0] = 0x01;

    validatebuf[1] = strlen(username);

    memcpy(validatebuf + 2, username, strlen(username));

    validatebuf[2 + strlen(username)] = strlen(pwd);

    memcpy(validatebuf + 3 + strlen(username), pwd, strlen(pwd));

    ret = send(s, validatebuf, 3 + strlen(username) + strlen(pwd), 0);

    nRecv = ::recv(s, buff, 156, 0);//接收数据 

 

                                    //发送远程目标连接

 

    unsigned long l = inet_addr("124.115.16.165");

 

    char dest[11] = { 0x05,0x01,0x00,0x01,0x7c,0x73,0x10,0xa5,0x00,0x50 };

    ret = send(s, dest, 10, 0);

    nRecv = ::recv(s, buff, 156, 0);//接收数据

 

    char copntent[11] = "get";

    ret = send(s, copntent, 4, 0);

    nRecv = ::recv(s, buff, 156, 0);//接收数据

 

    ::closesocket(s); //关闭套接字 

    ::WSACleanup(); //释放资源 

 

    return 0;

}

 

UDP代理测试:

// tt2.cpp : 定义控制台应用程序的入口点。

//

#include "stdafx.h" 

#include<WinSock2.h> 

#include<stdio.h>   

#pragma comment(lib, "WS2_32.lib")   

 

int main(int argc, char* argv[])

{

    WSADATA wsaData;

    WORD sockVersion = MAKEWORD(2, 0);//指定版本号   

    ::WSAStartup(sockVersion, &wsaData);//载入winsock的dll   

 

                                        //建立socket,基于tcp   

    SOCKET s = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

    if (s == INVALID_SOCKET)

    {

        printf("error");

        ::WSACleanup(); //释放资源   

        return 0;

    }

 

    sockaddr_in servAddr;

    servAddr.sin_family = AF_INET;

    servAddr.sin_port = htons(1080);//端口号   

    servAddr.sin_addr.S_un.S_addr = inet_addr("192.168.50.197");//IP 

 

    //连接   

    if (::connect(s, (sockaddr*)&servAddr, sizeof(servAddr)) == -1)

    {

        printf("error");

        ::WSACleanup(); //释放资源   

        return 0;

    }

 

    //发送链接请求 

    char request[10] = { 0x05,0x01,0x02 };

    int ret = send(s, request, 3, 0);

    char buff[156];//缓冲区   

    int nRecv = ::recv(s, buff, 156, 0);//接收数据   

    if (nRecv > 0)

    {

        buff[nRecv] = '\0';

    }

 

    //发送账户密码 

    char username[30] = "liujiayu";

    char pwd[30] = "liujiayu";

    char validatebuf[100] = { 0 };

    validatebuf[0] = 0x01;

    validatebuf[1] = strlen(username);

    memcpy(validatebuf + 2, username, strlen(username));

    validatebuf[2 + strlen(username)] = strlen(pwd);

    memcpy(validatebuf + 3 + strlen(username), pwd, strlen(pwd));

    ret = send(s, validatebuf, 3 + strlen(username) + strlen(pwd), 0);

    nRecv = ::recv(s, buff, 156, 0);//接收数据   

 

  //发送远程目标连接 

 

    unsigned long l = inet_addr("192.168.50.197");

 

    char dest[10] = { 0x05,0x03,0x00,0x01,0xc0,0xa8,0x32,0xc5,0x00,0x5a };

    ret = send(s, dest, 10, 0);

    nRecv = ::recv(s, buff, 156, 0);//接收数据

 

    unsigned short udpserverport = (buff[8] << 8) + buff[9];

    SOCKET sockClient = socket(AF_INET, SOCK_DGRAM, 0);

 

    SOCKADDR_IN addrSrv;

    addrSrv.sin_addr.S_un.S_addr = inet_addr("192.168.50.197");

    addrSrv.sin_family = AF_INET;

    addrSrv.sin_port = htons(udpserverport);

    char sendtobuf[30] = { 0x00,0x00,0x00,0x01,0xc0,0xa8,0x32,0xc5,0x04,0x38,0x31,0x11,0x11,0x11,0x11 };

    int to = sendto(sockClient, sendtobuf, 16, 0, (SOCKADDR*)&addrSrv, sizeof(SOCKADDR));

 

    ::closesocket(s); //关闭套接字   

    ::WSACleanup(); //释放资源   

    return 0;

}

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值