socks5代理浅识
在防火墙内部的客户端主机(A)想访问某个服务器(C)时,有时候是无法直接访问的;但是如果有一台服务(B),A可以直接访问,而B又可以直接访问C,那么就可以通过访问B服务达到间接访问C的目的,B称为代理服务器。这篇文章介绍下socks5的TCP代理。
一、什么是socks5代理
socks5是socks协议中最新版本协议,前有socks4和socks4a两个版本。socks是一种网络传输协议,主要用于客户端与外网服务器之间的中间传输。socks5相较于socks4新增了连接验证、UDP包代理和IPV6的支持。今天主要简单介绍socks5协议实现tcp代理。
二、socks5代理协议"三步走"
第一步:客户端和代理服务器建立socket-tcp代理连接后,客户端向代理服务器发送请求来确认协议版本和认证方式,协议格式(以字节为单位)如下:
-------------------------------------- | VER | NMETHODS | METHODS | -------------------------------------- | 1 | 1 | 1~255 | --------------------------------------
VER:socks版本号,socks5版本号:0x05,占用1字节
NMETHODS:METHODS字段的长度,占有1字节
METHODS:客户端支持的认证方法列表,每个方法占有一个字节。当前定义如下:
0x00:不需要认证
0x001:GSSAPI
0x02:用户名、密码认证
0x03-0x7F:由IANA分配,属于保留字段
0X80-0XFE:为私人方法保留
0XFF:无可接受的方法
代理服务从客户端收到的协议中选择一个认证方法,并发送如下格式(字节为单位)给客户端:
------------------------- | VER | METHOD | ------------------------- | 1 | 1 | -------------------------
VER:socks版本号
METHOD:认证方式,如果返回的是0XFF,客户端没有认证方式,需要与服务器关闭连接
客户端向代理服务器发送认证信息,如果认证成功,进入第二步,否则关闭连接,重新开始。
用户名和密码认证格式:
------------------------------------------------- | 签订协议版本 | 用户名长度 | 用户名 | 密码长度|密码 | | 1 | 1 | 动态 | 1 | 动态| -------------------------------------------------
签订协议版本号目前:0x01
代理服务器返回格式:
------------------- |签订协议版本|认证状态| | 1 | 1 | -------------------
认证状态码:
0x00:成功
0x01:失败
第二步:客户端向代理服务器发送代理请求信息,socks5请求格式(字节为单位)如下:
---------------------------------------------------------------------------- | VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT | ---------------------------------------------------------------------------| | 1 | 1 | 1 | 1 | 动态 | 2 | ----------------------------------------------------------------------------
VER:socks版本号
CMD:socks命令码:
0x01:连接请求
0x02:BIND请求
0x03:UDP转发
RSV:保留字段,0x00
ATYP:目标服务器的地址类型:
0x01:IPV4, DST.ADDR字节为4
0x03:域名,DST.ADDR第一个字节为域名长度,后面为域名存放字节,不要\0结尾
0x04:IPV6,DST.ADDR字节为16
DST.ADDR:目标服务器地址
DST.PORT:目标服务端口号
代理服务器收到客户端请求后,回复如下请求:
---------------------------------------------------------------------------- | VER | REP | RSV | ATYP | BND.ADDR | BND.PORT | ---------------------------------------------------------------------------| | 1 | 1 | 1 | 1 | 动态 | 2 | ----------------------------------------------------------------------------
VER:版本号
REP:应答字段:
0x00:成功
0x01:普通socks服务器连接失败
0x02:现有规则不允许连接
0x03:网络不可达
0x04:主机不可达
0x05:连接被拒
0x06:TTL超时
0x07:不支持的命令
0x08:不支持的地址类型
0x09-0xFF:未定义
RSV:保留
ATYP:同上
BND.ADDR:代理服务器绑定的地址
BND.PORT:代理服务器绑定的端口
第三步:以上两步都成功后,客户端和 代理服务器,代理服务器和目标服务器都建立了socket连接,这个时候客户端通过与代理服务器建立的socket发送消息,代理服务器会将消息发送给目标服务器。
以上是socks5代理(TCP穿透)原理的核心部分介绍,如果实现UDP代理,还需要一些其他处理才能实现,后面有机会再介绍。
三、socks5代理demo编写
客户端如何与代理服务器建立socks5代理连接的代码实现,遵循上面所说的三部走:
前提是客户端与代理服务器建立socket-tcp连接
1 bool InitWSA() 2 { 3 WORD wVersionRequested; 4 WSADATA wsaData; 5 int err; 6 7 wVersionRequested = MAKEWORD(1, 1); 8 err = WSAStartup(wVersionRequested, &wsaData); 9 if (err != 0) 10 { 11 return false; 12 } 13 if (LOBYTE(wsaData.wVersion) != 1 || 14 HIBYTE(wsaData.wVersion) != 1) 15 { 16 WSACleanup(); 17 return false; 18 } 19 return true; 20 }
1 void main() 2 { 3 InitWSA(); 4 SOCKET s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 5 }
第一步:认证
1 TSock5Request* proxyRequest; 2 proxyRequest = (TSock5Request*)buf; 3 proxyRequest->Ver = 0x05; 4 proxyRequest->nMethods = 0x01; 5 proxyRequest->Methods = 0x00; 6 Send(socket, buf, 3);
第二步:请求
1 TSock5Request2* proxyRequest2 2 proxyRequest2 = (TSock5Request2*)buf; 3 proxyRequest2->Ver = 5; 4 proxyRequest2->Cmd = 1; 5 proxyRequest2->Rsv = 0; 6 proxyRequest2->Atyp = 1; 7 unsigned long tmpLong = inet_addr(ip); 8 unsigned short port1 = ntohs(port); 9 memcpy((char*)&proxyreq2->other, &tmpLong, 4); 10 memcpy((char*)(&proxyreq2->other) + 4, &port1, 2); 11 12 Send(socket, buf, 10);
第三步:发送数据
1 while (true){ 2 Send(socket, buf, len); 3 Recive(socket, buf, len); 4 }
代理服务器响应的数据处理省略。
四、验证
1.准备工具:两台PC电脑;TCP/UDP socket工具;go的代理服务程序
2.一台电脑启动go代理服务程序,并使用TCP/UDP socket工具创建服务端口监听,查看go代理服务绑定的目标ip和端口
3.另外一台电脑启动上面编写的demo,验证另外一台代理服务器绑定的目标服务是否正常接受到数据
验证截图如下:
启动go的socks5代理服务器
客户端与代理服务器建立tcp连接后,执行socks5协议后,向代理服务器发送消息:
目标ip正常接受到消息
目标服务器发送消息:
客户端接受到目标服务器发送的数据
实现源码下载地址:https://files.cnblogs.com/files/smartNeo/socks5_proxy.zip