socks5是一个代理协议,主要的作用就是代理客户端来访问远程服务器,起到一个中介作用。
一般情况下当代理客户端因为防火墙等原因访问不了远程服务器,而另一个服务器即可以访问远程服务器又可以被客户端访问到时,可以在这个服务器上部署socks5服务端,本地部署socks5客户端,让这个中介服务器来代理访问远程服务器。
下面介绍协议流程,可以简单分为握手阶段,准备阶段和代理阶段
一,握手阶段
客户端建立和代理服的tcp连接A,并发送第一帧数据:
含义 | 协议版本 | 鉴权方法数 | 鉴权方法集 |
---|---|---|---|
字段 | VER | NMETHODS | METHODS |
字节数 | 1 | 1 | 1-255 |
示例数据 | 0x05 | 0x00 | 0x00 |
告诉代理服,我的支持的版本协议号是多少,一般情况下VER为0x05(即socks5)
代理服务器收到后,会鉴别VER,如果通过返回
含义 | 协议版本 | 鉴权方法 |
---|---|---|
字段 | VER | METHOD |
字节数 | 1 | 1 |
示例数据 | 0x05 | 0x00 |
上图中METHOD字段用于告诉客户端鉴权方法,当为0x00时,代表不需要客户端鉴权
至此,第一轮交流OK,代理服认可客户端了,可以进行下一步操作了(如果METHOD字段不为0x00时,需要走鉴权流程,下一篇讲)
二,准备阶段
客户端发送第二帧数据:
含义 | 协议版本 | 命令 | 保留位 | 地址类型 | 目标地址 | 目标端口 |
---|---|---|---|---|---|---|
字段 | VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
字节数 | 1 | 1 | 1 | 1 | 不固定长度 | 2 |
示例数据 | 0x05 | 0x01 | 0x00 | 0x03 | 0x0d7777772e62616964752e636f6d | 0x01bb |
客户端告诉代理服帮我代理tcp(CMD=0x01),我想连的目标服务器地址是DST.ADDR。
DST.ADDR有三种格式,
由ATYP来确定,0x01:ipv4地址,0x03:域名,0x04:ipv6地址
比如上图中的数据DST.ADDR就是"www.baidu.com:443"
代理服收到后,就直接建立和DST.ADDR的tcp连接B,并回复客户端
含义 | 协议版本 | 回复状态 | 保留位 | 地址类型 | 绑定地址 | 绑定端口 |
---|---|---|---|---|---|---|
字段 | VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
字节数 | 1 | 1 | 1 | 1 | 不固定长度 | 2 |
示例数据 | 0x05 | 0x00 | 0x00 | 0x01 | 0xc0a8c76a | 0xcdf0 |
REP=0x00代表代理连接DST.ADDR成功了,进入代理阶段
三,代理阶段
客户端把发给目标服的数据由连接A发给代理服,代理服将这些数据转由连接B发给目标服,同时代理服收到的目标服数据转由连接A返回给客户端
以上是整个socks5代理的tcp代理流程,udp代理会复杂些,后面会单独写一篇,
想详细了解的可以参照我的golang实现https://github.com/0990/socks5