Openrsync: RsyncプロトコルのモダンでBSDライセンスによる実装

数十年にわたり、rsyncはネットワークを介した効率的なファイル同期のゴールドスタンダードであり続けてきました。しかし、オリジナルの実装は長年のレガシーコードの重みとGPLライセンスの制約を抱えています。そこで登場したのが、OpenBSDチームによって開発されたrsyncプロトコルのクリーンルーム実装であるopenrsyncです。

もともとは、NetNodやSUNETといった組織から資金提供を受けているOpenBSD用のRPKIバリデータであるrpki-client(1)プロジェクトの一部として作成されましたが、その後openrsyncはOpenBSDのベースシステムに統合されました。これは、現代的なrsync(プロトコルバージョン27)と互換性があり、セキュリティとミニマリズムを重視した合理的なファイル同期アプローチを提供する、BSDライセンス(ISC)の代替手段を提供します。

コア・アルゴリズム:openrsyncの仕組み

その核心において、openrsyncは、ソースと送信先ファイルの間の差分のみを送信することでデータ転送を最小限に抑える、古典的なrsyncアルゴリズムを実装しています。プロセスは、sender(ソースファイルを管理)とreceiver(送信先を管理)に分かれています。

ブロック交換プロセス

openrsyncの効率性は、洗練された「ブロック交換」メカニズムに依存しています。

  1. ファイルリストの生成: senderはファイル名とメタデータのリストを生成します。両方のサイドは、ディレクトリがその中に含まれるファイルよりも先に処理されるように、このリストを辞書順にソートします。
  2. ハッシュ化による効率化: 通常のファイルの場合、receiverはファイルをブロックに分割します。各ブロックは2回ハッシュ化されます。まず、高速なAdler-32(4バイト)ハッシュ、次に、より低速なMD4(16バイト)ハッシュです。
  3. マッチング: receiverはこれらのハッシュをsenderに送信します。senderは自身のファイルバージョンのスキャンを行い、オンザフライで高速ハッシュを計算します。高速ハッシュが一致した場合、低速なMD4ハッシュで一致を確認します。
  4. 再構成: 一致が見つかった場合、senderはreceiverに対し、ローカルコピーのどのブロックを再利用すべきかを伝えます。一致が見つからない場合は、senderは生のバイトデータを送信します。これがファイルが完全に再構成されるまで続きます。

ブロックサイズの最適化

オーバーヘッドと精度のバランスを取るために、openrsyncは、最小値を700バイトとして、ファイル総サイズの平方根に基づいてブロックサイズを計算します。これにより、小さな設定ファイルから大規模なデータベースダンプまで、プロトコルが効率的に動作し続けることが保証されます。

アーキテクチャの改善

openrsyncとオリジナルのSamba rsyncとの主な違いの一つは、その内部アーキテクチャです。オリジナルのrsyncは、ファイルスキャンを処理するために(receiverからフォークされた)別の「generator」プロセスを使用しますが、openrsyncは、generatorとreceiverを単一のプロセスに統合しています。

event loopを利用することで、openrsyncはプロセス間通信のオーバーヘッドなしに、読み取りおよび書き込みリクエストに対してより迅速に応答できます。receiverは、uploader(ブロックメタデータの送信)とdownloader(senderから受信したデータの書き込み)の両方のタスクを効率的にこなします。

設計によるセキュリティ

OpenBSDチームによる開発であるため、セキュリティは後付けではなく、基礎となる要件です。openrsyncは、攻撃対象領域を制限するために、ネイティブのOpenBSDセキュリティ・プリミティブを活用しています。

  • pledge(2): これはプロセスが実行できるシステムコールを制限します。例えば、receiverは、「dry-run」モードでない限り、ディスクへの書き込み権限のみが付与されます。
  • unveil(2): これはプロセスのファイルシステムへのアクセス範囲を視覚化(制限)します。receiverは、送信先ディレクトリとその配下のみが「unveiled」され、プロセスがターゲットパス以外のファイルに誤って、あるいは悪意を持ってアクセスすることを防ぎます。
  • ランダム化されたシード: time(3)を使用する一部の実装とは異なり、openrsyncはサーバーモードにおいて、堅牢性を高めるためにMD4ハッシュにarc4random(3)を使用してシードを生成します。

移植性とエコシステム

公式にはOpenBSDでサポートされていますが、openrsyncは移植性を念頭に置いて設計されています。現在はLinux (glibcおよびmusl)、FreeBSD、NetBSD、macOS、およびOmniOS上でコンパイルおよび実行が可能です。

しかし、開発者は、pledgeunveilのセキュリティ保証が極めて重要であると警告しています。これらと同じセキュリティ体制を維持するためには、他のシステムへの移植(例えば、FreeBSDのCapsicumを使用するなど)が必要です。著者が述べているように、オリジナルのrsyncはネットワークからファイルシステムへ任意のデータを送り込みますが、これらの保護がなければ、いかなる実装であっても潜在的にリスクがあります。

コミュニティの視点と現状

アーリーアダプターやコミュニティメンバーは、その採用に関していくつかの重要な点を指摘しています。

  • 統合: 興味深いことに、いくつかの報告によれば、openrsyncはすでにmacOS 15.0で利用されていることが示唆されています。
  • 機能の同等性: rsyncのコマンドライン引数のサブセットをサポートしていますが、追いついつつあります。例えば、--excludeのサポートは、最近OpenBSD 7.9で追加されました。
  • ライセンスの魅力: BSDライセンスへの移行は、GPLを制限的と感じる人々にとって大きな利点と見なされており、他のプロプライエタリなOSや寛容なOSディストリビューションへの統合を容易にする可能性があります。

"rsyncの断片化という問題は、AppleやAndroidがそれを好むようになる一方で、Linuxや広範なGPLの世界では、慣性によりオリジナルの実装に固執し続けることにある。" — HN User @chasil

クリーンで、安全で、かつ寛容なライセンスで実装されていることにより、openrsyncは単にファイルを同期するためのツールを提供するだけでなく、現在のセキュリティ・ランドスケープにおいて、不可欠なシステム・ユーティリティがどのように構築されるべきかという現代的な設計図を提供しています。

Sources