Socks5 代理协议详解 & 基于 Netty 的实现

简介

Socks 属于一个代理协议,可以在一些应用层协议中间工作(比如HTTP(S),FTP等)。这个协议最初由David Koblas开发,而后由NEC的Ying-Da Lee将其扩展到SOCKS4。最新协议是SOCKS5,与前一版本相比,增加支持UDP、验证,以及IPv6。

Socks5代理协议支持多种协议,理论上应用层协议都可以支持,比如HTTP(S)/WS(S)/SSH等

通信细节

TCP

image.png

当客户端与Socks5代理服务器(默认1080端口)TCP握手完成后,会进行一次初始化报文的发送,来确认协议版本以及认证方式,格式为(报文大小单位为字节,长度字段皆无符号):

 +----+----------+----------+
 |VER | NMETHODS | METHODS  |
 +----+----------+----------+
 | 1  |    1     | 1 to 255 |
 +----+----------+----------+
  • VER SOCKS版本,Socks5下是0x05
  • NMETHODS METHODS部分的长度
  • METHODS 客户端支持的认证方式列表,每个方法占1字节。当前的定义是:

    • 0x00 不需要认证
    • 0x01 GSSAPI
    • 0x02 用户名、密码认证
    • 0x03 - 0x7F由IANA分配(保留)
    • 0x80 - 0xFE为私人方法保留
    • 0xFF 无可接受的方法

代理服务在接受到客户端的初始化报文后,会从METHODS中选择一个认证方式,并返回给客户端:

  +----+--------+
  |VER | METHOD |
  +----+--------+
  | 1  |   1    |
  +----+--------+
  • VER SOCKS版本,0x05;
  • METHOD 服务端选中的方法。如果返回0xFF表示没有一个认证方法被选中,客户端需要关闭连接

现在客户端就可以按照约定的认证方式来进行认证了,这里介绍一种“0x02 用户名、密码认证”的认证报文:

如果代理服务器返回了“0x02 用户名、密码认证”的认证方式,此时客户端会发送认证报文:

.------.------------------.-----------.------------------.-----------.
| VER  | USERNAME_LENGTH  | USERNAME  | PASSWORD_LNEGTH  | PASSWORD  |
:------+------------------+-----------+------------------+-----------:
| 0x01 | 1                | Variable  | 1                | Variable  |
'------'------------------'-----------'------------------'-----------'
  • VER 认证版本,默认只有0x01
  • USERNAME_LENGTH 用户名长度
  • USERNAME 用户名
  • PASSWORD_LNEGTH 密码长度
  • PASSWORD 密码

代理服务器接收到客户端的认证报文后,会验证用户名密码,同时返回验证结果:

.------.---------.
| VER  | STATUS  |
:------+---------:
| 0x01 | 1       |
'------'---------'
  • VER 认证版本,默认只有0x01
  • STATUS 认证结果

    • 0x00 认证成功
    • 0x01 认证失败

认证结束后(或者服务端选择了不需要认证),客户端就会发送连接报文,报文中会包含需要连接的目标服务地址:

 +----+-----+-------+------+----------+----------+
 |VER | CMD |  RSV  | ATYP | DST.ADDR | DST.PORT |
 +----+-----+-------+------+----------+----------+
 | 1  |  1  | 0x00  |  1   | Variable |    2     |
 +----+-----+-------+------+----------+----------+
  • VER 是SOCKS版本,0x05;
  • CMD 是SOCK的命令码
  • 0x01 表示CONNECT请求
  • 0x02 表示BIND请求
  • 0x03 表示UDP转发
  • RSV 0x00,保留
  • ATYP DST.ADDR类型

    • 0x01 IPv4地址,DST.ADDR部分4字节长度
    • 0x03 域名,DST.ADDR部分第一个字节为域名长度,DST.ADDR剩余的内容为域名,没有0结尾。
    • 0x04 IPv6地址,16个字节长度。
  • DST.ADDR 目标服务地址
  • DST.PORT 目标服务端口

