LumaTunnel 隧道协议 v1
端点与认证
- 控制 API:
https://节点域名/api/v1/* - 数据通道:
wss://节点域名/tunnel/v1 - WebSocket 子协议:
lumatunnel.v1 - WebSocket 压缩:关闭
升级请求必须包含:
Authorization: Bearer {deviceToken}
X-Luma-Device-Id: {deviceId}
X-Luma-Client-Version: {semver}
Sec-WebSocket-Protocol: lumatunnel.v1
设备令牌有 32 个随机字节。客户端只在 DPAPI CurrentUser 密文中保存明文令牌;服务端只持久化 SHA-256 摘要。
控制 API
| 方法 | 路由 | 认证 | 响应 |
|---|---|---|---|
| GET | /api/v1/health |
无 | NodeHealthDto |
| POST | /api/v1/device/enroll |
一次性配对码 | DeviceEnrollmentResponse |
| POST | /api/v1/node/status |
设备 ID + 设备令牌 | NodeStatusDto |
请求和响应为 UTF-8 JSON。错误使用相应 HTTP 状态码,错误正文不得包含配对码、令牌或请求正文。
二进制帧
每个 WebSocket 二进制消息承载一个完整帧。多字节整数使用网络字节序(big-endian)。
Offset Size Field
0 1 Version (固定 1)
1 1 FrameType
2 2 Flags
4 4 StreamId
8 4 PayloadLength
12 N Payload(0..32768)
客户端创建的 StreamId 必须为新的非零奇数;连接级 Ping/Pong 使用 StreamId 0。
| 帧 | 方向 | Payload | 语义 |
|---|---|---|---|
| Open | C→S | TunnelOpenRequest JSON |
请求连接目标主机和端口 |
| OpenOk | S→C | 空 | 目标 TCP 已连接 |
| OpenError | S→C | TunnelOpenError JSON |
DNS、策略、超时或连接失败 |
| Data | 双向 | 0..32768 字节 | TCP 字节流片段 |
| HalfClose | 双向 | 空 | 发送方不再发送数据,另一方向仍可继续 |
| Close | 双向 | 空 | 正常释放流 |
| Reset | 双向 | 空 | 异常终止流 |
| Ping/Pong | 双向 | 不透明 | 连接级保活 |
每端只有一个 WebSocket 发送循环。其他任务将帧写入有界 Channel,避免并发调用 SendAsync 和无限内存增长。每流每方向默认最多缓存 32 帧。
限制与错误
- 单设备最多 128 流,节点总计最多 512 流。
- 目标连接超时 10 秒,空闲流超时 15 分钟。
- 服务端解析目标域名,并在连接前检查全部解析结果。
- 端口 25、回环、RFC1918、链路本地、ULA 和组播地址默认禁止。
- 任何未知帧类型、长度不一致、错误版本或非法 StreamId 都会导致 Reset 或关闭 WSS。
客户端的控制 API、健康检查和 WSS 显式设置 UseProxy=false/Proxy=null,不会递归进入 LumaTunnel 的本地代理。