[学习记录]源码分析-lightsocks

这次是第一次研究别人的源码,之前因为看不懂,太长不看,不理解相对正规的写法等等,所以并没有很认真地读完过。

这一次首先读的源码较简单,其次也是稍微静下心来好好梳理了一下代码逻辑,并且把自己学到的东西记录下来。

gitub源地址  传送门

----------------------------------------------------------

1.目录结构

可以看出来大概目录树的情况,lightsocks目录下有core和utils两个子目录,utils下放置的是config.py和net.py,大概推测是配置信息和网络信息

core中包括cipher.py, password.py, securesocket.py,推测为加密解密模块、密码模块和安全socket模块。在lightsocks目录下有local.py和server.py, 应该就是负责服务器和客户端的模块,而在lightsocks目录外还存在lslocal.py, lsserver.py,推测这两个文件才是最终的服务端和客户端。

以上推测以未正式阅读源码为前提。

 

 -----------------------------------------------------

然后开始正式阅读源码,编程思想主要有两种,自顶向下或自底向上,

自顶向下即先思考整个系统的构成,然后一块一块拆分成子模块,再一点点地实现这些子模块,优点是整个系统功能会非常清晰,对于庞大的系统而言不易产生混乱。

自底向上即先考虑系统需要哪些基本功能,先将基本功能实现再堆砌起来,优点是代码复用性高。

 

这次采用自底向上的方法,先了解每个子模块的功能,再一点一点向上整合,最后拼出整体功能。

 

以下分析不直接粘贴源码,直接介绍感悟,源码传送门已经放在上面了。

----------------------------------------------------------------------------------------

cipher.py

1.创建了一个 cipher类,创建时需要提供加密密码和解密密码,拥有加密解密两种常用的方法,分别将利用对应密码来对输入内容进行加密解密。还具备一个类方法,输入加密密码,生成解密密码并且返回一个cipher实例

2.可以将cipher理解成这样一个角色:持有自己独一无二的密码,主要任务是负责对数据进行加密解密。

3.加密解密算法可以自定义,作者提供的是简单的位移变换

--------------------------------------------------------------------------------------------

password.py

1.这是一个方法库,定义了一个自定义的错误类型以及众多和密码有关的方法

2.通过如下格式定义了一个错误

class InvalidPasswordError(Exception):
    """不合法的密码"""

3.定义了一个安全性函数,用来检查密码是否合法。该函数被频繁地调用,并且会raise之前定义的密码错误

4.定义了将字节型的密码和字符串型密码相互变换的两个函数。

---------------------------------------------------------------------------------------

securesocket.py

1.通过如下方式引入了之前编写的类

from .cipher import Cipher

2.创建了一个安全套接字类

该类传入一个asyncio的事件循环和密码类进行创建

设置了用于单向通信的decodeRead和encodeWrite,

设置了用于持续双向通信的encodeCopy和decodeCopy,其中encodeCopy为获取信息后调用encodeWrite进行加密发送,decodeCopy为获取加密信息后解密再发送。至此可以推测解密发送是发送给被请求的主机,加密发送为发送给客户端。

--------------------------------------------------------------------------------

config.py

1.通过如下方式调用另一个目录下的文件

from lightsocks.core.password import (InvalidPasswordError, dumpsPassword,
                                      loadsPassword)

2.使用了一个namedtuple的结构,简要描述下就是一个包含名称的元组,可以直接通过属性名访问属性,类似一个没有方法仅有属性的对象

3.定义了将URL和Config对象相互转换的方法

4.定义了Config和json字符串互相转换的方法

5.定义了Config和json文件的转换方法

6.语法知识

*#告诉函数,入参是一个tuple

**#告诉函数,入参是一个dict

---------------------------------------------------------------------------------------------------

net.py

使用namedtupe定义了一个地址对象

为了构造一个namedtuple需要两个参数,分别是tuple的名字和其中域的名字。

例如

Address = namedtuple('Address', 'ip port')

tuple名字为Address,内部子域有ip和port

-----------------------------------------------------------------

local.py

1.创建了lslocal类,该类为securesocket的子类,为了创建它徐娅传入异步事件循环,字节型格式密码,代理监听地址与远程访问地址

定义了监听方法,用来与代理服务器进行通信,在循环中执行handleConn方法

定义了dialRemote方法,用来与代理服务器通信,是直接连接。

定义了handleConn方法,首先通过一个协程调用dialRemote获取连接,然后维持本地客户端与代理服务器的通信。

--------------------------------------------------------------------

server.py

1.定义了LsServer类,为了创建它需要传递一个事件循环、字节流密码以及监听地址

定义了监听方法,等待客户端的请求,

定义了请求处理方法handleConn:首先依照socks5协议进行协商,其中的通信均由decodeRead和encodeWrite完成,为了规避防火墙的检查。然后服务器接收用户传递的数据提取目的ip,目的端口。最后维护代理服务器与远端服务器的通信。

---------------------------------------------------------------------

lslocal.py

1.使用了argparse进行命令行参数解析,并进行初步设置,如果无要求则导入默认设置

2.最后本地运行客户端级服务器

-------------------------------------------------------------------------

lslocal.py

1.使用了argparse进行命令行参数解析,并进行初步设置,如果无要求则导入默认设置

2.最后运行代理服务器

--------------------------------------------------------------------------

 

 

小结

该程序总体代码量不算太长,各个模块较独立,易于修改。在面向对象方面在底层的一些事务处理全是由实例完成,

仅部分服务端与客户端都有相同需求的函数定义在utils库中。

最后再梳理一下shadowsocks的原理,本地在上网时通过本地代理服务器进行访问,本地代理服务器将会与远端的代理服务器进行加密通讯,最后交给远端代理服务器访问我们真正想要访问的网站。

posted @ 2019-06-26 14:34  冷血无情康纳酱  阅读(370)  评论(0编辑  收藏  举报