Minami Ueda

はじめに

前回の記事では EdgeRouter X (ER-X) の初期設定を行い、IPv4 での接続を確立するところまで説明しました。この記事では NURO 光の ONU における IPv6 の扱われ方を解明した上で、ndppd(NDP Proxy)を使うことによって ER-X とそのネットワーク内のクライアントが IPv6 で通信できるように設定をしていきます。IPv6 の仕様自体が IPv4 と異なるため、冒頭ではまず IPv6 の基本について説明していきます。

今回実現したいことは、以下の通りです。(その1より再掲)

  • NURO 光の ONU から ER-X に対して /60 のプレフィックスを付与する
  • /60 プレフィックスを用いて、ER-X で /64 のサブネットを作成する
  • EdgeRouter X 用に ndppd (NDP Proxy) をクロスコンパイル(ビルド)する
  • ndppd を用いて ER-X 下の LAN に IPv6 アドレスを割り当てる

この記事を書くにあたっては、『マスタリングTCP/IP IPv6編 第2版』を主に参照して勉強しました。参考にした資料や記事は全て記事最後にまとめていますので、必要に応じてご確認ください。

環境・ネットワーク概要

目次

  1. IPv6 の仕様を理解する
  2. 近隣探索プロトコル(NDP)と NDP Proxy
  3. NURO 光 の ONU の仕様と問題点
  4. ONU (F660A) でスタティックプレフィックスを設定する
  5. ndppd をクロスコンパイルする
  6. ER-X で IPv6 を設定する
  7. ファイアウォールを設定する
  8. ER-X で ndppd を設定する
  9. クライアントで IPv6 の接続を確認する
  10. おわりに
  11. 参考文献・URL

1. IPv6 の仕様を理解する

アドレスの長さ

IPv4 と IPv6 では、アドレスの長さの違いが特徴的です。IPv6 は IPv4 のグローバル IP アドレス枯渇問題への解決のために開発が進められたという経緯もあり、膨大なアドレス空間を有します。IPv4 が32 bitのビット長を持つのに対して、IPv6 は128 bitとなっています。ビット長では 4 倍ですが、IPv6 において表すことができるアドレス空間は IPv4 の 2 の 96乗(= 7.923 ✕ 10 の 23 乗)倍 にもなります。

IPv4 では、グローバル IP アドレス の枯渇に対応するために、NAT をしてプライベートIPアドレスを利用していましたが、IPv6 では膨大なアドレス空間があるため基本的には NAT を行わず、各ホストが グローバル IP アドレスを持ちます。

16進数で表記される IPv6 アドレスのそれぞれの桁は4 bitを示し、さらに 4 桁ごとに:によって区切られています。なお、この記事で IPv6 アドレスを例示する場合には RFC3849 に従って、以下のプレフィックスを使用します。

2001:db8::/32

アドレスの構造

128 bit のアドレスのうち、最初の 64 bit がネットワーク部、後ろの 64 bit がホスト部を示します。また IPv6 アドレスは、上位ビットから RIR / NIR / LIR 等の インターネットレジストリによって、階層的に割り当てられています。このためそれぞれの階層を見ることによって、どこに接続されているかが一目瞭然となっています。下の図のように、エンドユーザーは ISP から /48 から /56 程度のプレフィックスが割り振られ、その後ろにサブネットIDを設定することによってサブネットを構成することができます。

志田 智ほか『マスタリングTCP/IP IPv6編 第2版』(オーム社)
p17 図1.12「IPアドレスの階層的な分配」より引用

IP アドレスの付与

IPv4 では LAN 内でプライベート IP アドレスを付与するのに、DHCP が用いられることが一般的です。DHCP サーバが IP アドレスを決定し、クライアントに対して配布します。これはいわゆるステートフルな動作で、どのクライアントにどの IP アドレスを割り当てたかをサーバ側で管理できるというメリットを持ちます。

一方で、IPv6 ではステートレスアドレス自動生成SLAAC: Stateless Address Autoconfiguration)と呼ばれる機能によって、プレフィックスがルータから与えられれば、ホストが自ら IP アドレスを生成することができます。具体的には後述の近隣探索によってプレフィックスを取得した上で、EUI-64というフォーマットでホストの MAC アドレスを元に一意なインタフェース ID が作ることによって、IP アドレスが定まります。

