1 RustDesk 介绍
RustDesk 是类似于 TeamViewer 的远程控制 APP,核心语言是 Rust。
2 RustDesk 组成
2.1 服务端
源码:https://github.com/rustdesk/rustdesk-server-demo
服务端未开源,但作者提供了一个 demo。
服务端包括 relay server 和 signaling server。
- signaling server,监听 21116 端口,负责为客户端提供 peer 端的地址和公钥 pk、relay server 的地址,类似于 WebRTC 中的 signaling server。
- relay server,监听 21117 端口,负责在多个客户端之间转发 video、audio 流,类似于 WebRTC 中的 STUN/TURN。
2.2 客户端
源码:https://github.com/rustdesk/rustdesk
代码执行流:
- 启动后,src/ui.rs 会打开 ui/index.tis,同时启动 src/rendezvous_mediator.rs:RendezvousMediator 向 signaling server 注册自己的 id 和公钥 pk。
- 点击 “Connect” 后,会打开 ui/remote.tis,ui/remote.rs 中会创建 src/client.rs:Client,Client 会与 peer 端进行交互。
组成:
- libs:基础库
- src/ui:前端。src/ui/index,UI 启动界面;src/ui/remote,控制 peer 端界面。
- src/rendezvous_mediator.rs:当 APP 启动后,向 signaling server 请求注册自己的 id 和公钥 pk,并获取到 peer 端的 pk 和 address。
- src/client.rs:当用户点击 “Connect” 按钮后,向 signaling server 发出与 peer 端直连的请求,如果请求成功,说明和 peer 端位于同一个网段,进而直接与 peer 端进行交互;否则,说明和 peer 端不位于同一个网段,需要 relay server 中转,进而与 relay server 交互。
- src/server:包含了键盘、鼠标、音频、视频服务。
- src/ipc.rs:负责 UI 和 src/server 的交互。
3 网络交互
3.1 两个客户端位于同一个网段下
当两个客户端位于同一个网段下时,不需要通过 relay server 中转。
位于同一个网段下的两个客户端建立安全连接过程:
- 两个 client 启动后,都会生成自己的 (sk, pk),并把自己的 pk 注册到 signaling server 上。
- 当 client A 想要向 client B 发起连接时,signaling server 会将 client B 的 pk 发送给 client A,并通知 client B 将 client B 的 signed id 发送给 client A。
- client B 用自己的 sk 对 id 进行签名,得到 signed id,并生成 (B_pk_b, B_sk_b),将 signed id 和 B_pk_b 发送给 client A
- client A 收到 client B 的 signed id 后,如果通过 client B 的 pk 解出了 id,说明 client B 的 signed id 正确。接着会生自己的 (A_pk_b, A_sk_b)、nonce 以及 symmetric_key,并采用 (nonce, B_pk_b, A_sk_b) 对 symmetric_pk 进行加密得到 sealed_symmetric_key,然后将 (sealed_symmetric_pk, A_pk_b) 发送给 client B
- client B 生成 nonce,该 nonce 与 client A 的相等,采用 (nonce, A_pk_b, B_sk_b) 从 sealed_symmetirc_key 中解出 symmetric_key
- 以后,client A 和 client B 进行通信时,都会用 symmetirc_key 进行加密和解密。
3.2 两个客户端不位于同一个网段下
在上一个图的基础上,会增加 relay server 的中转。比如当 5: punch hole request 失败后,client A 会向 relay server 发出 request relay,后面与 client B 的交互都会由 relay server 中转。