shadowsocks-libev源码阅读总结
数据协议
socks5
握手阶段
1 | // client send |
客户端发起握手请求,数据格式如上图所示,具体如下
- VER:固定0x05,表示socks5协议
- NMETHODS:表示支持认证的方法数量,也是后面的METHODS字段占用的字节数
- METHODS:认证方法列表,一个协议占用一个字节,其中一些常见的协议如下
- 0x00:不需要认证
- 0x01:GSSAPI
- 0x02:用户名、密码认证
- 0x03~0x7F:保留
- 0x80~0xFE:私有
- 0xFF:无可接受的方法
1 | // |
服务端响应内容如上图所示,具体如下
- VER:固定0x01
- METHOD:认证方法,在shadowsocks源码里,选择0x00-不需要认证
认证阶段
忽略
请求连接阶段
1 | // |
客户端发起请求,数据格式如上图所示,具体如下
- VER:固定0x05
- CMD:命令码
- 0x01:CONNECT请求
- 0x02:BIND请求
- 0x03:UDP转发
- RSV:保留字段,默认0x00
- ATYP:目的地址类型
- 0x01:ipv4
- 0x03:域名
- 0x04:ipv6
- DST.ADDR:目的地址
- ipv4:4个字节
- 域名:1字节的len+最大255字节的域名
- ipv6:16个字节
- DST.PORT:目的端口,固定2个字节
1 | // |
服务端响应内容如上图所示,具体如下
- VER:固定0x05
- REP:响应码
- 0x00:成功
- RSV:保留字段,默认0x00
- ATYP:目的地址类型
- 0x01:ipv4
- 0x03:域名
- 0x04:ipv6
- BND.ADDR:服务器地址,一般为127.0.0.1或0.0.0.0
- BND.PORT:服务器端口
注意:BND.ADDR跟BND.PORT如果是用在tcp连接时可以忽略,没什么用。但在udp里,这是后续数据传输的实际地址
数据中继阶段
数据是原始的TCP流,不再有额外协议头
shadowsocks
1 | // |
shadowsocks会在数据流的前面加上3个字段,同socks5协议后面的几个字段,当然,这里指的是加密前的数据格式
shadowsocks
数据传输流程
1 | // |
应用角色
ss-server
- ss-server是服务器端进程,负责接收ss-local、ss-tunnel、ss-redir的客户端请求
- 负责将数据解密,然后根据目标地址,创建远程连接并中转数据,如上图的数据传输流程中的server角色
- 支持tcp和udp协议,但插件仅支持tcp协议
- 支持配置ACL过滤(即根据ip/域名判断是否block,用于广告过滤等)
ss-local
- ss-local本身是一个socks5服务器进程,负责接收应用数据,转发给ss-server
- 支持配置多个server地址,用于负载均衡(随机选一个服务器地址发送数据)
- 支持tcp和udp协议,但插件仅支持tcp协议
- 支持配置ACL过滤(即根据ip/域名判断是否需要proxy或直连或block)
ss-tunnel
- ss-tunnel类似ss-local,不同的是,这是一个单目标代理,应用数据转发给ss-server时,remote的地址会被ss-tunnel替换为一个固定值,比如8.8.8.8:53,常用于dns查询
- 支持配置多个server地址,用于负载均衡(随机选一个服务器地址发送数据)
- 支持tcp和udp协议,但插件仅支持tcp协议
- 不支持ACL配置
ss-redir
- ss-redir类似ss-local,不需要手动配置应用代理,只需要跟nftables配合导流到ss-redir端口,实现透明代理
- 支持配置多个server地址,用于负载均衡(随机选一个服务器地址发送数据)
- 支持tcp和udp协议,但插件仅支持tcp协议
- 不支持ACL配置
- 可以根据qos建立tcp、udp服务器
注意事项
- client->server->remote第一次请求过程中都会强制禁用nagle算法,完成第一批数据交换后才会根据配置判断是否开启nagle算法
- plugin-插件的交互方式实现很粗糙,本质是建立一个进程通过tcp来交互数据
- udp数据传输不支持plugin-插件,可以被gfw检查出