
モダンCで書かれたssh-chat

汎用BBSソフトウェア
SSH-Chatterは、Go言語で書かれたssh-chatサーバーをC言語で再実装したものから始まりました。現代的なC言語のパターンと、小さくてテスト可能なコアを使用しながら、元の動作を模倣・拡張しています。サーバーはSSH/TELNET接続を待ち受け、認証された各ユーザーを共有チャットルームに配置し、Go参照実装と同じコマンドインターフェースを提供します。
なぜC言語を理解するのに時間がかかるのか知っていますか?それは本能だからです。
/rss list、/rss read <tag>、さらに/rss add <url> <tag>および/rss del <tag>(オペレーターのみ)で、ルーム内で一緒に見出しを閲覧できます。/delete-msg。/bbsコマンドで、タグ、コメント、バンプ、マルチラインコンポーザーを備えた没入型レトロ掲示板システムを利用可能。
list [hot|top|new|bumped|all] を使用して、bumped(最近の活動)、hot(スコアとコメントでトレンド)、top(最高の正味アップ投票スコア)、new(作成日)で投稿を表示。search <query> で投稿タイトル、本文、作者、タグを大文字小文字区別なく即座に検索。▲ 12 💬 5)で表示。/bbsプレフィックスなしでコマンドを自動ルーティング。/asciiartライブコンポーザー:640行制限、IPごとに10分間のクールダウン、複数行出力、Ctrl+Aでキャンセル、Ctrl+Sまたはロケール対応の>/__ARTWORK_END>デフォルトで送信するキーボードショートカット。/birthdayで誕生日を登録、/grant <ip>でLANオペレーターがアドレスごとに権限を委任、/revoke <ip>でトップLAN管理者がそれらを取り戻す。/banのアップグレード。/weather <city> で簡単な世界の天気予報。

コードベースは意図的にコンパクトに保たれており、新しいコントリビューターが迅速にナビゲートできます:

