トンネルは消え、ネットワークアイコンは正常に見えるのに、何も読み込めない。VPNを切断し、アンインストールし、あるいは再起動したのに、切断時に身を守るはずだったブロックがまだ残っている。クライアントの画面では説明できない。ブロックしているのはクライアントではないからだ。判断はあなたの名前でカーネルに書き込まれ、それを取り除くものは何も残されていない。Windowsではその状態はWindows Filtering Platformにあり、Linuxではiptablesやnftablesのルールセットで、起動時に再生されるスナップショットを伴うことが多い。以下は私が使う順序だ。状態を読み、障害を説明する最も狭い対象を削除し、それを何度も戻してくるものを探す。

キルスイッチは設定ではなくカーネルの状態

デスクトップクライアントは、トンネル外の通信を拒否するフィルターを追加してブロックを実装する。Windowsではconnect-redirect層とtransport層のWFPフィルターで、一部は永続的だ。Base Filtering Engineのポリシーストアに記録され、VPNソフトウェアが動く前のマシン起動時に復元される。クライアントによって後片付けの時期は違う。切断時にフィルターを外すもの、正常終了時だけ外すもの、先にキルスイッチをオフにした場合だけ外すものがある。ブロックが有効なままアンインストールするか、プロセスを終了すると、フィルターは残る。

Linuxでの相当物は、出力経路のdropまたはrejectルール、ときに転送ルール、ときに変更されたチェーンポリシーだ。これらのルールはカーネルの状態なので、追加したプロセスより長生きする。クライアントを終了しても、クラッシュさせても、電源を切っても、カーネルはパケットを破棄し続け、取り消すものは残らない。永続化パッケージは現在のルールセットをスナップショットして起動時に復元することで、第二の永続層を加える。次の起動はブロックがすでに入った状態で始まる。

削除する前にWFPの状態を読む

Windowsには必要なツールが同梱されている。管理者権限のプロンプトでプラットフォームの状態をダンプする。ダンプは作業ディレクトリに wfpstate.xml として出力される。

netsh wfp show state
netsh wfp show filters
Get-Service bfe

XML内で、去ったベンダー名、Blockアクション、レイヤーを検索する。通常の通信を壊すのはconnect-redirectとtransportのフィルターだ。receive-accept層のフィルターが原因であることは通常ない。Base Filtering Engineが全く動いていなければ、別の場所を探す。それ以外にこれらのフィルターを実行できるものはない。

通常のファイアウォール表示も突き合わせる。ほとんどの人は二つのうち片方しか調べない。

netsh advfirewall show allprofiles
Get-NetFirewallProfile | Select-Object Name,Enabled,DefaultInboundAction

組み込みプロファイルが有効で、失敗している通信に一致するルールがなければ、ブロックはWindows Firewallではなくサードパーティのプロバイダーから来ている。この区別が、修復にどのツールを使うかを決める。

削除に使う構文でLinuxルールを読む

iptables -S は追加時と同じ形式でルールを出力するので、その出力は削除にそのまま再利用できる。iptables -L -v -n はパケットカウンターを追加し、そのカウンターは、ルールが失敗したリクエストに実際に一致しているのか、単にチェーンに座っているだけなのかを教えてくれる。

sudo iptables -S
sudo ip6tables -S
sudo iptables -t nat -S

ルールだけでなくチェーンポリシーも読む。-P OUTPUT DROP はルールが一致しなくても通信をブロックする。IPv6は別に調べる。両方のファミリーを導入したクライアントは、IPv4ルールが消えた後もIPv6のブロックを残すことがあり、症状はアプリケーションがどちらのファミリーを好むかで変わる。nftablesを使っている場合は nft list ruleset も実行する。二つのツールは互換層で共存しており、一方の一覧がパケットを落とせるすべてのルールを示すとは限らない。

障害を説明する最も狭い対象を削除する

Windowsでは最初の手順は今もベンダー自身の削除経路だ。インストーラーを再実行してrepairかuninstallを使うか、ベンダーが公開していればクリーンアップツールを実行する。残ったサービスやスケジュールタスクはよくあることで、ログオン時にクライアントを起動するタスクは次の起動でフィルターを再インストールする。クライアントのレジストリキーを読む段階で失敗するアンインストールは、通常、サービスかタスクがまだそれを保持しているという意味で、レジストリが壊れているわけではない。

Get-ScheduledTask | Where-Object TaskName -like '*vpn*'
Get-Service | Where-Object DisplayName -like '*vpn*'

永続フィルターは最後の手段だ。HKLM\SYSTEM\CurrentControlSet\Services\BFE\Parameters\Policy\Persistent\Filter の下にあり、フィルターごとにGUIDでキー付けされた値が一つある。まずキーをエクスポートし、削除するGUIDを記録し、去ったクライアントに属する値だけを削除してから再起動し、エンジンに状態を再構築させる。キー全体を削除せず、Base Filtering Engineも無効にしない。Windows FirewallとDefenderが依存しており、一つの障害をより悪い障害と交換することになる。

reg export "HKLM\SYSTEM\CurrentControlSet\Services\BFE\Parameters\Policy\Persistent" C:\temp\bfe-backup.reg

Linuxでは iptables -S が出力した行を取り、-A を -D に置き換える。特定した一つのルールを削除する方が、チェーンをフラッシュするより優れている。自分のポリシーがそのまま残るからだ。

sudo iptables -D OUTPUT -p udp -j REJECT

dropがユーザー定義チェーンにあるなら、まずそのチェーンへのジャンプを削除し、後で -X でチェーンを削除する。dropルールが残っているのにチェーンポリシーをACCEPTにしても、ポリシー判断まで到達するパケットにしか効かない。すべてのテーブルをフラッシュするのは最後の手段だ。他の理由で追加したルールも消え、ufwが有効なら、存在しないチェーンを所有しているとサービスに思わせてしまう。

元に戻す持ち主を探す

当面の修復の後、状態を復元するものを探す。Linuxでは、永続化ユニットが有効か、クライアントにログイン時にファイアウォールを復元する設定があるか、/etc の下に保存されたルールファイルがあるかを確認する。Windowsでは起動エントリ、サービス、スケジュールタスクを再度確認し、再起動して以前と同じコマンドで状態を読み直す。

ブロックが戻るなら、削除は解決ではなかった。持ち主が解決だ。どのクライアントやサービスがインストールするかを記録し、そこで機能を無効にする。切断のたびにファイアウォール層で戦うのではなく。

単発のpingではなく実際の通信で検証する

名前解決、TCP接続、新しいブラウザーセッションを試し、再起動して同じ三つの確認を繰り返す。HTTPSが失敗するのにpingが通るなら、ネットワークではなくtransport層のフィルターを指す。再起動後にだけ再び現れるブロックは、まだ見つけていない持ち主を指す。

証拠を残す。エクスポートしたBFEキー、または変更前に取得した iptables -S の出力だ。修正済みと言う前に、対象を削除した層、再インストールしうる持ち主、きれいに一度再起動した後の状態、VPNプロセスが動いていなくても通常のブラウジングが機能することを確認する。iptables(8) のマニュアルページには、クリーンアップをスクリプト化する場合の正確な削除とポリシーの構文がある。

関連記事