トンネルを起動し、トンネルを送信元インターフェースとして fe80::1 に ping しても、何も返ってきません。これは忘れたファイアウォールルールではありません。リンクローカルアドレスは、それが形成された単一のリンク上でのみ意味を持ち、ルーテッド VPN はそのリンクではありません。リモートルーターの fe80::1 はリモート LAN セグメント上にあり、あなたは別のセグメントで 一ホップ離れた場所にいて、IPv6 には、ルーターがリンクローカルパケットを転送する仕組みがそもそもありません。

fe80 プレフィックスは範囲ではなくスコープを表す

リンクローカルユニキャストは fe80::/10 で、定義する性質は番号ではなくスコープです。アドレスはひとつのリンク上でのみ有効で、各インターフェースは自身の識別子からひとつを形成するため、無関係な 二つのネットワーク上の無関係な 二台のマシンが、まったく競合せずにどちらも fe80::1 に応答できます。プレフィックスは要するに「どこかのリンク上」と言っているだけで、リンク自体はコンテキストから決まります。

ホストでは、そのコンテキストはパーセント記号の後に付けるゾーン、すなわちスコープ ID で、Linux では fe80::1%eth0、Windows やインターフェースインデックスを公開するツールでは fe80::1%3 や fe80::1%12 です。カーネルはアドレスをインターフェースインデックスとともに解決してから送信します。ゾーンを外すと宛先が曖昧になり、スタックにはセグメントを選ぶ手段がありません。

ルーテッドトンネルが届けられない理由

ルーテッド VPN は独自のアドレスを持つポイントツーポイントインターフェースで、通常はトンネル内のユニークローカルまたはプライベートな IPv6 空間の /64 です。リモート LAN は別のリンクであり、トンネルエンドポイントがあなたに代わってルーティングと転送を行うことで到達します。これは 二つの異なるセグメントなので、一方のアドレスはもう一方では有効な宛先ではありません。

転送ルールはクライアントの癖ではなく標準に明記されており、ルーターはリンクローカルな送信元または宛先を持つパケットを転送しません。だからルートテーブルが正しく見えてもパケットは死ぬのです。fe80::/64 をトンネルに向けるルートを追加すると、宛先のスコープは「このリンクのみ」と言い、出力インターフェースはそのリンクではないため、準拠したスタックはそれを拒否するか、受け入れて該当するすべてのパケットを破棄します。

近隣探索も同じ境界を補強します。ホストはリンクローカルのネクストホップを、ホップ制限 255 のリンクスコープマルチキャストに送る近隣要請で解決するため、ルーターは転送されたものを拒否できます。これをトンネル越しに機能させるには、リモートセグメントの探索をプロキシすることになり、それは別の帽子をかぶった Layer 2 ブリッジングです。

もっと静かな 二つ目の失敗があり、それでもルートを強制しようとする人を捕まえます——それはゾーンです。ローカルで入力するゾーンはトンネルインターフェースを指しますが、欲しいアドレスはリモート LAN インターフェースに結び付いています。両者は決して一致しないため、パケットを遠端の正しいインターフェースへ誘導できません。

実際の障害はどう見えるか

スコープの誤りのツール出力はルーティングやファイアウォールのエラーのように読めるので、だからこそ人々は間違った層で半日を費やすのです。

What you runWhat you seeWhat it means
ping fe80::1 with no zoneInvalid argument on Linux, or a transmit failure on WindowsThe stack cannot pick an interface for an ambiguous destination
ping -6 -I tun0 fe80::1Destination unreachable, or a silent timeoutThe address is not on the tunnel link, so there is nothing on-link to answer
ssh user@fe80::1 after the tunnel is upHangs, then no route to hostThe SYN never left the machine in a deliverable form; the server logs nothing
ip -6 neigh show dev tun0Empty tableNo neighbor entry can exist for a link-local host that is not on this link
fe80::/64 inside AllowedIPs or route-ipv6Config accepted, traffic still droppedThe tunnel carried the packet; the receiving stack refused to forward it

三行目が最も時間を浪費します、なぜなら出力のない ssh クライアントは待ち受けサービスの問題に見えるからです。入る手段があるなら、遠い側を確認し、sshd がすべてのアドレスにバインドされているのか 一つだけなのかを確かめてください。

ルーティングされる前提のアドレスを使う

トンネル経由で到達する必要があるものには、サービスがその目的のために与えられたアドレスを使ってください——グローバルユニキャストアドレス、または fc00::/7 からのユニークローカルアドレス、まさにこの内部用途のために予約された範囲です。リスナーが実際にそれをバインドしていること、戻り経路とホストのファイアウォールルールを確認してください。

推測せずにリモートホストを見てください。ip -6 addr show は存在するアドレスを一覧し、ss -6 -ltn はデーモンが何を待ち受けているかを一覧します。fe80:: だけにバインドされたサービスは自身のセグメントからしか到達できず、これは通常、誰も意図的に選んでいない既定値で、管理者の同意を得て変更できます。

サービスをどうしても再バインドできないときは、ブリッジをネットワーク層ではなくアプリケーション層へ上げてください。リモートホスト上のリレーがルーティング可能なアドレスで待ち受け、リンクローカルのアドレスへ接続すれば、セグメントを拡張せずに問題を解決できます:

socat TCP6-LISTEN:8080,bind=[fd00:1:2::10] TCP6:[fe80::1%eth0]:80

ここではゾーンが正しい側、つまりそのリンク上に実際に eth0 を持つホストにあります。クライアントは fd00:1:2::10 と通信し、これは通常どおりルーティングされ、リレーがリンクローカルのホップをローカルで行います。同じ技は、リンクローカルアドレスだけを広告するアプライアンスの Web UI や古い BMC にも効きます。

ブリッジングが本当に答えになるとき、何を確認するか

共有セグメントが本当に必要な配備もあります——リンクローカル探索だけを話すデバイス、マルチキャストに依存するアプライアンス、フラットな LAN を再現するラボなどです。それは Layer 2 の問題であり、リモートインターフェースにブリッジされた tap デバイスや、明示的なブリッジモードを持つクライアント製品のような Layer 2 の答えが必要です。その代償はトンネルを越えるブロードキャストとマルチキャストのトラフィック、そして端から端まで機能しなければならない近隣探索です。

ルーテッドプロファイルに fe80::/64 を足して済ませようとすると最悪の状態になります。設定は完成したように見え、ルートテーブルにはエントリが表示され、それでもすべてのパケットは正しく動作している 二つのスタックの間でどこかに破棄され続けます。

ping ではなくインターフェースで確認してください。ip -6 addr show tun0 はトンネルリンクが独自のリンクローカルアドレスを形成したかを教え、ip -6 route get fe80::1%tun0 はスコープ付き宛先に対してカーネルが実際に何をするかを教えます。カーネルがそのインターフェース上で宛先に到達できないと言うなら、どのトンネル設定もそれを変えられないため、プロファイルの編集をやめる時です。

疑問を決着させる短い手順:

  • リモートホストのアドレスを読み、それが fe80:: かルーティング可能なプレフィックスかを記録します。
  • fe80:: ならサービスを再バインドするか、そのホストでリレーするか、セグメントをブリッジし、ルーティング可能ならルート、ファイアウォール、バインドアドレスを直します。
  • 再テストのたびにゾーンを再確認してください、コピーしたコマンドはたいてい間違ったインターフェースを保持しているからです。

出典: RFC 4291、IPv6 アドレッシングアーキテクチャ。

関連記事