IPv6-Mostly Network を作ってみた

# :christmas_tree: はじめに
この記事はシスコの有志による [Cisco Systems Japan Advent Calendar 2024](https://qiita.com/advent-calendar/2024/cisco) の 16 日目 (シリーズ 1) として投稿しています。
シリーズ 2 では @hiokazak さんの記事が同日に公開されています。（お誕生日おめでとうございます！)

<details><summary>📅 これまでのカレンダーの一覧（クリックして開きます）</summary>

- 2017 年版: https://qiita.com/advent-calendar/2017/cisco
- 2018 年版: https://qiita.com/advent-calendar/2018/cisco
- 2019 年版: https://qiita.com/advent-calendar/2019/cisco
- 2020 年版 (1): https://qiita.com/advent-calendar/2020/cisco
- 2020 年版 (2): https://qiita.com/advent-calendar/2020/cisco2
- 2021 年版 (1): https://qiita.com/advent-calendar/2021/cisco
- 2021 年版 (2): https://qiita.com/advent-calendar/2021/cisco2
- 2022 年版 (1,2): https://qiita.com/advent-calendar/2022/cisco
- 2023 年版: https://qiita.com/advent-calendar/2023/cisco
- 2024 年版: https://qiita.com/advent-calendar/2024/cisco
</details>

