TurnoutがMacに対して行うこと

Turnoutはrootとして動くサービスをインストールします。そこで、それが何をするのか、どう確かめられるのかを正確に説明します。サービスが何か、何を変更し、何を保存し、どこに接続するのか。どれもご自身のMacで確認できます。

2つの部分:アプリとバックグラウンドサービス

アプリ(Turnout.app)はあなたのユーザとして、特別な権限なしに動きます。トンネルを表示し、構成を編集し、バックグラウンドサービスに接続と接続解除を頼みます。ネットワークの通信には一切触れません。

バックグラウンドサービスは、rootとして動くLaunchDaemon(cc.ctsite.turnout.daemon)です。そのプログラムturnout-daemonは、アプリの中の/Applications/Turnout.app/Contents/MacOS/にあります。TurnoutはこれをmacOSのログイン項目(SMAppService)として登録するので、macOSが“システム設定” › “一般” › “ログイン項目と機能拡張”で許可を求めます。オフにするのもそこからです。

サービスはトンネルごとにutunインターフェイスを作り、サービスに組み込まれたGotaTun(MullvadによるMPL-2.0ライセンスの実装)でWireGuardをユーザ空間で動かします。サービスを通るのはトンネルのパケットだけで、それ以外の通信はいつもどおりmacOSがルーティングします。トンネルはサービスの中にあるので、アプリを閉じても接続されたままです。

何を、どのツールで変更するか

アドレス、MTU、ルート、DNSは、macOSでwg-quickが使うのと同じプログラムで変更します。どれも引数を付けて直接実行し、シェルは通しません。

/sbin/ifconfig
トンネルインターフェイスのアドレスとMTU、そしてインターフェイスの有効化。
/sbin/route
トンネルへのルート、サーバーのアドレスを物理ネットワーク側に保つルート、そしてトンネルを通らないルート。
/usr/sbin/networksetup
ネットワークサービスのDNSサーバーと検索ドメイン。

なので、いつものコマンドで何をしたかがそのまま分かります:

netstat -rn
networksetup -listallnetworkservices
networksetup -getdnsservers Wi-Fi   # または一覧にある別のサービス

トンネルの接続を解除すると、サービスは追加したルートを削除し、置き換えたDNS設定を元に戻します。

構成ファイル

トンネルは、rootが所有するフォルダ/Library/Application Support/cc.ctsite.turnout/tunnelsに、トンネルごとに1ファイル、モード0600で、秘密鍵も含めて保存されます。そこに書き込むのはサービスだけで、アプリは保存をサービスに頼みます。

sudo ls -l "/Library/Application Support/cc.ctsite.turnout/tunnels"

フック

PreUp、PostUp、PreDown、PostDownは、rootとして/bin/bash -cで実行され、%iはトンネルのutunインターフェイスに、%Iはトンネル名に置き換えられます。sudoと同じだけの力があるので:

  • フックは必ずディスク上の構成ファイルから読み込まれ、アプリがサービスに送る内容から来ることはありません。
  • フックが新しい、または変更された構成を保存するには、管理者の承認が必要です。承認はサービス自身がmacOSのAuthorization Servicesで確認し、アプリの言い分をうのみにはしません。
  • フックに触れない編集なら、改めて承認する必要はありません。

承認する前に、構成のフックを読んでください。sudoで実行するスクリプトを読むのと同じです。

サービスが応答する相手

アプリはUnixソケット(/var/run/cc.ctsite.turnout.daemon.sock)でサービスと通信します。サービスは接続してくるプログラムごとにコード署名を確認し、同じ開発チームが署名し、Turnoutのバンドル識別子cc.ctsite.turnoutを持つプログラムにだけ応答します。それ以外のプログラムは拒否されます。

クラッシュのあと

サービスが止まると、macOSはトンネルインターフェイスを削除し、そこにあるルートも一緒に消えます。しかし物理ゲートウェイを通るルートとDNS設定は消えず、この方法で設定したDNSは再起動しても残ります。そこでサービスはすべての変更を、行う前にジャーナルに書き込み、次の起動時に前回の実行が残したものを元に戻します。それが終わるまでトンネルは接続されず、Turnoutはまだ残っているものを“今すぐ復元”と一緒に表示します。

