Un nouveau monde parfumé

香り立つ備忘録

Edgerouter X でひかり電話なし IPv6 をやる

表題のとおりですが、意外とがんばりが必要だったのと、同じような設定で悩む人が多いらしいので忘れないようにメモします

2年近く前の下書きを引っ張り出して焼き直してるので古かったり設定に齟齬があるかもしれません。ひらに

TL;DR

NGN から RA で降ってきた /64 のプレフィックスを Edgerouter で再び LAN 側に広報しつつどうにかして NDP プロキシをやるとできる。

背景

フレッツ光ネクストを使用して IPoE 方式による IPv6 接続を行う場合、ひかり電話契約の有無によってアドレス取得の方法が異なるというのは割と知られた事実だと思います。

具体的には、ひかり電話契約がある場合は DHCPv6-PD を用いてフレッツ網(NGN)から /56 の Prefix Delegation を受けることができ、NGNルーターは PD を受けたルーターにパケットを流してくれるようになります。1

一方、ひかり電話契約がない場合、PD は受けられず、NGNルーターから /64 の Router Advertisement が流れてきます。2 このとき、NTT が想定している使い方としては IPv6 のみ LAN 内のネットワークと L2 ブリッジ(a.k.a. IPv6 パススルー)してやることで LAN 内機器と NGN ルーターで直接通信するというものだと思います。

しかしながら、ウチのガバガバセキュリティの機器をインターネットに直接晒すのはやや怖い…… ので、なんとか L3 ルーティングでことを済ませたい、というのが本記事の背景となります。

構成

回線: Softbank光 マンション・ギガスピード3

ISP: インターリンク ZOOT NATIVE

ONU: GE-PON タイプD

ルーター: Edgerouter X (ER-X)

以降の設定例では次のインターフェイスを使用することとします。(適宜読み替えてください)

WAN側IF: eth0

LAN側IF: switch0 (eth2-4)

設定

1. WAN側インターフェイスIPv6 アドレスを当てる

これは単純で、RA を受けて SLAAC でアドレスを確定させるだけです。

set interfaces ethernet eth0 ipv6 address autoconf
set interfaces ethernet eth0 ipv6 dup-addr-detect-transmits 1

この段階で WAN 側インターフェイスにはグローバルアドレスがつき、ルーターから外へは IPv6 通信できるようになります。

4: eth0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether fc:ec:da:XX:XX:1e brd ff:ff:ff:ff:ff:ff
    inet6 2409:10:XXXX:XXXX:feec:daff:feXX:XX1e/64 scope global dynamic 
       valid_lft 2591862sec preferred_lft 604662sec
    inet6 fe80::feec:daff:fexx:xx1e/64 scope link 
       valid_lft forever preferred_lft forever

2. IPv4 接続性を確保する

本筋から外れるので設定だけ列挙して詳細な解説は割愛します。

2.1 DS-Lite

set interfaces ipv6-tunnel v6tun0 encapsulation ipip6
set interfaces ipv6-tunnel v6tun0 firewall in name DSLITE_IN
set interfaces ipv6-tunnel v6tun0 firewall local name DSLITE_LOCAL
set interfaces ipv6-tunnel v6tun0 local-ip '2409:10:XXXX:XXXX:feec:daff:feXX:XX1e'
set interfaces ipv6-tunnel v6tun0 mtu 1460
set interfaces ipv6-tunnel v6tun0 multicast disable
set interfaces ipv6-tunnel v6tun0 remote-ip '2404:8e00::feed:100'
set interfaces ipv6-tunnel v6tun0 ttl 64

出口は transix です local-ip に prefix を直打ちしない方法はまだ知らない

2.2 PPPoE

set interfaces ethernet eth0 description 'Internet(v4/v6)'
set interfaces ethernet eth0 duplex auto
set interfaces ethernet eth0 firewall in ipv6-name WAN6_IN
set interfaces ethernet eth0 firewall local ipv6-name WAN6_LOCAL
set interfaces ethernet eth0 ipv6 address autoconf
set interfaces ethernet eth0 ipv6 dup-addr-detect-transmits 1
set interfaces ethernet eth0 pppoe 0 default-route none
set interfaces ethernet eth0 pppoe 0 firewall in name WAN_IN
set interfaces ethernet eth0 pppoe 0 firewall local name WAN_LOCAL
set interfaces ethernet eth0 pppoe 0 mtu 1454
set interfaces ethernet eth0 pppoe 0 name-server auto
set interfaces ethernet eth0 pppoe 0 password XXXX
set interfaces ethernet eth0 pppoe 0 user-id XXX@sbb.ne.jp
set interfaces ethernet eth0 speed auto
set service nat rule 5010 description 'masquerade for WAN'
set service nat rule 5010 outbound-interface pppoe0
set service nat rule 5010 type masquerade

