1. 前言
本位将由浅入深带大家详细了解socks5协议。文章首先会对socks协议进行简单介绍,接着会介绍socks5协议的使用场景,然后介绍它的工作工程,最后介绍协议的细节(握手、数据转发)。
2. 协议介绍
2.1 什么是socks协议
啥是socks协议呢? 这里贴一段维基百科对它的定义
SOCKS is an Internet protocol that exchanges network packets between a client and server through a proxy server
大概的意思是: socks是一种互联网协议,它通过一个代理服务器在客户端和服务端之间交换网络数据。简单来说,它就是一种代理协议,扮演一个中间人的角色,在客户端和目标主机之间转发数据。
socks协议位于OSI模型中的第五层,即会话层(Session Layer)。
2.2 socks协议有什么用
对于广大的中国网友来说,一提到代理,肯定会想到翻墙,而socks5作为一种代理协议,肯定也能用来翻墙嘛。不过遗憾的是,虽然它是代理协议,然而并不能用于翻墙。因为它的数据都是明文传输,会被墙轻易阻断。
socks协议历史悠久,它面世时中国的互联网尚未成型,更别说墙,因此它并不是为翻墙而设计的协议。互联网早期,企业内部网络为了保证安全性,都是置于防火墙之后,这样带来的副作用就是访问内部资源会变得很麻烦,socks协议就是为了解决这个问题而诞生的。
socks相当于在防火墙撕了一道口子,让合法的用户可以通过这个口子连接到内部,从而访问内部的一些资源和进行管理。
2.3 什么是socks5协议
socks5顾名思义就是socks协议的第五个版本,作为socks4的一个延伸,在socks4的基础上新增UDP转发和认证功能。唯一遗憾的是socks5并不兼容socks4协议。socks5由IETF在1996年正式发布,经过这么多年的发展,互联网上基本上都以socks5为主,socks4已经退出了历史的舞台。
实际上,你并不需要回头去看socks4协议,因为socks5协议完全可以取代socks4,因此读者对此不必感觉有心理压力。
2.4 工作过程
在开始介绍socks5协议工作工程之前,先来了解一下浏览器不设置代理情况下的请求过程。假设读者通过浏览器访问本博(假设读者使用的是HTTP协议),流程如下:
建立TCP连接
浏览器向本博所在服务器建立TCP连接,经过3次握手后成功双方建立一条连接,用于数据传输
发起HTTP请求
TCP连接建立成功后,浏览器通过建立的连接发送HTTP请求
GET /
Host wiyi.org
服务器响应浏览器一段HTML内容,浏览器收到后对页面进行渲染
图2.1
上面是正常的请求过程,如果读者给浏览器设置了一个socks5代理,情况会复杂一些。在这里我们假设socks5代理位于读者本地,端口为7582,它的工作流程如下:
浏览器和socks5代理建立TCP连接
和上面不同的时,浏览器和服务器之间多了一个中间人,即socks5,因此浏览器需要跟socks5服务器建立一条连接。
socks5协商阶段
在浏览器正式向socks5服务器发起请求之前,双方需要协商,包括协议版本,支持的认证方式等,双方需要协商成功才能进行下一步。协商的细节将会在下一小节详细描述。
socks5请求阶段
协商成功后,浏览器向socks5代理发起一个请求。请求的内容包括,它要访问的服务器域名或ip,端口等信息。
socks5 relay阶段
scoks5收到浏览器请求后,解析请求内容,然后向目标服务器建立TCP连接。
数据传输阶段
经过上面步骤,我们成功建立了浏览器 –> socks5,socks5–>目标服务器之间的连接。这个阶段浏览器开始把数据传输给scoks5代理,socks5代理把数据转发到目标服务器。
上面的步骤虽然变多,但本质不变,非常容易理解,简单整理为下图
图2.2
2.5 协议细节
在上一个小节介绍了socks5代理简要的工作流程,我们可以把它的的过程总结为3个阶段,分别为:握手阶段、请求阶段,Relay阶段。
2.5.1 握手阶段
握手阶段包含协商和子协商阶段,我们把它拆分为两个分别讨论
2.5.1.1 协商阶段
在这个阶段,客户端向socks5发起请求,内容如下:
+----+----------+----------+
|VER | NMETHODS | METHODS |
+----+----------+----------+
| 1 | 1 | 1 to 255 |
+----+----------+----------+
#上方的数字表示字节数,下面的表格同理,不再赘述
VER: 协议版本,socks5为0x05
NMETHODS: 支持认证的方法数量
METHODS: 对应NMETHODS,NMETHODS的值为多少,METHODS就有多少个字节。RFC预定义了一些值的含义,内容如下:
X’00’ NO AUTHENTICATION REQUIRED
X’01’ GSSAPI
X’02’ USERNAME/PASSWORD
X’03’ to X’7F’ IANA ASSIGNED
X’80’ to X’FE’ RESERVED FOR PRIVATE METHODS
X’FF’ NO ACCEPTABLE METHODS
socks5服务器需要选中一个METHOD返回给客户端,格式如下:
+----+--------+
|VER | METHOD |
+----+--------+
| 1 | 1 |
+----+--------+
当客户端收到0x00时,会跳过认证阶段直接进入请求阶段; 当收到0xFF时,直接断开连接。其他的值进入到对应的认证阶段。
2.5.1.2 认证阶段(也叫子协商)
认证阶段作为协商的一个子流程,它不是必须的。socks5服务器可以决定是否需要认证,如果不需要认证,那么认证阶段会被直接略过。
如果需要认证,客户端向socks5服务器发起一个认证请求,这里以0x02的认证方式举例:
+----+------+----------+------+----------+
|VER | ULEN | UNAME | PLEN | PASSWD |
+----+------+----------+------+----------+
| 1 | 1 | 1 to 255 | 1 | 1 to 255 |
+----+------+----------+------+----------+
VER: 版本,通常为0x01
ULEN: 用户名长度
UNAME: 对应用户名的字节数据
PLEN: 密码长度
PASSWD: 密码对应的数据
socks5服务器收到客户端的认证请求后,解析内容,验证信息是否合法,然后给客户端响应结果。响应格式如下:
+----+--------+
|VER | STATUS |
+----+--------+
| 1 | 1 |
+----+--------+
STATUS字段如果为0x00表示认证成功,其他的值为认证失败。当客户端收到认证失败的响应后,它将会断开连接。
2.5.2 请求阶段
顺利通过协商阶段后,客户端向socks5服务器发起请求细节,格式如下:
+----+-----+-------+------+----------+----------+
|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X'00' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+
VER 版本号,socks5的值为0x05
CMD
0x01表示CONNECT请求
0x02表示BIND请求
0x03表示UDP转发
RSV 保留字段,值为0x00
ATYP 目标地址类型,DST.ADDR的数据对应这个字段的类型。
0x01表示IPv4地址,DST.ADDR为4个字节
0x03表示域名,DST.ADDR是一个可变长度的域名
0x04表示IPv6地址,DST.ADDR为16个字节长度
DST.ADDR 一个可变长度的值
DST.PORT 目标端口,固定2个字节
上面的值中,DST.ADDR是一个变长的数据,它的数据长度根据ATYP的类型决定。我们可以通过掐头去尾解析出这部分数据。分为下面3种情况:
X’01’
一个4字节的ipv4地址
X’03’
一个可变长度的域名,这种情况下DST.ADDR的第一个字节表示域名长度,剩下部分是域名内容。
X’04’
一个16字节的ipv6地址
socks5服务器收到客户端的请求后,需要返回一个响应,结构如下
+----+-----+-------+------+----------+----------+
|VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X'00' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+
VER socks版本,这里为0x05
REP Relay field,内容取值如下
X’00’ succeeded
X’01’ general SOCKS server failure
X’02’ connection not allowed by ruleset
X’03’ Network unreachable
X’04’ Host unreachable
X’05’ Connection refused
X’06’ TTL expired
X’07’ Command not supported
X’08’ Address type not supported
X’09’ to X’FF’ unassigned
RSV 保留字段
ATYPE 同请求的ATYPE
BND.ADDR 服务绑定的地址
BND.PORT 服务绑定的端口DST.PORT
针对响应的结构中,BND.ADDR和BND.PORT值得特别关注一下,可能有朋友在这里会产生困惑,返回的地址和端口是用来做什么的呢?
我们回过头看图2.2,可以发现在图中socks5既充当socks服务器,又充当relay服务器。实际上这两个是可以被拆开的,当我们的socks5 server和relay server不是一体的,就需要告知客户端relay server的地址,这个地址就是BND.ADDR和BND.PORT。
当我们的relay server和socks5 server是同一台服务器时,BND.ADDR和BND.PORT的值全部为0即可。
2.5.3 Relay阶段
socks5服务器收到请求后,解析内容。如果是UDP请求,服务器直接转发; 如果是TCP请求,服务器向目标服务器建立TCP连接,后续负责把客户端的所有数据转发到目标服务。
3.总结 & 下载
本文简单介绍了下socks5协议的作用以及处理过程,下一篇文章,将会手把手用Java实现一个socks5代理服务器,进一步认识socks5协议的处理过程。
读者可以点击socks5.pcapng下载抓包数据,使用wireshark可以查看本文事例的抓包数据。
4. 相关阅读
手把手使用Java实现一个Socks5代理
5.参考资料
https://en.wikipedia.org/wiki/SOCKS
https://datatracker.ietf.org/doc/html/rfc1928
https://datatracker.ietf.org/doc/html/rfc1929
https://www.rapidseedbox.com/blog/guide-to-socks5-proxy