Edgerouter (ER-X) で NDプロキシを使って IPv6通信を行う (ひかり電話なし)

# 前提条件

IPoEとして利用できる条件が整っていることが条件ですね。ご存知でしょうけど。

- フレッツ光クロス、フレッツ光ネクスト、またはフレッツ光ライトなど NTT東日本・西日本のNGN回線引き込み済み
- 「フレッツ・v6オプション」契約済み
- IPoEプロバイダに契約済み
- [Edgerouter X(ER-X) 用に ndppd をカンタンにビルドする (ひかり電話なし)](https://qiita.com/sho7650/items/da9bc34f1640223aaf99)で Edgerouter 用の `ndppd`をビルド&インストール済

なお、今すでに`PPPoE`を使っている状況の利用でも問題なく設定できます。安心して設定してください。IPv6アドレスは自動的にグローバルのIPアドレスが付与されます。

# この設定でできること

`IPoE`でIPv6接続できるようになります。

この図でいうとオレンジに囲われた「ココ」の部分を実現します。

<img width="1099" alt="Screen Shot 2020-05-04 at 14.35.57.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37263/6bb18817-d23d-273f-481d-b6e3de8233d4.png">

# IPv6アドレスの取得

[Edgerouter (ER-X) で DS-lite だけしてみる (ひかり電話なし)](https://qiita.com/sho7650/items/23d668d246166338c398)で設定済みの人はすっ飛ばしてくれて良いです。一応ここにも記載しておきます。以下、再掲。

まず、なにはともあれ IPv6アドレスを確認しましょう。以後の設定は、先程の図の通りWAN側を`eth0`、LAN側は`eth1`〜`eth4`を束ねた`switch0`として扱います。また、すべて`CLI`で実行します。`Edgerouter`のOSである`EdgeMax`ではIPv6の設定が、GUIからはちょっとやりにくい(できないとは言っていない)ので、コピペですんで確実なCLIでの操作にしています。大丈夫、1日格闘すれば覚えます。

さて、`ssh`でログインしたらば、次のコマンドを実行します。

```bash
configure
set interfaces ethernet eth0 ipv6 address autoconf
commit; exit
```

これで10分程待つと、IPv6アドレスが振られるはずです。我が家ではこんな感じです。`show interfaces` コマンドを実行してみましょう。ここで`eth0`にIPv6アドレスが振られていれば成功です。`ひかり電話`がないので `/64` でアドレスが振られています。このIPv6アドレスが重要ですので、コピペできるようにしておきましょう。

```bash
$ show interfaces
Codes: S - State, L - Link, u - Up, D - Down, A - Admin Down
Interface    IP Address                        S/L  Description
---------    ----------                        ---  -----------
eth0         2409:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/64
                                               u/u  Internet
eth1         -                                 A/D  disabled
eth2         -                                 u/u  Local
eth3         -                                 u/u  Local
eth4         -                                 A/D  disabled
lo           127.0.0.1/8                       u/u
             ::1/128
switch0      xxx.xxx.xxx.xxx/24                u/u  Local
```

次にIPv6のデフォルトゲートウェイを知ります。個人的には `ip -6 route | grep default` のが分かりやすい気がしないでもないですが、`VyOS`っぽく知るには、このパターンです。

```bash
$ show ipv6 route  | grep '::/0'
K      ::/0 [1/0] via fe80::xxxx:xxxx:xxxx, eth0, 01w4d14h
```

さて、設定としてはこれで終わらせても良いですが、Edgerouter の再起動時などにIPv6アドレスが付与されるまで 10分程度も待てない、ということであれば静的割当しておくことも一つの方法です。ただし、NTT局内工事などでIPv6アドレスの割り振りが変わる可能性もあります。普段はほぼほぼ再起動するようなこともないでしょうし、あまり気にしなくても良い気はしますが、それでも静的割当しておきたいという方は、次のようにします。

## IPv6アドレスの静的割当 (やりたい方だけ)

まず、IPv6アドレスの自動割当を削除します。

```bash
configure
delete interfaces ethernet eth0 ipv6
commit; exit
```

次に、今割り当てられているIPv6アドレスを消し去ります(付与されたままだと、IPアドレスの静的割り当てができません)。

```bash
$ sudo ip addr flush dev eth0
```

※ IPv4アドレスを割り振ってると、それも一緒にここで吹き飛びますから気をつけてください

あとは、先程確認したIPv6アドレスとデフォルトゲートウェイアドレスと個々に割り当てます。

```bash
configure
set interfaces ethernet eth0 address '2409:****:****:****:****:****:****:****/64'
set protocols static route6 ::/0 next-hop 'fe80::xxxx:xxxx:xxxx' interface eth0
commit; exit
```

# クライアント側へIPv6をばらまく

WAN側にIPv6アドレスが割り当てられたら、今度はLAN側にIPv6を割り振れるようにします。`Edgerouter`に割り当てられたIPv6アドレスを元に、ルータからLAN側に`EUI-64｀形式で、ルータ広告(Router Advertisement:もっといい訳はなかったのか)によりIPv6アドレスを自動的に割り振る形になります。

`eui64` 部分には、`eth0`に割り当てられた IPv6アドレスを定義します。

#### LAN内へRAを流す

```bash
set interfaces switch switch0 description Local
set interfaces switch switch0 ipv6 address eui64 '2409:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/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; exit
```

ここまでの定義が完了すると、LAN側でIPv6に対応している端末には 2つの IPv6アドレスが割り振られていることでしょう。あと少しです。

# ndppd を起動する

「[Edgerouter X(ER-X) 用に ndppd をカンタンにビルドする (ひかり電話なし)](https://qiita.com/sho7650/items/da9bc34f1640223aaf99)」でファイルをすべて配置したあとに、`Edgerouter`を再起動したりしていれば既に`ndppd`が動いているかもしれません。まだ再起動もしていなかったり動かしたりもしてなければ、次のコマンドで起動させます。

```bash
$ sudo /config/scripts/post-config.d/ndppd
```

ここまでですべてうまく行っていれば、クライアントからIPv6でネットへアクセス可能です。例えば、次のように`ping6`で`ping`しても帰ってくるはずです。

```bash
ping6 -c 1 www.google.com
PING6(56=40+8+8 bytes) 2409:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx --> 2404:6800:4004:800::2004
16 bytes from 2404:6800:4004:800::2004, icmp_seq=0 hlim=54 time=3.166 ms

--- www.google.com ping6 statistics ---
1 packets transmitted, 1 packets received, 0.0% packet loss
round-trip min/avg/max/std-dev = 3.166/3.166/3.166/0.000 ms
```

# DNSの設定(必要な方だけ)

もし、上記の`ping6`で`Unknown Host`などとでるようであれば、DNSの再設定が必要かもしれません。`Edgerouter`で名前解決できる方法も記述しておきます。

`Edgerouter`が IPv6の DNSサーバを指定して名前解決できるようにしておき、各クライアントの代わりに`Edgerouter`がDNS問い合わせを行います。その結果を各クライアントが受け取れるように、`DNS Forwarding`するという関係です。

#### DNS Forwarding を有効にする

```bash
set system name-server '2001:4860:4860::8888'
set system name-server '2001:4860:4860::8844'

set service dns forwarding cache-size 5000
set service dns forwarding listen-on switch0
set service dns forwarding listen-on lo
set service dns forwarding system
```

`set system name-server` で IPv6 DNSサーバを指定しています。すでに IPv4のDNSサーバが指定してあれば、削除しておきます。とは言え、IPv4のDNSサーバでも AAAA レコードは返してくれるので、どっちでもいい気がしますが、IPv6のがオーバヘッドが少ない(tunnelしてない分)ので気分は良さげです。

そして`set service dns forwarding`で`listen-on`と`cache-size`を決めておきます。DNSキャッシュしてくれるので、複数人で利用する場合にはこちらがお得です。

DHCPでDNSサーバのアドレスも配布している場合には、DNSサーバのアドレスを`Edgerouter`の`switch0`(LAN側)アドレスを指定しましょう。

# Firewall の設定(やっておきましょう)

通信できるようにはなりましたが、このままだと外からダイレクトにアクセスされてしまう状況です。IPアドレス多すぎるので、カンタンに攻撃の範囲になるとは限りませんが、見つかれば即やばい状況です。とっとと塞ぎましょう。

必要なことは、ICMPを受け入れることです。`eth0`(WAN)から入ってきても良いものはICMPだけです。逆張りされてもいいように`DS-lite`用の`ipip6`も受け入れられるようにしておきます。それ以外は排除です。その結果がこちら。

```bash
configure

set firewall all-ping enable
set firewall broadcast-ping disable
set firewall ipv6-name WANv6_IN default-action drop
set firewall ipv6-name WANv6_IN description 'IPv6 WAN to LAN'
set firewall ipv6-name WANv6_IN enable-default-log
set firewall ipv6-name WANv6_IN rule 10 action accept
set firewall ipv6-name WANv6_IN rule 10 description 'Allow established/related sessions'
set firewall ipv6-name WANv6_IN rule 10 state established enable
set firewall ipv6-name WANv6_IN rule 10 state related enable
set firewall ipv6-name WANv6_IN rule 20 action accept
set firewall ipv6-name WANv6_IN rule 20 description 'Allow IPv6 ICMP'
set firewall ipv6-name WANv6_IN rule 20 protocol ipv6-icmp
set firewall ipv6-name WANv6_IN rule 30 action drop
set firewall ipv6-name WANv6_IN rule 30 description 'Drop invalid state'
set firewall ipv6-name WANv6_IN rule 30 state invalid enable

set firewall ipv6-name WANv6_LOCAL default-action drop
set firewall ipv6-name WANv6_LOCAL description 'IPv6 WAN to router'
set firewall ipv6-name WANv6_LOCAL enable-default-log
set firewall ipv6-name WANv6_LOCAL rule 10 action accept
set firewall ipv6-name WANv6_LOCAL rule 10 description 'Allow established/related sessions'
set firewall ipv6-name WANv6_LOCAL rule 10 state established enable
set firewall ipv6-name WANv6_LOCAL rule 10 state related enable
set firewall ipv6-name WANv6_LOCAL rule 20 action accept
set firewall ipv6-name WANv6_LOCAL rule 20 description 'Allow IPv6 icmp'
set firewall ipv6-name WANv6_LOCAL rule 20 protocol ipv6-icmp
set firewall ipv6-name WANv6_LOCAL rule 30 action accept
set firewall ipv6-name WANv6_LOCAL rule 30 description 'Allow DS-Lite'
set firewall ipv6-name WANv6_LOCAL rule 30 protocol ipip
set firewall ipv6-name WANv6_LOCAL rule 40 action accept
set firewall ipv6-name WANv6_LOCAL rule 40 description 'allow dhcpv6'
set firewall ipv6-name WANv6_LOCAL rule 40 destination port 546
set firewall ipv6-name WANv6_LOCAL rule 40 protocol udp
set firewall ipv6-name WANv6_LOCAL rule 50 action drop
set firewall ipv6-name WANv6_LOCAL rule 50 description 'Drop invalid state'
set firewall ipv6-name WANv6_LOCAL rule 50 state invalid enable
set firewall ipv6-receive-redirects disable
set firewall ipv6-src-route disable
set firewall ip-src-route disable
set firewall log-martians enable

set interfaces ethernet eth0 firewall in ipv6-name WANv6_IN
set interfaces ethernet eth0 firewall local ipv6-name WANv6_LOCAL

commit; exit
```

あと、一応DHCPv6が飛んできてもいいように、WAN to Edgerouter で`udp:546`を開けています。固定化していれば不要な気もしますし、RAで割り当てられるだけなら`ICMP`だけで十分な気はしますが、一応。

# 参考

- [EdgeRouter X (ER-X) で IPv6 IPoE + DS-Lite するまで](https://qiita.com/ikai/items/292050d8fa2f185e654a)
- [EdgeRouter設定メモ: IPv6/IPoE + DS-Liteでインターネット高速化](http://stop-the-world.hatenablog.com/entry/2018/11/05/135911)