shadowsocks 原理详解

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。

ss架构图

协议详解

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 流量

  1. 本地 tcp包 首先通过 socks5 协议发送到 ss-local
  2. ss-local 将本地的tcp包数据加上 target addr,封装成 shadowsocks 协议包,发给 ss-server 的tcp端口
  3. ss-server 解包,与target addr建立tcp连接,将数据包发送给 target addr
  4. ss-servertarget addr 回的数据包通过原tcp连接返回给 ss-local
  5. ss-local 通过 socks5 返回数据包

UDP

  • udp 的整个流程和 tcp 类似,但是不同的是 udp 不是面对连接的,需要维持一个 nat map
  • ss-server 收到udp包时,回记录发送者的addr,为此创建一个 udp socket,并记录到 nat map
  • 通过上述 udp socket 发送/接受数据,收到数据时,根据nat map将数据发送给对应的 ss-local