tailscale/tailcat
アカウントも管理サーバも無しで、2台のあいだに暗号化トンネルを張る
どういうものか
Tailscale が自分たちの部品を組み替えて作った、netcat のようなコマンドです。標準入出力をつなぐ、ポートを転送する、SSH で入る、ファイルを送る、SOCKS5 のプロキシにする、といったことができます。特徴はTailscale のアカウントが要らないことで、root 権限もネットワーク設定の変更も要りません。
仕組みの中心は、Tailscale をデータプレーンとコントロールプレーンに分けて、後者を使っていないところにあります。ふだんの Tailscale では、「誰と誰がつながってよいか」「相手はどこにいるか」を管理サーバ(コントロールプレーン)が教えます。tailcat はその役目を、管理の外での受け渡しに置き換えました。サーバ側でコマンドを打つと短い文字列が1つ表示されるので、それをチャットなり口頭なりで相手に渡す。README はこれを tailcat address と呼んでいます。中には WireGuard の公開鍵と、それとは別の事前共有鍵が入っていて、どの DERP 中継にいるかも含まれます。この文字列を知っていること自体が、つないでよい証明になります。 渡し方は帯域外であれば何でもよく、チャットでも口頭でも構いません。
つなぎ方は2段階です。まずクライアントが DERP 中継越しに合図を送り、サーバが応じて、互いを WireGuard のピアとして設定します。同時に NAT 越えの穴あけを試み、成功すれば通信は直接の経路に切り替わります。失敗しても DERP が中継として残るので、接続そのものは維持されます。暗号化・トンネル・NAT 越えといった重い部分は、Tailscale 本体と同じ実装がそのまま使われています。
どんなときに使うか
一度きりのために、環境を汚したくないとき
別の場所にある1台へ、いまだけファイルを送りたい。VPN を入れてアカウントを作って、終わったら消す——という手順のほうが本題より重くなることがあります。root も設定変更も要らず、鍵も既定では使い捨てなので、済んだら閉じるだけで元に戻ります。
相手のアカウントを前提にできないとき
社外の人や、自分の管理下にない環境が相手だと、「まず同じサービスに登録してもらう」が最初の壁になります。tailcat は渡すものが短い文字列1つなので、その壁を飛ばせます。
注意点
互換性の約束がありません。 README には「Go の API、CLI のフラグと出力、通信のフォーマットは、すべて変わる可能性がある」と書かれています。手作業で使うぶんには困りませんが、スクリプトに組み込んで長く回す用途は想定されていません。
公開の DERP 中継に頼り切らないこと。 稼働率や速度の目標は無く、いつでも理由を問わず利用を止めることがある、と明記されています。穴あけに失敗した場合の経路がこれなので、うまく直接つながらない環境では速度が出ません。
渡し方が、そのまま安全性になります。 管理サーバが「誰とつなぐか」を判断しない設計なので、この文字列が漏れた相手=つながれる相手です。README も「これは本来は秘密で、知っていることが接続できる理由になる」と念を押しています。既定では毎回その場かぎりの鍵が作られ、プロセスが終われば二度と使えなくなりますが、鍵をファイルに保存すると同じ文字列が使い回されるので、過去に渡した相手が将来のサーバにもつなげる状態が残ります(serve --allow でつなげる相手を絞ることはできます)。
ライセンスは BSD-3-Clause で、商用利用の妨げになる条項はありません。