shadowsocks实现原理

shadowsocks是目前最好的科学上网方式,它的流量经过加密,所以没有流量特征不会被GFW阻断;关键是,它的实现原理也通俗易懂。

笔者是ss的重度用户,电脑和手机都在使用。本文不会介绍怎么安装使用shadowsocks,因为很多文章都有详细介绍。在文中简称shadowsocks为ss。

前言

shadowsocks已经出现很多年了,作者是clowwindy,大家可以去github查看他的主页。github上ss仓库https://github.com/shadowsocks/shadowsocks/tree/master的代码已经比较难维护了,状态机和epoll很好,提高了程序的性能效率,但是很多东西也影响了我们去看核心的东西是什么。所以本文解析的是一个轻量级的ss,clowwindy写的比较早的版本,那个时候使用select而不是epoll,网络通信的逻辑也很清晰,容易了解ss的原理,代码的仓库为https://github.com/YvesChan/shadowsocks

概述

ss要求本机运行local.py,海外服务器运行server.py。local.py默认监听localhost的1080端口,该端口代理浏览器的请求。browser要访问google时,会和localhost:1080进行一次基于sock5协议的通信,如上图的红色虚线框,sock5协议可以去了解下,维基百科有不错的介绍。

代理的流程如下:

  1. localhost:1080经过sock5协议后,就知道要访问google了

  2. local程序会把流量加密,然后把普通的TCP流量发往海外服务器;

  3. 海外服务器收到请求后,解密得到要访问google

  4. 海外服务器请求google后把得到的数据加密返回给local

  5. local解密返回给browser。

ss的解密和加密基于用户设置的密码,所以local和server之间可以做到加密和解密的一致。

网络编程

python网络编程相比C语言要少很多代码,由于有很多封装得很好的类可以使用,网络编程更加符合思维走向。作者clowwindy使用了SocketServer.TCPServer和SocketServer.StreamRequestHandler两个类完成TCP的处理。在python的官方文档可以查看到两者的详细介绍。从名字中也可以知道两者的作用:TCPServer负责处理连接accept或close等,此类的构造函数要求传入Handler类;Handler类负责连接的数据处理,包括recv和send,此类要求实现handle方法。StreamRequestHandler更进一步把recv和send封装为rfile读端的read和wfile.write,把socket操作转化为了文件的读写,更加便捷。

local程序的handle方法:

图截自github,本人已经标注handle函数每个部分的作用,最后的handle_tcp等待sock和remote的事件,sock可读则读取然后发往remote,remote可读就读取然后发往sock,代码如下图:

注意encrypt和decrypt,加密和解密的算法感兴趣可以去看看代码,使用到了python自带的加密解密方法。

server端的handle方法就不再截图了,因为和local.py很类似,只是一些细节流程不一致而已。大家感兴趣可以下载代码阅读。

运行效果
服务端先运行server.py后,本地运行loca.py,并且设置浏览器代理为本地1080就OK了

总结

ss除了python版本之外还有c和go的版本,后两者的口碑比python版本的好一点。

感谢clowwindy大牛,正是有能力的人的辛勤且无悔的付出,开源领域才越来越繁荣。

最后,我们应该为生活在有github的时代而感到幸福。