初版功能完成
This commit is contained in:
@@ -0,0 +1,477 @@
|
||||
# RemLink v1.0 三端部署与使用指南
|
||||
|
||||
本文覆盖 Linux Server、Windows Engineer、Windows Site 三端从准备、注册、联通、使用到备份升级的完整流程。根目录 DOCX 是需求权威来源;本文只描述当前代码和发布包已经提供的能力,不把自动化测试等同于物理环境验收。
|
||||
|
||||
## 1. 部署边界与端口
|
||||
|
||||
RemLink 是中心辐射结构:
|
||||
|
||||
- Server 运行在 Linux amd64,使用内核 WireGuard `wg0`,负责注册、Overlay 地址分配、Control、Session 编排和管理页面。
|
||||
- Engineer 运行在 Windows amd64,提供 GUI;每台 Engineer 同时只允许一个非终态远程 Session。
|
||||
- Site 运行在另一台 Windows amd64,提供控制台和进程内 gVisor netstack 网关。它用本机普通套接字访问现场目标,因此 PLC 不需要返回 Overlay 的路由。
|
||||
- 两类 Windows 节点都只创建并复用一个名为 `RemLink` 的 Wintun。不要在同一 Windows 主机同时部署 Engineer 和 Site。
|
||||
- Overlay 流量全部经 Server 中转,不建立 P2P,不使用 WinNAT、Windows IP Forwarding、SNAT/MASQUERADE,也不在 Server 为现场 LAN 配置 WireGuard `AllowedIPs`。
|
||||
|
||||
| 端口 | 作用 | 暴露范围 |
|
||||
|---|---|---|
|
||||
| `8080/tcp` | Web UI、Bootstrap、Admin API | 仅可信管理网;公网部署应由外部 HTTPS 反向代理保护 |
|
||||
| `51820/udp` | WireGuard 公网入口 | Engineer 和 Site 必须可达 |
|
||||
| `7001/tcp` | Overlay Control WebSocket | 只监听 Server Overlay IP,不做公网映射 |
|
||||
| `6200/udp` | Overlay Session 数据报 | 只在 Overlay 内使用,不做公网映射 |
|
||||
|
||||
`7001/tcp` 和 `6200/udp` 绝不能添加到公网端口映射。
|
||||
|
||||
## 2. 环境准备
|
||||
|
||||
### 2.1 Linux Server
|
||||
|
||||
准备一台 Linux amd64 主机,并确认:
|
||||
|
||||
- 有稳定公网 IPv4 或域名;NAT 场景已把 WireGuard UDP 端口转发到 Server。
|
||||
- 内核支持 WireGuard,存在 `/dev/net/tun`,Docker 和 Compose 插件可用;原生部署还需要 `iproute2`、`iptables` 和 `wireguard-tools`。
|
||||
- 主机时间同步正常。
|
||||
- 默认 Overlay `10.88.0.0/16` 与任一 Windows 主机本地直连网段不冲突。
|
||||
- 现场 CIDR 不与 Overlay、Engineer 本地网段或保留地址冲突,且不使用 `0.0.0.0/0`。
|
||||
|
||||
先完成宿主机检查:
|
||||
|
||||
~~~bash
|
||||
uname -m
|
||||
test -c /dev/net/tun && echo "TUN 就绪"
|
||||
sudo modprobe wireguard
|
||||
sudo ip link add dev wg-probe type wireguard
|
||||
sudo ip link del dev wg-probe
|
||||
docker version
|
||||
docker compose version
|
||||
~~~
|
||||
|
||||
若临时 `wg-probe` 创建失败,先修复内核支持,不要用 privileged 容器绕过预检。
|
||||
|
||||
### 2.2 Windows Engineer 与 Site
|
||||
|
||||
每台 Windows amd64 主机需要管理员权限,并且能访问 Server 的 HTTPS/HTTP Bootstrap 地址和 WireGuard 公网 UDP 地址。主机不能有与 Overlay 冲突的本地直连网段,也不能运行另一个占用 `RemLink` 适配器的 RemLink 角色。
|
||||
|
||||
Site 还必须从 Windows 本机访问每个现场目标网段。普通默认路由不算 Site 路由能力;目标应为直连网段或有明确非默认路由:
|
||||
|
||||
~~~powershell
|
||||
Get-NetRoute -AddressFamily IPv4 | Sort-Object DestinationPrefix,RouteMetric | Format-Table DestinationPrefix,NextHop,InterfaceAlias,RouteMetric
|
||||
~~~
|
||||
|
||||
## 3. 获取并核验发布包
|
||||
|
||||
三端发布物完全分开,构建后得到三个互不包含对方程序的 ZIP:
|
||||
|
||||
- `RemLink-Engineer-v1.0.0-windows-amd64.zip`:只包含 Engineer EXE、`engineer.yaml`、文档和校验工具。
|
||||
- `RemLink-Site-v1.0.0-windows-amd64.zip`:只包含 Site EXE、`site.yaml`、文档和校验工具。
|
||||
- `RemLink-Server-v1.0.0-linux-amd64.zip`:只包含 Linux Server、Docker 部署目录、文档和验收工具。
|
||||
|
||||
Engineer 与 Site 是便携式目录程序。配置、身份、日志和首次释放的 `wintun.dll` 都以各自 EXE 所在目录为根,不依赖当前工作目录,也不写入 `C:\ProgramData\RemLink`。Engineer 还会在同目录生成不含秘密的 `site-profiles.json`,按 Site 记忆 Remote CIDR。不得把两个 Windows 包合并到同一个目录。
|
||||
|
||||
先比对可信渠道公布的 ZIP SHA-256,再解压。Windows 可校验整个发布目录:
|
||||
|
||||
~~~powershell
|
||||
.\RemLink-Engineer-v1.0.0-windows-amd64\scripts\validation\Test-ReleasePackage.ps1 -PackagePath .\RemLink-Engineer-v1.0.0-windows-amd64 -Role Engineer
|
||||
.\RemLink-Site-v1.0.0-windows-amd64\scripts\validation\Test-ReleasePackage.ps1 -PackagePath .\RemLink-Site-v1.0.0-windows-amd64 -Role Site
|
||||
.\RemLink-Server-v1.0.0-linux-amd64\scripts\validation\Test-ReleasePackage.ps1 -PackagePath .\RemLink-Server-v1.0.0-linux-amd64 -Role Server
|
||||
~~~
|
||||
|
||||
Linux 可在包顶层执行:
|
||||
|
||||
~~~bash
|
||||
cd RemLink-Server-v1.0.0-linux-amd64
|
||||
sha256sum -c SHA256SUMS.txt
|
||||
~~~
|
||||
|
||||
当前构建未做 Authenticode 签名;若组织策略要求签名,应先完成内部签名发布流程。
|
||||
|
||||
## 4. 部署 Server
|
||||
|
||||
### 4.1 推荐:发布包 Docker Compose
|
||||
|
||||
将发布包固定放到 `/opt/remlink`,因为持久数据位于 `docker/data`:
|
||||
|
||||
~~~bash
|
||||
sudo mkdir -p /opt/remlink
|
||||
sudo cp -a RemLink-Server-v1.0.0-linux-amd64/. /opt/remlink/
|
||||
cd /opt/remlink/docker
|
||||
sudo cp .env.example .env
|
||||
sudo chmod 600 .env
|
||||
sudo mkdir -p data
|
||||
~~~
|
||||
|
||||
中国大陆网络把复制命令改为 `sudo cp .env.china.example .env`。该模板使用清华 TUNA 的 Debian 主仓库和安全仓库、强制 IPv4,并关闭可能导致连接重置的 apt HTTP pipelining。Debian 12 容器的软件源是 DEB822 文件,Dockerfile 会按构建参数替换 URI。TUNA 提示安全镜像可能存在同步延迟;如果官方安全源在你的网络中稳定,可把 `REMLINK_APT_SECURITY_MIRROR` 留空。参考 [TUNA Debian 镜像说明](https://mirrors.tuna.tsinghua.edu.cn/help/debian/)。
|
||||
|
||||
编辑 `.env`:
|
||||
|
||||
~~~dotenv
|
||||
REMLINK_WG_ENDPOINT=vpn.example.com:51820
|
||||
REMLINK_WG_PORT=51820
|
||||
REMLINK_HTTP_BIND=127.0.0.1
|
||||
REMLINK_ADMIN_TOKEN=替换为足够长的随机管理令牌
|
||||
REMLINK_APT_FORCE_IPV4=1
|
||||
REMLINK_APT_DEBIAN_MIRROR=
|
||||
REMLINK_APT_SECURITY_MIRROR=
|
||||
~~~
|
||||
|
||||
- `REMLINK_WG_ENDPOINT` 必须是 Windows 实际可达的公网 `主机:端口`。
|
||||
- `REMLINK_WG_PORT` 必须与 endpoint 端口、`server.yaml` 的 `wireguard_port`、NAT 和防火墙完全一致。
|
||||
- `REMLINK_HTTP_BIND=127.0.0.1` 用于同机 HTTPS 反向代理;可信管理网直连 HTTP 时改为该管理接口的具体 IP。仅在明确接受风险时使用 `0.0.0.0`。
|
||||
- `REMLINK_ADMIN_TOKEN` 建议始终设置,不能提交到版本库、截图或验收证据。
|
||||
- `REMLINK_APT_FORCE_IPV4=1` 让镜像构建阶段的 apt 避开常见 IPv6 黑洞;确认构建网络只有 IPv6 时才设为 `0`。
|
||||
- 两个 `REMLINK_APT_*_MIRROR` 只影响镜像构建,不影响 Ubuntu 宿主机软件源;中国模板已填入 TUNA URI,通用模板保持空值并使用 Debian 官方源。
|
||||
|
||||
`server.yaml` 默认内容如下;初次使用非默认 WireGuard 端口时同步修改:
|
||||
|
||||
~~~yaml
|
||||
server:
|
||||
http_listen: "0.0.0.0:8080"
|
||||
control_listen: "10.88.0.1:7001"
|
||||
wireguard_port: 51820
|
||||
data:
|
||||
directory: "/app/data"
|
||||
network:
|
||||
overlay_cidr: "10.88.0.0/16"
|
||||
server_overlay_ip: "10.88.0.1"
|
||||
session_udp_port: 6200
|
||||
mtu: 1280
|
||||
~~~
|
||||
|
||||
校验并启动:
|
||||
|
||||
~~~bash
|
||||
cd /opt/remlink/docker
|
||||
sudo docker compose --env-file .env -f compose.release.yaml config --quiet
|
||||
sudo docker compose --env-file .env -f compose.release.yaml up --build -d
|
||||
sudo docker compose --env-file .env -f compose.release.yaml ps
|
||||
sudo docker compose --env-file .env -f compose.release.yaml logs --tail=100 server
|
||||
curl --fail http://127.0.0.1:8080/api/v1/server/info
|
||||
~~~
|
||||
|
||||
容器只保留 `NET_ADMIN`、映射 `/dev/net/tun`,不启用 privileged。预检失败时根据日志修复 TUN、内核 WireGuard、转发或 capability 问题,不要扩大权限。
|
||||
|
||||
防火墙应允许 Windows 来源访问 `51820/udp`。直接使用 HTTP 时只允许可信管理网访问 `8080/tcp`;反向代理时只开放 `443/tcp` 并保留 `REMLINK_HTTP_BIND=127.0.0.1`;不要开放 `7001` 和 `6200`。
|
||||
|
||||
### 4.2 HTTPS 反向代理
|
||||
|
||||
RemLink v1.0 本身不终止 TLS。公网 Bootstrap 若直接使用 HTTP,Join Token、Node Token 和 Admin 请求不会被 HTTP 层加密;WireGuard 不能保护这条独立公网路径。
|
||||
|
||||
可用 Nginx、Caddy 或组织网关终止 HTTPS。Nginx 最小代理段如下,证书按实际配置:
|
||||
|
||||
~~~nginx
|
||||
server {
|
||||
listen 443 ssl;
|
||||
server_name remlink.example.com;
|
||||
ssl_certificate /etc/ssl/remlink/fullchain.pem;
|
||||
ssl_certificate_key /etc/ssl/remlink/privkey.pem;
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:8080;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto https;
|
||||
}
|
||||
}
|
||||
~~~
|
||||
|
||||
Windows YAML 的 `server` 随后填写 `https://remlink.example.com`,不能附加路径、查询参数、片段或 URL 用户名密码。
|
||||
|
||||
### 4.3 获取和轮换 Join Token
|
||||
|
||||
首次启动成功后获取当前 Token:
|
||||
|
||||
~~~bash
|
||||
cd /opt/remlink/docker
|
||||
sudo docker compose --env-file .env -f compose.release.yaml exec server remlink-server -config /etc/remlink/server.yaml -print-join-token
|
||||
~~~
|
||||
|
||||
Token 在轮换前可登记多个节点,不是每使用一次自动失效。全部预期节点注册后立即轮换:
|
||||
|
||||
~~~bash
|
||||
sudo docker compose --env-file .env -f compose.release.yaml exec server remlink-server -config /etc/remlink/server.yaml -rotate-join-token
|
||||
~~~
|
||||
|
||||
也可在管理页面“网络”页轮换;新值仅在本次响应中显示。
|
||||
|
||||
### 4.4 可选:原生 Linux 服务
|
||||
|
||||
~~~bash
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y ca-certificates iproute2 iptables wireguard-tools
|
||||
sudo install -m 0755 linux-amd64/remlink-server /usr/local/bin/remlink-server
|
||||
sudo install -d -m 0750 /etc/remlink /var/lib/remlink
|
||||
sudo cp linux-amd64/server.yaml /etc/remlink/server.yaml
|
||||
sudo chmod 0640 /etc/remlink/server.yaml
|
||||
~~~
|
||||
|
||||
把 `/etc/remlink/server.yaml` 的 `data.directory` 改为 `/var/lib/remlink`。创建 root 专用的 `/etc/remlink/remlink.env`:
|
||||
|
||||
~~~dotenv
|
||||
REMLINK_WG_ENDPOINT=vpn.example.com:51820
|
||||
REMLINK_ADMIN_TOKEN=替换为足够长的随机管理令牌
|
||||
~~~
|
||||
|
||||
创建 `/etc/systemd/system/remlink-server.service`:
|
||||
|
||||
~~~ini
|
||||
[Unit]
|
||||
Description=RemLink Server
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
[Service]
|
||||
Type=simple
|
||||
User=root
|
||||
WorkingDirectory=/var/lib/remlink
|
||||
EnvironmentFile=/etc/remlink/remlink.env
|
||||
ExecStart=/usr/local/bin/remlink-server -config /etc/remlink/server.yaml
|
||||
Restart=on-failure
|
||||
RestartSec=3
|
||||
NoNewPrivileges=true
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
~~~
|
||||
|
||||
~~~bash
|
||||
sudo chmod 600 /etc/remlink/remlink.env
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable --now remlink-server
|
||||
sudo systemctl status remlink-server
|
||||
sudo journalctl -u remlink-server -n 100 --no-pager
|
||||
curl --fail http://127.0.0.1:8080/api/v1/server/info
|
||||
sudo /usr/local/bin/remlink-server -config /etc/remlink/server.yaml -print-join-token
|
||||
~~~
|
||||
|
||||
原生进程需管理 `wg0`、路由和转发规则;当前基线以 root 运行,但不关闭主机防火墙,也不配置 SNAT。
|
||||
|
||||
## 5. 部署 Engineer
|
||||
|
||||
将 Engineer ZIP 单独解压到 Engineer 主机。建议把解压后的顶层目录固定为 `C:\RemLink\Engineer`,然后以管理员身份打开 PowerShell:
|
||||
|
||||
~~~powershell
|
||||
Set-Location C:\RemLink\Engineer
|
||||
notepad .\engineer.yaml
|
||||
~~~
|
||||
|
||||
配置文件直接包含首次注册所需的 Join Token:
|
||||
|
||||
~~~yaml
|
||||
server: "https://remlink.example.com"
|
||||
node_name: "Engineer-Shanghai-01"
|
||||
join_token: "粘贴从 Server 获取的 Join Token"
|
||||
~~~
|
||||
|
||||
`join_token` 以明文保存在本机 YAML 中,仅在尚无 `identity.json` 时用于首次注册。`NodeID`、`NodeToken` 和 WireGuard 私钥仍由程序管理,不能加入 YAML。默认文件位置:
|
||||
|
||||
- 配置:`C:\RemLink\Engineer\engineer.yaml`
|
||||
- 身份:`C:\RemLink\Engineer\identity.json`
|
||||
- 日志:`C:\RemLink\Engineer\logs\engineer.jsonl`
|
||||
- Wintun:`C:\RemLink\Engineer\wintun.dll`,由 EXE 首次释放并校验 SHA-256,不与 Site 共用文件。
|
||||
|
||||
保存配置后直接首次启动:
|
||||
|
||||
~~~powershell
|
||||
.\RemLinkEngineer.exe
|
||||
~~~
|
||||
|
||||
程序使用 Windows 机器级 DPAPI 保护注册后的身份。确认管理页显示节点 ONLINE 后,关闭 GUI并重新启动一次:
|
||||
|
||||
~~~powershell
|
||||
.\RemLinkEngineer.exe
|
||||
~~~
|
||||
|
||||
生产运行仍需管理员权限。Engineer 是交互式 GUI,不要注册为 SYSTEM 后台任务。
|
||||
|
||||
## 6. 部署 Site
|
||||
|
||||
将 Site ZIP 单独解压到另一台 Site 主机。建议把解压后的顶层目录固定为 `C:\RemLink\Site`,然后以管理员身份打开 PowerShell:
|
||||
|
||||
~~~powershell
|
||||
Set-Location C:\RemLink\Site
|
||||
notepad .\site.yaml
|
||||
~~~
|
||||
|
||||
~~~yaml
|
||||
server: "https://remlink.example.com"
|
||||
node_name: "Qingdao-Site-01"
|
||||
join_token: "粘贴从 Server 获取的 Join Token"
|
||||
netstack:
|
||||
tcp_flow_limit: 2048
|
||||
udp_flow_limit: 4096
|
||||
udp_idle_seconds: 60
|
||||
~~~
|
||||
|
||||
Site YAML 不允许保存现场 LAN CIDR;CIDR 由每次 Engineer Session 动态下发。三个 netstack 数值必须为正,`udp_idle_seconds` 范围为 1–86400 秒。
|
||||
|
||||
保存配置后直接首次启动:
|
||||
|
||||
~~~powershell
|
||||
.\RemLinkSite.exe
|
||||
~~~
|
||||
|
||||
看到以下状态后按 `Ctrl+C` 停止,再不带 Token 重启:
|
||||
|
||||
~~~text
|
||||
OverlayIP=<分配地址> WireGuard=CONNECTED
|
||||
Control=CONNECTED
|
||||
RemoteSubnet=READY SubnetGateway=GVISOR_NETSTACK/READY
|
||||
~~~
|
||||
|
||||
Site 的配置位于 `C:\RemLink\Site\site.yaml`,身份位于 `C:\RemLink\Site\identity.json`,日志位于 `C:\RemLink\Site\logs\site.jsonl`,Wintun 位于 `C:\RemLink\Site\wintun.dll`。这些文件均属于 Site 包目录,不与 Engineer 共用。Engineer/Site 的 Token 取值优先级均为命令行 `-join-token`、环境变量 `REMLINK_JOIN_TOKEN`、YAML `join_token`;日常部署只填写 YAML 即可。
|
||||
|
||||
如需随系统启动,先在前台完成注册和联通验证,停止前台进程,再注册最高权限任务:
|
||||
|
||||
~~~powershell
|
||||
$action = New-ScheduledTaskAction -Execute 'C:\RemLink\Site\RemLinkSite.exe' -Argument '-config "C:\RemLink\Site\site.yaml"' -WorkingDirectory 'C:\RemLink\Site'
|
||||
$trigger = New-ScheduledTaskTrigger -AtStartup
|
||||
$principal = New-ScheduledTaskPrincipal -UserId 'SYSTEM' -LogonType ServiceAccount -RunLevel Highest
|
||||
Register-ScheduledTask -TaskName 'RemLink Site' -Action $action -Trigger $trigger -Principal $principal
|
||||
Start-ScheduledTask -TaskName 'RemLink Site'
|
||||
Get-ScheduledTaskInfo -TaskName 'RemLink Site'
|
||||
~~~
|
||||
|
||||
不要同时运行前台 Site 和计划任务。SYSTEM 可读取同机机器级 DPAPI 身份;身份复制到另一台机器后不能解密,迁移主机必须重新注册。
|
||||
|
||||
## 7. 首次联通检查
|
||||
|
||||
Server:
|
||||
|
||||
~~~bash
|
||||
cd /opt/remlink/docker
|
||||
sudo docker compose --env-file .env -f compose.release.yaml ps
|
||||
sudo docker compose --env-file .env -f compose.release.yaml exec server wg show wg0
|
||||
sudo docker compose --env-file .env -f compose.release.yaml logs --tail=100 server
|
||||
~~~
|
||||
|
||||
应看到两个 Windows peer 的最近握手和计数;每个 peer 在 Server 只应有自己的 Overlay `/32`。
|
||||
|
||||
分别在 Engineer 和 Site:
|
||||
|
||||
~~~powershell
|
||||
$adapter = @(Get-NetAdapter -Name RemLink -ErrorAction Stop)
|
||||
if ($adapter.Count -ne 1) { throw "RemLink 适配器数量不是 1" }
|
||||
$adapter | Format-List Name,Status,InterfaceDescription,ifIndex
|
||||
Get-NetIPAddress -InterfaceAlias RemLink -AddressFamily IPv4
|
||||
Get-NetIPConfiguration -InterfaceAlias RemLink
|
||||
~~~
|
||||
|
||||
应只有一个 `RemLink` 适配器,地址属于 Overlay,MTU 为 1280。不要安装 WireGuardNT 第二适配器。
|
||||
|
||||
浏览器打开受保护的 Server URL。若配置了管理令牌,在左侧令牌框输入后点击“应用”。依次检查:
|
||||
|
||||
- “节点”:Engineer/Site 为 ONLINE,Overlay IP 唯一,WG Handshake 与 LastSeen 更新。
|
||||
- “会话”:首次部署为空。
|
||||
- “网络”:Overlay、Server IP、端口和 MTU 正确。
|
||||
- “日志”:没有持续 ERROR。
|
||||
|
||||
全部节点登记后轮换 Join Token。
|
||||
|
||||
## 8. 建立并使用 Session
|
||||
|
||||
1. 在 Site 本机先验证目标,例如 `ping 192.168.13.10` 和 `Test-NetConnection 192.168.13.10 -Port 502`。目标网段必须有直连或明确非默认路由。
|
||||
2. 启动 Engineer,确认“服务器已连接”和“Control 在线”。
|
||||
3. 选择 ONLINE 且 Remote Subnet“可用”的 Site。
|
||||
4. 输入规范 CIDR,例如 `192.168.13.0/24`;可添加多个。
|
||||
5. 等待本地冲突预检显示“通过,无冲突”。失败时处理 Engineer 已有直连/路由,不能强行绕过。
|
||||
6. 点击“连接现场”。正常状态为“正在创建(`CREATING`)”→“正在准备现场端(`PREPARING_SITE`)”→“准备就绪(`READY`)”→“活动中(`ACTIVE`)”。
|
||||
7. ACTIVE 后用原生工具访问目标:
|
||||
|
||||
~~~powershell
|
||||
ping 192.168.13.10
|
||||
Test-NetConnection 192.168.13.10 -Port 102
|
||||
Test-NetConnection 192.168.13.10 -Port 502
|
||||
Test-NetConnection 192.168.13.10 -Port 80
|
||||
~~~
|
||||
|
||||
TCP、UDP 和受约束的 ICMP Echo 走通用 netstack/主机套接字,不依赖协议专用代理。Site 日志记录 Session 和路由结果,不记录数据包载荷。
|
||||
|
||||
8. 结束后点击“断开会话”,确认 Engineer 远程路由删除。异常退出后,下次启动会清理本程序拥有的陈旧路由。
|
||||
|
||||
每个 Engineer 同时只能有一个非终态 Session;切换 Site 前先断开。多个 Engineer 可访问同一 Site,两个 Site 也可各自使用相同现场 CIDR,SessionID 会隔离数据流。
|
||||
|
||||
Engineer 的 Remote CIDR 按 Site NodeID 独立保存。选择现场时只加载并发送该现场的网段,例如现场 A 可保存 `192.168.17.0/24`,现场 B 可保存 `192.168.107.0/24`,不需要来回删除和重建。Site 心跳超过离线阈值后,Server 会以 `SITE_OFFLINE` 自动关闭相关会话并通知 Engineer 清理本地路由。
|
||||
|
||||
## 9. 日常管理
|
||||
|
||||
- “节点”页可改名称或 Overlay IP、撤销节点。修改在线节点 IP 会关闭相关 Session 并触发重新 Bootstrap;撤销后旧 Node Token 失效。
|
||||
- “会话”页显示 SessionID、两端节点、CIDR、状态、计数和持续时间,可强制断开 ACTIVE Session。
|
||||
- “日志”页可按时间、级别、模块、Node ID 和 Session ID 过滤。
|
||||
- Server 文件日志:Docker 为 `/opt/remlink/docker/data/logs/server.jsonl`;原生为 `/var/lib/remlink/logs/server.jsonl`。
|
||||
|
||||
三端面向操作员的日志消息、状态、级别、模块和常见错误均显示中文。协议状态、模块名与错误码会保留在括号中,例如“现场端没有通往远程网段的明确路由(`SITE_NO_ROUTE`)”,便于按文档和接口继续检索。Server 管理页会把旧版本已经写入数据库的常见英文事件即时翻译为中文;数据库原始记录不会被批量改写。JSON 文件日志的 `time`、`level`、`module`、`session_id` 等字段名保持稳定,供脚本和采集系统使用,`msg` 内容改为中文。
|
||||
|
||||
同机重新登记时,先停止角色进程/任务,把对应 `identity.json` 移到受控备份位置,再使用新 Join Token;不要编辑 DPAPI 内容。
|
||||
|
||||
修改完整 Overlay 前,先检查所有 Windows 主机无本地冲突。保存后 Server 会暂停新 Session、关闭现有 Session、更新数据库与 `wg0`,通知节点重新 Bootstrap,再切换监听。
|
||||
|
||||
Docker 修改 WireGuard 端口后,还要把 `.env` 的 `REMLINK_WG_PORT` 和 `REMLINK_WG_ENDPOINT` 改成同一端口并重建映射:
|
||||
|
||||
~~~bash
|
||||
cd /opt/remlink/docker
|
||||
sudo docker compose --env-file .env -f compose.release.yaml up -d --force-recreate
|
||||
~~~
|
||||
|
||||
重建期间短暂离线,`docker/data` 中数据库和密钥保留。
|
||||
|
||||
## 10. 备份、恢复与升级
|
||||
|
||||
Docker 权威数据均在 `docker/data`。一致性备份:
|
||||
|
||||
~~~bash
|
||||
cd /opt/remlink/docker
|
||||
sudo docker compose --env-file .env -f compose.release.yaml stop server
|
||||
sudo tar -C /opt/remlink/docker -czf /安全备份目录/remlink-data-$(date +%F-%H%M%S).tgz data
|
||||
sudo docker compose --env-file .env -f compose.release.yaml start server
|
||||
~~~
|
||||
|
||||
同时备份 `server.yaml` 和受保护的 `.env`。恢复时先停止 Server,恢复到原位置并保持权限,再启动检查节点重连。原生部署对应备份 `/var/lib/remlink`、`/etc/remlink/server.yaml` 和 `remlink.env`。
|
||||
|
||||
Windows `identity.json` 是机器级 DPAPI 密文,只能在生成它的主机恢复,不能用于跨机器迁移。更换主机应撤销旧节点并重新登记。
|
||||
|
||||
从旧版 `ProgramData` 目录模型升级时,必须先停止对应 Windows 进程。在同一台主机上,可把旧的 `C:\ProgramData\RemLink\Engineer\identity.json` 或 `C:\ProgramData\RemLink\Site\identity.json` 手工复制到新包 EXE 旁;机器级 DPAPI 密文仍可解密。日志可按需归档,不要把 Engineer 身份复制给 Site,也不要跨主机复制。确认新包已正常重连后,再决定是否归档旧目录;新版本不会继续读写旧目录。
|
||||
|
||||
升级顺序:
|
||||
|
||||
1. 核验新包,断开 Session,备份 Server 数据。
|
||||
2. 停止三端。
|
||||
3. 固定使用 `/opt/remlink` 时保留 `docker/data` 和本机 `docker/.env`,替换其余发布文件;原生部署替换 Server 二进制。
|
||||
4. 分别替换 Engineer、Site 包目录中的 EXE;保留同目录的 YAML、`identity.json`、`logs` 和已验证的 `wintun.dll`。不要用另一端的包覆盖当前目录。
|
||||
5. 先启动 Server,再 Site,最后 Engineer。
|
||||
6. 核对版本、节点 ONLINE、`wg show wg0`、日志和一条测试 Session。
|
||||
|
||||
Server 重启会关闭数据库中遗留的非终态 Session;升级后应新建 Session,不要期待旧 Session 自动恢复。
|
||||
|
||||
## 11. 常见故障
|
||||
|
||||
| 现象或错误 | 处理 |
|
||||
|---|---|
|
||||
| endpoint 端口不匹配 | `REMLINK_WG_ENDPOINT` 端口必须等于已保存的 `wireguard_port`;同时核对 `REMLINK_WG_PORT`、NAT、防火墙 |
|
||||
| 容器预检失败 | 检查 `/dev/net/tun`、内核 WireGuard、`NET_ADMIN` 和 IPv4 forwarding;不要改 privileged |
|
||||
| 构建长时间停在 `apt-get` | 中国大陆先使用 `.env.china.example`;再运行 `docker run --rm debian:bookworm-slim sh -c "apt-get -o Acquire::ForceIPv4=true -o Acquire::Retries=2 -o Acquire::http::Timeout=30 update"`;若仍超时,修复 Docker daemon DNS/代理或用 `docker build --network=host` |
|
||||
| Admin 401 | 输入与 `REMLINK_ADMIN_TOKEN` 完全一致的 Bearer token |
|
||||
| `JOIN_TOKEN_INVALID` | 安全获取当前 Token;不要继续使用已轮换值 |
|
||||
| `NODE_AUTH_FAILED` | 身份被撤销、损坏或复制到其他机器;隔离旧身份并重新登记 |
|
||||
| `OVERLAY_LOCAL_CONFLICT` | Overlay 与 Windows 本地直连网段重叠;恢复或选择无冲突 Overlay |
|
||||
| `CIDR_LOCAL_CONFLICT` | Engineer 本机已有覆盖远程 CIDR 的网络/路由;处理后重新预检 |
|
||||
| `SITE_NO_ROUTE` | Site 只有默认路由或无路由;增加真实直连/静态路由并先在 Site 验证 |
|
||||
| `NETSTACK_UNAVAILABLE` / `FLOW_LIMIT_REACHED` | 检查 Site 就绪、流量上限和长连接;按容量调整配置并重启 |
|
||||
| `SESSION_INJECT_FAILED` | 当前 Session 会关闭;检查适配器、路由和日志后新建 |
|
||||
| `ENGINEER_SESSION_EXISTS` | 先断开当前非终态 Session |
|
||||
| 节点 ONLINE 但业务不通 | 依次检查 Site 本机目标、Server `wg show`、Session ACTIVE、Engineer 路由、Site 日志和主机防火墙 |
|
||||
|
||||
## 12. 验收、停用
|
||||
|
||||
发布包中初始化验收:
|
||||
|
||||
~~~powershell
|
||||
.\scripts\validation\New-AcceptanceRun.ps1 -OutputDirectory C:\RemLink-Evidence\run-001
|
||||
~~~
|
||||
|
||||
按 `docs/validation/T01-T18-runbook.md` 采证,用 `Set-AcceptanceResult.ps1` 记录,再运行:
|
||||
|
||||
~~~powershell
|
||||
.\scripts\validation\Test-AcceptanceRun.ps1 -RunDirectory C:\RemLink-Evidence\run-001
|
||||
~~~
|
||||
|
||||
证据不存在、哈希不一致或前置 Gate 未通过时,不得标记 PASS。至少验证单适配器、Overlay 双向连通、目标 ICMP/TCP/UDP、断线重连、Server 重启、陈旧路由清理、节点 IP/Overlay 迁移和重复现场网段隔离。
|
||||
|
||||
停用时:Engineer 先断开 Session;Site 计划任务先执行 `Stop-ScheduledTask -TaskName 'RemLink Site'`,永久取消再执行 `Unregister-ScheduledTask -TaskName 'RemLink Site'`;Server 停止后归档 data 和配置;撤销不再使用的节点并轮换 Join Token。
|
||||
|
||||
当前包没有 Windows 卸载器。持久 `RemLink` Wintun 适配器是设计行为;若只暂停使用,可在确认没有 RemLink 进程后禁用。删除 Engineer 或 Site 包目录会同时删除该端身份和日志;执行前必须备份,并确认明确放弃该主机身份。不要用不明脚本删除第三方网络适配器。
|
||||
@@ -0,0 +1,18 @@
|
||||
# RemLink 界面设计记录
|
||||
|
||||
Engineer 和 Server 在实现前先生成全页面视觉参考,再翻译为 Vue/CSS;概念图没有被直接嵌入产品。两端统一使用冷色近白工作区、深蓝紫操作色、薄荷绿/琥珀/红状态色、细边框、紧凑表格和清晰左侧导航,适合运维桌面。
|
||||
|
||||
## 资源
|
||||
|
||||
- `engineer-concept.png`:Engineer 连接/Session 概念图。
|
||||
- `server-concept.png`:Server 运维仪表板概念图。
|
||||
- `engineer-render.png`:交互 QA 后的 1440×900 实际渲染。
|
||||
- `server-render.png`:交互 QA 后的 1440×900 实际渲染。
|
||||
|
||||
## 还原记录
|
||||
|
||||
- 保留:整体壳层、字号层级、连接拓扑线、状态色、表单密度、卡片、表格和主操作。
|
||||
- 调整:Server 实际渲染补充 Nodes/Sessions/Logs 完整运维内容;Engineer 远程 CIDR 列表支持真实多前缀纵向增长。
|
||||
- 功能新增:Admin token、运行时长、过滤、编辑/撤销、强制断开、Join Token 轮换、响应式表格滚动和真实心跳 RTT。
|
||||
|
||||
浏览器 QA 因交互式 Browser 插件不可用,使用已安装 Microsoft Edge 与项目内 Playwright。1440×900 和 1024×720 的核心交互通过,无控制台/页面/HTTP 错误,也无页面级横向溢出。
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 108 KiB |
@@ -0,0 +1,50 @@
|
||||
# RemLink v1.0 实现状态
|
||||
|
||||
日期:2026-08-25
|
||||
|
||||
Phase 0–10 的实现工作均已进入代码。`specs/tasks.md` 明确区分“已实现子任务”和“需要外部主机的验收项”。
|
||||
|
||||
## 已完成的代码与自动化测试
|
||||
|
||||
- 稳定协议:20 字节 Session 头、13 种 Control 消息、14 个精确错误码。
|
||||
- Linux 内核 WireGuard 编排、SQLite 迁移、IPAM、Bootstrap、Join/Node Token、Control Hub、心跳状态与重连策略。
|
||||
- 单 Wintun wireguard-go Client、PacketMux、自有 Windows 路由、本地重叠检查、普通 Overlay UDP Session 传输和严格数据包验证。
|
||||
- 单进程 gVisor netstack 网关、通用 TCP/UDP relay 与受约束 ICMP Echo relay;不使用 WinNAT、Windows forwarding 或协议专用代理。
|
||||
- Site TCP/UDP flow 上限和 UDP 空闲超时可配置,默认 `2048/4096/60s`,并通过 capability 上报。
|
||||
- 七状态双边 Session 编排、超时、统计、reconcile、rebootstrap、Admin 审计事件和七步 Overlay 网络迁移。
|
||||
- 网络迁移会原子暂停 Session 创建、关闭现有 Session、发布新 Bootstrap、在旧 Control 仍在线时通知节点、切换 `wg0`/监听,并在失败时恢复内核和应用状态。
|
||||
- Windows 节点在旧 Control 在线时预检新 Overlay;本地重叠会保持旧配置以报告 `OVERLAY_LOCAL_CONFLICT`,Server 记录 ERROR 事件。
|
||||
- PREPARE 拒绝与 CREATE 请求关联,陈旧结果不能终止后续请求;完全相同的 netstack PREPARE 重试幂等。
|
||||
- Site 和 Server 信任边界都拒绝 `DEFAULT_ONLY`。数据包注入失败只关闭受影响 Session 并报告 `SESSION_INJECT_FAILED`,节点监听仍可用。
|
||||
- 被拒 Session 数据报和 PacketMux 丢包只输出元数据、限速安全警告;默认不记录高频数据包 DEBUG,也没有接收载荷字节的日志 API。
|
||||
- PacketMux 在拦截/注入边界计数;UDP relay 空闲回收、Sender 关闭与 netstack 重试路径有 race/幂等覆盖。
|
||||
- Wails Engineer GUI 和内嵌 Vue Server Web UI 已实现;Server 五个管理页及指定 API 完整。节点显示 WG 握手,Session 显示持续时间,日志支持五维过滤,Token 轮换只显示一次,Engineer 显示 Site capability 与 LastSeen。
|
||||
- 浏览器侧 SessionID 使用十进制字符串,避免 JavaScript 舍入随机 `uint64`。新的 Node Bootstrap 会关闭 Server 侧本地运行时已经丢失的 Session;短 Control 重连保留运行时。
|
||||
- Engineer GUI 对所有非终态单 Session 状态做操作门禁;生产启动和输入默认失败关闭;Server 运行表刷新不会覆盖正在编辑的网络配置。
|
||||
- 多 Engineer、多 Site 并发与重复 CIDR flow 隔离已实现。
|
||||
- 配置、Bootstrap、IPAM、Client WG、Session 和 Admin 信任边界都拒绝 Overlay 网络/广播地址以及 `/0` Exit Node。Server 事件模块限制为规格定义的 11 个名称。
|
||||
- Server WireGuard 私钥并发发布原子;成功的 Linux 内核变更不会被误报为取消。
|
||||
- 固定依赖、CI、Windows/Linux 发布脚本、受限 Docker Compose、启动预检、第三方声明和自包含 T01–T18 证据工具已提供。
|
||||
- Docker 使用 `./data:/app/data` 持久化和对称 `REMLINK_WG_PORT` 映射,并支持限制 HTTP bind。源码 Compose 与发布包预编译二进制 Compose 分离。
|
||||
- Server 的 Join Token 打印/轮换 CLI 在 Session 恢复清理之前退出,不会因运维读取 Token 而关闭活动 Session。
|
||||
- Admin 空节点/Session/事件列表统一编码为 `[]`,Server 前端也会把旧版 `null` 响应归一为空数组,避免首次正确鉴权后的概览白屏。
|
||||
- 发布验证器会解压 ZIP、检查必需项、重算全部校验和、拒绝未覆盖文件,并冒烟运行包内验收初始化器,不伪造结果。
|
||||
- Engineer、Site、Server 生成三个独立目录和 ZIP,发布验证器会拒绝混入其他角色的可执行文件;Windows 两端默认以各自 EXE 目录保存 YAML、DPAPI 身份、日志和校验后的 Wintun DLL,不再写入或共享 `ProgramData` 文件。
|
||||
- Engineer/Site YAML 支持明文 `join_token` 作为自用部署便捷项;命令行和 `REMLINK_JOIN_TOKEN` 仍可覆盖 YAML,注册后的 Node Token 与 WireGuard 私钥继续由 DPAPI 保护。
|
||||
- Engineer 按 Site NodeID 在 EXE 旁的 `site-profiles.json` 独立记忆 Remote CIDR;选择现场时只加载该现场网段。Site 心跳进入 OFFLINE 后,Server 自动以 `SITE_OFFLINE` 关闭相关会话并释放 Engineer 会话门禁。
|
||||
- Server、Engineer、Site 的操作员日志与界面状态已中文化;稳定协议状态、模块名和错误码以括号形式保留,Server 管理页还能翻译旧数据库中的常见英文事件。
|
||||
- Engineer 发布构建固定使用 Wails `desktop,production` 标签,并写入 `BUILD-INFO.json`;架构检查会拒绝退回缺少标签、启动时只弹 Wails 错误框的普通 Go 构建。
|
||||
|
||||
## 待外部物理验收
|
||||
|
||||
Gate A–D 与 T01–T18 当前为 `NOT_RUN`,不是失败也不是通过。它们需要 Linux 内核 WireGuard、管理员权限 Windows Engineer/Site、真实路由、重复现场网络、目标服务、热点切换以及进程/网络重启。执行方式见 `docs/validation/T01-T18-runbook.md`。
|
||||
|
||||
## 本地验证说明
|
||||
|
||||
本地基线已执行 npm 清洁安装、Vue 类型检查和生产构建、`go mod verify`、全量 Go test、`go vet`、架构策略扫描、Windows/Linux 交叉构建、发布校验和验证以及包内验收初始化冒烟。
|
||||
|
||||
渲染 QA 使用已安装 Microsoft Edge 与 Playwright:Engineer 的 ACTIVE→断开→IDLE 与 Settings 导航通过;Server 的 SESSION 日志过滤和 Join Token 轮换通过;两个页面均无框架错误覆盖和浏览器 warning/error。
|
||||
|
||||
本机没有 Docker,因此不在本地声称镜像已构建;Linux CI 负责源码镜像构建。由于本机没有 C 编译器,race 测试由 Linux CI 承担。Windows EXE 未做 Authenticode 签名;工作区没有 commit 时 `BUILD-INFO.json` 会记录 `unknown`。这些限制均不能记为已通过的 Gate 或物理验收结果。
|
||||
|
||||
本次中文文档与发布包部署入口修改后,应以最新一次 `scripts/build-release.ps1` 生成的 Engineer、Site、Server 三个独立 ZIP、各包 `SHA256SUMS.txt` 和实际命令输出为准,不沿用旧包哈希。
|
||||
@@ -0,0 +1,24 @@
|
||||
# RemLink Engineer 独立便携包
|
||||
|
||||
本目录只属于 Engineer,不包含 Site 或 Server 程序。请把整个目录放在可持续写入的位置,例如 `C:\RemLink\Engineer`;不要只复制 EXE,也不要与 Site 解压到同一目录。
|
||||
|
||||
## 首次使用
|
||||
|
||||
1. 以管理员身份打开 PowerShell,进入本目录。
|
||||
2. 编辑 `engineer.yaml`,填写 Server URL、Engineer 名称和 `join_token`。
|
||||
3. 直接执行:
|
||||
|
||||
~~~powershell
|
||||
.\RemLinkEngineer.exe
|
||||
~~~
|
||||
|
||||
`join_token` 会以明文保存在 YAML 中,只在首次注册时使用;注册后的 Node Token 和 WireGuard 私钥仍由 DPAPI 保护。后续直接以管理员身份运行 `RemLinkEngineer.exe`。默认配置路径始终是 EXE 旁的 `engineer.yaml`,与启动时的当前工作目录无关。
|
||||
|
||||
## 本目录中的运行文件
|
||||
|
||||
- `identity.json`:NodeID、Node Token 和 WireGuard 私钥等 DPAPI 保护身份,仅可在生成它的 Windows 主机解密。
|
||||
- `site-profiles.json`:由界面自动生成,按 Site NodeID 保存各现场的 Remote CIDR;不包含密钥或 Token。切换现场时会自动加载对应网段。
|
||||
- `logs\engineer.jsonl`:Engineer 日志。
|
||||
- `wintun.dll`:EXE 内嵌的固定版本 Wintun 首次运行释放文件,程序会校验 SHA-256。
|
||||
|
||||
备份或升级前先退出 Engineer。升级时保留 `engineer.yaml`、`identity.json` 和 `logs`,只替换通过校验的新 EXE;完整三端流程见 `docs\deployment-and-usage.md`。
|
||||
@@ -0,0 +1,23 @@
|
||||
# RemLink Site 独立便携包
|
||||
|
||||
本目录只属于 Site,不包含 Engineer 或 Server 程序。请把整个目录放在可持续写入的位置,例如 `C:\RemLink\Site`;不要只复制 EXE,也不要与 Engineer 解压到同一目录。
|
||||
|
||||
## 首次使用
|
||||
|
||||
1. 以管理员身份打开 PowerShell,进入本目录。
|
||||
2. 编辑 `site.yaml`,填写 Server URL、Site 名称、`join_token` 和 netstack 容量。
|
||||
3. 直接执行:
|
||||
|
||||
~~~powershell
|
||||
.\RemLinkSite.exe
|
||||
~~~
|
||||
|
||||
`join_token` 会以明文保存在 YAML 中,只在首次注册时使用;注册后的 Node Token 和 WireGuard 私钥仍由 DPAPI 保护。确认 Overlay、Control 和 RemoteSubnet 均就绪后停止前台程序。后续直接运行 `RemLinkSite.exe`,或按完整指南注册最高权限启动任务;默认配置路径始终是 EXE 旁的 `site.yaml`。
|
||||
|
||||
## 本目录中的运行文件
|
||||
|
||||
- `identity.json`:NodeID、Node Token 和 WireGuard 私钥等 DPAPI 保护身份,仅可在生成它的 Windows 主机解密。
|
||||
- `logs\site.jsonl`:Site 日志。
|
||||
- `wintun.dll`:EXE 内嵌的固定版本 Wintun 首次运行释放文件,程序会校验 SHA-256。
|
||||
|
||||
备份或升级前先停止前台进程和计划任务。升级时保留 `site.yaml`、`identity.json` 和 `logs`,只替换通过校验的新 EXE;完整三端流程见 `docs\deployment-and-usage.md`。
|
||||
@@ -0,0 +1,26 @@
|
||||
# Phase 0 验证记录
|
||||
|
||||
- 日期:2026-08-25
|
||||
- 主机:Windows amd64
|
||||
- Go 工具链:1.26.7
|
||||
- 范围:仓库和基础模型
|
||||
|
||||
## 验证证据
|
||||
|
||||
| 检查 | 结果 |
|
||||
|---|---|
|
||||
| `gofmt` 清洁检查 | PASS |
|
||||
| `go mod verify` | PASS(全部模块已验证) |
|
||||
| `go test -count=1 ./...` | PASS |
|
||||
| `go vet ./...` | PASS |
|
||||
| Windows/amd64 `go build ./...` | PASS |
|
||||
| Linux/amd64 CGO=0 交叉构建 | PASS |
|
||||
| 运行三端 Phase 0 入口 | PASS |
|
||||
|
||||
协议测试覆盖 20 字节 Session 头黄金字节、帧往返、畸形头拒绝、13 种 Control 消息和权威规格实际枚举的 14 个错误码。
|
||||
|
||||
配置测试覆盖默认值、IPv4 网络、Client URL、未知/敏感 YAML 字段拒绝和多文档 YAML 拒绝。日志测试覆盖 11 个模块、结构化字段、滚动文件、幂等关闭、默认禁用包日志,以及显式启用采样后的逐键限速。
|
||||
|
||||
## 非阻塞环境说明
|
||||
|
||||
本机 Windows Go 环境 `CGO_ENABLED=0` 且没有 C 编译器,因此额外的 `go test -race ./...` 无法执行。Phase 0 验收不要求 race detector;日志采样器仍由互斥锁保护并有单元测试,CI 在 Windows 与 Linux 执行要求的构建、测试和 vet。
|
||||
@@ -0,0 +1,21 @@
|
||||
# Phase 0 实现说明
|
||||
|
||||
## 范围
|
||||
|
||||
Phase 0 包含仓库结构、共享模型、YAML 配置加载、结构化滚动日志、协议常量与编解码器、测试和 CI;不包含 Wintun、WireGuard、数据包路由、gVisor、数据库、Control 传输或 GUI。
|
||||
|
||||
## 协议决定
|
||||
|
||||
权威规格确定 Session 头字段和宽度,但没有指定字节序。RemLink 对全部多字节 Session 头字段使用网络字节序(大端);黄金字节测试固定该行为,防止后续实现静默分歧。
|
||||
|
||||
权威 DOCX 和 `specs/spec.md` 实际枚举 14 个错误码。早期 Phase 0 任务文字写成“15 个”;实现遵循权威枚举并修正文档计数,不虚构第 15 个错误码。
|
||||
|
||||
## 固定依赖
|
||||
|
||||
- Go 1.26.7
|
||||
- `gopkg.in/yaml.v3` v3.0.1
|
||||
- `gopkg.in/natefinch/lumberjack.v2` v2.2.1
|
||||
- `actions/checkout` v6.0.2(按 commit SHA 固定)
|
||||
- `actions/setup-go` v7.0.0(按 commit SHA 固定)
|
||||
|
||||
使用 YAML v3 是因为实现时 v4 仍只有候选版本。
|
||||
@@ -0,0 +1,33 @@
|
||||
# Phase 1 验证记录
|
||||
|
||||
- 日期:2026-08-25
|
||||
- 状态:进行中;Gate A 尚未通过
|
||||
- 主机:Windows amd64,非管理员 Codex 进程
|
||||
- Go 工具链:1.26.7
|
||||
|
||||
## 已完成自动化证据
|
||||
|
||||
| 检查 | 结果 |
|
||||
|---|---|
|
||||
| Wintun 0.14.1 ZIP 官方 SHA-256 | PASS |
|
||||
| 内嵌 AMD64 DLL SHA-256 | PASS(`e5da8447...20dafce`) |
|
||||
| 将内嵌 Wintun 安装到指定便携目录并校验/修复 | PASS |
|
||||
| 官方 Go 绑定报告 Wintun 0.14.1 | PASS |
|
||||
| MuxTun `tun.Device` 编译期断言 | PASS |
|
||||
| MuxTun 代理与幂等关闭测试 | PASS |
|
||||
| wireguard-go UAPI 黄金配置测试 | PASS |
|
||||
| 全量 Go test/vet、Windows 构建、Linux 交叉构建、模块校验 | PASS |
|
||||
|
||||
旧版 `ProgramData` 路径证据已作废。便携目录改造后,从系统临时目录启动位于 `.codex-qa\portable-runtime-probe` 的运行库探针,实际加载路径为该探针 EXE 旁的 `wintun.dll`;其 SHA-256 为固定值 `e5da8447...20dafce`。单元测试同时验证了指定便携目录下的原子安装、复用和异常文件修复。
|
||||
|
||||
确认主机不存在 `RemLink` 适配器或 `10.88.0.0/16` 路由后尝试管理员适配器探针;它在明确的管理员预检处以 `administrator privileges are required` 停止,因此没有创建或修改网络适配器。
|
||||
|
||||
## Gate A 仍需证据
|
||||
|
||||
- 在管理员进程运行 `phase1-node --adapter-probe`,确认一个可复用 `RemLink`、指定 Overlay IPv4 和 MTU 1280。
|
||||
- 用 `deploy/phase1-server` 准备 Linux 内核 WireGuard `wg0`。
|
||||
- 在两台管理员权限 Windows 节点运行内嵌 wireguard-go POC,Server peer 各自只用唯一 Overlay `/32`。
|
||||
- 采集 `wg show`、Windows 适配器清单和双向 Overlay ping。
|
||||
- 确认每节点恰好一个 RemLink Wintun 且没有 WireGuardNT。
|
||||
|
||||
完成全部物理证据前,Phase 1 和 Gate A 必须保持未勾选。
|
||||
@@ -0,0 +1,80 @@
|
||||
# RemLink v1.0 T01–T18 验收执行手册
|
||||
|
||||
本文是证据模板,不代表真实环境已经通过。每次运行先执行 `scripts/validation/New-AcceptanceRun.ps1`;在指定主机证据齐全前,场景保持 `NOT_RUN`。每个 PASS 都必须在同一运行目录内包含时间戳、节点名、应用日志和指定主机快照。
|
||||
|
||||
只能通过 `Set-AcceptanceResult.ps1` 记录结果;脚本要求证据文件位于运行目录内,并保存 SHA-256 和大小。每批记录后及归档前执行 `Test-AcceptanceRun.ps1`。验证器会拒绝缺失、移动或修改过的证据并执行 Gate 前置条件,但不会代替人工判断所选截图是否真正证明场景。
|
||||
|
||||
~~~powershell
|
||||
./scripts/validation/Set-AcceptanceResult.ps1 -RunDirectory evidence/run-001 -ID T01 -Status PASS -EvidencePath engineer-a/inventory.json,site-a/inventory.json
|
||||
./scripts/validation/Test-AcceptanceRun.ps1 -RunDirectory evidence/run-001
|
||||
~~~
|
||||
|
||||
## 必需拓扑
|
||||
|
||||
- 一台 Linux Server:内核 WireGuard、公网可达 UDP endpoint,只公开受保护的 Bootstrap/Admin 入口和 `51820/udp`。
|
||||
- Engineer-A、Engineer-B、Site-A、Site-B:分别位于受支持 Windows 系统,RemLink 进程均以管理员运行。
|
||||
- Site-A 和 Site-B 各自可达一个 `192.168.13.0/24` 测试网段;Site-A 另外可达 `192.168.21.0/24`。
|
||||
- 目标提供 ICMP Echo、TCP 102、TCP 502、HTTP、RDP 和普通 UDP echo;不能用 RemLink 内部的协议专用代码替代。
|
||||
|
||||
在相关场景前后,分别在 Windows 节点运行 `Collect-WindowsEvidence.ps1`,在 Server 运行 `Collect-ServerEvidence.sh`。第三方 WinNAT 只做只读快照。Server 采集器故意只使用公开 WireGuard 视图,绝不执行可能暴露私钥或预共享密钥的 `wg show ... dump`。
|
||||
|
||||
## 场景步骤与通过条件
|
||||
|
||||
| ID | 执行与必需证据 | 通过条件 |
|
||||
|---|---|---|
|
||||
| T01 | 启动 Engineer/Site,采集 Admin 节点页和 Windows inventory | 两者 ONLINE;每节点恰好一个 `RemLink` 适配器;无 WireGuardNT |
|
||||
| T02 | Engineer 执行 `ping <Site Overlay IP>`,采集 ping 和 Server `wg show` | 经 Server hub 回复成功,WireGuard 计数增加 |
|
||||
| T03 | Engineer 连接 Site,CIDR 为 `192.168.13.0/24`;采 GUI 与 Session 日志 | Session 到 ACTIVE,且只出现一条自有 Remote route |
|
||||
| T04 | Engineer 本地接入 `192.168.13.0/24` 后请求相同远程网段 | 在 Server 创建前以 `CIDR_LOCAL_CONFLICT` 拒绝 |
|
||||
| T05 | 删除 Site 到 `192.168.13.0/24` 的全部非默认路由后请求 | PREPARE 以 `SITE_NO_ROUTE` 失败;无 ACTIVE Session 或泄漏 flow |
|
||||
| T06 | T03/T07–T09 前后分别快照 Hyper-V/Docker/WinNAT | 远程访问成功,第三方 NAT 快照完全一致 |
|
||||
| T07 | 对 PLC/测试目标执行 `Test-RemoteTargets.ps1` | 四个 Echo Reply 保留目标身份,无注入错误 |
|
||||
| T08 | 探测 TCP 102/502/80/3389,并对每项运行一次真实连接 | 全部服务经通用 TCP relay 连接;源码审计无协议代理 |
|
||||
| T09 | 向 UDP echo 发送不同数据报,等待超过 idle timeout 后再发 | 两次均成功;间隔后 flow 数回到基线 |
|
||||
| T10 | 一个 Session 同时请求 `192.168.13.0/24` 和 `192.168.21.0/24` | 两网段目标均通过 ICMP 及至少一项 TCP/UDP |
|
||||
| T11 | Engineer-A→Site-A 与 Engineer-B→Site-B 同时连接;两个 Site 都声明 `192.168.13.0/24` | 两个 SessionID 保持 ACTIVE;载荷标记只回到来源 Engineer |
|
||||
| T12 | 两个 Engineer 同时连接 Site-A,以不同标记访问同一 endpoint/port | Site flow/事件正确区分 SessionID 和 Engineer Overlay IP,无串流 |
|
||||
| T13 | Engineer-A 已 ACTIVE 时请求第二个 Site | UI 禁止选择;构造请求被 Server 以 `ENGINEER_SESSION_EXISTS` 拒绝 |
|
||||
| T14 | 持续 ping/TCP 时把 Engineer Wi-Fi 切到手机热点 | WireGuard 与 Control 在有限中断后重连;用户可重建不会自动恢复的 Session |
|
||||
| T15 | ACTIVE 流量期间重启 Server | 数据库非终态 Session 变 CLOSED;节点自动重连并能新建 Session |
|
||||
| T16 | 强制终止 Engineer,管理员重启,采集前后路由 | 接受新 Session 前 reconcile 删除自有陈旧 Remote route |
|
||||
| T17 | 在 Admin UI 修改一个在线 Node 的 Overlay IP | Session 关闭;Node 公开 Bootstrap;新 IP 下单适配器重连 |
|
||||
| T18 | 在 Admin UI 修改完整 Overlay CIDR | 全部 Session 关闭;`wg0`、数据库分配、Node 适配器、Control 和 Bootstrap 使用递增配置;Site NAT 快照不变 |
|
||||
|
||||
## 建议证据目录
|
||||
|
||||
~~~text
|
||||
evidence/run-001/
|
||||
acceptance-run.json
|
||||
T01-T18-runbook.md
|
||||
server/
|
||||
engineer-a/
|
||||
engineer-b/
|
||||
site-a/
|
||||
site-b/
|
||||
targets/
|
||||
screenshots/
|
||||
~~~
|
||||
|
||||
文件名应包含场景 ID、主机和 UTC 时间。严禁把 Join Token、Admin token、Node Token、WireGuard 私钥、预共享密钥或数据包载荷放入证据。需要展示配置时只截取非敏感字段。
|
||||
|
||||
## Gate 记录
|
||||
|
||||
- Gate A 使用 T01/T02 证据,并增加双向 Overlay ping。
|
||||
- Gate B 还需持续远程流量,证明同一个适配器承载普通外层 UDP 且无 busy loop/deadlock。
|
||||
- Gate C 需要目标侧 TCP/UDP echo 和 Site netstack 日志。
|
||||
- Gate D 需要返回 raw IPv4 身份以及 T07/T08/T09 证据。
|
||||
|
||||
不能仅根据单元/进程内测试标记 Gate 或场景 PASS。自动化测试证明实现不变量,本手册证明指定物理部署行为。
|
||||
|
||||
## 一次完整执行顺序
|
||||
|
||||
1. 初始化运行目录,记录版本、包哈希、拓扑、主机名、时间同步状态和人员。
|
||||
2. 采集五台主机基线,确认无秘密进入证据。
|
||||
3. 先执行 Gate A 与 T01/T02,验证单适配器和中心辐射 Overlay。
|
||||
4. 执行 T03–T10,覆盖路由冲突、Site 路由、NAT 不变、ICMP/TCP/UDP 和多 CIDR。
|
||||
5. 执行 T11–T13,覆盖并发、重复 CIDR、同 Site 多 Engineer 和单 Engineer 限制。
|
||||
6. 执行 T14–T18,覆盖网络切换、Server 重启、异常退出、节点 IP 与 Overlay 迁移。
|
||||
7. 采集结束快照、应用日志和目标侧证据,记录每项 PASS/FAIL/NOT_RUN。
|
||||
8. 执行验证器;修复证据路径/哈希问题,但不得为通过验证器而改写真实结果。
|
||||
9. 将完整运行目录只读归档,并单独保存发布包和外部 ZIP 哈希。
|
||||
@@ -0,0 +1,33 @@
|
||||
# 自动化验证覆盖
|
||||
|
||||
权威的 R1–R16 与 Phase 0–10 实现/证据矩阵见 `requirements-evidence.md`;本文补充自动化覆盖细节。
|
||||
|
||||
自动化测试覆盖协议 framing、精确错误码、Bootstrap/IPAM/数据库、Control 状态、PacketMux、Session UDP 验证、完整 Session 状态机、进程内 gVisor TCP/UDP/ICMP 往返、Admin 网络迁移、rebootstrap 通知和重复 CIDR 隔离。测试还固定 v1 的 `DEFAULT_ONLY` 拒绝、Session 级注入失败清理、拒绝注入后的监听连续性、限速安全警告、WG `/32` peer、唯一 Server client peer、Admin 日志时间过滤和 Site Console 状态/事件字段。
|
||||
|
||||
回归套件还覆盖:
|
||||
|
||||
- PREPARE 失败关联、重试和陈旧拒绝隔离;
|
||||
- netstack 幂等、PacketMux 计数/队列丢包、严格 IPv4 framing、Sender 关闭 race、UDP 空闲回收;
|
||||
- Site flow 上限、Server WG 密钥并发发布、可用 Overlay 主机地址、`/0` 拒绝和事件模块分类;
|
||||
- 迁移期间 Session quiesce、迁移后 Session 配置、旧 Control 通知顺序、Overlay 冲突事件、Control rebind 回滚和 Linux 内核变更回滚;
|
||||
- 全宽随机 SessionID 的无损十进制 JSON、新 Bootstrap 清理陈旧 Session、严格公网/Overlay endpoint、Site 容量拒绝和 Engineer 单 Session GUI 门禁。
|
||||
|
||||
验收工具自测证明:没有证据文件不能 PASS;Gate 前置条件被执行;证据 SHA-256 与大小会持久化;记录后篡改可被发现。架构扫描还禁止 Server 采集器导出 WireGuard dump/私钥,检查 Docker data mount、可配置 WireGuard 映射、发布 Compose 权限和预编译二进制入口。
|
||||
|
||||
发布验证器会独立解压 ZIP、检查必需项、重算每条 SHA-256、拒绝未纳入清单的文件,并运行包内验收初始化器,保持全部 Gate/T 为 `NOT_RUN`。
|
||||
|
||||
前端渲染 QA 的开发 fixture 只提供展示数据,实际使用与内嵌构建相同的 Vue 组件。最近一次检查覆盖 Server Nodes/Sessions/Network/Logs 交互以及 Engineer Site capability/LastSeen 和导航;页面有有效 DOM,浏览器无 warning/error。该 UI QA 不声称物理网络操作成功。
|
||||
|
||||
以下映射只作为支持证据,不能把真实验收场景标记 PASS:
|
||||
|
||||
| 验收区域 | 自动化证据 | 仍需真实证据 |
|
||||
|---|---|---|
|
||||
| T03/T05/T13 | `internal/session` manager/runtime 测试 | 管理员 Engineer/Site 与实际路由 |
|
||||
| T04/T16 | Windows 路由、冲突、reconcile 测试 | 真实主机前后路由清单 |
|
||||
| T07/T08/T09 | gVisor 主机套接字往返 | 两台 Windows 间 PLC/服务 |
|
||||
| T10 | 多 CIDR 状态机与 PacketMux | 两个物理现场子网 |
|
||||
| T11/T12 | 并发 Session 与重复 CIDR flow key | 四节点载荷隔离 |
|
||||
| T15 | SQLite 关闭开放 Session 与 Control 重连 | 流量中 Server 重启 |
|
||||
| T17/T18 | Admin 更新/rebootstrap/迁移回滚测试 | 真实适配器和 `wg0` 迁移 |
|
||||
|
||||
Gate A–D 和 T01–T18 在执行手册证据齐全前保持 `NOT_RUN`。
|
||||
@@ -0,0 +1,67 @@
|
||||
# RemLink v1.0 需求与证据矩阵
|
||||
|
||||
日期:2026-08-25
|
||||
|
||||
本矩阵审计根目录权威 DOCX、`specs/spec.md`、`specs/tasks.md` 和 `specs/checklist.md`,并映射到生产代码与可重复验证。若派生 Markdown 与 DOCX 冲突,以 DOCX 为准。
|
||||
|
||||
状态词汇:
|
||||
|
||||
- `CODE_TESTED`:存在生产实现,并有可重复自动化测试或策略扫描覆盖该边界。
|
||||
- `BUILD_VERIFIED`:目标已编译/类型检查,但不声称管理员权限或物理网络行为成功。
|
||||
- `PHYSICAL_NOT_RUN`:Gate/场景需要真实 Linux/Windows 拓扑,不能从单元、集成、浏览器或交叉构建推导 PASS。
|
||||
|
||||
## 需求覆盖
|
||||
|
||||
| 需求 | 生产证据 | 自动化/构建证据 | 审计状态 | 仍需物理证据 |
|
||||
|---|---|---|---|---|
|
||||
| R1 架构与不可变约束 | `internal/overlay`、`internal/subnet`、`internal/subnetgateway`、Windows 平台层、`serverwg` | 架构扫描;重复 CIDR manager/netstack 测试;双平台发布构建 | `CODE_TESTED` | Gate A–D、T01–T02、T06、T11–T12 |
|
||||
| R2 Overlay 与 Server IPAM | `internal/ipam`、Admin network/handler、Bootstrap、serverwg | IPAM 稳定分配;原子 Node/network 设置;七步迁移、回滚、通知顺序、Node IP 更新/删除 | `CODE_TESTED` | T17–T18 真实适配器、`wg0`、Control |
|
||||
| R3 单 Wintun MuxTun/PacketMux | clientwg、Windows Wintun/runtime | 分类、framing、计数、丢包、关闭测试;DLL 并发发布;Windows 构建 | `CODE_TESTED + BUILD_VERIFIED` | Gate A–B、T01–T02 管理员 Windows |
|
||||
| R4 Remote Subnet Session | `internal/session`、`internal/subnet`、Windows route | 完整状态机、请求关联、超时、多 CIDR、冲突、双向数据报验证、并发 SessionID 和 MaxUint64 JSON | `CODE_TESTED` | T03–T05、T10、T13 与真实路由 |
|
||||
| R5 Site gVisor 网关 | netstack、TCP/UDP/ping relay | 进程内主机套接字往返、prepare 幂等、容量和 UDP idle-GC | `CODE_TESTED` | Gate C–D、T06–T09 真实目标 |
|
||||
| R6 Bootstrap、Control、身份 | Bootstrap、Control、nodeagent、identity、DPAPI | 严格 API/config/URL、token/DPAPI、HELLO/心跳/状态/重连/rebootstrap | `CODE_TESTED` | T14–T15 中断 |
|
||||
| R7 Server | `cmd/server`、database、Admin、serverwg、Server 前端 | 数据库/Admin/Control;Linux 构建;前端生产扫描;Docker 架构与发布入口 | `CODE_TESTED + BUILD_VERIFIED` | Linux WG/Docker 启动与 UI 拓扑 |
|
||||
| R8 Engineer | `cmd/engineer`、Engineer 前端、Engineer Session、Windows adapter/route | runtime 测试;禁止 Demo fallback;Vue 构建;Windows GUI 构建 | `CODE_TESTED + BUILD_VERIFIED` | 管理员 GUI、路由、Wintun、Gate/T |
|
||||
| R9 Site | `cmd/site`、Site Session、subnetgateway | Console 字段/事件;route/capacity/injection/relay/reconcile;Windows console 构建 | `CODE_TESTED + BUILD_VERIFIED` | Site Console 与真实 LAN TCP/UDP/ICMP |
|
||||
| R10 数据库与模型 | database、model、migrations | 六表迁移/store;原子网络/IP 替换;启动关闭开放 Session | `CODE_TESTED` | T15 部署 Server 重启 |
|
||||
| R11 API 与消息 | Bootstrap HTTP、Admin handler、protocol、Control | 严格 JSON/framing/auth/direction/error 与 handler 测试 | `CODE_TESTED` | T03/T17/T18 指定抓包/API |
|
||||
| R12 冲突、失败、恢复 | route、nodeagent、Bootstrap reconcile、Session runtime、迁移事务 | 本地/Overlay 冲突、陈旧路由、新 Node 清 Session、重连、超时、注入失败、迁移回滚 | `CODE_TESTED` | T04–T05、T14–T18 |
|
||||
| R13 日志、统计、可观测性 | logging、eventlog、Session counter/reporter、Admin log API | 模块分类、限速、仅元数据包警告、统计持久化/过滤、秘密扫描 | `CODE_TESTED` | T07–T12 流量计数与日志 |
|
||||
| R14 安全边界 | Node/Join token 哈希、DPAPI、WG `/32`、严格 listener/validator、Admin token | token/auth、地址/URL、listener/validator、证据秘密扫描 | `CODE_TESTED` | 防火墙、暴露面、AllowedIPs |
|
||||
| R15 结构、接口、依赖 | monorepo、Go/npm 锁、内嵌 Wintun、第三方声明 | 模块验证、架构扫描、前端清洁安装、双平台构建、发布校验和 | `BUILD_VERIFIED` | 部署策略要求时的签名 |
|
||||
| R16 阶段与验收 | tasks/checklist、执行手册、证据脚本 | 自测执行证据哈希、范围、前置条件和篡改检测 | `CODE_TESTED`;物理状态独立 | Gate A–D、T01–T18 均 `PHYSICAL_NOT_RUN` |
|
||||
|
||||
## 阶段审计
|
||||
|
||||
| 阶段 | 实现状态 | 验收状态 |
|
||||
|---|---|---|
|
||||
| Phase 0 | 仓库、模型、日志、配置、协议、CI 已实现并测试 | 自动化验收完成 |
|
||||
| Phase 1 | Wintun/MuxTun/wireguard-go 与内嵌 DLL;Windows 可构建 | Gate A `PHYSICAL_NOT_RUN` |
|
||||
| Phase 2 | 数据库、IPAM、Bootstrap、Server WG、身份 store | 模拟 Node/IPAM 完成;部署由后续物理测试覆盖 |
|
||||
| Phase 3 | Control Hub、心跳、节点列表、capability、重连 | 自动化集成完成 |
|
||||
| Phase 4 | PacketMux、自有路由与冲突逻辑 | 物理 Wintun 拦截 `PHYSICAL_NOT_RUN` |
|
||||
| Phase 5 | 普通 UDP 重入传输和验证 | Gate B `PHYSICAL_NOT_RUN` |
|
||||
| Phase 6 | gVisor netstack TCP/UDP 网关 | Gate C `PHYSICAL_NOT_RUN` |
|
||||
| Phase 7 | 对称返回传输和 ICMP Echo relay | Gate D `PHYSICAL_NOT_RUN` |
|
||||
| Phase 8 | 双边 Session 状态机、错误、统计、reconcile | T03/T04/T05/T13/T16 `PHYSICAL_NOT_RUN` |
|
||||
| Phase 9 | Engineer GUI、Server 五页 UI、Admin API | UI 驱动真实工作流 `PHYSICAL_NOT_RUN` |
|
||||
| Phase 10 | 并发、重复 CIDR、打包、Docker、证据工具 | T01–T18 与最终重复子网拓扑 `PHYSICAL_NOT_RUN` |
|
||||
|
||||
## 复现命令
|
||||
|
||||
在仓库根目录运行:
|
||||
|
||||
~~~powershell
|
||||
go mod verify
|
||||
go test -count=1 ./...
|
||||
go vet ./...
|
||||
npm ci --prefix frontend
|
||||
npm run typecheck --prefix frontend
|
||||
npm run build --prefix frontend
|
||||
./scripts/validation/Test-FrontendProduction.ps1
|
||||
./scripts/validation/Test-Architecture.ps1
|
||||
./scripts/validation/Test-AcceptanceTools.ps1
|
||||
./scripts/build-release.ps1 -Version 1.0.0
|
||||
~~~
|
||||
|
||||
发布构建会在生成二进制和校验和前重复关键测试。真实结果必须先用 `New-AcceptanceRun.ps1` 初始化,采证后用 `Set-AcceptanceResult.ps1` 记录,最后运行 `Test-AcceptanceRun.ps1`。只有证据文件在该运行目录内且哈希通过时,Gate/T 才允许标记 PASS。
|
||||
Reference in New Issue
Block a user