兑现之前的承诺。其实网上这类的文章比较多,但是还是想自己分析一下,加深印象。这里用的是nodejs的版本分析,究其原因,因为最近正在复习nodejs,所以趁热打铁吧。
项目地址:https://github.com/shadowsocks/shadowsocks-nodejs
其实shadowsocks的原理比较简单,最初的思想无非是把socks5协议拆分,并且加密了中间数据。
好吧,我们这里分析客户端,首先是本地创建了一个监听:
exports.createServer = createServer;
这个createServer函数定义是:
createServer = function(serverAddr, serverPort, port, key, method, timeout, local_address);
这其中创建了一个监听,作为socsk5的服务器,也就是我们本机流量走向的第一个地方:
server = net.createServer(function(connection);
其余的udpRelay部分不是分析重点,继续分析:
encryptor = new Encryptor(key, method);
这里创建了encryptor是用来进行后来的数据加密,科科shadowsocks的重要特性就是支持多种加密协议,其实我们也可以改写并添加自己的协议,不过貌似大部分人不会酱紫做,做了也不会公开吧0.0
connection.on("data", function(data) {});
这里监听数据到来事件,里面分成多个stage(stage 1,5,10等),初始化为stage 0并不包括在这5个stage中,因为此时协议还没握手0.0
if (stage === 0) { tempBuf = new Buffer(2); tempBuf.write("\u0005\u0000", 0); connection.write(tempBuf); stage = 1; utils.debug("stage = 1"); return; }
这里的stage 0发送的奇怪的unicode是什么呢?其实是socks5协议的头,socks5的协议过程如下:
1.向服务器的1080端口建立tcp连接。
2.向服务器发送 05 01 00 (此为16进制码,以下同)
3.如果接到 05 00 则是可以代理
4.发送 05 01 00 01 + 目的地址(4字节) + 目的端口(2字节),目的地址和端口都是16进制码(不是字符串!!)。 例202.103.190.27 -7201 则发送的信息为:05 01 00 01 CA 67 BE 1B 1C 21 (CA=202 67=103 BE=190 1B=27 1C21=7201)
5.接受服务器返回的自身地址和端口,连接完成
6.以后操作和直接与目的方进行TCP连接相同。
其实就是过程3,这里我们扮演的是本地socks5服务器的角色,谨记。那么后面的过程呢? 其实都是相同的,建立了一个没有密码验证的socks5服务器,其作用就是来接受本地数据。
接下来,按照socks5协议,响应了本地连接请求。之后:
remote = net.connect(aPort, aServer, function() {});
这里就是建立连接到远程的shadowsocks服务器的连接。然后,就进入stage 5了,就愉快的使用
data = encryptor.decrypt(data);
或者相反的方法互传数据了0.0其实到这里就差不多了,其余的部分:
remote.on("data", function(data) {});
你懂得,就是远程服务器返回数据时触发,然后数据回写。
其余的部分就是超时和事件处理,这里不再赘述。
exports.main = function() {});
其实就是说,导出一个main函数,然后
if (require.main === module) {
exports.main();
}
看bin文件夹下的sslocal:
#!/usr/bin/env node var path = require('path'); var fs = require('fs'); var lib = path.join(path.dirname(fs.realpathSync(__filename)), '../lib'); require(lib + '/shadowsocks/local').main()
这个才是最后的入口,是为了兼容shadowsocks的可执行文件路径。这里赞下,整个lib下所有文件都是每个文件有一个单独的立即执行匿名函数,酱紫保证自己的代码作用域不会污染全局作用域0.0,其中call(this)导入了exports这个对象引用。
以上就是简单的分析内容,其实我们可以添加自己的加密方案,错误处其实程序已经做的不错了,Nodejs的单线程异步模型,错误处理不好的话,很容易就满盘皆输0.0
转载请著名: SpringHack