OpenVPN の UDP 応答が誤ったアドレスから出る理由
複数のローカルアドレスを持つ UDP サーバーは、クライアントが接続したアドレスとは別のアドレスから応答することがあります。multihome は対応プラットフォームで送信元を修正します。
OpenVPN クライアントはあるアドレスに接続し、サーバーは別のアドレスから応答するため、トンネルは決して上がりません。サーバーのログにはパケットの到着が残り、キャプチャには応答の送出が写るので、障害はクライアントのせいにされます。複数のインターフェースを持つホストや、一つのインターフェースに複数のアドレスがあるホストでは、どちらのアドレスが使われているかについて双方の認識が単純に食い違います。応答は IP 層では正しいのですが、多くのクライアントは、接続したアドレス以外を送信元とするデータグラムを破棄します。
送信元が変わるとクライアントは何を見るか
特定のローカルアドレスに束縛されていない UDP ソケットには固定の送信元がないため、カーネルは送信時に一つを選びます。その選択はクライアントのアドレスへの経路検索から決まり、送信元は検索が選んだインターフェースのアドレスになります。単一インターフェースのマシンでは選択は見えませんが、管理用アドレス、公開アドレス、同じ NIC 上のセカンダリアドレスを持つホストでは、経路メトリックとポリシーに依存します。ポリシーベースのルーティングは、ルールがクライアントの到達しなかった上流リンクを選べるため、不一致を減らすどころか増やします。あるプロバイダーから学習したデフォルトルートと、別のプロバイダーを指す送信元ルールがあれば、それを生み出すのに十分です。
応答をフィルタリングするクライアントや、正確な四つ組と送信元を期待するコネクション追跡は、有用なメッセージもなく応答を捨てます。するとトンネルは何も届かなかったかのようにタイムアウトし、だからこそこれはクライアント側のファイアウォール問題と誤解されます。サーバーだけで取得したキャプチャは、応答が本当に出ていく以上、原因を説明するのではなく誤りを裏付けます。ほかの何かを変える前に、応答の送信元とクライアントが接続したアドレスを比べてください。
multihome オプションが実際に行うこと
このディレクティブは設定ファイルでは multihome、コマンドラインでは --multihome と書き、クライアントのパケットが届いたアドレスから UDP サーバーに応答させます。カーネルは受信時に元の宛先アドレスを補助データとして渡し、OpenVPN はその値を使い回して応答の送信元にします。こうしてワイルドカードアドレスで待ち受けるサーバーは、IPv4 なら local 0.0.0.0、IPv6 ならその相当値を使うことで、各クライアントが専用のリスナーに届いたかのように振る舞います。公開アドレス経由で来たクライアントには公開アドレスから応答し、内部アドレスのクライアントにはそのアドレスから応答します。パケット経路のほかの何も動かず、経路、フィルタルール、トンネル設定はそっくりそのまま残ります。
この最後の性質のおかげで、このオプションはほかの点で正常に動くサーバーに安全に追加でき、同時に、一つのアドレスしか許可しないフィルタは修復できない理由でもあります。パケットは依然として通る経路で受け入れられる必要があるので、送信元の修正が変えるのは応答の出所だけです。UDP 専用でもあり、TCP リスナーは接続が応答の送信元アドレスではなく四つ組で識別されるため、同じ形ではこの問題を抱えません。
固定ローカルアドレスが誤った既定値になる場合
オプションに手を伸ばす前に、束縛されたリスナーは常にそのアドレスから応答するため、サーバーが特定のローカルアドレスを束縛していないか確認してください。単一インターフェースの配備では正しく、クライアントが正当に複数のアドレスを使い始めた時点で誤りになります。束縛が意図的だったなら、サーバーが追加アドレスでトラフィックを受け入れるべきかどうかを決めてください。束縛を外すと露出が増えるので、許可するインターフェースと送信元ネットワークは、束縛アドレスだけでなくサービスとフィルタで強制する必要があります。
OpenVPN のリファレンスは、このオプションを UDP サーバーに限定し、パケット経路での追加処理に触れ、対応するプラットフォームを記録しています。それを前提に計画する前に、インストール済みのリリースで確認してください。対応していない場合は、特定のアドレスを束縛するか戻り経路を直すのが代案で、どちらも一見したより狭い変更です。ワイルドカードでの待ち受けには応答以外の影響もあり、全アドレスで待ち受けるサーバーは、ホストが接続しているあらゆるネットワークから到達可能で、それは誰も意図しなかった露出かもしれません。
応答の送信元を外から証明する
サーバーの外側から試し、何かをキャプチャする前にクライアントが使った正確なアドレスとトランスポートを記録します。以下の三つの調査は三つの異なる問いに答え、順序が重要です。
tcpdump -ni any udp port 1194
ss -lunp 'sport = :1194'
ip route get 203.0.113.10 from 198.51.100.20
キャプチャは応答の送信元アドレスを示し、記事全体はこの事実に懸かっています。ソケットの一覧は、ワイルドカードのリスナーと特定のリスナーが設定ファイルでは同じに見え、ネットワーク上では違う振る舞いをするため、サーバーが実際に何を束縛したかを示します。経路検索はそのフローに対してカーネルが選ぶ送信元を示し、何かを変える前にキャプチャを説明します。IPv4 と IPv6 は別のリスナーであり別の検索でもあるため、三つとも別々に繰り返すべきです。
ルーティング、検出、フィルタリングは別々のまま
応答の送信元を保つことは、外向きの経路を設定せず、動的 DNS を更新せず、一方のアドレスファミリーにもう一方を受け入れさせません。上流リンクが複数あるサーバーでは、送信元ごとの戻り経路を意図的に合意する必要があり、そうしなければ応答はクライアントのフィルタが決して許可しなかったインターフェースから出ていきます。同様に、プレフィックス変更後の新しいアドレスは、古いレコードではなく検出とサポートされている再接続フローを通じてクライアントに届く必要があります。
サーバー ID の確認と証明書の検証は、アドレスが変わったからといって未検証の相手を受け入れる正当化にはならないため、そのままにしてください。応答が意図した送信元から出るようになり、それでもトンネルが失敗するなら、送信元の問題は解決したものとして先に進んでください。次に観測されるエラーはルーティング、フィルタリング、認証のいずれかに属し、リスナーを再び変えてもそこには届きません。クライアントが接続したアドレスの隣に応答の送信元をチケットへ書き留めれば、次の担当者は同じ事実を一つのコマンドで確認できます。