shadowsocks 原理详解
详解
- 这个东西用的人不少,知道原理的人却不多,本文主要分析Shadowsocks实现的技术原理。
Shadowsocks的架构
Shadowsocks(后文缩写为SS)由两部分组成,客户端和服务器端。常用的客户端有shadowsocks-win、ShadowsocksX-NG、shadowsocks-Qt5、shadowsocks-android…;常用的服务器端有Python版本,Go语言版本,C、C++……。客户端启动后会开启一个本地代理(SOCKS5 / HTTP Proxy),通过修改操作系统配置或者浏览器配置把访问请求转发给本地代理。当我们通过浏览器访问某个地址的时候,数据会被转发到本地代理,由本地代理加密后转发到服务器端,服务器端处理完请求后把数据加密后返回给客户端的本地代理,本地代理再次返回给浏览器。
要澄清两点:1. SS协议和Http Proxy、Socks5没有半毛钱关系,这两个协议是浏览器或者操作系统所支持的标准代理协议,SS的架构中只是用这两种协议作为“获取用户请求”的手段而已。2. SS协议中没有任何控制流,本地代理获取用户原始TCP/UDP数据包获取之后会直接取出Data部分,重新构造一个IP数据包(可能是TCP或者UDP,和用户原始请求是TCP还是UDP有关系。),目标地址和端口是服务器地址,数据包的Data部分是加密后的用户原始Data。
协议详解
socks5 协议
- 请见 socks5 详解
- 该协议主要用于客户端流量代理到
ss-local
shadowsocks 协议
- 官方文档
- 用户实际请求的数据包。通过
ss-local
发送到ss-server
的格式十分简陋,由两部分组成:
1 | [target address][payload] |
ss-server
接收加密的数据流,解密并解析前导目标地址(target address
)。然后,将有效载荷数据转发给目标。ss-server
接收来自目标的回复,进行加密并将其转发回 ss-local。其中地址部分(
target address
)格式如下所示:
1 | [1-byte type][variable-length host][2-byte port] |
- 定义了以下地址类型:
- 0x01:主机是一个4字节的IPv4地址。
- 0x03:host是一个可变长度的字符串,从1字节长度开始,后跟最多255字节域名。
- 0x04:host是一个16字节的IPv6地址。
- 端口号是2字节的big-endian无符号整数。
数据传输
- 本部分将从本地流量产生出发,详细介绍整个流量转发的过程,可以根据转发流量的协议分成两种:tcp/udp
- 在shadowsocks的golang版本源码中,
ss-server
在同一个端口监听tcp/udp
TCP 流量
- 本地
tcp包
首先通过socks5
协议发送到ss-local
ss-local
将本地的tcp包数据加上target addr
,封装成 shadowsocks 协议包,发给ss-server
的tcp端口ss-server
解包,与target addr
建立tcp连接,将数据包发送给target addr
ss-server
将target addr
回的数据包通过原tcp连接返回给ss-local
ss-local
通过socks5
返回数据包
UDP
- udp 的整个流程和 tcp 类似,但是不同的是 udp 不是面对连接的,需要维持一个
nat map
- 当
ss-server
收到udp包时,回记录发送者的addr,为此创建一个 udp socket,并记录到nat map
中 - 通过上述 udp socket 发送/接受数据,收到数据时,根据nat map将数据发送给对应的
ss-local