はじめに

IPv6について、すぐ忘れるので学習したことを自分用にまとめる。

用語

個人的にL2,L3ヘッダについて触れるときは、送信元、送信先の意味で、ツールでよく表現される通り、ソース(Source), デスティネーション(Destination)という表現を使うことがあります。

基本

IPv6の誕生経緯

IPv4のアドレスが枯渇するので、対策として作られた。 ARPではなく後述するNDPが使われたりと、単にアドレスの種類が増えただけではなく、運用方法も大きく変化している。

IPv4との互換性

IPv6とIPv4プロトコルの間には互換性はない(IPv6対応のサーバとIPv6対応のクライアントでのみ通信できる)。

なので、サーバがIPv6対応していないとIPv6のPC(クライアントの意味)からアクセスできないし、サーバがIPv6対応していてもPCがIPv6対応していないとIPv6での通信はできない。

また、通信経路のルーターも全てIPv6対応していないといけない(つまり、ISPが対応してないといけない)。

アドレス比較

比較表

IPv4 IPv6 MAC
アドレスデータサイズ 4バイト 16バイト 6バイト
理論アドレス数 約43億 約340澗(1澗は1兆×1兆×1兆) 約281兆
アドレス例 127.0.0.0/32(DECIMAL、10進数) 1102:5::1BF5:80:F71F:A2/128(HEX、16進数) 14:A3:B0:24:89:1C(HEX、16進数)
アドレスの種類 ユニキャストアドレス ユニキャストアドレス
マルチキャストアドレス マルチキャストアドレス
ブロードキャストアドレス (廃止)

アドレスの表記

基本は、2byte:2byte:2byte:2byte:2byte:2byte:2byte:2byte(HEX) で表す(IPv4のときはDECIMAL表記が一般的だが、IPv6はHEX表記)。 大文字小文字は区別されない。

また、IPv4のときと同様に、サブネットは/<ビット>(例: /64)のように表す。

ここで2byte部分はデータ列というより数値と考えて良いみたい。つまり、0でHEX表記4文字にパディングしなくても勝手に先頭は0埋めしてくれる。自分で0埋めしてもよい。

また、上記の2byteの単位において、2byte=0が連続しているとき、連続している:0:::で置き換えて良い。

表記種類 アドレス例
最短(つまり、通常)表記 1102:5::1BF5:80:F71F:A2
中間表記(の1つ) 1102:0005:0:0:1BF5:0080:F71F:00A2
最長表記 1102:0005:0000:0000:1BF5:0080:F71F:00A2

オンラインコンバーター: https://dnschecker.org/ipv6-expand.php

アドレスの種類

大きく分けて、下記の3つがある。

  1. ユニキャストアドレス
  2. マルチキャストアドレス

順に見ていく。

1.ユニキャストアドレス

IPv4でも同じだが、利用して送付する際に最終的な宛先となるマシンが1つのアドレス。

大きく分けて、次の4つがある。順に見ていく。

項目名 ユニキャストアドレス名
1-1 グローバルユニキャストアドレス
1-2 ユニークローカルアドレス
1-3 リンクローカルアドレス
1-4 ループバックアドレス

1-1. グローバルユニキャストアドレス

インターネット上で一意に割り当てられるアドレス。 そこまで既存の挙動と大きく変わらない。

予約範囲 2000::/3(0x20=00100000なので、先頭3ビットが001で始まるものということ)
開始 2000::
終端 3FFF::FFFF::FFFF::FFFF::FFFF::FFFF::FFFF::FFFF
例(google.com) 2404:6800:4004:825::200e

1-2. ユニークローカルアドレス (Unique Local Address, ULA)

プライベートネットワーク内で使用するアドレス(IPv4のプライベートアドレスに相当)。 グローバルにはルーティングされないが、ルーターは超えることができる。

隣接した別のプライベートネットワークと通信できる。

[予約サブネット]