代理服务在接收到该连接报文后,会创建和目标服务器的连接,同时返回和目标服务建立连接的结果报文:

  +----+-----+-------+------+----------+----------+
  |VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
  +----+-----+-------+------+----------+----------+
  | 1  |  1  | 0x00  |  1   | Variable |    2     |
  +----+-----+-------+------+----------+----------+
  • VER是SOCKS版本,0x05;
  • REP应答字段,表示和目标服务建立连接的结果

    • 0x00 表示成功
    • 0x01 普通SOCKS服务器连接失败
    • 0x02 现有规则不允许连接
    • 0x03 网络不可达
    • 0x04 主机不可达
    • 0x05 连接被拒
    • 0x06 TTL超时
    • 0x07 不支持的命令
    • 0x08 不支持的地址类型
    • 0x09 - 0xFF未定义
  • RSV 0x00,保留
  • ATYP BND.ADDR类型

    • 0x01 IPv4地址,DST.ADDR部分4字节长度
    • 0x03 域名,DST.ADDR部分第一个字节为域名长度,DST.ADDR剩余的内容为域名,没有0结尾。
    • 0x04 IPv6地址,16个字节长度。
  • BND.ADDR 目标服务地址
  • BND.PORT 目标服务端口

至此,Socks5协议的“握手”部分完成,可以开始发送数据。代理服务器只需要将收到的客户端数据“盲目”的转发到目标服务,同时将收到的目标服务数据转发给客户端,只是一个中继(Relay)的角色

UDP

……

基于Netty的Socks5 代理实现

https://github.com/kongwu-/netty-proxy-server

相关文章

参考

坚持原创,专注分享 JAVA、网络、IO、JVM、GC 等技术干货

3.2k 声望
4.3k 粉丝
0 条评论
推荐阅读
PDF 那些事
PDF是 Portable Document Format的简称,翻译过来是“可携带文档格式”,由 Adobe于1992年创建。其格式特点是,与操作系统平台无关,在任意平台上都可以保持相同的渲染效果。​

空无5阅读 2k

封面图
Chrome 103支持使用本地字体,纯前端导出PDF优化
在前端导出PDF,解决中文乱码一直是一个头疼的问题。要解决这个问题,需要将ttf等字体文件内容注册到页面PDF生成器中。但是之前网页是没有权限直接获取客户机器字体文件,这时就需要从服务器下载字体文件或者提示...

葡萄城技术团队3阅读 13.9k

基于QUIC协议的HTTP/3,你了解多少?
前言了解一下HTTP发展史:HTTP/0.9-HTTP/1.0-HTTP/1.1-HTTP/2.0多个TCP连接 {代码...} Keep-alive {代码...} 管线化 {代码...} 多路复用 {代码...} {代码...} 并行多路复用的请求和响应不会相互阻塞尽管传输多个...

Henryk2阅读 1.1k评论 1

gitlab-ce将https修改为http
索性我们禁用gitlab的https功能,将期恢复为http。后期我们再在部署一个nginx进行数据转发,然后在nginx上起用https并设置证书。这样应该就规避了gitlab的证书错误问题。

myskies1阅读 629

Java基础-动态代理
Mybatis的源码实现中,使用到了动态代理的设计思想,为了搞明白Mybatis中的动态代理,本篇文章会结合实例和源码对JDK动态代理进行学习,并会在最后总结JDK动态代理与CGLIB动态代理的区别,以帮助更好的理解动态代...

半夏之沫1阅读 845

设计模式那些事(3)——使用建造者模式封装go的http库
{代码...} 具体实现 {代码...} 使用 {代码...}

爆裂Gopher1阅读 756

封面图
Hertz 性能持续优化,如何准确进行 Hertz 压测?这里有一份性能测试指南
2021 年 9 月 8 日,字节跳动宣布正式开源 CloudWeGo。CloudWeGo 是一套字节跳动内部微服务中间件集合,具备高性能、强扩展性和稳定性的特点,专注于解决微服务通信与治理的难题,满足不同业务在不同场景的诉求。...

CloudWeGo1阅读 695

封面图

坚持原创,专注分享 JAVA、网络、IO、JVM、GC 等技术干货

3.2k 声望
4.3k 粉丝
宣传栏