サーバーはルートをプッシュしたと言い、クライアントは接続済みだと言い、それでも宛先には到達できない。まさにこの光景を生む原因は三つある。デバイスが存在する前にルート追加が実行された、クライアントにテーブルを変更する権限がなかった、あるいはポリシーがクライアントにプッシュ済みオプションを無視するよう命じた、である。

外から見ると同一に見えるが、必要な修正は異なる。ルートの判断が下される箇所でクライアントのログを読む。

ルートが壊れているのではなく存在しないことを証明する

まずルートが壊れているのではなく存在しないことを証明する。Linux では ip route show dev tun0 がクライアントがトンネルデバイスに設定した内容を一覧表示する。Windows では route print または Get-NetRoute が同じ内容を表形式で示す。

ルートが存在してもトラフィックを転送しないのは別の問題である。それは調査を転送とファイアウォールの規則へ移し、ルートの設定へは向けない。

タイミング:デバイスが存在する前に追加が実行された

クライアントは制御チャネルが上がり、インターフェースを設定した後に、サーバーの PUSH_REPLY を解析する。その後になって初めて、プラットフォームが提供する仕組みでルーティングテーブルに触れる。Linux は netlink を通り、Windows は昇格したトークンを必要とする API を使う。構成を読むやいなやルートを追加するスクリプトやクライアントは、TUN/TAP デバイスが存在する前に動くことがあり、カーネルは追加を拒否する。

同じ競合が、入力するころにはインターフェースが上がっているために手入力のルートは機能し自動のルートは機能しない理由を説明する。

route-delay はこの場合のために存在し、route-up はインターフェースとルートが設定された後に走るスクリプトを指定する。トンネルアドレスに依存するルートは、早い段階ではなくそのフックに置く。

権限:誰がテーブルを変更できるか

Windows のルーティングテーブルを変更するには昇格したトークンが必要だ。標準ユーザーが起動した GUI は、サービス経由でアダプターのアドレスを設定できても、ルートを追加できないことがある。その場合ログには、プッシュが欠けているのではなく、アクセス拒否風のエラーが出る。

GUI を管理者として起動するか、サービスベースのクライアントを使えば、その結果は変わる。必要なトークンなしでクライアントを起動するスケジュールタスクでは変わらない。

何かを変える前に、クライアントが実際にどのアカウントで動いているかを確認する。バージョンとサービスのモードが、どの原因がそもそも可能かを決めるので、両方をルートの出力の横に記録する。

ポリシー:プッシュされたルートは意図的に捨てられる

route-nopull は、トンネルアドレスは依然として受け入れつつ、サーバーがプッシュするルート(プッシュされたデフォルトルートを含む)をクライアントに無視させる。プッシュされた DNS と DHCP のオプションも同じ指示で捨てられる。そのようなクライアントは故障ではなく、自分の構成に明示的なルート行を期待しているのだ。

route-noexec は別の制御で、クライアントがルート変更を一切実行しないようにする。クライアントが対応付けできないトポロジーでも同様の結果になり、ルートは追加ではなく拒否として記録される。三つのどれが当てはまるかを推測するのではなく、判断を報告するログ行を読む。その後で、インポーターや管理ツールがユーザーが編集したことのないオプションを追加している場合があるため、有効なプロファイルを確認する。

テキストエディターできれいに見えるプロファイルでも、実行時に追加された指示を抱えていることがある。

プッシュ一覧とテーブルを比較する

接続後に、サーバーのプッシュ一覧をクライアントのテーブルの横に置く。Linux では ip route show dev tun0、Windows では route print または Get-NetRoute だ。ルートが存在しなければ、まず設定を直す。存在するのにトラフィックが失敗するなら、転送とファイアウォールのポリシーへ進む。

クライアントのバージョン、動いているアカウント、サービスベースかどうかを記録する。この三つの事実が、どの原因が除外されたかを次の人に伝える。

関連記事