ルーターの VPN は機能するが LAN クライアントはインターネットに出られない
ルーター自体はトンネル経由でインターネットに到達するのに、背後の機器は到達できない。転送・変換・戻り経路はそれぞれ別の許可である。
ステータスはトンネルが稼働中と告げ、ルーター自身のブラウザーはページを読み込むのに、その後ろの機器はどれもタイムアウトする。この組み合わせは、多くの VPN 解説が決して触れない層へ問題を絞り込む。つまり、トンネルを通過させるべきパケットを持つホストはルーターだけではない。ローカルで生成されたトラフィックと転送されるトラフィックは、同じ筐体の中で別々の経路を通る。クライアントから試せば、その違いは理論ではなくなる。
LAN ホストから障害を読む
失敗している機器から始める。ルーター上で診断を走らせても、別の問いに答えることになるからだ。クライアントのデフォルトゲートウェイがこのルーターであることを確認し、その送信元アドレスとサブネットを記録してから、ルーターのトンネルインターフェースから何が出ていくかを見る。
クライアントのアドレスが変換されていれば、遠端にはトンネルのアドレスが見え、そこからはすべて健全に見えるのにクライアントは失敗し続ける。変換されていなければ、遠端はクライアントのサブネットへの戻り経路を知っている必要があり、多くのゲートウェイには既定でその経路がない。いずれにせよルーター自身の成功は無関係だ。そのパケットはローカルで生成され、転送経路を一度も通っていないからだ。
ローカルトラフィックと転送トラフィックは別物
Linux とほとんどのルーターファームウェアは、筐体自身が生成したパケットと、筐体を通過するパケットを別様に扱う。出力チェーンは前者を見て、転送チェーンは後者を見る。そして、ルーター自身のトラフィック向けに調整されたポリシーは転送を手つかずのまま残しうる。
sysctl net.ipv4.ip_forward
ip -4 address show br-lan
ip route get 203.0.113.9
nft list ruleset | grep -A 6 'chain forward'
まず転送が有効になっているか確認し、次に出力チェーンではなく転送チェーンを読む。暗号化された外側の接続を許可するルールは、復号されたパケットの転送を許可するルールではない。両者を混同すると、まさにこの症状が生じる。トンネルが稼働していることは前者だけを証明する。
戻り経路も存在しなければならない
送信元変換は、戻り経路が必要かどうかを決める。トンネルインターフェースでマスカレードしていれば、応答はトンネルのアドレスに戻り、ルーターがそれを変換解除する。していなければ、遠端のゲートウェイはクライアントのサブネットへの明示的な経路を必要とし、そのポリシーもその方向を許可しなければならない。
何かを変更する前に、配備がどちらの設計を使っているかを記録する。修復の方向が正反対だからだ。変換を追加すると、欠けている戻り経路が隠れ、元の送信元アドレスを必要とするアプリケーションが壊れる。変換なしで戻り経路を追加すると、遠端のファイアウォールが見慣れない送信元を落としたときに静かに失敗する。一方を選び、文書化し、もう一方を合わせる。
クライアントの DNS も同じレビューに含まれる。ルーターのリゾルバーは応答できても、別のサーバーを向いたクライアントは何も得られないことがある。
許可されるフローと拒否されるフローを一つずつ検証する
修正後は、既存のルーターのセッションではなく、クライアントから新しい接続を試す。次に、トンネルを使うべきでないセグメントが依然として使っていないことを確認する。
curl -sS --max-time 8 https://api.ipify.org
ip route get 203.0.113.9
dig +short intranet.example.net
遠端で観測される送信元アドレスを確認する。どちらの設計が実際に動いているかが分かるからだ。名前解決もアドレスと併せて検証する。リゾルバーの挙動は同じ筐体を通る別の経路だからだ。
ルールはトンネルを必要とするクライアントネットワークに限定し続け、一つのテストを通すために転送フィルターを無効にしない。その変更はテストを直すが、トンネルが提供すべき境界を取り除いてしまう。送信元アドレス、変換の判断、戻り経路を一つのメモに書き、日付を添える。