Asopitech With · メッシュVPN
Tailscale Taildrop with Alopex Chirps
Taildropは、メッシュVPNのTailscaleで、自分の端末どうしに暗号化した直接の接続でファイルを送る機能です。これをAlopex Chirpsを応用して再現すると…?
更新: 2026/10/13
どんなサービスか
Tailscaleは、自分の端末どうしを暗号化した直接の接続で結ぶネットワークです。Taildropを使うと、自分の端末から別の端末へ、ファイルを送れます。途中で切れた転送は、再開できます。扱うデータは、端末の一覧とその状態、そして送るファイルです。
通信の組み立て
- メンバーシップ:端末をノードとしてメッシュに参加させ、シードのリストからつなぎます。SWIM方式のgossipで、どの端末がalive・suspect・deadかを知り、送り先の一覧に出します。
- イベント:端末の参加、離脱、状態の変化をイベントで受け取り、画面の一覧を更新します。
- ファイル転送:ファイルを、宛先の端末へ直接送ります。受信側がハッシュを確かめ、メタデータを適用し、原子的に置いたあとに完了を返します。止まった転送は、セッションから再開できます。
どの端末に送るかを選ぶ画面と、受け取ったファイルの置き場所は、アプリのコードです。
配置の形
各端末のアプリにChirpsを組み込みます。端末ごとに証明書と秘密鍵を持たせ、信頼する証明書を設定します。端末どうしは、常に相互TLSで認証してから通信します。
Alopex Chirpsが合う理由
自分の端末どうしのファイルの送信は、相手の一覧と、確かな転送の2つでできています。Chirpsは、gossipによる一覧と、ハッシュの検証まで含むファイル転送を、1つのライブラリで渡します。
コードで見る
端末のイベントに一貫した順序を与える、ハイブリッド論理時計の中心だけを取り出したコードです(Rust)。
use alopex_chirps_gossip_swim::hlc::{Clock, LocalHlc};
use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Duration;
// 説明用の手動クロック(実際はシステム時計)
struct ManualClock(AtomicU64);
impl Clock for ManualClock {
fn now_millis(&self) -> u64 {
self.0.load(Ordering::SeqCst)
}
}
fn main() {
let skew = Duration::from_secs(1);
// メッシュの 2 つの端末 A / B。それぞれ論理時計を持つ
let mut a = LocalHlc::with_clock(skew, Arc::new(ManualClock(AtomicU64::new(100))));
let mut b = LocalHlc::with_clock(skew, Arc::new(ManualClock(AtomicU64::new(90))));
// A 側で端末のイベント(参加→状態変化)が起きるたびに時計を進める
let joined = a.tick();
let changed = a.tick();
println!("A: joined={joined:?} changed={changed:?}");
// A のイベントを B が受け取ると、B の時計は A を追い越す
let seen = b.receive(changed).expect("receive");
println!("B receives A: {seen:?}");
// その後 B 側で起きたイベントは、必ず A のイベントより後に順序づく
let b_event = b.tick();
println!("B next: {b_event:?}");
assert!(b_event > changed);
println!("OK: どの端末も、イベントの一覧を同じ順序で更新できる");
}端末のイベントに一貫した順序がつき、一覧の更新がどの端末でもそろいます。SWIM方式のgossipによる端末一覧(alive・suspect・dead)と、ハッシュ検証つきのファイル転送は、本文のとおりChirpsが受け持ちます。
端末の一覧から相互TLSでそのままファイルを送れるAlopex Chirpsで、ファイル送信のアプリを作ってみよう。GitHubのクイックスタートから始められます。