なお IPv6 でもDHCPv6DHCPv6-PDを用いることによって、サーバ側からホストに対してステートフルにアドレスを付与することが可能です。DHCPv6 がホストに /128 のアドレスを付与するのに対して、DHCPv6-PD(Prefix Delegation)では /60 などのプレフィックスを割り当てます。IPv6 のアドレス割り当てプロトコルは、厳密にはさらに細かい分類や仕様があるので、詳しく知りたい方はこちらの記事をおすすめします。


2. 近隣探索プロトコル(NDP)と NDP Proxy

IPv6 において、アドレスや経路の自動生成機能を担うのが近隣探索プロトコル(NDP: Neighbor Discovery Protocol)です。

近隣探索には ICMPv6 メッセージが用いられており、そのなかでも今回はルータ要請ルータ広告の2つが重要となります。この2つのメッセージのやりとりによって、ホストは自らで IPv6 アドレスを生成することができます。

  • ルータ要請(RS: Router Solicitation)
    • ホストがリンク上のルータを探索するために、ルータへ送信するメッセージ
  • ルータ広告(RA: Router Advertisement)
    • ルータがホストに対して、自分の存在を知らせるために送信するメッセージ
    • ホストのアドレス自動生成、経路設定に必要な情報を含む

志田 智ほか『マスタリングTCP/IP IPv6編 第2版』(オーム社)
p86 図3.2「ホストが明示的にルータ要請メッセージを送信する場合」より引用

NDP proxyはその名の通り近隣探索プロトコル(NDP)のプロキシであり、ホストからのルータ要請(RS)を待ち受けして、上流のルータの代理でルータ広告(RA)を行います。RS は本来であれば上流のルータ宛のメッセージですが、プロキシが設定されたインタフェースは、それがあたかも自らに充てられたメッセージであるかのように振る舞います。NDP Proxy はバッファローや NEC の家庭用ルータでは ND プロキシと呼ばれているようです。

これを用いることによって ER-X が F660A の代理でルータ広告を行い、ホストに対して /64 のアドレスを付与することが可能になります。今回はndppdという NDP Proxy のデーモンを使っていきます。


3. NURO 光 の ONU の仕様と問題点

NURO 光では、ONU に対して ISP から /56 のプレフィックスが付与されています。IPv6 の本来の仕様ではRADHCPv6-PDを用いることによって、/56 のプレフィックスから /60 や /64 のサブネットを作ることができるのですが、今回提供されている ONU (ZTE 社製の F660A) では少し工夫をしなければなりません。

というのも F660A の RA や DHCPv6-PD では直下に接続されたホストに対して /64 のアドレスしか 払い出すことができない仕様になっているようです。ER-X を F660Aにそのままつなげたとしても、56 bit から 64 bitの間の 8 bit 以下のサブネットを構成することができないということです。なんと無駄な贅沢な使い方でしょうか。

今回はまず ONU 側でスタティックプレフィックスを設定し、サブネットを構成できる /60 のプレフィックスを ER-X に対して割り当てることにします。さらに、ER-X に NDP Proxy を設定することによって、ER-X が ONU の代理でホストに対して /64 のアドレスを付与するようにします。以下はあくまでも例示用の IP アドレスですが、どのようにプレフィックスを分割していくかのイメージを掴んでいただけるのではないでしょうか。

NURO 光のONUの下に設置したルータで NDP proxy を動かすにあたっては、以下の記事がとても参考になりました。


4. ONU (F660A) でスタティックプレフィックスを設定する

IPv6 についての説明が長くなりましたが、実際の設定とその準備に入っていきましょう。ブラウザから ONU (F660A) にログインし、ER-X に /60 のスタティックプレフィックスを割り当てていきます。

まずはステータス > ネットワークインタフェース情報から、ONU に割り当てられているIPv6 プレフィックスアドレスを確認します。以下のように /56 のプレフィックスが割り当てられているはずなので、これをメモしておきます。

IPv6 プレフィックスアドレス: 2001:0db8:123a:b300::/56

次に ER-X に割り当てる予定の /60 のプレフィックスをスタティックプレフィックスとして設定します。ネットワーク > LAN > スタティックプレフィックスを開き、以下を追加します。上でメモしたプレフィックスを参考に、今回は 2001:0db8:123a:b310::/60 としました。

プレフィックス: 2001:0db8:123a:b310::/60
望ましいライフタイム: 86400(必要に応じて変更)
正式なライフタイム: 86400(必要に応じて変更)
有効にする: RAとDHCPv6のチェックはつけない

