FreeBSDルーターでIPv6のIPoE接続

IPoEをググると「次世代のホゲホゲ」とか何故かそんなのが多くヒットするようだけど、IPoEはトンネルだのトランスレートだの無しに普通にイーサネット回線をIPパケットが通る極めて普通な通信のことなので「IPoE」なんて但し書きは本来は要らない(「車が通る車道です」みたいな)ものだけど、NTTのフレッツではこれまでトンネルのPPPoEなどが当たり前だったのでIPoEが「新しい?」という意味不明に本末転倒的なことになってるのね。この記事は普通のIPv6でLAN外に繋ぐよっていう内容。

インターネットの接続にNTTのフレッツとSo-netを利用しているのだが、夜間の速度低下が酷いのとちょくちょく数秒から数十秒ほど通信が停まったようになることがあって困っていた。
So-netから公式なサービス開始アナウンスは無いもののIPoE接続の提供を始めているという話が2月あたりから出ていて「改善するなら切り替えようかな?、でも面倒だな」とズルズル1ヶ月以上放置してしまった。
ただ、ちょうどSo-netとFletsの契約が2年過ぎるということで契約の見直しをしたらフレッツの「V6オプション」も契約していたことを知った(忘れていただけ)。IPoE接続にはV6オプションが必要なんだけど既に契約していて、しかも(そのV6ネームが)未使用なら話は早い。
早速So-netのサポートに連絡したらフレッツの回線契約(名義)の確認をされて、3営業日後の昼までに使えるようになりますという連絡があったが、翌日の昼には既に使えるようになっていた(切り替わっていた)。

例によってルーターは家庭用のブロードバンドルーターとかじゃなくFreeBSDのPC。もちろんFreeBSDじゃなくてもLinuxでも良い。WindowsもIPoEには間違いなく繋がるけどNAT付きルーターになるかは知らない。

前提としてPCにネットワークのコネクタが2つあること。この記事ではNICはそれぞれWAN側(Flets側)のem0とLAN側のem1とする。emの部分はFreeBSDでIntelのご家庭向けネットワークチップを使うとこのデバイス名になる、安物PCに搭載されていることが多い蟹ならreになるetc。

この記事の内容はIPoE接続しようとするFreeBSDルーターが既にmpd5,mpd4,pppでIPv4のPPPoE接続していてもそちらの通信には影響しない。(システム再起動時を除く)

PPPoE接続
PPPoE接続の図。ネットワーク図としてこんなの出したらうるさい人たちは西川きよし並に目をひん剥いて「こんなのはダメだ💢」って怒りそうだけどわかり易さ優先で。
ネットワーク2つを書いたが、これは複数PPPoEセッション、つまり1つのフレッツ回線で2つのISPに繋いでいる図のつもり。
普通のご家庭なら左半分だけで見る(中央のONUの下のスイッチも無い筈)。
回線としてのNTTとユーザーの境界はONU(またはHGW)だが、ネットワーク的な境界はPPPoEを行うルーター。
ONUやスイッチはただの通り道なので本当は図中に登場する必要はないけど無理やり入れてみた。スイッチで縦横分岐してるけど図をコンパクトに収める為なので生暖かくみて欲しい。

IPoE接続
こちらがIPoE接続で、この記事のネットワーク図
おそらく普通のご家庭でIPoEを使うとしたら右のルーターから下が無い状態(薄緑色のフレッツのIPoEの部分だけ)になるかと思われる。今回はルーターでIPv6 NAT (NAT66)にしてインターネットにも繋がるけど一応別ネットワークとする。IPoEのネットワークの図は超ずさんでIPv6環境で必要なもの(フレッツ側)が何も書かれていないけどご容赦。
ところでIPv6なNATを行わない場合はネットワークの境界は何処なんだろう。

回線のIPoE切り替え

フレッツ回線(Bフレッツ除く)だと直にインターネットにはつながらないものの最初からIPv6な環境はある筈。まずはそれでIPv6アドレスが付与されることを確認しておく。