2.3 PBR

PBR で基本は全て DS-Lite に向けつつ、特定ホストやシステムのデフォルトルートは PPPoE に向けることにする。こうすると必要に応じてポート開放できたり、UPnP を喋らせたりできて便利

set firewall group network-group PRIVATE_NETS network 192.168.0.0/16
set firewall group network-group PRIVATE_NETS network 172.16.0.0/12
set firewall group network-group PRIVATE_NETS network 10.0.0.0/8
set firewall modify PBR-121 rule 10 action modify
set firewall modify PBR-121 rule 10 description 'これがないと VPN などが DS-Lite に吸われる'
set firewall modify PBR-121 rule 10 destination group network-group PRIVATE_NETS
set firewall modify PBR-121 rule 10 modify table main
set firewall modify PBR-121 rule 20 action modify
set firewall modify PBR-121 rule 20 destination group address-group ADDRv4_eth0
set firewall modify PBR-121 rule 20 modify table main
set firewall modify PBR-121 rule 91 action modify
set firewall modify PBR-121 rule 91 description 'ゲーム機とかはこうしてる'
set firewall modify PBR-121 rule 91 modify table main
set firewall modify PBR-121 rule 91 source address 192.168.XX.XX
set firewall modify PBR-121 rule 92 action modify
set firewall modify PBR-121 rule 100 action modify
set firewall modify PBR-121 rule 100 description 'Default to DS-Lite(table 121)'
set firewall modify PBR-121 rule 100 modify table 121

set interfaces switch switch0 firewall in modify PBR-121

set protocols static table 121 description 'default to v6tun0'
set protocols static table 121 interface-route 0.0.0.0/0 next-hop-interface v6tun0 distance 100

# デフォルトルート設定など
set port-forward wan-interface pppoe0
set protocols static interface-route 0.0.0.0/0 next-hop-interface pppoe0 distance 11
set protocols static interface-route 0.0.0.0/0 next-hop-interface v6tun0 distance 12
set service upnp listen-on switch0 outbound-interface pppoe0

3. LAN 内に IPv6 プレフィックスを広報する

1 で取得した /64 を RA で LAN 内に配ります。

set interfaces switch switch0 ipv6 address autoconf
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 0
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 false
set interfaces switch switch0 ipv6 router-advert prefix '2409:10:XXXX:XXXX::/64' autonomous-flag true
set interfaces switch switch0 ipv6 router-advert prefix '2409:10:XXXX:XXXX::/64' on-link-flag true
set interfaces switch switch0 ipv6 router-advert prefix '2409:10:XXXX:XXXX::/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

できればここも autoconf だけで済ませて直打ちを避けたかったんですが、再起動するとアドレスが当たらなくなるので諦めています。4 フレッツの IPv6 プレフィックスは「半固定」とのことなので滅多なことでは変わらないと思いますが、過去1度再起動後に変わったことがあります。あと引っ越しでは(契約は引き継いだが)当然変わりました。

うまくいけば LAN 側インターフェイスにも IPv6 アドレスが付きます。

2: switch0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UNKNOWN group default qlen 1000
    link/ether fc:ec:da:XX:XX:23 brd ff:ff:ff:ff:ff:ff
    inet6 2409:10:XXXX:XXXX:feec:daff:feXX:XX23/64 scope global dynamic 
       valid_lft 2591805sec preferred_lft 604605sec
    inet6 fe80::feec:daff:feXX:XX23/64 scope link 
       valid_lft forever preferred_lft forever

LAN 内のクライアントも SLAAC で global IPv6 アドレスが取得できます。

 $ ip a

2: wlp60s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
    link/ether a8:7d:12:XX:XX:XX brd ff:ff:ff:ff:ff:ff
    inet 192.168.XX.XX/24 brd 192.168.XX.255 scope global dynamic noprefixroute wlp60s0
       valid_lft 67359sec preferred_lft 67359sec
    inet6 2409:10:XXXX:XXXX:f6e3:2d57:97ba:a680/64 scope global dynamic noprefixroute 
       valid_lft 2591891sec preferred_lft 604691sec
    inet6 fe80::d234:29c:34:5381/64 scope link noprefixroute 
       valid_lft forever preferred_lft forever

4. NDP Proxy する

さてここまでで見かけ上 LAN 内には global IPv6 が当たりましたが、このままでは通信ができません。これは、上流の NGNルーターが LAN 内クライアントのアドレスを知らないためです。というわけで NDP Proxy で LAN 内クライアントのアドレス情報を上流ルーターに伝えてやります。

