本書は翻訳である。英語版が正本であり、両者の内容が食い違う場合は英語版に従う。 本書のライセンスは CC BY-ND 4.0 である。本仕様は誰でも自由に実装でき、使用料は発生しない。
0. 本書について
| 項目 | 内容 |
|---|---|
| 拡張の名称 | Naptify Guild Protocol(略称 NGP。英語表記は Guild) |
| 版 | 文書:1.0 草案(2026-09-28)、プロトコルバージョン:1 |
| 発行元 | Naptify プロジェクト |
| 公開先 | https://naptify.net/ (版ごとの固定 URL は未定) |
| 準拠 | OpenNap プロジェクトが公開したプロトコル仕様の原典 [NAP](§18)に準拠(§1) |
| 適用対象 | [NAP] のクライアント向けメッセージのうち、本書がペイロードを流用するもの(§1.1)を実装した OpenNap 系サーバーであれば、どれでも実装可能。8000 番台のサーバー間リンクや、OpenNap のサーバー間メッセージ(10010 番台)の実装は不要 |
| 既存リンクとの関係 | 独立。8000 番台(SlavaNap 系リンク)と OpenNap のサーバー間メッセージは、使用も変更もしない。同じ待ち受けポートで共存可能(§6.1)。互いにリンクしているサーバー群は、ギルドには 1 台のサーバーとして参加する(§3.2)。互いにリンクしているサーバーの間ではギルドを確立せず、2 つのリンクしているサーバー群の間のギルド接続は多くとも 1 本である(§3.3)。SlavaNap や FaceNap など、ギルドに参加できないサーバーとリンクしているサーバーは、ギルドに参加しない(§3.4) |
ギルドとは。 異なる運営者が運用する OpenNap サーバー同士が、相互に登録したピアと 1 対 1 で直接接続する仕組みである。
- 中継するもの:チャット、IM、プレゼンス(オンライン状態)、参照、検索、ファイル転送の中継、その他サーバーがユーザーからユーザーへ渡すメッセージ(§12.4)。
- 中継しないもの:wallop とアナウンス。サーバーの運営者が自サーバーのユーザーへ伝えるためのメッセージである(§13)。
- 共有しないもの:登録ユーザー、BAN、ユーザーレベル、ポイント、各種の制限。
- 各サーバーは、自サーバーにログインしているユーザーについてのみ責任を負う。
- 互いにリンクしているサーバー群は、そのうちの 1 台を通じて、1 台のサーバーとして参加する(§3.2)。
1. 準拠範囲と拡張範囲
1.1 準拠する事項
- フレーム。 [NAP] §2 の形式に従う。長さ 2 バイトと種別 2 バイトからなる 4 バイトのヘッダー(いずれもリトルエンディアン)の後に、ペイロードが続く。
- 文字列の形式。 [NAP] §2 に従う。
- フィールドは空白 1 文字(0x20)で区切る。
- 空白を含む可能性のある値は
"で囲む。 - 行末に CR・LF は付けない。
- 既存メッセージの意味は変更しない。 次のメッセージのペイロードは、[NAP] の形式のまま、本書で定義するメッセージに格納して運ぶ。
- 200・201(検索要求と検索結果)
- 203・204・206(ダウンロードの要求・応答・エラー)
- 205(IM。サーバーからクライアントへの形式)
- 211・212・213(参照)
- 403・406・407・410(チャンネルの発言・入室・退室・トピック)
- 501(ファイアウォール越しの応答)
- 609(アップロードの拒否)
- 824(エモート)
- 430・619・626・640・641・751・752(チャンネルへの招待、キューの上限、データポートのエラー、直接参照の要求と承諾、ユーザーへの ping と pong。クライアントからサーバーへの形式。§12.4)
- クライアントには新しいメッセージを送らない。 ピアのユーザーは、既存のメッセージだけを使ってクライアントに提示する。
1.2 本拡張で追加する事項
- メッセージ種別 9000〜9199 の割り当てと、その意味(§5〜§13)。
- 相互認証、バージョンと対応機能のネゴシエーション、プレゼンスの同期、表示名の規則、リクエスト ID、切断と拒否の理由コード。
- ギルドのメッセージのペイロードの文字コードを UTF-8 と定めること(§4.2)。
- リンクしているサーバー群を 1 台のサーバーとして扱うこと、リンクしているサーバー群の構成を通知すること(§3.2、§3.3)。
- サーバーがユーザーからユーザーへ渡すメッセージのための、汎用の中継(§12.4)。
1.3 本書で規定しない事項
- クライアントとサーバー間の手順([NAP] のとおり)。
- 8000 番台のリンク、および代表サーバーがほかのリンクサーバーへメッセージを渡す方法(§3.2 は、ピアから見える結果だけを規定する)。
- クライアント間の転送そのもの([NAP] §5 のとおり)。
2. 用語と規範的キーワード
| 用語 | 意味 |
|---|---|
| サーバー | OpenNap クライアントを受け付けるサーバー |
| ピア(相手サーバー) | ギルドとして相互に登録されたサーバー |
| ギルド接続 | ピアとの間の、認証済みの 1 本の TCP 接続 |
| 接続元/接続先 | その TCP 接続を開始した側/受け付けた側 |
| ローカルユーザー | そのサーバーにクライアントとしてログインしているユーザー。代表サーバーでは、ほかのリンクサーバーにログインしているユーザーも含む(§3.2)。ピアのユーザーは、ローカルユーザーに含まれない |
| ピアのユーザー | ピアのローカルユーザーのうち、プレゼンス(§8)で通知されたユーザー。ユーザー名と送信元サーバーの組で識別 |
| リンクしているサーバー群 | 同じ運営者が運用し、互いにリンク(8000 番台など)しているサーバーの全体。リンクしていないサーバーは、1 台だけのリンクしているサーバー群とみなす(§3.2) |
| リンクサーバー | リンクしているサーバー群を構成する個々のサーバー(§3.2) |
| 代表サーバー | リンクしているサーバー群のギルド接続を受け持つ、1 台のリンクサーバー(§3.2) |
| 送信元サーバー(origin) | メッセージを生成したサーバーの名前 |
| 表示名 | ピアのユーザーをローカルユーザーに表示するときの名前(§8.3) |
| 対応機能(capability) | 任意の機能を実装していることを示す短い語(§6.5) |
| 共有鍵 | 2 台のサーバーの運用者が事前に共有した秘密のバイト列(§6.4) |
| リクエスト ID | 検索と参照の要求と応答を対応付ける番号(§11) |
規範的キーワードは RFC 2119 と RFC 8174 [RFC2119][RFC8174] に従って解釈する。日本語版では、キーワードを括弧内に大文字で併記した箇所だけが規範的な意味を持つ。
日本語版での対応
| 本書の表現 | キーワード |
|---|---|
| しなければならない | MUST |
| してはならない | MUST NOT |
| すべきである | SHOULD |
| すべきでない | SHOULD NOT |
| してもよい | MAY |
3. 全体構成
3.1 原則
- 直接接続のみ。 各サーバーは、自らが登録したピアとだけ直接接続する。 – ピアから受信したプレゼンス・発言・要求を、直接であれ他のサーバーを経由してであれ、他のピアへ転送してはならない(MUST NOT)。 – 代表サーバーは、§3.2 のとおりそれらをほかのリンクサーバーへ渡す。自らとリンクしていないサーバーへ渡してはならない(MUST NOT)。 – ピアの間で転送を行わないため、接続がループを形成してもかまわない。 – A と B、B と C がそれぞれギルドを組んでいる場合でも、A と C の間では何もやり取りされない。A と C がやり取りするには、A と C が直接ギルドを組む。
- 通知するのは自サーバーのユーザーのみ。 プレゼンスで通知するのは、ローカルユーザーだけでなければならない(MUST)(代表サーバーでは、ほかのリンクサーバーのユーザーを含む。§3.2)。いずれかのギルド接続で知ったピアのユーザーを、ピアへ通知してはならない(MUST NOT)。
- 送るのはイベントであり、命令ではない。 – メッセージが運ぶのは、ローカルユーザーが行った操作の結果(発言、入室など)である。 – ピアのユーザーやサーバーの状態を変更する命令は、本拡張には存在しない。 – 受信側は、ピアのユーザーレベルを理由に、ローカルユーザーや自らが保持する情報を変更してはならない(MUST NOT)。
- 規則を適用するのは、ユーザーが接続しているサーバー。 – 発言禁止、連続投稿の制限、ダウンロードの条件などは、そのユーザーがログインしているサーバーが送信前に適用する。 – 転送の要求については、要求を受けたサーバーも、要求に対する自らの制限を適用する(§12.3)。 – 受信側は、自らの判断でローカルユーザーへの配送を停止してもよい(MAY)。
3.2 リンクしているサーバー群
同じ運営者が運用し、互いにリンク(8000 番台のリンクなど)しているサーバーの全体を、本書ではリンクしているサーバー群と呼び、その個々のサーバーをリンクサーバーと呼ぶ。ギルドから見ると、リンクしているサーバー群は 1 台のサーバーである。リンクしていないサーバーは、1 台だけのリンクしているサーバー群とみなし、その場合、本節の内容は 1 台のサーバーの動作と同じになる。
- 代表サーバー。 リンクしているサーバー群は、リンクサーバーのうちの 1 台である代表サーバーを通じてギルドに参加する。代表サーバーは、リンクしているサーバー群のギルド接続をすべて受け持つ。 – リンクしているサーバー群の中に、ギルド接続を持つサーバーが 2 台以上あってはならない(MUST NOT)。2 台のリンクサーバーがギルド接続を持つと、一方がほかのリンクサーバーへ渡したピアのユーザーが、他方にはリンクサーバーの通常のユーザーとして届き、そのピアへ通知されてしまう。これは §3.1 の 1 で禁止している。 – ほかのリンクサーバーはギルド接続を持たず、本拡張のメッセージを実装していなくてもよい。ただし、すべてのリンクサーバーは、ギルドに参加できるサーバーでなければならない(MUST)(§3.4)。 – 代表サーバーは、ハンドシェイク(§6)と、送信するすべてのメッセージの送信元サーバー(§4.4)に、自らの名前を使う。ピアからは、すべてのリンクサーバーのユーザーが代表サーバーのユーザーに見える。
- リンクサーバーからピアへ。 代表サーバーは、ほかのリンクサーバーのユーザーをローカルユーザーとして扱う。 – プレゼンス(§8)は、すべてのリンクサーバーのユーザーを対象とする。ほかのリンクサーバーのユーザーがログインまたはログアウトしたとき、あるいはリンクが切れて退出したとき、代表サーバーはそれに応じて 9010 または 9011 を送信する。 – 他のサーバーのユーザーのチャンネルの発言、IM、要求、中継(§9〜§12)は、リンクを通じて代表サーバーに届き、自サーバーのクライアントのものと同じようにピアへ送信する。そのユーザーがログインしているサーバーの規則は、すでに適用されている(§3.1 の 4)。代表サーバーは、さらに自らの規則を適用してもよい(MAY)。
- ピアからリンクサーバーへ。 代表サーバーは、自サーバーのクライアントに配送するものを、リンクを通じてほかのリンクサーバーにも渡す。このとき、ピアのユーザーは、表示名(§8.3)を持つ代表サーバーのユーザーとして見せる。 – ピアからの検索と参照は、すべてのリンクサーバーを対象とする。代表サーバーは、自サーバーのクライアントからの要求と同じようにリンクへ展開し、結果をまとめて、終了メッセージを 1 回だけ返す(§11)。 – ほかのリンクサーバーのユーザーを宛先とする転送の中継は、リンクを通じてそのサーバーへ渡す(§12)。 – ほかのリンクサーバーからは、ピアのユーザーは代表サーバーのユーザーとしてだけ見える。
- ピアの間では転送しない。 代表サーバーは、ほかのリンクサーバーに見せているユーザーのうち、どれがピアのユーザーであり、どのピアから来たかを知っている。それらのユーザーを、どのピアへ送るプレゼンスにも含めてはならず(MUST NOT)、あるピアのユーザーから発したものを、他のピアへ渡してはならない(MUST NOT)。たとえば、あるピアから受信した検索はリンクサーバーだけに展開し、他のピアへは展開しない。
- アドレス。 ほかのリンクサーバーのユーザーについて、代表サーバーがピアに示す IP アドレスとデータ用のポート(§11、§12)は、リンクサーバー同士で互いのユーザーについて示す値、すなわちリンクを通じて知った値とする。
- 代表サーバーが停止した場合。 代表サーバーが停止するか、そのギルド接続が切れると、そのピアからはすべてのリンクサーバーが見えなくなる。バージョン 1 には、ほかのリンクサーバーが自動で代わりを務める仕組みはない。
3.3 リンクしているサーバー群の組ごとにギルドは 1 本
2 つのリンクしているサーバー群の間のギルド接続は、多くとも 1 本である。
- 双方は、自らとリンクしているサーバーの構成を 9008 で通知する。初回の一覧(§8.2)の最初に送り、構成が変わるたびに送り直す。
- ピア P について、P の名前と、P から最後に受信した 9008 に含まれる名前からなる集合を C(P) とする。自サーバーについて、自らの名前と、ほかのリンクサーバーの名前からなる集合を C(ローカル) とする。名前は、ASCII の小文字に変換して比較する。
- 登録時。 実装は、C(ローカル) に含まれる名前、または確立済みのいずれかのピア P の C(P) に含まれる名前を、ピアとして登録することを拒否し、運用者にエラーを示すべきである(SHOULD)。
- 確立後の検出。 9008 を受信したとき、および自らとリンクしているサーバーが変わったとき、サーバーは次を確認し、該当する接続を 9006(13)で切断する。
- C(P) と C(ローカル) に共通の名前があれば、そのピアは自らとリンクしている。互いにリンクしているサーバーの間ではギルドを確立しないので、P を切断する。
- 確立済みの 2 つのピア P と Q について、C(P) と C(Q) に共通の名前があれば、2 つのピアは同じリンクしているサーバー群に属している。名前(小文字に変換したバイト列)が小さい方のピアとの接続を残し、他方を切断する。すべてのサーバーが同じ規則を適用するため、両方に接続しているサーバーは同じピアを残すことになる。
- この理由で接続を切断したサーバーは、関係するピアの名前を運用者に通知すべきである(SHOULD)。
| 番号 | 名前 | 方向 | フィールドの並びと型 | 受信時の動作 |
|---|---|---|---|---|
| 9008 | GUILD_CLUSTER | 双方向 | srv 送信元サーバー、rest メンバー(送信側とリンクしているサーバーの名前。それぞれ srv で、空白 1 文字で区切る。1 台もなければ -) |
そのピアとリンクしているサーバーの構成として保持しているものを、受信したもので置き換え、上記のとおり確認する |
- 構成には、直接リンクしているサーバーだけでなく、ほかのリンクサーバーを経由してリンクしているサーバーも含める。
srvとして表せない名前のサーバーは省く。そのようなサーバーは、そもそもその名前でピアとして登録できない。- リンクを持たないサーバーは、
-の 9008 を送る。
3.4 参加できないサーバー
リンクしているサーバー群がギルドに参加できるのは、すべてのリンクサーバーがギルドに参加できる間だけである。
- 本節と §3.2 を守ることが分かっていない実装のサーバーは、参加できない。特に、SlavaNap や FaceNap など、本拡張より前からある実装のサーバーがこれにあたる。このようなサーバーは、リンクを通じて渡されたピアのユーザー(§3.2 の 3)を通常のユーザーと見分ける印を運べず、自らがギルド接続を持っているかどうかを他のサーバーに伝えることもできない。そのため、2 台目の代表サーバーを通じてピアのユーザーが他のピアへ漏れること(§3.2 の 1)を、リンクサーバーの間で防ぐことも検出することもできない。
- 参加できないサーバーとリンクしている間、サーバーはギルド接続を持ってはならない(MUST NOT)。
- 確立済みのギルド接続は 9006(14)で切断する。
- 9000 には 9006(14)で応答し(§6.3)、自分からは接続しない。
- ギルドを使えないことを、参加できないサーバーの名前とともに運用者に示すべきである(SHOULD)。
- 参加できないサーバーとのリンクがなくなれば、サーバーは再び参加する。自分から接続し、9000 を通常どおり受け付ける(§7.1)。
- ほかのリンクサーバーの実装を知る方法は、本書では規定しない(§1.3)。(参考:Naptify は、8000 番台のリンクが網のすべてのサーバーについて通知するバージョン文字列(直接のリンクは 8000・8001、それ以外のサーバーは 8011)で判断する。リンクにメッセージは追加しない。)
4. メッセージの共通規則
4.1 フレーム
+--------+--------+--------+--------+----------------+
| len lo | len hi | typ lo | typ hi | payload (len) |
+--------+--------+--------+--------+----------------+
lenとtypは、符号なし 16 ビットのリトルエンディアン整数である。- 受信側は、65535 バイトまでのペイロードを受け付けなければならない(MUST)。
- ビッグエンディアン形式を使用してはならない(MUST NOT)。
4.2 文字コード
- ギルドのメッセージのペイロードは UTF-8 でなければならない(MUST)。 不正な UTF-8 を含むメッセージは破棄しなければならず(MUST)、受信側は 9007(理由コード 6)を返してもよい(MAY)。
- クライアントと別の文字コード(CP932、CP1252 など)で通信するサーバーは、ギルドへ送信する前に UTF-8 に変換し、受信したデータを自サーバーのクライアントの文字コードに変換する。
- ローカルクライアントの文字コードで表現できない文字を含む名前・チャンネル名・ファイル名は、その文字を
?などに置き換えて表示してはならない(MUST NOT)。表示できないものとして扱う(そのユーザーやその結果を、当該クライアントには表示しない)。 - ファイル名の往復変換に関する注意(参考)。 CP932 のクライアントが送るファイル名は、通常、Windows が Unicode から変換して生成したバイト列であるため、UTF-8 を経由して CP932 に戻しても同じバイト列になる。例外は、2 通りの符号を持つ文字(NEC 選定 IBM 拡張文字と NEC 特殊文字の一部)を、標準でない側の符号で含むファイル名である。このようなファイル名は往復変換で別のバイト列に変わるため、ギルド越しのダウンロードが失敗することがある。
4.3 フィールドの型
| 型 | 形式 |
|---|---|
srv |
サーバー名。ASCII の英数字と .、-、_ のみで、1〜63 バイト。比較時は ASCII の小文字に変換 |
nick |
ユーザー名。UTF-8 で 1〜255 バイト。空白(U+0020)、"、制御文字(U+0000〜U+001F、U+007F)は含まない |
ch |
チャンネル名。UTF-8 で 1〜255 バイト。空白(U+0020)、"、制御文字(U+0000〜U+001F、U+007F)は含まない |
token |
空白を含まない、ASCII の印字可能文字からなる文字列。1〜255 バイト |
int |
10 進の非負整数。先頭に 0 は付けない(0 自体を除く)。上限はフィールドごとに規定。ハンドシェイク完了後のメッセージでは、上限を超える値を書式エラー(§14 の理由コード 6)として扱う。ハンドシェイク中(9000〜9003)は §6.2 に従う |
hex |
小文字の 16 進数 |
md5 |
[NAP] の 204・501 の md5 フィールドと同じ。値を変更せずにそのまま運ぶ |
qstr |
" で囲んだ文字列。内部に " は含まない |
abbr |
サーバーの略称。各サーバーの運用者が自サーバーに設定する短い名称。Unicode のコードポイント数で 1〜16 文字、かつ UTF-8 で 64 バイト以下。空白、"、(、)、制御文字は含まない。未設定の場合は - を送る |
rest |
その位置からペイロードの末尾までのすべて。空白を含んでもよい。最後のフィールドにのみ使用 |
body(N) |
[NAP] のメッセージ N のペイロードそのもの。常に最後に配置 |
- ユーザー名の比較では、ASCII 英字の大文字と小文字だけを同一視し、それ以外はバイト単位で比較する。
- 実装が独自の規則でより広い範囲を同一視する場合(全角英字など)、そのように同一視した名前同士も同じ名前として扱わなければならない(MUST)。
4.4 送信元サーバーのフィールド
- 9008 と、ユーザーに関するメッセージ(9010 以降)は、最初のフィールドに送信元サーバー
srvを持つ。 - バージョン 1 では、送信元サーバーは、その接続のピア名(§6 で認証したもの)と一致しなければならない(MUST)。代表サーバーは、すべてのリンクサーバーのユーザーについて、自らの名前を送信元サーバーとする(§3.2)。
- 送信元サーバーが一致しないメッセージは破棄し、9007(理由コード 14)を返すべきである(SHOULD)。これが繰り返される場合、受信側は 9006(12)で切断してもよい(MAY)。
4.5 送信者の検証
- メッセージがピアのユーザーの名前を操作の主体(発言者、IM の送信者、要求者、ダウンロードするユーザー、アップロードするユーザー、中継の操作の主体)として含む場合、受信側は、その名前がそのピアのプレゼンスに存在することを検証しなければならない(MUST)。
- 存在しない場合、そのメッセージは破棄する(理由コード 13)。
4.6 処理順序と未知のメッセージ
- 受信側は、受信した順序でメッセージを処理しなければならない(MUST)。
- 9000〜9199 の範囲内の未知の種別は、無視しなければならない(MUST)。受信側は 9007(理由コード 8)を返してもよい(MAY)。
- ギルド接続で受信した範囲外の種別も、無視しなければならない(MUST)。
- クライアント接続で受信した種別 9000〜9199 のメッセージを、ギルドのメッセージとして扱ってはならない(MUST NOT)。唯一の例外は、ログイン前の最初の 9000 である(§6.1)。
5. 番号の割り当て
| 範囲 | 用途 |
|---|---|
| 9000〜9008 | 接続、認証、キープアライブ、切断、リンクしているサーバー群の構成(§3.3、§6、§7) |
| 9010〜9012 | プレゼンス(§8) |
| 9020〜9024 | チャンネル(§9) |
| 9030〜9031 | IM(§10) |
| 9040〜9043 | 参照と取り消し(§11) |
| 9050〜9052 | 検索(§11) |
| 9060〜9065 | 転送(§12) |
| 9070 | 欠番(以前の wallop。§13)。バージョン 1 では割り当て直してはならない(MUST NOT) |
| 9080〜9081 | ユーザー間の中継(§12.4) |
| 上記の間の空き番号、9082〜9099 | バージョン 1.x 用の予備 |
| 9100〜9189 | 将来のバージョン用の予約 |
| 9190〜9199 | 実装者の試験用。正式な割り当てはなし。ピアの同意がない限り送信してはならない(MUST NOT) |
6. 接続とハンドシェイク
6.1 接続の識別
- 接続元は、ピアの OpenNap の待ち受けポートへ TCP で接続し、最初のフレームとして 9000 を送る。
- 接続先は、ログイン前の最初のフレームの種別で接続の種類を識別する。
- 9000:ギルドのハンドシェイク。
- 既存のリンクのメッセージ(8000 など):リンク。
- それ以外:クライアント。
- 9000 のペイロードは、ASCII の
GUILDで始まらなければならない(MUST)。そうでない場合、接続先は 9006(理由コード 2)で切断する。 - 運用者は、ギルド専用のポートを別途開いてもよい(MAY)。
6.2 シーケンス
接続元 I 接続先 A
| 9000 GUILD <vmin> <vmax> <I名> <nI> <capsI> <abbrI> --> | I が登録済みのピアかを確認
| <-- 9001 <ver> <A名> <nA> <capsA> <abbrA> |
| 9002 <proofI> --> | proofI を検証
| <-- 9003 <proofA> |
| proofA を検証 |
|========== 双方がプレゼンスの一覧を送信(§8.2) ==========|
- ハンドシェイク全体は 30 秒以内に完了しなければならない(MUST)。超過した場合、どちらの側も理由コード 2 で切断してもよい(MAY)。
- ハンドシェイクの完了前に 9000〜9003・9006 以外のメッセージを受信した場合は、9006(理由コード 2)で切断する。
- ハンドシェイク中(9000〜9003)に、書式エラーや上限を超える値を含むメッセージを受信した場合は、9006(理由コード 2)で切断する。
6.3 メッセージ
| 番号 | 名前 | 方向 | フィールドの並びと型 | 受信時の動作 |
|---|---|---|---|---|
| 9000 | GUILD_HELLO | 接続元→接続先 | token "GUILD"、int 最小バージョン(上限 65535)、int 最大バージョン(上限 65535)、srv 接続元の名前、hex nI(32 桁、128 ビット)、token 対応機能、abbr 略称 |
次の順に確認。① 書式が不正なら 9006(2)。② 名前が未登録なら 9006(4)。③ リンクとして登録されていれば 9006(10)。④ 無効化されていれば 9006(7)。⑤ ギルドに参加できないサーバーとリンクしていれば 9006(14)(§3.4)。⑥ 共通のバージョンがなければ 9006(3)。⑦ いずれにも該当しなければ 9001 を返送 |
| 9001 | GUILD_CHALLENGE | 接続先→接続元 | int 選択したバージョン(上限 65535)、srv 接続先の名前、hex nA(32 桁)、token 対応機能、abbr 略称 |
接続先の名前が、ローカルに登録されたピア名と異なれば 9006(12)。接続元は、選択されたバージョンが自らが 9000 で送った範囲内にあることを検証しなければならない(MUST)。範囲外なら 9006(3)。いずれにも該当しなければ 9002 を返送 |
| 9002 | GUILD_AUTH | 接続元→接続先 | hex proofI(64 桁) |
定数時間で比較。不一致なら 9006(5)。一致すれば 9003 を返送し、接続を確立 |
| 9003 | GUILD_WELCOME | 接続先→接続元 | hex proofA(64 桁) |
不一致なら 9006(5)。一致すれば接続を確立 |
- nI と nA は、暗号論的に安全な乱数源から生成しなければならない(MUST)。同じ値を 2 度使用してはならない(MUST NOT)。
6.4 証明値の計算
入力 = "GUILD1" SP 役割 SP I名 SP A名 SP nI SP nA SP ver SP capsI SP capsA SP abbrI SP abbrA
proof = hex( HMAC-SHA256( 共有鍵, 入力 ) )
- 役割は、proofI では
initiator、proofA ではacceptorとする。 - 名前は ASCII の小文字に変換する。対応機能は送信したとおりの綴りを使う。SP は空白 1 文字である。
- 略称は送信したとおりのバイト列(UTF-8)を使う。
- HMAC は [RFC2104]、SHA-256 は [FIPS180-4] に従う。
- 共有鍵は、2 台のサーバーの運用者が本拡張の外で共有した、16 バイト以上のバイト列とする(32 バイトを推奨)。
- 共有鍵の受け渡しには、16 進文字列を使用すべきである(SHOULD)。
- 共有鍵そのものをメッセージに含めてはならない(MUST NOT)。
- 対応機能が入力に含まれるため、経路上で対応機能の一覧を削る改ざんを行うと、証明値の検証に失敗する。
6.5 バージョンと対応機能
- バージョンは整数である。接続先は、双方の範囲に共通する最大のバージョンを選択する。
- 対応機能は、カンマ区切りの語で表す。対応機能がない場合は
-とする。
| 対応機能 | 意味 | 必須/任意 |
|---|---|---|
| (なし) | 9008(§3.3)、プレゼンス(§8)、§7 | 必須 |
chat |
§9、および §12.4 の 430 | 任意 |
im |
§10、および §12.4 の 751・752 | 任意 |
browse |
§11 の参照、および §12.4 の 640・641 | 任意 |
search |
§11 の検索 | 任意 |
xfer |
§12.1〜§12.3、および §12.4 の 619・626 | 任意 |
- 使用できる対応機能は、双方が持つものに限る。
- 使用できない機能のメッセージを送信してはならない(MUST NOT)。受信した場合は無視し、9007(8)を返してもよい(MAY)。
- 未知の語は無視しなければならない(MUST)。
tlsは予約語であり、バージョン 1 では意味を持たない。以前の草案のwallopは廃止した(§13)。受信側は未知の語と同じく無視する。バージョン 1 では割り当て直してはならない(MUST NOT)。
6.6 同一ピアとの重複接続
同一ピアとの確立済みの接続が 2 本になった場合、双方が同じ規則を適用し、一方を 9006(6)で切断する。
- 2 本とも同じ側が開始した接続であれば、新しい方を残す。
- 開始した側が互いに逆であれば、接続元の名前(小文字に変換したバイト列)が小さい方の接続を残す。
6.7 例(テストベクター)
条件:
– 共有鍵 = 000102…1e1f(32 バイト)
– I = alpha.example、A = beta.example
– nI = 00112233445566778899aabbccddeeff、nA = ffeeddccbbaa99887766554433221100
– capsI = chat,im,search,browse,xfer、capsA = chat,im
– 略称:I は A、A は B
– バージョン:1
メッセージ:
– 9000 のヘッダーは 55 00 28 23。ペイロードは GUILD 1 1 alpha.example 00112233445566778899aabbccddeeff chat,im,search,browse,xfer A(85 バイト)。
– 9001 のヘッダーは 39 00 29 23。ペイロードは 1 beta.example ffeeddccbbaa99887766554433221100 chat,im B(57 バイト)。
– proofI = 40b84fa36f627cd9988ec893353ca1ff16478b218fa9d2866846ae231a6a024f
– proofA = 9bd22197252d05512ccdbe0a7d6df7618cd60c5d9b174788cc2690110cddb5d3
(Python の hmac と hashlib で計算した値。公開前に、独立した実装で再検証する。)
7. キープアライブ、エラー、切断
| 番号 | 名前 | 方向 | フィールドの並びと型 | 受信時の動作 |
|---|---|---|---|---|
| 9004 | GUILD_PING | 双方向 | rest 識別子(ASCII、32 バイト以下) |
同じ識別子で 9005 を返さなければならない(MUST) |
| 9005 | GUILD_PONG | 双方向 | rest 識別子 |
ピアの生存を記録 |
| 9006 | GUILD_CLOSE | 双方向 | int 理由コード(下表。上限 255)、rest 説明(任意) |
応答せずに TCP 接続を閉じ、ログに記録。§7.1 に従って再接続 |
| 9007 | GUILD_ERROR | 双方向 | int 対象の種別(上限 65535)、int 理由コード(§14。上限 255)、rest 説明(任意) |
通知のみ。接続は維持し、ログに記録 |
- 60 秒間何も送信していない場合、9004 を送信すべきである(SHOULD)。
- 180 秒間何も受信していない場合、9006(8)で切断してもよい(MAY)。
切断の理由コード
| 番号 | 意味 | 自動再接続 |
|---|---|---|
| 1 | 正常終了(運用者の操作、停止) | 30 分以上の間隔を空けて実施 |
| 2 | プロトコル違反(書式、順序、ハンドシェイクのタイムアウト) | 運用者の対処まで保留 |
| 3 | バージョンの不一致 | なし |
| 4 | ピアとして登録されていない名前 | 間隔を延ばしながら実施 |
| 5 | 認証の失敗 | なし |
| 6 | 重複した接続(§6.6 で残した接続を使用) | なし |
| 7 | 運用者によるピアの無効化 | なし |
| 8 | キープアライブのタイムアウト | 間隔を延ばしながら実施 |
| 9 | リソースの上限(送信キューのあふれ、プレゼンス数の上限) | 間隔を延ばしながら実施 |
| 10 | 種類の不一致(このピアはリンクとして登録済み) | なし |
| 11 | 再起動(すぐに復帰する見込み) | 30 秒後から実施 |
| 12 | 名前の不一致(ピア名、送信元サーバー) | なし |
| 13 | 同じリンクしているサーバー群(ピアが自らとリンクしている、または他のピアとリンクしている。§3.3) | 間隔を延ばしながら実施 |
| 14 | 送信側が、ギルドに参加できないサーバーとリンクしている(§3.4) | 間隔を延ばしながら実施 |
7.1 再接続
- 「間隔を延ばしながら」とは、30 秒から始めて毎回倍にし、上限を 10 分とすることを指す。接続が確立したら、間隔は 30 秒に戻る。
- 理由コード 4 は、多くの場合、ピアの運用者がまだこのサーバーを登録していないことを意味する。登録は双方がそれぞれ行う。そのため接続元は間隔を延ばしながら再接続を続け、ピアが登録した時点で接続が確立する。
- 理由コード 13 で再接続を続けるのは、リンクしているサーバー群の構成が変わるためである。リンクしているサーバー群が重ならなくなった時点で接続が確立する。間隔の上限が 10 分であるため、接続先の負荷は小さい。
- 理由コード 14 で再接続を続けるのも同じ理由である。送信側と参加できないサーバーとのリンクがなくなった時点で接続が確立する。理由コード 14 を送った側は、そのサーバーがいる間は自分からは接続しない(§3.4)。
- 自動再接続が「なし」の理由コードで切断された側は、自動で再接続すべきでない(SHOULD NOT)。
7.2 送信キューのあふれ
- プレゼンスとチャンネルの入退室のメッセージは、破棄してはならない(MUST NOT)。送信できない場合は 9006(9)で切断する。
- 検索と参照の結果は破棄してもよい(MAY)。ただし、終了メッセージは破棄してはならない(MUST NOT)。終了メッセージを送信するかどうかは §11 の規則に従う。
8. プレゼンス
8.1 メッセージ
| 番号 | 名前 | 方向 | フィールドの並びと型 | 受信時の動作 |
|---|---|---|---|---|
| 9010 | GUILD_USER | 双方向 | srv 送信元サーバー、nick ユーザー名、int ログイン時刻(UNIX 秒、UTC。上限 2^63−1)、token ユーザーレベル(User、Moderator、Admin、Elite、Leech)、int 共有ファイル数(上限 4294967295)、int 回線速度(0〜10)、qstr クライアント名、int フラグ(上限 4294967295) |
プレゼンスのエントリを追加。同じピアから同じ名前のエントリがすでにあれば、フィールドを置き換え。ログイン時刻が変わっていれば、いったん退出して再ログインしたものとして処理。表示名は §8.3 に従って決定 |
| 9011 | GUILD_USER_QUIT | 双方向 | srv 送信元サーバー、nick ユーザー名 |
そのプレゼンスのエントリを削除。そのユーザーのチャンネルへの入室もすべて削除し、ローカルユーザーに 407 を送信。hotlist の 210 もこの時点で送信 |
| 9012 | GUILD_SYNC_END | 双方向 | srv 送信元サーバー、int 送信した 9010 の数(上限 4294967295) |
初回の一覧の完了。受信した 9010 の数と一致しない場合、受信側はログに記録してもよい(MAY)。接続は維持 |
- ユーザーレベルは表示専用である。 受信側は、ユーザーレベルを権限の判定に使用してはならない(MUST NOT)。
- フラグ:ビット 0(値 1)は「一覧に表示しない」を表す。受信側は、このユーザーを一覧、チャンネルのメンバー一覧、whois に表示してはならない(MUST NOT)。未知のビットは無視する。
qstr クライアント名に"が含まれる場合は、送信側が取り除く。- IP アドレスとデータ用のポートは、プレゼンスに含めない。これらが現れるのは、転送と中継(§12)と検索結果(201 のペイロード)だけである。
8.2 初回の一覧
接続が確立したら、双方は次の順序で送信する。
- 9008(自らとリンクしているサーバーの構成。§3.3)。
- すべてのローカルユーザーの 9010。
- 対応機能
chatをネゴシエーションした場合は、共有するチャンネルの 9020(全メンバーの入室)と 9024(トピック)。 - 最後に 9012。
- 9012 より前に、ほかの種類のメッセージを送信してはならない(MUST NOT)。
- 接続が切れた場合、受信側はそのピアのプレゼンスとチャンネルへの入室を、すべて削除しなければならない(MUST)。
8.3 表示名の規則
ピアのユーザーは、ユーザー名と送信元サーバーの組で識別する。同じユーザー名のユーザーが、異なるサーバーに同時に存在してもよい。ギルドを理由として、ユーザーを切断したりログインを拒否したりはしない(後述の 3 を除く)。代表サーバーは、すべてのリンクサーバーでの表示名を決める(§3.2)。
- 衝突しない名前はそのまま表示する。 ピアのユーザーの名前が次のいずれとも一致しなければ、その名前のままローカルユーザーに表示する。 – ローカルユーザー(ログイン中)の名前 – ローカルサーバーに登録されている名前(そのユーザーがオフラインでも) – すでにそのまま表示している、他のピアのユーザーの名前
- 衝突する名前には送信元サーバーを付加する。 上記のいずれかと一致する場合は、送信元サーバーを付加した名前で表示しなければならない(MUST)。
– 推奨する形式は
ユーザー名(送信元サーバー)である(例:masa(guild-b.example))。括弧は ASCII の(と)であり、どの文字コードのクライアントでも表現できる。 – ピアのユーザーを、ローカルユーザーや登録名と同じ名前のまま表示してはならない(MUST NOT)。これは、なりすましを防ぐためである。 – 実装は、衝突しない場合も含めて、常に送信元サーバーを付加した形式で表示してもよい(MAY)。 –@を区切り文字として使用すべきでない(SHOULD NOT)。@は、ユーザーが名前の一部としてよく使用するためである。 – 送信元サーバーの代わりに、ピアがハンドシェイクで通知した略称(§4.3 のabbr)を使用してもよい(MAY)。例:masa(B)。ただし、次のいずれかに該当する略称は使用してはならず(MUST NOT)、代わりにサーバー名を使用する。-(未設定)- 他のピアの略称またはサーバー名と同じもの
- ローカルサーバーのサーバー名または略称と同じもの
- 名前の比較方法は、§4.3 のユーザー名と同じである(ASCII 英字の大文字と小文字だけを同一視する)。
- 表示名の予約。 ローカルユーザーによる次の名前でのログインと登録は、拒否しなければならない(MUST)。
– ピアのユーザーをそのまま表示している名前([NAP] の「すでにログインしている」旨の拒否を使用する)。
– 送信元サーバーを付加した形式の名前。推奨形式の場合、
(ピアのサーバー名)で終わる名前である。 – 実装は、ピアのサーバー名または略称(およびローカルサーバーのサーバー名と略称)を含む名前をすべて、禁止語として拒否すべきである(SHOULD)。ただし、1〜2 文字の略称は通常の名前に含まれやすいため、その場合は(略称)の形式だけを拒否すればよい。形式を問わず拒否するので、括弧の付け方を変えた名乗りも防げる。 – ピアを後から登録した場合、その名前を含む既存の登録名は、引き続き使用可能としてもよい(MAY)。ただし、そのユーザーがピアのユーザーと取り違えられないよう、運用者に通知すべきである(SHOULD)。 - 宛先の変換。 ローカルユーザーが表示名(送信元サーバーを付加した形式を含む)を宛先として IM、whois、参照、ダウンロードを要求した場合、サーバーはそれをピアのユーザー(名前と送信元サーバーの組)に変換し、そのピアへ送信する。ピアへ送るメッセージ内の名前は、送信元サーバーを付加しない元の名前である。
- ピアが 9011 を送信した、または接続が切れたことにより、ある表示名が空いた場合でも、他のピアのユーザーの表示名を途中で変更する必要はない。変更してもよい(MAY)。変更する場合は、ローカルユーザーに対して 407 と 406 で退室・再入室したように見せる。
- リンクサーバーへ渡す名前。 代表サーバーは、ほかのリンクサーバーに対しては、名前が衝突しない場合でも、ピアのユーザーを送信元サーバーを付加した形式で見せるべきである(SHOULD)。他のサーバーには、代表サーバーから見えない登録名があるかもしれず、また、リンク上の名前の衝突はユーザーの切断で解決されることがあるためである。リンクサーバーで使っている名前が後から衝突した場合、代表サーバーは 5 のとおり名前を変更する。送信元サーバーを付加した形式は、宛先として常に受け付ける(4)。同じピアのユーザーを自サーバーのクライアントには名前のまま見せている代表サーバーでも同じである。
9. チャンネル(対応機能 chat)
| 番号 | 名前 | 方向 | フィールドの並びと型 | 受信時の動作 |
|---|---|---|---|---|
| 9020 | GUILD_CHAN_JOIN | 双方向 | srv 送信元サーバー、body(406) = ch nick int 共有ファイル数 int 回線速度(共有ファイル数は上限 4294967295、回線速度は 0〜10) |
ローカルサーバーもそのチャンネルを共有していれば、メンバー一覧(408、825)に表示名で追加し、チャンネル内のローカルユーザーに 406 を送信。共有していなければ無視 |
| 9021 | GUILD_CHAN_PART | 双方向 | srv 送信元サーバー、body(407) |
メンバー一覧から削除し、407 を送信 |
| 9022 | GUILD_CHAN_PUBLIC | 双方向 | srv 送信元サーバー、body(403) = ch nick rest 本文 |
チャンネル内のローカルユーザーに、表示名で 403 を送信 |
| 9023 | GUILD_CHAN_EMOTE | 双方向 | srv 送信元サーバー、body(824) = ch nick "本文" |
チャンネル内のローカルユーザーに 824 を送信 |
| 9024 | GUILD_CHAN_TOPIC | 双方向 | srv 送信元サーバー、body(410) = ch rest トピック |
自サーバーのチャンネルのトピックとして適用してもよい(MAY)。適用した場合は 410 を送信 |
- 共有するチャンネルは各サーバーが決める。リンクしているサーバー群では代表サーバーが決める。送信側は、共有しないチャンネルのメッセージを送信してはならず(MUST NOT)、受信側はそれを無視する。
- チャンネル名は、ASCII 英字の大文字と小文字を区別せずに比較する。
- 送信側は、発言禁止、連続投稿の制限、チャンネルの規則をローカルユーザーに適用してから送信する。
- 受信側は、自サーバーのチャンネルの規則を理由に、ピアのユーザーの発言をローカルユーザーへ配送しなくてもよい(MAY)。
- キック、BAN、オペレーターの任命、モードの変更は運ばない。
10. IM(対応機能 im)
| 番号 | 名前 | 方向 | フィールドの並びと型 | 受信時の動作 |
|---|---|---|---|---|
| 9030 | GUILD_PRIVMSG | 送信者側サーバー→受信者側サーバー | srv 送信元サーバー、nick 宛先、body(205) = nick 送信者 rest 本文 |
宛先がローカルユーザーであれば、送信者の表示名で 205 を配送。存在しなければ 9031(1)を返送。宛先の設定(無視リストなど)により配送しない場合は、黙って破棄するか 9031(2)を返送 |
| 9031 | GUILD_PRIVMSG_FAIL | 受信者側サーバー→送信者側サーバー | srv 送信元サーバー、nick 元の送信者、nick 元の宛先、int 理由コード(上限 255) |
元の送信者がローカルユーザーであれば、404 で通知 |
- オンラインでない宛先。 受信者側サーバーは、宛先がオンラインでない 9030 を、自サーバーのユーザーからオンラインでないユーザーへのメッセージと同じように扱う。たとえば、伝言の機能を持つサーバーはメッセージを保管し、宛先の次回のログイン時に配送する。いずれの場合も 9031(1)を返送する。
- 送信者側サーバーは、宛先がピアを出どころを添えた形(§8.3)で指していれば、そのピアのプレゼンスにないユーザー宛てでも 9030 を送信してよい(MAY)。受信者側サーバーが上のように扱えるようにするためである。
- 代表サーバーでは、9031 の元の送信者がほかのリンクサーバーのユーザーのことがある。その場合は、リンクを通じてそのユーザーへ通知する(§3.2)。ただし、元の送信者へ不在を通知済みの 9030(たとえば、リンクサーバーがオフラインの宛先として自サーバーの伝言に保管し、送信者へ 404 を返したメッセージを、代表サーバーが中継したもの)に対する 9031 では、重ねて通知しない。
- オンラインでないピアのユーザーへのメッセージは、送信者の側のリンクサーバーではなく、そのユーザーのサーバーが保管する。ほかのリンクサーバーが、出どころを添えた形でピアのユーザーを指したメッセージを保管してリンクで伝えた場合(代表サーバーがそのピアのユーザーのログアウトをリンクサーバーへ伝えた後など)、代表サーバーはそれを保管せず、9030 でそのピアへ送信する。
11. 参照と検索(対応機能 browse・search)
- リクエスト ID は 1〜4294967295 の
intである。要求側は、接続ごと・方向ごとに 1 から順に増やして割り当てるべきであり(SHOULD)、応答が完了していない ID を再利用してはならない(MUST NOT)。
| 番号 | 名前 | 方向 | フィールドの並びと型 | 受信時の動作 |
|---|---|---|---|---|
| 9040 | GUILD_BROWSE | 要求側→応答側 | srv 送信元サーバー、int リクエスト ID、nick 要求者、int 最大件数(1〜4294967295)、body(211) = nick 対象 |
対象がローカルユーザーであれば、最大件数を超えない数の 9041 を送信し、最後に 9042(0)を送信。存在しなければ 9042(1)。参照を停止中なら(5)。ポリシーにより拒否する場合は(3) |
| 9041 | GUILD_BROWSE_ITEM | 応答側→要求側 | srv 送信元サーバー、int リクエスト ID、body(212) |
要求者に 212 を配送(ユーザー名は表示名に変換) |
| 9042 | GUILD_BROWSE_END | 応答側→要求側 | srv 送信元サーバー、int リクエスト ID、int 理由コード(上限 255)、body(213) |
要求者に 213 を配送。理由コードが 0 以外の場合は、その前に 404 で通知してもよい(MAY) |
| 9043 | GUILD_QUERY_CANCEL | 要求側→応答側 | srv 送信元サーバー、int リクエスト ID |
応答側はその要求を中断すべきである(SHOULD)。終了メッセージの扱いは、後述の「上限と中断」に従う |
| 9050 | GUILD_SEARCH | 要求側→応答側 | srv 送信元サーバー、int リクエスト ID、nick 要求者、int 最大件数(1〜1000)、body(200) |
ローカルユーザー(代表サーバーでは、すべてのリンクサーバーのユーザー。§3.2)の共有ファイルだけを、ローカルクライアントからの検索と同じ意味で検索。ピアのユーザーの共有ファイルは検索しない。件数の上限は、最大件数とペイロード内の MAX_RESULTS の小さい方。結果の 9051 を送信し、最後に 9052 を送信(終了メッセージの扱いは、後述の「上限と中断」に従う) |
| 9051 | GUILD_SEARCH_ITEM | 応答側→要求側 | srv 送信元サーバー、int リクエスト ID、body(201) |
要求者に 201 を配送(ユーザー名は表示名に変換)。自サーバーのポリシーによる件数の上限を超えた分は破棄 |
| 9052 | GUILD_SEARCH_END | 応答側→要求側 | srv 送信元サーバー、int リクエスト ID、int 理由コード(上限 255)、int 送信した件数(上限 4294967295) |
そのピアの分の完了 |
上限と中断 – 応答側は、受信した要求ごとに、終了メッセージ(9042 または 9052)をちょうど 1 回送信しなければならない(MUST)。唯一の例外は 9043 で取り消された要求であり、この場合は送信を省略してもよい(MAY)。 – 応答側は、要求を他のピアへ転送してはならない(MUST NOT)。代表サーバーがほかのリンクサーバーへ要求を展開することは、転送にあたらない(§3.2)。 – 応答側は、要求者のユーザーレベルや共有ファイル数を理由に拒否すべきでない(SHOULD NOT)。そうした規則は要求者のサーバーが適用する。 – 応答側は、ピアごとに同時に処理する要求の数を定めてもよい(MAY)。それを超えた要求は、終了メッセージの理由コード 4 で拒否する。 – 要求側は、1 つのピアに対して、16 を超える要求を同時に未完了の状態にすべきでない(SHOULD NOT)。 – 応答側は、60 秒以内に終了メッセージを送信すべきである(SHOULD)。要求をリンクへ展開する代表サーバーは、これに間に合うようにリンクの待ちを打ち切るべきである(SHOULD)。 – 要求側は、90 秒経っても完了しないピアの分を中断してもよい(MAY)。中断する場合、要求側は応答側へ 9043 を送信すべきである(SHOULD)。中断後にそのリクエスト ID で届いたものは破棄する。 – ローカルの結果と、すべてのピアの終了(または中断)がそろったら、ユーザーに 202 を送る。 – 結果に含まれる IP アドレス(201 と 213 のフィールド)には、応答側が「外部から到達可能なアドレス」を設定する(ほかのリンクサーバーのユーザーについては §3.2 の 5 を参照)。 – 接続が切れた場合、その接続上の要求はすべて完了したものとみなす。
12. ファイル転送の中継(対応機能 xfer)とユーザー間の中継
転送そのものは、クライアント同士が直接行う([NAP] §5)。本節のメッセージが運ぶのは、転送の中継に必要な情報だけである。ペイロードは、操作の主体となるユーザーが接続しているサーバーが生成し、そのサーバーが、ローカルユーザーの外部から到達可能な IP アドレスとポートを設定する(ほかのリンクサーバーのユーザーについては §3.2 の 5 を参照)。
12.1 メッセージ
| 番号 | 名前 | 方向 | フィールドの並びと型 | 受信時の動作 |
|---|---|---|---|---|
| 9060 | GUILD_XFER_REQUEST | ダウンロード側サーバー→アップロード側サーバー | srv 送信元サーバー、nick ダウンロードするユーザー、body(203) = nick アップロードするユーザー "ファイル名" |
アップロードするユーザーがローカルユーザーであれば、§12.3 の規則を適用する。許可する場合は 607 ダウンロードするユーザーの表示名 "ファイル名" 回線速度 を配送し、拒否する場合は 9065 を返送。存在しなければ 9063 |
| 9061 | GUILD_XFER_ACCEPT | アップロード側サーバー→ダウンロード側サーバー | srv 送信元サーバー、nick ダウンロードするユーザー、body(204) = nick アップロードするユーザー int ip int port "ファイル名" md5 int 回線速度(ip は上限 4294967295、port は上限 65535、回線速度は 0〜10) |
ダウンロードするユーザーに 204 を配送 |
| 9062 | GUILD_XFER_REFUSE | 同上 | srv 送信元サーバー、nick ダウンロードするユーザー、body(609) |
アップロードするユーザー(クライアント)が拒否した。609 を配送 |
| 9063 | GUILD_XFER_NOTFOUND | 同上 | srv 送信元サーバー、nick ダウンロードするユーザー、body(206) = nick 相手ユーザー "ファイル名" |
206 を配送 |
| 9064 | GUILD_XFER_PUSH | ダウンロード側サーバー→アップロード側サーバー | srv 送信元サーバー、nick アップロードするユーザー、body(501) = nick ダウンロードするユーザー int ip int port "ファイル名" md5 int 回線速度(ip は上限 4294967295、port は上限 65535、回線速度は 0〜10) |
アップロードするユーザーがローカルユーザーであれば、§12.3 の規則を適用する。許可する場合は 501 を配送し、拒否する場合は送信元サーバーへ 9065 を返送。存在しなければ、送信元サーバーへ 9063 を返送 |
| 9065 | GUILD_XFER_DENY | アップロード側サーバー→ダウンロード側サーバー | srv 送信元サーバー、nick ダウンロードするユーザー、int 理由コード(§14。上限 255)、body(609) = nick アップロードするユーザー "ファイル名" |
アップロード側サーバーが自らの規則(§12.3)で拒否した。ダウンロードするユーザーに 609 を配送。理由コード 2 は、アップロードするユーザーがオフラインである場合と同じように提示する。それ以外の理由コードでは、その前に 404 で通知してもよい(MAY) |
12.2 処理の流れ
D は S_D のユーザー、U は S_U のユーザーとする。
- 通常のダウンロード: 1. D が S_D に 203 を送る。 2. S_D は自サーバーの規則(§12.3)で D を確認し、S_U に 9060 を送る。 3. S_U は自サーバーの規則(§12.3)で要求を確認し、U に 607 を配送する。S_U が拒否した場合は S_D に 9065 を送り、S_D は D に 609 を配送する。 4. U が 608 を返した場合、S_U は S_D に 9061 を送り、S_D は D に 204 を配送する。U が 609 を返した場合は、同様に 9062 と 609 を用いる。
- ファイアウォール越し(204 のポートが 0 の場合):D が S_D に 500 を送り、S_D は D の外部から到達可能な IP アドレスとポートを設定した 9064 を S_U に送り、S_U は自サーバーの規則で確認して U に 501 を配送する(または 9065 を返送する)。
12.3 双方のサーバーの規則
転送の要求には、双方のサーバーの規則、すなわちダウンロード側サーバーの規則とアップロード側サーバーの規則が適用される。
- ダウンロード側サーバーは、9060 または 9064 を送信する前に、ローカルユーザーからのダウンロードと同じように、自らの規則をダウンロードするユーザーに適用する。ポイント、ダウンロード要求とキュー要求の回数の制限、共有の条件などである。拒否する場合は、ダウンロードするユーザーに自ら応答し、ピアには何も送らない。
- 双方のファイアウォール。 双方のユーザーがファイアウォールの内側にあるとして拒否する(16)のは、双方のデータ用のポートが 0 で、かつ双方のユーザーの IPv4 アドレスが分かる場合だけである。IPv6 で接続したユーザー(IP アドレスは 0 として運ぶ)など、IPv4 アドレスが分からないユーザーは、データ用のポートが 0 であることを理由にファイアウォールの内側にあるとはみなさない。640 と 641(§12.4)、検索結果の除外でも同じである。
- アップロード側サーバーは、9060 または 9064 を受信したときに、他のサーバーのユーザーからの要求に対する自らの制限と、アップロードするユーザー自身の設定を適用する。
- 要求に対する制限。一定時間あたりの要求の回数の制限などである。回数は、ピアのユーザー(ユーザー名と送信元サーバーの組)ごとに数える。
- アップロードするユーザーの設定(無視リストなど)と、そのサーバーでアップロードするユーザーが満たすべき条件(利用承諾をしていることなど)。
- ダウンロードするユーザーのユーザーレベルを使用してはならない(MUST NOT)(§8.1)。ダウンロードするユーザーのポイントや登録など、ダウンロード側サーバーだけが持つ情報に依存する規則は、適用すべきでない(SHOULD NOT)。
- 拒否する場合は、理由コードを付けて 9065 を返送する。アップロードするユーザーの設定によるものは 2、要求の制限を超えたものは 15、それ以外の自サーバーの規則によるものは 3 とする。サーバーはピアのユーザーに対する権限を持たないため(§17)、ピアのユーザーを切断・BAN したり、ユーザーレベルを変更したりしてはならない(MUST NOT)。
- 受信側は、操作の主体のプレゼンスを検証する(§4.5)。配送先がローカルユーザーでなければ、そのメッセージは破棄する。
- 218〜221(転送数の通知)は各サーバー内だけで扱い、運ばない。219 と 221 で変わるもの(ポイント、転送数など)は、それぞれのユーザーのサーバーが変更する。
12.4 ユーザー間の中継
[NAP] には、転送の中継のほかにも、サーバーがユーザーからユーザーへ渡すクライアントのメッセージがある。キューの上限(619→620)、データポートのエラー(626)、直接参照(640〜642)、ユーザーへの ping と pong(751、752)、チャンネルへの招待(430)である。これらは汎用の中継 9080 で運び、1 台のサーバーの 2 人のユーザーの間と同じ意味で処理する。
- 操作の主体のサーバーは、宛先がローカルユーザーである場合と同じように、メッセージ N に対する自らの規則を操作の主体に適用し、§8.3 の 4 のとおり宛先を変換する。そのうえで 9080 を送信する。
body(N)は N のクライアントからサーバーへのペイロードであり、最初のフィールドは宛先の元の名前である。 - 宛先のサーバーは、
body(N)を、操作の主体から受信したメッセージ N として処理する。このとき、操作の主体の名前には表示名を使う。適用するのは、宛先に対する規則と、他のサーバーのユーザーからの要求に対する規則だけであり、操作の主体に対する規則は適用しない。操作の主体のユーザーレベルを使用してはならない(MUST NOT)。そのうえで、N に対して配送するサーバーからクライアントへのメッセージを宛先に配送する。宛先がローカルユーザーでない場合、または規則により拒否する場合は、理由コードを付けて 9081 を返送する。 - 操作の主体のサーバーは、9081 を受信したら、ローカルユーザーの場合と同じ内容を操作の主体に伝える(640 と 641 では 642、それ以外の種別では、宛先がオフラインの場合に伝える内容)。理由コード 2 は、[NAP] のサーバーが無視リストについて行うのと同じく、理由コード 1 と同じように提示する。
- 運べるのは下表の種別だけである。表にない種別を 9080 で送信してはならない(MUST NOT)。受信した場合は 9081(8)を返送する。種別ごとに示した対応機能が使用できない場合は、その種別を送信してはならない(MUST NOT)(§6.5)。
| 番号 | 名前 | 方向 | フィールドの並びと型 | 受信時の動作 |
|---|---|---|---|---|
| 9080 | GUILD_RELAY | 操作の主体のサーバー→宛先のサーバー | srv 送信元サーバー、int 種別(下表の N。上限 65535)、nick 操作の主体、int ip(上限 4294967295)、int port(上限 65535)、body(N) |
上記 2 のとおり。ip と port は、操作の主体の外部から到達可能な IP アドレスとデータ用のポート。640 と 641 では設定し、それ以外の種別では 0 とする |
| 9081 | GUILD_RELAY_FAIL | 宛先のサーバー→操作の主体のサーバー | srv 送信元サーバー、int 種別(上限 65535)、nick 元の操作の主体、nick 元の宛先、int 理由コード(§14。上限 255) |
元の操作の主体がローカルユーザーであれば、上記 3 のとおり通知 |
| N | body(N)(クライアントからサーバーへの形式) |
宛先に配送するもの | 宛先のサーバーが確認すること(拒否する場合の理由コード) | 対応機能 |
|---|---|---|---|---|
| 430 | nick 宛先 ch |
ローカルユーザーからの招待と同じ 430 | 宛先のサーバーがその名前のチャンネルを共有すること。その名前のチャンネルがそこにあり、共有しないチャンネル(非公開・匿名など)であれば拒否する(12)。そこに無い名前は拒否しない | chat |
| 619 | nick 宛先 "ファイル名" [int 上限] |
620 操作の主体 "ファイル名" サイズ 上限。サイズと、省略された場合の上限は、ローカルの 619 と同じように決める |
なし | xfer |
| 626 | nick 宛先 [rest] |
626 操作の主体 [rest] |
なし | xfer |
| 640 | nick 宛先 |
640 操作の主体。宛先のデータ用のポートが 0 であれば、その後に操作の主体の ip port を続ける |
無視リスト(2)、双方のファイアウォール(16、§12.3) | browse |
| 641 | nick 宛先 |
641 操作の主体 ip port |
無視リスト(2)、双方のファイアウォール(16、§12.3) | browse |
| 751 | nick 宛先 [rest] |
751 操作の主体 [rest] |
無視リスト(2) | im |
| 752 | nick 宛先 [rest] |
752 操作の主体 [rest] |
なし | im |
- 配送するメッセージの
操作の主体は、操作の主体の表示名(§8.3)である。 - 642 は運ばない。642 は操作の主体のサーバー自身による応答であり、9081 をもとに生成する。
- 送信者のサーバーは、自らが共有するチャンネル(§9)についてだけ 430 を送る。宛先は自サーバーの同じ名前のチャンネルに入る。そのチャンネルが無ければ、宛先のサーバーの規則で作られ、共有される。ピアのユーザーからの招待(430)だけで、招待を必要とするチャンネルに宛先が入れるようになるわけではない。これは宛先のサーバーが、自らのチャンネルの規則で判断する。操作の主体は宛先のサーバーのチャンネルにはいない。宛先のサーバーは、操作の主体が招待してよいか(そのチャンネルにいるかなど)を確認しない。これは操作の主体のサーバーが確認している(上記 1)。代表サーバーがリンクで渡した招待は、ほかのリンクサーバーも同じように配送する。431 と 432 は各サーバー内だけで扱い、運ばない。
- 600(回線速度の問い合わせ)には、プレゼンスから応答する(§15)。
13. wallop とアナウンス(運ばない)
wallop(627)とアナウンス(628)は、サーバーの運営者が自サーバーのユーザーへ伝えるためのメッセージである。ピア同士は運営者を共有しない(§17)ので、どちらも運ばない。
- 本拡張には 627・628 に相当するメッセージはない。どちらも、どのような形でもギルド接続で送信してはならない(MUST NOT)。
- 9070 は欠番である。以前の草案では wallop のメッセージ(GUILD_WALLOP)に割り当てていた。9070 を受信した場合は未知の種別として扱う(§4.6)。
- 対応機能
wallopは廃止した(§6.5)。 - リンクサーバーの間では、wallop とアナウンスはリンクが従来どおり運ぶ。代表サーバーはそれらをピアへ渡さない。
14. 拒否の理由コード
9007、9031、9042、9052、9065、9081 で使用する。
| 番号 | 意味 |
|---|---|
| 0 | 成功(正常終了) |
| 1 | 対象ユーザーがオフライン |
| 2 | ユーザーの設定による拒否 |
| 3 | サーバーのポリシーによる拒否 |
| 4 | 混雑(同時要求数の上限) |
| 5 | 休止中(検索・参照を停止中) |
| 6 | 書式エラー(不正な UTF-8 を含む、フィールドの値が上限を超える) |
| 7 | 表現できない文字 |
| 8 | 未対応(対応機能がない、未知の種別) |
| 11 | 名前として扱えない値 |
| 12 | 共有されていないチャンネル |
| 13 | 送信者の不一致(その名前がそのピアのプレゼンスに存在しない) |
| 14 | 送信元サーバーの不一致(送信元サーバーが、その接続のピア名と異なる) |
| 15 | 要求の制限を超えた(一定時間あたりの要求の回数など) |
| 16 | 双方のユーザーがファイアウォールの内側にある(双方のデータ用のポートが 0。§12.3) |
(9 と 10 は欠番。)
15. クライアントへの提示(参考。規範ではない)
- whois(603):受信側は、プレゼンスから 604 をその場で組み立ててよい。オフラインのピアのユーザーは「オンラインでない」とする。どのサーバーのユーザーかを示すことを推奨する。
- 一覧、メンバー一覧、hotlist(830、408、825、209、210):ピアのユーザーを表示名で含めてよい。
- 回線速度(600):受信側は、プレゼンスの回線速度から 601 を返してよい。
16. 互換性
- 本拡張を知らないサーバーに接続した場合。 9000 は、ログイン前のクライアントから届いた未知のメッセージとして扱われる。応答がないか、ただちに切断される。接続元は、30 秒でハンドシェイクを打ち切って「ピアがギルドに対応していない」旨を運用者に示すべきであり(SHOULD)、自動再接続の間隔を延ばすべきである(SHOULD)。
- バージョンが異なる場合。 §6.5 のとおり、共通する最大のバージョンを選択する。存在しなければ理由コード 3 で切断する。
- 一部の機能だけの実装。 プレゼンス以外は対応機能でネゴシエーションするため、一部の機能だけを実装したサーバーでも接続できる。
- 未知の種別。 §4.6 のとおり無視する。バージョン 1.x で追加するメッセージは、この規則を前提とする。
- クライアント。 新しい番号のメッセージがクライアントに届くことはない。クライアントの変更は不要である。表示名に
(送信元サーバー)が付加されることがある(§8.3)。 - リンクとの共存。 同じポート上で、最初のメッセージによって接続の種類を識別する。互いにリンクしているサーバーの間ではギルドを確立しない(§3.3)。ギルドを通じて得た情報は、§3.2 のとおりリンクサーバーに限って渡してよく(MAY)、リンクしていないサーバーへ渡してはならない(MUST NOT)。
- 理由コード 4 のあとに再接続しない実装。 相互接続はできる。後から相手を登録した側が接続したとき、または運用者が手動で再接続したときに、接続が確立する。
- 他の実装のサーバーとのリンク。 SlavaNap や FaceNap など、参加できないサーバーとリンクしているサーバーは、ギルドに参加しない(§3.4)。リンクそのものには影響しない。ギルドに参加する場合、ほかのリンクサーバーは、本拡張のメッセージを実装していなくてもよく、ピアのユーザーを、リンクを通じて代表サーバーの通常のユーザーとして受け取る(§3.2)。
17. セキュリティに関する考慮事項
- 認証。 HMAC-SHA256 による相互認証であり、共有鍵がメッセージに含まれることはない。128 ビットの使い捨てのナンスと役割を表す語により、証明値の再利用と反射攻撃を防ぐ。対応機能を入力に含めることで、機能を無効化させる改ざんを防ぐ。
- 認証後の通信は保護されない。 バージョン 1 は、暗号化も改ざん検知も行わない(OpenNap 本体と同様)。信頼できない経路を通す場合は、VPN や TLS のトンネルを使用すべきである(SHOULD)。
tlsは将来のために予約する。 - 共有鍵の管理。 ピアごとに別のランダムな共有鍵を使用し、本拡張の外で受け渡す。保存時には暗号化すべきである(SHOULD)。漏洩した場合は交換する。
- ピアに権限を及ぼさない。 ピアの状態を変更するメッセージは存在しない。ユーザーレベルは表示にのみ使用する。管理操作、BAN、登録、設定、wallop、アナウンスは運ばない。
- なりすまし。 §8.3 のとおり、ピアのユーザーを、ローカルユーザーや登録名と同じ名前のまま表示してはならない(MUST NOT)。
- 個人情報。 プレゼンスに IP アドレスは含めない。IP アドレスは、検索結果、転送の中継、直接参照の中継には含まれる(OpenNap 本体と同様)。運用者は、ギルドに参加するとローカルユーザーの IP アドレスがピアのユーザーから見える可能性があることを、ユーザーに周知すべきである(SHOULD)。
- リソース枯渇攻撃。 受信側は、ピアごとに、プレゼンスの数、同時要求数、1 秒あたりのメッセージ数に上限を設けてもよい(MAY)。プレゼンスの数が上限を超えた場合は、理由コード 9 で切断する。ハンドシェイクの 30 秒のタイムアウトと、接続してくる IP アドレスごとの接続数制限を適用すべきである(SHOULD)。
- 未登録の名前での接続。 理由コード 4 により、名前が登録されているかどうかが判明してしまう。これを懸念する運用者は、理由コード 4 の代わりに 5 を返してもよい(MAY)。ただし理由コード 5 では自動再接続が止まる(§7)ため、登録した後も接続元は自分からは接続し直さず、運用者による手動の再接続が必要になる。理由コード 4 のあとの再接続は間隔の上限 10 分(§7.1)に収まるため、接続先の負荷はわずかである。
- リンクしているサーバー群に関する申告。 9008 の構成は、認証済みのピアによる申告である。ピアは、他のピアのサーバーの名前を構成に含めることで、そのピアとの接続を切断させることができる(§3.3)。運用者は信頼できるピアだけを登録し、運用者への通知には関係するピアの名前を示す。
- 中継。 9080 が運ぶのは §12.4 に挙げた種別だけであるため、管理用の命令を渡すことはできない。宛先のサーバーは、操作の主体のユーザーレベルを使用しない。
18. 参考文献
- [NAP] drscholl@users.sourceforge.net(OpenNap プロジェクト)”napster messages”。原文の日付は 2000-04-07、変更履歴は 2001-04-07 まで。https://opennap.sourceforge.net/napster.txt 。原文は冒頭で、自らを “an open specification” と述べている。本書が参照する節番号は原文のとおりである:§2(Client-Server protocol。フレームと文字列)、§3(Message Types。200〜206・209〜213・218〜221・403・404・406〜410・430〜432・500・501・600・601・603・604・607〜609・619・620・626〜628・640〜642・751・752・824・825・830)、§5.1・§5.2・§5.3(Client-Client Protocol の 5.1 Normal Downloading、5.2 Firwalled Downloading [sic]、5.3 Client to Client Browsing。クライアント間の転送と参照)。
- [NAP-JA] 『Nap プロトコル仕様書』日本語訳 v1.0(2002-02-08)。[NAP] とその改訂版の翻訳。参考情報であり、規範的な参照ではない。
- [RFC2119] Key words for use in RFCs to Indicate Requirement Levels.
- [RFC8174] Ambiguity of Uppercase vs Lowercase in RFC 2119 Key Words.
- [RFC2104] HMAC: Keyed-Hashing for Message Authentication.
- [FIPS180-4] Secure Hash Standard.
- [RFC3629] UTF-8, a transformation format of ISO 10646.
原典との照合は 2026-09-27 に実施した(節構成、参照するメッセージの定義、フィールドの並び)。バイト単位の照合は公開前に実施する。
付録 A. 変更履歴
- 1.0 草案(2026-09-27):最初の草案。
- 1.0 草案(2026-09-27):理由コード 4(ピアとして登録されていない名前)のあとも、間隔を延ばしながら自動で再接続するように改めた(§7、§7.1、§16、§17)。
- 1.0 草案(2026-09-27):リンクしているサーバー群は代表サーバーを通じて 1 台のサーバーとして参加し、代表サーバーはギルドのやり取りをほかのリンクサーバーへ渡すが、ピアの間では渡さないものとした(§0、§1、§2、§3.1、§3.2、§4.4、§8.3、§9、§11、§12、§16)。
- 1.0 草案(2026-09-27):2 つのリンクしているサーバー群の間のギルド接続を 1 本に限るため、9008 GUILD_CLUSTER と切断の理由コード 13 を追加した(§3.3、§4.4、§5、§6.5、§7、§7.1、§8.2、§17)。
- 1.0 草案(2026-09-27):転送の要求に双方のサーバーの規則を適用するものとし、アップロード側サーバーが拒否するための 9065 GUILD_XFER_DENY と拒否の理由コード 15 を追加した(§3.1、§12.1〜§12.3、§14)。
- 1.0 草案(2026-09-27):430・619・626・640・641・751・752 のための汎用の中継 9080 GUILD_RELAY・9081 GUILD_RELAY_FAIL と、拒否の理由コード 16 を追加した(§0、§1.1、§1.2、§4.5、§5、§6.5、§8.1、§12.4、§14、§15、§17、§18)。
- 1.0 草案(2026-09-27):SlavaNap や FaceNap など、参加できないサーバーとリンクしているサーバーはギルドに参加しないものとし、切断の理由コード 14 を追加した(§0、§3.2、§3.4、§6.3、§7、§7.1、§8.3、§16)。
- 1.0 草案(2026-09-27):招待(430)は、宛先のサーバーにまだ無いチャンネルを指してもよいものとした(§12.4)。
- 1.0 草案(2026-09-28):オンラインでない宛先への IM は、受信者側サーバーが自サーバーのユーザーのメッセージと同じように扱う(次回のログインまで保管するなど)ものとし、送信者側サーバーは出どころを添えた形で指したピアへそのような IM を送信してよいものとした(§10)。
- 1.0 草案(2026-09-28):オンラインでないピアのユーザーへのメッセージは、ほかのリンクサーバーが先に保管した場合も、そのユーザーのサーバーが保管するものとした(§10)。招待(430)の宛先のサーバーは、操作の主体が招待してよいかを確認しないものとした(§12.4)。IPv6 で接続したユーザーなど IPv4 アドレスが分からないユーザーは、双方のファイアウォールとして拒否しないものとした(§12.3、§12.4、§14)。
- 1.0 草案(2026-09-28):wallop を運ばないものとした。9070 GUILD_WALLOP と対応機能
wallopを廃止して欠番とし、試験値をwallopを除いて計算し直した(§0、§1.1、§3.2、§4.5、§5、§6.5、§6.7、§13、§17)。