/etc/rc.conf (IPoE切り替え前のIPv6関係の部分だけ)
1
2
3
ipv6_activate_all_interaces="YES"
ifconfig_em0_ipv6="inet6 accept_rtadv"
rtsold_enable="YES"

これでシステムを再起動するなりネットワークだけ再起動するとFletsのIPv6アドレスが付与される筈。

$ ifconfig em0
em0: flags=8843<up ,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	中略
	2001:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx prefixlen 64 autoconf
	nd6 options=23<performnud ,ACCEPT_RTADV,AUTO_LINKLOCAL>
	media: Ethernet autoselect (1000baseT <full -duplex>)
	status: active

おそらくこんな感じでIPv6のアドレスが表示される筈。フレッツのv6オプション(IPoEのサービス)申し込み時(切り替わり前)に付与されてるこのアドレス(の最初の4文字)を確認しておくと良い。上の例では2001から始まるIPv6アドレスだが必ずそれとは限らない。
v6オプションが有効になりIPoEが利用できるようになるとIPv6アドレス変わるので最初の4文字が別のものになっていることを確認。またはアドレス表示して変わっていなくても(切り替えが済んでいれば)システムを再起動すると変わる。今回は2409で始まるものに変わった。

IPoEはこれで終わりっちゃ終わり。

念のために名前解決の設定だけ変更しておく。

/etc/resolv.conf
1
2
3
4
5
6
7
8
9
search localnet
#opendns
nameserver 2620:0:ccc::2
nameserver 2620:0:ccd::2
#google
nameserver 2001:4860:4860::8888
nameserver 2001:4860:4860::8844
nameserver 8.8.8.8
nameserver 8.8.4.4
So-netのPPPoEのIPv4接続で利用していたSo-netのDNSは外す。←こいつはAAAAレコードを返さないのでIPv4,IPv6デュアルスタック環境ではトラブルの元。(IPv4 PPPoEだけのときは寧ろありがたい)

これで上のIPoEの図の中央のノートPCの位置づけになった。

接続確認

$ host www.google.com
www.google.com has address 74.125.***.***
www.google.com has address 74.125.***.***
www.google.com has address 74.125.***.***
www.google.com has address 74.125.***.***
www.google.com has address 74.125.***.***
www.google.com has address 74.125.***.***
www.google.com has IPv6 address 2404:6800:****:****::****

隠す必要はないだろうけど一応*は伏せ字。
返答するのがIPv4のDNSだろうがIPv6のDNSだろうがとにかくIPv6のレコードが1つでも返ってきてればそれで良い。

$ ping6 www.google.com
PING6(56=40+8+8 bytes) 2409:****:****:****:****:****:****:**** --> 2404:****:****:****::****
16 bytes from 2404:6800:****:****::****, icmp_seq=0 hlim=46 time=42.931 ms
16 bytes from 2404:6800:****:****::****, icmp_seq=1 hlim=46 time=43.130 ms

IPv6版のpingはping6。これで応答があればIPv6が疎通していることがわかる。当然だけど通信相手のホストがIPv6対応にしていること。

IPv6でNAT

疎通はできた。でも、これだと同じネットワークの端末それぞれ個別にセキュリティの設定が必要。面倒なので ファイアウォール付きIPv6なNATのルーターにして自宅側IPv6LANの安全を簡単に確保できるようにしたい。
単にIPoEに繋いだだけだとインターネット側から丸見えということもあるのでそのあたり十分に注意。これまで家庭用のブロードバンドルーターのNAT環境を利用してた等でセキュリティを特に考えてなかった人は考えを改めた方がよさ気。

IPv6のNATは凄い簡単。

/etc/rc.conf (IPv6関係部分だけ)
1
2
3
4
5
6
7
8
ipv6_gateway_enable="YES"
ipv6_activate_all_interaces="YES"
ifconfig_em0_ipv6="inet6 accept_rtadv"  #←WAN側
ifconfig_em1_ipv6="inet6 xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx prefixlen 64 -accept_rtadv" #←LAN側IPアドレス指定
rtsold_enable="YES"
 
rtadvd_enable="YES"
rtadvd_interfaces="em1" #←LAN側