また、ネットワーク > LAN > プレフィックスデリゲーション(IPv6)を開いて修正ボタンを押し、RADHCPv6のチェックを外します。忘れずに更新ボタンを押せば、ONU 側の設定は完了です。


5. ndppd をクロスコンパイルする

早速ndppdの設定に入っていきたいところですが、ここではまずクロスコンパイルするところから始めなくてはいけません。ER-X は MIPS アーキテクチャで動いていて、Mac や Windows でコンパイルしたものをそのまま使用することができないのです。ER-X 上でコンパイルできれば良いのですが、本体のリソースの問題上厳しそうなので、今回は Mac 上にセットアップした仮想マシンで ndppd のクロスコンパイルを行うことにしました。

仮想マシンの環境構築

今回は普段から使っている Parallels Desktop を使って、Ubuntu の仮想マシンをセットアップしました。Ubuntu のインストールが完了した後は、Mac のターミナルから SSH で接続するために SSH の設定も済ませてしまいます。

$ sudo apt-get install nettools
$ sudo apt-get install ssh
$ systemctl start sshd
$ ifconfig # UbuntuのIPアドレスを確認(eth0)

仮想マシンの IP アドレスがわかったら、Mac から SSH 接続して作業をしていきます。apt-getで MIPS コンパイラなど必要なパッケージをインストールします。

$ sudo apt-get update -y
$ sudo apt-get install -y g++-mipsel-linux-gnu vim git

ndppd をビルドする

次に、GitHub から ndppdをクローンします。リポジトリには開発途中のブランチもあるので-bオプションをつけて、安定版のmasterブランチを指定します。クローン後、ndppd ディレクトリに移動します。

$ git clone -b master https://github.com/DanielAdolfsson/ndppd.git
$ cd ndppd

コンパイルの設定を変更するために、Makefile を書き換えていきます。ここでは元のファイルはそのまま残しておき、Makefile-edgeに変更を加えていくことにしました。

$ cp Makefile Makefile-edge
$ vim Makefile-edge

PREFIX と CXX を以下の通り書き換え、LDFLAGS を追加します。?=ではなく=となっていることに注意してください。

PREFIX  = /ndppd/local
CXX     = /usr/bin/mipsel-linux-gnu-g++
LDFLAGS = -static

保存してビルドします。ビルドが完了すると同じディレクトリにndppdの実行ファイルができているはずです。

$ make -f Makefile-edge

file ndppd で MIPS 用にコンパイルができているか確認してみましょう。ここで MIPS と表示されていない場合は、コンパイラの指定に失敗していると考えられます。コンパイルしたndppdのファイルサイズは 2.5 MB ほどとなっているはずです。

$ file ndppd
ndppd: ELF 32-bit LSB executable, MIPS, MIPS32 rel2 version 1 (SYSV), statically linked, for GNU/Linux 3.2.0, BuildID[sha1]=xxxxxxxxxxxxxxxxxxxxxxxxxxx, not stripped

scp で ER-X にコピーします。後ほどディレクトリを作成するので、ここではひとまずホームディレクトリをコピー先として指定しています。Ubuntu での作業はここまでです。クロスコンパイルお疲れさまでした!

$ scp ./ndppd hogehoge@192.168.1.1:

6. ER-X で IPv6 を設定する

概要

ER-X ではeth0switch0に、以下のとおり IPv6 アドレスを設定していきます。eth0は ONU でスタティックプレフィックスを設定した /60 のアドレスとなります。switch0では頭から16桁目( /64 のプレフィックスの最後の桁)を1としたサブネットを作成することにしました。今回はサブネットを一つしか構成しませんが、今後 ER-X 下にさらにサブネットを増やしていくことも可能です。

  • eth0: 2001:0db8:123a:b310::/60
  • switch0: 2001:0db8:123a:b311::/64

再掲ですが、IPアドレスの分割の仕方のイメージとしてはこのような感じになります。

eth0 の設定

まずはeth0を設定し、ER-X の WAN が IPv6 で通信できるように設定します。SSH で ER-X にログインして、以下のコマンドを実行します。

$ configure
# set interfaces ethernet eth0 address 2001:0db8:123a:b310::/60
# set interfaces ethernet eth0 ipv6 address autoconf
# set interfaces ethernet eth0 ipv6 dup-addr-detect-transmits 1
# commit; save; exit

