フレッツ光でEdgerouter XでIPv6(IPoE)する
前提
NTT西日本
フレッツ・v6オプションでIPoE接続している
IIJmio FiberAccess/NFでインターネットに繋ぐ
DS-Liteの話はここではしない
宅内ノードにもIPv6 GUAを配りたい
難しいポイント
IPv6のグローバルユニキャストアドレスの構造は・・・
RFC 4291: 2.5.1: IPv6ユニキャストアドレスは基本的にインターフェイス識別子を64bitで記述しなければならない
すると、サブネットプレフィックスには残り64bitしか使えない
フレッツはどのようにIPアドレスを配るかというと・・・
ひかり電話を契約しているとき: /56のprefixを配る
RA(+ m-flag) + DHCPv6-PDでprefixを配ってくる
ルータのWANインターフェイス自体はリンクローカルアドレスだけ持つ
残り8bitをサブネットプレフィックスとして自由に使っていい
i.e. 勝手にルーティングしていい
ネットワーク(L3)上もセグメント(L2)上も別物
普通にルーティングする
ひかり電話を契約していないとき: /64のprefixを配る
RAでprefixを配ってくる
サブネットプレフィックスを作れない
i.e. ルーティングの余地がない
i.e. すべて同じネットワークセグメントに収められる
どれだけ複雑なハブ配置にしても、論理的にはでっかい単一のハブにぶら下がっているだけ、に見えるということ
WAN側のインターフェイスと、LAN側にあるすべてのインターフェイスが同一のprefixにいるが、セグメント(L2)では2つに分割されている状態
ネットワーク(L3)上は同一だが、セグメント(L2)上では別物
ルータは、ネットワークの一員として配置される形になる
近隣探索プロトコルをプロキシさせる必要性
さて、IPv6上でネットワークとして相互に疎通するためには近隣探索プロトコル(NDP; RFC 4861)が確立されなければならない
そもそも、あるインターフェイスにパケットを送りたいとき、どこにパケットを投げればいいのか?
IPアドレスから、より1つ下のレイヤのMACアドレスを解決しなければならない
IPv4では、MACアドレス解決のためにARPを利用していた
「このIPアドレス持ってんの誰ですか」「私です」
IPv6では、MACアドレスの解決、到達性の確認、ルータ探索などの機能がNDPに統合された
NDPはICMPv6上でやりとりされるため、このポートは疎通させなければならない
! ところが、RFC 4861によれば、Neighbor SolicitationなどについてNDPのHop Limitは255に設定され、受信時に255でなければ破棄しなければならない仕様になっている 平たく言うと、近隣ノード探索のメッセージはルータを飛び越えられない
近隣インターフェイスの探索は同一リンク内でやるべき仕事であり、ネットワーク間の転送はルータの領分なので、それはそう
ひかり電話を契約している場合は/56のprefixがあるので、サブネットを切ることで普通にルーティングできるようになる
ひかり電話を契約していない場合は/64のprefixなので、サブネットを切れない
ルーティングするには2つのネットワークが必要だが、サブネットがないのでネットワークが1つしかない
NDProxy
ありがたいことに、NDPをプロキシするサーバが存在する
ndppd
EdgeRouter XはMIPSなのでこれ用にクロスビルドする
ビルドまでの手順は同じだが、EdgeOS 3ではsystemdになっている(従来は別のやつだった)ので
$ docker run -v $PWD/ndppd:/ndppd:z -it --rm sho7650/mipsel
:z: SELinuxが有効だとvolume mount失敗することがあるのでその対応
$ cd /ndppd && make -j8
EdgeRouter Xでsshを有効化しておく
あぶないので内部アドレスでリッスンすること
実行ファイル・設定ファイル・起動用ユニットファイルを配置する
code:/config/user-data/ndppd/ndppd.conf
proxy eth0 {
autowire yes
router no
rule ::/0 {
iface switch0
}
}
proxy switch0 {
autowire yes
router yes
rule ::/0 {
iface eth0
}
}
unit file
code:/etc/systemd/system/ndppd.service
Description=ndppd daemon
Wants=network.target
After=network.target
Type=forking
ExecStart=/config/user-data/ndppd/ndppd -c /config/user-data/ndppd/ndppd.conf -d -p /var/run/ndppd/ndppd.pid
PIDFile=/var/run/ndppd/ndppd.pid
Restart=on-failure
RestartSec=2s
WantedBy=multi-user.target
cf.2. にあるNDPPD_DIRは不要だと思われるため削除した。
cf.2. ではType=simpleだが、forkingが適当だと思われたためsimpleからforkingへと変更し、PID Fileを用意するようにした。
code:sh
$ (sshしてディレクトリを掘っておく /config/user-data/ndppd や /var/run/ndppd )
$ scp ndppd <user>@<hostname>:/config/user-data/ndppd/
$ scp ndppd.conf <user>@<hostname>:/config/user-data/ndppd/
$ scp ndppd.service <user>@<hostname>:/config/user-data/ndppd/ # 移動してからsudo cpする
$ ssh (edgerouter)
$ sudo cp /config/user-data/ndppd/ndppd.service /etc/systemd/system/
! /etc/に置いたものはファームウェア更新で消えるので、都度持ってくること $ sudo systemctl daemon-reload
$ sudo systemctl enable ndppd
$ sudo systemctl start ndppd
コツ
ndppdは/config/以下に配置する