使用netty实现socks5协议
一、socks5协议简介
SOCKS是一种网络传输协议,主要用于客户端与外网服务器之间通讯的中间传递。
SOCKS是”SOCKetS”的缩写[注 1]。 当防火墙后的客户端要访问外部的服务器时,就跟SOCKS代理服务器连接,这个代理服务器控制客户端访问外网的资格,允许的话,就将客户端的请求发往外部的服务器。
SOCKS 协议第 4 版本为基于 TCP 协议的 C/S 应用,包括 TELNET, FTP 和 使用广泛的信息发现协议如 HTTP 、 WAIS 提供了不保证安全性的防火墙穿透服务。
SOCKS 5 扩展了第 4 版本,加入了 UDP 协议支持,在框架上加入了强认证功能,并且地址信息也加入了域名和 IPV6 的支持。
SOCKS协议不提供加密。
socks5协议适用如下几种场景:
- 局域网内只有某台机器被授权访问网络,其它机器需要连接外部网络,但是未被授权,这时候可以在被授权机器上运行socks5协议的服务端,其它局域网内未被授权的机器上运行socks5客户端程序通过被授权机器上网。
- 网络管理。socks5代理服务器会代理所有流量,所以能获取所有客户端想要访问的目标地址和端口号,这时候代理服务器可以自主决定是否允许客户端访问目标服务器。
- 其它。懂的自然懂,但是由于流量特征明显而且未加密,所以一旦开始用,立马会被封掉服务器,不要玩火,这里仅作为技术研究使用。
二、socks5协议交互过程
socks5协议大体上会经过两个或者三个交互过程,这取决于是否有认证流程。以用户名密码认证方式为例,完整的流程如下图所示
1、版本和认证方式交互
第一步,客户端向代理服务器发送代理请求,其中包含了代理的版本和认证方式:
+----+----------+----------+
|VER | NMETHODS | METHODS |
+----+----------+----------+
| 1 | 1 | 1 to 255 |
+----+----------+----------+
如果是socks5代理,第一个字段VER
的值是0x05
,表明是socks代理的第5个版本。
第二个字段NMETHODS
表示支持的认证方式,第三个字段是一个数组,包含了支持的认证方式列表:
0x00
: 不需要认证0x01
: GSSAPI认证0x02
: 用户名和密码方式认证0x03
: IANA认证0x80-0xfe
: 保留的认证方式0xff
: 不支持任何认证方式
服务端收到客户端的代理请求后,选择双方都支持的认证方式回复给客户端:
+----+--------+
|VER | METHOD |
+----+--------+
| 1 | 1 |
+----+--------+
这个过程完成之后,服务端知道了客户端想要使用的socks版本号,告诉客户端是否使用认证;客户端则通过请求服务端,得知下一步是否需要认证。
2、认证交互
如果上一步版本和认证方式交互的结果,服务器不需要认证,则可以跳过该步骤,否则需要进行认证交互。
上一步协商好了使用的认证方式,这里以使用用户名和密码交互方式为例,接下来客户端需要发送用户名和密码给服务端让服务端进行认证,请求格式如下所示
+----+------+----------+------+----------+
|VER | ULEN | UNAME | PLEN | PASSWD |
+----+------+----------+------+----------+
| 1 | 1 | 1 to 255 | 1 | 1 to 255 |
+----+------+----------+------+----------+
- VER:固定长度一个字节,固定值X'01'表示用户名密码认证
- ULEN:用户名长度,固定一个字节大小
- UNAME:用户名,不固定大小,但是其长度和ULEN一致
- PLEN:密码长度,固定一个字节大小
- PASSWD:密码,不固定大小,但是其长度和PLEN一致
服务端会进行用户名和密码的校验,然后做出如下响应
+----+--------+
|VER | STATUS |
+----+--------+
| 1 | 1 |
+----+--------+
如果服务器响应STATUS的值为X'00',表示认证成功;其它状态表示认证失败,这时候客户端需要关闭连接。
3、数据交互
如果上一步用户名密码认证成功,或者无用户名密码认证,则会进入数据交互阶段,这阶段会进行真正的数据传输。首先,客户端会发送一个请求告诉服务端本次请求的信息,格式如下所示
+----+-----+-------+------+----------+----------+
|VER | CMD | RSV | ATYP | DST.ADDR | DST.PORT |
+----+-----+-------+------+----------+----------+
| 1 | 1 | X'00' | 1 | Variable | 2 |
+----+-----+-------+------+----------+----------+
- VER 是SOCKS版本,0x05;
- CMD 是SOCK的命令码
- 0x01 表示CONNECT请求
- 0x02 表示BIND请求
- 0x03 表示UDP转发
- RSV 0x00,保留
- ATYP DST.ADDR类型
- 0x01 IPv4地址
- 0x03 域名类型
- 0x04 IPv6地址
- DST.ADDR 目标服务地址,如果是IPv4类型,则固定4个字节长度;如果是域名类型,第一个字节是域名长度,剩余的内容为域名内容;如果是IPv6类型,固定16个字节长度。
- 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)的角色。
三、netty实现
1.基本实现
netty作为使用java实现的高级网络编程框架,实现socks5协议最终作为代理服务器程序再合适不过了。从上面的交互流程上来看,整个过程还是稍稍有些复杂的,netty框架的特色之一就是实现了各种协议的编解码器给开发人员使用,开箱即用,非常方便。
netty提供了三个解码器和一个编码器帮助开发人员实现socks5协议的服务端的绝大多数功能。
编码器 | 作用 |
---|---|
io.netty.handler.codec.socksx.v5.Socks5ServerEncoder | socks5协议交互过程中编码服务端给客户端的响应 |
解码器 | 作用 |
---|---|
io.netty.handler.codec.socksx.v5.Socks5InitialRequestDecoder | 版本和认证方式交互阶段解码客户端请求 |
io.netty.handler.codec.socksx.v5.Socks5PasswordAuthRequestDecoder | 认证交互阶段解码客户端认证请求 |
io.netty.handler.codec.socksx.v5.Socks5CommandRequestDecoder | 数据交互阶段解码客户端连接请求 |
这几个解码器解决了从抽象的协议请求到对象的转换;而编码器解决了对象到抽象的协议转换。所以这些编解码器只是解决了这些问题还是不够的,剩下的逻辑需要自己实现才行。所以对应着三个解码器,有三个后续的自定义的入栈处理器与其一一对应
处理器 | 作用 |
---|---|
Socks5InitialRequestInboundHandler | 响应版本和认证方式交互阶段客户端请求 |
Socks5PasswordAuthRequestInboundHandler | 响应认证交互阶段客户端认证请求 |
Socks5CommandRequestInboundHandler | 响应数据交互阶段客户端连接请求 |
在第三阶段,在收到客户端发起连接请求后,代理服务器连接目标服务器,这时候涉及到转发客户端的请求到目标服务器以及转发目标服务器的响应到客户端,所以这里设计了两个入栈处理器
处理器 | 作用 | 绑定的Channel |
---|---|---|
Client2DestInboundHandler | 转发客户端请求到目标服务器 | 客户端与代理服务器之间的Channel |
Dest2ClientInboundHandler | 转发目标服务器响应到客户端 | 代理服务器和目标服务器之间的Cahnnel |
2.黑名单处理
这里想要实现一个功能,就是在黑名单中的地址不允许连接,如果是http请求,则直接返回错误页面;https请求或者其它类型协议则直接断开连接。
这个功能在第三阶段连接阶段实现,因为只有这时候才知道客户端想要访问的网络地址。
//检查黑名单
if (inBlackList(msg.dstAddr())) {
log.info("{} 地址在黑名单中,拒绝连接", msg.dstAddr());
//假装连接成功
DefaultSocks5CommandResponse commandResponse = new DefaultSocks5CommandResponse(Socks5CommandStatus.SUCCESS, socks5AddressType);
ctx.writeAndFlush(commandResponse);
ctx.pipeline().addLast("HttpServerCodec", new HttpServerCodec());
ctx.pipeline().addLast(new BlackListInboundHandler());
ctx.pipeline().remove(Socks5CommandRequestInboundHandler.class);
ctx.pipeline().remove(Socks5CommandRequestDecoder.class);
return;
}
这里自定义了BlackListInboundHandler
处理http请求类型并返回在黑名单中的友好页面提示。
四、项目地址和使用说明
项目地址:https://gitee.com/kdyzm/socks5-netty
使用方法:由于在windows环境下系统并非天然支持socks5协议,所以需要借助Proxifier工具使其支持socks5;另外,如果出现了连接速度缓慢,有些网页打不开的现象,是Proxifier没设置好,一定要注意使用代理的dns设置,菜单:Profile->Name Resolution 取消Detect DNS settings automatically
选项,勾选Resolve hostnames through proxy
,之后就好了。
五、参考文档
https://zh.wikipedia.org/wiki/SOCKS
https://cloud.tencent.com/developer/article/1781560
https://www.dyxmq.cn/network/socks5.html
https://www.quarkay.com/code/383/socks5-protocol-rfc-chinese-traslation
https://blog.csdn.net/qq_33215972/article/details/105657960
https://segmentfault.com/a/1190000038498680
https://tools.ietf.org/html/rfc1928
https://tools.ietf.org/html/rfc1929
https://tools.ietf.org/html/rfc1961
使用netty实现socks5协议的更多相关文章
- netty系列之:netty对SOCKS协议的支持
目录 简介 SocksMessage Socks4Message Socks5Message 总结 简介 SOCKS是一个优秀的网络协议,主要被用来做代理,它的两个主要版本是SOCKS4和SOCKS5 ...
- [转]netty对http协议解析原理
本文主要介绍netty对http协议解析原理,着重讲解keep-alive,gzip,truncked等机制,详细描述了netty如何实现对http解析的高性能. 1 http协议 1.1 描述 标示 ...
- dubbo源码分析4-基于netty的dubbo协议的server
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
- netty 对 protobuf 协议的解码与包装探究(2)
netty 默认支持protobuf 的封装与解码,如果通信双方都使用netty则没有什么障碍,但如果客户端是其它语言(C#)则需要自己仿写与netty一致的方式(解码+封装),提前是必须很了解net ...
- netty对http协议解析原理解析
本文主要介绍netty对http协议解析原理,着重讲解keep-alive,gzip,truncked等机制,详细描述了netty如何实现对http解析的高性能. 1 http协议 1.1 描述 标示 ...
- HTTP协议和SOCKS5协议
HTTP协议和SOCKS5协议 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 我们平时上网的时候基本上是离不开浏览器的,尤其是搜索资料的时候,那么这个浏览器是如何工作的呢?用的又是 ...
- SOCKS5 协议解析
代理 根据 HTTP 1.1 的定义,proxy 是: An intermediary program which acts as both a server and a client for the ...
- netty支持的协议
流经网络的数据总是具有相同的类型:字节.这些字节是如何流动的主要取决于我们所说的 网络传输--一个帮助我们抽象底层数据传输机制的概念.用户并不关心这些细节:他们只想确保他们的字节被可靠地发送和接收. ...
- netty对http协议解析原理解析(转载)
本文主要介绍netty对http协议解析原理,着重讲解keep-alive,gzip,truncked等机制,详细描述了netty如何实现对http解析的高性能. 1 http协议 1.1 描述 标示 ...
随机推荐
- Tango with django 1.9 中文——3.Django基础
让我们开始运用Django.本章主要是给你一个关于创建新项目和新应用过程的概览.在本章的末尾,你将建立起一个简单的由Django驱动的网站. 3.1 配置测试 让我们测试以下你的Python和Djan ...
- MySQL注入点与SQL语句的关系
目录 注入位置分类 内联式 - UNION query SQL injection 终止式 - End SQL injection 堆叠式 - Stacked queries SQL injectio ...
- let、const、var区别?
let.const.var区别? let和const不存在变量提升(没有预解析,var有预解析). let和const在同一作用域范围内不能重复定义变量.(var可以). let和const有严格的作 ...
- 2020年12月-第02阶段-前端基础-CSS Day02
CSS Day02 复合选择器 后代选择器 并集选择器 1. CSS复合选择器 理解 理解css复合选择器分别的应用场景 为什么要学习css复合选择器 CSS选择器分为 基础选择器 和 复合选择器 , ...
- 【python+selenium的web自动化】- 8种元素定位方式详解
我们在做WEB自动化时,最根本的就是操作页面上的各种元素,而操作的基础便是元素的定位,只有准确地定位到唯一元素才能进行后续的自动化控制,下面将对各种元素定位方式进行总结归纳. 说明:以下操作统 ...
- P2014 选课 题解(树形DP)
题目链接 P2014 选课 解题思路 树形动归,用\(f[i][j]\)表示以\(i\)为根,\(j\)个子节点(不包括自己)的最大学分 首先根据题意建图,用根节点\(0\)将森林连成树. 从根节点开 ...
- golang 三维向量相关操作
package vector import ( "math" "fmt" )// 三维向量:(x,y,z) type Vector3 struct { X fl ...
- Ajax数据爬取--爬取微博
Ajax Ajax,即异步的JaveScript和XML.它不是一门编程语言,而是利用JaveScript在保证页面不被刷新,页面链接不改变的情况下与服务器交换数据并更新部分网页的技术. 对于传统的网 ...
- winnt.h
winnt.h https://docs.microsoft.com/en-us/windows/win32/api/winnt/ /*++ BUILD Version: 0091 Increment ...
- [BFS]P1434 [SHOI2002]滑雪
P1434 [SHOI2002]滑雪 Description Michael喜欢滑雪百这并不奇怪, 因为滑雪的确很刺激.可是为了获得速度,滑的区域必须向下倾斜,而且当你滑到坡底,你不得不再次走上坡或者 ...