ip a または show interfaces コマンドを実行して、eth0 に上で設定した IPv6 アドレスが表示されていることを確認してください。なおfe80::/64はリンクローカルアドレスなので、今回設定したグローバル IPv6 アドレスとは異なります。

接続が確立するまで 5〜10 分待ったあと、ping6 google.comで接続ができているかを確認します。ping が返ってくれば問題ありません。これで ER-X 自体は IPv6 でインターネットへ疎通できるようになりました。(あくまでも WAN 側の設定なので、まだ LAN では IPv6 は繋がりません)

switch0 の設定

次に LAN 側のswitch0の設定をします。概要で説明したようにこちらには 2001:0db8:123a:b311::/64 というアドレスを指定し、サブネットを構成します。また、ルータ広告(RA)を LAN に流すように設定を行います。

$ configure
# set interfaces switch switch0 ipv6 address eui64 '2001:0db8:123a:b311::/64'
# set interfaces switch switch0 ipv6 dup-addr-detect-transmits 1
# set interfaces switch switch0 ipv6 router-advert cur-hop-limit 64
# set interfaces switch switch0 ipv6 router-advert link-mtu 1500
# set interfaces switch switch0 ipv6 router-advert managed-flag false
# set interfaces switch switch0 ipv6 router-advert max-interval 600
# set interfaces switch switch0 ipv6 router-advert other-config-flag true
# set interfaces switch switch0 ipv6 router-advert prefix '::/64' autonomous-flag true
# set interfaces switch switch0 ipv6 router-advert prefix '::/64' on-link-flag true
# set interfaces switch switch0 ipv6 router-advert prefix '::/64' valid-lifetime 2592000
# set interfaces switch switch0 ipv6 router-advert reachable-time 0
# set interfaces switch switch0 ipv6 router-advert retrans-timer 0
# set interfaces switch switch0 ipv6 router-advert send-advert true
# commit; save; exit;

ここでもip a または show interfaces コマンドを実行して、switch0 に上で設定した IPv6 アドレスが表示されていることを確認してください。


7. ファイアウォールを設定する

初期設定のウィザードの時点で IPv4 に対するファイアウォールは有効化されていますが、ここで IPv6 も含めて改めて設定をしていきます。以下の記事を参考にしつつ、一部カスタマイズしました。

実際の設定コマンドはかなり長いので、 GitHub Gist に置いておきました。ファイアウォールを設定したら、改めて ER-X 上でping6 google.comをして接続を確認しておきます。

EdgeRouter X Firewall Settings (excerpt) | GitHub Gist


8. ER-X で ndppd を設定する

基本設定

さて、ようやく ER-X 本体で ndppd の設定に取り掛かることができます。まずは/ndppd/local/sbinというディレクトリを作成し、ホームディレクトリにコピーしておいたファイルを移動します。

$ sudo mkdir -p /ndppd/local/sbin/
$ sudo mv ndppd /ndppd/local/sbin/

次に ndppd の設定ファイル/etc/ndppd.confを作成します。ER-X 上の vi を使用するか、Macのローカルで事前に用意したものを scp でコピーします。設定内容について詳しく知りたい方は上でも紹介しているこの記事ndppd の公式ドキュメントがおすすめです。

proxy eth0 {
   router no
   timeout 500
   autowire yes
   keepalive yes
   retries 3
   ttl 30000
   rule ::/0 {
       iface switch0
   }
}

proxy switch0 {
   router yes
   timeout 500
   autowire yes
   keepalive yes
   retries 3
   ttl 30000
   rule ::/0 {
       auto
   }
}

あとは ndppd を起動すれば、LAN のクライアントも IPv6 で通信できるようになります。ルータ起動時に手動で起動させるのは大変なので、ndppd が自動起動されるように設定しておきましょう。

ルータ起動時に自動実行する