mainとの同期を維持するworkブランチは定期的に上流の開発から分岐し、大きな機能が本番トラフィックを妨げずに育成できるようにしています。mainと同期する時期が来たら、最新のツリーをプルしてローカルでマージしてからプルリクエストを開いてください:```bash
git fetch origin main
git checkout work
git merge --no-ff origin/main
競合はその場で解決してください(`src/host_aggregate.c` ヘルパールーチンは既に `main` で使用されているレイアウトを反映しているため、マージは通常簡単です)。結果をプッシュする前に `make` を実行してビルドが成功することを確認してください。
## 自動化フック
- `host_snapshot_last_captcha` は、最新に生成されたキャプチャプロンプトと回答をタイムスタンプとともに公開し、外部クライアントが無人自動化に代わってチャレンジを通過できるようにします。
## セキュリティ強化
- `scripts/safe_permission.sh` は、ランタイムデータファイル(BBS状態、投票状態、クールダウンスナップショット、一般チャッター状態)の所有者とモードを厳格化します。デプロイ後に実行して、データディレクトリを `ssh-chatter` に限定し、各ファイルが `0600` に設定されていることを確認します。明示的なパスを渡すか、実行前に `STATE_ROOT` または対応する `CHATTER_*_FILE` 環境変数をエクスポートしてターゲットを上書きします。
- バックグラウンドのBBS watchdogは、定期的に投稿とコメントをAIモデレーションパイプライン(プライマリはGemini、フォールバックはOllama)に送信します。フラグが立てられた投稿は自動的に削除され、ルームに通知がブロードキャストされます。
- チャットメッセージ、ASCIIアート、BBSの投稿/コメントはAIモデレーションパイプラインを通過します。`CHATTER_SECURITY_AI=on` で有効にします(Geminiの場合は `GEMINI_API_KEY` を設定。デーモンは自動的にローカルのOllamaエンドポイント `http://127.0.0.1:11434` にフォールバックします)。`CHATTER_SECURITY_FILTER=off` ですべて無効にします。すべてのプロバイダが失敗した場合、フィルタは自動的に無効になり、コンテンツを静かにドロップする代わりに会話を継続させます。
- SSHトランスポートは最新の鍵交換、暗号、MACに固定されており、すべてのブリッジペイロードは三重のAES-256-GCMオニオンでラップされるため、リレーは暗号文のみを認識します。
- レイヤーフィルタに引っかかった不審な投稿はIPごとに追跡され、有効にすると繰り返しのヒットが自動キックと禁止をトリガーします。一方、高速再接続検出器はより長い回復ウィンドウを許可するため、不安定なネットワークセッションがペナルティを受けることなく再接続できます。自動禁止エントリはデフォルトで**オフ**です。`CHATTER_AUTO_BAN=on`(または `true`/`1`)を設定して有効にするか、変数を未設定のままにして、自動禁止エントリを書き込まずに警告とスロットリングを維持します。
- オペレーターは `CHATTER_PROTECTED_IPS`(カンマ区切り、デフォルトは `127.0.0.1,::1,192.168.0.1`)を使用して信頼できる入口ポイント(VPN出口、リバースプロキシ、localhost)をマークできるため、緊急禁止によってデーモンが自身のコントロールプレーンからロックアウトされることはありません。
## ファイルストレージと転送
- すべてのユーザー管理ファイルは `/etc/ssh-chatter/user-files` に配置されます(`CHATTER_FILESTORE_PATH` で上書き、レガシーフォールバック: `CHATTER_FILE_STORAGE_ROOT`)。デーモンは必要に応じてディレクトリを作成し、アップロードをそのディレクトリ内に限定します。
- SSHクライアントはカスタムラッパーなしで標準の `scp` を使用します。`/name.ext` をストレージツリーのルートとして扱います。`scp my.zip user@host:/demos/my.zip` は `/etc/ssh-chatter/user-files/demos/my.zip` に書き込み、`scp user@host:/readme.txt ./` は `/etc/ssh-chatter/user-files/readme.txt` をダウンロードします。
- TELNETクライアントは新しい `/filestore` コマンドを使用します。`/filestore` は利用可能なファイルを一覧表示し、`/filestore-upload` は `rz` セッションを開始し、`/filestore-download <name>` は `sz` セッションを開始します。サーバーに `lrzsz`(または `rz`/`sz` を提供する任意のパッケージ)をインストールして、ZMODEMバックエンドがこれらのヘルパーを起動できるようにします。
- `/filestore-upload` はオプションの保存先を受け付けます(例: `/filestore-upload /kitten/meow.png`)。SSH-Chatterは `/kitten` ディレクトリを自動的に作成し、アップロードされたファイルをそこに配置します。これはSCPが `user@host:/kitten/meow.png` のようなパスを使用する方法を反映しています。
- 両方のトランスポートは混在して使用できます。SSHは無人スクリプト転送に、TELNETは組み込みZMODEMツールを備えた懐かしいBBSクライアントに適しています。
## モールスリレー
SSH-Chatterはアマチュア無線リレーをサポートしています。これはグローバルモールス信号を表示します。表示するには `/morse on`、送信するには `/morse-reply` を使用します。
### プロトコル詳細
実装はBinkpプロトコル仕様に従います:
- 2バイトヘッダーを持つ標準のBinkpフレーム構造
- セッションパスワード認証 (CMD\_PWD/CMD\_OK)
- 60秒ごとのキープアライブメカニズム (CMD\_NUL)
- メッセージ同期のためのカスタムCHATコマンド (CMD\_CHAT, 拡張)
## 前提条件
プロジェクトのビルドにはPOSIX環境が必要です:
- C23互換コンパイラ(例: `gcc` または `clang`)
- `make`
- `libssh` 開発用ヘッダーとライブラリ(Debian/Ubuntuでは `libssh-dev`)
- `libcurl` 開発用ヘッダーとライブラリ(Debian/Ubuntuでは `libcurl4-openssl-dev`)
- `uchardet` 開発用ヘッダーとライブラリ(Debian/Ubuntuでは `libuchardet-dev`)
- `icu`(International Components for Unicode)開発用ヘッダーとライブラリ(Debian/Ubuntuでは `libicu-dev`)
- `lz4` 圧縮ライブラリと開発用ヘッダー(Debian/Ubuntuでは `liblz4-dev`)
- POSIXスレッド(通常はシステムの `libpthread` によって提供)
- `python3-pygments`(テトリスカモフラージュ画面用の `pygmentize` ハイライターを提供)
Debian/Ubuntuでは、依存関係は以下のようにインストールできます:
``````bash
sudo apt-get update
sudo apt-get install build-essential libssh-dev libcurl4-openssl-dev libuchardet-dev libicu-dev liblz4-dev
リポジトリをクローンし、提供された Makefile を使用してください:```bash
make
これにより、リポジトリルートに `ssh-chatter` バイナリと、他のアプリケーションで再利用するための翻訳ヘルパーを公開する共有オブジェクト `libssh_chatter_backend.so` が生成されます。中間生成物は `make clean` でクリーンアップします。
### 共有翻訳バックエンドの使用
この共有オブジェクトは、サーバーのC言語翻訳パイプライン(ANSIプレースホルダーの保存を含む)を再利用するため、他のプロセスは完全なSSHホストを起動せずに翻訳を取得できます。`libssh_chatter_backend.so` にリンクし、`include/ssh_chatter/ssh_chatter_backend.h` をインクルードします:```c
#include "ssh_chatter/ssh_chatter_backend.h"
int main(void) {
char translated[4096];
char detected[64];
if (ssh_chatter_backend_translate_line("Hello, world!", "ko", translated, sizeof(translated), detected, sizeof(detected))) {
printf("Detected %s -> %s\n", detected, translated);
}
}
環境変数に GEMINI_API_KEY(およびオプションで GEMINI_API_BASE または GEMINI_MODEL)を設定します。これにより、ヘルパーが Google Generative Language API にアクセスできるようになり、メインデーモンのランタイム要件を反映します。チャットサーバーを起動する前に ./scripts/test_gemini_connection.sh を実行して、資格情報が外部への呼び出しを許可していることを確認できます。スクリプトは Gemini からの生の応答を出力するため、リクエストが成功したかどうかを確認できます。
サーバーはデフォルトで 0.0.0.0:2222 で待機します。利用可能なフラグを使用してランタイムパラメータを調整できます。```
Usage: ./ssh-chatter [-a address] [-p port] [-m motd_file] [-k host_key_dir] [-T telnet_port|off] [-J json_port|off]
./ssh-chatter [-h]
./ssh-chatter [-V]
指定された場合、`-m`は指定されたファイルパスから今日のメッセージを読み取ります。
一般的な例:```bash
# Start the chat server on port 2022, loading host keys from /etc/ssh
./ssh-chatter -p 2022 -k /etc/ssh
# Enable telnet access on 0.0.0.0:4242 alongside SSH
./ssh-chatter -T 0.0.0.0:4242
# Serve a custom MOTD from a file and bind to localhost
./ssh-chatter -a 127.0.0.1 -m /etc/ssh-chatter/motd
ホスト鍵ディレクトリには、ssh_host_rsa_key ファイル(およびオプションで .pub)が含まれている必要があります。システムのSSHホスト鍵を再利用したくない場合は、ssh-keygen -t rsa -b 4096 -f /path/to/dir/ssh_host_rsa_key で生成してください。ssh_host_ed25519_key および ssh_host_ecdsa_key という名前の追加のホスト鍵が存在する場合、自動的に読み込まれ、サーバーは鍵交換中に最新のアルゴリズムを提供できます。
実行後、任意のSSHクライアントで接続します:```bash ssh -p 2222 user@server-address
公開サーバーは `bbs.chatter.pw` のデフォルトSSHポートで利用可能です:```bash
ssh -p 2222 [email protected]
SSHプロンプトで入力されたユーザー名がチャットのニックネームとして使用されます。
Telnetクライアントも同じ機能セットで参加できます。Telnetの待ち受けはデフォルトでポート2323で有効になっており、-Tフラグで調整または無効にできます。-T address:portを指定してバインドアドレスを上書きします(省略時はSSHのバインドを継承します。すべてのインターフェースで待ち受けるには、-T :4242のように空のホストを使用します)。例えば、レトロな端末からtelnetで参加するには:```bash
telnet server-address 2323
Pass `-T off`(または `-T disable`)を渡すと、telnetリスナーを完全にオフにできます。
### JSONラインAPI
サーバーはまた、自動化や外部統合のためにTCP経由でJSONラインプロトコルを公開しています。デフォルトではポート`34567`でリッスンし、`-J`で無効化または再設定できます。```bash
# Disable the JSON API
./ssh-chatter -J off
# Bind JSON API on a custom port
./ssh-chatter -J 0.0.0.0:45678
各リクエストは、\nで終了する単一のJSONオブジェクトです。レスポンスとチャットイベントもJSONオブジェクトであり、同様に改行区切りです。APIは一般的なチャットと、/poll、/vote、/image、/video、/audio、/files、/asciiartのフローをサポートしています。
イベントペイロード (サーバー → クライアント)```json {"type":"event","event":"message","payload":{"id":123,"username":"alice","message":"hello","created_at":1710000000,"system":false,"preserve_whitespace":false,"attachment":{"type":"none","target":"","caption":""}}}
**リクエスト例 (client → server)**```json
{"type":"chat","id":1,"username":"alice","message":"안녕하세요"}
{"type":"image","id":2,"username":"alice","url":"https://example.com/cat.png","caption":"cat"}
{"type":"asciiart","id":3,"username":"alice","message":" /\\_/\\\\n( o.o )\\\\n > ^ <"}
{"type":"poll","id":4,"username":"op","is_operator":true,"question":"Favorite color?","options":["red","blue","green"]}
{"type":"poll","id":5,"username":"bob","action":"vote","choice":2}
{"type":"vote","id":6,"username":"op","label":"weekend","question":"Plan?","options":["hike","rest"],"allow_multiple":true}
{"type":"vote","id":7,"username":"bob","label":"weekend","action":"vote","choice":1}
応答は id をエコーし、status、message、およびオプションの result オブジェクトを含みます:```json
{"type":"response","id":4,"status":"ok","message":"poll started","result":{"poll":{"active":true,"allow_multiple":false,"id":10,"question":"Favorite color?","options":[{"index":1,"text":"red","votes":0},{"index":2,"text":"blue","votes":0}]}}}
実行可能な例については、 `scripts/json_api_example.py`を参照してください:```bash
python3 scripts/json_api_example.py --url tcp://127.0.0.1:34567 --save /tmp/json_api_output.txt
systemdを使用するシステムでのインストールを自動化するヘルパースクリプトが提供されています:```bash
sudo ./scripts/install_chatter_service.sh
スクリプトの機能:
1. プロジェクトをコンパイルします(`make`)。
2. 生成されたバイナリを `/usr/local/bin/ssh-chatter` にインストールします。
3. 専用の `ssh-chatter` システムユーザーとグループを作成します(まだ存在しない場合)。
4. 実行時状態(SSHホストキーを含む)用の `/var/lib/ssh-chatter` と、設定ファイル用の `/etc/ssh-chatter` を作成します。
5. デフォルトのRSAホストキーが存在しない場合、`/var/lib/ssh-chatter/ssh_host_rsa_key` に生成します。
6. `/etc/ssh-chatter/motd` にデフォルトのMOTDを作成し、環境変数によるチューニング用のオーバーライドファイル `/etc/ssh-chatter/chatter.env` を作成します。
7. `/etc/systemd/system/chatter.service` を書き込み、`systemd` をリロードし、サービスを有効にして即座に起動します。
結果として生成される `chatter.service` ユニットは、適切なデフォルト設定でサーバーを起動し、`CAP_NET_BIND_SERVICE` ケーパビリティを付与するため、非rootのサービスアカウントでも必要に応じて特権ポートにバインドできます。
### サービスのカスタマイズ
`/etc/ssh-chatter/chatter.env` を編集してデフォルトを調整し、サービスを再起動してください:```bash
sudo systemctl edit chatter.service # or edit the environment file directly
sudo systemctl restart chatter.service
サポートされている環境変数:
CHATTER_BIND_ADDRESS – バインドするIPアドレス(デフォルト 0.0.0.0)。CHATTER_PORT – クライアントに公開するTCPポート(デフォルト 2222)。CHATTER_MOTD_FILE – 今日のメッセージファイルへのパス(デフォルト /etc/ssh-chatter/motd)。CHATTER_HOST_KEY_DIR – ssh_host_rsa_key を含むディレクトリ(デフォルト /var/lib/ssh-chatter)。CHATTER_EXTRA_ARGS – ssh-chatter 呼び出しに追加される追加引数。CHATTER_VOTE_FILE – 投票状態ファイルへのパス(デフォルト vote_state.dat)。CHATTER_GEMINI_COOLDOWN_FILE – Geminiクールダウン状態ファイルへのパス(デフォルト )。カモフラージュコードスニペット:
Tetrisのカモフラージュ機能では、ランタイムは /var/lib/ssh-chatter/ ディレクトリ内のコードスニペットファイルを期待します。
このリポジトリには、./camouflage/ ディレクトリにすぐに使える例が含まれています(c.txt、cpp.txt、java.txt、go.txt、js.txt、ts.txt、rust.txt)。
セットアップ時に一度、ランタイムディレクトリにコピーしてください。```bash
sudo install -d /var/lib/ssh-chatter
sudo cp camouflage/*.txt /var/lib/ssh-chatter/
カモフラージュ画面がアクティブなときに表示される内容をカスタマイズするには、コピーした任意のファイルを編集できます。
翻訳機能は現在、Google Gemini API を利用しています。これを有効にするには、`chatter.env`(または環境変数)に以下を設定します。
- `GEMINI_API_KEY` – 翻訳リクエストの認証に使用するシークレット API キー。
- `GEMINI_API_BASE` – API ベース URL のオプション上書き(デフォルトは `https://generativelanguage.googleapis.com/v1beta`)。
- `GEMINI_MODEL` – Gemini モデル名のオプション上書き(デフォルトは `gemini-2.5-flash`)。
翻訳が有効な場合、チャットは各メッセージを元の言語で即座に配信し、Gemini の応答が到着すると、インデントされたキャプションに翻訳テキストを含めてフォローアップします。リアクションのサマリーも同じキャプションスタイルを使用するため、更新は参照元のメッセージの真下に表示されます。
インラインキャプションの挿入が気になる場合は、`/chat-spacing <0-5>` であらかじめ小さな空白行バッファを確保できます。この設定はライブチャットスレッドにのみ影響し、掲示板のコンテンツは予約なしで翻訳され続けるため、長文の投稿に影響を与えることなく、自分のセッションのスペーシングを調整できます。
翻訳の切り替えと言語の選択は `chatter_state.dat` に保存されるため、再接続すると将来のセッションで自動的に同じ設定が復元されます。
サービスをすぐに開始せずにインストールする場合は、`SKIP_START=1` を指定してスクリプトを実行してください。
サービス管理コマンド:```bash
sudo systemctl status chatter.service
sudo systemctl restart chatter.service
sudo systemctl disable --now chatter.service
-m フラグまたはサービス管理設定ファイルによるMOTD配信。/help コマンド。/ban, /poke) のサーバーサイドログ記録。/weather/vote 投票と単一選択 /vote-single オプションをサポートし、テキストフレンドリーな投票ショートカットとして /elect <label> <choice> を含みます。/bbs からアクセス可能なレトロな掲示板システム。タグ付け、コメント、バンプ、およびロケール対応のターミネーター(デフォルト >/__BBS_END>)で終了するインタラクティブコンポーザーを備えています。/asciiart エディタ:640行の下書き、IPごとに10分間の投稿クールダウン、複数行配信、Ctrl+A/Ctrl+S ショートカット。/game ハブ:内蔵の (元のソビエト時代のC実装からトランスコード)と の両方を搭載。どちらも または Ctrl+Z で中断可能。Issue とプルリクエストを歓迎します。 バグの再現手順を含め、変更を送信する前に make が成功することを確認してください。
| Path | Description |
|---|
src/main.c | コマンドライン解析とプロセスのブートストラップ(バインドアドレス、ポート、MOTD、ホスト鍵ディレクトリ)。 |
src/host_aggregate.c, include/ssh_chatter/host.h | チャットホスト実装 – セッションライフサイクル、MOTD処理、将来のメッセージブロードキャストロジックのフック。 |
src/host | src/host_aggregate.cを通じて単一の翻訳単位にコンパイルされるモジュラーホストサブシステム。 |
include/ssh_chatter | デーモン、ストレステストツール、翻訳バックエンドの共有ヘッダー。 |
include/ssh_chatter/contexts | 接続ごとの状態をカプセル化するsession_ctx_tおよび関連構造体の定義。 |
data/banner/banner | CHATTER_WELCOME_BANNERで指定可能なサンプルウェルカムバナー。 |
scripts/install_chatter_service.sh | バイナリをビルドし、/usr/local/binにインストールし、systemdユニット(chatter.service)を設定する便利なインストーラ。 |
scripts/install_dependencies.sh | Debian/Ubuntuシステムのビルド前提条件の最小パッケージインストーラ。 |
gemini_cooldown.datCHATTER_SECURITY_FILTER – レイヤー化セキュリティフィルターを無効にするには off/false/0 に設定(デフォルトで有効)。CHATTER_SECURITY_AI – AIモデレーションを有効にするには on/true/1 に設定(デフォルトで無効)。CHATTER_FILESTORE_PATH – 管理ファイルストレージパスを上書き(デフォルト /etc/ssh-chatter/user-files)。CHATTER_FILE_STORAGE_ROOT – 管理ファイルストレージパスのレガシーフォールバック。CHATTER_MAX_ALLOC_BYTES – 内部メモリマネージャにおける単一連続割り当て試行の上限。デフォルトでは上限なし(SIZE_MAX)。単一の割り当てにハードリミットを課したい場合のみ設定します。0、unlimited、inf、または infinity に設定すると、明示的に上限を削除します。tetrisliargame/suspend!