PSSP 连接故障排查
当客户端无法连接、认证、订阅、发布、绑定 UDP 或恢复数据时,请使用本指南并从上到下检查。修改密码无法修复未监听的 Broker,修改 ACL 也无法修复失败的登录。
当命令行找不到 pssp-broker 时
仅检出此仓库不会自动把可执行文件安装到 PATH。其源代码位于 broker/;本地构建产物位于 target/debug/pssp-broker 或 target/release/pssp-broker(Windows 上带有 .exe)。在仓库根目录中,可以通过 Cargo 运行,也可以直接使用构建产物路径:
cargo run -p pssp-broker -- --help
./target/debug/pssp-broker --help # macOS/Linux
.\target\debug\pssp-broker.exe --help # Windows PowerShell
以 pssp-broker 开头的示例表示可执行文件已安装并位于 PATH 中的部署环境。进行仓库开发时,请将该前缀替换为 cargo run -p pssp-broker --,或 target/ 下适合当前平台的路径。完整路径表和示例请参阅在哪里查找以及如何运行 Broker。
按此顺序诊断
- 启动 Broker。确认进程持续运行,没有因配置、证书、密钥或数据库错误而退出。
- 确认 TCP 可达。确认预期进程正在监听 TCP
6688,且客户端能够访问该主机和端口。 - 匹配安全模式。TLS、PSSP AES、客户端 TLS 选项、证书信任和仅 AES 公钥固定值必须一致。
- 验证认证。精确的
clientId+username记录必须存在、已启用且密码正确。 - 验证授权。登录成功并不自动授予发布/订阅权限;检查主体的主题 ACL。
- 测试数据流。依次测试 TCP 连通性、订阅/发布、UDP 绑定与连通性,以及重放与保留行为。
“连接被拒绝(Connection refused)”通常表示没有监听进程或地址错误。TLS 或 AES 固定值错误发生在 AUTH 之前。authentication_failed 来自凭据数据库。publish_not_authorized 和 subscribe_not_authorized 表示认证已成功,但 ACL 检查失败。
案例:pssp-admin / admin 无法连接
调查客户端使用客户端 ID pssp-admin、用户名 admin 和指定密码时发现了以下问题。开发环境很容易同时出现这些问题,因此在此保留完整记录。
| 发现 | 阻塞原因 | 解决方法 |
|---|---|---|
没有进程监听 TCP 或 UDP 6688。 | 客户端无法访问 Broker,凭据验证根本没有开始。 | 先启动 Broker 并确认监听端口,再修改凭据。 |
当前配置的 storage.sqlite_path 指向受保护的生产数据库;该文件属于 root 且权限为 0600。 | 普通开发用户无法进入数据库目录或打开 SQLite,因此 Broker 立即退出。 | 普通用户运行 Broker 时使用仓库开发配置;安装服务时则让数据库所有者与服务账号一致,然后重新运行 setup。不要使用 chmod 777。 |
| TLS 关闭而 PSSP AES 开启。 | 仅 AES 模式下,桌面客户端必须先固定准确的 Broker X25519 公钥,才会发送凭据。该输入框默认为空。 | 按下方仅 AES 步骤生成并分发公钥,然后粘贴到客户端。 |
| 配置的私钥是全零格式示例。 | 它在格式上有效,但公开可知,不能作为安全的 Broker 身份密钥。 | 生成随机私钥、妥善保护、更新配置,并重新分发新公钥固定值。 |
pssp-admin 和 admin 只出现在设置示例中。 | PSSP 没有内置默认账号或默认密码。密码是在 setup 或后续轮换时由管理员输入的值。 | 列出主体、必要时启用,或轮换密码。密码哈希无法反向还原或显示。 |
未发现已安装的 macOS launchd 服务、安装版二进制或 /etc/pssp/pssp.toml。 | 仓库配置与数据库处于不完整安装状态,没有任何组件自动启动 Broker。 | 开发时从仓库运行,或完整执行平台服务安装。 |
第一个根因是服务不可用:Broker 进程身份与当前配置选定的数据库所有者不一致。下一层阻塞是仅 AES 公钥固定。只有修复这两项后,指定密码才会真正进入验证流程。
正确启动桌面客户端
- 首次安装依赖。
cd client npm install - 启动包含 Rust 后端的 Tauri 应用。
npm run tauri:dev - 不要把
npm run dev当作完整客户端;它只启动 Vite 网页界面。connect等原生命令需要 Tauri 桌面运行时。
如果构建失败,请确认 Node.js 20+、当前 Rust 工具链以及 Tauri 2 所需的操作系统依赖。可单独检查 Rust 工作区以显示后端编译错误:
cargo check --workspace
确认 Broker 已运行并监听
开发环境启动
cargo run -p pssp-broker -- serve \
--config broker/config/pssp.example.toml
保持终端打开并读取第一条错误。健康启动会记录 TCP/UDP 监听地址及所选 TLS/AES 模式。
监听端口检查
| 平台 | 命令 |
|---|---|
| macOS | lsof -nP -iTCP:6688 -sTCP:LISTEN |
| Linux | ss -lntup | grep 6688 |
| Windows PowerShell | Get-NetTCPConnection -LocalPort 6688 -State Listen |
| 远程 TCP 检查 | nc -vz BROKER_HOST 6688 或 Test-NetConnection BROKER_HOST -Port 6688 |
如果 Broker 只监听 127.0.0.1,远程客户端无法连接。仅在防火墙限制到可信网络时使用 0.0.0.0:6688 等接口,并确认端口没有被其他进程占用。
服务检查
| 平台 | 常用检查 |
|---|---|
| Linux/systemd | systemctl status pssp-brokerjournalctl -u pssp-broker -n 100 --no-pager |
| macOS/launchd | launchctl print system/io.oxrecorder.pssp-broker检查配置的标准输出与错误日志。 |
| Windows 任务计划程序 | Get-ScheduledTask -TaskName 'PSSP Broker'检查任务历史及二进制/配置路径。 |
初始化 SQLite 并安全修复权限
数据库缺失、未初始化或不可读时,Broker 不会启动。SQLite 保存主体、Argon2id 密码哈希、启用状态、ACL 和凭据审计事件;主题负载与会话状态只保存在内存中。
Broker 没有一个固定的数据库目录。传给 setup、所有管理命令和 serve 的同一份配置中的 storage.sqlite_path 才是准确信息。相对路径以 Broker 进程的工作目录为基准。仓库开发配置使用 data/pssp-broker.sqlite3;从仓库根目录运行本文的 Cargo 命令时,实际位置是 <仓库根目录>/data/pssp-broker.sqlite3。安装服务应在部署配置中选择受保护的绝对路径。
- 打开正在使用的 TOML 配置并确认
storage.sqlite_path。不要用一份配置排查,却用另一份配置启动 Broker。 - 选择运行 Broker 服务的账号。在 Unix 上,将
storage.unix_owner_user和storage.unix_owner_group同时设置为已存在的服务账号;用户自有的开发数据库则可同时省略这两项。不能只设置其中一项。 - 用同一份配置初始化结构并创建引导管理员。命令会创建缺失的父目录与 SQLite 文件,并安全提示输入至少 12 个字符的密码。在 Unix 上,数据库及已有旁路文件权限会限制为
0600。如果配置了 Unix 所有者与组,父目录还会限制为0700并应用该所有权;应以root或该服务账号运行 setup,确保有权执行这些修改。pssp-broker setup --config /etc/pssp/pssp.toml \ --bootstrap-client-id pssp-admin \ --bootstrap-username admin - 验证元数据;以下命令不会显示密码哈希。
pssp-broker list-principals --config /etc/pssp/pssp.toml pssp-broker list-acls --config /etc/pssp/pssp.toml \ --client-id pssp-admin --username admin - 以同一账号启动服务,然后确认监听端口。
文件系统权限与主题授权是两回事
| 权限层 | 配置方式 | 控制内容 |
|---|---|---|
| 操作系统文件访问 | storage.sqlite_path、unix_owner_user、unix_owner_group 和 setup | Broker 进程能否打开数据库并创建 SQLite WAL/SHM 旁路文件。 |
| PSSP 认证 | setup、create-principal、rotate-password 以及启用/禁用账户命令 | 准确的 clientId + username + 密码能否通过认证。 |
| PSSP 主题授权 | grant-acl 和 revoke-acl | 主体可发布哪些具体主题、可订阅哪些过滤器。新建主体在授予 ACL 前没有任何主题访问权限。 |
所有主体和 ACL 命令都必须使用与 serve 相同的 --config。修改型 CLI 命令会保留配置的 Unix 所有者和安全权限;把数据库文件手动改成所有人可读或可写,并不会授予任何 PSSP 主题权限。
本地仓库替代方案
本地开发使用 broker/config/pssp.example.toml,并从仓库根目录运行下列命令。配置的相对路径会在工作区内创建 data/pssp-broker.sqlite3,避免用户运行的 Broker 混用安装服务的数据库:
cargo run -p pssp-broker -- setup \
--config broker/config/pssp.example.toml \
--bootstrap-client-id pssp-admin --bootstrap-username admin
cargo run -p pssp-broker -- serve \
--config broker/config/pssp.example.toml
数据库错误应通过匹配服务账号与目录/文件所有权来解决。避免全局可写权限,也不要让不受信任的桌面客户端直接访问 Broker 数据库;客户端只能通过 PSSP 认证。
解决 authentication_failed
线上登录包含三个独立值:clientId、username 和 password。前两个值选择一条精确 SQLite 记录,第三个值与 Argon2id 哈希比较。
- 列出主体并确认精确拼写、大小写和启用状态。
pssp-broker list-principals --config /etc/pssp/pssp.toml - 如果密码未知,请轮换密码;无法从哈希恢复原密码。
pssp-broker rotate-password --config /etc/pssp/pssp.toml \ --client-id pssp-admin --username admin - 启用已禁用主体。
pssp-broker set-principal-enabled --config /etc/pssp/pssp.toml \ --client-id pssp-admin --username admin --enabled - 修改或失败后等待
storage.auth_cache_seconds(默认 30 秒),或重启 Broker 后再测试。 - 输入值时不要带前后空格。客户端按原样发送,不会创建账号或替换为默认密码。
如果主体已存在,再次运行 setup 只会确认管理员 ACL,不会替换现有密码。需要改密码时使用 rotate-password。
逐步设置仅 AES 连接
仅 AES 表示关闭 TLS,同时启用 PSSP AES-256-GCM。Broker 使用长期 X25519 身份密钥;每个会话通过固定的 Broker 公钥、客户端临时密钥和 HKDF-SHA-256 派生新的 AES 密钥。AES 会话密钥不会通过网络传输。
- 将仅 AES 模板复制到受保护的部署配置。
cp broker/config/pssp.aes-only.example.toml /etc/pssp/pssp.toml - 生成随机私钥并保存在仅管理员可读的位置。
umask 077 pssp-broker generate-aes-only-private-key \ > /etc/pssp/aes-only-private-key - 把生成值复制到
/etc/pssp/pssp.toml的encryption.static_private_key。不要使用AAAAAAAA...AAA;它只是格式示例。 - 派生客户端必须固定的公钥。
pssp-broker aes-only-public-key \ --private-key-file /etc/pssp/aes-only-private-key - 确认安全配置。
[tls] enabled = false [encryption] enabled = true static_private_key = "GENERATED_PRIVATE_KEY" [transport] allow_insecure_tcp_udp = false - 使用同一配置初始化 SQLite,然后启动 Broker。
pssp-broker setup --config /etc/pssp/pssp.toml \ --bootstrap-client-id pssp-admin --bootstrap-username admin pssp-broker serve --config /etc/pssp/pssp.toml - 在桌面客户端输入 Broker 主机和端口,关闭 TLS 1.3 传输(TLS 1.3 transport),把派生公钥粘贴到 Broker 仅 AES X25519 公钥(Broker AES-only X25519 public key),输入准确凭据并选择连接(Connect)。
- 确认客户端显示“AES 会话:活动(AES session: active)”,然后测试 TCP 连通性、订阅/发布、UDP 绑定和 UDP 连通性。
| 仅 AES 症状 | 原因与修复 |
|---|---|
TLS-off AES broker requires a pinned X25519 public key | 固定值为空。请预置并粘贴派生的 Broker 公钥。 |
broker AES-only public key does not match the pinned key | Broker 密钥已变化、选择了错误环境,或复制错误。替换固定值前请通过独立可信渠道核验。 |
| Broker 拒绝配置或密钥协商 | 确认私钥使用无填充 base64url,解码后正好为 32 字节。 |
| 密钥轮换后现有客户端失败 | 轮换会改变公钥固定值。按计划在切换前或切换期间安全更新所有客户端。 |
请通过受管设备配置、签名软件包或独立核验的管理员渠道分发公钥。直接信任同一网络端点临时显示的未知公钥,会失去固定公钥的防中间人意义。
设置 TLS + AES
- 从
broker/config/pssp.production.example.toml开始。 - 安装 Broker 服务账号可读的 TLS 证书和私钥。证书必须包含客户端使用的 DNS 名称。
- 配置两个保护层。
[tls] enabled = true certificate_file = "/etc/pssp/tls/fullchain.pem" private_key_file = "/etc/pssp/tls/privkey.pem" [encryption] enabled = true [transport] allow_insecure_tcp_udp = false - 初始化 SQLite、启动 Broker,并确认日志显示
tls=true和encryption=true。 - 客户端使用证书中的 DNS 主机名连接并开启 TLS 1.3 传输(TLS 1.3 transport);此模式不使用仅 AES 公钥输入框。
TLS 握手错误通常表示客户端 TLS 选项与 Broker 不一致、证书过期或不受信任、主机名不匹配,或缺少中间证书。除非证书的使用者可选名称(Subject Alternative Name)包含该 IP,否则使用 IP 地址连接会失败。
仅在隔离的本地环境使用明文
[tls]
enabled = false
[encryption]
enabled = false
[transport]
allow_insecure_tcp_udp = true
关闭客户端 TLS 并保持仅 AES 固定值为空。当 TLS/AES 都关闭时,Broker 要求显式设置 allow_insecure_tcp_udp = true;当 TLS 或 AES 任一开启时,该值又必须为 false。
只在隔离开发机或明确可信的私有边界中使用。不要暴露到 Wi-Fi、公网或不可信局域网。
修复发布和订阅授权
认证与授权相互独立。主体可以成功登录但没有任何 ACL。
pssp-broker list-acls --config /etc/pssp/pssp.toml \
--client-id pssp-admin --username admin
为管理员测试账号授予所有主题权限:
pssp-broker grant-acl --config /etc/pssp/pssp.toml \
--client-id pssp-admin --username admin \
--action publish --topic-filter '#'
pssp-broker grant-acl --config /etc/pssp/pssp.toml \
--client-id pssp-admin --username admin \
--action subscribe --topic-filter '#'
| 问题 | 解决方法 |
|---|---|
publish_not_authorized | 授予匹配的发布 ACL。发布到 demo/topic 等具体主题;不要发布到 # 或包含 + 的主题。 |
subscribe_not_authorized | 授予包含请求过滤器的订阅 ACL。ACL 和订阅过滤器可以使用 + 和末尾 #。 |
| 小负载成功,大负载失败 | 检查 Broker 全局 limits.max_payload_bytes 和主体可选的单账号最大值。 |
| ACL 修改似乎未生效 | 等待认证缓存 TTL,或按情况重连/重启。 |
修复 UDP 绑定与连通测试
- 先完成已认证 TCP 连接。UDP 关联到活动 TCP 会话。
- 先选择绑定 UDP(Bind UDP),再选择 UDP 连通测试(UDP Ping)。
- 保持 TCP 连接;关闭后 UDP 令牌、AES 材料和端点关联全部失效。
- 允许 UDP
6688通过主机防火墙、云防火墙、VPN、NAT 以及容器/虚拟机转发。 - 确认 TCP 与 UDP 指向相同 Broker 主机和配置端口。
- 如果 TCP 正常而 UDP 超时,请在绑定时查看 Broker 日志。网络策略可能允许 TCP 但静默丢弃 UDP。
UDP 是 QoS 0:没有重放、接收保证或重试。一次心跳丢失不代表 TCP 会话已断开;使用 TCP 连通测试(TCP Ping)检查可靠控制路径。
重放、GAP、断线和慢客户端
| 现象 | 含义与操作 |
|---|---|
GAP | 请求序列已从有界内存主题环中淘汰。请从应用存储恢复,或在评估内存后增加保留量。 |
resume 没有返回旧消息 | 复用相同订阅者标识,在 subscriber_resume_ttl_seconds 过期前重连,并确认 Broker 没有重启。 |
| Broker 重启后数据消失 | 这是预期行为:主题环、会话密钥、订阅、UDP 关联、去重状态和恢复游标都是易失的。 |
| 慢订阅者漏掉实时投递 | 每个会话的发送队列有上限,防止慢客户端阻塞 Broker。请重连并重放保留数据,或修复消费者。 |
| 同一客户端 ID 有多个连接 | 这是预期行为。PSSP 不会因为另一个会话使用相同客户端 ID 而驱逐现有连接。 |
| 空闲连接关闭 | 在 limits.idle_timeout_seconds 到期前定期发送 TCP PING。 |
常见错误与症状参考
| 错误或症状 | 可能层级 | 第一步 |
|---|---|---|
connect TCP、连接被拒绝(connection refused) | 进程/网络 | 启动 Broker,验证监听地址与端口。 |
| 连接超时 | 路由/防火墙 | 检查主机、路由、防火墙、VPN、NAT 和安全组。 |
open SQLite database / 错误代码 14 | 存储权限 | 让 Broker 进程账号与数据库目录/文件所有权一致。 |
database is not initialized | 数据库结构 | 使用与 serve 相同的配置运行 pssp-broker setup。 |
| TLS 与 AES 均关闭但未显式允许 | 配置验证 | 仅在隔离明文测试中设置 transport.allow_insecure_tcp_udp = true。 |
TLS requires certificate_file and private_key_file | 配置/TLS | 设置两个受保护文件路径,确认服务账号可读,并验证私钥与证书匹配。 |
TLS-off PSSP AES requires encryption.static_private_key | 配置/AES | 生成并配置 32 字节 base64url X25519 私钥。 |
Broker requires TLS | 安全模式不匹配 | 客户端开启 TLS,并使用可信且匹配的主机名。 |
| TLS 握手失败 | 证书/TLS | 检查信任链、有效期、主机名和 TLS 模式。 |
| 仅 AES 固定值缺失/不匹配 | 公钥固定 | 通过独立可信渠道核验并预置 Broker X25519 公钥。 |
authentication_failed | 身份 | 检查精确主体、启用状态、密码和认证缓存时间。 |
publish_not_authorized | ACL/主题 | 检查发布 ACL,并使用具体主题。 |
subscribe_not_authorized | ACL/过滤器 | 检查订阅 ACL 和过滤器语法。 |
PSSP payload exceeds limit | 限制 | 减小/分片负载,或有计划地提高兼容限制。 |
PSSP request timed out | 会话/Broker | 检查 Broker 日志、TCP 存活、加密状态和防火墙。 |
unsupported PSSP version、魔数无效(invalid magic)或未知记录类型/标志 | 协议兼容性 | 确认两端使用兼容的 PSSP v1 构建,并确认该端口确实是 PSSP Broker,而不是 HTTP/TLS 服务。 |
connection limit reached 或发送队列已满 | 容量/背压 | 查找泄漏或过慢会话,检查 max_connections 和队列容量,并在测量资源使用后再扩容。 |
| UDP 绑定/连通测试超时 | UDP 路径 | 保持 TCP 活动、先绑定,并允许 UDP 6688。 |
GAP | 保留 | 从外部存储恢复或检查主题环限制。 |
收集有效的故障报告
向其他开发者求助前,请记录以下信息,但不要包含密码、私钥、原始会话密钥或敏感负载:
- 操作系统,以及 Broker 是通过 Cargo、systemd、launchd 还是任务计划程序运行。
- Broker 和客户端版本或提交 ID。
- 主机和端口;必要时隐藏私有地址。
- 所选模式:TLS + AES、仅 AES 或有意明文。
- 客户端显示的准确错误及对应 Broker 日志行。
- TCP
6688是否监听且可远程访问。 - SQLite 配置路径及所有者/权限;不要提供数据库内容或密码哈希。
list-principals和相关list-acls输出;这些命令不会显示哈希。- 问题属于 TCP 连接、认证、ACL、TCP 数据、UDP 还是重放。
不要把 encryption.static_private_key、TLS 私钥、密码、数据库文件或包含明文凭据的抓包粘贴到问题报告中。仅 AES 公钥可以用于识别,但公开它仍可能暴露环境之间的关系。