Files
One-KVM/docs/report/rustdesk/05-message-format.md
mofeng-git a8a3b6c66b feat: 添加 RustDesk 协议支持和项目文档
- 新增 RustDesk 模块,支持与 RustDesk 客户端连接
  - 实现会合服务器协议和 P2P 连接
  - 支持 NaCl 加密和密钥交换
  - 添加视频帧和 HID 事件适配器
- 添加 Protobuf 协议定义 (message.proto, rendezvous.proto)
- 新增完整项目文档
  - 各功能模块文档 (video, hid, msd, otg, webrtc 等)
  - hwcodec 和 RustDesk 协议技术报告
  - 系统架构和技术栈文档
- 更新 Web 前端 RustDesk 配置界面和 API
2025-12-31 18:59:52 +08:00

12 KiB
Raw Blame History

消息格式定义

概述

RustDesk 使用 Protocol Buffers (protobuf) 定义所有网络消息格式。主要有两个 proto 文件:

  • rendezvous.proto - Rendezvous/Relay 服务器通信消息
  • message.proto - 客户端之间通信消息

Rendezvous 消息 (rendezvous.proto)

顶层消息

message RendezvousMessage {
  oneof union {
    RegisterPeer register_peer = 6;
    RegisterPeerResponse register_peer_response = 7;
    PunchHoleRequest punch_hole_request = 8;
    PunchHole punch_hole = 9;
    PunchHoleSent punch_hole_sent = 10;
    PunchHoleResponse punch_hole_response = 11;
    FetchLocalAddr fetch_local_addr = 12;
    LocalAddr local_addr = 13;
    ConfigUpdate configure_update = 14;
    RegisterPk register_pk = 15;
    RegisterPkResponse register_pk_response = 16;
    SoftwareUpdate software_update = 17;
    RequestRelay request_relay = 18;
    RelayResponse relay_response = 19;
    TestNatRequest test_nat_request = 20;
    TestNatResponse test_nat_response = 21;
    PeerDiscovery peer_discovery = 22;
    OnlineRequest online_request = 23;
    OnlineResponse online_response = 24;
    KeyExchange key_exchange = 25;
    HealthCheck hc = 26;
  }
}

注册相关

// Peer 注册
message RegisterPeer {
  string id = 1;      // Peer ID
  int32 serial = 2;   // 配置序列号
}

message RegisterPeerResponse {
  bool request_pk = 2;  // 是否需要注册公钥
}

// 公钥注册
message RegisterPk {
  string id = 1;       // Peer ID
  bytes uuid = 2;      // 设备 UUID
  bytes pk = 3;        // Ed25519 公钥
  string old_id = 4;   // 旧 ID
}

message RegisterPkResponse {
  enum Result {
    OK = 0;
    UUID_MISMATCH = 2;
    ID_EXISTS = 3;
    TOO_FREQUENT = 4;
    INVALID_ID_FORMAT = 5;
    NOT_SUPPORT = 6;
    SERVER_ERROR = 7;
  }
  Result result = 1;
  int32 keep_alive = 2;
}

连接协调相关

// 连接类型
enum ConnType {
  DEFAULT_CONN = 0;
  FILE_TRANSFER = 1;
  PORT_FORWARD = 2;
  RDP = 3;
  VIEW_CAMERA = 4;
}

// NAT 类型
enum NatType {
  UNKNOWN_NAT = 0;
  ASYMMETRIC = 1;   // 可打洞
  SYMMETRIC = 2;    // 需要中转
}

// Punch Hole 请求
message PunchHoleRequest {
  string id = 1;           // 目标 Peer ID
  NatType nat_type = 2;
  string licence_key = 3;
  ConnType conn_type = 4;
  string token = 5;
  string version = 6;
}

// Punch Hole 响应
message PunchHoleResponse {
  bytes socket_addr = 1;      // 目标地址
  bytes pk = 2;               // 公钥(已签名)
  enum Failure {
    ID_NOT_EXIST = 0;
    OFFLINE = 2;
    LICENSE_MISMATCH = 3;
    LICENSE_OVERUSE = 4;
  }
  Failure failure = 3;
  string relay_server = 4;
  oneof union {
    NatType nat_type = 5;
    bool is_local = 6;
  }
  string other_failure = 7;
  int32 feedback = 8;
}

// 服务器转发给被控端
message PunchHole {
  bytes socket_addr = 1;      // 控制端地址
  string relay_server = 2;
  NatType nat_type = 3;
}

// 被控端发送给服务器
message PunchHoleSent {
  bytes socket_addr = 1;
  string id = 2;
  string relay_server = 3;
  NatType nat_type = 4;
  string version = 5;
}

Relay 相关

// Relay 请求
message RequestRelay {
  string id = 1;
  string uuid = 2;          // 配对 UUID
  bytes socket_addr = 3;
  string relay_server = 4;
  bool secure = 5;
  string licence_key = 6;
  ConnType conn_type = 7;
  string token = 8;
}

