同じホストでサーバーが動くと OpenVPN クライアントが停止する
一台のホスト上の二つの OpenVPN インスタンスが、同じローカルポートとルートテーブルを奪い合います。ポートを固定し、デバイスを分け、どちらのテーブルが勝つかを確認します。
遠隔サイトからのトンネルを受け入れ、同時にベンダーのネットワークへ発信する実験用マシンがありました。外向きのプロファイルは何週間も動いていました。内向きのサーバーを追加した後、外向きのほうは接続したものの数秒でトラフィックを流さなくなり、あるいはアドレスが使用中というエラーで起動を拒否しました。設定ファイルは変わっておらず、ホストがポートとルートについて独自の意見を持つ二つ目の OpenVPN プロセスを手に入れただけでした。
この障害はランダムではなく、認証の問題でもありません。一台のマシン上の二つのデーモンが同じローカルソケットと同じルーティングテーブルを奪い合い、最後に起動した、あるいは再接続したほうが勝つ傾向があります。この二つの衝突のどちらなのかを把握することが、最初に見る場所を決めます。
症状を逆から読む
トンネルがいつ死ぬかから始めます。起動時のバインドエラーは、何かがすでにそのポートを所有しており、OpenVPN が共有するのではなく起動を拒否することを示します。立ち上がってから沈黙するトンネルは、もう一方のインスタンスが入れたルートが外側の接続のパケットをその経路から引き離すことがあるため、ルーティングを指します。
どちらの場合もユーザーの苦情は同じなので、再試行ループやウォッチドッグスクリプトでは何も直りません。クライアントを同じ衝突へ再接続させるだけです。最初に役立つ問いは、トラフィックが止まったときにプロセスがまだ動いているかどうかです。
インスタンスごとに一つのソケットと一つのデバイス
待ち受けるサーバーは自分のポートをバインドします。外向きのクライアントも、カプセル化されたトラフィック用にローカルポートを必要とし、両方が同じホストに住むとクライアントの既定の動作がサーバーのポートと衝突することがあります。クライアントのローカルポートは固定できますし、相手が固定の送信元ポートを必要としない場合はバインドを省略できます:
lport 1195
nobind
dev tun1これらの数値は例であり、要件ではありません。重要なのは、クライアントがサーバーのポートを奪い合うのをやめ、各インスタンスが別々のトンネルデバイスを手に入れることです。tun0 を共有する二つのデーモンは、ポートが違っていても互いのデバイス状態を上書きするので、トンネルごとに一つのデバイスは任意ではありません。
nobind はクライアント側のものです。サーバーは依然としてバインドして待ち受ける必要があるので、この行をサーバー設定にコピーせず、相手が固定の送信元ポートでフィルタリングするクライアントではバインドを無効にしないでください。
既定ルートの所有者を一人に決める
既定ルートをインストールできる接続は一つだけです。両方のプロファイルがすべてのトラフィックをリダイレクトすると、二つ目の接続が一つ目を静かに置き換え、一つ目は壊れたように見えます。外向きトンネルを分割したままベンダーのプレフィックスだけを流すか、別のルーティングテーブルを与えるかしてください。
ip rule add from 10.9.0.2 table 120
ip route add default dev tun1 table 120
ip route get 10.9.0.2上のアドレスとテーブル番号はプレースホルダーであり、ルールを追加した直後に VPN サーバー自身のアドレスが通常のテーブルでまだ解決されることを確認してください。外側のトランスポートを捕まえるテーブルは、守るはずだったトンネルを壊し、その後に続く再接続ループは信頼できないプロバイダーのように見えます。
再接続や再起動に耐える必要がある構成では、ネットワーク名前空間のほうが堅固な境界です。二つ目のクライアントは独自の名前空間の中で独自のインターフェースとルートを持って動き、越える必要のあるサービスだけが公開されます。ホストは既定ルートを一つ保ち、名前空間の再接続がそれを書き換えることはできません。
ステータス行ではなくテーブルで確認する
接続済みと報告するクライアントは、その制御チャネルを証明するだけです。各接続の前後でルーティング状態を記録し、実際の宛先がどのデバイスを使うかをカーネルに尋ねてください:
ip route show
ip route get 10.40.0.20
ss -lunp | grep 1194二つ目のトンネルが始まったときにベンダーアドレス用に選ばれるデバイスが変われば、ルートの衝突です。両方のプロセスが同じローカルポートに現れれば、ソケットの衝突です。二つ目を直さずに一つ目だけを直すと、障害は次の再接続に移るだけです。
ポート、デバイス、テーブル、ルートの所有者をホストのランブックに書き留めてください。そうしなければ、三つ目のトンネルを追加する次の人が同じ衝突を再発見し、目に見える唯一の証拠は、誰か他の人のデーモンが再起動するまで動く接続だけになります。