|
本帖最后由 SmRiley 于 2020-3-12 21:22 编辑
此文并非原创,而是对吴浩麟大佬的你也能写个Shadowsocks错误疏漏以及对新手较为晦涩的内容进行重写.使之更便于新手理解与学习,原文最终成品为Lightsocks,此文中更替为SharpSocks.
目前主流的代理程序有Shadowsocks,shadowsocksR以及时下最火的V2ray等,但是其核心思想是一致的:对数据的加密混淆转发,如果只是要了解这最基础的功能,那么从Shadowsocks来剖析肯定是最合适的(据说最初的Shadowsocks只有400行代码,后期各种插件极其协议的55不在讨论行列),本文将教你从0写一个Shadowsocks,只需一点Socket的基础,读完本文你就能完成一个轻量级、高性能的 Shadowsocks 代替品。
我们暂且把最终完成的项目叫做 SharpSocks,如果你很急切地想看到结果,可以先体验本文最终完成的项目
SharpSocks
,也可以下载阅读源码。
麻烦带佬们帮我点个Star,也算是对我一点鼓励了,谢谢带佬
认识 Shadowsocks
Shadowsocks 是一个能骗过防火墙的网络代理工具。它把要传输的原数据经过加密后再传输,网络中的防火墙由于得不出要传输的原内容是什么而只好放行,于是就完成了防火墙穿透,也即是所谓的“上网代理”。
在自由的网络环境下,在本机上访问服务时是直接和远程服务建立连接传输数据,流程如图:
但在受限的网络环境下会有防火墙,本机电脑和远程服务之间传输的数据都必须通过防火墙的检查,流程如图:
如果防火墙发现你在传输受限的内容,就把拦截本次传输,就会导致在本机无法访问远程服务。
而 Shadowsocks 所做的就是把传输的数据加密,防火墙得到的数据是加密后的数据,防火墙不知道传输的原内容是什么,于是防火墙就放行本次请求,于是在本机就访问到了远程服务,流程如图:
也就是说使用 Shadowsocks 的前提是:
一台在防火墙之外的服务器;
在本机需要安装 Shadowsocks 本地端,用于加密传输数据;
服务器需要安装 Shadowsocks 服务端,用于解密加密后的传输数据,解密出原数据后发送到目标服务器。
Shadowsocks 原理
Shadowsocks 由两部分组成,运行在本地的 ss-local 和运行在防火墙之外服务器上的 ss-server,下面来分别详细介绍它们的职责(以下对 Shadowsocks 原理的解析只是我的大概估计,可能会有细微的差别)。
ss-local
ss-local 的职责是在本机启动和监听着一个服务,本地软件的网络请求都先发送到 ss-local,ss-local 收到来自本地软件的网络请求后,把要传输的原数据根据用户配置的加密方法和密码进行加密,再转发到墙外的服务器去。
ss-server
ss-server 的职责是在墙外服务器启动和监听一个服务,该服务监听来自本机的 ss-local 的请求。在收到来自 ss-local 转发过来的数据时,会先根据用户配置的加密方法和密码对数据进行对称解密,以获得加密后的数据的原内容。同时还会解 SOCKS5 协议,读出本次请求真正的目标服务地址(例如 Google 服务器地址),再把解密后得到的原数据转发到真正的目标服务。
SOCKS5 协议介绍
由于我此前写过一篇较为具体的文章,这里不做过多赘述,不懂的可以移步socks5文档详解
其实,这个协议简单理解为一个建立在TCP协议之上的数据传输封装协议就可以了.
SOCKS5 协议的目的其实就是为了把来自原本应该在本机直接请求目标服务的流程,放到了服务端去代理客户端访问。
其运行流程总结如下:
1.本机和代理服务端协商和建立连接;
2.本机告诉代理服务端目标服务的地址;
3.代理服务端去连接目标服务,成功后告诉本机;
本机开始发送原本应发送到目标服务的数据给代理服务端,由代理服务端完成数据转发。
当真正的目标服务返回了数据时,ss-server 端会把返回的数据加密后转发给对应的 ss-local 端,ss-local 端收到数据再解密后,转发给本机的软件。这是一个对称相反的过程。
由于 ss-local 和 ss-server 端都需要用对称加密算法对数据进行加密和解密,因此这两端的加密方法和密码必须配置为一样。Shadowsocks 提供了一系列标准可靠的对称算法可供用户选择,例如 rc4、aes、des、chacha20 等等。Shadowsocks 对数据加密后再传输的目的是为了混淆原数据,让途中的防火墙无法得出传输的原数据。但其实用这些安全性高计算量大的对称加密算法去实现混淆有点“杀鸡用牛刀”。
Sharpsocks 实现
要实现 Lightsocks 需要实现两部分:运行在本地的 lightsocks-local,和运行在墙外代理服务器上 lightsocks-server。
下面来分别教你如果使用 C# 来实现它们,采用 C# 语言的原因在于:性能好、跨平台、适合高并发、学习门槛低。
实现数据混淆
在 Shadowsocks 中是采用的标准的对称加密算法去实现数据混淆的,对称算法在加密和解密过程中需要大量计算。
为了简单起见,Sharpsocks 将采用最简单高效的方法去实现数据混淆,具体原理如下
这个数据混淆算法和对称加密很相似,两端都需要有同样的密钥。
这个密钥有如下要求:
由256个 byte 组成,也就是一个数组,在 C# 中类型表示为 [256]byte;
这个数组必须由 0~255 这256个数字组成,一个都不能差;
把1~255 这256个数字确定一种一对一的映射关系,加密是从一个数字得到对应的一个数字,而解密则是反向的过程,而这个密钥的作用正是描述这个映射关系。这其实就是中学学的反函数。
为什么要这样设计数据混淆算法呢?在数据传输时,数据是以 byte 为最小单位流式传输的。一个 byte 的取值只可能是 0~255。该混淆算法可以直接对一个个 byte 进行加解密,而无需像标准的对称算法那样只能对一大块数据进行加密。
再加上本算法的加解密 N byte 数据的算法复杂度为 N(直接通过数组索引访问),非常适合流式加密。而不像55或者别的加密传输一样会放大传输流量.
如果你看过”凯撒密码”的故事,一定会觉得相当熟悉,实际上这就是一个简单的将凯撒密码中的26个字母换成了字节的256位.以实现最简单的混淆,但是因为原理一样,所以和凯撒密码有着相同的弱点:即极其容易受到统计学与数学穷举的攻击.这个协议只能说足够用,但是SS的作者也说过Shadowsocks更注重混淆而非安全的话,所以暂时不需要考虑它的安全问题.
密码以字符串的形式出现,将字符串生成密码本的代码为:
[ol] /// /// 得到密匙 /// /// /// public static List Get_Pass(string Key) { int Bytes_Key = 0; foreach (var i in Encoding.UTF8.GetBytes(Key)) { Bytes_Key += i; } var random = new Random(Bytes_Key); var Bytes_Pass = new List(); for (int i = 0; i 复制代码
因为随机数的种子一样,所以相同密码对应的密码本是绝对一样的.至于加解密函数就更简单了
[ol]/// /// 加密 /// /// /// public static byte[] En_Bytes(byte[] Bytes) { var List_Byte = new List(); foreach (var b in Bytes) { List_Byte.Add((byte)Key.IndexOf(b)); } return List_Byte.ToArray(); } /// /// 解密 /// /// /// public static byte[] De_Bytes(byte[] Bytes) { var List_Byte = new List(); foreach (var b in Bytes) { List_Byte.Add(Key); } return List_Byte.ToArray(); }[/ol]复制代码
|
|