# :memo: この記事は何なのか
- 大規模なカンファレンスが行われる会場において **IPv6-Mostly Network** と呼ばれるネットワーク構成を最近耳にするようになりましたが、ご存知ですか？[^confs]
- ようは **「ほぼ」IPv6 ネットワーク** ということらしい[^ipv6mostly]
- あまり日本語の構築事例は見つからなかった
    - 本邦の「ほぼ」といえば、[🦀ほぼ、これ🦀](https://www.kanetetsu.com/pages/hobokani)
- なので自宅のシスコルータを使って構築してみた

[^confs]: [稲冨花保, 一味違う!?JANOG52会場ネットワーク解説～AS運用を添えて～, JANOG 52](https://www.janog.gr.jp/meeting/janog52/wp-content/uploads/2023/06/janog52-j52noc-inatomi.pdf#page=13)
[Brian Candlerm, Experimental IPv6-only network at APRICOT 2024, AFRINIC](https://blog.afrinic.net/apricot-ipv6-only)
[Ondřej Caletka, Deploying IPv6-Mostly Access Networks, RIPE Labs](https://labs.ripe.net/author/ondrej_caletka_1/deploying-ipv6-mostly-access-networks/)
[^ipv6mostly]: [Nick Buraglio and Ondřej Caletka and Jen Linkova, IPv6-Mostly Networks: Deployment and Operations Considerations, Internet-Draft](https://datatracker.ietf.org/doc/draft-ietf-v6ops-6mops/)

IPv6-Mostly Network について知りたい方は [こちら](#qiita-ipv6-mostly-network-%E3%81%A8%E3%81%AF) をクリックして下にスクロールしてください。

# :qiitan: コンフィグ
おそらくネットワークエンジニアなら第一にコンフィグが知りたいはず :qiitan:

検証環境は ISR4321/K9, IOS XE 17.12.04 です。
後述しますが、少なくとも 17.11.x 以降でなければ動きません。

```
ip dhcp pool ipv4-dhcp-pool
 network 192.0.2.0 255.255.255.0
 default-router 192.0.2.1
 ! Cisco Umbrella - Recursive IPv4 DNS servers
 dns-server 208.67.222.222 208.67.220.220
 ! IPv6-Only Preferred Option, RFC 8925
 ! Wait time: 30 minutes = 1800 (decimal) = 0x708 (hex)
 option 108 ascii 00000708
!
ipv6 unicast-routing
!
interface GigabitEthernet0/0/0
 description *** WAN ***
 ip address dhcp
 nat64 enable
 ipv6 nd ra suppress
 ipv6 address autoconfig default
 ipv6 enable
!
interface GigabitEthernet0/0/1
 description *** LAN ***
 ip address 192.0.2.1 255.255.255.0
 nat64 enable
 ipv6 address 2001:0DB8::1/64
 ipv6 enable
 ! Discovering PREF64 in RA, RFC 8781
 ipv6 nd ra nat64-prefix 64:FF9B::/96
 ! RDNSS, RFC 8106
 ! Cisco Umbrella - Recursive IPv6 DNS servers
 ipv6 nd ra dns server 2620:119:35::35
 ipv6 nd ra dns server 2620:119:53::53
!
ipv6 access-list acl-allow-nat64
 sequence 10 permit ipv6 2001:0DB8::/64 any
!
! Stateful NAT64, RFC 6146
nat64 v4 pool nat64-pool 198.51.100.1 198.51.100.1
nat64 v6v4 list acl-allow-nat64 pool nat64-pool overload
```

## :warning: ハマりやすいところ
- Stateful NAT64 のために **WAN インターフェイスに割り当てられていない IPv4 アドレス** を最低ひとつ用意しなければなりません（上記の例では `198.51.100.1`）
    -  NAT44 と違って NAT64 では interface overload は利用できず、address pool を使います
        -  いわゆる `ip nat inside source ... interface ...` のようにして外側の IPv4 アドレスの指定を省略することができません
    - （NAT64 に限った話ではありませんが）address pool に指定する IP アドレスは、ルータ上で使われている IP アドレス（例えば WAN インターフェイス）と重複することができません[^natoutsideaddress]
    - 以上のことから、WAN 側で 2 つの IPv4 アドレスを用意して、これらがルータに到着するようにルーティングを工夫する必要があるでしょう
- 同じインターフェイスで NAT44 と NAT64 を動かしてはいけません [^nat44]
    - ~~実際にやってみたら動いたけれど...~~

[^natoutsideaddress]: [IOS-XE ではルータ上の IP アドレス を NAT アドレスプールの一部、または NAT 変換アドレスとして使用することはサポートされていない](https://community.cisco.com/t5/-/-/ta-p/3895446)
[^nat44]: > Both NAT44 (static, dynamic and PAT) configuration and stateful NAT64 configuration are not supported on the same interface.
[Restrictions for Configuring Stateful Network Address Translation 64, Stateful Network Address Translation 64, IP Addressing Configuration Guide, Cisco IOS XE 17.x](https://www.cisco.com/c/en/us/td/docs/routers/ios/config/17-x/ip-addressing/b-ip-addressing/m_iadnat-stateful-nat64.html#GUID-2804400D-FE1D-43E3-A7BC-91462239C392)

## :memo: 気づいたこと
- 既存の構築事例では PREF64 を RA に埋め込む RFC 8781 の実装で苦労していた様子ですが[^raoption]、IOS XE では 17.11.1 以降でサポートされているようです [^17111]

[^raoption]: > New DHCP option is easy, new RA option is harder
[Ondřej Caletka, Deploying IPv6-Mostly Access Networks, RIPE Labs](https://labs.ripe.net/author/ondrej_caletka_1/deploying-ipv6-mostly-access-networks/)
[^17111]: [Support for RFC8781 - PREF64 in IPv6 RA, Software Features in Cisco IOS XE Dublin 17.11.1](https://www.cisco.com/c/en/us/td/docs/switches/lan/catalyst9600/software/release/17-11/release_notes/ol-17-11-9600/whats_new_in_cisco_ios_dublin_1711x.html#topic-rn-sw-features-17111.xml)

# :qiita: IPv6-Mostly Network とは

IPv4/IPv6 のデュアルスタックは（特に日本国内では非常に）普及していますが、これは文字通り IPv4 と IPv6 を同時に使っています。引き続き IPv4 が使われる限り、IPv6 で解決したい課題である **IPv4 リソースの枯渇** には対応できません。

多くのアプリケーションが IPv4 に依存しているため IPv4 の廃止は非現実的でしたが、端末で **CLAT** (Customer-side translator) (RFC 6877[^rfc6877]) の実装が進んだことで状況が変わりました。

CLAT は端末上で IPv4 アドレスと IPv6 アドレスをステートレスに変換します。つまり、IPv4 アドレス宛の IPv4 通信であっても、IPv6 アドレス宛に変換されて IPv6 パケットとして端末から送信されます（逆も然り）。

例えば NTT ドコモは端末への IPv4 アドレス割当を廃止し、IPv4 アドレス枯渇問題へ対応しているそうです[^docomo]。つまり、Android や iPhone を使っているユーザは知らず知らずのうちに WAN 側（網側）のインターフェイスに IPv6 アドレスだけが割り当てられています。しかし、スマートフォンで実行されている CLAT のおかげで、IPv4 しか対応しないアプリケーションも問題なく通信することができています。

つまり、現状の端末は

1. IPv4-Only Endpoint: IPv4 シングルスタック
2. Dual-Stack Endpoint (Not IPv6-Only Capable): IPv4/IPv6 デュアルスタック
3. IPv6-only capable Endpoint: IPv6 シングルスタック（ただし CLAT で IPv4 通信可能）

に分類することができます。 

以上を踏まえて IPv6-Mostly Networks が実現するのは、これら 3 つを全て同じ L2 ネットワークに接続させながら、「Dual-Stack Endpoint」の端末が自動的に「IPv6-only capable Endpoint」に切り替わるように促すことです。

具体的には、DHCP で IPv4 アドレスを取得しようとする端末に対して、もし端末自身が IPv6-only に対応すると判断するなら、積極的に IPv4 アドレスを捨てさせようとします。もし端末がそのように判断しないのならば、IPv4 シングルスタック、もしくはデュアルスタックであることを許容します。

以上を実現するために、IPv6-Mostly Networks ではこれらの既存技術を組み合わせています。

1. IPv4 ネットワーク宛の通信ができるように NAT64 を提供する (RFC 6146[^rfc6146])
2. 端末がネットワーク内の NAT64 prefix (PREF64) に気付くように RA を使う (RFC 8781[^rfc8781])
3. CLAT を持ち IPv6 シングルスタックに対応するクライアントは IPv4 アドレスを破棄するように IPv4 DHCP Option 108 を使う (RFC 8925[^rfc8925])

[^rfc6877]: [Masataka Mawatari and Masanobu Kawashima and Cameron Byrne, 464XLAT: Combination of Stateful and Stateless Translation, RFC 6877](https://datatracker.ietf.org/doc/html/rfc6877)
[^rfc6146]: [Philip Matthews and Iljitsch van Beijnum and Marcelo Bagnulo, Stateful NAT64: Network Address and Protocol Translation from IPv6 Clients to IPv4 Servers, RFC 6146](https://datatracker.ietf.org/doc/html/rfc6146)
[^rfc8781]: [Lorenzo Colitti and Jen Linkova, Discovering PREF64 in Router Advertisements, RFC 8781](https://datatracker.ietf.org/doc/html/rfc8781)
[^rfc8925]: [Lorenzo Colitti and Jen Linkova and Michael Richardson and Tomek Mrugalski, IPv6-Only Preferred Option for DHCPv4, RFC 8925](https://datatracker.ietf.org/doc/html/rfc8925)
[^docomo]: [報道発表資料 : 「IPv6シングルスタック方式」の提供を開始 | お知らせ | NTTドコモ](https://www.docomo.ne.jp/info/news_release/2022/01/31_00.html)

# :wave: 最後に

- やってみて気づいたのですが、IPv6-only capable Endpoint と IPv4-Only Endpoint 間の通信はどうしたらいいんでしょうか？
    - 上のコンフィグ例では IPv4 インターネット行きの NAT64 が構成されていますが、LAN 行きの NAT64 は行っていません
        -  `ping 8.8.8.8` はできるけれど、LAN 上のプリンタの IPv4 リテラルアドレス宛に通信できません
    - LAN 内の IPv4 通信 (IPv4-only internal destinations) も NAT64 すれば解決するんですが、LAN 内で NAT することの違和感が...（個人の感想です）
- ちらちら耳にする IPv6-Mostly Network を自分の手で作ってみましたが、ハマりそうなところも少なく、比較的簡単に始めることができそうです
    - この記事は IPv6-Mostly Network に接続した macOS 15.1.1 (24B91) を使って Qiita サイト上で執筆しました

# :bow: 免責事項
本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、私の所属する組織の意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、私の所属する組織や他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Webサイトの利用に関するあらゆる責任から私の所属する組織を免責することに同意したものとします。