NDP Proxy の実装はこれを使わせてもらってます。

github.com

で、こいつを MIPS 向けにビルドする必要があるんですが、まあまあダルいのでビルドしたやつを置いておきます。無保証/自己責任でお願いします。 musl に static link しているので、環境を選ばず動くと思います。

https://minio.venusark.p1kachu.net/public/ndppd.zip

たぶん 2.x ファームなら Debian リポジトリからもインストールできるとは思いますが、これをやったのは 1.x ファームの時代で、 wheezy には ndppd なかった。

/config/user-data/ndppd に実行ファイルと設定を配置します。設定 ndppd.conf は以下です。

proxy eth0 {
      autowire yes

      rule ::/0 {
        iface switch0
      }
}

proxy switch0 {
      autowire yes
      router yes

      rule ::/0 {
        iface eth0
      }
}

起動スクリプト/etc/init.d/ndppd に配置します。こちらのコードは https://community.ui.com/questions/Set-up-IPv6-without-Prefix-Delegation/ea0998be-2d13-4747-ac1e-9a26cb1a2976 を参考にさせていただきました。

#!/bin/bash
ACTION=$1
NDPPD_DIR="/config/user-data/ndppd"
NDPPD_BIN="$NDPPD_DIR/ndppd"
NDPPD_CONF="$NDPPD_DIR/ndppd.conf"
NDPPD_PID="/run/ndppd.pid"

do_stop(){
        if [ -f $NDPPD_PID ]; then
                kill `cat $NDPPD_PID` > /dev/null 2>&1
                rm -f $NDPPD_PID
        fi
        echo 0 > /proc/sys/net/ipv6/conf/all/proxy_ndp
        echo 0 > /proc/sys/net/ipv6/conf/default/proxy_ndp
        /sbin/ifconfig switch0 -promisc
        /sbin/ifconfig eth4 -promisc
        /sbin/ifconfig eth3 -promisc
        /sbin/ifconfig eth2 -promisc
        /sbin/ifconfig eth1 -promisc
        /sbin/ifconfig eth0 -promisc
}
do_start(){
        if [ -f $NDPPD_CONF ]; then
                echo "Starting NDP Proxy Daemon ..."
                /sbin/ifconfig eth0 promisc
                /sbin/ifconfig eth1 promisc
                /sbin/ifconfig eth2 promisc
                /sbin/ifconfig eth3 promisc
                /sbin/ifconfig eth4 promisc
                /sbin/ifconfig switch0 promisc
                echo 1 > /proc/sys/net/ipv6/conf/default/proxy_ndp
                echo 1 > /proc/sys/net/ipv6/conf/all/proxy_ndp
                $NDPPD_BIN -d -c $NDPPD_CONF -p $NDPPD_PID
        else
                echo "ERROR: $NDPPD_CONF not found"
                exit 1
        fi
}
case "$ACTION" in
        start)
                do_start
        ;;
        restart)
                do_stop
                do_start
        ;;
        stop)
                do_stop
        ;;
        *)
                echo "$1 start|stop|restart"
        ;;
esac
exit 0

/etc/rc.local に追記すると自動起動できます。

service ndppd start

なお、 /config/user-data 外に配置したファイルについてはファームウェアアップデート時に失われるので、 /etc 以下をいじる際にはアップデート後に再度設定を行うことをお忘れなく。

できた

全てが上手く行っていれば LAN 内から IPv6 通信ができる状態になっていると思います。お疲れ様でした。あと v6 側のファイアウォール設定とかはよしなにやってください。

この記事を下書きから救い出した理由ですが、まだファームが1.xで止まってるのでいい加減2.xに上げようと思います。VPN周りのデグレが問題で上げれてなかった。


  1. ひかり電話がある場合、大体は NTT の HGW(ホームゲートウェイ)を利用することになると思うのですが、その場合 HGW が /56 を受け、その下流ルーターを置くことでさらに /60 が移譲されます。

  2. ひかり電話ありでも RA は送出されるが managed Flag 付きで DHCPv6 の利用が必須

  3. 工事費が安くなるという口車に乗せられてSB光にしたが情弱プレイだったと思う / 内容はフレッツの再販なので大した違いはないがBB光ユニットとかいうやつの存在がウザかった(返却しないと他のv6オプションが使えない)

  4. なんか net.ipv6.conf.switch0.accept_ra = 2 するとか色々頑張ってた気がするんだけど今見たらその設定どこにも見当たらないしすっかり忘れてしまった