昨日は一致していたルールが今日は一致しないのは、クライアントが別のトンネルアドレスで戻ってきたからだ。しかし割り当て器は無作為ではなく、その順序を知っていれば、この驚きは予測できる出来事になる。同じクライアントが以前に持っていたアドレスを優先し、次に最も長く遊んでいた空きアドレスへ退避し、覚えておく場所を与えなければすべてを忘れる。リースを前提とするルールは、静かに一致しなくなる日まで一致し続ける。

割り当て器が従う順序

common name ごとにセッションが一つのとき、割り当て器はまず同じクライアントが以前に使い、現在空いているアドレスを探す。そのアドレスがなければ、最も長く未使用だった空きアドレスを取る。同じ名前で同時セッションが有効な場合、以前のアドレスの優先は働かず、代わりに最初の空きアドレスが使われるのは、セッションが別々の対等ノードとして扱われるからだ。

SituationAddress chosenPractical effect
Reconnect, old address still freeThe remembered addressRules appear stable for days
Old address taken by another clientLeast recently used free addressA working rule silently stops matching
Concurrent sessions, same nameFirst free address, per sessionOne identity can hold several leases

そこから二つの結果がすぐに生じる。素早く再接続するクライアントは通常アドレスを保つので、それが変わるまで誰もこの仕組みに気づかない。そして、その小さな窓の間に接続した別の端末が、アドレスが短時間空いているうちに取ってしまうことがあり、その後最初のクライアントは別のものを受け取り、古い番号に基づくルールはすべて誤りになる。どちらの出来事も、障害に見えるログ行を生まない。

リースが安定して見えてから動く理由

ここでの安定性は、他の誰かがアドレスを要求する前に再接続が届くという創発的な性質だ。約束ではなく、クライアントが切断されている間は担保されない。驚かされるのではなく、アドレスが変わる前提で計画する。端末数よりわずかに大きいだけのプールでは衝突が日常になり、最も長く未使用のアドレスへの退避には選ぶ余地がほとんどない。

ピーク同時接続数こそがサイズを決める数字で、利用者数ではない。同時に二台の端末から試す人や、古いセッションが切れる前に再接続するクライアントは、しばらく二つのリースを占める。人数だけで設計したプールは、人々がサーバーのせいにする入れ替わりをちょうど生み出す。

永続化ファイルは覚えるだけで、予約はしない

サービスの再起動を越えて残るアドレスには永続化ファイルが要る。終了時にクライアント名とアドレスを保存し、サービス開始時に読み戻すので、計画的な再起動でも書いたルールが混ざらなくなる。

ifconfig-pool-persist /etc/openvpn/ipp.txt
server 10.8.0.0 255.255.255.0

それがしないのは、クライアントが離れている間アドレスを保持することだ。その隙間で割り当て器は番号を他人に渡してよく、ファイルには次の接続が守れない古い希望が記録される。再起動時の挙動を改善するヒントとして扱い、固定アドレスとは考えないこと。

ファイルを見ているついでに、プールをルーティング済みの各サブネットと突き合わせる。重複した範囲はサーバーがルーティングできないアドレスを配り、症状は接続してアドレスを受け取ったのに何にも届かないクライアントだ。

アドレスを正しく固定する

ファイアウォールのルールや DNS レコードが本当に固定アドレスを必要とするなら、期待せずに割り当てる。クライアントごとの設定項目はアドレスとマスクを直接プッシュでき、その項目は実際に効いているクライアント名をキーにしている。

# client-config-dir entry for "laptop-acme"
ifconfig-push 10.8.0.50 255.255.255.0

固定アドレスは動的プールの外に置いて、割り当て器が同じ番号を別のセッションに渡さないようにする。次に、各クライアントが消費するプールアドレスの数が変わるので、トンネルの構成を確認する:古いポイントツーポイント構成はクライアントごとに小さなブロックを消費するが、サブネット構成なら一台につき一アドレスで済む。片方の構成で余裕に見えるプールが、もう片方では尽きることがある。

サーバーの帳簿を信じず、クライアントで結果を確かめる。セッションが戻ったら、インターフェースのアドレスとプッシュされたルートを見るのは、サーバーのログが要求したアドレスを報じていても、インターフェース自身は別のアドレスを持っていることがあるからだ。

リモートアドレスは別の話だ

クライアントの remote 行のアドレスは、トンネルが存在する前に到達できなければならない。プールのアドレス、たとえばサーバー自身のトンネル端点をそこに置くと、クライアントはまだ築いていないトンネル越しに端点へ届こうとし、結果は近道ではなくループか無音のタイムアウトになる。

事業者が用意した公開端点を使い、プールは本来の用途、つまりトンネル内部のアドレスに取っておく。プールの範囲、固定割り当て、永続化のパスを一か所に記しておけば、次の人がすべてのリースを気まぐれと見なすことはない。

関連記事