二つの設計は同じことを約束する。トンネルが落ちたとき、平文のまま外へ出るものはない。一方は切断時にスクリプトを実行してインターフェースを切る。もう一方はファイアウォール規則を有効なまま残し、VPN クライアントには何も求めない。違いは、誰に行為の権限があるか、隙間の間に何が起きるか、その後マシンがどうやって再びオンラインに戻るかにある。この三点で比べるほうが、どちらが厳しいかを論じるより役に立つ。

同じ仕事を二つの仕組みで

クライアントは、プロファイルがスクリプト実行を許していれば、トンネル確立時と切断時にフックを実行できる。そのフックはクライアントのライフサイクルの中で、接続が閉じるまさにその瞬間に走る。これに対してファイアウォール規則はシステムに属し、クライアントが動いていても、落ちても、強制終了されても関係しない。

PropertyTeardown scriptFirewall unit
Runs when the client is killedNoYes
Needs privilege at teardown timeUsually yesConfigured once, at boot
Acts on the whole machineOften, including recovery pathsOnly on the flows it matches

この表が論点のすべてだ。正常な終了でしか走らないスクリプトは、最も心配していなかった事例を覆うだけである。重要なのはクラッシュやネットワークの消失であり、どちらもきれいな切断を生まない。

切断フックにできることとできないこと

文書化されたパターンはネットワークインターフェースをたどり、loopback 以外をすべて落とす。物理デバイスが落ちていれば、トンネルの外へ逃げられるものは何もなく、まさにそれが狙いである。

#!/bin/sh
for dev in /sys/class/net/*; do
  name=$(basename "$dev")
  [ "$name" = lo ] || ip link set dev "$name" down
done

これはローカルネットワーク、マシンが提供するあらゆるサービス、そして問題を直すために使う経路まで落とす。ノート PC では後から無線デバイスを手動で切り替える必要があることもあり、短い障害が修理作業になってしまう。さらに悪いことに、フックにそれが許されない場合がある。クライアントが権限を落とすと、切断スクリプトは非特権アカウントで走り、インターフェースの変更はすべて権限エラーで失敗する。そのエラーは誰もログを読まないまさにその瞬間に書かれる。

フックを信じる前に、クライアントがどう起動されるかを確認しよう。root で手動実行すれば動くスクリプトは、起動時に始まるサービスについて何も証明しない。

ファイアウォール規則が違う点

トンネルの通信だけを許可する規則は、クライアントのプロセスが消えても効き続ける。カーネルはそのプロセスに依存しないからだ。規則はより狭くもあり、一致するフローだけを遮断し、loopback、ローカルサブネット、復旧経路には手を出さない。だからマシンを孤立させない。

代償は、規則をホストのファイアウォールの持ち主が書き、維持しなければならないことであり、規則は クライアントが実際に作るトンネルデバイスを名指ししなければならない。つまり規則とプロファイルは一緒に保守する必要がある。名前を変えたインターフェースは、すべてを遮断して何も説明しないファイアウォールを残す。

どちらの仕組みも他方を不要にしない。編集後に一度も再読み込みされないファイアウォール規則は、決して走らないスクリプトと同じくらい絵空事である。

隙間ができるかどうかは persist-tun が決める

トンネルデバイスが切断後も残れば、そこへ向かう経路も残る。そのとき通信は転送されずに破棄されるので、既定経路が物理ゲートウェイへ戻ることはない。この振る舞いが、ファイアウォール規則が関与する前から漏えいを起こりにくくしている。

この設定がなければデバイスは経路ごと取り除かれ、既定経路は物理ゲートウェイへ戻りうる。戻るかどうかはプラットフォームとクライアント次第であり、だからこそ状態は仮定せず観察しなければならない。この設定は性能の選択肢ではなく、kill switch の一部として扱うこと。

再接続の経路を生かしたまま、四つの状態を試す

厳格な遮断はクライアントの再接続も妨げうる。他のすべてが拒否されるなかで、クライアントは物理ゲートウェイ経由でサーバーへの経路をなお必要とするからだ。トンネルが上がる前にその一つのアドレス向けのホスト経路を入れ、先に名前を解決しておくこと。必要になる頃には DNS が遮断されているかもしれない。

ip route add 198.51.100.20/32 via 192.168.0.1 dev wlan0

次にラベルではなく状態を確かめる。四つの瞬間を意図的に試す。トンネルなしのコールドスタート、健全なセッション、誰も要求していない切断、そして復旧後のセッションだ。どの瞬間にも既定経路を読み、出口アドレスが見える要求を一つ出す。トンネルが落ちている間に諦めるアプリケーションは、メールクライアントや更新プログラムについて何も語らない。だから最後の確認はバックグラウンドのアプリケーション一つで繰り返す。規則とインターフェース名と復旧手順を書き留めておくこと。誰も検証できない kill switch は噂にすぎない。

関連記事