IPv6のLAN用アドレスは RFC4193のUnique Local IPv6 Unicast Addresses を見て作ればいいけど Unique Local IPv6 Generator という便利なページがあるのでこちらで作る(表示するだけ)。表示されたプレフィックス(Ipv4でいうところのネットワークアドレス)の1st subnetというのを使うのが簡単。これはネットワークのアドレスなのでインターフェースID(IPv4でいうところのホスト部)のアドレスも決めておく。/64の直前に64ビット16進数の値を何かテキトーに決めて入れてルーターのLAN側アドレスとする。64ビット分を決めるというのも面倒なので普通にただの1で良いかと。

上で挙げたジェネレータで表示された1st subnetはおそらくxxxx:xxxx:xxxx::/64な筈。
これは実際にはxxxx:xxxx:xxxx:0000::/64のこと。/64 (64ビット)の場合は自由に決めてよいインターフェースIDは
xxxx:xxxx:xxxx:0000:yyyy:yyyy:yyyy:yyyy のyの部分。末尾1以外を0にすると
xxxx:xxxx:xxxx:0000:0000:0000:0000:0001 となる。IPv6アドレスは0が連続するところ(何桁でも)を1箇所だけ::で省略してよいのでxxxx:xxxx:xxxx::1となる。これをルーターのLAN側のアドレスとする。

RAの設定

FreeBSDにはrtadvdが入ってるので設定ファイルは/etc/rtadvd.conf。(有効化に必要なのは上の/etc/rc.confの最後の2行)

1
2
3
4
5
em1:\  
    :addr="xxxx:xxxx:xxxx:xxxx::":prefixlen#64:
    :pinfoflags="l":\
    :rdnss="xxxx:xxxx:xxxx:xxxx::xxxx":\
    :dnssl="localnet":

1行目でLAN側のネットワークインターフェース(NIC)を指定する。
2行目でLAN側に広告するIPv6 LANのネットワークのアドレス(プレフィックス)を指定する。xxxx:xxxx:xxxx::の部分は上で決めたLAN側のプレフィックス(ジェネレータで表示された1st subnetそのもの)。プレフィックス長をprefixlen#で指定。IPv6のDNSサーバのIPv6アドレスをrdnssでLAN内に通知する。

IPv6 NATはIPv4と同じくFreeBSDに入っているファイアウォールのpfで行うこととする。(これしかダメということではない。)

/etc/pf.conf
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
#macro部に記述
ext_ifv4 = "ng0"   #PPPoE用 IPv4など
int_ifv4 = "em1"   #LAN側
int_netv4 = "192.168.0.0/24"

#IPv6
ext_ifv6 = "em0"
ext_ipv6="xxx:xxx:xxx::1" #WAN(em0)側のIPv6アドレス 2409*など
int_netv6 = "xxx:xxx:xxx::/64" #IPv6 LANのプレフィックス 

#normalization部とfilter部の間に記述
nat on $ext_ifv4 from $int_netv4 to any -> ($ext_ifv4)		#IPv4 NAT (PPPoEなど)
nat on $ext_ifv6 inet6 from $int_netv6 to any -> $ext_ipv6	#NAT66

IPv4関係の記述はIPv4のPPPoE接続が既にあるとしてそれのNATの例。IPv4のPPPoE接続が無いなら無視で。
pfの設定はパート単位で記述順序が決まっているのでFilter部ルールを先に書いてNormalization部ルール(scrubなど)を後に書くとかはダメ。

filter部のルールはIPv4とIPv6それぞれWAN,LAN,DMZをしっかり分けて考えて無駄に通し過ぎないこと。逆に通し忘れも注意。icmp6とか結構考慮漏れがあったりする。

service pf reload または service pf restart でpfの設定を再読み込みせさるか再起動させる。

夜間の通信速度低下の面は肝心のIPv4がPPPoEのままなので改善していない。次の記事でDS-Liteの設定を行って対応する(予定)。
GIF (generic tunnel interface)使うだけなのでアホみたいに簡単。

関連記事: