Freenet 概述
Freenet 是 Ian Clarke's 在 1999~2001 年于爱丁堡大学(University of Edinburgh)的学生项目。其是一个基于点对点的分布式信息存储和检索系统,其开源于 Github。其主要开发者也经过多次更迭。
严禁来说,Freenet 只是一个分布式的文件资源存储和检索系统,并不是严格意义的匿名通信工具,但是由于网站本身也是一种资源,因此可以在其内部搭建网站,并实现各种服务。与 Tor、I2P 等工具相比,其更类似于 BitTorrent 等技术。
安装及使用
Windows 环境下,直接下载安装包即可
在 Linux 下,原则上可以使用包管理安装。但是由于未知原因,Arch Linux 目前版本的包有问题,会安装失败,因此选择文档中的安装方式
wget 'https://github.com/freenet/fred/releases/download/build01485/new_installer_offline_1485.jar' -O new_installer_offline.jar;
java -jar new_installer_offline.jar -console
需要额外注意的只有一点,如果是纯命令行的 Linux,需要加上 -console
参数,而有图形界面的则不必加
安装完成后,进入安装目录,使用./run.sh
控制 freenet 的运行
Your java executable at /bin/java seems suitable Usage: ./run.sh { console | start | stop | restart | status | dump }
预备知识
六度分隔理论
六度分隔理论(Six Degrees of Separation, SDS)是一个广为人知的理论:任意两个互不相识的人,平均只需要通过 6 个人即可建立联系。
美国社会心理学专家 Stanley Milgram 曾经根据此问题进行了小世界时延,尽管实验本身由于各种外界因素被收到质疑,但是随着目前互联网技术的发展,各大平台的内部数据都可以证明该理论的正确性(任意两个维基词条的跳转次数,Facebook、MSN 的好友网络……)
而该理论在 P2P 网络中,则说明了即使每个 P2P 节点只有极少数的邻居,但是最终能将信息发送到任意一个节点
分布式哈希表
分布式哈希表(Distributed Hash Table, DHT)是一种根据哈希距离在分布式系统中检索数据的方法
要存放的数据会按照哈希距离(节点的哈希和文件哈希取异或计算距离)存放在距离其最近的节点中。每个节点会维护距离自己比较近的多个节点信息以及特定区间内的部分节点数据(K-桶)
要查询时,如果当前节点知道要查询的节点信息,则直接返回对应的节点信息;否则则会计算对应的节点在某个 K-桶 中,并将查询转发给自己认识的对应桶内的节点,由其进行进一步查询。
由于二叉树的特点,该查询效率是 的。
使用该方式,可以快速将查询送至距离结果较近的节点,并且由于每个节点会优先与距离自己近的节点建立连接,因此会很快得到查询结果
键
Freenet 中每一个文件都存在一个键用以作为资源索引符。大部分的键都是散列的,且不存在相关性
要访问Freenet的资源,可以使用 FProxy 来访问资源,类似于http://localhost:8888/[Freenet KEy]
在 Freenet 中,有下面几种键
- 内容散列键(Content Hash Key, CHK): 最基本的键,所有超过 1kB 的文件都会被划分成一个或多个 32kB 的 CHK,其文件名由其内容决定
- 符号子空间键(Signed Subspace Key, SSK): SSK 将公钥与人们可读的文件名组合
- 可更新子空间键(Updatable Subspace Key, USK): 可更新的密钥形式,对于站点和地址解析密钥尤其有用
- 关键字签名键(Keyword Signed Key, KSK): 由可读的文件名构成
- 地址解析键(Address Resolution Key): 是节点在 IP 发生变化时插入的 USK,其包含节点的引用
内容散列键(CHK)
由于哈希的特点,同一个 CHK 只会对应一个文件,即使节点的改动很小,仍然会生成不同的 CHK。
每一个 CHK 将包含下面三部分:
- 文件哈希
- 文件解密密钥
- 加/解密方法
其格式为: CHK@file hash,decryption key,crypto settings
一个实际的例子是: CHK@SVbD9~HM5nzf3AX4yFCBc-A4dhNUF5DPJZLL5NX5Brs,bA7qLNJR7IXRKn6uS5PAySjIM6azPFvK~18kSi6bbNQ,AAEA--8
要访问该地址,只需要通过 FProxy 中访问: http://localhost:8888/CHK@SVbD9~[..]X5Brs,bA7qLN[..]Si6bbNQ,AAEA--8
符号子空间键(SSK)
符号子空间键主要用于那些可能会随着时间改变的站点,如网站可能会对内容进行增删改。
使用 SSK 可以确保用户可以使用一个固定的内容访问你的资源,同时确保只有所有者可以对其进行修改
每一个 SSK 包含五个部分:
- 公钥散列
- 文件解密密钥
- 加/解密方式
- 用户选择名称: 维护者选择的一个名称
- 版本: 站点的版本
由于无法更新 Freenet 中已插入的数据,因此在这里版本需要是确保递增的
使用 USK 可以确保这部分内容对用户透明
其格式为: SSK@public key hash,decryption key,crypto settings/user selected name-version
一个实际的例子是: SSK@GB3wuHmt[..]o-eHK35w,c63EzO7u[..]3YDduXDs,AQABAAE/mysite-4
SSK 工作方式:
- 文件的作者生成一个密钥对: 用于签署文件的私钥和验证签名
- 生成一个对称密钥: 用于加解密文件
- 将文件插入到 Freenet 中使用对称密钥加密并使用私有密钥签名
签名存储在文件中,节点不存储对称密钥只存储 SSK 的公钥,作为数据的索引。这么做可以保证节点的拥有者可以验证文件是否被修改,同时只有有密钥的访问者可以解密文件本身
SSK 基本已经被 USK 替代,USK 可以理解成是支持自动检索最新版本的 SSK
可更新子空间键(USK)
实际上 USK 是一个对用户友好的 SSK 包装器,其隐藏了搜索站点最新版本的过程
一个典型的 USK 密钥格式: USK@public key hash,decryption key,crypto settings/user selected name/number/
除去少了版本号外,其与 SSK 几乎相同
USK 有两个版本:
- 结尾是正数: 自己的节点会维护一个已知的版本列表,根据上次访问的记录来确定本次访问的版本,同时在后台持续与其他节点交互获取最新的版本号
- 结尾是负数: 将会从负数的绝对值开始查找后面 5 个版本是否存在,如果连续四次都不存在,则使用已知的最新版本
关键字签名键(KSK)
允许在 Freenet 中保存指定的页面,不同人可以各自插入不同的文件,且拥有相同的地址
由于任何人都可以插入同名的文件从而导致将访问指定文件的流量截取,但是仍们可以更容易地记住可读的链接
KSK 可以包含对 CHK 的重定向,也可以包含文件本身
其格式: KSK@myfile.txt
容器(Container)
容器是一个最大不超过 2MB 的压缩包
当要加载一个页面时,可以使用一个键获得该页面对应的所有文件
连接建立
对于目前版本的 Freenet,连接存在两种模式:
- 非安全模式(Opennet): Freenet 自动查找结点(陌生人结点)
非安全模式下,如果自己的结点是新建立的结点,可能需要几天的时间才能找到足够的节点用以通信(这个过程会用到中心服务器,并且很容易被审查,因此……) - 安全模式(Darknet): 只连接自己认识(现实中)人提供的结点
在安全模式下,需要自己结点中添加好友的信息,同时好友也必须添加自己的信息(信任必须是相互的),当网络建立成功后,相当于成立了一个私有的群组网络,因此也可以认为构建了一个暗网
一般而言,要确保功能正常使用,至少需要确保有 3 个节点能够持续连接,理想状况下应该有 5~7 个节点。而由于有些节点可能会下线,因此需要保证更多的节点连接才能获得预期的效果。通常而言,需要保证有十个好友后,才可以关闭不安全模式。
对于每个节点而言,只有与其直接连接的节点(好友)才是可见的,并且流量也只会被发送到这些节点。
尽管每个节点只能和自己认识的节点连接,但是由于每个人都会连接自己认识的人,根据六度分隔理论2,节点可以通过中转连接到其余任意一个节点,实现访问整个网络。
用于 IPv4 的地址数量问题,(国内)很多设备并没有公网 IP,只能通过 NAT 转发上网。由于没有中央服务器的存在,无法进行 UDP 打洞,因此要求节点应该手动设置 NAT 的端口转发。(如果不设置,只有在邻居中存在有公网 IP 或者转发端口的 NAT 才能建立连接)
路由构建
无论是要上传(插入)文档还是要下载(检索)文档,都将与和自己所能联系到的,与文件哈希距离最近的节点建立连接。这个过程很类似于分布式哈希表3
也即任务为:当前节点要寻找距离指定文件哈希值最近的节点
首先,发出请求的节点,要生成一个请求,请求包含以下内容:
- 全局唯一的请求ID(global universally unique identifier, GUID)
- 跳数限制(hop-to-live, HTL)
- 深度限制
- 要请求的文件键
该请求将会采用深度优先遍历(Depth-first Search, DFS),在网络中进行遍历。由于要寻找的是距离特定哈希值最近的节点,因此将优先遍历距离该哈希最近的节点
每个节点收到请求时,会首先检查自己是否存在对应的文件,如果存在则将文件返回,否则会继续向按照距离顺序向自己认识的节点转发请求。如果节点收到请求时,跳数或深度超过限制值,则其会直接拒绝请求。
在返回文件的过程中,从请求发起节点和拥有文件所属节点所途径的所有结点都会自己保存一份文件,以加速下次请求的速度。同时在这个过程中,节点可能认识更多新的陌生节点,并将其加入自己的邻居节点
按照上述的流程,尽管在网络构建初期,其路由近似随机构建,但是随着使用次数的增加,其会按照键来对文件进行集群,借助该模式,整个网络中文档将会被划分成多个集群,从而加速检索。
在检索内容的过程中,实际上文件内容和 CHK 并不需要有特殊的关系,只需要保证所有的节点都按照同样的算法检索即可。
比如可以按照节点 ID 与 CHK 取异或,按照结果中 1 的顺序从高到底开始尝试检索
当检索到内容时,由于这条检索线路上的所有节点都会保存一份文件,相当于文件在逐渐向节点 ID 异或 1 更多的节点“移动”(资源会随着检索次数的降低而被删除)
最终,随着整个网络检索次数的增加,文件将越来越趋近于它应该在的节点,总体的检索消耗会越来越小
协议
在两个 Freenet 节点间建立一条新的连接,将会根据谈判类型(Negotiation Type,negType)决定握手阶段的协议:
- negType=7: DSA + DH
- negType=8: DSA + ECDH
- negType=9: ECDSA + ECDH
内容
Freenet 作为一个内容分发网络(Content Distribution Network, CDN),其还拥有如下优点:
- 完全分散: 信息不需要依赖任何集中式的服务器,只需要将内容的“键”提供给别人即可下载
- 自适应缓存: 许多 CDN 架构只允许已下载文件的对等点和其他对等点共享文件,Freenet 将会根据需要自适应地缓存对等点的信息,以满足需求(比其他的方案更容易扩展,并且改进了负载均衡的实现)
- 安全: Freenet 长期以来一直支持“内容散列键”的概念,以保证检索到的数据的完整性。Freenet 还支持允许对内容进行数字签名的“符号子空间键”,这也保证了内容的完整性
- 前向纠错: 与其他 CDN 架构一样,Freenet 使用前向纠错,即使一些文件的某些部分无法检索,也可以重构该文件。特别的是,Freenet 还支持修复、重建的功能
由于部分内容可能会降低匿名性,因此 Freenet 会删除或替换危险的内容(如跳转到互联网的链接、插入的图像、插入的脚本)
优缺点
原始版本的评价
Hanlin D. Qian 针对最初的论文进行了如下评价4:
传统文件存储系统存在的问题:
- 文件只存储在几个主机(中心节点)上,拒绝服务攻击和系统故障都会导致系统无法使用
- 文件的所有者无法隐匿个人的身份和信息本身
- 恶意的第三方可能修改存储的信息
而 Freenet 则解决了这些问题,并且提供了如下优点:
- 信息生产者和消费者的匿名性
- 信息存储器的可变性
- 拒绝第三方非法访问信息的可能
- 高效的动态信息存储和路由
- 所有网络功能均有节点自己完成
- 每一个请求都有一个事务 ID、一个跳数计数器和深度计数器,确保数据不会被无限转发
- 数据的复制将在传输路径的每个节点复制
- 插入数据冲突时,原始文件将会在传播路径上传播,避免恶意插入的干扰
- 每一跳都是随机的,避免文件发送者身份泄露
- 请求密钥和文件本身都会加密,因此节点所有者也无法访问存储的信息
- 每个节点的路由表只会维护有限的数据。当超过存储上限时,按照最近最少使用(LRU)算法替换文件,因此存储的文件需要经常请求以确保维护
Freenet 可能存在的缺点:
- 为了确保安全,数据的检索将变得困难
- 文件需要经常性地被访问避免被删除
而在 Freenet 官网,也将 Freenet 和 Tor 等工具进行对比,并指出了其相对的优势以及弱势
优点:
- 站点维护者不再需要维护服务端(站点文件会被发送到其他节点)
- 在安全模式下,不存在中心节点,很难被监管(用户可以和好友间组织一个“局域网”)
- 文件将会被发布到很多节点中保存,且可以确保安全性和隐私性
缺点:
- 不能访问谷歌等正常网站站点(Freenet 只能访问其构建的网络内部的站点)
- 冷门数据不会被永久保存(节点本身会删除资源,且节点可能会下线)
- 无法知晓自己贡献的空间被用于存放何种数据
- 文件的更新较为复杂
- 只支持静态站点