7个版本
0.9.12 | 2024年6月5日 |
---|---|
0.9.10 | 2024年2月2日 |
0.9.8 | 2024年1月8日 |
0.9.6 | 2023年11月30日 |
0.9.4 | 2023年10月31日 |
#578 in 网络编程
每月414次下载
用于 aelhometta
51KB
596 行
Emyzelium (Rust)
是ZeroMQ的ZeroMQ的发布-订阅消息模式的另一个包装器,具有强制性的Curve安全和可选的ZAP身份验证过滤器,通过Tor,通过Tor SOCKS代理,用于分布式人工生命、决策等系统,其中每个对等方,由其公钥、洋葱地址和端口号标识,将数据字节数组向量发布到其他对等方订阅的唯一主题下,并接收相应的数据。
需要Rust、libzmq (更多关于构建信息,例如Linux中的libzmq3-dev
和libzmq5
软件包)和Tor。
其他语言版本
警告
在有些任务和规模中,这种模型可能成功(从宠物级项目开始),而在有些任务和规模中,它将失败得很惨(以行业级和特别是关键基础设施级结束),直至国际哀悼日。请谨慎行事。
另请参阅 真菌感染。
演示
让我们使用 Emyzelium 将可分配性引入细胞自动机,包括经典的 康威生命游戏 及其变体。 一旦... 更多... 再... 再次...
为了明确起见,假设使用已安装 Rust 和 libzmq5
软件包的 Linux 系统。但演示也应该在其他操作系统上运行。
在单台连接到互联网的计算机上
使用 RAM 中同一台计算机上的对等节点连接时,是否需要 Tor 和公钥加密?当然不需要。然而,在涉及多台计算机之前,可能您想确保这个事情在原则上可以工作。
首先,安装 Tor,到您的 Linux,并在 3 个不同的端口上设置 3 个隐藏服务,任意大于 1024 的端口。更准确地说,在您的 /etc/tor/torrc
中添加以下类似的行
HiddenServiceDir /var/lib/tor/p2p_dummysite1/
HiddenServicePort 60847
HiddenServiceDir /var/lib/tor/p2p_dummysite2/
HiddenServicePort 60848
HiddenServiceDir /var/lib/tor/p2p_dummysite3/
HiddenServicePort 60849
并在终端(注意 tor@default
而不是 tor
)中
$ sudo systemctl restart tor@default
然后检查是否有任何问题
$ systemctl status tor@default
应显示 ... active(正在运行) ...
和 ... 引导 100% (完成): 完成 ...
等待 3 个指定的目录出现,在每个目录中,都有一个名为 hostname
的文件。
现在下载 Emyzelium 文件,例如到 ~/emz-rs/
,或者简单地通过 cargo install emyzelium
。打开 examples/demo.rs
并在导入之后,将 ALIEN_ONION
的值更改为来自 /var/lib/tor/p2p_dummysite1/hostname
的洋葱地址(不要包含 .onion
后缀)。同时将 ALIEN_PORT
的值更改为 60847
如果它不是这个值的话。
对 JOHN_ONION
、JOHN_PORT
(2)和 MARY_ONION
、MARY_PORT
(3)进行类似的更改。将更改保存到 demo.rs
。
您还可以检查这些洋葱地址是否已为 Tor 网络所知;如果是的话,例如 netcat
应该可以工作,— 打开 2 个终端并查看是否如此
term1$ nc -v -l 60847
term2$ torsocks nc -v ONION1.onion 60847
来自 ...
和 连接到 ...
表示洋葱是可到达的。如果它们不可达,请等待几分钟。
从 ~/emz-rs/
构建
$ cargo build --release --example demo
最后,进行 Life 的 emyzelium 化。打开 3 个终端,并从 ~/emz-rs/
以任意顺序运行以下命令
term1$ cargo run --release --example demo Alien
term2$ cargo run --release --example demo John
term3$ cargo run --release --example demo Mary
(或者,从 ~/emz-rs/target/release/examples/
运行 ./demo Name
。)
然后您应该看到类似以下内容
- 终端 1(对等节点 Alien)
- 终端 2(对等节点 John)
- 终端 3(对等节点 Mary)
当Alien的、John的、Mary的同伴(efungi)在Tor上建立连接(ehyphae)后,它们的细胞自动机(realms)可以实时地交换细胞区域(etales)。
在建立连接之前,SLUs(自上次更新以来)是“大”的(尚未更新);之后它们保持在0-10秒范围内。按“1”或“2”实际导入其他领域的更新区域。
如果您将导入和发射都设置为自动,例如每8秒从随机其他领域导入,那么整个过程将更加自主。当然,在这样的小环境中,进化潜力有限。
请注意,Alien的CA,B34/S34的出生/生存规则与John和Mary的CA的经典B3/S23不同。换句话说,尽管领域的“局部几何形状”相同(摩尔邻域),但它们的“物理”不同。
“Alien”、“John”、“Mary”这些名字不是必需的,只是为了方便。每个同伴由其公钥、洋葱地址和端口识别。
您可以在任何时候退出这3个实例之一,稍后再重新运行,连接将会恢复。给定同伴发布的最后“快照”被保存在接收过它的每个同伴那里,直到被下一个快照替换。
并且您可以混合不同语言的版本,只要同一时间不会运行每个同伴的多个实例。也就是说,您可以
term1$ cargo run --release --example demo Alien
替换为
term1$ ./demo Alien
在连接到互联网的多台PC上
如预期的那样,与“单机”场景的唯一主要区别是隐藏服务在多台PC之间分配。假设有3个,PC1“Alien的”,PC2“John的”,PC3“Mary的”。
这次端口号可以是相同的:在所有3台PC上,/etc/tor/torrc
包含
HiddenServiceDir /var/lib/tor/p2p_dummysite/
HiddenServicePort 60847
只有onion地址在hostname
文件中不同,并且与之前一样,应在demo.rs
-s中指定为ALIEN_ONION
、JOHN_ONION
、MARY_ONION
值;所有_PORT
都必须是60847
。此外,这次每个PC只需在demo.rs
中有一个对应的_SECRETKEY
。
将相应修改的demo.rs
的Emyzelium文件放置在这些PC上,并且成功构建了demo
可执行文件后,执行以下操作
pc1$ cargo run --release --example demo Alien
pc2$ cargo run --release --example demo John
pc3$ cargo run --release --example demo Mary
并且应该观察到几乎与上面相同的结果。
安全和密钥
Emyzelium依赖于ZeroMQ的Curve和ZAP加密和身份验证方案,以及各种公钥加密(假定具备基本知识)。因此,emyzelium中的每个“主题”都需要并部分由一个密钥和一个相应的公钥定义。此类密钥有2种编码:原始(32字节,每个字节从0-255范围)和可打印的Z85(40个符号,每个符号来自ASCII的85元素集合)。
Emyzelium的方法期望以Z85编码的&str
形式提供密钥。
如何获得这样的密钥对
use std::ffi::{
c_int,
c_char
};
#[link(name = "zmq")]
extern "C" {
fn zmq_curve_keypair(z85_public_key: *mut c_char, z85_secret_key: *mut c_char) -> c_int;
}
const KEY_Z85_LEN: usize = 40;
const KEY_Z85_CSTR_LEN: usize = KEY_Z85_LEN + 1;
fn zmqe_curve_keypair() -> (String, String, i32) {
let mut publickey_bufn = vec![0u8; KEY_Z85_CSTR_LEN];
let mut secretkey_bufn = vec![0u8; KEY_Z85_CSTR_LEN];
let r = unsafe {
zmq_curve_keypair(
(&mut publickey_bufn).as_mut_ptr() as *mut c_char,
(&mut secretkey_bufn).as_mut_ptr() as *mut c_char
)
} as i32;
(String::from_utf8(publickey_bufn[..KEY_Z85_LEN].to_vec()).unwrap(), String::from_utf8(secretkey_bufn[..KEY_Z85_LEN].to_vec()).unwrap(), r)
}
fn main() {
let (publickey, secretkey, _) = zmqe_curve_keypair();
println!("Public key: {}", &publickey);
// Make sure no one is behind your back...
println!("Secret key: {}", &secretkey);
}
注意Emyzelium在此处未使用;另一方面,此代码位于examples/genkeypair.rs
中。
显然,密钥不是长度为40的任意ASCII字符串,不能通过键盘敲击输入。特别是,
如何从密钥派生出公钥
...
#[link(name = "zmq")]
extern "C" {
fn zmq_curve_public(z85_public_key: *mut c_char, z85_secret_key: *mut c_char) -> c_int;
}
...
unsafe {
secretkey.as_ptr().copy_to((&mut secretkey_bufn).as_mut_ptr(), KEY_Z85_LEN);
zmq_curve_public(
(&mut publickey_bufn).as_mut_ptr() as *mut c_char,
(&mut secretkey_bufn).as_mut_ptr() as *mut c_char
);
}
println!("Public key: {}", String::from_utf8(publickey_bufn[..KEY_Z85_LEN].to_vec()).unwrap());
您使用独特的密钥构建对等方,每个对等方一个。除了您和您信任的人,没有人应该知道这些密钥。任何想与您的对等方通信的人都必须知道相应的公钥。相应地,如果您想与别人运行的对等方通信,除了他们的洋葱地址和端口,您还必须知道这些对等方的公钥。基于ZAP的“白名单”功能(见下文),对等方的所有者可以限制那些能够与此对等方通信的人。
现在我们仔细看看这些
实体,它们的角色和用法
简而言之,efunguz发布etales,伸出ehyphae来接触其他efungi并接收它们发布的etales(在这里你应该有似曾相识的感觉,因为这和Synopsis中的“真菌学”隐喻有关)。
这一群blob更好地服务于某种目的——有需要连接以交换数据的程序。我们称这样的程序为“领域”,以强调它们可能属于非常不同的环境,可能用不同的语言编写,不能轻易一次性全部替换。就像森林中的两朵蘑菇,一朵长在洞穴里,另一朵长在河岸上,但它们是同一个菌丝体的一部分,您附加到每个程序上的efungi进行通信,通过efungi,“洞穴程序”和“河岸程序”也能通信。请参阅演示屏幕录制,终端1-3。
遵循发布-订阅模式,Emyzelium模型更倾向于“读取”而不是“写入”:在对方想要读取并对其进行操作之前,您不能将某些数据写入对方的程序内存,除非您想读取这些数据并对其进行操作,没有人可以将他们的数据写入您程序的内存,除非您想读取这些数据并对其进行操作。
此模式的另一个重要属性是多播:数据没有单一的目标接收者。任何允许订阅您的efunguz的etales的人都可以接收它发布的任何etale,如果他们知道其标题。此外,即使他们收到了,您也不知道谁实际上收到了什么etale,直到他们以某种方式将其传达给您。
关于这一点将在下面进一步说明,但就现在而言,请考虑这些限制,并决定它们是否符合您的目标。
如果它们确实如此,并且您的某个程序是用Rust编写的,请继续。否则,请参阅S&B、此列表等。
下面的代码片段假定
[dependencies]
emyzelium = "X.Y.Z"
和
extern crate emyzelium;
use emyzelium::{self as emz, Efunguz};
另请参阅demo.rs
。此外,它还包含带有更多参数的方法调用。
因此,Efunguz、Ehypha和Etale只是对知名概念的时髦名称
Efunguz,又称对等方,是某些“领域”(由您的Rust程序表示)与Tor网络(由托尔SOCKS代理上的ZeroMQ表示)之间的中介。对于前者,它简化了安全、(重)连接和数据流任务。
构建efunguz的最简单方法是
let my_secretkey: &str = "gbMF0ZKztI28i6}ax!&Yw/US<CCA9PLs.Osr3APc";
let mut efunguz = Efunguz::new(my_secretkey, & HashSet::new(), emz::DEF_PUBSUB_PORT, emz::DEF_TOR_PROXY_PORT, emz::DEF_TOR_PROXY_HOST);
更多定制
let whitelist_publickeys = HashSet::from([String::from("WR)%3-d9dw)%3VQ@O37dVe<09FuNzI{vh}Vfi+]0"), String::from("iGxlt)JYh!P9xPCY%BlY4Y]c^<=W)k^$T7GirF[R")]);
let mut efunguz = Efunguz::new(my_secretkey, &whitelist_publickeys, 54321, 9955, emz::DEF_TOR_PROXY_HOST);
现在只有与whitelist_publickeys
对应的密钥的所有者才能订阅并接收此efunguz的etales。他们必须连接到端口号54321
,而不是“默认”端口号。
默认情况下,白名单为空,这意味着...与您的预期相反:任何人都可以订阅。
Efunguz是可变的。您可以
-
通过Efunguz对象的
add_whitelist_publickeys()
、read_whitelist_publickeys()
、del_whitelist_publickeys()
和clear_whitelist_publickeys()
方法,添加和删除白名单中的密钥。 -
通过
add_ehypha()
和del_ehypha()
添加和删除(以下定义的)ehyphae。
let that_publickey: &str = "WR)%3-d9dw)%3VQ@O37dVe<09FuNzI{vh}Vfi+]0";
let that_onion: &str = "abcde23456abcde23456abcde23456abcde23456abcde23456abcdef";
let that_port: u16 = 12345;
if let Ok(ehypha) = efunguz.add_ehypha(that_publickey, that_onion, that_port) {
...
}
- 通过
get_ehypha()
和get_mut_ehypha()
方法,通过公钥获取ehypha的不可变和可变引用。
let that_publickey: &str = "iGxlt)JYh!P9xPCY%BlY4Y]c^<=W)k^$T7GirF[R";
if let Some(ehypha) = efunguz.get_ehypha(that_publickey) {
...
}
- 通过
emit_etale()
发布/发出etales。
let title: &str = "status2";
let parts: Vec<Vec<u8>> = vec![vec![2, 1], vec![255, 0, 2, 1]];
efunguz.emit_etale(title, &parts);
标题可以是空的,即""
。这可能是一种协议,在空标题下发布一些关于“正常”etales的描述,以便其他efungi能够获取可用的etales列表。
efunguz.emit_etale("",
vec!["status2".as_bytes().to_vec(), "2B humidity, 4B kappa level".as_bytes().to_vec(),
"advice".as_bytes().to_vec(), "C string with today's advice".as_bytes().to_vec()]);
- 通过
update()
方法使用从连接的efungi接收到的数据更新其状态、ehypha及其etales。
调用update()
的合适位置是您程序的主循环。例如:
while !quit { // main program loop
// do something here
efunguz.update();
if my_status_updated {
efunguz.emit_etale("status2", &status_parts);
}
if that_etale.t_in() > t_last_etale {
if (that_etale.parts.len() == 2) && (that_etale.parts[1].len() == 4) { // sanity checks
let mut buf: [0u8; 4];
buf.copy_from_slice(& that_etale.parts[1]);
let kappa_level = i32::from_le_bytes(buf);
// do something with kappa level
}
t_last_etale = that_etale.t_in;
}
}
-
通过
in_absorbing_num()
获取从其他efungi成功认证的传入连接的当前数量(以下用IN1
表示)。 -
通过
in_permitted_num()
获取成功认证的传入连接的总数(IN2
)。 -
通过
in_attempted_num()
获取尝试的传入连接的总数(IN3
)。
大多数情况下,IN1
≤ IN2
,因为一些efungi可能已经断开连接,且IN2
≤ IN3
,因为一些efungi可能甚至没有通过认证过滤器。
- 获取最后发生的以下时间点:1) 尝试的传入连接,通过
t_last_attempt()
,2) 认证的传入连接,通过t_last_permit()
,3) 断开连接,通过t_last_disconnect()
。
请参阅demo.rs
中的Realm_CA::run()
。
在内部,Efunguz拥有ZeroMQ上下文、etales的PUB套接字、ZAP认证的REP套接字和监视PUB的PAIR套接字。
Ehypha,即从一个efunguz到另一个efunguz的连接。通过ehypha,前者从后者接收etales。它是Efunguz的一部分,因此其构造已在上面考虑。
Ehypha是可变的。您可以
- 通过
add_etale()
和del_etale()
从目标 efunguz 订阅和取消订阅 etales。
if let Ok(that_etale) = ehypha.add_etale("status3") {
...
}
最初,etale 是空的(没有部分)。如果公钥为 WR)%3-d9dw)%3VQ@O37dVe<09FuNzI{vh}Vfi+]0
的 efunguz 在洋葱地址 abcde23456abcde23456abcde23456abcde23456abcde23456abcdef
上,端口 12345
,允许您的 efunguz 订阅,并以 status3
为标题发布 etale,那么,经过一段时间,这个 etale 将在您调用 efunguz.update()
后收到,并且只要这些条件成立,就会不断更新。其字段在下面的 Etale 段落中描述。
- 通过
get_etale()
通过标题获取 etale 的不可变引用。
let title: &str = "status7";
if let Some(etale) = ehypha.get_etale(title) {
...
}
- 通过
pause_etale[s]()
和resume_etale[s]()
暂停和恢复单个 etale 或所有 etales 的更新。
在内部,Ehypha 拥有用于 etales 的 SUB 套接字。上下文是 Efunguz 的。
Etale,即带有元数据的分区数据块,是 efungi 交换的主要数据单元。它有以下公共方法来访问其只读字段
-
parts() -> & Vec<Vec<u8>>
是最新获取的数据 -
t_out() -> i64
是从 Unix 纪元以来的时间(以微秒为单位),在发送时测量 etale 发布的时间 -
t_in() -> i64
是从 Unix 纪元以来的时间(以微秒为单位),在接收时测量 etale 被获取的时间
Etale 从外部是不可变的,并由构建它的 Ehypha 所拥有。
让“tale”在名称中提醒人们,一个 tale 可能是一个 lie,无论讲述者的意图或听众的期望如何。
主要数据流如下
领域 1 ↔ Efunguz 1 ↔ ZeroMQ ↔ Tor ↔ turtles ↔ Tor ↔ ZeroMQ ↔ Efunguz 2 ↔ 领域 2
这里它是双向的,但也可以是单向的。为此,每个 efunguz 必须知道所有收集 etales 的 efungi 的网络地址,即与其 ehyphae 连接的 efungi 的地址。这就是 Tor 网络的洋葱地址发挥作用的地方...
在 v0.9.0 之前,存在名为 Ecataloguzes 的服务器,也就是名称服务器。Efungi 与它们进行交互,交换它们的(动态)IP 地址,而 Emyzelium 通过基本的 TCP/IP 互联网进行工作……或者更确切地说,如果没有 NAT、防火墙等,它 将会 工作(实际上它是在局域网内工作的)。现在,由于 Tor 解决了这个问题,我们不必在这里再写一个关于那些名称服务器的无聊部分!同时,再见,端口转发、打孔等。
PAQ(可能被问到的问题)
问:与其他类似项目相比,Emyzelium 引入了什么新特性?
答:IOHO,没有。
问:Emyzelium 的可靠性如何?安全性如何?是否有后门?
答:尚未进行“审计”,所以……仔细阅读源代码,它足够小——Rust 版本比这个 README 文件还小。那么,责任就转移到底层——ZeroMQ、Curve、Tor、TCP/IP、BIOS/EFI、硬件等等。抱歉,如果您只信任自己或当前的 Planck 时间单位,没有其他方式。
是的,存在后门。不,不存在后门。
不要在接收 etales 和它们的反序列化过程中省略健全性检查。
不要使用演示中的密钥,生成您自己的唯一密钥对。
问:Emyzelium 是垃圾,我永远不会使用它,但我想与一些 efungi 交换数据。除了他们的洋葱、端口和公钥之外,我还需要什么?
答:这里描述的实体之间流动的数据中没有“Emyzelium 特定的”内容。您在 Efunguz 的“发布者”端口上订阅了一些以 null 结尾的主题吗?——它将向您发送相应的 etale,如果没有白名单或您在其中。编写自己的/使用别人的包装器,围绕您需要的 ZeroMQ、Tor 等部分的代码(参见图 STREAM 套接字)。实际上,Emyzelium 的 实现(或任何传统名称)的 架构 已经在这里。与 Emyzelium 交换数据就是成为它的一部分。如果数据随后流向其他地方,也许您目标是 桥接器。毕竟,您始终可以从头开始重写或改进引起您反感的部分,将其重命名为“Epór”/“Ekinzhitai”/“E...”(基于爱尔兰语/日语中的“mycelium”)并使用它。
问:有些人正在用 emyzelium 做坏事。如何阻止他们?
答:对于此类架构可能没有特殊之处。限制对 Tor 的访问,识别参与网络的设备……进行一些元数据分析……还有其他领域除了菌类学。
问:有些人正在关闭我们用于做好事的 emyzelium。如何阻止他们?
答:对于此类架构可能没有特殊之处。使用 Tor 桥接器,切换参与网络的设备……进行一些元数据混淆……还有其他领域除了菌类学。
S&B
大多是大型...
许可证
此包装器为自由软件:您可以在自由软件基金会发布的 GNU 通用许可证条款下重新分发它和/或修改它,无论是许可证的第 3 版,还是(根据您的选择)许可证的任何后续版本。
此包装器分发时希望它是有用的,但没有任何保证;甚至没有关于其可销售性或适用于特定目的的暗示性保证。有关详细信息,请参阅 GNU 通用许可证。
依赖关系
~215KB