// Relay 响应
message RelayResponse {
  bytes socket_addr = 1;
  string uuid = 2;
  string relay_server = 3;
  oneof union {
    string id = 4;
    bytes pk = 5;
  }
  string refuse_reason = 6;
  string version = 7;
  int32 feedback = 9;
}

会话消息 (message.proto)

顶层消息

message Message {
  oneof union {
    SignedId signed_id = 3;
    PublicKey public_key = 4;
    TestDelay test_delay = 5;
    VideoFrame video_frame = 6;
    LoginRequest login_request = 7;
    LoginResponse login_response = 8;
    Hash hash = 9;
    MouseEvent mouse_event = 10;
    AudioFrame audio_frame = 11;
    CursorData cursor_data = 12;
    CursorPosition cursor_position = 13;
    uint64 cursor_id = 14;
    KeyEvent key_event = 15;
    Clipboard clipboard = 16;
    FileAction file_action = 17;
    FileResponse file_response = 18;
    Misc misc = 19;
    Cliprdr cliprdr = 20;
    MessageBox message_box = 21;
    SwitchSidesResponse switch_sides_response = 22;
    VoiceCallRequest voice_call_request = 23;
    VoiceCallResponse voice_call_response = 24;
    PeerInfo peer_info = 25;
    PointerDeviceEvent pointer_device_event = 26;
    Auth2FA auth_2fa = 27;
    MultiClipboards multi_clipboards = 28;
  }
}

认证相关

// ID 和公钥
message IdPk {
  string id = 1;
  bytes pk = 2;
}

// 密钥交换
message PublicKey {
  bytes asymmetric_value = 1;  // X25519 公钥
  bytes symmetric_value = 2;   // 加密的对称密钥
}

// 签名的 ID
message SignedId {
  bytes id = 1;  // 签名的 IdPk
}

// 密码哈希挑战
message Hash {
  string salt = 1;
  string challenge = 2;
}

// 登录请求
message LoginRequest {
  string username = 1;
  bytes password = 2;         // 加密的密码
  string my_id = 4;
  string my_name = 5;
  OptionMessage option = 6;
  oneof union {
    FileTransfer file_transfer = 7;
    PortForward port_forward = 8;
    ViewCamera view_camera = 15;
  }
  bool video_ack_required = 9;
  uint64 session_id = 10;
  string version = 11;
  OSLogin os_login = 12;
  string my_platform = 13;
  bytes hwid = 14;
}

// 登录响应
message LoginResponse {
  oneof union {
    string error = 1;
    PeerInfo peer_info = 2;
  }
  bool enable_trusted_devices = 3;
}

// 2FA 认证
message Auth2FA {
  string code = 1;
  bytes hwid = 2;
}

视频相关

// 编码后的视频帧
message EncodedVideoFrame {
  bytes data = 1;
  bool key = 2;     // 是否关键帧
  int64 pts = 3;    // 时间戳
}

message EncodedVideoFrames {
  repeated EncodedVideoFrame frames = 1;
}

// 视频帧
message VideoFrame {
  oneof union {
    EncodedVideoFrames vp9s = 6;
    RGB rgb = 7;
    YUV yuv = 8;
    EncodedVideoFrames h264s = 10;
    EncodedVideoFrames h265s = 11;
    EncodedVideoFrames vp8s = 12;
    EncodedVideoFrames av1s = 13;
  }
  int32 display = 14;  // 显示器索引
}

// 显示信息
message DisplayInfo {
  sint32 x = 1;
  sint32 y = 2;
  int32 width = 3;
  int32 height = 4;
  string name = 5;
  bool online = 6;
  bool cursor_embedded = 7;
  Resolution original_resolution = 8;
  double scale = 9;
}

输入相关

// 鼠标事件
message MouseEvent {
  int32 mask = 1;      // 按钮掩码
  sint32 x = 2;
  sint32 y = 3;
  repeated ControlKey modifiers = 4;
}

// 键盘事件
message KeyEvent {
  bool down = 1;       // 按下/释放
  bool press = 2;      // 单击
  oneof union {
    ControlKey control_key = 3;
    uint32 chr = 4;         // 字符码
    uint32 unicode = 5;     // Unicode
    string seq = 6;         // 字符序列
    uint32 win2win_hotkey = 7;
  }
  repeated ControlKey modifiers = 8;
  KeyboardMode mode = 9;
}

// 键盘模式
enum KeyboardMode {
  Legacy = 0;
  Map = 1;
  Translate = 2;
  Auto = 3;
}

// 控制键枚举(部分)
enum ControlKey {
  Unknown = 0;
  Alt = 1;
  Backspace = 2;
  CapsLock = 3;
  Control = 4;
  Delete = 5;
  // ... 更多按键
  CtrlAltDel = 100;
  LockScreen = 101;
}

音频相关

// 音频格式
message AudioFormat {
  uint32 sample_rate = 1;
  uint32 channels = 2;
}

