VPNは接続し、メニューバーにも表示され、それでも内部ホストはタイムアウトします。この状況では原因の候補が三つあり、どれが当てはまるかはトンネルの設定方法によって決まります。ルートコマンドがネットワークアドレスを要する場所でホストアドレスを使ったか、プロファイル自体が判断を飲み込む既定ルートをインストールしているか、あるいはクライアントがプロファイルのキーではなくフックを必要とするPPPトンネルです。この順に確認してください。最初のものを除外するのが最も安く済みます。

宛先はネットワークアドレスで、マスクがプレフィックスを表す

networksetup -setadditionalroutes は宛先、サブネットマスク、ゲートウェイの三つ組を受け取ります。内部サブネットを一つトンネル経由で送る呼び出しは次のようになります。

sudo networksetup -setadditionalroutes "VPN (L2TP)" 192.168.1.0 255.255.255.0 10.2.0.0

宛先が何かを確認してください。ネットワークアドレスであり、到達しようとしているサーバーのアドレスではありません。この記事のきっかけになった事例では、その位置に 192.168.1.20 を置いた同じコマンドは何の役にも立たず、192.168.1.0 に置き換えるとすぐに機能しました。マスクもゲートウェイも同じで、違うのは数字一つだけです。これが失敗の全体を縮小したものです。

理由はポリシーではなく算術です。/24 マスクと組にしたホストアドレスは 192.168.1.0/24 を表しません。ルーティングテーブルが有効に保持できないものを表すため、エントリは拒否されるか無視され、トンネルは意図より少ないものしか運びません。

ホストをちょうど一つだけ望む場合は、ホストアドレスに 255.255.255.255 のマスクを組み合わせます。誤りになるのは混在した組であり、ホストアドレスの使用そのものではありません。一つのアドレスから作る /32 は正当なルートで、一つのアドレスから作る /24 は誤りです。

呼び出しはリストを置き換え、名前はそのまま使う

最初の試行で人は二つの挙動に驚きます。コマンドは追加ではなく追加ルートのリスト全体を設定するため、一つのプレフィックスを加える呼び出しは以前あった他のものを黙って削除します。集合全体を一回の呼び出しで組み立ててください。

サービス名も、あなたが考えたラベルではありません。ツールから読み取り、種類の接尾辞も含めて正確にコピーしてください。

networksetup -listallnetworkservices

一文字でも違う名前は、読む価値のあるエラーもルートも生みません。ここで正しい手法はコピーアンドペーストであり、記憶から打ち直すことではありません。

プロファイルが既定ルートを主張するとき

分割ルートは、明示的にカバーしていないあらゆる宛先について既定ルートに負けます。フルトンネル用に設定された L2TP プロファイルはまさにそれをインストールします。プロファイルがすべてトンネル経由だと述べているなら、追加ルートのリストはほとんど意味を持ちません。あなたのエントリは誤りではなく、決して名指ししない宛先にとって単に無関係なだけです。この制御は通常、どのルートコマンドではなく、プロファイルの全トラフィック送信設定にあります。

さらにエントリを編集する前に、本当に欲しいモデルを決めてください。例外付きのフルトンネルは、特定のプレフィックスを持つ分割トンネルとは別の構成であり、両者を混ぜると誰も予測できない表になります。

組織がフルトンネルを要求するなら、ローカルで分割しようとするのをやめ、要件をポリシーの所有者に持ち込んでください。それに反するローカル追加ルートは、いずれにせよ次のプロファイル更新で削除されます。

PPPトンネルにはキーではなくフックが必要

PPPベースのトンネルでは、defaultroute が既定ルートを作るプロファイルキーで、外せばクライアントはあらゆる宛先を主張しなくなります。その後、インターフェースが現れてからルートを追加します。通常は /etc/ppp/ip-up からです。

#!/bin/sh
/sbin/route add -net 192.168.1.0 -interface ppp0

スクリプトはroot所有で実行可能に保ち、マシンに複数のトンネルプロファイルがある場合はインターフェース名に対するガードを追加してください。すべてのPPPリンクで動き、一つのデバイス名を前提にするフックは、寿命の長い小さなバグです。

三つのリクエストで分割を検証する

接続した状態で表を取得し、どのインターフェースがトンネルを担うか記録します。そのうえで、作成したコマンドの終了ステータスを信じるのではなく、具体的な宛先を確認してください。終了コードが示すのは、ツールが引数を受け付けたかどうかであり、通信が意図した経路を通るかどうかではありません。

分割を証明する三つのリクエストで締めくくります。アドレスによる内部ホスト一つ、内部リゾルバー経由の内部名一つ、そして今もローカル接続を使うべき公開サイト一つです。公開サイトも今トンネルを通るなら、ルートリストが何を言っているように見えても、分割は起きていません。

もう一度再接続して内部リクエストを繰り返すのは、手で追加したルートが、それを有効にしたインターフェースより長く生き残り、トンネルが切れた後に通信を静かにブラックホール化することがあるからです。

関連記事