OpenVPN の route-nopull が実際にサーバーの push を止める範囲
route-nopull が落とすのは push されたルートと DHCP オプションで、ハンドシェイクではありません。これと pull-filter、あるいは何もしないかを選び、ルートは自分で追加します。
トンネルが既定ルートを飲み込まないようにクライアントプロファイルへ route-nopull を入れたのに、クライアントは接続済みと言い続けながらオフィスのサブネットには届かない。どちらの観察も正しく、何も壊れてはいません。このフラグは、サーバーが push するルートと DHCP エントリをスキップするようクライアントに指示するもので、追加するときに多くの人が期待するより狭い指示です。残るのは、どの宛先が使うべきかについて何も語らない、動作するトンネルです。
その隙間こそが、この記事が扱う判断のすべてです。ネットワークを記述するのはサーバーかクライアントのどちらかであり、このフラグはその仕事を、あなたの代わりに何もせずクライアントへ渡します。
接続時にフラグが止めるもの
pull する OpenVPN クライアントは通常、認証後にサーバーからルート、既定ゲートウェイのリダイレクト、DNS サーバー、そしていくつかの調整ディレクティブの束を受け取ります。route-nopull が有効でも、クライアントはセッションを受け入れ、証明書を検証し、暗号と keepalive を交渉し、インターフェースを立ち上げます。捨てるのは、push された route 行と push された dhcp-option 行の適用で、DNS も含まれます。
混乱は、死んだアプリケーションの隣にある緑のインジケーターから来ます。トンネルは存在しますが、宛先をそのトンネルへ対応づける処理は存在せず、クライアントのステータスパネルには「接続済みでルーティング中」と「接続済みだが無効」を区別するものが何もありません。トンネルから見ればどちらも同じ状態だからです。
生きたトンネルでも何もルーティングできない理由
インターフェースは自身のアドレスとともに現れ、ポイントツーポイントのリンクでは、ピアへのホストルートより具体的なものはしばしばありません。プライベートなサブネットは、正しいプレフィックスでそのインターフェースを指すルートがあって初めて到達可能になり、push が無効ならそのルートは決して届きません。ダウンロードしたプロファイルも、サーバーがまさにこの情報を提供するという前提で書かれているため普通は役に立ちません。だからインターフェースは健全に見えても、サブネットは暗いままなのです。
したがってプロファイルを読んでもほとんど何も証明できないため、代わりに接続中のマシンで実行中の状態を読んでください。
ip addr show tun0
ip route show dev tun0
ip route get 10.20.5.10
二番目のコマンドにサブネットルートのないアドレスがあれば、これがこの問題の兆候です。三番目のコマンドは、使われると期待した一覧ではなく、特定の宛先に対してカーネルが選ぶインターフェースを報告するため、利用者が本当に気にする問いに答えます。それが物理リンク経由で答えるなら、トンネルは経路にまったく入っていません。
名前解決の失敗は別の理由ではなく、関連する理由によるものです。push された dhcp-option DNS エントリは同じフラグで飛ばされるため、内部ホストへの問い合わせはローカルネットワークが用意したリゾルバーへ向かいます。そのリゾルバーにはオフィスのゾーンがないので、問い合わせは失敗するか公開の答えを返し、クライアント設定の問題がサーバーの問題のように見えます。名前より先にアドレスを試すことが、この二つを切り分けます。
フラグとプレフィックスフィルターの選択
二つの選択肢は同じ不満の異なる形を解消し、まずい選択が「接続済みだが役に立たない」状態を生みます。一方は push されたポリシーを丸ごと置き換え、もう一方はプレフィックス単位で編集します。表が短い版を示し、その次の段落が人を驚かせる部分を扱います。
| Setting | What the client keeps | Reasonable when |
|---|---|---|
| no option | every pushed route and DHCP entry | the server's view of the network is correct |
route-nopull | the session, none of the pushed routing or DNS | you will write the full local policy yourself |
pull-filter | everything except lines matching your prefixes | the push is nearly right and one or two lines are wrong |
pull-filter は三つの動詞を持つプレフィックス照合で、行の一族を受け入れることも、黙って無視することも、プレフィックスが現れたときに接続自体を拒否することもできます。知っておく価値があるのは最後の挙動で、拒否ルールはポリシーの不一致を、静かな省略ではなく失敗したハンドシェイクに変えます。OpenVPN 2.6 のマニュアルに、受け入れられるプレフィックスと各動詞の正確な意味が載っています。
よくある中間案は redirect-gateway だけを拒否し、オフィスのルートと DNS を意図どおりに届けることです。サーバーのほうがよく理解している部分については push を機能させたまま、既定ルートを奪ってしまう一行だけを防げます。
ルートとリゾルバーを手動で追加する
フラグを残すなら、プロファイルがサーバーの言うはずだったことを語る必要があります。クライアント側の route ディレクティブは接続確立後に適用されるので、フラグに阻まれるのではなく、フラグと並んで機能します。対話的なコマンドラインではなくプロファイルに書かないと、次の再接続で動作する状態が再現されません。
route-nopull
route 10.20.0.0 255.255.0.0
dhcp-option DNS 10.20.0.53
DNS 行はクライアント側のディレクティブでありながら、一部のクライアントはプラットフォームの DNS 統合を通してしか適用せず、リンクが変わると上書きされうる厄介な位置にあり、systemd のホストではクライアントが優先順位争いに勝つことを願うより、トンネルインターフェースに直接リゾルバーを設定するほうが予測しやすいです。
resolvectl dns tun0 10.20.0.53
resolvectl domain tun0 ~corp.example.com
ルーティングドメインはアドレスと同じくらい重要です。これがなければ、公開名の問い合わせも内部リゾルバーへ送られることがあり、再帰を拒否する内部リゾルバーはプライベートゾーンを動かしたまま閲覧を壊します。これがあれば、その接尾辞の下の名前だけがトンネルのリゾルバーへ回され、それ以外は物理リンクに従います。
結果の確認: アドレス、名前、外側の経路
三つのテストが起こりうる失敗を切り分けます。まず IP でプライベートアドレスを取得し、次に名前で同じホスト、最後に普通の公開サイトです。IP が通り名前が失敗すればリゾルバー、IP が失敗し名前が通ればルーティング、両方失敗ならトンネルが経路にないのが普通です。
次に内側ではなく外側を見てください。トンネルの端点自身のルートが変化を生き延びる必要があり、遮断の失敗は端点を巻き込まずトンネルに限定されなければなりません。トンネルが落ちた後も閲覧を続けるクライアントはルーティングではなくポリシーの問題で、上の三つのテストのどれにも現れません。
最終的な一覧を、ルート、リゾルバー、ドメイン、そしてそれぞれが存在する理由とともにプロファイルのドキュメントに書いてください。同じ表を再現する再接続だけが、ローカルポリシーが完全である証拠になります。トンネルが上がり三つのテストがすべて通ってもアプリが失敗するなら、次に見るべきは検証済みの証明書ではなく、接続済みなのにオフラインという種類の問題です。