ER-X では/config/scripts/post-config.d/内に置かれたシェルスクリプトが起動時に自動実行される仕組みになっています。このディレクトリ内にndppd.shというスクリプトを書き、ndppdをバックグラウンドで実行するようにします。(-d オプション

#!/bin/vbash
# save this script in /config/scripts/post-config.d/
/ndppd/local/sbin/ndppd -d

忘れずに chmod 755 ndppd.sh でスクリプトに対して実行権限を与えます。

rebootで ER-X を再起動して、ndppd が自動起動するかを確認しておきましょう。起動後にps ax | grep ndppdに上で設定したデーモンが出てくれば大丈夫です。ここまでの設定が正しくできていれば、LAN のクライアントで IPv6 接続ができるようになっているはずです。

$ ps ax | grep ndppd
2295 ?        Ss     0:00 /ndppd/local/sbin/ndppd -d

9. クライアントで IPv6 の接続を確認する

ブラウザからの確認

待ちに待った瞬間です。クライアントで IPv6 接続を試してみます。まずは定番の kame.net にアクセスしてみましょう。IPv6 で接続されていればカメが踊るはずですが、果たしてどうでしょうか。

… 動きました!IPv6 で接続できているということですね。この他にも、IIJ のサイトに行くと右上に CONNECTED via IPv6 という表示が確認できました。IPv6 テストサイト でも 10/10 の結果が出たので、これでバッチリです。

CUI からの確認

念の為、Mac のターミナルからも確認してみます。ping6 google.comで ping が返ってくれば OK です。

どんな IPv6 アドレスがクライアントに振られているかも見てみましょう。Mac でifconfig en0コマンドを実行すると、以下のような文字列を含む結果が表示されるはずです。

inet6 (IPv6アドレス) prefixlen 64 autoconf secured
inet6 (IPv6アドレス) prefixlen 64 autoconf temporary

IPv6 アドレスがダブって付与されているように見えますが、これは一時アドレスが割り当てられているためです。SLAAC では MAC アドレスを使って一意な IPv6 アドレスを生成しますが、このままでは個人が特定されやすいというプライバシー上の懸念があるため、インターフェース ID 部分に乱数を取り込んだ一時アドレスも同時に生成されているのです。


おわりに

とてつもなく長い工程となりましたが、無事に NURO 光の IPv4 と IPv6 の両方を EdgeRouter X で使えるようになりました。厳密な比較をしたわけではありませんが、速度と安定度は F660A 内蔵のルータを使用していたときよりも向上しているように感じています。

設定の自由さという点でも、コストパフォーマンスという点でも、EdgeRouter X にはとても満足です。VPN の設定についても別記事で紹介できればと思っていますが、少しこだわりたい自宅ネットワークや SOHO にはぴったりのルータと言えるのではないでしょうか。いろんな人が絶賛して愛用している理由がよくわかります。

さてここまでを振り返ってみると、いろんなブログ記事を読んで、わからないことは教科書を読んで理解して、それでもわからなければさらに検索して… というサイクルの繰り返しでしたが、IPv6 の知識が深まる機会となったのは間違いありません。ネットワーク環境が快適になって、さらにインターネットについて詳しくなれるなんて一石二鳥ですね!

EdgeRouter X で始めるおうちネットワーク強化プロジェクト、とってもおすすめです!


参考文献・URL

  1. 志田 智ほか『マスタリングTCP/IP IPv6編 第2版』(オーム社、2013)
  2. 小川晃通『プロフェッショナルIPv6』(ラムダノート、2018)
  3. IPv6 Linux Router with NDP Proxy.” BENEDICAM TE., 9 Oct. 2018.
  4. ikai. “EdgeRouter X (ER-X) で ndppd を動かす.” Qiita, 22 July. 2019.
  5. ikai. “EdgeRouter X (ER-X) で IPv6 IPoE DS-Lite するまで.” Qiita, 30 Nov. 2019.
  6. sonson. “Edgerouter Xとの戦い〜結〜結局ndppdをビルドする.” note, 5 April. 2020.
  7. sonson. “Edgerouter Xとの戦い〜ONUはいつもクソ〜後編.” note, 1 April. 2020.
  8. hnakamur. “IIJmioひかりとEdgeRouter-LiteでDS-Liteを試してみた.” hnakamur’s blog, 13 May. 2017.
  9. hnakamur. “EdgeRouter LiteでIPv6の静的ルーティング設定.” hnakamur’s blog, 28 May. 2017.
  10. 小川晃通. “ややこしいIPv6アドレス自動設定の話.” Geekなページ, 1 October. 2017.
  11. IPv6アドレス – EUI-64で自動生成するインターフェースID.” ネットワークエンジニアとして.
  12. 永沢茂. “ソネット、最大2Gbpsの光ファイバー通信サービス「NURO」、IPv6対応開始.” INTERNET Watch, 30 September. 2013.
  13. KAMEプロジェクト.” Wikipedia.