理論予約範囲 FC00::/7(0xFC=11111010なので、先頭7ビットが1111101で始まるものということ)
実際予約範囲 FD00::/8(0xFD=11111011なので、先頭8ビットが11111011で始まるものということ)

主な用途

複数のプライベートネットワークが隣接しているとき、それらをまたいだ通信をしたい場合に利用する。 というのは、前提として特に小規模な構成であれば1つのプライベートネットワークはしばしば1つのリンクで構成される。

なので、マシンが1つのプライベートネットワークにしか参加していない場合、そのリンクで利用するIPアドレスは後述するLLAで全て済んでしまうため。

自動生成される

従来のIPv4では、クラスA,B,Cの範囲が予約されいていたが、この中だと企業間でVPNをつないだりしたときに衝突することがあった。

ユニークローカルアドレスは、ランダムにアドレスを自動生成するためぶつからないらしい。

NATが不要

よくある記載: IPv4のプライベートアドレスと異なり、NATの必要性がない。

上記のような記載のある時があるが、個人的に混乱したので細かく解説。

IPv4においては、よくある構成としては外部インターネットへ接続するためのルーターだけがグローバルIPアドレスを持ち、LAN内部のマシンはプライベートアドレスを1つずつのみもっていた。

そして、内部のマシンが外部と通信するときは、ルーターがグローバルIPアドレスへL3ヘッダのソースIPアドレスを書き換えることで、グローバルIPアドレスを節約していた。

一方、IPv6においては、LAN内部のマシンがグローバルIPアドレス、ULA、LLAの3つなど複数、特にグローバルIPアドレスも持つことが想定される仕様になっている。

このため、マシンが通信したい対象のIPアドレスに応じて、下記のようなルーティングテーブルにより適切に設定するソースIPアドレスを選択することで、ちゃんとレスポンスが返ってくることになる。

[IPv6の仕様に対して自然なルーティングテーブル]

L3の宛先IPアドレス 設定するL3のソースIPアドレス 利用するインターフェース
グローバルIPアドレス範囲 マシンのグローバルIPアドレス eth0
プライベートIPアドレス範囲 マシンのプライベートIPアドレス eth0
リンクローカルIPアドレス範囲 マシンのリンクローカルIPアドレス eth0

サブネットとしては、 FDxx:xxxx:xxxx::/48 のように、各組織がランダムに /48 を選ぶことが推奨されているらしい。

個人的疑問: NATが不要というが、別にIPv4でも可能な気がする

ざっくり、次のような設定をすれば、IPv4でもNAT不要にできる(ChatGPTに聞いても、できそうであった)。

しかし、グローバルIPアドレスが枯渇していること、仕様が積極的にサポートしていないので、一般的でない。

  1. マシンにおいて、下記のようなルーティングテーブルを設定する
default dev eth0 src <ISPより取得したグローバルIPアドレス>
192.168.0.0/16 dev eth0 src 192.168.1.2
  1. ルーターにおいて、特定のインターフェースからのパケットはNATの設定をオフにする

同じリンク上でのみ使えるユニキャストアドレス。

自動的に割り当てられ、IPv6の場合は必ず存在する(逆にIPv4においてはDHCP失敗時しか利用しないので、かなり出番は限られる。一方、IPv6では積極的に利用される)。 後述するユニークローカルアドレスとは異なり、ルーターを超える通信には使用できない。 IPv4のときにもリンクローカルアドレスはあったが、IPv6においては全てのインターフェースがリンクローカルアドレスを持っていることが保証されているので、より重要な役割を果たすらしい。

なお、結局MACアドレスに変換して利用するという意味では、IPv4のネクストホップアドレスと同じ。

[予約サブネット]

理論予約範囲 FE80::/10(0xFE 80=11111110 10000000なので、最初の10ビットが11111110 10ということ)
実際予約範囲 FE80::/64(0xFE 80=11111110 10000000なので、最初の64ビットが11111110 1000...0ということ)
開始 FE80::
終端 FEBF:FFFF:FFFF:FFFF:FFFF:FFFF

