基于 C++20、libssh 和 SQLite 的 SSH 匿名论坛服务器。连接后直接进入全屏 TUI,帖子采用「主帖 + 平铺回复」结构,新帖子显示稳定匿名标识,例如 Anonymous#ABCDEFGH,没有注册、账户或权限分级。
Linux 环境,需要 C++20 编译器、CMake ≥ 3.20、libssh ≥ 0.10、SQLite3、OpenSSL ≥ 3.0。项目提供 toolbox 构建脚本;Python/Paramiko 只用于 SSH 集成测试。
# 如果还没有 toolbox 容器,先创建一个
toolbox create -c fedora-toolbox-45
# 安装依赖、构建并运行测试(安装操作发生在 toolbox 内)
bash scripts/build-toolbox.sh --install
# 已安装依赖时
bash scripts/build-toolbox.sh
# 在项目目录启动服务,默认监听 0.0.0.0:2222
toolbox run -c fedora-toolbox-45 ./build/sshforum使用其他现有容器时可设置 TOOLBOX_CONTAINER=容器名。toolbox 和宿主机共享项目目录;无需在宿主机安装开发库。
另开终端连接:
ssh -tt -p 2222 anonymous@localhost用户名任意,标准 SSH 客户端的 none 认证直接成功,不需要输入密码。主动使用 password、publickey 或 keyboard-interactive 的客户端也会被接受,不查询系统用户、密码或 authorized_keys。SSH 协议本身的加密、签名和握手由 libssh 处理。
第一次连接时仍有标准 SSH 主机指纹确认,这是客户端验证服务器身份。服务器首次启动自动生成 Ed25519 主机密钥,后续复用同一文件。
./build/sshforum --bind 127.0.0.1 --port 2222 \
--db data/forum.db --host-key data/ssh_host_ed25519_key --max-sessions 128
./build/sshforum --help如果宿主机没有兼容的运行库,以上命令也应通过 toolbox run -c fedora-toolbox-45 执行。远程连接使用服务器地址,监听端口需能从客户端访问。
none 认证使用「对端 IP + SSH 用户名」;直接使用 password / publickey 认证时还加入认证方式和收到的密码 / 公钥。keyboard-interactive 不询问答案,使用 IP、用户名和认证方式。普通 OpenSSH 客户端通常先尝试 none,成功后不会再发送密码或公钥,因此更改 PreferredAuthentications 不保证改变标识来源。
服务器用持久化的随机密钥计算 HMAC-SHA256,保存完整摘要,显示前 40 位对应的 8 个 Base32 字符。相同输入在重连、源端口变化和服务重启后保持一致;IP、用户名或认证材料变化会产生不同标识。共享出口 IP 且用户名相同的 none 用户会得到相同标识;短显示名也可能碰撞。它只是匿名标签,不是账号、权限或身份认证保证。
首次升级会在事务中自动将 SQLite schema 从 v0 迁移到 v1:为主帖和回复增加作者字段,并保存身份密钥。历史帖子仍显示 Anonymous,不推断作者。旧版本显式列插入仍兼容;遇到高于 v1 的数据库会拒绝启动,避免误改。密钥存储在数据库的 forum_metadata 中,完整备份数据库即可保留标识;异常密钥会报错而不会自动替换。
| 页面 | 按键 | 操作 |
|---|---|---|
| 帖子列表 | ↑ / ↓ 或 k / j | 选择帖子 |
| 帖子列表 | PgUp / PgDn | 翻页选择 |
| 帖子列表 | Enter / → | 进入选中帖子 |
| 帖子列表 | n | 新建帖子 |
| 列表 / 帖子 | r | 从数据库刷新 |
| 帖子详情 | ↑ / ↓ 或 k / j | 上下滚动 |
| 帖子详情 | PgUp / PgDn | 翻页 |
| 帖子详情 | a | 匿名回帖 |
| 帖子详情 | b / ← | 返回列表 |
| 标题编辑 | Enter | 进入正文编辑 |
| 正文编辑 | Enter | 换行 |
| 正文编辑 | Ctrl+D | 提交 |
| 编辑 | ← / → | 前后移动光标 |
| 正文编辑 | ↑ / ↓ | 按显示行移动光标 |
| 编辑 | Home / End | 移到当前显示行的行首 / 行尾 |
| 编辑 | Ctrl+Home / Ctrl+End | 移到当前输入内容开头 / 结尾 |
| 编辑 | Backspace / Delete | 删除光标前 / 后的字符 |
| 编辑 | Esc | 取消 |
| 帖子列表 | q | 退出 |
| 任意页面 | Ctrl+C | 退出 |
支持中文 UTF-8 输入、光标位置插入与删除、窗口大小调整;编辑时显示真实终端光标,正文视口随光标滚动。新回复会将帖子顶到列表前方。另一位用户发帖或回帖后,按 r 查看。标题最多 120 字节,正文和每条回复最多 16 KiB,不接受空白内容。列表展示最近活跃的 200 个帖子。
主列表每个主题占两行,主题之间留一行空白,右侧分别显示发帖时间和最近回复时间:24 小时内为 2h 30m ago,更早为 3d ago;无回复显示 No replies yet,按 r 刷新。详情中相邻消息之间用横线分隔。
主题详情显示主帖发布时间(Posted)和最后回复时间(Last reply),每条回复也显示自己的发布时间;尚无回复时显示 No replies yet。时间采用 UTC(末尾 Z),按 r 刷新最后回复时间。
src/main.cpp 命令行选项与启动
src/server.cpp libssh 回调、非阻塞连接、poll 调度器
include/sshforum/task.hpp C++20 coroutine Task / RAII
src/tui.cpp TUI 状态机、增量键盘解析、终端渲染
src/store.cpp SQLite 持久化、事务、参数绑定
src/identity.cpp HMAC 作者 ID 与短显示名
tests/ 存储、TUI、真实 SSH 端到端测试
每个 SSH 连接由一个 C++20 协程负责,从密钥交换、认证、等待 shell 请求,到读取输入、发送输出及关闭连接。等待网络进展时通过 co_await 让出执行权,由单线程 poll 循环继续调度;没有每连接线程,也没有启动系统 shell。SSH 的 PTY 请求只记录终端尺寸,显示由 ANSI/VT100 转义序列完成。
监听 socket 显式设置 O_NONBLOCK。每轮输入处理以 32 个按键命令或约 2 毫秒为预算,在字节处理之间检查并让出执行权;剩余输入保留到后续轮次,存在可处理的缓冲输入时不等待新的网络事件。预算不能中断正在执行的单次数据库调用或渲染。
SQLite 使用 WAL、外键、prepared statements 和事务。数据库访问保持同步,适合小型服务;写事务和较大的帖子渲染可能短暂阻塞事件循环。认证/进入界面超时为 30 秒,空闲连接超时 30 分钟,慢客户端输出有缓冲上限;这些是资源边界,不是账户权限。
服务仅实现论坛终端,不提供 exec 命令执行、SFTP、端口转发。帖子内容输出前过滤控制字符,防止终端转义注入。数据库保存帖子、回复、完整匿名作者 ID 和服务器身份密钥,不保存原始 IP、登录名、密码或公钥。当前版本没有附件、搜索、删除、管理面板或自动推送;正文很长时需滚动阅读。
生产安装、DynamicUser 隔离服务、systemd-run 临时测试和 SRPM/RPM 构建见 安装与打包说明。项目采用 MIT 许可。
默认数据在 data/forum.db,主机密钥在 data/ssh_host_ed25519_key。两者应持久保存。停止服务后备份整个 data/ 目录即可;运行中备份 SQLite 应使用 SQLite 的备份工具,不只复制主数据库文件。Ctrl+C / SIGTERM 停止服务并释放连接。
toolbox run -c fedora-toolbox-45 ctest --test-dir build --output-on-failureidentity 验证 HMAC 向量、字段编码和显示名;store 验证 schema 迁移、身份密钥与持久化、排序、输入边界、并发和事务;tui 验证导航、编辑、UTF-8 与控制字符处理;ssh_smoke 启动临时服务器,通过 Paramiko 验证开放认证、双客户端操作、窗口调整、终端恢复和重启持久化。测试使用独立临时数据,不污染实际论坛。
libssh API 参考:官方服务端文档。