ノート PC には IPv6 アドレスがあり、トンネルは IPv4 上で上がっているのに、IPv6 のテストはすべて失敗します。さらに悪いのは、テストが成功してトラフィックがトンネルに入らず ISP の経路から出てしまう場合です。どちらの結果も、ルーターにクライアントへ流せるプレフィックスを与えた人がいないという、ひとつの欠けた判断に帰着します。クライアントから外へ経路をたどれば、欠けている部品が見つかります。

クライアントがいるところから始める

サーバーに触れる前にクライアントを見ます。ip -6 addr はプールからのトンネルアドレスを示し、ip -6 route はトンネルデバイスを指すプッシュされたプレフィックスを示すはずです。アドレスはあるのに経路がないなら、プッシュがないかクライアントが無視しています。どちらもないなら、サーバーは何も割り当てていません。

次に、クライアントが外の世界をどう見ているかを確かめます。トンネル経由のデフォルト経路はすべての IPv6 トラフィックを主張し、2000::/3 への経路はグローバルユニキャストだけを主張します。どちらも正しくありえ、漏れについて別の問いに答えます。

IPv6 のデフォルト経路をまったく持たないクライアントは、トンネル自体が健全でも公開テストのすべてに失敗します。それはポリシーの隙間であって、壊れたトンネルではありません。

サーバーが実際に経路に載せられるプールを確認する

サーバーは、自分が実際に制御しているプレフィックスからしか割り当てられません。ISP が /56 を委任するなら、/64 をひとつトンネル用に確保し、残りを LAN に残します。ISP が WAN で /64 をひとつだけ渡し、それ以上は経路を流さない場合は、LAN のプレフィックスはそのままにして、トンネルに固有のローカル範囲を与え、クライアントにグローバルな出口がないことは受け入れます。

プールとプッシュはひと組です。server-ipv6 2001:db8:80:10::/64 はアドレスを割り当て、push "route-ipv6 2000::/3" はクライアントにトンネルへ何を送るかを伝えます。2000::/3 をプッシュするとグローバルユニキャストを覆い、リンクローカルとマルチキャストの範囲はトンネルの外に残ります。

選んだプレフィックスは導入記録に書き残します。次に ISP の受け渡しを変える人が、トンネルがどの /64 をすでに使っているかを知る必要があります。

二つ目のファミリーの転送を有効にする

IPv4 の転送は IPv6 の転送を意味しません。net.ipv6.conf.all.forwarding=1 を設定し、IPv4 の FORWARD ポリシーがすでに許していることをそのまま写します。FORWARD チェーンが既定で破棄するルーターでは、ルール群の欠落は死んだトンネルとまったく同じに見えます。

ハンドシェイクは成功し、クライアントはアドレスを受け取り、戻ってくるものはありません。LAN には届いてもインターネットには届かないトンネルは三つ目のテストで失敗するので、両方向と WAN 側のルールを追加します。失敗した試行のあとでチェーンのカウンターを見てください、一度も一致しなかったルールは、一致して破棄したルールとは別の問題です。

ip6tables -A FORWARD -i br0 -o tun0 -j ACCEPT
ip6tables -A FORWARD -i tun0 -o br0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
ip6tables -A FORWARD -i tun0 -o wan0 -j ACCEPT

ひとつの副作用が、最後にトンネルを責める人を捕まえます。転送を有効にすると、特に指示しない限りカーネルはルーター広告によるアドレス設定を飛ばし、そうして覚えたデフォルト経路も一緒に消えます。WAN インターフェースに明示的なデフォルト経路を固定するか、そこでは意図的に accept_ra を 2 にします。どちらの変更でも、クライアントを再試験する前にルーターが外へ出る使える IPv6 経路をまだ持っていることを確認します。

上流が経路を流さないときは近隣探索に答える

上流の機器は、委任された /64 を自分のリンクのものとみなし、下位プレフィックスを VPN ボックスへ流すのを拒むことがあります。そうなったら、何かがクライアントのアドレスごとに近隣要請へ個別に答える必要があります。

OpenVPN は割り当てたアドレスを client-connect フックに渡すので、手で保守する一覧ではなく実際のプールに追従できます。フックは ip -6 neigh add proxy $ifconfig_pool_remote_ip6 dev eth0 を追加し、対応する client-disconnect フックがそれを外します。外さないとプロキシ表が古くなり、後から来たクライアントが受け取っていないアドレスの項目を引き継ぐことがあります。状態は ip -6 neigh show proxy で確認します。

プロキシは回避策として扱います。トンネルの /64 をルーターに向ける静的経路はクライアントの入れ替わりに耐え、特権シェルフックもまったく要りません。

外へ向かう経路をホップごとにたどる

外へ向けて 三つの段階で試します、まずルーターのトンネルアドレス、次に LAN のホスト、三つ目に traceroute6 で公開先です。プールは第一段階で、転送と LAN のファイアウォールは第二段階で、上流を経た戻り経路は第三段階で証明されます。失敗のたびに、設計全体を開き直すのではなく、探索は一台の機器に絞られます。

トンネルの MTU に気をつけます。経路上の IPv6 ルーターは代わりに分割してくれません。大きすぎる MTU は、きれいな失敗ではなく packet-too-big エラーと止まった TLS として現れるので、明示的に設定し、上限に近いペイロードで試します。

関連記事