リンクローカルネットワークのサブネット自体は、リンクごとに統一されていればいい(同一マシンの複数インターフェースが同一リンクローカルサブネットに所属していても問題ない)ので、 何も考えずにFE80::/10を利用しても良い。 ただ、通常は幅をずっと狭めた FE80::/64 が使われる(なんなら、IPv6の仕様や実装の多くが FE80::/64 を前提としているため、それ以外を使うと互換性の問題が生じる可能性があるらしい)。

自動生成される

リンクローカルアドレスは各インターフェイスでユニークになるように、通常はMACアドレスや他のインターフェイス識別子から自動生成される。

また、LLAもULAも自動生成されるが、LLAのほうが変わりやすいらしい。 そのため、プライベートアドレスを固定するという目的ではULAのほうが利用されるらしい。

%プレフィクスでリンクを指定

なお、リンクローカルアドレスはサブネットが基本的にFE80::/64で固定なので、外部のリンクローカルアドレスを参照するときにどのリンク上のアドレスか分かりづらいときがある。

そういったときは、利用するリンクが所属する(自身のマシンの)インターフェースをアドレスの後ろに%プレフィクスで指定して、(インターフェースを指定することで)どのリンクかを指定する (手元のUbuntuマシンでテストしたところ、指定しない場合はip routeで見てリンクローカルのルーティングにヒットするインターフェースのうち一番上のものにヒットした)。

例えば、FE80::10%eth0は、FE80::10のアドレスであり、自身のeth0インターフェースが属しているリンクのリンクローカルアドレスを指す。

%プレフィクスが必要になりがちな理由

説明のためにIPv4,IPv6のルーティングテーブル例を下記に示す。

[IPv4における、一般的なルーティングテーブル例]

サブネット インターフェース
default eth0
LLAアドレスはほとんど使われないので省略 -
192.168.1.0/24(プライベートアドレス) eth0
192.168.2.0/24(プライベートアドレス) eth1

[IPv6における、一般的なルーティングテーブル例]

サブネット インターフェース
default eth0
FE80::/64(LLA) eth0
FE80::/64(LLA) eth1
FD12:3456:789A:1::/48(ULA) eth0

IPv4においては上記のようなルーティングテーブルがあり、インターフェースの指定がなくてもサブネットが異なるので、 インターフェースを指定しなければならない場面は少ない。 インターフェースごとにIPv4のサブネットがかぶらないように存在するのがIPv4通常の運用だからである。

一方、IPv6のリンクローカルアドレスにおいてはどのLLAであってもサブネットの指定がほぼほぼFE80/64で固定のため、 リンクローカルアドレスの指定の際に(自身のマシンの)インターフェースを指定する必要がありがちとなる。

同じリンクに含まれるLLA一覧を取得

同じリンクに含まれるリンクローカルアドレスの一覧を得るには、下記コマンドを打つ。FF02::1は、全てのリンクローカルアドレスへのマルチキャストアドレスのよう。

ping6 FF02::1%<インターフェース名>

個人的疑問: LLAを使わずもっぱらULAを利用して良い?

個人的に、「IPv6において、L2の宛先MACアドレスを決定する際、LLAを使わずにもっぱらULAアドレスで解決するのでも、一応問題ないのでは?」という疑問が湧いた。

調べたところによると、一応問題ないが、LLAは確実に存在するのに対してULAはないこともある、などの理由で、やはりリンクで完結する通信はLLAを利用したほうがよいらしい。

1-4. ループバックアドレス

::1/128のみ。つまり、000...001のみ。IPv4における、127.0.0.1に相当。

IPv4では、127.0.0.0/8と1677万個もあるのに、1個に大きく減った(自分のマシンを表すIPアドレスは1つで十分だから、らしい)。

2. マルチキャストアドレス

マルチキャストアドレスとは(IPv4でも同じだが)、利用して送付する際に最終的な宛先となるマシンが複数あるアドレス。

