redirect-gateway をプロファイルに入れて接続すると、マシンの既定ルートは消えることも、二つに分かれることも、元の場所にそのまま残ることもある。決め手は、誰も二度は読まないフラグだ。このオプションが変えるのはルーティング状態だけで他は何も変えないので、何をしたかの信頼できる証拠は接続後にクライアントが入れたテーブルだけになる。以下では、接続後のテーブル、トンネル自体を生かし続けるルート、そしてこの指示が決して覆うと主張しない IPv6 トラフィックを見ていく。どの手順もトンネルが上がっている間にクライアントで実行できるコマンドだ。

各フラグが既定ルートに何をするか

フラグを一つも付けなければ、このオプションは通常の既定ルートを削除し、その場所にトンネルを置く。そのため接続中は古いゲートウェイがテーブルから消える。def1 を足すとその既定ルートは一覧に残り、代わりに二本の狭いルートが仕事をする。bypass-dhcp を足すと DHCP ルートも残る。クライアントがまだローカルの DHCP サーバーに届く必要があるネットワークではこれが効いてくる。OpenVPN 2.6 のマニュアルページのフラグ一覧は一度読むには十分短く、どの項目もテーブルに残るルートを変える。

プッシュされたオプションも届けば同じように振る舞うので、クライアントのプロファイルに何もなくてもテーブルは完全にリダイレクトされたように見えることがある。これは正常で、サーバーがフラグを送り、クライアントが適用し、ローカルのファイルはその指示に一切触れていない。プッシュが何もしていないように見えるときは、引き出されたオプションを受け入れるか捨てるクライアント側のフィルターを確認する。捨てられたオプションはどちらの端でもエラーを出さない。

def1 は既定ルートに触れずに具体性で勝つ

二つの半既定ルートが合わせて IPv4 空間を覆う。0.0.0.0/1 と 128.0.0.0/1 だ。どちらも 0.0.0.0/0 より具体的なので、検索はこちらを優先し、本当の既定ルートは最も具体的でない一致を求めるもののためにテーブルに残る。

プロファイルではなくテーブルを読むこと、どちらの場合なのかを示すのはテーブルだけだ。二行あれば見分けられる:

ip route show default
ip route show | grep -E '^(0\.0\.0\.0/1|128\.0\.0\.0/1)'

各行の宛先だけでなく、インターフェースとメトリックにも注目する。トンネルを指す既定ルートと、トンネルを指す二本の半既定ルートの組は同じ意図を表すが、トンネルが落ちたときの失敗の仕方が違う。一方にはフォールバックがまだ残っているからだ。両方の項目を変更記録に書く。残ったフォールバックが、トンネルを直すのに十分な時間だけ遠隔セッションを生かすこともあり、意図が完全なトンネルだったときには情報が漏れる原因にもなる。

トンネルの終端に到達できる状態を保つ

クライアントには、自分ではトンネルを通らない、トンネルの遠い側へのルートが要る。OpenVPN は他の何かを変える前にそのホストルートを入れるが、手動のルート編集や二台目の VPN クライアントがそれを外してしまうことがある。その後の症状は、接続済みと報告しながら何も通さない接続だ。

トンネルが上がっている間に、終端アドレスにはどのインターフェースを使うかをカーネルに尋ねる。答えは物理インターフェースとそのゲートウェイを示すべきで、決して tun0 であってはならない:

ip route get 198.51.100.20

その検索がトンネルデバイスを返すなら、トンネルが自分の転送を運んでおり、パケットを外に出す必要が生じた瞬間に崩れる。ローカルのプレフィックス、二枚目のアダプター、ポリシールーティングはここでも効いてくる。だからきれいなノート PC で動くリダイレクトが、管理用インターフェースと二つの既定ルートを持つホストでは失敗することがある。たいていはプロファイルのせいにされるが、実際にやったのはアドレス計画だ。

IPv6 トラフィックは自分のテーブルを使い続ける

IPv4 をリダイレクトしても IPv6 はそのまま残り、二つのファミリーは別々のフラグで変わる。v6 の既定ルートが機能するデュアルスタックのホストでは、v4 のトラフィックが完全にトンネルの中に収まる一方、v6 対応の宛先はすべて物理リンクから出ていく。片方のテーブルで正しく見えるホストが、もう片方では漏れている。

トンネルが覆ったと決めつけず、接続後に v6 テーブルを確認する。この指示がアドレスファミリーのフラグを持つのはまさにこの理由で、それを省いたプロファイルはプラットフォームの既定の振る舞いを引き継ぐ:

ip -6 route show default
ip -6 route get 2001:db8::10

アプリケーションがどのインターフェースを使うかを証明する

接続済みという状態はブロックではなく、ルートの変更はキルスイッチでもない。トンネルが落ちたときに直接のトラフィックを止める必要があるなら、その方針はファイアウォールにあり、独自の試験が必要だ。

プロファイルが示す経路ではなく、アプリケーションが実際に通る経路を試す。まずルートを尋ね、次に各インターフェースへ順にリクエストを結び付け、遠い側が何を報告するか比べる:

ip route get 203.0.113.10
curl -s --interface tun0 https://ifconfig.me
curl -s --interface eth0 https://ifconfig.me

両方のリクエストが同じアドレスを返すなら、ルーティングテーブルがそうすべきと言っていても、アプリケーションはトンネルを使っていない。トンネルに結び付けたリクエストだけが成功するなら、その宛先では物理経路がフィルターされており、トンネルは頼んだとおりに動いている。フラグ、入ったルート、終端の検索、両方の出口の結果を変更記録に書き、次の人がスクリーンショットではなく事実を引き継げるようにする。

関連記事