// 音频帧
message AudioFrame {
  bytes data = 1;  // Opus 编码数据
}

剪贴板相关

// 剪贴板格式
enum ClipboardFormat {
  Text = 0;
  Rtf = 1;
  Html = 2;
  ImageRgba = 21;
  ImagePng = 22;
  ImageSvg = 23;
  Special = 31;
}

// 剪贴板内容
message Clipboard {
  bool compress = 1;
  bytes content = 2;
  int32 width = 3;
  int32 height = 4;
  ClipboardFormat format = 5;
  string special_name = 6;
}

message MultiClipboards {
  repeated Clipboard clipboards = 1;
}

文件传输相关

// 文件操作
message FileAction {
  oneof union {
    ReadDir read_dir = 1;
    FileTransferSendRequest send = 2;
    FileTransferReceiveRequest receive = 3;
    FileDirCreate create = 4;
    FileRemoveDir remove_dir = 5;
    FileRemoveFile remove_file = 6;
    ReadAllFiles all_files = 7;
    FileTransferCancel cancel = 8;
    FileTransferSendConfirmRequest send_confirm = 9;
    FileRename rename = 10;
    ReadEmptyDirs read_empty_dirs = 11;
  }
}

// 文件响应
message FileResponse {
  oneof union {
    FileDirectory dir = 1;
    FileTransferBlock block = 2;
    FileTransferError error = 3;
    FileTransferDone done = 4;
    FileTransferDigest digest = 5;
    ReadEmptyDirsResponse empty_dirs = 6;
  }
}

// 文件传输块
message FileTransferBlock {
  int32 id = 1;
  sint32 file_num = 2;
  bytes data = 3;
  bool compressed = 4;
  uint32 blk_id = 5;
}

// 文件条目
message FileEntry {
  FileType entry_type = 1;
  string name = 2;
  bool is_hidden = 3;
  uint64 size = 4;
  uint64 modified_time = 5;
}

杂项消息

message Misc {
  oneof union {
    ChatMessage chat_message = 4;
    SwitchDisplay switch_display = 5;
    PermissionInfo permission_info = 6;
    OptionMessage option = 7;
    AudioFormat audio_format = 8;
    string close_reason = 9;
    bool refresh_video = 10;
    bool video_received = 12;
    BackNotification back_notification = 13;
    bool restart_remote_device = 14;
    // ... 更多选项
  }
}

// Peer 信息
message PeerInfo {
  string username = 1;
  string hostname = 2;
  string platform = 3;
  repeated DisplayInfo displays = 4;
  int32 current_display = 5;
  bool sas_enabled = 6;
  string version = 7;
  Features features = 9;
  SupportedEncoding encoding = 10;
  SupportedResolutions resolutions = 11;
  string platform_additions = 12;
  WindowsSessions windows_sessions = 13;
}

// 选项消息
message OptionMessage {
  enum BoolOption {
    NotSet = 0;
    No = 1;
    Yes = 2;
  }
  ImageQuality image_quality = 1;
  BoolOption lock_after_session_end = 2;
  BoolOption show_remote_cursor = 3;
  BoolOption privacy_mode = 4;
  BoolOption block_input = 5;
  int32 custom_image_quality = 6;
  BoolOption disable_audio = 7;
  BoolOption disable_clipboard = 8;
  BoolOption enable_file_transfer = 9;
  SupportedDecoding supported_decoding = 10;
  int32 custom_fps = 11;
  // ... 更多选项
}

消息编码

长度前缀

TCP 传输时使用长度前缀编码:

// hbb_common/src/bytes_codec.rs
pub struct BytesCodec {
    state: DecodeState,
    raw: bool,
}

impl Decoder for BytesCodec {
    type Item = BytesMut;
    type Error = std::io::Error;

    fn decode(&mut self, buf: &mut BytesMut) -> Result<Option<BytesMut>, Self::Error> {
        if self.raw {
            // 原始模式:直接返回数据
            if buf.is_empty() {
                Ok(None)
            } else {
                Ok(Some(buf.split()))
            }
        } else {
            // 标准模式4 字节长度前缀 + 数据
            match self.state {
                DecodeState::Head => {
                    if buf.len() < 4 {
                        return Ok(None);
                    }
                    let len = u32::from_le_bytes([buf[0], buf[1], buf[2], buf[3]]) as usize;
                    buf.advance(4);
                    self.state = DecodeState::Data(len);
                    self.decode(buf)
                }
                DecodeState::Data(len) => {
                    if buf.len() < len {
                        return Ok(None);
                    }
                    let data = buf.split_to(len);
                    self.state = DecodeState::Head;
                    Ok(Some(data))
                }
            }
        }
    }
}

加密模式

当启用加密时,消息结构为:

┌─────────────┬─────────────┬─────────────────────────┐
│  Length(4)  │  Nonce(8)   │  Encrypted Data(N)      │
└─────────────┴─────────────┴─────────────────────────┘