特にIPv6においては、特定のグループあての送信となるアドレス。

予約範囲 FF00::/8(0xFF=11111111なので、先頭8ビットが11111111で始まるものということ)

その次の1バイト(つまり、9ビットから16ビットまで)はマルチキャストのスコープを表す。

予約されたスコープの主なもの:

次の8ビット マルチキャストアドレス名
02(つまり、FF02::/16) リンクローカルマルチキャストアドレス
05(つまり、FF05::/16) サイトローカルマルチキャストアドレス
08(つまり、FF08::/16) 組織ローカルマルチキャストアドレス
0E グローバルマルチキャストアドレス

代表的なIPv6マルチキャストアドレス

アドレス 説明
FF02::1 リンクローカルのすべてのノード
FF02::2 リンクローカルのすべてのルータ
FF02::5 OSPFv3ルータ
FF02::6 OSPFv3設計atedルータ
FF02::1:FFxx:xxxx 近隣探索(NDP)のためのアドレス

デフォルトゲートウェイを知るには

ip -6 route
2400:2411:3ec4:bd01::/64 dev enx6c1ff71a06b4 proto ra metric 100 pref medium
fe80::/64 dev docker0 proto kernel metric 256 pref medium
fe80::/64 dev vetha7dbd4e proto kernel metric 256 pref medium
fe80::/64 dev enx6c1ff71a06b4 proto kernel metric 1024 pref medium
default via fe80::1e7c:98ff:fe13:5420 dev enx6c1ff71a06b4 proto ra metric 100 pref medium

ここで、1行目について、RAという仕組みがあるらしいので調べた。

Router Advertisementとは

役割 デバイス
送信者 IPv6対応ルーター
受信者 IPv6クライアントデバイス(ホスト)

内容: 以下のような情報を提供する。

  • ネットワークプレフィックス ホストが自身のIPv6アドレスを生成するためのプレフィックス情報(例: /64)。
  • デフォルトゲートウェイの情報 ルーターのリンクローカルアドレス(例: FE80::1)。 ルーターパラメータ ルーターの有効期限や優先度。
  • その他オプション MTU(最大転送単位)。 DNSサーバーアドレス(RFC 6106)。

RAメッセージの仕組み

  • ルーターからの送信 IPv6対応ルーターは、定期的にまたはホストからのリクエストに応じて、RAメッセージを送信する。 送信先アドレスはリンクローカルマルチキャストアドレス FF02::1(リンク内の全ノード)である。

  • ホスト側での処理 ホストはRAを受信すると、その内容に基づいて以下を設定する:

IPv6アドレスの自動生成(SLAAC: Stateless Address Autoconfiguration) RAメッセージに含まれるプレフィックス情報を使用して、インターフェースIDを付加し、自身のIPv6アドレスを生成する。

  • デフォルトゲートウェイの設定 RAに含まれるルーターのリンクローカルアドレスをデフォルトゲートウェイとして設定する。
  • ルートエントリの追加 ネットワークプレフィックスを基に適切なルートエントリを作成する。
  • ホストからのリクエスト 必要に応じて、ホストは Router Solicitation (RS) メッセージを送信し、RAを要求することができる。 ルーターがこれに応答してRAを送信することで、ネットワーク情報がホストに提供される。

NDP(Neighbor Discovery Protocol)

IPv4のARPに代わって、Neighbor Discovery Protocolを利用する。

ARPはIPv4アドレスからMACアドレスへの変換を行なうプロトコルだったが、NDPは同様にIPv6からMACアドレスへの変換を行う。 さらに他にも、近隣キャッシュ管理、自動アドレス設定(SLAAC)、デフォルトゲートウェイの検出、重複アドレス検出 (DAD)、ルータープレフィックス学習などを行うらしい。

ARP相当CLIコマンド: ip -6 neighbor

デフォルトゲートウェイを、MACアドレスから探す方法: ip -6 route | grep default