“Turnout” › “ネットワーク設定を修復…”で、いつでも同じことを行えます。サービスが動いていない場合は管理者パスワードを求め、自分でジャーナルをたどって元に戻します。

ネットワーク接続

アップデートのために、アプリ自体は2か所に接続します。新しいバージョンがあるかを確かめるGitHubと、インストール数を数えるGoogle Analyticsです。ライセンスのためには、購入後はPolarに、そしてあなたのiCloudアカウントに接続します。いつ何を送るかは、下のライセンスにあります。

  • 自動で確認するのは/Applicationsにあるコピーだけで、メニューかウインドウを開いたときに、多くても1時間に1回です。“Turnout” › “アップデートを確認…”は、選べばいつでも確認します。
  • 確認では、GitHub上のこのプロジェクトの最新リリースにある小さなファイルを取得します。アカウントは使わず、あなたやトンネルに関する情報も含みません。GitHubに見えるのは、そのリクエストとあなたのIPアドレスです。
  • 確認のたびに、アプリはGoogle Analyticsにイベントを1件送ります(www.google-analytics.com、Measurement Protocol経由)。内容は、Turnoutが最初の使用時に作って環境設定に保存するランダムなインストールID(ハードウェアから導いたものではありません)、Turnoutのバージョンとビルド、macOSのバージョン、プロセッサのアーキテクチャ、システムの言語、そしてGoogle Analyticsが数えるのに必要な2つの項目(Turnoutの起動時刻から取ったセッション番号と、固定のエンゲージメント時間)です。トンネル、サーバー、鍵、ネットワークに関する情報は含まず、アカウントやユーザIDもありません。Googleに見えるのはそのリクエストとあなたのIPアドレスで、Googleのプライバシーポリシーが適用されます。
  • “一般”(“Turnout” › “設定…”)で“アップデートを自動的に確認”をオフにすると、自動の確認とこの報告の両方が止まります。“アップデートを確認…”は選べば確認しますが、報告は送りません。
  • アップデートをインストールする場合、インストーラは同じリリースから取得され、TurnoutはそのチェックサムとDeveloper IDの署名を確認してから、macOSのインストーラに渡します。

トンネルは構成に書かれたサーバーに接続し、フックはあなたが書いたとおりに動きます。それ以外に、アプリもサービスもどこにも接続しません。独自のクラッシュレポートも、広告も、アカウントもありません。

ライセンス

Turnoutは、Macごとに7日間の試用期間中すべての機能が使え、希望すればさらに7日間、1回だけ延長できます。その後、トンネルの接続にはライセンスが必要です。必要なのは接続だけです。接続中のトンネルは接続されたままで、接続解除、編集、読み込み、書き出し、“ネットワーク設定を修復…”、アンインストールはいつでも使えます。ライセンスを理由に接続が切られることはありません。

ライセンスの処理はアプリの中だけで行います。バックグラウンドサービスはライセンスについて何も知らず、PolarにもiCloudにも接続しません。

  • 試用期間中はライセンスの確認を行いません。試用の日付は、このMacのキーチェーンのcc.ctsite.turnout.licenseという項目に保存されます。Turnoutをアンインストールしても残るので、インストールし直しても試用が始まり直すことはありません。
  • 購入後、アプリはPolarのライセンスサービスapi.polar.shに、次のときに接続します。このMacのライセンス認証のとき(ライセンスキー、Macに付けた名前、機種ID、macOSとTurnoutのバージョン、ハードウェア識別子から計算した一方向のハッシュ)、週に1回程度メニューかウインドウを開いたときと手動で確認したとき(ライセンスキー、このMacの認証ID、ハッシュ)、そしてMacを外すとき(ライセンスキーとそのMacの認証ID)です。アカウントはなく、トンネルに関する情報も含みません。
  • Polarに接続できなくても何も変わりません。ライセンス認証済みのMacは、どれだけ長くオフラインでも接続でき、“ライセンス”パネルが最後にライセンスを確認できた日を示すだけです。
  • ライセンスキーと、それを使っているMacの一覧は、あなたのiCloudアカウントのTurnout用の領域(CloudKit)にレコードとして保存されます。そのため、同じアカウントにサインインしているほかのMacがライセンスを見つけ、クリック1回で使えます。アプリは起動したときと、メニューかウインドウを開いたときにこれを読み、書き込むのは認証、確認、削除のあとだけです。Appleの標準のiCloud保護で保存されますが、エンドツーエンドで暗号化されてはいません。iCloudにサインインしていないMacでは何も同期されないので、そのMacではキーを手で入力します。

送られるものと送り先の一覧はプライバシーポリシーに、条項はライセンス条項にあります。

位置情報とWi-Fiルール

Wi-Fiルール(#@ OnWiFi)には、Macが接続しているネットワークの名前が必要です。macOSはその名前を位置情報として扱うので、位置情報へのアクセスを持つアプリしか読めません。TurnoutはWi-Fiルールを設定するときにアクセスを求め、起動時に求めることはありません。使うのはネットワークの名前だけで、あなたの居場所には使いません。並べた名前はMac上の構成ファイルに残ります。アクセスがなければ、Wi-Fiルールは何もしません。

ログ

/Library/Logs/cc.ctsite.turnout.daemon.log
バックグラウンドサービスが行ったことと、そのエラー。
/Library/Logs/cc.ctsite.turnout.update.log
アップデートをインストールしたときに書き込まれます。

“ヘルプ” › “Finderでログを表示”で、両方のファイルを表示できます。アプリ自体のメッセージはシステムログにあります:

/usr/bin/log show --predicate 'subsystem == "cc.ctsite.turnout"' --last 1h

zshでは、ただのlogは別の組み込みコマンドなので、フルパスで入力してください。

自分で確かめる

launchctl print system/cc.ctsite.turnout.daemon   # launchdから見たサービス
ls -l /Applications/Turnout.app/Contents/MacOS/    # Turnoutとturnout-daemon
cat /Applications/Turnout.app/Contents/Resources/uninstall.sh
defaults read cc.ctsite.turnout analyticsClientID  # ランダムなインストールID
netstat -rn
networksetup -getdnsservers Wi-Fi

アンインストーラは、アプリの中にあるシェルスクリプトです。実行する前に読んでみてください。

アンインストール

方法は3つあり、どれも同じスクリプトを実行します:

  • Turnoutのウインドウを開いた状態で、“Turnout” › “Turnoutをアンインストール…”を選びます。確認で“保存済みのトンネルとその秘密鍵も削除”を選ぶと、それらも削除されます。ライセンス認証済みのMacでは、先にこのMacをライセンスから外し、iCloudアカウントにあるレコードも削除します(確認のときに外さないことも選べます)。
  • インストーラを開き、インストールする項目の一覧でRemove Turnoutを選びます。保存済みのトンネルも削除するなら、Delete saved tunnelsも選びます(インストーラは今のところ英語のみです)。
  • “ターミナル”で実行します(--purgeを付けると、保存済みのトンネルも削除します):
    sudo sh /Applications/Turnout.app/Contents/Resources/uninstall.sh

どの方法でも、すべてのトンネルの接続を解除し(ルートとDNSも元に戻ります)、バックグラウンドサービスをログイン項目から外し、クラッシュしたサービスが残したものを元に戻し、アプリ、ログ、インストーラのレシート、そして全ユーザのTurnoutの環境設定、ウインドウの状態、キャッシュを削除します。/Library/Application Support/cc.ctsite.turnoutにある保存済みのトンネルと秘密鍵は、削除を選ばない限り残ります。

キーチェーンのライセンスの項目は残るので、インストールし直しても試用が始まり直すことはありません。ライセンスキーも、ほかのMacのためにiCloudアカウントに残ります。インストーラとターミナルのスクリプトはrootとして動き、あなたのキーチェーンやiCloudアカウントには触れないため、このMacをライセンスから外すことはできません。先に“ライセンス”パネルで外すか、あとで別のMacかPolarのカスタマーポータルで外してください。