Android の OpenVPN はトンネルアドレスがないとルートを追加できない
Android の OpenVPN クライアントは、端末がトンネルアドレスを持つまでルートを追加できません。誰が割り当てるのか、どの pull フィルタが落とすのか、いつ自分で入力すべきかを確認します。
お使いの Android の OpenVPN プロファイルがルートを追加できないのは、端末が仮想インターフェース上にアドレスを持っていないため、ルートが指し示す先が存在しないからです。ルートが答えるのは、パケットをどこへ送るかという点だけです。トンネルアドレスが答えるのは、トンネル内で端末が誰であるかという点で、インターフェースを作る前にクライアントがこれを用意しなければなりません。以下の四つの確認を順番に行い、最初の失敗で止めてください。アドレスが存在する前にルートを編集すると、本当の問題が見えなくなります。
クライアントが実行する順序で失敗を読む
Android の VpnService.Builder はこの二つを別物として扱います。addAddress() はアプリが構築中のインターフェースにアドレスを載せ、addRoute() は宛先プレフィックスを追加し、establish() は少なくとも一つのアドレスが追加されるまでインターフェースの作成を拒否します。OpenVPN クライアントはプロファイルとサーバーが push するオプションを、まさにこれらの呼び出しに対応付けます。したがって、アドレスを一度も解釈しない接続はインターフェースを構築できません。
読んでいるログ行がルートを名指ししていても、原因が一つ手前にあるのはそのためです。クライアントがルートの段階に進むのはインターフェースができた後だけであり、アドレスがなければルート呼び出しは即座に失敗するか、まったく実行されません。ログがルートを追加できないと述べているときは、ルートの書式ではなくアドレスから確認してください。
チェック 1: サーバーは応答にアドレスを入れるか
ルーティング型の OpenVPN サービスでは、アドレスはサーバーのプールかクライアントごとの割り当てから供給され、その形はトポロジーで決まります。OpenVPN 2.4 以降のサーバーでは、サブネットトポロジーのサービスは次のようになります。
topology subnet
server 10.8.0.0 255.255.255.0
client-config-dir ccd
この形ならサーバーは ifconfig 10.8.0.6 255.255.255.0 のようなものを push します。古い topology net30 の構成では代わりにピアアドレス、たとえば ifconfig 10.8.0.6 10.8.0.5 を push するため、二つのモデルの間で移したプロファイルは正しく見えても誤ったネットマスクを抱えます。
クライアントの接続ログで、push されたオプション群を探してください。ifconfig の行がまったくないなら、サーバーがアドレスを送っていないか、クライアントがそのオプションを拒否しています。client-config-dir を使うサーバーでは、証明書の common name にちなんだファイルが存在し、割り当てを記載している必要があります。
# ccd/phone-anna
ifconfig-push 10.8.0.6 255.255.255.0
チェック 2: クライアントは与えられたアドレスを保持するか
広すぎるフィルタが二つ目のよくある原因です。pull-filter は OpenVPN 2.4 以降にあり、複数のフィルタが同じオプションに一致する場合、最後に一致したものが優先されるため、末尾の catch-all はエラーも出さずにアドレスを消します。
# removes every pushed option, including the address
pull-filter ignore "ifconfig"
pull-filter ignore "route"
フィルタは本当に消したいオプションだけに絞り、アドレスには触れないでください。
# keeps the pushed address, drops one unwanted LAN route
pull-filter ignore "route 10.60.0.0"
すべての pull を無効にせよという助言は、たいてい一つのルートを消したいだけの人が出しています。route-nopull はより狭いスイッチで、ifconfig とその他の push オプションを保ったまま、push されたルートと DHCP 風のオプションを断ります。本当にそれが目的のときだけ使い、アドレスの問題は別に扱ってください。
チェック 3: そのアドレスは自分で入力してよいものか
手動でのアドレス指定が正当なのは、運用者から値を受け取った場合だけです。自分で入力するなら、VPN クライアントのサブネットから取り、稼働中のセッションの中で一意であり、サーバーが使うトポロジーと一致しなければなりません。デスクトップのブリッジやリモート LAN 上のホストのアドレスを写すのは二重に誤りです。端末は他所に既にあるアドレスを主張することになり、ゲートウェイにはそこへの戻り経路がなくなります。
ルートに書くリモート LAN のプレフィックスは宛先であり、端末の身元ではありません。10.60.0.0/24 へのルートは、そのネットワークへトンネル経由で到達せよという意味で、端末がどの 10.60.0.x を持つべきかは何も語りませんし、端末はそのいずれも持つべきではありません。固定の割り当てはサーバー側に置くもので、そこでなら動的プールと衝突しません。
一つの身元で二つのセッションを張ると、同じ衝突が露呈します。同じ証明書で二回接続し、サーバーが両方に一つの固定アドレスを push すると、二つ目のセッションが一つ目を複製します。直すべきはクライアント側の編集ではなく、身元や割り当てを分けることです。
チェック 4: 別の何かがトンネルの枠を押さえていないか
Android が同時に許す VPN サービスは一つだけです。別の VPN アプリや、もう動かないプロファイルに対して有効なまま残った常時接続 VPN の項目が、OpenVPN クライアントが establish() を呼ぶ前にその枠を取ることがあります。するとプロファイルが有効でもインターフェースは現れません。プロファイルに触る前に、もう一方の VPN を切断し、常時接続の設定を切ってから再接続してください。
イーサネットブリッジにこだわるサービスも行き止まりです。root なしの Android アプリが作れるのは IP トンネルであり、ブリッジされたイーサネットセグメントではないため、どんなアドレスを入力しても dev tap サーバーは動きません。運用者がルーティング型のサービスを用意する必要があります。問題を報告するときは、クライアント名とバージョン、push されたオプション群、トポロジー、そしてアドレスが現れるはずだった正確な段階を含めてください。
四つの確認がすべて通り、アドレスが存在し、一意で正しくマスクされていれば、ルートの問いはありふれたものになります。サーバーがどのプレフィックスを許可し、クライアントがどう範囲を定めるべきかです。ほかを変更する前に、トンネルアドレス、ネットマスク、トポロジーを書き留めてください。運用者がサーバー側の見え方と突き合わせるのに必要なのは、この三つの値だからです。