Kermitからrsyncまで、ファイル転送の歴史と進化
Kermitが45周年を迎え、C-Kermit 11.0.506をリリースしました。壊れた回線向けの設計から、NAT越しのFTP、SSH時代にrsyncとSFTPが主流になるまでを解説します。
ファイル転送プロトコルが変化し続けた理由
ファイル転送プロトコルは、それぞれの時代に固有の障害を想定して設計されました。Kermit は、回線によってバイト列が破損すると想定していました。XMODEM と ZMODEM は、接続速度が遅く、1 分ごとに料金がかかると想定していました。FTP (file transfer protocol) は、途中のネットワークが協調的に動作すると想定していました。SSH は、ネットワークが敵対的だと想定していました。現在、この最後の想定が主流になっています。そのため、現在の VPS では、SSH 経由の SFTP と rsync が利用でき、それ以外の選択肢はほとんどありません。
現在この歴史を振り返る理由があります。C-Kermit 11.0.506 は 2026 年 8 月 3 日にリリースされました。これは、2011 年 8 月 20 日の C-Kermit 9.0.302 以来、初めてのベータ版ではないリリースです。また、実装されているプロトコルは 1981 年 5 月に設計されました。45 年あれば、あるカテゴリが生まれ、標準化され、動作していたネットワークによって破壊され、その後 SSH に取り込まれるまでの過程を一通り見届けられます。
Kermit、1981年:バイトを消費する回線向けに設計
Kermit は、Frank da Cruz と Bill Catchings によって、1981年5月にColumbia University Computer Centerで作成されました。名称はKermit the Frogに由来します。da Cruzによると、グループが名称を考えていたとき、壁にMuppetsのカレンダーが掛かっていました。その仕組みが広く使われるようになるとは、誰も予想していませんでした。
Kermitが解決した問題は、速度ではありません。端末とメインフレームの間の経路は、任意のバイトを通すパイプではありませんでした。そこには独自の制約を持つ文字デバイスがありました。7-bitの場合もあれば、半二重の場合もありました。制御文字を破棄したり、そのうちの1つをコマンドとして実行したりすることもありました。バイナリファイルを変更せずに送信しても、正常には動作しませんでした。
そこで、Kermitの設計ではこれらの制約をそのまま前提にしました。Kermit Projectの公式の沿革には、次のように記載されています。
- 短いパケット。ほとんどのメインフレームは、端末からの長いデータバーストを受信できなかったためです
- 半二重のストップアンドウェイト方式。IBMのメインフレームは全二重通信をサポートしていなかったためです
- 制御文字と8-bit文字の印字可能文字によるエンコーディング。どちらもメインフレームの端末ドライバーを通過できなかったためです
- 各パケットへのチェックサム付加と受信側からの応答。破損したパケットの再送だけで済み、ファイル全体の再送を避けられるためです
3つ目の点が特に重要です。Kermitはファイルそのものではなく、ファイルをテキストセーフな形式にエンコードして送信します。制御バイトは、プレフィックス文字と印字可能文字の組み合わせに変換されます。上位ビットが設定されたバイトも、7-bit回線向けに同じ方法でエンコードできます。途中にある機器が印字可能テキストしか理解できなくても、そこを通るのは印字可能テキストです。代償はサイズです。バイナリファイルは回線上で大きくなります。それ以外の方法では転送全体が破壊されるメインフレームのフロントエンドに対しては、これが適切なトレードオフでした。
Kermitのもう1つの特徴は、その対象範囲です。XMODEMは、ファイルとは何かについてすでに合意している2台のマシン間でファイルを移動しました。一方、Kermitは、互いに合意していないシステム間の最小公倍数として作られました。システムごとに文字セット、レコード構造、テキスト行の終端に対する考え方が異なっていたためです。これは、メインフレームからクラウドサーバーへの長い移行が説明する世界であり、ネットワーク層が相互運用性を処理する前の時代に、Kermitが担っていた役割です。
Columbiaは2011年に支援を終了し、改訂版3-clause BSD licenceの下でC-Kermitを公開しました。Frank da Cruzは、1981年の設計から2025年までの44年間、プロジェクトに関わり続けました。2026 releaseはOpenKermit projectによって保守されており、現在これを読む人の大半よりも古いC codebaseの現代化をJohn Goerzenが進めています。
XMODEM と ZMODEM: 電話料金が設計を左右した時代
Ward Christensen は 1977 年に MODEM.ASM を作成し、そこで導入したプロトコルが XMODEM です。1978 年、彼と Randy Suess は CBBS をオンラインで公開しました。これは最初の公開掲示板システムです。Christensen は 2024 年 10 月 11 日に亡くなりました。
XMODEM は、プロトコルとしてほぼ限界まで小規模です。データは 128 バイトのブロック単位で転送されます。各ブロックには 1 バイトのチェックサムが含まれます。これは 128 バイトのデータの合計を 256 で割った余りです。受信側は各ブロックを確認応答するか、再送を要求します。この構成になった理由は経済性です。ダイヤルアップ回線では接続時間に対して料金が発生するため、回線エラーが発生しても転送全体ではなく 1 ブロックだけの損失で済むようにしています。
弱点も同じ仕組みにあります。XMODEM は 128 バイト転送するたびに確認応答を待ちます。Chuck Forsberg は ZMODEM 仕様書で、次のように明確に説明しています。「短いブロック長は、タイムシェアリングシステム、パケット交換ネットワーク、衛星回線で使用するとスループットを低下させる」。ストップアンドウェイト方式を損なうのは帯域幅ではなく遅延です。料金が発生している回線上で、ラウンドトリップのたびに通信が停止します。
次に登場したのが YMODEM で、Ward Christensen が 1985 年にこの名称を付けました。YMODEM の特徴はバッチ転送です。送信側はデータの前にファイル名とサイズを通知するため、1 回のセッションで複数のファイルを転送できます。受信側も各ファイルの終端を把握できます。
ZMODEM は、Omen Technology で Chuck Forsberg が作成した回答です。仕様書の改訂日は 1988 年 10 月 14 日で、そこには「ZMODEM は Telenet との契約に基づき、パブリックドメイン向けに開発された」と記載されています。Telenet は公開パケット交換データネットワークを運用しており、その契約が設計に反映されています。ZMODEM はネットワーク制御文字をエスケープするため、途中のパケットネットワークがそれらを消費することはありません。無音状態からフレーム境界を推測するのではなく、一意の文字列で各フレームの開始を示すため、タイムアウトを待たずにノイズから復旧できます。明示的な再開機能も備えているため、中断した転送を停止位置から再開できます。
最も重要なのは、待機をやめたことです。仕様書自身の説明では、「ZMODEM は実質的にファイル全体をウィンドウとして使用する」とされています。送信側はストリーム転送を続け、受信側から問題が報告された場合にだけ停止します。これは TCP がウィンドウに組み込んだものと同じ発想です。ただし、こちらはモデムがアイドル状態になる様子を見ていた人物が、逆方向から到達したものです。
FTPの2本の接続方式が長く使われなかった理由
FTPは、この中で最も古いプロトコルです。RFC 114「A File Transfer Protocol」は、A. Bhushanによって執筆され、1971年4月16日付で公開されています。
知っておくべき点は、RFC 114が2本の接続方式を検討したうえで採用しなかったことです。Bhushanは「制御情報用とデータ用に、2本の全二重リンクを使用する」案を検討し、最終的に「データ情報と制御情報の両方の交換には、1本の全二重接続を使用することを推奨する」と結論付けました。接続の分離はその後に導入されました。1972年7月8日付のRFC 354には、「データとファイルはデータ接続経由でのみ転送する」とあり、コマンドは別のTelnet接続で送信されます。PostelとReynoldsによる1985年10月のRFC 959が、現在も広く実装されているバージョンです。
RFC 959ではポートも固定されました。サーバーのデフォルトのデータポートは「制御接続ポートに隣接するポート(つまりL-1)」です。制御接続がポート21の場合、データポートはポート20です。
ここで、現在まで残らなかった仕組みが問題になります。FTPの元のモードでは、データ接続をサーバーからクライアントへ開きます。NAT(network address translation)の背後にあるクライアントには、サーバーから到達できるアドレスがありません。ファイアウォールの背後にあるクライアントは受信接続を受け付けません。そのため、データ接続は確立されず、一覧やファイルを要求した時点で転送が停止します。これに対する解決策がPASVです。RFC 959では、PASVを「データポート(デフォルトのデータポートとは異なるポート)でサーバーが『待ち受け』、転送コマンドを受信した際に接続を開始するのではなく、接続を待つ」ための要求と定義しています。サーバーは接続先のアドレスとポートを次のように返します。
PASV
227 Entering Passive Mode (203,0,113,10,195,80)この応答は、ホスト203.0.113.10のポートが、195に256を掛けて80を足した50000であることを示します。もう一度読むと、構造上の問題が分かります。2本目の接続のエンドポイントが、1本目の接続のペイロード内で通知されるのです。NAT装置やファイアウォールは、制御チャネルを解析して、そこに記載されたポートを開かなければ、この接続を通過させられません。Linuxには、まさにこの処理を行うコネクショントラッキングヘルパーが組み込まれています。ただし、このヘルパーが動作するのは制御接続が平文の場合だけです。そのため、FTPをTLS(transport layer security)でラップすると、FTPを利用可能にしていた中間装置から制御チャネルの内容が見えなくなります。
FTPから得られる教訓は、1文で言えます。FTPはネットワークをプロトコルの参加者にしました。プロトコルの内容をネットワークが理解する必要がある場合、そのプロトコルは、内容を信頼しなくなったネットワークでは存続できません。
結末は記録に残っています。Firefoxは2021年7月、version 90でFTPサポートを削除しました。Chromeは2021年10月、Chrome 95でFTPコードを削除しました。
rcp と r-command:ホスト名による信頼
4.2BSD は、DARPA の資金提供を受けて Berkeley が 1983 年にリリースし、rcp、rsh、rlogin を導入しました。これらは、1 つのネットワーク上にある Unix マシンで構成されたキャンパス向けに作られており、認証モデルにもその前提が表れています。ホストは、どのユーザーが呼び出しているかを申告しました。/etc/hosts.equiv またはユーザーの ~/.rhosts がそのホストを信頼済みと示していれば、その申告が受け入れられ、パスワードは要求されませんでした。
これらのコマンドが廃れた理由を明確にするため、仕組みをそのまま説明します。信頼の根拠は、アドレスと申告でした。どちらもネットワーク上を平文で送られるため、経路上の誰でも読み取ることができ、偽装することもできます。このモデルは、Unix から Linux への道のりで説明した、ネットワークが建物内に限定されていた環境では成立していました。ネットワークがインターネットになった時点で、意味を失いました。
rcp が正しく設計していたのは、インターフェースです。送信元、宛先、完了です。開くセッションはなく、転送モードをネゴシエートする必要もなく、2 本目の接続を用意する必要もありません。パス中のコロンを使って cp のように動作します。このインターフェースは、プロトコルが廃れてからも 40 年にわたって残りました。
SSH がカテゴリ全体を取り込みました
1995 年、当時 Helsinki University of Technology の研究者だった Tatu Ylonen は、大学ネットワークに対するパスワード盗聴攻撃を受けて SSH を開発しました。1995 年 7 月、ソースコード付きの free software としてリリースしました。同年末には、50 か国で約 20,000 人のユーザーがいると推定されていました。1995 年 12 月には、開発を継続するため SSH Communications Security を設立しました。
後のバージョンではライセンスの制限が強化されたため、OpenBSD の開発者は、最後に自由なライセンスで提供されたリリースである ssh 1.2.12 を fork しました。最初の取り込みは 26 September 1999 に行われ、OpenSSH 1.2.2 は 1 December 1999 に OpenBSD 2.6 とともにリリースされました。この fork は、オープンソースのライセンス条件が実際の運用で重要になる理由を示す簡潔な事例です。現在、ほとんどのユーザーが実行している SSH 実装は、ライセンスによって利用がまだ認められていた 1 つのバージョンを起源としているためです。
SSH が登場すると、ファイル転送は独立した問題ではなくなりました。複数のチャネルを運ぶ認証済みの暗号化ストリームによって、以前のプロトコルが独自に実装する必要があった機能がすでに提供されます。完全性、順序制御、そして 2 本目の TCP 接続を必要としない別のデータ経路です。これらの仕組みが初めての場合は、先に SSH とは何かを確認することをお勧めします。
ここから 2 つのツールが生まれました。scp は SSH セッション内で実行する rcp の wire protocol であり、そのため rcp とまったく同じコマンドラインを継承しました。SFTP は別の設計です。ディレクトリ一覧、ファイル属性、ランダムアクセスを備えた実際のファイルプロトコルであり、SSH channel 上で転送されます。SFTP が RFC になったことはありません。IETF draft の draft-ietf-secsh-filexfer は 18 July 2006 に version 13 に到達した後、期限切れになりました。OpenSSH はこの draft の version 3 を実装しています。世界で最も広く使われている secure file transfer protocol は、廃止された draft の番号付き revision ですが、実際に機能しています。
従来の scp protocol も、現在は廃止されています。26 September 2021 にリリースされた OpenSSH 8.8 は、「近い将来の OpenSSH release では、scp(1) が従来の scp/rcp protocol ではなく、デフォルトで SFTP を使用するようになる」と警告しました。8 April 2022 にリリースされた OpenSSH 9.0 で、実際に変更されました。「この release では、scp(1) が従来の scp/rcp protocol ではなく、デフォルトで SFTP protocol を使用するように変更されました。」
この理由から、ある種の慣行が生まれた背景も分かります。従来の scp protocol は、リモートのファイル名に含まれる wildcard を remote shell に渡して展開していました。そのため、リモートパス内のすべてのメタ文字を二重引用符で囲むように教えられてきました。8.8 の notes によれば、SFTP over scp では「この扱いにくく壊れやすい quoting が不要になりました」。したがって現在の server では、scp は rcp のコマンドラインを使用する SFTP client です。1983 年のインターフェースは残りました。1983 年の wire protocol は残りませんでした。
rsync, 1996: ファイル全体ではなく差分を送る
Andrew Tridgell と Paul Mackerras は、1996 年 6 月 19 日に Australian National University で rsync を発表しました。同時に、技術報告書 TR-CS-96-05「The rsync algorithm」も公開されました。
rsync より前のプロトコルは、ファイルを破損させずに移動する方法を問うものでした。rsync は、相手側にこのファイルがどの程度すでに存在するかを問いました。この報告書では、対象を「低帯域幅・高遅延の双方向通信リンク」とし、目的を「送信元ファイルの一部と送信先ファイルの一部が同一である箇所」を特定することとしています。これにより、一致しない部分だけを送信します。
この仕組みを理解しておくと、rsync の動作を説明できます。受信側は既存のコピーを固定長のブロックに分割し、各ブロックについて 2 つのチェックサムを計算します。1 つは弱く安価なもの、もう 1 つは強く計算コストの高いものです。受信側はその一覧を送信側に送ります。送信側は自身のファイル上でウィンドウを 1 バイトずつ移動し、弱いチェックサムを差分更新します。これにより、バイト単位の走査を現実的なコストで実行できます。弱いチェックサムが一致したら、強いチェックサムで確認します。確認済みの一致はブロック参照になります。それ以外はリテラルバイトとして送信します。受信側は、すでに保持しているブロックへの参照と、受信したリテラルバイトからファイルを再構築します。
大きなファイルの先頭に 1 バイトを挿入すると、単純な差分ツールはファイル全体を送信する必要があります。すべてのオフセットが移動するためです。ローリングウィンドウは、新しいオフセットにある同じブロックを検出します。そのため、rsync が送るのは 1 バイトと管理情報だけです。この特性があるため、複数回コピーするディレクトリには、現在でも rsync が適しています。
2 つの動作は、よく利用者を驚かせます。どちらもマニュアルに記載されています。1 つ目は、rsync がファイルを確認するかどうかを決めるために、ファイルの内容をチェックサム計算するわけではないことです。rsync は「デフォルトでは、サイズまたは最終変更時刻が変わったファイルを探す『クイックチェック』アルゴリズムを使用して、転送が必要なファイルを見つける」と説明されています。サイズとタイムスタンプが同じまま内容だけが変更されたファイルは、スキップされます。--checksum を指定すると、この動作が変わり、両側で候補ファイルをすべて読み取って内容全体を確認します。2 つ目は、両方のパスがローカルの場合、デフォルトでは差分アルゴリズムが無効になることです。1 台のマシン上で 2 つのコピーを読み取り、チェックサムを計算するほうが、バイトをコピーするよりコストが高いためです。差分による節約が発生するのは、リンクがボトルネックになる場合だけです。
VPS で実際に使うものと、その理由
短く言えば、少数のファイルには SFTP、再度コピーするディレクトリには SSH 経由の rsync を使います。
どちらも SSH 上で動作するため、追加設定なしでホスト鍵の検証と暗号化を利用できます。これは、50 年分の成果がデフォルト設定に凝縮されたものです。Kermit の設計者は回線によってデータが破損すると想定し、プロトコルにチェックサムと再送を組み込みました。現在は TCP がそれを担います。Christensen と Forsberg は、すべてのバイトにコストがかかると想定し、再開とストリーミングを組み込みました。現在は rsync の差分アルゴリズムがそれを担い、しかもより適切に実現しています。FTP の開発者は、ホスト同士が協調するネットワークを想定しました。そして、これらの想定のうち、プロトコルをどれだけ改良しても修正できない形で誤っていたのは、それだけです。
チェックサムに今も意味がある場面
「checksum」という語は、この歴史の中で 3 つの異なる役割を担ってきました。これらは置き換え可能ではありません。
Kermit と XMODEM のパケット単位のチェックサムは、通信中の破損を検出しました。現在は TCP checksum とリンク層の誤り訂正がこれを担っています。そのため、現代の転送ツールでこの点を意識するよう求められることはありません。
rsync のブロックチェックサムは、「このデータは正しいか」という問いに答えるものではありません。「このブロックをすでに持っているか」という問いに答えます。ここでの強力なチェックサムは検索キーであり、ファイルの出所を示すものではありません。
3 つ目の役割は、今も利用者に残されています。リリースファイルに公開されたチェックサムは、TLS では答えられない問いに答えます。TLS により、正しいサーバーと通信したことは証明できます。しかし、そのサーバーに正しいファイルが置かれていたことまでは証明できません。また、ミラーから取得したファイルには何の保証も与えません。だからこそ、リリースのチェックサムと署名を 30 秒かけて確認する価値があります。習慣にするのも簡単です。インストールするすべてのダウンロードでチェックサムを確認する
この話に登場したその他の問題は、下位層によって解決されました。しかし、これは解決されていません。そもそもネットワークの問題ではなかったからです。
FAQ
FTP は VPS で今も安全に使用できますか?
いいえ。平文の FTP では認証情報とファイル内容がクリアテキストで送信されるため、経路上の誰でも両方を読み取れます。また、FTP は制御チャネルを解析するファイアウォールに依存しますが、制御チャネルを TLS で暗号化した時点で、その対応はできなくなります。ブラウザーではすでに FTP のサポートが廃止されています。Firefox は 2021 年 7 月の version 90 で FTP サポートを削除し、Chrome は 2021 年 10 月の version 95 でコードを削除しました。SSH 上の SFTP を使用してください。SFTP は 1 つのポートだけを必要とし、プロトコルを認識する中間装置も必要ありません。
FTP にはなぜパッシブモードが必要なのですか?
FTP の元のモードでは、サーバーがクライアントへのデータ接続を開くためです。RFC 959 では、サーバーのデフォルトのデータポートを「制御接続ポートに隣接するポート(つまり L-1)」と定めています。そのため、制御ポートが 21 の場合はポート 20 になります。NAT(network address translation)の背後にあるクライアントには、サーバーから到達できるアドレスがありません。そのため接続が到達せず、転送が停止します。PASV では方向が逆になります。サーバーが待ち受け、クライアントが接続するためのアドレスとポートを 227 Entering Passive Mode の応答で返します。
scp は現在も独自のプロトコルを使用しますか?
OpenSSH 9.0 以降は使用しません。OpenSSH 9.0 は 2022 年 4 月 8 日にリリースされ、「scp(1) が従来の scp/rcp プロトコルではなく、デフォルトで SFTP プロトコルを使用するよう切り替わった」バージョンです。OpenSSH 8.8 は 2021 年 9 月にこの変更を発表しました。目に見える違いは引用符の扱いです。従来のプロトコルでは、リモートのワイルドカードをリモートシェルに渡して展開していました。SFTP ベースの方式では展開しません。そのため、シェルによる展開に依存していたパスは現在、異なる動作になります。
VPS では、どのような場合に rsync が scp より適していますか?
同じツリーを複数回コピーする場合です。rsync は、宛先にまだ存在しない各ファイルの部分だけを送信するため、2 回目のコピーは 1 回目より大幅に少ないコストで済みます。宛先に一度も存在しない単一ファイルでは、scp と rsync が移動するバイト数はおおむね同じで、scp のほうが簡単です。デフォルトでは、rsync はサイズと変更時刻によって確認対象を判断します。そのため、サイズとタイムスタンプが変わらないまま内容が変更されたファイルを rsync が検出するには、--checksum が必要です。
Kermit はなぜファイルを生のバイト列ではなく印刷可能なテキストとしてエンコードしたのですか?
対象とした接続がバイトパイプではなく、メインフレームに接続する端末回線だったためです。そのような回線は 7-bit の場合があり、メインフレームの端末ドライバーは制御文字をそのまま渡さずに処理していました。Kermit は制御バイトと上位ビットのバイトを印刷可能な文字にエンコードし、途中の機器がそれらに反応しないようにしました。このエンコードにより、ネットワーク上でバイナリファイルは大きくなります。しかし、転送結果が破損する事態を避けるためには、適切なトレードオフでした。