意図はもっともです:一社のドメイン宛ての通信をすべてトンネル経由にし、それ以外はそのままにしたい、というものです。編集している指示はルートを設定するものであり、ルートには照合すべきホスト名という概念がありません。そこにワイルドカードを書こうとすれば、解析エラーになるか、さらに悪いことに、名前が一つのアドレスに解決されたために今日たまたま動いているルートができあがります。二つの異なる仕組みに、互いの仕事をさせようとしているのです。

ルートが設定するもの、そして決して読まないもの

ルートのエントリは、宛先プレフィックスがインターフェース経由で到達可能であることを示します。カーネルはパケットをそれらのプレフィックスと照合するため、関与する識別子はアドレスとマスクだけです。ホスト名が転送の判断に現れることはなく、だからこそそこでパターンを照合することはできません。

OpenVPN は一部のルートパラメータで解決可能な名前を受け付けますが、その寛容さが混乱の源です。名前は設定の適用時に解決され、通常のルートになる一つ以上のアドレスを生み出します。その後、名前は完全に視界から消えます。

つまり、名前から作られたルートはルールではなくスナップショットです。トンネルが起動した瞬間にその名前が解決された先を覆うだけで、変化するホスト群に対して望む挙動とは正反対です。明日移るレコードは、ルートを昨日のまま指し示して残します。

宛先が本当にプレフィックスの場合

対象が既知のプライベートネットワークであれば、プレフィックスを書きます:ドキュメンテーション用の例では、単一のホストとサブネットは次のようになります。

route 10.60.4.20 255.255.255.255
route 10.60.0.0 255.255.0.0

どちらのエントリもアドレスとマスクを指定しており、どちらも名前に依存する部分がないため DNS の変更に耐えます。これが利点のすべてです:ルートは、一度きりの名前解決ではなく、トポロジーについての表明なのです。

一つの DNS 応答から大きなプレフィックスを推測してはいけません。一つのアドレスに解決される一つのホスト名は、その背後のネットワークの大きさを何も教えてくれず、推測したプレフィックスは、誰も意図していなかった通信をトンネルが取り込んでしまう原因になります。名前解決から推測するのではなく、ネットワークの所有者に実際のプレフィックスを尋ねてください。

作業単位がホスト名の場合

ドメインで選別するには、ドメインを読むもの、つまりアプリケーション層のコンポーネントが必要です。通常の答えは、トンネルの向こう側に置く HTTP プロキシで、どのリクエストをそこへ送るかをクライアントが選びます。

プロキシの設定ファイルでその選択を表現できます:以下の例示的なルールは、一つのドメインとそのサブドメインをプロキシへ、それ以外をすべて直接へ送ります。

function FindProxyForURL(url, host) {
    var h = host.toLowerCase();
    if (h === "corp.example" || dnsDomainIs(h, ".corp.example")) {
        return "PROXY 10.60.0.12:3128";
    }
    return "DIRECT";
}

完全一致の比較はドメイン自体を覆い、接尾辞の比較はその子を覆いますが、似た文字で終わるだけの名前には一致しません。どちらも必要で、一方を欠くと正しく見えるのに頂点や偽装を見逃すルールになります。

これらのルールはプロキシを選ぶものであり、プロキシを作るわけでも、オペレーティングシステムのルートを変えるわけでもありません。プロキシのアドレスには依然としてトンネルを通る独自の経路が必要で、直接と記されたリクエストはマシンがすでに持つルーティングポリシーに従います。

プロキシのオプションが覆わないもの

ブラウザのプロキシ設定を無視するプログラムには、このどれも影響しません。コマンドラインツール、アップデータ、独自のネットワークスタックを持つアプリケーションは PAC ファイルではなくルートテーブルを使うため、そうしたケースにはサポートされたアプリケーション単位の仕組みか別の設計が必要です。ブラウザのルールがワークフローを覆うと約束する前に、重要なクライアントを洗い出してください。

直接に戻ることも逃げ道ではありません。マシンのルーティングポリシーがすでにすべてをトンネルへ送っているなら、プロキシの選択とルートテーブルが異なる層で下される別々の判断だから、直接と記されたリクエストはその中にとどまります。

名前解決は三つ目の別の問いです。どのリクエストをプロキシへ送るかを選んでも、どのリゾルバがそれに答えるかは何も分からず、両者を一つの設定として扱うと、外部から誰かが試すまで見えない漏えいが生まれます。各クエリがどこで答えられるかを決め、その決定をプロキシのルールの隣に書き留めてください。トンネルが上がったために変わるリゾルバは、静かに答えを移してしまいます。

両方の経路を試すこと、うまくいく方だけでなく

一致すべきホスト名、一致すべきでないホスト名、そして接尾辞だけのルールが最も見落とすドメインの頂点を試してください。そのうえで、ページが読み込めたかどうかから推測するのではなく、各リクエストが実際にどちらの経路を通ったかを確認してください。

最後に、失敗の分岐を試してください。到達できないプロキシは、黙って直接接続に戻るのではなく、あらかじめ決めた方法で失敗するべきです。ネットワークオプションのリファレンスはルートのパラメータを正確に記述しており、この設計のドメイン側の半分は、完全にその外側にあります。

関連記事